Recommended Posts

Regeneration (health)

This resource lets you regenerate player and vehicle* health. It is not an unique idea, I know... but there weren't good implementations for it at the community resource list. So that's why I share this with YOU.

* Vehicle regeneration for the driver only.

 

Version 1.0.0

  • Not compiled!
  • Smooth health regeneration
  • No UI, just the manager
  • Settings (Admin panel)

 

Settings

  • Regeneration [on/off] (player/vehicle)
  • Regeneration value (player/vehicle)
  • Regeneration delay (player/vehicle)
  • Regeneration [on/off] while the vehicle is burning
     

settings-health-regen.png

 

 

Download link:

https://community.multitheftauto.com/?p=resources&s=details&id=15757

 

Take a quick look into the source code (v1.0.0)

Client

Spoiler


local developmentSettings = {
	basicFPS = 60, -- 60 fps for starters. When developing, set this basic fps to the same value as the server.	
	developmentMode = false, -- View all the data
	
	memorySaving = false, --[[ 
		[Enable] Will save memory. >> But can cause incapability with some gamemodes (for example race). 
		[Disable] Will use more memory.
		
		When to disable? If the function `warpPedIntoVehicle` is used on players in your gamemode.
		https://wiki.multitheftauto.com/wiki/WarpPedIntoVehicle
	]]
	
}

-----------------------------------------
--[[ 
	Before you are going to change values, please keep in mind that serverside edits some of those values.
]]

local healthRegeneration = {
	
	--[[ 
		Regeneration things for the vehicle 
	]]
	
	vehicle = (function ()
		local vehicleHealthRegeneration
		
		vehicleHealthRegeneration = {
			enabled = false, 
			
			lastDamageTime = -1/0, -- infinity negative
			
			delay =  8000, -- [X milliseconds] delay before kicking in
			
			basicTimeSlice = 1000 / developmentSettings.basicFPS,  -- basic timeslice for developers
			
			status = false, -- watching/updating or not?
			
			additionalHealth = 10, -- X health per second
			
			regenerationOnBurning = false, --[[ 
				When the health of a vehicle is lower than 250, it will start burning. This setting makes health regen enabled or disabled for that scenario.
			]]
			
			watchAndUpdate = function (timeSlice) -- The magic happens here!
				local self_ = vehicleHealthRegeneration
				
				local vehicle = getPedOccupiedVehicle (localPlayer)
				if vehicle and getPedOccupiedVehicleSeat (localPlayer) == 0 and not isVehicleBlown ( vehicle ) then
					local timeNow = getTickCount()
					if timeNow > self_.lastDamageTime + self_.delay then
						
						local currentHealth = getElementHealth(vehicle)
						if developmentSettings.regenerationOnBurning or currentHealth > 250 then
							local maxHealth = 1000
							
							local additionalHealthMultiplier = self_.basicTimeSlice / timeSlice -- calculate the new health based on the time between the frames.
							local currentAdditionalHealth = self_.additionalHealth / 100 * additionalHealthMultiplier
							
							if currentHealth < maxHealth then
								setElementHealth(vehicle, math.min(currentHealth + currentAdditionalHealth, maxHealth))
							else
								self_:stopWatchProcess ()
							end
						else
							self_:stopWatchProcess ()
						end
					end
				else
					self_:stopWatchProcess ()
				end
			end,
			registerDamage = {
				handler = {
					status = false,					
				},
				onDamage = function ()
					vehicleHealthRegeneration.lastDamageTime = getTickCount()
					vehicleHealthRegeneration:startWatchProcess()
				end
			}
		}
		
		-- functions for managing which vehicle should attach onClientVehicleDamage (Currently disabled, but you can enable it for memory saving, see developmentSettings on top)
		function vehicleHealthRegeneration.registerDamage.handler:add(vehicle)
			if not self.status then
			
				if self.lastVehicle and isElement(self.lastVehicle) then
					removeEventHandler("onClientVehicleDamage", self.lastVehicle, vehicleHealthRegeneration.registerDamage.onDamage)
				end
				self.lastVehicle = nil
				
				if not isVehicleBlown ( vehicle ) then
					addEventHandler("onClientVehicleDamage", vehicle, vehicleHealthRegeneration.registerDamage.onDamage, false)
					
					self.lastVehicle = vehicle
					self.status = true
					return true
				end
			end
			return false
		end
		
		function vehicleHealthRegeneration.registerDamage.handler:remove (vehicle)
			if self.status then
				removeEventHandler("onClientVehicleDamage", vehicle, vehicleHealthRegeneration.registerDamage.onDamage)
				self.lastVehicle = nil
				self.status = false
				return true
			end
			return false
		end
		
		-- main functions
		function vehicleHealthRegeneration:isDamaged ()
			local vehicle = getPedOccupiedVehicle (localPlayer)
			if vehicle and getPedOccupiedVehicleSeat (localPlayer) == 0 then
				local currentHealth = getElementHealth(vehicle)
				return currentHealth < 1000
			end
			return false
		end
		
		function vehicleHealthRegeneration:startWatchProcess ()
			if not self.status then
				addEventHandler("onClientPreRender", root, self.watchAndUpdate)
				self.status = true
			end
		end

		function vehicleHealthRegeneration:stopWatchProcess ()
			if self.status then
				removeEventHandler("onClientPreRender", root, self.watchAndUpdate)
				self.status = false
			end
		end
		return vehicleHealthRegeneration
	end)(),
	
	------------------------------------------------------------------------------
	
	--[[ 
		Regeneration things for the player. 
	]]
	
	player = (function ()
		local playerHealthRegeneration
		
		local getPedMaxHealth = function (ped)
			-- Grab his player health stat.
			local stat = getPedStat(ped, 24)

			-- Do a linear interpolation to get how many health a ped can have.
			-- Assumes: 100 health = 569 stat, 200 health = 1000 stat.
			local maxhealth = 100 + (stat - 569) / 4.31

			-- Return the max health. Make sure it can't be below 1
			return math.max(1, maxhealth)
		end 
		-- Documentation/source of this function: https://wiki.multitheftauto.com/wiki/GetPedMaxHealth
		
		playerHealthRegeneration = {
			enabled = false,
		
			lastDamageTime = -1/0, -- infinity negative
			
			delay =  8000, -- [X milliseconds] delay before kicking in
			
			basicTimeSlice = 1000 / developmentSettings.basicFPS,  -- basic timeslice for developers
			
			status = false, -- watching/updating or not?
			
			additionalHealth = 5, -- X health per second
			
			watchAndUpdate = function (timeSlice) -- The magic happens here!
				local self_ = playerHealthRegeneration
				
				local timeNow = getTickCount()
				if timeNow > self_.lastDamageTime + self_.delay then
					
					local currentHealth = getElementHealth(localPlayer)
					local maxHealth = getPedMaxHealth(localPlayer)
					
					local additionalHealthMultiplier = self_.basicTimeSlice / timeSlice -- calculate the new health based on the time between the frames.
					local currentAdditionalHealth = self_.additionalHealth / 100 * additionalHealthMultiplier
					
					if currentHealth < maxHealth then
						setElementHealth(localPlayer, math.min(currentHealth + currentAdditionalHealth, maxHealth))
					else
						self_:stopWatchProcess ()
					end
				end
			end
		}
		
		-- main functions
		function playerHealthRegeneration:isDamaged ()
			local currentHealth = getElementHealth(localPlayer)
			local maxHealth = getPedMaxHealth(localPlayer)
			return currentHealth < maxHealth
		end
		
		function playerHealthRegeneration:startWatchProcess ()
			
			if not self.status then
				addEventHandler("onClientPreRender", root, self.watchAndUpdate)
				self.status = true
			end
		end

		function playerHealthRegeneration:stopWatchProcess ()
			if self.status then
				removeEventHandler("onClientPreRender", root, self.watchAndUpdate)
				self.status = false
			end
		end
		
		return playerHealthRegeneration
	end)()
}







