~yellowapple/WarZoneTweaks

8c1eff20af909be11f8afeab1c1c8d1d79683151 — Ryan S. Northrup (RyNo) 9 months ago
Get everything into git
5 files changed, 256 insertions(+), 0 deletions(-)

A COPYING
A README.md
A data/scripts/sector/background/warzonecheck.lua
A modinfo.lua
A thumbnail.png
A  => COPYING +14 -0
@@ 1,14 @@
Copyright (c) 2020 Ryan S. Northrup ("RyNo") <northrup@yellowapple.us>

Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.

A  => README.md +110 -0
@@ 1,110 @@
# What is it?

A mod for the video game [Avorion](https://www.avorion.net/).

# How do I install it?

It's on the [Steam
Workshop](https://steamcommunity.com/sharedfiles/filedetails/?id=1997069970&tscn=1589517092).
Else:

```shell
cd ~/.avorion/mods  # For Linux; no idea what it'd be for Windows or macOS
git clone https://github.com/YellowApple/WarZoneTweaks.git
```

And in either case, enable it in the in-game mod menu.


# What does it do?

Fixes a rather wide variety of annoyances and even outright bugs with
so-called "Hazard Zones" ("war zones" in the game code).

In particular:

- Explicitly restricts war zone score increases to the destruction of
  specific entity types (ships, stations, turrets, and fighters). The
  vanilla code looked... wonky in that regard.

- A sector defending itself against an attacker will not cause the war
  zone score to increase just because the defenders blew up one of the
  attackers. This should cut down on all those situations where Head
  Hunters turn player-owned sectors into war zones and scare away all
  the merchant ships.

- The player is no longer special; ship destruction (when eligible to
  increase the war zone score) will bump the score by 10 points, no
  matter who owned it or who blew it to smithereens.

- Turrets and fighters only contribute 5 points to the war zone score
  when destroyed.

- Any sector can become a war zone, even one without any stations in
  it (yet).

- The war zone score starts decaying after 5 minutes instead of 60
  (per the comments in the mod's code: "An hour? Ain't nobody got time
  for that!").

- The threshold for declaring a sector to be a "Hazard Zone" is now 75
  points instead of 60. To compensate for this and the shorter decay
  period, the threshold for clearing that status / declaring a sector
  to be peaceful again is now 25 points instead of 40.

# What might it do in the future?

I'm just spitballing here, but here are some neat things I'd like to
do that (as far as I can tell) are well within the realm of
possibility (though whether or not they're possible without tanking
performance is another question entirely...):

- Overhaul the hazard zones to account for the factions involved
  (e.g. if faction Foo has stations being visited by factions Bar and
  Baz, and faction Bam (who is hostile to Foo and Bar but not to Baz)
  comes in and starts blowing up Foo's and Bar's ships, Baz shouldn't
  necessarily care unless/until one of its own ships gets hit in the
  crossfire).

- Enforce higher minimum scores or lower maximum scores in certain
  situations (e.g. each hostile ship in the sector should increase the
  minimum score).

- Make the "Hazard Zone" designation more of a spectrum rather than an
  all-or-nothing proposition (e.g. inverse relationship between war
  zone score and the number/frequency of civil ships spawned,
  potentially adjusted further by the number of friendly v. hostile
  ships in the sector).

- Apply war zone rules to ships other than cargo ships (for example:
  the mobile merchants that occasionally warp in; they should probably
  wait until the fighting's over to warp in, and/or warp out as soon
  as they can if there's ongoing fighting).

- Other things, I'm sure.

# Is this compatible with other mods?

It should be. I play with a lot of mods, and this doesn't seem to
impact them at all (at least at the moment).

# Will this break my saves?

![Well yes, but actually no.](https://i.imgur.com/0ptZQLI.jpg)

Due to a bug (or perhaps merely an oversight on Boxelware's part), the
vanilla code controlling the war zone checking loads the decay
cooldown and thresholds (from what I can tell) on a per-sector basis,
and has no means to override this should those values have changed for
some reason (e.g. by this mod). Conversely, in order for this mod to
set these values for already-generated sectors, it has to override
WarZoneCheck.restore() with a version that explicitly overwrites those
values (namely: noDecayTime, warZoneThreshold, pacefulThreshold [sic],
and maxScore in self.data). Until/unless Boxelware fixes this (might I
recommend a certain mod which implements this more robustly? ;) ) or
someone (perhaps myself) adds a cleanup mod specifically for this
purpose, be aware that these changes are effectively permanent for
sectors loaded with this mod active.

All the other changes this mod makes happen in real-time and do not
involve any modification to saved data.

A  => data/scripts/sector/background/warzonecheck.lua +72 -0
@@ 1,72 @@
if onServer() then

    function WarZoneCheck.restore(data_in)
        self.data = data_in

        -- We override a couple data members that are supposed to be
        -- "constants", so that existing sectors get these tweaks, too.
        self.data.noDecayTime = 5*60 -- An hour? Ain't nobody got time for that!
        self.data.warZoneThreshold = 75
        self.data.pacefulThreshold = 25 -- "paceful" ಠ_ಠ
        self.data.maxScore = 100
    end

    -- Common function to evaluate destruction/capture score increase.
    -- Notable differences:
    --
    --   1. Only react to the destruction of ships, stations, turrets,
    --      or fighters.
    --
    --   2. Don't react differently to the "destroyer" being the player
    --      v. the AI.
    --
    --   3. React to turret/fighter destruction less than normal ship
    --      destruction (by half).
    --
    --   4. Don't react to the destruction of ships if the "attacker"
    --      of those ships controls the sector (fixes cases where the
    --      destruction of Head Hunters attacking player-owned sectors
    --      will inexplicably bump up the war zone score).
    function WarZoneCheck.maybeIncreaseScore(victim, defender, attacker)
        if not victim then return end

        local delta = 0
        if     WarZoneCheck.controlsThisSector(attacker) then delta = 0
        elseif victim:getValue("is_pirate")              then delta = 0
        elseif victim:getValue("is_xsotan")              then delta = 0
        elseif victim:getValue("is_persecutor")          then delta = 0
        elseif victim.type == EntityType.Ship            then delta = 10
        elseif victim.type == EntityType.Station         then delta = 100
        elseif victim.type == EntityType.Turret          then delta = 5
        elseif victim.type == EntityType.Fighter         then delta = 5
        end
        if delta == 0 then return end

        WarZoneCheck.increaseScore(delta)
    end

    -- This probably should be modded into the Sector namespace somehow
    -- (I'm pretty thoroughly surprised it hasn't been already)
    function WarZoneCheck.controlsThisSector(factionIndex)
        local x, y = Sector():getCoordinates()
        local controller = Galaxy():getControllingFaction(x, y)
        if controller then
            return Galaxy():getControllingFaction(x, y).index == factionIndex
        else -- Nobody controls this sector.
            return false
        end
    end

    function WarZoneCheck.onDestroyed(destroyedId, destroyerId)
        local victim = Entity(destroyedId)
        local defender = victim.factionIndex
        local attacker = Entity(destroyerId).factionIndex
        WarZoneCheck.maybeIncreaseScore(victim, defender, attacker)
    end

    function WarZoneCheck.onBoardingSuccessful(id, oldFacIdx, newFacIdx)
        local victim = Entity(id)
        WarZoneCheck.maybeIncreaseScore(victim, oldFacIdx, newFacIdx)
    end

end -- onServer()

A  => modinfo.lua +60 -0
@@ 1,60 @@

meta =
{
    -- ID of your mod; Make sure this is unique!
    -- Will be used for identifying the mod in dependency lists
    -- Will be changed to workshop ID (ensuring uniqueness) when you upload the mod to the workshop
    id = "1997069970",

    -- Name of your mod; You may want this to be unique, but it's not absolutely necessary.
    -- This is an additional helper attribute for you to easily identify your mod in the Mods() list
    name = "WarZoneTweaks",

    -- Title of your mod that will be displayed to players
    title = "War Zone / Hazard Zone Tweaks",

    -- Type of your mod, either "mod" or "factionpack"
    type = "mod",

    -- Description of your mod that will be displayed to players
    description = "Fixes a rather wide variety of annoyances and even outright bugs with so-called \"Hazard Zones\" (\"war zones\" in the game code).",

    -- Insert all authors into this list
    authors = {"YellowApple"},

    -- Version of your mod, should be in format 1.0.0 (major.minor.patch) or 1.0 (major.minor)
    -- This will be used to check for unmet dependencies or incompatibilities
    version = "0.2",

    -- If your mod requires dependencies, enter them here. The game will check that all dependencies given here are met.
    -- Possible attributes:
    -- id: The ID of the other mod as stated in its modinfo.lua
    -- min, max, exact: version strings that will determine minimum, maximum or exact version required (exact is only syntactic sugar for min == max)
    -- optional: set to true if this mod is only an optional dependency (will only influence load order, not requirement checks)
    -- incompatible: set to true if your mod is incompatible with the other one
    -- Example:
    -- dependencies = {
    --      {id = "Avorion", min = "0.17", max = "0.21"}, -- we can only work with Avorion between versions 0.17 and 0.21
    --      {id = "SomeModLoader", min = "1.0", max = "2.0"}, -- we require SomeModLoader, and we need its version to be between 1.0 and 2.0
    --      {id = "AnotherMod", max = "2.0"}, -- we require AnotherMod, and we need its version to be 2.0 or lower
    --      {id = "IncompatibleMod", incompatible = true}, -- we're incompatible with IncompatibleMod, regardless of its version
    --      {id = "IncompatibleModB", exact = "2.0", incompatible = true}, -- we're incompatible with IncompatibleModB, but only exactly version 2.0
    --      {id = "OptionalMod", min = "0.2", optional = true}, -- we support OptionalMod optionally, starting at version 0.2
    -- },
    dependencies = {
        {id = "Avorion", min = "0.31", max = "1.0.99"}
    },

    -- Set to true if the mod only has to run on the server. Clients will get notified that the mod is running on the server, but they won't download it to themselves
    serverSideOnly = false,

    -- Set to true if the mod only has to run on the client, such as UI mods
    clientSideOnly = false,

    -- Set to true if the mod changes the savegame in a potentially breaking way, as in it adds scripts or mechanics that get saved into database and no longer work once the mod gets disabled
    -- logically, if a mod is client-side only, it can't alter savegames, but Avorion doesn't check for that at the moment
    saveGameAltering = false,

    -- Contact info for other users to reach you in case they have questions
    contact = "",
}

A  => thumbnail.png +0 -0