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.
This commit is contained in:
mr-russ 2004-07-08 22:34:31 +00:00
parent 0408df5c3a
commit 087c4c85e9
25 changed files with 211 additions and 219 deletions

View file

@ -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

View file

@ -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");

View file

@ -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;

View file

@ -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.

View file

@ -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) {

View file

@ -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();

View file

@ -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.

View file

@ -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
----------------------------------------------------------------------------*/

View file

@ -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
----------------------------------------------------------------------------*/

View file

@ -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;
}
/**

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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;
}

View file

@ -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();

View file

@ -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;

View file

@ -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 &&

View file

@ -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;
}
/**

View file

@ -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);
}

View file

@ -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();
}

View file

@ -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);
}
}
//

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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;
}
}