/** * Loads the saved battle game from a YAML file. * @param node YAML node. */ void SavedBattleGame::load(const YAML::Node &node, Ruleset *rule, SavedGame* savedGame) { int a; int selectedUnit = 0; node["width"] >> _width; node["length"] >> _length; node["height"] >> _height; node["missionType"] >> _missionType; node["globalshade"] >> _globalShade; node["turn"] >> _turn; node["selectedUnit"] >> selectedUnit; for (YAML::Iterator i = node["mapdatasets"].begin(); i != node["mapdatasets"].end(); ++i) { std::string name; *i >> name; MapDataSet *mds = new MapDataSet(name); _mapDataSets.push_back(mds); } initMap(_width, _length, _height); for (YAML::Iterator i = node["tiles"].begin(); i != node["tiles"].end(); ++i) { Position pos; (*i)["position"][0] >> pos.x; (*i)["position"][1] >> pos.y; (*i)["position"][2] >> pos.z; getTile(pos)->load((*i)); } for (YAML::Iterator i = node["nodes"].begin(); i != node["nodes"].end(); ++i) { Node *n = new Node(); n->load(*i); _nodes.push_back(n); } for (YAML::Iterator i = node["units"].begin(); i != node["units"].end(); ++i) { UnitFaction faction; (*i)["faction"] >> a; faction = (UnitFaction)a; (*i)["soldierId"] >> a; BattleUnit *b; if (a < BattleUnit::MAX_SOLDIER_ID) // Unit is linked to a geoscape soldier { // look up the matching soldier b = new BattleUnit(savedGame->getSoldier(a), faction); } else { std::string type, armor; (*i)["genUnitType"] >> type; (*i)["genUnitArmor"] >> armor; // create a new Unit. b = new BattleUnit(rule->getUnit(type), faction, a, rule->getArmor(armor)); } b->load(*i); _units.push_back(b); if (faction == FACTION_PLAYER) { if (b->getId() == selectedUnit) _selectedUnit = b; } else if (b->getStatus() != STATUS_DEAD) { std::string state; BattleAIState *aiState; (*i)["AI"]["state"] >> state; if (state == "PATROL") { aiState = new PatrolBAIState(this, b, 0); } else if (state == "AGGRO") { aiState = new AggroBAIState(this, b); } else { continue; } aiState->load((*i)["AI"]); b->setAIState(aiState); } }
/** * Animates the projectile (move to the next point in it's trajectory). * If the animation is finished the projectile sprite is removed from the map. * And this state is finished. */ void ProjectileFlyBState::think() { /* TODO refactoring : store the projectile in this state, instead of getting it from the map each time? */ if (_parent->getMap()->getProjectile() == 0) { if (_action.type == BA_AUTOSHOT && _action.autoShotCounter < 3 && !_action.actor->isOut() && _ammo->getAmmoQuantity() != 0) { createNewProjectile(); } else { if (_action.cameraPosition.z != -1) { _parent->getMap()->getCamera()->setMapOffset(_action.cameraPosition); } if (_action.type != BA_PANIC && _action.type != BA_MINDCONTROL) { _parent->getTileEngine()->checkReactionFire(_unit); } _unit->abortTurn(); _parent->popState(); } } else { if(!_parent->getMap()->getProjectile()->move()) { // impact ! if (_action.type == BA_THROW) { Position pos = _parent->getMap()->getProjectile()->getPosition(-1); pos.x /= 16; pos.y /= 16; pos.z /= 24; BattleItem *item = _parent->getMap()->getProjectile()->getItem(); _parent->getResourcePack()->getSound("BATTLE.CAT", 38)->play(); if (Options::getBool("battleInstantGrenade") && item->getRules()->getBattleType() == BT_GRENADE && item->getExplodeTurn() != 0 && item->getExplodeTurn() <= _parent->getSave()->getTurn()) { // it's a hot grenade to explode immediately _parent->statePushFront(new ExplosionBState(_parent, _parent->getMap()->getProjectile()->getPosition(-1), item, _action.actor)); } else { _parent->dropItem(pos, item); } } else if (_action.type == BA_LAUNCH && _action.waypoints.size() > 1 && _projectileImpact == -1) { _origin = _action.waypoints.front(); _action.waypoints.pop_front(); _action.target = _action.waypoints.front(); // launch the next projectile in the waypoint cascade _parent->statePushBack(new ProjectileFlyBState(_parent, _action, _origin)); } else { if (_ammo && _action.type == BA_LAUNCH && _ammo->spendBullet() == false) { _parent->getSave()->removeItem(_ammo); _action.weapon->setAmmoItem(0); } if (_projectileImpact != 5) // out of map { int offset = 0; // explosions impact not inside the voxel but two steps back (projectiles generally move 2 voxels at a time) if (_ammo && ( _ammo->getRules()->getDamageType() == DT_HE || _ammo->getRules()->getDamageType() == DT_IN)) { offset = -2; } _parent->statePushFront(new ExplosionBState(_parent, _parent->getMap()->getProjectile()->getPosition(offset), _ammo, _action.actor, 0, (_action.type != BA_AUTOSHOT || _action.autoShotCounter == 3|| !_action.weapon->getAmmoItem()))); if (_projectileImpact == 4) { BattleUnit *victim = _parent->getSave()->getTile(_parent->getMap()->getProjectile()->getPosition(offset) / Position(16,16,24))->getUnit(); if (victim && !victim->isOut() && victim->getFaction() == FACTION_HOSTILE) { AggroBAIState *aggro = dynamic_cast<AggroBAIState*>(victim->getCurrentAIState()); if (aggro == 0) { aggro = new AggroBAIState(_parent->getSave(), victim); victim->setAIState(aggro); } aggro->setAggroTarget(_action.actor); } } } else if (_action.type != BA_AUTOSHOT || _action.autoShotCounter == 3 || !_action.weapon->getAmmoItem()) { _unit->aim(false); _parent->getMap()->cacheUnits(); } } delete _parent->getMap()->getProjectile(); _parent->getMap()->setProjectile(0); } } }
/** * Loads the saved battle game from a YAML file. * @param node YAML node. */ void SavedBattleGame::load(const YAML::Node &node, Ruleset *rule, SavedGame* savedGame) { int a; int selectedUnit = 0; node["width"] >> _width; node["length"] >> _length; node["height"] >> _height; node["globalshade"] >> _globalShade; node["selectedUnit"] >> selectedUnit; for (YAML::Iterator i = node["mapdatasets"].begin(); i != node["mapdatasets"].end(); ++i) { std::string name; *i >> name; MapDataSet *mds = new MapDataSet(name); _mapDataSets.push_back(mds); } initMap(_width, _length, _height); for (YAML::Iterator i = node["tiles"].begin(); i != node["tiles"].end(); ++i) { Position pos; (*i)["position"][0] >> pos.x; (*i)["position"][1] >> pos.y; (*i)["position"][2] >> pos.z; getTile(pos)->load((*i)); } for (YAML::Iterator i = node["nodes"].begin(); i != node["nodes"].end(); ++i) { Node *n = new Node(); n->load(*i); _nodes.push_back(n); } for (YAML::Iterator i = node["units"].begin(); i != node["units"].end(); ++i) { UnitFaction faction; (*i)["faction"] >> a; faction = (UnitFaction)a; (*i)["soldierId"] >> a; Unit *unit; if (a != -1) // Unit is linked to a geoscape soldier { // look up the matching soldier unit = savedGame->getSoldier(a); } else { // create a new Unit. unit = new GenUnit(rule->getGenUnit("SECTOID_SOLDIER"), rule->getArmor("SECTOID_ARMOR0")); } BattleUnit *b = new BattleUnit(unit, faction); b->load(*i); _units.push_back(b); if (faction == FACTION_PLAYER) { if (b->getId() == selectedUnit) _selectedUnit = b; } else { std::string state; BattleAIState *aiState; (*i)["AI"]["state"] >> state; if (state == "PATROL") { aiState = new PatrolBAIState(this, b, 0); } else if (state == "AGGRO") { aiState = new AggroBAIState(this, b); } else { continue; } aiState->load((*i)["AI"]); b->setAIState(aiState); } } // matches up tiles and units resetUnitTiles(); for (YAML::Iterator i = node["items"].begin(); i != node["items"].end(); ++i) { std::string type; (*i)["type"] >> type; if (type != "0") { BattleItem *item = new BattleItem(rule->getItem(type), &_itemId); item->load(*i); (*i)["inventoryslot"] >> type; if (type != "NULL") item->setSlot(rule->getInventory(type)); (*i)["owner"] >> a; // match up items and units for (std::vector<BattleUnit*>::iterator bu = _units.begin(); bu != _units.end(); ++bu) { if ((*bu)->getId() == a) { item->moveToOwner(*bu); break; } } // match up items and tiles if (item->getSlot() && item->getSlot()->getType() == INV_GROUND) { Position pos; (*i)["position"][0] >> pos.x; (*i)["position"][1] >> pos.y; (*i)["position"][2] >> pos.z; if (pos.x != -1) getTile(pos)->addItem(item); } _items.push_back(item); }