-
Notifications
You must be signed in to change notification settings - Fork 354
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor earthquakes to its own class
- Loading branch information
Showing
7 changed files
with
308 additions
and
252 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,237 @@ | ||
--[[ Copyright (c) 2024 Toby "tobylane" | ||
Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
this software and associated documentation files (the "Software"), to deal in | ||
the Software without restriction, including without limitation the rights to | ||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | ||
of the Software, and to permit persons to whom the Software is furnished to do | ||
so, subject to the following conditions: | ||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. --]] | ||
|
||
--! Manages all earthquakes in the world | ||
class "Earthquake" | ||
|
||
---@type Earthquake | ||
local Earthquake = _G["Earthquake"] | ||
|
||
-- All fields relating to the current or next earthquake: | ||
-- active (boolean) If we are currently running the warning or damage timers | ||
-- (after start_day of start_month is passed) | ||
-- next_planned (boolean) If the next earthquake has been planned/generated | ||
-- start_month (integer) The month the earthquake warning is triggered | ||
-- start_day (integer) The day of the month the earthquake warning is triggered | ||
-- size (integer) The amount of damage the earthquake causes (1-9) | ||
-- remaining_damage (integer) The amount of damage this earthquake has yet to inflict | ||
-- damage_timer (integer) The number of hours until the earthquake next inflicts damage if active | ||
-- warning_timer (integer) The number of hours left until the real damaging earthquake begins | ||
-- current_map_earthquake (integer) The number of earthquakes that have happened on this map so far | ||
|
||
local damage_time = 16 -- Hours between each damage caused by an earthquake | ||
local warning_period = 600 -- Hours between warning and real thing | ||
local warning_length = 25 -- Length of early warning quake | ||
|
||
local month_length = { | ||
31, -- Jan | ||
28, -- Feb (29 in leap years, but TH doesn't have leap years) | ||
31, -- Mar | ||
30, -- Apr | ||
31, -- May | ||
30, -- Jun | ||
31, -- Jul | ||
31, -- Aug | ||
30, -- Sep | ||
31, -- Oct | ||
30, -- Nov | ||
31, -- Dec | ||
} | ||
|
||
--! Track earthquakes in the world | ||
--!param world (table) Owned by this world | ||
--!param convert (boolean) If true, world is upgraded from before this Earthquake class | ||
function Earthquake:Earthquake(world, convert) | ||
self.world = world | ||
if not convert then | ||
self.current_map_earthquake = 0 | ||
self:nextEarthquake() | ||
end | ||
end | ||
|
||
--! Perform actions to simulate an active earthquake. | ||
function Earthquake:tick() | ||
if not self.active then return end | ||
local hosp = self.world:getLocalPlayerHospital() | ||
-- Check if this is the day that the earthquake is supposed to stop | ||
if self.remaining_damage == 0 then | ||
self.active = false | ||
hosp:tickEarthquake("end") | ||
-- If the earthquake measured more than 7 on the richter scale, tell the user about it | ||
if self.size > 7 then | ||
hosp:giveAdvice({_A.earthquake.ended:format(math.floor(self.size))}) | ||
end | ||
|
||
-- Set up the next earthquake date | ||
self:nextEarthquake() | ||
return | ||
end | ||
|
||
-- Start of warning quake | ||
if self.warning_timer == warning_period then | ||
self.next_planned = false | ||
hosp:tickEarthquake("warning start") | ||
end | ||
|
||
-- End of warning quake | ||
if self.warning_timer >= warning_period - warning_length and | ||
self.warning_timer - self.world.hours_per_tick < warning_period - warning_length then | ||
hosp:tickEarthquake("end") | ||
end | ||
|
||
if self.warning_timer > 0 then | ||
self.warning_timer = self.warning_timer - self.world.hours_per_tick | ||
-- Nothing more to do during inactive warning period | ||
if self.warning_timer < warning_period - warning_length then | ||
return | ||
end | ||
|
||
-- Start of real earthquake | ||
if self.warning_timer <= 0 then | ||
hosp:tickEarthquake("main start") | ||
end | ||
end | ||
|
||
-- All earthquakes start and end small (small earthquakes never become | ||
-- larger), so when there has been less than 2 damage applied or only | ||
-- 2 damage remaining to be applied, move the screen with less | ||
-- intensity than otherwise. | ||
if self.remaining_damage <= 2 or | ||
self.size - self.remaining_damage <= 2 then | ||
hosp:tickEarthquake("small damage") | ||
else | ||
hosp:tickEarthquake("large damage") | ||
end | ||
|
||
hosp:tickEarthquake("sound") | ||
|
||
-- Do not continue to damage phase while in a warning quake | ||
if self.warning_timer > 0 then | ||
return | ||
end | ||
|
||
-- Check if damage phase should go ahead | ||
self.damage_timer = self.damage_timer - self.world.hours_per_tick | ||
if self.damage_timer > 0 then return end | ||
|
||
for _, room in pairs(self.world.rooms) do | ||
for object, _ in pairs(room.objects) do | ||
if object.strength then | ||
object:machineUsed(room) | ||
end | ||
end | ||
end | ||
|
||
self.remaining_damage = self.remaining_damage - 1 | ||
self.damage_timer = self.damage_timer + damage_time | ||
|
||
-- Patient falling: work in progress, see PR 1848 | ||
end | ||
|
||
--! Check if it's time for an earthquake | ||
function Earthquake:onEndDay() | ||
if self.world.game_date:monthOfGame() == self.start_month and | ||
self.world.game_date:dayOfMonth() == self.start_day then | ||
-- Warn the user that an earthquake is on the way | ||
self.active = true | ||
end | ||
end | ||
|
||
--! Called when it is time to have another earthquake | ||
function Earthquake:nextEarthquake() | ||
self.active = false | ||
|
||
local level_config = self.world.map.level_config | ||
-- Check carefully that no value that we are going to use is going to be nil | ||
if level_config.quake_control and level_config.quake_control[self.current_map_earthquake] and | ||
level_config.quake_control[self.current_map_earthquake].Severity ~= 0 then | ||
-- This map has rules to follow when making earthquakes, let's follow them | ||
local control = level_config.quake_control[self.current_map_earthquake] | ||
self.start_month = math.random(control.StartMonth, control.EndMonth) | ||
|
||
-- Month length of the start of the earthquake. From start to finish | ||
-- earthquakes do not persist for >= a month so we can wrap all days | ||
-- after the start around the month length unambiguously. | ||
local eqml = month_length[(self.start_month % 12) + 1] | ||
self.start_day = math.random(1, eqml) | ||
|
||
self.size = control.Severity | ||
self.remaining_damage = self.size | ||
self.damage_timer = damage_time | ||
self.warning_timer = warning_period | ||
self.current_map_earthquake = self.current_map_earthquake + 1 | ||
self.next_planned = true | ||
end | ||
end | ||
|
||
--! The create an earthquake override from cheat menu | ||
function Earthquake:createEarthquake() | ||
-- Make sure an earthquake isn't already happening | ||
if self.active then return false end | ||
|
||
self.start_day = self.world.game_date:dayOfMonth() | ||
self.start_month = self.world.game_date:monthOfGame() | ||
if not self.next_planned then | ||
-- Forcefully make an earthquake if there are none left in level file | ||
self.size = math.random(1, 6) -- Above 6 seems disastrous | ||
self.remaining_damage = self.size | ||
self.damage_timer = damage_time | ||
self.warning_timer = warning_period | ||
end | ||
end | ||
|
||
--! Check if there is a current earthquake | ||
--!return (boolean) True if there is a current earthquake | ||
function Earthquake:isActive() | ||
return self.active | ||
end | ||
|
||
--! Afterload sections before 189 were taken from World | ||
--!param old (integer) The old version of the save game. | ||
--!param new (integer) The current version of the save game format. | ||
function Earthquake:afterLoad(old, new) -- luacheck: ignore 212 keep params from parent function | ||
local old_quake = self.world.next_earthquake | ||
if old < 115 then | ||
if old_quake.active then | ||
local rd = 0 | ||
for _, room in pairs(self.world.rooms) do | ||
for object, _ in pairs(room.objects) do | ||
if object.quake_points then | ||
rd = math.max(rd, object.quake_points) | ||
object.quake_points = nil | ||
end | ||
end | ||
end | ||
old_quake.remaining_damage = rd | ||
old_quake.damage_timer = damage_time | ||
old_quake.warning_timer = 0 | ||
end | ||
end | ||
|
||
if old < 189 then | ||
if old_quake then | ||
for k, v in pairs(old_quake) do | ||
self[k] = v | ||
end | ||
else | ||
self:nextEarthquake() | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.