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