Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Samyro #192

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
4 changes: 4 additions & 0 deletions addons/sourcemod/scripting/saxtonhale.sp
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ ConVar tf_arena_preround_time;
#include "vsh/abilities/ability_brave_jump.sp"
#include "vsh/abilities/ability_dash_jump.sp"
#include "vsh/abilities/ability_drop_model.sp"
#include "vsh/abilities/ability_conditions.sp"
#include "vsh/abilities/ability_float_jump.sp"
#include "vsh/abilities/ability_force_forward.sp"
#include "vsh/abilities/ability_groundpound.sp"
Expand Down Expand Up @@ -390,6 +391,7 @@ ConVar tf_arena_preround_time;
#include "vsh/bosses/boss_pyromancer_scorched.sp"
#include "vsh/bosses/boss_pyromancer_scalded.sp"
#include "vsh/bosses/boss_redmond.sp"
#include "vsh/bosses/boss_samyro.sp"
#include "vsh/bosses/boss_seeldier.sp"
#include "vsh/bosses/boss_seeman.sp"
#include "vsh/bosses/boss_uberranger.sp"
Expand Down Expand Up @@ -680,6 +682,7 @@ public void OnPluginStart()
SaxtonHale_RegisterClass("CPainisCupcake", VSHClassType_Boss);
SaxtonHale_RegisterClass("CPyroCar", VSHClassType_Boss);
SaxtonHale_RegisterClass("CRedmond", VSHClassType_Boss);
SaxtonHale_RegisterClass("CSamyro", VSHClassType_Boss);
SaxtonHale_RegisterClass("CScaldedPyromancer", VSHClassType_Boss);
SaxtonHale_RegisterClass("CScorchedPyromancer", VSHClassType_Boss);
SaxtonHale_RegisterClass("CSeeldier", VSHClassType_Boss);
Expand All @@ -700,6 +703,7 @@ public void OnPluginStart()
SaxtonHale_RegisterClass("CZombie", VSHClassType_Boss);

//Register ability
SaxtonHale_RegisterClass("CAddCond", VSHClassType_Ability);
SaxtonHale_RegisterClass("CBodyEat", VSHClassType_Ability);
SaxtonHale_RegisterClass("CBomb", VSHClassType_Ability);
SaxtonHale_RegisterClass("CBombProjectile", VSHClassType_Ability);
Expand Down
139 changes: 139 additions & 0 deletions addons/sourcemod/scripting/vsh/abilities/ability_conditions.sp
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
static float g_flCondCooldownWait[TF_MAXPLAYERS + 1];
static float g_flCondCooldown[TF_MAXPLAYERS + 1];
static float g_flCondDuration[TF_MAXPLAYERS + 1];
static float g_flCondMaxCharge[TF_MAXPLAYERS + 1];
static bool g_bRemoveOnRage[TF_MAXPLAYERS + 1];
static ArrayList g_aConditions[TF_MAXPLAYERS + 1];

