From 087c4c85e9cc8dd586b1507207943321fb494bac Mon Sep 17 00:00:00 2001 From: mr-russ <> Date: Thu, 8 Jul 2004 22:34:31 +0000 Subject: [PATCH] Removed MAX_ORDERS, units can have as many orders as they require. Added Memory management for Orders, so they are reused, less mallocs. Remove MustRedraw and EnableRedraw, they are not used, everything is redrawn each frame. Remove TrainingQueue LIMIT, you can train as many units as you like if the training queue is enable. This needs further configuration work. But operates correctly. --- src/action/action_move.cpp | 2 - src/action/action_train.cpp | 24 ++---- src/action/actions.cpp | 4 +- src/action/command.cpp | 147 +++++++++++++++++++++--------------- src/ai/ai.cpp | 1 - src/editor/editloop.cpp | 8 +- src/include/editor.h | 10 ++- src/include/stratagus.h | 16 +--- src/include/unit.h | 22 +++--- src/map/map.cpp | 2 - src/map/map_rock.cpp | 3 - src/map/map_wall.cpp | 4 - src/map/map_wood.cpp | 3 - src/pathfinder/astar.cpp | 4 + src/stratagus/mainloop.cpp | 3 +- src/stratagus/stratagus.cpp | 11 +-- src/ui/botpanel.cpp | 6 +- src/ui/interface.cpp | 4 - src/ui/mainscr.cpp | 22 +++--- src/ui/menus.cpp | 9 +-- src/ui/mouse.cpp | 18 ++--- src/unit/script_unit.cpp | 35 ++------- src/unit/unit.cpp | 54 +++++++++---- src/unit/unit_draw.cpp | 2 +- src/unit/upgrade.cpp | 16 ++-- 25 files changed, 211 insertions(+), 219 deletions(-) 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; } }