do -- (Re)starting the script? It still works.
	addEvent("health-regeneration-settings--receive", true)
	
	-- receive the settings here!
	local function receiveSettings (settingsContainer)
		removeEventHandler("health-regeneration-settings--receive", resourceRoot, receiveSettings, false)
		receiveSettings = nil
		
		-- Apply the settings from serverside on clientside
		for i=1, #settingsContainer do
			local settingsGroup = settingsContainer[i]
			local settingsGroupType = settingsGroup.type
			local settings = settingsGroup.settings
			for j=1, #settings do
				local setting = settings[j]
				healthRegeneration[settingsGroupType][setting.key] = setting.value
			end
		end
		
		
		-- stop both regeneration types when you die
		addEventHandler("onClientPlayerWasted", localPlayer, 
		function ()
			if healthRegeneration.player.enabled then
				healthRegeneration.player:stopWatchProcess ()
			end
			if healthRegeneration.vehicle.enabled then
				healthRegeneration.vehicle:stopWatchProcess ()
			end
		end, false)

		
		-- enable health regeneration for players
		if healthRegeneration.player.enabled then
			if healthRegeneration.player:isDamaged() then
				healthRegeneration.player:startWatchProcess()
			end
			
			addEventHandler("onClientPlayerDamage", localPlayer, 
			function ()
				healthRegeneration.player.lastDamageTime = getTickCount()
				healthRegeneration.player:startWatchProcess()
			end, false)
			
			addEventHandler("onClientPlayerSpawn", localPlayer, 
			function ()
				healthRegeneration.player:stopWatchProcess ()
			end, false)
		end
		
		
		
		-- enable health regeneration for vehicles with YOU as driver
		if healthRegeneration.vehicle.enabled then
			local vehicle = getPedOccupiedVehicle (localPlayer)
			if vehicle and getPedOccupiedVehicleSeat (localPlayer) == 0 then
			
				if healthRegeneration.vehicle:isDamaged() then
					healthRegeneration.vehicle:startWatchProcess()
				end
			
				if developmentSettings.memorySaving then
					healthRegeneration.vehicle.registerDamage.handler:add(vehicle)
				end
			end
			
			if developmentSettings.memorySaving then -- saving memory?
				addEventHandler("onClientPlayerVehicleEnter", localPlayer, 
				function (vehicle, seat)
					if seat == 0 then
						healthRegeneration.vehicle.registerDamage.handler:add(vehicle)
						
						if healthRegeneration.vehicle:isDamaged () then
							healthRegeneration.vehicle.lastDamageTime = getTickCount() -- No cheating by getting in and out of the vehicle
							healthRegeneration.vehicle:startWatchProcess ()
						end
					end
				end, false)

				addEventHandler("onClientPlayerVehicleExit", localPlayer, 
				function (vehicle, seat)
					if seat == 0 then
						healthRegeneration.vehicle.registerDamage.handler:remove(vehicle)
						healthRegeneration.vehicle:stopWatchProcess ()
					end
				end, false)
			else -- or more memory use and less bugs?
			
				addEventHandler("onClientPlayerVehicleEnter", localPlayer, 
				function (vehicle, seat)
					if seat == 0 and healthRegeneration.vehicle:isDamaged () then
						healthRegeneration.vehicle.lastDamageTime = getTickCount() -- No cheating by getting in and out of the vehicle
						healthRegeneration.vehicle:startWatchProcess ()
					end
				end, false)
				
				addEventHandler("onClientPlayerVehicleExit", localPlayer, 
				function (vehicle, seat)
					if seat == 0 then
						healthRegeneration.vehicle:stopWatchProcess ()
					end
				end, false)
					
				addEventHandler("onClientVehicleDamage", root, 
				function ()
					if source == getPedOccupiedVehicle(localPlayer) and getPedOccupiedVehicleSeat (localPlayer) == 0 and not isVehicleBlown ( source ) then
						local vehicleHealthRegeneration = healthRegeneration.vehicle
						vehicleHealthRegeneration.lastDamageTime = getTickCount()
						vehicleHealthRegeneration:startWatchProcess()
					end
				end)	
			end
		end
		
		
	end
	
	
	local function resourceStartFunction () 
		-- clean up
		removeEventHandler("onClientResourceStart", resourceRoot, resourceStartFunction)
		resourceStartFunction = nil
		
		-- get the settings!
		addEventHandler("health-regeneration-settings--receive", resourceRoot, receiveSettings, false)
		triggerServerEvent("health-regeneration-settings--request", resourceRoot)
		
	end
	addEventHandler("onClientResourceStart", resourceRoot, resourceStartFunction, false)
	
