From 8545d15304825944333fd052384ffe5d454a5be1 Mon Sep 17 00:00:00 2001 From: AndreFaramir Date: Thu, 9 Feb 2012 03:27:29 -0200 Subject: [PATCH] implementing battle window, need some improvements but its working --- modules/game/creature.lua | 65 +++-- modules/game/game.lua | 6 + modules/game/game.otmod | 1 + modules/game_battle/battle.lua | 365 ++++++++++++++++++++++++ modules/game_battle/battle.otmod | 7 + modules/game_battle/battle.otui | 91 ++++++ modules/game_battle/battle.png | Bin 0 -> 2063 bytes modules/game_battle/battleButton.otui | 56 ++++ modules/game_battle/battle_monsters.png | Bin 0 -> 3158 bytes modules/game_battle/battle_npcs.png | Bin 0 -> 3115 bytes modules/game_battle/battle_party.png | Bin 0 -> 2990 bytes modules/game_battle/battle_players.png | Bin 0 -> 3084 bytes modules/game_battle/battle_skulls.png | Bin 0 -> 2571 bytes 13 files changed, 569 insertions(+), 22 deletions(-) create mode 100644 modules/game_battle/battle.lua create mode 100644 modules/game_battle/battle.otmod create mode 100644 modules/game_battle/battle.otui create mode 100644 modules/game_battle/battle.png create mode 100644 modules/game_battle/battleButton.otui create mode 100644 modules/game_battle/battle_monsters.png create mode 100644 modules/game_battle/battle_npcs.png create mode 100644 modules/game_battle/battle_party.png create mode 100644 modules/game_battle/battle_players.png create mode 100644 modules/game_battle/battle_skulls.png diff --git a/modules/game/creature.lua b/modules/game/creature.lua index c7e357c6..4c915423 100644 --- a/modules/game/creature.lua +++ b/modules/game/creature.lua @@ -23,53 +23,74 @@ EmblemGreen = 1 EmblemRed = 2 EmblemBlue = 3 -function Creature:onSkullChange(skullId) +function getSkullImagePath(skullId) if skullId == SkullYellow then - self:setSkullTexture(resolvepath('images/skull_yellow.png')) + return 'images/skull_yellow.png' elseif skullId == SkullGreen then - self:setSkullTexture(resolvepath('images/skull_green.png')) + return 'images/skull_green.png' elseif skullId == SkullWhite then - self:setSkullTexture(resolvepath('images/skull_white.png')) + return 'images/skull_white.png' elseif skullId == SkullRed then - self:setSkullTexture(resolvepath('images/skull_red.png')) + return 'images/skull_red.png' elseif skullId == SkullBlack then - self:setSkullTexture(resolvepath('images/skull_black.png')) + return 'images/skull_black.png' elseif skullId == SkullOrange then - self:setSkullTexture(resolvepath('images/skull_orange.png')) + return 'images/skull_orange.png' end end -function Creature:onShieldChange(shieldId) +function getShieldImagePathAndBlink(shieldId) if shieldId == ShieldWhiteYellow then - self:setShieldTexture(resolvepath('images/shield_yellow_white.png'), false) + return 'images/shield_yellow_white.png', false elseif shieldId == ShieldWhiteBlue then - self:setShieldTexture(resolvepath('images/shield_blue_white.png'), false) + return 'images/shield_blue_white.png', false elseif shieldId == ShieldBlue then - self:setShieldTexture(resolvepath('images/shield_blue.png'), false) + return 'images/shield_blue.png', false elseif shieldId == ShieldYellow then - self:setShieldTexture(resolvepath('images/shield_yellow.png'), false) + return 'images/shield_yellow.png', false elseif shieldId == ShieldBlueSharedExp then - self:setShieldTexture(resolvepath('images/shield_blue_shared.png'), false) + return 'images/shield_blue_shared.png', false elseif shieldId == ShieldYellowSharedExp then - self:setShieldTexture(resolvepath('images/shield_yellow_shared.png'), false) + return 'images/shield_yellow_shared.png', false elseif shieldId == ShieldBlueNoSharedExpBlink then - self:setShieldTexture(resolvepath('images/shield_blue_not_shared.png'), true) + return 'images/shield_blue_not_shared.png', true elseif shieldId == ShieldYellowNoSharedExpBlink then - self:setShieldTexture(resolvepath('images/shield_yellow_not_shared.png'), true) + return 'images/shield_yellow_not_shared.png', true elseif shieldId == ShieldBlueNoSharedExp then - self:setShieldTexture(resolvepath('images/shield_blue_not_shared.png'), false) + return 'images/shield_blue_not_shared.png', false elseif shieldId == ShieldYellowNoSharedExp then - self:setShieldTexture(resolvepath('images/shield_yellow_not_shared.png'), false) + return 'images/shield_yellow_not_shared.png', false end end -function Creature:onEmblemChange(emblemId) +function getEmblemImagePath(emblemId) if emblemId == EmblemGreen then - self:setEmblemTexture(resolvepath('images/emblem_green.png')) + return 'images/emblem_green.png' elseif emblemId == EmblemRed then - self:setEmblemTexture(resolvepath('images/emblem_red.png')) + return 'images/emblem_red.png' elseif emblemId == EmblemBlue then - self:setEmblemTexture(resolvepath('images/emblem_blue.png')) + return 'images/emblem_blue.png' + end +end + +function Creature:onSkullChange(skullId) + local imagePath = getSkullImagePath(skullId) + if imagePath then + self:setSkullTexture(resolvepath(imagePath)) + end +end + +function Creature:onShieldChange(shieldId) + local imagePath, blink = getShieldImagePathAndBlink(shieldId) + if imagePath then + self:setShieldTexture(resolvepath(imagePath), blink) + end +end + +function Creature:onEmblemChange(emblemId) + local imagePath = getEmblemImagePath(emblemId) + if imagePath then + self:setEmblemTexture(resolvepath(imagePath)) end end diff --git a/modules/game/game.lua b/modules/game/game.lua index 3c7c58be..7a0b9952 100644 --- a/modules/game/game.lua +++ b/modules/game/game.lua @@ -27,6 +27,12 @@ local function onUseWithMouseRelease(self, mousePosition, mouseButton) end elseif clickedWidget:getClassName() == 'UIItem' and not clickedWidget:isVirtual() then g_game.useWith(g_game.selectedThing, clickedWidget:getItem()) + elseif clickedWidget.isBattleButton or clickedWidget.battleButtonChild then + local battleButton = clickedWidget + if clickedWidget.battleButtonChild then + battleButton = clickedWidget:getParent() + end + g_game.useWith(g_game.selectedThing, battleButton.creature) end end end diff --git a/modules/game/game.otmod b/modules/game/game.otmod index a32671f7..54d25fa0 100644 --- a/modules/game/game.otmod +++ b/modules/game/game.otmod @@ -15,6 +15,7 @@ Module - game_containers - game_combatcontrols - game_hotkeys + - game_battle onLoad: | dofile 'game' diff --git a/modules/game_battle/battle.lua b/modules/game_battle/battle.lua new file mode 100644 index 00000000..e8c9517e --- /dev/null +++ b/modules/game_battle/battle.lua @@ -0,0 +1,365 @@ +Battle = {} + +--TODO +--onCreatureAppears onCreatureHealthChange onCreatureDisappears +--reloadable/disconnects + +-- private variables +local battleWindow +local battleButton +local battlePanel +local lastBattleButtonSwitched +local checkCreaturesEvent +local battleButtonsByCreaturesList = {} + +local mouseWidget + +local hidePlayersButton +local hideNPCsButton +local hideMonstersButton +local hideSkullsButton +local hidePartyButton + +local battleButtonColors = { + onIdle = {notHovered = '#888888', hovered = '#FFFFFF' }, + onTargeted = {notHovered = '#FF0000', hovered = '#FF8888' }, + onFollowed = {notHovered = '#00FF00', hovered = '#88FF88' } +} + +local lifeBarColors = {} --Must be sorted by percentAbose +table.insert(lifeBarColors, {percentAbove = 92, color = '#00BC00' } ) +table.insert(lifeBarColors, {percentAbove = 60, color = '#50A150' } ) +table.insert(lifeBarColors, {percentAbove = 30, color = '#A1A100' } ) +table.insert(lifeBarColors, {percentAbove = 8, color = '#3C2727' } ) +table.insert(lifeBarColors, {percentAbove = 3, color = '#3C0000' } ) +table.insert(lifeBarColors, {percentAbove = -1, color = '#4F0000' } ) + +-- public functions +function Battle.create() + battleWindow = displayUI('battle.otui', { parent = g_game.gameRightPanel }) + battleWindow:hide() + battleButton = TopMenu.addGameButton('battleButton', 'Battle (Ctrl+B)', '/game_battle/battle.png', Battle.toggle) + Keyboard.bindKeyDown('Ctrl+B', Battle.toggle) + + battlePannel = battleWindow:getChildById('battlePanel') + + hidePlayersButton = battleWindow:getChildById('hidePlayers') + hideNPCsButton = battleWindow:getChildById('hideNPCs') + hideMonstersButton = battleWindow:getChildById('hideMonsters') + hideSkullsButton = battleWindow:getChildById('hideSkulls') + hidePartyButton = battleWindow:getChildById('hideParty') + + mouseWidget = createWidget('UIButton') + mouseWidget:setVisible(false) + mouseWidget:setFocusable(false) + + connect(UIWidget, { onHoverChange = Battle.onbattlePannelHoverChange, + onMouseRelease = Battle.onMouseRelease } ) + + connect(Creature, { onSkullChange = Battle.checkCreatureSkull, + onEmblemChange = Battle.checkCreatureEmblem } ) + + connect(g_game, { onAttackingCreatureChange = Battle.onAttack, + onFollowingCreatureChange = Battle.onFollow } ) + + addEvent(Battle.addAllCreatures) + checkCreaturesEvent = scheduleEvent(Battle.checkCreatures, 200) +end + +function Battle.destroy() + Keyboard.unbindKeyDown('Ctrl+B') + battlePannel = nil + lastBattleButtonTargeted = nil + lastBattleButtonFollowed = nil + battleButtonsByCreaturesList = {} + removeEvent(checkCreaturesEvent) + hidePlayersButton = nil + hideNPCsButton = nil + hideMonstersButton = nil + hideSkullsButton = nil + hidePartyButton = nil + checkCreaturesEvent = nil + battleButton:destroy() + battleButton = nil + battleWindow:destroy() + battleWindow = nil + + disconnect(UIWidget, { onHoverChange = Battle.onbattlePannelHoverChange, + onMouseRelease = Battle.onMouseRelease } ) + + disconnect(Creature, { onSkullChange = Battle.checkCreatureSkull, + onEmblemChange = Battle.checkCreatureEmblem } ) + + disconnect(g_game, { onAttackingCreatureChange = Battle.onAttack } ) +end + +function Battle.toggle() + local visible = not battleWindow:isExplicitlyVisible() + battleWindow:setVisible(visible) + battleButton:setOn(visible) +end + +function Battle.addAllCreatures() + local spectators = {} + local player = g_game.getLocalPlayer() + if player then + creatures = g_map.getSpectators(player:getPosition(), false) + for i, creature in ipairs(creatures) do + if creature ~= player and Battle.doCreatureFitFilters(creature) then + table.insert(spectators, creature) + end + end + end + + for i, v in pairs(spectators) do + Battle.addCreature(v) + end +end + +function Battle.doCreatureFitFilters(creature) + local hidePlayers = hidePlayersButton:isChecked() + local hideNPCs = hideNPCsButton:isChecked() + local hideMonsters = hideMonstersButton:isChecked() + local hideSkulls = hideSkullsButton:isChecked() + local hideParty = hidePartyButton:isChecked() + + if hidePlayers and not creature:asMonster() and not creature:asNpc() then + return false + elseif hideNPCs and creature:asNpc() then + return false + elseif hideMonsters and creature:asMonster() then + return false + elseif hideSkulls and creature:getSkull() == SkullNone then + return false + elseif hideParty and creature:getShield() > ShieldWhiteBlue then + return false + end + + return true +end + +function Battle.checkCreatures() + local player = g_game.getLocalPlayer() + if player then + local spectators = {} + + -- reloading list of spectators + local creaturesAppeared = {} + creatures = g_map.getSpectators(player:getPosition(), false) + for i, creature in ipairs(creatures) do + if creature ~= player and Battle.doCreatureFitFilters(creature) then + -- searching for creatures that appeared on battle list + local battleButton = battleButtonsByCreaturesList[creature:getId()] + if battleButton == nil then + table.insert(creaturesAppeared, creature) + else + Battle.setLifeBarPercent(battleButton, creature:getHealthPercent()) + end + spectators[creature:getId()] = creature + end + end + + for i, v in pairs(creaturesAppeared) do + Battle.addCreature(v) + end + + -- searching for creatures that disappeared from battle list + local creaturesDisappeared = {} + for i, creature in pairs(battleButtonsByCreaturesList) do + if spectators[creature.creatureId] == nil then + table.insert(creaturesDisappeared, creature.creature) + end + end + + for i, v in pairs(creaturesDisappeared) do + Battle.removeCreature(v) + end + end + checkCreaturesEvent = scheduleEvent(Battle.checkCreatures, 500) +end + +function Battle.addCreature(creature) + local creatureId = creature:getId() + + if battleButtonsByCreaturesList[creatureId] == nil then + local battleButton = displayUI('battleButton.otui', { parent = battlePannel }) + local creatureWidget = battleButton:getChildById('creature') + local labelWidget = battleButton:getChildById('label') + local lifeBarWidget = battleButton:getChildById('lifeBar') + + battleButton:setId('BattleButton_' .. creature:getName():gsub('%s','_')) + battleButton.creatureId = creatureId + battleButton.creature = creature + battleButton.isHovered = false + battleButton.isTarget = false + battleButton.isFollowed = false + + labelWidget:setText(creature:getName()) + creatureWidget:setCreature(creature) + Battle.setLifeBarPercent(battleButton, creature:getHealthPercent()) + + battleButtonsByCreaturesList[creatureId] = battleButton + + Battle.checkCreatureSkull(battleButton.creature) + Battle.checkCreatureEmblem(battleButton.creature) + end +end + +function Battle.checkCreatureSkull(creature, skullId) + local battleButton = battleButtonsByCreaturesList[creature:getId()] + if battleButton then + local skullWidget = battleButton:getChildById('skull') + local labelWidget = battleButton:getChildById('label') + local creature = battleButton.creature + + if creature:getSkull() ~= SkullNone then + skullWidget:setWidth(skullWidget:getHeight()) + local imagePath = getSkullImagePath(creature:getSkull()) + skullWidget:setImageSource('/game/' .. imagePath) + labelWidget:setMarginLeft(5) + else + skullWidget:setWidth(0) + if creature:getEmblem() == EmblemNone then + labelWidget:setMarginLeft(2) + end + end + end +end + +function Battle.checkCreatureEmblem(creature, emblemId) + local battleButton = battleButtonsByCreaturesList[creature:getId()] + if battleButton then + local emblemId = emblemId or creature:getEmblem() + local emblemWidget = battleButton:getChildById('emblem') + local labelWidget = battleButton:getChildById('label') + local creature = battleButton.creature + + if emblemId ~= EmblemNone then + emblemWidget:setWidth(emblemWidget:getHeight()) + local imagePath = getEmblemImagePath(emblemId) + emblemWidget:setImageSource('/game/' .. imagePath) + emblemWidget:setMarginLeft(5) + labelWidget:setMarginLeft(5) + else + emblemWidget:setWidth(0) + emblemWidget:setMarginLeft(0) + if creature:getSkull() == SkullNone then + labelWidget:setMarginLeft(2) + end + end + end +end + +function Battle.onMouseRelease(self, mousePosition, mouseButton) + if mouseButton == MouseRightButton then + local clickedWidget = g_game.gameUi:recursiveGetChildByPos(mousePosition) + if clickedWidget then + if clickedWidget:getStyleName() == 'BattleButton' then + g_game.createThingMenu(mousePosition, nil, nil, clickedWidget.creature) + return true + end + end + end +end + +function Battle.removeCreature(creature) + local creatureId = creature:getId() + + if battleButtonsByCreaturesList[creatureId] ~= nil then + if lastBattleButtonSwitched == battleButtonsByCreaturesList[creatureId] then + lastBattleButtonSwitched = nil + end + + battleButtonsByCreaturesList[creatureId]:destroy() + battleButtonsByCreaturesList[creatureId] = nil + end +end + +function Battle.setLifeBarPercent(battleButton, percent) + local lifeBarWidget = battleButton:getChildById('lifeBar') + lifeBarWidget:setPercent(percent) + + local color + for i, v in pairs(lifeBarColors) do + if percent > v.percentAbove then + color = v.color + break + end + end + + lifeBarWidget:setBackgroundColor(color) +end + +function Battle.onButtonClick(battleButton) + if battleButton then + if battleButton.isTarget then + g_game.cancelAttack() + else + g_game.attack(battleButton.creature) + end + end +end + +function Battle.onbattlePannelHoverChange(widget, hovered) + if widget.isBattleButton or widget.battleButtonChild then + local battleButton = widget + if widget.battleButtonChild then + battleButton = widget:getParent() + end + + if battleButton then + battleButton.isHovered = hovered + Battle.checkBattleButton(battleButton) + end + end +end + +function Battle.onAttack(creature) + local battleButton = creature and battleButtonsByCreaturesList[creature:getId()] or lastBattleButtonSwitched + if battleButton then + battleButton.isTarget = creature and true or false + Battle.checkBattleButton(battleButton) + end +end + +function Battle.onFollow(creature) + local battleButton = creature and battleButtonsByCreaturesList[creature:getId()] or lastBattleButtonSwitched + if battleButton then + battleButton.isFollowed = creature and true or false + Battle.checkBattleButton(battleButton) + end +end + +function Battle.checkBattleButton(battleButton) + local color = battleButtonColors.onIdle + if battleButton.isTarget then + color = battleButtonColors.onTargeted + elseif battleButton.isFollowed then + color = battleButtonColors.onFollowed + end + + color = battleButton.isHovered and color.hovered or color.notHovered + + if battleButton.isHovered or battleButton.isTarget or battleButton.isFollowed then + battleButton.creature:showStaticSquare(color) + battleButton:getChildById('creature'):setBorderWidth(1) + battleButton:getChildById('creature'):setBorderColor(color) + battleButton:getChildById('label'):setColor(color) + else + battleButton.creature:hideStaticSquare() + battleButton:getChildById('creature'):setBorderWidth(0) + battleButton:getChildById('label'):setColor(color) + end + + if battleButton.isTarget or battleButton.isFollowed then + if lastBattleButtonSwitched and lastBattleButtonSwitched ~= battleButton then + lastBattleButtonSwitched.isTarget = false + lastBattleButtonSwitched.isFollowed = false + Battle.checkBattleButton(lastBattleButtonSwitched) + end + lastBattleButtonSwitched = battleButton + end +end + +connect(g_game, { onGameStart = Battle.create, + onGameEnd = Battle.destroy } ) \ No newline at end of file diff --git a/modules/game_battle/battle.otmod b/modules/game_battle/battle.otmod new file mode 100644 index 00000000..885e430b --- /dev/null +++ b/modules/game_battle/battle.otmod @@ -0,0 +1,7 @@ +Module + name: game_battle + description: Manage battle window + author: OTClient team + website: https://github.com/edubart/otclient + onLoad: | + dofile 'battle' diff --git a/modules/game_battle/battle.otui b/modules/game_battle/battle.otui new file mode 100644 index 00000000..f235c4ca --- /dev/null +++ b/modules/game_battle/battle.otui @@ -0,0 +1,91 @@ +BattleIcon < UICheckBox + size: 20 20 + image-color: white + image-rect: 0 0 20 20 + + $hover !disabled: + color: #cccccc + + $!checked: + image-clip: 0 0 20 20 + + $hover !checked: + image-clip: 0 40 20 20 + + $checked: + image-clip: 0 20 20 20 + + $hover checked: + image-clip: 0 60 20 20 + + $disabled: + image-color: #ffffff88 + +BattlePlayers < BattleIcon + image-source: /game_battle/battle_players.png + +BattleNPCs < BattleIcon + image-source: /game_battle/battle_npcs.png + +BattleMonsters < BattleIcon + image-source: /game_battle/battle_monsters.png + +BattleSkulls < BattleIcon + image-source: /game_battle/battle_skulls.png + +BattleParty < BattleIcon + image-source: /game_battle/battle_party.png + +MiniWindow + id: battleWindow + text: Battle + height: 250 + + BattlePlayers + id: hidePlayers + tooltip: Hide players + anchors.top: parent.top + anchors.right: next.left + margin-right: 5 + + BattleNPCs + id: hideNPCs + tooltip: Hide Npc's + anchors.top: parent.top + anchors.right: next.left + margin-right: 5 + + BattleMonsters + id: hideMonsters + tooltip: Hide monsters + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + + BattleSkulls + id: hideSkulls + tooltip: Hide non-skull players + anchors.top: prev.top + anchors.left: prev.right + margin-left: 5 + + BattleParty + id: hideParty + tooltip: Hide party members + anchors.top: prev.top + anchors.left: prev.right + margin-left: 5 + + HorizontalSeparator + anchors.top: prev.bottom + anchors.left: parent.left + anchors.right: parent.right + margin-top: 5 + + Panel + id: battlePanel + anchors.fill: parent + anchors.top: prev.bottom + margin-top: 5 + layout: verticalBox + + diff --git a/modules/game_battle/battle.png b/modules/game_battle/battle.png new file mode 100644 index 0000000000000000000000000000000000000000..247c6ec68f406aa9c1348e4b4a33643514ee6b7a GIT binary patch literal 2063 zcmd^;dq`Ay6vw}JoaT;`x>>HNnQi7sQEaS1NDpCbYL%$9vLKS(h!(eHqh2e5Z zu~3#Ymlet;qoUB_crmOl608pmOr4S>8n0K&kb=caHUK)w(*kfJovqpi#pl7Q;tKJ+ zwPRFxa52-IBJSKciCn7$N--y@tV17;SMS+9apWfyZn9xCID@Iv2lms*v8+Ra!H>V( zw2=W>I?Vw6m?(C7TpslF_M^wEgKhsB6zr%OO2ezCj$o4%lph-+8W0~tX92iaa})RN z&8UCsg=R2eKu#nsE}GX&iAfBlb;=t_bY{6(5AL3Y#ZrXn2`VNgjN`o8Yj@ym?_&75 zW+Q0S{ay`|QseRDziy7xI^~TdI=!MmlN&=+MyA z3OeY=Y{wbe`tmjYykTeGC_C9wX@@abIf5}mZs5bZ5;13bs#uXdMXXztAyT3ZqNo0h z$onc;JnQZjx0_o;N%jhHBsbO$u?|XS92E{xzNmTAGz;9)B z95F=+IG%N4-dF?5_myJT-UGNC^Cg4qw;PAb@a}CN+iq7cYgcy{ii$S}*V!QW#ftC6 zsr{??Gh2_BiL6+a?Z%&rSm(^n6x88pH^G7(550nBOLo)YJvdQeLv`D0lo+2N;jJPb@wf^VNV76&`r&`*e`5FbCMvy<~9XUYj7kFXhs#MvbHOOJQhiwXL_ kJC1xwr2i=$N7j7C{?XF1hHCZH78*hR;^o%!x$F0R0I}Ge-~a#s literal 0 HcmV?d00001 diff --git a/modules/game_battle/battleButton.otui b/modules/game_battle/battleButton.otui new file mode 100644 index 00000000..838ce8e8 --- /dev/null +++ b/modules/game_battle/battleButton.otui @@ -0,0 +1,56 @@ +BattleButton < UIButton + +BattleButton + height: 20 + margin-top: 5 + fixed-size: true + @onClick: Battle.onButtonClick(self) + &isBattleButton: true + + UICreature + id: creature + size: 20 20 + anchors.left: parent.left + anchors.top: parent.top + @onClick: Battle.onButtonClick(parent) + &battleButtonChild: true + + UIWidget + id: spacer + width: 5 + anchors.left: creature.right + anchors.top: creature.top + &battleButtonChild: true + + UIWidget + id: skull + height: 11 + anchors.left: spacer.right + anchors.top: spacer.top + &battleButtonChild: true + + UIWidget + id: emblem + height: 11 + anchors.left: skull.right + anchors.top: creature.top + &battleButtonChild: true + + LargerLabel + id: label + anchors.left: emblem.right + anchors.top: creature.top + color: #888888 + margin-left: 2 + @onClick: Battle.onButtonClick(parent) + &battleButtonChild: true + + ProgressBar + id: lifeBar + height: 5 + anchors.left: spacer.right + anchors.right: parent.right + anchors.top: label.bottom + margin-top: 2 + @onClick: Battle.onButtonClick(parent) + &battleButtonChild: true \ No newline at end of file diff --git a/modules/game_battle/battle_monsters.png b/modules/game_battle/battle_monsters.png new file mode 100644 index 0000000000000000000000000000000000000000..9c01361cd39c4d771d8bb40aeda9698d923cfe4f GIT binary patch literal 3158 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 literal 0 HcmV?d00001