diff --git a/src/action/action_move.cpp b/src/action/action_move.cpp index 1f8b438db..97edd9744 100644 --- a/src/action/action_move.cpp +++ b/src/action/action_move.cpp @@ -125,8 +125,6 @@ static int ActionMoveGeneric(Unit* unit, const Animation* anim) y = unit->Y + yd; MoveUnitToXY(unit, x, y); - MustRedraw |= RedrawMinimap; - // Remove unit from the current selection if (unit->Selected && !IsMapFieldVisible(ThisPlayer, x, y)) { if (NumSelected == 1) { // Remove building cursor diff --git a/src/action/action_train.cpp b/src/action/action_train.cpp index efae665ad..cd67fcae9 100644 --- a/src/action/action_train.cpp +++ b/src/action/action_train.cpp @@ -102,20 +102,18 @@ void HandleActionTrain(Unit* unit) // if (!unit->SubAction) { unit->Data.Train.Ticks = 0; - unit->Data.Train.What[0] = unit->Orders[0].Type; - unit->Data.Train.Count = 1; unit->SubAction = 1; } unit->Data.Train.Ticks += SpeedTrain; // FIXME: Should count down if (unit->Data.Train.Ticks >= - unit->Data.Train.What[0]->Stats[player->Player].Costs[TimeCost]) { + unit->Orders[0].Type->Stats[player->Player].Costs[TimeCost]) { // // Check if there are still unit slots. // if (NumUnits >= UnitMax) { unit->Data.Train.Ticks = - unit->Data.Train.What[0]->Stats[player->Player].Costs[TimeCost]; + unit->Orders[0].Type->Stats[player->Player].Costs[TimeCost]; unit->Reset = 1; unit->Wait = CYCLES_PER_SECOND / 6; return; @@ -124,20 +122,20 @@ void HandleActionTrain(Unit* unit) // // Check if enough supply available. // - food = PlayerCheckLimits(player, unit->Data.Train.What[0]); + food = PlayerCheckLimits(player, unit->Orders[0].Type); if (food < 0) { if (food == -3 && unit->Player->AiEnabled) { AiNeedMoreSupply(unit, unit->Orders[0].Type); } unit->Data.Train.Ticks = - unit->Data.Train.What[0]->Stats[player->Player].Costs[TimeCost]; + unit->Orders[0].Type->Stats[player->Player].Costs[TimeCost]; unit->Reset = 1; unit->Wait = CYCLES_PER_SECOND / 6; return; } - nunit = MakeUnit(unit->Data.Train.What[0], player); + nunit = MakeUnit(unit->Orders[0].Type, player); nunit->X = unit->X; nunit->Y = unit->Y; type = unit->Type; @@ -166,16 +164,8 @@ void HandleActionTrain(Unit* unit) unit->Reset = unit->Wait = 1; - if (--unit->Data.Train.Count) { - int z; - for (z = 0; z < unit->Data.Train.Count; ++z) { - unit->Data.Train.What[z] = unit->Data.Train.What[z + 1]; - } - unit->Data.Train.Ticks = 0; - } else { - unit->Orders[0].Action = UnitActionStill; - unit->SubAction = 0; - } + unit->Orders[0].Action = UnitActionStill; + unit->SubAction = 0; if (!CanHandleOrder(nunit, &unit->NewOrder)) { DebugPrint("Wrong order for unit\n"); diff --git a/src/action/actions.cpp b/src/action/actions.cpp index c9a32d48b..e9dc9e267 100644 --- a/src/action/actions.cpp +++ b/src/action/actions.cpp @@ -555,7 +555,7 @@ void UnitActions(void) fprintf(logf, "%d %s S%d/%d-%d P%d Refs %d: %X %d,%d %d,%d\n", UnitNumber(unit), unit->Type ? unit->Type->Ident : "unit-killed", unit->State, unit->SubAction, - unit->Orders[0].Action, + unit->Orders ? unit->Orders[0].Action : -1, unit->Player ? unit->Player->Player : -1, unit->Refs,SyncRandSeed, unit->X, unit->Y, unit->IX, unit->IY); @@ -569,7 +569,7 @@ void UnitActions(void) // Calculate some hash. // SyncHash = (SyncHash << 5) | (SyncHash >> 27); - SyncHash ^= unit->Orders[0].Action << 18; + SyncHash ^= unit->Orders ? unit->Orders[0].Action << 18 : 0; SyncHash ^= unit->State << 12; SyncHash ^= unit->SubAction << 6; SyncHash ^= unit->Refs << 3; diff --git a/src/action/command.cpp b/src/action/command.cpp index 900a6e950..8fba311a6 100644 --- a/src/action/command.cpp +++ b/src/action/command.cpp @@ -36,6 +36,7 @@ #include <stdio.h> #include <stdlib.h> +#include <string.h> #include "stratagus.h" #include "unittype.h" @@ -96,21 +97,57 @@ static void ReleaseOrders(Unit* unit) */ static Order* GetNextOrder(Unit* unit, int flush) { + Order *OldOrders; if (flush) { // empty command queue ReleaseOrders(unit); - } else if (unit->OrderCount == MAX_ORDERS) { - // FIXME: johns: wrong place for an error message. - // FIXME: johns: should be checked by AI or the user interface - // NOTE: But must still be checked here. - NotifyPlayer(unit->Player, NotifyYellow, unit->X, unit->Y, - "Unit order list is full"); - return NULL; + } else if (unit->OrderCount == unit->TotalOrders) { + // Expand Order Queue if filled + OldOrders = unit->Orders; + unit->Orders = realloc(unit->Orders, sizeof(Order) * unit->TotalOrders * 2); + // Realloc failed, fail gracefully + if (!unit->Orders) { + unit->Orders = OldOrders; + NotifyPlayer(unit->Player, NotifyYellow, unit->X, unit->Y, + "Unable to add order to list"); + return NULL; + } + memset(&unit->Orders[unit->TotalOrders], 0, sizeof(Order) * unit->TotalOrders); + unit->TotalOrders *= 2; } return &unit->Orders[(int)unit->OrderCount++]; } +/* +** Remove an order from the list of orders pending +** +** @param unit pointer to unit +** @param order number of the order to remove +*/ +static void RemoveOrder(Unit* unit, int order) +{ + int i; + + i = order; + while(i < unit->OrderCount - 1) { + unit->Orders[i] = unit->Orders[i + 1]; + ++i; + } + + if (unit->OrderCount > 1) { + --unit->OrderCount; + } else { + unit->Orders[i].Action = UnitActionStill; + unit->Orders[i].X = unit->Orders[i].Y = -1; + unit->SubAction = 0; + unit->Orders[i].Type = NULL; + unit->Orders[i].Arg1 = NULL; + } + + return; +} + /** ** Clear the saved action. ** @@ -839,6 +876,8 @@ void CommandReturnGoods(Unit* unit, Unit* goal, int flush) void CommandTrainUnit(Unit* unit, UnitType* type, int flush __attribute__((unused))) { + Order* order; + // // Check if unit is still valid? (NETWORK!) // @@ -855,32 +894,19 @@ void CommandTrainUnit(Unit* unit, UnitType* type, // // Not already training? // - if (unit->Orders[0].Action != UnitActionTrain) { - if (unit->OrderCount == 2 && unit->Orders[1].Action == UnitActionTrain) { - DebugPrint("FIXME: not supported. Unit queue full!\n"); - return; - } else { - ReleaseOrders(unit); - unit->Orders[1].Action = UnitActionTrain; - } - Assert(unit->OrderCount == 1 && unit->OrderFlush == 1); - - unit->OrderCount = 2; - unit->Orders[1].Type = type; - unit->Orders[1].X = unit->Orders[1].Y = -1; - unit->Orders[1].Goal = NoUnitP; - unit->Orders[1].Arg1 = NULL; - } else { - // - // Training slots are all already full. (NETWORK!) - // - if (!EnableTrainingQueue || unit->Data.Train.Count >= MAX_UNIT_TRAIN) { - DebugPrint("Unit queue full!\n"); - return; - } - - unit->Data.Train.What[unit->Data.Train.Count++] = type; + if (!EnableTrainingQueue && unit->Orders[0].Action == UnitActionTrain) { + DebugPrint("Unit queue full!\n"); + return; } + if (!(order = GetNextOrder(unit, 0))) { + return; + } + + order->Action = UnitActionTrain; + order->Type = type; + order->X = order->Y = -1; + order->Goal = NoUnitP; + order->Arg1 = NULL; // FIXME: if you give quick an other order, the resources are lost! PlayerSubUnitType(unit->Player, type); } @@ -896,8 +922,6 @@ void CommandTrainUnit(Unit* unit, UnitType* type, */ void CommandCancelTraining(Unit* unit, int slot, const UnitType* type) { - int i; - int n; DebugPrint("Cancel %d type: %s\n" _C_ slot _C_ type ? type->Ident : "-any-"); @@ -907,42 +931,45 @@ void CommandCancelTraining(Unit* unit, int slot, const UnitType* type) // // Check if unit is still training 'slot'? (NETWORK!) // - if (unit->Orders[0].Action == UnitActionTrain) { - n = unit->Data.Train.Count; - Assert(n >= 1); - if (slot == -1) { // default last slot! - slot += n; + + if (slot == -1) { + // Cancel All training + while(unit->Orders[0].Action == UnitActionTrain) { + PlayerAddCostsFactor(unit->Player, + unit->Orders[0].Type->Stats[unit->Player->Player].Costs, + CancelTrainingCostsFactor); + RemoveOrder(unit, 0); + } + unit->Data.Train.Ticks = 0; + unit->Wait = unit->Reset = 1; // immediately start next training + if (unit->Player == ThisPlayer && unit->Selected) { + SelectedUnitChanged(); } - // - // Check if slot and unit-type is still trained? (NETWORK!) - // - if (slot >= n || (type && unit->Data.Train.What[slot] != type)) { - // FIXME: we can look if this is now in an earlier slot. + } else if (unit->OrderCount < slot) { + // Order has moved + return; + } else if (unit->Orders[slot].Action != UnitActionTrain) { + // Order has moved, we are not training + return; + } else if (unit->Orders[slot].Action == UnitActionTrain) { + // Still training this order, same unit? + if (type && unit->Orders[slot].Type != type) { + // Different unit being trained return; } DebugPrint("Cancel training\n"); PlayerAddCostsFactor(unit->Player, - unit->Data.Train.What[slot]->Stats[unit->Player->Player].Costs, + unit->Orders[slot].Type->Stats[unit->Player->Player].Costs, CancelTrainingCostsFactor); - if (--n) { - // Copy the other slots down - for (i = slot; i < n; ++i) { - unit->Data.Train.What[i] = unit->Data.Train.What[i + 1]; - } - if (!slot) { // Canceled in work slot - unit->Data.Train.Ticks = 0; - unit->Wait = unit->Reset = 1; // immediately start next training - } - unit->Data.Train.Count = n; - } else { - DebugPrint("Last slot\n"); - unit->Orders[0].Action = UnitActionStill; - unit->SubAction = 0; - unit->Wait = unit->Reset = 1; + + if (!slot) { // Canceled in work slot + unit->Data.Train.Ticks = 0; + unit->Wait = unit->Reset = 1; // immediately start next training } + RemoveOrder(unit, slot); // // Update interface. diff --git a/src/ai/ai.cpp b/src/ai/ai.cpp index 32e597280..8fe361631 100644 --- a/src/ai/ai.cpp +++ b/src/ai/ai.cpp @@ -1513,7 +1513,6 @@ static int FindTransporterOnZone(int waterzone, ZoneSet* destzones, // If transporter is moving, check if it is moving on our coast if (!unitok && unit->OrderCount + (unit->OrderFlush ? 1 : 0) >= 2 && - unit->OrderCount < MAX_ORDERS - 1 && unit->Orders[unit->OrderFlush ? 1 : 0].Action == UnitActionFollow && unit->Orders[unit->OrderCount - 1].Action == UnitActionUnload && unit->BoardCount + unit->OrderCount - (unit->OrderFlush ? 1 : 0) <= unit->Type->MaxOnBoard) { diff --git a/src/editor/editloop.cpp b/src/editor/editloop.cpp index a51451439..e5881364e 100644 --- a/src/editor/editloop.cpp +++ b/src/editor/editloop.cpp @@ -77,10 +77,10 @@ static int IconWidth; /// Icon width in panels static int IconHeight; /// Icon height in panels -char EditorRunning; /// True editor is running char EditorMapLoaded; /// Map loaded in editor -EditorStateType EditorState; /// Current editor state. +EditorStateType EditorState; /// Current editor state. +EditorRunningType EditorRunning; /// Running State of editor. static char TileToolRandom; /// Tile tool draws random static char TileToolDecoration; /// Tile tool draws with decorations @@ -201,7 +201,6 @@ void EditTile(int x, int y, int tile) UpdateMinimapSeenXY(x, y); UpdateMinimapXY(x, y); - MustRedraw |= RedrawMinimap; EditorTileChanged(x, y); } @@ -1168,7 +1167,6 @@ static void EditorCallbackButtonDown(unsigned button __attribute__ ((unused))) if (TheMap.Info->PlayerType[CursorPlayer] != PlayerNobody) { SelectedPlayer = CursorPlayer; ThisPlayer = Players + SelectedPlayer; - MustRedraw |= RedrawMinimap; } return; } @@ -2025,7 +2023,7 @@ void EditorMainLoop(void) while (1) { EditorMapLoaded = 0; - EditorRunning = 1; + EditorRunning = EditorEditing; CreateEditor(); diff --git a/src/include/editor.h b/src/include/editor.h index 153c7d4ec..7295f86f5 100644 --- a/src/include/editor.h +++ b/src/include/editor.h @@ -38,7 +38,15 @@ ----------------------------------------------------------------------------*/ /// Editor is running -extern char EditorRunning; +typedef enum _editor_running_state_ { + EditorNotRunning = 0, ///< Not Running + EditorStarted = 1, ///< Editor Enabled at all + EditorCommandLine = 2, ///< Called from Command Line + EditorEditing = 4 ///< Editor is fully running +} EditorRunningType; + +extern EditorRunningType EditorRunning; + /// Map loaded in editor extern char EditorMapLoaded; /// Current editor state type. diff --git a/src/include/stratagus.h b/src/include/stratagus.h index 0462fde78..0698508f7 100644 --- a/src/include/stratagus.h +++ b/src/include/stratagus.h @@ -248,6 +248,7 @@ extern char NameLine[]; /// Game cycles per second to simulate (original 30-40) #define CYCLES_PER_SECOND 30 // 1/30s 0.33ms +#define DEFAULT_START_ORDERS 4 // The number of Orders allocated on unit creation /// Must redraw flags enum _must_redraw_flags_ { RedrawNothing = 1 << 0, ///< Nothing to do @@ -275,21 +276,6 @@ enum _must_redraw_flags_ { RedrawEverything = -1, ///< Must redraw everything }; - /// Must redraw all maps -#define RedrawMaps (RedrawMinimap | RedrawMap) - /// Must redraw all cursors -#define RedrawCursors (RedrawMinimapCursor | RedrawCursor) - /// Must redraw all panels -#define RedrawPanels (RedrawInfoPanel | RedrawButtonPanel) - /// Must redraw after color cycle -#define RedrawColorCycle (RedrawMap | RedrawInfoPanel | RedrawButtonPanel | RedrawResources) - - /// Invalidated redraw flags -extern int MustRedraw; - - /// Enable redraw flags -extern int EnableRedraw; - /*---------------------------------------------------------------------------- -- clone.c ----------------------------------------------------------------------------*/ diff --git a/src/include/unit.h b/src/include/unit.h index 795ef657d..9cb37f6cc 100644 --- a/src/include/unit.h +++ b/src/include/unit.h @@ -331,18 +331,23 @@ ** Unit::OrderCount ** ** The number of the orders unit to process. An unit has atleast -** one order. Unit::OrderCount should be a number between 1 and -** ::MAX_ORDERS. The orders are in Unit::Orders[]. +** one order. Unit::OrderCount should be a number at least 1. +** The orders are in Unit::Orders[]. ** ** Unit::OrderFlush ** ** A flag, which tells the unit to stop with the current order ** and immediately start with the next order. ** +** Unit::TotalOrders +** +** The number of Orders allocated for this unit to use. +** Default is 4, but is dynamically updated if more orders are +** given. +** ** Unit::Orders ** ** Contains all orders of the unit. Slot 0 is always used. -** Up to ::MAX_ORDERS can be stored. ** ** Unit::SavedOrder ** @@ -596,10 +601,10 @@ struct _unit_ { unsigned Rs : 8; unsigned char CurrentResource; -#define MAX_ORDERS 16 ///< How many outstanding orders? char OrderCount; ///< how many orders in queue char OrderFlush; ///< cancel current order, take next - Order Orders[MAX_ORDERS]; ///< orders to process + int TotalOrders; ///< Total Number of orders available + Order* Orders; ///< orders to process Order SavedOrder; ///< order to continue after current Order NewOrder; ///< order for new trained units char* AutoCastSpell; ///< spells to auto cast @@ -632,10 +637,6 @@ struct _unit_ { } UpgradeTo; ///< Upgrade to action struct _order_train_ { int Ticks; ///< Ticks to complete - int Count; ///< Units in training queue - // TODO: vladi: later we should train more units or automatic -#define MAX_UNIT_TRAIN 6 ///< max number of units in queue - UnitType* What[MAX_UNIT_TRAIN]; ///< Unit trained } Train; ///< Train units action } Data; ///< Storage room for different commands @@ -729,6 +730,9 @@ extern int NumTeamSelected[PlayerMax]; ///< Number of Units a team member ha extern Unit* ReleasedHead; ///< Head of the released unit list. extern Unit* ReleasedTail; ///< Tail of the released unit list. +extern Order* ReleasedOrderHead; ///< Head of the released orders list. +extern Order* ReleasedOrderTail; ///< Tail of the released unit list. + /*---------------------------------------------------------------------------- -- Functions ----------------------------------------------------------------------------*/ diff --git a/src/map/map.cpp b/src/map/map.cpp index 7dfa0395a..a1d25711e 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -207,8 +207,6 @@ void ViewportSetViewpoint(Viewport* vp, int x, int y, int offsetx, int offsety) vp->OffsetY = y % TileSizeY; vp->MapWidth = ((vp->EndX - vp->X) + vp->OffsetX - 1) / TileSizeX + 1; vp->MapHeight = ((vp->EndY - vp->Y) + vp->OffsetY - 1) / TileSizeY + 1; - - MustRedraw |= RedrawMinimap | RedrawMinimapCursor; } /** diff --git a/src/map/map_rock.cpp b/src/map/map_rock.cpp index aa4a2187c..6dede6f02 100644 --- a/src/map/map_rock.cpp +++ b/src/map/map_rock.cpp @@ -178,7 +178,6 @@ void MapFixSeenRockTile(int x, int y) // FIXME: can this only happen if seen? if (IsMapFieldVisible(ThisPlayer, x, y)) { UpdateMinimapSeenXY(x, y); - MustRedraw |= RedrawMinimap; } } @@ -317,7 +316,6 @@ void MapFixRockTile(int x, int y) if (IsMapFieldVisible(ThisPlayer, x, y)) { UpdateMinimapSeenXY(x, y); MapMarkSeenTile(x, y); - MustRedraw |= RedrawMinimap; } } } @@ -344,7 +342,6 @@ void MapRemoveRock(unsigned x, unsigned y) if (IsMapFieldVisible(ThisPlayer, x, y)) { UpdateMinimapSeenXY(x, y); MapMarkSeenTile(x, y); - MustRedraw |= RedrawMinimap; } #ifdef MAP_REGIONS MapSplitterTilesCleared(x, y, x, y); diff --git a/src/map/map_wall.cpp b/src/map/map_wall.cpp index af194631d..d2585767e 100644 --- a/src/map/map_wall.cpp +++ b/src/map/map_wall.cpp @@ -165,7 +165,6 @@ void MapFixSeenWallTile(int x, int y) // FIXME: can this only happen if seen? if (IsMapFieldVisible(ThisPlayer, x, y)) { UpdateMinimapSeenXY(x, y); - MustRedraw |= RedrawMinimap; } } } @@ -265,7 +264,6 @@ void MapFixWallTile(int x, int y) if (IsMapFieldVisible(ThisPlayer, x, y)) { UpdateMinimapSeenXY(x, y); MapMarkSeenTile(x, y); - MustRedraw |= RedrawMinimap; } } } @@ -305,7 +303,6 @@ void MapRemoveWall(unsigned x, unsigned y) if (IsMapFieldVisible(ThisPlayer, x, y)) { UpdateMinimapSeenXY(x, y); MapMarkSeenTile(x, y); - MustRedraw |= RedrawMinimap; } #ifdef MAP_REGIONS MapSplitterTilesCleared(x, y, x, y); @@ -347,7 +344,6 @@ void MapSetWall(unsigned x, unsigned y, int humanwall) if (IsMapFieldVisible(ThisPlayer, x, y)) { UpdateMinimapSeenXY(x, y); MapMarkSeenTile(x, y); - MustRedraw |= RedrawMinimap; } #ifdef MAP_REGIONS MapSplitterTilesOccuped(x, y, x, y); diff --git a/src/map/map_wood.cpp b/src/map/map_wood.cpp index 01b4e57f7..65df1de80 100644 --- a/src/map/map_wood.cpp +++ b/src/map/map_wood.cpp @@ -176,7 +176,6 @@ void MapFixSeenWoodTile(int x, int y) // FIXME: can this only happen if seen? if (IsMapFieldVisible(ThisPlayer, x, y)) { UpdateMinimapSeenXY(x, y); - MustRedraw |= RedrawMinimap; } } @@ -313,7 +312,6 @@ void MapFixWoodTile(int x, int y) if (IsMapFieldVisible(ThisPlayer, x, y)) { UpdateMinimapSeenXY(x, y); MapMarkSeenTile(x, y); - MustRedraw |= RedrawMinimap; } } } @@ -341,7 +339,6 @@ void MapRemoveWood(unsigned x, unsigned y) if (IsMapFieldVisible(ThisPlayer, x, y)) { UpdateMinimapSeenXY(x, y); MapMarkSeenTile(x, y); - MustRedraw |= RedrawMinimap; } #ifdef MAP_REGIONS MapSplitterTilesCleared(x, y, x, y); diff --git a/src/pathfinder/astar.cpp b/src/pathfinder/astar.cpp index 802edc551..6ce0b276f 100644 --- a/src/pathfinder/astar.cpp +++ b/src/pathfinder/astar.cpp @@ -729,6 +729,10 @@ int AStarFindPath(Unit* unit, int gx, int gy, int gw, int gh, int minrange, int // let's clean up the matrix now AStarCleanUp(num_in_close); + if ((TheMap.Width*TheMap.Height) - counter > 500) { + DebugPrint("%s:%d Visited %d tiles\n" _C_ unit->Type->Name _C_ UnitNumber(unit) + _C_ (TheMap.Width*TheMap.Height) - counter); + } return path_length; } diff --git a/src/stratagus/mainloop.cpp b/src/stratagus/mainloop.cpp index c81dd8090..f82a2a540 100644 --- a/src/stratagus/mainloop.cpp +++ b/src/stratagus/mainloop.cpp @@ -67,6 +67,7 @@ #include "commands.h" #include "cdaudio.h" #include "pathfinder.h" +#include "editor.h" #ifdef USE_SDLCD #include "SDL.h" @@ -336,7 +337,7 @@ void DrawMapArea(void) */ void UpdateDisplay(void) { - if (EnableRedraw != RedrawMenu) { + if (GameRunning || EditorRunning == EditorEditing) { int i; DrawMapArea(); diff --git a/src/stratagus/stratagus.cpp b/src/stratagus/stratagus.cpp index 4ab71eba2..43f2d01fd 100644 --- a/src/stratagus/stratagus.cpp +++ b/src/stratagus/stratagus.cpp @@ -257,10 +257,6 @@ int SpeedResearch = 1; ///< speed factor for researching == DISPLAY ============================================================================*/ -// FIXME: not the correct place -int MustRedraw = RedrawEverything; ///< Redraw flags -int EnableRedraw = RedrawEverything; ///< Enable flags - unsigned long GameCycle; ///< Game simulation cycle counter unsigned long FastForwardCycle; ///< Cycle to fastforward to in a replay @@ -664,8 +660,6 @@ void MenuLoop(char* filename, WorldMap* map) PlayMusic(MenuMusic); } - EnableRedraw = RedrawMenu; - GuiGameStarted = 0; while (GuiGameStarted == 0) { int old_video_sync; @@ -673,7 +667,7 @@ void MenuLoop(char* filename, WorldMap* map) old_video_sync = VideoSyncSpeed; VideoSyncSpeed = 100; SetVideoSync(); - if (EditorRunning == 2) { + if (EditorRunning == EditorCommandLine) { SetupEditor(); } if (EditorRunning) { @@ -685,7 +679,6 @@ void MenuLoop(char* filename, WorldMap* map) SetVideoSync(); } - EnableRedraw = RedrawEverything; DebugPrint("Menu start: NetPlayers %d\n" _C_ NetPlayers); filename = CurrentMapPath; } else { @@ -983,7 +976,7 @@ int main(int argc, char** argv) } continue; case 'e': - EditorRunning = 2; + EditorRunning = EditorCommandLine; continue; case 'E': EditorStartFile = optarg; diff --git a/src/ui/botpanel.cpp b/src/ui/botpanel.cpp index d03172ac7..efccd6173 100644 --- a/src/ui/botpanel.cpp +++ b/src/ui/botpanel.cpp @@ -811,8 +811,7 @@ void DoButtonButtonClicked(int button) break; case ButtonCancelTrain: - Assert(Selected[0]->Orders[0].Action == UnitActionTrain && - Selected[0]->Data.Train.Count); + Assert(Selected[0]->Orders[0].Action == UnitActionTrain); SendCommandCancelTraining(Selected[0], -1, NULL); ClearStatusLine(); ClearCosts(); @@ -848,8 +847,7 @@ void DoButtonButtonClicked(int button) // FIXME: training queue full check is not correct for network. // FIXME: this can be correct written, with a little more code. if (Selected[0]->Orders[0].Action == UnitActionTrain && - (Selected[0]->Data.Train.Count == MAX_UNIT_TRAIN || - !EnableTrainingQueue)) { + !EnableTrainingQueue) { NotifyPlayer(Selected[0]->Player, NotifyYellow, Selected[0]->X, Selected[0]->Y, "Unit training queue is full"); } else if (PlayerCheckLimits(Selected[0]->Player, type) >= 0 && diff --git a/src/ui/interface.cpp b/src/ui/interface.cpp index 7d248e29c..be79ff7ef 100644 --- a/src/ui/interface.cpp +++ b/src/ui/interface.cpp @@ -461,8 +461,6 @@ static void UiToggleBigMap(void) SetViewportMode(TheUI.ViewportMode); - EnableRedraw = RedrawMap | RedrawCursor | RedrawMessage | RedrawMenu | - RedrawTimer | RedrawAll; SetStatusLine("Big map enabled"); } else { TheUI.MapArea.X = mapx; @@ -472,7 +470,6 @@ static void UiToggleBigMap(void) SetViewportMode(TheUI.ViewportMode); - EnableRedraw = RedrawEverything; SetStatusLine("Returning to old map"); } } @@ -559,7 +556,6 @@ static void UiToggleTerrain(void) } else { SetStatusLine("Terrain hidden."); } - MustRedraw |= RedrawMinimap; } /** diff --git a/src/ui/mainscr.cpp b/src/ui/mainscr.cpp index 48b7ccc0a..c97cbee79 100644 --- a/src/ui/mainscr.cpp +++ b/src/ui/mainscr.cpp @@ -375,20 +375,20 @@ static void DrawUnitInfo(const Unit* unit) // Building training units. // if (unit->Orders[0].Action == UnitActionTrain) { - if (unit->Data.Train.Count == 1) { + if (unit->Orders[1].Action != UnitActionTrain) { if (TheUI.SingleTrainingText) { VideoDrawText(TheUI.SingleTrainingTextX, TheUI.SingleTrainingTextY, TheUI.SingleTrainingFont, TheUI.SingleTrainingText); } if (TheUI.SingleTrainingButton) { - DrawUnitIcon(unit->Player, unit->Data.Train.What[0]->Icon.Icon, + DrawUnitIcon(unit->Player, unit->Orders[0].Type->Icon.Icon, (ButtonAreaUnderCursor == ButtonAreaTraining && ButtonUnderCursor == 0) ? (IconActive | (MouseButtons & LeftButton)) : 0, TheUI.SingleTrainingButton->X, TheUI.SingleTrainingButton->Y); } - UiDrawCompletedBar(unit->Data.Train.What[0]->Stats[ + UiDrawCompletedBar(unit->Orders[0].Type->Stats[ unit->Player->Player].Costs[TimeCost], unit->Data.Train.Ticks); } else { @@ -397,17 +397,19 @@ static void DrawUnitInfo(const Unit* unit) TheUI.TrainingFont, TheUI.TrainingText); } if (TheUI.TrainingButtons) { - for (i = 0; i < unit->Data.Train.Count && + for (i = 0; i < unit->OrderCount && i < TheUI.NumTrainingButtons; ++i) { - DrawUnitIcon(unit->Player, unit->Data.Train.What[i]->Icon.Icon, - (ButtonAreaUnderCursor == ButtonAreaTraining && - ButtonUnderCursor == i) ? - (IconActive | (MouseButtons & LeftButton)) : 0, - TheUI.TrainingButtons[i].X, TheUI.TrainingButtons[i].Y); + if (unit->Orders[i].Action == UnitActionTrain) { + DrawUnitIcon(unit->Player, unit->Orders[i].Type->Icon.Icon, + (ButtonAreaUnderCursor == ButtonAreaTraining && + ButtonUnderCursor == i) ? + (IconActive | (MouseButtons & LeftButton)) : 0, + TheUI.TrainingButtons[i].X, TheUI.TrainingButtons[i].Y); + } } } - UiDrawCompletedBar(unit->Data.Train.What[0]->Stats[ + UiDrawCompletedBar(unit->Orders[0].Type->Stats[ unit->Player->Player].Costs[TimeCost], unit->Data.Train.Ticks); } diff --git a/src/ui/menus.cpp b/src/ui/menus.cpp index 3a56d6b6f..c388a0701 100644 --- a/src/ui/menus.cpp +++ b/src/ui/menus.cpp @@ -1837,7 +1837,6 @@ static void SetFogOfWar(Menuitem *mi __attribute__((unused))) UpdateFogOfWarChange(); CommandLog("input", NoUnitP, FlushCommands, -1, -1, NoUnitP, "fow on", -1); } - MustRedraw &= ~RedrawMinimap; } /** @@ -4718,7 +4717,7 @@ static void StartEditor(void) { SetupEditor(); - EditorRunning = 1; + EditorRunning = EditorStarted; EndMenu(); } @@ -4763,7 +4762,7 @@ void SetupEditor(void) static void EditorSelectCancel(void) { QuitToMenu = 1; - EditorRunning = 0; + EditorRunning = EditorNotRunning; EndMenu(); } @@ -5349,7 +5348,7 @@ void EditorLoadMenu(void) } EditorMapLoaded = 1; - EditorRunning = 0; + EditorRunning = EditorNotRunning; EndMenu(); } @@ -6193,7 +6192,7 @@ static void EditorSaveConfirmCancel(void) static void EditorQuitToMenu(void) { QuitToMenu = 1; - EditorRunning = 0; + EditorRunning = EditorNotRunning; EndMenu(); } diff --git a/src/ui/mouse.cpp b/src/ui/mouse.cpp index 75475d855..32978d53f 100644 --- a/src/ui/mouse.cpp +++ b/src/ui/mouse.cpp @@ -445,7 +445,7 @@ static void HandleMouseOn(int x, int y) } if (NumSelected == 1 && Selected[0]->Type->Building && !BigMapMode) { if (Selected[0]->Orders[0].Action == UnitActionTrain) { - if (Selected[0]->Data.Train.Count == 1) { + if (Selected[0]->OrderCount == 1) { if (TheUI.SingleTrainingButton && x >= TheUI.SingleTrainingButton->X && x < TheUI.SingleTrainingButton->X + TheUI.SingleTrainingButton->Width + 7 && @@ -457,10 +457,10 @@ static void HandleMouseOn(int x, int y) return; } } else { - i = (TheUI.NumTrainingButtons < Selected[0]->Data.Train.Count) ? - TheUI.NumTrainingButtons : Selected[0]->Data.Train.Count; - for (--i; i >= 0; --i) { - if (x >= TheUI.TrainingButtons[i].X && + for (i = 0; i < Selected[0]->OrderCount && + i < TheUI.NumTrainingButtons; ++i) { + if (Selected[0]->Orders[i].Action == UnitActionTrain && + x >= TheUI.TrainingButtons[i].X && x < TheUI.TrainingButtons[i].X + TheUI.TrainingButtons[i].Width + 7 && y >= TheUI.TrainingButtons[i].Y && y < TheUI.TrainingButtons[i].Y + TheUI.TrainingButtons[i].Height + 7) { @@ -1482,7 +1482,6 @@ void UIHandleButtonDown(unsigned button) if (NumSelected && Selected[0]->Player == ThisPlayer && CursorState == CursorStatePoint) { CursorState = CursorStatePieMenu; - MustRedraw |= RedrawCursor; } } else if (MouseButtons & LeftButton) { // enter select mode CursorStartX = CursorX; @@ -1587,13 +1586,14 @@ void UIHandleButtonDown(unsigned button) } else if (ButtonAreaUnderCursor == ButtonAreaTraining) { if (!GameObserve && !GamePaused && PlayersTeamed(ThisPlayer->Player, Selected[0]->Player->Player)) { - if (ButtonUnderCursor < Selected[0]->Data.Train.Count) { + if (ButtonUnderCursor < Selected[0]->OrderCount && + Selected[0]->Orders[ButtonUnderCursor].Action == UnitActionTrain) { DebugPrint("Cancel slot %d %s\n" _C_ ButtonUnderCursor _C_ - Selected[0]->Data.Train.What[ButtonUnderCursor]->Ident); + Selected[0]->Orders[ButtonUnderCursor].Type->Ident); SendCommandCancelTraining(Selected[0], ButtonUnderCursor, - Selected[0]->Data.Train.What[ButtonUnderCursor]); + Selected[0]->Orders[ButtonUnderCursor].Type); } } // diff --git a/src/unit/script_unit.cpp b/src/unit/script_unit.cpp index bc8fa1792..cbdcd3dcb 100644 --- a/src/unit/script_unit.cpp +++ b/src/unit/script_unit.cpp @@ -348,12 +348,9 @@ void CclParseOrder(lua_State* l, Order* order) */ static void CclParseOrders(lua_State* l, Unit* unit) { - int args; int j; - args = luaL_getn(l, -1); - Assert(args == MAX_ORDERS); - for (j = 0; j < args; ++j) { + for (j = 0; j < unit->TotalOrders; ++j) { lua_rawgeti(l, -1, j + 1); CclParseOrder(l, &unit->Orders[j]); lua_pop(l, 1); @@ -514,7 +511,6 @@ static void CclParseUpgradeTo(lua_State* l, Unit* unit) static void CclParseTrain(lua_State* l, Unit* unit) { const char* value; - int i; int args; int j; @@ -531,30 +527,6 @@ static void CclParseTrain(lua_State* l, Unit* unit) lua_rawgeti(l, -1, j + 1); unit->Data.Train.Ticks = LuaToNumber(l, -1); lua_pop(l, 1); - } else if (!strcmp(value, "count")) { - lua_rawgeti(l, -1, j + 1); - unit->Data.Train.Count = LuaToNumber(l, -1); - lua_pop(l, 1); - } else if (!strcmp(value, "queue")) { - int subargs; - int k; - - lua_rawgeti(l, -1, j + 1); - if (!lua_istable(l, -1)) { - LuaError(l, "incorrect argument"); - } - subargs = luaL_getn(l, -1); - for (i = 0, k = 0; i < MAX_UNIT_TRAIN && k < subargs; ++i, ++k) { - lua_rawgeti(l, -1, k + 1); - value = LuaToString(l, -1); - lua_pop(l, 1); - if (!strcmp(value, "unit-none")) { - unit->Data.Train.What[i] = NULL; - } else { - unit->Data.Train.What[i] = UnitTypeByIdent(value); - } - } - lua_pop(l, 1); } } } @@ -859,6 +831,11 @@ static int CclUnit(lua_State* l) unit->OrderCount = LuaToNumber(l, j + 1); } else if (!strcmp(value, "order-flush")) { unit->OrderFlush = LuaToNumber(l, j + 1); + } else if (!strcmp(value, "order-total")) { + unit->TotalOrders = LuaToNumber(l, j + 1); + free(unit->Orders); + // Allocate the space for orders + unit->Orders = calloc(unit->TotalOrders, sizeof(Order)); } else if (!strcmp(value, "orders")) { int hp; diff --git a/src/unit/unit.cpp b/src/unit/unit.cpp index 54514d33c..7fcd5e759 100644 --- a/src/unit/unit.cpp +++ b/src/unit/unit.cpp @@ -74,6 +74,9 @@ Unit** UnitSlotFree; ///< First free unit slot Unit* ReleasedHead; ///< List of released units. Unit* ReleasedTail; ///< List tail of released units. +Order* ReleasedOrderHead; ///< List of released Orders. +Order* ReleasedOrderTail; ///< List tail of released orders. + Unit* Units[MAX_UNIT_SLOTS]; ///< Array of used slots int NumUnits; ///< Number of slots used @@ -225,6 +228,18 @@ void ReleaseUnit(Unit* unit) unit->Refs = GameCycle + (NetworkMaxLag << 1); // could be reuse after this time unit->Type = 0; // for debugging. free(unit->CacheLinks); + + if (ReleasedOrderHead) { + ReleasedOrderTail->Arg1 = unit->Orders; + ReleasedOrderTail = unit->Orders; + unit->Orders->Arg1 = NULL; + } else { + ReleasedOrderHead = ReleasedOrderTail = unit->Orders; + unit->Orders->Arg1 = NULL; + } + unit->Orders->X = GameCycle + (NetworkMaxLag << 1); // could be reuse after this time + unit->Orders->Y = unit->TotalOrders; // store order count for when reused + unit->Orders = NULL; } /** @@ -339,6 +354,18 @@ void InitUnit(Unit* unit, UnitType* type) unit->Rs = MyRand() % 100; // used for fancy buildings and others + // Init Orders and Default to Still/None + if (ReleasedOrderHead && (unsigned)ReleasedOrderHead->X < GameCycle) { + unit->Orders = ReleasedOrderHead; + unit->TotalOrders = ReleasedOrderHead->Y; + ReleasedOrderHead = (Order*)ReleasedOrderHead->Arg1; + } else { + // No Available Orders in Memory, create new ones + unit->TotalOrders = DEFAULT_START_ORDERS; + unit->Orders = calloc(unit->TotalOrders, sizeof(Order)); + } + + unit->OrderCount = 1; // No orders unit->Orders[0].Action = UnitActionStill; unit->Orders[0].X = unit->Orders[0].Y = -1; @@ -596,7 +623,6 @@ static void MarkUnitFieldFlags(const Unit* unit) MapSplitterTilesOccuped(x, y, x + type->TileWidth - 1, y + type->TileHeight - 1); } #endif - } /** @@ -761,7 +787,6 @@ void PlaceUnit(Unit* unit, int x, int y) // Vision MapMarkUnitSight(unit); - MustRedraw |= RedrawMinimap; UnitCountSeen(unit); } @@ -832,7 +857,6 @@ void RemoveUnit(Unit* unit, Unit* host) if (unit == UnitUnderCursor) { UnitUnderCursor = NULL; } - MustRedraw |= RedrawMinimap; } /** @@ -3576,8 +3600,9 @@ void SaveUnit(const Unit* unit, CLFile* file) } CLprintf(file, "\"order-count\", %d,\n ", unit->OrderCount); CLprintf(file, "\"order-flush\", %d,\n ", unit->OrderFlush); + CLprintf(file, "\"order-total\", %d,\n ", unit->TotalOrders); CLprintf(file, "\"orders\", {"); - for (i = 0; i < MAX_ORDERS; ++i) { + for (i = 0; i < unit->TotalOrders; ++i) { CLprintf(file, "\n "); SaveOrder(&unit->Orders[i], file); CLprintf(file, ","); @@ -3643,17 +3668,7 @@ void SaveUnit(const Unit* unit, CLFile* file) case UnitActionTrain: CLprintf(file, ",\n \"data-train\", {"); CLprintf(file, "\"ticks\", %d, ", unit->Data.Train.Ticks); - CLprintf(file, "\"count\", %d, ", unit->Data.Train.Count); - CLprintf(file, "\"queue\", {"); - for (i = 0; i < MAX_UNIT_TRAIN; ++i) { - if (i < unit->Data.Train.Count) { - CLprintf(file, "\"%s\", ", unit->Data.Train.What[i]->Ident); - } else { - /* this slot is currently unused */ - CLprintf(file, "\"unit-none\", "); - } - } - CLprintf(file, "}}"); + CLprintf(file, "}"); break; default: CLprintf(file, ",\n \"data-move\", {"); @@ -3791,6 +3806,7 @@ void CleanUnits(void) { Unit** table; Unit* unit; + Order* order; // // Free memory for all units in unit table. @@ -3809,6 +3825,14 @@ void CleanUnits(void) ReleasedHead = unit->Next; free(unit); } + + // + // Release memory of Orders in the release queue. + while ((order = ReleasedOrderHead)) { + ReleasedOrderHead = order->Arg1; + free(order); + } + InitUnitsMemory(); XpDamage = 0; diff --git a/src/unit/unit_draw.cpp b/src/unit/unit_draw.cpp index 031350545..6aafa52fe 100644 --- a/src/unit/unit_draw.cpp +++ b/src/unit/unit_draw.cpp @@ -1083,7 +1083,7 @@ static void DrawDecoration(const Unit* unit, const UnitType* type, int x, int y) if (unit->Orders[0].Action == UnitActionTrain) { unit->Variable[TRAINING_INDEX].Value = unit->Data.Train.Ticks; unit->Variable[TRAINING_INDEX].Max = - unit->Data.Train.What[0]->Stats[unit->Player->Player].Costs[TimeCost]; + unit->Orders[0].Type->Stats[unit->Player->Player].Costs[TimeCost]; } // UpgradeTo diff --git a/src/unit/upgrade.cpp b/src/unit/upgrade.cpp index 8f6f1646e..46a04d139 100644 --- a/src/unit/upgrade.cpp +++ b/src/unit/upgrade.cpp @@ -1165,16 +1165,16 @@ static void ConvertUnitTypeTo(Player* player, const UnitType* src, UnitType* dst // FIXME: what about buildings? // } else { - if (unit->Orders[0].Action == UnitActionTrain) { - for (j = 0; j < unit->Data.Train.Count; ++j) { - if (unit->Data.Train.What[j] == src) { - unit->Data.Train.What[j] = dst; - } - } - } - for (j = 1; j < unit->OrderCount; ++j) { + for (j = 0; j < unit->OrderCount; ++j) { if (unit->Orders[j].Action == UnitActionTrain && unit->Orders[j].Type == src) { + if (j == 0) { + // Must Adjust Ticks to the fraction that was trained + unit->Data.Train.Ticks = + unit->Data.Train.Ticks * + dst->Stats[player->Player].Costs[TimeCost] / + src->Stats[player->Player].Costs[TimeCost]; + } unit->Orders[j].Type = dst; } }