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 <sstream>
00036 #include <iomanip>
00037
00038 #include "stratagus.h"
00039 #include "unit.h"
00040 #include "unittype.h"
00041 #include "unit_manager.h"
00042 #include "player.h"
00043 #include "animation.h"
00044 #include "spells.h"
00045 #include "construct.h"
00046 #include "iolib.h"
00047
00048
00049
00050
00051
00055 std::string UnitReference(const CUnit *unit)
00056 {
00057 std::ostringstream ss;
00058 ss << "U" << std::setfill('0') << std::setw(4) << std::uppercase <<
00059 std::hex << UnitNumber(unit);
00060 return ss.str();
00061 }
00062
00069 void SaveOrder(const COrder *order, CFile *file)
00070 {
00071 file->printf("{");
00072 switch (order->Action) {
00073 case UnitActionNone:
00074 file->printf("\"action-none\",");
00075 break;
00076
00077 case UnitActionStill:
00078 file->printf("\"action-still\",");
00079 break;
00080 case UnitActionStandGround:
00081 file->printf("\"action-stand-ground\",");
00082 break;
00083 case UnitActionFollow:
00084 file->printf("\"action-follow\",");
00085 break;
00086 case UnitActionMove:
00087 file->printf("\"action-move\",");
00088 break;
00089 case UnitActionAttack:
00090 file->printf("\"action-attack\",");
00091 break;
00092 case UnitActionAttackGround:
00093 file->printf("\"action-attack-ground\",");
00094 break;
00095 case UnitActionDie:
00096 file->printf("\"action-die\",");
00097 break;
00098
00099 case UnitActionSpellCast:
00100 file->printf("\"action-spell-cast\",");
00101 break;
00102
00103 case UnitActionTrain:
00104 file->printf("\"action-train\",");
00105 break;
00106 case UnitActionBuilt:
00107 file->printf("\"action-built\",");
00108 break;
00109
00110 case UnitActionBoard:
00111 file->printf("\"action-board\",");
00112 break;
00113 case UnitActionUnload:
00114 file->printf("\"action-unload\",");
00115 break;
00116 case UnitActionPatrol:
00117 file->printf("\"action-patrol\",");
00118 break;
00119 case UnitActionBuild:
00120 file->printf("\"action-build\",");
00121 break;
00122
00123 case UnitActionRepair:
00124 file->printf("\"action-repair\",");
00125 break;
00126 case UnitActionResource:
00127 file->printf("\"action-resource\",");
00128 break;
00129 default:
00130 DebugPrint("Unknown action in order\n");
00131 }
00132
00133 file->printf(" \"range\", %d,", order->Range);
00134 file->printf(" \"width\", %d,", order->Width);
00135 file->printf(" \"height\", %d,", order->Height);
00136 file->printf(" \"min-range\", %d,", order->MinRange);
00137 if (order->Goal) {
00138 if (order->Goal->Destroyed) {
00139
00140
00141 printf ("FIXME: storing destroyed Goal - loading will fail.\n");
00142 }
00143 file->printf(" \"goal\", \"%s\",", UnitReference(order->Goal).c_str());
00144 }
00145 file->printf(" \"tile\", {%d, %d},", order->X, order->Y);
00146 if (order->Type) {
00147 file->printf(" \"type\", \"%s\",", order->Type->Ident.c_str());
00148 }
00149
00150
00151 switch (order->Action) {
00152 case UnitActionPatrol:
00153 file->printf(" \"patrol\", {%d, %d},",
00154 order->Arg1.Patrol.X, order->Arg1.Patrol.Y);
00155 break;
00156 case UnitActionSpellCast:
00157 if (order->Arg1.Spell) {
00158 file->printf(" \"spell\", \"%s\",", order->Arg1.Spell->Ident.c_str());
00159 }
00160 break;
00161 default:
00162 break;
00163 }
00164
00165 file->printf("}");
00166 }
00167
00174 void SaveUnit(const CUnit *unit, CFile *file)
00175 {
00176 CUnit *uins;
00177 int i;
00178
00179 file->printf("\nUnit(%d, ", UnitNumber(unit));
00180
00181
00182 file->printf("\"type\", \"%s\", ", unit->Type->Ident.c_str());
00183 if (unit->Seen.Type) {
00184 file->printf("\"seen-type\", \"%s\", ", unit->Seen.Type->Ident.c_str());
00185 }
00186
00187 file->printf("\"player\", %d,\n ", unit->Player->Index);
00188
00189 if (unit->Next) {
00190 file->printf("\"next\", %d, ", UnitNumber(unit->Next));
00191 }
00192
00193 file->printf("\"tile\", {%d, %d}, ", unit->X, unit->Y);
00194 file->printf("\"seen-tile\", {%d, %d}, ", unit->Seen.X, unit->Seen.Y);
00195 file->printf("\"refs\", %lu, ", unit->Refs);
00196 #if 0
00197
00198
00199 for (i = 0; i < PlayerMax; ++i) {
00200 if (&unit->Type->Stats[i] == unit->Stats) {
00201 file->printf("\"stats\", %d,\n ", i);
00202 break;
00203 }
00204 }
00205
00206 if (i == PlayerMax) {
00207 file->printf("\"stats\", \"S%08X\",\n ", (int)unit->Stats);
00208 }
00209 #else
00210 file->printf("\"stats\", %d,\n ", unit->Player->Index);
00211 #endif
00212 file->printf("\"pixel\", {%d, %d}, ", unit->IX, unit->IY);
00213 file->printf("\"seen-pixel\", {%d, %d}, ", unit->Seen.IX, unit->Seen.IY);
00214 file->printf("\"frame\", %d, ", unit->Frame);
00215 if (unit->Seen.Frame != UnitNotSeen) {
00216 file->printf("\"seen\", %d, ", unit->Seen.Frame);
00217 } else {
00218 file->printf("\"not-seen\", ");
00219 }
00220 file->printf("\"direction\", %d,\n ", unit->Direction);
00221 file->printf("\"attacked\", %lu,\n ", unit->Attacked);
00222 file->printf(" \"current-sight-range\", %d,", unit->CurrentSightRange);
00223 if (unit->Burning) {
00224 file->printf(" \"burning\",");
00225 }
00226 if (unit->Destroyed) {
00227 file->printf(" \"destroyed\",");
00228 }
00229 if (unit->Removed) {
00230 file->printf(" \"removed\",");
00231 }
00232 if (unit->Selected) {
00233 file->printf(" \"selected\",");
00234 }
00235 if (unit->RescuedFrom) {
00236 file->printf(" \"rescued-from\", %d,", unit->RescuedFrom->Index);
00237 }
00238
00239
00240
00241
00242 if (unit->Container && unit->Removed) {
00243 file->printf(" \"host-info\", {%d, %d, %d, %d}, ",
00244 unit->Container->X, unit->Container->Y,
00245 unit->Container->Type->TileWidth,
00246 unit->Container->Type->TileHeight);
00247 }
00248 file->printf(" \"seen-by-player\", \"");
00249 for (i = 0; i < PlayerMax; ++i) {
00250 file->printf("%c", (unit->Seen.ByPlayer & (1 << i)) ? 'X' : '_');
00251 }
00252 file->printf("\",\n ");
00253 file->printf(" \"seen-destroyed\", \"");
00254 for (i = 0; i < PlayerMax; ++i) {
00255 file->printf("%c", (unit->Seen.Destroyed & (1 << i)) ? 'X' : '_');
00256 }
00257 file->printf("\",\n ");
00258 if (unit->Constructed) {
00259 file->printf(" \"constructed\",");
00260 }
00261 if (unit->Seen.Constructed) {
00262 file->printf(" \"seen-constructed\",");
00263 }
00264
00265 if (unit->Seen.CFrame) {
00266 CConstructionFrame *cframe = unit->Seen.Type->Construction->Frames;
00267 int frame = 0;
00268 while (cframe != unit->Seen.CFrame) {
00269 cframe = cframe->Next;
00270 ++frame;
00271 }
00272 file->printf(" \"seen-cframe\", %d,", frame);
00273 }
00274
00275 file->printf(" \"seen-state\", %d, ", unit->Seen.State);
00276 file->printf("\"ttl\", %lu, ", unit->TTL);
00277
00278 for (i = 0; i < UnitTypeVar.NumberVariable; i++) {
00279 file->printf("\"%s\", {Value = %d, Max = %d, Increase = %d, Enable = %s},\n ",
00280 UnitTypeVar.VariableName[i], unit->Variable[i].Value, unit->Variable[i].Max,
00281 unit->Variable[i].Increase, unit->Variable[i].Enable ? "true" : "false");
00282 }
00283
00284 file->printf("\"group-id\", %d,\n ", unit->GroupId);
00285 file->printf("\"last-group\", %d,\n ", unit->LastGroup);
00286
00287 file->printf("\"resources-held\", {");
00288 for (i = 0; i < MaxCosts; ++i) {
00289 file->printf("%s%d", (i ? ", " : ""), unit->ResourcesHeld[i]);
00290 }
00291 file->printf("},\n ");
00292
00293 file->printf("\"production-efficiency\", %d, ", unit->ProductionEfficiency);
00294
00295 file->printf("\"sub-action\", %d, ", unit->SubAction);
00296 file->printf("\"wait\", %d, ", unit->Wait);
00297 file->printf("\"state\", %d,", unit->State);
00298 file->printf("\"anim-wait\", %d,", unit->Anim.Wait);
00299 for (i = 0; i < NumAnimations; ++i) {
00300 if (AnimationsArray[i] == unit->Anim.CurrAnim) {
00301 file->printf("\"curr-anim\", %d,", i);
00302 file->printf("\"anim\", %d,", unit->Anim.Anim - unit->Anim.CurrAnim);
00303 break;
00304 }
00305 }
00306 if (unit->Anim.Unbreakable) {
00307 file->printf(" \"unbreakable\",");
00308 }
00309 file->printf("\n \"blink\", %d,", unit->Blink);
00310 if (unit->Moving) {
00311 file->printf(" \"moving\",");
00312 }
00313 if (unit->ReCast) {
00314 file->printf(" \"re-cast\",");
00315 }
00316 if (unit->Boarded) {
00317 file->printf(" \"boarded\",");
00318 }
00319 if (unit->AutoRepair) {
00320 file->printf(" \"auto-repair\",");
00321 }
00322
00323 file->printf(" \"units-boarded-count\", %d,", unit->BoardCount);
00324
00325 if (unit->UnitInside) {
00326 file->printf("\n \"units-contained\", {");
00327 uins = unit->UnitInside->PrevContained;
00328 for (i = unit->InsideCount; i; --i, uins = uins->PrevContained) {
00329 file->printf("\"%s\"", UnitReference(uins).c_str());
00330 if (i > 1) {
00331 file->printf(", ");
00332 }
00333 }
00334 file->printf("},\n ");
00335 }
00336 Assert((unsigned int)unit->OrderCount == unit->Orders.size());
00337 file->printf("\"order-count\", %d,\n ", unit->OrderCount);
00338 file->printf("\"order-flush\", %d,\n ", unit->OrderFlush);
00339 file->printf("\"orders\", {");
00340 for (i = 0; i < unit->OrderCount; ++i) {
00341 file->printf("\n ");
00342 SaveOrder(unit->Orders[i], file);
00343 file->printf(",");
00344 }
00345 file->printf("},\n \"saved-order\", ");
00346 SaveOrder(&unit->SavedOrder, file);
00347 file->printf(",\n \"new-order\", ");
00348 SaveOrder(&unit->NewOrder, file);
00349
00350
00351
00352
00353 switch (unit->Orders[0]->Action) {
00354 case UnitActionStill:
00355 break;
00356 case UnitActionBuilt:
00357 {
00358 CConstructionFrame *cframe;
00359 int frame;
00360
00361 cframe = unit->Type->Construction->Frames;
00362 frame = 0;
00363 while (cframe != unit->Data.Built.Frame) {
00364 cframe = cframe->Next;
00365 ++frame;
00366 }
00367 file->printf(",\n \"data-built\", {");
00368
00369 if (unit->Data.Built.Worker) {
00370 file->printf("\"worker\", \"%s\", ",
00371 UnitReference(unit->Data.Built.Worker).c_str());
00372 }
00373 file->printf("\"progress\", %d, \"frame\", %d,",
00374 unit->Data.Built.Progress, frame);
00375 if (unit->Data.Built.Cancel) {
00376 file->printf(" \"cancel\",");
00377 }
00378 file->printf("}");
00379 break;
00380 }
00381 case UnitActionTrain:
00382 file->printf(",\n \"data-train\", {");
00383 file->printf("\"ticks\", %d, ", unit->Data.Train.Ticks);
00384 file->printf("}");
00385 break;
00386 case UnitActionResource:
00387 file->printf(",\n \"data-harvest\", {");
00388 file->printf("\"current-production\", {");
00389 for (i = 0; i < MaxCosts; ++i) {
00390 file->printf("%s%d", (i ? ", " : ""), unit->Data.Harvest.CurrentProduction[i]);
00391 }
00392 file->printf("}}");
00393 break;
00394 default:
00395 file->printf(",\n \"data-move\", {");
00396 if (unit->Data.Move.Fast) {
00397 file->printf("\"fast\", ");
00398 }
00399 if (unit->Data.Move.Length > 0) {
00400 file->printf("\"path\", {");
00401 for (i = 0; i < unit->Data.Move.Length; ++i) {
00402 file->printf("%d, ", unit->Data.Move.Path[i]);
00403 }
00404 file->printf("},");
00405 }
00406 file->printf("}");
00407 break;
00408 }
00409
00410 if (unit->Goal) {
00411 file->printf(",\n \"goal\", %d", UnitNumber(unit->Goal));
00412 }
00413 if (unit->AutoCastSpell) {
00414 for (i = 0; (unsigned int) i < SpellTypeTable.size(); ++i) {
00415 if (unit->AutoCastSpell[i]) {
00416 file->printf(",\n \"auto-cast\", \"%s\"", SpellTypeTable[i]->Ident.c_str());
00417 }
00418 }
00419 }
00420
00421 file->printf(")\n");
00422 }
00423
00429 void SaveUnits(CFile *file)
00430 {
00431 UnitManager.Save(file);
00432
00433 for (CUnit **table = Units; table < &Units[NumUnits]; ++table) {
00434 SaveUnit(*table, file);
00435 }
00436 }
00437