|
1 /* $Id$ */ |
|
2 |
|
3 #include "stdafx.h" |
|
4 #include "openttd.h" |
|
5 #include "variables.h" |
|
6 #include "macros.h" |
|
7 #include "oldpool.h" |
|
8 #include "newgrf_spritegroup.h" |
|
9 #include "date.h" |
|
10 |
|
11 static void SpriteGroupPoolCleanBlock(uint start_item, uint end_item); |
|
12 |
|
13 static uint _spritegroup_count = 0; |
|
14 STATIC_OLD_POOL(SpriteGroup, SpriteGroup, 9, 250, NULL, SpriteGroupPoolCleanBlock) |
|
15 |
|
16 static void DestroySpriteGroup(SpriteGroup *group) |
|
17 { |
|
18 /* Free dynamically allocated memory */ |
|
19 /* XXX Cast away the consts due to MSVC being buggy... */ |
|
20 switch (group->type) { |
|
21 case SGT_REAL: |
|
22 free((SpriteGroup**)group->g.real.loaded); |
|
23 free((SpriteGroup**)group->g.real.loading); |
|
24 break; |
|
25 |
|
26 case SGT_DETERMINISTIC: |
|
27 free(group->g.determ.adjusts); |
|
28 free(group->g.determ.ranges); |
|
29 break; |
|
30 |
|
31 case SGT_RANDOMIZED: |
|
32 free((SpriteGroup**)group->g.random.groups); |
|
33 break; |
|
34 |
|
35 default: |
|
36 break; |
|
37 } |
|
38 } |
|
39 |
|
40 static void SpriteGroupPoolCleanBlock(uint start_item, uint end_item) |
|
41 { |
|
42 uint i; |
|
43 |
|
44 for (i = start_item; i <= end_item; i++) { |
|
45 DestroySpriteGroup(GetSpriteGroup(i)); |
|
46 } |
|
47 } |
|
48 |
|
49 |
|
50 /* Allocate a new SpriteGroup */ |
|
51 SpriteGroup *AllocateSpriteGroup(void) |
|
52 { |
|
53 /* This is totally different to the other pool allocators, as we never remove an item from the pool. */ |
|
54 if (_spritegroup_count == GetSpriteGroupPoolSize()) { |
|
55 if (!AddBlockToPool(&_SpriteGroup_pool)) return NULL; |
|
56 } |
|
57 |
|
58 return GetSpriteGroup(_spritegroup_count++); |
|
59 } |
|
60 |
|
61 |
|
62 void InitializeSpriteGroupPool(void) |
|
63 { |
|
64 CleanPool(&_SpriteGroup_pool); |
|
65 |
|
66 _spritegroup_count = 0; |
|
67 } |
|
68 |
|
69 |
|
70 static inline uint32 GetVariable(const ResolverObject *object, byte variable, byte parameter, bool *available) |
|
71 { |
|
72 /* Return common variables */ |
|
73 switch (variable) { |
|
74 case 0x00: return max(_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0); |
|
75 case 0x01: return clamp(_cur_year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR; |
|
76 case 0x02: return _cur_month; |
|
77 case 0x03: return _opt.landscape; |
|
78 case 0x09: return _date_fract; |
|
79 case 0x0A: return _tick_counter; |
|
80 case 0x0C: return object->callback; |
|
81 case 0x10: return object->callback_param1; |
|
82 case 0x11: return 0; |
|
83 case 0x18: return object->callback_param2; |
|
84 case 0x1A: return -1; |
|
85 case 0x1B: return GB(_display_opt, 0, 6); |
|
86 case 0x1C: return object->last_value; |
|
87 case 0x20: return _opt.landscape == LT_HILLY ? _opt.snow_line : 0xFF; |
|
88 |
|
89 /* Not a common variable, so evalute the feature specific variables */ |
|
90 default: return object->GetVariable(object, variable, parameter, available); |
|
91 } |
|
92 } |
|
93 |
|
94 |
|
95 /* Evaluate an adjustment for a variable of the given size. This is a bit of |
|
96 * an unwieldy macro, but it saves triplicating the code. */ |
|
97 #define BUILD_EVAL_ADJUST(size, usize) \ |
|
98 static inline usize EvalAdjust_ ## size(const DeterministicSpriteGroupAdjust *adjust, usize last_value, int32 value) \ |
|
99 { \ |
|
100 value >>= adjust->shift_num; \ |
|
101 value &= adjust->and_mask; \ |
|
102 \ |
|
103 if (adjust->type != DSGA_TYPE_NONE) value += (size)adjust->add_val; \ |
|
104 \ |
|
105 switch (adjust->type) { \ |
|
106 case DSGA_TYPE_DIV: value /= (size)adjust->divmod_val; break; \ |
|
107 case DSGA_TYPE_MOD: value %= (usize)adjust->divmod_val; break; \ |
|
108 case DSGA_TYPE_NONE: break; \ |
|
109 } \ |
|
110 \ |
|
111 /* Get our value to the correct range */ \ |
|
112 value = (usize)value; \ |
|
113 \ |
|
114 switch (adjust->operation) { \ |
|
115 case DSGA_OP_ADD: return last_value + value; \ |
|
116 case DSGA_OP_SUB: return last_value - value; \ |
|
117 case DSGA_OP_SMIN: return min(last_value, value); \ |
|
118 case DSGA_OP_SMAX: return max(last_value, value); \ |
|
119 case DSGA_OP_UMIN: return min((usize)last_value, (usize)value); \ |
|
120 case DSGA_OP_UMAX: return max((usize)last_value, (usize)value); \ |
|
121 case DSGA_OP_SDIV: return last_value / value; \ |
|
122 case DSGA_OP_SMOD: return last_value % value; \ |
|
123 case DSGA_OP_UDIV: return (usize)last_value / (usize)value; \ |
|
124 case DSGA_OP_UMOD: return (usize)last_value % (usize)value; \ |
|
125 case DSGA_OP_MUL: return last_value * value; \ |
|
126 case DSGA_OP_AND: return last_value & value; \ |
|
127 case DSGA_OP_OR: return last_value | value; \ |
|
128 case DSGA_OP_XOR: return last_value ^ value; \ |
|
129 default: return value; \ |
|
130 } \ |
|
131 } |
|
132 |
|
133 |
|
134 BUILD_EVAL_ADJUST(int8, uint8) |
|
135 BUILD_EVAL_ADJUST(int16, uint16) |
|
136 BUILD_EVAL_ADJUST(int32, uint32) |
|
137 |
|
138 |
|
139 static inline const SpriteGroup *ResolveVariable(const SpriteGroup *group, ResolverObject *object) |
|
140 { |
|
141 static SpriteGroup nvarzero; |
|
142 int32 last_value = object->last_value; |
|
143 int32 value = -1; |
|
144 uint i; |
|
145 |
|
146 object->scope = group->g.determ.var_scope; |
|
147 |
|
148 for (i = 0; i < group->g.determ.num_adjusts; i++) { |
|
149 DeterministicSpriteGroupAdjust *adjust = &group->g.determ.adjusts[i]; |
|
150 |
|
151 /* Try to get the variable. We shall assume it is available, unless told otherwise. */ |
|
152 bool available = true; |
|
153 value = GetVariable(object, adjust->variable, adjust->parameter, &available); |
|
154 |
|
155 if (!available) { |
|
156 /* Unsupported property: skip further processing and return either |
|
157 * the group from the first range or the default group. */ |
|
158 return Resolve(group->g.determ.num_ranges > 0 ? group->g.determ.ranges[0].group : group->g.determ.default_group, object); |
|
159 } |
|
160 |
|
161 switch (group->g.determ.size) { |
|
162 case DSG_SIZE_BYTE: value = EvalAdjust_int8(adjust, last_value, value); break; |
|
163 case DSG_SIZE_WORD: value = EvalAdjust_int16(adjust, last_value, value); break; |
|
164 case DSG_SIZE_DWORD: value = EvalAdjust_int32(adjust, last_value, value); break; |
|
165 default: NOT_REACHED(); break; |
|
166 } |
|
167 last_value = value; |
|
168 } |
|
169 |
|
170 if (group->g.determ.num_ranges == 0) { |
|
171 /* nvar == 0 is a special case -- we turn our value into a callback result */ |
|
172 nvarzero.type = SGT_CALLBACK; |
|
173 nvarzero.g.callback.result = GB(value, 0, 15); |
|
174 return &nvarzero; |
|
175 } |
|
176 |
|
177 for (i = 0; i < group->g.determ.num_ranges; i++) { |
|
178 if (group->g.determ.ranges[i].low <= (uint32)value && (uint32)value <= group->g.determ.ranges[i].high) { |
|
179 return Resolve(group->g.determ.ranges[i].group, object); |
|
180 } |
|
181 } |
|
182 |
|
183 return Resolve(group->g.determ.default_group, object); |
|
184 } |
|
185 |
|
186 |
|
187 static inline const SpriteGroup *ResolveRandom(const SpriteGroup *group, ResolverObject *object) |
|
188 { |
|
189 uint32 mask; |
|
190 byte index; |
|
191 |
|
192 object->scope = group->g.random.var_scope; |
|
193 |
|
194 if (object->trigger != 0) { |
|
195 /* Handle triggers */ |
|
196 /* Magic code that may or may not do the right things... */ |
|
197 byte waiting_triggers = object->GetTriggers(object); |
|
198 byte match = group->g.random.triggers & (waiting_triggers | object->trigger); |
|
199 bool res; |
|
200 |
|
201 res = (group->g.random.cmp_mode == RSG_CMP_ANY) ? |
|
202 (match != 0) : (match == group->g.random.triggers); |
|
203 |
|
204 if (res) { |
|
205 waiting_triggers &= ~match; |
|
206 object->reseed |= (group->g.random.num_groups - 1) << group->g.random.lowest_randbit; |
|
207 } else { |
|
208 waiting_triggers |= object->trigger; |
|
209 } |
|
210 |
|
211 object->SetTriggers(object, waiting_triggers); |
|
212 } |
|
213 |
|
214 mask = (group->g.random.num_groups - 1) << group->g.random.lowest_randbit; |
|
215 index = (object->GetRandomBits(object) & mask) >> group->g.random.lowest_randbit; |
|
216 |
|
217 return Resolve(group->g.random.groups[index], object); |
|
218 } |
|
219 |
|
220 |
|
221 /* ResolverObject (re)entry point */ |
|
222 const SpriteGroup *Resolve(const SpriteGroup *group, ResolverObject *object) |
|
223 { |
|
224 /* We're called even if there is no group, so quietly return nothing */ |
|
225 if (group == NULL) return NULL; |
|
226 |
|
227 switch (group->type) { |
|
228 case SGT_REAL: return object->ResolveReal(object, group); |
|
229 case SGT_DETERMINISTIC: return ResolveVariable(group, object); |
|
230 case SGT_RANDOMIZED: return ResolveRandom(group, object); |
|
231 default: return group; |
|
232 } |
|
233 } |