methodmap CAddCond < SaxtonHaleBase
{
property float flCondCooldown
{
public get()
{
return g_flCondCooldown[this.iClient];
}
public set(float flVal)
{
g_flCondCooldown[this.iClient] = flVal;
}
}

property float flCondDuration
{
public get()
{
return g_flCondDuration[this.iClient];
}
public set(float flVal)
{
g_flCondDuration[this.iClient] = flVal;
}
}

property float flCondMaxCharge
{
public get()
{
return g_flCondMaxCharge[this.iClient];
}
public set(float flVal)
{
g_flCondMaxCharge[this.iClient] = flVal;
}
}

property bool bRemoveOnRage
{
public get()
{
return g_bRemoveOnRage[this.iClient];
}
public set(bool bVal)
{
g_bRemoveOnRage[this.iClient] = bVal;
}
}

public CAddCond(CAddCond ability)
{
g_flCondCooldownWait[ability.iClient] = 0.0;

if (g_aConditions[ability.iClient] == null)
g_aConditions[ability.iClient] = new ArrayList();
g_aConditions[ability.iClient].Clear();

ability.flCondCooldown = 30.0;
ability.flCondDuration = 8.0;
ability.flCondMaxCharge = 1.0;
}

public void AddCond(TFCond cond)
{
g_aConditions[this.iClient].Push(cond);
}

public void OnThink()
{
if (GameRules_GetRoundState() == RoundState_Preround)
return;

char sMessage[255];
int iCharge;

if (g_flCondCooldownWait[this.iClient] < GetGameTime())
{
iCharge = RoundToFloor(this.flCondMaxCharge * 100.0);
}
else
{
float flPercentage = (g_flCondCooldownWait[this.iClient] - GetGameTime()) / this.flCondCooldown;
iCharge = RoundToFloor((this.flCondMaxCharge - flPercentage) * 100.0);
}

if (iCharge >= 100)
Format(sMessage, sizeof(sMessage), "Ability Charge: %d%%%% - Press MOUSE2 to use!", iCharge);
else
Format(sMessage, sizeof(sMessage), "Ability Charge: %d%%%%", iCharge);

Hud_AddText(this.iClient, sMessage);
}

public void OnButtonPress(int iButton)
{
if (iButton == IN_ATTACK2 && GameRules_GetRoundState() != RoundState_Preround && !TF2_IsPlayerInCondition(this.iClient, TFCond_Dazed))
{
if (g_flCondCooldownWait[this.iClient] < GetGameTime())
g_flCondCooldownWait[this.iClient] = GetGameTime();

float flPercentage = (g_flCondCooldownWait[this.iClient] - GetGameTime()) / this.flCondCooldown;
float flCharge = this.flCondMaxCharge - flPercentage;

if (flCharge < 1.0)
return;

for (int i = 0; i < g_aConditions[this.iClient].Length; i++)
{
TF2_AddCondition(this.iClient, g_aConditions[this.iClient].Get(i), this.flCondDuration);
}

g_flCondCooldownWait[this.iClient] += this.flCondCooldown;

char sSound[PLATFORM_MAX_PATH];
this.CallFunction("GetSoundAbility", sSound, sizeof(sSound), "CAddCond");
if (!StrEmpty(sSound))
EmitSoundToAll(sSound, this.iClient, SNDCHAN_VOICE, SNDLEVEL_SCREAMING);
}
}

public void OnRage()
{
if (this.bRemoveOnRage)
{
for (int i = 0; i < g_aConditions[this.iClient].Length; i++)
{
TF2_RemoveCondition(this.iClient, g_aConditions[this.iClient].Get(i));
}
}
}
};
219 changes: 219 additions & 0 deletions addons/sourcemod/scripting/vsh/bosses/boss_samyro.sp
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
#define SAMYRO_MUSIC "vsh_rewrite/samyro/samyro_music.mp3"

static int g_iSamyroModelHat;
static int g_iSamyroModelMask;
static int g_iSamyroModelKatana;
static int g_iSamyroModelHands;

static float g_flClientRageGainLastTime[TF_MAXPLAYERS + 1];

static char g_strSamyroRoundStart[][] = {
"vo/pyro_battlecry01.mp3",
"vo/pyro_battlecry02.mp3"
};

static char g_strSamyroRoundWin[][] = {
"vo/taunts/pyro/pyro_taunt_head_pain_21.mp3",
"vo/taunts/pyro/pyro_taunt_head_pain_22.mp3"
};

static char g_strSamyroRoundLose[][] = {
"vo/pyro_paincrticialdeath01.mp3",
"vo/pyro_paincrticialdeath02.mp3",
"vo/pyro_paincrticialdeath03.mp3",
"vo/taunts/pyro/pyro_taunt_rps_lose_03.mp3"
};

static char g_strSamyroRage[][] = {
"vo/pyro_laughlong01.mp3"
};

static char g_strSamyroKill[][] = {
"vo/taunts/pyro_taunts01.mp3",
"vo/taunts/pyro_taunts02.mp3",
"vo/taunts/pyro_taunts03.mp3",
"vo/taunts/pyro_taunts04.mp3",
"vo/compmode/cm_pyro_pregamelostlast_02.mp3",
"vo/compmode/cm_pyro_pregamelostlast_03.mp3"
};

static char g_strSamyroLastMan[][] = {
"vo/cm_pyro_pregamewonlast_01.mp3"
};

