105 MarkWholeScreenDirty(); |
105 MarkWholeScreenDirty(); |
106 |
106 |
107 this->xy = 0; |
107 this->xy = 0; |
108 } |
108 } |
109 |
109 |
|
110 /** |
|
111 * Generate a random town road layout. |
|
112 * |
|
113 * The layout is based on the TileHash. |
|
114 */ |
|
115 void Town::InitializeLayout() |
|
116 { |
|
117 this->layout = (TownLayout)(TileHash(TileX(this->xy), TileY(this->xy)) % NUM_TLS); |
|
118 |
|
119 /* Set invalid layouts to valid ones */ |
|
120 switch (this->layout) { |
|
121 default: break; |
|
122 case TL_RANDOM: this->layout = TL_ORIGINAL; break; |
|
123 case TL_NO_ROADS: this->layout = TL_BETTER_ROADS; break; |
|
124 } |
|
125 } |
|
126 |
110 // Local |
127 // Local |
111 static int _grow_town_result; |
128 static int _grow_town_result; |
112 |
129 |
113 /* Describe the possible states */ |
130 /* Describe the possible states */ |
114 enum TownGrowthResult { |
131 enum TownGrowthResult { |
123 { |
140 { |
124 AddChildSpriteScreen(SPR_LIFT, PAL_NONE, 14, 60 - GetLiftPosition(ti->tile)); |
141 AddChildSpriteScreen(SPR_LIFT, PAL_NONE, 14, 60 - GetLiftPosition(ti->tile)); |
125 } |
142 } |
126 |
143 |
127 typedef void TownDrawTileProc(const TileInfo *ti); |
144 typedef void TownDrawTileProc(const TileInfo *ti); |
128 static TownDrawTileProc * const _town_draw_tile_procs[1] = { |
145 static TownDrawTileProc *const _town_draw_tile_procs[1] = { |
129 TownDrawHouseLift |
146 TownDrawHouseLift |
130 }; |
147 }; |
131 |
|
132 uint OriginalTileRandomiser(uint x, uint y) |
|
133 { |
|
134 uint variant; |
|
135 variant = x >> 4; |
|
136 variant ^= x >> 6; |
|
137 variant ^= y >> 4; |
|
138 variant -= y >> 6; |
|
139 variant &= 3; |
|
140 return variant; |
|
141 } |
|
142 |
148 |
143 /** |
149 /** |
144 * Return a random direction |
150 * Return a random direction |
145 * |
151 * |
146 * @return a random direction |
152 * @return a random direction |
155 * Part of the tile loop process |
161 * Part of the tile loop process |
156 * @param ti TileInfo of the tile to draw |
162 * @param ti TileInfo of the tile to draw |
157 */ |
163 */ |
158 static void DrawTile_Town(TileInfo *ti) |
164 static void DrawTile_Town(TileInfo *ti) |
159 { |
165 { |
160 const DrawBuildingsTileStruct *dcts; |
|
161 SpriteID image; |
|
162 SpriteID pal; |
|
163 HouseID house_id = GetHouseType(ti->tile); |
166 HouseID house_id = GetHouseType(ti->tile); |
164 |
167 |
165 if (house_id >= NEW_HOUSE_OFFSET) { |
168 if (house_id >= NEW_HOUSE_OFFSET) { |
166 /* Houses don't necessarily need new graphics. If they don't have a |
169 /* Houses don't necessarily need new graphics. If they don't have a |
167 * spritegroup associated with them, then the sprite for the substitute |
170 * spritegroup associated with them, then the sprite for the substitute |
173 house_id = GetHouseSpecs(house_id)->substitute_id; |
176 house_id = GetHouseSpecs(house_id)->substitute_id; |
174 } |
177 } |
175 } |
178 } |
176 |
179 |
177 /* Retrieve pointer to the draw town tile struct */ |
180 /* Retrieve pointer to the draw town tile struct */ |
178 dcts = &_town_draw_tile_data[house_id << 4 | OriginalTileRandomiser(ti->x, ti->y) << 2 | GetHouseBuildingStage(ti->tile)]; |
181 const DrawBuildingsTileStruct *dcts = &_town_draw_tile_data[house_id << 4 | TileHash2Bit(ti->x, ti->y) << 2 | GetHouseBuildingStage(ti->tile)]; |
179 |
182 |
180 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED); |
183 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED); |
181 |
184 |
182 image = dcts->ground.sprite; |
185 DrawGroundSprite(dcts->ground.sprite, dcts->ground.pal); |
183 pal = dcts->ground.pal; |
186 |
184 DrawGroundSprite(image, pal); |
187 /* If houses are invisible, do not draw the upper part */ |
|
188 if (IsInvisibilitySet(TO_HOUSES)) return; |
185 |
189 |
186 /* Add a house on top of the ground? */ |
190 /* Add a house on top of the ground? */ |
187 image = dcts->building.sprite; |
191 SpriteID image = dcts->building.sprite; |
188 if (image != 0) { |
192 if (image != 0) { |
189 AddSortableSpriteToDraw(image, dcts->building.pal, |
193 AddSortableSpriteToDraw(image, dcts->building.pal, |
190 ti->x + dcts->subtile_x, |
194 ti->x + dcts->subtile_x, |
191 ti->y + dcts->subtile_y, |
195 ti->y + dcts->subtile_y, |
192 dcts->width, |
196 dcts->width, |
241 DeleteAnimatedTile(tile); |
243 DeleteAnimatedTile(tile); |
242 return; |
244 return; |
243 } |
245 } |
244 |
246 |
245 if (!LiftHasDestination(tile)) { |
247 if (!LiftHasDestination(tile)) { |
246 int i; |
248 uint i; |
247 |
249 |
248 /* Building has 6 floors, number 0 .. 6, where 1 is illegal. |
250 /* Building has 6 floors, number 0 .. 6, where 1 is illegal. |
249 * This is due to the fact that the first floor is, in the graphics, |
251 * This is due to the fact that the first floor is, in the graphics, |
250 * the height of 2 'normal' floors. |
252 * the height of 2 'normal' floors. |
251 * Furthermore, there are 6 lift positions from floor N (incl) to floor N + 1 (excl) */ |
253 * Furthermore, there are 6 lift positions from floor N (incl) to floor N + 1 (excl) */ |
252 do { |
254 do { |
253 i = (Random() & 7) - 1; |
255 i = RandomRange(7); |
254 } while (i < 0 || i == 1 || i * 6 == GetLiftPosition(tile)); |
256 } while (i == 1 || i * 6 == GetLiftPosition(tile)); |
255 |
257 |
256 SetLiftDestination(tile, i); |
258 SetLiftDestination(tile, i); |
257 } |
259 } |
258 |
260 |
259 pos = GetLiftPosition(tile); |
261 int pos = GetLiftPosition(tile); |
260 dest = GetLiftDestination(tile) * 6; |
262 int dest = GetLiftDestination(tile) * 6; |
261 pos += (pos < dest) ? 1 : -1; |
263 pos += (pos < dest) ? 1 : -1; |
262 SetLiftPosition(tile, pos); |
264 SetLiftPosition(tile, pos); |
263 |
265 |
264 if (pos == dest) HaltLift(tile); |
266 if (pos == dest) HaltLift(tile); |
265 |
267 |
305 * population (creation or growth or else) |
307 * population (creation or growth or else) |
306 * @param t Town to update |
308 * @param t Town to update |
307 */ |
309 */ |
308 void UpdateTownVirtCoord(Town *t) |
310 void UpdateTownVirtCoord(Town *t) |
309 { |
311 { |
310 Point pt; |
|
311 |
|
312 MarkTownSignDirty(t); |
312 MarkTownSignDirty(t); |
313 pt = RemapCoords2(TileX(t->xy) * TILE_SIZE, TileY(t->xy) * TILE_SIZE); |
313 Point pt = RemapCoords2(TileX(t->xy) * TILE_SIZE, TileY(t->xy) * TILE_SIZE); |
314 SetDParam(0, t->index); |
314 SetDParam(0, t->index); |
315 SetDParam(1, t->population); |
315 SetDParam(1, t->population); |
316 UpdateViewportSignPos(&t->sign, pt.x, pt.y - 24, |
316 UpdateViewportSignPos(&t->sign, pt.x, pt.y - 24, |
317 _patches.population_in_label ? STR_TOWN_LABEL_POP : STR_TOWN_LABEL); |
317 _patches.population_in_label ? STR_TOWN_LABEL_POP : STR_TOWN_LABEL); |
318 MarkTownSignDirty(t); |
318 MarkTownSignDirty(t); |
401 * Periodic tic handler for houses and town |
400 * Periodic tic handler for houses and town |
402 * @param tile been asked to do its stuff |
401 * @param tile been asked to do its stuff |
403 */ |
402 */ |
404 static void TileLoop_Town(TileIndex tile) |
403 static void TileLoop_Town(TileIndex tile) |
405 { |
404 { |
406 Town *t; |
|
407 uint32 r; |
|
408 HouseID house_id = GetHouseType(tile); |
405 HouseID house_id = GetHouseType(tile); |
409 HouseSpec *hs = GetHouseSpecs(house_id); |
|
410 |
406 |
411 /* NewHouseTileLoop returns false if Callback 21 succeeded, i.e. the house |
407 /* NewHouseTileLoop returns false if Callback 21 succeeded, i.e. the house |
412 * doesn't exist any more, so don't continue here. */ |
408 * doesn't exist any more, so don't continue here. */ |
413 if (house_id >= NEW_HOUSE_OFFSET && !NewHouseTileLoop(tile)) return; |
409 if (house_id >= NEW_HOUSE_OFFSET && !NewHouseTileLoop(tile)) return; |
414 |
410 |
416 /* Construction is not completed. See if we can go further in construction*/ |
412 /* Construction is not completed. See if we can go further in construction*/ |
417 MakeTownHouseBigger(tile); |
413 MakeTownHouseBigger(tile); |
418 return; |
414 return; |
419 } |
415 } |
420 |
416 |
|
417 const HouseSpec *hs = GetHouseSpecs(house_id); |
|
418 |
421 /* If the lift has a destination, it is already an animated tile. */ |
419 /* If the lift has a destination, it is already an animated tile. */ |
422 if ((hs->building_flags & BUILDING_IS_ANIMATED) && |
420 if ((hs->building_flags & BUILDING_IS_ANIMATED) && |
423 house_id < NEW_HOUSE_OFFSET && |
421 house_id < NEW_HOUSE_OFFSET && |
424 !LiftHasDestination(tile) && |
422 !LiftHasDestination(tile) && |
425 Chance16(1, 2)) |
423 Chance16(1, 2)) { |
426 AddAnimatedTile(tile); |
424 AddAnimatedTile(tile); |
427 |
425 } |
428 t = GetTownByTile(tile); |
426 |
429 |
427 Town *t = GetTownByTile(tile); |
430 r = Random(); |
428 uint32 r = Random(); |
431 |
429 |
432 if (HasBit(hs->callback_mask, CBM_HOUSE_PRODUCE_CARGO)) { |
430 if (HasBit(hs->callback_mask, CBM_HOUSE_PRODUCE_CARGO)) { |
433 for (uint i = 0; i < 256; i++) { |
431 for (uint i = 0; i < 256; i++) { |
434 uint16 callback = GetHouseCallback(CBID_HOUSE_PRODUCE_CARGO, i, r, house_id, t, tile); |
432 uint16 callback = GetHouseCallback(CBID_HOUSE_PRODUCE_CARGO, i, r, house_id, t, tile); |
435 |
433 |
458 } |
456 } |
459 } |
457 } |
460 } else { |
458 } else { |
461 if (GB(r, 0, 8) < hs->population) { |
459 if (GB(r, 0, 8) < hs->population) { |
462 uint amt = GB(r, 0, 8) / 8 + 1; |
460 uint amt = GB(r, 0, 8) / 8 + 1; |
463 uint moved; |
|
464 |
461 |
465 if (_economy.fluct <= 0) amt = (amt + 1) >> 1; |
462 if (_economy.fluct <= 0) amt = (amt + 1) >> 1; |
466 t->new_max_pass += amt; |
463 t->new_max_pass += amt; |
467 moved = MoveGoodsToStation(tile, 1, 1, CT_PASSENGERS, amt); |
464 t->new_act_pass += MoveGoodsToStation(tile, 1, 1, CT_PASSENGERS, amt); |
468 t->new_act_pass += moved; |
|
469 } |
465 } |
470 |
466 |
471 if (GB(r, 8, 8) < hs->mail_generation) { |
467 if (GB(r, 8, 8) < hs->mail_generation) { |
472 uint amt = GB(r, 8, 8) / 8 + 1; |
468 uint amt = GB(r, 8, 8) / 8 + 1; |
473 uint moved; |
|
474 |
469 |
475 if (_economy.fluct <= 0) amt = (amt + 1) >> 1; |
470 if (_economy.fluct <= 0) amt = (amt + 1) >> 1; |
476 t->new_max_mail += amt; |
471 t->new_max_mail += amt; |
477 moved = MoveGoodsToStation(tile, 1, 1, CT_MAIL, amt); |
472 t->new_act_mail += MoveGoodsToStation(tile, 1, 1, CT_MAIL, amt); |
478 t->new_act_mail += moved; |
|
479 } |
473 } |
480 } |
474 } |
481 |
475 |
482 _current_player = OWNER_TOWN; |
476 _current_player = OWNER_TOWN; |
483 |
477 |
506 /* not used */ |
500 /* not used */ |
507 } |
501 } |
508 |
502 |
509 static CommandCost ClearTile_Town(TileIndex tile, byte flags) |
503 static CommandCost ClearTile_Town(TileIndex tile, byte flags) |
510 { |
504 { |
511 int rating; |
|
512 CommandCost cost(EXPENSES_CONSTRUCTION); |
|
513 Town *t; |
|
514 HouseSpec *hs = GetHouseSpecs(GetHouseType(tile)); |
|
515 |
|
516 if (flags & DC_AUTO) return_cmd_error(STR_2004_BUILDING_MUST_BE_DEMOLISHED); |
505 if (flags & DC_AUTO) return_cmd_error(STR_2004_BUILDING_MUST_BE_DEMOLISHED); |
517 if (!CanDeleteHouse(tile)) return CMD_ERROR; |
506 if (!CanDeleteHouse(tile)) return CMD_ERROR; |
518 |
507 |
|
508 const HouseSpec *hs = GetHouseSpecs(GetHouseType(tile)); |
|
509 |
|
510 CommandCost cost(EXPENSES_CONSTRUCTION); |
519 cost.AddCost(_price.remove_house * hs->removal_cost >> 8); |
511 cost.AddCost(_price.remove_house * hs->removal_cost >> 8); |
520 |
512 |
521 rating = hs->remove_rating_decrease; |
513 int rating = hs->remove_rating_decrease; |
522 _cleared_town_rating += rating; |
514 _cleared_town_rating += rating; |
523 _cleared_town = t = GetTownByTile(tile); |
515 Town *t = _cleared_town = GetTownByTile(tile); |
524 |
516 |
525 if (IsValidPlayer(_current_player)) { |
517 if (IsValidPlayer(_current_player)) { |
526 if (rating > t->ratings[_current_player] && !(flags & DC_NO_TOWN_RATING) && !_cheats.magic_bulldozer.value) { |
518 if (rating > t->ratings[_current_player] && !(flags & DC_NO_TOWN_RATING) && !_cheats.magic_bulldozer.value) { |
527 SetDParam(0, t->index); |
519 SetDParam(0, t->index); |
528 return_cmd_error(STR_2009_LOCAL_AUTHORITY_REFUSES); |
520 return_cmd_error(STR_2009_LOCAL_AUTHORITY_REFUSES); |
535 } |
527 } |
536 |
528 |
537 return cost; |
529 return cost; |
538 } |
530 } |
539 |
531 |
|
532 static void GetProducedCargo_Town(TileIndex tile, CargoID *b) |
|
533 { |
|
534 HouseID house_id = GetHouseType(tile); |
|
535 const HouseSpec *hs = GetHouseSpecs(house_id); |
|
536 Town *t = GetTownByTile(tile); |
|
537 |
|
538 if (HasBit(hs->callback_mask, CBM_HOUSE_PRODUCE_CARGO)) { |
|
539 for (uint i = 0; i < 256; i++) { |
|
540 uint16 callback = GetHouseCallback(CBID_HOUSE_PRODUCE_CARGO, i, 0, house_id, t, tile); |
|
541 |
|
542 if (callback == CALLBACK_FAILED || callback == CALLBACK_HOUSEPRODCARGO_END) break; |
|
543 |
|
544 CargoID cargo = GetCargoTranslation(GB(callback, 8, 7), hs->grffile); |
|
545 |
|
546 if (cargo == CT_INVALID) continue; |
|
547 *(b++) = cargo; |
|
548 } |
|
549 } else { |
|
550 if (hs->population > 0) { |
|
551 *(b++) = CT_PASSENGERS; |
|
552 } |
|
553 if (hs->mail_generation > 0) { |
|
554 *(b++) = CT_MAIL; |
|
555 } |
|
556 } |
|
557 } |
|
558 |
540 static void GetAcceptedCargo_Town(TileIndex tile, AcceptedCargo ac) |
559 static void GetAcceptedCargo_Town(TileIndex tile, AcceptedCargo ac) |
541 { |
560 { |
542 HouseSpec *hs = GetHouseSpecs(GetHouseType(tile)); |
561 const HouseSpec *hs = GetHouseSpecs(GetHouseType(tile)); |
543 CargoID accepts[3]; |
562 CargoID accepts[3]; |
544 |
563 |
545 /* Set the initial accepted cargo types */ |
564 /* Set the initial accepted cargo types */ |
546 for (uint8 i = 0; i < lengthof(accepts); i++) { |
565 for (uint8 i = 0; i < lengthof(accepts); i++) { |
547 accepts[i] = hs->accepts_cargo[i]; |
566 accepts[i] = hs->accepts_cargo[i]; |
700 } |
719 } |
701 |
720 |
702 /** |
721 /** |
703 * Check if a Road is allowed on a given tile |
722 * Check if a Road is allowed on a given tile |
704 * |
723 * |
|
724 * @param t The current town |
705 * @param tile The target tile |
725 * @param tile The target tile |
706 * @param dir The direction in which we want to extend the town |
726 * @param dir The direction in which we want to extend the town |
707 * @return true if it is allowed else false |
727 * @return true if it is allowed else false |
708 */ |
728 */ |
709 static bool IsRoadAllowedHere(TileIndex tile, DiagDirection dir) |
729 static bool IsRoadAllowedHere(Town *t, TileIndex tile, DiagDirection dir) |
710 { |
730 { |
711 if (TileX(tile) < 2 || TileX(tile) >= MapMaxX() || TileY(tile) < 2 || TileY(tile) >= MapMaxY()) return false; |
731 if (TileX(tile) < 2 || TileX(tile) >= MapMaxX() || TileY(tile) < 2 || TileY(tile) >= MapMaxY()) return false; |
712 |
732 |
713 Slope cur_slope, desired_slope; |
733 Slope cur_slope, desired_slope; |
714 |
734 |
725 |
745 |
726 cur_slope = GetTileSlope(tile, NULL); |
746 cur_slope = GetTileSlope(tile, NULL); |
727 if (cur_slope == SLOPE_FLAT) { |
747 if (cur_slope == SLOPE_FLAT) { |
728 no_slope: |
748 no_slope: |
729 /* Tile has no slope */ |
749 /* Tile has no slope */ |
730 switch (_patches.town_layout) { |
750 switch (t->GetActiveLayout()) { |
731 default: NOT_REACHED(); |
751 default: NOT_REACHED(); |
732 |
752 |
733 case TL_ORIGINAL: // Disallow the road if any neighboring tile has a road (distance: 1) |
753 case TL_ORIGINAL: // Disallow the road if any neighboring tile has a road (distance: 1) |
734 return !IsNeighborRoadTile(tile, dir, 1); |
754 return !IsNeighborRoadTile(tile, dir, 1); |
735 |
755 |
760 } |
780 } |
761 } |
781 } |
762 |
782 |
763 static bool TerraformTownTile(TileIndex tile, int edges, int dir) |
783 static bool TerraformTownTile(TileIndex tile, int edges, int dir) |
764 { |
784 { |
765 CommandCost r; |
|
766 |
|
767 TILE_ASSERT(tile); |
785 TILE_ASSERT(tile); |
768 |
786 |
769 r = DoCommand(tile, edges, dir, DC_AUTO | DC_NO_WATER, CMD_TERRAFORM_LAND); |
787 CommandCost r = DoCommand(tile, edges, dir, DC_AUTO | DC_NO_WATER, CMD_TERRAFORM_LAND); |
770 if (CmdFailed(r) || r.GetCost() >= 126 * 16) return false; |
788 if (CmdFailed(r) || r.GetCost() >= (_price.terraform + 2) * 8) return false; |
771 DoCommand(tile, edges, dir, DC_AUTO | DC_NO_WATER | DC_EXEC, CMD_TERRAFORM_LAND); |
789 DoCommand(tile, edges, dir, DC_AUTO | DC_NO_WATER | DC_EXEC, CMD_TERRAFORM_LAND); |
772 return true; |
790 return true; |
773 } |
791 } |
774 |
792 |
775 static void LevelTownLand(TileIndex tile) |
793 static void LevelTownLand(TileIndex tile) |
776 { |
794 { |
777 Slope tileh; |
|
778 |
|
779 TILE_ASSERT(tile); |
795 TILE_ASSERT(tile); |
780 |
796 |
781 /* Don't terraform if land is plain or if there's a house there. */ |
797 /* Don't terraform if land is plain or if there's a house there. */ |
782 if (IsTileType(tile, MP_HOUSE)) return; |
798 if (IsTileType(tile, MP_HOUSE)) return; |
783 tileh = GetTileSlope(tile, NULL); |
799 Slope tileh = GetTileSlope(tile, NULL); |
784 if (tileh == SLOPE_FLAT) return; |
800 if (tileh == SLOPE_FLAT) return; |
785 |
801 |
786 /* First try up, then down */ |
802 /* First try up, then down */ |
787 if (!TerraformTownTile(tile, ~tileh & SLOPE_ELEVATED, 1)) { |
803 if (!TerraformTownTile(tile, ~tileh & SLOPE_ELEVATED, 1)) { |
788 TerraformTownTile(tile, tileh & SLOPE_ELEVATED, 0); |
804 TerraformTownTile(tile, tileh & SLOPE_ELEVATED, 0); |
796 * @param tile tile in reference to the town |
812 * @param tile tile in reference to the town |
797 * @param dir The direction to which we are growing ATM |
813 * @param dir The direction to which we are growing ATM |
798 * @return the RoadBit of the current tile regarding |
814 * @return the RoadBit of the current tile regarding |
799 * the selected town layout |
815 * the selected town layout |
800 */ |
816 */ |
801 static RoadBits GetTownRoadGridElement(Town* t, TileIndex tile, DiagDirection dir) |
817 static RoadBits GetTownRoadGridElement(Town *t, TileIndex tile, DiagDirection dir) |
802 { |
818 { |
803 /* align the grid to the downtown */ |
819 /* align the grid to the downtown */ |
804 TileIndexDiffC grid_pos = TileIndexToTileIndexDiffC(t->xy, tile); // Vector from downtown to the tile |
820 TileIndexDiffC grid_pos = TileIndexToTileIndexDiffC(t->xy, tile); // Vector from downtown to the tile |
805 RoadBits rcmd = ROAD_NONE; |
821 RoadBits rcmd = ROAD_NONE; |
806 |
822 |
807 switch (_patches.town_layout) { |
823 switch (t->GetActiveLayout()) { |
808 default: NOT_REACHED(); |
824 default: NOT_REACHED(); |
809 |
825 |
810 case TL_2X2_GRID: |
826 case TL_2X2_GRID: |
811 if ((grid_pos.x % 3) == 0) rcmd |= ROAD_Y; |
827 if ((grid_pos.x % 3) == 0) rcmd |= ROAD_Y; |
812 if ((grid_pos.y % 3) == 0) rcmd |= ROAD_X; |
828 if ((grid_pos.y % 3) == 0) rcmd |= ROAD_X; |
999 if (rcmd == ROAD_NONE) return; |
1015 if (rcmd == ROAD_NONE) return; |
1000 break; |
1016 break; |
1001 |
1017 |
1002 case TL_BETTER_ROADS: |
1018 case TL_BETTER_ROADS: |
1003 case TL_ORIGINAL: |
1019 case TL_ORIGINAL: |
1004 if (!IsRoadAllowedHere(tile, target_dir)) return; |
1020 if (!IsRoadAllowedHere(t1, tile, target_dir)) return; |
1005 |
1021 |
1006 DiagDirection source_dir = ReverseDiagDir(target_dir); |
1022 DiagDirection source_dir = ReverseDiagDir(target_dir); |
1007 |
1023 |
1008 if (Chance16(1, 4)) { |
1024 if (Chance16(1, 4)) { |
1009 /* Randomize a new target dir */ |
1025 /* Randomize a new target dir */ |
1010 do target_dir = RandomDiagDir(); while (target_dir == source_dir); |
1026 do target_dir = RandomDiagDir(); while (target_dir == source_dir); |
1011 } |
1027 } |
1012 |
1028 |
1013 if (!IsRoadAllowedHere(TileAddByDiagDir(tile, target_dir), target_dir)) { |
1029 if (!IsRoadAllowedHere(t1, TileAddByDiagDir(tile, target_dir), target_dir)) { |
1014 /* A road is not allowed to continue the randomized road, |
1030 /* A road is not allowed to continue the randomized road, |
1015 * return if the road we're trying to build is curved. */ |
1031 * return if the road we're trying to build is curved. */ |
1016 if (target_dir != ReverseDiagDir(source_dir)) return; |
1032 if (target_dir != ReverseDiagDir(source_dir)) return; |
1017 |
1033 |
1018 /* Return if neither side of the new road is a house */ |
1034 /* Return if neither side of the new road is a house */ |
1033 /* Continue building on a partial road. |
1049 /* Continue building on a partial road. |
1034 * Should be allways OK, so we only generate |
1050 * Should be allways OK, so we only generate |
1035 * the fitting RoadBits */ |
1051 * the fitting RoadBits */ |
1036 _grow_town_result = GROWTH_SEARCH_STOPPED; |
1052 _grow_town_result = GROWTH_SEARCH_STOPPED; |
1037 |
1053 |
1038 switch (_patches.town_layout) { |
1054 switch (t1->GetActiveLayout()) { |
1039 default: NOT_REACHED(); |
1055 default: NOT_REACHED(); |
1040 |
1056 |
1041 case TL_NO_ROADS: /* Disallow Roads */ |
1057 case TL_NO_ROADS: /* Disallow Roads */ |
1042 return; |
1058 return; |
1043 |
1059 |
1095 |
1111 |
1096 case TL_ORIGINAL: |
1112 case TL_ORIGINAL: |
1097 /* Allow a house at the edge. 60% chance or |
1113 /* Allow a house at the edge. 60% chance or |
1098 * always ok if no road allowed. */ |
1114 * always ok if no road allowed. */ |
1099 rcmd = DiagDirToRoadBits(target_dir); |
1115 rcmd = DiagDirToRoadBits(target_dir); |
1100 allow_house = (!IsRoadAllowedHere(house_tile, target_dir) || Chance16(6, 10)); |
1116 allow_house = (!IsRoadAllowedHere(t1, house_tile, target_dir) || Chance16(6, 10)); |
1101 break; |
1117 break; |
1102 } |
1118 } |
1103 |
1119 |
1104 if (allow_house) { |
1120 if (allow_house) { |
1105 /* Build a house, but not if there already is a house there. */ |
1121 /* Build a house, but not if there already is a house there. */ |
1216 if (a == b) b ^= 2; |
1232 if (a == b) b ^= 2; |
1217 return (RoadBits)((ROAD_NW << a) + (ROAD_NW << b)); |
1233 return (RoadBits)((ROAD_NW << a) + (ROAD_NW << b)); |
1218 } |
1234 } |
1219 |
1235 |
1220 /** Grow the town |
1236 /** Grow the town |
1221 * @Return true if a house was built, or no if the build failed. */ |
1237 * @param t town to grow |
|
1238 * @return true iff a house was built |
|
1239 */ |
1222 static bool GrowTown(Town *t) |
1240 static bool GrowTown(Town *t) |
1223 { |
1241 { |
1224 |
|
1225 /* Let the town be a ghost town |
1242 /* Let the town be a ghost town |
1226 * The player wanted it in such a way. Thus there he has it. ;) |
1243 * The player wanted it in such a way. Thus there he has it. ;) |
1227 * Never reached in editor mode. */ |
1244 * Never reached in editor mode. */ |
1228 if (_patches.town_layout == TL_NO_ROADS && _generating_world) { |
1245 if (_patches.town_layout == TL_NO_ROADS && _generating_world) { |
1229 return false; |
1246 return false; |
1242 {-2, 2}, |
1259 {-2, 2}, |
1243 { 2, 2}, |
1260 { 2, 2}, |
1244 { 2, -2}, |
1261 { 2, -2}, |
1245 { 0, 0} |
1262 { 0, 0} |
1246 }; |
1263 }; |
1247 const TileIndexDiffC *ptr; |
|
1248 |
1264 |
1249 /* Current player is a town */ |
1265 /* Current player is a town */ |
1250 PlayerID old_player = _current_player; |
1266 PlayerID old_player = _current_player; |
1251 _current_player = OWNER_TOWN; |
1267 _current_player = OWNER_TOWN; |
1252 |
1268 |
1253 TileIndex tile = t->xy; // The tile we are working with ATM |
1269 TileIndex tile = t->xy; // The tile we are working with ATM |
1254 |
1270 |
1255 /* Find a road that we can base the construction on. */ |
1271 /* Find a road that we can base the construction on. */ |
|
1272 const TileIndexDiffC *ptr; |
1256 for (ptr = _town_coord_mod; ptr != endof(_town_coord_mod); ++ptr) { |
1273 for (ptr = _town_coord_mod; ptr != endof(_town_coord_mod); ++ptr) { |
1257 if (GetTownRoadBits(tile) != ROAD_NONE) { |
1274 if (GetTownRoadBits(tile) != ROAD_NONE) { |
1258 int r = GrowTownAtRoad(t, tile); |
1275 int r = GrowTownAtRoad(t, tile); |
1259 _current_player = old_player; |
1276 _current_player = old_player; |
1260 return r != 0; |
1277 return r != 0; |
1390 * @param size Parameter for size determination |
1407 * @param size Parameter for size determination |
1391 */ |
1408 */ |
1392 static void DoCreateTown(Town *t, TileIndex tile, uint32 townnameparts, TownSizeMode size_mode, uint size) |
1409 static void DoCreateTown(Town *t, TileIndex tile, uint32 townnameparts, TownSizeMode size_mode, uint size) |
1393 { |
1410 { |
1394 extern int _nb_orig_names; |
1411 extern int _nb_orig_names; |
1395 int x, i; |
|
1396 |
1412 |
1397 t->xy = tile; |
1413 t->xy = tile; |
1398 t->num_houses = 0; |
1414 t->num_houses = 0; |
1399 t->time_until_rebuild = 10; |
1415 t->time_until_rebuild = 10; |
1400 UpdateTownRadius(t); |
1416 UpdateTownRadius(t); |
1439 t->townnameparts = townnameparts; |
1454 t->townnameparts = townnameparts; |
1440 |
1455 |
1441 UpdateTownVirtCoord(t); |
1456 UpdateTownVirtCoord(t); |
1442 _town_sort_dirty = true; |
1457 _town_sort_dirty = true; |
1443 |
1458 |
|
1459 t->InitializeLayout(); |
|
1460 |
1444 /* Random town size. */ |
1461 /* Random town size. */ |
1445 x = (Random() & 0xF) + 8; |
1462 int x = (Random() & 0xF) + 8; |
1446 |
1463 |
1447 switch (size_mode) { |
1464 switch (size_mode) { |
1448 default: NOT_REACHED(); |
1465 default: NOT_REACHED(); |
1449 |
1466 |
1450 case TSM_RANDOM: |
1467 case TSM_RANDOM: |
1483 * @param p1 size of the town (0 = small, 1 = medium, 2 = large) |
1500 * @param p1 size of the town (0 = small, 1 = medium, 2 = large) |
1484 * @param p2 size mode (@see TownSizeMode) |
1501 * @param p2 size mode (@see TownSizeMode) |
1485 */ |
1502 */ |
1486 CommandCost CmdBuildTown(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1503 CommandCost CmdBuildTown(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1487 { |
1504 { |
1488 uint32 townnameparts; |
|
1489 |
|
1490 /* Only in the scenario editor */ |
1505 /* Only in the scenario editor */ |
1491 if (_game_mode != GM_EDITOR) return CMD_ERROR; |
1506 if (_game_mode != GM_EDITOR) return CMD_ERROR; |
1492 if (p2 > TSM_CITY) return CMD_ERROR; |
1507 if (p2 > TSM_CITY) return CMD_ERROR; |
1493 |
1508 |
1494 /* Check if too close to the edge of map */ |
1509 /* Check if too close to the edge of map */ |
1501 } |
1516 } |
1502 |
1517 |
1503 /* Check distance to all other towns. */ |
1518 /* Check distance to all other towns. */ |
1504 if (IsCloseToTown(tile, 20)) |
1519 if (IsCloseToTown(tile, 20)) |
1505 return_cmd_error(STR_0238_TOO_CLOSE_TO_ANOTHER_TOWN); |
1520 return_cmd_error(STR_0238_TOO_CLOSE_TO_ANOTHER_TOWN); |
|
1521 |
|
1522 uint32 townnameparts; |
1506 |
1523 |
1507 /* Get a unique name for the town. */ |
1524 /* Get a unique name for the town. */ |
1508 if (!CreateTownName(&townnameparts)) |
1525 if (!CreateTownName(&townnameparts)) |
1509 return_cmd_error(STR_023A_TOO_MANY_TOWNS); |
1526 return_cmd_error(STR_023A_TOO_MANY_TOWNS); |
1510 |
1527 |
1523 return CommandCost(); |
1540 return CommandCost(); |
1524 } |
1541 } |
1525 |
1542 |
1526 Town *CreateRandomTown(uint attempts, TownSizeMode mode, uint size) |
1543 Town *CreateRandomTown(uint attempts, TownSizeMode mode, uint size) |
1527 { |
1544 { |
1528 TileIndex tile; |
|
1529 Town *t; |
|
1530 uint32 townnameparts; |
|
1531 |
|
1532 do { |
1545 do { |
1533 /* Generate a tile index not too close from the edge */ |
1546 /* Generate a tile index not too close from the edge */ |
1534 tile = RandomTile(); |
1547 TileIndex tile = RandomTile(); |
1535 if (DistanceFromEdge(tile) < 20) continue; |
1548 if (DistanceFromEdge(tile) < 20) continue; |
1536 |
1549 |
1537 /* Make sure the tile is plain */ |
1550 /* Make sure the tile is plain */ |
1538 if (!IsTileType(tile, MP_CLEAR) || GetTileSlope(tile, NULL) != SLOPE_FLAT) continue; |
1551 if (!IsTileType(tile, MP_CLEAR) || GetTileSlope(tile, NULL) != SLOPE_FLAT) continue; |
1539 |
1552 |
1540 /* Check not too close to a town */ |
1553 /* Check not too close to a town */ |
1541 if (IsCloseToTown(tile, 20)) continue; |
1554 if (IsCloseToTown(tile, 20)) continue; |
1542 |
1555 |
|
1556 uint32 townnameparts; |
|
1557 |
1543 /* Get a unique name for the town. */ |
1558 /* Get a unique name for the town. */ |
1544 if (!CreateTownName(&townnameparts)) break; |
1559 if (!CreateTownName(&townnameparts)) break; |
1545 |
1560 |
1546 /* Allocate a town struct */ |
1561 /* Allocate a town struct */ |
1547 t = new Town(tile); |
1562 Town *t = new Town(tile); |
1548 if (t == NULL) break; |
1563 if (t == NULL) break; |
1549 |
1564 |
1550 DoCreateTown(t, tile, townnameparts, mode, size); |
1565 DoCreateTown(t, tile, townnameparts, mode, size); |
1551 return t; |
1566 return t; |
1552 } while (--attempts); |
1567 } while (--attempts != 0); |
|
1568 |
1553 return NULL; |
1569 return NULL; |
1554 } |
1570 } |
1555 |
1571 |
1556 static const byte _num_initial_towns[4] = {5, 11, 23, 46}; |
1572 static const byte _num_initial_towns[4] = {5, 11, 23, 46}; |
1557 |
1573 |
1588 /** Returns the bit corresponding to the town zone of the specified tile |
1604 /** Returns the bit corresponding to the town zone of the specified tile |
1589 * @param t Town on which radius is to be found |
1605 * @param t Town on which radius is to be found |
1590 * @param tile TileIndex where radius needs to be found |
1606 * @param tile TileIndex where radius needs to be found |
1591 * @return the bit position of the given zone, as defined in HouseZones |
1607 * @return the bit position of the given zone, as defined in HouseZones |
1592 */ |
1608 */ |
1593 HouseZonesBits GetTownRadiusGroup(const Town* t, TileIndex tile) |
1609 HouseZonesBits GetTownRadiusGroup(const Town *t, TileIndex tile) |
1594 { |
1610 { |
1595 uint dist = DistanceSquare(tile, t->xy); |
1611 uint dist = DistanceSquare(tile, t->xy); |
1596 HouseZonesBits smallest; |
|
1597 uint i; |
|
1598 |
1612 |
1599 if (t->fund_buildings_months && dist <= 25) return HZB_TOWN_CENTRE; |
1613 if (t->fund_buildings_months && dist <= 25) return HZB_TOWN_CENTRE; |
1600 |
1614 |
1601 smallest = HZB_TOWN_EDGE; |
1615 HouseZonesBits smallest = HZB_TOWN_EDGE; |
1602 for (i = 0; i != lengthof(t->radius); i++) { |
1616 for (HouseZonesBits i = HZB_BEGIN; i < HZB_END; i++) { |
1603 if (dist < t->radius[i]) smallest = (HouseZonesBits)i; |
1617 if (dist < t->radius[i]) smallest = i; |
1604 } |
1618 } |
1605 |
1619 |
1606 return smallest; |
1620 return smallest; |
1607 } |
1621 } |
1608 |
1622 |
1759 /* MapSize() is sure dividable by both MapSizeX() and MapSizeY(), |
1773 /* MapSize() is sure dividable by both MapSizeX() and MapSizeY(), |
1760 * so to do only one memory access, use MapSize() */ |
1774 * so to do only one memory access, use MapSize() */ |
1761 uint dx = MapSize() + TileX(t->xy) - TileX(tile); |
1775 uint dx = MapSize() + TileX(t->xy) - TileX(tile); |
1762 uint dy = MapSize() + TileY(t->xy) - TileY(tile); |
1776 uint dy = MapSize() + TileY(t->xy) - TileY(tile); |
1763 |
1777 |
1764 switch (_patches.town_layout) { |
1778 switch (t->GetActiveLayout()) { |
1765 case TL_2X2_GRID: |
1779 case TL_2X2_GRID: |
1766 if ((dx % 3) != 0 || (dy % 3) != 0) return false; |
1780 if ((dx % 3) != 0 || (dy % 3) != 0) return false; |
1767 break; |
1781 break; |
1768 |
1782 |
1769 case TL_3X3_GRID: |
1783 case TL_3X3_GRID: |
1864 uint probs[HOUSE_MAX]; |
1878 uint probs[HOUSE_MAX]; |
1865 uint probability_max = 0; |
1879 uint probability_max = 0; |
1866 |
1880 |
1867 /* Generate a list of all possible houses that can be built. */ |
1881 /* Generate a list of all possible houses that can be built. */ |
1868 for (uint i = 0; i < HOUSE_MAX; i++) { |
1882 for (uint i = 0; i < HOUSE_MAX; i++) { |
1869 HouseSpec *hs = GetHouseSpecs(i); |
1883 const HouseSpec *hs = GetHouseSpecs(i); |
1870 /* Verify that the candidate house spec matches the current tile status */ |
1884 /* Verify that the candidate house spec matches the current tile status */ |
1871 if ((~hs->building_availability & bitmask) == 0 && hs->enabled) { |
1885 if ((~hs->building_availability & bitmask) == 0 && hs->enabled) { |
1872 /* Without NewHouses, all houses have probability '1' */ |
1886 /* Without NewHouses, all houses have probability '1' */ |
1873 uint cur_prob = (_loaded_newgrf_features.has_newhouses ? hs->probability : 1); |
1887 uint cur_prob = (_loaded_newgrf_features.has_newhouses ? hs->probability : 1); |
1874 probability_max += cur_prob; |
1888 probability_max += cur_prob; |
1893 /* remove tested house from the set */ |
1907 /* remove tested house from the set */ |
1894 num--; |
1908 num--; |
1895 houses[i] = houses[num]; |
1909 houses[i] = houses[num]; |
1896 probs[i] = probs[num]; |
1910 probs[i] = probs[num]; |
1897 |
1911 |
1898 HouseSpec *hs = GetHouseSpecs(house); |
1912 const HouseSpec *hs = GetHouseSpecs(house); |
1899 |
1913 |
1900 if (_loaded_newgrf_features.has_newhouses) { |
1914 if (_loaded_newgrf_features.has_newhouses) { |
1901 if (hs->override != 0) { |
1915 if (hs->override != 0) { |
1902 house = hs->override; |
1916 house = hs->override; |
1903 hs = GetHouseSpecs(house); |
1917 hs = GetHouseSpecs(house); |
1977 DeleteAnimatedTile(tile); |
1991 DeleteAnimatedTile(tile); |
1978 } |
1992 } |
1979 |
1993 |
1980 void ClearTownHouse(Town *t, TileIndex tile) |
1994 void ClearTownHouse(Town *t, TileIndex tile) |
1981 { |
1995 { |
|
1996 assert(IsTileType(tile, MP_HOUSE)); |
|
1997 |
1982 HouseID house = GetHouseType(tile); |
1998 HouseID house = GetHouseType(tile); |
1983 uint eflags; |
|
1984 HouseSpec *hs; |
|
1985 |
|
1986 assert(IsTileType(tile, MP_HOUSE)); |
|
1987 |
1999 |
1988 /* need to align the tile to point to the upper left corner of the house */ |
2000 /* need to align the tile to point to the upper left corner of the house */ |
1989 if (house >= 3) { // house id 0,1,2 MUST be single tile houses, or this code breaks. |
2001 if (house >= 3) { // house id 0,1,2 MUST be single tile houses, or this code breaks. |
1990 if (GetHouseSpecs(house-1)->building_flags & TILE_SIZE_2x1) { |
2002 if (GetHouseSpecs(house-1)->building_flags & TILE_SIZE_2x1) { |
1991 house--; |
2003 house--; |
2018 } else if (hs->building_flags & BUILDING_IS_STADIUM) { |
2030 } else if (hs->building_flags & BUILDING_IS_STADIUM) { |
2019 ClrBit(t->flags12, TOWN_HAS_STADIUM); |
2031 ClrBit(t->flags12, TOWN_HAS_STADIUM); |
2020 } |
2032 } |
2021 |
2033 |
2022 /* Do the actual clearing of tiles */ |
2034 /* Do the actual clearing of tiles */ |
2023 eflags = hs->building_flags; |
2035 uint eflags = hs->building_flags; |
2024 DoClearTownHouseHelper(tile); |
2036 DoClearTownHouseHelper(tile); |
2025 if (eflags & BUILDING_2_TILES_X) DoClearTownHouseHelper(tile + TileDiffXY(1, 0)); |
2037 if (eflags & BUILDING_2_TILES_X) DoClearTownHouseHelper(tile + TileDiffXY(1, 0)); |
2026 if (eflags & BUILDING_2_TILES_Y) DoClearTownHouseHelper(tile + TileDiffXY(0, 1)); |
2038 if (eflags & BUILDING_2_TILES_Y) DoClearTownHouseHelper(tile + TileDiffXY(0, 1)); |
2027 if (eflags & BUILDING_HAS_4_TILES) DoClearTownHouseHelper(tile + TileDiffXY(1, 1)); |
2039 if (eflags & BUILDING_HAS_4_TILES) DoClearTownHouseHelper(tile + TileDiffXY(1, 1)); |
2028 } |
2040 } |
2047 * @param p1 town ID to rename |
2059 * @param p1 town ID to rename |
2048 * @param p2 unused |
2060 * @param p2 unused |
2049 */ |
2061 */ |
2050 CommandCost CmdRenameTown(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
2062 CommandCost CmdRenameTown(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
2051 { |
2063 { |
2052 Town *t; |
|
2053 |
|
2054 if (!IsValidTownID(p1) || StrEmpty(_cmd_text)) return CMD_ERROR; |
2064 if (!IsValidTownID(p1) || StrEmpty(_cmd_text)) return CMD_ERROR; |
2055 |
2065 |
2056 t = GetTown(p1); |
|
2057 |
|
2058 if (!IsUniqueTownName(_cmd_text)) return_cmd_error(STR_NAME_MUST_BE_UNIQUE); |
2066 if (!IsUniqueTownName(_cmd_text)) return_cmd_error(STR_NAME_MUST_BE_UNIQUE); |
2059 |
2067 |
2060 if (flags & DC_EXEC) { |
2068 if (flags & DC_EXEC) { |
|
2069 Town *t = GetTown(p1); |
|
2070 |
2061 free(t->name); |
2071 free(t->name); |
2062 t->name = strdup(_cmd_text); |
2072 t->name = strdup(_cmd_text); |
2063 |
2073 |
2064 UpdateTownVirtCoord(t); |
2074 UpdateTownVirtCoord(t); |
2065 _town_sort_dirty = true; |
2075 _town_sort_dirty = true; |
2071 } |
2081 } |
2072 |
2082 |
2073 /** Called from GUI */ |
2083 /** Called from GUI */ |
2074 void ExpandTown(Town *t) |
2084 void ExpandTown(Town *t) |
2075 { |
2085 { |
2076 uint amount, n; |
|
2077 |
|
2078 _generating_world = true; |
2086 _generating_world = true; |
2079 |
2087 |
2080 /* The more houses, the faster we grow */ |
2088 /* The more houses, the faster we grow */ |
2081 amount = RandomRange(ClampToU16(t->num_houses / 10)) + 3; |
2089 uint amount = RandomRange(ClampToU16(t->num_houses / 10)) + 3; |
2082 t->num_houses += amount; |
2090 t->num_houses += amount; |
2083 UpdateTownRadius(t); |
2091 UpdateTownRadius(t); |
2084 |
2092 |
2085 n = amount * 10; |
2093 uint n = amount * 10; |
2086 do GrowTown(t); while (--n); |
2094 do GrowTown(t); while (--n); |
2087 |
2095 |
2088 t->num_houses -= amount; |
2096 t->num_houses -= amount; |
2089 UpdateTownRadius(t); |
2097 UpdateTownRadius(t); |
2090 |
2098 |
2094 |
2102 |
2095 extern const byte _town_action_costs[8] = { |
2103 extern const byte _town_action_costs[8] = { |
2096 2, 4, 9, 35, 48, 53, 117, 175 |
2104 2, 4, 9, 35, 48, 53, 117, 175 |
2097 }; |
2105 }; |
2098 |
2106 |
2099 static void TownActionAdvertiseSmall(Town* t) |
2107 static void TownActionAdvertiseSmall(Town *t) |
2100 { |
2108 { |
2101 ModifyStationRatingAround(t->xy, _current_player, 0x40, 10); |
2109 ModifyStationRatingAround(t->xy, _current_player, 0x40, 10); |
2102 } |
2110 } |
2103 |
2111 |
2104 static void TownActionAdvertiseMedium(Town* t) |
2112 static void TownActionAdvertiseMedium(Town *t) |
2105 { |
2113 { |
2106 ModifyStationRatingAround(t->xy, _current_player, 0x70, 15); |
2114 ModifyStationRatingAround(t->xy, _current_player, 0x70, 15); |
2107 } |
2115 } |
2108 |
2116 |
2109 static void TownActionAdvertiseLarge(Town* t) |
2117 static void TownActionAdvertiseLarge(Town *t) |
2110 { |
2118 { |
2111 ModifyStationRatingAround(t->xy, _current_player, 0xA0, 20); |
2119 ModifyStationRatingAround(t->xy, _current_player, 0xA0, 20); |
2112 } |
2120 } |
2113 |
2121 |
2114 static void TownActionRoadRebuild(Town* t) |
2122 static void TownActionRoadRebuild(Town *t) |
2115 { |
2123 { |
2116 t->road_build_months = 6; |
2124 t->road_build_months = 6; |
2117 |
2125 |
2118 SetDParam(0, t->index); |
2126 SetDParam(0, t->index); |
2119 SetDParam(1, _current_player); |
2127 SetDParam(1, _current_player); |
2122 NM_NORMAL, NF_TILE, NT_GENERAL, DNC_NONE, t->xy, 0); |
2130 NM_NORMAL, NF_TILE, NT_GENERAL, DNC_NONE, t->xy, 0); |
2123 } |
2131 } |
2124 |
2132 |
2125 static bool DoBuildStatueOfCompany(TileIndex tile, TownID town_id) |
2133 static bool DoBuildStatueOfCompany(TileIndex tile, TownID town_id) |
2126 { |
2134 { |
2127 PlayerID old; |
|
2128 CommandCost r; |
|
2129 |
|
2130 /* Statues can be build on slopes, just like houses. Only the steep slopes is a no go. */ |
2135 /* Statues can be build on slopes, just like houses. Only the steep slopes is a no go. */ |
2131 if (IsSteepSlope(GetTileSlope(tile, NULL))) return false; |
2136 if (IsSteepSlope(GetTileSlope(tile, NULL))) return false; |
2132 |
2137 |
2133 if (!IsTileType(tile, MP_HOUSE) && |
2138 if (!IsTileType(tile, MP_HOUSE) && |
2134 !IsTileType(tile, MP_CLEAR) && |
2139 !IsTileType(tile, MP_CLEAR) && |
2135 !IsTileType(tile, MP_TREES)) { |
2140 !IsTileType(tile, MP_TREES)) { |
2136 return false; |
2141 return false; |
2137 } |
2142 } |
2138 |
2143 |
2139 old = _current_player; |
2144 PlayerID old = _current_player; |
2140 _current_player = OWNER_NONE; |
2145 _current_player = OWNER_NONE; |
2141 r = DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR); |
2146 CommandCost r = DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR); |
2142 _current_player = old; |
2147 _current_player = old; |
2143 |
2148 |
2144 if (CmdFailed(r)) return false; |
2149 if (CmdFailed(r)) return false; |
2145 |
2150 |
2146 MakeStatue(tile, _current_player, town_id); |
2151 MakeStatue(tile, _current_player, town_id); |
2163 /** |
2168 /** |
2164 * Perform a 9x9 tiles circular search from the center of the town |
2169 * Perform a 9x9 tiles circular search from the center of the town |
2165 * in order to find a free tile to place a statue |
2170 * in order to find a free tile to place a statue |
2166 * @param t town to search in |
2171 * @param t town to search in |
2167 */ |
2172 */ |
2168 static void TownActionBuildStatue(Town* t) |
2173 static void TownActionBuildStatue(Town *t) |
2169 { |
2174 { |
2170 TileIndex tile = t->xy; |
2175 TileIndex tile = t->xy; |
2171 |
2176 |
2172 if (CircularTileSearch(tile, 9, SearchTileForStatue, t->index)) |
2177 if (CircularTileSearch(tile, 9, SearchTileForStatue, t->index)) { |
2173 SetBit(t->statues, _current_player); // Once found and built, "inform" the Town |
2178 SetBit(t->statues, _current_player); // Once found and built, "inform" the Town |
2174 } |
2179 } |
2175 |
2180 } |
2176 static void TownActionFundBuildings(Town* t) |
2181 |
|
2182 static void TownActionFundBuildings(Town *t) |
2177 { |
2183 { |
2178 /* Build next tick */ |
2184 /* Build next tick */ |
2179 t->grow_counter = 1; |
2185 t->grow_counter = 1; |
2180 /* If we were not already growing */ |
2186 /* If we were not already growing */ |
2181 SetBit(t->flags12, TOWN_IS_FUNDED); |
2187 SetBit(t->flags12, TOWN_IS_FUNDED); |
2182 /* And grow for 3 months */ |
2188 /* And grow for 3 months */ |
2183 t->fund_buildings_months = 3; |
2189 t->fund_buildings_months = 3; |
2184 } |
2190 } |
2185 |
2191 |
2186 static void TownActionBuyRights(Town* t) |
2192 static void TownActionBuyRights(Town *t) |
2187 { |
2193 { |
2188 /* Check if it's allowed to by the rights */ |
2194 /* Check if it's allowed to by the rights */ |
2189 if (!_patches.exclusive_rights) return; |
2195 if (!_patches.exclusive_rights) return; |
2190 |
2196 |
2191 t->exclusive_counter = 12; |
2197 t->exclusive_counter = 12; |
2192 t->exclusivity = _current_player; |
2198 t->exclusivity = _current_player; |
2193 |
2199 |
2194 ModifyStationRatingAround(t->xy, _current_player, 130, 17); |
2200 ModifyStationRatingAround(t->xy, _current_player, 130, 17); |
2195 } |
2201 } |
2196 |
2202 |
2197 static void TownActionBribe(Town* t) |
2203 static void TownActionBribe(Town *t) |
2198 { |
2204 { |
2199 if (!RandomRange(15)) { |
2205 if (Chance16(1, 14)) { |
2200 Station *st; |
|
2201 |
|
2202 /* set as unwanted for 6 months */ |
2206 /* set as unwanted for 6 months */ |
2203 t->unwanted[_current_player] = 6; |
2207 t->unwanted[_current_player] = 6; |
2204 |
2208 |
2205 /* set all close by station ratings to 0 */ |
2209 /* set all close by station ratings to 0 */ |
|
2210 Station *st; |
2206 FOR_ALL_STATIONS(st) { |
2211 FOR_ALL_STATIONS(st) { |
2207 if (st->town == t && st->owner == _current_player) { |
2212 if (st->town == t && st->owner == _current_player) { |
2208 for (CargoID i = 0; i < NUM_CARGO; i++) st->goods[i].rating = 0; |
2213 for (CargoID i = 0; i < NUM_CARGO; i++) st->goods[i].rating = 0; |
2209 } |
2214 } |
2210 } |
2215 } |
2223 } else { |
2228 } else { |
2224 ChangeTownRating(t, RATING_BRIBE_UP_STEP, RATING_BRIBE_MAXIMUM); |
2229 ChangeTownRating(t, RATING_BRIBE_UP_STEP, RATING_BRIBE_MAXIMUM); |
2225 } |
2230 } |
2226 } |
2231 } |
2227 |
2232 |
2228 typedef void TownActionProc(Town* t); |
2233 typedef void TownActionProc(Town *t); |
2229 static TownActionProc * const _town_action_proc[] = { |
2234 static TownActionProc *const _town_action_proc[] = { |
2230 TownActionAdvertiseSmall, |
2235 TownActionAdvertiseSmall, |
2231 TownActionAdvertiseMedium, |
2236 TownActionAdvertiseMedium, |
2232 TownActionAdvertiseLarge, |
2237 TownActionAdvertiseLarge, |
2233 TownActionRoadRebuild, |
2238 TownActionRoadRebuild, |
2234 TownActionBuildStatue, |
2239 TownActionBuildStatue, |
2247 * @param p1 town to do the action at |
2252 * @param p1 town to do the action at |
2248 * @param p2 action to perform, @see _town_action_proc for the list of available actions |
2253 * @param p2 action to perform, @see _town_action_proc for the list of available actions |
2249 */ |
2254 */ |
2250 CommandCost CmdDoTownAction(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
2255 CommandCost CmdDoTownAction(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
2251 { |
2256 { |
2252 Town *t; |
|
2253 |
|
2254 if (!IsValidTownID(p1) || p2 > lengthof(_town_action_proc)) return CMD_ERROR; |
2257 if (!IsValidTownID(p1) || p2 > lengthof(_town_action_proc)) return CMD_ERROR; |
2255 |
2258 |
2256 t = GetTown(p1); |
2259 Town *t = GetTown(p1); |
2257 |
2260 |
2258 if (!HasBit(GetMaskOfTownActions(NULL, _current_player, t), p2)) return CMD_ERROR; |
2261 if (!HasBit(GetMaskOfTownActions(NULL, _current_player, t), p2)) return CMD_ERROR; |
2259 |
2262 |
2260 CommandCost cost(EXPENSES_OTHER, (_price.build_industry >> 8) * _town_action_costs[p2]); |
2263 CommandCost cost(EXPENSES_OTHER, (_price.build_industry >> 8) * _town_action_costs[p2]); |
2261 |
2264 |
2267 return cost; |
2270 return cost; |
2268 } |
2271 } |
2269 |
2272 |
2270 static void UpdateTownGrowRate(Town *t) |
2273 static void UpdateTownGrowRate(Town *t) |
2271 { |
2274 { |
2272 int n; |
2275 /* Increase player ratings if they're low */ |
2273 Station *st; |
2276 const Player *p; |
2274 uint16 m; |
|
2275 Player *p; |
|
2276 |
|
2277 /* Reset player ratings if they're low */ |
|
2278 FOR_ALL_PLAYERS(p) { |
2277 FOR_ALL_PLAYERS(p) { |
2279 if (p->is_active && t->ratings[p->index] <= 200) { |
2278 if (p->is_active) { |
2280 t->ratings[p->index] += 5; |
2279 t->ratings[p->index] = min((int)RATING_GROWTH_MAXIMUM, t->ratings[p->index] + RATING_GROWTH_UP_STEP); |
2281 } |
2280 } |
2282 } |
2281 } |
2283 |
2282 |
2284 n = 0; |
2283 int n = 0; |
|
2284 |
|
2285 const Station *st; |
2285 FOR_ALL_STATIONS(st) { |
2286 FOR_ALL_STATIONS(st) { |
2286 if (DistanceSquare(st->xy, t->xy) <= t->radius[0]) { |
2287 if (DistanceSquare(st->xy, t->xy) <= t->radius[0]) { |
2287 if (st->time_since_load <= 20 || st->time_since_unload <= 20) { |
2288 if (st->time_since_load <= 20 || st->time_since_unload <= 20) { |
2288 n++; |
2289 n++; |
2289 if (IsValidPlayer(st->owner) && t->ratings[st->owner] <= 1000-12) |
2290 if (IsValidPlayer(st->owner)) { |
2290 t->ratings[st->owner] += 12; |
2291 int new_rating = t->ratings[st->owner] + RATING_STATION_UP_STEP; |
|
2292 t->ratings[st->owner] = min(new_rating, INT16_MAX); // do not let it overflow |
|
2293 } |
2291 } else { |
2294 } else { |
2292 if (IsValidPlayer(st->owner) && t->ratings[st->owner] >= -1000+15) |
2295 if (IsValidPlayer(st->owner)) { |
2293 t->ratings[st->owner] -= 15; |
2296 int new_rating = t->ratings[st->owner] + RATING_STATION_DOWN_STEP; |
|
2297 t->ratings[st->owner] = max(new_rating, INT16_MIN); |
|
2298 } |
2294 } |
2299 } |
2295 } |
2300 } |
|
2301 } |
|
2302 |
|
2303 /* clamp all ratings to valid values */ |
|
2304 for (uint i = 0; i < MAX_PLAYERS; i++) { |
|
2305 t->ratings[i] = Clamp(t->ratings[i], RATING_MINIMUM, RATING_MAXIMUM); |
2296 } |
2306 } |
2297 |
2307 |
2298 ClrBit(t->flags12, TOWN_IS_FUNDED); |
2308 ClrBit(t->flags12, TOWN_IS_FUNDED); |
2299 if (_patches.town_growth_rate == 0 && t->fund_buildings_months == 0) return; |
2309 if (_patches.town_growth_rate == 0 && t->fund_buildings_months == 0) return; |
2300 |
2310 |
2303 static const uint16 _grow_count_values[2][6] = { |
2313 static const uint16 _grow_count_values[2][6] = { |
2304 { 120, 120, 120, 100, 80, 60 }, // Fund new buildings has been activated |
2314 { 120, 120, 120, 100, 80, 60 }, // Fund new buildings has been activated |
2305 { 320, 420, 300, 220, 160, 100 } // Normal values |
2315 { 320, 420, 300, 220, 160, 100 } // Normal values |
2306 }; |
2316 }; |
2307 |
2317 |
|
2318 uint16 m; |
|
2319 |
2308 if (t->fund_buildings_months != 0) { |
2320 if (t->fund_buildings_months != 0) { |
2309 m = _grow_count_values[0][min(n, 5)]; |
2321 m = _grow_count_values[0][min(n, 5)]; |
2310 t->fund_buildings_months--; |
2322 t->fund_buildings_months--; |
2311 } else { |
2323 } else { |
2312 m = _grow_count_values[1][min(n, 5)]; |
2324 m = _grow_count_values[1][min(n, 5)]; |
2353 InvalidateWindow(WC_TOWN_VIEW, t->index); |
2365 InvalidateWindow(WC_TOWN_VIEW, t->index); |
2354 } |
2366 } |
2355 |
2367 |
2356 static void UpdateTownUnwanted(Town *t) |
2368 static void UpdateTownUnwanted(Town *t) |
2357 { |
2369 { |
2358 const Player* p; |
2370 const Player *p; |
2359 |
2371 |
2360 FOR_ALL_PLAYERS(p) { |
2372 FOR_ALL_PLAYERS(p) { |
2361 if (t->unwanted[p->index] > 0) t->unwanted[p->index]--; |
2373 if (t->unwanted[p->index] > 0) t->unwanted[p->index]--; |
2362 } |
2374 } |
2363 } |
2375 } |
2364 |
2376 |
2365 bool CheckIfAuthorityAllows(TileIndex tile) |
2377 bool CheckIfAuthorityAllows(TileIndex tile) |
2366 { |
2378 { |
2367 Town *t; |
|
2368 |
|
2369 if (!IsValidPlayer(_current_player)) return true; |
2379 if (!IsValidPlayer(_current_player)) return true; |
2370 |
2380 |
2371 t = ClosestTownFromTile(tile, _patches.dist_local_authority); |
2381 Town *t = ClosestTownFromTile(tile, _patches.dist_local_authority); |
2372 if (t == NULL) return true; |
2382 if (t == NULL) return true; |
2373 |
2383 |
2374 if (t->ratings[_current_player] > -200) return true; |
2384 if (t->ratings[_current_player] > RATING_VERYPOOR) return true; |
2375 |
2385 |
2376 _error_message = STR_2009_LOCAL_AUTHORITY_REFUSES; |
2386 _error_message = STR_2009_LOCAL_AUTHORITY_REFUSES; |
2377 SetDParam(0, t->index); |
2387 SetDParam(0, t->index); |
2378 |
2388 |
2379 return false; |
2389 return false; |
2380 } |
2390 } |
2381 |
2391 |
2382 |
2392 |
2383 Town* CalcClosestTownFromTile(TileIndex tile, uint threshold) |
2393 Town *CalcClosestTownFromTile(TileIndex tile, uint threshold) |
2384 { |
2394 { |
2385 Town *t; |
2395 Town *t; |
2386 uint dist, best = threshold; |
2396 uint best = threshold; |
2387 Town *best_town = NULL; |
2397 Town *best_town = NULL; |
2388 |
2398 |
2389 FOR_ALL_TOWNS(t) { |
2399 FOR_ALL_TOWNS(t) { |
2390 dist = DistanceManhattan(tile, t->xy); |
2400 uint dist = DistanceManhattan(tile, t->xy); |
2391 if (dist < best) { |
2401 if (dist < best) { |
2392 best = dist; |
2402 best = dist; |
2393 best_town = t; |
2403 best_town = t; |
2394 } |
2404 } |
2395 } |
2405 } |
2428 _town_rating_test = !(ref_count == 0); |
2438 _town_rating_test = !(ref_count == 0); |
2429 } |
2439 } |
2430 |
2440 |
2431 void ChangeTownRating(Town *t, int add, int max) |
2441 void ChangeTownRating(Town *t, int add, int max) |
2432 { |
2442 { |
2433 int rating; |
|
2434 |
|
2435 /* if magic_bulldozer cheat is active, town doesn't penaltize for removing stuff */ |
2443 /* if magic_bulldozer cheat is active, town doesn't penaltize for removing stuff */ |
2436 if (t == NULL || |
2444 if (t == NULL || |
2437 !IsValidPlayer(_current_player) || |
2445 !IsValidPlayer(_current_player) || |
2438 (_cheats.magic_bulldozer.value && add < 0)) { |
2446 (_cheats.magic_bulldozer.value && add < 0)) { |
2439 return; |
2447 return; |
2440 } |
2448 } |
2441 |
2449 |
2442 SetBit(t->have_ratings, _current_player); |
2450 SetBit(t->have_ratings, _current_player); |
2443 |
2451 |
2444 rating = _town_rating_test ? t->test_rating : t->ratings[_current_player]; |
2452 int rating = _town_rating_test ? t->test_rating : t->ratings[_current_player]; |
2445 |
2453 |
2446 if (add < 0) { |
2454 if (add < 0) { |
2447 if (rating > max) { |
2455 if (rating > max) { |
2448 rating += add; |
2456 rating += add; |
2449 if (rating < max) rating = max; |
2457 if (rating < max) rating = max; |
2469 { 96, 384, 768}, // Hostile |
2477 { 96, 384, 768}, // Hostile |
2470 }; |
2478 }; |
2471 |
2479 |
2472 bool CheckforTownRating(uint32 flags, Town *t, byte type) |
2480 bool CheckforTownRating(uint32 flags, Town *t, byte type) |
2473 { |
2481 { |
2474 int modemod; |
|
2475 |
|
2476 /* if magic_bulldozer cheat is active, town doesn't restrict your destructive actions */ |
2482 /* if magic_bulldozer cheat is active, town doesn't restrict your destructive actions */ |
2477 if (t == NULL || !IsValidPlayer(_current_player) || _cheats.magic_bulldozer.value) |
2483 if (t == NULL || !IsValidPlayer(_current_player) || _cheats.magic_bulldozer.value) |
2478 return true; |
2484 return true; |
2479 |
2485 |
2480 /* check if you're allowed to remove the street/bridge/tunnel/industry |
2486 /* check if you're allowed to remove the street/bridge/tunnel/industry |
2481 * owned by a town no removal if rating is lower than ... depends now on |
2487 * owned by a town no removal if rating is lower than ... depends now on |
2482 * difficulty setting. Minimum town rating selected by difficulty level |
2488 * difficulty setting. Minimum town rating selected by difficulty level |
2483 */ |
2489 */ |
2484 modemod = _default_rating_settings[_opt.diff.town_council_tolerance][type]; |
2490 int modemod = _default_rating_settings[_opt.diff.town_council_tolerance][type]; |
2485 |
2491 |
2486 if ((_town_rating_test ? t->test_rating : t->ratings[_current_player]) < 16 + modemod && !(flags & DC_NO_TOWN_RATING)) { |
2492 if ((_town_rating_test ? t->test_rating : t->ratings[_current_player]) < 16 + modemod && !(flags & DC_NO_TOWN_RATING)) { |
2487 SetDParam(0, t->index); |
2493 SetDParam(0, t->index); |
2488 _error_message = STR_2009_LOCAL_AUTHORITY_REFUSES; |
2494 _error_message = STR_2009_LOCAL_AUTHORITY_REFUSES; |
2489 return false; |
2495 return false; |
2508 } |
2514 } |
2509 } |
2515 } |
2510 |
2516 |
2511 void InitializeTowns() |
2517 void InitializeTowns() |
2512 { |
2518 { |
2513 Subsidy *s; |
|
2514 |
|
2515 /* Clean the town pool and create 1 block in it */ |
2519 /* Clean the town pool and create 1 block in it */ |
2516 _Town_pool.CleanPool(); |
2520 _Town_pool.CleanPool(); |
2517 _Town_pool.AddBlockToPool(); |
2521 _Town_pool.AddBlockToPool(); |
2518 |
2522 |
2519 memset(_subsidies, 0, sizeof(_subsidies)); |
2523 memset(_subsidies, 0, sizeof(_subsidies)); |
2520 for (s=_subsidies; s != endof(_subsidies); s++) |
2524 for (Subsidy *s = _subsidies; s != endof(_subsidies); s++) { |
2521 s->cargo_type = CT_INVALID; |
2525 s->cargo_type = CT_INVALID; |
|
2526 } |
2522 |
2527 |
2523 _cur_town_ctr = 0; |
2528 _cur_town_ctr = 0; |
2524 _cur_town_iter = 0; |
2529 _cur_town_iter = 0; |
2525 _total_towns = 0; |
2530 _total_towns = 0; |
2526 _town_sort_dirty = true; |
2531 _town_sort_dirty = true; |
2528 |
2533 |
2529 static CommandCost TerraformTile_Town(TileIndex tile, uint32 flags, uint z_new, Slope tileh_new) |
2534 static CommandCost TerraformTile_Town(TileIndex tile, uint32 flags, uint z_new, Slope tileh_new) |
2530 { |
2535 { |
2531 if (AutoslopeEnabled()) { |
2536 if (AutoslopeEnabled()) { |
2532 HouseID house = GetHouseType(tile); |
2537 HouseID house = GetHouseType(tile); |
2533 HouseSpec *hs = GetHouseSpecs(house); |
2538 const HouseSpec *hs = GetHouseSpecs(house); |
2534 |
2539 |
2535 /* Here we differ from TTDP by checking TILE_NOT_SLOPED */ |
2540 /* Here we differ from TTDP by checking TILE_NOT_SLOPED */ |
2536 if (((hs->building_flags & TILE_NOT_SLOPED) == 0) && !IsSteepSlope(tileh_new) && |
2541 if (((hs->building_flags & TILE_NOT_SLOPED) == 0) && !IsSteepSlope(tileh_new) && |
2537 (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform); |
2542 (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform); |
2538 } |
2543 } |
2549 GetTileTrackStatus_Town, /* get_tile_track_status_proc */ |
2554 GetTileTrackStatus_Town, /* get_tile_track_status_proc */ |
2550 ClickTile_Town, /* click_tile_proc */ |
2555 ClickTile_Town, /* click_tile_proc */ |
2551 AnimateTile_Town, /* animate_tile_proc */ |
2556 AnimateTile_Town, /* animate_tile_proc */ |
2552 TileLoop_Town, /* tile_loop_clear */ |
2557 TileLoop_Town, /* tile_loop_clear */ |
2553 ChangeTileOwner_Town, /* change_tile_owner_clear */ |
2558 ChangeTileOwner_Town, /* change_tile_owner_clear */ |
2554 NULL, /* get_produced_cargo_proc */ |
2559 GetProducedCargo_Town, /* get_produced_cargo_proc */ |
2555 NULL, /* vehicle_enter_tile_proc */ |
2560 NULL, /* vehicle_enter_tile_proc */ |
2556 GetFoundation_Town, /* get_foundation_proc */ |
2561 GetFoundation_Town, /* get_foundation_proc */ |
2557 TerraformTile_Town, /* terraform_tile_proc */ |
2562 TerraformTile_Town, /* terraform_tile_proc */ |
2558 }; |
2563 }; |
2559 |
2564 |
2692 } |
2697 } |
2693 |
2698 |
2694 void AfterLoadTown() |
2699 void AfterLoadTown() |
2695 { |
2700 { |
2696 _town_sort_dirty = true; |
2701 _town_sort_dirty = true; |
|
2702 |
|
2703 Town *t; |
|
2704 FOR_ALL_TOWNS(t) t->InitializeLayout(); |
2697 } |
2705 } |
2698 |
2706 |
2699 extern const ChunkHandler _town_chunk_handlers[] = { |
2707 extern const ChunkHandler _town_chunk_handlers[] = { |
2700 { 'HIDS', Save_HOUSEIDS, Load_HOUSEIDS, CH_ARRAY }, |
2708 { 'HIDS', Save_HOUSEIDS, Load_HOUSEIDS, CH_ARRAY }, |
2701 { 'CITY', Save_TOWN, Load_TOWN, CH_ARRAY | CH_LAST}, |
2709 { 'CITY', Save_TOWN, Load_TOWN, CH_ARRAY | CH_LAST}, |