Files
wnsrc/lua/stormfox2/lib/sh_terrain.lua
lifestorm 94063e4369 Upload
2024-08-04 22:55:00 +03:00

371 lines
11 KiB
Lua

--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
--[[
Terrain control. Changes the ground
Terrain.Create( sName ) Creates a new terrain type and stores it
Terrain.Get( sName ) Returns the terrain.
Terrain.Set( sName ) Sets the terrain. (This should only be done serverside)
Terrain.GetCurrent() Returns the terrain obj or nil.
StormFox2.Terrain.Reset() Resets the terrain to default.
StormFox2.Terrain.HasMaterialChanged( iMaterial ) Returns true if the terrain has changed the material.
Terrain Meta:
:LockUntil( fFunc ) Makes the terrian
:MakeFootprints( sndList, sndName ) Makes footprints. Allows to overwrite footstep sounds.
:AddTextureSwap( material, basetexture, basetextire2 ) Changes a materials textures.
:RenderWindow( width, height ) A function that renders a window-texure. (Weather will trump this)
:RenderWindowRefract( width, height ) A function that renders a window-texure. (Weather will trump this)
:RenderWindow64x64( width, height ) A function that renders a window-texure. (Weather will trump this)
:RenderWindowRefract64x64( width, height ) A function that renders a window-texure. (Weather will trump this)
:Apply Applies the terrain (This won't reset old terrain)
Hooks:
StormFox2.terrain.footstep Entity foot[0 = left,1 = right] sTexture bTerrainTexture
]]
---@class SF2Terrain
local meta = {}
meta.__index = meta
meta.__tostring = function(self) return "SF_TerrainType[" .. (self.Name or "Unknwon") .. "]" end
meta.__eq = function(self, other)
if type(other) ~= "table" then return false end
if not other.Name then return false end
return other.Name == self.Name
end
debug.getregistry()["SFTerrain"] = meta
local terrains = {}
StormFox2.Terrain = {}
--- Creates a new terrain type, stores and returns it.
---@param sName string
---@return SF2Terrain
---@shared
function StormFox2.Terrain.Create( sName )
local t = {}
t.Name = sName
setmetatable(t, meta)
terrains[sName] = t
t.swap = {}
return t
end
local CURRENT_TERRAIN
---Returns the current applies terrain.
---@return SF2Terrain|nil
---@shared
function StormFox2.Terrain.GetCurrent()
return CURRENT_TERRAIN
end
---Returns a terrain by name.
---@param sName string
---@return SF2Terrain|nil
---@shared
function StormFox2.Terrain.Get( sName )
if not sName then return end
return terrains[sName]
end
-- Makes the terrain stay until this function returns true or another terrain overwrites.
---@param fFunc function
---@shared
function meta:LockUntil( fFunc )
self.lock = fFunc
end
---Sets the ground texture. e.i; snow texture.
---@param iTexture string
---@param bOnlyGround boolean
---@shared
function meta:SetGroundTexture( iTexture, bOnlyGround )
self.ground = iTexture
self.only_ground = bOnlyGround
end
-- Adds a texture swap for when this terrain gets applied.
---@param mMaterial Material|string
---@param basetexture string
---@param basetextire2 string
---@shared
function meta:AddTextureSwap( mMaterial, basetexture, basetextire2 )
if type(mMaterial) ~= "IMaterial" then
mMaterial = Material(mMaterial)
end
if not basetexture and not basetextire2 then return end
self.swap[mMaterial] = { basetexture, basetextire2 }
end
---Makes footprints and allows to overwrite default footstep sounds.
---@param bool boolean
---@param sndList? table
---@param sndName? string
---@param OnPrint? function
---@shared
function meta:MakeFootprints( bool, sndList, sndName, OnPrint )
self.footprints = bool
if sndList or sndName then
self.footprintSnds = {sndList, sndName}
end
self.footstepFunc = OnPrint
self.footstepLisen = bool or sndList or sndName or OnPrint
end
---A function that renders a window-texure. (Weather will trump this)
---@param fFunc function
---@shared
function meta:RenderWindow( fFunc )
self.windRender = fFunc
end
---A function that renders a window-texure. (Weather will trump this)
---@param fFunc function
---@shared
function meta:RenderWindowRefract( fFunc )
self.windRenderRef = fFunc
end
---A function that renders a window-texure. (Weather will trump this)
---@param fFunc function
---@shared
function meta:RenderWindow64x64( fFunc )
self.windRender64 = fFunc
end
---A function that renders a window-texure. (Weather will trump this)
---@param fFunc function
---@shared
function meta:RenderWindowRefract64x64( fFunc )
self.windRenderRef64 = fFunc
end
-- Texture handler
_STORMFOX_TEXCHANGES = _STORMFOX_TEXCHANGES or {} -- List of changed materials.
_STORMFOX_TEXORIGINAL = _STORMFOX_TEXORIGINAL or {} -- This is global, just in case.
local footStepLisen = false -- If set to true, will enable footprints.
local function StringTex(iTex)
if not iTex then return end
if type(iTex) == "string" then return iTex end
return iTex:GetName()
end
local function HasChanged( self, materialTexture )
local mat = self:GetName() or "unknown"
local b = materialTexture == "$basetexture2" and 2 or 1
return _STORMFOX_TEXCHANGES[mat] and _STORMFOX_TEXCHANGES[mat][b] or false
end
---Returns true if the material has changed.
---@param iMaterial Material
---@return boolean
---@shared
function StormFox2.Terrain.HasMaterialChanged( iMaterial )
local mat = iMaterial:GetName() or iMaterial
return _STORMFOX_TEXCHANGES[mat] and true or false
end
---Returns the original texture for said material.
---@param iMaterial Material
---@return stirng
---@shared
function StormFox2.Terrain.GetOriginalTexture( iMaterial )
local mat = iMaterial:GetName() or iMaterial
return _STORMFOX_TEXORIGINAL[mat] and _STORMFOX_TEXORIGINAL[mat][1]
end
-- We're going to overwrite SetTexture. As some mods might change the default texture.
local mat_meta = FindMetaTable("IMaterial")
STORMFOX_TEX_APPLY = STORMFOX_TEX_APPLY or mat_meta.SetTexture
function mat_meta:SetTexture(materialTexture, texture)
-- Check if it is basetexutre or basetexture2 we're changing.
if materialTexture ~= "$basetexture" and materialTexture ~= "$basetexture2" then
return STORMFOX_TEX_APPLY( self, materialTexture, texture )
end
-- Overwrite the original texture list.
local mat = self:GetName() or "unknown"
if not _STORMFOX_TEXORIGINAL[mat] then _STORMFOX_TEXORIGINAL[mat] = {} end
if materialTexture == "$basetexture" then
_STORMFOX_TEXORIGINAL[mat][1] = StringTex(texture)
else
_STORMFOX_TEXORIGINAL[mat][2] = StringTex(texture)
end
-- If we havn't changed the texture, allow change.
if not HasChanged(self, materialTexture) then
return STORMFOX_TEX_APPLY( self, materialTexture, texture )
end
end
-- Resets the material. Returns false if unable to reset.
local function ResetMaterial( self )
local mat = self:GetName() or "unknown"
if not _STORMFOX_TEXCHANGES[mat] or not _STORMFOX_TEXORIGINAL[mat] then return false end
if _STORMFOX_TEXCHANGES[mat][1] and _STORMFOX_TEXORIGINAL[mat][1] then
STORMFOX_TEX_APPLY( self, "$basetexture", _STORMFOX_TEXORIGINAL[mat][1] )
end
if _STORMFOX_TEXCHANGES[mat][2] and _STORMFOX_TEXORIGINAL[mat][2] then
STORMFOX_TEX_APPLY( self, "$basetexture2", _STORMFOX_TEXORIGINAL[mat][2] )
end
_STORMFOX_TEXCHANGES[mat] = nil
return true
end
-- Set the material
local function SetMat(self, tex1, tex2)
if not tex1 and not tex2 then return end
local mat = self:GetName() or "unknown"
-- Save the default texture
if not _STORMFOX_TEXORIGINAL[mat] then _STORMFOX_TEXORIGINAL[mat] = {} end
if tex1 and not _STORMFOX_TEXORIGINAL[mat][1] then
_STORMFOX_TEXORIGINAL[mat][1] = StringTex(self:GetTexture("$basetexture"))
end
if tex2 and not _STORMFOX_TEXORIGINAL[mat][2] then
_STORMFOX_TEXORIGINAL[mat][2] = StringTex(self:GetTexture("$basetexture2"))
end
-- Set texture
if tex1 then
if CLIENT then
STORMFOX_TEX_APPLY( self, "$basetexture", tex1 )
end
if not _STORMFOX_TEXCHANGES[ mat ] then _STORMFOX_TEXCHANGES[ mat ] = {} end
_STORMFOX_TEXCHANGES[ mat ][ 1 ] = true
end
if tex2 then
if CLIENT then
STORMFOX_TEX_APPLY( self, "$basetexture2", tex2 )
end
if not _STORMFOX_TEXCHANGES[ mat ] then _STORMFOX_TEXCHANGES[ mat ] = {} end
_STORMFOX_TEXCHANGES[ mat ][ 2 ] = true
end
end
-- Resets the terrain to default. Setting bNoUpdate to true on the server, will not notify the clients or relays.
---@param bNoUpdate boolean
---@shared
function StormFox2.Terrain.Reset( bNoUpdate )
--print("Reset")
if SERVER and not bNoUpdate then
StormFox2.Map.CallLogicRelay("terrain_clear")
end
CURRENT_TERRAIN = nil
if SERVER and not bNoUpdate then
net.Start(StormFox2.Net.Terrain)
net.WriteString( "" )
net.Broadcast()
end
if next(_STORMFOX_TEXCHANGES) == nil then return end
for tex,_ in pairs( _STORMFOX_TEXCHANGES ) do
local mat = Material( tex )
if not ResetMaterial( mat ) then
StormFox2.Warning( "Can't reset [" .. tostring( mat ) .. "]." )
end
end
_STORMFOX_TEXCHANGES = {}
end
--- Sets the terrain. (This should only be done serverside)
---@param sName string
---@return boolean
---@shared
function StormFox2.Terrain.Set( sName )
-- Apply terrain.
local t = StormFox2.Terrain.Get( sName )
if not t then
StormFox2.Terrain.Reset()
return false
end
StormFox2.Terrain.Reset( true )
t:Apply()
if SERVER then
StormFox2.Map.CallLogicRelay( "terrain_" .. string.lower(sName) )
end
return true
end
--- Reapplies the current terrain
---@shared
function StormFox2.Terrain.Update()
local terrain = StormFox2.Terrain.GetCurrent()
if not terrain then return end
StormFox2.Terrain.Reset( true )
terrain:Apply()
end
local NO_TYPE = -1
local DIRTGRASS_TYPE = 0
local ROOF_TYPE = 1
local ROAD_TYPE = 2
local PAVEMENT_TYPE = 3
local function checkType(n, bOnlkyG)
if not n then return false end
if n == 0 then return true end
if n == 1 and not bOnlkyG then return true end
return false
end
-- Applies the terrain (This won't reset old terrain)
function meta:Apply()
CURRENT_TERRAIN = self
if SERVER then
net.Start(StormFox2.Net.Terrain)
net.WriteString( CURRENT_TERRAIN.Name )
net.Broadcast()
end
-- Swap materials
if self.swap then
for mat,tab in pairs( self.swap ) do
SetMat( mat, tab[1], tab[2] )
end
end
-- Set ground
if self.ground then
for materialName,tab in pairs( StormFox2.Map.GetTextureTree() ) do
local mat = Material( materialName )
local a,b = checkType(tab[1], self.only_ground), checkType(tab[2], self.only_ground)
SetMat( mat, a and self.ground,b and self.ground)
end
end
footStepLisen = self.footprints or self.footprintSnds
end
-- NET
if SERVER then
net.Receive(StormFox2.Net.Terrain, function(len, ply) -- OI, what terrain?
net.Start(StormFox2.Net.Terrain)
net.WriteString( CURRENT_TERRAIN and CURRENT_TERRAIN.Name or "" )
net.Send(ply)
end)
else
net.Receive(StormFox2.Net.Terrain, function(len)
local sName = net.ReadString()
local b = StormFox2.Terrain.Set( sName )
--"Terrain Recived: ", sName, b)
end)
-- Ask the server
hook.Add("StormFox2.InitPostEntity", "StormFox2.terrain.init", function()
timer.Simple(1, function()
net.Start(StormFox2.Net.Terrain)
net.WriteBit(1)
net.SendToServer()
end)
end)
end
-- A bit ballsy, but lets try.
hook.Add("ShutDown","StormFox2.Terrain.Clear",function()
StormFox2.Msg("Reloading all changed materials ..")
for k, _ in pairs( _STORMFOX_TEXORIGINAL ) do
RunConsoleCommand("mat_reloadmaterial", k)
end
end)