First off, I'd like to thank anyone that takes the time to help me out.
Down to business, I'm making a system that increases damage of weapons for use in a post-apocalyptic server, Zombie Roleplay. Separate from this, there is another system that will cause players to bleed if they're shot, as long as they're not already bleeding.
This script is meant to perform:
-Additional bullet damage, aiming for realism. Makes many GTA weapons kill in only a few shots. -Additional damage falls off over range due to air resistance on the bullet. -A sniper hit to the chest will knock a player out. (That code is separate in another system and not part of this issue.)
However I'm running into a snag. From certain distances and angles and even randomly, the onPlayerDamage() server side event appears to be triggering more than once. Since the script relies on it to tell when the player has been damaged, it needs to be accurate.
Also, the setWeaponProperty for the weapon range is not working. At least, not in the Freeroam gamemode.
I'm wondering, is there anything we can do about this without waiting for a fix from MTA devs?
Here is the code for those that wish to test for themselves. It's all server-side, as I ran into syncing issues when using client side.
--[[
Author: Jordan
Date: September 26, 2015
Purpose: Create a realistic system for increasing bullet damage in a roleplay setting.
Also, cause extra damage to drop off as bullets are affected by air resistance over long distances.
]]
function RPDamage (attacker, weapon, bodypart)
--THIS FUCKIN SHIT DON'T WORK. CONSTANTLY FUCKIN' TRIGGERING TWICE ON THE ZRP SERVER ONLY!!!
if attacker == nil then -- Covering an error I got randomly sometimes where attacker wasn't met.
attacker = source
end
local x,y,z = getElementPosition( source )
local ex,ey,ez = getElementPosition( attacker )
local distance = (getDistanceBetweenPoints3D (ex, ey, ez, x, y, z))
-- If someone attacks someone with a weapon not on this list, it will return an error can't compare nil. This is normal.
-- In the future could populate list with every weapon in the game, just with 0 values.
local weaponDamage = {["Colt 45"] = 20, ["Silenced"] = 20, ["Deagle"] = 25, ["Shotgun"] = 55, ["Sawed-off"] = 30, ["Combat Shotgun"] = 35, ["Uzi"] = 10, ["MP5"] = 12, ["AK-47"] = 33, ["M4"] = 24, ["Tec-9"] = 10, ["Rifle"] = 44, ["Sniper"] = 58, ["Brassknuckle"] = 0, ["Golfclub"] = 0, ["Nightstick"] = 0, ["Knife"] = 0, ["Bat"] = 0, ["Shovel"] = 0, ["Poolstick"] = 0, ["Katana"] = 0, ["Chainsaw"] = 0, ["Dildo"] = 0, ["Vibrator"] = 0, ["Flower"] = 0, ["Fist"] = 0, ["Cane"] = 0, ["Teargas"] = 0, ["Minigun"] = 0, ["Spraycan"] = 0, ["Fire Extinguisher"] = 0, ["Drowned"] = 0-1}
local weaponDamageModifier = {["Colt 45"] = 1/((distance+0.001)/15), ["Silenced"] = 1/((distance+0.001)/10), ["Deagle"] = 1/((distance+0.001)/15), ["Shotgun"] = 1/((distance+0.001)/8), ["Sawed-off"] = 1/((distance+0.001)/3), ["Combat Shotgun"] = 1/((distance+0.001)/5), ["Uzi"] = 1/((distance+0.001)/12), ["MP5"] = 1/((distance+0.001)/18), ["AK-47"] = 1/((distance+0.001)/15), ["M4"] = 1/((distance+0.001)/30), ["Tec-9"] = 1/((distance+0.001)/12), ["Rifle"] = 1/((distance+0.001)/40), ["Sniper"] = 1/((distance+0.001)/50), ["Brassknuckle"] = 1, ["Golfclub"] = 1, ["Nightstick"] = 1, ["Knife"] = 1, ["Bat"] = 1, ["Shovel"] = 1, ["Poolstick"] = 1, ["Katana"] = 1, ["Chainsaw"] = 1, ["Dildo"] = 1, ["Vibrator"] = 1, ["Flower"] = 1, ["Fist"] = 1, ["Cane"] = 1, ["Teargas"] = 1, ["Minigun"] = 1, ["Spraycan"] = 1, ["Fire Extinguisher"] = 1, ["Drowned"] = 1}
local weaponName = getWeaponNameFromID(weapon)
local originalDamage = weaponDamage[weaponName]
local modifierDamage = weaponDamageModifier[weaponName]
if bodypart == 3 and getPedArmor(source) == 0 and distance > 0.85 then
if weapon == 34 then
--call(getResourceFromName ( "lses-system" ), "knockout", source)
outputChatBox("KO! Sniper to the chest!")
end
if modifierDamage ~= nil then -- This covers for the problem in line 11. It avoids the entire calculation if the weapon isn't in the list.
if modifierDamage > 1 then
local damageMod = originalDamage
outputChatBox("FULL EXTRA DAMAGE!")
if getElementHealth(source) <= damageMod then
killPed (source, attacker, weapon, bodypart, false)
else
setElementHealth(source, getElementHealth(source) - damageMod)
outputChatBox("Damage after falloff: " .. tostring(damageMod))
end
else
local damageMod = math.ceil(originalDamage * modifierDamage) -- Round up, will always do one extra damage.
outputChatBox("Extra damage is falling off.")
if getElementHealth(source) <= damageMod then
killPed (source, attacker, weapon, bodypart, false)
else
setElementHealth(source, getElementHealth(source) - damageMod)
outputChatBox("Damage after falloff: " .. tostring(damageMod))
end
end
end
end
outputChatBox("-------------------------------------------------------")
outputChatBox("Weapon: " .. tostring(weaponName))
outputChatBox("Distance: " .. tostring(distance))
outputChatBox("Extra damage: " .. tostring(originalDamage))
outputChatBox("Multiplyer: " .. tostring(modifierDamage))
outputChatBox("Bone: " .. tostring(bodypart))
outputChatBox("-------------------------------------------------------")
outputChatBox("Health after: " .. tostring(getElementHealth(source)))
end
function weaponStats()
setWeaponProperty(38, "std", "damage", 10)
setWeaponProperty(38, "pro", "damage", 10)
setWeaponProperty(38, "poor", "damage", 10)
setWeaponProperty(22, "std", "weapon_range", 500.0)
setWeaponProperty(22, "pro", "weapon_range", 500.0)
setWeaponProperty(22, "poor", "weapon_range", 500.0)
setWeaponProperty(23, "std", "weapon_range", 500.0)
setWeaponProperty(23, "pro", "weapon_range", 500.0)
setWeaponProperty(23, "poor", "weapon_range", 500.0)
setWeaponProperty(24, "std", "weapon_range", 500.0)
setWeaponProperty(24, "pro", "weapon_range", 500.0)
setWeaponProperty(24, "poor", "weapon_range", 500.0)
setWeaponProperty(25, "std", "weapon_range", 500.0)
setWeaponProperty(25, "pro", "weapon_range", 500.0)
setWeaponProperty(25, "poor", "weapon_range", 500.0)
setWeaponProperty(26, "std", "weapon_range", 500.0)
setWeaponProperty(26, "pro", "weapon_range", 500.0)
setWeaponProperty(26, "poor", "weapon_range", 500.0)
setWeaponProperty(27, "std", "weapon_range", 500.0)
setWeaponProperty(27, "pro", "weapon_range", 500.0)
setWeaponProperty(27, "poor", "weapon_range", 500.0)
setWeaponProperty(28, "std", "weapon_range", 500.0)
setWeaponProperty(28, "pro", "weapon_range", 500.0)
setWeaponProperty(28, "poor", "weapon_range", 500.0)
setWeaponProperty(29, "std", "weapon_range", 500.0)
setWeaponProperty(29, "pro", "weapon_range", 500.0)
setWeaponProperty(29, "poor", "weapon_range", 500.0)
setWeaponProperty(30, "std", "weapon_range", 500.0)
setWeaponProperty(30, "pro", "weapon_range", 500.0)
setWeaponProperty(30, "poor", "weapon_range", 500.0)
setWeaponProperty(31, "std", "weapon_range", 500.0)
setWeaponProperty(31, "pro", "weapon_range", 500.0)
setWeaponProperty(31, "poor", "weapon_range", 500.0)
setWeaponProperty(32, "std", "weapon_range", 500.0)
setWeaponProperty(32, "pro", "weapon_range", 500.0)
setWeaponProperty(32, "poor", "weapon_range", 500.0)
setWeaponProperty(33, "std", "weapon_range", 500.0)
setWeaponProperty(33, "pro", "weapon_range", 500.0)
setWeaponProperty(33, "poor", "weapon_range", 500.0)
outputChatBox("Now AK range: " .. tostring(getWeaponProperty(30, "pro", "weapon_range")))
outputChatBox("Original AK range: " .. tostring(getOriginalWeaponProperty(30, "pro", "weapon_range")))
end
addEventHandler ("onPlayerDamage", getRootElement(), RPDamage)
addEventHandler ("onResourceStart", getRootElement(), weaponStats)
PS: I've never scripted in LUA before, so feel free to let me know how I've done.