From abf2ae3f80ae874aff477f84f0cb33916fe2c288 Mon Sep 17 00:00:00 2001 From: darkvater Date: Sun, 30 Jan 2005 15:57:38 +0000 Subject: (svn r1731) - Fix: [ 1106930 ] BugFix: placing signals with 2x1 drags workaround is completely rewritten. Also features checks for hacked/modified clients. Thanks a lot Hackykid! --- command.c | 25 +++---- command.h | 13 ++-- rail_cmd.c | 216 +++++++++++++++++++++++++++++-------------------------------- rail_gui.c | 99 ++++------------------------ 4 files changed, 137 insertions(+), 216 deletions(-) diff --git a/command.c b/command.c index cb25ad574..eab5c6f90 100644 --- a/command.c +++ b/command.c @@ -22,8 +22,8 @@ DEF_COMMAND(CmdBuildRailroadStation); DEF_COMMAND(CmdRemoveFromRailroadStation); DEF_COMMAND(CmdConvertRail); -DEF_COMMAND(CmdBuildSignals); -DEF_COMMAND(CmdRemoveSignals); +DEF_COMMAND(CmdBuildSingleSignal); +DEF_COMMAND(CmdRemoveSingleSignal); DEF_COMMAND(CmdTerraformLand); @@ -163,7 +163,8 @@ DEF_COMMAND(CmdRefitRailVehicle); DEF_COMMAND(CmdStartScenario); -DEF_COMMAND(CmdBuildManySignals); +DEF_COMMAND(CmdBuildSignalTrack); +DEF_COMMAND(CmdRemoveSignalTrack); DEF_COMMAND(CmdReplaceVehicle); @@ -177,8 +178,8 @@ static CommandProc * const _command_proc_table[] = { CmdBuildBridge, /* 5 */ CmdBuildRailroadStation, /* 6 */ CmdBuildTrainDepot, /* 7 */ - CmdBuildSignals, /* 8 */ - CmdRemoveSignals, /* 9 */ + CmdBuildSingleSignal, /* 8 */ + CmdRemoveSingleSignal, /* 9 */ CmdTerraformLand, /* 10 */ CmdPurchaseLandArea, /* 11 */ CmdSellLandArea, /* 12 */ @@ -302,12 +303,14 @@ static CommandProc * const _command_proc_table[] = { CmdRestoreOrderIndex, /* 107 */ CmdBuildLock, /* 108 */ CmdStartScenario, /* 109 */ - CmdBuildManySignals, /* 110 */ - //CmdDestroyIndustry, /* 109 */ - CmdDestroyCompanyHQ, /* 111 */ - CmdGiveMoney, /* 112 */ - CmdChangePatchSetting, /* 113 */ - CmdReplaceVehicle, /* 114 */ + CmdBuildSignalTrack, /* 110 */ + CmdRemoveSignalTrack, /* 111 */ + CmdDestroyCompanyHQ, /* 112 */ + CmdGiveMoney, /* 113 */ + CmdChangePatchSetting, /* 114 */ + CmdReplaceVehicle, /* 115 */ + + //CmdDestroyIndustry, /* 109 */ }; /* This function range-checks a cmd, and checks if the cmd is not NULL */ diff --git a/command.h b/command.h index 10dee17a2..dc682db09 100644 --- a/command.h +++ b/command.h @@ -141,14 +141,15 @@ enum { CMD_BUILD_LOCK = 108, CMD_START_SCENARIO = 109, - CMD_BUILD_MANY_SIGNALS = 110, + CMD_BUILD_SIGNAL_TRACK = 110, + CMD_REMOVE_SIGNAL_TRACK = 111, - //CMD_DESTROY_INDUSTRY = 109, - CMD_DESTROY_COMPANY_HQ = 111, - CMD_GIVE_MONEY = 112, - CMD_CHANGE_PATCH_SETTING = 113, + CMD_DESTROY_COMPANY_HQ = 112, + CMD_GIVE_MONEY = 113, + CMD_CHANGE_PATCH_SETTING = 114, - CMD_REPLACE_VEHICLE = 114, + CMD_REPLACE_VEHICLE = 115, + //CMD_DESTROY_INDUSTRY = 109, }; enum { diff --git a/rail_cmd.c b/rail_cmd.c index f6f8944f0..c6068e49b 100644 --- a/rail_cmd.c +++ b/rail_cmd.c @@ -512,64 +512,99 @@ skip_mark_dirty:; static const struct { int8 xinc[16]; int8 yinc[16]; - byte initial[16]; } _railbit = {{ -// 0 1 2 3 4 5 - 16, 0,-16, 0, 16, 0, 0, 0, - -16, 0, 0, 16, 0,-16, 0, 0, +// 0 1 2 3 4 5 + -16, 0,-16, 0, 16, 0, 0, 0, + 16, 0, 0, 16, 0,-16, 0, 0, },{ - 0, 16, 0, 16, 0, 16, 0, 0, - 0, -16, -16, 0,-16, 0, 0, 0, -},{ - 5, 1, 0, 4, // normal - 2, 1, 8|0, 3, // x > sx - 8|2, 8|1, 0, 8|3, // y > sy - 8|5, 8|1, 8|0, 8|4, // x > sx && y > sy + 0, 16, 0, 16, 0, 16, 0, 0, + 0,-16,-16, 0,-16, 0, 0, 0, }}; +static int32 ValidateAutoDrag(int *railbit, int x, int y, int ex, int ey) +{ + int dx, dy, trdx, trdy; -/* Build either NE or NW sequence of tracks. - * p1 0:15 - end pt X - * p1 16:31 - end pt y - * - * p2 0:3 - rail type - * p2 4:7 - rail direction - */ + if (*railbit > 5) return CMD_ERROR; // only 6 possible track-combinations + // calculate delta x,y from start to end tile + dx = ex - x; + dy = ey - y; -int32 CmdBuildRailroadTrack(int x, int y, uint32 flags, uint32 p1, uint32 p2) + // calculate delta x,y for the first direction + trdx = _railbit.xinc[*railbit]; + trdy = _railbit.yinc[*railbit]; + + if (*railbit & 0x6) { + trdx += _railbit.xinc[*railbit ^ 1]; + trdy += _railbit.yinc[*railbit ^ 1]; + } + + // validate the direction + while (((trdx <= 0) && (dx > 0)) || ((trdx >= 0) && (dx < 0)) || + ((trdy <= 0) && (dy > 0)) || ((trdy >= 0) && (dy < 0))) { + if (*railbit < 8) { // first direction is invalid, try the other + SETBIT(*railbit, 3); + trdx = -trdx; + trdy = -trdy; + } else // other direction is invalid too, invalid drag + return CMD_ERROR; + } + + // (for diagonal tracks, this is already made sure of by above test), but: + // for non-diagonal tracks, check if the start and end tile are on 1 line + if (*railbit & 0x6) { + trdx = _railbit.xinc[*railbit]; + trdy = _railbit.yinc[*railbit]; + if ((abs(dx) != abs(dy)) && (abs(dx) + abs(trdy) != abs(dy) + abs(trdx))) + return CMD_ERROR; + } + + return 0; +} + +/* Build a stretch of railroad tracks. + * x,y= start tile + * p1 = end tile + * p2 = (bit 0-3) - railroad type normal/maglev + * p2 = (bit 4-6) - track-orientation, valid values: 0-5 + * p2 = (bit 7) - 0 = build, 1 = remove tracks + */ +static int32 CmdRailTrackHelper(int x, int y, uint32 flags, uint32 p1, uint32 p2) { - int sx, sy; + int ex, ey; int32 ret, total_cost = 0; - int railbit; + int railbit = (p2 >> 4) & 7; + byte mode = HASBIT(p2, 7); + + /* unpack end point */ + ex = TileX(p1) * 16; + ey = TileY(p1) * 16; SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); if (flags & DC_EXEC) SndPlayTileFx(SND_20_SPLAT_2, TILE_FROM_XY(x,y)); - /* unpack end point */ - sx = (p1 & 0xFFFF) & ~0xF; - sy = (p1 >> 16) & ~0xF; - - railbit = _railbit.initial[(p2 >> 4) + (x > sx ? 4 : 0) + (y > sy ? 8 : 0)]; + if (ValidateAutoDrag(&railbit, x, y, ex, ey) == CMD_ERROR) + return CMD_ERROR; for(;;) { - ret = DoCommand(x, y, p2&0xF, railbit&7, flags, CMD_BUILD_SINGLE_RAIL); + ret = DoCommand(x, y, p2&0x3, railbit&7, flags, (mode == 0) ? CMD_BUILD_SINGLE_RAIL : CMD_REMOVE_SINGLE_RAIL); if (ret == CMD_ERROR) { - if (_error_message != STR_1007_ALREADY_BUILT) + if ((_error_message != STR_1007_ALREADY_BUILT) && (mode == 0)) break; } else total_cost += ret; - if (x == sx && y == sy) + if (x == ex && y == ey) break; x += _railbit.xinc[railbit]; y += _railbit.yinc[railbit]; - // toggle railbit for the diagonal tiles + // toggle railbit for the non-diagonal tracks if (railbit & 0x6) railbit ^= 1; } @@ -579,48 +614,14 @@ int32 CmdBuildRailroadTrack(int x, int y, uint32 flags, uint32 p1, uint32 p2) return total_cost; } - -/* Remove either NE or NW sequence of tracks. - * p1 0:15 - start pt X - * p1 16:31 - start pt y - * - * p2 0:3 - rail type - * p2 4:7 - rail direction - */ - +int32 CmdBuildRailroadTrack(int x, int y, uint32 flags, uint32 p1, uint32 p2) +{ + return CmdRailTrackHelper(x, y, flags, p1, p2); +} int32 CmdRemoveRailroadTrack(int x, int y, uint32 flags, uint32 p1, uint32 p2) { - int sx, sy; - int32 ret, total_cost = 0; - int railbit; - - SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); - - if (flags & DC_EXEC) - SndPlayTileFx(SND_20_SPLAT_2, TILE_FROM_XY(x,y)); - - /* unpack start point */ - sx = (p1 & 0xFFFF) & ~0xF; - sy = (p1 >> 16) & ~0xF; - - railbit = _railbit.initial[(p2 >> 4) + (x > sx ? 4 : 0) + (y > sy ? 8 : 0)]; - - for(;;) { - ret = DoCommand(x, y, p2&0xF, railbit&7, flags, CMD_REMOVE_SINGLE_RAIL); - if (ret != CMD_ERROR) total_cost += ret; - if (x == sx && y == sy) - break; - x += _railbit.xinc[railbit]; - y += _railbit.yinc[railbit]; - // toggle railbit for the diagonal tiles - if (railbit & 0x6) railbit ^= 1; - } - - if (total_cost == 0) - return CMD_ERROR; - - return total_cost; + return CmdRailTrackHelper(x, y, flags, p1, SETBIT(p2, 7)); } /* Build a train depot @@ -870,7 +871,7 @@ int32 CmdRenameWaypoint(int x, int y, uint32 flags, uint32 p1, uint32 p2) * 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 CmdBuildSingleSignal(int x, int y, uint32 flags, uint32 p1, uint32 p2) { TileIndex tile = TILE_FROM_XY(x, y); bool semaphore; @@ -992,68 +993,45 @@ int32 CmdBuildSignals(int x, int y, uint32 flags, uint32 p1, uint32 p2) } /* Build many signals by dragging: AutoSignals - x,y= start tile - p1 = end tile - p2 = (byte 0) - 0 = build, 1 = remove signals - p2 = (byte 3) - 0 = signals, 1 = semaphores - p2 = (byte 7-4) - track-orientation - p2 = (byte 8-) - track style - p2 = (byte 24-31) - user defined signals_density + * x,y = start tile + * p1 = end tile + * p2 = (bit 0) - 0 = build, 1 = remove signals + * p2 = (bit 3) - 0 = signals, 1 = semaphores + * p2 = (bit 4-6) - track-orientation, valid values: 0-5 + * p2 = (bit 24-31) - user defined signals_density */ -int32 CmdBuildManySignals(int x, int y, uint32 flags, uint32 p1, uint32 p2) +static int32 CmdSignalTrackHelper(int x, int y, uint32 flags, uint32 p1, uint32 p2) { - int ex, ey, railbit; + int ex, ey; + int railbit = (p2 >> 4) & 7; bool error = true; TileIndex tile = TILE_FROM_XY(x, y); int32 ret, total_cost, signal_ctr; byte m5, semaphores = (HASBIT(p2, 3)) ? 8 : 0; - int mode = (p2 >> 4)&0xF; + int mode = p2 & 0x1; // for vertical/horizontal tracks, double the given signals density // since the original amount will be too dense (shorter tracks) - byte signal_density = (mode == 1 || mode == 2) ? (p2 >> 24) : (p2 >> 24) * 2; - byte signals = (p2 >> 8)&0xFF; - mode = p2 & 0x1; // build/remove signals + byte signal_density = (railbit & 0x6) ? (p2 >> 24) * 2: (p2 >> 24); + byte signals; SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); - /* unpack end tile */ + // unpack end tile ex = TileX(p1) * 16; ey = TileY(p1) * 16; - railbit = _railbit.initial[((p2 >> 4)&0xF) + (x > ex ? 4 : 0) + (y > ey ? 8 : 0)]; + if (ValidateAutoDrag(&railbit, x, y, ex, ey) == CMD_ERROR) + return CMD_ERROR; // copy the signal-style of the first rail-piece if existing m5 = _map5[tile]; if (!(m5 & RAIL_TYPE_SPECIAL) && (m5 & RAIL_BIT_MASK) && (m5 & RAIL_TYPE_SIGNALS)) { - if (m5 & 0x3) // X,Y direction tracks - signals = _map3_lo[tile]&0xC0; - else { - /* W-E or N-S direction, only copy the side which was chosen, leave - * the other side alone */ - switch (signals) { - case 0x20: case 8: /* east corner (N-S), south corner (W-E) */ - if (_map3_lo[tile]&0x30) - signals = _map3_lo[tile]&0x30; - else - signals = 0x30 | (_map3_lo[tile]&0xC0); - break; - case 0x10: case 4: /* west corner (N-S), north corner (W-E) */ - if (_map3_lo[tile]&0xC0) - signals = _map3_lo[tile]&0xC0; - else - signals = 0xC0 | (_map3_lo[tile]&0x30); - break; - } - } + signals = _map3_lo[tile] & _signals_table_both[railbit]; + if (signals == 0) signals = _signals_table_both[railbit]; semaphores = (_map3_hi[tile] & ~3) ? 8 : 0; // copy signal/semaphores style (independent of CTRL) } else { // no signals exist, drag a two-way signal stretch - switch (signals) { - case 0x20: case 8: /* east corner (N-S), south corner (W-E) */ - signals = 0x30; break; - case 0x10: case 4: /* west corner (N-S), north corner (W-E) */ - signals = 0xC0; - } + signals = _signals_table_both[railbit]; } /* signal_density_ctr - amount of tiles already processed @@ -1089,19 +1067,25 @@ int32 CmdBuildManySignals(int x, int y, uint32 flags, uint32 p1, uint32 p2) y += _railbit.yinc[railbit]; signal_ctr++; - // toggle railbit for the diagonal tiles (|, -- tracks) + // toggle railbit for the non-diagonal tracks (|, -- tracks) if (railbit & 0x6) railbit ^= 1; } return (error) ? CMD_ERROR : total_cost; } +/* Stub for the unified Signal builder/remover */ +int32 CmdBuildSignalTrack(int x, int y, uint32 flags, uint32 p1, uint32 p2) +{ + return CmdSignalTrackHelper(x, y, flags, p1, p2); +} + /* Remove signals * p1 bits 0..2 = track * p2 = unused */ -int32 CmdRemoveSignals(int x, int y, uint32 flags, uint32 p1, uint32 p2) +int32 CmdRemoveSingleSignal(int x, int y, uint32 flags, uint32 p1, uint32 p2) { TileInfo ti; uint tile; @@ -1159,6 +1143,12 @@ int32 CmdRemoveSignals(int x, int y, uint32 flags, uint32 p1, uint32 p2) return _price.remove_signals; } +/* Stub for the unified Signal builder/remover */ +int32 CmdRemoveSignalTrack(int x, int y, uint32 flags, uint32 p1, uint32 p2) +{ + return CmdSignalTrackHelper(x, y, flags, p1, SETBIT(p2, 1)); +} + typedef int32 DoConvertRailProc(uint tile, uint totype, bool exec); static int32 DoConvertRail(uint tile, uint totype, bool exec) diff --git a/rail_gui.c b/rail_gui.c index 050c83d7e..a49ded5ca 100644 --- a/rail_gui.c +++ b/rail_gui.c @@ -309,117 +309,45 @@ static void BuildRailClick_Landscaping(Window *w) ShowTerraformToolbar(); } - static void DoRailroadTrack(int mode) { - DoCommandP(TILE_FROM_XY(_thd.selstart.x, _thd.selstart.y), PACK_POINT(_thd.selend.x, _thd.selend.y), (mode << 4) | _cur_railtype, NULL, + DoCommandP(TILE_FROM_XY(_thd.selstart.x, _thd.selstart.y), TILE_FROM_XY(_thd.selend.x, _thd.selend.y), _cur_railtype | (mode << 4), NULL, _remove_button_clicked ? CMD_REMOVE_RAILROAD_TRACK | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1012_CAN_T_REMOVE_RAILROAD_TRACK) : - CMD_BUILD_RAILROAD_TRACK | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1011_CAN_T_BUILD_RAILROAD_TRACK) + CMD_BUILD_RAILROAD_TRACK | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1011_CAN_T_BUILD_RAILROAD_TRACK) ); } - -// This function is more or less a hack because DoRailroadTrack() would otherwise screw up -static void SwapSelection(void) -{ - TileHighlightData *thd = &_thd; - Point pt = thd->selstart; - thd->selstart.x = thd->selend.x & ~0xF; - thd->selstart.y = thd->selend.y & ~0xF; - thd->selend = pt; -} - - static void HandleAutodirPlacement(void) { TileHighlightData *thd = &_thd; - int bit; - int dx = thd->selstart.x - (thd->selend.x&~0xF); - int dy = thd->selstart.y - (thd->selend.y&~0xF); + int trackstat = thd->drawstyle & 0xF; // 0..5 if (thd->drawstyle & HT_RAIL) { // one tile case - bit = thd->drawstyle & 0xF; - GenericPlaceRail(TILE_FROM_XY(thd->selend.x, thd->selend.y), bit); - } else if ( !(thd->drawstyle & 0xE) ) { // x/y dir - if (dx == 0) { // Y dir - DoRailroadTrack(1); - } else { - DoRailroadTrack(2); - } - } else if (myabs(dx)+myabs(dy) >= 32) { // long line (more than 2 tiles) - if(thd->drawstyle == (HT_LINE | HT_DIR_HU)) - DoRailroadTrack(0); - if(thd->drawstyle == (HT_LINE | HT_DIR_HL)) - DoRailroadTrack(3); - if(thd->drawstyle == (HT_LINE | HT_DIR_VL)) - DoRailroadTrack(3); - if(thd->drawstyle == (HT_LINE | HT_DIR_VR)) - DoRailroadTrack(0); - } else { // 2x1 pieces line - if(thd->drawstyle == (HT_LINE | HT_DIR_HU)) { - DoRailroadTrack(0); - } else if (thd->drawstyle == (HT_LINE | HT_DIR_HL)) { - SwapSelection(); - DoRailroadTrack(0); - SwapSelection(); - } else if (thd->drawstyle == (HT_LINE | HT_DIR_VL)) { - if(dx == 0) { - SwapSelection(); - DoRailroadTrack(0); - SwapSelection(); - } else { - DoRailroadTrack(3); - } - } else if (thd->drawstyle == (HT_LINE | HT_DIR_VR)) { - if(dx == 0) { - DoRailroadTrack(0); - } else { - SwapSelection(); - DoRailroadTrack(3); - SwapSelection(); - } - } + GenericPlaceRail(TILE_FROM_XY(thd->selend.x, thd->selend.y), trackstat); + return; } + + DoRailroadTrack(trackstat); } static void HandleAutoSignalPlacement(void) { TileHighlightData *thd = &_thd; - int mode = 0; - uint trackstat = 0; - - int dx = thd->selstart.x - (thd->selend.x&~0xF); - int dy = thd->selstart.y - (thd->selend.y&~0xF); + byte trackstat = thd->drawstyle & 0xF; // 0..5 if (thd->drawstyle == HT_RECT) { // one tile case GenericPlaceSignals(TILE_FROM_XY(thd->selend.x, thd->selend.y)); return; } - if (!(thd->drawstyle & 0xE)) { // X/Y direction - mode = (dx == 0) ? VPM_FIX_X : VPM_FIX_Y; - trackstat = 0xC0; - } else if (myabs(dx) + myabs(dy) >= 32) { // long line (more than 2 tiles) - mode = ((thd->drawstyle & 0xF) == HT_DIR_HU || (thd->drawstyle & 0xF) == HT_DIR_VR) ? 0 : 3; - - if (dx == dy || abs(dx - dy) == 16) // North<->South track | - trackstat = (thd->drawstyle & 1) ? 0x20 : 0x10; - else if (dx == -dy || abs(dx + dy) == 16) // East<->West track -- - trackstat = (thd->drawstyle & 1) ? 8 : 4; - - } else { // 2x1 pieces line - GenericPlaceSignals(TILE_FROM_XY(thd->selstart.x, thd->selstart.y)); - return; - } - // _patches.drag_signals_density is given as a parameter such that each user in a network // game can specify his/her own signal density DoCommandP(TILE_FROM_XY(thd->selstart.x, thd->selstart.y), TILE_FROM_XY(thd->selend.x, thd->selend.y), - (mode << 4) | (_remove_button_clicked | _ctrl_pressed) | (trackstat << 8) | (_patches.drag_signals_density << 24), + (_ctrl_pressed ? 1 << 3 : 0) | (trackstat << 4) | (_patches.drag_signals_density << 24), CcPlaySound1E, - (_remove_button_clicked ? CMD_BUILD_MANY_SIGNALS | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1013_CAN_T_REMOVE_SIGNALS_FROM) : - CMD_BUILD_MANY_SIGNALS | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1010_CAN_T_BUILD_SIGNALS_HERE) ) ); + (_remove_button_clicked ? CMD_REMOVE_SIGNAL_TRACK | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1013_CAN_T_REMOVE_SIGNALS_FROM) : + CMD_BUILD_SIGNAL_TRACK | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1010_CAN_T_BUILD_SIGNALS_HERE) ) ); } static OnButtonClick * const _build_railroad_button_proc[] = { @@ -527,9 +455,8 @@ static void BuildRailToolbWndProc(Window *w, WindowEvent *e) DoCommandP(end_tile, start_tile, _cur_railtype, CcPlaySound10, CMD_LEVEL_LAND | CMD_AUTO); } else if (e->place.userdata == VPM_X_AND_Y_LIMITED) { HandleStationPlacement(start_tile, end_tile); - } else { - DoRailroadTrack(e->place.userdata); - } + } else + DoRailroadTrack(e->place.userdata & 1); } break; -- cgit v1.2.3-70-g09d2