Author Topic: Advanced Programming (MethodMaps are awesome!)  (Read 577 times)

El Diablo

  • Hero Member
  • *****
  • Posts: 1126
    • View Profile
    • War3Evo
Advanced Programming (MethodMaps are awesome!)
« on: January 24, 2016, 08:20:38 AM »
THIS EXAMPLE IS ALL ABOUT IMPLEMENTING METHODMAPS INTO WAR3SOURCE

Here is a example of one of my methodmaps:

Code: [Select]
methodmap W3player

{

public W3player(int playerindex) //constructor

{

if(!ValidPlayer(playerindex)) return view_as<W3player>(0);

return view_as<W3player>(playerindex); //make sure you do validity check on players

}

property int index

{

public get() { return view_as<int>(this); }

}

property int alive

{

public get() { return ValidPlayer(this.index,true); }

}

property int team

{

public get() { return GetClientTeam(this.index); }

}

property int maxhp

{

public get() { return W3GetPlayerProp(this.index, iMaxHP); }

public set( int value ) { W3SetPlayerProp(this.index, iMaxHP, value); }

}

property int gold

{

public get() { return W3GetPlayerProp(this.index, PlayerGold); }

public set( int value ) { W3SetPlayerProp(this.index, PlayerGold, value); }

}

property int diamonds

{

public get() { return W3GetPlayerProp(this.index, PlayerDiamonds); }

public set( int value ) { W3SetPlayerProp(this.index, PlayerDiamonds, value); }

}

property int raceid

{

public get() { return War3_GetRace(this.index); }

public set( int value ) { War3_SetRace(this.index, value); }

}



property bool stunned

{

public get() { return W3GetBuffHasTrue(this.index,bStunned); }

}

property bool silenced

{

public get() { return W3GetBuffHasTrue(this.index,bSilenced); }

}

property bool hexed

{

public get() { return W3GetBuffHasTrue(this.index,bHexed); }

}

property bool perplexed

{

public get() { return W3GetBuffHasTrue(this.index,bPerplexed); }

}



property int speed

{

public get() { return W3GetSpeedMulti(this.index); }

}



property int hastalents

{

public get() { return W3GetPlayerProp(this.index,talentsLoaded); }

}



property TFClassType class

{

public get() { return TF2_GetPlayerClass(this.index); }

}



public void teleport(int target=-1, float ScaleVectorDistance=-1.0, float distance=1200.0, int raceid=-1, int skillid=-1)

{

W3Teleport(this.index,target,ScaleVectorDistance,distance,raceid,skillid);

}



//buff

//RESETS ALL BUFFS PERTAINGIN TO THIS CLIENT AND RACE, basically fully getting rid if all buffs attatched to this player from your race

public void resetallbuffs(int raceid)

{

W3ResetAllBuffRace(this.index, raceid);

}

public void resetbuff(W3Buff buffindex, int raceid)

{

W3ResetBuffRace(this.index,buffindex,raceid);

}



public bool immunity(War3Immunity immunityindex)

{

return W3HasImmunity(this.index, immunityindex);

}



public void setbuff(W3Buff buffindex, int raceid, any value, int buffowner=-1)

{

War3_SetBuff(this.index,buffindex,raceid,value,buffowner);

}

public any getbuff(W3Buff buffindex, int raceid)

{

return W3GetBuff(this.index,buffindex,raceid);

}



public void removeaura( int tAuraID )

{

W3RemovePlayerAura(tAuraID,this.index);

}

public bool hasaura( int tAuraID, int &level )

{

return W3HasAura(tAuraID,this.index,level);

}



public void setcooldown(float cooldownTime, int raceid, int skillNum, bool resetOnSpawn=true, bool printMsgOnExpireByTime=true)

{

War3_CooldownMGR(this.index,cooldownTime,raceid,skillNum,resetOnSpawn,printMsgOnExpireByTime);

}



public int getskilllevel( int raceid, int skill )

{

return War3_GetSkillLevel(this.index,raceid,skill);

}



public bool skillnotcooldown( int raceid, int skillNum, bool printTextIfNotReady=false )

{

return War3_SkillNotInCooldown(this.index,raceid,skillNum,printTextIfNotReady);

}

public bool skillcooldown( int raceid, int skillNum, bool printTextIfNotReady=false )

{

return !War3_SkillNotInCooldown(this.index,raceid,skillNum,printTextIfNotReady);

}



public void respawn()

{

War3_SpawnPlayer(this.index);

}



//War3_HealToMaxHP

public void HealToMaxHP( int HealAmount)

{

War3_HealToMaxHP(this.index,HealAmount);

}

//War3_TFHealingEvent

public void TFHealingEvent( int HealAmount)

{

War3_TFHealingEvent(this.index,HealAmount);

}



public void message( char szMessage[MAX_MESSAGE_LENGTH], any ... )

{

if (this.index == 0)

{

char szBuffer[MAX_MESSAGE_LENGTH];

for (int i = 1; i <= MaxClients; i++)

{

if (IsClientInGame(i) && !IsFakeClient(i))

{

SetGlobalTransTarget(i);

VFormat(szBuffer, sizeof(szBuffer), szMessage, 3);

Format(szBuffer, sizeof(szBuffer), "{green}[War3Evo]{default} %s", szBuffer);

CPrintToChat(i, szBuffer);

}

}

}

else

{

char szBuffer[MAX_MESSAGE_LENGTH];

SetGlobalTransTarget(this.index);

VFormat(szBuffer, sizeof(szBuffer), szMessage, 3);

Format(szBuffer, sizeof(szBuffer), "{green}[War3Evo]{default} %s", szBuffer);



if(ValidPlayer(this.index) && !IsFakeClient(this.index))

{

CPrintToChat(this.index, szBuffer);

}

}

}

}

