00001
00002
00003
00004
00005
00006
00007
00008
00009
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00030
00031
00032
00033
00034
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037
00038 #include "stratagus.h"
00039 #include "unittype.h"
00040 #include "animation.h"
00041 #include "player.h"
00042 #include "unit.h"
00043 #include "missile.h"
00044 #include "actions.h"
00045 #include "sound.h"
00046 #include "map.h"
00047 #include "pathfinder.h"
00048 #include "interface.h"
00049 #include "ai.h"
00050
00051
00052
00053
00054
00063 static bool RestoreSavedOrder(CUnit *unit)
00064 {
00065 if (unit->SavedOrder.Action != UnitActionStill) {
00066 unit->SubAction = 0;
00067 Assert(unit->Orders[0]->Goal == NoUnitP);
00068 *unit->Orders[0] = unit->SavedOrder;
00069 NewResetPath(unit);
00070 unit->SavedOrder.Action = UnitActionStill;
00071
00072
00073 Assert(unit->SavedOrder.Goal == NoUnitP);
00074 return true;
00075 }
00076 return false;
00077 }
00078
00084 static void MoveToLocation(CUnit *unit)
00085 {
00086
00087 if (!unit->SubAction) {
00088 unit->SubAction = 1;
00089 NewResetPath(unit);
00090 }
00091
00092 if (unit->Wait) {
00093
00094 unit->Wait--;
00095 return;
00096 }
00097
00098 CUnit *goal = unit->Orders[0]->Goal;
00099 int err = 0;
00100
00101 switch (DoActionMove(unit)) {
00102 case PF_FAILED:
00103 case PF_UNREACHABLE:
00104
00105
00106
00107 if (unit->SubAction++ < 10) {
00108
00109
00110 unit->Wait = 10;
00111 return;
00112 }
00113
00114 if (goal) {
00115 goal->RefsDecrease();
00116 unit->Orders[0]->Goal = NoUnitP;
00117 }
00118 unit->ClearAction();
00119 return;
00120
00121 case PF_REACHED:
00122 break;
00123
00124 default:
00125
00126 break;
00127 }
00128
00129 if (unit->Anim.Unbreakable) {
00130 return;
00131 }
00132
00133
00134
00135
00136
00137 if (goal) {
00138 if (!goal->IsVisibleAsGoal(unit->Player)) {
00139 DebugPrint("repair target gone.\n");
00140 unit->Orders[0]->X = goal->X;
00141 unit->Orders[0]->Y = goal->Y;
00142 goal->RefsDecrease();
00143 unit->Orders[0]->Goal = goal = NULL;
00144 unit->SubAction = 0;
00145 }
00146 } else if (unit->Player->AiEnabled) {
00147
00148 err = -1;
00149 }
00150
00151
00152
00153
00154
00155 bool goalReached = goal && MapDistanceBetweenUnits(unit, goal) <= unit->Type->RepairRange;
00156 if (goalReached && goal->Variable[HP_INDEX].Value < goal->Variable[HP_INDEX].Max) {
00157 unit->State = 0;
00158 unit->SubAction = 20;
00159 unit->Data.Repair.Progress = 0;
00160 UnitHeadingFromDeltaXY(unit,
00161 goal->X + (goal->Type->TileWidth - 1) / 2 - unit->X,
00162 goal->Y + (goal->Type->TileHeight - 1) / 2 - unit->Y);
00163
00164 int costs[MaxCosts];
00165 CalculateRequestedAmount(unit->Type, unit->Orders[0]->Goal->Type->ProductionCosts, costs);
00166 unit->Player->AddToUnitsConsumingResources(unit, costs);
00167 } else if (err < 0 || goalReached) {
00168 if (goal) {
00169 goal->RefsDecrease();
00170 unit->Orders[0]->Goal = NoUnitP;
00171 }
00172 if (!RestoreSavedOrder(unit)) {
00173 unit->ClearAction();
00174 unit->State = 0;
00175 }
00176 return;
00177 }
00178
00179
00180 Assert(unit->Orders[0]->Action == UnitActionRepair);
00181 }
00182
00188 static int AnimateActionRepair(CUnit *unit)
00189 {
00190 UnitShowAnimation(unit, unit->Type->Animations->Repair);
00191 return 0;
00192 }
00193
00202 static bool DoRepair(CUnit *unit, CUnit *goal)
00203 {
00204 int *pcosts = goal->Type->ProductionCosts;
00205 int pcost = pcosts[EnergyCost] ? pcosts[EnergyCost] : pcosts[MagmaCost];
00206 bool healed = false;
00207
00208 if (goal->Orders[0]->Action != UnitActionBuilt) {
00209 Assert(goal->Variable[HP_INDEX].Max);
00210
00211 int *costs = unit->Player->UnitsConsumingResourcesActual[unit];
00212 int cost = costs[EnergyCost] ? costs[EnergyCost] : costs[MagmaCost];
00213 int step = pcost / goal->Variable[HP_INDEX].Max;
00214 int hp = 0;
00215
00216 unit->Data.Repair.Progress += cost;
00217 while (unit->Data.Repair.Progress > step) {
00218 unit->Data.Repair.Progress -= step;
00219 ++hp;
00220 }
00221 goal->Variable[HP_INDEX].Value += hp;
00222 if (goal->Variable[HP_INDEX].Value >= goal->Variable[HP_INDEX].Max) {
00223 goal->Variable[HP_INDEX].Value = goal->Variable[HP_INDEX].Max;
00224 healed = true;
00225 }
00226 } else {
00227
00228 int hp = (goal->Data.Built.Progress * goal->Variable[HP_INDEX].Max) / pcost - goal->Variable[HP_INDEX].Value;
00229
00230
00231 int *costs = unit->Player->UnitsConsumingResourcesActual[unit];
00232 int cost = costs[EnergyCost] ? costs[EnergyCost] : costs[MagmaCost];
00233 goal->Data.Built.Progress += cost * SpeedBuild;
00234 if (goal->Data.Built.Progress > pcost) {
00235 goal->Data.Built.Progress = pcost;
00236 }
00237
00238
00239 goal->Variable[HP_INDEX].Value = (goal->Data.Built.Progress * goal->Stats->Variables[HP_INDEX].Max) / pcost - hp;
00240 if (goal->Variable[HP_INDEX].Value >= goal->Variable[HP_INDEX].Max) {
00241 goal->Variable[HP_INDEX].Value = goal->Variable[HP_INDEX].Max;
00242 healed = true;
00243 }
00244 }
00245 return healed;
00246 }
00247
00253 static void RepairUnit(CUnit *unit)
00254 {
00255 CUnit *goal = unit->Orders[0]->Goal;
00256 bool visible = goal->IsVisibleAsGoal(unit->Player);
00257 bool inrange = MapDistanceBetweenUnits(unit, goal) <= unit->Type->RepairRange;
00258 bool healed = false;
00259
00260 if (goal && visible && inrange) {
00261 healed = DoRepair(unit, goal);
00262 goal = unit->Orders[0]->Goal;
00263 }
00264
00265 AnimateActionRepair(unit);
00266 if (unit->Anim.Unbreakable) {
00267 return;
00268 }
00269
00270
00271 if (goal && !visible) {
00272 DebugPrint("repair goal is gone\n");
00273 unit->Orders[0]->X = goal->X;
00274 unit->Orders[0]->Y = goal->Y;
00275 goal->RefsDecrease();
00276 unit->Orders[0]->Goal = goal = NoUnitP;
00277 NewResetPath(unit);
00278 }
00279
00280
00281 if (goal && !inrange && !healed) {
00282 unit->Player->RemoveFromUnitsConsumingResources(unit);
00283 unit->State = 0;
00284 unit->SubAction = 0;
00285 }
00286
00287
00288 if (!goal || healed) {
00289 unit->Player->RemoveFromUnitsConsumingResources(unit);
00290 if (goal) {
00291 goal->RefsDecrease();
00292 unit->Orders[0]->Goal = NULL;
00293 }
00294 if (!RestoreSavedOrder(unit)) {
00295 unit->ClearAction();
00296 unit->State = 0;
00297 }
00298 return;
00299 }
00300 }
00301
00307 void HandleActionRepair(CUnit *unit)
00308 {
00309 if (unit->SubAction <= 10) {
00310 MoveToLocation(unit);
00311 }
00312 if (unit->SubAction == 20) {
00313 RepairUnit(unit);
00314 }
00315 }
00316