OpenTTD Source 20260731-master-g77ba2b244a
disaster_vehicle.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
24
25
26#include "stdafx.h"
27
28#include "aircraft.h"
29#include "disaster_vehicle.h"
30#include "industry.h"
31#include "station_base.h"
32#include "command_func.h"
33#include "news_func.h"
34#include "town.h"
35#include "company_func.h"
36#include "strings_func.h"
37#include "viewport_func.h"
38#include "vehicle_func.h"
39#include "sound_func.h"
40#include "effectvehicle_func.h"
41#include "roadveh.h"
42#include "train.h"
43#include "ai/ai.hpp"
44#include "game/game.hpp"
45#include "company_base.h"
46#include "core/random_func.hpp"
47#include "core/backup_type.hpp"
48#include "landscape_cmd.h"
49#include "script/api/script_event_types.hpp"
50#include "timer/timer.h"
52
53#include "table/strings.h"
54
55#include "safeguards.h"
56
59
60static void DisasterClearSquare(TileIndex tile)
61{
62 if (EnsureNoVehicleOnGround(tile).Failed()) return;
63
64 switch (GetTileType(tile)) {
66 if (Company::IsHumanID(GetTileOwner(tile)) && !IsRailDepot(tile)) {
68 Command<Commands::LandscapeClear>::Do(DoCommandFlag::Execute, tile);
69
70 /* update signals in buffer */
72 }
73 break;
74
75 case TileType::House: {
77 Command<Commands::LandscapeClear>::Do(DoCommandFlag::Execute, tile);
78 break;
79 }
80
81 case TileType::Trees:
82 case TileType::Clear:
83 DoClearSquare(tile);
84 break;
85
86 default:
87 break;
88 }
89}
90
109
120
121void DisasterVehicle::UpdateImage()
122{
123 SpriteID img = this->image_override;
124 if (img == 0) img = _disaster_images[this->subtype][this->direction];
125 this->sprite_cache.sprite_seq.Set(img);
126}
127
139{
141
142 this->x_pos = x;
143 this->y_pos = y;
144 switch (subtype) {
145 case ST_ZEPPELINER:
146 case ST_SMALL_UFO:
147 case ST_AIRPLANE:
148 case ST_HELICOPTER:
149 case ST_BIG_UFO:
151 GetAircraftFlightLevelBounds(this, &this->z_pos, nullptr);
152 break;
153
155 GetAircraftFlightLevelBounds(this, &this->z_pos, nullptr);
156 this->z_pos += ROTOR_Z_OFFSET;
157 break;
158
160 case ST_BIG_SUBMARINE:
161 this->z_pos = 0;
162 break;
163
170 this->z_pos = 0;
171 this->vehstatus.Set(VehState::Shadow);
172 break;
173 }
174
175 this->direction = direction;
176 this->tile = TileVirtXY(x, y);
177 this->subtype = subtype;
178 this->UpdateDeltaXY();
179 this->owner = OWNER_NONE;
180 this->image_override = 0;
181 this->state = 0;
182
183 this->UpdateImage();
185}
186
193void DisasterVehicle::UpdatePosition(int x, int y, int z)
194{
195 this->x_pos = x;
196 this->y_pos = y;
197 this->z_pos = z;
198 this->tile = TileVirtXY(x, y);
199
200 this->UpdateImage();
202
203 DisasterVehicle *u = this->Next();
204 if (u != nullptr) {
205 int safe_x = Clamp(x, 0, Map::MaxX() * TILE_SIZE);
206 int safe_y = Clamp(y - 1, 0, Map::MaxY() * TILE_SIZE);
207
208 u->x_pos = x;
209 u->y_pos = y - 1 - (std::max(z - GetSlopePixelZ(safe_x, safe_y), 0) >> 3);
210 safe_y = Clamp(u->y_pos, 0, Map::MaxY() * TILE_SIZE);
211 u->z_pos = GetSlopePixelZ(safe_x, safe_y);
212 u->direction = this->direction;
213
214 u->UpdateImage();
216
217 if ((u = u->Next()) != nullptr) {
218 u->x_pos = x;
219 u->y_pos = y;
220 u->z_pos = z + ROTOR_Z_OFFSET;
222 }
223 }
224}
225
236{
237 v->tick_counter++;
238
239 if (v->state < 2) {
240 if (HasBit(v->tick_counter, 0)) return true;
241
243
244 v->UpdatePosition(gp.x, gp.y, GetAircraftFlightLevel(v));
245
246 if (v->state == 1) {
247 if (++v->age == 38) {
248 v->state = 2;
250 }
251
252 if (GB(v->tick_counter, 0, 3) == 0) CreateEffectVehicleRel(v, 0, -17, 2, EV_CRASH_SMOKE);
253
254 } else if (v->state == 0) {
255 if (IsValidTile(v->tile) && IsAirportTile(v->tile)) {
256 v->state = 1;
258
259 AddTileNewsItem(GetEncodedString(STR_NEWS_DISASTER_ZEPPELIN, GetStationIndex(v->tile)), NewsType::Accident, v->tile);
260 AI::NewEvent(GetTileOwner(v->tile), new ScriptEventDisasterZeppelinerCrashed(GetStationIndex(v->tile)));
261 }
262 }
263
264 if (v->y_pos >= (int)((Map::SizeY() + 9) * TILE_SIZE - 1)) {
265 delete v;
266 return false;
267 }
268
269 return true;
270 }
271
272 if (IsValidTile(v->tile) && IsAirportTile(v->tile)) {
274 }
275
276 if (v->state > 2) {
277 if (++v->age <= 13320) return true;
278
279 if (IsValidTile(v->tile) && IsAirportTile(v->tile)) {
282 AI::NewEvent(GetTileOwner(v->tile), new ScriptEventDisasterZeppelinerCleared(st->index));
283 }
284
285 v->UpdatePosition(v->x_pos, v->y_pos, GetAircraftFlightLevel(v));
286 delete v;
287 return false;
288 }
289
290 int x = v->x_pos;
291 int y = v->y_pos;
292 int z = GetSlopePixelZ(x, y);
293 if (z < v->z_pos) z = v->z_pos - 1;
294 v->UpdatePosition(x, y, z);
295
296 if (++v->age == 1) {
298 if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_12_EXPLOSION, v);
300 } else if (v->age == 70) {
302 } else if (v->age <= 300) {
303 if (GB(v->tick_counter, 0, 3) == 0) {
304 uint32_t r = Random();
305
307 GB(r, 0, 4) - 7,
308 GB(r, 4, 4) - 7,
309 GB(r, 8, 3) + 5,
311 }
312 } else if (v->age == 350) {
313 v->state = 3;
315 }
316
317 return true;
318}
319
329{
331
332 if (ufo->state == 0) {
333 /* Fly around randomly */
334 int x = TileX(ufo->dest_tile) * TILE_SIZE;
335 int y = TileY(ufo->dest_tile) * TILE_SIZE;
336 if (Delta(x, ufo->x_pos) + Delta(y, ufo->y_pos) >= (int)TILE_SIZE) {
337 ufo->direction = GetDirectionTowards(ufo, x, y);
339 ufo->UpdatePosition(gp.x, gp.y, GetAircraftFlightLevel(ufo));
340 return true;
341 }
342 if (++ufo->age < 6) {
343 ufo->dest_tile = RandomTile();
344 return true;
345 }
346 ufo->state = 1;
347
348 uint n = 0; // Total number of targetable road vehicles.
349 for (const Company *c : Company::Iterate()) {
350 n += c->group_all[VehicleType::Road].num_vehicle;
351 }
352
353 if (n == 0) {
354 /* If there are no targetable road vehicles, destroy the UFO. */
355 delete ufo;
356 return false;
357 }
358
359 n = RandomRange(n); // Choose one of them.
360 for (RoadVehicle *u : RoadVehicle::Iterate()) {
361 /* Find (n+1)-th road vehicle. */
362 if (u->IsFrontEngine() && (n-- == 0)) {
363 if (u->crashed_ctr != 0 || u->disaster_vehicle != VehicleID::Invalid()) {
364 /* Targetted vehicle is crashed or already a target, destroy the UFO. */
365 delete ufo;
366 return false;
367 }
368 /* Target it. */
369 ufo->dest_tile = TileIndex{u->index.base()};
371 u->disaster_vehicle = ufo->index;
372 break;
373 }
374 }
375
376 return true;
377 } else {
378 /* Target a vehicle */
379 RoadVehicle *target = RoadVehicle::Get(ufo->dest_tile.base());
380 assert(target != nullptr && target->type == VehicleType::Road && target->IsFrontEngine());
381
382 uint dist = Delta(ufo->x_pos, target->x_pos) + Delta(ufo->y_pos, target->y_pos);
383
384 if (dist < TILE_SIZE && !target->vehstatus.Test(VehState::Hidden) && target->breakdown_ctr == 0) {
385 target->breakdown_ctr = 3;
386 target->breakdown_delay = 140;
387 }
388
389 ufo->direction = GetDirectionTowards(ufo, target->x_pos, target->y_pos);
391
392 int z = ufo->z_pos;
393 if (dist <= TILE_SIZE && z > target->z_pos) z--;
394 ufo->UpdatePosition(gp.x, gp.y, z);
395
396 /* If the vehicle is hidden in a depot or similar treat it as having "escaped" being crashed to avoid the Ufo looping forever,
397 * but we'll still explode the surrounding area ;) */
398 if (z <= target->z_pos) {
399 ufo->age++;
400 if (!target->vehstatus.Test(VehState::Hidden) && target->crashed_ctr == 0) {
401 uint victims = target->Crash();
402 target->disaster_vehicle = VehicleID::Invalid();
403
404 AddTileNewsItem(GetEncodedString(STR_NEWS_DISASTER_SMALL_UFO), NewsType::Accident, target->tile);
405
406 AI::NewEvent(target->owner, new ScriptEventVehicleCrashed(target->index, target->tile, ScriptEventVehicleCrashed::CRASH_RV_UFO, victims, target->owner));
407 Game::NewEvent(new ScriptEventVehicleCrashed(target->index, target->tile, ScriptEventVehicleCrashed::CRASH_RV_UFO, victims, target->owner));
408 }
409 }
410
411 /* Destroy? */
412 if (ufo->age > 50) {
414 if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_12_EXPLOSION, ufo);
415 delete ufo;
416 return false;
417 }
418 }
419
420 return true;
421}
422
423static void DestructIndustry(Industry *i)
424{
425 for (const auto tile : Map::Iterate()) {
426 if (i->TileBelongsToIndustry(tile)) {
429 }
430 }
431}
432
447static bool DisasterTick_Aircraft(DisasterVehicle *v, uint16_t image_override, bool leave_at_top, StringID news_message, IndustryBehaviour behaviour)
448{
449 v->tick_counter++;
450 v->image_override = (v->state == 1 && HasBit(v->tick_counter, 2)) ? image_override : 0;
451
453 v->UpdatePosition(gp.x, gp.y, GetAircraftFlightLevel(v));
454
455 if ((leave_at_top && gp.x < (-10 * (int)TILE_SIZE)) || (!leave_at_top && gp.x > (int)(Map::SizeX() * TILE_SIZE + 9 * TILE_SIZE) - 1)) {
456 delete v;
457 return false;
458 }
459
460 if (v->state == 2) {
461 if (GB(v->tick_counter, 0, 2) == 0) {
462 Industry *i = Industry::Get(v->dest_tile.base()); // Industry destructor calls ReleaseDisastersTargetingIndustry, so this is valid
463 int x = TileX(i->location.tile) * TILE_SIZE;
464 int y = TileY(i->location.tile) * TILE_SIZE;
465 uint32_t r = Random();
466
468 GB(r, 0, 6) + x,
469 GB(r, 6, 6) + y,
470 GB(r, 12, 4),
472
473 if (++v->age >= 55) v->state = 3;
474 }
475 } else if (v->state == 1) {
476 if (++v->age == 112) {
477 v->state = 2;
479
480 Industry *i = Industry::Get(v->dest_tile.base()); // Industry destructor calls ReleaseDisastersTargetingIndustry, so this is valid
481 DestructIndustry(i);
482
483 AddIndustryNewsItem(GetEncodedString(news_message, i->town->index), NewsType::Accident, i->index);
484 if (_settings_client.sound.disaster) SndPlayTileFx(SND_12_EXPLOSION, i->location.tile);
485 }
486 } else if (v->state == 0) {
487 int x = v->x_pos + ((leave_at_top ? -15 : 15) * TILE_SIZE);
488 int y = v->y_pos;
489
490 if ((uint)x > Map::MaxX() * TILE_SIZE - 1) return true;
491
492 TileIndex tile = TileVirtXY(x, y);
493 if (!IsTileType(tile, TileType::Industry)) return true;
494
495 IndustryID ind = GetIndustryIndex(tile);
496 v->dest_tile = TileIndex{ind.base()};
497
498 if (GetIndustrySpec(Industry::Get(ind)->type)->behaviour.Test(behaviour)) {
499 v->state = 1;
501 }
502 }
503
504 return true;
505}
506
509{
510 return DisasterTick_Aircraft(v, SPR_F_15_FIRING, true, STR_NEWS_DISASTER_AIRPLANE_OIL_REFINERY, IndustryBehaviour::AirplaneAttacks);
511}
512
515{
516 return DisasterTick_Aircraft(v, SPR_AH_64A_FIRING, false, STR_NEWS_DISASTER_HELICOPTER_FACTORY, IndustryBehaviour::ChopperAttacks);
517}
518
521{
522 v->tick_counter++;
523 if (HasBit(v->tick_counter, 0)) return true;
524
525 SpriteID &cur_image = v->sprite_cache.sprite_seq.seq[0].sprite;
526 if (++cur_image > SPR_ROTOR_MOVING_3) cur_image = SPR_ROTOR_MOVING_1;
527
529
530 return true;
531}
532
541{
542 v->tick_counter++;
543
544 if (v->state == 1) {
545 int x = TileX(v->dest_tile) * TILE_SIZE + TILE_SIZE / 2;
546 int y = TileY(v->dest_tile) * TILE_SIZE + TILE_SIZE / 2;
547 if (Delta(v->x_pos, x) + Delta(v->y_pos, y) >= 8) {
548 v->direction = GetDirectionTowards(v, x, y);
549
551 v->UpdatePosition(gp.x, gp.y, GetAircraftFlightLevel(v));
552 return true;
553 }
554
555 if (!IsValidTile(v->dest_tile)) {
556 /* Make sure we don't land outside the map. */
557 delete v;
558 return false;
559 }
560
561 int z = GetSlopePixelZ(v->x_pos, v->y_pos);
562 if (z < v->z_pos) {
563 v->UpdatePosition(v->x_pos, v->y_pos, v->z_pos - 1);
564 return true;
565 }
566
567 v->state = 2;
568
569 for (Vehicle *target : Vehicle::Iterate()) {
570 if (target->IsGroundVehicle()) {
571 if (Delta(target->x_pos, v->x_pos) + Delta(target->y_pos, v->y_pos) <= 12 * (int)TILE_SIZE) {
572 target->breakdown_ctr = 5;
573 target->breakdown_delay = 0xF0;
574 }
575 }
576 }
577
578 Town *t = ClosestTownFromTile(v->dest_tile, UINT_MAX);
579 AddTileNewsItem(GetEncodedString(STR_NEWS_DISASTER_BIG_UFO, t->index), NewsType::Accident, v->tile);
580
581 if (!Vehicle::CanAllocateItem(2)) {
582 delete v;
583 return false;
584 }
587 u->SetNext(w);
588 } else if (v->state == 0) {
589 int x = TileX(v->dest_tile) * TILE_SIZE;
590 int y = TileY(v->dest_tile) * TILE_SIZE;
591 if (Delta(x, v->x_pos) + Delta(y, v->y_pos) >= (int)TILE_SIZE) {
592 v->direction = GetDirectionTowards(v, x, y);
594 v->UpdatePosition(gp.x, gp.y, GetAircraftFlightLevel(v));
595 return true;
596 }
597
598 if (++v->age < 6) {
599 v->dest_tile = RandomTile();
600 return true;
601 }
602 v->state = 1;
603
604 const auto is_valid_target = [](const Train *t) {
605 return t->IsFrontEngine() // Only the engines
606 && Company::IsHumanID(t->owner) // Don't break AIs
607 && IsPlainRailTile(t->tile) // No tunnels
608 && !t->vehstatus.Test(VehState::Crashed); // Not crashed
609 };
610
611 uint n = 0; // Total number of targetable trains.
612 for (const Train *t : Train::Iterate()) {
613 if (is_valid_target(t)) n++;
614 }
615
616 if (n == 0) {
617 /* If there are no targetable trains, destroy the UFO. */
618 delete v;
619 return false;
620 }
621
622 n = RandomRange(n); // Choose one of them.
623 for (const Train *t : Train::Iterate()) {
624 /* Find (n+1)-th train. */
625 if (is_valid_target(t) && (n-- == 0)) {
626 /* Target it. */
627 v->dest_tile = t->tile;
629 break;
630 }
631 }
632 }
633
634 return true;
635}
636
643{
644 v->tick_counter++;
645
647 v->UpdatePosition(gp.x, gp.y, GetAircraftFlightLevel(v));
648
649 if (gp.x > (int)(Map::SizeX() * TILE_SIZE + 9 * TILE_SIZE) - 1) {
650 delete v;
651 return false;
652 }
653
654 if (v->state == 0) {
656 if (Delta(v->x_pos, u->x_pos) > (int)TILE_SIZE) return true;
657 v->state = 1;
658
660 if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_12_EXPLOSION, u);
661
662 delete u;
663
664 for (int i = 0; i != 80; i++) {
665 uint32_t r = Random();
667 GB(r, 0, 6) + v->x_pos - 32,
668 GB(r, 5, 6) + v->y_pos - 32,
669 0,
671 }
672
673 for (int dy = -3; dy < 3; dy++) {
674 for (int dx = -3; dx < 3; dx++) {
675 TileIndex tile = TileAddWrap(v->tile, dx, dy);
676 if (tile != INVALID_TILE) DisasterClearSquare(tile);
677 }
678 }
679 }
680
681 return true;
682}
683
690{
691 v->tick_counter++;
692
693 if (++v->age > 8880) {
694 delete v;
695 return false;
696 }
697
698 if (!HasBit(v->tick_counter, 0)) return true;
699
701 if (IsValidTile(tile)) {
703 if (trackbits == TRACK_BIT_ALL && !Chance16(1, 90)) {
705 v->UpdatePosition(gp.x, gp.y, v->z_pos);
706 return true;
707 }
708 }
709
710 v->direction = ChangeDir(v->direction, GB(Random(), 0, 1) ? DirDiff::Right90 : DirDiff::Left90);
711
712 return true;
713}
714
715
717static bool DisasterTick_NULL([[maybe_unused]] DisasterVehicle *v)
718{
719 return true;
720}
721
728
729static DisasterVehicleTickProc * const _disastervehicle_tick_procs[] = {
738};
739
740
742{
743 return _disastervehicle_tick_procs[this->subtype](this);
744}
745
746typedef void DisasterInitProc();
747
748
754{
755 if (!Vehicle::CanAllocateItem(2)) return;
756
757 /* Pick a random place, unless we find an airport */
758 int x = TileX(RandomTile()) * TILE_SIZE + TILE_SIZE / 2;
759
760 for (const Station *st : Station::Iterate()) {
761 if (st->airport.tile != INVALID_TILE && (st->airport.type == AT_SMALL || st->airport.type == AT_LARGE)) {
762 x = (TileX(st->airport.tile) + 2) * TILE_SIZE;
763 break;
764 }
765 }
766
768 /* Allocate shadow */
770 v->SetNext(u);
771}
772
773
779{
780 if (!Vehicle::CanAllocateItem(2)) return;
781
782 int x = TileX(RandomTile()) * TILE_SIZE + TILE_SIZE / 2;
784 v->dest_tile = TileXY(Map::SizeX() / 2, Map::SizeY() / 2);
785
786 /* Allocate shadow */
788 v->SetNext(u);
789}
790
791
794{
795 if (!Vehicle::CanAllocateItem(2)) return;
796
797 Industry *found = nullptr;
798
799 for (Industry *i : Industry::Iterate()) {
801 (found == nullptr || Chance16(1, 2))) {
802 found = i;
803 }
804 }
805
806 if (found == nullptr) return;
807
808 /* Start from the bottom (south side) of the map */
809 int x = (Map::SizeX() + 9) * TILE_SIZE - 1;
810 int y = TileY(found->location.tile) * TILE_SIZE + 37;
811
814 v->SetNext(u);
815}
816
817
820{
821 if (!Vehicle::CanAllocateItem(3)) return;
822
823 Industry *found = nullptr;
824
825 for (Industry *i : Industry::Iterate()) {
827 (found == nullptr || Chance16(1, 2))) {
828 found = i;
829 }
830 }
831
832 if (found == nullptr) return;
833
834 int x = -16 * (int)TILE_SIZE;
835 int y = TileY(found->location.tile) * TILE_SIZE + 37;
836
839 v->SetNext(u);
840
842 u->SetNext(w);
843}
844
845
848{
849 if (!Vehicle::CanAllocateItem(2)) return;
850
851 int x = TileX(RandomTile()) * TILE_SIZE + TILE_SIZE / 2;
852 int y = Map::MaxX() * TILE_SIZE - 1;
853
855 v->dest_tile = TileXY(Map::SizeX() / 2, Map::SizeY() / 2);
856
857 /* Allocate shadow */
859 v->SetNext(u);
860}
861
862
868{
869 if (!Vehicle::CanAllocateItem()) return;
870
871 int y;
872 Direction dir;
873 uint32_t r = Random();
874 int x = TileX(RandomTileSeed(r)) * TILE_SIZE + TILE_SIZE / 2;
875
876 if (HasBit(r, 31)) {
877 y = Map::MaxY() * TILE_SIZE - TILE_SIZE / 2 - 1;
878 dir = Direction::NW;
879 } else {
880 y = TILE_SIZE / 2;
881 if (_settings_game.construction.freeform_edges) y += TILE_SIZE;
882 dir = Direction::SE;
883 }
884 if (!IsWaterTile(TileVirtXY(x, y))) return;
885
886 DisasterVehicle::Create(x, y, dir, subtype);
887}
888
894
895
901
902
908{
909 int index = GB(Random(), 0, 4);
910
911 for (uint m = 0; m < 15; m++) {
912 for (const Industry *i : Industry::Iterate()) {
914 AddTileNewsItem(GetEncodedString(STR_NEWS_DISASTER_COAL_MINE_SUBSIDENCE, i->town->index), NewsType::Accident, i->location.tile + TileDiffXY(1, 1)); // keep the news, even when the mine closes
915
916 {
917 TileIndex tile = i->location.tile;
918 TileIndexDiff step = TileOffsByDiagDir((DiagDirection)GB(Random(), 0, 2));
919
920 for (uint n = 0; n < 30; n++) {
921 DisasterClearSquare(tile);
922 tile += step;
923 if (!IsValidTile(tile)) break;
924 }
925 }
926 return;
927 }
928 }
929 }
930}
931
938
950
952static void DoDisaster()
953{
954 std::vector<DisasterInitProc *> available_disasters;
955
956 for (auto &disaster : _disasters) {
957 if (TimerGameCalendar::year >= disaster.min_year && TimerGameCalendar::year < disaster.max_year) {
958 available_disasters.push_back(disaster.init_proc);
959 }
960 }
961
962 if (available_disasters.empty()) return;
963
964 available_disasters[RandomRange(static_cast<uint32_t>(available_disasters.size()))]();
965}
966
969{
970 _disaster_delay = GB(Random(), 0, 9) + 730;
971}
972
974static const IntervalTimer<TimerGameEconomy> _economy_disaster_daily({TimerGameEconomy::Trigger::Day, TimerGameEconomy::Priority::Disaster}, [](auto)
975{
976 if (--_disaster_delay != 0) return;
977
979
980 if (_settings_game.difficulty.disasters != 0) DoDisaster();
981});
982
985{
987}
988
995{
997 /* primary disaster vehicles that have chosen target */
998 if (v->subtype == ST_AIRPLANE || v->subtype == ST_HELICOPTER) {
999 /* if it has chosen target, and it is this industry (yes, dest_tile is IndustryID here), set order to "leaving map peacefully" */
1000 if (v->state > 0 && v->dest_tile == i.base()) v->state = 3;
1001 }
1002 }
1003}
1004
1010{
1012 if (v == nullptr) return;
1013
1014 /* primary disaster vehicles that have chosen target */
1015 assert(v->type == VehicleType::Disaster);
1016 assert(v->subtype == ST_SMALL_UFO);
1017 assert(v->state != 0);
1018
1019 /* Revert to target-searching */
1020 v->state = 0;
1021 v->dest_tile = RandomTile();
1022 GetAircraftFlightLevelBounds(v, &v->z_pos, nullptr);
1024}
1025
1027{
1028 this->bounds = {{-1, -1, 0}, {2, 2, 5}, {}};
1029}
Base functions for all AIs.
Base for aircraft.
void GetAircraftFlightLevelBounds(const Vehicle *v, int *min, int *max)
Get the 'flight level' bounds, in pixels from 'z_pos' 0 for a particular vehicle for normal flight si...
static const int ROTOR_Z_OFFSET
Z Offset between helicopter- and rotorsprite.
Definition aircraft.h:51
@ Zeppeliner
Block for the zeppeliner disaster vehicle.
Definition airport.h:130
@ RunwayIn
Runway used for landing (metropolitan / international / intercontinental airports).
Definition airport.h:101
@ AT_SMALL
Small airport.
Definition airport.h:29
@ AT_LARGE
Large airport.
Definition airport.h:30
Class for backupping variables and making sure they are restored later.
static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
static void NewEvent(CompanyID company, ScriptEvent *event)
Queue a new event for an AI.
Definition ai_core.cpp:231
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Timpl & Reset()
Reset all bits.
static void NewEvent(class ScriptEvent *event)
Queue a new event for the game script.
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition timer.h:76
static Year year
Current year, starting at 0.
static constexpr TimerGame< struct Calendar >::Date MIN_DATE
StrongType::Typedef< int32_t, struct YearTag< struct Calendar >, StrongType::Compare, StrongType::Integer > Year
Functions related to commands.
@ Execute
execute the given command
Definition of stuff that is very close to a company, like the company struct itself.
CompanyID _current_company
Company currently doing an action.
Functions related to companies.
static constexpr Owner OWNER_NONE
The tile has no ownership.
static constexpr Owner OWNER_WATER
The tile/execution is done by "water".
Direction ChangeDir(Direction d, DirDiff delta)
Change a direction by a given difference.
DiagDirection DirToDiagDir(Direction dir)
Convert a Direction to a DiagDirection.
@ Left90
Angle of 90 degrees left.
@ Right90
Angle of 90 degrees right.
Direction
Defines the 8 directions on the map.
@ SW
Southwest.
@ NW
Northwest.
@ NE
Northeast.
@ SE
Southeast.
EnumIndexArray< T, Direction, Direction::End > DirectionIndexArray
Array with Direction as index.
DiagDirection
Enumeration for diagonal directions.
static bool DisasterTick_Big_Ufo_Destroyer(DisasterVehicle *v)
Skyranger destroying (Big) Ufo handling, v->state states: 0: Home in on landed Ufo and shoot it down.
static void Disaster_Airplane_Init()
Combat airplane which destroys an oil refinery.
static constexpr DirectionIndexArray< SpriteID > _disaster_images_2
Sprites for small UFO.
static void Disaster_Small_Ufo_Init()
Ufo which flies around aimlessly from the middle of the map a bit until it locates a road vehicle whi...
static const DisasterCreation _disasters[]
Table per disaster subtype when to create disasters, and how to create them.
static void ResetDisasterDelay()
Resets the introduction of the next disaster.
static constexpr DirectionIndexArray< SpriteID > _disaster_images_7
Sprites for large UFO destroyer.
static void DoDisaster()
Create a random disaster, if there is one available.
static bool DisasterTick_Big_Ufo(DisasterVehicle *v)
(Big) Ufo handling, v->state states: 0: Fly around to the middle of the map, then randomly for a whil...
static void Disaster_Helicopter_Init()
Combat helicopter that destroys a factory.
static bool DisasterTick_Zeppeliner(DisasterVehicle *v)
Zeppeliner handling, v->state states: 0: Zeppeliner initialization has found an airport,...
static bool DisasterTick_Helicopter_Rotors(DisasterVehicle *v)
Helicopter rotor blades; keep these spinning.
static void Disaster_Big_Submarine_Init()
Curious submarine #2, just floats around.
static const IntervalTimer< TimerGameEconomy > _economy_disaster_daily({TimerGameEconomy::Trigger::Day, TimerGameEconomy::Priority::Disaster}, [](auto) { if(--_disaster_delay !=0) return;ResetDisasterDelay();if(_settings_game.difficulty.disasters !=0) DoDisaster();})
Daily trigger to check whether to add a new disaster.
static constexpr DirectionIndexArray< SpriteID > _disaster_images_8
Sprites for combat helicopter.
static void Disaster_Small_Submarine_Init()
Curious submarine #1, just floats around.
static bool DisasterTick_Airplane(DisasterVehicle *v)
Airplane handling.
static constexpr DirectionIndexArray< SpriteID > _disaster_images_1
Sprites for blimp.
static void Disaster_Zeppeliner_Init()
Zeppeliner which crashes on an airport if one found, otherwise crashes on a random tile.
static void Disaster_Submarine_Init(DisasterSubType subtype)
Initialise a submarine.
uint16_t _disaster_delay
Delay counter for considering the next disaster.
static constexpr DirectionIndexArray< SpriteID > _disaster_images_4
Sprites for small submarine.
static constexpr DirectionIndexArray< SpriteID > _disaster_images_5
Sprites for large submarine.
bool(DisasterVehicle *v) DisasterVehicleTickProc
Perform any actions for a given vehicle.
void ReleaseDisasterVehicle(VehicleID vehicle)
Notify disasters that we are about to delete a vehicle.
static constexpr DirectionIndexArray< SpriteID > _disaster_images_6
Sprites for large UFO.
static bool DisasterTick_NULL(DisasterVehicle *v)
No-op vehicle tick.
static bool DisasterTick_Aircraft(DisasterVehicle *v, uint16_t image_override, bool leave_at_top, StringID news_message, IndustryBehaviour behaviour)
Aircraft handling, v->state states: 0: Fly towards the targeted industry 1: If within 15 tiles,...
static bool DisasterTick_Ufo(DisasterVehicle *ufo)
(Small) Ufo handling, v->state states: 0: Fly around to the middle of the map, then randomly,...
static constexpr DirectionIndexArray< SpriteID > _disaster_images[]
Sprites for each disaster vehicle.
static constexpr DirectionIndexArray< SpriteID > _disaster_images_9
Sprites for combat helicopter rotor.
void StartupDisasters()
Starts up disasters.
static bool DisasterTick_Submarine(DisasterVehicle *v)
Submarine, v->state states: Unused, just float around aimlessly and pop up at different places,...
static bool DisasterTick_Helicopter(DisasterVehicle *v)
Helicopter handling.
void ReleaseDisastersTargetingIndustry(IndustryID i)
Marks all disasters targeting this industry in such a way they won't call Industry::Get(v->dest_tile)...
static void Disaster_Big_Ufo_Init()
Big Ufo which lands on a piece of rail and will consequently be shot down by a combat airplane,...
static void Disaster_CoalMine_Init()
Coal mine catastrophe, destroys a stretch of 30 tiles of land in a certain direction.
static constexpr DirectionIndexArray< SpriteID > _disaster_images_3
Sprites for combat aircraft.
All disaster vehicles.
DisasterSubType
Different sub types of disaster vehicles.
@ ST_ZEPPELINER_SHADOW
Shadow of the zeppelin.
@ ST_HELICOPTER_SHADOW
Shadow of helicopter.
@ ST_SMALL_UFO_SHADOW
Shadow of small UFO.
@ ST_SMALL_UFO
Small UFO, tries to find a road vehicle to destroy.
@ ST_BIG_UFO
Big UFO, finds a piece of railroad to "park" on.
@ ST_BIG_UFO_SHADOW
Shadow of the big UFO.
@ ST_ZEPPELINER
Zeppelin, crashes at airports.
@ ST_BIG_UFO_DESTROYER_SHADOW
Shadow of the aircraft.
@ ST_BIG_UFO_DESTROYER
Aircraft the will bomb the big UFO.
@ ST_BIG_SUBMARINE
Big submarine, pops up in the oceans but doesn't do anything.
@ ST_SMALL_SUBMARINE
Small submarine, pops up in the oceans but doesn't do anything.
@ ST_HELICOPTER
Helicopter destroying a factory.
@ ST_AIRPLANE
Airplane destroying an oil refinery.
@ ST_HELICOPTER_ROTORS
Rotors of helicopter.
@ ST_AIRPLANE_SHADOW
Shadow of airplane.
EffectVehicle * CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicleType type)
Create an effect vehicle above a particular vehicle.
EffectVehicle * CreateEffectVehicleAbove(int x, int y, int z, EffectVehicleType type)
Create an effect vehicle above a particular location.
Functions related to effect vehicles.
@ EV_CRASH_SMOKE
Smoke of disasters.
@ EV_EXPLOSION_SMALL
Various explosions.
@ EV_EXPLOSION_LARGE
Various explosions.
Base functions for all Games.
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset, int tile_height_override)
Mark a tile given by its index dirty for repaint.
static const SpriteID SPR_SUB_SMALL_SW
Definition sprites.h:1215
static const SpriteID SPR_SUB_LARGE_NE
Definition sprites.h:1217
static const SpriteID SPR_SUB_LARGE_SW
Definition sprites.h:1219
static const SpriteID SPR_SUB_SMALL_NW
Definition sprites.h:1216
static const SpriteID SPR_F_15_FIRING
Definition sprites.h:1224
static const SpriteID SPR_BLIMP
Definition sprites.h:1203
static const SpriteID SPR_SUB_LARGE_NW
Definition sprites.h:1220
static const SpriteID SPR_AH_64A
Definition sprites.h:1227
static const SpriteID SPR_SUB_SMALL_SE
Definition sprites.h:1214
static const SpriteID SPR_XCOM_SKYRANGER
Definition sprites.h:1210
static const SpriteID SPR_BLIMP_CRASHING
Definition sprites.h:1202
static const SpriteID SPR_UFO_SMALL_SCOUT_DARKER
Definition sprites.h:1208
static const SpriteID SPR_AH_64A_FIRING
Definition sprites.h:1228
static const SpriteID SPR_BLIMP_CRASHED
Definition sprites.h:1204
static const SpriteID SPR_SUB_LARGE_SE
Definition sprites.h:1218
static const SpriteID SPR_UFO_SMALL_SCOUT
Definition sprites.h:1207
static const SpriteID SPR_UFO_HARVESTER
Definition sprites.h:1209
static const SpriteID SPR_SUB_SMALL_NE
Definition sprites.h:1213
static const SpriteID SPR_F_15
Definition sprites.h:1223
Base of all industries.
const IndustrySpec * GetIndustrySpec(IndustryType thistype)
Accessor for array _industry_specs.
void ResetIndustryConstructionStage(Tile tile)
Reset the construction stage counter of the industry, as well as the completion bit.
IndustryID GetIndustryIndex(Tile t)
Get the industry ID of the given tile.
IndustryBehaviour
Various industry behaviours mostly to represent original TTD specialities.
@ AirplaneAttacks
can be exploded by a military airplane (oil refinery)
@ CanSubsidence
can cause a subsidence (coal mine, shaft that collapses)
@ ChopperAttacks
can be exploded by a military helicopter (factory)
TrackStatus GetTileTrackStatus(TileIndex tile, TransportType mode, RoadTramType sub_mode, DiagDirection side)
Returns information about trackdirs and signal states.
int GetSlopePixelZ(int x, int y, bool ground_vehicle)
Return world Z coordinate of a given point of a tile.
Command definitions related to landscape (slopes etc.).
TileIndex TileAddWrap(TileIndex tile, int addx, int addy)
This function checks if we add addx/addy to tile, if we do wrap around the edges.
Definition map.cpp:120
static TileIndex TileVirtXY(uint x, uint y)
Get a tile from the virtual XY-coordinate.
Definition map_func.h:407
TileIndex RandomTileSeed(uint32_t r)
Get a random tile out of a given seed.
Definition map_func.h:645
TileIndexDiff TileDiffXY(int x, int y)
Calculates an offset for the given coordinate(-offset).
Definition map_func.h:392
static TileIndex TileXY(uint x, uint y)
Returns the TileIndex of a coordinate.
Definition map_func.h:376
static uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:429
static uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:419
#define RandomTile()
Get a valid random tile.
Definition map_func.h:656
TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
Definition map_func.h:574
int32_t TileIndexDiff
An offset value between two tiles.
Definition map_type.h:23
constexpr T Delta(const T a, const T b)
Returns the (absolute) difference between two (scalar) variables.
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
Functions related to news.
@ Accident
An accident or disaster has occurred.
Definition news_type.h:32
static bool IsRailDepot(Tile t)
Is this rail tile a rail depot?
Definition rail_map.h:95
static bool IsPlainRailTile(Tile t)
Checks whether the tile is a rail tile or rail tile with signals.
Definition rail_map.h:60
Pseudo random number generator.
uint32_t RandomRange(uint32_t limit, const std::source_location location=std::source_location::current())
Pick a random number between 0 and limit - 1, inclusive.
bool Chance16(const uint32_t a, const uint32_t b, const std::source_location location=std::source_location::current())
Flips a coin with given probability.
@ Invalid
Invalid marker.
Definition road_type.h:42
Road vehicle states.
A number of safeguards to prevent using unsafe methods.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:61
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
void UpdateSignalsInBuffer()
Update signals in buffer Called from 'outside'.
Definition signal.cpp:582
Functions related to sound.
@ SND_12_EXPLOSION
16 == 0x10 Destruction, crashes, disasters, ...
Definition sound_type.h:64
static const SpriteID SPR_ROTOR_MOVING_3
Definition sprites.h:1108
static const SpriteID SPR_ROTOR_MOVING_1
Definition sprites.h:1107
Base classes/functions for stations.
bool IsAirportTile(Tile t)
Is this tile a station tile and an airport tile?
StationID GetStationIndex(Tile t)
Get StationID from a tile.
Definition station_map.h:28
Definition of base types and functions in a cross-platform compatible way.
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:90
Functions related to OTTD's strings.
StrongType::Typedef< uint32_t, struct StringIDTag, StrongType::Compare, StrongType::Integer > StringID
Numeric value that represents a string, independent of the selected language.
AirportBlocks blocks
stores which blocks on the airport are taken. was 16 bit earlier on, then 32
Class to backup a specific variable and restore it upon destruction of this object to prevent stack v...
static BaseStation * GetByTile(TileIndex tile)
Get the base station belonging to a specific tile.
VehicleType type
Type of vehicle.
static bool IsHumanID(auto index)
Is this company a company not controlled by a NoAI program?
Initialisation function and time period to run the different disasters.
TimerGameCalendar::Year min_year
The first year this disaster will occur.
DisasterInitProc * init_proc
The init function for this disaster.
TimerGameCalendar::Year max_year
The last year this disaster will occur.
Disasters, like submarines, skyrangers and their shadows, belong to this class.
void UpdateDeltaXY() override
Updates the x and y offsets and the size of the sprite used for this vehicle.
SpriteID image_override
Override for the default disaster vehicle sprite.
DisasterVehicle(VehicleID index)
For use by saveload.
void UpdatePosition(int x, int y, int z)
Update the position of the vehicle.
VehicleID big_ufo_destroyer_target
The big UFO that this destroyer is supposed to bomb.
bool Tick() override
Calls the tick handler of the vehicle.
uint16_t state
Action stage of the disaster vehicle.
Position information of a vehicle after it moved.
int y
x and y position of the vehicle after moving
IndustryBehaviours behaviour
How this industry will behave, and how others entities can use it.
Defines the internal data of a functional industry.
Definition industry.h:64
IndustryType type
type of industry.
Definition industry.h:117
Town * town
Nearest town.
Definition industry.h:109
TileArea location
Location of the industry.
Definition industry.h:108
bool TileBelongsToIndustry(TileIndex tile) const
Check if a given tile belongs to this industry.
Definition industry.h:150
static uint SizeX()
Get the size of the map along the X.
Definition map_func.h:262
static uint SizeY()
Get the size of the map along the Y.
Definition map_func.h:271
static IterateWrapper Iterate()
Returns an iterable ensemble of all Tiles.
Definition map_func.h:366
static uint MaxY()
Gets the maximum Y coordinate within the map, including TileType::Void.
Definition map_func.h:298
static uint MaxX()
Gets the maximum X coordinate within the map, including TileType::Void.
Definition map_func.h:289
VehicleSpriteSeq sprite_seq
Vehicle appearance.
TileIndex tile
The base tile of the area.
static Pool::IterateWrapper< Company > Iterate(size_t from=0)
static T * Create(Targs &&... args)
static Vehicle * Get(auto index)
static bool CanAllocateItem(size_t n=1)
static Vehicle * GetIfValid(auto index)
Buses, trucks and trams belong to this class.
Definition roadveh.h:105
uint Crash(bool flooded=false) override
Common code executed for crashed ground vehicles.
uint16_t crashed_ctr
Animation counter when the vehicle has crashed.
Definition roadveh.h:112
VehicleID disaster_vehicle
NOSAVE: Disaster vehicle targetting this vehicle.
Definition roadveh.h:116
static Pool::IterateWrapper< Station > Iterate(size_t from=0)
SpecializedVehicle< DisasterVehicle, Type > SpecializedVehicleBase
Station data structure.
Airport airport
Tile area the airport covers.
Town data structure.
Definition town.h:64
'Train' is either a loco or a wagon.
Definition train.h:97
Vehicle data structure.
int32_t z_pos
z coordinate.
Direction direction
facing
uint8_t subtype
subtype (Filled with values from AircraftSubType/DisasterSubType/EffectVehicleType/GroundVehicleSubty...
uint8_t breakdown_ctr
Counter for managing breakdown events.
uint8_t breakdown_delay
Counter for managing breakdown length.
VehStates vehstatus
Status.
int32_t y_pos
y coordinate.
int32_t x_pos
x coordinate.
SpriteBounds bounds
Bounding box of vehicle.
bool IsFrontEngine() const
Check if the vehicle is a front engine.
TimerGameCalendar::Date age
Age in calendar days.
void SetNext(Vehicle *next)
Set the next vehicle of this vehicle.
Definition vehicle.cpp:2985
MutableSpriteCache sprite_cache
Cache of sprites and values related to recalculating them, see MutableSpriteCache.
void UpdatePositionAndViewport()
Update the position of the vehicle, and update the viewport.
Definition vehicle.cpp:1783
uint8_t tick_counter
Increased by one for each tick.
TileIndex tile
Current tile index.
TileIndex dest_tile
Heading for this tile.
void UpdatePosition()
Update the position of the vehicle.
Definition vehicle.cpp:1700
Owner owner
Which company owns the vehicle?
static bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition tile_map.h:150
Owner GetTileOwner(Tile tile)
Returns the owner of a tile.
Definition tile_map.h:178
bool IsValidTile(Tile tile)
Checks if a tile is valid.
Definition tile_map.h:161
static TileType GetTileType(Tile tile)
Get the tiletype of a given tile.
Definition tile_map.h:96
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > > TileIndex
The index/ID of a Tile.
Definition tile_type.h:92
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:100
static constexpr uint TILE_SIZE
Tile size in world coordinates.
Definition tile_type.h:15
@ Industry
Part of an industry.
Definition tile_type.h:57
@ Railway
A tile with railway.
Definition tile_type.h:50
@ Trees
Tile with one or more trees.
Definition tile_type.h:53
@ House
A house by a town.
Definition tile_type.h:52
@ Clear
A tile without any structures, i.e. grass, rocks, farm fields etc.
Definition tile_type.h:49
Definition of Interval and OneShot timers.
Definition of the game-economy-timer.
Base of the town class.
Town * ClosestTownFromTile(TileIndex tile, uint threshold)
Return the town closest (in distance or ownership) to a given tile, within a given threshold.
TrackBits TrackdirBitsToTrackBits(TrackdirBits bits)
Discards all directional information from a TrackdirBits value.
Definition track_func.h:281
EnumBitSet< Track, uint8_t > TrackBits
Bitset of Track elements.
Definition track_type.h:43
static constexpr TrackBits TRACK_BIT_ALL
All possible tracks.
Definition track_type.h:52
Base for the train class.
@ Water
Transport over water.
CommandCost EnsureNoVehicleOnGround(TileIndex tile)
Ensure there is no vehicle at the ground at the given position.
Definition vehicle.cpp:558
GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
Get position information of a vehicle when moving one pixel in the direction it is facing.
Definition vehicle.cpp:1803
@ Unclickable
Vehicle is not clickable by the user (shadow vehicles).
@ Crashed
Vehicle is crashed.
@ Shadow
Vehicle is a shadow vehicle.
@ Hidden
Vehicle is not visible.
Functions related to vehicles.
PoolID< uint32_t, struct VehicleIDTag, 0xFF000, 0xFFFFF > VehicleID
The type all our vehicle IDs have.
@ Road
Road vehicle type.
@ Disaster
Disaster vehicle type.
Functions related to (drawing on) viewports.
bool IsWaterTile(Tile t)
Is it a water tile with plain water?
Definition water_map.h:192