oscar-broman / samp-weapon-config

A more consistent and responsive damage system with many new features
Apache License 2.0
93 stars 83 forks source link

weapon-config.inc

This is an include that provides a more consistent and responsive damage system with many new features.

It's pretty much plug-and-play if you don't have any filterscripts that interfere with the health or death events.

How to use

  1. #include <weapon-config> before any other script
  2. Replace OnPlayerGiveDamage and OnPlayerTakeDamage with just one callback:

    public OnPlayerDamage(&playerid, &Float:amount, &issuerid, &WEAPON:weapon, &bodypart)
  3. Add config functions in OnGameModeInit (or any other places, they can be called at any time). Recommended:

    public OnGameModeInit() {
        SetVehiclePassengerDamage(true);
        SetDisableSyncBugs(true);
    }

Requirements

This include file requires the SKY or Pawn.RakNet plugin.

Note: SKY has a higher priority if the user has not included any of these dependencies before weapon-config (it will automatically try to include SKY and only then Pawn.RakNet, if fail with the first). Also, SKY will take precedence if both dependencies are included (it will use the SKY plugin instead of Pawn.RakNet).

Features

Implementation details

All players are given infinite health and set to the same team. Damage is counted by the script whenever OnPlayer(Give/Take)Damage is called. The real GetPlayerHealth is never read by the include file.

The players healthbars are modified by editing SA-MP packets, so they are very responsive.

The death animations are applied as "forcesync" and even the facing angle is force synced (with SKY or Pawn.RakNet). This allows perfect animations even for laggy/paused players.

The real OnPlayerDeath is never called from the SA-MP server (only in some rare cases). A player never actually dies in their game - they just see a death animation applied and get respawned.

Many SA-MP functions are hooked to provide new values (such as GetPlayerState, (Get/Set)Player(Health/Armour), GetPlayerTeam).

Caveats

At the moment, filterscripts are not fully supported. If you need to modify the health, go into spec mode, change the virtual world, and more then you should do it through the gamemode.

A simple workaround is to just do something like this:

// In the gamemode
forward SetHealth(playerid, Float:health);
public SetHealth(playerid, Float:health) {
    SetPlayerHealth(playerid, health);
}
// In the filterscript
CallRemoteFunction("SetHealth", "if", playerid, health);

API

Callbacks

Existing callbacks

OnPlayerGiveDamage and OnPlayerTakeDamage are removed. Use OnPlayerDamage (see below).

OnPlayerDeath and OnPlayerWeaponShot are called as usual.

New callbacks

public OnPlayerDamage(&playerid, &Float:amount, &issuerid, &WEAPON:weapon, &bodypart)

Called when damage is about to be inflicted on a player Most arguments can be modified (e.g. the damage could be adjusted)

Return 0 to prevent the damage from being inflicted

public OnPlayerDamageDone(playerid, Float:amount, issuerid, WEAPON:weapon, bodypart)

Called after damage has been inflicted

Same parameters as above, but they can not be modified

Return value ignored

public OnPlayerPrepareDeath(playerid, animlib[32], animname[32], &anim_lock, &respawn_time)

Before the death animation is applied

Return value ignored

public OnPlayerDeathFinished(playerid)

When the death animation has finished and the player has been sent to respawn

Return value ignored

public OnRejectedHit(playerid, hit[E_REJECTED_HIT])

When a shot or damage given is rejected See E_REJECTED_HIT and GetRejectedHit for more

Return value ignored

public OnInvalidWeaponDamage(playerid, damagedid, Float:amount, WEAPON:weaponid, bodypart, error, bool:given)

When a player takes or gives invalid damage (WC_* errors above)

Return value ignored

Functions

AverageShootRate(playerid, shots, &multiple_weapons = 0);

The average time (in milliseconds) between shots.

Returns -1 if there is not enough data to calculate the rate, otherwise the average time is returned.

AverageHitRate(playerid, hits, &multiple_weapons = 0);

Same as above, but for hits inflicted with OnPlayerGiveDamage

DamagePlayer(playerid, Float:amount, issuerid = INVALID_PLAYER_ID, WEAPON:weaponid = WEAPON_UNKNOWN, bodypart = BODY_PART_UNKNOWN, bool:ignore_armour = false);

