00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "variables.h"
00008 #include "debug.h"
00009 #include "viewport_func.h"
00010 #include "landscape.h"
00011 #include "town.h"
00012 #include "town_map.h"
00013 #include "sprite.h"
00014 #include "newgrf.h"
00015 #include "newgrf_house.h"
00016 #include "newgrf_spritegroup.h"
00017 #include "newgrf_callbacks.h"
00018 #include "newgrf_town.h"
00019 #include "newgrf_sound.h"
00020 #include "newgrf_commons.h"
00021 #include "transparency.h"
00022 #include "functions.h"
00023 #include "player_func.h"
00024
00025 #include "table/strings.h"
00026 #include "table/sprites.h"
00027 #include "table/town_land.h"
00028
00029 static BuildingCounts _building_counts;
00030 static HouseClassMapping _class_mapping[HOUSE_CLASS_MAX];
00031
00032 HouseOverrideManager _house_mngr(NEW_HOUSE_OFFSET, HOUSE_MAX, INVALID_HOUSE_ID);
00033 extern TileIndex GetHouseNorthPart(HouseID &house);
00034
00043 void UpdateHousesAndTowns()
00044 {
00045 Town *town;
00046 InitializeBuildingCounts();
00047
00048
00049 FOR_ALL_TOWNS(town) {
00050 town->population = 0;
00051 town->num_houses = 0;
00052 }
00053
00054 for (TileIndex t = 0; t < MapSize(); t++) {
00055 HouseID house_id;
00056
00057 if (!IsTileType(t, MP_HOUSE)) continue;
00058
00059 house_id = GetHouseType(t);
00060 if (!GetHouseSpecs(house_id)->enabled && house_id >= NEW_HOUSE_OFFSET) {
00061
00062
00063 house_id = _house_mngr.GetSubstituteID(house_id);
00064 SetHouseType(t, house_id);
00065 }
00066
00067 town = GetTownByTile(t);
00068 IncreaseBuildingCount(town, house_id);
00069 if (IsHouseCompleted(t)) town->population += GetHouseSpecs(house_id)->population;
00070
00071
00072 if (GetHouseNorthPart(house_id) == 0) town->num_houses++;
00073 }
00074
00075
00076 FOR_ALL_TOWNS(town) {
00077 UpdateTownRadius(town);
00078 UpdateTownMaxPass(town);
00079 }
00080 }
00081
00082 HouseClassID AllocateHouseClassID(byte grf_class_id, uint32 grfid)
00083 {
00084
00085 for (int i = 1; i != lengthof(_class_mapping); i++) {
00086 HouseClassMapping *map = &_class_mapping[i];
00087
00088 if (map->class_id == grf_class_id && map->grfid == grfid) return (HouseClassID)i;
00089
00090 if (map->class_id == 0 && map->grfid == 0) {
00091 map->class_id = grf_class_id;
00092 map->grfid = grfid;
00093 return (HouseClassID)i;
00094 }
00095 }
00096 return HOUSE_NO_CLASS;
00097 }
00098
00099 void InitializeBuildingCounts()
00100 {
00101 memset(&_building_counts, 0, sizeof(_building_counts));
00102 }
00103
00110 void IncreaseBuildingCount(Town *t, HouseID house_id)
00111 {
00112 HouseClassID class_id = GetHouseSpecs(house_id)->class_id;
00113
00114 if (!_loaded_newgrf_features.has_newhouses) return;
00115
00116
00117
00118
00119 if (t->building_counts.id_count[house_id] == 255) return;
00120
00121 t->building_counts.id_count[house_id]++;
00122 if (_building_counts.id_count[house_id] < 255) _building_counts.id_count[house_id]++;
00123
00124
00125
00126 if (class_id == HOUSE_NO_CLASS || t->building_counts.class_count[class_id] == 255) return;
00127
00128 t->building_counts.class_count[class_id]++;
00129 if (_building_counts.class_count[class_id] < 255) _building_counts.class_count[class_id]++;
00130 }
00131
00138 void DecreaseBuildingCount(Town *t, HouseID house_id)
00139 {
00140 HouseClassID class_id = GetHouseSpecs(house_id)->class_id;
00141
00142 if (!_loaded_newgrf_features.has_newhouses) return;
00143
00144 if (t->building_counts.id_count[house_id] > 0) t->building_counts.id_count[house_id]--;
00145 if (_building_counts.id_count[house_id] > 0) _building_counts.id_count[house_id]--;
00146
00147 if (class_id == HOUSE_NO_CLASS) return;
00148
00149 if (t->building_counts.class_count[class_id] > 0) t->building_counts.class_count[class_id]--;
00150 if (_building_counts.class_count[class_id] > 0) _building_counts.class_count[class_id]--;
00151 }
00152
00153 static uint32 HouseGetRandomBits(const ResolverObject *object)
00154 {
00155 const TileIndex tile = object->u.house.tile;
00156 return (tile == INVALID_TILE || !IsTileType(tile, MP_HOUSE)) ? 0 : GetHouseRandomBits(tile);
00157 }
00158
00159 static uint32 HouseGetTriggers(const ResolverObject *object)
00160 {
00161 const TileIndex tile = object->u.house.tile;
00162 return (tile == INVALID_TILE || !IsTileType(tile, MP_HOUSE)) ? 0 : GetHouseTriggers(tile);
00163 }
00164
00165 static void HouseSetTriggers(const ResolverObject *object, int triggers)
00166 {
00167 const TileIndex tile = object->u.house.tile;
00168 if (IsTileType(tile, MP_HOUSE)) SetHouseTriggers(tile, triggers);
00169 }
00170
00171 static uint32 GetNumHouses(HouseID house_id, const Town *town)
00172 {
00173 uint8 map_id_count, town_id_count, map_class_count, town_class_count;
00174 HouseClassID class_id = GetHouseSpecs(house_id)->class_id;
00175
00176 map_id_count = _building_counts.id_count[house_id];
00177 map_class_count = _building_counts.class_count[class_id];
00178 town_id_count = town->building_counts.id_count[house_id];
00179 town_class_count = town->building_counts.class_count[class_id];
00180
00181 return map_class_count << 24 | town_class_count << 16 | map_id_count << 8 | town_id_count;
00182 }
00183
00184 static uint32 GetGRFParameter(HouseID house_id, byte parameter)
00185 {
00186 const HouseSpec *hs = GetHouseSpecs(house_id);
00187 const GRFFile *file = hs->grffile;
00188
00189 if (parameter >= file->param_end) return 0;
00190 return file->param[parameter];
00191 }
00192
00193 uint32 GetNearbyTileInformation(byte parameter, TileIndex tile)
00194 {
00195 tile = GetNearbyTile(parameter, tile);
00196 return GetNearbyTileInformation(tile);
00197 }
00198
00204 static uint32 HouseGetVariable(const ResolverObject *object, byte variable, byte parameter, bool *available)
00205 {
00206 const Town *town = object->u.house.town;
00207 TileIndex tile = object->u.house.tile;
00208 HouseID house_id = object->u.house.house_id;
00209
00210 if (object->scope == VSG_SCOPE_PARENT) {
00211 return TownGetVariable(variable, parameter, available, town);
00212 }
00213
00214 switch (variable) {
00215
00216 case 0x40: return (IsTileType(tile, MP_HOUSE) ? GetHouseBuildingStage(tile) : 0) | OriginalTileRandomiser(TileX(tile), TileY(tile)) << 2;
00217
00218
00219 case 0x41: return Clamp(_cur_year - GetHouseConstructionYear(tile), 0, 0xFF);
00220
00221
00222 case 0x42: return GetTownRadiusGroup(town, tile);
00223
00224
00225 case 0x43: return GetTerrainType(tile);
00226
00227
00228 case 0x44: return GetNumHouses(house_id, town);
00229
00230
00231 case 0x45: return _generating_world ? 1 : 0;
00232
00233
00234 case 0x46: return IsTileType(tile, MP_HOUSE) ? GetHouseAnimationFrame(tile) : 0;
00235
00236
00237
00238 case 0x60: return GetNumHouses(parameter, town);
00239
00240
00241 case 0x61: {
00242 const HouseSpec *hs = GetHouseSpecs(house_id);
00243 if (hs->grffile == NULL) return 0;
00244
00245 HouseID new_house = _house_mngr.GetID(parameter, hs->grffile->grfid);
00246 return new_house == INVALID_HOUSE_ID ? 0 : GetNumHouses(new_house, town);
00247 }
00248
00249
00250 case 0x62: return GetNearbyTileInformation(parameter, tile);
00251
00252
00253 case 0x7F: return GetGRFParameter(object->u.house.house_id, parameter);
00254 }
00255
00256 DEBUG(grf, 1, "Unhandled house property 0x%X", variable);
00257
00258 *available = false;
00259 return UINT_MAX;
00260 }
00261
00262 static const SpriteGroup *HouseResolveReal(const ResolverObject *object, const SpriteGroup *group)
00263 {
00264
00265 return NULL;
00266 }
00267
00273 static void NewHouseResolver(ResolverObject *res, HouseID house_id, TileIndex tile, Town *town)
00274 {
00275 res->GetRandomBits = HouseGetRandomBits;
00276 res->GetTriggers = HouseGetTriggers;
00277 res->SetTriggers = HouseSetTriggers;
00278 res->GetVariable = HouseGetVariable;
00279 res->ResolveReal = HouseResolveReal;
00280
00281 res->u.house.tile = tile;
00282 res->u.house.town = town;
00283 res->u.house.house_id = house_id;
00284
00285 res->callback = CBID_NO_CALLBACK;
00286 res->callback_param1 = 0;
00287 res->callback_param2 = 0;
00288 res->last_value = 0;
00289 res->trigger = 0;
00290 res->reseed = 0;
00291 }
00292
00293 uint16 GetHouseCallback(CallbackID callback, uint32 param1, uint32 param2, HouseID house_id, Town *town, TileIndex tile)
00294 {
00295 ResolverObject object;
00296 const SpriteGroup *group;
00297
00298 NewHouseResolver(&object, house_id, tile, town);
00299 object.callback = callback;
00300 object.callback_param1 = param1;
00301 object.callback_param2 = param2;
00302
00303 group = Resolve(GetHouseSpecs(house_id)->spritegroup, &object);
00304 if (group == NULL || group->type != SGT_CALLBACK) return CALLBACK_FAILED;
00305
00306 return group->g.callback.result;
00307 }
00308
00309 void DrawTileLayout(const TileInfo *ti, const SpriteGroup *group, byte stage, HouseID house_id)
00310 {
00311 const DrawTileSprites *dts = group->g.layout.dts;
00312 const DrawTileSeqStruct *dtss;
00313
00314 SpriteID image = dts->ground.sprite;
00315 SpriteID pal = dts->ground.pal;
00316
00317 if (IS_CUSTOM_SPRITE(image)) image += stage;
00318
00319 if (GB(image, 0, SPRITE_WIDTH) != 0) DrawGroundSprite(image, pal);
00320
00321 foreach_draw_tile_seq(dtss, dts->seq) {
00322 if (GB(dtss->image.sprite, 0, SPRITE_WIDTH) == 0) continue;
00323
00324 image = dtss->image.sprite;
00325 pal = dtss->image.pal;
00326
00327 if (IS_CUSTOM_SPRITE(image)) image += stage;
00328
00329 if ((HasBit(image, SPRITE_MODIFIER_OPAQUE) || !IsTransparencySet(TO_HOUSES)) && HasBit(image, PALETTE_MODIFIER_COLOR)) {
00330 if (pal == 0) {
00331 const HouseSpec *hs = GetHouseSpecs(house_id);
00332 if (HasBit(hs->callback_mask, CBM_HOUSE_COLOUR)) {
00333 uint16 callback = GetHouseCallback(CBID_HOUSE_COLOUR, 0, 0, house_id, GetTownByTile(ti->tile), ti->tile);
00334 if (callback != CALLBACK_FAILED) {
00335
00336 pal = HasBit(callback, 14) ? GB(callback, 0, 8) + SPR_2CCMAP_BASE : callback;
00337 }
00338 } else {
00339 pal = hs->random_colour[OriginalTileRandomiser(ti->x, ti->y)] + PALETTE_RECOLOR_START;
00340 }
00341 }
00342 } else {
00343 pal = PAL_NONE;
00344 }
00345
00346 if ((byte)dtss->delta_z != 0x80) {
00347 AddSortableSpriteToDraw(
00348 image, pal,
00349 ti->x + dtss->delta_x, ti->y + dtss->delta_y,
00350 dtss->size_x, dtss->size_y,
00351 dtss->size_z, ti->z + dtss->delta_z,
00352 IsTransparencySet(TO_HOUSES)
00353 );
00354 } else {
00355 AddChildSpriteScreen(image, pal, (byte)dtss->delta_x, (byte)dtss->delta_y, IsTransparencySet(TO_HOUSES));
00356 }
00357 }
00358 }
00359
00360 void DrawNewHouseTile(TileInfo *ti, HouseID house_id)
00361 {
00362 const HouseSpec *hs = GetHouseSpecs(house_id);
00363 const SpriteGroup *group;
00364 ResolverObject object;
00365
00366 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
00367
00368 NewHouseResolver(&object, house_id, ti->tile, GetTownByTile(ti->tile));
00369
00370 group = Resolve(hs->spritegroup, &object);
00371 if (group == NULL || group->type != SGT_TILELAYOUT) {
00372
00373 DrawGroundSprite(SPR_SHADOW_CELL, PAL_NONE);
00374 } else {
00375
00376 byte stage = GetHouseBuildingStage(ti->tile);
00377 stage = Clamp(stage - 4 + group->g.layout.num_sprites, 0, group->g.layout.num_sprites - 1);
00378 DrawTileLayout(ti, group, stage, house_id);
00379 }
00380 }
00381
00382 void AnimateNewHouseTile(TileIndex tile)
00383 {
00384 const HouseSpec *hs = GetHouseSpecs(GetHouseType(tile));
00385 byte animation_speed = hs->animation_speed;
00386 bool frame_set_by_callback = false;
00387
00388 if (HasBit(hs->callback_mask, CBM_HOUSE_ANIMATION_SPEED)) {
00389 uint16 callback_res = GetHouseCallback(CBID_HOUSE_ANIMATION_SPEED, 0, 0, GetHouseType(tile), GetTownByTile(tile), tile);
00390 if (callback_res != CALLBACK_FAILED) animation_speed = Clamp(callback_res & 0xFF, 2, 16);
00391 }
00392
00393
00394
00395
00396
00397 if (_tick_counter % (1 << animation_speed) != 0) return;
00398
00399 byte frame = GetHouseAnimationFrame(tile);
00400 byte num_frames = GB(hs->animation_frames, 0, 7);
00401
00402 if (HasBit(hs->callback_mask, CBM_HOUSE_ANIMATION_NEXT_FRAME)) {
00403 uint32 param = (hs->extra_flags & CALLBACK_1A_RANDOM_BITS) ? Random() : 0;
00404 uint16 callback_res = GetHouseCallback(CBID_HOUSE_ANIMATION_NEXT_FRAME, param, 0, GetHouseType(tile), GetTownByTile(tile), tile);
00405
00406 if (callback_res != CALLBACK_FAILED) {
00407 frame_set_by_callback = true;
00408
00409 switch (callback_res & 0xFF) {
00410 case 0xFF:
00411 DeleteAnimatedTile(tile);
00412 break;
00413 case 0xFE:
00414
00415 frame_set_by_callback = false;
00416 break;
00417 default:
00418 frame = callback_res & 0xFF;
00419 break;
00420 }
00421
00422
00423
00424 if (GB(callback_res, 8, 7) != 0) PlayHouseSound(GB(callback_res, 8, 7), tile);
00425 }
00426 }
00427
00428 if (!frame_set_by_callback) {
00429 if (frame < num_frames) {
00430 frame++;
00431 } else if (frame == num_frames && HasBit(hs->animation_frames, 7)) {
00432
00433 frame = 0;
00434 } else {
00435
00436 DeleteAnimatedTile(tile);
00437 }
00438 }
00439
00440 SetHouseAnimationFrame(tile, frame);
00441 MarkTileDirtyByTile(tile);
00442 }
00443
00444 void ChangeHouseAnimationFrame(TileIndex tile, uint16 callback_result)
00445 {
00446 switch (callback_result & 0xFF) {
00447 case 0xFD: break;
00448 case 0xFE: AddAnimatedTile(tile); break;
00449 case 0xFF: DeleteAnimatedTile(tile); break;
00450 default:
00451 SetHouseAnimationFrame(tile, callback_result & 0xFF);
00452 AddAnimatedTile(tile);
00453 break;
00454 }
00455
00456
00457 if (GB(callback_result, 8, 7) != 0) PlayHouseSound(GB(callback_result, 8, 7), tile);
00458 }
00459
00460 bool CanDeleteHouse(TileIndex tile)
00461 {
00462 const HouseSpec *hs = GetHouseSpecs(GetHouseType(tile));
00463
00464
00465
00466 if ((IsValidPlayer(_current_player) && IsHumanPlayer(_current_player))
00467 || _current_player == OWNER_WATER || _current_player == OWNER_NONE) return true;
00468
00469 if (HasBit(hs->callback_mask, CBM_HOUSE_DENY_DESTRUCTION)) {
00470 uint16 callback_res = GetHouseCallback(CBID_HOUSE_DENY_DESTRUCTION, 0, 0, GetHouseType(tile), GetTownByTile(tile), tile);
00471 return (callback_res == CALLBACK_FAILED || callback_res == 0);
00472 } else {
00473 return !(hs->extra_flags & BUILDING_IS_PROTECTED);
00474 }
00475 }
00476
00477 static void AnimationControl(TileIndex tile, uint16 random_bits)
00478 {
00479 const HouseSpec *hs = GetHouseSpecs(GetHouseType(tile));
00480
00481 if (HasBit(hs->callback_mask, CBM_HOUSE_ANIMATION_START_STOP)) {
00482 uint32 param = (hs->extra_flags & SYNCHRONISED_CALLBACK_1B) ? (GB(Random(), 0, 16) | random_bits << 16) : Random();
00483 uint16 callback_res = GetHouseCallback(CBID_HOUSE_ANIMATION_START_STOP, param, 0, GetHouseType(tile), GetTownByTile(tile), tile);
00484
00485 if (callback_res != CALLBACK_FAILED) ChangeHouseAnimationFrame(tile, callback_res);
00486 }
00487 }
00488
00489 bool NewHouseTileLoop(TileIndex tile)
00490 {
00491 const HouseSpec *hs = GetHouseSpecs(GetHouseType(tile));
00492
00493 if (GetHouseProcessingTime(tile) > 0) {
00494 DecHouseProcessingTime(tile);
00495 return true;
00496 }
00497
00498 TriggerHouse(tile, HOUSE_TRIGGER_TILE_LOOP);
00499 TriggerHouse(tile, HOUSE_TRIGGER_TILE_LOOP_TOP);
00500
00501 if (HasBit(hs->callback_mask, CBM_HOUSE_ANIMATION_START_STOP)) {
00502
00503
00504
00505
00506 if (hs->extra_flags & SYNCHRONISED_CALLBACK_1B) {
00507 uint16 random = GB(Random(), 0, 16);
00508
00509 if (hs->building_flags & BUILDING_HAS_1_TILE) AnimationControl(tile, random);
00510 if (hs->building_flags & BUILDING_2_TILES_Y) AnimationControl(TILE_ADDXY(tile, 0, 1), random);
00511 if (hs->building_flags & BUILDING_2_TILES_X) AnimationControl(TILE_ADDXY(tile, 1, 0), random);
00512 if (hs->building_flags & BUILDING_HAS_4_TILES) AnimationControl(TILE_ADDXY(tile, 1, 1), random);
00513 } else {
00514 AnimationControl(tile, 0);
00515 }
00516 }
00517
00518
00519 if (HasBit(hs->callback_mask, CBM_HOUSE_DESTRUCTION)) {
00520 uint16 callback_res = GetHouseCallback(CBID_HOUSE_DESTRUCTION, 0, 0, GetHouseType(tile), GetTownByTile(tile), tile);
00521 if (callback_res != CALLBACK_FAILED && GB(callback_res, 0, 8) > 0) {
00522 ClearTownHouse(GetTownByTile(tile), tile);
00523 return false;
00524 }
00525 }
00526
00527 SetHouseProcessingTime(tile, hs->processing_time);
00528 return true;
00529 }
00530
00531 static void DoTriggerHouse(TileIndex tile, HouseTrigger trigger, byte base_random, bool first)
00532 {
00533 ResolverObject object;
00534
00535
00536 assert(IsTileType(tile, MP_HOUSE));
00537
00538 HouseID hid = GetHouseType(tile);
00539 HouseSpec *hs = GetHouseSpecs(hid);
00540
00541 if (hs->spritegroup == NULL) return;
00542
00543 NewHouseResolver(&object, hid, tile, GetTownByTile(tile));
00544
00545 object.callback = CBID_RANDOM_TRIGGER;
00546 object.trigger = trigger;
00547
00548 const SpriteGroup *group = Resolve(hs->spritegroup, &object);
00549 if (group == NULL) return;
00550
00551 byte new_random_bits = Random();
00552 byte random_bits = GetHouseRandomBits(tile);
00553 random_bits &= ~object.reseed;
00554 random_bits |= (first ? new_random_bits : base_random) & object.reseed;
00555 SetHouseRandomBits(tile, random_bits);
00556
00557 switch (trigger) {
00558 case HOUSE_TRIGGER_TILE_LOOP:
00559
00560 break;
00561
00562 case HOUSE_TRIGGER_TILE_LOOP_TOP:
00563 if (!first) break;
00564
00565 if (hs->building_flags & BUILDING_2_TILES_Y) DoTriggerHouse(TILE_ADDXY(tile, 0, 1), trigger, random_bits, false);
00566 if (hs->building_flags & BUILDING_2_TILES_X) DoTriggerHouse(TILE_ADDXY(tile, 1, 0), trigger, random_bits, false);
00567 if (hs->building_flags & BUILDING_HAS_4_TILES) DoTriggerHouse(TILE_ADDXY(tile, 1, 1), trigger, random_bits, false);
00568 break;
00569 }
00570 }
00571
00572 void TriggerHouse(TileIndex t, HouseTrigger trigger)
00573 {
00574 DoTriggerHouse(t, trigger, 0, true);
00575 }