In theroy, you should be able to put this on the very bottom of your addons/sourcemod/scripting/W3SIncs/War3Source_Interface.inc


Here is an example of it being used by my Undead Scourge:

PLEASE NOTE, THIS RACE WILL NOT WORK WITH YOUR WAR3SOURCE.  COMES DIRECTLY FROM MY VERSION OF IT!  My version uses private forwards, you'd have to change the code to make it work for you.

Notice that the "methodmap ThisRacePlayer < W3player"can be inherited in your races!

Code: [Select]
#include <war3source>
#assert GGAMEMODE == MODE_WAR3SOURCE
#assert GGAMETYPE_JAILBREAK == JAILBREAK_OFF

#define RACE_ID_NUMBER 10
#define RACE_LONGNAME "Undead Scourge"
#define RACE_SHORTNAME "undead"


/**
* File: War3Source_UndeadScourge.sp
* Description: The Undead Scourge race for War3Source.
* Author(s): Anthony Iacono, Necavi
*/

//#pragma semicolon 1

//#include <sourcemod>
//#include "W3SIncs/War3Source_Interface"

new thisRaceID;

new Float:CritDamageIncrease = 0.25;

#if GGAMETYPE == GGAME_TF2
// Chance/Data Arrays
//new Float:SuicideBomberRadius[5]={0.0,250.0,290.0,310.0,333.0};
//new Float:SuicideBomberDamageTF[5]={0.0,100.0,135.0,170.0,200.0};
new Float:Reincarnation[5]={0.0,60.0,50.0,40.0,30.0};

new Float:UnholySpeed[5]={1.0,1.05,1.10,1.15,1.24};
//new Float:LevitationGravity[5]={1.0,0.85,0.7,0.6,0.5};

//new Float:VampirePercent[5]={0.0,0.02,0.06,0.08,0.10};
float VampirePercent[5]={0.0,0.02,0.06,0.08,0.10};
#elseif (GGAMETYPE == GGAME_CSS || GGAMETYPE == GGAME_CSGO)
//new Float:SuicideBomberRadius[5]={0.0,250.0,290.0,310.0,333.0};
//new Float:SuicideBomberDamageTF[5]={0.0,100.0,135.0,170.0,200.0};

new Float:UnholySpeed[5]={1.0,1.05,1.10,1.15,1.24};
//new Float:LevitationGravity[5]={1.0,0.85,0.7,0.6,0.5};
new Float:VampirePercent[5]={0.0,0.02,0.06,0.08,0.10};

new Float:Reincarnation[5]={0.0,60.0,50.0,40.0,30.0};
#endif

new bool:RESwarn[MAXPLAYERSCUSTOM];
#if GGAMETYPE == GGAME_TF2
new Handle:ClientInfoMessage;
#endif

// Team switch checker
bool Can_Player_Revive[MAXPLAYERSCUSTOM+1];