end

-- debug the whole thing!
if developmentSettings.developmentMode then
	addEventHandler("onClientRender", root,
	function ()
		dxDrawText(inspect(healthRegeneration), 20, 200) -- with just one line of output! Whohohoho!
	end)
end

 

 

Server

Spoiler

local settingsContainer
do 
	local _outputDebugString = outputDebugString
	local outputDebugString = function  (...)
		local arg = {...}
		arg[1] = "[settings validation] " ..  arg[1]
		_outputDebugString(unpack(arg), 0, 0, 0, 255)
	end
	
	settingsContainer = {
		{
			type = "vehicle",
			settings = {
				{key = "enabled", value = string.lower(tostring(get ("vehicleRegenerationEnabled" ))) == "true"},
				{
					key = "additionalHealth", 
					value = (function () 
						local settingName = "vehicleRegenerationValue"
						local defaultValue = 10
						local value = tonumber(get(settingName))
						if not value then
							value = defaultValue
							outputDebugString(tostring(settingName) .. " must be filled in. Reset to: " .. tostring(value))
						elseif value < 0 then
							value = defaultValue
							outputDebugString(tostring(settingName) .. " must be higher than 0. Reset to: " .. tostring(value))
						end
						
						return value
					end)()
				},
				{	key = "delay", 
					value = (function () 
						local settingName = "vehicleRegenerationDelay"
						local defaultValue = 8000
						local value = tonumber(get(settingName))
						if not value then
							value = defaultValue
							outputDebugString(tostring(settingName) .. " must be filled in. Reset to: " .. tostring(value))
						elseif value < 0 then
							value = defaultValue
							outputDebugString(tostring(settingName) .. " must be higher than 0. Reset to: " .. tostring(value))
						end
						
						return value
					end)()
				},
				{key = "regenerationOnBurning", value = string.lower(tostring(get ("vehicleRegenerationOnBurning" ))) == "true"}
			}
		},
		{
			type = "player",
			settings = {
				{key = "enabled", value = string.lower(tostring(get ("playerRegenerationEnabled" ))) == "true"},
				{
					key = "additionalHealth", 
					value = (function () 
						local settingName = "playerRegenerationValue"
						local defaultValue = 5
						local value = tonumber(get(settingName))
						if not value then
							value = defaultValue
							outputDebugString(tostring(settingName) .. " must be filled in. Reset to: " .. tostring(value))
						elseif value < 0 then
							value = defaultValue
							outputDebugString(tostring(settingName) .. " must be higher than 0. Reset to: " .. tostring(value))
						end
						return value
					end)()
				},
				{
					key = "delay",
					value = (function () 
						local settingName = "playerRegenerationDelay"
						local defaultValue = 8000
						local value = tonumber(get(settingName))
						if not value then
							value = defaultValue
							outputDebugString(tostring(settingName) .. " must be filled in. Reset to: " .. tostring(value))
						elseif value < 0 then
							value = defaultValue
							outputDebugString(tostring(settingName) .. " must be higher than 0. Reset to: " .. tostring(value))
						end
						
						return value
					end)()
				},
			}
		}
	}
