00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "company_base.h"
00014 #include "company_func.h"
00015 #include "debug.h"
00016 #include "newgrf_class_func.h"
00017 #include "newgrf_object.h"
00018 #include "newgrf_sound.h"
00019 #include "object_base.h"
00020 #include "object_map.h"
00021 #include "tile_cmd.h"
00022 #include "town.h"
00023 #include "water.h"
00024 #include "newgrf_animation_base.h"
00025
00027 ObjectOverrideManager _object_mngr(NEW_OBJECT_OFFSET, NUM_OBJECTS, INVALID_OBJECT_TYPE);
00028
00029 extern const ObjectSpec _original_objects[NEW_OBJECT_OFFSET];
00031 ObjectSpec _object_specs[NUM_OBJECTS];
00032
00038 const ObjectSpec *ObjectSpec::Get(ObjectType index)
00039 {
00040 assert(index < NUM_OBJECTS);
00041 return &_object_specs[index];
00042 }
00043
00049 const ObjectSpec *ObjectSpec::GetByTile(TileIndex tile)
00050 {
00051 return ObjectSpec::Get(GetObjectType(tile));
00052 }
00053
00058 bool ObjectSpec::IsEverAvailable() const
00059 {
00060 return this->enabled && HasBit(this->climate, _settings_game.game_creation.landscape) &&
00061 (this->flags & (_game_mode != GM_EDITOR ? OBJECT_FLAG_ONLY_IN_SCENEDIT : OBJECT_FLAG_ONLY_IN_GAME)) == 0;
00062 }
00063
00068 bool ObjectSpec::IsAvailable() const
00069 {
00070 return this->IsEverAvailable() && _date > this->introduction_date &&
00071 (_date < this->end_of_life_date || this->end_of_life_date < this->introduction_date + 365);
00072 }
00073
00078 uint ObjectSpec::Index() const
00079 {
00080 return this - _object_specs;
00081 }
00082
00084 void ResetObjects()
00085 {
00086
00087 MemSetT(_object_specs, 0, lengthof(_object_specs));
00088
00089
00090 MemCpyT(_object_specs, _original_objects, lengthof(_original_objects));
00091
00092 for (uint16 i = 0; i < lengthof(_original_objects); i++) {
00093 _object_specs[i].grf_prop.local_id = i;
00094 }
00095 }
00096
00097 template <typename Tspec, typename Tid, Tid Tmax>
00098 void NewGRFClass<Tspec, Tid, Tmax>::InsertDefaults()
00099 {
00100 ObjectClassID cls = ObjectClass::Allocate('LTHS');
00101 ObjectClass::Get(cls)->name = STR_OBJECT_CLASS_LTHS;
00102 _object_specs[OBJECT_LIGHTHOUSE].cls_id = cls;
00103 ObjectClass::Assign(&_object_specs[OBJECT_LIGHTHOUSE]);
00104
00105 cls = ObjectClass::Allocate('TRNS');
00106 ObjectClass::Get(cls)->name = STR_OBJECT_CLASS_TRNS;
00107 _object_specs[OBJECT_TRANSMITTER].cls_id = cls;
00108 ObjectClass::Assign(&_object_specs[OBJECT_TRANSMITTER]);
00109 }
00110
00111 template <typename Tspec, typename Tid, Tid Tmax>
00112 bool NewGRFClass<Tspec, Tid, Tmax>::IsUIAvailable(uint index) const
00113 {
00114 return this->GetSpec(index)->IsEverAvailable();
00115 }
00116
00117 INSTANTIATE_NEWGRF_CLASS_METHODS(ObjectClass, ObjectSpec, ObjectClassID, OBJECT_CLASS_MAX)
00118
00119
00126 ObjectScopeResolver::ObjectScopeResolver(ResolverObject *ro, Object *obj, TileIndex tile, uint8 view)
00127 : ScopeResolver(ro)
00128 {
00129 this->obj = obj;
00130 this->tile = tile;
00131 this->view = view;
00132 }
00133
00134 uint32 ObjectScopeResolver::GetRandomBits() const
00135 {
00136 return IsValidTile(this->tile) && IsTileType(this->tile, MP_OBJECT) ? GetObjectRandomBits(this->tile) : 0;
00137 }
00138
00145 static uint32 GetObjectIDAtOffset(TileIndex tile, uint32 cur_grfid)
00146 {
00147 if (!IsTileType(tile, MP_OBJECT)) {
00148 return 0xFFFF;
00149 }
00150
00151 const ObjectSpec *spec = ObjectSpec::GetByTile(tile);
00152
00153
00154 if (spec->grf_prop.grffile == NULL) {
00155 return 0xFFFE;
00156 }
00157
00158 if (spec->grf_prop.grffile->grfid == cur_grfid) {
00159 return spec->grf_prop.local_id;
00160 }
00161
00162 return 0xFFFE;
00163 }
00164
00173 static uint32 GetNearbyObjectTileInformation(byte parameter, TileIndex tile, ObjectID index, bool grf_version8)
00174 {
00175 if (parameter != 0) tile = GetNearbyTile(parameter, tile);
00176 bool is_same_object = (IsTileType(tile, MP_OBJECT) && GetObjectIndex(tile) == index);
00177
00178 return GetNearbyTileInformation(tile, grf_version8) | (is_same_object ? 1 : 0) << 8;
00179 }
00180
00188 static uint32 GetClosestObject(TileIndex tile, ObjectType type, const Object *current)
00189 {
00190 uint32 best_dist = UINT32_MAX;
00191 const Object *o;
00192 FOR_ALL_OBJECTS(o) {
00193 if (GetObjectType(o->location.tile) != type || o == current) continue;
00194
00195 best_dist = min(best_dist, DistanceManhattan(tile, o->location.tile));
00196 }
00197
00198 return best_dist;
00199 }
00200
00209 static uint32 GetCountAndDistanceOfClosestInstance(byte local_id, uint32 grfid, TileIndex tile, const Object *current)
00210 {
00211 uint32 grf_id = GetRegister(0x100);
00212 uint32 idx;
00213
00214
00215 switch (grf_id) {
00216 case 0:
00217 idx = local_id;
00218 break;
00219
00220 case 0xFFFFFFFF:
00221 grf_id = grfid;
00222
00223
00224 default:
00225 idx = _object_mngr.GetID(local_id, grf_id);
00226 break;
00227 }
00228
00229
00230 if (idx >= NUM_OBJECTS) return 0 | 0xFFFF;
00231
00232 return Object::GetTypeCount(idx) << 16 | min(GetClosestObject(tile, idx, current), 0xFFFF);
00233 }
00234
00236 uint32 ObjectScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const
00237 {
00238
00239
00240 const Town *t = NULL;
00241
00242 if (this->obj == NULL) {
00243 switch (variable) {
00244
00245 case 0x41:
00246 case 0x60:
00247 case 0x61:
00248 case 0x62:
00249 case 0x64:
00250 break;
00251
00252
00253 case 0x45:
00254 case 0x46:
00255 if (!IsValidTile(this->tile)) goto unhandled;
00256 t = ClosestTownFromTile(this->tile, UINT_MAX);
00257 break;
00258
00259
00260 case 0x42: return _date;
00261
00262
00263 case 0x44: return _current_company;
00264
00265
00266 case 0x48: return this->view;
00267
00268
00269
00270
00271
00272
00273
00274
00275 default:
00276 goto unhandled;
00277 }
00278
00279
00280 if (!IsValidTile(this->tile)) goto unhandled;
00281 } else {
00282 t = this->obj->town;
00283 }
00284
00285 switch (variable) {
00286
00287 case 0x40: {
00288 uint offset = this->tile - this->obj->location.tile;
00289 uint offset_x = TileX(offset);
00290 uint offset_y = TileY(offset);
00291 return offset_y << 20 | offset_x << 16 | offset_y << 8 | offset_x;
00292 }
00293
00294
00295 case 0x41: return GetTileSlope(this->tile) << 8 | GetTerrainType(this->tile);
00296
00297
00298 case 0x42: return this->obj->build_date;
00299
00300
00301 case 0x43: return GetAnimationFrame(this->tile);
00302
00303
00304 case 0x44: return GetTileOwner(this->tile);
00305
00306
00307 case 0x45: return GetTownRadiusGroup(t, this->tile) << 16 | min(DistanceManhattan(this->tile, t->xy), 0xFFFF);
00308
00309
00310 case 0x46: return GetTownRadiusGroup(t, this->tile) << 16 | min(DistanceSquare(this->tile, t->xy), 0xFFFF);
00311
00312
00313 case 0x47: return this->obj->colour;
00314
00315
00316 case 0x48: return this->obj->view;
00317
00318
00319 case 0x60: return GetObjectIDAtOffset(GetNearbyTile(parameter, this->tile), this->ro->grffile->grfid);
00320
00321
00322 case 0x61: {
00323 TileIndex tile = GetNearbyTile(parameter, this->tile);
00324 return (IsTileType(tile, MP_OBJECT) && Object::GetByTile(tile) == this->obj) ? GetObjectRandomBits(tile) : 0;
00325 }
00326
00327
00328 case 0x62: return GetNearbyObjectTileInformation(parameter, this->tile, this->obj == NULL ? INVALID_OBJECT : this->obj->index, this->ro->grffile->grf_version >= 8);
00329
00330
00331 case 0x63: {
00332 TileIndex tile = GetNearbyTile(parameter, this->tile);
00333 return (IsTileType(tile, MP_OBJECT) && Object::GetByTile(tile) == this->obj) ? GetAnimationFrame(tile) : 0;
00334 }
00335
00336
00337 case 0x64: return GetCountAndDistanceOfClosestInstance(parameter, this->ro->grffile->grfid, this->tile, this->obj);
00338 }
00339
00340 unhandled:
00341 DEBUG(grf, 1, "Unhandled object variable 0x%X", variable);
00342
00343 *available = false;
00344 return UINT_MAX;
00345 }
00346
00353 static const SpriteGroup *GetObjectSpriteGroup(const ObjectSpec *spec, const Object *o)
00354 {
00355 const SpriteGroup *group = NULL;
00356
00357 if (o == NULL) group = spec->grf_prop.spritegroup[CT_PURCHASE_OBJECT];
00358 if (group != NULL) return group;
00359
00360
00361 return spec->grf_prop.spritegroup[0];
00362
00363 }
00364
00374 ObjectResolverObject::ObjectResolverObject(const ObjectSpec *spec, Object *obj, TileIndex tile, uint8 view,
00375 CallbackID callback, uint32 param1, uint32 param2)
00376 : ResolverObject(spec->grf_prop.grffile, callback, param1, param2), object_scope(this, obj, tile, view)
00377 {
00378 this->town_scope = NULL;
00379 }
00380
00381 ObjectResolverObject::~ObjectResolverObject()
00382 {
00383 delete this->town_scope;
00384 }
00385
00391 TownScopeResolver *ObjectResolverObject::GetTown()
00392 {
00393 if (this->town_scope == NULL) {
00394 Town *t;
00395 if (this->object_scope.obj != NULL) {
00396 t = this->object_scope.obj->town;
00397 } else {
00398 t = ClosestTownFromTile(this->object_scope.tile, UINT_MAX);
00399 }
00400 if (t == NULL) return NULL;
00401 this->town_scope = new TownScopeResolver(this, t, this->object_scope.obj == NULL);
00402 }
00403 return this->town_scope;
00404 }
00405
00417 uint16 GetObjectCallback(CallbackID callback, uint32 param1, uint32 param2, const ObjectSpec *spec, Object *o, TileIndex tile, uint8 view)
00418 {
00419 ObjectResolverObject object(spec, o, tile, view, callback, param1, param2);
00420 const SpriteGroup *group = SpriteGroup::Resolve(GetObjectSpriteGroup(spec, o), &object);
00421 if (group == NULL) return CALLBACK_FAILED;
00422
00423 return group->GetCallbackResult();
00424 }
00425
00432 static void DrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, const ObjectSpec *spec)
00433 {
00434 const DrawTileSprites *dts = group->ProcessRegisters(NULL);
00435 PaletteID palette = ((spec->flags & OBJECT_FLAG_2CC_COLOUR) ? SPR_2CCMAP_BASE : PALETTE_RECOLOUR_START) + Object::GetByTile(ti->tile)->colour;
00436
00437 SpriteID image = dts->ground.sprite;
00438 PaletteID pal = dts->ground.pal;
00439
00440 if (GB(image, 0, SPRITE_WIDTH) != 0) {
00441
00442
00443 if ((image == SPR_FLAT_WATER_TILE || spec->flags & OBJECT_FLAG_DRAW_WATER) && IsTileOnWater(ti->tile)) {
00444 DrawWaterClassGround(ti);
00445 } else {
00446 DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, palette));
00447 }
00448 }
00449
00450 DrawNewGRFTileSeq(ti, dts, TO_STRUCTURES, 0, palette);
00451 }
00452
00458 void DrawNewObjectTile(TileInfo *ti, const ObjectSpec *spec)
00459 {
00460 Object *o = Object::GetByTile(ti->tile);
00461 ObjectResolverObject object(spec, o, ti->tile);
00462
00463 const SpriteGroup *group = SpriteGroup::Resolve(GetObjectSpriteGroup(spec, o), &object);
00464 if (group == NULL || group->type != SGT_TILELAYOUT) return;
00465
00466 DrawTileLayout(ti, (const TileLayoutSpriteGroup *)group, spec);
00467 }
00468
00476 void DrawNewObjectTileInGUI(int x, int y, const ObjectSpec *spec, uint8 view)
00477 {
00478 ObjectResolverObject object(spec, NULL, INVALID_TILE, view);
00479 const SpriteGroup *group = SpriteGroup::Resolve(GetObjectSpriteGroup(spec, NULL), &object);
00480 if (group == NULL || group->type != SGT_TILELAYOUT) return;
00481
00482 const DrawTileSprites *dts = ((const TileLayoutSpriteGroup *)group)->ProcessRegisters(NULL);
00483
00484 PaletteID palette;
00485 if (Company::IsValidID(_local_company)) {
00486
00487 if (spec->flags & OBJECT_FLAG_2CC_COLOUR) {
00488 const Livery *l = Company::Get(_local_company)->livery;
00489 palette = SPR_2CCMAP_BASE + l->colour1 + l->colour2 * 16;
00490 } else {
00491 palette = COMPANY_SPRITE_COLOUR(_local_company);
00492 }
00493 } else {
00494
00495 palette = (spec->flags & OBJECT_FLAG_2CC_COLOUR) ? SPR_2CCMAP_BASE : PALETTE_RECOLOUR_START;
00496 }
00497
00498 SpriteID image = dts->ground.sprite;
00499 PaletteID pal = dts->ground.pal;
00500
00501 if (GB(image, 0, SPRITE_WIDTH) != 0) {
00502 DrawSprite(image, GroundSpritePaletteTransform(image, pal, palette), x, y);
00503 }
00504
00505 DrawNewGRFTileSeqInGUI(x, y, dts, 0, palette);
00506 }
00507
00519 uint16 StubGetObjectCallback(CallbackID callback, uint32 param1, uint32 param2, const ObjectSpec *spec, Object *o, TileIndex tile, int extra_data)
00520 {
00521 return GetObjectCallback(callback, param1, param2, spec, o, tile);
00522 }
00523
00525 struct ObjectAnimationBase : public AnimationBase<ObjectAnimationBase, ObjectSpec, Object, int, StubGetObjectCallback> {
00526 static const CallbackID cb_animation_speed = CBID_OBJECT_ANIMATION_SPEED;
00527 static const CallbackID cb_animation_next_frame = CBID_OBJECT_ANIMATION_NEXT_FRAME;
00528
00529 static const ObjectCallbackMask cbm_animation_speed = CBM_OBJ_ANIMATION_SPEED;
00530 static const ObjectCallbackMask cbm_animation_next_frame = CBM_OBJ_ANIMATION_NEXT_FRAME;
00531 };
00532
00537 void AnimateNewObjectTile(TileIndex tile)
00538 {
00539 const ObjectSpec *spec = ObjectSpec::GetByTile(tile);
00540 if (spec == NULL || !(spec->flags & OBJECT_FLAG_ANIMATION)) return;
00541
00542 ObjectAnimationBase::AnimateTile(spec, Object::GetByTile(tile), tile, (spec->flags & OBJECT_FLAG_ANIM_RANDOM_BITS) != 0);
00543 }
00544
00552 void TriggerObjectTileAnimation(Object *o, TileIndex tile, ObjectAnimationTrigger trigger, const ObjectSpec *spec)
00553 {
00554 if (!HasBit(spec->animation.triggers, trigger)) return;
00555
00556 ObjectAnimationBase::ChangeAnimationFrame(CBID_OBJECT_ANIMATION_START_STOP, spec, o, tile, Random(), trigger);
00557 }
00558
00565 void TriggerObjectAnimation(Object *o, ObjectAnimationTrigger trigger, const ObjectSpec *spec)
00566 {
00567 if (!HasBit(spec->animation.triggers, trigger)) return;
00568
00569 TILE_AREA_LOOP(tile, o->location) {
00570 TriggerObjectTileAnimation(o, tile, trigger, spec);
00571 }
00572 }