From c6506b567c791c6ef9a80df01f666c2c6d6d4b48 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sun, 1 Mar 2015 10:07:03 -0500 Subject: XEEN: Implemented more spells --- engines/xeen/dialogs_spells.cpp | 116 +++++++++++- engines/xeen/dialogs_spells.h | 25 ++- engines/xeen/map.h | 2 +- engines/xeen/resources.cpp | 18 ++ engines/xeen/resources.h | 6 + engines/xeen/spells.cpp | 411 +++++++++++++++++++++++++++++----------- 6 files changed, 464 insertions(+), 114 deletions(-) (limited to 'engines/xeen') diff --git a/engines/xeen/dialogs_spells.cpp b/engines/xeen/dialogs_spells.cpp index f5357766ba..eb7373313e 100644 --- a/engines/xeen/dialogs_spells.cpp +++ b/engines/xeen/dialogs_spells.cpp @@ -21,6 +21,7 @@ */ #include "xeen/dialogs_spells.h" +#include "xeen/dialogs_input.h" #include "xeen/dialogs_query.h" #include "xeen/resources.h" #include "xeen/spells.h" @@ -579,12 +580,18 @@ void CastSpell::loadButtons() { /*------------------------------------------------------------------------*/ -int SpellOnWho::show(XeenEngine *vm, int spellId) { +Character *SpellOnWho::show(XeenEngine *vm, int spellId) { SpellOnWho *dlg = new SpellOnWho(vm); int result = dlg->execute(spellId); delete dlg; - return result; + if (result == -1) + return nullptr; + + Combat &combat = *vm->_combat; + Party &party = *vm->_party; + return combat._combatMode == 2 ? combat._combatParty[result] : + &party._activeParty[result]; } int SpellOnWho::execute(int spellId) { @@ -773,7 +780,6 @@ bool LloydsBeacon::execute() { Party &party = *_vm->_party; Screen &screen = *_vm->_screen; SoundManager &sound = *_vm->_sound; - Spells &spells = *_vm->_spells; Window &w = screen._windows[10]; bool isDarkCc = _vm->_files->_isDarkCc; Character &c = *combat._oldCharacter; @@ -863,4 +869,108 @@ void LloydsBeacon::loadButtons() { addButton(Common::Rect(242, 108, 266, 128), Common::KEYCODE_t, &_iconSprites); } +/*------------------------------------------------------------------------*/ + +int Teleport::show(XeenEngine *vm) { + Teleport *dlg = new Teleport(vm); + int result = dlg->execute(); + delete dlg; + + return result; +} + +int Teleport::execute() { + Map &map = *_vm->_map; + Party &party = *_vm->_party; + Screen &screen = *_vm->_screen; + Window &w = screen._windows[6]; + Common::String num; + + w.open(); + w.writeString(Common::String::format(HOW_MANY_SQUARES, + DIRECTION_TEXT[party._mazeDirection])); + w.update(); + int lineSize = Input::show(_vm, &w, num, 1, 200, true); + w.close(); + + if (!lineSize) + return -1; + int numSquares = atoi(num.c_str()); + Common::Point pt = party._mazePosition; + int v; + + switch (party._mazeDirection) { + case DIR_NORTH: + pt.y += numSquares; + break; + case DIR_EAST: + pt.x += numSquares; + break; + case DIR_SOUTH: + pt.y -= numSquares; + break; + case DIR_WEST: + pt.x -= numSquares; + break; + } + + v = map.mazeLookup(pt, map._isOutdoors ? 0xF : 0xFFFF, 0); + + if ((v != (map._isOutdoors ? 0 : INVALID_CELL)) && + (!map._isOutdoors || v == SURFTYPE_DWATER)) { + party._mazePosition = pt; + return 1; + } else { + return 0; + } +} + +/*------------------------------------------------------------------------*/ + +int TownPortal::show(XeenEngine *vm) { + TownPortal *dlg = new TownPortal(vm); + int townNumber = dlg->execute(); + delete dlg; + + return townNumber; +} + +int TownPortal::execute() { + Map &map = *_vm->_map; + Screen &screen = *_vm->_screen; + Window &w = screen._windows[20]; + Common::String townNames[5]; + Mode oldMode = _vm->_mode; + _vm->_mode = MODE_FF; + + // Build up a lsit of the names of the towns on the current side of Xeen + for (int idx = 0; idx < 5; ++idx) { + File f(Common::String::format("%s%04d.txt", + map._sideTownPortal ? "dark" : "xeen", + TOWN_MAP_NUMBERS[map._sideTownPortal][idx])); + townNames[idx] = f.readString(); + f.close(); + } + + w.open(); + w.writeString(Common::String::format(TOWN_PORTAL, + townNames[0].c_str(), townNames[1].c_str(), townNames[2].c_str(), + townNames[3].c_str(), townNames[4].c_str() + )); + w.update(); + + // Get the town number + int townNumber; + Common::String num; + do { + int result = Input::show(_vm, &w, num, 1, 160, true); + townNumber = !result ? 0 : atoi(num.c_str()); + } while (townNumber > 5); + + w.close(); + _vm->_mode = oldMode; + + return townNumber; +} + } // End of namespace Xeen diff --git a/engines/xeen/dialogs_spells.h b/engines/xeen/dialogs_spells.h index ca7bb17b5e..9f4af15636 100644 --- a/engines/xeen/dialogs_spells.h +++ b/engines/xeen/dialogs_spells.h @@ -81,7 +81,7 @@ private: int execute(int spellId); public: - static int show(XeenEngine *vm, int spellId); + static Character *show(XeenEngine *vm, int spellId); }; class SelectElement : public ButtonContainer { @@ -123,6 +123,29 @@ public: static bool show(XeenEngine *vm); }; +class Teleport : public ButtonContainer { +private: + XeenEngine *_vm; + SpriteResource _iconSprites; + + Teleport(XeenEngine *vm) : ButtonContainer(), _vm(vm) {} + + int execute(); +public: + static int show(XeenEngine *vm); +}; + +class TownPortal : public ButtonContainer { +private: + XeenEngine *_vm; + + TownPortal(XeenEngine *vm) : ButtonContainer(), _vm(vm) {} + + int execute(); +public: + static int show(XeenEngine *vm); +}; + } // End of namespace Xeen #endif /* XEEN_DIALOGS_SPELLS_H */ diff --git a/engines/xeen/map.h b/engines/xeen/map.h index bfc09ec053..a7e88c1726 100644 --- a/engines/xeen/map.h +++ b/engines/xeen/map.h @@ -356,7 +356,6 @@ private: XeenEngine *_vm; MazeData _mazeData[9]; SpriteResource _wallPicSprites; - int _sideTownPortal; int _sidePictures; int _sideObjects; int _sideMonsters; @@ -387,6 +386,7 @@ public: int _currentSurfaceId; bool _currentSteppedOn; bool _loadDarkSide; + int _sideTownPortal; public: Map(XeenEngine *vm); diff --git a/engines/xeen/resources.cpp b/engines/xeen/resources.cpp index a75f77ba5c..085cfab58d 100644 --- a/engines/xeen/resources.cpp +++ b/engines/xeen/resources.cpp @@ -1554,4 +1554,22 @@ const char *const LLOYDS_BEACON = "%s\x3l\n" "x = %d\x3r\t000y = %d\x3""c\x2\v122\t021\f15S\fdet\t060\f15R\fdeturn\x1"; +const char *const HOW_MANY_SQUARES = "\x03cTeleport\nHow many squares %s (1-9)"; + +const char *const TOWN_PORTAL = + "\x3""cTown Portal\x3l\n" + "\n" + "\t0101. %s\n" + "\t0102. %s\n" + "\t0103. %s\n" + "\t0104. %s\n" + "\t0105. %s\x3""c\n" + "\n" + "To which Town (1-5)\n" + "\n"; + +const int TOWN_MAP_NUMBERS[2][5] = { + { 28, 29, 30, 31, 32 }, { 29, 31, 33, 35, 37 } +}; + } // End of namespace Xeen diff --git a/engines/xeen/resources.h b/engines/xeen/resources.h index 89dc74a4fe..29e86112a1 100644 --- a/engines/xeen/resources.h +++ b/engines/xeen/resources.h @@ -550,6 +550,12 @@ extern const char *const DETECT_MONSTERS; extern const char *const LLOYDS_BEACON; +extern const char *const HOW_MANY_SQUARES; + +extern const char *const TOWN_PORTAL; + +extern const int TOWN_MAP_NUMBERS[2][5]; + } // End of namespace Xeen #endif /* XEEN_RESOURCES_H */ diff --git a/engines/xeen/spells.cpp b/engines/xeen/spells.cpp index e3978aef65..e2e8cfde36 100644 --- a/engines/xeen/spells.cpp +++ b/engines/xeen/spells.cpp @@ -331,79 +331,59 @@ void Spells::createFood() { } void Spells::cureDisease() { - Combat &combat = *_vm->_combat; Interface &intf = *_vm->_interface; - Party &party = *_vm->_party; SoundManager &sound = *_vm->_sound; - int charIndex = SpellOnWho::show(_vm, MS_Revitalize); - if (charIndex == -1) + Character *c = SpellOnWho::show(_vm, MS_CureDisease); + if (!c) return; - Character &c = combat._combatMode == 2 ? *combat._combatParty[charIndex] : - party._activeParty[charIndex]; - sound.playFX(30); - c.addHitPoints(0); - c._conditions[DISEASED] = 0; + c->addHitPoints(0); + c->_conditions[DISEASED] = 0; intf.drawParty(true); } void Spells::cureParalysis() { - Combat &combat = *_vm->_combat; Interface &intf = *_vm->_interface; - Party &party = *_vm->_party; SoundManager &sound = *_vm->_sound; - int charIndex = SpellOnWho::show(_vm, MS_Revitalize); - if (charIndex == -1) + Character *c = SpellOnWho::show(_vm, MS_CureParalysis); + if (!c) return; - Character &c = combat._combatMode == 2 ? *combat._combatParty[charIndex] : - party._activeParty[charIndex]; - sound.playFX(30); - c.addHitPoints(0); - c._conditions[PARALYZED] = 0; + c->addHitPoints(0); + c->_conditions[PARALYZED] = 0; intf.drawParty(true); } void Spells::curePoison() { - Combat &combat = *_vm->_combat; Interface &intf = *_vm->_interface; - Party &party = *_vm->_party; SoundManager &sound = *_vm->_sound; - int charIndex = SpellOnWho::show(_vm, MS_Revitalize); - if (charIndex == -1) + Character *c = SpellOnWho::show(_vm, MS_CurePoison); + if (!c) return; - Character &c = combat._combatMode == 2 ? *combat._combatParty[charIndex] : - party._activeParty[charIndex]; - sound.playFX(30); - c.addHitPoints(0); - c._conditions[POISONED] = 0; + c->addHitPoints(0); + c->_conditions[POISONED] = 0; intf.drawParty(true); } void Spells::cureWounds() { - Combat &combat = *_vm->_combat; - Party &party = *_vm->_party; SoundManager &sound = *_vm->_sound; - int charIndex = SpellOnWho::show(_vm, MS_Revitalize); - if (charIndex == -1) + Character *c = SpellOnWho::show(_vm, MS_CureWounds); + if (!c) return; - Character &c = combat._combatMode == 2 ? *combat._combatParty[charIndex] : - party._activeParty[charIndex]; - - if (c.isDead()) { + if (c->isDead()) { spellFailed(); } else { sound.playFX(30); - c.addHitPoints(15); + c->addHitPoints(15); } } @@ -559,17 +539,13 @@ void Spells::elementalStorm() { } void Spells::enchantItem() { - Combat &combat = *_vm->_combat; - Party &party = *_vm->_party; Mode oldMode = _vm->_mode; - int charIndex = SpellOnWho::show(_vm, MS_FirstAid); - if (charIndex == -1) + Character *c = SpellOnWho::show(_vm, MS_EnchantItem); + if (!c) return; - Character &c = combat._combatMode == 2 ? *combat._combatParty[charIndex] : - party._activeParty[charIndex]; - ItemsDialog::show(_vm, &c, ITEMMODE_ENCHANT); + ItemsDialog::show(_vm, c, ITEMMODE_ENCHANT); _vm->_mode = oldMode; } @@ -648,23 +624,17 @@ void Spells::fireball() { } void Spells::firstAid() { - Combat &combat = *_vm->_combat; - Party &party = *_vm->_party; SoundManager &sound = *_vm->_sound; - int charIndex = SpellOnWho::show(_vm, MS_FirstAid); - if (charIndex == -1) + Character *c = SpellOnWho::show(_vm, MS_FirstAid); + if (!c) return; - Character &c = combat._combatMode == 2 ? *combat._combatParty[charIndex] : - party._activeParty[charIndex]; - - if (c.isDead()) { + if (c->isDead()) { spellFailed(); - } - else { + } else { sound.playFX(30); - c.addHitPoints(6); + c->addHitPoints(6); } } @@ -788,20 +758,15 @@ void Spells::insectSpray() { } void Spells::itemToGold() { - Combat &combat = *_vm->_combat; - Party &party = *_vm->_party; - - int charIndex = SpellOnWho::show(_vm, MS_Revitalize); - if (charIndex == -1) + Character *c = SpellOnWho::show(_vm, MS_ItemToGold); + if (!c) return; - Character &c = combat._combatMode == 2 ? *combat._combatParty[charIndex] : - party._activeParty[charIndex]; Mode oldMode = _vm->_mode; _vm->_mode = MODE_FF; _vm->_screen->_windows[11].close(); - ItemsDialog::show(_vm, &c, ITEMMODE_TO_GOLD); + ItemsDialog::show(_vm, c, ITEMMODE_TO_GOLD); _vm->_mode = oldMode; } @@ -931,23 +896,17 @@ void Spells::moonRay() { } void Spells::naturesCure() { - Combat &combat = *_vm->_combat; - Interface &intf = *_vm->_interface; - Party &party = *_vm->_party; SoundManager &sound = *_vm->_sound; - int charIndex = SpellOnWho::show(_vm, MS_Revitalize); - if (charIndex == -1) + Character *c = SpellOnWho::show(_vm, MS_NaturesCure); + if (!c) return; - Character &c = combat._combatMode == 2 ? *combat._combatParty[charIndex] : - party._activeParty[charIndex]; - - if (c.isDead()) { + if (c->isDead()) { spellFailed(); } else { sound.playFX(30); - c.addHitPoints(25); + c->addHitPoints(25); } } @@ -974,12 +933,39 @@ void Spells::poisonVolley() { } void Spells::powerCure() { - + SoundManager &sound = *_vm->_sound; + + Character *c = SpellOnWho::show(_vm, MS_PowerCure); + if (!c) + return; + + if (c->isDead()) { + spellFailed(); + } else { + sound.playFX(30); + c->addHitPoints(_vm->getRandomNumber(2, 12) * _vm->_combat->_oldCharacter->getCurrentLevel()); + } +} + +void Spells::powerShield() { + Combat &combat = *_vm->_combat; + Party &party = *_vm->_party; + SoundManager &sound = *_vm->_sound; + + sound.playFX(20); + party._powerShield = combat._oldCharacter->getCurrentLevel(); } -void Spells::powerShield() { error("TODO: spell"); } +void Spells::prismaticLight() { + Combat &combat = *_vm->_combat; + SoundManager &sound = *_vm->_sound; -void Spells::prismaticLight() { error("TODO: spell"); } + combat._monsterDamage = 80; + combat._damageType = (DamageType)_vm->getRandomNumber(DT_PHYSICAL, DT_ENERGY); + combat._rangeType = RT_ALL; + sound.playFX(18); + combat.multiAttack(14); +} void Spells::protectionFromElements() { Combat &combat = *_vm->_combat; @@ -1013,32 +999,91 @@ void Spells::protectionFromElements() { } } -void Spells::raiseDead() { error("TODO: spell"); } +void Spells::raiseDead() { + Interface &intf = *_vm->_interface; + SoundManager &sound = *_vm->_sound; -void Spells::rechargeItem() { error("TODO: spell"); } + Character *c = SpellOnWho::show(_vm, MS_RaiseDead); + if (!c) + return; -void Spells::resurrection() { error("TODO: spell"); } + if (!c->_conditions[DEAD]) { + spellFailed(); + } else { + c->_conditions[DEAD] = 0; + c->_conditions[UNCONSCIOUS] = 0; + c->_currentHp = 0; + sound.playFX(30); + c->addHitPoints(1); + if (--c->_endurance._permanent < 1) + c->_endurance._permanent = 1; -void Spells::revitalize() { - Combat &combat = *_vm->_combat; + intf.drawParty(true); + } +} + +void Spells::rechargeItem() { + Mode oldMode = _vm->_mode; + + Character *c = SpellOnWho::show(_vm, MS_RechargeItem); + if (!c) + return; + + ItemsDialog::show(_vm, c, ITEMMODE_RECHARGE); + _vm->_mode = oldMode; +} + +void Spells::resurrection() { Interface &intf = *_vm->_interface; - Party &party = *_vm->_party; SoundManager &sound = *_vm->_sound; - int charIndex = SpellOnWho::show(_vm, MS_Revitalize); - if (charIndex == -1) + Character *c = SpellOnWho::show(_vm, MS_RaiseDead); + if (!c) return; - Character &c = combat._combatMode == 2 ? *combat._combatParty[charIndex] : - party._activeParty[charIndex]; + if (!c->_conditions[ERADICATED]) { + spellFailed(); + sound.playFX(30); + } else { + sound.playFX(30); + c->addHitPoints(0); + c->_conditions[ERADICATED] = 0; + + if (--c->_endurance._permanent < 1) + c->_endurance._permanent = 1; + if ((c->_tempAge + 5) >= 250) + c->_tempAge = 250; + else + c->_tempAge += 5; + + intf.drawParty(true); + } +} + +void Spells::revitalize() { + Interface &intf = *_vm->_interface; + SoundManager &sound = *_vm->_sound; + + Character *c = SpellOnWho::show(_vm, MS_Revitalize); + if (!c) + return; sound.playFX(30); - c.addHitPoints(0); - c._conditions[WEAK] = 0; + c->addHitPoints(0); + c->_conditions[WEAK] = 0; intf.drawParty(true); } -void Spells::shrapMetal() { error("TODO: spell"); } +void Spells::shrapMetal() { + Combat &combat = *_vm->_combat; + SoundManager &sound = *_vm->_sound; + + combat._monsterDamage = combat._oldCharacter->getCurrentLevel() * 2; + combat._damageType = DT_PHYSICAL; + combat._rangeType = RT_GROUP; + sound.playFX(16); + combat.multiAttack(15); +} void Spells::sleep() { Combat &combat = *_vm->_combat; @@ -1062,47 +1107,182 @@ void Spells::sparks() { combat.multiAttack(5); } -void Spells::starBurst() { error("TODO: spell"); } +void Spells::starBurst() { + Combat &combat = *_vm->_combat; + SoundManager &sound = *_vm->_sound; -void Spells::stoneToFlesh() { error("TODO: spell"); } + combat._monsterDamage = 500; + combat._damageType = DT_FIRE; + combat._rangeType = RT_ALL; + sound.playFX(13); + combat.multiAttack(15); +} -void Spells::sunRay() { error("TODO: spell"); } +void Spells::stoneToFlesh() { + Interface &intf = *_vm->_interface; + SoundManager &sound = *_vm->_sound; -void Spells::superShelter() { error("TODO: spell"); } + Character *c = SpellOnWho::show(_vm, MS_StoneToFlesh); + if (!c) + return; -void Spells::suppressDisease() { error("TODO: spell"); } + sound.playFX(30); + c->addHitPoints(0); + c->_conditions[STONED] = 0; + intf.drawParty(true); +} -void Spells::suppressPoison() { +void Spells::sunRay() { Combat &combat = *_vm->_combat; + SoundManager &sound = *_vm->_sound; + + combat._monsterDamage = 200; + combat._damageType = DT_ENERGY; + combat._rangeType = RT_ALL; + sound.playFX(16); + combat.multiAttack(13); +} + +void Spells::superShelter() { Interface &intf = *_vm->_interface; - Party &party = *_vm->_party; + Map &map = *_vm->_map; SoundManager &sound = *_vm->_sound; - int charIndex = SpellOnWho::show(_vm, MS_FirstAid); - if (charIndex == -1) + if (map.mazeData()._mazeFlags & RESTRICTION_SUPER_SHELTER) { + spellFailed(); + } else { + Mode oldMode = _vm->_mode; + _vm->_mode = MODE_12; + sound.playFX(30); + intf.rest(); + _vm->_mode = oldMode; + } +} + +void Spells::suppressDisease() { + Interface &intf = *_vm->_interface; + SoundManager &sound = *_vm->_sound; + + Character *c = SpellOnWho::show(_vm, MS_SuppressDisease); + if (!c) return; - Character &c = combat._combatMode == 2 ? *combat._combatParty[charIndex] : - party._activeParty[charIndex]; + if (c->_conditions[DISEASED]) { + if (c->_conditions[DISEASED] >= 4) + c->_conditions[DISEASED] -= 3; + else + c->_conditions[DISEASED] = 1; + + sound.playFX(20); + c->addHitPoints(0); + intf.drawParty(true); + } +} + +void Spells::suppressPoison() { + Interface &intf = *_vm->_interface; + SoundManager &sound = *_vm->_sound; + + Character *c = SpellOnWho::show(_vm, MS_FirstAid); + if (!c) + return; - if (c._conditions[POISONED]) { - if (c._conditions[POISONED] >= 4) { - c._conditions[POISONED] -= 2; + if (c->_conditions[POISONED]) { + if (c->_conditions[POISONED] >= 4) { + c->_conditions[POISONED] -= 2; } else { - c._conditions[POISONED] = 1; + c->_conditions[POISONED] = 1; } } sound.playFX(20); - c.addHitPoints(0); + c->addHitPoints(0); intf.drawParty(1); } -void Spells::teleport() { error("TODO: spell"); } // Not while engaged +void Spells::teleport() { + Map &map = *_vm->_map; + SoundManager &sound = *_vm->_sound; -void Spells::timeDistortion() { error("TODO: spell"); } + if (map.mazeData()._mazeFlags & RESTRICTION_TELPORT) { + spellFailed(); + } else { + switch (Teleport::show(_vm)) { + case 0: + spellFailed(); + break; + case 1: + sound.playFX(51); + break; + default: + break; + } + } +} + +void Spells::timeDistortion() { + Interface &intf = *_vm->_interface; + Map &map = *_vm->_map; + Party &party = *_vm->_party; + SoundManager &sound = *_vm->_sound; + + if (map.mazeData()._mazeFlags & RESTRICTION_TIME_DISTORTION) { + spellFailed(); + } else { + party.moveToRunLocation(); + sound.playFX(51); + intf.draw3d(true); + } +} + +void Spells::townPortal() { + Map &map = *_vm->_map; + Party &party = *_vm->_party; + SoundManager &sound = *_vm->_sound; + + if (map.mazeData()._mazeFlags & RESTRICTION_TOWN_PORTAL) { + spellFailed(); + return; + } + + int townNumber = TownPortal::show(_vm); + if (!townNumber) + return; + + sound.playFX(51); + map._loadDarkSide = map._sideTownPortal; + _vm->_files->_isDarkCc = map._sideTownPortal > 0; + map.load(TOWN_MAP_NUMBERS[map._sideTownPortal][townNumber - 1]); -void Spells::townPortal() { error("TODO: spell"); } // Not while engaged + if (!_vm->_files->_isDarkCc) { + party.moveToRunLocation(); + } else { + switch (townNumber) { + case 1: + party._mazePosition = Common::Point(14, 11); + party._mazeDirection = DIR_SOUTH; + break; + case 2: + party._mazePosition = Common::Point(5, 12); + party._mazeDirection = DIR_WEST; + break; + case 3: + party._mazePosition = Common::Point(2, 15); + party._mazeDirection = DIR_EAST; + break; + case 4: + party._mazePosition = Common::Point(8, 11); + party._mazeDirection = DIR_NORTH; + break; + case 5: + party._mazePosition = Common::Point(2, 6); + party._mazeDirection = DIR_NORTH; + break; + default: + break; + } + } +} void Spells::toxicCloud() { Combat &combat = *_vm->_combat; @@ -1126,9 +1306,22 @@ void Spells::turnUndead() { combat.multiAttack(13); } -void Spells::walkOnWater() { error("TODO: spell"); } +void Spells::walkOnWater() { + Party &party = *_vm->_party; + SoundManager &sound = *_vm->_sound; + + party._walkOnWaterActive = true; + sound.playFX(20); +} + +void Spells::wizardEye() { + Party &party = *_vm->_party; + SoundManager &sound = *_vm->_sound; -void Spells::wizardEye() { error("TODO: spell"); } // Not while engaged + party._wizardEyeActive = true; + party._automapOn = false; + sound.playFX(20); +} void Spells::frostbite2() { Combat &combat = *_vm->_combat; -- cgit v1.2.3