From 664929c8f9243ea5619e57645003bc9e762d1492 Mon Sep 17 00:00:00 2001 From: jsalmon3 <> Date: Mon, 5 Jul 2004 17:27:46 +0000 Subject: [PATCH] Undo last commit --- src/action/action_follow.cpp | 1 + src/action/action_move.cpp | 10 +- src/action/action_resource.cpp | 4 + src/action/action_unload.cpp | 2 + src/action/command.cpp | 21 ++ src/editor/editloop.cpp | 1 + src/include/map.h | 44 ++- src/include/unit.h | 4 +- src/map/map_fog.cpp | 4 - src/stratagus/selection.cpp | 13 +- src/stratagus/spells.cpp | 24 +- src/unit/unit.cpp | 504 ++++++++++++--------------------- src/unit/unit_cache.cpp | 6 +- 13 files changed, 265 insertions(+), 373 deletions(-) diff --git a/src/action/action_follow.cpp b/src/action/action_follow.cpp index 64cadbee7..8311c63a2 100644 --- a/src/action/action_follow.cpp +++ b/src/action/action_follow.cpp @@ -136,6 +136,7 @@ void HandleActionFollow(Unit* unit) // Teleport the unit RemoveUnit(unit, NULL); + UnitCacheRemove(unit); unit->X = goal->Goal->X; unit->Y = goal->Goal->Y; DropOutOnSide(unit, unit->Direction, 1, 1); diff --git a/src/action/action_move.cpp b/src/action/action_move.cpp index 30c88a6f2..b66f50b17 100644 --- a/src/action/action_move.cpp +++ b/src/action/action_move.cpp @@ -74,12 +74,14 @@ */ static int ActionMoveGeneric(Unit* unit, const Animation* anim) { - int xd; // X movement in tile. - int yd; // Y movement in tile. + int xd; + int yd; int state; int d; - int x; // Unit->X - int y; // Unit->Y + int i; + int x; + int y; + Unit* uninside; // FIXME: state 0?, should be wrong, should be Reset. // FIXME: Reset flag is cleared by HandleUnitAction. diff --git a/src/action/action_resource.cpp b/src/action/action_resource.cpp index 58dce1bb5..843c3eb08 100644 --- a/src/action/action_resource.cpp +++ b/src/action/action_resource.cpp @@ -229,6 +229,8 @@ static int StartGathering(Unit* unit) unit->Orders[0].Goal = NoUnitP; RemoveUnit(unit, goal); + unit->X = goal->X; + unit->Y = goal->Y; } unit->Data.ResWorker.TimeToHarvest = resinfo->WaitAtResource / @@ -596,6 +598,8 @@ static int MoveToDepot(Unit* unit) // Place unit inside the depot // RemoveUnit(unit, goal); + unit->X = goal->X; + unit->Y = goal->Y; // // Update resource. diff --git a/src/action/action_unload.cpp b/src/action/action_unload.cpp index 0940a07dd..369ce2f52 100644 --- a/src/action/action_unload.cpp +++ b/src/action/action_unload.cpp @@ -153,6 +153,8 @@ int UnloadUnit(Unit* unit) if (!FindUnloadPosition(unit->X, unit->Y, &x, &y, UnitMovementMask(unit))) { return 0; } + unit->X = x; + unit->Y = y; unit->Wait = 1; // should be correct unit has still action unit->Boarded = 0; PlaceUnit(unit, x, y); diff --git a/src/action/command.cpp b/src/action/command.cpp index 900a6e950..3f18e5d3b 100644 --- a/src/action/command.cpp +++ b/src/action/command.cpp @@ -587,6 +587,27 @@ void CommandUnload(Unit* unit, int x, int y, Unit* what, int flush) // Check if unit is still valid? (NETWORK!) // if (!unit->Removed && unit->Orders[0].Action != UnitActionDie) { + // + // For bunkers, don't go into an action. Just drop everything here and now. + // + if (unit->Type->Building) { + int i; + Unit* uins; + + // Unload all units. + uins = unit->UnitInside; + for (i = unit->InsideCount; i; --i, uins = uins->NextContained) { + if (uins->Boarded) { + uins->X = unit->X; + uins->Y = unit->Y; + if (UnloadUnit(uins)) { + unit->BoardCount--; + } + } + } + return; + } + if (!(order = GetNextOrder(unit, flush))) { return; } diff --git a/src/editor/editloop.cpp b/src/editor/editloop.cpp index a51451439..35e9e727a 100644 --- a/src/editor/editloop.cpp +++ b/src/editor/editloop.cpp @@ -1372,6 +1372,7 @@ static void EditorCallbackKeyDown(unsigned key, unsigned keychar) Unit* unit; RemoveUnit(unit = UnitUnderCursor, NULL); + UnitCacheRemove(unit); UnitLost(unit); UnitClearOrders(unit); ReleaseUnit(unit); diff --git a/src/include/map.h b/src/include/map.h index 82511985a..6a4998da1 100644 --- a/src/include/map.h +++ b/src/include/map.h @@ -345,22 +345,19 @@ extern int AnyMapAreaVisibleInViewport(const Viewport*, int , int , int , int); // // in map_fog.c // -/// Function to (un)mark the vision table. -typedef void MapMarkerFunc(const Player*, int x, int y); - /// Filter map flags through fog extern int MapFogFilterFlags(Player* player, int x, int y, int mask); /// Mark a tile for normal sight -extern MapMarkerFunc MapMarkTileSight; +extern void MapMarkTileSight(const Player* player, int x, int y); /// Unmark a tile for normal sight -extern MapMarkerFunc MapUnmarkTileSight; +extern void MapUnmarkTileSight(const Player* player, int x, int y); /// Mark a tile for cloak detection -extern MapMarkerFunc MapMarkTileDetectCloak; +extern void MapMarkTileDetectCloak(const Player* player,int x,int y); /// Unmark a tile for cloak detection -extern MapMarkerFunc MapUnmarkTileDetectCloak; +extern void MapUnmarkTileDetectCloak(const Player* player,int x,int y); /// Mark sight changes -extern void MapSight(const Player* player, int x, int y, int w, int h, int range, MapMarkerFunc *marker); +extern void MapSight(const Player* player, int x, int y, int w, int h, int range, void (*marker)(const Player*, int, int)); /// Find if a tile is visible (With shared vision) extern unsigned char IsTileVisible(const Player* player, int x, int y); /// Mark tiles with fog of war to be redrawn @@ -486,13 +483,6 @@ extern void PreprocessMap(void); /// Set wall on field extern void MapSetWall(unsigned x, unsigned y, int humanwall); -// in unit.c - -/// Mark on vision table the Sight of the unit. -void MapMarkUnitSight(Unit* unit); -/// Unmark on vision table the Sight of the unit. -void MapUnmarkUnitSight(Unit* unit); - /*---------------------------------------------------------------------------- -- Defines ----------------------------------------------------------------------------*/ @@ -504,6 +494,30 @@ void MapUnmarkUnitSight(Unit* unit); #define MapMarkSight(player,x,y,w,h,range) MapSight((player),(x),(y),(w),(h),(range),MapMarkTileSight) #define MapUnmarkSight(player,x,y,w,h,range) MapSight((player),(x),(y),(w),(h),(range),MapUnmarkTileSight) +#define MapMarkUnitSight(unit) \ +{ \ + MapSight((unit)->Player, (unit)->X,(unit)->Y, (unit)->Type->TileWidth,\ + (unit)->Type->TileHeight, (unit)->CurrentSightRange, MapMarkTileSight); \ + if (unit->Type->DetectCloak) { \ + MapSight((unit)->Player, (unit)->X,(unit)->Y, (unit)->Type->TileWidth,\ + (unit)->Type->TileHeight, (unit)->CurrentSightRange, MapMarkTileDetectCloak); \ + }\ +} + +#define MapUnmarkUnitSight(unit) \ +{ \ + MapSight((unit)->Player,(unit)->X,(unit)->Y, (unit)->Type->TileWidth,\ + (unit)->Type->TileHeight,(unit)->CurrentSightRange,MapUnmarkTileSight); \ + if (unit->Type->DetectCloak) { \ + MapSight((unit)->Player, (unit)->X,(unit)->Y, (unit)->Type->TileWidth,\ + (unit)->Type->TileHeight, (unit)->CurrentSightRange, MapUnmarkTileDetectCloak); \ + }\ +} + +#define MapMarkUnitOnBoardSight(unit,host) MapSight((unit)->Player,(host)->X,(host)->Y, \ + (host)->Type->TileWidth,(host)->Type->TileHeight,(unit)->CurrentSightRange,MapMarkTileSight) +#define MapUnmarkUnitOnBoardSight(unit,host) MapSight((unit)->Player,(host)->X,(host)->Y, \ + (host)->Type->TileWidth,(host)->Type->TileHeight,(unit)->CurrentSightRange,MapUnmarkTileSight) /// Check if a field for the user is explored #define IsMapFieldExplored(player,x,y) \ (IsTileVisible((player),(x),(y))) diff --git a/src/include/unit.h b/src/include/unit.h index a7596e4f5..9a9fcf3c6 100644 --- a/src/include/unit.h +++ b/src/include/unit.h @@ -763,10 +763,10 @@ extern Unit* MakeUnit(UnitType* type,Player* player); extern void PlaceUnit(Unit* unit, int x, int y); /// Create a new unit and place on map extern Unit* MakeUnitAndPlace(int x, int y, UnitType* type,Player* player); - /// Move unit to tile(x, y). (Do special stuff : vision, cachelist, pathfinding) -extern void MoveUnitToXY(Unit* unit, int x, int y); /// Add an unit inside a container. Only deal with list stuff. extern void AddUnitInContainer(Unit* unit, Unit* host); + /// Remove an unit from inside a container. Only deals with list stuff. +extern void RemoveUnitFromContainer(Unit* unit); /// Remove unit from map/groups/... extern void RemoveUnit(Unit* unit, Unit* host); /// Handle the loose of an unit (food,...) diff --git a/src/map/map_fog.cpp b/src/map/map_fog.cpp index a94be0d03..f61599dd6 100644 --- a/src/map/map_fog.cpp +++ b/src/map/map_fog.cpp @@ -212,8 +212,6 @@ void MapMarkTileSight(const Player* player, int x, int y) { unsigned char v; - Assert(0 <= x && x < TheMap.Width); - Assert(0 <= y && y < TheMap.Height); v = TheMap.Fields[x + y * TheMap.Width].Visible[player->Player]; switch (v) { case 0: // Unexplored @@ -249,8 +247,6 @@ void MapUnmarkTileSight(const Player* player, int x, int y) { unsigned char v; - Assert(0 <= x && x < TheMap.Width); - Assert(0 <= y && y < TheMap.Height); v = TheMap.Fields[x + y * TheMap.Width].Visible[player->Player]; switch (v) { case 255: diff --git a/src/stratagus/selection.cpp b/src/stratagus/selection.cpp index 005cd3416..5bebae67b 100644 --- a/src/stratagus/selection.cpp +++ b/src/stratagus/selection.cpp @@ -127,11 +127,8 @@ void ChangeSelectedUnits(Unit** units,int count) if (count == 1 && units[0]->Type->ClicksToExplode && !units[0]->Type->Decoration) { HandleSuicideClick(units[0]); - if (units[0]->Orders[0].Action == UnitActionDie) { - NetworkSendSelection(units, count); - return ; - } } + UnSelectAll(); NetworkSendSelection(units, count); for (n = i = 0; i < count; ++i) { @@ -346,16 +343,16 @@ int SelectUnitsByType(Unit* base) r = UnitCacheSelect(vp->MapX - 1, vp->MapY - 1, vp->MapX + vp->MapWidth + 1, vp->MapY + vp->MapHeight + 1, table); - if (base->Type->ClicksToExplode) { - HandleSuicideClick(base); - } - // if unit is a cadaver or hidden (not on map) // no unit can be selected. if (base->Removed || base->Orders[0].Action == UnitActionDie) { return 0; } + if (base->Type->ClicksToExplode) { + HandleSuicideClick(base); + } + if (base->Type->Decoration && GameRunning) { return 0; } diff --git a/src/stratagus/spells.cpp b/src/stratagus/spells.cpp index d606e859a..4b145735a 100644 --- a/src/stratagus/spells.cpp +++ b/src/stratagus/spells.cpp @@ -206,7 +206,10 @@ int CastSpawnPortal(Unit* caster, const SpellType* spell __attribute__((unused)) DebugPrint("Spawning a portal exit.\n"); portal = caster->Goal; if (portal) { - MoveUnitToXY(portal, x, y); + // FIXME: if cop is already defined --> move it, but it doesn't work? + RemoveUnit(portal, NULL); + UnitCacheRemove(portal); + PlaceUnit(portal, x, y); } else { portal = MakeUnitAndPlace(x, y, ptype, &Players[PlayerNumNeutral]); } @@ -565,6 +568,7 @@ int CastPolymorph(Unit* caster, const SpellType* spell, // as said somewhere else -- no corpses :) RemoveUnit(target, NULL); + UnitCacheRemove(target); for (i = 0; i < type->TileWidth; ++i) { for (j = 0; j < type->TileHeight; ++j) { if (!UnitTypeCanMoveTo(x + i, y + j, type)) { @@ -639,17 +643,27 @@ int CastSummon(Unit* caster, const SpellType* spell, // FIXME: do summoned units count on food? // target = MakeUnit(unittype, caster->Player); - // This is a hack to walk around behaviour of DropOutOnSide - target->X = x + 1; + target->X = x; target->Y = y; - DropOutOnSide(target, LookingW, 0, 0); // FIXME : 0,0) : good parameter ? // // set life span. ttl=0 results in a permanent unit. // if (ttl) { target->TTL = GameCycle + ttl; } - + // + // Revealers are always removed, since they don't have graphics + // + if (target->Type->Revealer) { + DebugPrint("summoned unit is a revealer, removed.\n"); + target->Removed = 1; + target->CurrentSightRange = target->Stats->SightRange; + MapMarkUnitSight(target); + } else { + // This is a hack to walk around behaviour of DropOutOnSide + target->X++; + DropOutOnSide(target, LookingW, 0, 0); + } caster->Mana -= spell->ManaCost; return 1; } diff --git a/src/unit/unit.cpp b/src/unit/unit.cpp index 09fcc7ee4..92564a713 100644 --- a/src/unit/unit.cpp +++ b/src/unit/unit.cpp @@ -431,303 +431,6 @@ Unit* MakeUnit(UnitType* type, Player* player) return unit; } -/** -** (Un)Mark on vision table the Sight of the unit -** (and units inside for transporter (recursively)) -** -** @param unit Unit to (un)mark. -** @param x X coord of first container of unit. -** @param y Y coord of first container of unit. -** @param width Width of the first container of unit. -** @param height Height of the first container of unit. -** @param f Function to (un)mark for normal vision. -** @param f2 Function to (un)mark for cloaking vision. -*/ -static void MapMarkUnitSightRec(Unit* unit, int x, int y, int width, int height, - MapMarkerFunc* f, MapMarkerFunc* f2) -{ - Unit* unit_inside; // iterator on units inside unit. - int i; // number of units inside to process. - - Assert(unit); - Assert(f); - MapSight(unit->Player, x, y, width, height, unit->CurrentSightRange, f); - - if (unit->Type && unit->Type->DetectCloak && f2) { - MapSight(unit->Player, x, y, width, height, unit->CurrentSightRange, f2); - } - - unit_inside = unit->UnitInside; - for (i = unit->InsideCount; i--; unit_inside = unit_inside->NextContained) { - MapMarkUnitSightRec(unit_inside, x, y, width, height, f, f2); - } -} - -/** -** Return the unit not transported, by viewing the container recursively. -** -** @param unit unit from where look the first conatiner. -** -** @return Container of container of ... of unit. It is not null. -*/ -static Unit* GetFirstContainer(const Unit* unit) -{ - Assert(unit); - while (unit->Container) { - unit = unit->Container; - } - return (Unit *) unit; -} - -/** -** Mark on vision table the Sight of the unit -** (and units inside for transporter) -** -** @param unit unit to unmark its vision. -** @see MapUnmarkUnitSight. -*/ -void MapMarkUnitSight(Unit* unit) -{ - Unit* container; // First container of the unit. - - Assert(unit); - - container = GetFirstContainer(unit); - Assert(container->Type); - MapMarkUnitSightRec(unit, - container->X, container->Y, container->Type->TileWidth, container->Type->TileHeight, - MapMarkTileSight, MapMarkTileDetectCloak); -} - -/** -** Unmark on vision table the Sight of the unit -** (and units inside for transporter) -** -** @param unit unit to unmark its vision. -** @see MapMarkUnitSight. -*/ -void MapUnmarkUnitSight(Unit* unit) -{ - Unit* container; // First container of the unit. - - Assert(unit); - Assert(unit->Type); - - container = GetFirstContainer(unit); - Assert(container->Type); - MapMarkUnitSightRec(unit, - container->X, container->Y, container->Type->TileWidth, container->Type->TileHeight, - MapUnmarkTileSight, MapUnmarkTileDetectCloak); -} - -/** -** Update the Unit Current sight range to good value and transported units inside. -** -** @param unit unit to update SightRange -** -** @internal before use it, MapUnmarkUnitSight(unit) -** and after MapMarkUnitSight(unit) -** are often necessary. -** -** FIXME @todo manage differently unit inside with option. -** (no vision, min, host value, own value, bonus value, ...) -*/ -static void UpdateUnitSightRange(Unit* unit) -{ - Unit* unit_inside; // iterator on units inside unit. - int i; // number of units inside to process. - -#if 0 // which is the better ? caller check ? - if (SaveGameLoading) { - return ; - } -#else - Assert(!SaveGameLoading); -#endif - // FIXME : these values must be configurable. - if (unit->Constructed) { // Units under construction have no sight range. - unit->CurrentSightRange = 0; - } else if (!unit->Container) { // proper value. - unit->CurrentSightRange = unit->Stats->SightRange; - } else { // value of it container. - unit->CurrentSightRange = unit->Container->CurrentSightRange; - } - - unit_inside = unit->UnitInside; - for (i = unit->InsideCount; i--; unit_inside = unit_inside->NextContained) { - UpdateUnitSightRange(unit_inside); - } -} - -/** -** Mark the field with the FieldFlags. -** -** @param unit unit to mark. -*/ -static void MarkUnitFieldFlags(const Unit* unit) -{ - UnitType* type; // Type of the unit. - unsigned flags; // - int h; // Tile height of the unit. - int w; // Tile width of the unit. - int x; // X tile of the unit. - int y; // Y tile of the unit. - - Assert(unit); - type = unit->Type; - x = unit->X; - y = unit->Y; - flags = type->FieldFlags; - for (h = type->TileHeight; h--;) { - for (w = type->TileWidth; w--;) { - TheMap.Fields[x + w + (y + h) * TheMap.Width].Flags |= flags; - } - } -#ifdef MAP_REGIONS - // Update map splitting. - if (type->Building && (flags & - (MapFieldLandUnit | MapFieldSeaUnit | MapFieldBuilding | - MapFieldUnpassable | MapFieldWall | MapFieldRocks | MapFieldForest))) { - MapSplitterTilesOccuped(x, y, x + type->TileWidth - 1, y + type->TileHeight - 1); - } -#endif - -} - -/** -** Mark the field with the FieldFlags. -** -** @param unit unit to mark. -*/ -static void UnmarkUnitFieldFlags(const Unit* unit) -{ - UnitType* type; // Type of the unit. - unsigned flags; // - int h; // Tile height of the unit. - int w; // Tile width of the unit. - int x; // X tile of the unit. - int y; // Y tile of the unit. - - Assert(unit); - type = unit->Type; - x = unit->X; - y = unit->Y; - flags = type->FieldFlags; - for (h = type->TileHeight; h--;) { - for (w = type->TileWidth; w--;) { - TheMap.Fields[x + w + (y + h) * TheMap.Width].Flags &= ~flags; - } - } -#ifdef MAP_REGIONS - // Update map splitting. - if (type->Building && (flags & - (MapFieldLandUnit | MapFieldSeaUnit | MapFieldBuilding | - MapFieldUnpassable | MapFieldWall | MapFieldRocks | MapFieldForest))){ - MapSplitterTilesCleared(x, y, x + type->TileWidth - 1, y + type->TileHeight - 1); - } -#endif -} - -/** -** Add unit to a container. It only updates linked list stuff -** -** @param unit Pointer to unit. -** @param host Pointer to container. -*/ -void AddUnitInContainer(Unit* unit, Unit* host) -{ - Assert(host && unit->Container == 0); - unit->Container = host; - if (host->InsideCount == 0) { - unit->NextContained = unit->PrevContained = unit; - } else { - unit->NextContained = host->UnitInside; - unit->PrevContained = host->UnitInside->PrevContained; - host->UnitInside->PrevContained->NextContained = unit; - host->UnitInside->PrevContained = unit; - } - host->UnitInside = unit; - host->InsideCount++; -} - -/** -** Remove unit from a container. It only updates linked list stuff -** -** @param unit Pointer to unit. -*/ -static void RemoveUnitFromContainer(Unit* unit) -{ - Unit* host; // transporter which contain unit. - - host = unit->Container; - Assert(unit->Container); - Assert(unit->Container->InsideCount > 0); - host->InsideCount--; - unit->NextContained->PrevContained = unit->PrevContained; - unit->PrevContained->NextContained = unit->NextContained; - if (host->InsideCount == 0) { - host->UnitInside = NoUnitP; - } else { - if (host->UnitInside == unit) { - host->UnitInside = unit->NextContained; - } - } - unit->Container = NoUnitP; -} - - -/** -** Affect Tile coord of an unit (with units inside) to tile (x, y). -** -** @param unit unit to move. -** @param x X map tile position. -** @param y Y map tile position. -** -** @internal before use it, UnitCacheRemove(unit), MapUnmarkUnitSight(unit) -** and after UnitCacheInsert(unit), MapMarkUnitSight(unit) -** are often necessary. Check Flag also for Pathfinder. -*/ -static void UnitInXY(Unit* unit, int x, int y) -{ - Unit* unit_inside; // iterator on units inside unit. - int i; // number of units inside to process. - - Assert(unit); - unit->X = x; - unit->Y = y; - - unit_inside = unit->UnitInside; - for (i = unit->InsideCount; i--; unit_inside = unit_inside->NextContained) { - UnitInXY(unit_inside, x, y); - } -} - -/** -** Move an unit (with units inside) to tile (x, y). -** (Do stuff with vision, cachelist and pathfinding). -** -** @param unit unit to move. -** @param x X map tile position. -** @param y Y map tile position. -** -*/ -void MoveUnitToXY(Unit* unit, int x, int y) -{ - MapUnmarkUnitSight(unit); - UnitCacheRemove(unit); - UnmarkUnitFieldFlags(unit); - - // Move the unit. - UnitInXY(unit, x, y); - - UnitCacheInsert(unit); - MarkUnitFieldFlags(unit); - MapMarkUnitSight(unit); -} - - - - /** ** Place unit on map. ** @@ -737,23 +440,63 @@ void MoveUnitToXY(Unit* unit, int x, int y) */ void PlaceUnit(Unit* unit, int x, int y) { + const UnitType* type; + int h; + int w; + unsigned flags; + Assert(unit->Removed); - if (unit->Container) { - RemoveUnitFromContainer(unit); + type = unit->Type; + + + unit->X = x; + unit->Y = y; + + // + // Place unit on the map, mark the field with the FieldFlags. + // + flags = type->FieldFlags; + for (h = type->TileHeight; h--;) { + for (w = type->TileWidth; w--;) { + TheMap.Fields[x + w + (y + h) * TheMap.Width].Flags |= flags; + } } - unit->Next = 0; - if (!SaveGameLoading) { - UpdateUnitSightRange(unit); + +#ifdef MAP_REGIONS + if (type->Building && + (type->FieldFlags & + (MapFieldLandUnit | MapFieldSeaUnit | MapFieldBuilding | + MapFieldUnpassable | MapFieldWall | MapFieldRocks | MapFieldForest))){ + MapSplitterTilesOccuped(x, y, x + type->TileWidth - 1, y + type->TileHeight - 1); } +#endif + + x += unit->Type->TileWidth / 2; + y += unit->Type->TileHeight / 2; + + // + // Units under construction have no sight range. + // + if (!unit->Constructed) { + // + // Update fog of war, if unit belongs to player on this computer + // + if (unit->Container && unit->Removed) { + MapUnmarkUnitOnBoardSight(unit, unit->Container); + } + if (unit->Container) { + RemoveUnitFromContainer(unit); + } + if (!SaveGameLoading) { + unit->CurrentSightRange = unit->Stats->SightRange; + } + MapMarkUnitSight(unit); + } + unit->Removed = 0; - UnitInXY(unit, x, y); - // Pathfinding info. - MarkUnitFieldFlags(unit); - // Tha cache list. + unit->Next = 0; UnitCacheInsert(unit); - // Vision - MapMarkUnitSight(unit); MustRedraw |= RedrawMinimap; UnitCountSeen(unit); @@ -779,6 +522,61 @@ Unit* MakeUnitAndPlace(int x, int y, UnitType* type, Player* player) return unit; } +/** +** Add unit to a container. It only updates linked list stuff +** +** @param unit Pointer to unit. +** @param host Pointer to container. +*/ +void AddUnitInContainer(Unit* unit, Unit* host) +{ + if (unit->Container) { + DebugPrint("Unit is already contained.\n"); + exit(0); + } + unit->Container = host; + if (host->InsideCount == 0) { + unit->NextContained = unit->PrevContained = unit; + } else { + unit->NextContained = host->UnitInside; + unit->PrevContained = host->UnitInside->PrevContained; + host->UnitInside->PrevContained->NextContained = unit; + host->UnitInside->PrevContained = unit; + } + host->UnitInside = unit; + host->InsideCount++; +} + +/** +** Remove unit from a container. It only updates linked list stuff +** +** @param unit Pointer to unit. +*/ +void RemoveUnitFromContainer(Unit* unit) +{ + Unit* host; + host = unit->Container; + if (!unit->Container) { + DebugPrint("Unit not contained.\n"); + exit(0); + } + if (host->InsideCount == 0) { + DebugPrint("host's inside count reached -1."); + exit(0); + } + host->InsideCount--; + unit->NextContained->PrevContained = unit->PrevContained; + unit->PrevContained->NextContained = unit->NextContained; + if (host->InsideCount == 0) { + host->UnitInside = NoUnitP; + } else { + if (host->UnitInside == unit) { + host->UnitInside = unit->NextContained; + } + } + unit->Container = NoUnitP; +} + /** ** Remove unit from map. ** @@ -791,24 +589,27 @@ Unit* MakeUnitAndPlace(int x, int y, UnitType* type, Player* player) */ void RemoveUnit(Unit* unit, Unit* host) { + int h; + int w; + const UnitType* type; + unsigned flags; + + if (unit->Removed && unit->Container) { + MapUnmarkUnitOnBoardSight(unit, unit->Container); + } else { + MapUnmarkUnitSight(unit); + } + if (host) { + unit->CurrentSightRange = host->CurrentSightRange; + MapMarkUnitOnBoardSight(unit, host); + AddUnitInContainer(unit, host); + } + if (unit->Removed) { // could happen! // If unit is removed (inside) and building is destroyed. - DebugPrint("unit '%s' already remove" _C_ unit->Type->Ident); return; } - UnitCacheRemove(unit); - MapUnmarkUnitSight(unit); - UnmarkUnitFieldFlags(unit); - if (host) { - AddUnitInContainer(unit, host); - UpdateUnitSightRange(unit); - UnitInXY(unit, host->X, host->Y); - MapMarkUnitSight(unit); - unit->Next = host; // What is it role ? - } - unit->Removed = 1; - // Remove unit from the current selection if (unit->Selected) { if (NumSelected == 1) { // Remove building cursor @@ -826,6 +627,37 @@ void RemoveUnit(Unit* unit, Unit* host) if (unit == UnitUnderCursor) { UnitUnderCursor = NULL; } + + type = unit->Type; + + // + // Update map + // + flags = ~type->FieldFlags; + for (h = type->TileHeight; h--;) { + for (w = type->TileWidth; w--;) { + TheMap.Fields[unit->X + w + (unit->Y + h) * TheMap.Width].Flags &= flags; + } + } + +#ifdef MAP_REGIONS + // + // Update map splitting. + // + if (type->Building && + (type->FieldFlags & + (MapFieldLandUnit | MapFieldSeaUnit | MapFieldBuilding | + MapFieldUnpassable | MapFieldWall | MapFieldRocks | MapFieldForest))){ + MapSplitterTilesCleared(unit->X, unit->Y, + unit->X + type->TileWidth - 1, unit->Y + type->TileHeight - 1); + } +#endif + + if (host) { + UnitCacheRemove(unit); + unit->Next = host; + } + MustRedraw |= RedrawMinimap; } @@ -1525,9 +1357,15 @@ void ChangeUnitOwner(Unit* unit, Player* newplayer) } *unit->PlayerSlot = unit; - MapUnmarkUnitSight(unit); - unit->Player = newplayer; - MapMarkUnitSight(unit); + if (unit->Removed && unit->Container) { + MapUnmarkUnitOnBoardSight(unit, unit->Next); + unit->Player = newplayer; + MapMarkUnitOnBoardSight(unit, unit->Next); + } else { + MapUnmarkUnitSight(unit); + unit->Player = newplayer; + MapMarkUnitSight(unit); + } unit->Stats = &unit->Type->Stats[newplayer->Player]; // @@ -2696,6 +2534,7 @@ void LetUnitDie(Unit* unit) // removed units, just remove. if (unit->Removed) { DebugPrint("Killing a removed unit?\n"); + RemoveUnit(unit, NULL); UnitLost(unit); UnitClearOrders(unit); ReleaseUnit(unit); @@ -2741,8 +2580,8 @@ void LetUnitDie(Unit* unit) // Restore value for oil-patch unit->Value = unit->Data.Builded.Worker->Value; } - DestroyAllInside(unit); + RemoveUnit(unit, NULL); UnitLost(unit); UnitClearOrders(unit); @@ -2753,6 +2592,7 @@ void LetUnitDie(Unit* unit) unit->State = unit->Type->CorpseScript; Assert(type->TileWidth == type->CorpseType->TileWidth && type->TileHeight == type->CorpseType->TileHeight); + MapMarkUnitSight(unit); type = unit->Type = type->CorpseType; #ifdef DYNAMIC_LOAD @@ -2764,7 +2604,7 @@ void LetUnitDie(Unit* unit) unit->IY = (type->Height - VideoGraphicHeight(type->Sprite)) / 2; unit->SubAction = 0; - unit->Removed = 0; + //unit->Removed = 0; unit->Frame = 0; unit->Orders[0].Action = UnitActionDie; @@ -2772,11 +2612,13 @@ void LetUnitDie(Unit* unit) unit->Type->Animations->Die); UnitShowAnimation(unit, unit->Type->Animations->Die); DebugPrint("Frame %d\n" _C_ unit->Frame); + MapUnmarkUnitSight(unit); unit->CurrentSightRange = type->Stats[unit->Player->Player].SightRange; MapMarkUnitSight(unit); - UnitCacheInsert(unit); } else { // no corpse available + MapMarkUnitSight(unit); + MapUnmarkUnitSight(unit); unit->CurrentSightRange = 0; } return; @@ -2787,6 +2629,7 @@ void LetUnitDie(Unit* unit) // FIXME: destroy or unload : do a flag. DestroyAllInside(unit); } + RemoveUnit(unit, NULL); UnitLost(unit); UnitClearOrders(unit); @@ -2797,18 +2640,18 @@ void LetUnitDie(Unit* unit) // Not good: UnitUpdateHeading(unit); unit->SubAction = 0; + //unit->Removed = 0; unit->State = 0; unit->Reset = 0; unit->Wait = 1; unit->Orders[0].Action = UnitActionDie; + if (unit->Type->CorpseType) { unit->CurrentSightRange = unit->Type->CorpseType->Stats[unit->Player->Player].SightRange; - MapMarkUnitSight(unit); } else { unit->CurrentSightRange = 0; } - unit->Removed = 0; - UnitCacheInsert(unit); + MapMarkUnitSight(unit);; } /** @@ -2826,6 +2669,7 @@ void DestroyAllInside(Unit* source) if (unit->UnitInside) { DestroyAllInside(unit); } + RemoveUnit(unit, NULL); UnitLost(unit); UnitClearOrders(unit); ReleaseUnit(unit); diff --git a/src/unit/unit_cache.cpp b/src/unit/unit_cache.cpp index 4f6720abd..74dea90f1 100644 --- a/src/unit/unit_cache.cpp +++ b/src/unit/unit_cache.cpp @@ -58,8 +58,6 @@ void UnitCacheInsert(Unit* unit) MapField* mf; UnitListItem* listitem; - Assert(!unit->Removed); - for (i = 0; i < unit->Type->TileHeight; ++i) { for (j = 0; j < unit->Type->TileWidth; ++j) { mf = TheMap.Fields + (i + unit->Y) * TheMap.Width + j + unit->X; @@ -176,9 +174,8 @@ int UnitCacheSelect(int x1, int y1, int x2, int y2, Unit** table) // It should only be used in here, unless you somehow want the unit // to be out of cache. // - if (!listitem->Unit->CacheLock && !listitem->Unit->Type->Revealer) { + if (!listitem->Unit->CacheLock) { listitem->Unit->CacheLock = 1; - Assert(!listitem->Unit->Removed); table[n++] = listitem->Unit; } } @@ -217,7 +214,6 @@ int UnitCacheOnTile(int x, int y, Unit** table) listitem = TheMap.Fields[y * TheMap.Width + x].UnitCache; for (; listitem; listitem = listitem->Next) { if (!listitem->Unit->CacheLock) { - Assert(!listitem->Unit->Removed); table[n++] = listitem->Unit; } }