/** ** Send command: Defend some unit. ** ** @param unit pointer to unit. ** @param dest defend this unit. ** @param flush Flag flush all pending commands. */ void SendCommandDefend(CUnit &unit, CUnit &dest, int flush) { if (!IsNetworkGame()) { CommandLog("defend", &unit, flush, -1, -1, &dest, NULL, -1); CommandDefend(unit, dest, flush); } else { NetworkSendCommand(MessageCommandDefend, unit, 0, 0, &dest, 0, flush); } }
/* virtual */ void CAnimation_SpawnUnit::Action(CUnit &unit, int &/*move*/, int /*scale*/) const { Assert(unit.Anim.Anim == this); const int offX = ParseAnimInt(unit, this->offXStr.c_str()); const int offY = ParseAnimInt(unit, this->offYStr.c_str()); const int range = ParseAnimInt(unit, this->rangeStr.c_str()); const int playerId = ParseAnimInt(unit, this->playerStr.c_str()); const SpawnUnit_Flags flags = (SpawnUnit_Flags)(ParseAnimFlags(unit, this->flagsStr.c_str())); CPlayer &player = Players[playerId]; const Vec2i pos(unit.tilePos.x + offX, unit.tilePos.y + offY); CUnitType *type = UnitTypeByIdent(this->unitTypeStr.c_str()); Assert(type); Vec2i resPos; DebugPrint("Creating a %s\n" _C_ type->Name.c_str()); FindNearestDrop(*type, pos, resPos, LookingW); if (SquareDistance(pos, resPos) <= square(range)) { CUnit *target = MakeUnit(*type, &player); if (target != NULL) { target->tilePos = resPos; target->Place(resPos); if (flags & SU_Summoned) { target->Summoned = 1; } if ((flags & SU_JoinToAIForce) && unit.Player->AiEnabled) { int force = unit.Player->Ai->Force.GetForce(unit); if (force != -1) { unit.Player->Ai->Force[force].Insert(*target); target->GroupId = unit.GroupId; CommandDefend(*target, unit, FlushCommands); } } //DropOutOnSide(*target, LookingW, NULL); } else { DebugPrint("Unable to allocate Unit"); } } }
/** ** Execute a command (from network). ** ** @param msgnr Network message type ** @param unum Unit number (slot) that receive the command. ** @param x optional X map position. ** @param y optional y map position. ** @param dstnr optional destination unit. */ void ExecCommand(unsigned char msgnr, UnitRef unum, unsigned short x, unsigned short y, UnitRef dstnr) { CUnit &unit = UnitManager.GetSlotUnit(unum); const Vec2i pos(x, y); const int arg1 = x; const int arg2 = y; // // Check if unit is already killed? // if (unit.Destroyed) { DebugPrint(" destroyed unit skipping %d\n" _C_ UnitNumber(unit)); return; } Assert(unit.Type); const int status = (msgnr & 0x80) >> 7; // Note: destroyed destination unit is handled by the action routines. switch (msgnr & 0x7F) { case MessageSync: return; case MessageQuit: return; case MessageChat: return; case MessageCommandStop: CommandLog("stop", &unit, FlushCommands, -1, -1, NoUnitP, NULL, -1); CommandStopUnit(unit); break; case MessageCommandStand: CommandLog("stand-ground", &unit, status, -1, -1, NoUnitP, NULL, -1); CommandStandGround(unit, status); break; case MessageCommandDefend: { if (dstnr != (unsigned short)0xFFFF) { CUnit &dest = UnitManager.GetSlotUnit(dstnr); Assert(dest.Type); CommandLog("defend", &unit, status, -1, -1, &dest, NULL, -1); CommandDefend(unit, dest, status); } break; } case MessageCommandFollow: { if (dstnr != (unsigned short)0xFFFF) { CUnit &dest = UnitManager.GetSlotUnit(dstnr); Assert(dest.Type); CommandLog("follow", &unit, status, -1, -1, &dest, NULL, -1); CommandFollow(unit, dest, status); } break; } case MessageCommandMove: //Wyrmgus start // CommandLog("move", &unit, status, pos.x, pos.y, NoUnitP, NULL, -1); // CommandMove(unit, pos, status); if (!unit.CanMove()) { //FIXME: find better way to identify whether the unit should move or set a rally point CommandLog("rally-point", &unit, status, pos.x, pos.y, NoUnitP, NULL, -1); CommandRallyPoint(unit, pos); } else { CommandLog("move", &unit, status, pos.x, pos.y, NoUnitP, NULL, -1); CommandMove(unit, pos, status); } //Wyrmgus end break; //Wyrmgus start case MessageCommandPickUp: { if (dstnr != (unsigned short)0xFFFF) { CUnit &dest = UnitManager.GetSlotUnit(dstnr); Assert(dest.Type); CommandLog("pick-up", &unit, status, -1, -1, &dest, NULL, -1); CommandPickUp(unit, dest, status); } break; } //Wyrmgus end case MessageCommandRepair: { CUnit *dest = NoUnitP; if (dstnr != (unsigned short)0xFFFF) { dest = &UnitManager.GetSlotUnit(dstnr); Assert(dest && dest->Type); } CommandLog("repair", &unit, status, pos.x, pos.y, dest, NULL, -1); CommandRepair(unit, pos, dest, status); break; } case MessageCommandAutoRepair: CommandLog("auto-repair", &unit, status, arg1, arg2, NoUnitP, NULL, 0); CommandAutoRepair(unit, arg1); break; case MessageCommandAttack: { CUnit *dest = NoUnitP; if (dstnr != (unsigned short)0xFFFF) { dest = &UnitManager.GetSlotUnit(dstnr); Assert(dest && dest->Type); } CommandLog("attack", &unit, status, pos.x, pos.y, dest, NULL, -1); CommandAttack(unit, pos, dest, status); break; } case MessageCommandGround: CommandLog("attack-ground", &unit, status, pos.x, pos.y, NoUnitP, NULL, -1); CommandAttackGround(unit, pos, status); break; //Wyrmgus start case MessageCommandUse: { if (dstnr != (unsigned short)0xFFFF) { CUnit &dest = UnitManager.GetSlotUnit(dstnr); Assert(dest.Type); CommandLog("use", &unit, status, -1, -1, &dest, NULL, -1); CommandUse(unit, dest, status); } break; } //Wyrmgus end case MessageCommandPatrol: CommandLog("patrol", &unit, status, pos.x, pos.y, NoUnitP, NULL, -1); CommandPatrolUnit(unit, pos, status); break; case MessageCommandBoard: { if (dstnr != (unsigned short)0xFFFF) { CUnit &dest = UnitManager.GetSlotUnit(dstnr); Assert(dest.Type); CommandLog("board", &unit, status, arg1, arg2, &dest, NULL, -1); CommandBoard(unit, dest, status); } break; } case MessageCommandUnload: { CUnit *dest = NULL; if (dstnr != (unsigned short)0xFFFF) { dest = &UnitManager.GetSlotUnit(dstnr); Assert(dest && dest->Type); } CommandLog("unload", &unit, status, pos.x, pos.y, dest, NULL, -1); CommandUnload(unit, pos, dest, status); break; } case MessageCommandBuild: CommandLog("build", &unit, status, pos.x, pos.y, NoUnitP, UnitTypes[dstnr]->Ident.c_str(), -1); CommandBuildBuilding(unit, pos, *UnitTypes[dstnr], status); break; case MessageCommandDismiss: CommandLog("dismiss", &unit, FlushCommands, -1, -1, NULL, NULL, -1); CommandDismiss(unit); break; case MessageCommandResourceLoc: CommandLog("resource-loc", &unit, status, pos.x, pos.y, NoUnitP, NULL, -1); CommandResourceLoc(unit, pos, status); break; case MessageCommandResource: { if (dstnr != (unsigned short)0xFFFF) { CUnit &dest = UnitManager.GetSlotUnit(dstnr); Assert(dest.Type); CommandLog("resource", &unit, status, -1, -1, &dest, NULL, -1); CommandResource(unit, dest, status); } break; } case MessageCommandReturn: { CUnit *dest = (dstnr != (unsigned short)0xFFFF) ? &UnitManager.GetSlotUnit(dstnr) : NULL; CommandLog("return", &unit, status, -1, -1, dest, NULL, -1); CommandReturnGoods(unit, dest, status); break; } case MessageCommandTrain: //Wyrmgus start // CommandLog("train", &unit, status, -1, -1, NoUnitP, UnitTypes[dstnr]->Ident.c_str(), -1); // CommandTrainUnit(unit, *UnitTypes[dstnr], status); CommandLog("train", &unit, status, -1, -1, NoUnitP, UnitTypes[dstnr]->Ident.c_str(), arg1); // use X as a way to mark the player CommandTrainUnit(unit, *UnitTypes[dstnr], arg1, status); //Wyrmgus end break; case MessageCommandCancelTrain: // We need (short)x for the last slot -1 if (dstnr != (unsigned short)0xFFFF) { CommandLog("cancel-train", &unit, FlushCommands, -1, -1, NoUnitP, UnitTypes[dstnr]->Ident.c_str(), (short)x); CommandCancelTraining(unit, (short)x, UnitTypes[dstnr]); } else { CommandLog("cancel-train", &unit, FlushCommands, -1, -1, NoUnitP, NULL, (short)x); CommandCancelTraining(unit, (short)x, NULL); } break; case MessageCommandUpgrade: //Wyrmgus start /* CommandLog("upgrade-to", &unit, status, -1, -1, NoUnitP, UnitTypes[dstnr]->Ident.c_str(), -1); CommandUpgradeTo(unit, *UnitTypes[dstnr], status); break; */ if (arg1 == 2) { //use X as a way to mark whether this is an upgrade or a transformation CommandLog("transform-into", &unit, status, -1, -1, NoUnitP, UnitTypes[dstnr]->Ident.c_str(), -1); CommandTransformIntoType(unit, *UnitTypes[dstnr]); } else { CommandLog("upgrade-to", &unit, status, -1, -1, NoUnitP, UnitTypes[dstnr]->Ident.c_str(), -1); CommandUpgradeTo(unit, *UnitTypes[dstnr], status); } break; //Wyrmgus end case MessageCommandCancelUpgrade: CommandLog("cancel-upgrade-to", &unit, FlushCommands, -1, -1, NoUnitP, NULL, -1); CommandCancelUpgradeTo(unit); break; case MessageCommandResearch: CommandLog("research", &unit, status, -1, -1, NoUnitP, AllUpgrades[arg1]->Ident.c_str(), -1); CommandResearch(unit, *AllUpgrades[arg1], status); break; case MessageCommandCancelResearch: CommandLog("cancel-research", &unit, FlushCommands, -1, -1, NoUnitP, NULL, -1); CommandCancelResearch(unit); break; //Wyrmgus start case MessageCommandQuest: { CommandLog("quest", &unit, 0, 0, 0, NoUnitP, Quests[arg1]->Ident.c_str(), -1); CommandQuest(unit, Quests[arg1]); break; } case MessageCommandBuy: { if (dstnr != (unsigned short)0xFFFF) { CUnit &dest = UnitManager.GetSlotUnit(dstnr); Assert(dest.Type); CommandLog("buy", &unit, 0, -1, -1, &dest, NULL, arg1); CommandBuy(unit, &dest, arg1); } break; } //Wyrmgus end default: { int id = (msgnr & 0x7f) - MessageCommandSpellCast; if (arg2 != (unsigned short)0xFFFF) { CUnit *dest = NULL; if (dstnr != (unsigned short)0xFFFF) { dest = &UnitManager.GetSlotUnit(dstnr); Assert(dest && dest->Type); } CommandLog("spell-cast", &unit, status, pos.x, pos.y, dest, NULL, id); CommandSpellCast(unit, pos, dest, *SpellTypeTable[id], status); } else { CommandLog("auto-spell-cast", &unit, status, arg1, -1, NoUnitP, NULL, id); CommandAutoSpellCast(unit, id, arg1); } break; } } }
//Wyrmgus start ///* virtual */ int Spell_Summon::Cast(CUnit &caster, const SpellType &spell, CUnit *target, const Vec2i &goalPos) /* virtual */ int Spell_Summon::Cast(CUnit &caster, const SpellType &spell, CUnit *target, const Vec2i &goalPos, int z) //Wyrmgus end { Vec2i pos = goalPos; bool cansummon; CUnitType &unittype = *this->UnitType; int ttl = this->TTL; if (this->RequireCorpse) { const Vec2i offset(1, 1); const Vec2i minPos = pos - offset; const Vec2i maxPos = pos + offset; //Wyrmgus start // CUnit *unit = FindUnit_If(minPos, maxPos, IsDyingAndNotABuilding()); CUnit *unit = FindUnit_If(minPos, maxPos, z, IsDyingAndNotABuilding()); //Wyrmgus end cansummon = false; if (unit != NULL) { // Found a corpse. eliminate it and proceed to summoning. pos = unit->tilePos; //Wyrmgus start z = unit->MapLayer; //Wyrmgus end unit->Remove(NULL); unit->Release(); cansummon = true; } } else { cansummon = true; } if (cansummon) { //Wyrmgus start // DebugPrint("Summoning a %s\n" _C_ unittype.Name.c_str()); DebugPrint("Summoning a %s\n" _C_ unittype.GetDefaultName(*caster.Player).c_str()); //Wyrmgus end // // Create units. // FIXME: do summoned units count on food? // target = MakeUnit(unittype, caster.Player); if (target != NULL) { target->tilePos = pos; //Wyrmgus start target->MapLayer = z; //Wyrmgus end DropOutOnSide(*target, LookingW, NULL); // To avoid defending summoned unit for AI target->Summoned = 1; // // set life span. ttl=0 results in a permanent unit. // if (ttl) { target->TTL = GameCycle + ttl; } // Insert summoned unit to AI force so it will help them in battle if (this->JoinToAiForce && caster.Player->AiEnabled) { int force = caster.Player->Ai->Force.GetForce(caster); if (force != -1) { caster.Player->Ai->Force[force].Insert(*target); target->GroupId = caster.GroupId; CommandDefend(*target, caster, FlushCommands); } } caster.Variable[MANA_INDEX].Value -= spell.ManaCost; } else { DebugPrint("Unable to allocate Unit"); } return 1; } return 0; }
/** ** Force on attack ride. We attack until there is no unit or enemy left. ** ** @param force Force pointer. */ void AiForce::Update() { Assert(Defending == false); if (Size() == 0) { Attacking = false; if (!Defending && State > AiForceAttackingState_Waiting) { DebugPrint("%d: Attack force #%lu was destroyed, giving up\n" _C_ AiPlayer->Player->Index _C_(long unsigned int)(this - & (AiPlayer->Force[0]))); Reset(true); } return; } Attacking = false; for (unsigned int i = 0; i < Size(); ++i) { CUnit *aiunit = Units[i]; if (aiunit->Type->CanAttack) { Attacking = true; break; } } if (Attacking == false) { if (!Defending && State > AiForceAttackingState_Waiting) { DebugPrint("%d: Attack force #%lu has lost all agresive units, giving up\n" _C_ AiPlayer->Player->Index _C_(long unsigned int)(this - & (AiPlayer->Force[0]))); Reset(true); } return ; } #if 0 if (State == AiForceAttackingState_Waiting) { if (!this->PlanAttack()) { DebugPrint("Can't transport, look for walls\n"); if (!AiFindWall(this)) { Attacking = false; return ; } } State = AiForceAttackingState_Boarding; } #endif if (State == AiForceAttackingState_Boarding) { AiGroupAttackerForTransport(*this); return ; } if (State == AiForceAttackingState_AttackingWithTransporter) { // Move transporters to goalpos std::vector<CUnit *> transporters; bool emptyTrans = true; for (unsigned int i = 0; i != Size(); ++i) { CUnit &aiunit = *Units[i]; if (aiunit.CanMove() && aiunit.Type->MaxOnBoard) { transporters.push_back(&aiunit); if (aiunit.BoardCount > 0) { emptyTrans = false; } } } if (transporters.empty()) { // Our transporters have been destroyed DebugPrint("%d: Attack force #%lu has lost all agresive units, giving up\n" _C_ AiPlayer->Player->Index _C_(long unsigned int)(this - & (AiPlayer->Force[0]))); Reset(true); } else if (emptyTrans) { // We have emptied our transporters, go go go State = AiForceAttackingState_GoingToRallyPoint; } else { for (size_t i = 0; i != transporters.size(); ++i) { CUnit &trans = *transporters[i]; const int delay = i / 5; // To avoid lot of CPU consuption, send them with a small time difference. trans.Wait = delay; CommandUnload(trans, this->GoalPos, NULL, FlushCommands); } } return; } CUnit *leader = NULL; for (unsigned int i = 0; i != Size(); ++i) { CUnit &aiunit = *Units[i]; if (aiunit.IsAgressive()) { leader = &aiunit; break; } } const int thresholdDist = 5; // Hard coded value Assert(Map.Info.IsPointOnMap(GoalPos)); if (State == AiForceAttackingState_GoingToRallyPoint) { // Check if we are near the goalpos int minDist = Units[0]->MapDistanceTo(this->GoalPos); int maxDist = minDist; for (size_t i = 0; i != Size(); ++i) { const int distance = Units[i]->MapDistanceTo(this->GoalPos); minDist = std::min(minDist, distance); maxDist = std::max(maxDist, distance); } if (WaitOnRallyPoint > 0 && minDist <= thresholdDist) { --WaitOnRallyPoint; } if (maxDist <= thresholdDist || !WaitOnRallyPoint) { const CUnit *unit = NULL; AiForceEnemyFinder<AIATTACK_BUILDING>(*this, &unit); if (!unit) { AiForceEnemyFinder<AIATTACK_ALLMAP>(*this, &unit); if (!unit) { // No enemy found, give up // FIXME: should the force go home or keep trying to attack? DebugPrint("%d: Attack force #%lu can't find a target, giving up\n" _C_ AiPlayer->Player->Index _C_(long unsigned int)(this - & (AiPlayer->Force[0]))); Attacking = false; State = AiForceAttackingState_Waiting; return; } } this->GoalPos = unit->tilePos; State = AiForceAttackingState_Attacking; for (size_t i = 0; i != this->Size(); ++i) { CUnit &aiunit = *this->Units[i]; const int delay = i / 5; // To avoid lot of CPU consuption, send them with a small time difference. aiunit.Wait = delay; if (aiunit.IsAgressive()) { CommandAttack(aiunit, this->GoalPos, NULL, FlushCommands); } else { if (leader) { CommandDefend(aiunit, *leader, FlushCommands); } else { CommandMove(aiunit, this->GoalPos, FlushCommands); } } } } } std::vector<CUnit *> idleUnits; for (unsigned int i = 0; i != Size(); ++i) { CUnit &aiunit = *Units[i]; if (aiunit.IsIdle()) { idleUnits.push_back(&aiunit); } } if (idleUnits.empty()) { return; } if (State == AiForceAttackingState_Attacking && idleUnits.size() == this->Size()) { const CUnit *unit = NULL; bool isNaval = false; for (size_t i = 0; i != this->Units.size(); ++i) { CUnit *const unit = this->Units[i]; if (unit->Type->UnitType == UnitTypeNaval && unit->Type->CanAttack) { isNaval = true; break; } } if (isNaval) { AiForceEnemyFinder<AIATTACK_ALLMAP>(*this, &unit); } else { AiForceEnemyFinder<AIATTACK_BUILDING>(*this, &unit); } if (!unit) { // No enemy found, give up // FIXME: should the force go home or keep trying to attack? DebugPrint("%d: Attack force #%lu can't find a target, giving up\n" _C_ AiPlayer->Player->Index _C_(long unsigned int)(this - & (AiPlayer->Force[0]))); Attacking = false; State = AiForceAttackingState_Waiting; return; } else { Vec2i resultPos; NewRallyPoint(unit->tilePos, &resultPos); this->GoalPos = resultPos; this->State = AiForceAttackingState_GoingToRallyPoint; } } for (size_t i = 0; i != idleUnits.size(); ++i) { CUnit &aiunit = *idleUnits[i]; const int delay = i / 5; // To avoid lot of CPU consuption, send them with a small time difference. aiunit.Wait = delay; if (leader) { if (aiunit.IsAgressive()) { if (State == AiForceAttackingState_Attacking) { CommandAttack(aiunit, leader->tilePos, NULL, FlushCommands); } else { CommandAttack(aiunit, this->GoalPos, NULL, FlushCommands); } } else { CommandDefend(aiunit, *leader, FlushCommands); } } else { if (aiunit.IsAgressive()) { CommandAttack(aiunit, this->GoalPos, NULL, FlushCommands); } else { CommandMove(aiunit, this->GoalPos, FlushCommands); } } } }
void AiForce::Attack(const Vec2i &pos) { bool isDefenceForce = false; RemoveDeadUnit(); if (Units.size() == 0) { this->Attacking = false; this->State = AiForceAttackingState_Waiting; return; } if (!this->Attacking) { // Remember the original force position so we can return there after attack if (this->Role == AiForceRoleDefend || (this->Role == AiForceRoleAttack && this->State == AiForceAttackingState_Waiting)) { this->HomePos = this->Units[this->Units.size() - 1]->tilePos; } this->Attacking = true; } Vec2i goalPos(pos); bool isNaval = false; for (size_t i = 0; i != this->Units.size(); ++i) { CUnit *const unit = this->Units[i]; if (unit->Type->UnitType == UnitTypeNaval && unit->Type->CanAttack) { isNaval = true; break; } } bool isTransporter = false; for (size_t i = 0; i != this->Units.size(); ++i) { CUnit *const unit = this->Units[i]; if (unit->Type->CanTransport() && unit->IsAgressive() == false) { isTransporter = true; break; } } if (Map.Info.IsPointOnMap(goalPos) == false) { /* Search in entire map */ const CUnit *enemy = NULL; if (isTransporter) { AiForceEnemyFinder<AIATTACK_AGRESSIVE>(*this, &enemy); } else if (isNaval) { AiForceEnemyFinder<AIATTACK_ALLMAP>(*this, &enemy); } else { AiForceEnemyFinder<AIATTACK_BUILDING>(*this, &enemy); } if (enemy) { goalPos = enemy->tilePos; } } else { isDefenceForce = true; } if (Map.Info.IsPointOnMap(goalPos) == false || isTransporter) { DebugPrint("%d: Need to plan an attack with transporter\n" _C_ AiPlayer->Player->Index); if (State == AiForceAttackingState_Waiting && !PlanAttack()) { DebugPrint("%d: Can't transport\n" _C_ AiPlayer->Player->Index); Attacking = false; } return; } if (this->State == AiForceAttackingState_Waiting && isDefenceForce == false) { Vec2i resultPos; NewRallyPoint(goalPos, &resultPos); this->GoalPos = resultPos; this->State = AiForceAttackingState_GoingToRallyPoint; } else { this->GoalPos = goalPos; this->State = AiForceAttackingState_Attacking; } // Send all units in the force to enemy. CUnit *leader = NULL; for (size_t i = 0; i != this->Units.size(); ++i) { CUnit *const unit = this->Units[i]; if (unit->IsAgressive()) { leader = unit; break; } } for (size_t i = 0; i != this->Units.size(); ++i) { CUnit *const unit = this->Units[i]; if (unit->Container == NULL) { const int delay = i / 5; // To avoid lot of CPU consuption, send them with a small time difference. unit->Wait = delay; if (unit->IsAgressive()) { CommandAttack(*unit, this->GoalPos, NULL, FlushCommands); } else { if (leader) { CommandDefend(*unit, *leader, FlushCommands); } else { CommandMove(*unit, this->GoalPos, FlushCommands); } } } } }
/** ** Cast capture. ** ** @param caster Unit that casts the spell ** @param spell Spell-type pointer ** @param target Target unit that spell is addressed to ** @param goalPos coord of target spot when/if target does not exist ** ** @return =!0 if spell should be repeated, 0 if not */ /* virtual */ int Spell_Capture::Cast(CUnit &caster, const SpellType &spell, CUnit *target, const Vec2i &/*goalPos*/) { if (!target || caster.Player == target->Player) { return 0; } if (this->DamagePercent) { if ((100 * target->Variable[HP_INDEX].Value) / target->Variable[HP_INDEX].Max > this->DamagePercent && target->Variable[HP_INDEX].Value > this->Damage) { HitUnit(&caster, *target, this->Damage); if (this->SacrificeEnable) { // No corpse. caster.Remove(NULL); caster.Release(); } return 1; } } caster.Player->Score += target->Variable[POINTS_INDEX].Value; if (caster.IsEnemy(*target)) { if (target->Type->Building) { caster.Player->TotalRazings++; } else { caster.Player->TotalKills++; } //Wyrmgus start caster.Player->UnitTypeKills[target->Type->Slot]++; /* if (UseHPForXp) { caster.Variable[XP_INDEX].Max += target->Variable[HP_INDEX].Value; } else { caster.Variable[XP_INDEX].Max += target->Variable[POINTS_INDEX].Value; } caster.Variable[XP_INDEX].Value = caster.Variable[XP_INDEX].Max; */ //distribute experience between nearby units belonging to the same player if (!target->Type->BoolFlag[BUILDING_INDEX].value) { std::vector<CUnit *> table; SelectAroundUnit(caster, 6, table, MakeAndPredicate(HasSamePlayerAs(*caster.Player), IsNotBuildingType())); if (UseHPForXp) { caster.Variable[XP_INDEX].Max += target->Variable[HP_INDEX].Value / (table.size() + 1); } else { caster.Variable[XP_INDEX].Max += target->Variable[POINTS_INDEX].Value / (table.size() + 1); } caster.Variable[XP_INDEX].Value = caster.Variable[XP_INDEX].Max; caster.XPChanged(); for (size_t i = 0; i != table.size(); ++i) { if (UseHPForXp) { table[i]->Variable[XP_INDEX].Max += target->Variable[HP_INDEX].Value / (table.size() + 1); } else { table[i]->Variable[XP_INDEX].Max += target->Variable[POINTS_INDEX].Value / (table.size() + 1); } table[i]->Variable[XP_INDEX].Value = table[i]->Variable[XP_INDEX].Max; table[i]->XPChanged(); } } //Wyrmgus end caster.Variable[KILL_INDEX].Value++; caster.Variable[KILL_INDEX].Max++; caster.Variable[KILL_INDEX].Enable = 1; } target->ChangeOwner(*caster.Player); UnitClearOrders(*target); if (this->JoinToAIForce && caster.Player->AiEnabled) { int force = caster.Player->Ai->Force.GetForce(caster); if (force != -1) { caster.Player->Ai->Force[force].Insert(*target); target->GroupId = caster.GroupId; CommandDefend(*target, caster, FlushCommands); } } if (this->SacrificeEnable) { // No corpse. caster.Remove(NULL); caster.Release(); } else { caster.Variable[MANA_INDEX].Value -= spell.ManaCost; } return 0; }