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 #include <string.h>
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037
00038 #include "stratagus.h"
00039 #include "video.h"
00040 #include "map.h"
00041 #include "sound.h"
00042 #include "unitsound.h"
00043 #include "unittype.h"
00044 #include "animation.h"
00045 #include "icons.h"
00046 #include "missile.h"
00047 #include "script.h"
00048 #include "construct.h"
00049 #include "spells.h"
00050 #include "font.h"
00051 #include "unit.h"
00052 #include "unit_manager.h"
00053 #include "player.h"
00054 #include "luacallback.h"
00055
00056
00057
00058
00059
00060
00061 #define MAGIC_FOR_NEW_UNITS 33
00062
00063
00064
00065
00066
00067 CAnimation *AnimationsArray[ANIMATIONS_MAXANIM];
00068 int NumAnimations;
00069
00070 std::map<std::string, CAnimations *> AnimationMap;
00071
00072 CUnitTypeVar UnitTypeVar;
00073
00074 struct LabelsStruct {
00075 CAnimation *Anim;
00076 std::string Name;
00077 };
00078 static std::vector<LabelsStruct> Labels;
00079
00080 struct LabelsLaterStruct {
00081 CAnimation **Anim;
00082 std::string Name;
00083 };
00084 static std::vector<LabelsLaterStruct> LabelsLater;
00085
00086
00087
00088
00089
00090 extern int GetSpriteIndex(const std::string &spriteName);
00091
00099 unsigned CclGetResourceByName(lua_State *l)
00100 {
00101 const char *value;
00102
00103 value = LuaToString(l, -1);
00104 for (int i = 0; i < MaxCosts; ++i) {
00105 if (value == DefaultResourceNames[i]) {
00106 return i;
00107 }
00108 }
00109 LuaError(l, "Unsupported resource tag: %s" _C_ value);
00110 return 0xABCDEF;
00111 }
00112
00119 static void ParseBuildingRules(lua_State *l, std::vector<CBuildRestriction *> &blist)
00120 {
00121 const char *value;
00122 int args;
00123 CBuildRestrictionAnd *andlist = new CBuildRestrictionAnd();
00124
00125 args = lua_objlen(l, -1);
00126 Assert(!(args & 1));
00127
00128 for (int i = 0; i < args; ++i) {
00129 lua_rawgeti(l, -1, i + 1);
00130 value = LuaToString(l, -1);
00131 lua_pop(l, 1);
00132 ++i;
00133 lua_rawgeti(l, -1, i + 1);
00134 if (!lua_istable(l, -1)) {
00135 LuaError(l, "incorrect argument");
00136 }
00137 if (!strcmp(value, "distance")) {
00138 CBuildRestrictionDistance *b = new CBuildRestrictionDistance;
00139
00140 for (lua_pushnil(l); lua_next(l, -2); lua_pop(l, 1)) {
00141 value = LuaToString(l, -2);
00142 if (!strcmp(value, "Distance")) {
00143 b->Distance = LuaToNumber(l, -1);
00144 } else if (!strcmp(value, "DistanceType")) {
00145 value = LuaToString(l, -1);
00146 if (value[0] == '=') {
00147 if ((value[1] == '=' && value[2] == '\0') || (value[1] == '\0')) {
00148 b->DistanceType = Equal;
00149 }
00150 } else if (value[0] == '>') {
00151 if (value[1] == '=' && value[2] == '\0') {
00152 b->DistanceType = GreaterThanEqual;
00153 } else if (value[1] == '\0') {
00154 b->DistanceType = GreaterThan;
00155 }
00156 } else if (value[0] == '<') {
00157 if (value[1] == '=' && value[2] == '\0') {
00158 b->DistanceType = LessThanEqual;
00159 } else if (value[1] == '\0') {
00160 b->DistanceType = LessThan;
00161 }
00162 } else if (value[0] == '!' && value[1] == '=' && value[2] == '\0') {
00163 b->DistanceType = NotEqual;
00164 }
00165 } else if (!strcmp(value, "Type")) {
00166 b->RestrictTypeName = LuaToString(l, -1);
00167 } else {
00168 LuaError(l, "Unsupported BuildingRules distance tag: %s" _C_ value);
00169 }
00170 }
00171 andlist->push_back(b);
00172 } else if (!strcmp(value, "addon")) {
00173 CBuildRestrictionAddOn *b = new CBuildRestrictionAddOn;
00174
00175 for (lua_pushnil(l); lua_next(l, -2); lua_pop(l, 1)) {
00176 value = LuaToString(l, -2);
00177 if (!strcmp(value, "OffsetX")) {
00178 b->OffsetX = LuaToNumber(l, -1);
00179 } else if (!strcmp(value, "OffsetY")) {
00180 b->OffsetY = LuaToNumber(l, -1);
00181 } else if (!strcmp(value, "Type")) {
00182 b->ParentName = LuaToString(l, -1);
00183 } else {
00184 LuaError(l, "Unsupported BuildingRules addon tag: %s" _C_ value);
00185 }
00186 }
00187 andlist->push_back(b);
00188 } else if (!strcmp(value, "ontop")) {
00189 CBuildRestrictionOnTop *b = new CBuildRestrictionOnTop;
00190
00191 for (lua_pushnil(l); lua_next(l, -2); lua_pop(l, 1)) {
00192 value = LuaToString(l, -2);
00193 if (!strcmp(value, "Type")) {
00194 b->ParentName = LuaToString(l, -1);
00195 } else if (!strcmp(value, "ReplaceOnDie")) {
00196 b->ReplaceOnDie = LuaToBoolean(l, -1);
00197 } else if (!strcmp(value, "ReplaceOnBuild")) {
00198 b->ReplaceOnBuild = LuaToBoolean(l, -1);
00199 } else {
00200 LuaError(l, "Unsupported BuildingRules ontop tag: %s" _C_ value);
00201 }
00202 }
00203 andlist->push_back(b);
00204 } else {
00205 LuaError(l, "Unsupported BuildingRules tag: %s" _C_ value);
00206 }
00207 lua_pop(l, 1);
00208 }
00209 blist.push_back(andlist);
00210 }
00211
00217 static int CclDefineUnitType(lua_State *l)
00218 {
00219 const char *value;
00220 CUnitType *type;
00221 const char *str;
00222 int i;
00223 int redefine;
00224 int subargs;
00225 int k;
00226
00227 LuaCheckArgs(l, 2);
00228 if (!lua_istable(l, 2)) {
00229 LuaError(l, "incorrect argument");
00230 }
00231
00232
00233 str = LuaToString(l, 1);
00234 type = UnitTypeByIdent(str);
00235 if (type) {
00236 redefine = 1;
00237 } else {
00238 type = NewUnitTypeSlot(str);
00239 redefine = 0;
00240 }
00241
00242 type->NumDirections = 0;
00243
00244
00245
00246
00247 for (lua_pushnil(l); lua_next(l, 2); lua_pop(l, 1)) {
00248 value = LuaToString(l, -2);
00249 if (!strcmp(value, "Name")) {
00250 type->Name = LuaToString(l, -1);
00251 } else if (!strcmp(value, "Image")) {
00252 if (!lua_istable(l, -1)) {
00253 LuaError(l, "incorrect argument");
00254 }
00255 subargs = lua_objlen(l, -1);
00256 for (k = 0; k < subargs; ++k) {
00257 lua_rawgeti(l, -1, k + 1);
00258 value = LuaToString(l, -1);
00259 lua_pop(l, 1);
00260 ++k;
00261
00262 if (!strcmp(value, "file")) {
00263 lua_rawgeti(l, -1, k + 1);
00264 type->File = LuaToString(l, -1);
00265 lua_pop(l, 1);
00266 } else if (!strcmp(value, "size")) {
00267 lua_rawgeti(l, -1, k + 1);
00268 if (!lua_istable(l, -1)) {
00269 LuaError(l, "incorrect argument");
00270 }
00271 lua_rawgeti(l, -1, 1);
00272 type->Width = LuaToNumber(l, -1);
00273 lua_pop(l, 1);
00274 lua_rawgeti(l, -1, 2);
00275 type->Height = LuaToNumber(l, -1);
00276 lua_pop(l, 1);
00277 lua_pop(l, 1);
00278 } else {
00279 LuaError(l, "Unsupported image tag: %s" _C_ value);
00280 }
00281 }
00282 } else if (!strcmp(value, "Shadow")) {
00283 if (!lua_istable(l, -1)) {
00284 LuaError(l, "incorrect argument");
00285 }
00286 subargs = lua_objlen(l, -1);
00287 for (k = 0; k < subargs; ++k) {
00288 lua_rawgeti(l, -1, k + 1);
00289 value = LuaToString(l, -1);
00290 lua_pop(l, 1);
00291 ++k;
00292
00293 if (!strcmp(value, "file")) {
00294 lua_rawgeti(l, -1, k + 1);
00295 type->ShadowFile = LuaToString(l, -1);
00296 lua_pop(l, 1);
00297 } else if (!strcmp(value, "size")) {
00298 lua_rawgeti(l, -1, k + 1);
00299 if (!lua_istable(l, -1)) {
00300 LuaError(l, "incorrect argument");
00301 }
00302 lua_rawgeti(l, -1, 1);
00303 type->ShadowWidth = LuaToNumber(l, -1);
00304 lua_pop(l, 1);
00305 lua_rawgeti(l, -1, 2);
00306 type->ShadowHeight = LuaToNumber(l, -1);
00307 lua_pop(l, 1);
00308 lua_pop(l, 1);
00309 } else if (!strcmp(value, "offset")) {
00310 lua_rawgeti(l, -1, k + 1);
00311 if (!lua_istable(l, -1)) {
00312 LuaError(l, "incorrect argument");
00313 }
00314 lua_rawgeti(l, -1, 1);
00315 type->ShadowOffsetX = LuaToNumber(l, -1);
00316 lua_pop(l, 1);
00317 lua_rawgeti(l, -1, 2);
00318 type->ShadowOffsetY = LuaToNumber(l, -1);
00319 lua_pop(l, 1);
00320 lua_pop(l, 1);
00321 } else {
00322 LuaError(l, "Unsupported shadow tag: %s" _C_ value);
00323 }
00324 }
00325 } else if (!strcmp(value, "Offset")) {
00326 if (!lua_istable(l, -1) || lua_objlen(l, -1) != 2) {
00327 LuaError(l, "incorrect argument");
00328 }
00329 lua_rawgeti(l, -1, 1);
00330 type->OffsetX = LuaToNumber(l, -1);
00331 lua_pop(l, 1);
00332 lua_rawgeti(l, -1, 2);
00333 type->OffsetY = LuaToNumber(l, -1);
00334 lua_pop(l, 1);
00335 } else if (!strcmp(value, "Flip")) {
00336 type->Flip = LuaToBoolean(l, -1);
00337 } else if (!strcmp(value, "Animations")) {
00338 type->Animations = AnimationsByIdent(LuaToString(l, -1));
00339 if (!type->Animations) {
00340 DebugPrint("Warning animation `%s' not found\n" _C_ LuaToString(l, -1));
00341 }
00342 } else if (!strcmp(value, "Icon")) {
00343 type->Icon.Name = LuaToString(l, -1);
00344 type->Icon.Icon = NULL;
00345 } else if (!strcmp(value, "EnergyValue")) {
00346 if (!lua_isnumber(l, -1)) {
00347 LuaError(l, "incorrect argument");
00348 }
00349 type->SetEnergyValue(LuaToNumber(l, -1));
00350 } else if (!strcmp(value, "MagmaValue")) {
00351 if (!lua_isnumber(l, -1)) {
00352 LuaError(l, "incorrect argument");
00353 }
00354 type->SetMagmaValue(LuaToNumber(l, -1));
00355 } else if (!strcmp(value, "MaxEnergyUtilizationRate")) {
00356 if (!lua_isnumber(l, -1)) {
00357 LuaError(l, "incorrect argument");
00358 }
00359 type->SetMaxEnergyUtilizationRate(LuaToNumber(l, -1));
00360 } else if (!strcmp(value, "MaxMagmaUtilizationRate")) {
00361 if (!lua_isnumber(l, -1)) {
00362 LuaError(l, "incorrect argument");
00363 }
00364 type->SetMaxMagmaUtilizationRate(LuaToNumber(l, -1));
00365 } else if (!strcmp(value, "EnergyProductionRate")) {
00366 if (!lua_isnumber(l, -1)) {
00367 LuaError(l, "incorrect argument");
00368 }
00369 type->SetEnergyProductionRate(LuaToNumber(l, -1));
00370 } else if (!strcmp(value, "MagmaProductionRate")) {
00371 if (!lua_isnumber(l, -1)) {
00372 LuaError(l, "incorrect argument");
00373 }
00374 type->SetMagmaProductionRate(LuaToNumber(l, -1));
00375 } else if (!strcmp(value, "EnergyStorageCapacity")) {
00376 if (!lua_isnumber(l, -1)) {
00377 LuaError(l, "incorrect argument");
00378 }
00379 type->SetEnergyStorageCapacity(LuaToNumber(l, -1));
00380 } else if (!strcmp(value, "MagmaStorageCapacity")) {
00381 if (!lua_isnumber(l, -1)) {
00382 LuaError(l, "incorrect argument");
00383 }
00384 type->SetMagmaStorageCapacity(LuaToNumber(l, -1));
00385 } else if (!strcmp(value, "Construction")) {
00386
00387 type->Construction = ConstructionByIdent(LuaToString(l, -1));
00388 } else if (!strcmp(value, "DrawLevel")) {
00389 type->DrawLevel = LuaToNumber(l, -1);
00390 } else if (!strcmp(value, "MaxOnBoard")) {
00391 type->MaxOnBoard = LuaToNumber(l, -1);
00392 } else if (!strcmp(value, "RegenerationRate")) {
00393 type->Variable[HP_INDEX].Increase = LuaToNumber(l, -1);
00394 } else if (!strcmp(value, "BurnPercent")) {
00395 type->BurnPercent = LuaToNumber(l, -1);
00396 } else if (!strcmp(value, "BurnDamageRate")) {
00397 type->BurnDamageRate = LuaToNumber(l, -1);
00398 } else if (!strcmp(value, "MaxMana")) {
00399 type->Variable[MANA_INDEX].Max = LuaToNumber(l, -1);
00400 type->Variable[MANA_INDEX].Value = (type->Variable[MANA_INDEX].Max * MAGIC_FOR_NEW_UNITS) / 100;
00401 type->Variable[MANA_INDEX].Increase = 1;
00402 type->Variable[MANA_INDEX].Enable = 1;
00403 } else if (!strcmp(value, "TileSize")) {
00404 if (!lua_istable(l, -1) || lua_objlen(l, -1) != 2) {
00405 LuaError(l, "incorrect argument");
00406 }
00407 lua_rawgeti(l, -1, 1);
00408 type->TileWidth = LuaToNumber(l, -1);
00409 lua_pop(l, 1);
00410 lua_rawgeti(l, -1, 2);
00411 type->TileHeight = LuaToNumber(l, -1);
00412 lua_pop(l, 1);
00413 } else if (!strcmp(value, "Decoration")) {
00414 type->Decoration = LuaToBoolean(l, -1);
00415 } else if (!strcmp(value, "NeutralMinimapColor")) {
00416 if (!lua_istable(l, -1) || lua_objlen(l, -1) != 3) {
00417 LuaError(l, "incorrect argument");
00418 }
00419 lua_rawgeti(l, -1, 1);
00420 type->NeutralMinimapColorRGB.r = LuaToNumber(l, -1);
00421 lua_pop(l, 1);
00422 lua_rawgeti(l, -1, 2);
00423 type->NeutralMinimapColorRGB.g = LuaToNumber(l, -1);
00424 lua_pop(l, 1);
00425 lua_rawgeti(l, -1, 3);
00426 type->NeutralMinimapColorRGB.b = LuaToNumber(l, -1);
00427 lua_pop(l, 1);
00428 } else if (!strcmp(value, "BoxSize")) {
00429 if (!lua_istable(l, -1) || lua_objlen(l, -1) != 2) {
00430 LuaError(l, "incorrect argument");
00431 }
00432 lua_rawgeti(l, -1, 1);
00433 type->BoxWidth = LuaToNumber(l, -1);
00434 lua_pop(l, 1);
00435 lua_rawgeti(l, -1, 2);
00436 type->BoxHeight = LuaToNumber(l, -1);
00437 lua_pop(l, 1);
00438 } else if (!strcmp(value, "NumDirections")) {
00439 type->NumDirections = LuaToNumber(l, -1);
00440 } else if (!strcmp(value, "Revealer")) {
00441 type->Revealer = LuaToBoolean(l, -1);
00442 } else if (!strcmp(value, "ComputerReactionRange")) {
00443 type->ReactRangeComputer = LuaToNumber(l, -1);
00444 } else if (!strcmp(value, "PersonReactionRange")) {
00445 type->ReactRangePerson = LuaToNumber(l, -1);
00446 } else if (!strcmp(value, "Missile")) {
00447 type->Missile.Name = LuaToString(l, -1);
00448 type->Missile.Missile = NULL;
00449 } else if (!strcmp(value, "MinAttackRange")) {
00450 type->MinAttackRange = LuaToNumber(l, -1);
00451 } else if (!strcmp(value, "MaxAttackRange")) {
00452 type->Variable[ATTACKRANGE_INDEX].Value = LuaToNumber(l, -1);
00453 type->Variable[ATTACKRANGE_INDEX].Max = LuaToNumber(l, -1);
00454 } else if (!strcmp(value, "Priority")) {
00455 type->Priority = LuaToNumber(l, -1);
00456 } else if (!strcmp(value, "AnnoyComputerFactor")) {
00457 type->AnnoyComputerFactor = LuaToNumber(l, -1);
00458 } else if (!strcmp(value, "DecayRate")) {
00459 type->DecayRate = LuaToNumber(l, -1);
00460 } else if (!strcmp(value, "Points")) {
00461 type->Points = LuaToNumber(l, -1);
00462 } else if (!strcmp(value, "Corpse")) {
00463 type->CorpseName = LuaToString(l, -1);
00464 type->CorpseType = NULL;
00465 } else if (!strcmp(value, "ExplodeWhenKilled")) {
00466 type->ExplodeWhenKilled = 1;
00467 type->Explosion.Name = LuaToString(l, -1);
00468 type->Explosion.Missile = NULL;
00469 } else if (!strcmp(value, "DeathExplosion")) {
00470 type->DeathExplosion = new LuaCallback(l, -1);
00471 } else if (!strcmp(value, "Type")) {
00472 value = LuaToString(l, -1);
00473 if (!strcmp(value, "land")) {
00474 type->UnitType = UnitTypeLand;
00475 } else if (!strcmp(value, "fly")) {
00476 type->UnitType = UnitTypeFly;
00477 } else if (!strcmp(value, "naval")) {
00478 type->UnitType = UnitTypeNaval;
00479 } else {
00480 LuaError(l, "Unsupported Type: %s" _C_ value);
00481 }
00482
00483 } else if (!strcmp(value, "RightMouseAction")) {
00484 value = LuaToString(l, -1);
00485 if (!strcmp(value, "none")) {
00486 type->MouseAction = MouseActionNone;
00487 } else if (!strcmp(value, "attack")) {
00488 type->MouseAction = MouseActionAttack;
00489 } else if (!strcmp(value, "move")) {
00490 type->MouseAction = MouseActionMove;
00491 } else if (!strcmp(value, "harvest")) {
00492 type->MouseAction = MouseActionHarvest;
00493 } else if (!strcmp(value, "spell-cast")) {
00494 type->MouseAction = MouseActionSpellCast;
00495 } else if (!strcmp(value, "sail")) {
00496 type->MouseAction = MouseActionSail;
00497 } else {
00498 LuaError(l, "Unsupported RightMouseAction: %s" _C_ value);
00499 }
00500
00501 } else if (!strcmp(value, "CanGroundAttack")) {
00502 type->GroundAttack = LuaToBoolean(l, -1);
00503 } else if (!strcmp(value, "CanAttack")) {
00504 type->CanAttack = LuaToBoolean(l, -1);
00505 } else if (!strcmp(value, "RepairRange")) {
00506 type->RepairRange = LuaToNumber(l, -1);
00507 } else if (!strcmp(value, "RepairHp")) {
00508 type->RepairHP = LuaToNumber(l, -1);
00509 } else if (!strcmp(value, "CanTargetLand")) {
00510 if (LuaToBoolean(l, -1)) {
00511 type->CanTarget |= CanTargetLand;
00512 } else {
00513 type->CanTarget &= ~CanTargetLand;
00514 }
00515 } else if (!strcmp(value, "CanTargetSea")) {
00516 if (LuaToBoolean(l, -1)) {
00517 type->CanTarget |= CanTargetSea;
00518 } else {
00519 type->CanTarget &= ~CanTargetSea;
00520 }
00521 } else if (!strcmp(value, "CanTargetAir")) {
00522 if (LuaToBoolean(l, -1)) {
00523 type->CanTarget |= CanTargetAir;
00524 } else {
00525 type->CanTarget &= ~CanTargetAir;
00526 }
00527
00528 } else if (!strcmp(value, "Building")) {
00529 type->Building = LuaToBoolean(l, -1);
00530 } else if (!strcmp(value, "VisibleUnderFog")) {
00531 type->VisibleUnderFog = LuaToBoolean(l, -1);
00532 } else if (!strcmp(value, "BuildingRules")) {
00533 if (!lua_istable(l, -1)) {
00534 LuaError(l, "incorrect argument");
00535 }
00536 subargs = lua_objlen(l, -1);
00537
00538 for (std::vector<CBuildRestriction *>::iterator b = type->BuildingRules.begin();
00539 b != type->BuildingRules.end(); ++b) {
00540 delete *b;
00541 }
00542 type->BuildingRules.clear();
00543 for (k = 0; k < subargs; ++k) {
00544 lua_rawgeti(l, -1, k + 1);
00545 if (!lua_istable(l, -1)) {
00546 LuaError(l, "incorrect argument");
00547 }
00548 ParseBuildingRules(l, type->BuildingRules);
00549 lua_pop(l, 1);
00550 }
00551 } else if (!strcmp(value, "BuilderOutside")) {
00552 type->BuilderOutside = LuaToBoolean(l, -1);
00553 } else if (!strcmp(value, "BuilderLost")) {
00554 type->BuilderLost = LuaToBoolean(l, -1);
00555 } else if (!strcmp(value, "ShoreBuilding")) {
00556 type->ShoreBuilding = LuaToBoolean(l, -1);
00557 } else if (!strcmp(value, "LandUnit")) {
00558 type->LandUnit = LuaToBoolean(l, -1);
00559 } else if (!strcmp(value, "AirUnit")) {
00560 type->AirUnit = LuaToBoolean(l, -1);
00561 } else if (!strcmp(value, "SeaUnit")) {
00562 type->SeaUnit = LuaToBoolean(l, -1);
00563 } else if (!strcmp(value, "Indestructible")) {
00564 type->Indestructible = LuaToNumber(l, -1);
00565 } else if (!strcmp(value, "CanTransport")) {
00566 type->CanTransport = LuaToBoolean(l, -1);
00567 } else if (!strcmp(value, "AttackFromTransporter")) {
00568 type->AttackFromTransporter = LuaToBoolean(l, -1);
00569 } else if (!strcmp(value, "Coward")) {
00570 type->Coward = LuaToBoolean(l, -1);
00571 } else if (!strcmp(value, "Harvester")) {
00572 type->Harvester = LuaToBoolean(l, -1);
00573 } else if (!strcmp(value, "Neutral")) {
00574 type->Neutral = LuaToBoolean(l, -1);
00575 } else if (!strcmp(value, "CanHarvestFrom")) {
00576 type->CanHarvestFrom = LuaToBoolean(l, -1);
00577 } else if (!strcmp(value, "Vanishes")) {
00578 type->Vanishes = LuaToBoolean(l, -1);
00579 } else if (!strcmp(value, "CanCastSpell")) {
00580 if (!lua_istable(l, -1)) {
00581 LuaError(l, "incorrect argument");
00582 }
00583
00584
00585
00586
00587 if (!type->CanCastSpell) {
00588 type->CanCastSpell = new char[SpellTypeTable.size()];
00589 memset(type->CanCastSpell, 0, SpellTypeTable.size() * sizeof(char));
00590 }
00591 subargs = lua_objlen(l, -1);
00592 if (subargs == 0) {
00593 delete[] type->CanCastSpell;
00594 type->CanCastSpell = NULL;
00595
00596 }
00597 for (k = 0; k < subargs; ++k) {
00598 const SpellType *spell;
00599
00600 lua_rawgeti(l, -1, k + 1);
00601 value = LuaToString(l, -1);
00602 spell = SpellTypeByIdent(value);
00603 if (spell == NULL) {
00604 LuaError(l, "Unknown spell type: %s" _C_ value);
00605 }
00606 lua_pop(l, 1);
00607 type->CanCastSpell[spell->Slot] = 1;
00608 }
00609 } else if (!strcmp(value, "AutoCastActive")) {
00610 if (!lua_istable(l, -1)) {
00611 LuaError(l, "incorrect argument");
00612 }
00613
00614
00615
00616
00617 if (!type->AutoCastActive) {
00618 type->AutoCastActive = new char[SpellTypeTable.size()];
00619 memset(type->AutoCastActive, 0, SpellTypeTable.size() * sizeof(char));
00620 }
00621 subargs = lua_objlen(l, -1);
00622 if (subargs == 0) {
00623 delete[] type->AutoCastActive;
00624 type->AutoCastActive = NULL;
00625
00626 }
00627 for (k = 0; k < subargs; ++k) {
00628 const SpellType *spell;
00629
00630 lua_rawgeti(l, -1, k + 1);
00631 value = LuaToString(l, -1);
00632 spell = SpellTypeByIdent(value);
00633 if (spell == NULL) {
00634 LuaError(l, "AutoCastActive : Unknown spell type: %s" _C_ value);
00635 }
00636 if (!spell->AutoCast) {
00637 LuaError(l, "AutoCastActive : Define autocast method for %s." _C_ value);
00638 }
00639 lua_pop(l, 1);
00640 type->AutoCastActive[spell->Slot] = 1;
00641 }
00642 } else if (!strcmp(value, "ProductionEfficiency")) {
00643 type->ProductionEfficiency = LuaToNumber(l, -1);
00644 } else if (!strcmp(value, "IsNotSelectable")) {
00645 type->IsNotSelectable = LuaToBoolean(l, -1);
00646 } else if (!strcmp(value, "SelectableByRectangle")) {
00647 type->SelectableByRectangle = LuaToBoolean(l, -1);
00648 } else if (!strcmp(value, "Organic")) {
00649 type->Organic = LuaToBoolean(l, -1);
00650 } else if (!strcmp(value, "Sounds")) {
00651 if (!lua_istable(l, -1)) {
00652 LuaError(l, "incorrect argument");
00653 }
00654 subargs = lua_objlen(l, -1);
00655 for (k = 0; k < subargs; ++k) {
00656 lua_rawgeti(l, -1, k + 1);
00657 value = LuaToString(l, -1);
00658 lua_pop(l, 1);
00659 ++k;
00660
00661 if (!strcmp(value, "selected")) {
00662 lua_rawgeti(l, -1, k + 1);
00663 type->Sound.Selected.Name = LuaToString(l, -1);
00664 lua_pop(l, 1);
00665 } else if (!strcmp(value, "acknowledge")) {
00666 lua_rawgeti(l, -1, k + 1);
00667 type->Sound.Acknowledgement.Name = LuaToString(l, -1);
00668 lua_pop(l, 1);
00669 } else if (!strcmp(value, "ready")) {
00670 lua_rawgeti(l, -1, k + 1);
00671 type->Sound.Ready.Name = LuaToString(l, -1);
00672 lua_pop(l, 1);
00673 } else if (!strcmp(value, "repair")) {
00674 lua_rawgeti(l, -1, k + 1);
00675 type->Sound.Repair.Name = LuaToString(l, -1);
00676 lua_pop(l, 1);
00677 } else if (!strcmp(value, "harvest")) {
00678 lua_rawgeti(l, -1, k + 1);
00679 type->Sound.Harvest.Name = LuaToString(l, -1);
00680 lua_pop(l, 1);
00681 } else if (!strcmp(value, "help")) {
00682 lua_rawgeti(l, -1, k + 1);
00683 type->Sound.Help.Name = LuaToString(l, -1);
00684 lua_pop(l, 1);
00685 } else if (!strcmp(value, "dead")) {
00686 lua_rawgeti(l, -1, k + 1);
00687 type->Sound.Dead.Name = LuaToString(l, -1);
00688 lua_pop(l, 1);
00689 } else {
00690 LuaError(l, "Unsupported sound tag: %s" _C_ value);
00691 }
00692 }
00693 } else {
00694 i = GetVariableIndex(value);
00695 if (i != -1) {
00696 if (lua_isboolean(l, -1)) {
00697 type->Variable[i].Enable = LuaToBoolean(l, -1);
00698 } else if (lua_istable(l, -1)) {
00699 DefineVariableField(l, type->Variable + i, -1);
00700 } else if (lua_isnumber(l, -1)) {
00701 type->Variable[i].Enable = 1;
00702 type->Variable[i].Value = LuaToNumber(l, -1);
00703 type->Variable[i].Max = LuaToNumber(l, -1);
00704 } else {
00705 LuaError(l, "incorrect argument for the variable in unittype");
00706 }
00707 continue;
00708 }
00709 printf("\n%s\n", type->Name.c_str());
00710 LuaError(l, "Unsupported tag: %s" _C_ value);
00711 }
00712 }
00713
00714
00715
00716 if (type->Building && type->NumDirections == 0) {
00717 type->NumDirections = 1;
00718 } else if (type->NumDirections == 0) {
00719 type->NumDirections = 8;
00720 }
00721
00722
00723 if (type->MouseAction == MouseActionAttack && !type->CanAttack) {
00724 LuaError(l, "Unit-type `%s': right-attack is set, but can-attack is not\n" _C_ type->Name.c_str());
00725 }
00726
00727 return 0;
00728 }
00729
00730
00731
00737 CUnitType *CclGetUnitType(lua_State *l)
00738 {
00739 CUnitType *unittype = NULL;
00740
00741 if (lua_isstring(l, -1)) {
00742 unittype = UnitTypeByIdent(LuaToString(l, -1));
00743 } else if (lua_isuserdata(l, -1)) {
00744 LuaUserData *data;
00745 data = (LuaUserData *)lua_touserdata(l, -1);
00746 if (data->Type == LuaUnitType) {
00747 unittype = (CUnitType *)data->Data;
00748 }
00749 }
00750 if (!unittype) {
00751 LuaError(l, "CclGetUnitType: not a unit-type");
00752 }
00753 return unittype;
00754 }
00755
00756
00757
00761 static void AddLabel(lua_State *l, CAnimation *anim, const std::string &name)
00762 {
00763 LabelsStruct label;
00764 label.Anim = anim;
00765 label.Name = name;
00766 Labels.push_back(label);
00767 }
00768
00772 static CAnimation *FindLabel(lua_State *l, const std::string &name)
00773 {
00774 for (int i = 0; i < (int)Labels.size(); ++i) {
00775 if (Labels[i].Name == name) {
00776 return Labels[i].Anim;
00777 }
00778 }
00779 LuaError(l, "Label not found: %s" _C_ name.c_str());
00780 return NULL;
00781 }
00782
00786 static void FindLabelLater(lua_State *l, CAnimation **anim, const std::string &name)
00787 {
00788 LabelsLaterStruct label;
00789 label.Anim = anim;
00790 label.Name = name;
00791 LabelsLater.push_back(label);
00792 }
00793
00797 static void FixLabels(lua_State *l)
00798 {
00799 for (int i = 0; i < (int)LabelsLater.size(); ++i) {
00800 *LabelsLater[i].Anim = FindLabel(l, LabelsLater[i].Name);
00801 }
00802 }
00803
00807 static void ParseAnimationFrame(lua_State *l, const char *str,
00808 CAnimation *anim)
00809 {
00810 char *op1;
00811 char *op2;
00812
00813 op1 = new_strdup(str);
00814 op2 = strchr(op1, ' ');
00815 if (op2) {
00816 while (*op2 == ' ') {
00817 *op2++ = '\0';
00818 }
00819 }
00820
00821 if (!strcmp(op1, "frame")) {
00822 anim->Type = AnimationFrame;
00823 anim->D.Frame.Frame = atoi(op2);
00824 } else if (!strcmp(op1, "exact-frame")) {
00825 anim->Type = AnimationExactFrame;
00826 anim->D.Frame.Frame = atoi(op2);
00827 } else if (!strcmp(op1, "random-frame")) {
00828 anim->Type = AnimationRandomFrame;
00829 anim->D.RandomFrame.MinFrame = atoi(op2);
00830 op2 = strchr(op2, ' ');
00831 while (*op2 == ' ') {
00832 ++op2;
00833 }
00834 anim->D.RandomFrame.MaxFrame = atoi(op2);
00835 } else if (!strcmp(op1, "wait")) {
00836 anim->Type = AnimationWait;
00837 anim->D.Wait.Wait = atoi(op2);
00838 } else if (!strcmp(op1, "random-wait")) {
00839 anim->Type = AnimationRandomWait;
00840 anim->D.RandomWait.MinWait = atoi(op2);
00841 op2 = strchr(op2, ' ');
00842 while (*op2 == ' ') {
00843 ++op2;
00844 }
00845 anim->D.RandomWait.MaxWait = atoi(op2);
00846 } else if (!strcmp(op1, "sound")) {
00847 anim->Type = AnimationSound;
00848 anim->D.Sound.Name = new_strdup(op2);
00849 } else if (!strcmp(op1, "random-sound")) {
00850 int count;
00851 char *next;
00852
00853 anim->Type = AnimationRandomSound;
00854 count = 0;
00855 while (op2 && *op2) {
00856 next = strchr(op2, ' ');
00857 if (next) {
00858 while (*next == ' ') {
00859 *next++ = '\0';
00860 }
00861 }
00862 ++count;
00863 char **newname = new char *[count];
00864 if (anim->D.RandomSound.Name) {
00865 memcpy(newname, anim->D.RandomSound.Name, (count - 1) * sizeof(char *));
00866 delete[] anim->D.RandomSound.Name;
00867 }
00868 anim->D.RandomSound.Name = newname;
00869 anim->D.RandomSound.Name[count - 1] = new_strdup(op2);
00870 op2 = next;
00871 }
00872 anim->D.RandomSound.NumSounds = count;
00873 anim->D.RandomSound.Sound = new CSound *[count];
00874 } else if (!strcmp(op1, "attack")) {
00875 anim->Type = AnimationAttack;
00876 } else if (!strcmp(op1, "rotate")) {
00877 anim->Type = AnimationRotate;
00878 anim->D.Rotate.Rotate = atoi(op2);
00879 } else if (!strcmp(op1, "random-rotate")) {
00880 anim->Type = AnimationRandomRotate;
00881 anim->D.Rotate.Rotate = atoi(op2);
00882 } else if (!strcmp(op1, "move")) {
00883 anim->Type = AnimationMove;
00884 anim->D.Move.Move = atoi(op2);
00885 } else if (!strcmp(op1, "unbreakable")) {
00886 anim->Type = AnimationUnbreakable;
00887 if (!strcmp(op2, "begin")) {
00888 anim->D.Unbreakable.Begin = 1;
00889 } else if (!strcmp(op2, "end")) {
00890 anim->D.Unbreakable.Begin = 0;
00891 } else {
00892 LuaError(l, "Unbreakable must be 'begin' or 'end'. Found: %s" _C_ op2);
00893 }
00894 } else if (!strcmp(op1, "label")) {
00895 anim->Type = AnimationLabel;
00896 AddLabel(l, anim, op2);
00897 } else if (!strcmp(op1, "goto")) {
00898 anim->Type = AnimationGoto;
00899 FindLabelLater(l, &anim->D.Goto.Goto, op2);
00900 } else if (!strcmp(op1, "random-goto")) {
00901 char *label;
00902
00903 anim->Type = AnimationRandomGoto;
00904 label = strchr(op2, ' ');
00905 if (!label) {
00906 LuaError(l, "Missing random-goto label");
00907 } else {
00908 while (*label == ' ') {
00909 *label++ = '\0';
00910 }
00911 }
00912 anim->D.RandomGoto.Random = atoi(op2);
00913 FindLabelLater(l, &anim->D.RandomGoto.Goto, label);
00914 } else {
00915 LuaError(l, "Unknown animation: %s" _C_ op1);
00916 }
00917
00918 delete[] op1;
00919 }
00920
00924 static CAnimation *ParseAnimation(lua_State *l, int idx)
00925 {
00926 CAnimation *anim;
00927 CAnimation *tail;
00928 int args;
00929 int j;
00930 const char *str;
00931
00932 if (!lua_istable(l, idx)) {
00933 LuaError(l, "incorrect argument");
00934 }
00935 args = lua_objlen(l, idx);
00936 anim = new CAnimation[args + 1];
00937 tail = NULL;
00938 Labels.clear();
00939 LabelsLater.clear();
00940
00941 for (j = 0; j < args; ++j) {
00942 lua_rawgeti(l, idx, j + 1);
00943 str = LuaToString(l, -1);
00944 lua_pop(l, 1);
00945 ParseAnimationFrame(l, str, &anim[j]);
00946 if (!tail) {
00947 tail = &anim[j];
00948 } else {
00949 tail->Next = &anim[j];
00950 tail = &anim[j];
00951 }
00952 }
00953 FixLabels(l);
00954
00955 return anim;
00956 }
00957
00961 static void AddAnimationToArray(CAnimation *anim)
00962 {
00963 if (!anim) {
00964 return;
00965 }
00966
00967 AnimationsArray[NumAnimations++] = anim;
00968 Assert(NumAnimations != ANIMATIONS_MAXANIM);
00969 }
00970
00976 static int CclDefineAnimations(lua_State *l)
00977 {
00978 const char *name;
00979 const char *value;
00980 CAnimations *anims;
00981
00982 LuaCheckArgs(l, 2);
00983 if (!lua_istable(l, 2)) {
00984 LuaError(l, "incorrect argument");
00985 }
00986
00987 name = LuaToString(l, 1);
00988 anims = AnimationsByIdent(name);
00989 if (!anims) {
00990 anims = new CAnimations;
00991 AnimationMap[name] = anims;
00992 }
00993
00994 lua_pushnil(l);
00995 while (lua_next(l, 2)) {
00996 value = LuaToString(l, -2);
00997
00998 if (!strcmp(value, "Start")) {
00999 anims->Start = ParseAnimation(l, -1);
01000 } else if (!strcmp(value, "Still")) {
01001 anims->Still = ParseAnimation(l, -1);
01002 } else if (!strcmp(value, "Death")) {
01003 anims->Death = ParseAnimation(l, -1);
01004 } else if (!strcmp(value, "Attack")) {
01005 anims->Attack = ParseAnimation(l, -1);
01006 } else if (!strcmp(value, "Move")) {
01007 anims->Move = ParseAnimation(l, -1);
01008 } else if (!strcmp(value, "Repair")) {
01009 anims->Repair = ParseAnimation(l, -1);
01010 } else if (!strcmp(value, "Train")) {
01011 anims->Train = ParseAnimation(l, -1);
01012 } else if (!strcmp(value, "Harvest")) {
01013 anims->Harvest = ParseAnimation(l, -1);
01014 } else {
01015 LuaError(l, "Unsupported animation: %s" _C_ value);
01016 }
01017 lua_pop(l, 1);
01018 }
01019
01020
01021 AddAnimationToArray(anims->Start);
01022 AddAnimationToArray(anims->Still);
01023 AddAnimationToArray(anims->Death);
01024 AddAnimationToArray(anims->Attack);
01025 AddAnimationToArray(anims->Move);
01026 AddAnimationToArray(anims->Repair);
01027 AddAnimationToArray(anims->Train);
01028 AddAnimationToArray(anims->Harvest);
01029
01030 return 0;
01031 }
01032
01042 void DefineVariableField(lua_State *l, CVariable *var, int lua_index)
01043 {
01044 if (lua_index < 0) {
01045 --lua_index;
01046 }
01047 lua_pushnil(l);
01048 while (lua_next(l, lua_index)) {
01049 const char *key;
01050
01051 key = LuaToString(l, -2);
01052 if (!strcmp(key, "Value")) {
01053 var->Value = LuaToNumber(l, -1);
01054 } else if (!strcmp(key, "Max")) {
01055 var->Max = LuaToNumber(l, -1);
01056 } else if (!strcmp(key, "Increase")) {
01057 var->Increase = LuaToNumber(l, -1);
01058 } else if (!strcmp(key, "Enable")) {
01059 var->Enable = LuaToBoolean(l, -1);
01060 } else {
01061 LuaError(l, "incorrect field '%s' for variable\n" _C_ key);
01062 }
01063 lua_pop(l, 1);
01064 }
01065 }
01066
01074 int GetVariableIndex(const char *varname)
01075 {
01076 for (int i = 0; i < UnitTypeVar.NumberVariable; ++i) {
01077 if (!strcmp(varname, UnitTypeVar.VariableName[i])) {
01078 return i;
01079 }
01080 }
01081 return -1;
01082 }
01083
01089 static int CclDefineVariables(lua_State *l)
01090 {
01091 const char *str;
01092 int i;
01093 int j;
01094 int args;
01095
01096 args = lua_gettop(l);
01097 for (j = 0; j < args; ++j) {
01098 str = LuaToString(l, j + 1);
01099 i = GetVariableIndex(str);
01100 if (i == -1) {
01101 i = UnitTypeVar.NumberVariable;
01102 char **v = new char *[i + 1];
01103 memcpy(v, UnitTypeVar.VariableName, i * sizeof(char *));
01104 delete[] UnitTypeVar.VariableName;
01105 UnitTypeVar.VariableName = v;
01106 UnitTypeVar.VariableName[i] = new_strdup(str);
01107
01108 CVariable *t = new CVariable[i + 1];
01109 for (int x = 0; x < i; ++x) {
01110 t[x] = UnitTypeVar.Variable[x];
01111 }
01112 delete[] UnitTypeVar.Variable;
01113 UnitTypeVar.Variable = t;
01114 UnitTypeVar.NumberVariable++;
01115 } else {
01116 DebugPrint("Warning, User Variable \"%s\" redefined\n" _C_ str);
01117 }
01118 if (!lua_istable(l, j + 2)) {
01119 continue;
01120 }
01121 ++j;
01122 DefineVariableField(l, UnitTypeVar.Variable + i, j + 1);
01123 }
01124 return 0;
01125 }
01126
01135 static int CclDefineDecorations(lua_State *l)
01136 {
01137 int i;
01138 int nargs;
01139 const char *key;
01140 CDecoVar *decovar;
01141 struct {
01142 int Index;
01143 int OffsetX;
01144 int OffsetY;
01145 int OffsetXPercent;
01146 int OffsetYPercent;
01147 bool IsCenteredInX;
01148 bool IsCenteredInY;
01149 bool ShowIfNotEnable;
01150 bool ShowWhenMax;
01151 bool ShowOnlySelected;
01152 bool HideNeutral;
01153 bool HideAllied;
01154 bool ShowOpponent;
01155 } tmp;
01156
01157 nargs = lua_gettop(l);
01158 for (i = 0; i < nargs; i++) {
01159 Assert(lua_istable(l, i + 1));
01160 decovar = NULL;
01161 memset(&tmp, 0, sizeof(tmp));
01162 lua_pushnil(l);
01163 while (lua_next(l, i + 1)) {
01164 key = LuaToString(l, -2);
01165 if (!strcmp(key, "Index")) {
01166 tmp.Index = GetVariableIndex(LuaToString(l, -1));
01167 Assert(tmp.Index != -1);
01168 } else if (!strcmp(key, "Offset")) {
01169 Assert(lua_istable(l, -1));
01170 lua_rawgeti(l, -1, 1);
01171 lua_rawgeti(l, -2, 2);
01172 tmp.OffsetX = LuaToNumber(l, -2);
01173 tmp.OffsetY = LuaToNumber(l, -1);
01174 lua_pop(l, 2);
01175 } else if (!strcmp(key, "OffsetPercent")) {
01176 Assert(lua_istable(l, -1));
01177 lua_rawgeti(l, -1, 1);
01178 lua_rawgeti(l, -2, 2);
01179 tmp.OffsetXPercent = LuaToNumber(l, -2);
01180 tmp.OffsetYPercent = LuaToNumber(l, -1);
01181 lua_pop(l, 2);
01182 } else if (!strcmp(key, "CenterX")) {
01183 tmp.IsCenteredInX = LuaToBoolean(l, -1);
01184 } else if (!strcmp(key, "CenterY")) {
01185 tmp.IsCenteredInY = LuaToBoolean(l, -1);
01186 } else if (!strcmp(key, "ShowIfNotEnable")) {
01187 tmp.ShowIfNotEnable = LuaToBoolean(l, -1);
01188 } else if (!strcmp(key, "ShowWhenMax")) {
01189 tmp.ShowWhenMax = LuaToBoolean(l, -1);
01190 } else if (!strcmp(key, "ShowOnlySelected")) {
01191 tmp.ShowOnlySelected = LuaToBoolean(l, -1);
01192 } else if (!strcmp(key, "HideNeutral")) {
01193 tmp.HideNeutral = LuaToBoolean(l, -1);
01194 } else if (!strcmp(key, "HideAllied")) {
01195 tmp.HideAllied = LuaToBoolean(l, -1);
01196 } else if (!strcmp(key, "ShowOpponent")) {
01197 tmp.ShowOpponent = LuaToBoolean(l, -1);
01198 } else if (!strcmp(key, "Method")) {
01199 Assert(lua_istable(l, -1));
01200 lua_rawgeti(l, -1, 1);
01201 lua_rawgeti(l, -2, 2);
01202 Assert(lua_istable(l, -1));
01203 key = LuaToString(l, -2);
01204 if (!strcmp(key, "sprite")) {
01205 CDecoVarSpriteBar *decovarspritebar = new CDecoVarSpriteBar;
01206 lua_rawgeti(l, -1, 1);
01207 decovarspritebar->SpriteIndex = GetSpriteIndex(LuaToString(l, -1));
01208 if (decovarspritebar->SpriteIndex == -1) {
01209 LuaError(l, "invalid sprite-name '%s' for Method in DefineDecorations" _C_
01210 LuaToString(l, -1));
01211 }
01212 lua_pop(l, 1);
01213
01214 decovar = decovarspritebar;
01215 } else {
01216 LuaError(l, "invalid method '%s' for Method in DefineDecorations" _C_ key);
01217 }
01218 lua_pop(l, 2);
01219 } else {
01220 LuaError(l, "invalid key '%s' for DefineDecorations" _C_ key);
01221 }
01222 lua_pop(l, 1);
01223 }
01224 decovar->Index = tmp.Index;
01225 decovar->OffsetX = tmp.OffsetX;
01226 decovar->OffsetY = tmp.OffsetY;
01227 decovar->OffsetXPercent = tmp.OffsetXPercent;
01228 decovar->OffsetYPercent = tmp.OffsetYPercent;
01229 decovar->IsCenteredInX = tmp.IsCenteredInX;
01230 decovar->IsCenteredInY = tmp.IsCenteredInY;
01231 decovar->ShowIfNotEnable = tmp.ShowIfNotEnable;
01232 decovar->ShowWhenMax = tmp.ShowWhenMax;
01233 decovar->ShowOnlySelected = tmp.ShowOnlySelected;
01234 decovar->HideNeutral = tmp.HideNeutral;
01235 decovar->HideAllied = tmp.HideAllied;
01236 decovar->ShowOpponent = tmp.ShowOpponent;
01237 UnitTypeVar.DecoVar.push_back(decovar);
01238 }
01239 Assert(lua_gettop(l));
01240 return 0;
01241 }
01242
01243
01244
01245
01246
01250 void UpdateUnitVariables(const CUnit *unit)
01251 {
01252 int i;
01253 const CUnitType *type;
01254
01255 type = unit->Type;
01256 for (i = 0; i < NVARALREADYDEFINED; i++) {
01257 if (i == ARMOR_INDEX || i == PIERCINGDAMAGE_INDEX ||
01258 i == BASICDAMAGE_INDEX || i == MANA_INDEX ||
01259 i == KILL_INDEX || i == HP_INDEX) {
01260 continue;
01261 }
01262 unit->Variable[i].Value = 0;
01263 unit->Variable[i].Max = 0;
01264 unit->Variable[i].Enable = 1;
01265 }
01266
01267
01268 if (unit->Orders[0]->Action == UnitActionBuilt) {
01269 const int *pcosts = type->ProductionCosts;
01270 int pcost = CYCLES_PER_SECOND * (pcosts[EnergyCost] ? pcosts[EnergyCost] : pcosts[MagmaCost]);
01271 unit->Variable[BUILD_INDEX].Value = unit->Data.Built.Progress;
01272 unit->Variable[BUILD_INDEX].Max = pcost;
01273
01274
01275
01276
01277 if (unit->Variable[BUILD_INDEX].Value > unit->Variable[BUILD_INDEX].Max) {
01278
01279 unit->Variable[BUILD_INDEX].Value = unit->Variable[BUILD_INDEX].Max;
01280 }
01281 }
01282
01283
01284 unit->Variable[TRANSPORT_INDEX].Value = unit->BoardCount;
01285 unit->Variable[TRANSPORT_INDEX].Max = unit->Type->MaxOnBoard;
01286
01287
01288 if (unit->Orders[0]->Action == UnitActionTrain) {
01289 unit->Variable[TRAINING_INDEX].Value = unit->Data.Train.Ticks;
01290 int *costs = unit->Orders[0]->Type->ProductionCosts;
01291 int cost = costs[EnergyCost] ? costs[EnergyCost] : costs[MagmaCost];
01292 unit->Variable[TRAINING_INDEX].Max = cost;
01293 }
01294
01295
01296 if (unit->Type->CanHarvestFrom) {
01297 int i;
01298 for (i = 0; i < MaxCosts; ++i) {
01299 if (unit->ResourcesHeld[i] != 0) {
01300 break;
01301 }
01302 }
01303 Assert(i != MaxCosts);
01304 unit->Variable[GIVERESOURCE_INDEX].Value = unit->ResourcesHeld[i] / CYCLES_PER_SECOND;
01305 unit->Variable[GIVERESOURCE_INDEX].Max = 0x7FFFFFFF;
01306 }
01307
01308
01309 unit->Variable[SIGHTRANGE_INDEX].Value = type->Variable[SIGHTRANGE_INDEX].Value;
01310 unit->Variable[SIGHTRANGE_INDEX].Max = unit->Stats->Variables[SIGHTRANGE_INDEX].Max;
01311
01312
01313 unit->Variable[ATTACKRANGE_INDEX].Value = type->Variable[ATTACKRANGE_INDEX].Max;
01314 unit->Variable[ATTACKRANGE_INDEX].Max = unit->Stats->Variables[ATTACKRANGE_INDEX].Max;
01315
01316
01317 unit->Variable[POSX_INDEX].Value = unit->X;
01318 unit->Variable[POSX_INDEX].Max = Map.Info.MapWidth;
01319 unit->Variable[POSY_INDEX].Value = unit->Y;
01320 unit->Variable[POSY_INDEX].Max = Map.Info.MapHeight;
01321
01322
01323 unit->Variable[RADAR_INDEX].Value = unit->Stats->Variables[RADAR_INDEX].Value;
01324 unit->Variable[RADAR_INDEX].Max = unit->Stats->Variables[RADAR_INDEX].Value;
01325
01326
01327 unit->Variable[RADARJAMMER_INDEX].Value = unit->Stats->Variables[RADARJAMMER_INDEX].Value;
01328 unit->Variable[RADARJAMMER_INDEX].Max = unit->Stats->Variables[RADARJAMMER_INDEX].Value;
01329
01330
01331 unit->Variable[SLOT_INDEX].Value = unit->Slot;
01332 unit->Variable[SLOT_INDEX].Max = UnitSlotFree - 1;
01333
01334 for (i = 0; i < NVARALREADYDEFINED; i++) {
01335 unit->Variable[i].Enable &= unit->Variable[i].Max > 0;
01336 #ifdef DEBUG
01337 if (unit->Variable[i].Value > unit->Variable[i].Max) {
01338 DebugPrint("Value out of range: '%s'(%d), for variable '%s',"
01339 " value = %d, max = %d\n"
01340 _C_ type->Ident.c_str() _C_ unit->Slot _C_ UnitTypeVar.VariableName[i]
01341 _C_ unit->Variable[i].Value _C_ unit->Variable[i].Max);
01342 }
01343 #endif
01344 Assert(unit->Variable[i].Value <= unit->Variable[i].Max);
01345 }
01346 }
01347
01351 void InitDefinedVariables()
01352 {
01353 const char *var[NVARALREADYDEFINED] = {"HitPoints", "Build", "Mana", "Transport",
01354 "Training", "GiveResource", "Kill", "Armor", "SightRange",
01355 "AttackRange", "PiercingDamage", "BasicDamage", "PosX", "PosY", "RadarRange",
01356 "RadarJammerRange", "AutoRepairRange", "Slot"};
01357 int i;
01358
01359
01360 UnitTypeVar.VariableName = new char *[NVARALREADYDEFINED];
01361 for (i = 0; i < NVARALREADYDEFINED; ++i) {
01362 UnitTypeVar.VariableName[i] = new_strdup(var[i]);
01363 }
01364 UnitTypeVar.Variable = new CVariable[i];
01365 UnitTypeVar.NumberVariable = i;
01366 }
01367
01371 void UnitTypeCclRegister(void)
01372 {
01373 lua_register(Lua, "DefineUnitType", CclDefineUnitType);
01374 lua_register(Lua, "DefineVariables", CclDefineVariables);
01375 lua_register(Lua, "DefineDecorations", CclDefineDecorations);
01376
01377 InitDefinedVariables();
01378
01379 lua_register(Lua, "DefineAnimations", CclDefineAnimations);
01380 }
01381