From eb2aef790efa578d6f517016a71132616847943f Mon Sep 17 00:00:00 2001 From: Ivan Date: Sat, 1 Aug 2026 03:34:51 -0700 Subject: [PATCH 1/5] implement base-engine items --- engine/assets/langs/en.txt | 71 ++++++++++++ engine/items/bisicle.lua | 35 ++++++ engine/items/blanket.lua | 26 +++++ engine/items/butterscotch_pie.lua | 26 +++++ engine/items/cinnamon_bunny.lua | 26 +++++ engine/items/monster_candy.lua | 87 ++++++++++++++ engine/items/nice_cream.lua | 108 ++++++++++++++++++ engine/items/snowman_piece.lua | 26 +++++ engine/items/spider_cider.lua | 26 +++++ engine/items/spider_donut.lua | 80 +++++++++++++ engine/items/temmie_flakes.lua | 26 +++++ engine/items/unisicle.lua | 26 +++++ engine/mods/world_example/assets/langs/en.txt | 14 ++- engine/mods/world_example/mod.lua | 6 +- .../world_example/scripts/items/bisicle2.lua | 35 ++++++ .../scripts/world/shop/dummy_shop.lua | 8 +- engine/utils/utils.lua | 13 +++ 17 files changed, 629 insertions(+), 10 deletions(-) create mode 100644 engine/items/bisicle.lua create mode 100644 engine/items/blanket.lua create mode 100644 engine/items/butterscotch_pie.lua create mode 100644 engine/items/cinnamon_bunny.lua create mode 100644 engine/items/monster_candy.lua create mode 100644 engine/items/nice_cream.lua create mode 100644 engine/items/snowman_piece.lua create mode 100644 engine/items/spider_cider.lua create mode 100644 engine/items/spider_donut.lua create mode 100644 engine/items/temmie_flakes.lua create mode 100644 engine/items/unisicle.lua create mode 100644 engine/mods/world_example/scripts/items/bisicle2.lua diff --git a/engine/assets/langs/en.txt b/engine/assets/langs/en.txt index ed0ec41..a2316ba 100644 --- a/engine/assets/langs/en.txt +++ b/engine/assets/langs/en.txt @@ -103,6 +103,77 @@ ITEM_STICK_SHORTNAME=Stick ITEM_STICK_DESCRIPTION=* "Stick" - Weapon AT 0\n* Its bark is worse than\n its bite. ITEM_STICK_USE=* You threw the stick away.[wait:5]\n* Then picked it back up. +ITEM_MONSTER_CANDY_NAME=Monster Candy +ITEM_MONSTER_CANDY_SHORTNAME=MnstrCndy +ITEM_MONSTER_CANDY_DESCRIPTION=* "Monster Candy" - Heals 10 HP\n* Has a distinct,[wait:5] \n non-licorice flavor. +ITEM_MONSTER_CANDY_DESCRIPTION_SHOP=Heals 10 HP\n(Licorice-\nfree\nguaranteed.) +BATTLE_MONSTER_CANDY_USE=\n* Very un-licorice-like. +BATTLE_MONSTER_CANDY_USE_2=\n* ... tastes like licorice. + +ITEM_SPIDER_DONUT_NAME=Spider Donut +ITEM_SPIDER_DONUT_SHORTNAME=SpidrDont +ITEM_SPIDER_DONUT_SHORTNAME2=SpdrDonut +ITEM_SPIDER_DONUT_DESCRIPTION=* "Spider Donut" - Heals 12 HP\n* A donut made with Spider\n Cider in the batter. +ITEM_SPIDER_DONUT_DESCRIPTION_SHOP=undefined +BATTLE_SPIDER_DONUT_USE=* Don't worry,[wait:5] Spider didn't. + +ITEM_SPIDER_CIDER_NAME=Spider Cider +ITEM_SPIDER_CIDER_SHORTNAME=SpidrCidr +ITEM_SPIDER_CIDER_SHORTNAME2=SpdrCider +ITEM_SPIDER_CIDER_DESCRIPTION=* "Spider Cider" - Heals 24 HP\n* Made with whole spiders,[wait:5]\n not just the juice. +ITEM_SPIDER_CIDER_DESCRIPTION_SHOP=undefined + +ITEM_BUTTERSCOTCH_PIE_NAME=Butterscotch Pie +ITEM_BUTTERSCOTCH_PIE_SHORTNAME=ButtsPie +ITEM_BUTTERSCOTCH_PIE_SHORTNAME2=Pie +ITEM_BUTTERSCOTCH_PIE_DESCRIPTION=* "Butterscotch Pie" - All HP\n* Butterscotch-cinnamon\n pie,[wait:5] one slice. +ITEM_BUTTERSCOTCH_PIE_DESCRIPTION_SHOP=undefined + +ITEM_SNOWMAN_PIECE_NAME=Snowman Piece +ITEM_SNOWMAN_PIECE_SHORTNAME=SnowPiece +ITEM_SNOWMAN_PIECE_SHORTNAME2=SnowPiece +ITEM_SNOWMAN_PIECE_DESCRIPTION=* "Snowman Piece" - Heals 45 HP\n* Please take this to the\n ends of the earth. +ITEM_SNOWMAN_PIECE_DESCRIPTION_SHOP=undefined + +ITEM_NICE_CREAM_NAME=Nice Cream +ITEM_NICE_CREAM_SHORTNAME=NiceCream +ITEM_NICE_CREAM_SHORTNAME2=NiceCream +ITEM_NICE_CREAM_DESCRIPTION=* "Nice Cream" - Heals 15 HP\n* Instead of a joke,[wait:5] the\n wrapper says something nice. +ITEM_NICE_CREAM_DESCRIPTION_SHOP=undefined +BATTLE_NICE_CREAM_USE=* You're just great! +BATTLE_NICE_CREAM_USE_2=* You look nice today! +BATTLE_NICE_CREAM_USE_3=* Are those claws natural? +BATTLE_NICE_CREAM_USE_4=* You're super spiffy! +BATTLE_NICE_CREAM_USE_5=* Have a wonderful day! +BATTLE_NICE_CREAM_USE_6=* Is this as sweet as you? +BATTLE_NICE_CREAM_USE_7=* (An illustration of a hug.) +BATTLE_NICE_CREAM_USE_8=* Love yourself! I love you! + +ITEM_BISICLE_NAME=Bisicle +ITEM_BISICLE_SHORTNAME=Bisicle +ITEM_BISICLE_SHORTNAME2=Bisicle +ITEM_BISICLE_DESCRIPTION=* "Bisicle" - Heals 11 HP\n* It's a two-pronged popsicle,[wait:5]\n so you can eat it twice. +ITEM_BISICLE_DESCRIPTION_SHOP=Heals 11HP x 2\nEat it twice! +BATTLE_BISICLE_USE=* You eat one half of\n the Bisicle. + +ITEM_UNISICLE_NAME=Unisicle +ITEM_UNISICLE_SHORTNAME=Unisicle +ITEM_UNISICLE_SHORTNAME2=Popsicle +ITEM_UNISICLE_DESCRIPTION=* "Unisicle" - Heals 11 HP\n* It's a SINGLE-pronged popsicle.[wait:5]\n* Wait,[wait:5] that's just normal... +ITEM_UNISICLE_DESCRIPTION_SHOP=undefined + +ITEM_CINNAMON_BUNNY_NAME=Cinnamon Bunny +ITEM_CINNAMON_BUNNY_SHORTNAME=CinnaBun +ITEM_CINNAMON_BUNNY_SHORTNAME2=C. Bun +ITEM_CINNAMON_BUNNY_DESCRIPTION=* "Cinnamon Bunny" - Heals 22 HP\n* A cinnamon roll in the shape\n of a bunny. +ITEM_CINNAMON_BUNNY_DESCRIPTION_SHOP=Heals 22HP\nIt's my own\nrecipe. + +ITEM_TEMMIE_FLAKES_NAME=Temmie Flakes +ITEM_TEMMIE_FLAKES_SHORTNAME=TemFlakes +ITEM_TEMMIE_FLAKES_SHORTNAME2=TemFlakes +ITEM_TEMMIE_FLAKES_DESCRIPTION=* "Temmie Flakes" - Heals 2 HP\n* It's just torn up pieces\n of colored construction paper. +ITEM_TEMMIE_FLAKES_DESCRIPTION_SHOP=Heals 2HP\nfood of\ntem + # World shop WORLD_SHOP_ACTION_BUY=Buy WORLD_SHOP_ACTION_SELL=Sell diff --git a/engine/items/bisicle.lua b/engine/items/bisicle.lua new file mode 100644 index 0000000..897e7ce --- /dev/null +++ b/engine/items/bisicle.lua @@ -0,0 +1,35 @@ +--- @class Item.Bisicle : Dummy.Item.Consumable +local BisicleItem = Class(ItemConsumable, "Item.Bisicle") + +--- Creates a bisicle +--- @return Item.Bisicle +function BisicleItem:new() + self = Class:new(BisicleItem, { + "bisicle", -- item identifier + "ITEM_BISICLE_NAME", -- item name + "ITEM_BISICLE_SHORTNAME", -- item short name + "ITEM_BISICLE_DESCRIPTION", -- item description + 11, + "food" + }) + + -- the price the player will pay to buy the item in the shop + self:setBuyPrice(15) + -- the price at which the item will be sold in the shop + self:setSellPrice(5) + -- the text that will appear in the shop item info at the top right on the buy menu when hovering an item + self:setShopDescription("ITEM_BISICLE_DESCRIPTION_SHOP") + + self.use_texts = { + "BATTLE_BISICLE_USE" + } + + return self +end + +function BisicleItem:onUse() + local unisicle = modRequire("scripts.items.unisicle"):new() + Player.addItem(unisicle) +end + +return BisicleItem diff --git a/engine/items/blanket.lua b/engine/items/blanket.lua new file mode 100644 index 0000000..67d9899 --- /dev/null +++ b/engine/items/blanket.lua @@ -0,0 +1,26 @@ +--- @class Item.Blanket : Dummy.Item.Consumable +local BlanketItem = Class(ItemEquipment, "Item.Blanket") + +--- Creates a monster candy +--- @return Item.Blanket +function BlanketItem:new() + self = Class:new(BlanketItem, { + "blanket", -- item identifier + "WORLD_EXAMPLE_MOD_ITEM_BLANKET_NAME", -- item name + "WORLD_EXAMPLE_MOD_ITEM_BLANKET_SHORTNAME", -- item short name + "WORLD_EXAMPLE_MOD_ITEM_BLANKET_DESCRIPTION", -- item description + 1, + "armor" + }) + + -- the price the player will pay to buy the item in the shop + self:setBuyPrice(10) + -- the price at which the item will be sold in the shop + self:setSellPrice(1) + -- the text that will appear in the shop item info at the top right on the buy menu when hovering an item + self:setShopDescription("WORLD_EXAMPLE_MOD_ITEM_BLANKET_DESCRIPTION_SHOP") + + return self +end + +return BlanketItem diff --git a/engine/items/butterscotch_pie.lua b/engine/items/butterscotch_pie.lua new file mode 100644 index 0000000..1e592ae --- /dev/null +++ b/engine/items/butterscotch_pie.lua @@ -0,0 +1,26 @@ +--- @class Item.ButterScotchPie : Dummy.Item.Consumable +local ButterScotchPieItem = Class(ItemConsumable, "Item.ButterScotchPie") + +--- Creates a spider donut +--- @return Item.ButterScotchPie +function ButterScotchPieItem:new() + self = Class:new(ButterScotchPieItem, { + "butterscotch_pie", -- item identifier + "ITEM_BUTTERSCOTCH_PIE_NAME", -- item name + "ITEM_BUTTERSCOTCH_PIE_SHORTNAME", -- item short name + "ITEM_BUTTERSCOTCH_PIE_DESCRIPTION", -- item description + Player.getMaxHP(), + "food" + }) + + -- the price the player will pay to buy the item in the shop + self:setBuyPrice(1) + -- the price at which the item will be sold in the shop + self:setSellPrice(180) + -- the text that will appear in the shop item info at the top right on the buy menu when hovering an item + self:setShopDescription("ITEM_BUTTERSCOTCH_PIE_DESCRIPTION_SHOP") + + return self +end + +return ButterScotchPieItem diff --git a/engine/items/cinnamon_bunny.lua b/engine/items/cinnamon_bunny.lua new file mode 100644 index 0000000..33aa7aa --- /dev/null +++ b/engine/items/cinnamon_bunny.lua @@ -0,0 +1,26 @@ +--- @class Item.CinnamonBunny : Dummy.Item.Consumable +local CinnamonBunnyItem = Class(ItemConsumable, "Item.CinnamonBunny") + +--- Creates a cinnamon bunny +--- @return Item.CinnamonBunny +function CinnamonBunnyItem:new() + self = Class:new(CinnamonBunnyItem, { + "cinnamon_bunny", -- item identifier + "ITEM_CINNAMON_BUNNY_NAME", -- item name + "ITEM_CINNAMON_BUNNY_SHORTNAME", -- item short name + "ITEM_CINNAMON_BUNNY_DESCRIPTION", -- item description + 22, + "food" + }) + + -- the price the player will pay to buy the item in the shop + self:setBuyPrice(25) + -- the price at which the item will be sold in the shop + self:setSellPrice(8) + -- the text that will appear in the shop item info at the top right on the buy menu when hovering an item + self:setShopDescription("ITEM_CINNAMON_BUNNY_DESCRIPTION_SHOP") + + return self +end + +return CinnamonBunnyItem diff --git a/engine/items/monster_candy.lua b/engine/items/monster_candy.lua new file mode 100644 index 0000000..80e98d7 --- /dev/null +++ b/engine/items/monster_candy.lua @@ -0,0 +1,87 @@ +--- @class Item.MonsterCandy : Dummy.Item.Consumable +local MonsterCandyItem = Class(ItemConsumable, "Item.MonsterCandy") + +--- Creates a monster candy +--- @return Item.MonsterCandy +function MonsterCandyItem:new() + self = Class:new(MonsterCandyItem, { + "monster_candy", -- item identifier + "ITEM_MONSTER_CANDY_NAME", -- item name + "ITEM_MONSTER_CANDY_SHORTNAME", -- item short name + "ITEM_MONSTER_CANDY_DESCRIPTION", -- item description + 10, + "food" + }) + + -- the price the player will pay to buy the item in the shop + self:setBuyPrice(15) + -- the price at which the item will be sold in the shop + self:setSellPrice(25) + -- the text that will appear in the shop item info at the top right on the buy menu when hovering an item + self:setShopDescription("ITEM_MONSTER_CANDY_DESCRIPTION_SHOP") + + self.use_texts = { + "BATTLE_ITEM_FOOD_USE" + } + + -- Use Comments. Randomly selected. Discarded if empty. + + self.use_comments = { + "BATTLE_MONSTER_CANDY_USE", + "BATTLE_MONSTER_CANDY_USE_2" + } + + return self +end + +function MonsterCandyItem:use() + local rand = love.math.random(1, 15) + -- Random comments on use + local usecomment = "" -- Default + if #self.use_comments > 0 then -- Check nil + if rand <= 2 then + usecomment = self.use_comments[1] + elseif rand == 15 then + usecomment = self.use_comments[2] + end + end + + if type(self.onBeforeUse) == "function" then + self:onBeforeUse() + end + + local heal_text = Lang.translate("BATTLE_ITEM_HEAL", self:getHeal()) + if self:getHeal() + Player.getHP() >= Player.getMaxHP() then + heal_text = Lang.translate("BATTLE_ITEM_HEAL_MAX") + end + + local dialogue_text = heal_text + local use_texts = self:getUseTexts() + if #use_texts > 0 then + if usecomment ~= "" then + dialogue_text = Lang.translate(use_texts[1], Lang.translate(self:getName())) .. Lang.translate(usecomment) .. "\n" .. heal_text + else + dialogue_text = Lang.translate(use_texts[1], Lang.translate(self:getName())) .. "\n" .. heal_text + end + end + + local texts = { dialogue_text, table.unpack(use_texts, 2) } + if World.isInBattle() then + Battle.playDialogueText(table.unpack(texts)) + else + World.playDialogue(texts) + end + Player.removeItem(self) + Assets.playSound("swallow") + + Soul.heal(self:getHeal(), true) + Timer.after(0.5, function() + Assets.playSound("heal") + end) + + if type(self.onUse) == "function" then + self:onUse() + end +end + +return MonsterCandyItem diff --git a/engine/items/nice_cream.lua b/engine/items/nice_cream.lua new file mode 100644 index 0000000..4fd6333 --- /dev/null +++ b/engine/items/nice_cream.lua @@ -0,0 +1,108 @@ +--- @class Item.NiceCream : Dummy.Item.Consumable +local NiceCreamItem = Class(ItemConsumable, "Item.NiceCream") + +--- Creates a spider donut +--- @return Item.NiceCream +function NiceCreamItem:new() + self = Class:new(NiceCreamItem, { + "nice_cream", -- item identifier + "ITEM_NICE_CREAM_NAME", -- item name + "ITEM_NICE_CREAM_SHORTNAME", -- item short name + "ITEM_NICE_CREAM_DESCRIPTION", -- item description + 15, + "food" + }) + + -- the price the player will pay to buy the item in the shop + self:setBuyPrice(15) + -- the price at which the item will be sold in the shop + self:setSellPrice(2) + -- the text that will appear in the shop item info at the top right on the buy menu when hovering an item + self:setShopDescription("ITEM_NICE_CREAM_DESCRIPTION_SHOP") + + self.use_texts = { + "BATTLE_ITEM_FOOD_USE" + } + + -- Use Comments. Randomly selected. Discarded if empty. + + self.use_comments = { + "BATTLE_NICE_CREAM_USE", + "BATTLE_NICE_CREAM_USE_2", + "BATTLE_NICE_CREAM_USE_3", + "BATTLE_NICE_CREAM_USE_4", + "BATTLE_NICE_CREAM_USE_5", + "BATTLE_NICE_CREAM_USE_6", + "BATTLE_NICE_CREAM_USE_7", + "BATTLE_NICE_CREAM_USE_8" + } + + return self +end + +function NiceCreamItem:use() + + if type(self.onBeforeUse) == "function" then + self:onBeforeUse() + end + + local heal_text = Lang.translate("BATTLE_ITEM_HEAL", self:getHeal()) + if self:getHeal() + Player.getHP() >= Player.getMaxHP() then + heal_text = Lang.translate("BATTLE_ITEM_HEAL_MAX") + end + + local dialogue_text = heal_text + local use_texts = self:getUseTexts() + if #use_texts > 0 then + dialogue_text = Lang.translate(use_texts[1], Lang.translate(self:getName())) .. "\n" .. heal_text + end + + local rand = love.math.random(8) + -- Random comments on use + if #self.use_comments > 0 then -- Check nil + if rand == 0 then + dialogue_text = Lang.translate(self.use_comments[1]) + end + if rand == 1 then + dialogue_text = Lang.translate(self.use_comments[2]) + end + if rand == 2 then + dialogue_text = Lang.translate(self.use_comments[3]) + end + if rand == 3 then + dialogue_text = Lang.translate(self.use_comments[4]) + end + if rand == 4 then + dialogue_text = Lang.translate(self.use_comments[5]) + end + if rand == 5 then + dialogue_text = Lang.translate(self.use_comments[6]) + end + if rand == 6 then + dialogue_text = Lang.translate(self.use_comments[7]) + end + if rand == 7 then + dialogue_text = Lang.translate(self.use_comments[8]) + end + end + + local texts = { dialogue_text, table.unpack(use_texts, 2) } + if World.isInBattle() then + Battle.playDialogueText(table.unpack(texts)) + else + World.playDialogue(texts) + end + Player.removeItem(self) + Assets.playSound("swallow") + + Soul.heal(self:getHeal(), true) + Timer.after(0.5, function() + Assets.playSound("heal") + end) + + if type(self.onUse) == "function" then + self:onUse() + end +end + +return NiceCreamItem diff --git a/engine/items/snowman_piece.lua b/engine/items/snowman_piece.lua new file mode 100644 index 0000000..3b04234 --- /dev/null +++ b/engine/items/snowman_piece.lua @@ -0,0 +1,26 @@ +--- @class Item.SnowManPiece : Dummy.Item.Consumable +local SnowManPieceItem = Class(ItemConsumable, "Item.SnowManPiece") + +--- Creates a spider donut +--- @return Item.SnowManPiece +function SnowManPieceItem:new() + self = Class:new(SnowManPieceItem, { + "snowman_piece", -- item identifier + "ITEM_SNOWMAN_PIECE_NAME", -- item name + "ITEM_SNOWMAN_PIECE_SHORTNAME", -- item short name + "ITEM_SNOWMAN_PIECE_DESCRIPTION", -- item description + 45, + "food" + }) + + -- the price the player will pay to buy the item in the shop + self:setBuyPrice(1) + -- the price at which the item will be sold in the shop + self:setSellPrice(40) + -- the text that will appear in the shop item info at the top right on the buy menu when hovering an item + self:setShopDescription("ITEM_SNOWMAN_PIECE_DESCRIPTION_SHOP") + + return self +end + +return SnowManPieceItem diff --git a/engine/items/spider_cider.lua b/engine/items/spider_cider.lua new file mode 100644 index 0000000..9fe0b43 --- /dev/null +++ b/engine/items/spider_cider.lua @@ -0,0 +1,26 @@ +--- @class Item.SpiderCider : Dummy.Item.Consumable +local SpiderCiderItem = Class(ItemConsumable, "Item.SpiderCider") + +--- Creates a spider Cider +--- @return Item.SpiderCider +function SpiderCiderItem:new() + self = Class:new(SpiderCiderItem, { + "spider_cider", -- item identifier + "ITEM_SPIDER_CIDER_NAME", -- item name + "ITEM_SPIDER_CIDER_SHORTNAME", -- item short name + "ITEM_SPIDER_CIDER_DESCRIPTION", -- item description + 24, + "drink" + }) + + -- the price the player will pay to buy the item in the shop + self:setBuyPrice(18) + -- the price at which the item will be sold in the shop + self:setSellPrice(60) + -- the text that will appear in the shop item info at the top right on the buy menu when hovering an item + self:setShopDescription("ITEM_SPIDER_CIDER_DESCRIPTION_SHOP") + + return self +end + +return SpiderCiderItem diff --git a/engine/items/spider_donut.lua b/engine/items/spider_donut.lua new file mode 100644 index 0000000..bbbfac1 --- /dev/null +++ b/engine/items/spider_donut.lua @@ -0,0 +1,80 @@ +--- @class Item.SpiderDonut : Dummy.Item.Consumable +local SpiderDonutItem = Class(ItemConsumable, "Item.SpiderDonut") + +--- Creates a spider donut +--- @return Item.SpiderDonut +function SpiderDonutItem:new() + self = Class:new(SpiderDonutItem, { + "spider_donut", -- item identifier + "ITEM_SPIDER_DONUT_NAME", -- item name + "ITEM_SPIDER_DONUT_SHORTNAME", -- item short name + "ITEM_SPIDER_DONUT_DESCRIPTION", -- item description + 12, + "food" + }) + + -- the price the player will pay to buy the item in the shop + self:setBuyPrice(7) + -- the price at which the item will be sold in the shop + self:setSellPrice(30) + -- the text that will appear in the shop item info at the top right on the buy menu when hovering an item + self:setShopDescription("ITEM_SPIDER_DONUT_DESCRIPTION_SHOP") + + self.use_texts = { + "BATTLE_ITEM_FOOD_USE" + } + + -- Use Comments. Randomly selected. Discarded if empty. + + self.use_comments = { + "BATTLE_SPIDER_DONUT_USE" + } + + return self +end + +function SpiderDonutItem:use() + + if type(self.onBeforeUse) == "function" then + self:onBeforeUse() + end + + local heal_text = Lang.translate("BATTLE_ITEM_HEAL", self:getHeal()) + if self:getHeal() + Player.getHP() >= Player.getMaxHP() then + heal_text = Lang.translate("BATTLE_ITEM_HEAL_MAX") + end + + local dialogue_text = heal_text + local use_texts = self:getUseTexts() + if #use_texts > 0 then + dialogue_text = Lang.translate(use_texts[1], Lang.translate(self:getName())) .. "\n" .. heal_text + end + + local rand = love.math.random(10) + -- Random comments on use + if #self.use_comments > 0 then -- Check nil + if rand > 9 then + dialogue_text = Lang.translate(self.use_comments[1]) + end + end + + local texts = { dialogue_text, table.unpack(use_texts, 2) } + if World.isInBattle() then + Battle.playDialogueText(table.unpack(texts)) + else + World.playDialogue(texts) + end + Player.removeItem(self) + Assets.playSound("swallow") + + Soul.heal(self:getHeal(), true) + Timer.after(0.5, function() + Assets.playSound("heal") + end) + + if type(self.onUse) == "function" then + self:onUse() + end +end + +return SpiderDonutItem diff --git a/engine/items/temmie_flakes.lua b/engine/items/temmie_flakes.lua new file mode 100644 index 0000000..d87cb96 --- /dev/null +++ b/engine/items/temmie_flakes.lua @@ -0,0 +1,26 @@ +--- @class Item.TemmieFlakes : Dummy.Item.Consumable +local TemmieFlakesItem = Class(ItemConsumable, "Item.TemmieFlakes") + +--- Creates a spider Cider +--- @return Item.TemmieFlakes +function TemmieFlakesItem:new() + self = Class:new(TemmieFlakesItem, { + "temmie_flakes", -- item identifier + "ITEM_TEMMIE_FLAKES_NAME", -- item name + "ITEM_TEMMIE_FLAKES_SHORTNAME", -- item short name + "ITEM_TEMMIE_FLAKES_DESCRIPTION", -- item description + 2, + "food" + }) + + -- the price the player will pay to buy the item in the shop + self:setBuyPrice(1) + -- the price at which the item will be sold in the shop + self:setSellPrice(2) + -- the text that will appear in the shop item info at the top right on the buy menu when hovering an item + self:setShopDescription("ITEM_TEMMIE_FLAKES_DESCRIPTION_SHOP") + + return self +end + +return TemmieFlakesItem diff --git a/engine/items/unisicle.lua b/engine/items/unisicle.lua new file mode 100644 index 0000000..bfece41 --- /dev/null +++ b/engine/items/unisicle.lua @@ -0,0 +1,26 @@ +--- @class Item.Unisicle : Dummy.Item.Consumable +local UnisicleItem = Class(ItemConsumable, "Item.Unisicle") + +--- Creates a spider Cider +--- @return Item.Unisicle +function UnisicleItem:new() + self = Class:new(UnisicleItem, { + "unisicle", -- item identifier + "ITEM_UNISICLE_NAME", -- item name + "ITEM_UNISICLE_SHORTNAME", -- item short name + "ITEM_UNISICLE_DESCRIPTION", -- item description + 11, + "food" + }) + + -- the price the player will pay to buy the item in the shop + self:setBuyPrice(1) + -- the price at which the item will be sold in the shop + self:setSellPrice(2) + -- the text that will appear in the shop item info at the top right on the buy menu when hovering an item + self:setShopDescription("ITEM_UNISICLE_DESCRIPTION_SHOP") + + return self +end + +return UnisicleItem diff --git a/engine/mods/world_example/assets/langs/en.txt b/engine/mods/world_example/assets/langs/en.txt index 45ed427..2bae46f 100644 --- a/engine/mods/world_example/assets/langs/en.txt +++ b/engine/mods/world_example/assets/langs/en.txt @@ -81,11 +81,15 @@ WORLD_EXAMPLE_MOD_WORLD_SHOP_DUMMY_TALK_PAT_TEXT_2=* (...but it doesn't respond. WORLD_EXAMPLE_MOD_WORLD_SHOP_DUMMY_TALK_SIDE_TEXT=. . . # Items -WORLD_EXAMPLE_MOD_ITEM_MONSTER_CANDY_NAME=Monster Candy -WORLD_EXAMPLE_MOD_ITEM_MONSTER_CANDY_SHORTNAME=MnstrCndy -WORLD_EXAMPLE_MOD_ITEM_MONSTER_CANDY_DESCRIPTION=* "Monster Candy" - Heals 10 HP\n* Has a distinct,[wait:5] \n non-licorice flavor. -WORLD_EXAMPLE_MOD_ITEM_MONSTER_CANDY_DESCRIPTION_SHOP=Heals 10 HP\n(Licorice-\nfree\nguaranteed.) WORLD_EXAMPLE_MOD_ITEM_BLANKET_NAME=Blanket WORLD_EXAMPLE_MOD_ITEM_BLANKET_SHORTNAME=Blanket WORLD_EXAMPLE_MOD_ITEM_BLANKET_DESCRIPTION=* "Blanket" - Armor DF 1\n* The fabric is very soft. -WORLD_EXAMPLE_MOD_ITEM_BLANKET_DESCRIPTION_SHOP=Armor: 1DF\n({} DF)\n(It makes\nyou sleepy...) \ No newline at end of file +WORLD_EXAMPLE_MOD_ITEM_BLANKET_DESCRIPTION_SHOP=Armor: 1DF\n({} DF)\n(It makes\nyou sleepy...) + +# This overrides engine content +ITEM_BISICLE_NAME=Bisicle SP +ITEM_BISICLE_SHORTNAME=BscleSP +ITEM_BISICLE_SHORTNAME2=BscleSP +ITEM_BISICLE_DESCRIPTION=* "Bisicle SP" - Heals 11 HP\n* It's like a regular bisicle,[wait:5]\n but local to a mod! +ITEM_BISICLE_DESCRIPTION_SHOP=Heals 11HP x 2\nspecil +BATTLE_BISICLE_USE=* You eat one half of it.[wait:5]\n* You feel special. \ No newline at end of file diff --git a/engine/mods/world_example/mod.lua b/engine/mods/world_example/mod.lua index 121a317..0c0c185 100644 --- a/engine/mods/world_example/mod.lua +++ b/engine/mods/world_example/mod.lua @@ -85,14 +85,14 @@ function WorldExampleMod:loadSaveData() -- equipped weapon if save_data.weapon ~= nil then if save_data.weapon ~= "stick" then - Player.setWeapon(modRequire("scripts.items." .. save_data.weapon):new()) + Player.setWeapon(tryRequire("scripts.items." .. save_data.weapon, "items." .. save_data.weapon):new()) end end -- equipped armor if save_data.armor ~= nil then if save_data.armor ~= "bandage" then - Player.setArmor(modRequire("scripts.items." .. save_data.armor):new()) + Player.setArmor(tryRequire("scripts.items." .. save_data.armor, "items." .. save_data.armor):new()) end end @@ -134,7 +134,7 @@ function WorldExampleMod:loadItem(item_id) item = bandage end else - item = modRequire("scripts.items." .. item_id):new() + item = tryRequire("scripts.items." .. item_id, "items." .. item_id):new() end return item end diff --git a/engine/mods/world_example/scripts/items/bisicle2.lua b/engine/mods/world_example/scripts/items/bisicle2.lua new file mode 100644 index 0000000..b43aec5 --- /dev/null +++ b/engine/mods/world_example/scripts/items/bisicle2.lua @@ -0,0 +1,35 @@ +--- @class Item.Bisicle : Dummy.Item.Consumable +local BisicleItem = Class(ItemConsumable, "Item.Bisicle") + +--- Creates a bisicle +--- @return Item.Bisicle +function BisicleItem:new() + self = Class:new(BisicleItem, { + "bisicle", -- item identifier + "ITEM_BISICLE_NAME", -- item name + "ITEM_BISICLE_SHORTNAME", -- item short name + "ITEM_BISICLE_DESCRIPTION", -- item description + 11, + "food" + }) + + -- the price the player will pay to buy the item in the shop + self:setBuyPrice(15) + -- the price at which the item will be sold in the shop + self:setSellPrice(5) + -- the text that will appear in the shop item info at the top right on the buy menu when hovering an item + self:setShopDescription("ITEM_BISICLE_DESCRIPTION_SHOP") + + self.use_texts = { + "BATTLE_BISICLE_USE" + } + + return self +end + +function BisicleItem:onUse() + local unisicle = require("items.unisicle"):new() + Player.addItem(unisicle) +end + +return BisicleItem diff --git a/engine/mods/world_example/scripts/world/shop/dummy_shop.lua b/engine/mods/world_example/scripts/world/shop/dummy_shop.lua index 49f6c9a..64aa5bb 100644 --- a/engine/mods/world_example/scripts/world/shop/dummy_shop.lua +++ b/engine/mods/world_example/scripts/world/shop/dummy_shop.lua @@ -41,11 +41,15 @@ end --- Prepares the shop items function DummyShop:prepareItems() - local MonsterCandy = modRequire("scripts.items.monster_candy") + local MonsterCandy = require("items.monster_candy") + local SpiderDonut = require("items.spider_donut") + local bisicle2 = modRequire("scripts.items.bisicle2") -- amount `-1` for infinite stock self:addItem(MonsterCandy, -1) + self:addItem(SpiderDonut, -1) + self:addItem(bisicle2, -1) - local BlanketItem = modRequire("scripts.items.blanket") + local BlanketItem = require("items.blanket") local blanket_amount = 1 -- track wether the blanket has been bought if WorldExampleMod.flag["dummy_shop_blanket"] == 1 then diff --git a/engine/utils/utils.lua b/engine/utils/utils.lua index df08acd..315f2e7 100644 --- a/engine/utils/utils.lua +++ b/engine/utils/utils.lua @@ -7,6 +7,19 @@ function modRequire(modname) return require("mods." .. mod:getId() .. "." .. modname) end +--- Tries to require a module from the current mod, or the base game if it fails. +--- @param modname string +--- @param altname string +--- @return unknown +function tryRequire(modname, altname) + local mod = ModList.getCurrentMod() + local success, result = pcall(modRequire, modname) + if success then + return result + else + return require(altname) + end +end -- table -- -- https://gist.github.com/revolucas/dd1ecccfca32d558fddf70ddb39eb8a6 From b554775e0d9a44079f62a9008df7e4230a98ec8e Mon Sep 17 00:00:00 2001 From: Ivan Date: Mon, 3 Aug 2026 02:33:53 -0700 Subject: [PATCH 2/5] stop overriding use functions in items items of every type have a getdialoguetexts() function which allows you to override text in an item without reconstructing the use function --- engine/item/consumable.lua | 26 ++++-- engine/item/equipment.lua | 14 +++- engine/item/item.lua | 13 ++- engine/items/bisicle.lua | 2 +- engine/items/blanket.lua | 2 +- engine/items/butterscotch_pie.lua | 2 +- engine/items/monster_candy.lua | 55 +++---------- engine/items/nice_cream.lua | 82 ++++++------------- engine/items/snowman_piece.lua | 2 +- engine/items/spider_donut.lua | 45 ++-------- engine/items/temmie_flakes.lua | 2 +- engine/items/unisicle.lua | 2 +- engine/mods/froggit/mod.lua | 9 +- .../world_example/scripts/items/bisicle.lua | 35 ++++++++ .../scripts/world/shop/dummy_shop.lua | 6 +- 15 files changed, 125 insertions(+), 172 deletions(-) create mode 100644 engine/mods/world_example/scripts/items/bisicle.lua diff --git a/engine/item/consumable.lua b/engine/item/consumable.lua index 534b08d..de76564 100644 --- a/engine/item/consumable.lua +++ b/engine/item/consumable.lua @@ -28,16 +28,20 @@ function ItemConsumable:setType(type) self.type = type end ---- Uses the consumable item -function ItemConsumable:use() - if type(self.onBeforeUse) == "function" then - self:onBeforeUse() - end - +--- Gets the item's heal text +--- @return Dummy.Text.Text +function ItemConsumable:getHealText() local heal_text = Lang.translate("BATTLE_ITEM_HEAL", self:getHeal()) if self:getHeal() + Player.getHP() >= Player.getMaxHP() then heal_text = Lang.translate("BATTLE_ITEM_HEAL_MAX") end + return heal_text +end + +--- (Override) Gets the item's final dialogue text when used +--- @return Dummy.Text.Text[] +function ItemConsumable:getDialogueTexts() + local heal_text = self:getHealText() local dialogue_text = heal_text local use_texts = self:getUseTexts() @@ -46,6 +50,16 @@ function ItemConsumable:use() end local texts = { dialogue_text, table.unpack(use_texts, 2) } + return texts +end + +--- Uses the consumable item +function ItemConsumable:use() + if type(self.onBeforeUse) == "function" then + self:onBeforeUse() + end + + local texts = self:getDialogueTexts() if World.isInBattle() then Battle.playDialogueText(table.unpack(texts)) else diff --git a/engine/item/equipment.lua b/engine/item/equipment.lua index 4480b61..3f51511 100644 --- a/engine/item/equipment.lua +++ b/engine/item/equipment.lua @@ -28,16 +28,22 @@ function ItemEquipment:setType(type) self.type = type end +--- (Override) Gets the item's final dialogue text when used +--- @return Dummy.Text.Text[] +function ItemEquipment:getDialogueTexts() + local texts = self:getUseTexts() + if #texts <= 0 then + texts = { { "BATTLE_ITEM_EQUIPMENT_USE", Lang.translate(self:getName()) } } + end + return texts +end --- Uses the equipment item function ItemEquipment:use() if type(self.onBeforeUse) == "function" then self:onBeforeUse() end - local texts = self:getUseTexts() - if #texts <= 0 then - texts = { { "BATTLE_ITEM_EQUIPMENT_USE", Lang.translate(self:getName()) } } - end + local texts = self:getDialogueTexts() if World.isInBattle() then Battle.playDialogueText(table.unpack(texts)) else diff --git a/engine/item/item.lua b/engine/item/item.lua index 789888b..626b411 100644 --- a/engine/item/item.lua +++ b/engine/item/item.lua @@ -91,6 +91,11 @@ function Item:setDropText(text, ...) self.drop_texts = { text, ... } end +--- (Override) Gets the item's final dialogue text when used +--- @return Dummy.Text.Text[] +function Item:getDialogueTexts() + return self:getUseTexts() +end --- Gets the item's buy price --- @return integer function Item:getBuyPrice() @@ -123,12 +128,12 @@ function Item:use() end if not can_use then return end - local use_texts = self:getUseTexts() - if #use_texts > 0 then + local dialogue_texts = self:getDialogueTexts() + if #dialogue_texts > 0 then if World.isInBattle() then - Battle.playDialogueText(table.unpack(use_texts)) + Battle.playDialogueText(table.unpack(dialogue_texts)) else - World.playDialogue(use_texts) + World.playDialogue(dialogue_texts) end end diff --git a/engine/items/bisicle.lua b/engine/items/bisicle.lua index 897e7ce..5051b53 100644 --- a/engine/items/bisicle.lua +++ b/engine/items/bisicle.lua @@ -28,7 +28,7 @@ function BisicleItem:new() end function BisicleItem:onUse() - local unisicle = modRequire("scripts.items.unisicle"):new() + local unisicle = require("items.unisicle"):new() Player.addItem(unisicle) end diff --git a/engine/items/blanket.lua b/engine/items/blanket.lua index 67d9899..bdc7db3 100644 --- a/engine/items/blanket.lua +++ b/engine/items/blanket.lua @@ -1,7 +1,7 @@ --- @class Item.Blanket : Dummy.Item.Consumable local BlanketItem = Class(ItemEquipment, "Item.Blanket") ---- Creates a monster candy +--- Creates a blanket --- @return Item.Blanket function BlanketItem:new() self = Class:new(BlanketItem, { diff --git a/engine/items/butterscotch_pie.lua b/engine/items/butterscotch_pie.lua index 1e592ae..f5264bb 100644 --- a/engine/items/butterscotch_pie.lua +++ b/engine/items/butterscotch_pie.lua @@ -1,7 +1,7 @@ --- @class Item.ButterScotchPie : Dummy.Item.Consumable local ButterScotchPieItem = Class(ItemConsumable, "Item.ButterScotchPie") ---- Creates a spider donut +--- Creates a butterscotch pie --- @return Item.ButterScotchPie function ButterScotchPieItem:new() self = Class:new(ButterScotchPieItem, { diff --git a/engine/items/monster_candy.lua b/engine/items/monster_candy.lua index 80e98d7..4074660 100644 --- a/engine/items/monster_candy.lua +++ b/engine/items/monster_candy.lua @@ -34,54 +34,21 @@ function MonsterCandyItem:new() return self end -function MonsterCandyItem:use() +function MonsterCandyItem:getDialogueTexts() local rand = love.math.random(1, 15) + local usecomment = "" + local dialogue_text = { Lang.translate(self:getUseTexts()[1], Lang.translate(self:getName())) .. + "\n" .. self:getHealText() } -- Random comments on use - local usecomment = "" -- Default - if #self.use_comments > 0 then -- Check nil - if rand <= 2 then - usecomment = self.use_comments[1] - elseif rand == 15 then - usecomment = self.use_comments[2] - end + if rand <= 2 then + usecomment = self.use_comments[1] + elseif rand == 15 then + usecomment = self.use_comments[2] end - - if type(self.onBeforeUse) == "function" then - self:onBeforeUse() - end - - local heal_text = Lang.translate("BATTLE_ITEM_HEAL", self:getHeal()) - if self:getHeal() + Player.getHP() >= Player.getMaxHP() then - heal_text = Lang.translate("BATTLE_ITEM_HEAL_MAX") - end - - local dialogue_text = heal_text - local use_texts = self:getUseTexts() - if #use_texts > 0 then - if usecomment ~= "" then - dialogue_text = Lang.translate(use_texts[1], Lang.translate(self:getName())) .. Lang.translate(usecomment) .. "\n" .. heal_text - else - dialogue_text = Lang.translate(use_texts[1], Lang.translate(self:getName())) .. "\n" .. heal_text - end - end - - local texts = { dialogue_text, table.unpack(use_texts, 2) } - if World.isInBattle() then - Battle.playDialogueText(table.unpack(texts)) - else - World.playDialogue(texts) - end - Player.removeItem(self) - Assets.playSound("swallow") - - Soul.heal(self:getHeal(), true) - Timer.after(0.5, function() - Assets.playSound("heal") - end) - - if type(self.onUse) == "function" then - self:onUse() + if usecomment ~= "" then + dialogue_text = { Lang.translate(self:getUseTexts()[1], Lang.translate(self:getName())) .. Lang.translate(usecomment) .. "\n" .. self:getHealText() } end + return { dialogue_text, table.unpack(self:getUseTexts(), 2) } end return MonsterCandyItem diff --git a/engine/items/nice_cream.lua b/engine/items/nice_cream.lua index 4fd6333..8c1a09d 100644 --- a/engine/items/nice_cream.lua +++ b/engine/items/nice_cream.lua @@ -1,7 +1,7 @@ --- @class Item.NiceCream : Dummy.Item.Consumable local NiceCreamItem = Class(ItemConsumable, "Item.NiceCream") ---- Creates a spider donut +--- Creates a nice cream --- @return Item.NiceCream function NiceCreamItem:new() self = Class:new(NiceCreamItem, { @@ -40,69 +40,35 @@ function NiceCreamItem:new() return self end -function NiceCreamItem:use() - - if type(self.onBeforeUse) == "function" then - self:onBeforeUse() +function NiceCreamItem:getDialogueTexts() + local rand = love.math.random(8) + local dialogue_text = Lang.translate(self:getUseTexts()[1], Lang.translate(self:getName())) .. "\n" .. self:getHealText() + -- Random comments on use + if rand == 0 then + dialogue_text = Lang.translate(self.use_comments[1]) end - - local heal_text = Lang.translate("BATTLE_ITEM_HEAL", self:getHeal()) - if self:getHeal() + Player.getHP() >= Player.getMaxHP() then - heal_text = Lang.translate("BATTLE_ITEM_HEAL_MAX") + if rand == 1 then + dialogue_text = Lang.translate(self.use_comments[2]) end - - local dialogue_text = heal_text - local use_texts = self:getUseTexts() - if #use_texts > 0 then - dialogue_text = Lang.translate(use_texts[1], Lang.translate(self:getName())) .. "\n" .. heal_text + if rand == 2 then + dialogue_text = Lang.translate(self.use_comments[3]) end - - local rand = love.math.random(8) - -- Random comments on use - if #self.use_comments > 0 then -- Check nil - if rand == 0 then - dialogue_text = Lang.translate(self.use_comments[1]) - end - if rand == 1 then - dialogue_text = Lang.translate(self.use_comments[2]) - end - if rand == 2 then - dialogue_text = Lang.translate(self.use_comments[3]) - end - if rand == 3 then - dialogue_text = Lang.translate(self.use_comments[4]) - end - if rand == 4 then - dialogue_text = Lang.translate(self.use_comments[5]) - end - if rand == 5 then - dialogue_text = Lang.translate(self.use_comments[6]) - end - if rand == 6 then - dialogue_text = Lang.translate(self.use_comments[7]) - end - if rand == 7 then - dialogue_text = Lang.translate(self.use_comments[8]) - end + if rand == 3 then + dialogue_text = Lang.translate(self.use_comments[4]) end - - local texts = { dialogue_text, table.unpack(use_texts, 2) } - if World.isInBattle() then - Battle.playDialogueText(table.unpack(texts)) - else - World.playDialogue(texts) + if rand == 4 then + dialogue_text = Lang.translate(self.use_comments[5]) end - Player.removeItem(self) - Assets.playSound("swallow") - - Soul.heal(self:getHeal(), true) - Timer.after(0.5, function() - Assets.playSound("heal") - end) - - if type(self.onUse) == "function" then - self:onUse() + if rand == 5 then + dialogue_text = Lang.translate(self.use_comments[6]) + end + if rand == 6 then + dialogue_text = Lang.translate(self.use_comments[7]) + end + if rand == 7 then + dialogue_text = Lang.translate(self.use_comments[8]) end + return { dialogue_text, table.unpack(self:getUseTexts(), 2) } end return NiceCreamItem diff --git a/engine/items/snowman_piece.lua b/engine/items/snowman_piece.lua index 3b04234..1ff4749 100644 --- a/engine/items/snowman_piece.lua +++ b/engine/items/snowman_piece.lua @@ -1,7 +1,7 @@ --- @class Item.SnowManPiece : Dummy.Item.Consumable local SnowManPieceItem = Class(ItemConsumable, "Item.SnowManPiece") ---- Creates a spider donut +--- Creates a snowman piece --- @return Item.SnowManPiece function SnowManPieceItem:new() self = Class:new(SnowManPieceItem, { diff --git a/engine/items/spider_donut.lua b/engine/items/spider_donut.lua index bbbfac1..e48dedf 100644 --- a/engine/items/spider_donut.lua +++ b/engine/items/spider_donut.lua @@ -33,48 +33,13 @@ function SpiderDonutItem:new() return self end -function SpiderDonutItem:use() - - if type(self.onBeforeUse) == "function" then - self:onBeforeUse() - end - - local heal_text = Lang.translate("BATTLE_ITEM_HEAL", self:getHeal()) - if self:getHeal() + Player.getHP() >= Player.getMaxHP() then - heal_text = Lang.translate("BATTLE_ITEM_HEAL_MAX") - end - - local dialogue_text = heal_text - local use_texts = self:getUseTexts() - if #use_texts > 0 then - dialogue_text = Lang.translate(use_texts[1], Lang.translate(self:getName())) .. "\n" .. heal_text - end - +function SpiderDonutItem:getDialogueTexts() local rand = love.math.random(10) - -- Random comments on use - if #self.use_comments > 0 then -- Check nil - if rand > 9 then - dialogue_text = Lang.translate(self.use_comments[1]) - end - end - - local texts = { dialogue_text, table.unpack(use_texts, 2) } - if World.isInBattle() then - Battle.playDialogueText(table.unpack(texts)) - else - World.playDialogue(texts) - end - Player.removeItem(self) - Assets.playSound("swallow") - - Soul.heal(self:getHeal(), true) - Timer.after(0.5, function() - Assets.playSound("heal") - end) - - if type(self.onUse) == "function" then - self:onUse() + local dialogue_text = Lang.translate(self:getUseTexts()[1], Lang.translate(self:getName())) .. "\n" .. self:getHealText() + if rand > 9 then + dialogue_text = Lang.translate(self.use_comments[1]) end + return { dialogue_text, table.unpack(self:getUseTexts(), 2) } end return SpiderDonutItem diff --git a/engine/items/temmie_flakes.lua b/engine/items/temmie_flakes.lua index d87cb96..6027da7 100644 --- a/engine/items/temmie_flakes.lua +++ b/engine/items/temmie_flakes.lua @@ -1,7 +1,7 @@ --- @class Item.TemmieFlakes : Dummy.Item.Consumable local TemmieFlakesItem = Class(ItemConsumable, "Item.TemmieFlakes") ---- Creates a spider Cider +--- Creates a temmie flakes --- @return Item.TemmieFlakes function TemmieFlakesItem:new() self = Class:new(TemmieFlakesItem, { diff --git a/engine/items/unisicle.lua b/engine/items/unisicle.lua index bfece41..fd93a2e 100644 --- a/engine/items/unisicle.lua +++ b/engine/items/unisicle.lua @@ -1,7 +1,7 @@ --- @class Item.Unisicle : Dummy.Item.Consumable local UnisicleItem = Class(ItemConsumable, "Item.Unisicle") ---- Creates a spider Cider +--- Creates a unisicle --- @return Item.Unisicle function UnisicleItem:new() self = Class:new(UnisicleItem, { diff --git a/engine/mods/froggit/mod.lua b/engine/mods/froggit/mod.lua index c67eb32..1e0d1ee 100644 --- a/engine/mods/froggit/mod.lua +++ b/engine/mods/froggit/mod.lua @@ -19,14 +19,7 @@ function mod:load() Player.setLV(1) -- add items - Player.addItem(ItemConsumable:new( - "monster_candy", - "FROGGIT_MOD_MONSTER_CANDY_NAME", - "FROGGIT_MOD_MONSTER_CANDY_SHORTNAME", - "", - 50, - "food" - )) + Player.addItem(require("items.monster_candy"):new()) Player.addItem(ItemEquipment:new( "toy_knife", "FROGGIT_MOD_TOY_KNIFE_NAME", diff --git a/engine/mods/world_example/scripts/items/bisicle.lua b/engine/mods/world_example/scripts/items/bisicle.lua new file mode 100644 index 0000000..b43aec5 --- /dev/null +++ b/engine/mods/world_example/scripts/items/bisicle.lua @@ -0,0 +1,35 @@ +--- @class Item.Bisicle : Dummy.Item.Consumable +local BisicleItem = Class(ItemConsumable, "Item.Bisicle") + +--- Creates a bisicle +--- @return Item.Bisicle +function BisicleItem:new() + self = Class:new(BisicleItem, { + "bisicle", -- item identifier + "ITEM_BISICLE_NAME", -- item name + "ITEM_BISICLE_SHORTNAME", -- item short name + "ITEM_BISICLE_DESCRIPTION", -- item description + 11, + "food" + }) + + -- the price the player will pay to buy the item in the shop + self:setBuyPrice(15) + -- the price at which the item will be sold in the shop + self:setSellPrice(5) + -- the text that will appear in the shop item info at the top right on the buy menu when hovering an item + self:setShopDescription("ITEM_BISICLE_DESCRIPTION_SHOP") + + self.use_texts = { + "BATTLE_BISICLE_USE" + } + + return self +end + +function BisicleItem:onUse() + local unisicle = require("items.unisicle"):new() + Player.addItem(unisicle) +end + +return BisicleItem diff --git a/engine/mods/world_example/scripts/world/shop/dummy_shop.lua b/engine/mods/world_example/scripts/world/shop/dummy_shop.lua index 64aa5bb..8b96797 100644 --- a/engine/mods/world_example/scripts/world/shop/dummy_shop.lua +++ b/engine/mods/world_example/scripts/world/shop/dummy_shop.lua @@ -43,11 +43,13 @@ end function DummyShop:prepareItems() local MonsterCandy = require("items.monster_candy") local SpiderDonut = require("items.spider_donut") - local bisicle2 = modRequire("scripts.items.bisicle2") + local bisicle = tryRequire("scripts.items.bisicle", "items.bisicle") + local nice_cream = require("items.nice_cream") -- amount `-1` for infinite stock self:addItem(MonsterCandy, -1) self:addItem(SpiderDonut, -1) - self:addItem(bisicle2, -1) + self:addItem(bisicle, -1) + self:addItem(nice_cream, -1) local BlanketItem = require("items.blanket") local blanket_amount = 1 From b61f1ea6a6b684a76e8bc6c632c89ff6582013e4 Mon Sep 17 00:00:00 2001 From: Ivan Date: Mon, 3 Aug 2026 03:54:51 -0700 Subject: [PATCH 3/5] Clean up, delete unused files & Comment stuff --- engine/assets/langs/en.txt | 24 ++++---- engine/items/bisicle.lua | 5 +- engine/items/monster_candy.lua | 20 +++---- engine/items/nice_cream.lua | 59 ++++++------------- engine/items/spider_donut.lua | 22 +++---- .../world_example/scripts/items/bisicle2.lua | 35 ----------- .../world_example/scripts/items/blanket.lua | 26 -------- .../scripts/items/monster_candy.lua | 26 -------- 8 files changed, 51 insertions(+), 166 deletions(-) delete mode 100644 engine/mods/world_example/scripts/items/bisicle2.lua delete mode 100644 engine/mods/world_example/scripts/items/blanket.lua delete mode 100644 engine/mods/world_example/scripts/items/monster_candy.lua diff --git a/engine/assets/langs/en.txt b/engine/assets/langs/en.txt index a2316ba..1df7944 100644 --- a/engine/assets/langs/en.txt +++ b/engine/assets/langs/en.txt @@ -107,15 +107,15 @@ ITEM_MONSTER_CANDY_NAME=Monster Candy ITEM_MONSTER_CANDY_SHORTNAME=MnstrCndy ITEM_MONSTER_CANDY_DESCRIPTION=* "Monster Candy" - Heals 10 HP\n* Has a distinct,[wait:5] \n non-licorice flavor. ITEM_MONSTER_CANDY_DESCRIPTION_SHOP=Heals 10 HP\n(Licorice-\nfree\nguaranteed.) -BATTLE_MONSTER_CANDY_USE=\n* Very un-licorice-like. -BATTLE_MONSTER_CANDY_USE_2=\n* ... tastes like licorice. +ITEM_MONSTER_CANDY_USE=\n* Very un-licorice-like. +ITEM_MONSTER_CANDY_USE_2=\n* ... tastes like licorice. ITEM_SPIDER_DONUT_NAME=Spider Donut ITEM_SPIDER_DONUT_SHORTNAME=SpidrDont ITEM_SPIDER_DONUT_SHORTNAME2=SpdrDonut ITEM_SPIDER_DONUT_DESCRIPTION=* "Spider Donut" - Heals 12 HP\n* A donut made with Spider\n Cider in the batter. ITEM_SPIDER_DONUT_DESCRIPTION_SHOP=undefined -BATTLE_SPIDER_DONUT_USE=* Don't worry,[wait:5] Spider didn't. +ITEM_SPIDER_DONUT_USE=* Don't worry,[wait:5] Spider didn't. ITEM_SPIDER_CIDER_NAME=Spider Cider ITEM_SPIDER_CIDER_SHORTNAME=SpidrCidr @@ -140,21 +140,21 @@ ITEM_NICE_CREAM_SHORTNAME=NiceCream ITEM_NICE_CREAM_SHORTNAME2=NiceCream ITEM_NICE_CREAM_DESCRIPTION=* "Nice Cream" - Heals 15 HP\n* Instead of a joke,[wait:5] the\n wrapper says something nice. ITEM_NICE_CREAM_DESCRIPTION_SHOP=undefined -BATTLE_NICE_CREAM_USE=* You're just great! -BATTLE_NICE_CREAM_USE_2=* You look nice today! -BATTLE_NICE_CREAM_USE_3=* Are those claws natural? -BATTLE_NICE_CREAM_USE_4=* You're super spiffy! -BATTLE_NICE_CREAM_USE_5=* Have a wonderful day! -BATTLE_NICE_CREAM_USE_6=* Is this as sweet as you? -BATTLE_NICE_CREAM_USE_7=* (An illustration of a hug.) -BATTLE_NICE_CREAM_USE_8=* Love yourself! I love you! +ITEM_NICE_CREAM_USE=* You're just great! +ITEM_NICE_CREAM_USE_2=* You look nice today! +ITEM_NICE_CREAM_USE_3=* Are those claws natural? +ITEM_NICE_CREAM_USE_4=* You're super spiffy! +ITEM_NICE_CREAM_USE_5=* Have a wonderful day! +ITEM_NICE_CREAM_USE_6=* Is this as sweet as you? +ITEM_NICE_CREAM_USE_7=* (An illustration of a hug.) +ITEM_NICE_CREAM_USE_8=* Love yourself! I love you! ITEM_BISICLE_NAME=Bisicle ITEM_BISICLE_SHORTNAME=Bisicle ITEM_BISICLE_SHORTNAME2=Bisicle ITEM_BISICLE_DESCRIPTION=* "Bisicle" - Heals 11 HP\n* It's a two-pronged popsicle,[wait:5]\n so you can eat it twice. ITEM_BISICLE_DESCRIPTION_SHOP=Heals 11HP x 2\nEat it twice! -BATTLE_BISICLE_USE=* You eat one half of\n the Bisicle. +ITEM_BISICLE_USE=* You eat one half of\n the Bisicle. ITEM_UNISICLE_NAME=Unisicle ITEM_UNISICLE_SHORTNAME=Unisicle diff --git a/engine/items/bisicle.lua b/engine/items/bisicle.lua index 5051b53..e0a7ab4 100644 --- a/engine/items/bisicle.lua +++ b/engine/items/bisicle.lua @@ -19,15 +19,16 @@ function BisicleItem:new() self:setSellPrice(5) -- the text that will appear in the shop item info at the top right on the buy menu when hovering an item self:setShopDescription("ITEM_BISICLE_DESCRIPTION_SHOP") - + -- the main text that will appear when the item is used. self.use_texts = { - "BATTLE_BISICLE_USE" + "ITEM_BISICLE_USE" } return self end function BisicleItem:onUse() + -- Add a unisicle to the player's inventory when the bisicle is used. local unisicle = require("items.unisicle"):new() Player.addItem(unisicle) end diff --git a/engine/items/monster_candy.lua b/engine/items/monster_candy.lua index 4074660..47199b9 100644 --- a/engine/items/monster_candy.lua +++ b/engine/items/monster_candy.lua @@ -19,32 +19,30 @@ function MonsterCandyItem:new() self:setSellPrice(25) -- the text that will appear in the shop item info at the top right on the buy menu when hovering an item self:setShopDescription("ITEM_MONSTER_CANDY_DESCRIPTION_SHOP") - - self.use_texts = { - "BATTLE_ITEM_FOOD_USE" - } - - -- Use Comments. Randomly selected. Discarded if empty. - + -- Random comments on use self.use_comments = { - "BATTLE_MONSTER_CANDY_USE", - "BATTLE_MONSTER_CANDY_USE_2" + "ITEM_MONSTER_CANDY_USE", + "ITEM_MONSTER_CANDY_USE_2" } return self end function MonsterCandyItem:getDialogueTexts() - local rand = love.math.random(1, 15) + -- Generate a random number + local rand = love.math.random(0, 15) + -- Set the comment to initially be empty local usecomment = "" + -- Set Default Dialogue Text local dialogue_text = { Lang.translate(self:getUseTexts()[1], Lang.translate(self:getName())) .. "\n" .. self:getHealText() } - -- Random comments on use + -- Change use comment based on random number if rand <= 2 then usecomment = self.use_comments[1] elseif rand == 15 then usecomment = self.use_comments[2] end + -- If the use comment is not empty, change the dialogue text to include the use comment if usecomment ~= "" then dialogue_text = { Lang.translate(self:getUseTexts()[1], Lang.translate(self:getName())) .. Lang.translate(usecomment) .. "\n" .. self:getHealText() } end diff --git a/engine/items/nice_cream.lua b/engine/items/nice_cream.lua index 8c1a09d..3dbd470 100644 --- a/engine/items/nice_cream.lua +++ b/engine/items/nice_cream.lua @@ -19,54 +19,31 @@ function NiceCreamItem:new() self:setSellPrice(2) -- the text that will appear in the shop item info at the top right on the buy menu when hovering an item self:setShopDescription("ITEM_NICE_CREAM_DESCRIPTION_SHOP") - - self.use_texts = { - "BATTLE_ITEM_FOOD_USE" - } - - -- Use Comments. Randomly selected. Discarded if empty. - + -- Random comments on use self.use_comments = { - "BATTLE_NICE_CREAM_USE", - "BATTLE_NICE_CREAM_USE_2", - "BATTLE_NICE_CREAM_USE_3", - "BATTLE_NICE_CREAM_USE_4", - "BATTLE_NICE_CREAM_USE_5", - "BATTLE_NICE_CREAM_USE_6", - "BATTLE_NICE_CREAM_USE_7", - "BATTLE_NICE_CREAM_USE_8" + "ITEM_NICE_CREAM_USE", + "ITEM_NICE_CREAM_USE_2", + "ITEM_NICE_CREAM_USE_3", + "ITEM_NICE_CREAM_USE_4", + "ITEM_NICE_CREAM_USE_5", + "ITEM_NICE_CREAM_USE_6", + "ITEM_NICE_CREAM_USE_7", + "ITEM_NICE_CREAM_USE_8" } return self end function NiceCreamItem:getDialogueTexts() - local rand = love.math.random(8) - local dialogue_text = Lang.translate(self:getUseTexts()[1], Lang.translate(self:getName())) .. "\n" .. self:getHealText() - -- Random comments on use - if rand == 0 then - dialogue_text = Lang.translate(self.use_comments[1]) - end - if rand == 1 then - dialogue_text = Lang.translate(self.use_comments[2]) - end - if rand == 2 then - dialogue_text = Lang.translate(self.use_comments[3]) - end - if rand == 3 then - dialogue_text = Lang.translate(self.use_comments[4]) - end - if rand == 4 then - dialogue_text = Lang.translate(self.use_comments[5]) - end - if rand == 5 then - dialogue_text = Lang.translate(self.use_comments[6]) - end - if rand == 6 then - dialogue_text = Lang.translate(self.use_comments[7]) - end - if rand == 7 then - dialogue_text = Lang.translate(self.use_comments[8]) + -- Generate a random number + local rand = love.math.random(9) + print(rand) + -- Set Default Dialogue Text + local dialogue_text = Lang.translate(self:getUseTexts()[1], Lang.translate(self:getName())) .. + "\n" .. self:getHealText() + -- Override dialogue text with a random comment based on the random number + if rand < 9 then + dialogue_text = Lang.translate(self.use_comments[rand]) end return { dialogue_text, table.unpack(self:getUseTexts(), 2) } end diff --git a/engine/items/spider_donut.lua b/engine/items/spider_donut.lua index e48dedf..f9ccc1b 100644 --- a/engine/items/spider_donut.lua +++ b/engine/items/spider_donut.lua @@ -20,24 +20,20 @@ function SpiderDonutItem:new() -- the text that will appear in the shop item info at the top right on the buy menu when hovering an item self:setShopDescription("ITEM_SPIDER_DONUT_DESCRIPTION_SHOP") - self.use_texts = { - "BATTLE_ITEM_FOOD_USE" - } - - -- Use Comments. Randomly selected. Discarded if empty. - - self.use_comments = { - "BATTLE_SPIDER_DONUT_USE" - } - return self end function SpiderDonutItem:getDialogueTexts() - local rand = love.math.random(10) + -- Set Default Dialogue Text local dialogue_text = Lang.translate(self:getUseTexts()[1], Lang.translate(self:getName())) .. "\n" .. self:getHealText() - if rand > 9 then - dialogue_text = Lang.translate(self.use_comments[1]) + -- Check if the player is in a battle + if World.isInBattle() then + -- Generate a random number + local rand = love.math.random(0, 10) + -- Override dialogue text with a comment based on the random number + if rand > 9 then + dialogue_text = Lang.translate("ITEM_SPIDER_DONUT_USE") + end end return { dialogue_text, table.unpack(self:getUseTexts(), 2) } end diff --git a/engine/mods/world_example/scripts/items/bisicle2.lua b/engine/mods/world_example/scripts/items/bisicle2.lua deleted file mode 100644 index b43aec5..0000000 --- a/engine/mods/world_example/scripts/items/bisicle2.lua +++ /dev/null @@ -1,35 +0,0 @@ ---- @class Item.Bisicle : Dummy.Item.Consumable -local BisicleItem = Class(ItemConsumable, "Item.Bisicle") - ---- Creates a bisicle ---- @return Item.Bisicle -function BisicleItem:new() - self = Class:new(BisicleItem, { - "bisicle", -- item identifier - "ITEM_BISICLE_NAME", -- item name - "ITEM_BISICLE_SHORTNAME", -- item short name - "ITEM_BISICLE_DESCRIPTION", -- item description - 11, - "food" - }) - - -- the price the player will pay to buy the item in the shop - self:setBuyPrice(15) - -- the price at which the item will be sold in the shop - self:setSellPrice(5) - -- the text that will appear in the shop item info at the top right on the buy menu when hovering an item - self:setShopDescription("ITEM_BISICLE_DESCRIPTION_SHOP") - - self.use_texts = { - "BATTLE_BISICLE_USE" - } - - return self -end - -function BisicleItem:onUse() - local unisicle = require("items.unisicle"):new() - Player.addItem(unisicle) -end - -return BisicleItem diff --git a/engine/mods/world_example/scripts/items/blanket.lua b/engine/mods/world_example/scripts/items/blanket.lua deleted file mode 100644 index 6e4003b..0000000 --- a/engine/mods/world_example/scripts/items/blanket.lua +++ /dev/null @@ -1,26 +0,0 @@ ---- @class WorldExample.Item.Blanket : Dummy.Item.Consumable -local BlanketItem = Class(ItemEquipment, "WorldExample.Item.Blanket") - ---- Creates a monster candy ---- @return WorldExample.Item.Blanket -function BlanketItem:new() - self = Class:new(BlanketItem, { - "blanket", -- item identifier - "WORLD_EXAMPLE_MOD_ITEM_BLANKET_NAME", -- item name - "WORLD_EXAMPLE_MOD_ITEM_BLANKET_SHORTNAME", -- item short name - "WORLD_EXAMPLE_MOD_ITEM_BLANKET_DESCRIPTION", -- item description - 1, - "armor" - }) - - -- the price the player will pay to buy the item in the shop - self:setBuyPrice(10) - -- the price at which the item will be sold in the shop - self:setSellPrice(1) - -- the text that will appear in the shop item info at the top right on the buy menu when hovering an item - self:setShopDescription("WORLD_EXAMPLE_MOD_ITEM_BLANKET_DESCRIPTION_SHOP") - - return self -end - -return BlanketItem diff --git a/engine/mods/world_example/scripts/items/monster_candy.lua b/engine/mods/world_example/scripts/items/monster_candy.lua deleted file mode 100644 index 79460d9..0000000 --- a/engine/mods/world_example/scripts/items/monster_candy.lua +++ /dev/null @@ -1,26 +0,0 @@ ---- @class WorldExample.Item.MonsterCandy : Dummy.Item.Consumable -local MonsterCandyItem = Class(ItemConsumable, "WorldExample.Item.MonsterCandy") - ---- Creates a monster candy ---- @return WorldExample.Item.MonsterCandy -function MonsterCandyItem:new() - self = Class:new(MonsterCandyItem, { - "monster_candy", -- item identifier - "WORLD_EXAMPLE_MOD_ITEM_MONSTER_CANDY_NAME", -- item name - "WORLD_EXAMPLE_MOD_ITEM_MONSTER_CANDY_SHORTNAME", -- item short name - "WORLD_EXAMPLE_MOD_ITEM_MONSTER_CANDY_DESCRIPTION", -- item description - 10, - "food" - }) - - -- the price the player will pay to buy the item in the shop - self:setBuyPrice(15) - -- the price at which the item will be sold in the shop - self:setSellPrice(5) - -- the text that will appear in the shop item info at the top right on the buy menu when hovering an item - self:setShopDescription("WORLD_EXAMPLE_MOD_ITEM_MONSTER_CANDY_DESCRIPTION_SHOP") - - return self -end - -return MonsterCandyItem From b8d62b5547f8e947e6cbfff1cb754fb8b4da324e Mon Sep 17 00:00:00 2001 From: Ivan Date: Mon, 3 Aug 2026 07:58:13 -0700 Subject: [PATCH 4/5] dog residue + quiche --- engine/assets/langs/en.txt | 24 +++++++ engine/assets/sounds/dogresidue.wav | Bin 0 -> 112718 bytes engine/items/abandoned_quiche.lua | 30 ++++++++ engine/items/dog_residue.lua | 65 ++++++++++++++++++ engine/items/nice_cream.lua | 1 - .../world_example/scripts/items/bisicle.lua | 2 +- .../scripts/world/shop/dummy_shop.lua | 6 +- 7 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 engine/assets/sounds/dogresidue.wav create mode 100644 engine/items/abandoned_quiche.lua create mode 100644 engine/items/dog_residue.lua diff --git a/engine/assets/langs/en.txt b/engine/assets/langs/en.txt index 1df7944..6ef7dcc 100644 --- a/engine/assets/langs/en.txt +++ b/engine/assets/langs/en.txt @@ -174,6 +174,30 @@ ITEM_TEMMIE_FLAKES_SHORTNAME2=TemFlakes ITEM_TEMMIE_FLAKES_DESCRIPTION=* "Temmie Flakes" - Heals 2 HP\n* It's just torn up pieces\n of colored construction paper. ITEM_TEMMIE_FLAKES_DESCRIPTION_SHOP=Heals 2HP\nfood of\ntem +ITEM_ABANDONED_QUICHE_NAME=Abandoned Quiche +ITEM_ABANDONED_QUICHE_SHORTNAME=Ab Quiche +ITEM_ABANDONED_QUICHE_SHORTNAME2=Quiche +ITEM_ABANDONED_QUICHE_DESCRIPTION=* "Abandoned Quiche" Heals 34 HP\n* A psychologically damaged\n spinach egg pie. +ITEM_ABANDONED_QUICHE_DESCRIPTION_SHOP=undefined +ITEM_ABANDONED_QUICHE_DROP=* You leave the Quiche on the\n ground and tell it you'll\n be right back. +ITEM_ABANDONED_QUICHE_USE=* You eat the quiche. + +ITEM_DOG_RESIDUE_NAME=Dog Residue +ITEM_DOG_RESIDUE_SHORTNAME=DogResidu +ITEM_DOG_RESIDUE_SHORTNAME2=D.Residue +ITEM_DOG_RESIDUE_DESCRIPTION=* "Dog Residue" - Dog Item\n* Shiny trail left\n behind by a dog. +ITEM_DOG_RESIDUE_DESCRIPTION_2=* "Dog Residue" - Dog Item\n* Dog-shaped husk shed\n from a dog's carapace. +ITEM_DOG_RESIDUE_DESCRIPTION_3=* "Dog Residue" - Dog Item\n* Dirty dishes left\n unwashed by a dog. +ITEM_DOG_RESIDUE_DESCRIPTION_4=* "Dog Residue" - Dog Item\n* Glowing crystals secreted\n by a dog. +ITEM_DOG_RESIDUE_DESCRIPTION_5=* "Dog Residue" - Dog Item\n* Jigsaw puzzle left\n unfinished by a dog. +ITEM_DOG_RESIDUE_DESCRIPTION_6=* "Dog Residue" - Dog Item\n* Web spun by a dog\n to ensnare prey. +ITEM_DOG_RESIDUE_DESCRIPTION_SHOP=undefined +ITEM_DOG_RESIDUE_USE=* You used the Dog Residue. +ITEM_DOG_RESIDUE_USE_SUCCESS=* The rest of your inventory\n filled up with Dog Residue. +ITEM_DOG_RESIDUE_USE_FAIL=* ... +ITEM_DOG_RESIDUE_USE_FAIL_2=* You finished using it. +ITEM_DOG_RESIDUE_USE_FAIL_3=* An uneasy atmosphere fills\n the room. + # World shop WORLD_SHOP_ACTION_BUY=Buy WORLD_SHOP_ACTION_SELL=Sell diff --git a/engine/assets/sounds/dogresidue.wav b/engine/assets/sounds/dogresidue.wav new file mode 100644 index 0000000000000000000000000000000000000000..055029b6a6b6cfc579e73214cc29203243470130 GIT binary patch literal 112718 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 T literal 0 HcmV?d00001 diff --git a/engine/items/abandoned_quiche.lua b/engine/items/abandoned_quiche.lua new file mode 100644 index 0000000..94c996e --- /dev/null +++ b/engine/items/abandoned_quiche.lua @@ -0,0 +1,30 @@ +--- @class Item.AbandonedQuiche : Dummy.Item.Consumable +local AbandonedQuicheItem = Class(ItemConsumable, "Item.AbandonedQuiche") + +--- Creates an abandoned quiche +--- @return Item.AbandonedQuiche +function AbandonedQuicheItem:new() + self = Class:new(AbandonedQuicheItem, { + "abandoned_quiche", -- item identifier + "ITEM_ABANDONED_QUICHE_NAME", -- item name + "ITEM_ABANDONED_QUICHE_SHORTNAME", -- item short name + "ITEM_ABANDONED_QUICHE_DESCRIPTION", -- item description + Player.getMaxHP(), + "food" + }) + + -- the price the player will pay to buy the item in the shop + self:setBuyPrice(1) + -- the price at which the item will be sold in the shop + self:setSellPrice(76) + -- the text that will appear in the shop item info at the top right on the buy menu when hovering an item + self:setShopDescription("ITEM_ABANDONED_QUICHE_DESCRIPTION_SHOP") + -- the text that will appear when the item is dropped on the ground + self:setDropText("ITEM_ABANDONED_QUICHE_DROP") + -- the text that will appear when the item is used + self:setUseText("ITEM_ABANDONED_QUICHE_USE") + + return self +end + +return AbandonedQuicheItem diff --git a/engine/items/dog_residue.lua b/engine/items/dog_residue.lua new file mode 100644 index 0000000..9e4c166 --- /dev/null +++ b/engine/items/dog_residue.lua @@ -0,0 +1,65 @@ +--- @class Item.DogResidue : Dummy.Item.Consumable +local DogResidueItem = Class(Item, "Item.DogResidue") + +--- Creates a dog residue +--- @return Item.DogResidue +function DogResidueItem:new() + self = Class:new(DogResidueItem, { + "dog_residue", -- item identifier + "ITEM_DOG_RESIDUE_NAME", -- item name + "ITEM_DOG_RESIDUE_SHORTNAME", -- item short name + "ITEM_DOG_RESIDUE_DESCRIPTION" -- item description + }) + + -- the price the player will pay to buy the item in the shop + self:setBuyPrice(1) + -- the price at which the item will be sold in the shop + self:setSellPrice(180) + -- the text that will appear in the shop item info at the top right on the buy menu when hovering an item + self:setShopDescription("ITEM_DOG_RESIDUE_DESCRIPTION_SHOP") + -- the text that will appear when the item is used + self:setUseText("ITEM_DOG_RESIDUE_USE") + -- descriptions for each dog residue type + self.descriptions = { + "ITEM_DOG_RESIDUE_DESCRIPTION", + "ITEM_DOG_RESIDUE_DESCRIPTION_2", + "ITEM_DOG_RESIDUE_DESCRIPTION_3", + "ITEM_DOG_RESIDUE_DESCRIPTION_4", + "ITEM_DOG_RESIDUE_DESCRIPTION_5", + "ITEM_DOG_RESIDUE_DESCRIPTION_6" + } + -- Random description when a new version of the object is added (copies will retain the same description) + self.random_description = love.math.random(6) + + return self +end + +function DogResidueItem:getDialogueTexts() + -- define dialogue_text as an empty table because it keeps adding to it if we don't. For some reason. + local dialogue_text = {} + table.insert(dialogue_text, self:getUseTexts()) + -- Show mini-cutscene depending on if the item can create clones + if #Player.getItems() == Player.getMaxItems() then + table.insert(dialogue_text, Lang.translate("ITEM_DOG_RESIDUE_USE_FAIL")) + table.insert(dialogue_text, Lang.translate("ITEM_DOG_RESIDUE_USE_FAIL_2")) + table.insert(dialogue_text, Lang.translate("ITEM_DOG_RESIDUE_USE_FAIL_3")) + else + table.insert(dialogue_text, Lang.translate("ITEM_DOG_RESIDUE_USE_SUCCESS")) + end + return dialogue_text +end + +function DogResidueItem:onUse() + -- Clone the item to all empty slots in the player's inventory + Assets.playSound("dogresidue") + for i = 1, Player.getMaxItems() - #Player.getItems() do + local dog_residue = require("items.dog_residue"):new() + Player.addItem(dog_residue) + end +end + +function DogResidueItem:getDescription() + return Lang.translate(self.descriptions[self.random_description]) +end + +return DogResidueItem diff --git a/engine/items/nice_cream.lua b/engine/items/nice_cream.lua index 3dbd470..e330b9f 100644 --- a/engine/items/nice_cream.lua +++ b/engine/items/nice_cream.lua @@ -37,7 +37,6 @@ end function NiceCreamItem:getDialogueTexts() -- Generate a random number local rand = love.math.random(9) - print(rand) -- Set Default Dialogue Text local dialogue_text = Lang.translate(self:getUseTexts()[1], Lang.translate(self:getName())) .. "\n" .. self:getHealText() diff --git a/engine/mods/world_example/scripts/items/bisicle.lua b/engine/mods/world_example/scripts/items/bisicle.lua index b43aec5..f719602 100644 --- a/engine/mods/world_example/scripts/items/bisicle.lua +++ b/engine/mods/world_example/scripts/items/bisicle.lua @@ -21,7 +21,7 @@ function BisicleItem:new() self:setShopDescription("ITEM_BISICLE_DESCRIPTION_SHOP") self.use_texts = { - "BATTLE_BISICLE_USE" + "ITEM_BISICLE_USE" } return self diff --git a/engine/mods/world_example/scripts/world/shop/dummy_shop.lua b/engine/mods/world_example/scripts/world/shop/dummy_shop.lua index 8b96797..558af90 100644 --- a/engine/mods/world_example/scripts/world/shop/dummy_shop.lua +++ b/engine/mods/world_example/scripts/world/shop/dummy_shop.lua @@ -45,11 +45,13 @@ function DummyShop:prepareItems() local SpiderDonut = require("items.spider_donut") local bisicle = tryRequire("scripts.items.bisicle", "items.bisicle") local nice_cream = require("items.nice_cream") + local quiche = require("items.abandoned_quiche") + local dog_residue = require("items.dog_residue") -- amount `-1` for infinite stock self:addItem(MonsterCandy, -1) - self:addItem(SpiderDonut, -1) self:addItem(bisicle, -1) - self:addItem(nice_cream, -1) + self:addItem(quiche, -1) + self:addItem(dog_residue, -1) local BlanketItem = require("items.blanket") local blanket_amount = 1 From 05d9f59ff6b83b77a79bf20b16776925f9fc6163 Mon Sep 17 00:00:00 2001 From: Ivan Date: Mon, 3 Aug 2026 08:03:44 -0700 Subject: [PATCH 5/5] last minute numerical changes --- engine/items/abandoned_quiche.lua | 2 +- engine/items/dog_residue.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/items/abandoned_quiche.lua b/engine/items/abandoned_quiche.lua index 94c996e..9816231 100644 --- a/engine/items/abandoned_quiche.lua +++ b/engine/items/abandoned_quiche.lua @@ -9,7 +9,7 @@ function AbandonedQuicheItem:new() "ITEM_ABANDONED_QUICHE_NAME", -- item name "ITEM_ABANDONED_QUICHE_SHORTNAME", -- item short name "ITEM_ABANDONED_QUICHE_DESCRIPTION", -- item description - Player.getMaxHP(), + 34, "food" }) diff --git a/engine/items/dog_residue.lua b/engine/items/dog_residue.lua index 9e4c166..fa1d38d 100644 --- a/engine/items/dog_residue.lua +++ b/engine/items/dog_residue.lua @@ -14,7 +14,7 @@ function DogResidueItem:new() -- the price the player will pay to buy the item in the shop self:setBuyPrice(1) -- the price at which the item will be sold in the shop - self:setSellPrice(180) + self:setSellPrice(love.math.random(4)) -- the text that will appear in the shop item info at the top right on the buy menu when hovering an item self:setShopDescription("ITEM_DOG_RESIDUE_DESCRIPTION_SHOP") -- the text that will appear when the item is used