169 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			169 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* $Id$ */
 | |
| 
 | |
| #include "stdafx.h"
 | |
| #include "openttd.h"
 | |
| #include "sprite.h"
 | |
| #include "variables.h"
 | |
| #include "debug.h"
 | |
| 
 | |
| 
 | |
| SpriteGroup *EvalDeterministicSpriteGroup(const DeterministicSpriteGroup *dsg, int value)
 | |
| {
 | |
| 	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++) {
 | |
| 		DeterministicSpriteGroupRange *range = &dsg->ranges[i];
 | |
| 
 | |
| 		if (range->low <= value && value <= range->high)
 | |
| 			return range->group;
 | |
| 	}
 | |
| 
 | |
| 	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;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| SpriteGroup *EvalRandomizedSpriteGroup(const RandomizedSpriteGroup *rsg, byte random_bits)
 | |
| {
 | |
| 	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);
 | |
| 	return rsg->groups[index];
 | |
| }
 | |
| 
 | |
| byte RandomizedSpriteGroupTriggeredBits(const RandomizedSpriteGroup *rsg,
 | |
| 	byte triggers, byte *waiting_triggers)
 | |
| {
 | |
| 	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;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * 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++) {
 | |
| 				if (rsg->loading[i] != NULL) UnloadSpriteGroup(&rsg->loading[i]);
 | |
| 			}
 | |
| 			for (i = 0; i < rsg->loaded_count; i++) {
 | |
| 				if (rsg->loaded[i] != NULL) UnloadSpriteGroup(&rsg->loaded[i]);
 | |
| 			}
 | |
| 			free(group);
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		case SGT_DETERMINISTIC:
 | |
| 		{
 | |
| 			DeterministicSpriteGroup *dsg = &group->g.determ;
 | |
| 			for (i = 0; i < group->g.determ.num_ranges; i++) {
 | |
| 				if (dsg->ranges[i].group != NULL) UnloadSpriteGroup(&dsg->ranges[i].group);
 | |
| 			}
 | |
| 			if (dsg->default_group != NULL) UnloadSpriteGroup(&dsg->default_group);
 | |
| 			free(group->g.determ.ranges);
 | |
| 			free(group);
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		case SGT_RANDOMIZED:
 | |
| 		{
 | |
| 			for (i = 0; i < group->g.random.num_groups; i++) {
 | |
| 				if (group->g.random.groups[i] != NULL) UnloadSpriteGroup(&group->g.random.groups[i]);
 | |
| 			}
 | |
| 			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);
 | |
| }
 | 
