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 #include <string.h>
00038
00039 #include "stratagus.h"
00040 #include "player.h"
00041 #include "unit.h"
00042 #include "unittype.h"
00043 #include "animation.h"
00044 #include "actions.h"
00045 #include "pathfinder.h"
00046 #include "interface.h"
00047 #include "sound.h"
00048
00049
00050
00051
00052
00053 #define SUB_START_RESOURCE 0
00054 #define SUB_MOVE_TO_RESOURCE 5
00055 #define SUB_UNREACHABLE_RESOURCE 31
00056 #define SUB_START_GATHERING 55
00057 #define SUB_GATHER_RESOURCE 60
00058
00059 int AlliedUnitRecyclingEfficiency[MaxCosts] = {0, 50};
00060 int EnemyUnitRecyclingEfficiency[MaxCosts] = {0, 40};
00061
00062
00063
00064
00065
00073 static int MoveToResource(CUnit *unit)
00074 {
00075 switch (DoActionMove(unit)) {
00076 case PF_UNREACHABLE:
00077 return -1;
00078 case PF_REACHED:
00079 break;
00080 default:
00081
00082 if (unit->Anim.Unbreakable || unit->Orders[0]->Goal->IsVisibleAsGoal(unit->Player)) {
00083 return 0;
00084 }
00085 break;
00086 }
00087 return 1;
00088 }
00089
00097 static bool StartGathering(CUnit *unit)
00098 {
00099 CUnit *goal = unit->Orders[0]->Goal;
00100
00101 Assert(!unit->IX && !unit->IY);
00102
00103
00104
00105
00106 if (!goal->IsVisibleAsGoal(unit->Player)) {
00107 goal->RefsDecrease();
00108
00109 unit->Orders[0]->X = unit->Orders[0]->Y = -1;
00110 if ((goal = UnitFindResource(unit, unit->X, unit->Y, 10))) {
00111 unit->SubAction = SUB_START_RESOURCE;
00112 unit->Orders[0]->Goal = goal;
00113 goal->RefsIncrease();
00114 } else {
00115 unit->ClearAction();
00116 unit->Orders[0]->Goal = NoUnitP;
00117 }
00118 return false;
00119 }
00120
00121
00122 Assert(MapDistanceBetweenUnits(unit, goal) <= 1);
00123
00124
00125
00126
00127 UnitHeadingFromDeltaXY(unit,
00128 goal->X + (goal->Type->TileWidth - 1) / 2 - unit->X,
00129 goal->Y + (goal->Type->TileHeight - 1) / 2 - unit->Y);
00130
00131 return true;
00132 }
00133
00139 static void AnimateActionHarvest(CUnit *unit)
00140 {
00141 Assert(unit->Type->Animations->Harvest);
00142 UnitShowAnimation(unit, unit->Type->Animations->Harvest);
00143 }
00144
00151 static void FindNewResource(CUnit *unit)
00152 {
00153 unit->Orders[0]->Goal->RefsDecrease();
00154 unit->Orders[0]->Goal = NoUnitP;
00155
00156 unit->Orders[0]->X = unit->Orders[0]->Y = -1;
00157 if ((unit->Orders[0]->Goal = UnitFindResource(unit, unit->X, unit->Y, 10))) {
00158 DebugPrint("Unit %d found another resource.\n" _C_ unit->Slot);
00159 unit->SubAction = SUB_START_RESOURCE;
00160 unit->State = 0;
00161 unit->Orders[0]->Goal->RefsIncrease();
00162 } else {
00163 DebugPrint("Unit %d did not find another resource.\n" _C_ unit->Slot);
00164 unit->ClearAction();
00165 unit->State = 0;
00166 }
00167 }
00168
00174 static void GatherResource(CUnit *unit)
00175 {
00176 CUnit *source = unit->Orders[0]->Goal;
00177 int amount[MaxCosts] = {1, 1};
00178 bool visible = source->IsAliveOnMap();
00179 int i;
00180 const int totalEfficiency[MaxCosts] = {100, 100};
00181 const int *efficiency = totalEfficiency;
00182
00183 AnimateActionHarvest(unit);
00184
00185
00186 if (visible && UnitHoldsResources(source)) {
00187
00188 if (unit->Player == source->Player || unit->Player->IsAllied(source)) {
00189 efficiency = AlliedUnitRecyclingEfficiency;
00190 } else if (unit->Player->IsEnemy(source)) {
00191 efficiency = EnemyUnitRecyclingEfficiency;
00192 }
00193
00194
00195
00196
00197 if (efficiency != totalEfficiency) {
00198 int hp = source->Variable[HP_INDEX].Max *
00199 source->ResourcesHeld[1] / source->Type->ProductionCosts[1];
00200 if (hp != 0 && hp != source->Variable[HP_INDEX].Value) {
00201 for (i = 0; i < MaxCosts; ++i) {
00202 source->ResourcesHeld[i] = source->Type->ProductionCosts[i] *
00203 source->Variable[HP_INDEX].Value / source->Variable[HP_INDEX].Max;
00204 }
00205 }
00206 }
00207
00208
00209 CalculateRequestedAmount(unit->Type, source->ResourcesHeld, amount);
00210 for (i = 0; i < MaxCosts; ++i) {
00211 unit->Player->ProductionRate[i] -= unit->Data.Harvest.CurrentProduction[i];
00212 unit->Data.Harvest.CurrentProduction[i] = amount[i] * efficiency[i] / 100;
00213 unit->Player->ProductionRate[i] += unit->Data.Harvest.CurrentProduction[i];
00214 source->ResourcesHeld[i] -= amount[i];
00215 }
00216
00217
00218 if (efficiency != totalEfficiency) {
00219 source->Variable[HP_INDEX].Value = source->Variable[HP_INDEX].Max *
00220 source->ResourcesHeld[1] / source->Type->ProductionCosts[1];
00221 if (source->Variable[HP_INDEX].Value == 0 && source->ResourcesHeld[1] != 0) {
00222 source->Variable[HP_INDEX].Value = 1;
00223 }
00224 }
00225 }
00226
00227
00228
00229
00230 if (!visible || !UnitHoldsResources(source)) {
00231 if (unit->Anim.Unbreakable) {
00232
00233 return;
00234 }
00235
00236 DebugPrint("Resource is destroyed for unit %d\n" _C_ unit->Slot);
00237
00238 for (i = 0; i < MaxCosts; ++i) {
00239 unit->Player->ProductionRate[i] -= unit->Data.Harvest.CurrentProduction[i];
00240 unit->Data.Harvest.CurrentProduction[i] = 0;
00241 }
00242
00243 if (unit->OrderCount == 1) {
00244
00245 FindNewResource(unit);
00246 } else {
00247 unit->Orders[0]->Goal->RefsDecrease();
00248 unit->Orders[0]->Goal = NoUnitP;
00249 unit->ClearAction();
00250 }
00251
00252
00253
00254 if (visible) {
00255 LetUnitDie(source);
00256 }
00257 }
00258 }
00259
00265 static void ResourceGiveUp(CUnit *unit)
00266 {
00267 DebugPrint("Unit %d gave up on resource gathering.\n" _C_ unit->Slot);
00268 if (unit->Orders[0]->Goal) {
00269 unit->Orders[0]->Goal->RefsDecrease();
00270 unit->Orders[0]->Goal = NULL;
00271 }
00272 unit->ClearAction();
00273 }
00274
00282 void HandleActionResource(CUnit *unit)
00283 {
00284 if (unit->Wait) {
00285 unit->Wait--;
00286 return;
00287 }
00288
00289
00290 if (unit->SubAction == SUB_START_RESOURCE) {
00291 if (unit->Orders[0]->Goal->Type->CanHarvestFrom) {
00292 NewResetPath(unit);
00293 unit->SubAction = SUB_MOVE_TO_RESOURCE;
00294 } else {
00295 ResourceGiveUp(unit);
00296 return;
00297 }
00298 }
00299
00300
00301 if (unit->SubAction >= SUB_MOVE_TO_RESOURCE &&
00302 unit->SubAction < SUB_UNREACHABLE_RESOURCE) {
00303 int ret = MoveToResource(unit);
00304
00305 if (ret == -1) {
00306
00307 unit->SubAction++;
00308 unit->Wait = 10;
00309 return;
00310 } else if (ret == 1) {
00311
00312 unit->SubAction = SUB_START_GATHERING;
00313 memset(unit->Data.Harvest.CurrentProduction, 0, sizeof(unit->Data.Harvest.CurrentProduction));
00314 } else {
00315
00316 return;
00317 }
00318 }
00319
00320
00321 if (unit->SubAction == SUB_UNREACHABLE_RESOURCE) {
00322 ResourceGiveUp(unit);
00323 return;
00324 }
00325
00326
00327 if (unit->SubAction == SUB_START_GATHERING) {
00328 if (StartGathering(unit)) {
00329 unit->SubAction = SUB_GATHER_RESOURCE;
00330 } else {
00331 return;
00332 }
00333 }
00334
00335
00336 if (unit->SubAction == SUB_GATHER_RESOURCE) {
00337 GatherResource(unit);
00338 return;
00339 }
00340 }
00341