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 "unittype.h"
00041 #include "player.h"
00042 #include "unit.h"
00043 #include "actions.h"
00044 #include "map.h"
00045 #include "upgrade.h"
00046 #include "pathfinder.h"
00047 #include "spells.h"
00048 #include "interface.h"
00049 #include "ui.h"
00050
00051
00052
00053
00054
00060 static void ReleaseOrder(COrder *order)
00061 {
00062 if (order->Goal) {
00063 order->Goal->RefsDecrease();
00064 order->Goal = NoUnitP;
00065 }
00066 }
00067
00073 static void ReleaseOrders(CUnit *unit)
00074 {
00075 int n;
00076
00077 if ((n = unit->OrderCount) > 1) {
00078 while (--n) {
00079 ReleaseOrder(unit->Orders[n]);
00080 delete unit->Orders[n];
00081 unit->Orders.pop_back();
00082 }
00083 unit->OrderCount = 1;
00084 }
00085 unit->OrderFlush = 1;
00086
00087 }
00088
00097 static COrder *GetNextOrder(CUnit *unit, int flush)
00098 {
00099 if (flush) {
00100
00101 ReleaseOrders(unit);
00102 }
00103 if (unit->OrderCount == 0x7F) {
00104 return NULL;
00105 }
00106
00107 unit->Orders.push_back(new COrder);
00108
00109 return unit->Orders[(int)unit->OrderCount++];
00110 }
00111
00118 static void RemoveOrder(CUnit *unit, int order)
00119 {
00120 int i;
00121
00122 Assert(0 <= order && order < unit->OrderCount);
00123 if (order != 0) {
00124 delete unit->Orders[order];
00125 }
00126 i = order;
00127 while (i < unit->OrderCount - 1) {
00128 unit->Orders[i] = unit->Orders[i + 1];
00129 ++i;
00130 }
00131
00132 if (unit->OrderCount > 1) {
00133 unit->Orders.pop_back();
00134 --unit->OrderCount;
00135 if (order == 0) {
00136 unit->SubAction = 0;
00137 }
00138 } else {
00139 Assert(i == 0);
00140 unit->Orders[0]->Init();
00141 unit->Orders[0]->Action = UnitActionStill;
00142 unit->SubAction = 0;
00143 }
00144 }
00145
00154 static void ClearSavedAction(CUnit *unit)
00155 {
00156 ReleaseOrder(&unit->SavedOrder);
00157
00158 unit->SavedOrder.Init();
00159 unit->SavedOrder.Action = UnitActionStill;
00160 }
00161
00162
00163
00164
00165
00171 void CommandStopUnit(CUnit *unit)
00172 {
00173 COrder *order;
00174
00175
00176
00177 order = GetNextOrder(unit, FlushCommands);
00178 Assert(order);
00179 order->Init();
00180
00181 order->Action = UnitActionStill;
00182 ReleaseOrder(&unit->SavedOrder);
00183 ReleaseOrder(&unit->NewOrder);
00184 unit->SavedOrder = unit->NewOrder = *order;
00185 }
00186
00194 void CommandAnyOrder(CUnit *unit, COrder *cpyorder, int flush)
00195 {
00196 COrder *order;
00197
00198 if (!(order = GetNextOrder(unit, flush))) {
00199 return;
00200 }
00201
00202 *order = *cpyorder;
00203 if (order->Goal) {
00204 order->Goal->RefsIncrease();
00205 }
00206 ClearSavedAction(unit);
00207 }
00208
00217 void CommandMoveOrder(CUnit *unit, int src, int dst)
00218 {
00219 COrder *tmp;
00220 int i;
00221
00222 Assert(src != 0 && dst != 0 && src < unit->OrderCount && dst < unit->OrderCount);
00223
00224 if (src == dst) {
00225 return;
00226 }
00227
00228 if (src < dst) {
00229 tmp = unit->Orders[src];
00230 for (i = src; i < dst; ++i) {
00231 unit->Orders[i] = unit->Orders[i+1];
00232 }
00233 unit->Orders[dst] = tmp;
00234 } else {
00235
00236 tmp = unit->Orders[src];
00237 for (i = src - 1 ; i >= dst; --i) {
00238 unit->Orders[i + 1] = unit->Orders[i];
00239 }
00240 unit->Orders[dst] = tmp;
00241 }
00242 }
00243
00250 void CommandStandGround(CUnit *unit, int flush)
00251 {
00252 COrder *order;
00253
00254
00255
00256 if (unit->Type->Building) {
00257
00258 order = &unit->NewOrder;
00259 ReleaseOrder(order);
00260 } else if (!(order = GetNextOrder(unit, flush))) {
00261 return;
00262 }
00263 order->Init();
00264 order->Action = UnitActionStandGround;
00265 ClearSavedAction(unit);
00266 }
00267
00275 void CommandFollow(CUnit *unit, CUnit *dest, int flush)
00276 {
00277 COrder *order;
00278
00279
00280
00281
00282 if (!unit->Removed && unit->Orders[0]->Action != UnitActionDie) {
00283 if (!CanMove(unit)) {
00284
00285 order = &unit->NewOrder;
00286 ReleaseOrder(order);
00287 } else if (!(order = GetNextOrder(unit, flush))) {
00288 return;
00289 }
00290 order->Init();
00291
00292 order->Action = UnitActionFollow;
00293
00294
00295
00296
00297
00298 if (dest->Destroyed) {
00299 order->X = dest->X + dest->Type->TileWidth / 2;
00300 order->Y = dest->Y + dest->Type->TileHeight / 2;
00301 } else {
00302 order->Goal = dest;
00303 dest->RefsIncrease();
00304 order->Range = 1;
00305 }
00306 }
00307 ClearSavedAction(unit);
00308 }
00309
00318 void CommandMove(CUnit *unit, int x, int y, int flush)
00319 {
00320 COrder *order;
00321
00322 Assert(x >= 0 && y >= 0 && x < Map.Info.MapWidth && y < Map.Info.MapHeight);
00323
00324
00325
00326
00327 if (!unit->Removed && unit->Orders[0]->Action != UnitActionDie) {
00328 if (!CanMove(unit)) {
00329
00330 order = &unit->NewOrder;
00331 ReleaseOrder(order);
00332 } else if (!(order = GetNextOrder(unit, flush))) {
00333 return;
00334 }
00335 order->Init();
00336
00337 order->Action = UnitActionMove;
00338 order->X = x;
00339 order->Y = y;
00340 }
00341 ClearSavedAction(unit);
00342 }
00343
00353 void CommandRepair(CUnit *unit, int x, int y, CUnit *dest, int flush)
00354 {
00355 COrder *order;
00356
00357
00358
00359
00360 if (!unit->Removed && unit->Orders[0]->Action != UnitActionDie) {
00361 if (unit->Type->Building) {
00362
00363 order = &unit->NewOrder;
00364 ReleaseOrder(order);
00365 } else if (!(order = GetNextOrder(unit, flush))) {
00366 return;
00367 }
00368 order->Init();
00369
00370 order->Action = UnitActionRepair;
00371
00372
00373
00374
00375
00376 if (dest) {
00377 if (dest->Destroyed) {
00378 order->X = dest->X + dest->Type->TileWidth / 2;
00379 order->Y = dest->Y + dest->Type->TileHeight / 2;
00380 } else {
00381 order->Goal = dest;
00382 dest->RefsIncrease();
00383 order->Range = unit->Type->RepairRange;
00384 }
00385 } else {
00386 order->X = x;
00387 order->Y = y;
00388 }
00389 }
00390 ClearSavedAction(unit);
00391 }
00392
00399 void CommandAutoRepair(CUnit *unit, int on)
00400 {
00401
00402
00403
00404 if (!unit->Removed && unit->Orders[0]->Action != UnitActionDie) {
00405 unit->AutoRepair = on;
00406 }
00407 }
00408
00418 void CommandAttack(CUnit *unit, int x, int y, CUnit *attack, int flush)
00419 {
00420 COrder *order;
00421
00422 Assert(x >= 0 && y >= 0 && x < Map.Info.MapWidth && y < Map.Info.MapHeight);
00423
00424
00425
00426
00427 if (!unit->Removed && unit->Orders[0]->Action != UnitActionDie) {
00428 if (!unit->Type->CanAttack) {
00429
00430 order = &unit->NewOrder;
00431 ReleaseOrder(order);
00432 } else if (!(order = GetNextOrder(unit, flush))) {
00433 return;
00434 }
00435 order->Init();
00436
00437 order->Action = UnitActionAttack;
00438 if (attack) {
00439
00440
00441
00442
00443
00444 if (attack->Destroyed) {
00445 order->X = attack->X + attack->Type->TileWidth / 2;
00446 order->Y = attack->Y + attack->Type->TileHeight / 2;
00447 } else {
00448
00449 order->Goal = attack;
00450 attack->RefsIncrease();
00451 order->Range = unit->Stats->Variables[ATTACKRANGE_INDEX].Max;
00452 order->MinRange = unit->Type->MinAttackRange;
00453 }
00454 } else {
00455 order->X = x;
00456 order->Y = y;
00457 }
00458 }
00459 ClearSavedAction(unit);
00460 }
00461
00470 void CommandAttackGround(CUnit *unit, int x, int y, int flush)
00471 {
00472 COrder *order;
00473
00474 Assert(x >= 0 && y >= 0 && x < Map.Info.MapWidth && y < Map.Info.MapHeight);
00475
00476
00477
00478
00479 if (!unit->Removed && unit->Orders[0]->Action != UnitActionDie) {
00480 if (unit->Type->Building) {
00481
00482 order = &unit->NewOrder;
00483 ReleaseOrder(order);
00484 } else if (!(order = GetNextOrder(unit, flush))) {
00485 return;
00486 }
00487 order->Init();
00488
00489 order->Action = UnitActionAttackGround;
00490 order->X = x;
00491 order->Y = y;
00492 order->Range = unit->Stats->Variables[ATTACKRANGE_INDEX].Max;
00493 order->MinRange = unit->Type->MinAttackRange;
00494
00495 DebugPrint("FIXME this next\n");
00496 }
00497 ClearSavedAction(unit);
00498 }
00499
00510 void CommandPatrolUnit(CUnit *unit, int x, int y, int flush)
00511 {
00512 COrder *order;
00513
00514 Assert(x >= 0 && y >= 0 && x < Map.Info.MapWidth && y < Map.Info.MapHeight);
00515
00516
00517
00518
00519 if (!unit->Removed && unit->Orders[0]->Action != UnitActionDie) {
00520 if (!CanMove(unit)) {
00521
00522 order = &unit->NewOrder;
00523 ReleaseOrder(order);
00524 } else if (!(order = GetNextOrder(unit, flush))) {
00525 return;
00526 }
00527 order->Init();
00528
00529 order->Action = UnitActionPatrol;
00530 order->X = x;
00531 order->Y = y;
00532 Assert(!(unit->X & ~0xFFFF) && !(unit->Y & ~0xFFFF));
00533 order->Arg1.Patrol.X = unit->X;
00534 order->Arg1.Patrol.Y = unit->Y;
00535 }
00536 ClearSavedAction(unit);
00537 }
00538
00546 void CommandBoard(CUnit *unit, CUnit *dest, int flush)
00547 {
00548 COrder *order;
00549
00550
00551
00552
00553 if (!unit->Removed && unit->Orders[0]->Action != UnitActionDie) {
00554
00555
00556
00557
00558
00559 if (dest->Destroyed) {
00560 return;
00561 }
00562
00563 if (unit->Type->Building) {
00564
00565 order = &unit->NewOrder;
00566 ReleaseOrder(order);
00567 } else if (!(order = GetNextOrder(unit, flush))) {
00568 return;
00569 }
00570 order->Init();
00571
00572 order->Action = UnitActionBoard;
00573 order->Goal = dest;
00574 dest->RefsIncrease();
00575 order->Range = 1;
00576 }
00577 ClearSavedAction(unit);
00578 }
00579
00589 void CommandUnload(CUnit *unit, int x, int y, CUnit *what, int flush)
00590 {
00591 COrder *order;
00592
00593
00594
00595
00596 if (!unit->Removed && unit->Orders[0]->Action != UnitActionDie) {
00597 if (!(order = GetNextOrder(unit, flush))) {
00598 return;
00599 }
00600 order->Init();
00601
00602 order->Action = UnitActionUnload;
00603 order->X = x;
00604 order->Y = y;
00605
00606
00607
00608
00609
00610 if (what && !what->Destroyed) {
00611 order->Goal = what;
00612 what->RefsIncrease();
00613 }
00614 }
00615 ClearSavedAction(unit);
00616 }
00617
00627 void CommandBuildBuilding(CUnit *unit, int x, int y,
00628 CUnitType *what, int flush)
00629 {
00630 COrder *order;
00631
00632
00633
00634
00635 if (!unit->Removed && unit->Orders[0]->Action != UnitActionDie) {
00636 if (unit->Type->Building) {
00637
00638 order = &unit->NewOrder;
00639 ReleaseOrder(order);
00640 } else if (!(order = GetNextOrder(unit, flush))) {
00641 return;
00642 }
00643 order->Init();
00644
00645 order->Action = UnitActionBuild;
00646 order->X = x;
00647 order->Y = y;
00648 order->Width = what->TileWidth;
00649 order->Height = what->TileHeight;
00650 if (what->BuilderOutside) {
00651 order->Range = unit->Type->RepairRange;
00652 } else {
00653
00654 if (what->ShoreBuilding && unit->Type->UnitType == UnitTypeLand) {
00655
00656 order->Range = 1;
00657 }
00658 }
00659 order->Type = what;
00660 if (what->BuilderOutside) {
00661 order->MinRange = 1;
00662 }
00663 }
00664 ClearSavedAction(unit);
00665 }
00666
00672 void CommandDismiss(CUnit *unit)
00673 {
00674
00675
00676
00677 if (unit->Orders[0]->Action == UnitActionBuilt) {
00678 unit->Data.Built.Cancel = 1;
00679 } else {
00680 DebugPrint("Suicide unit ... \n");
00681 LetUnitDie(unit);
00682 }
00683 ClearSavedAction(unit);
00684 }
00685
00693 void CommandResource(CUnit *unit, CUnit *dest, int flush)
00694 {
00695 COrder *order;
00696
00697
00698
00699
00700 if (!unit->Removed && unit->Orders[0]->Action != UnitActionDie &&
00701 !dest->Destroyed) {
00702 if (!unit->Type->Building && !unit->Type->Harvester) {
00703 ClearSavedAction(unit);
00704 return;
00705 }
00706
00707
00708
00709 if (unit->Type->Building) {
00710
00711 order = &unit->NewOrder;
00712 ReleaseOrder(order);
00713 } else if (!(order = GetNextOrder(unit, flush))) {
00714 return;
00715 }
00716 order->Init();
00717 order->Action = UnitActionResource;
00718 order->Goal = dest;
00719 dest->RefsIncrease();
00720 order->Range = 1;
00721 }
00722 ClearSavedAction(unit);
00723 }
00724
00732 void CommandTrainUnit(CUnit *unit, CUnitType *type, int flush)
00733 {
00734 COrder *order;
00735
00736
00737
00738
00739 if (!unit->Removed && unit->Orders[0]->Action != UnitActionDie) {
00740
00741
00742
00743
00744 if (unit->Player->CheckLimits(type) < 0 ) {
00745 return;
00746 }
00747
00748 if (!(order = GetNextOrder(unit, 0))) {
00749 return;
00750 }
00751 order->Init();
00752
00753 order->Action = UnitActionTrain;
00754 order->Type = type;
00755 }
00756 ClearSavedAction(unit);
00757 }
00758
00766 void CommandCancelTraining(CUnit *unit, int slot, const CUnitType *type)
00767 {
00768 DebugPrint("Cancel %d type: %s\n" _C_ slot _C_
00769 type ? type->Ident.c_str() : "-any-");
00770
00771 ClearSavedAction(unit);
00772
00773
00774
00775
00776
00777 if (slot == -1) {
00778 if (unit->Orders[0]->Action == UnitActionTrain) {
00779 unit->Player->RemoveFromUnitsConsumingResources(unit);
00780 }
00781
00782
00783 while (unit->Orders[0]->Action == UnitActionTrain) {
00784 RemoveOrder(unit, 0);
00785 }
00786 unit->Data.Train.Ticks = 0;
00787 if (unit->Player == ThisPlayer && unit->Selected) {
00788 SelectedUnitChanged();
00789 }
00790 } else if (unit->OrderCount <= slot) {
00791
00792 return;
00793 } else if (unit->Orders[slot]->Action != UnitActionTrain) {
00794
00795 return;
00796 } else if (unit->Orders[slot]->Action == UnitActionTrain) {
00797
00798 if (type && unit->Orders[slot]->Type != type) {
00799
00800 return;
00801 }
00802
00803 DebugPrint("Cancel training\n");
00804
00805 if (!slot) {
00806 unit->Data.Train.Ticks = 0;
00807 unit->Player->RemoveFromUnitsConsumingResources(unit);
00808 }
00809 RemoveOrder(unit, slot);
00810
00811
00812
00813
00814 if (unit->Player == ThisPlayer && unit->Selected) {
00815 SelectedUnitChanged();
00816 }
00817 }
00818 }
00819
00830 void CommandSpellCast(CUnit *unit, int x, int y, CUnit *dest,
00831 SpellType *spell, int flush)
00832 {
00833 COrder *order;
00834
00835 Assert(x >= 0 && y >= 0 && x < Map.Info.MapWidth && y < Map.Info.MapHeight);
00836
00837 DebugPrint(": %d casts %s at %d %d on %d\n" _C_
00838 UnitNumber(unit) _C_ spell->Ident.c_str() _C_ x _C_ y _C_ dest ? UnitNumber(dest) : 0);
00839 Assert(unit->Type->CanCastSpell[spell->Slot]);
00840
00841
00842
00843
00844 if (!unit->Removed && unit->Orders[0]->Action != UnitActionDie) {
00845
00846
00847 if (!(order = GetNextOrder(unit, flush))) {
00848 return;
00849 }
00850 order->Init();
00851
00852 order->Action = UnitActionSpellCast;
00853 order->Range = spell->Range;
00854 if (dest) {
00855
00856
00857
00858
00859
00860 if (dest->Destroyed) {
00861
00862
00863 order->X = dest->X - order->Range;
00864 order->Y = dest->Y - order->Range;
00865 order->Range <<= 1;
00866 } else {
00867 order->Goal = dest;
00868 dest->RefsIncrease();
00869 }
00870 } else {
00871 order->Range = 1;
00872 order->X = x;
00873 order->Y = y;
00874 }
00875 order->Arg1.Spell = spell;
00876 }
00877 ClearSavedAction(unit);
00878 }
00879
00887 void CommandAutoSpellCast(CUnit *unit, int spellid, int on)
00888 {
00889
00890
00891
00892 if (!unit->Removed && unit->Orders[0]->Action != UnitActionDie) {
00893 unit->AutoCastSpell[spellid] = on;
00894 }
00895 }
00896
00904 void CommandDiplomacy(int player, int state, int opponent)
00905 {
00906 switch (state) {
00907 case DiplomacyNeutral:
00908 Players[player].Enemy &= ~(1 << opponent);
00909 Players[player].Allied &= ~(1 << opponent);
00910 break;
00911 case DiplomacyAllied:
00912 Players[player].Enemy &= ~(1 << opponent);
00913 Players[player].Allied |= 1 << opponent;
00914 break;
00915 case DiplomacyEnemy:
00916 Players[player].Enemy |= 1 << opponent;
00917 Players[player].Allied &= ~(1 << opponent);
00918 break;
00919 case DiplomacyCrazy:
00920 Players[player].Enemy |= 1 << opponent;
00921 Players[player].Allied |= 1 << opponent;
00922 break;
00923 }
00924
00925 }
00926
00934 void CommandSharedVision(int player, bool state, int opponent)
00935 {
00936 int before;
00937 int after;
00938 int x;
00939 int y;
00940 int i;
00941 CMapField *mf;
00942
00943
00944
00945
00946 for (i = 0; i < NumUnits; ++i) {
00947 if (!Units[i]->Destroyed) {
00948 MapUnmarkUnitSight(Units[i]);
00949 }
00950 }
00951
00952
00953
00954
00955 before = Players[player].IsBothSharedVision(&Players[opponent]);
00956 if (state == false) {
00957 Players[player].SharedVision &= ~(1 << opponent);
00958 } else {
00959 Players[player].SharedVision |= (1 << opponent);
00960 }
00961 after = Players[player].IsBothSharedVision(&Players[opponent]);
00962
00963 if (before && !after) {
00964
00965
00966
00967 for (x = 0; x < Map.Info.MapWidth; ++x) {
00968 for (y = 0; y < Map.Info.MapHeight; ++y) {
00969 mf = Map.Field(x, y);
00970 if (mf->Visible[player] && !mf->Visible[opponent]) {
00971 mf->Visible[opponent] = 1;
00972 }
00973 if (mf->Visible[opponent] && !mf->Visible[player]) {
00974 mf->Visible[player] = 1;
00975 }
00976 }
00977 }
00978 }
00979
00980
00981
00982
00983 for (i = 0; i < NumUnits; ++i) {
00984 if (!Units[i]->Destroyed) {
00985 MapMarkUnitSight(Units[i]);
00986 }
00987 }
00988 }
00989
00995 void CommandQuit(int player)
00996 {
00997 int i;
00998
00999
01000
01001 Players[player].Type = PlayerNeutral;
01002 for (i = 0; i < NumPlayers; ++i) {
01003 if (i != player && Players[i].Team != Players[player].Team) {
01004 Players[i].Allied &= ~(1 << player);
01005 Players[i].Enemy &= ~(1 << player);
01006 Players[player].Enemy &= ~(1 << i);
01007 Players[player].Allied &= ~(1 << i);
01008
01009
01010 CommandSharedVision(i, 0, player);
01011 CommandSharedVision(player, 0, i);
01012
01013 ChangeTeamSelectedUnits(&Players[player], NULL, 0, 0);
01014 }
01015 }
01016
01017 if (Players[player].TotalNumUnits != 0) {
01018 SetMessage(_("Player \"%s\" has left the game"), Players[player].Name.c_str());
01019 } else {
01020 SetMessage(_("Player \"%s\" has been killed"), Players[player].Name.c_str());
01021 }
01022 }
01023