Inflict a hit on a player. All callbacks except OnPlayerWeaponShot will be called.
Note: do not use it inside OnPlayerDamage as you can just modify amount there

Float:GetPlayerHealth(playerid, &Float:health = 0.0);

Hooked version of the original, which also returns the value

Float:GetPlayerArmour(playerid, &Float:armour = 0.0);

Hooked version of the original, which also returns the value

GetRejectedHit(playerid, idx, output[], maxlength = sizeof(output));

Get a string explaining why the hit was rejected at idx (max. WC_MAX_REJECTED_HITS - 1)

SetRespawnTime(ms);

Set the respawn time in milliseconds

GetRespawnTime();

Get the respawn time

IsBulletWeapon(WEAPON:weaponid);

Returns true if the weapon shoots bullets

IsHighRateWeapon(WEAPON:weaponid);

Returns true if the weapon's damage can be reported in high rates to the server (such as fire)

IsMeleeWeapon(WEAPON:weaponid);

Returns true if it's a melee weapon (including WEAPON_PISTOLWHIP)

IsPlayerDying(playerid);

Returns true if the player is between the dying animation and spawning

WC_IsPlayerSpawned(playerid);

Returns true if the player is spawned and not in a dying animation

WC_IsPlayerPaused(playerid);

Returns true if the player is paused (AFK) within last two seconds

GetWeaponName(WEAPON:weaponid, weapon[], len = sizeof(weapon));

Hooked version of the native, fixed and containing custom weapons (such as pistol whip)

ReturnWeaponName(WEAPON:weaponid);

Return the weapon name (uses the fixed GetWeaponName)

SetCustomFallDamage(bool:toggle, Float:damage_multiplier = 25.0, Float:death_velocity = -0.6);

Toggle custom falling damage

SetCustomVendingMachines(bool:toggle);

Toggle vending machines (they are removed and disabled by default)

SetCbugAllowed(bool:enabled, playerid = INVALID_PLAYER_ID);

Toggle anti-cbug per player or globally. (Using no playerid param will default all users to default)

bool:GetCbugAllowed(playerid = INVALID_PLAYER_ID);

Check if users anti-cbug is toggled. (Using no playerid param will show the global toggle value)

SetDamageFeed(bool:toggle);

Toggle damage feed for all

SetDamageFeedForPlayer(playerid, toggle = -1);

Toggle damage feed for player

IsDamageFeedActive(playerid = -1);

Returns true if damage feed is active for player (for all, if playerid passed as -1)

SetDamageSounds(taken, given);

Set sounds when damage is given and taken (0 to disable)

SetVehiclePassengerDamage(bool:toggle);

Allow vehicles to be damaged when they have a passenger and no driver

SetVehicleUnoccupiedDamage(bool:toggle);

Allow vehicles to be damaged when they don't have any players inside them

SetWeaponDamage(WEAPON:weaponid, damage_type, Float:amount, Float:...);

Modify a weapon's damage

Float:GetWeaponDamage(WEAPON:weaponid);

Get the amount of damage of a weapon

SetWeaponMaxRange(WEAPON:weaponid, Float:range);

Set the max range of a weapon. The default value is those from weapon.dat Because of a SA-MP bug, weapons can (and will) exceed this range. This script, however, will block those out-of-range shots and give a rejected hit.

Float:GetWeaponMaxRange(WEAPON:weaponid);

Get the max range of a weapon

SetWeaponShootRate(WEAPON:weaponid, max_rate);

Set the max allowed shoot rate of a weapon. Could be used to prevent C-bug damage or allow infinite shooting if a script uses GivePlayerWeapon to do so.

GetWeaponShootRate(WEAPON:weaponid);

Get the max allowed shoot rate of a weapon

SetCustomArmourRules(bool:armour_rules, bool:torso_rules);

Toggle the custom armour rules on and off. Both are disabled by default.

SetWeaponArmourRule(WEAPON:weaponid, bool:affects_armour, bool:torso_only);

Set custom rules for a weapon. The defaults aren't going to comfort EVERYONE, so everyone needs the ability to modify the weapons themselves.

EnableHealthBarForPlayer(playerid, bool:enable);

Show or hide health bar for player.