static void AnimateActionTrain(CUnit &unit) { if (unit.Type->Animations->Train) { UnitShowAnimation(unit, unit.Type->Animations->Train); } else { UnitShowAnimation(unit, unit.Type->Animations->Still); } }
static void AnimateActionBuild(CUnit &unit) { CAnimations *animations = unit.Type->Animations; if (animations == NULL) { return ; } if (animations->Build) { UnitShowAnimation(unit, animations->Build); } else if (animations->Repair) { UnitShowAnimation(unit, animations->Repair); } }
/** ** Animate unit spell cast ** ** @param unit Unit, for that spell cast/attack animation is played. */ static void AnimateActionSpellCast(CUnit &unit, COrder_SpellCast &order) { const CAnimations *animations = unit.Type->Animations; if (!animations || (!animations->Attack && !animations->SpellCast)) { // if don't have animations just cast spell order.OnAnimationAttack(unit); return; } if (animations->SpellCast) { UnitShowAnimation(unit, animations->SpellCast); } else { UnitShowAnimation(unit, animations->Attack); } }
/** ** Unit stands still or stand ground. ** ** @param unit Unit pointer for action. ** @param stand_ground true if unit is standing ground. */ void ActionStillGeneric(CUnit *unit, bool stand_ground) { // If unit is not bunkered and removed, wait if (unit->Removed && (!unit->Container || !unit->Container->Type->CanTransport || !unit->Container->Type->AttackFromTransporter || unit->Type->Missile.Missile->Class == MissileClassNone)) { // If unit is in building or transporter it is removed. return; } // Animations if (unit->SubAction) { // attacking unit in attack range. AnimateActionAttack(unit); } else { UnitShowAnimation(unit, unit->Type->Animations->Still); } if (unit->Anim.Unbreakable) { // animation can't be aborted here return; } if (AutoCast(unit) || AutoRepair(unit)) { return; } AutoAttack(unit, stand_ground); }
/* virtual */ void COrder_Move::Execute(CUnit &unit) { Assert(unit.CanMove()); if (unit.Wait) { if (!unit.Waiting) { unit.Waiting = 1; unit.WaitBackup = unit.Anim; } UnitShowAnimation(unit, unit.Type->Animations->Still); unit.Wait--; return; } if (unit.Waiting) { unit.Anim = unit.WaitBackup; unit.Waiting = 0; } // FIXME: (mr-russ) Make a reachable goal here with GoalReachable ... switch (DoActionMove(unit)) { // reached end-point? case PF_UNREACHABLE: // Some tries to reach the goal this->Range++; break; case PF_REACHED: this->Finished = true; break; default: break; } }
/* virtual */ void COrder_Still::Execute(CUnit &unit) { // If unit is not bunkered and removed, wait if (unit.Removed //Wyrmgus start // && (unit.Container == nullptr || unit.Container->Type->BoolFlag[ATTACKFROMTRANSPORTER_INDEX].value == false)) { && (unit.Container == nullptr || !unit.Container->Type->BoolFlag[ATTACKFROMTRANSPORTER_INDEX].value || !unit.Type->BoolFlag[ATTACKFROMTRANSPORTER_INDEX].value)) { // make both the unit and the transporter have the tag be necessary for the attack to be possible if (unit.Container != nullptr) { LeaveShelter(unit); // leave shelter if surrounded } //Wyrmgus end return ; } this->Finished = false; switch (this->State) { case SUB_STILL_STANDBY: //Wyrmgus start // UnitShowAnimation(unit, unit.Type->Animations->Still); if (unit.Variable[STUN_INDEX].Value == 0) { //only show the idle animation when still if the unit is not stunned UnitShowAnimation(unit, unit.GetAnimations()->Still); } if (SyncRand(100000) == 0) { PlayUnitSound(unit, VoiceIdle); } unit.StepCount = 0; //Wyrmgus end break; case SUB_STILL_ATTACK: // attacking unit in attack range. AnimateActionAttack(unit, *this); break; } if (unit.Anim.Unbreakable) { // animation can't be aborted here return; } //Wyrmgus start if (unit.Variable[STUN_INDEX].Value > 0) { //if unit is stunned, remain still return; } //Wyrmgus end this->State = SUB_STILL_STANDBY; this->Finished = (this->Action == UnitActionStill); if (this->Action == UnitActionStandGround || unit.Removed || unit.CanMove() == false) { if (unit.AutoCastSpell) { this->AutoCastStand(unit); } if (unit.IsAgressive()) { this->AutoAttackStand(unit); } } else { if (AutoCast(unit) || (unit.IsAgressive() && AutoAttack(unit)) || AutoRepair(unit) //Wyrmgus start // || MoveRandomly(unit)) { || MoveRandomly(unit) || PickUpItem(unit)) { //Wyrmgus end } } }
/** ** Animate a unit that is harvesting ** ** @param unit Unit to animate */ static void AnimateActionHarvest(CUnit &unit) { //Wyrmgus start // Assert(unit.Type->Animations->Harvest[unit.CurrentResource]); // UnitShowAnimation(unit, unit.Type->Animations->Harvest[unit.CurrentResource]); Assert(unit.GetAnimations()->Harvest[unit.CurrentResource]); UnitShowAnimation(unit, unit.GetAnimations()->Harvest[unit.CurrentResource]); //Wyrmgus end }
static void AnimateActionUpgradeTo(CUnit &unit) { //Wyrmgus start // CAnimations &animations = *unit.Type->Animations; // UnitShowAnimation(unit, animations.Upgrade ? animations.Upgrade : animations.Still); CAnimations &animations = *unit.GetAnimations(); UnitShowAnimation(unit, animations.Upgrade ? animations.Upgrade : animations.Still); //Wyrmgus end }
static bool AnimateActionDie(CUnit &unit) { //Wyrmgus start // const CAnimations *animations = unit.Type->Animations; const CAnimations *animations = unit.GetAnimations(); //Wyrmgus end if (animations == NULL) { return false; } if (animations->Death[unit.DamagedType]) { UnitShowAnimation(unit, animations->Death[unit.DamagedType]); return true; } else if (animations->Death[ANIMATIONS_DEATHTYPES]) { UnitShowAnimation(unit, animations->Death[ANIMATIONS_DEATHTYPES]); return true; } return false; }
/** ** Animate unit attack! ** ** @param unit Unit, for that the attack animation is played. ** ** @todo manage correctly unit with no animation attack. */ void AnimateActionAttack(CUnit &unit, COrder &order) { // No animation. // So direct fire missile. // FIXME : wait a little. if (!unit.Type->Animations || !unit.Type->Animations->Attack) { order.OnAnimationAttack(unit); return; } UnitShowAnimation(unit, unit.Type->Animations->Attack); }
/** ** Research upgrade. ** ** @return true when finished. */ /* virtual */ void COrder_Research::Execute(CUnit &unit) { const CUpgrade &upgrade = this->GetUpgrade(); const CUnitType &type = *unit.Type; //Wyrmgus start // UnitShowAnimation(unit, type.Animations->Research ? type.Animations->Research : type.Animations->Still); UnitShowAnimation(unit, unit.GetAnimations()->Research ? unit.GetAnimations()->Research : unit.GetAnimations()->Still); //Wyrmgus end if (unit.Wait) { unit.Wait--; return ; } #if 0 if (unit.Anim.Unbreakable) { return ; } #endif //Wyrmgus start // CPlayer &player = *unit.Player; CPlayer &player = Players[this->Player]; // player.UpgradeTimers.Upgrades[upgrade.ID] += std::max(1, player.SpeedResearch / SPEEDUP_FACTOR); player.UpgradeTimers.Upgrades[upgrade.ID] += std::max(1, (player.SpeedResearch + unit.Variable[TIMEEFFICIENCYBONUS_INDEX].Value + unit.Variable[RESEARCHSPEEDBONUS_INDEX].Value) / SPEEDUP_FACTOR); //Wyrmgus end if (player.UpgradeTimers.Upgrades[upgrade.ID] >= upgrade.Costs[TimeCost]) { if (upgrade.Name.empty()) { //Wyrmgus start // player.Notify(NotifyGreen, unit.tilePos, _("%s: research complete"), type.Name.c_str()); player.Notify(NotifyGreen, unit.tilePos, unit.MapLayer->ID, _("%s: research complete"), type.GetDefaultName(player).c_str()); //Wyrmgus end } else { player.Notify(NotifyGreen, unit.tilePos, unit.MapLayer->ID, _("%s: research complete"), upgrade.Name.c_str()); } if (&player == ThisPlayer) { //Wyrmgus start // CSound *sound = GameSounds.ResearchComplete[player.Race].Sound; CSound *sound = GameSounds.ResearchComplete[unit.Player->Race].Sound; //Wyrmgus end if (sound) { PlayGameSound(sound, MaxSampleVolume); } } if (player.AiEnabled) { AiResearchComplete(unit, &upgrade); } UpgradeAcquire(player, &upgrade); this->Finished = true; return ; } unit.Wait = CYCLES_PER_SECOND / 6; }
/** ** Unit upgrades unit! ** ** @param unit Pointer to unit. */ void HandleActionUpgradeTo(CUnit &unit) { if (!unit.SubAction) { // first entry unit.Data.UpgradeTo.Ticks = 0; unit.SubAction = 1; } unit.Type->Animations->Upgrade ? UnitShowAnimation(unit, unit.Type->Animations->Upgrade) : UnitShowAnimation(unit, unit.Type->Animations->Still); if (unit.Wait) { unit.Wait--; return; } CPlayer *player = unit.Player; CUnitType &newtype = *unit.CurrentOrder()->Arg1.Type; const CUnitStats *newstats = &newtype.Stats[player->Index]; // FIXME: Should count down here unit.Data.UpgradeTo.Ticks += SpeedUpgrade; if (unit.Data.UpgradeTo.Ticks < newstats->Costs[TimeCost]) { unit.Wait = CYCLES_PER_SECOND / 6; return; } unit.ClearAction(); unit.State = 0; if (TransformUnitIntoType(unit, newtype) == 0) { player->Notify(NotifyGreen, unit.tilePos.x, unit.tilePos.y, _("Upgrade to %s canceled"), newtype.Name.c_str()); return ; } // Warn AI. if (player->AiEnabled) { AiUpgradeToComplete(unit, newtype); } player->Notify(NotifyGreen, unit.tilePos.x, unit.tilePos.y, _("Upgrade to %s complete"), unit.Type->Name.c_str()); }
static void AnimateActionTrain(CUnit &unit) { //Wyrmgus start /* if (unit.Type->Animations->Train) { UnitShowAnimation(unit, unit.Type->Animations->Train); } else { UnitShowAnimation(unit, unit.Type->Animations->Still); } */ CAnimations *animations = unit.Type->Animations; VariationInfo *varinfo = unit.Type->VarInfo[unit.Variation]; if (varinfo && varinfo->Animations) { animations = varinfo->Animations; } if (animations->Train) { UnitShowAnimation(unit, animations->Train); } else { UnitShowAnimation(unit, animations->Still); } //Wyrmgus end }
/* virtual */ void COrder_Build::Execute(CUnit &unit) { if (unit.Wait) { if (!unit.Waiting) { unit.Waiting = 1; unit.WaitBackup = unit.Anim; } UnitShowAnimation(unit, unit.Type->Animations->Still); unit.Wait--; return; } if (unit.Waiting) { unit.Anim = unit.WaitBackup; unit.Waiting = 0; } if (this->State <= State_MoveToLocationMax) { if (this->MoveToLocation(unit)) { this->Finished = true; return ; } } const CUnitType &type = this->GetUnitType(); if (State_NearOfLocation <= this->State && this->State < State_StartBuilding_Failed) { if (CheckLimit(unit, type) == false) { this->Finished = true; return ; } CUnit *ontop = this->CheckCanBuild(unit); if (ontop != NULL) { this->StartBuilding(unit, *ontop); } } if (this->State == State_StartBuilding_Failed) { unit.Player->Notify(NotifyYellow, unit.tilePos, _("You cannot build %s here"), type.Name.c_str()); if (unit.Player->AiEnabled) { AiCanNotBuild(unit, type); } this->Finished = true; return ; } if (this->State == State_BuildFromOutside) { if (this->BuildFromOutside(unit)) { this->Finished = true; } } }
/* virtual */ void COrder_Board::Execute(CUnit &unit) { switch (this->State) { // Wait for transporter case State_WaitForTransporter: if (this->WaitForTransporter(unit)) { this->State = State_EnterTransporter; } else { UnitShowAnimation(unit, unit.Type->Animations->Still); } break; case State_EnterTransporter: { EnterTransporter(unit, *this); this->Finished = true; return ; } case State_Init: if (unit.Wait) { unit.Wait--; return; } this->State = 1; // FALL THROUGH default: { // Move to transporter if (this->State <= State_MoveToTransporterMax) { const int pathRet = MoveToTransporter(unit); // FIXME: if near transporter wait for enter if (pathRet) { if (pathRet == PF_UNREACHABLE) { if (++this->State == State_MoveToTransporterMax) { this->Finished = true; return; } else { // Try with a bigger range. this->Range++; this->State--; } } else if (pathRet == PF_REACHED) { this->State = State_WaitForTransporter; } } } break; } } }
/** ** Generic unit attacker. ** ** @param unit Unit, for that the attack animation is played. ** @param attack Attack animation. */ local void DoActionAttackGeneric(Unit* unit,Animation* attack) { int flags; int oframe; oframe=unit->Frame; flags=UnitShowAnimation(unit,attack); IfDebug( if( (unit->Frame&127)>=unit->Type->RleSprite->NumFrames ) { DebugLevel0("Oops what this %s %d,%d %d #%d\n" ,unit->Type->Ident ,oframe,oframe&127 ,unit->Frame&127 ,unit->Type->RleSprite->NumFrames); SaveUnit(unit,stdout); abort(); return; } );
/** ** Research upgrade. ** ** @return true when finished. */ /* virtual */ void COrder_Research::Execute(CUnit &unit) { const CUpgrade &upgrade = this->GetUpgrade(); const CUnitType &type = *unit.Type; UnitShowAnimation(unit, type.Animations->Research ? type.Animations->Research : type.Animations->Still); if (unit.Wait) { unit.Wait--; return ; } #if 0 if (unit.Anim.Unbreakable) { return ; } #endif CPlayer &player = *unit.Player; player.UpgradeTimers.Upgrades[upgrade.ID] += std::max(1, player.SpeedResearch / SPEEDUP_FACTOR); if (player.UpgradeTimers.Upgrades[upgrade.ID] >= upgrade.Costs[TimeCost]) { if (upgrade.Name.empty()) { player.Notify(NotifyGreen, unit.tilePos, _("%s: research complete"), type.Name.c_str()); } else { player.Notify(NotifyGreen, unit.tilePos, _("%s: research complete"), upgrade.Name.c_str()); } if (&player == ThisPlayer) { CSound *sound = GameSounds.ResearchComplete[player.Race].Sound; if (sound) { PlayGameSound(sound, MaxSampleVolume); } } if (player.AiEnabled) { AiResearchComplete(unit, &upgrade); } UpgradeAcquire(player, &upgrade); this->Finished = true; return ; } unit.Wait = CYCLES_PER_SECOND / 6; }
/** ** Unit dies! ** ** @param unit The unit which dies. */ global void HandleActionDie(Unit* unit) { // // Show death animation // if( unit->Type->Animations && unit->Type->Animations->Die ) { UnitShowAnimation(unit,unit->Type->Animations->Die); } else { // some units has no death animation unit->Reset=unit->Wait=1; } // // Die sequence terminated, generate corpse. // if( unit->Reset ) { DebugLevel3("Die complete %d\n" _C_ UnitNumber(unit)); if( !unit->Type->CorpseType ) { UnitMarkSeen(unit); ReleaseUnit(unit); return; } #ifdef NEW_FOW //Fixes sight from death MapUnmarkSight(unit->Player,unit->X,unit->Y,unit->CurrentSightRange); //unit->CurrentSightRange=unit->Type->Stats->SightRange; #endif unit->State=unit->Type->CorpseScript; unit->Type=unit->Type->CorpseType; CommandStopUnit(unit); // This clears all order queues IfDebug( if( unit->Orders[0].Action!=UnitActionDie ) { DebugLevel0Fn("Reset to die is really needed\n"); } );
/* virtual */ void COrder_Still::Execute(CUnit &unit) { // If unit is not bunkered and removed, wait if (unit.Removed && (unit.Container == NULL || unit.Container->Type->BoolFlag[ATTACKFROMTRANSPORTER_INDEX].value == false)) { return ; } this->Finished = false; switch (this->State) { case SUB_STILL_STANDBY: UnitShowAnimation(unit, unit.Type->Animations->Still); break; case SUB_STILL_ATTACK: // attacking unit in attack range. AnimateActionAttack(unit, *this); break; } if (unit.Anim.Unbreakable) { // animation can't be aborted here return; } this->State = SUB_STILL_STANDBY; this->Finished = (this->Action == UnitActionStill); if (this->Action == UnitActionStandGround || unit.Removed || unit.CanMove() == false) { if (unit.AutoCastSpell) { this->AutoCastStand(unit); } if (unit.IsAgressive()) { this->AutoAttackStand(unit); } } else { if (AutoCast(unit) || (unit.IsAgressive() && AutoAttack(unit)) || AutoRepair(unit) || MoveRandomly(unit)) { } } }
/** ** The unit boards a transporter. ** ** @todo FIXME: While waiting for the transporter the units must defend themselves. ** ** @param unit Pointer to unit. */ void HandleActionBoard(CUnit *unit) { int i; CUnit *goal; switch (unit->SubAction) { // // Wait for transporter // case 201: if (WaitForTransporter(unit)) { unit->SubAction = 202; } else { UnitShowAnimation(unit, unit->Type->Animations->Still); } break; // // Enter transporter // case 202: EnterTransporter(unit); break; // // Move to transporter // case 0: if (unit->Wait) { unit->Wait--; return; } NewResetPath(unit); unit->SubAction = 1; // FALL THROUGH default: if (unit->SubAction <= 200) { // FIXME: if near transporter wait for enter if ((i = MoveToTransporter(unit))) { if (i == PF_UNREACHABLE) { if (++unit->SubAction == 200) { unit->ClearAction(); if ((goal = unit->Orders[0]->Goal)) { goal->RefsDecrease(); unit->Orders[0]->Goal = NoUnitP; } } else { // // Try with a bigger range. // if (unit->Orders[0]->Range <= Map.Info.MapWidth || unit->Orders[0]->Range <= Map.Info.MapHeight) { unit->Orders[0]->Range++; unit->SubAction--; } } } else if (i == PF_REACHED) { unit->SubAction = 201; } } } break; } }
/* virtual */ void COrder_Unload::Execute(CUnit &unit) { const int maxSearchRange = 20; if (!unit.CanMove()) { this->State = 2; } if (unit.Wait) { if (!unit.Waiting) { unit.Waiting = 1; unit.WaitBackup = unit.Anim; } UnitShowAnimation(unit, unit.Type->Animations->Still); unit.Wait--; return; } if (unit.Waiting) { unit.Anim = unit.WaitBackup; unit.Waiting = 0; } if (this->State == 1 && this->Range >= 5) { // failed to reach the goal this->State = 2; } switch (this->State) { case 0: // Choose destination if (!this->HasGoal()) { Vec2i pos; if (!ClosestFreeDropZone(unit, this->goalPos, maxSearchRange, &pos)) { this->Finished = true; return ; } this->goalPos = pos; } this->State = 1; // follow on next case case 1: // Move unit to destination // The Goal is the unit that we have to unload. if (!this->HasGoal()) { const int moveResult = MoveToDropZone(unit); // We have to unload everything if (moveResult) { if (moveResult == PF_REACHED) { if (++this->State == 1) { this->Finished = true; return ; } } else if (moveResult == PF_UNREACHABLE) { unit.Wait = 30; this->Range++; break; } else { this->State = 2; } } return ; } case 2: { // Leave the transporter // FIXME: show still animations ? if (LeaveTransporter(unit)) { this->Finished = true; return ; } return ; } default: return ; } }
bool COrder_Build::StartBuilding(CUnit &unit, CUnit &ontop) { const CUnitType &type = this->GetUnitType(); unit.Player->SubUnitType(type); CUnit *build = MakeUnit(const_cast<CUnitType &>(type), unit.Player); // If unable to make unit, stop, and report message if (build == NULL) { // FIXME: Should we retry this? unit.Player->Notify(NotifyYellow, unit.tilePos, _("Unable to create building %s"), type.Name.c_str()); if (unit.Player->AiEnabled) { AiCanNotBuild(unit, type); } return false; } build->Constructed = 1; build->CurrentSightRange = 0; // Building on top of something, may remove what is beneath it if (&ontop != &unit) { CBuildRestrictionOnTop *b; b = static_cast<CBuildRestrictionOnTop *>(OnTopDetails(*build, ontop.Type)); Assert(b); if (b->ReplaceOnBuild) { build->ResourcesHeld = ontop.ResourcesHeld; // We capture the value of what is beneath. build->Variable[GIVERESOURCE_INDEX].Value = ontop.Variable[GIVERESOURCE_INDEX].Value; build->Variable[GIVERESOURCE_INDEX].Max = ontop.Variable[GIVERESOURCE_INDEX].Max; build->Variable[GIVERESOURCE_INDEX].Enable = ontop.Variable[GIVERESOURCE_INDEX].Enable; ontop.Remove(NULL); // Destroy building beneath UnitLost(ontop); UnitClearOrders(ontop); ontop.Release(); } } // Must set action before placing, otherwise it will incorrectly mark radar delete build->CurrentOrder(); build->Orders[0] = COrder::NewActionBuilt(unit, *build); UpdateUnitSightRange(*build); // Must place after previous for map flags build->Place(this->goalPos); // HACK: the building is not ready yet build->Player->UnitTypesCount[type.Slot]--; if (build->Active) { build->Player->UnitTypesAiActiveCount[type.Slot]--; } // We need somebody to work on it. if (!type.BoolFlag[BUILDEROUTSIDE_INDEX].value) { UnitShowAnimation(unit, unit.Type->Animations->Still); unit.Remove(build); this->State = State_BuildFromInside; if (unit.Selected) { SelectedUnitChanged(); } } else { this->State = State_BuildFromOutside; this->BuildingUnit = build; unit.Direction = DirectionToHeading(build->tilePos - unit.tilePos); UnitUpdateHeading(unit); } return true; }
/** ** Animate unit repair ** ** @param unit Unit, for that the repair animation is played. */ static int AnimateActionRepair(CUnit &unit) { UnitShowAnimation(unit, unit.Type->Animations->Repair); return 0; }
static void AnimateActionUpgradeTo(CUnit &unit) { CAnimations &animations = *unit.Type->Animations; UnitShowAnimation(unit, animations.Upgrade ? animations.Upgrade : animations.Still); }
/* virtual */ void COrder_Defend::Execute(CUnit &unit) { if (unit.Wait) { if (!unit.Waiting) { unit.Waiting = 1; unit.WaitBackup = unit.Anim; } //Wyrmgus start // UnitShowAnimation(unit, unit.Type->Animations->Still); VariationInfo *varinfo = unit.Type->VarInfo[unit.Variation]; if (varinfo && varinfo->Animations && varinfo->Animations->Still) { UnitShowAnimation(unit, varinfo->Animations->Still); } else { UnitShowAnimation(unit, unit.Type->Animations->Still); } //Wyrmgus end unit.Wait--; return; } if (unit.Waiting) { unit.Anim = unit.WaitBackup; unit.Waiting = 0; } CUnit *goal = this->GetGoal(); if (this->State == State_Init) { if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) { this->Finished = true; return; } this->State = State_MovingToTarget; } else if (this->State == State_Defending) { if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) { this->Finished = true; return; } } if (!unit.Anim.Unbreakable) { if (AutoCast(unit) || AutoAttack(unit) || AutoRepair(unit)) { return; } } switch (DoActionMove(unit)) { case PF_UNREACHABLE: // Some tries to reach the goal this->Range++; break; case PF_REACHED: { if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) { // goal has died this->Finished = true; return; } // Now defend the goal this->goalPos = goal->tilePos; this->State = State_Defending; } default: break; } // Target destroyed? if (goal && !goal->IsVisibleAsGoal(*unit.Player)) { DebugPrint("Goal gone\n"); this->goalPos = goal->tilePos + goal->Type->GetHalfTileSize(); this->ClearGoal(); goal = NULL; if (this->State == State_Defending) { this->Finished = true; return; } } }
/** ** Control the unit action: getting a resource. ** ** This the generic function for oil, gold, ... ** ** @param unit Pointer to unit. */ void COrder_Resource::Execute(CUnit &unit) { // can be different by Cloning (trained unit)... this->worker = &unit; if (unit.Wait) { if (!unit.Waiting) { unit.Waiting = 1; unit.WaitBackup = unit.Anim; } //Wyrmgus start // UnitShowAnimation(unit, unit.Type->Animations->Still); UnitShowAnimation(unit, unit.GetAnimations()->Still); //Wyrmgus end unit.Wait--; return; } if (unit.Waiting) { unit.Anim = unit.WaitBackup; unit.Waiting = 0; } // Let's start mining. if (this->State == SUB_START_RESOURCE) { if (ActionResourceInit(unit) == false) { ResourceGiveUp(unit); return; } } // Move to the resource location. if (SUB_MOVE_TO_RESOURCE <= this->State && this->State < SUB_UNREACHABLE_RESOURCE) { const int ret = MoveToResource(unit); switch (ret) { case -1: { // Can't Reach this->State++; unit.Wait = 5; return; } case 1: { // Reached this->State = SUB_START_GATHERING; break; } case 0: // Move along. return; default: { Assert(0); break; } } } // Resource seems to be unreachable if (this->State == SUB_UNREACHABLE_RESOURCE) { if (this->FindAnotherResource(unit) == false) { ResourceGiveUp(unit); return; } } // Start gathering the resource if (this->State == SUB_START_GATHERING) { if (StartGathering(unit)) { this->State = SUB_GATHER_RESOURCE; } else { return; } } // Gather the resource. if (this->State == SUB_GATHER_RESOURCE) { if (GatherResource(unit)) { this->State = SUB_STOP_GATHERING; } else { return; } } // Stop gathering the resource. if (this->State == SUB_STOP_GATHERING) { if (StopGathering(unit)) { this->State = SUB_MOVE_TO_DEPOT; unit.pathFinderData->output.Cycles = 0; //moving counter } else { return; } } // Move back home. if (SUB_MOVE_TO_DEPOT <= this->State && this->State < SUB_UNREACHABLE_DEPOT) { const int ret = MoveToDepot(unit); switch (ret) { case -1: { // Can't Reach this->State++; unit.Wait = 5; return; } case 1: { // Reached this->State = SUB_RETURN_RESOURCE; return; } case 0: // Move along. return; default: { Assert(0); return; } } } // Depot seems to be unreachable if (this->State == SUB_UNREACHABLE_DEPOT) { ResourceGiveUp(unit); return; } // Unload resources at the depot. if (this->State == SUB_RETURN_RESOURCE) { if (WaitInDepot(unit)) { this->State = SUB_START_RESOURCE; // It's posible, though very rare that the unit's goal blows up // this cycle, but after this unit. Thus, next frame the unit // will start mining a destroyed site. If, on the otherhand we // are already in SUB_MOVE_TO_RESOURCE then we can handle it. // So, we pass through SUB_START_RESOURCE the very instant it // goes out of the depot. //HandleActionResource(order, unit); } } }
/* ** Chop the wood. ** Return TRUE if ready, otherwise FALSE. */ local int ChopWood(Unit* unit) { Unit* destu; int flags; extern Animation PeonAttack[]; flags=UnitShowAnimation(unit,PeonAttack); if( (flags&AnimationSound) ) { PlayUnitSound(unit,VoiceTreeChopping); } if( unit->Reset ) { DebugCheck( unit->Wait!=1 ); // // This a work around the bug: "lumber bug" // We give a worker a new command and in the next cycle // the worker is ready chopping. // #if 0 // FIXME: johns+cade: this didn't work with the current code if( unit->NextCommand[0].Action==UnitActionHarvest || unit->NextCommand[0].Action==UnitActionMineGold ) { unit->SubAction=0; return 0; } #endif // // Wood gone while chopping? // if( !ForestOnMap(unit->Command.Data.Move.DX ,unit->Command.Data.Move.DY) ) { if( FindWoodInSight(unit ,&unit->Command.Data.Move.DX ,&unit->Command.Data.Move.DY) ) { unit->Command.Data.Move.Fast=1; unit->Command.Data.Move.Goal=NoUnitP; unit->Command.Data.Move.Range=0; // FIXME: shouldn't it be range=1 ?? DebugCheck( unit->Command.Action!=UnitActionHarvest ); unit->SubAction=0; } else { unit->Command.Action=UnitActionStill; unit->SubAction=0; DebugLevel3("NO-WOOD in sight range\n"); } return 0; } // // Ready chopping wood? // if( !(unit->WoodToHarvest = --unit->Value) ) { // Have wood if( unit->Type->Type==UnitPeon ) { unit->Type=&UnitTypes[UnitPeonWithWood]; } else if( unit->Type->Type==UnitPeasant ) { unit->Type=&UnitTypes[UnitPeasantWithWood]; } else { DebugLevel0("Wrong unit for chopping wood %d\n" ,unit->Type->Type); } // // Update the display. // if( UnitVisible(unit) ) { MustRedraw|=RedrawMap; } if( IsSelected(unit) ) { UpdateBottomPanel(); MustRedraw|=RedrawBottomPanel; } // // Update the map. // MapRemoveWood(unit->Command.Data.Move.DX ,unit->Command.Data.Move.DY); // // Find place to return wood. // unit->Command.Data.Move.SX=unit->X; unit->Command.Data.Move.SY=unit->Y; if( !(destu=FindWoodDeposit(unit->Player,unit->X,unit->Y)) ) { unit->Command.Action=UnitActionStill; unit->SubAction=0; } else { unit->Command.Data.Move.Fast=1; unit->Command.Data.Move.Range=1; unit->Command.Data.Move.Goal=destu; #if 1 // Fast movement need this?? NearestOfUnit(destu,unit->X,unit->Y ,&unit->Command.Data.Move.DX ,&unit->Command.Data.Move.DY); #else unit->Command.Data.Move.DX=destu->X; unit->Command.Data.Move.DY=destu->Y; #endif DebugLevel3("Return to %Zd=%d,%d\n" ,destu-UnitsPool ,unit->Command.Data.Move.DX ,unit->Command.Data.Move.DY); DebugCheck( unit->Command.Action!=UnitActionHarvest ); return 1; } } } return 0; }
/* virtual */ void COrder_Defend::Execute(CUnit &unit) { if (unit.Wait) { if (!unit.Waiting) { unit.Waiting = 1; unit.WaitBackup = unit.Anim; } //Wyrmgus start // UnitShowAnimation(unit, unit.Type->Animations->Still); UnitShowAnimation(unit, unit.GetAnimations()->Still); //Wyrmgus end unit.Wait--; return; } if (unit.Waiting) { unit.Anim = unit.WaitBackup; unit.Waiting = 0; } CUnit *goal = this->GetGoal(); if (this->State == State_Init) { if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) { this->Finished = true; return; } this->State = State_MovingToTarget; } else if (this->State == State_Defending) { if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) { this->Finished = true; return; } } if (!unit.Anim.Unbreakable) { if (AutoCast(unit) || AutoAttack(unit) || AutoRepair(unit)) { return; } } switch (DoActionMove(unit)) { case PF_UNREACHABLE: //Wyrmgus start //if is unreachable and is on a raft, see if the raft can move closer to the enemy if ((Map.Field(unit.tilePos)->Flags & MapFieldBridge) && !unit.Type->BoolFlag[BRIDGE_INDEX].value && unit.Type->UnitType == UnitTypeLand) { std::vector<CUnit *> table; Select(unit.tilePos, unit.tilePos, table); for (size_t i = 0; i != table.size(); ++i) { if (!table[i]->Removed && table[i]->Type->BoolFlag[BRIDGE_INDEX].value && table[i]->CanMove()) { if (table[i]->CurrentAction() == UnitActionStill) { CommandStopUnit(*table[i]); CommandMove(*table[i], this->HasGoal() ? this->GetGoal()->tilePos : this->goalPos, FlushCommands); } return; } } } //Wyrmgus end // Some tries to reach the goal this->Range++; break; case PF_REACHED: { if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) { // goal has died this->Finished = true; return; } // Now defend the goal this->goalPos = goal->tilePos; this->State = State_Defending; } default: break; } // Target destroyed? if (goal && !goal->IsVisibleAsGoal(*unit.Player)) { DebugPrint("Goal gone\n"); this->goalPos = goal->tilePos + goal->Type->GetHalfTileSize(); this->ClearGoal(); goal = NULL; if (this->State == State_Defending) { this->Finished = true; return; } } }
/** ** Animate unit repair ** ** @param unit Unit, for that the repair animation is played. */ static void AnimateActionRepair(CUnit &unit) { UnitShowAnimation(unit, unit.Type->Animations->Repair); }
/* virtual */ void COrder_Follow::Execute(CUnit &unit) { if (unit.Wait) { if (!unit.Waiting) { unit.Waiting = 1; unit.WaitBackup = unit.Anim; } //Wyrmgus start // UnitShowAnimation(unit, unit.Type->Animations->Still); UnitShowAnimation(unit, unit.GetAnimations()->Still); //Wyrmgus end unit.Wait--; return; } if (unit.Waiting) { unit.Anim = unit.WaitBackup; unit.Waiting = 0; } CUnit *goal = this->GetGoal(); // Reached target if (this->State == State_TargetReached) { if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) { DebugPrint("Goal gone\n"); this->Finished = true; return ; } // Don't follow after immobile units if (goal && goal->CanMove() == false) { this->Finished = true; return; } //Wyrmgus start // if (goal->tilePos == this->goalPos) { if (goal->tilePos == this->goalPos && goal->MapLayer == this->MapLayer) { //Wyrmgus end // Move to the next order if (unit.Orders.size() > 1) { this->Finished = true; return ; } unit.Wait = 10; if (this->Range > 1) { this->Range = 1; this->State = State_Init; } return ; } this->State = State_Init; } if (this->State == State_Init) { // first entry this->State = State_Initialized; } switch (DoActionMove(unit)) { // reached end-point? case PF_UNREACHABLE: //Wyrmgus start if ((Map.Field(unit.tilePos, unit.MapLayer)->Flags & MapFieldBridge) && !unit.Type->BoolFlag[BRIDGE_INDEX].value && unit.Type->UnitType == UnitTypeLand) { std::vector<CUnit *> table; Select(unit.tilePos, unit.tilePos, table, unit.MapLayer); for (size_t i = 0; i != table.size(); ++i) { if (!table[i]->Removed && table[i]->Type->BoolFlag[BRIDGE_INDEX].value && table[i]->CanMove()) { if (table[i]->CurrentAction() == UnitActionStill) { CommandStopUnit(*table[i]); CommandMove(*table[i], this->HasGoal() ? this->GetGoal()->tilePos : this->goalPos, FlushCommands, this->HasGoal() ? this->GetGoal()->MapLayer : this->MapLayer); } return; } } } //Wyrmgus end // Some tries to reach the goal this->Range++; break; case PF_REACHED: { if (!goal) { // goal has died this->Finished = true; return ; } // Handle Teleporter Units // FIXME: BAD HACK // goal shouldn't be busy and portal should be alive if (goal->Type->BoolFlag[TELEPORTER_INDEX].value && goal->Goal && goal->Goal->IsAlive() && unit.MapDistanceTo(*goal) <= 1) { if (!goal->IsIdle()) { // wait unit.Wait = 10; return; } // Check if we have enough mana if (goal->Goal->Type->TeleportCost > goal->Variable[MANA_INDEX].Value) { this->Finished = true; return; } else { goal->Variable[MANA_INDEX].Value -= goal->Goal->Type->TeleportCost; } // Everything is OK, now teleport the unit unit.Remove(NULL); if (goal->Type->TeleportEffectIn) { goal->Type->TeleportEffectIn->pushPreamble(); goal->Type->TeleportEffectIn->pushInteger(UnitNumber(unit)); goal->Type->TeleportEffectIn->pushInteger(UnitNumber(*goal)); goal->Type->TeleportEffectIn->pushInteger(unit.GetMapPixelPosCenter().x); goal->Type->TeleportEffectIn->pushInteger(unit.GetMapPixelPosCenter().y); goal->Type->TeleportEffectIn->run(); } unit.tilePos = goal->Goal->tilePos; //Wyrmgus start unit.MapLayer = goal->Goal->MapLayer; //Wyrmgus end DropOutOnSide(unit, unit.Direction, NULL); // FIXME: we must check if the units supports the new order. CUnit &dest = *goal->Goal; if (dest.Type->TeleportEffectOut) { dest.Type->TeleportEffectOut->pushPreamble(); dest.Type->TeleportEffectOut->pushInteger(UnitNumber(unit)); dest.Type->TeleportEffectOut->pushInteger(UnitNumber(dest)); dest.Type->TeleportEffectOut->pushInteger(unit.GetMapPixelPosCenter().x); dest.Type->TeleportEffectOut->pushInteger(unit.GetMapPixelPosCenter().y); dest.Type->TeleportEffectOut->run(); } if (dest.NewOrder == NULL || (dest.NewOrder->Action == UnitActionResource && !unit.Type->BoolFlag[HARVESTER_INDEX].value) //Wyrmgus start // || (dest.NewOrder->Action == UnitActionAttack && !unit.Type->CanAttack) || (dest.NewOrder->Action == UnitActionAttack && !unit.CanAttack(true)) //Wyrmgus end || (dest.NewOrder->Action == UnitActionBoard && unit.Type->UnitType != UnitTypeLand)) { this->Finished = true; return ; } else { if (dest.NewOrder->HasGoal()) { if (dest.NewOrder->GetGoal()->Destroyed) { delete dest.NewOrder; dest.NewOrder = NULL; this->Finished = true; return ; } unit.Orders.insert(unit.Orders.begin() + 1, dest.NewOrder->Clone()); this->Finished = true; return ; } } } this->goalPos = goal->tilePos; //Wyrmgus start this->MapLayer = goal->MapLayer; //Wyrmgus end this->State = State_TargetReached; } // FALL THROUGH default: break; } // Target destroyed? if (goal && !goal->IsVisibleAsGoal(*unit.Player)) { DebugPrint("Goal gone\n"); this->goalPos = goal->tilePos + goal->Type->GetHalfTileSize(); //Wyrmgus start this->MapLayer = goal->MapLayer; //Wyrmgus end this->ClearGoal(); goal = NULL; } if (unit.Anim.Unbreakable) { return ; } // If our leader is dead or stops or attacks: // Attack any enemy in reaction range. // If don't set the goal, the unit can than choose a // better goal if moving nearer to enemy. //Wyrmgus start // if (unit.Type->CanAttack if (unit.CanAttack() //Wyrmgus end && (!goal || goal->CurrentAction() == UnitActionAttack || goal->CurrentAction() == UnitActionStill)) { CUnit *target = AttackUnitsInReactRange(unit); if (target) { // Save current command to come back. COrder *savedOrder = NULL; if (unit.CanStoreOrder(unit.CurrentOrder())) { savedOrder = this->Clone(); } this->Finished = true; //Wyrmgus start // unit.Orders.insert(unit.Orders.begin() + 1, COrder::NewActionAttack(unit, target->tilePos)); unit.Orders.insert(unit.Orders.begin() + 1, COrder::NewActionAttack(unit, target->tilePos, target->MapLayer)); //Wyrmgus end if (savedOrder != NULL) { unit.SavedOrder = savedOrder; } } } }