// Methodmap inherits W3player methodmap from war3source.inc
methodmap ThisRacePlayer < W3player
{
// constructor
public ThisRacePlayer(int playerindex) //constructor
{
if(!ValidPlayer(playerindex)) return view_as<ThisRacePlayer>(0);
return view_as<ThisRacePlayer>(playerindex); //make sure you do validity check on players
}
property bool canrevive
{
public get() { return Can_Player_Revive[this.index]; }
public set( bool value ) { Can_Player_Revive[this.index] =  value; }
}
property bool RESwarn
{
public get() { return RESwarn[this.index]; }
public set( bool value ) { RESwarn[this.index] =  value; }
}

public void hudmessage( char szMessage[MAX_MESSAGE_LENGTH], any ... )
{
char szBuffer[MAX_MESSAGE_LENGTH];
SetGlobalTransTarget(this.index);
VFormat(szBuffer, sizeof(szBuffer), szMessage, 3);
SetHudTextParams(-1.0, -1.0, 0.1, 255, 255, 0, 255);
ShowSyncHudText(this.index, ClientInfoMessage, szBuffer);
}
}


new SKILL_LEECH,SKILL_SPEED,SKILL_LOWGRAV,SKILL_SUICIDE;

public Plugin:myinfo =
{
name = RACE_LONGNAME,
author = "PimpinJuice, Necavi",
description = "The Undead Scourge race for War3Source.",
version = "1.0",
url = "http://war3source.com"
};

bool HooksLoaded = false;
public void Load_Hooks()
{
if(HooksLoaded) return;
HooksLoaded = true;

W3Hook(W3Hook_OnWar3Event, OnWar3Event);
W3Hook(W3Hook_OnWar3EventSpawn, OnWar3EventSpawn);
}
public void UnLoad_Hooks()
{
if(!HooksLoaded) return;
HooksLoaded = false;

W3UnhookAll(W3Hook_OnWar3Event);
W3UnhookAll(W3Hook_OnWar3EventSpawn);
}
bool RaceDisabled=true;
public void OnWar3RaceEnabled(newrace)
{
if(newrace==thisRaceID)
{
Load_Hooks();

RaceDisabled=false;
}
}
public void OnWar3RaceDisabled(oldrace)
{
if(oldrace==thisRaceID)
{
RaceDisabled=true;

UnLoad_Hooks();
}
}
// War3Source Functions
public OnPluginStart()
{
//LoadTranslations("w3s.race.undead.phrases");
#if GGAMETYPE == GGAME_TF2
ClientInfoMessage = CreateHudSynchronizer();
#endif

HookEvent("player_team",PlayerTeamEvent);

CreateTimer(0.1,ResWarning,_,TIMER_REPEAT);

}
public OnAllPluginsLoaded()
{
War3_RaceOnPluginStart(RACE_SHORTNAME);
}
public OnMapStart()
{
// Reset Can Player Revive
for(new i=1;i<=MaxClients;i++)    // was MAXPLAYERSCUSTOM
{
Can_Player_Revive[i]=true;
}
}

public OnWar3PlayerAuthed(client)
{
Can_Player_Revive[client]=true;
}

public OnPluginEnd()
{
if(LibraryExists("RaceClass"))
War3_RaceOnPluginEnd(RACE_SHORTNAME);
}
public OnWar3LoadRaceOrItemOrdered2(num,reloadrace_id,String:shortname[])
{
if(num==RACE_ID_NUMBER||(reloadrace_id>0&&StrEqual(RACE_SHORTNAME,shortname,false)))
{
thisRaceID=War3_CreateNewRace(RACE_LONGNAME,RACE_SHORTNAME,"Suicidal,fast,leech hp",reloadrace_id);
SKILL_LEECH=War3_AddRaceSkill(thisRaceID,"Vampiric Aura","Leech Health\nYou recieve up to 10% of your damage dealt as Health\nCan not buy item mask any level",false,4);
SKILL_SPEED=War3_AddRaceSkill(thisRaceID,"Unholy Aura","You run 20% faster",false,4);
SKILL_LOWGRAV=War3_AddRaceSkill(thisRaceID,"Blood Lust","When you gain health from Vampiric Aura,\nyour crit chance increases slowly.\nCrit Chance resets on death.\nCrits count as 25% damage increase.",false,4);
SKILL_SUICIDE=War3_AddRaceSkill(thisRaceID,"Reincarnation","When you die, you revive on the spot.\nHas a 60/50/40/30 second cooldown.",true,4);
War3_CreateRaceEnd(thisRaceID);

War3_AddSkillBuff(thisRaceID, SKILL_LEECH, fVampirePercent, VampirePercent);
War3_AddSkillBuff(thisRaceID, SKILL_SPEED, fMaxSpeed, UnholySpeed);
//War3_AddSkillBuff(thisRaceID, SKILL_LOWGRAV, fLowGravitySkill, LevitationGravity);
War3_SetDependency(thisRaceID, SKILL_LOWGRAV, SKILL_LEECH, 4);
}
}

/* ***************************  OnRaceChanged *************************************/

public OnRaceChanged(client,oldrace,newrace)
{
if(newrace==thisRaceID)
{
InitPassiveSkills(client);
}
else //if(newrace==oldrace)
{
RemovePassiveSkills(client);
}
}
/* ****************************** InitPassiveSkills ************************** */
public InitPassiveSkills(client)
{
}
/* ****************************** RemovePassiveSkills ************************** */
public RemovePassiveSkills(client)
{
ThisRacePlayer player = ThisRacePlayer(client);
player.setbuff(fCritChance, thisRaceID, 0.0);
player.setbuff(iCritMode, thisRaceID, 0,client);
player.setbuff(fCritModifier, thisRaceID, 1.0,client);
player.RESwarn = false;
}


public PlayerTeamEvent(Handle:event,const String:name[],bool:dontBroadcast)
{
if(RaceDisabled)
return;

// Team Switch checker
int userid=GetEventInt(event,"userid");
int client=GetClientOfUserId(userid);
ThisRacePlayer player = ThisRacePlayer(client);
if(player)
{
player.setbuff(fCritChance, thisRaceID, 0.0);
player.setbuff(iCritMode, thisRaceID, 0,client);
player.setbuff(fCritModifier, thisRaceID, 1.0,client);

player.canrevive = false;
player.RESwarn = false;

int skilllevel=player.getskilllevel(thisRaceID,SKILL_SUICIDE);
CreateTimer(Reincarnation[skilllevel],PlayerCanRevive,userid);

player.setcooldown(Reincarnation[skilllevel],thisRaceID,SKILL_SUICIDE,false,true);
}
}

public Action:PlayerCanRevive(Handle:timer,any:userid)
{
// Team Switch checker
int client=GetClientOfUserId(userid);
ThisRacePlayer player = ThisRacePlayer(client);
if(player)
{
player.canrevive=true;
}
}
public OnW3Denyable(W3DENY:event,client)
{
if(RaceDisabled)
return;

if((event == DN_CanBuyItem1) && (W3GetVar(EventArg1) == War3_GetItemIdByShortname("mask")))
{
ThisRacePlayer player = ThisRacePlayer(client);
if(player.raceid==thisRaceID)
{
W3Deny();
player.message("{lightgreen}The mask would suffocate me!");
}
}
}

public void OnWar3Event(W3EVENT event,int client)
{
if(RaceDisabled)
return;

ThisRacePlayer player = ThisRacePlayer(client);

if(event==VampireImmunityCheckPre)
{
if(player && player.raceid==thisRaceID)
{
W3SetVar(EventArg1, Immunity_Skills);
W3SetVar(EventArg2, SKILL_LEECH);
return;
}
}
else if(event==OnVampireBuff)
{
if(player)
{
if(player.raceid==thisRaceID)
{
int skill_level=player.getskilllevel( thisRaceID, SKILL_LOWGRAV );
if(skill_level>0)
{
float CurrentCritChance = player.getbuff(fCritChance,thisRaceID);
//DP("Crit before %f",CurrentCritChance);
if(CurrentCritChance<1.0)
{
CurrentCritChance+=0.01 * skill_level;
player.setbuff(fCritChance,thisRaceID,CurrentCritChance,client);
player.setbuff(iCritMode,thisRaceID,1,client);
player.setbuff(fCritModifier,thisRaceID,CritDamageIncrease,client);
player.message("{blue}BloodLust increases crit chance by %f",CurrentCritChance);
}
else if(CurrentCritChance>1.0)
{
CurrentCritChance=1.0;
player.setbuff(fCritChance,thisRaceID,CurrentCritChance,client);
player.setbuff(iCritMode,thisRaceID,1,client);
player.setbuff(fCritModifier,thisRaceID,CritDamageIncrease,client);
}
//DP("Crit after %f",CurrentCritChance);
}
}
}
}
}

public void OnWar3EventSpawn (int client)
{
ThisRacePlayer player = ThisRacePlayer(client);
if(player.raceid==thisRaceID)
{
RemovePassiveSkills(client);
}
}

/*
public OnUltimateCommand(client,race,bool:pressed)
{
if(RaceDisabled)
return;

if(pressed && War3_GetRace(client)==thisRaceID && IsPlayerAlive(client) && !Silenced(client))
{
#if GGAMETYPE == GGAME_TF2
if(!Spying(client))
{
#endif
new ult_level=War3_GetSkillLevel(client,race,SKILL_SUICIDE);
if(ult_level>0)
{
ForcePlayerSuicide(client);
}
else
{
//DP("undad ");
W3MsgUltNotLeveled(client);
}
#if GGAMETYPE == GGAME_TF2
}
else
{
PrintHintText(client,"No cloaking/disguised to use ultimate");
}
#endif
}
}*/

float djAngle[MAXPLAYERSCUSTOM][3];
float djPos[MAXPLAYERSCUSTOM][3];

public OnWar3EventDeath(victim, attacker)
{
if(RaceDisabled)
return;

ThisRacePlayer pVictim = ThisRacePlayer(victim);
//ThisRacePlayer pAttacker = ThisRacePlayer(attacker);

pVictim.setbuff(fCritChance, thisRaceID, 0.0);
pVictim.setbuff(iCritMode, thisRaceID, 0);
pVictim.setbuff(fCritModifier, thisRaceID, 1.0);

if(victim==attacker)
return;

int race=W3GetVar(DeathRace);
int skill=pVictim.getskilllevel(thisRaceID,SKILL_SUICIDE);
//#if GGAMETYPE == GGAME_TF2
//if(!Spying(victim))
//{
//#endif
if(race==thisRaceID && skill>0 && !pVictim.hexed && pVictim.skillnotcooldown(thisRaceID,SKILL_SUICIDE,true))
{
pVictim.RESwarn = true;
float VecPos[3];
float Angles[3];
War3_CachedAngle(victim,Angles);
War3_CachedPosition(victim,VecPos);
djAngle[victim]=Angles;
djPos[victim]=VecPos;
CreateTimer(2.5,DoDeathReject,GetClientUserId(victim));

/*
if(!War3_IsNewPlayer(victim))
{
decl Float:location[3];
GetClientAbsOrigin(victim,location);
War3_SuicideBomber(victim, location, SuicideBomberDamageTF[skill], SKILL_SUICIDE, SuicideBomberRadius[skill]);
}
else
{
W3MsgNewbieProjectBlocked(victim,"Suicide Bomber",
"You would have\nbeen killed by Undead Scourge's Suicide Bomber,\nbut because you are new\nyou are immune",
"When your newbie protection wears out,\nyou will need to type lace in chat in order to be immune.");
}*/
}
else if(pVictim.skillcooldown(thisRaceID,SKILL_SUICIDE,true))
{
pVictim.message("{blue}Your Reincarnation skill is on cooldown.");
}
//#if GGAMETYPE == GGAME_TF2
//}
//#endif
}

/* ****************************** DoDeathReject ************************** */

public Action:DoDeathReject(Handle:timer,any:userid)
{
int client=GetClientOfUserId(userid);
ThisRacePlayer player = ThisRacePlayer(client);
if(player)
{
if(player.canrevive==false)
{
return Plugin_Handled;
}
int skilllevel=player.getskilllevel(thisRaceID,SKILL_SUICIDE);
player.respawn();
//nsEntity_SetHealth(client, death_reject_health[skilllevel]);
//War3_EmitSoundToAll(DeathRejectSound,client);
TeleportEntity(client, djPos[client], djAngle[client], NULL_VECTOR);
player.RESwarn=false;
player.setcooldown(Reincarnation[skilllevel],thisRaceID,SKILL_SUICIDE,false,true);
}
return Plugin_Continue;
}

public Action:ResWarning(Handle:timer,any:userid)
{
if(RaceDisabled)
return;

ThisRacePlayer player;

for(int client=1;client<=MaxClients;client++)
{
player = ThisRacePlayer(client);
if(player && player.RESwarn)
{
#if GGAMETYPE == GGAME_TF2
player.hudmessage("PREPARE TO REVIVE!");
//SetHudTextParams(-1.0, -1.0, 0.1, 255, 255, 0, 255);
//ShowSyncHudText(client, ClientInfoMessage, "PREPARE TO REVIVE!");
#else
player.message("PREPARE TO REVIVE!");
#endif
}
}
}
public OnClientPutInServer(client)
{
ThisRacePlayer player = ThisRacePlayer(client);
player.RESwarn=false;
}

public OnClientDisconnect(client)
{
ThisRacePlayer player = ThisRacePlayer(client);
player.RESwarn=false;
}


Its still a work in progress... but with this example, you get the picture!  It makes it so much more easier to read (even though i didn't spend anytime to clean up the code for you to look at it good enough).