📄 battle.cpp
字号:
/*************************************************************************** battle.cpp - description ------------------- begin : Sat May 3 2003 copyright : (C) 2003 by Gabor Torok email : cctorok@yahoo.com ***************************************************************************//*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/#include "battle.h"//#define DEBUG_BATTLE#define GOD_MODE 0#define MONSTER_IMORTALITY 0enum { NO_ACTION = 0, LOITER, ATTACK, MOVE, NO_TARGET, WAIT,};char *actionName[] = { "NO ACTION", "LOITER", "ATTACK", "MOVE", "NO_TARGET", "WAIT"};Battle::Battle() { this->creature = NULL;}Battle::Battle(Scourge *scourge, Creature *creature) { this->scourge = scourge; this->creature = creature; this->item = NULL; this->creatureInitiative = 0; this->initiativeCheck = false; this->speed = 0; this->dist = creature->getDistanceToTarget(); this->spell = NULL; this->empty = false;}Battle::~Battle() {}void Battle::setupBattles(Scourge *scourge, Battle *battle[], int count, vector<Battle *> *turns) { if(count == 0) return; bool battleStarted = false; int battleCount = count; int initiative = -10;//char message[200]; int turn = 0;#ifdef DEBUG_BATTLE cerr << "==================================================" << endl; cerr << "battleCount=" << battleCount << endl; for(int i = 0; i < battleCount; i++) { cerr << "\t(" << battle[i]->creature->getName() << "->" << (battle[i]->creature->getTargetCreature() ? battle[i]->creature->getTargetCreature()->getName() : "NULL") << ")" << endl; }#endif// this is O(n^2) unfortunately... maybe we could use a linked list or something here while(battleCount > 0) { bool creatureFound = false; for(int i = 0; i < battleCount; i++) { int action = NO_ACTION; battle[i]->empty = false; battle[i]->projectileHit = false; if(!battle[i]->creature->hasTarget()) { // remove creatures with no target creature from this round action = NO_TARGET; } else if(!battle[i]->creature->isTargetValid()) { // if someone already killed this target, skip it battle[i]->creature->cancelTarget(); if(battle[i]->creature->isMonster()) { //battle[i]->creature->setMotion(Constants::MOTION_LOITER); action = LOITER; } else { // if party member re-join the battle Creature *c = battle[i]->creature; c->setTargetCreature(scourge->getClosestVisibleMonster(c->getX(), c->getY(), c->getShape()->getWidth(), c->getShape()->getDepth(), 20)); } } else { GLint t = SDL_GetTicks(); // get the best weapon given the distance from the target battle[i]->initTurn(); // check the creature's initiative if(!battle[i]->initiativeCheck || battle[i]->creatureInitiative < initiative) { // remember that it passed (creature can attack next time if timing (below) is good) battle[i]->initiativeCheck = true; creatureFound = true; // this is to slow down battle, depending on your weapon // getLastTurn is 0 when an action is decided to be executed // this way it's two trips through this method forcing a spell (e.g.) // to use the clock. bool initialActionTurn = (battle[i]->creature->getLastTurn() == 0);#ifdef DEBUG_BATTLE cerr << "speed=" << battle[i]->speed << " last=" << battle[i]->creature->getLastTurn() << " diff=" << (t - battle[i]->creature->getLastTurn()) << endl;#endif if(initialActionTurn || battle[i]->speed < t - battle[i]->creature->getLastTurn()) { // remember the last active turn battle[i]->creature->setLastTurn(t); if(!battleStarted) { scourge->getMap()->addDescription("A round of battle begins...", 1, 1, 1); battleStarted = true; } if(initialActionTurn) { // add a waiting term battle[i]->empty = true; action = WAIT; turns->push_back(battle[i]); } else { // save this turn turns->push_back(battle[i]); action = ATTACK; } } else { // add a waiting term battle[i]->empty = true; action = WAIT; turns->push_back(battle[i]); } } } if(action != NO_ACTION) {#ifdef DEBUG_BATTLE cerr << "Turn: " << turn << " " << actionName[action] << ", " << battle[i]->creature->getName() << "(" << battle[i]->creatureInitiative << ")" << "->" << (battle[i]->creature->getTargetCreature() ? battle[i]->creature->getTargetCreature()->getName() : "<no target>") << endl;#endif // remove this battle from the turn Battle *tmp = battle[i]; for(int t = i; t < battleCount - 1; t++) { battle[t] = battle[t + 1]; } // move current one to the end of the list so we don't loose it battle[battleCount - 1] = tmp; battleCount--; i--; turn++; } } // if there are no creatures for this initiative slot, go to the next one if(!creatureFound) initiative++; }} void Battle::fightTurn() { // waiting to cast a spell? if(creature->getAction() == Constants::ACTION_CAST_SPELL) { creature->startEffect(Constants::EFFECT_CAST_SPELL, Constants::DAMAGE_DURATION * 4); } // waiting to attack? if(isEmpty()) return; // target killed? if(!creature->hasTarget()) return; // if there was no 'item' selected it's because we're too far from the target // (getBestWeapon returned NULL) and we're not casting a spell, follow the target // // If it's an empty-handed attack, follow the target // // If it's a ranged attack and we're not in range, follow the target (will move away from target) // // This sure is confusing code... /* cerr << "projectileHit=" << projectileHit << " dist=" << dist << " creature->isInRange()=" << creature->isInRange() << " item=" << item << " creature->getActionSpell()=" << creature->getActionSpell() << " spell=" << spell << endl; */ if(!projectileHit && ((dist > Constants::MIN_DISTANCE && !item && !creature->getActionSpell() && !spell) || !creature->isInRange())) { //cerr << "\tfollowing..." << endl; creature->followTarget(); return; } //cerr << "\tcontinuing" << endl; // handle action: eat/drink items if(creature->getAction() == Constants::ACTION_EAT_DRINK) { executeEatDrinkAction(); return; } // the attacked target may get upset creature->decideMonsterAction(); // handle the action if(!projectileHit && item && item->getRpgItem()->isRangedWeapon()) { launchProjectile(); } else if(spell) { // a spell projectile hit SpellCaster *sc = new SpellCaster(this, spell, true); sc->spellSucceeded(); delete sc; } else if(creature->getActionSpell()) { // casting a spell for the first time castSpell(); } else { hitWithItem(); }}void Battle::castSpell() { // use up some MP (not when using a scroll) if(!creature->getActionItem()) { int n = creature->getMp() - creature->getActionSpell()->getMp(); if(n < 0) n = 0; creature->setMp( n ); } else { // try to destroy the scroll int itemIndex = creature->findInInventory(creature->getActionItem()); if(itemIndex > -1) { creature->removeInventory(itemIndex); sprintf(message, "%s crumbles into dust.", creature->getActionItem()->getItemName());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -