mirror of https://github.com/OpenTTD/OpenTTD
(svn r2389) - Feature: [newgrf] Implement the mechanism for handling newgrf callbacks.
- Feature: [newgrf] Implement the 'refit capacity' callback.release/0.4.5
parent
d1c1a7cba7
commit
351d7aaa9f
85
engine.c
85
engine.c
|
@ -317,16 +317,17 @@ void SetCustomEngineSprites(byte engine, byte cargo, SpriteGroup *group)
|
||||||
_engine_custom_sprites[engine][cargo] = *group;
|
_engine_custom_sprites[engine][cargo] = *group;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef RealSpriteGroup *(*resolve_callback)(SpriteGroup *spritegroup,
|
typedef SpriteGroup *(*resolve_callback)(SpriteGroup *spritegroup,
|
||||||
const Vehicle *veh, void *callback); /* XXX data pointer used as function pointer */
|
const Vehicle *veh, uint16 callback_info, void *resolve_func); /* XXX data pointer used as function pointer */
|
||||||
|
|
||||||
static RealSpriteGroup* ResolveVehicleSpriteGroup(SpriteGroup *spritegroup,
|
static SpriteGroup* ResolveVehicleSpriteGroup(SpriteGroup *spritegroup,
|
||||||
const Vehicle *veh, resolve_callback callback)
|
const Vehicle *veh, uint16 callback_info, resolve_callback resolve_func)
|
||||||
{
|
{
|
||||||
//debug("spgt %d", spritegroup->type);
|
//debug("spgt %d", spritegroup->type);
|
||||||
switch (spritegroup->type) {
|
switch (spritegroup->type) {
|
||||||
case SGT_REAL:
|
case SGT_REAL:
|
||||||
return &spritegroup->g.real;
|
case SGT_CALLBACK:
|
||||||
|
return spritegroup;
|
||||||
|
|
||||||
case SGT_DETERMINISTIC: {
|
case SGT_DETERMINISTIC: {
|
||||||
DeterministicSpriteGroup *dsg = &spritegroup->g.determ;
|
DeterministicSpriteGroup *dsg = &spritegroup->g.determ;
|
||||||
|
@ -334,8 +335,10 @@ static RealSpriteGroup* ResolveVehicleSpriteGroup(SpriteGroup *spritegroup,
|
||||||
int value = -1;
|
int value = -1;
|
||||||
|
|
||||||
//debug("[%p] Having fun resolving variable %x", veh, dsg->variable);
|
//debug("[%p] Having fun resolving variable %x", veh, dsg->variable);
|
||||||
|
if (dsg->variable == 0x0C) {
|
||||||
if ((dsg->variable >> 6) == 0) {
|
/* Callback ID */
|
||||||
|
value = callback_info & 0xFF;
|
||||||
|
} else if ((dsg->variable >> 6) == 0) {
|
||||||
/* General property */
|
/* General property */
|
||||||
value = GetDeterministicSpriteValue(dsg->variable);
|
value = GetDeterministicSpriteValue(dsg->variable);
|
||||||
} else {
|
} else {
|
||||||
|
@ -351,7 +354,7 @@ static RealSpriteGroup* ResolveVehicleSpriteGroup(SpriteGroup *spritegroup,
|
||||||
} else {
|
} else {
|
||||||
target = dsg->default_group;
|
target = dsg->default_group;
|
||||||
}
|
}
|
||||||
return callback(target, NULL, callback);
|
return resolve_func(target, NULL, callback_info, resolve_func);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dsg->var_scope == VSG_SCOPE_PARENT) {
|
if (dsg->var_scope == VSG_SCOPE_PARENT) {
|
||||||
|
@ -472,7 +475,7 @@ static RealSpriteGroup* ResolveVehicleSpriteGroup(SpriteGroup *spritegroup,
|
||||||
|
|
||||||
target = value != -1 ? EvalDeterministicSpriteGroup(dsg, value) : dsg->default_group;
|
target = value != -1 ? EvalDeterministicSpriteGroup(dsg, value) : dsg->default_group;
|
||||||
//debug("Resolved variable %x: %d, %p", dsg->variable, value, callback);
|
//debug("Resolved variable %x: %d, %p", dsg->variable, value, callback);
|
||||||
return callback(target, veh, callback);
|
return resolve_func(target, veh, callback_info, resolve_func);
|
||||||
}
|
}
|
||||||
|
|
||||||
case SGT_RANDOMIZED: {
|
case SGT_RANDOMIZED: {
|
||||||
|
@ -482,7 +485,7 @@ static RealSpriteGroup* ResolveVehicleSpriteGroup(SpriteGroup *spritegroup,
|
||||||
/* Purchase list of something. Show the first one. */
|
/* Purchase list of something. Show the first one. */
|
||||||
assert(rsg->num_groups > 0);
|
assert(rsg->num_groups > 0);
|
||||||
//debug("going for %p: %d", rsg->groups[0], rsg->groups[0].type);
|
//debug("going for %p: %d", rsg->groups[0], rsg->groups[0].type);
|
||||||
return callback(&rsg->groups[0], NULL, callback);
|
return resolve_func(&rsg->groups[0], NULL, callback_info, resolve_func);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rsg->var_scope == VSG_SCOPE_PARENT) {
|
if (rsg->var_scope == VSG_SCOPE_PARENT) {
|
||||||
|
@ -491,7 +494,7 @@ static RealSpriteGroup* ResolveVehicleSpriteGroup(SpriteGroup *spritegroup,
|
||||||
veh = GetFirstVehicleInChain(veh);
|
veh = GetFirstVehicleInChain(veh);
|
||||||
}
|
}
|
||||||
|
|
||||||
return callback(EvalRandomizedSpriteGroup(rsg, veh->random_bits), veh, callback);
|
return resolve_func(EvalRandomizedSpriteGroup(rsg, veh->random_bits), veh, callback_info, resolve_func);
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -543,14 +546,17 @@ int GetCustomEngineSprite(byte engine, const Vehicle *v, byte direction)
|
||||||
}
|
}
|
||||||
|
|
||||||
group = GetVehicleSpriteGroup(engine, v);
|
group = GetVehicleSpriteGroup(engine, v);
|
||||||
rsg = ResolveVehicleSpriteGroup(group, v, (resolve_callback) ResolveVehicleSpriteGroup);
|
group = ResolveVehicleSpriteGroup(group, v, 0, (resolve_callback) ResolveVehicleSpriteGroup);
|
||||||
|
|
||||||
if (rsg->sprites_per_set == 0 && cargo != 29) { /* XXX magic number */
|
if (group->type == SGT_REAL && group->g.real.sprites_per_set == 0 && cargo != GC_DEFAULT) {
|
||||||
// This group is empty but perhaps there'll be a default one.
|
// This group is empty but perhaps there'll be a default one.
|
||||||
rsg = ResolveVehicleSpriteGroup(&_engine_custom_sprites[engine][29], v,
|
group = ResolveVehicleSpriteGroup(&_engine_custom_sprites[engine][GC_DEFAULT], v, 0,
|
||||||
(resolve_callback) ResolveVehicleSpriteGroup);
|
(resolve_callback) ResolveVehicleSpriteGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(group->type == SGT_REAL);
|
||||||
|
rsg = &group->g.real;
|
||||||
|
|
||||||
if (!rsg->sprites_per_set) {
|
if (!rsg->sprites_per_set) {
|
||||||
// This group is empty. This function users should therefore
|
// This group is empty. This function users should therefore
|
||||||
// look up the sprite number in _engine_original_sprites.
|
// look up the sprite number in _engine_original_sprites.
|
||||||
|
@ -582,6 +588,39 @@ int GetCustomEngineSprite(byte engine, const Vehicle *v, byte direction)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates a newgrf callback
|
||||||
|
* @param callback_info info about which callback to evaluate
|
||||||
|
* (bit 0-7) = CallBack id of the callback to use, see CallBackId enum
|
||||||
|
* (bit 8-15) = Other info some callbacks need to have, callback specific, see CallBackId enum, not used yet
|
||||||
|
* @param engine Engine type of the vehicle to evaluate the callback for
|
||||||
|
* @param vehicle The vehicle to evaluate the callback for, NULL if it doesnt exist (yet)
|
||||||
|
* @return The value the callback returned, or CALLBACK_FAILED if it failed
|
||||||
|
*/
|
||||||
|
uint16 GetCallBackResult(uint16 callback_info, byte engine, const Vehicle *v)
|
||||||
|
{
|
||||||
|
SpriteGroup *group;
|
||||||
|
byte cargo = GC_DEFAULT;
|
||||||
|
|
||||||
|
if (v != NULL)
|
||||||
|
cargo = _global_cargo_id[_opt.landscape][v->cargo_type];
|
||||||
|
|
||||||
|
group = &_engine_custom_sprites[engine][cargo];
|
||||||
|
group = ResolveVehicleSpriteGroup(group, v, callback_info, (resolve_callback) ResolveVehicleSpriteGroup);
|
||||||
|
|
||||||
|
if (group->type == SGT_REAL && group->g.real.sprites_per_set == 0 && cargo != GC_DEFAULT) {
|
||||||
|
// This group is empty but perhaps there'll be a default one.
|
||||||
|
group = ResolveVehicleSpriteGroup(&_engine_custom_sprites[engine][GC_DEFAULT], v, callback_info,
|
||||||
|
(resolve_callback) ResolveVehicleSpriteGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (group->type != SGT_CALLBACK)
|
||||||
|
return CALLBACK_FAILED;
|
||||||
|
|
||||||
|
return group->g.callback.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Global variables are evil, yes, but we would end up with horribly overblown
|
// Global variables are evil, yes, but we would end up with horribly overblown
|
||||||
// calling convention otherwise and this should be 100% reentrant.
|
// calling convention otherwise and this should be 100% reentrant.
|
||||||
|
@ -590,8 +629,8 @@ static byte _vsg_bits_to_reseed;
|
||||||
|
|
||||||
extern int _custom_sprites_base;
|
extern int _custom_sprites_base;
|
||||||
|
|
||||||
static RealSpriteGroup *TriggerVehicleSpriteGroup(SpriteGroup *spritegroup,
|
static SpriteGroup *TriggerVehicleSpriteGroup(SpriteGroup *spritegroup,
|
||||||
Vehicle *veh, resolve_callback callback)
|
Vehicle *veh, uint16 callback_info, resolve_callback resolve_func)
|
||||||
{
|
{
|
||||||
if (spritegroup->type == SGT_RANDOMIZED) {
|
if (spritegroup->type == SGT_RANDOMIZED) {
|
||||||
_vsg_bits_to_reseed |= RandomizedSpriteGroupTriggeredBits(
|
_vsg_bits_to_reseed |= RandomizedSpriteGroupTriggeredBits(
|
||||||
|
@ -601,23 +640,29 @@ static RealSpriteGroup *TriggerVehicleSpriteGroup(SpriteGroup *spritegroup,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResolveVehicleSpriteGroup(spritegroup, veh, callback);
|
return ResolveVehicleSpriteGroup(spritegroup, veh, callback_info, resolve_func);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DoTriggerVehicle(Vehicle *veh, VehicleTrigger trigger, byte base_random_bits, bool first)
|
static void DoTriggerVehicle(Vehicle *veh, VehicleTrigger trigger, byte base_random_bits, bool first)
|
||||||
{
|
{
|
||||||
|
SpriteGroup *group;
|
||||||
RealSpriteGroup *rsg;
|
RealSpriteGroup *rsg;
|
||||||
byte new_random_bits;
|
byte new_random_bits;
|
||||||
|
|
||||||
_vsg_random_triggers = trigger;
|
_vsg_random_triggers = trigger;
|
||||||
_vsg_bits_to_reseed = 0;
|
_vsg_bits_to_reseed = 0;
|
||||||
rsg = TriggerVehicleSpriteGroup(GetVehicleSpriteGroup(veh->engine_type, veh), veh,
|
group = TriggerVehicleSpriteGroup(GetVehicleSpriteGroup(veh->engine_type, veh), veh, 0,
|
||||||
(resolve_callback) TriggerVehicleSpriteGroup);
|
(resolve_callback) TriggerVehicleSpriteGroup);
|
||||||
if (rsg->sprites_per_set == 0 && veh->cargo_type != 29) { /* XXX magic number */
|
|
||||||
|
if (group->type == SGT_REAL && group->g.real.sprites_per_set == 0 && veh->cargo_type != GC_DEFAULT) {
|
||||||
// This group turned out to be empty but perhaps there'll be a default one.
|
// This group turned out to be empty but perhaps there'll be a default one.
|
||||||
rsg = TriggerVehicleSpriteGroup(&_engine_custom_sprites[veh->engine_type][29], veh,
|
group = TriggerVehicleSpriteGroup(&_engine_custom_sprites[veh->engine_type][GC_DEFAULT], veh, 0,
|
||||||
(resolve_callback) TriggerVehicleSpriteGroup);
|
(resolve_callback) TriggerVehicleSpriteGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(group->type == SGT_REAL);
|
||||||
|
rsg = &group->g.real;
|
||||||
|
|
||||||
new_random_bits = Random();
|
new_random_bits = Random();
|
||||||
veh->random_bits &= ~_vsg_bits_to_reseed;
|
veh->random_bits &= ~_vsg_bits_to_reseed;
|
||||||
veh->random_bits |= (first ? new_random_bits : base_random_bits) & _vsg_bits_to_reseed;
|
veh->random_bits |= (first ? new_random_bits : base_random_bits) & _vsg_bits_to_reseed;
|
||||||
|
|
12
engine.h
12
engine.h
|
@ -122,6 +122,17 @@ enum GlobalCargo {
|
||||||
NUM_GLOBAL_CID = 31
|
NUM_GLOBAL_CID = 31
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// This enum only lists implemented callbacks
|
||||||
|
enum CallbackID {
|
||||||
|
// Refit capacity, the passed vehicle needs to have its ->cargo_type set to
|
||||||
|
// the cargo we are refitting to, returns the new cargo capacity
|
||||||
|
CB_REFIT_CAP = 0x15,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CALLBACK_FAILED = 0xFFFF
|
||||||
|
};
|
||||||
|
|
||||||
VARDEF const uint32 _default_refitmasks[NUM_VEHICLE_TYPES];
|
VARDEF const uint32 _default_refitmasks[NUM_VEHICLE_TYPES];
|
||||||
VARDEF const CargoID _global_cargo_id[NUM_LANDSCAPE][NUM_CARGO];
|
VARDEF const CargoID _global_cargo_id[NUM_LANDSCAPE][NUM_CARGO];
|
||||||
VARDEF const uint32 _landscape_global_cargo_mask[NUM_LANDSCAPE];
|
VARDEF const uint32 _landscape_global_cargo_mask[NUM_LANDSCAPE];
|
||||||
|
@ -133,6 +144,7 @@ void SetWagonOverrideSprites(byte engine, struct SpriteGroup *group, byte *train
|
||||||
void SetCustomEngineSprites(byte engine, byte cargo, struct SpriteGroup *group);
|
void SetCustomEngineSprites(byte engine, byte cargo, struct SpriteGroup *group);
|
||||||
// loaded is in percents, overriding_engine 0xffff is none
|
// loaded is in percents, overriding_engine 0xffff is none
|
||||||
int GetCustomEngineSprite(byte engine, const Vehicle *v, byte direction);
|
int GetCustomEngineSprite(byte engine, const Vehicle *v, byte direction);
|
||||||
|
uint16 GetCallBackResult(uint16 callback_info, byte engine, const Vehicle *v);
|
||||||
#define GetCustomVehicleSprite(v, direction) GetCustomEngineSprite(v->engine_type, v, direction)
|
#define GetCustomVehicleSprite(v, direction) GetCustomEngineSprite(v->engine_type, v, direction)
|
||||||
#define GetCustomVehicleIcon(et, direction) GetCustomEngineSprite(et, NULL, direction)
|
#define GetCustomVehicleIcon(et, direction) GetCustomEngineSprite(et, NULL, direction)
|
||||||
|
|
||||||
|
|
42
newgrf.c
42
newgrf.c
|
@ -1080,6 +1080,28 @@ ignoring:
|
||||||
|
|
||||||
#undef FOR_EACH_OBJECT
|
#undef FOR_EACH_OBJECT
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a spritegroup representing a callback result
|
||||||
|
* @param value The value that was used to represent this callback result
|
||||||
|
* @return A spritegroup representing that callback result
|
||||||
|
*/
|
||||||
|
SpriteGroup NewCallBackResult(uint16 value)
|
||||||
|
{
|
||||||
|
SpriteGroup group;
|
||||||
|
|
||||||
|
group.type = SGT_CALLBACK;
|
||||||
|
|
||||||
|
// Old style callback results have the highest byte 0xFF so signify it is a callback result
|
||||||
|
// New style ones only have the highest bit set (allows 15-bit results, instead of just 8)
|
||||||
|
if ((value >> 8) == 0xFF)
|
||||||
|
value &= 0xFF;
|
||||||
|
else
|
||||||
|
value &= ~0x8000;
|
||||||
|
|
||||||
|
group.g.callback.result = value;
|
||||||
|
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
/* Action 0x01 */
|
/* Action 0x01 */
|
||||||
static void NewSpriteSet(byte *buf, int len)
|
static void NewSpriteSet(byte *buf, int len)
|
||||||
|
@ -1183,36 +1205,42 @@ static void NewSpriteGroup(byte *buf, int len)
|
||||||
dg->divmod_val = grf_load_byte(&buf);
|
dg->divmod_val = grf_load_byte(&buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (groupid & 0x8000) means this is callback result; we happily
|
/* (groupid & 0x8000) means this is callback result. */
|
||||||
* ignore that for now. */
|
|
||||||
|
|
||||||
dg->num_ranges = grf_load_byte(&buf);
|
dg->num_ranges = grf_load_byte(&buf);
|
||||||
dg->ranges = calloc(dg->num_ranges, sizeof(*dg->ranges));
|
dg->ranges = calloc(dg->num_ranges, sizeof(*dg->ranges));
|
||||||
for (i = 0; i < dg->num_ranges; i++) {
|
for (i = 0; i < dg->num_ranges; i++) {
|
||||||
groupid = grf_load_word(&buf);
|
groupid = grf_load_word(&buf);
|
||||||
if (groupid & 0x8000 || groupid >= _cur_grffile->spritegroups_count) {
|
if (groupid & 0x8000) {
|
||||||
|
dg->ranges[i].group = NewCallBackResult(groupid);
|
||||||
|
} else if (groupid >= _cur_grffile->spritegroups_count) {
|
||||||
/* This doesn't exist for us. */
|
/* This doesn't exist for us. */
|
||||||
grf_load_word(&buf); // skip range
|
grf_load_word(&buf); // skip range
|
||||||
i--; dg->num_ranges--;
|
i--; dg->num_ranges--;
|
||||||
continue;
|
continue;
|
||||||
}
|
} else {
|
||||||
/* XXX: If multiple surreal sets attach a surreal
|
/* XXX: If multiple surreal sets attach a surreal
|
||||||
* set this way, we are in trouble. */
|
* set this way, we are in trouble. */
|
||||||
dg->ranges[i].group = _cur_grffile->spritegroups[groupid];
|
dg->ranges[i].group = _cur_grffile->spritegroups[groupid];
|
||||||
|
}
|
||||||
|
|
||||||
dg->ranges[i].low = grf_load_byte(&buf);
|
dg->ranges[i].low = grf_load_byte(&buf);
|
||||||
dg->ranges[i].high = grf_load_byte(&buf);
|
dg->ranges[i].high = grf_load_byte(&buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
groupid = grf_load_word(&buf);
|
groupid = grf_load_word(&buf);
|
||||||
if (groupid & 0x8000 || groupid >= _cur_grffile->spritegroups_count) {
|
if (groupid & 0x8000) {
|
||||||
|
dg->default_group = malloc(sizeof(*dg->default_group));
|
||||||
|
*dg->default_group = NewCallBackResult(groupid);
|
||||||
|
} else if (groupid >= _cur_grffile->spritegroups_count) {
|
||||||
/* This spritegroup stinks. */
|
/* This spritegroup stinks. */
|
||||||
free(dg->ranges), dg->ranges = NULL;
|
free(dg->ranges), dg->ranges = NULL;
|
||||||
grfmsg(GMS_WARN, "NewSpriteGroup(%02x:0x%x): Default groupid %04x is cargo callback or unknown, ignoring spritegroup.", setid, numloaded, groupid);
|
grfmsg(GMS_WARN, "NewSpriteGroup(%02x:0x%x): Default groupid %04x is cargo callback or unknown, ignoring spritegroup.", setid, numloaded, groupid);
|
||||||
return;
|
return;
|
||||||
}
|
} else {
|
||||||
|
|
||||||
dg->default_group = malloc(sizeof(*dg->default_group));
|
dg->default_group = malloc(sizeof(*dg->default_group));
|
||||||
memcpy(dg->default_group, &_cur_grffile->spritegroups[groupid], sizeof(*dg->default_group));
|
memcpy(dg->default_group, &_cur_grffile->spritegroups[groupid], sizeof(*dg->default_group));
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
6
sprite.h
6
sprite.h
|
@ -107,10 +107,15 @@ typedef struct RandomizedSpriteGroup {
|
||||||
SpriteGroup *groups;
|
SpriteGroup *groups;
|
||||||
} RandomizedSpriteGroup;
|
} RandomizedSpriteGroup;
|
||||||
|
|
||||||
|
typedef struct CallbackResultSpriteGroup {
|
||||||
|
uint16 result;
|
||||||
|
} CallbackResultSpriteGroup;
|
||||||
|
|
||||||
typedef enum SpriteGroupType {
|
typedef enum SpriteGroupType {
|
||||||
SGT_REAL,
|
SGT_REAL,
|
||||||
SGT_DETERMINISTIC,
|
SGT_DETERMINISTIC,
|
||||||
SGT_RANDOMIZED,
|
SGT_RANDOMIZED,
|
||||||
|
SGT_CALLBACK,
|
||||||
} SpriteGroupType;
|
} SpriteGroupType;
|
||||||
|
|
||||||
struct SpriteGroup {
|
struct SpriteGroup {
|
||||||
|
@ -120,6 +125,7 @@ struct SpriteGroup {
|
||||||
RealSpriteGroup real;
|
RealSpriteGroup real;
|
||||||
DeterministicSpriteGroup determ;
|
DeterministicSpriteGroup determ;
|
||||||
RandomizedSpriteGroup random;
|
RandomizedSpriteGroup random;
|
||||||
|
CallbackResultSpriteGroup callback;
|
||||||
} g;
|
} g;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
22
train_cmd.c
22
train_cmd.c
|
@ -1318,10 +1318,6 @@ int32 CmdRefitRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
|
||||||
cost = 0;
|
cost = 0;
|
||||||
num = 0;
|
num = 0;
|
||||||
|
|
||||||
// newgrf stuff can change graphics when refitting
|
|
||||||
if (!(flags & DC_EXEC))
|
|
||||||
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
/* XXX: We also refit all the attached wagons en-masse if they
|
/* XXX: We also refit all the attached wagons en-masse if they
|
||||||
* can be refitted. This is how TTDPatch does it. TODO: Have
|
* can be refitted. This is how TTDPatch does it. TODO: Have
|
||||||
|
@ -1330,19 +1326,29 @@ int32 CmdRefitRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
|
||||||
|
|
||||||
if (v->cargo_cap != 0) {
|
if (v->cargo_cap != 0) {
|
||||||
RailVehicleInfo *rvi = RailVehInfo(v->engine_type);
|
RailVehicleInfo *rvi = RailVehInfo(v->engine_type);
|
||||||
uint16 amount = rvi->capacity;
|
uint16 amount;
|
||||||
CargoID old_cid = rvi->cargo_type;
|
CargoID temp_cid = v->cargo_type;
|
||||||
|
|
||||||
/* the capacity depends on the cargo type, a rail vehicle
|
/* Check the 'refit capacity' callback */
|
||||||
|
v->cargo_type = new_cid;
|
||||||
|
amount = GetCallBackResult(CB_REFIT_CAP, v->engine_type, v);
|
||||||
|
v->cargo_type = temp_cid;
|
||||||
|
|
||||||
|
if (amount == CALLBACK_FAILED) { // callback failed, use default
|
||||||
|
CargoID old_cid = rvi->cargo_type;
|
||||||
|
/* normally, the capacity depends on the cargo type, a rail vehicle
|
||||||
* can carry twice as much mail/goods as normal cargo,
|
* can carry twice as much mail/goods as normal cargo,
|
||||||
* and four times as much passengers */
|
* and four times as much passengers */
|
||||||
|
amount = rvi->capacity;
|
||||||
(old_cid == CT_PASSENGERS) ||
|
(old_cid == CT_PASSENGERS) ||
|
||||||
(amount <<= 1, old_cid == CT_MAIL || old_cid == CT_GOODS) ||
|
(amount <<= 1, old_cid == CT_MAIL || old_cid == CT_GOODS) ||
|
||||||
(amount <<= 1, true);
|
(amount <<= 1, true);
|
||||||
(new_cid == CT_PASSENGERS) ||
|
(new_cid == CT_PASSENGERS) ||
|
||||||
(amount >>= 1, new_cid == CT_MAIL || new_cid == CT_GOODS) ||
|
(amount >>= 1, new_cid == CT_MAIL || new_cid == CT_GOODS) ||
|
||||||
(amount >>= 1, true);
|
(amount >>= 1, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (amount != 0) {
|
||||||
if (new_cid != v->cargo_type)
|
if (new_cid != v->cargo_type)
|
||||||
cost += (_price.build_railvehicle >> 8);
|
cost += (_price.build_railvehicle >> 8);
|
||||||
num += amount;
|
num += amount;
|
||||||
|
@ -1354,6 +1360,8 @@ int32 CmdRefitRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
|
||||||
v->cargo_type = new_cid;
|
v->cargo_type = new_cid;
|
||||||
v->cargo_cap = amount;
|
v->cargo_cap = amount;
|
||||||
InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
|
InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
|
||||||
|
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// SkipStoppedInDepotCheck is called by CmdReplace and it should only apply to the single car it is called for
|
// SkipStoppedInDepotCheck is called by CmdReplace and it should only apply to the single car it is called for
|
||||||
|
|
Loading…
Reference in New Issue