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 "stratagus.h"
00036
00037 #include <stdio.h>
00038 #include <stdlib.h>
00039 #include <string.h>
00040 #include <ctype.h>
00041 #include <string>
00042 #include <map>
00043
00044 #include "video.h"
00045 #include "map.h"
00046 #include "sound.h"
00047 #include "unitsound.h"
00048 #include "construct.h"
00049 #include "unittype.h"
00050 #include "animation.h"
00051 #include "player.h"
00052 #include "missile.h"
00053 #include "script.h"
00054 #include "spells.h"
00055 #include "iolib.h"
00056 #include "luacallback.h"
00057
00058
00059
00060
00061
00062 std::vector<CUnitType *> UnitTypes;
00063 std::map<std::string, CUnitType *> UnitTypeMap;
00064
00068 std::string DefaultResourceNames[MaxCosts];
00069
00070
00071
00072
00073
00074 CUnitType::CUnitType() :
00075 Slot(0), Width(0), Height(0), OffsetX(0), OffsetY(0), DrawLevel(0),
00076 ShadowWidth(0), ShadowHeight(0), ShadowOffsetX(0), ShadowOffsetY(0),
00077 Animations(NULL), StillFrame(0),
00078 DeathExplosion(NULL), CorpseType(NULL),
00079 Construction(NULL), RepairHP(0), TileWidth(0), TileHeight(0),
00080 BoxWidth(0), BoxHeight(0), NumDirections(0), MinAttackRange(0),
00081 ReactRangeComputer(0), ReactRangePerson(0), Priority(0),
00082 BurnPercent(0), BurnDamageRate(0), RepairRange(0),
00083 CanCastSpell(NULL), AutoCastActive(NULL),
00084 CanTransport(false), MaxOnBoard(0),
00085 UnitType(UnitTypeLand), DecayRate(0), AnnoyComputerFactor(0),
00086 MouseAction(0), Points(0), CanTarget(0),
00087 Flip(0), Revealer(0), LandUnit(0), AirUnit(0), SeaUnit(0),
00088 ExplodeWhenKilled(0), Building(0), VisibleUnderFog(0),
00089 Coward(0), AttackFromTransporter(0),
00090 Vanishes(0), GroundAttack(0), ShoreBuilding(0), CanAttack(0),
00091 BuilderOutside(0), BuilderLost(0), CanHarvestFrom(0), Harvester(0),
00092 Neutral(0), SelectableByRectangle(0), IsNotSelectable(0), Decoration(0),
00093 Indestructible(0), Organic(0), Variable(NULL),
00094 ProductionEfficiency(100), FieldFlags(0), MovementMask(0),
00095 Sprite(NULL), ShadowSprite(NULL)
00096 {
00097 memset(&NeutralMinimapColorRGB, 0, sizeof(NeutralMinimapColorRGB));
00098 memset(ProductionRate, 0, sizeof(ProductionRate));
00099 memset(MaxUtilizationRate, 0, sizeof(MaxUtilizationRate));
00100 memset(ProductionCosts, 0, sizeof(ProductionCosts));
00101 memset(StorageCapacity, 0, sizeof(StorageCapacity));
00102 }
00103
00104
00105 CUnitType::~CUnitType()
00106 {
00107 delete DeathExplosion;
00108
00109 delete[] Variable;
00110
00111 for (int i = 0; i < PlayerMax; ++i) {
00112 delete[] Stats[i].Variables;
00113 }
00114
00115
00116 for (std::vector<CBuildRestriction *>::iterator b = BuildingRules.begin();
00117 b != BuildingRules.end(); ++b) {
00118 delete *b;
00119 }
00120 BuildingRules.clear();
00121
00122 delete[] CanCastSpell;
00123 delete[] AutoCastActive;
00124
00125 CGraphic::Free(Sprite);
00126 CGraphic::Free(ShadowSprite);
00127 }
00128
00133 void UpdateStats(int reset)
00134 {
00135 CUnitType *type;
00136 CUnitStats *stats;
00137
00138
00139
00140
00141 for (size_t j = 0; j < UnitTypes.size(); ++j) {
00142 type = UnitTypes[j];
00143 if (reset) {
00144
00145 for (int player = 0; player < PlayerMax; ++player) {
00146 stats = &type->Stats[player];
00147 if (!stats->Variables) {
00148 stats->Variables = new CVariable[UnitTypeVar.NumberVariable];
00149 }
00150 for (int i = 0; i < UnitTypeVar.NumberVariable; ++i) {
00151 stats->Variables[i] = type->Variable[i];
00152 }
00153 }
00154 }
00155
00156
00157
00158
00159 switch (type->UnitType) {
00160 case UnitTypeLand:
00161 type->MovementMask =
00162 MapFieldLandUnit |
00163 MapFieldSeaUnit |
00164 MapFieldBuilding |
00165 MapFieldCoastAllowed |
00166 MapFieldWaterAllowed |
00167 MapFieldUnpassable;
00168 break;
00169 case UnitTypeFly:
00170 type->MovementMask =
00171 MapFieldAirUnit;
00172 break;
00173 case UnitTypeNaval:
00174 if (type->CanTransport) {
00175 type->MovementMask =
00176 MapFieldLandUnit |
00177 MapFieldSeaUnit |
00178 MapFieldBuilding |
00179 MapFieldLandAllowed;
00180
00181 } else {
00182 type->MovementMask =
00183 MapFieldLandUnit |
00184 MapFieldSeaUnit |
00185 MapFieldBuilding |
00186 MapFieldCoastAllowed |
00187 MapFieldLandAllowed |
00188 MapFieldUnpassable;
00189 }
00190 break;
00191 default:
00192 DebugPrint("Where moves this unit?\n");
00193 type->MovementMask = 0;
00194 break;
00195 }
00196 if (type->Building || type->ShoreBuilding) {
00197
00198 if (type->ShoreBuilding) {
00199 type->MovementMask =
00200 MapFieldLandUnit |
00201 MapFieldSeaUnit |
00202 MapFieldBuilding |
00203 MapFieldLandAllowed;
00204 }
00205 type->MovementMask |= MapFieldNoBuilding;
00206
00207
00208
00209
00210 if (type->Variable[HP_INDEX].Max) {
00211 type->FieldFlags = MapFieldBuilding;
00212 } else {
00213 type->FieldFlags = MapFieldNoBuilding;
00214 }
00215 } else switch (type->UnitType) {
00216 case UnitTypeLand:
00217 type->FieldFlags = MapFieldLandUnit;
00218 break;
00219 case UnitTypeFly:
00220 type->FieldFlags = MapFieldAirUnit;
00221 break;
00222 case UnitTypeNaval:
00223 type->FieldFlags = MapFieldSeaUnit;
00224 break;
00225 default:
00226 DebugPrint("Where moves this unit?\n");
00227 type->FieldFlags = 0;
00228 break;
00229 }
00230 }
00231 }
00232
00240 CAnimations *AnimationsByIdent(const std::string &ident)
00241 {
00242 return AnimationMap[ident];
00243 }
00244
00252 CUnitType *UnitTypeByIdent(const std::string &ident)
00253 {
00254 return UnitTypeMap[ident];
00255 }
00256
00264 CUnitType *NewUnitTypeSlot(const std::string &ident)
00265 {
00266 CUnitType *type;
00267
00268 type = new CUnitType;
00269 if (!type) {
00270 fprintf(stderr, "Out of memory\n");
00271 ExitFatal(-1);
00272 }
00273 type->Slot = UnitTypes.size();
00274 type->Ident = ident;
00275 type->Variable = new CVariable[UnitTypeVar.NumberVariable];
00276 memcpy(type->Variable, UnitTypeVar.Variable,
00277 UnitTypeVar.NumberVariable * sizeof(*type->Variable));
00278
00279 UnitTypes.push_back(type);
00280 UnitTypeMap[type->Ident] = type;
00281 return type;
00282 }
00283
00297 void DrawUnitType(const CUnitType *type, CPlayerColorGraphic *sprite, int player, int frame,
00298 int x, int y)
00299 {
00300
00301 x -= (type->Width - type->TileWidth * TileSizeX) / 2;
00302 y -= (type->Height - type->TileHeight * TileSizeY) / 2;
00303 x += type->OffsetX;
00304 y += type->OffsetY;
00305
00306 if (type->Flip) {
00307 if (frame < 0) {
00308 sprite->DrawPlayerColorFrameClipX(player, -frame - 1, x, y);
00309 } else {
00310 sprite->DrawPlayerColorFrameClip(player, frame, x, y);
00311 }
00312 } else {
00313 int row;
00314
00315 row = type->NumDirections / 2 + 1;
00316 if (frame < 0) {
00317 frame = ((-frame - 1) / row) * type->NumDirections + type->NumDirections - (-frame - 1) % row;
00318 } else {
00319 frame = (frame / row) * type->NumDirections + frame % row;
00320 }
00321 sprite->DrawPlayerColorFrameClip(player, frame, x, y);
00322 }
00323 }
00324
00328 static int GetStillFrame(CUnitType *type)
00329 {
00330 CAnimation *anim;
00331
00332 anim = type->Animations->Still;
00333 while (anim) {
00334 if (anim->Type == AnimationFrame) {
00335
00336 return anim->D.Frame.Frame + type->NumDirections / 2;
00337 } else if (anim->Type == AnimationExactFrame) {
00338 return anim->D.Frame.Frame;
00339 }
00340 anim = anim->Next;
00341 }
00342 return type->NumDirections / 2;
00343 }
00344
00348 void InitUnitTypes(int reset_player_stats)
00349 {
00350 CUnitType *type;
00351
00352 for (size_t i = 0; i < UnitTypes.size(); ++i) {
00353 type = UnitTypes[i];
00354 Assert(type->Slot == (int)i);
00355
00356
00357 UnitTypeMap[type->Ident] = UnitTypes[i];
00358
00359
00360 type->StillFrame = GetStillFrame(type);
00361
00362
00363 for (std::vector<CBuildRestriction *>::iterator b = type->BuildingRules.begin();
00364 b < type->BuildingRules.end(); ++b) {
00365 (*b)->Init();
00366 }
00367 }
00368
00369
00370 UpdateStats(reset_player_stats);
00371 }
00372
00378 void LoadUnitTypeSprite(CUnitType *type)
00379 {
00380 if (!type->ShadowFile.empty()) {
00381 type->ShadowSprite = CGraphic::ForceNew(type->ShadowFile, type->ShadowWidth,
00382 type->ShadowHeight);
00383 type->ShadowSprite->Load();
00384 if (type->Flip) {
00385 type->ShadowSprite->Flip();
00386 }
00387 type->ShadowSprite->MakeShadow();
00388 }
00389
00390 if (!type->File.empty()) {
00391 type->Sprite = CPlayerColorGraphic::New(type->File, type->Width, type->Height);
00392 type->Sprite->Load();
00393 if (type->Flip) {
00394 type->Sprite->Flip();
00395 }
00396 }
00397 }
00398
00402 void LoadUnitTypes(void)
00403 {
00404 CUnitType *type;
00405
00406 for (size_t i = 0; i < UnitTypes.size(); ++i) {
00407 type = UnitTypes[i];
00408
00409
00410
00411
00412 type->Icon.Load();
00413
00414
00415
00416 type->Missile.Missile = MissileTypeByIdent(type->Missile.Name);
00417 if (!type->Explosion.Name.empty()) {
00418 type->Explosion.Missile = MissileTypeByIdent(type->Explosion.Name);
00419 }
00420
00421
00422
00423 if (!type->CorpseName.empty()) {
00424 type->CorpseType = UnitTypeByIdent(type->CorpseName);
00425 }
00426
00427
00428
00429
00430 if (!type->Sprite) {
00431 ShowLoadProgress("Unit \"%s\"", type->Name.c_str());
00432 LoadUnitTypeSprite(type);
00433 }
00434 }
00435 }
00436
00440 static void CleanAnimation(CAnimation *anim)
00441 {
00442 int i;
00443 CAnimation *ptr;
00444
00445 ptr = anim;
00446 while (ptr->Type != AnimationNone) {
00447 if (ptr->Type == AnimationSound) {
00448 delete[] ptr->D.Sound.Name;
00449 } else if (ptr->Type == AnimationRandomSound) {
00450 for (i = 0; i < ptr->D.RandomSound.NumSounds; ++i) {
00451 delete[] ptr->D.RandomSound.Name[i];
00452 }
00453 delete[] ptr->D.RandomSound.Name;
00454 delete[] ptr->D.RandomSound.Sound;
00455 }
00456 ++ptr;
00457 }
00458 delete[] anim;
00459 }
00460
00464 void CleanUnitTypes(void)
00465 {
00466 int j;
00467
00468
00469 for (int j = 0; j < NumAnimations; ++j) {
00470 CleanAnimation(AnimationsArray[j]);
00471 }
00472 NumAnimations = 0;
00473
00474 std::map<std::string, CAnimations *>::iterator at;
00475 for (at = AnimationMap.begin(); at != AnimationMap.end(); ++at) {
00476 delete (*at).second;
00477 }
00478 AnimationMap.clear();
00479
00480
00481
00482 for (size_t i = 0; i < UnitTypes.size(); ++i) {
00483 delete UnitTypes[i];
00484 }
00485 UnitTypes.clear();
00486 UnitTypeMap.clear();
00487
00488 for (j = 0; j < UnitTypeVar.NumberVariable; ++j) {
00489 delete[] UnitTypeVar.VariableName[j];
00490 }
00491 delete[] UnitTypeVar.VariableName;
00492 UnitTypeVar.VariableName = NULL;
00493 delete[] UnitTypeVar.Variable;
00494 UnitTypeVar.Variable = NULL;
00495 UnitTypeVar.NumberVariable = 0;
00496 for (std::vector<CDecoVar *>::iterator it = UnitTypeVar.DecoVar.begin();
00497 it != UnitTypeVar.DecoVar.end(); ++it) {
00498 delete (*it);
00499 }
00500 UnitTypeVar.DecoVar.clear();
00501 }
00502