New unit-type flag "Wall", which will treat unit as wall.
This will use the unit's Direction field to show different wall connections. The unit should be a building and have NumDirections = 16 and Flip = false. The wall unit didn't count in GetNumOpponents. When it attacked, AI didn't fight back and no warnings are shown. NOTE: need to modify triggers, so they won't count the wall units when calculating player's remaining units. Not needed for those games which don't use this feature. Wall mapping: Frame 0 - wall without connections. Frame 1 - wall with north connection. Frame 2 - wall with west connection. Frame 3 - wall with north and west connections. Frame 4 - wall with south connection. Frame 5 - wall with south and north connections. Frame 6 - wall with south and west connections. Frame 7 - wall with south, north and west connections. Frame 8 - wall with east connection. Frame 9 - wall with east and north connections. Frame 10 - wall with east and west connections. Frame 11 - wall with east, north and west connections. Frame 12 - wall with east and south connections. Frame 13 - wall with east, south and north connections. Frame 14 - wall with east, south and west connections. Frame 15 - wall with all connections. patch from Cybermind.
This commit is contained in:
parent
d1ad94a052
commit
55d2e864ee
7 changed files with 147 additions and 22 deletions
src
action
game
include
unit
|
@ -593,7 +593,12 @@ void HandleActionBuilt(COrder& order, CUnit &unit)
|
|||
|
||||
// Set the direction of the building if it supports them
|
||||
if (unit.Type->NumDirections > 1) {
|
||||
unit.Direction = (MyRand() >> 8) & 0xFF; // random heading
|
||||
if (unit.Type->Wall) { // Special logic for walls
|
||||
CorrectWallDirections(unit);
|
||||
CorrectWallNeighBours(unit);
|
||||
} else {
|
||||
unit.Direction = (MyRand() >> 8) & 0xFF; // random heading
|
||||
}
|
||||
UnitUpdateHeading(unit);
|
||||
}
|
||||
|
||||
|
|
|
@ -443,13 +443,19 @@ int GetNumOpponents(int player)
|
|||
|
||||
// Check the player opponents
|
||||
for (int i = 0; i < PlayerMax; ++i) {
|
||||
const int unitCount = Players[i].TotalNumUnits;
|
||||
|
||||
// This player is our enemy and has units left.
|
||||
if (((Players[player].Enemy & (1 << i)) || (Players[i].Enemy & (1 << player))) &&
|
||||
Players[i].TotalNumUnits) {
|
||||
++n;
|
||||
if ((Players[player].Enemy & (1 << i)) || (Players[i].Enemy & (1 << player))) {
|
||||
// Don't count walls
|
||||
for (int j = 0; j < unitCount; ++j) {
|
||||
if (Players[i].Units[j]->Type->Wall == false) {
|
||||
++n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
|
|
@ -1046,6 +1046,11 @@ extern int DirectionToHeading(const Vec2i &dir);
|
|||
/// Convert direction (dx,dy) to heading (0-255)
|
||||
extern int DirectionToHeading(const PixelDiff &dir);
|
||||
|
||||
///Correct directions for placed wall.
|
||||
extern void CorrectWallDirections(CUnit &unit);
|
||||
/// Correct the surrounding walls.
|
||||
extern void CorrectWallNeighBours(CUnit &unit);
|
||||
|
||||
/// Update frame from heading
|
||||
extern void UnitUpdateHeading(CUnit &unit);
|
||||
/// Heading and frame from delta direction
|
||||
|
|
|
@ -645,6 +645,7 @@ enum {
|
|||
TELEPORTER_INDEX,
|
||||
SHIELDPIERCE_INDEX,
|
||||
SAVECARGO_INDEX,
|
||||
WALL_INDEX,
|
||||
NBARALREADYDEFINED
|
||||
};
|
||||
|
||||
|
@ -1007,8 +1008,9 @@ public:
|
|||
unsigned Decoration : 1; /// Unit is a decoration (act as tile).
|
||||
unsigned Indestructible : 1; /// Unit is indestructible (take no damage).
|
||||
unsigned Teleporter : 1; /// Can teleport other units.
|
||||
unsigned ShieldPiercing : 1; /// Can directly damage shield-protected units, without shield damaging.
|
||||
unsigned SaveCargo : 1; /// Unit unloads his passengers after death.
|
||||
unsigned ShieldPiercing : 1; /// Can directly damage shield-protected units, without shield damaging.
|
||||
unsigned SaveCargo : 1; /// Unit unloads his passengers after death.
|
||||
unsigned Wall : 1; /// Use special logic for Direction field.
|
||||
|
||||
CVariable *Variable; /// Array of user defined variables.
|
||||
struct BoolFlags {
|
||||
|
|
|
@ -106,6 +106,7 @@ static const char INDESTRUCTIBLE_KEY[] = "Indestructible";
|
|||
static const char TELEPORTER_KEY[] = "Teleporter";
|
||||
static const char SHIELDPIERCE_KEY[] = "ShieldPiercing";
|
||||
static const char SAVECARGO_KEY[] = "LoseCargo";
|
||||
static const char WALL_KEY[] = "Wall";
|
||||
// names of the variable.
|
||||
static const char HITPOINTS_KEY[] = "HitPoints";
|
||||
static const char BUILD_KEY[] = "Build";
|
||||
|
@ -153,7 +154,7 @@ CUnitTypeVar::CBoolKeys::CBoolKeys() {
|
|||
SHOREBUILDING_KEY, CANATTACK_KEY,BUILDEROUTSIDE_KEY,
|
||||
BUILDERLOST_KEY,CANHARVEST_KEY,HARVESTER_KEY,SELECTABLEBYRECTANGLE_KEY,
|
||||
ISNOTSELECTABLE_KEY,DECORATION_KEY,INDESTRUCTIBLE_KEY,TELEPORTER_KEY,SHIELDPIERCE_KEY,
|
||||
SAVECARGO_KEY};
|
||||
SAVECARGO_KEY, WALL_KEY};
|
||||
|
||||
for (int i = 0; i < NBARALREADYDEFINED; ++i) {
|
||||
buildin[i].offset = i;
|
||||
|
@ -1005,6 +1006,8 @@ static int CclDefineUnitType(lua_State *l)
|
|||
type->ShieldPiercing = LuaToBoolean(l, -1);
|
||||
} else if (!strcmp(value, "SaveCargo")) {
|
||||
type->SaveCargo = LuaToBoolean(l, -1);
|
||||
} else if (!strcmp(value, "Wall")) {
|
||||
type->Wall = LuaToBoolean(l, -1);
|
||||
} else if (!strcmp(value, "Sounds")) {
|
||||
if (!lua_istable(l, -1)) {
|
||||
LuaError(l, "incorrect argument");
|
||||
|
@ -2095,9 +2098,9 @@ void UpdateUnitVariables(const CUnit &unit)
|
|||
type->BoolFlag[DECORATION_INDEX].value = type->Decoration;
|
||||
type->BoolFlag[INDESTRUCTIBLE_INDEX].value = type->Indestructible;
|
||||
type->BoolFlag[TELEPORTER_INDEX].value = type->Teleporter;
|
||||
type->BoolFlag[SHIELDPIERCE_INDEX].value = type->ShieldPiercing;
|
||||
type->BoolFlag[SAVECARGO_INDEX].value = type->SaveCargo;
|
||||
|
||||
type->BoolFlag[SHIELDPIERCE_INDEX].value = type->ShieldPiercing;
|
||||
type->BoolFlag[SAVECARGO_INDEX].value = type->SaveCargo;
|
||||
type->BoolFlag[WALL_INDEX].value = type->Wall;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -428,7 +428,7 @@ void CUnit::AssignToPlayer(CPlayer *player)
|
|||
// don't count again
|
||||
if (type->Building) {
|
||||
// FIXME: support more races
|
||||
if (type != UnitTypeOrcWall && type != UnitTypeHumanWall) {
|
||||
if (!type->Wall && type != UnitTypeOrcWall && type != UnitTypeHumanWall) {
|
||||
player->TotalBuildings++;
|
||||
}
|
||||
} else {
|
||||
|
@ -445,7 +445,7 @@ void CUnit::AssignToPlayer(CPlayer *player)
|
|||
// Don't Add the building if it's dieing, used to load a save game
|
||||
if (type->Building && CurrentAction() != UnitActionDie) {
|
||||
// FIXME: support more races
|
||||
if (type != UnitTypeOrcWall && type != UnitTypeHumanWall) {
|
||||
if (!type->Wall && type != UnitTypeOrcWall && type != UnitTypeHumanWall) {
|
||||
player->NumBuildings++;
|
||||
}
|
||||
}
|
||||
|
@ -860,6 +860,12 @@ void CUnit::Place(const Vec2i &pos)
|
|||
UnitCountSeen(*this);
|
||||
// Vision
|
||||
MapMarkUnitSight(*this);
|
||||
// Correct directions for wall units
|
||||
if (this->Type->Wall && this->CurrentAction() != UnitActionBuilt){
|
||||
CorrectWallDirections(*this);
|
||||
UnitUpdateHeading(*this);
|
||||
CorrectWallNeighBours(*this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -912,6 +918,11 @@ void CUnit::Remove(CUnit *host)
|
|||
|
||||
Removed = 1;
|
||||
|
||||
// Correct surrounding walls directions
|
||||
if (this->Type->Wall){
|
||||
CorrectWallNeighBours(*this);
|
||||
}
|
||||
|
||||
// Remove unit from the current selection
|
||||
if (Selected) {
|
||||
if (NumSelected == 1) { // Remove building cursor
|
||||
|
@ -974,7 +985,7 @@ void UnitLost(CUnit &unit)
|
|||
|
||||
if (unit.Type->Building) {
|
||||
// FIXME: support more races
|
||||
if (type != UnitTypeOrcWall && type != UnitTypeHumanWall) {
|
||||
if (!type->Wall && type != UnitTypeOrcWall && type != UnitTypeHumanWall) {
|
||||
player->NumBuildings--;
|
||||
}
|
||||
}
|
||||
|
@ -1152,6 +1163,97 @@ static void UnitFillSeenValues(CUnit &unit)
|
|||
unit.CurrentOrder()->FillSeenValues(unit);
|
||||
}
|
||||
|
||||
class SamePlayerAndTypeAs
|
||||
{
|
||||
public:
|
||||
explicit SamePlayerAndTypeAs(const CUnit &unit) :
|
||||
player(unit.Player), type(unit.Type)
|
||||
{}
|
||||
|
||||
bool operator() (const CUnit *unit) const
|
||||
{
|
||||
return (unit->Player == player && unit->Type == type);
|
||||
}
|
||||
|
||||
private:
|
||||
const CPlayer *player;
|
||||
const CUnitType *type;
|
||||
};
|
||||
|
||||
// Wall unit positions
|
||||
enum {
|
||||
W_NORTH = 0x10,
|
||||
W_WEST = 0x20,
|
||||
W_SOUTH = 0x40,
|
||||
W_EAST = 0x80
|
||||
};
|
||||
|
||||
/**
|
||||
** Correct direction for placed wall.
|
||||
**
|
||||
** @param unit The wall unit.
|
||||
*/
|
||||
void CorrectWallDirections(CUnit &unit)
|
||||
{
|
||||
Assert(unit.Type->Wall);
|
||||
Assert(unit.Type->NumDirections == 16);
|
||||
Assert(!unit.Type->Flip);
|
||||
|
||||
if (!Map.Info.IsPointOnMap(unit.tilePos)) {
|
||||
return ;
|
||||
}
|
||||
const struct {
|
||||
Vec2i offset;
|
||||
const int dirFlag;
|
||||
} configs[] = {{{0, -1}, W_NORTH}, {{1, 0}, W_EAST},
|
||||
{{0, 1}, W_SOUTH}, {{-1, 0}, W_WEST}};
|
||||
int flags = 0;
|
||||
|
||||
for (int i = 0; i != sizeof (configs) / sizeof (*configs); ++i) {
|
||||
const Vec2i pos = unit.tilePos + configs[i].offset;
|
||||
const int dirFlag = configs[i].dirFlag;
|
||||
|
||||
if (Map.Info.IsPointOnMap(pos) == false) {
|
||||
flags |= dirFlag;
|
||||
} else {
|
||||
const CUnitCache &unitCache = Map.Field(pos)->UnitCache;
|
||||
const CUnit *neighboor = unitCache.find(SamePlayerAndTypeAs(unit));
|
||||
|
||||
if (neighboor != NULL) {
|
||||
flags |= dirFlag;
|
||||
}
|
||||
}
|
||||
}
|
||||
unit.Direction = flags;
|
||||
}
|
||||
|
||||
/**
|
||||
** Correct the surrounding walls.
|
||||
**
|
||||
** @param unit The wall unit.
|
||||
*/
|
||||
void CorrectWallNeighBours(CUnit &unit)
|
||||
{
|
||||
Assert(unit.Type->Wall);
|
||||
|
||||
const Vec2i offset[] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
|
||||
|
||||
for (unsigned int i = 0; i < sizeof (offset) / sizeof (*offset); ++i) {
|
||||
const Vec2i pos = unit.tilePos + offset[i];
|
||||
|
||||
if (Map.Info.IsPointOnMap(pos) == false) {
|
||||
continue;
|
||||
}
|
||||
CUnitCache &unitCache = Map.Field(pos)->UnitCache;
|
||||
CUnit *neighboor = unitCache.find(SamePlayerAndTypeAs(unit));
|
||||
|
||||
if (neighboor != NULL) {
|
||||
CorrectWallDirections(*neighboor);
|
||||
UnitUpdateHeading(*neighboor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** This function should get called when a unit goes under fog of war.
|
||||
**
|
||||
|
@ -1554,9 +1656,10 @@ void CUnit::ChangeOwner(CPlayer &newplayer)
|
|||
|
||||
PlayerSlot = newplayer.Units + newplayer.TotalNumUnits++;
|
||||
if (Type->Building) {
|
||||
newplayer.TotalBuildings++;
|
||||
}
|
||||
else {
|
||||
if (!Type->Wall) {
|
||||
newplayer.TotalBuildings++;
|
||||
}
|
||||
} else {
|
||||
newplayer.TotalUnits++;
|
||||
}
|
||||
*PlayerSlot = this;
|
||||
|
@ -1581,7 +1684,7 @@ void CUnit::ChangeOwner(CPlayer &newplayer)
|
|||
newplayer.MaxResources[i] += Type->_Storing[i];
|
||||
}
|
||||
}
|
||||
if (Type->Building) {
|
||||
if (Type->Building && !Type->Wall) {
|
||||
newplayer.NumBuildings++;
|
||||
}
|
||||
newplayer.UnitTypesCount[Type->Slot]++;
|
||||
|
@ -2842,7 +2945,7 @@ void HitUnit(CUnit *attacker, CUnit &target, int damage)
|
|||
if (attacker) {
|
||||
target.DamagedType = ExtraDeathIndex(attacker->Type->DamageType.c_str());
|
||||
}
|
||||
if (!lastattack || lastattack + 2 * CYCLES_PER_SECOND < GameCycle) {
|
||||
if (!target.Type->Wall && (!lastattack || lastattack + 2 * CYCLES_PER_SECOND < GameCycle)) {
|
||||
// NOTE: perhaps this should also be moved into the notify?
|
||||
if (target.Player == ThisPlayer) {
|
||||
// FIXME: Problem with load+save.
|
||||
|
@ -2875,7 +2978,7 @@ void HitUnit(CUnit *attacker, CUnit &target, int damage)
|
|||
}
|
||||
}
|
||||
|
||||
if (attacker && target.Type->Building && target.Player->AiEnabled) {
|
||||
if (attacker && !target.Type->Wall && target.Type->Building && target.Player->AiEnabled) {
|
||||
AiHelpMe(attacker, target);
|
||||
}
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ CUnitType::CUnitType() :
|
|||
ShadowWidth(0), ShadowHeight(0), ShadowOffsetX(0), ShadowOffsetY(0),
|
||||
Animations(NULL), StillFrame(0),
|
||||
DeathExplosion(NULL), CorpseType(NULL),
|
||||
Construction(NULL), RepairHP(0), TileWidth(0), TileHeight(0),
|
||||
Construction(NULL), RepairHP(0), TileWidth(0), TileHeight(0),
|
||||
BoxWidth(0), BoxHeight(0), NumDirections(0), MinAttackRange(0),
|
||||
ReactRangeComputer(0), ReactRangePerson(0), Priority(0),
|
||||
BurnPercent(0), BurnDamageRate(0), RepairRange(0),
|
||||
|
@ -129,7 +129,8 @@ CUnitType::CUnitType() :
|
|||
Vanishes(0), GroundAttack(0), ShoreBuilding(0), CanAttack(0),
|
||||
BuilderOutside(0), BuilderLost(0), CanHarvest(0), Harvester(0),
|
||||
Neutral(0), SelectableByRectangle(0), IsNotSelectable(0), Decoration(0),
|
||||
Indestructible(0), Teleporter(0), ShieldPiercing(0), SaveCargo(0), Variable(NULL),
|
||||
Indestructible(0), Teleporter(0), ShieldPiercing(0), SaveCargo(0),
|
||||
Wall(0), Variable(NULL),
|
||||
GivesResource(0), Supply(0), Demand(0), FieldFlags(0), MovementMask(0),
|
||||
Sprite(NULL), ShadowSprite(NULL)
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue