2005-07-24 14:12:37 +00:00
|
|
|
/* $Id$ */
|
|
|
|
|
2004-11-14 20:53:34 +00:00
|
|
|
#include "stdafx.h"
|
2005-06-02 19:30:21 +00:00
|
|
|
#include "openttd.h"
|
2004-11-14 20:53:34 +00:00
|
|
|
#include "sprite.h"
|
2005-07-21 18:44:27 +00:00
|
|
|
#include "variables.h"
|
2005-10-04 21:42:00 +00:00
|
|
|
#include "debug.h"
|
2004-11-14 20:53:34 +00:00
|
|
|
|
|
|
|
|
2005-07-30 18:04:49 +00:00
|
|
|
SpriteGroup *EvalDeterministicSpriteGroup(const DeterministicSpriteGroup *dsg, int value)
|
2004-11-14 20:53:34 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
value >>= dsg->shift_num; // This should bring us to the byte range.
|
|
|
|
value &= dsg->and_mask;
|
|
|
|
|
|
|
|
if (dsg->operation != DSG_OP_NONE)
|
|
|
|
value += (signed char) dsg->add_val;
|
|
|
|
|
|
|
|
switch (dsg->operation) {
|
|
|
|
case DSG_OP_DIV:
|
|
|
|
value /= (signed char) dsg->divmod_val;
|
|
|
|
break;
|
|
|
|
case DSG_OP_MOD:
|
|
|
|
value %= (signed char) dsg->divmod_val;
|
|
|
|
break;
|
|
|
|
case DSG_OP_NONE:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < dsg->num_ranges; i++) {
|
2005-03-10 07:01:43 +00:00
|
|
|
DeterministicSpriteGroupRange *range = &dsg->ranges[i];
|
2004-11-14 20:53:34 +00:00
|
|
|
|
|
|
|
if (range->low <= value && value <= range->high)
|
2005-10-04 19:52:26 +00:00
|
|
|
return range->group;
|
2004-11-14 20:53:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return dsg->default_group;
|
|
|
|
}
|
|
|
|
|
|
|
|
int GetDeterministicSpriteValue(byte var)
|
|
|
|
{
|
|
|
|
switch (var) {
|
|
|
|
case 0x00:
|
|
|
|
return _date;
|
|
|
|
case 0x01:
|
|
|
|
return _cur_year;
|
|
|
|
case 0x02:
|
|
|
|
return _cur_month;
|
|
|
|
case 0x03:
|
|
|
|
return _opt.landscape;
|
|
|
|
case 0x09:
|
|
|
|
return _date_fract;
|
|
|
|
case 0x0A:
|
|
|
|
return _tick_counter;
|
|
|
|
case 0x0C:
|
|
|
|
/* If we got here, it means there was no callback or
|
|
|
|
* callbacks aren't supported on our callpath. */
|
|
|
|
return 0;
|
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
2004-11-17 08:52:47 +00:00
|
|
|
|
2005-07-30 18:04:49 +00:00
|
|
|
SpriteGroup *EvalRandomizedSpriteGroup(const RandomizedSpriteGroup *rsg, byte random_bits)
|
2004-11-17 08:52:47 +00:00
|
|
|
{
|
|
|
|
byte mask;
|
|
|
|
byte index;
|
|
|
|
|
|
|
|
/* Noone likes mangling with bits, but you don't get around it here.
|
|
|
|
* Sorry. --pasky */
|
|
|
|
// rsg->num_groups is always power of 2
|
|
|
|
mask = (rsg->num_groups - 1) << rsg->lowest_randbit;
|
|
|
|
index = (random_bits & mask) >> rsg->lowest_randbit;
|
|
|
|
assert(index < rsg->num_groups);
|
2005-10-04 19:52:26 +00:00
|
|
|
return rsg->groups[index];
|
2004-11-17 08:52:47 +00:00
|
|
|
}
|
|
|
|
|
2005-07-30 18:04:49 +00:00
|
|
|
byte RandomizedSpriteGroupTriggeredBits(const RandomizedSpriteGroup *rsg,
|
2005-03-10 07:01:43 +00:00
|
|
|
byte triggers, byte *waiting_triggers)
|
2004-11-17 08:52:47 +00:00
|
|
|
{
|
|
|
|
byte match = rsg->triggers & (*waiting_triggers | triggers);
|
|
|
|
bool res;
|
|
|
|
|
|
|
|
if (rsg->cmp_mode == RSG_CMP_ANY) {
|
|
|
|
res = (match != 0);
|
|
|
|
} else { /* RSG_CMP_ALL */
|
|
|
|
res = (match == rsg->triggers);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!res) {
|
|
|
|
*waiting_triggers |= triggers;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
*waiting_triggers &= ~match;
|
|
|
|
|
|
|
|
return (rsg->num_groups - 1) << rsg->lowest_randbit;
|
|
|
|
}
|
2005-10-04 21:42:00 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Traverse a sprite group and release its and its child's memory.
|
|
|
|
* A group is only released if its reference count is zero.
|
|
|
|
* We pass a pointer to a pointer so that the original reference can be set to NULL.
|
|
|
|
* @param group_ptr Pointer to sprite group reference.
|
|
|
|
*/
|
|
|
|
void UnloadSpriteGroup(SpriteGroup **group_ptr)
|
|
|
|
{
|
|
|
|
SpriteGroup *group;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
assert(group_ptr != NULL);
|
|
|
|
assert(*group_ptr != NULL);
|
|
|
|
|
|
|
|
group = *group_ptr;
|
|
|
|
*group_ptr = NULL; // Remove this reference.
|
|
|
|
|
|
|
|
group->ref_count--;
|
|
|
|
if (group->ref_count > 0) {
|
|
|
|
DEBUG(grf, 6)("UnloadSpriteGroup: Group at `%p' (type %d) has %d reference(s) left.", group, group->type, group->ref_count);
|
|
|
|
return; // Still some references left, so don't clear up.
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUG(grf, 6)("UnloadSpriteGroup: Releasing group at `%p'.", group);
|
|
|
|
switch (group->type) {
|
|
|
|
case SGT_REAL:
|
|
|
|
{
|
|
|
|
RealSpriteGroup *rsg = &group->g.real;
|
|
|
|
for (i = 0; i < rsg->loading_count; i++) {
|
2005-10-14 20:10:12 +00:00
|
|
|
if (rsg->loading[i] != NULL) UnloadSpriteGroup(&rsg->loading[i]);
|
2005-10-04 21:42:00 +00:00
|
|
|
}
|
|
|
|
for (i = 0; i < rsg->loaded_count; i++) {
|
2005-10-14 20:10:12 +00:00
|
|
|
if (rsg->loaded[i] != NULL) UnloadSpriteGroup(&rsg->loaded[i]);
|
2005-10-04 21:42:00 +00:00
|
|
|
}
|
|
|
|
free(group);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
case SGT_DETERMINISTIC:
|
|
|
|
{
|
|
|
|
DeterministicSpriteGroup *dsg = &group->g.determ;
|
|
|
|
for (i = 0; i < group->g.determ.num_ranges; i++) {
|
2005-10-14 20:10:12 +00:00
|
|
|
if (dsg->ranges[i].group != NULL) UnloadSpriteGroup(&dsg->ranges[i].group);
|
2005-10-04 21:42:00 +00:00
|
|
|
}
|
2005-10-14 20:10:12 +00:00
|
|
|
if (dsg->default_group != NULL) UnloadSpriteGroup(&dsg->default_group);
|
2005-10-04 21:42:00 +00:00
|
|
|
free(group->g.determ.ranges);
|
|
|
|
free(group);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
case SGT_RANDOMIZED:
|
|
|
|
{
|
|
|
|
for (i = 0; i < group->g.random.num_groups; i++) {
|
2005-10-14 20:10:12 +00:00
|
|
|
if (group->g.random.groups[i] != NULL) UnloadSpriteGroup(&group->g.random.groups[i]);
|
2005-10-04 21:42:00 +00:00
|
|
|
}
|
|
|
|
free(group->g.random.groups);
|
|
|
|
free(group);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
case SGT_CALLBACK:
|
|
|
|
case SGT_RESULT:
|
|
|
|
free(group);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUG(grf, 1)("Unable to remove unknown sprite group type `0x%x'.", group->type);
|
|
|
|
}
|