/* gabenmod.inc is part of GabenMod
*  Copyright ©2005-2006 by Basic-Master (AMX Mod X Dev Team)
*
*  Yes, Gabe, this mod is dedicated to you, we hope you like
*  it as much as we do! Nevertheless, VALVe, your code still
*  sucks. Especially your HL2SDK, it's a nightmare. Someday
*  Gaben will appear and eat you and your SDK >_<. HE WILL!
*
*/

#if defined _gabenmod_included
  #endinput
#endif
#define _gabenmod_included

#include <amxmodx>
#include <hlsdk_const>
#include <fakemeta> // for the stock

// Comment the line below if you want to use GabenMod without CSDM
//#define CSDM_COMPILATION
// DO NOT USE THIS FUNCTION, THIS IS FOR THE OFFICIAL SERVER ONLY!
//#define KARMA_SUPPORTED


#define GABENMOD_VERSION "1.3"
#define GABENMOD_VERSION_NUM 13


// Set the *available param to 0 if you want to set the total points (e.g. if you are trying to reload the points
// with another plugin:
/* Set user's points */
native gm_SetPoints(id, newpoints, setavailable = 1)

/* Get user's points */
native gm_GetPoints(id, getavailable = 1)

/* Add points to user */
native gm_AddPoints(id, addpoints, addavailable = 1)

/* Remove user's points */
native gm_RemPoints(id, rempoints, remavailable = 1)

// Miscellaneous natives
/* Add extradamage to an user, thanks to the SuperheroMod team :) */
native gm_ExtraDamage(attacker, victim, damage, weaponDescription[], headshot, dmgType = DMG_BULLET, ff = -1)

/* Register power, initfunction must be a public function 
*  Native returns class index or -1 if registration failed 
*  You SHOULD set requiredpoints to 0 and update the skills during
*  the game but you needn't if you don't want.
*
*  The initfunction should look like this:
*  public cmdInit(id, hasclass) { ... }
*
*  And the menu function like this:
*  public cmdMenu(id) { ... }
*
*  Note: If isbaseclass is set, requiredpoints and requiredkarma will be automatically set to 0 and -25.
*/
native gm_RegClass(name[], shorthelp[], initfunction[], menufunction[], buyfunction[], requiredpoints, requiredkarma = -25, isbaseclass = 0)

/* Create an owned item */
native gm_CreateOwnedItem(id, class[])

/* Strip user's weapons */
native gm_StripWeapons(id)

/* A simple check function to check whether you can give items to an user */
native gm_IsValidPlayer(id)

/* Returns the current class of a player */
native gm_GetUserClass(id, class[], len)

/* Check if a user is aiming at a wall */
native gm_AimingAtWall(id, dist = 9999)

/* VelocityByAim clone */
native gm_VelocityByAim(ent, velocity, Float:Result[3])

/* set_rendering clone */
native gm_SetRendering(entity, fx=kRenderFxNone, r=255, g=255, b=255, render=kRenderNormal, amount=0)

/* fakedamage clone */
native gm_FakeDamage(ent, class[], Float:dmg, dmgtype)

/* find_ent_by_owner clone */
native gm_FindEntByOwner(class[], owner)

/* Writes information about a map */
native gm_WriteMapInfo(key[], value[])

/* Reads stored information of a map, return 0 on fail */
native gm_ReadMapInfo(key[], value[], maxlen)

/* Deletes stored map info, returns 0 on error */
native gm_DeleteMapInfo(key[])

/* Can be used in a MapInfoWrite forward only (to set the read value) */
native gm_SetReadResult(newvalue[])

/* Returns 1 if GabenMod is enabled */
native gm_IsEnabled()

// For the karma stuff
#if defined KARMA_SUPPORTED
	#define FORUM_UNRESOLVED -1
	#define FORUM_UNKNOWN     0
	#define FORUM_REGISTERED  1
	#define FORUM_DONOR       2
	#define FORUM_MODERATOR   3
	#define FORUM_DEVELOPER   4
	
	native get_forum_name(client, out[], maxlen)
	native get_user_karma(client)
	native alter_user_karma(client, diff)
	native get_forum_flags(client)
#endif

/* Called after the weapons of a user have been stripped */
forward gm_WeaponsStripped(id)

/* Called when a user has entered the server [when the points have been reset] */
forward gm_UserJoined(id)