static char g_strSamyroAbility[][] = {
"items/samurai/tf_samurai_noisemaker_seta_01.wav",
"items/samurai/tf_samurai_noisemaker_seta_02.wav",
"items/samurai/tf_samurai_noisemaker_seta_03.wav"
};

methodmap CSamyro < SaxtonHaleBase
{
public CSamyro(CSamyro boss)
{
boss.CallFunction("CreateAbility", "CWallClimb");

CAddCond abilityCond = boss.CallFunction("CreateAbility", "CAddCond");
abilityCond.AddCond(TFCond_RuneAgility);
abilityCond.bRemoveOnRage = true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like both mannpower conds can be gained if rage is used first, then m2 ability during rage


CRageAddCond rageCond = boss.CallFunction("CreateAbility", "CRageAddCond");
rageCond.flRageCondDuration = 12.0;
rageCond.flRageCondSuperRageMultiplier = 14.0 / 12.0;
rageCond.AddCond(TFCond_RuneHaste);
rageCond.AddCond(TFCond_DefenseBuffed);

boss.iBaseHealth = 700;
boss.iHealthPerPlayer = 650;
boss.nClass = TFClass_Pyro;
boss.iMaxRageDamage = 2500;

AddCommandListener(Command_DropItem, "dropitem");
}

public void GetBossName(char[] sName, int length)
{
strcopy(sName, length, "Samyro");
}

public void GetBossInfo(char[] sInfo, int length)
{
StrCat(sInfo, length, "\nHealth: Low");
StrCat(sInfo, length, "\n ");
StrCat(sInfo, length, "\nAbilities");
StrCat(sInfo, length, "\n- Passive Rage Gain");
StrCat(sInfo, length, "\n- Wall Climb");
StrCat(sInfo, length, "\n- Agility");
StrCat(sInfo, length, "\n ");
StrCat(sInfo, length, "\nRage");
StrCat(sInfo, length, "\n- Gain the Haste powerup and a defensive buff for 12 seconds");
StrCat(sInfo, length, "\n- Rage overrides Agility");
StrCat(sInfo, length, "\n- 200%% Rage: Become übercharged and extend duration by 2 seconds");
}

public void OnSpawn()
{
char attribs[128];
Format(attribs, sizeof(attribs), "2 ; 2.80 ; 252 ; 0.5 ; 259 ; 1.0 ; 180 ; 0.0 ; 226 ; 0.0");
int iWeapon = this.CallFunction("CreateWeapon", 357, "tf_weapon_katana", 100, TFQual_Collectors, attribs);
if (iWeapon > MaxClients)
{
SetEntProp(iWeapon, Prop_Send, "m_nModelIndexOverrides", g_iSamyroModelKatana);

int iViewModel = CreateViewModel(this.iClient, g_iSamyroModelKatana);
SetEntPropEnt(iViewModel, Prop_Send, "m_hWeaponAssociatedWith", iWeapon);
SetEntPropEnt(iWeapon, Prop_Send, "m_hExtraWearableViewModel", iViewModel);

CreateViewModel(this.iClient, g_iSamyroModelHands);
SetEntProp(GetEntPropEnt(this.iClient, Prop_Send, "m_hViewModel"), Prop_Send, "m_fEffects", EF_NODRAW);

SetEntPropEnt(this.iClient, Prop_Send, "m_hActiveWeapon", iWeapon);
}
/*
Half-Zatoichi attributes:

2: damage bonus
252: reduction in push force taken from damage
259: deals 3x falling damage to the player you land on
180: 0% health restored on kill
226: not honorbound
*/

int iWearable = -1;

iWearable = this.CallFunction("CreateWeapon", 627, "tf_wearable", 1, TFQual_Collectors, ""); //The Flamboyant Flamenco
if (iWearable > MaxClients)
SetEntProp(iWearable, Prop_Send, "m_nModelIndexOverrides", g_iSamyroModelHat);

iWearable = this.CallFunction("CreateWeapon", 570, "tf_wearable", 1, TFQual_Collectors, ""); //The Last Breath
if (iWearable > MaxClients)
SetEntProp(iWearable, Prop_Send, "m_nModelIndexOverrides", g_iSamyroModelMask);
}

public void OnThink()
{
if (GameRules_GetRoundState() == RoundState_Preround)
return;

//Passive rage gain
if (g_flClientRageGainLastTime[this.iClient] <= GetGameTime() - 0.05)
{
this.CallFunction("AddRage", 1);
g_flClientRageGainLastTime[this.iClient] = GetGameTime();
}
}

public void OnRage()
{
//Übercharge on 200% rage
if (this.bSuperRage)
{
CRageAddCond rageCond = this.CallFunction("FindAbility", "CRageAddCond");
if (rageCond != INVALID_ABILITY)
{
TF2_AddCondition(this.iClient, TFCond_Ubercharged, rageCond.flRageCondDuration * rageCond.flRageCondSuperRageMultiplier);
}
}
}

public void GetSound(char[] sSound, int length, SaxtonHaleSound iSoundType)
{
switch (iSoundType)
{
case VSHSound_RoundStart: strcopy(sSound, length, g_strSamyroRoundStart[GetRandomInt(0, sizeof(g_strSamyroRoundStart) - 1)]);
case VSHSound_Win: strcopy(sSound, length, g_strSamyroRoundWin[GetRandomInt(0, sizeof(g_strSamyroRoundWin) - 1)]);
case VSHSound_Lose: strcopy(sSound, length, g_strSamyroRoundLose[GetRandomInt(0, sizeof(g_strSamyroRoundLose) - 1)]);
case VSHSound_Rage: strcopy(sSound, length, g_strSamyroRage[GetRandomInt(0, sizeof(g_strSamyroRage) - 1)]);
case VSHSound_Lastman: strcopy(sSound, length, g_strSamyroLastMan[GetRandomInt(0, sizeof(g_strSamyroLastMan) - 1)]);
}
}

public void GetSoundAbility(char[] sSound, int length, const char[] sType)
{
if (strcmp(sType, "CAddCond") == 0)
strcopy(sSound, length, g_strSamyroAbility[GetRandomInt(0, sizeof(g_strSamyroAbility) - 1)]);
}

public void GetSoundKill(char[] sSound, int length, TFClassType nClass)
{
strcopy(sSound, length, g_strSamyroKill[GetRandomInt(0, sizeof(g_strSamyroKill) - 1)]);
}

public void GetMusicInfo(char[] sSound, int length, float &time)
{
strcopy(sSound, length, SAMYRO_MUSIC);
time = 195.0;
}

public void Precache()
{
g_iSamyroModelHat = PrecacheModel("models/player/items/pyro/fwk_pyro_flamenco.mdl");
g_iSamyroModelMask = PrecacheModel("models/workshop/player/items/pyro/pyro_halloween_gasmask/pyro_halloween_gasmask.mdl");
g_iSamyroModelKatana = PrecacheModel("models/workshop_partner/weapons/c_models/c_shogun_katana/c_shogun_katana.mdl");
g_iSamyroModelHands = PrecacheModel("models/weapons/c_models/c_pyro_arms.mdl");

PrepareSound(SAMYRO_MUSIC);

for (int i = 0; i < sizeof(g_strSamyroRoundStart); i++) PrecacheSound(g_strSamyroRoundStart[i]);
for (int i = 0; i < sizeof(g_strSamyroRoundWin); i++) PrecacheSound(g_strSamyroRoundWin[i]);
for (int i = 0; i < sizeof(g_strSamyroRoundLose); i++) PrecacheSound(g_strSamyroRoundLose[i]);
for (int i = 0; i < sizeof(g_strSamyroRage); i++) PrecacheSound(g_strSamyroRage[i]);
for (int i = 0; i < sizeof(g_strSamyroKill); i++) PrecacheSound(g_strSamyroKill[i]);
for (int i = 0; i < sizeof(g_strSamyroLastMan); i++) PrecacheSound(g_strSamyroLastMan[i]);
for (int i = 0; i < sizeof(g_strSamyroAbility); i++) PrecacheSound(g_strSamyroAbility[i]);
}

public bool IsBossHidden()
{
return true;
}
};

public Action Command_DropItem(int iClient, const char[] sCommand, int iArgs)
{
//Prevent boss from dropping powerups
if (SaxtonHaleBase(iClient).bValid)
return Plugin_Handled;

return Plugin_Continue;
}
Binary file added sound/vsh_rewrite/samyro/samyro_music.mp3
Binary file not shown.