(svn r2306) - CodeChange: Check the last commands; refits. This needed an extensive rewrite and global/local-cargo ID juggling and bitmasking. However with this done it looks better as well and is compatible with newgrf handling. Big thanks to HackyKid for doing most of the work. This also closes patch "[ 1199277 ] Command checks"

This commit is contained in:
Darkvater 2005-05-14 12:36:16 +00:00
parent 3a4bedaad6
commit 5174d3adfe
17 changed files with 291 additions and 344 deletions

View File

@ -504,32 +504,38 @@ int32 CmdChangeAircraftServiceInt(int x, int y, uint32 flags, uint32 p1, uint32
return 0;
}
// p1 = vehicle
// p2 = new cargo type(0xFF)
// p2 = skip check for stopped in hanger (0x0100)
/** Refits an aircraft to the specified cargo type.
* @param x,y unused
* @param p1 vehicle ID of the aircraft to refit
* @param p2 various bitstuffed elements
* - p2 = (bit 0-7) - the new cargo type to refit to (p2 & 0xFF)
* - p2 = (bit 8) - skip check for stopped in hangar, used by autoreplace (p2 & 0x100)
* @todo p2 bit8 check <b>NEEDS TO GO</b>
*/
int32 CmdRefitAircraft(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
Vehicle *v,*u;
Vehicle *v;
int pass, mail;
int32 cost;
byte SkipStoppedInHangerCheck = (p2 & 0x100) >> 8; //excludes the cargo value
byte new_cargo_type = p2 & 0xFF; //gets the cargo number
AircraftVehicleInfo *avi;
bool SkipStoppedInHangerCheck = !!HASBIT(p2, 8); // XXX - needs to go, yes?
CargoID new_cid = p2 & 0xFF; //gets the cargo number
const AircraftVehicleInfo *avi;
if (!IsVehicleIndex(p1)) return CMD_ERROR;
v = GetVehicle(p1);
if (v->type != VEH_Aircraft) return CMD_ERROR;
if (v->type != VEH_Aircraft || !CheckOwnership(v->owner)) return CMD_ERROR;
if (!SkipStoppedInHangerCheck && !CheckStoppedInHangar(v)) return_cmd_error(STR_A01B_AIRCRAFT_MUST_BE_STOPPED);
avi = AircraftVehInfo(v->engine_type);
if (!CheckOwnership(v->owner) || (!CheckStoppedInHangar(v) && !(SkipStoppedInHangerCheck)))
return CMD_ERROR;
/* Check cargo */
if (new_cid > NUM_CARGO || !CanRefitTo(v, new_cid)) return CMD_ERROR;
SET_EXPENSES_TYPE(EXPENSES_AIRCRAFT_RUN);
switch (new_cargo_type) {
switch (new_cid) {
case CT_PASSENGERS:
pass = avi->passenger_capacity;
break;
@ -548,24 +554,22 @@ int32 CmdRefitAircraft(int x, int y, uint32 flags, uint32 p1, uint32 p2)
_aircraft_refit_capacity = pass;
cost = 0;
if (IS_HUMAN_PLAYER(v->owner) && new_cargo_type != v->cargo_type) {
if (IS_HUMAN_PLAYER(v->owner) && new_cid != v->cargo_type) {
cost = _price.aircraft_base >> 7;
}
if (flags & DC_EXEC) {
Vehicle *u;
v->cargo_cap = pass;
u = v->next;
mail = avi->mail_capacity;
if (new_cargo_type != CT_PASSENGERS) {
mail = 0;
}
mail = (new_cid != CT_PASSENGERS) ? 0 : avi->mail_capacity;
u->cargo_cap = mail;
//autorefitted planes wants to keep the cargo
//it will be checked if the cargo is valid in CmdReplaceVehicle
if (!(SkipStoppedInHangerCheck))
v->cargo_count = u->cargo_count = 0;
v->cargo_type = new_cargo_type;
v->cargo_type = new_cid;
InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
}

View File

@ -205,64 +205,11 @@ static void ShowBuildAircraftWindow(uint tile)
}
}
#define MAX_REFIT 0xFF
const byte _aircraft_refit_normal[] = {
CT_PASSENGERS,
CT_MAIL,
CT_GOODS,
CT_VALUABLES,
MAX_REFIT
};
const byte _aircraft_refit_arctic[] = {
CT_PASSENGERS,
CT_MAIL,
CT_GOODS,
CT_FOOD,
MAX_REFIT
};
const byte _aircraft_refit_desert[] = {
CT_PASSENGERS,
CT_MAIL,
CT_FRUIT,
CT_GOODS,
CT_DIAMONDS,
MAX_REFIT
};
const byte _aircraft_refit_candy[] = {
CT_PASSENGERS,
CT_SUGAR,
CT_TOYS,
CT_CANDY,
CT_COLA,
CT_COTTON_CANDY,
CT_BUBBLES,
CT_TOFFEE,
CT_BATTERIES,
CT_PLASTIC,
CT_FIZZY_DRINKS,
MAX_REFIT
};
const byte * const _aircraft_refit_types[4] = {
_aircraft_refit_normal, _aircraft_refit_arctic, _aircraft_refit_desert, _aircraft_refit_candy
};
#undef MAX_REFIT
static void AircraftRefitWndProc(Window *w, WindowEvent *e)
{
switch(e->event) {
switch (e->event) {
case WE_PAINT: {
Vehicle *v = GetVehicle(w->window_number);
const byte *b;
int sel;
int x,y;
byte color;
int cargo;
const Vehicle *v = GetVehicle(w->window_number);
SetDParam(0, v->string_id);
SetDParam(1, v->unitnumber);
@ -271,72 +218,31 @@ static void AircraftRefitWndProc(Window *w, WindowEvent *e)
DrawString(1, 15, STR_A040_SELECT_CARGO_TYPE_TO_CARRY, 0);
/* TODO: Support for custom GRFSpecial-specified refitting! --pasky */
WP(w,refit_d).cargo = DrawVehicleRefitWindow(v, WP(w, refit_d).sel);
cargo = -1;
x = 6;
y = 25;
sel = WP(w,refit_d).sel;
#define show_cargo(ctype) { \
color = 16; \
if (sel == 0) { \
cargo = ctype; \
color = 12; \
} \
sel--; \
DrawString(x, y, _cargoc.names_s[ctype], color); \
y += 10; \
}
if (_engine_refit_masks[v->engine_type]) {
uint32 mask = _engine_refit_masks[v->engine_type];
int cid = 0;
for (; mask; mask >>= 1, cid++) {
if (!(mask & 1)) // not this cid
continue;
if (!(_local_cargo_id_landscape[cid] & (1 << _opt.landscape))) // not in this landscape
continue;
show_cargo(_local_cargo_id_ctype[cid]);
}
} else { // generic refit list
b = _aircraft_refit_types[_opt.landscape];
do {
show_cargo(*b);
} while (*++b != 0xFF);
}
#undef show_cargo
WP(w,refit_d).cargo = cargo;
if (cargo != -1) {
int32 cost = DoCommandByTile(v->tile, v->index, cargo, DC_QUERY_COST, CMD_REFIT_AIRCRAFT);
if (cost != CMD_ERROR) {
if (WP(w,refit_d).cargo != CT_INVALID) {
int32 cost = DoCommandByTile(v->tile, v->index, WP(w,refit_d).cargo, DC_QUERY_COST, CMD_REFIT_AIRCRAFT);
if (!CmdFailed(cost)) {
SetDParam(2, cost);
SetDParam(0, _cargoc.names_long_p[cargo]);
SetDParam(0, _cargoc.names_long_p[WP(w,refit_d).cargo]);
SetDParam(1, _aircraft_refit_capacity);
DrawString(1, 137, STR_A041_NEW_CAPACITY_COST_OF_REFIT, 0);
}
}
break;
}
} break;
case WE_CLICK:
switch(e->click.widget) {
case 2: { /* listbox */
int y = e->click.pt.y - 25;
if (y >= 0) {
WP(w,refit_d).sel = y / 10;
SetWindowDirty(w);
}
} break;
int y = e->click.pt.y - 25;
if (y >= 0) {
WP(w,refit_d).sel = y / 10;
SetWindowDirty(w);
}
} break;
case 4: /* refit button */
if (WP(w,refit_d).cargo != 0xFF) {
Vehicle *v = GetVehicle(w->window_number);
if (WP(w,refit_d).cargo != CT_INVALID) {
const Vehicle *v = GetVehicle(w->window_number);
if (DoCommandP(v->tile, v->index, WP(w,refit_d).cargo, NULL, CMD_REFIT_AIRCRAFT | CMD_MSG(STR_A042_CAN_T_REFIT_AIRCRAFT)))
DeleteWindow(w);
}

View File

@ -229,7 +229,7 @@ static CommandProc * const _command_proc_table[] = {
CmdBuildAircraft, /* 61 */
CmdSendAircraftToHangar, /* 62 */
CmdChangeAircraftServiceInt, /* 63 */
CmdRefitAircraft, /* 64 <-- REFIT: Hackykid */
CmdRefitAircraft, /* 64 */
CmdPlaceSign, /* 65 */
CmdRenameSign, /* 66 */
@ -263,7 +263,7 @@ static CommandProc * const _command_proc_table[] = {
CmdBuildShip, /* 88 */
CmdSendShipToDepot, /* 89 */
CmdChangeShipServiceInt, /* 90 */
CmdRefitShip, /* 91 <-- REFIT: Hackykid */
CmdRefitShip, /* 91 */
NULL, /* 92 */
NULL, /* 93 */
@ -284,7 +284,7 @@ static CommandProc * const _command_proc_table[] = {
CmdLevelLand, /* 105 */
CmdRefitRailVehicle, /* 106 <-- REFIT: Hackykid */
CmdRefitRailVehicle, /* 106 */
CmdRestoreOrderIndex, /* 107 */
CmdBuildLock, /* 108 */
NULL, /* 109 */

View File

@ -20,34 +20,74 @@ enum {
ENGINE_PREVIEWING = 4,
};
/* This maps per-landscape cargo ids to globally unique cargo ids usable ie. in
* the custom GRF files. It is basically just a transcribed table from
* TTDPatch's newgrf.txt. */
byte _global_cargo_id[NUM_LANDSCAPE][NUM_CARGO] = {
/* LT_NORMAL */ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12 },
/* LT_HILLY */ { 0, 1, 2, 3, 4, 5, 6, 7, 28, 11, 10, 12 },
/* LT_DESERT */ { 0, 16, 2, 3, 13, 5, 6, 7, 14, 15, 10, 12 },
/* LT_CANDY */ { 0, 17, 2, 18, 19, 20, 21, 22, 23, 24, 25, 26 },
// 27 is paper in temperate climate in TTDPatch
// Following can be renumbered:
// 29 is the default cargo for the purpose of spritesets
// 30 is the purchase list image (the equivalent of 0xff) for the purpose of spritesets
/** TRANSLATE FROM LOCAL CARGO TO GLOBAL CARGO ID'S.
* This maps the per-landscape cargo ID's to globally unique cargo ID's usable ie. in
* the custom GRF files. It is basically just a transcribed table from TTDPatch's newgrf.txt.
*/
const CargoID _global_cargo_id[NUM_LANDSCAPE][NUM_CARGO] = {
/* LT_NORMAL */ {GC_PASSENGERS, GC_COAL, GC_MAIL, GC_OIL, GC_LIVESTOCK, GC_GOODS, GC_GRAIN, GC_WOOD, GC_IRON_ORE, GC_STEEL, GC_VALUABLES, GC_PAPER_TEMP},
/* LT_HILLY */ {GC_PASSENGERS, GC_COAL, GC_MAIL, GC_OIL, GC_LIVESTOCK, GC_GOODS, GC_GRAIN, GC_WOOD, GC_INVALID, GC_PAPER, GC_VALUABLES, GC_FOOD },
/* LT_DESERT */ {GC_PASSENGERS, GC_RUBBER,GC_MAIL, GC_OIL, GC_FRUIT, GC_GOODS, GC_GRAIN, GC_WOOD, GC_COPPER_ORE, GC_WATER, GC_VALUABLES, GC_FOOD },
/* LT_CANDY */ {GC_PASSENGERS, GC_SUGAR, GC_MAIL, GC_TOYS,GC_BATTERIES, GC_CANDY, GC_TOFFEE,GC_COLA, GC_COTTON_CANDY,GC_BUBBLES,GC_PLASTIC, GC_FIZZY_DRINKS },
/**
* - GC_INVALID (255) means that cargo is not available for that climate
* - GC_PAPER_TEMP (27) is paper in temperate climate in TTDPatch
* Following can be renumbered:
* - GC_DEFAULT (29) is the defa ult cargo for the purpose of spritesets
* - GC_PURCHASE (30) is the purchase list image (the equivalent of 0xff) for the purpose of spritesets
*/
};
/* These two arrays provide a reverse mapping. */
byte _local_cargo_id_ctype[NUM_CID] = {
CT_PASSENGERS, CT_COAL, CT_MAIL, CT_OIL, CT_LIVESTOCK, CT_GOODS, CT_GRAIN, CT_WOOD, // 0-7
CT_IRON_ORE, CT_STEEL, CT_VALUABLES, CT_PAPER, CT_FOOD, CT_FRUIT, CT_COPPER_ORE, CT_WATER, // 8-15
CT_RUBBER, CT_SUGAR, CT_TOYS, CT_BATTERIES, CT_CANDY, CT_TOFFEE, CT_COLA, CT_COTTON_CANDY, // 16-23
CT_BUBBLES, CT_PLASTIC, CT_FIZZY_DRINKS, CT_PAPER /* unsup. */, CT_HILLY_UNUSED // 24-28
/** BEGIN --- TRANSLATE FROM GLOBAL CARGO TO LOCAL CARGO ID'S **/
/** Map global cargo ID's to local-cargo ID's */
const CargoID _local_cargo_id_ctype[NUM_GLOBAL_CID] = {
CT_PASSENGERS,CT_COAL, CT_MAIL, CT_OIL, CT_LIVESTOCK,CT_GOODS, CT_GRAIN, CT_WOOD, /* 0- 7 */
CT_IRON_ORE, CT_STEEL, CT_VALUABLES, CT_PAPER, CT_FOOD, CT_FRUIT, CT_COPPER_ORE, CT_WATER, /* 8-15 */
CT_RUBBER, CT_SUGAR, CT_TOYS, CT_BATTERIES,CT_CANDY, CT_TOFFEE, CT_COLA, CT_COTTON_CANDY, /* 16-23 */
CT_BUBBLES, CT_PLASTIC,CT_FIZZY_DRINKS,CT_PAPER /* unsup. */,CT_HILLY_UNUSED, /* 24-28 */
CT_INVALID, CT_INVALID /* 29-30 */
};
/* LT'th bit is set of the particular landscape if cargo available there.
* 1: LT_NORMAL, 2: LT_HILLY, 4: LT_DESERT, 8: LT_CANDY */
byte _local_cargo_id_landscape[NUM_CID] = {
15, 3, 15, 7, 3, 7, 7, 7, 1, 1, 7, 2, 7, // 0-12
4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 1, 2, // 13-28
#define MC(cargo) (1 << cargo)
/** Bitmasked value where the global cargo ID is available in landscape
* 0: LT_NORMAL, 1: LT_HILLY, 2: LT_DESERT, 3: LT_CANDY */
const uint32 _landscape_global_cargo_mask[NUM_LANDSCAPE] =
{ /* LT_NORMAL: temperate */
MC(GC_PASSENGERS)|MC(GC_COAL)|MC(GC_MAIL)|MC(GC_OIL)|MC(GC_LIVESTOCK)|MC(GC_GOODS)|MC(GC_GRAIN)|MC(GC_WOOD)|
MC(GC_IRON_ORE)|MC(GC_STEEL)|MC(GC_VALUABLES)|MC(GC_FOOD)|MC(GC_UNDEFINED),
/* LT_HILLY: arctic */
MC(GC_PASSENGERS)|MC(GC_COAL)|MC(GC_MAIL)|MC(GC_OIL)|MC(GC_LIVESTOCK)|MC(GC_GOODS)|
MC(GC_GRAIN)|MC(GC_WOOD)|MC(GC_VALUABLES)|MC(GC_PAPER)|MC(GC_FOOD)|MC(GC_UNDEFINED),
/* LT_DESERT: rainforest/desert */
MC(GC_PASSENGERS)|MC(GC_MAIL)|MC(GC_OIL)|MC(GC_GOODS)|MC(GC_GRAIN)|MC(GC_WOOD)|
MC(GC_VALUABLES)|MC(GC_FOOD)|MC(GC_FRUIT)|MC(GC_COPPER_ORE)|MC(GC_WATER)|MC(GC_RUBBER),
/* LT_CANDY: toyland */
MC(GC_PASSENGERS)|MC(GC_MAIL)|MC(GC_SUGAR)|MC(GC_TOYS)|MC(GC_BATTERIES)|MC(GC_CANDY)|
MC(GC_TOFFEE)|MC(GC_COLA)|MC(GC_COTTON_CANDY)|MC(GC_BUBBLES)|MC(GC_PLASTIC)|MC(GC_FIZZY_DRINKS)
};
/** END --- TRANSLATE FROM GLOBAL CARGO TO LOCAL CARGO ID'S **/
/** Bitmasked values of what type of cargo is refittable for the given vehicle-type.
* This coupled with the landscape information (_landscape_global_cargo_mask) gives
* us exactly what is refittable and what is not */
const uint32 _default_refitmasks[NUM_VEHICLE_TYPES] = {
/* Trains */
MC(GC_PASSENGERS)|MC(GC_COAL)|MC(GC_MAIL)|MC(GC_LIVESTOCK)|MC(GC_GOODS)|MC(GC_GRAIN)|MC(GC_WOOD)|MC(GC_IRON_ORE)|
MC(GC_STEEL)|MC(GC_VALUABLES)|MC(GC_PAPER)|MC(GC_FOOD)|MC(GC_FRUIT)|MC(GC_COPPER_ORE)|MC(GC_WATER)|MC(GC_SUGAR)|
MC(GC_TOYS)|MC(GC_CANDY)|MC(GC_TOFFEE)|MC(GC_COLA)|MC(GC_COTTON_CANDY)|MC(GC_BUBBLES)|MC(GC_PLASTIC)|MC(GC_FIZZY_DRINKS),
/* Road vehicles (not refittable by default) */
0,
/* Ships */
MC(GC_COAL)|MC(GC_MAIL)|MC(GC_LIVESTOCK)|MC(GC_GOODS)|MC(GC_GRAIN)|MC(GC_WOOD)|MC(GC_IRON_ORE)|MC(GC_STEEL)|MC(GC_VALUABLES)|
MC(GC_PAPER)|MC(GC_FOOD)|MC(GC_FRUIT)|MC(GC_COPPER_ORE)|MC(GC_WATER)|MC(GC_RUBBER)|MC(GC_SUGAR)|MC(GC_TOYS)|MC(GC_BATTERIES)|
MC(GC_CANDY)|MC(GC_TOFFEE)|MC(GC_COLA)|MC(GC_COTTON_CANDY)|MC(GC_BUBBLES)|MC(GC_PLASTIC)|MC(GC_FIZZY_DRINKS),
/* Aircraft */
MC(GC_PASSENGERS)|MC(GC_MAIL)|MC(GC_GOODS)|MC(GC_VALUABLES)|MC(GC_FOOD)|MC(GC_FRUIT)|MC(GC_SUGAR)|MC(GC_TOYS)|
MC(GC_BATTERIES)|MC(GC_CANDY)|MC(GC_TOFFEE)|MC(GC_COLA)|MC(GC_COTTON_CANDY)|MC(GC_BUBBLES)|MC(GC_PLASTIC)|MC(GC_FIZZY_DRINKS),
/* Special/Disaster */
0,0
};
#undef MC
void ShowEnginePreviewWindow(int engine);
@ -267,7 +307,7 @@ byte _engine_original_sprites[TOTAL_NUM_ENGINES];
// (It isn't and shouldn't be like this in the GRF files since new cargo types
// may appear in future - however it's more convenient to store it like this in
// memory. --pasky)
static SpriteGroup _engine_custom_sprites[TOTAL_NUM_ENGINES][NUM_CID];
static SpriteGroup _engine_custom_sprites[TOTAL_NUM_ENGINES][NUM_GLOBAL_CID];
void SetCustomEngineSprites(byte engine, byte cargo, SpriteGroup *group)
{
@ -462,10 +502,11 @@ static RealSpriteGroup* ResolveVehicleSpriteGroup(SpriteGroup *spritegroup,
static SpriteGroup *GetVehicleSpriteGroup(byte engine, const Vehicle *v)
{
SpriteGroup *group;
byte cargo = CID_PURCHASE;
byte cargo = GC_PURCHASE;
if (v != NULL) {
cargo = _global_cargo_id[_opt.landscape][v->cargo_type];
assert(cargo != GC_INVALID);
}
group = &_engine_custom_sprites[engine][cargo];
@ -483,7 +524,7 @@ int GetCustomEngineSprite(byte engine, const Vehicle *v, byte direction)
{
SpriteGroup *group;
RealSpriteGroup *rsg;
byte cargo = CID_PURCHASE;
byte cargo = GC_PURCHASE;
byte loaded = 0;
bool in_motion = 0;
int totalsets, spriteset;
@ -493,6 +534,8 @@ int GetCustomEngineSprite(byte engine, const Vehicle *v, byte direction)
int capacity = v->cargo_cap;
cargo = _global_cargo_id[_opt.landscape][v->cargo_type];
assert(cargo != GC_INVALID);
if (capacity == 0) capacity = 1;
loaded = (v->cargo_count * 100) / capacity;
in_motion = (v->cur_speed != 0);

View File

@ -79,23 +79,56 @@ enum {
RVI_WAGON = 2,
};
enum {
NUM_VEHICLE_TYPES = 6
};
void AddTypeToEngines(void);
void StartupEngines(void);
extern byte _global_cargo_id[NUM_LANDSCAPE][NUM_CARGO];
enum {
CID_DEFAULT = 29,
CID_PURCHASE = 30,
NUM_CID = 31,
enum GlobalCargo {
GC_PASSENGERS = 0,
GC_COAL = 1,
GC_MAIL = 2,
GC_OIL = 3,
GC_LIVESTOCK = 4,
GC_GOODS = 5,
GC_GRAIN = 6, // GC_WHEAT / GC_MAIZE
GC_WOOD = 7,
GC_IRON_ORE = 8,
GC_STEEL = 9,
GC_VALUABLES = 10, // GC_GOLD / GC_DIAMONDS
GC_PAPER = 11,
GC_FOOD = 12,
GC_FRUIT = 13,
GC_COPPER_ORE = 14,
GC_WATER = 15,
GC_RUBBER = 16,
GC_SUGAR = 17,
GC_TOYS = 18,
GC_BATTERIES = 19,
GC_CANDY = 20,
GC_TOFFEE = 21,
GC_COLA = 22,
GC_COTTON_CANDY = 23,
GC_BUBBLES = 24,
GC_PLASTIC = 25,
GC_FIZZY_DRINKS = 26,
GC_PAPER_TEMP = 27,
GC_UNDEFINED = 28, // undefined; unused slot in arctic climate
GC_DEFAULT = 29,
GC_PURCHASE = 30,
GC_INVALID = 255,
NUM_GLOBAL_CID = 31
};
extern byte _local_cargo_id_ctype[NUM_CID];
extern byte _local_cargo_id_landscape[NUM_CID];
extern uint32 _engine_refit_masks[256];
VARDEF const uint32 _default_refitmasks[NUM_VEHICLE_TYPES];
VARDEF const CargoID _global_cargo_id[NUM_LANDSCAPE][NUM_CARGO];
VARDEF const uint32 _landscape_global_cargo_mask[NUM_LANDSCAPE];
VARDEF const CargoID _local_cargo_id_ctype[NUM_GLOBAL_CID];
extern byte _engine_original_sprites[256];
VARDEF uint32 _engine_refit_masks[256];
VARDEF byte _engine_original_sprites[256];
void SetWagonOverrideSprites(byte engine, struct SpriteGroup *group, byte *train_id, int trains);
void SetCustomEngineSprites(byte engine, byte cargo, struct SpriteGroup *group);
// loaded is in percents, overriding_engine 0xffff is none

View File

@ -2445,6 +2445,7 @@ STR_882C_BUILT_VALUE :{LTBLUE}{STRING
STR_882D_VALUE :{LTBLUE}{STRING}{BLACK} Value: {LTBLUE}{CURRENCY}
STR_882E :{WHITE}{STRING}
STR_882F_LOADING_UNLOADING :{LTBLUE}Loading / Unloading
STR_TRAIN_MUST_BE_STOPPED :{WHITE}Train must be stopped inside depot
STR_8830_CAN_T_SEND_TRAIN_TO_DEPOT :{WHITE}Can't send train to depot...
STR_8831_NO_MORE_SPACE_FOR_ORDERS :{WHITE}No more space for orders
STR_8832_TOO_MANY_ORDERS :{WHITE}Too many orders

View File

@ -1450,8 +1450,7 @@ static void NewVehicle_SpriteGroupMapping(byte *buf, int len)
return;
}
if (ctype == 0xFF)
ctype = CID_PURCHASE;
if (ctype == GC_INVALID) ctype = GC_PURCHASE;
if (wagover) {
// TODO: No multiple cargo types per vehicle yet. --pasky
@ -1482,7 +1481,7 @@ static void NewVehicle_SpriteGroupMapping(byte *buf, int len)
// TODO: No multiple cargo types per vehicle yet. --pasky
SetWagonOverrideSprites(engine, &_cur_grffile->spritegroups[groupid], last_engines, last_engines_count);
} else {
SetCustomEngineSprites(engine, CID_DEFAULT, &_cur_grffile->spritegroups[groupid]);
SetCustomEngineSprites(engine, GC_DEFAULT, &_cur_grffile->spritegroups[groupid]);
last_engines[i] = engine;
}
}

View File

@ -1067,36 +1067,39 @@ int32 CmdChangeShipServiceInt(int x, int y, uint32 flags, uint32 p1, uint32 p2)
return 0;
}
// p1 = vehicle
// p2 = new cargo (0xFF)
// p2 = skip check for stopped in hanger (0x0100)
/** Refits a ship to the specified cargo type.
* @param x,y unused
* @param p1 vehicle ID of the ship to refit
* @param p2 various bitstuffed elements
* - p2 = (bit 0-7) - the new cargo type to refit to (p2 & 0xFF)
* - p2 = (bit 8) - skip check for stopped in depot, used by autoreplace (p2 & 0x100)
* @todo p2 bit8 check <b>NEEDS TO GO</b>
*/
int32 CmdRefitShip(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
Vehicle *v;
int32 cost;
byte SkipStoppedInDepotCheck = (p2 & 0x100) >> 8; //excludes the cargo value
p2 = p2 & 0xFF;
CargoID new_cid = p2 & 0xFF; //gets the cargo number
bool SkipStoppedInDepotCheck = !!HASBIT(p2, 8); // XXX - needs to go, yes?
if (!IsVehicleIndex(p1)) return CMD_ERROR;
v = GetVehicle(p1);
if (v->type != VEH_Ship || !CheckOwnership(v->owner))
return CMD_ERROR;
if (!( SkipStoppedInDepotCheck )) {
if (!IsTileDepotType(v->tile, TRANSPORT_WATER) ||
!(v->vehstatus&VS_STOPPED) ||
v->u.ship.state != 0x80)
if (v->type != VEH_Ship || !CheckOwnership(v->owner)) return CMD_ERROR;
if (!SkipStoppedInDepotCheck) {
if (!IsTileDepotType(v->tile, TRANSPORT_WATER) || !(v->vehstatus&VS_STOPPED) || v->u.ship.state != 0x80)
return_cmd_error(STR_980B_SHIP_MUST_BE_STOPPED_IN);
}
}
/* Check cargo */
if (!ShipVehInfo(v->engine_type)->refittable) return CMD_ERROR;
if (new_cid > NUM_CARGO || !CanRefitTo(v, new_cid)) return CMD_ERROR;
SET_EXPENSES_TYPE(EXPENSES_SHIP_RUN);
cost = 0;
if (IS_HUMAN_PLAYER(v->owner) && (byte)p2 != v->cargo_type) {
if (IS_HUMAN_PLAYER(v->owner) && new_cid != v->cargo_type) {
cost = _price.ship_base >> 7;
}
@ -1105,12 +1108,10 @@ int32 CmdRefitShip(int x, int y, uint32 flags, uint32 p1, uint32 p2)
//it will be checked if the cargo is valid in CmdRenewVehicle
if (!(SkipStoppedInDepotCheck))
v->cargo_count = 0;
v->cargo_type = (byte)p2;
v->cargo_type = new_cid;
InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
}
return cost;
}

View File

@ -45,23 +45,11 @@ static void DrawShipImage(const Vehicle *v, int x, int y, VehicleID selection)
}
}
const byte _ship_refit_types[4][16] = {
{CT_MAIL, CT_COAL, CT_LIVESTOCK, CT_GOODS, CT_GRAIN, CT_WOOD, CT_IRON_ORE, CT_STEEL, CT_VALUABLES, 255},
{CT_MAIL, CT_COAL, CT_LIVESTOCK, CT_GOODS, CT_GRAIN, CT_WOOD, CT_PAPER, CT_FOOD, CT_VALUABLES, 255},
{CT_MAIL, CT_FRUIT, CT_GOODS, CT_COPPER_ORE, CT_GRAIN, CT_WOOD, CT_WATER, CT_VALUABLES, 255},
{CT_MAIL, CT_SUGAR, CT_TOYS, CT_CANDY, CT_COLA, CT_COTTON_CANDY, CT_BUBBLES, CT_TOFFEE, CT_BATTERIES, CT_PLASTIC, CT_FIZZY_DRINKS, 255},
};
static void ShipRefitWndProc(Window *w, WindowEvent *e)
{
switch(e->event) {
switch (e->event) {
case WE_PAINT: {
Vehicle *v = GetVehicle(w->window_number);
const byte *b;
int sel;
int x,y;
byte color;
int cargo;
const Vehicle *v = GetVehicle(w->window_number);
SetDParam(0, v->string_id);
SetDParam(1, v->unitnumber);
@ -69,71 +57,32 @@ static void ShipRefitWndProc(Window *w, WindowEvent *e)
DrawString(1, 15, STR_983F_SELECT_CARGO_TYPE_TO_CARRY, 0);
cargo = -1;
x = 6;
y = 25;
sel = WP(w,refit_d).sel;
/* TODO: Support for custom GRFSpecial-specified refitting! --pasky */
WP(w,refit_d).cargo = DrawVehicleRefitWindow(v, WP(w, refit_d).sel);;
#define show_cargo(ctype) { \
color = 16; \
if (sel == 0) { \
cargo = ctype; \
color = 12; \
} \
sel--; \
DrawString(x, y, _cargoc.names_s[ctype], color); \
y += 10; \
}
if (_engine_refit_masks[v->engine_type]) {
uint32 mask = _engine_refit_masks[v->engine_type];
int cid = 0;
for (; mask; mask >>= 1, cid++) {
if (!(mask & 1)) // not this cid
continue;
if (!(_local_cargo_id_landscape[cid] & (1 << _opt.landscape))) // not in this landscape
continue;
show_cargo(_local_cargo_id_ctype[cid]);
}
} else { // generic refit list
b = _ship_refit_types[_opt.landscape];
do {
show_cargo(*b);
} while (*++b != 255);
}
#undef show_cargo
WP(w,refit_d).cargo = cargo;
if (cargo != -1) {
int32 cost = DoCommandByTile(v->tile, v->index, cargo, 0, CMD_REFIT_SHIP);
if (cost != CMD_ERROR) {
if (WP(w,refit_d).cargo != CT_INVALID) {
int32 cost = DoCommandByTile(v->tile, v->index, WP(w,refit_d).cargo, DC_QUERY_COST, CMD_REFIT_SHIP);
if (!CmdFailed(cost)) {
SetDParam(2, cost);
SetDParam(0, _cargoc.names_long_p[cargo]);
SetDParam(0, _cargoc.names_long_p[WP(w,refit_d).cargo]);
SetDParam(1, v->cargo_cap);
DrawString(1, 137, STR_9840_NEW_CAPACITY_COST_OF_REFIT, 0);
}
}
break;
}
} break;
case WE_CLICK:
switch(e->click.widget) {
case 2: { /* listbox */
int y = e->click.pt.y - 25;
if (y >= 0) {
WP(w,refit_d).sel = y / 10;
SetWindowDirty(w);
}
} break;
int y = e->click.pt.y - 25;
if (y >= 0) {
WP(w,refit_d).sel = y / 10;
SetWindowDirty(w);
}
} break;
case 4: /* refit button */
if (WP(w,refit_d).cargo != 0xFF) {
Vehicle *v = GetVehicle(w->window_number);
if (WP(w,refit_d).cargo != CT_INVALID) {
const Vehicle *v = GetVehicle(w->window_number);
if (DoCommandP(v->tile, v->index, WP(w,refit_d).cargo, NULL, CMD_REFIT_SHIP | CMD_MSG(STR_9841_CAN_T_REFIT_SHIP)))
DeleteWindow(w);
}

View File

@ -248,7 +248,7 @@ typedef struct StationSpec {
StationLayout **layouts;
/* Sprite offsets for renderdata->seq->image. spritegroup[0] is default
* whilst spritegroup[1] is "CID_PURCHASE". */
* whilst spritegroup[1] is "GC_PURCHASE". */
SpriteGroup spritegroup[2];
} StationSpec;

View File

@ -1282,25 +1282,31 @@ int32 CmdForceTrainProceed(int x, int y, uint32 flags, uint32 p1, uint32 p2)
return 0;
}
// p1 = vehicle to refit
// p2 = new cargo (0xFF)
// p2 = skip check for stopped in hanger (0x0100)
/** Refits a train to the specified cargo type.
* @param x,y unused
* @param p1 vehicle ID of the train to refit
* @param p2 various bitstuffed elements
* - p2 = (bit 0-7) - the new cargo type to refit to (p2 & 0xFF)
* - p2 = (bit 8) - skip check for stopped in depot, used by autoreplace (p2 & 0x100)
* @todo p2 bit8 check <b>NEEDS TO GO</b>
*/
int32 CmdRefitRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
Vehicle *v;
int32 cost;
uint num;
byte SkipStoppedInDepotCheck = (p2 & 0x100) >> 8;
p2 = p2 & 0xFF;
CargoID new_cid = p2 & 0xFF; //gets the cargo number
bool SkipStoppedInDepotCheck = !!HASBIT(p2, 8); // XXX - needs to go, yes?
if (!IsVehicleIndex(p1)) return CMD_ERROR;
v = GetVehicle(p1);
if (v->type != VEH_Train || !CheckOwnership(v->owner) || ((CheckTrainStoppedInDepot(v) < 0) && !(SkipStoppedInDepotCheck)))
return CMD_ERROR;
if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR;
if (!SkipStoppedInDepotCheck && CheckTrainStoppedInDepot(v) < 0) return_cmd_error(STR_TRAIN_MUST_BE_STOPPED);
/* Check cargo */
if (new_cid > NUM_CARGO) return CMD_ERROR;
SET_EXPENSES_TYPE(EXPENSES_TRAIN_RUN);
@ -1311,17 +1317,17 @@ int32 CmdRefitRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
/* XXX: We also refit all the attached wagons en-masse if they
* can be refitted. This is how TTDPatch does it. TODO: Have
* some nice [Refit] button near each wagon. --pasky */
if ((!(RailVehInfo(v->engine_type)->flags & RVI_WAGON)
|| (_engine_refit_masks[v->engine_type] & (1 << p2)))
&& (byte) p2 != v->cargo_type && v->cargo_cap != 0) {
if (!CanRefitTo(v, new_cid)) continue;
if (new_cid != v->cargo_type && v->cargo_cap != 0) {
cost += (_price.build_railvehicle >> 8);
num += v->cargo_cap;
if (flags & DC_EXEC) {
//autorefitted train cars wants to keep the cargo
//it will be checked if the cargo is valid in CmdReplaceVehicle
//autorefitted train cars wants to keep the cargo
//it will be checked if the cargo is valid in CmdReplaceVehicle
if (!(SkipStoppedInDepotCheck))
v->cargo_count = 0;
v->cargo_type = (byte)p2;
v->cargo_type = new_cid;
InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
}
}

View File

@ -662,23 +662,11 @@ void ShowTrainDepotWindow(uint tile)
}
}
const byte _rail_vehicle_refit_types[4][16] = {
{ 0,1,2,4,5,6,7,8,9,10,0xFF }, // normal
{ 0,1,4,5,6,7,9,11,10,0xFF }, // arctic
{ 0,4,5,8,6,7,9,10,0xFF }, // desert
{ 0,1,3,5,7,8,9,6,4,10,11,0xFF }// candy
};
static void RailVehicleRefitWndProc(Window *w, WindowEvent *e)
{
switch(e->event) {
switch (e->event) {
case WE_PAINT: {
Vehicle *v = GetVehicle(w->window_number);
const byte *b;
int sel;
int x,y;
byte color;
int cargo;
const Vehicle *v = GetVehicle(w->window_number);
SetDParam(0, v->string_id);
SetDParam(1, v->unitnumber);
@ -686,57 +674,19 @@ static void RailVehicleRefitWndProc(Window *w, WindowEvent *e)
DrawString(1, 15, STR_983F_SELECT_CARGO_TYPE_TO_CARRY, 0);
cargo = -1;
x = 6;
y = 25;
sel = WP(w,refit_d).sel;
/* TODO: Support for custom GRFSpecial-specified refitting! --pasky */
WP(w,refit_d).cargo = DrawVehicleRefitWindow(v, WP(w, refit_d).sel);
#define show_cargo(ctype) { \
color = 16; \
if (sel == 0) { \
cargo = ctype; \
color = 12; \
} \
sel--; \
DrawString(x, y, _cargoc.names_s[ctype], color); \
y += 10; \
}
if (_engine_refit_masks[v->engine_type]) {
uint32 mask = _engine_refit_masks[v->engine_type];
int cid = 0;
for (; mask; mask >>= 1, cid++) {
if (!(mask & 1)) // not this cid
continue;
if (!(_local_cargo_id_landscape[cid] & (1 << _opt.landscape))) // not in this landscape
continue;
show_cargo(_local_cargo_id_ctype[cid]);
}
} else { // generic refit list
b = _rail_vehicle_refit_types[_opt.landscape];
do {
show_cargo(*b);
} while (*++b != 255);
}
#undef show_cargo
WP(w,refit_d).cargo = cargo;
if (cargo != -1) {
int32 cost = DoCommandByTile(v->tile, v->index, cargo, 0, CMD_REFIT_RAIL_VEHICLE);
if (cost != CMD_ERROR) {
if (WP(w,refit_d).cargo != CT_INVALID) {
int32 cost = DoCommandByTile(v->tile, v->index, WP(w,refit_d).cargo, DC_QUERY_COST, CMD_REFIT_RAIL_VEHICLE);
if (!CmdFailed(cost)) {
SetDParam(2, cost);
SetDParam(0, _cargoc.names_long_p[cargo]);
SetDParam(0, _cargoc.names_long_p[WP(w,refit_d).cargo]);
SetDParam(1, _returned_refit_amount);
DrawString(1, 137, STR_9840_NEW_CAPACITY_COST_OF_REFIT, 0);
}
}
break;
}
} break;
case WE_CLICK:
switch(e->click.widget) {
@ -748,8 +698,8 @@ static void RailVehicleRefitWndProc(Window *w, WindowEvent *e)
}
} break;
case 4: /* refit button */
if (WP(w,refit_d).cargo != 0xFF) {
Vehicle *v = GetVehicle(w->window_number);
if (WP(w,refit_d).cargo != CT_INVALID) {
const Vehicle *v = GetVehicle(w->window_number);
if (DoCommandP(v->tile, v->index, WP(w,refit_d).cargo, NULL, CMD_REFIT_RAIL_VEHICLE | CMD_MSG(STR_RAIL_CAN_T_REFIT_VEHICLE)))
DeleteWindow(w);
}
@ -809,9 +759,9 @@ static Widget _train_view_widgets[] = {
static void TrainViewWndProc(Window *w, WindowEvent *e)
{
switch(e->event) {
switch (e->event) {
case WE_PAINT: {
Vehicle *v, *u;
const Vehicle *v, *u;
StringID str;
v = GetVehicle(w->window_number);
@ -820,22 +770,16 @@ static void TrainViewWndProc(Window *w, WindowEvent *e)
SETBIT(w->disabled_state, 12);
/* See if any carriage can be refitted */
/* See if any vehicle can be refitted */
for ( u = v; u != NULL; u = u->next) {
if (_engine_refit_masks[u->engine_type] != 0) {
if (_engine_refit_masks[u->engine_type] != 0 ||
(!(RailVehInfo(v->engine_type)->flags & RVI_WAGON) && v->cargo_cap != 0)) {
CLRBIT(w->disabled_state, 12);
/* We have a refittable carriage, bail out */
break;
}
}
/* Above code doesn't seem to handle non-newgrf engines, do it separately
TODO: handle engines which are NOT the head of the train, but don't break wagons */
if (v->cargo_cap != 0) {
/* we can refit this engine */
CLRBIT(w->disabled_state, 12);
}
/* draw widgets & caption */
SetDParam(0, v->string_id);
SetDParam(1, v->unitnumber);

1
ttd.h
View File

@ -67,6 +67,7 @@ typedef struct DrawPixelInfo DrawPixelInfo;
typedef uint16 VehicleID;
typedef byte PlayerID;
typedef byte OrderID;
typedef byte CargoID;
typedef uint16 StringID;
typedef uint16 SpriteID;
typedef uint32 PalSpriteID;

View File

@ -501,6 +501,28 @@ bool CanFillVehicle(Vehicle *v)
return false;
}
/** Check if a given vehicle (type) can be refitted to a given cargo
* @param *v vehicle to check
* @param cid_to check refit to this cargo-type
* @return true if it is possible, false otherwise
*/
bool CanRefitTo(const Vehicle *v, CargoID cid_to)
{
CargoID cid = _global_cargo_id[_opt_ptr->landscape][cid_to];
if (cid == GC_INVALID) return false;
if (_engine_refit_masks[v->engine_type]) {
if (!HASBIT(_engine_refit_masks[v->engine_type], cid)) return false;
} else {
/* If we are talking about normal vehicles (no newgrf), you can only refit engines */
if (v->type == VEH_Train && (RailVehInfo(v->engine_type)->flags & RVI_WAGON)) return false;
if (!HASBIT(_default_refitmasks[v->type - VEH_Train], cid)) return false;
}
return true;
}
static void DoDrawVehicle(Vehicle *v)
{
uint32 image = v->cur_image;

View File

@ -262,6 +262,7 @@ Vehicle *FindVehicleOnTileZ(TileIndex tile, byte z);
void InitializeTrains(void);
bool CanFillVehicle(Vehicle *v);
bool CanRefitTo(const Vehicle *v, CargoID cid_to);
void ViewportAddVehicles(DrawPixelInfo *dpi);

View File

@ -165,6 +165,42 @@ void DrawVehicleProfitButton(Vehicle *v, int x, int y)
DrawSprite(SPR_BLOT | ormod, x, y);
}
/** Draw the list of available refit options.
* Draw the list and highlight the selected refit option (if any)
* @param *v vehicle(type) to get the refit-options of
* @param sel selected refit cargo-type in the window
* @return the cargo type that is hightlighted, CT_INVALID if none
*/
CargoID DrawVehicleRefitWindow(const Vehicle *v, int sel)
{
uint32 cmask;
CargoID cid, cargo = CT_INVALID;
int y = 25;
#define show_cargo(ctype) { \
byte colour = 16; \
if (sel == 0) { \
cargo = ctype; \
colour = 12; \
} \
sel--; \
DrawString(6, y, _cargoc.names_s[ctype], colour); \
y += 10; \
}
/* Check if engine has custom refit or normal ones, and get its bitmasked value.
* Now just and it with the bitmasked available cargo on the current landscape, and
* where the bits are set: those are available */
cmask = (_engine_refit_masks[v->engine_type] != 0) ? _engine_refit_masks[v->engine_type] : _default_refitmasks[v->type - VEH_Train];
cmask &= _landscape_global_cargo_mask[_opt_ptr->landscape];
/* Check which cargo has been selected from the refit window and draw list */
for (cid = 0; cmask != 0; cmask >>= 1, cid++) {
if (HASBIT(cmask, 0)) // vehicle is refittable to this cargo
show_cargo(_local_cargo_id_ctype[cid]);
}
return cargo;
}
/************ Sorter functions *****************/
int CDECL GeneralOwnerSorter(const void *a, const void *b)
{

View File

@ -6,6 +6,7 @@
struct vehiclelist_d;
void DrawVehicleProfitButton(Vehicle *v, int x, int y);
CargoID DrawVehicleRefitWindow(const Vehicle *v, int sel);
void InitializeVehiclesGuiList(void);
/* sorter stuff */