/* Called when a user's class has changed */
forward gm_ClassChanged(id, oldclass[], newclass[])

/* Called when a user opens his class menu, return PLUGIN_HANDLED to block this command, otherwise PLUGIN_CONTINUE */
forward gm_OpeningClassMenu(id, class[], class_has_menu)

/* Called when a user opens the buy menu, return PLUGIN_HANDLED to block this command, otherwise PLUGIN_CONTINUE */
forward gm_OpeningBuyMenu(id, class[], class_has_buymenu)

/* Called *before* a new item is given to the user, return PLUGIN_HANDLED to block this call, otherwise PLUGIN_CONTINUE */
forward gm_CreatingOwnedItem(id, itemclass[])

/* Called when a skill function is being used by a user where skillid can be a value between 1 and 5 */
forward gm_UsingSkillCommand(id, skillid)

/* Called when a skill function is not longer in use (skillid can be a value between 1 and 5) */
forward gm_UsedSkillCommand(id, skillid)

/* Use this forward for damage calls, a Damage hook won't work properly! */
forward gm_DamageEvent(victim, attacker, weapon[], damage, extradamage)

/* Called before the playerinfo hudmessage shows up, return PLUGIN_HANDLED to block it */
forward gm_PlayerInfo(id, player, playerclass[])

/* Called before a saved value is being read, return PLUGIN_HANDLED and use gm_SetReadResult to set your read value */
forward gm_OnMapInfoRead(key[])

/* Called before a value is being written, return PLUGIN_HANDLED to block this call */
forward gm_OnMapInfoWrite(key[], value[])

/* Called before a value is being deleted, return PLUGIN_HANDLED to block */
forward gm_OnMapInfoDelete(key[])

/* Called when a user respawns [coders: use this one or I'll beat you!] */
forward gm_Respawn(id)

/* Called when GabenMod is being enabled */
forward gm_EnablingMod()

/* Called when GabenMod is being disabled */
forward gm_DisablingMod()

// Some stocks
/* I'll use this to set keyvalues easily */
stock set_keyvalue(ent, key[], value[]) {
	new classname[32]
	pev(ent, pev_classname, classname, 31)
	set_kvd(0, KV_ClassName, classname)
	set_kvd(0, KV_KeyName, key)
	set_kvd(0, KV_Value, value)
	set_kvd(0, KV_fHandled, 0)
	
	dllfunc(DLLFunc_KeyValue, ent, 0)
}

/* vector_distance() in Pawn! */
stock vec_distance(Float:v1[3], Float:v2[3]) {
	new tmp[3]
	tmp[0] = floatround(v2[0] - v1[0])
	tmp[1] = floatround(v2[1] - v1[1])
	tmp[2] = floatround(v2[2] - v1[2])
	
	return sqroot(tmp[0] * tmp[0] + tmp[1] * tmp[1] + tmp[2] * tmp[2])
}

/* get_speed() clone */
stock get_ent_speed(ent) {
	new Float:Vel[3], rVel[3]
	pev(ent, pev_velocity, Vel)
	rVel[0] = floatround(Vel[0])
	rVel[1] = floatround(Vel[1])
	rVel[2] = floatround(Vel[2])
	
	return sqroot(rVel[0] * rVel[0] + rVel[1] * rVel[1] + rVel[2] * rVel[2])
}

/* useful stock, thanks PM!11 */
stock pos_between_vectors(const Float:eStart[3], const Float:eEnd[3], Float:distance, Float:output[3]) 
{ 
   // output used as temporary
 
   // 1) place direction vector into output
   output[0] = eEnd[0] - eStart[0];
   output[1] = eEnd[1] - eStart[1];
   output[2] = eEnd[2] - eStart[2];
 
   // 2 + 3) normalise direction vector; and multiply by distance
   // each component /= length; then *= distance
   new Float:x = distance/floatsqroot(output[0]*output[0] + output[1]*output[1] + output[2]*output[2]);
   output[0] *= x;
   output[1] *= x;
   output[2] *= x;
 
   // 4) direction vector + start point = output 
   output[0] += eStart[0]; 
   output[1] += eStart[1]; 
   output[2] += eStart[2]; 
} 

/* use this to set a user's health */
stock set_user_health(id, Float:health) {
	set_pev(id, pev_health, health)
	set_pev(id, pev_max_health, health)
}