end



addEvent("health-regeneration-settings--request", true)
addEventHandler("health-regeneration-settings--request", resourceRoot, 
function ()
	-- send the settings to the client
	triggerClientEvent(client, "health-regeneration-settings--receive", resourceRoot, settingsContainer)
end)

 

 

Meta

Spoiler

<meta>
    <info author="IIYAMA" type="script" version="1.0.0" name="Health regeneration" desc="This resource lets you regenerate health of players and their vehicle while driving it.(driver only) You can edit the optional settings in Admin panel." />


    <min_mta_version client="1.5.4" server="1.5.4" />


    <script src="scripts/server.lua" />
	<script src="scripts/client.lua" type="client" />
	
    <settings>
         <setting group="vehicle" name="*vehicleRegenerationEnabled" friendlyname="Vehicle regeneration, yes or no?" accept="true,false,TRUE,FALSE" value="true" examples="true" desc="[vehicle] This setting toggles regeneration for vehicles" />
		 <setting group="vehicle" name="*vehicleRegenerationValue" friendlyname="Vehicle regeneration per second" accept="number" value="10" examples="10" desc="[vehicle] This setting is used for the amount of regeneration per second" /> 
		 <setting group="vehicle" name="*vehicleRegenerationDelay" friendlyname="Delay before vehicle regeneration" accept="number(milliseconds)" value="8000" examples="8000" desc="[vehicle] This setting is used for the regeneration delay" /> 
		 <setting group="vehicle" name="*vehicleRegenerationOnBurning" friendlyname="Vehicle regeneration while burning, yes or no?"  accept="true,false,TRUE,FALSE" value="false" examples="false" desc="[vehicle] This setting toggles regeneration for burning vehicles" />
	
		 <setting group="player" name="*playerRegenerationEnabled" friendlyname="Player regeneration, yes or no?"  accept="true,false,TRUE,FALSE" value="true" examples="true" desc="[player] This setting toggles regeneration for players" /> 
		 <setting group="player" name="*playerRegenerationValue" friendlyname="Player regeneration per second" accept="number" value="5" examples="5" desc="[player] This setting is used for the amount of regeneration per second" /> 
		 <setting group="player" name="*playerRegenerationDelay" friendlyname="Delay before player regeneration" accept="number(milliseconds)" value="8000" examples="8000" desc="[Player] This setting is used for the regeneration delay" /> 
    </settings>
</meta>

 

 

 

 

 

 

 

 

Edited by IIYAMA
  • Like 4
  • Thanks 3

Share this post


Link to post
4 hours ago, Gordon_G said:

A simple but efficient resource

Yea, I believe that describes the resource the best.

And yet, it surprised me how many conditions (for critical gamemode scenario's) it required to work properly. 😓

  • Haha 1

Share this post


Link to post
8 hours ago, KINGKHAN said:

Not a bad one ilyama its a best resource +1

You are making me shy ☺️

Share this post


Link to post
On 26/11/2018 at 00:31, IIYAMA said:

Yea, I believe that describes the resource the best.

And yet, it surprised me how many conditions (for critical gamemode scenario's) it required to work properly. 😓

It never amazes me how much if else i have to use for even the simplest resource haha. I like having everything green so ignoring warnings is not an option for me as well :D nice work bro ;)

  • Thanks 1

Share this post


Link to post

Good job 👍

  • Like 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.