OpenTTD
newgrf_object.cpp
Go to the documentation of this file.
1 /* $Id: newgrf_object.cpp 26482 2014-04-23 20:13:33Z rubidium $ */
2 
3 /*
4  * This file is part of OpenTTD.
5  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8  */
9 
12 #include "stdafx.h"
13 #include "company_base.h"
14 #include "company_func.h"
15 #include "debug.h"
16 #include "genworld.h"
17 #include "newgrf_class_func.h"
18 #include "newgrf_object.h"
19 #include "newgrf_sound.h"
20 #include "object_base.h"
21 #include "object_map.h"
22 #include "tile_cmd.h"
23 #include "town.h"
24 #include "water.h"
25 #include "newgrf_animation_base.h"
26 
27 #include "safeguards.h"
28 
31 
32 extern const ObjectSpec _original_objects[NEW_OBJECT_OFFSET];
35 
41 /* static */ const ObjectSpec *ObjectSpec::Get(ObjectType index)
42 {
43  assert(index < NUM_OBJECTS);
44  return &_object_specs[index];
45 }
46 
52 /* static */ const ObjectSpec *ObjectSpec::GetByTile(TileIndex tile)
53 {
54  return ObjectSpec::Get(GetObjectType(tile));
55 }
56 
62 {
63  return this->enabled && HasBit(this->climate, _settings_game.game_creation.landscape) &&
64  (this->flags & ((_game_mode != GM_EDITOR && !_generating_world) ? OBJECT_FLAG_ONLY_IN_SCENEDIT : OBJECT_FLAG_ONLY_IN_GAME)) == 0;
65 }
66 
72 {
73  return this->IsEverAvailable() && _date > this->introduction_date;
74 }
75 
81 {
82  return this->WasEverAvailable() &&
83  (_date < this->end_of_life_date || this->end_of_life_date < this->introduction_date + 365);
84 }
85 
90 uint ObjectSpec::Index() const
91 {
92  return this - _object_specs;
93 }
94 
97 {
98  /* Clean the pool. */
99  MemSetT(_object_specs, 0, lengthof(_object_specs));
100 
101  /* And add our originals. */
102  MemCpyT(_object_specs, _original_objects, lengthof(_original_objects));
103 
104  for (uint16 i = 0; i < lengthof(_original_objects); i++) {
105  _object_specs[i].grf_prop.local_id = i;
106  }
107 }
108 
109 template <typename Tspec, typename Tid, Tid Tmax>
111 {
112  ObjectClassID cls = ObjectClass::Allocate('LTHS');
113  ObjectClass::Get(cls)->name = STR_OBJECT_CLASS_LTHS;
114  _object_specs[OBJECT_LIGHTHOUSE].cls_id = cls;
115  ObjectClass::Assign(&_object_specs[OBJECT_LIGHTHOUSE]);
116 
117  cls = ObjectClass::Allocate('TRNS');
118  ObjectClass::Get(cls)->name = STR_OBJECT_CLASS_TRNS;
119  _object_specs[OBJECT_TRANSMITTER].cls_id = cls;
120  ObjectClass::Assign(&_object_specs[OBJECT_TRANSMITTER]);
121 }
122 
123 template <typename Tspec, typename Tid, Tid Tmax>
125 {
126  return this->GetSpec(index)->IsEverAvailable();
127 }
128 
130 
131 
139  : ScopeResolver(ro)
140 {
141  this->obj = obj;
142  this->tile = tile;
143  this->view = view;
144 }
145 
146 /* virtual */ uint32 ObjectScopeResolver::GetRandomBits() const
147 {
148  return IsValidTile(this->tile) && IsTileType(this->tile, MP_OBJECT) ? GetObjectRandomBits(this->tile) : 0;
149 }
150 
157 static uint32 GetObjectIDAtOffset(TileIndex tile, uint32 cur_grfid)
158 {
159  if (!IsTileType(tile, MP_OBJECT)) {
160  return 0xFFFF;
161  }
162 
163  const Object *o = Object::GetByTile(tile);
164  const ObjectSpec *spec = ObjectSpec::Get(o->type);
165 
166  /* Default objects have no associated NewGRF file */
167  if (spec->grf_prop.grffile == NULL) {
168  return 0xFFFE; // Defined in another grf file
169  }
170 
171  if (spec->grf_prop.grffile->grfid == cur_grfid) { // same object, same grf ?
172  return spec->grf_prop.local_id | o->view << 16;
173  }
174 
175  return 0xFFFE; // Defined in another grf file
176 }
177 
186 static uint32 GetNearbyObjectTileInformation(byte parameter, TileIndex tile, ObjectID index, bool grf_version8)
187 {
188  if (parameter != 0) tile = GetNearbyTile(parameter, tile); // only perform if it is required
189  bool is_same_object = (IsTileType(tile, MP_OBJECT) && GetObjectIndex(tile) == index);
190 
191  return GetNearbyTileInformation(tile, grf_version8) | (is_same_object ? 1 : 0) << 8;
192 }
193 
201 static uint32 GetClosestObject(TileIndex tile, ObjectType type, const Object *current)
202 {
203  uint32 best_dist = UINT32_MAX;
204  const Object *o;
205  FOR_ALL_OBJECTS(o) {
206  if (o->type != type || o == current) continue;
207 
208  best_dist = min(best_dist, DistanceManhattan(tile, o->location.tile));
209  }
210 
211  return best_dist;
212 }
213 
222 static uint32 GetCountAndDistanceOfClosestInstance(byte local_id, uint32 grfid, TileIndex tile, const Object *current)
223 {
224  uint32 grf_id = GetRegister(0x100); // Get the GRFID of the definition to look for in register 100h
225  uint32 idx;
226 
227  /* Determine what will be the object type to look for */
228  switch (grf_id) {
229  case 0: // this is a default object type
230  idx = local_id;
231  break;
232 
233  case 0xFFFFFFFF: // current grf
234  grf_id = grfid;
235  /* FALL THROUGH */
236 
237  default: // use the grfid specified in register 100h
238  idx = _object_mngr.GetID(local_id, grf_id);
239  break;
240  }
241 
242  /* If the object type is invalid, there is none and the closest is far away. */
243  if (idx >= NUM_OBJECTS) return 0 | 0xFFFF;
244 
245  return Object::GetTypeCount(idx) << 16 | min(GetClosestObject(tile, idx, current), 0xFFFF);
246 }
247 
249 /* virtual */ uint32 ObjectScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const
250 {
251  /* We get the town from the object, or we calculate the closest
252  * town if we need to when there's no object. */
253  const Town *t = NULL;
254 
255  if (this->obj == NULL) {
256  switch (variable) {
257  /* Allow these when there's no object. */
258  case 0x41:
259  case 0x60:
260  case 0x61:
261  case 0x62:
262  case 0x64:
263  break;
264 
265  /* Allow these, but find the closest town. */
266  case 0x45:
267  case 0x46:
268  if (!IsValidTile(this->tile)) goto unhandled;
269  t = ClosestTownFromTile(this->tile, UINT_MAX);
270  break;
271 
272  /* Construction date */
273  case 0x42: return _date;
274 
275  /* Object founder information */
276  case 0x44: return _current_company;
277 
278  /* Object view */
279  case 0x48: return this->view;
280 
281  /*
282  * Disallow the rest:
283  * 0x40: Relative position is passed as parameter during construction.
284  * 0x43: Animation counter is only for actual tiles.
285  * 0x47: Object colour is only valid when its built.
286  * 0x63: Animation counter of nearby tile, see above.
287  */
288  default:
289  goto unhandled;
290  }
291 
292  /* If there's an invalid tile, then we don't have enough information at all. */
293  if (!IsValidTile(this->tile)) goto unhandled;
294  } else {
295  t = this->obj->town;
296  }
297 
298  switch (variable) {
299  /* Relative position. */
300  case 0x40: {
301  uint offset = this->tile - this->obj->location.tile;
302  uint offset_x = TileX(offset);
303  uint offset_y = TileY(offset);
304  return offset_y << 20 | offset_x << 16 | offset_y << 8 | offset_x;
305  }
306 
307  /* Tile information. */
308  case 0x41: return GetTileSlope(this->tile) << 8 | GetTerrainType(this->tile);
309 
310  /* Construction date */
311  case 0x42: return this->obj->build_date;
312 
313  /* Animation counter */
314  case 0x43: return GetAnimationFrame(this->tile);
315 
316  /* Object founder information */
317  case 0x44: return GetTileOwner(this->tile);
318 
319  /* Get town zone and Manhattan distance of closest town */
320  case 0x45: return GetTownRadiusGroup(t, this->tile) << 16 | min(DistanceManhattan(this->tile, t->xy), 0xFFFF);
321 
322  /* Get square of Euclidian distance of closes town */
323  case 0x46: return GetTownRadiusGroup(t, this->tile) << 16 | min(DistanceSquare(this->tile, t->xy), 0xFFFF);
324 
325  /* Object colour */
326  case 0x47: return this->obj->colour;
327 
328  /* Object view */
329  case 0x48: return this->obj->view;
330 
331  /* Get object ID at offset param */
332  case 0x60: return GetObjectIDAtOffset(GetNearbyTile(parameter, this->tile), this->ro.grffile->grfid);
333 
334  /* Get random tile bits at offset param */
335  case 0x61: {
336  TileIndex tile = GetNearbyTile(parameter, this->tile);
337  return (IsTileType(tile, MP_OBJECT) && Object::GetByTile(tile) == this->obj) ? GetObjectRandomBits(tile) : 0;
338  }
339 
340  /* Land info of nearby tiles */
341  case 0x62: return GetNearbyObjectTileInformation(parameter, this->tile, this->obj == NULL ? INVALID_OBJECT : this->obj->index, this->ro.grffile->grf_version >= 8);
342 
343  /* Animation counter of nearby tile */
344  case 0x63: {
345  TileIndex tile = GetNearbyTile(parameter, this->tile);
346  return (IsTileType(tile, MP_OBJECT) && Object::GetByTile(tile) == this->obj) ? GetAnimationFrame(tile) : 0;
347  }
348 
349  /* Count of object, distance of closest instance */
350  case 0x64: return GetCountAndDistanceOfClosestInstance(parameter, this->ro.grffile->grfid, this->tile, this->obj);
351  }
352 
353 unhandled:
354  DEBUG(grf, 1, "Unhandled object variable 0x%X", variable);
355 
356  *available = false;
357  return UINT_MAX;
358 }
359 
370  CallbackID callback, uint32 param1, uint32 param2)
371  : ResolverObject(spec->grf_prop.grffile, callback, param1, param2), object_scope(*this, obj, tile, view)
372 {
373  this->town_scope = NULL;
374  this->root_spritegroup = (obj == NULL && spec->grf_prop.spritegroup[CT_PURCHASE_OBJECT] != NULL) ?
376 }
377 
378 ObjectResolverObject::~ObjectResolverObject()
379 {
380  delete this->town_scope;
381 }
382 
389 {
390  if (this->town_scope == NULL) {
391  Town *t;
392  if (this->object_scope.obj != NULL) {
393  t = this->object_scope.obj->town;
394  } else {
395  t = ClosestTownFromTile(this->object_scope.tile, UINT_MAX);
396  }
397  if (t == NULL) return NULL;
398  this->town_scope = new TownScopeResolver(*this, t, this->object_scope.obj == NULL);
399  }
400  return this->town_scope;
401 }
402 
414 uint16 GetObjectCallback(CallbackID callback, uint32 param1, uint32 param2, const ObjectSpec *spec, Object *o, TileIndex tile, uint8 view)
415 {
416  ObjectResolverObject object(spec, o, tile, view, callback, param1, param2);
417  return object.ResolveCallback();
418 }
419 
426 static void DrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, const ObjectSpec *spec)
427 {
428  const DrawTileSprites *dts = group->ProcessRegisters(NULL);
429  PaletteID palette = ((spec->flags & OBJECT_FLAG_2CC_COLOUR) ? SPR_2CCMAP_BASE : PALETTE_RECOLOUR_START) + Object::GetByTile(ti->tile)->colour;
430 
431  SpriteID image = dts->ground.sprite;
432  PaletteID pal = dts->ground.pal;
433 
434  if (GB(image, 0, SPRITE_WIDTH) != 0) {
435  /* If the ground sprite is the default flat water sprite, draw also canal/river borders
436  * Do not do this if the tile's WaterClass is 'land'. */
437  if ((image == SPR_FLAT_WATER_TILE || spec->flags & OBJECT_FLAG_DRAW_WATER) && IsTileOnWater(ti->tile)) {
438  DrawWaterClassGround(ti);
439  } else {
440  DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, palette));
441  }
442  }
443 
444  DrawNewGRFTileSeq(ti, dts, TO_STRUCTURES, 0, palette);
445 }
446 
452 void DrawNewObjectTile(TileInfo *ti, const ObjectSpec *spec)
453 {
454  Object *o = Object::GetByTile(ti->tile);
455  ObjectResolverObject object(spec, o, ti->tile);
456 
457  const SpriteGroup *group = object.Resolve();
458  if (group == NULL || group->type != SGT_TILELAYOUT) return;
459 
460  DrawTileLayout(ti, (const TileLayoutSpriteGroup *)group, spec);
461 }
462 
470 void DrawNewObjectTileInGUI(int x, int y, const ObjectSpec *spec, uint8 view)
471 {
472  ObjectResolverObject object(spec, NULL, INVALID_TILE, view);
473  const SpriteGroup *group = object.Resolve();
474  if (group == NULL || group->type != SGT_TILELAYOUT) return;
475 
476  const DrawTileSprites *dts = ((const TileLayoutSpriteGroup *)group)->ProcessRegisters(NULL);
477 
478  PaletteID palette;
480  /* Get the colours of our company! */
481  if (spec->flags & OBJECT_FLAG_2CC_COLOUR) {
482  const Livery *l = Company::Get(_local_company)->livery;
483  palette = SPR_2CCMAP_BASE + l->colour1 + l->colour2 * 16;
484  } else {
485  palette = COMPANY_SPRITE_COLOUR(_local_company);
486  }
487  } else {
488  /* There's no company, so just take the base palette. */
489  palette = (spec->flags & OBJECT_FLAG_2CC_COLOUR) ? SPR_2CCMAP_BASE : PALETTE_RECOLOUR_START;
490  }
491 
492  SpriteID image = dts->ground.sprite;
493  PaletteID pal = dts->ground.pal;
494 
495  if (GB(image, 0, SPRITE_WIDTH) != 0) {
496  DrawSprite(image, GroundSpritePaletteTransform(image, pal, palette), x, y);
497  }
498 
499  DrawNewGRFTileSeqInGUI(x, y, dts, 0, palette);
500 }
501 
513 uint16 StubGetObjectCallback(CallbackID callback, uint32 param1, uint32 param2, const ObjectSpec *spec, Object *o, TileIndex tile, int extra_data)
514 {
515  return GetObjectCallback(callback, param1, param2, spec, o, tile);
516 }
517 
519 struct ObjectAnimationBase : public AnimationBase<ObjectAnimationBase, ObjectSpec, Object, int, StubGetObjectCallback> {
520  static const CallbackID cb_animation_speed = CBID_OBJECT_ANIMATION_SPEED;
521  static const CallbackID cb_animation_next_frame = CBID_OBJECT_ANIMATION_NEXT_FRAME;
522 
523  static const ObjectCallbackMask cbm_animation_speed = CBM_OBJ_ANIMATION_SPEED;
524  static const ObjectCallbackMask cbm_animation_next_frame = CBM_OBJ_ANIMATION_NEXT_FRAME;
525 };
526 
532 {
533  const ObjectSpec *spec = ObjectSpec::GetByTile(tile);
534  if (spec == NULL || !(spec->flags & OBJECT_FLAG_ANIMATION)) return;
535 
537 }
538 
547 {
548  if (!HasBit(spec->animation.triggers, trigger)) return;
549 
551 }
552 
560 {
561  if (!HasBit(spec->animation.triggers, trigger)) return;
562 
563  TILE_AREA_LOOP(tile, o->location) {
564  TriggerObjectTileAnimation(o, tile, trigger, spec);
565  }
566 }