1
0
Fork 0

(svn r1585) Rewrite CmdBuildSignals()

This addresses several issues:
- Correct comments
- Check input parameters for validity (and don't assert() them)
- Reorder checks if action is possible to produce more meaningful error messages
- Correct bug where money was charged for an action which should be free
- Kill warning about uninitialized variable, because the variable exists no more
- Make more clear how the function works (at least i hope so)
release/0.4.5
tron 2005-01-22 14:52:20 +00:00
parent 4ce10986b5
commit 5d443a2482
1 changed files with 87 additions and 58 deletions

View File

@ -862,96 +862,125 @@ int32 CmdRenameWaypoint(int x, int y, uint32 flags, uint32 p1, uint32 p2)
} }
/* build signals, alternate between double/single, signal/semaphore, pre/exit/combo -signals /* build signals, alternate between double/single, signal/semaphore,
p1 = (lower 3 bytes) - track-orientation * pre/exit/combo-signals
p1 = (byte 4) - semaphores/signals * p1 bits 0-2 - track-orientation, valid values: 0-5
p2 = used for CmdBuildManySignals() to copy style first signal * p1 bit 3 - choose semaphores/signals or cycle normal/pre/exit/combo
* depending on context
* p2 = used for CmdBuildManySignals() to copy style of first signal
*/ */
int32 CmdBuildSignals(int x, int y, uint32 flags, uint32 p1, uint32 p2) int32 CmdBuildSignals(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{ {
uint tile; TileIndex tile = TILE_FROM_XY(x, y);
bool semaphore;
bool pre_signal;
uint track = p1 & 0x7;
byte m5; byte m5;
int32 cost; int32 cost;
int track = p1 & 0x7;
byte a,b,c,d;
assert(track >= 0 && track < 6); // only 6 possible track-combinations if (!(track < 6) || // only 6 possible track-combinations
!IsTileType(tile, MP_RAILWAY) ||
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); !EnsureNoVehicle(tile))
tile = TILE_FROM_XY(x,y);
if (!EnsureNoVehicle(tile))
return CMD_ERROR; return CMD_ERROR;
// must be railway, and not a depot, and it must have a track in the suggested position. // Protect against invalid signal copying
if (!IsTileType(tile, MP_RAILWAY) || (m5 = _map5[tile], m5 & 0x80) || !HASBIT(m5, track)) if (p2 != 0 && (p2 & _signals_table_both[track]) == 0)
return CMD_ERROR; return CMD_ERROR;
m5 = _map5[tile];
if (m5 & 0x80 || // mustn't be a depot
!HASBIT(m5, track)) // track must exist
return CMD_ERROR;
if (!CheckTileOwnership(tile)) return CMD_ERROR;
_error_message = STR_1005_NO_SUITABLE_RAILROAD_TRACK; _error_message = STR_1005_NO_SUITABLE_RAILROAD_TRACK;
// check rail combination
{ {
byte m = m5 & RAIL_BIT_MASK; byte m = m5 & RAIL_BIT_MASK;
if (m != RAIL_BIT_DIAG1 && m != RAIL_BIT_DIAG2 && m != RAIL_BIT_UPPER && m != RAIL_BIT_LOWER && if (m != RAIL_BIT_DIAG1 &&
m != RAIL_BIT_LEFT && m != RAIL_BIT_RIGHT && m != (RAIL_BIT_UPPER|RAIL_BIT_LOWER) && m != (RAIL_BIT_LEFT|RAIL_BIT_RIGHT)) m != RAIL_BIT_DIAG2 &&
m != RAIL_BIT_UPPER &&
m != RAIL_BIT_LOWER &&
m != RAIL_BIT_LEFT &&
m != RAIL_BIT_RIGHT &&
m != (RAIL_BIT_UPPER | RAIL_BIT_LOWER) &&
m != (RAIL_BIT_LEFT | RAIL_BIT_RIGHT))
return CMD_ERROR; return CMD_ERROR;
} }
// check ownership SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
if (!CheckTileOwnership(tile))
return CMD_ERROR;
// calculate masks for.. // Same bit, used in different contexts
a = _signals_table[track]; // .. signal for this track in one direction semaphore = pre_signal = HASBIT(p1, 3);
b = _signals_table[track + 8]; // .. signal for this track in the other direction
c = a | b; // .. 2-way signal for this track
// If it had signals previously it is free to change orientation/pre-exit-combo signals if ((_map3_lo[tile] & _signals_table_both[track]) == 0) {
cost = 0; // build new signals
if (!(m5 & RAIL_TYPE_SIGNALS)) {
cost = _price.build_signals; cost = _price.build_signals;
} else { } else {
d = _map3_lo[tile] & c; // mask of built signals. it only affects &0xF0 if (p2 != 0 &&
if (d == 0) cost += _price.build_signals; // no signals built yet ((semaphore && !HASBIT(_map3_hi[tile], 2)) ||
// if converting signals<->semaphores, charge the player for it (!semaphore && HASBIT(_map3_hi[tile], 2)))) {
if (p2 && ((HASBIT(p1, 3) && !HASBIT(_map3_hi[tile], 2)) || (!HASBIT(p1, 3) && HASBIT(_map3_hi[tile], 2)) ) ) // convert signals <-> semaphores
cost += _price.build_signals + _price.remove_signals; cost = _price.build_signals + _price.remove_signals;
} else {
// it is free to change orientation/pre-exit-combo signals
cost = 0;
}
} }
if (flags & DC_EXEC) { if (flags & DC_EXEC) {
if (!(m5 & RAIL_TYPE_SIGNALS)) {
// there are no signals at all on this tile yet
if (!(m5 & RAIL_TYPE_SIGNALS)) { // if there are no signals yet present on the track
_map5[tile] |= RAIL_TYPE_SIGNALS; // change into signals _map5[tile] |= RAIL_TYPE_SIGNALS; // change into signals
_map2[tile] |= 0xF0; // all signals are on _map2[tile] |= 0xF0; // all signals are on
_map3_lo[tile] &= ~0xF0; // no signals built by default _map3_lo[tile] &= ~0xF0; // no signals built by default
_map3_hi[tile] = (p1 & 8) ? 4 : 0;// initial presignal state, semaphores depend on ctrl key _map3_hi[tile] = semaphore ? 4 : 0;
d = 0; // no existing signals
if (!p2)
goto ignore_presig;
} }
if (!p2) { // not called from CmdBuildManySignals if (p2 == 0) {
if (!HASBIT(p1, 3)) { // not CTRL pressed if ((_map3_lo[tile] & _signals_table_both[track]) == 0) {
ignore_presig: // build new signals
// Alternate between a|b, b, a _map3_lo[tile] |= _signals_table_both[track];
if ( d != 0 && d != a) } else {
c = (d == c)?b:a; if (pre_signal) {
// cycle between normal -> pre -> exit -> combo -> ...
byte type = (_map3_hi[tile] + 1) & 0x03;
_map3_hi[tile] &= ~0x03;
_map3_hi[tile] |= type;
} else {
// cycle between two-way -> one-way -> one-way -> ...
switch (track) {
case 3:
case 5: {
byte signal = (_map3_lo[tile] - 0x10) & 0x30;
if (signal == 0) signal = 0x30;
_map3_lo[tile] &= ~0x30;
_map3_lo[tile] |= signal;
break;
}
_map3_lo[tile] = (_map3_lo[tile]&~(a|b)) | c; default: {
} else // CTRL pressed byte signal = (_map3_lo[tile] - 0x40) & 0xC0;
_map3_hi[tile] = (_map3_hi[tile] & ~3) | ((_map3_hi[tile] + 1) & 3); if (signal == 0) signal = 0xC0;
} else { _map3_lo[tile] &= ~0xC0;
/* If CmdBuildManySignals is called with copying signals, just copy the style of the first signal _map3_lo[tile] |= signal;
* given as parameter by CmdBuildManySignals */ break;
switch (track) { }
case 2: case 4: _map3_lo[tile] = (p2&0xC0) | (_map3_lo[tile]&~0xC0); break; }
case 3: case 5: _map3_lo[tile] = (p2&0x30) | (_map3_lo[tile]&~0x30); break; }
default : _map3_lo[tile] = (p2&0xF0) | (_map3_lo[tile]&0xF);
} }
} else {
/* If CmdBuildManySignals is called with copying signals, just copy the
* style of the first signal given as parameter by CmdBuildManySignals */
_map3_lo[tile] &= ~_signals_table_both[track];
_map3_lo[tile] |= p2 & _signals_table_both[track];
// convert between signal<->semaphores when dragging // convert between signal<->semaphores when dragging
HASBIT(p1, 3) ? SETBIT(_map3_hi[tile], 2) : CLRBIT(_map3_hi[tile], 2); if (semaphore)
SETBIT(_map3_hi[tile], 2);
else
CLRBIT(_map3_hi[tile], 2);
} }
MarkTileDirtyByTile(tile); MarkTileDirtyByTile(tile);