Description: this is a a server-sent plugin which gives GG2
a new game mode and
doesn't affect other game modesIt will turn
any arena map that starts with "vsh_" into a "Versus
Hale Haxton Heroes" mode
How to use:
- The plugin's name is "
vsh" (without quotes)
- include the plugin in the ini (
how)
- include arena maps that start with "vsh_" in the map rotation
-
ONLY HOST VSH MAPS, I made a mistake that "destroyed" other game modes and I will fix it next build
Features:
- there will be only one BLU with a huge hp pool and melee attack, all other REDs will have to fight them
- capture is slower than it is shown
- humiliation slow you down
a lot- RED's attacks will slow BLU down
- spy's stab cause humiliation and heal spy completely
- pyro's after burn slow BLU
- sniper max scoped damage increased to 110
- quote's blade decreased range
- every class except medics will heal 1hp per second if not injured for 3 seconds
- huge hp pool, 75 damage meele attack (left mouse) with knock back
- speed increase as health drop, from soldier speed to faster than scout
- scout, pyro, soldier, medic, and demoman can super jump in any direction (right mouse) every 15 second
- after taken a fixed amount of damage, you can taunt to perform rage which will humiliated nearby enemies
- each class have specific perks:
+ scout have increased initial speed, can double jump and have doubled cap strength
+ pyro attacks burn enemies for approximately 30 damage, immune to after burn
+ soldier rage is global and last 8 seconds
+ heavy block 2 damage, have 120% more hp and can eat to heal 1/8 hp, can't super jump
+ medic regenerate 0.25% hp per second
+ demoman leech 2% hp per hit and gain small rage meter per kill
+ engineer can build an invulnerable sentry (vulnerable to stab) instantly, can't super jump, lowered hp to 70%
+ sniper basically have a weaker sniper rifle with bullet instead of laser, can't super jump
+ spy have weaker attack but can cloak and can move (but can't jump) while stabbing, can't super jump
+ quote have 120% more hp
Notes:
-
REMEMBER to include atleast an arena map starts with "vsh_" into the map rotation
- if you are forced to change team in the new round, your class will change to scout (class limit bug?)
- spy stab humiliate longer than intended (bug)
- this plugin is hastily made for haxxy (I went offline for a long time) so it is heavily unbalanced, there will be more bugs
- this is unfinished: no new sprites (that's why i named it vs heroes instead of haxton) nor sound
Code for anyone who wants to look at (give me suggestions if you can)
/*VERSUS HAXTON PLUGIN*/
//By MTK5012//
global.vsh = 0;
global.vshBoss = -1;
global.vshBuffer = buffer_create();
//HUD//
object_event_add(ArenaHUD, ev_draw, 0, "
if (global.vsh > 0) {
var boss;
if (ds_list_find_value(global.players,global.vshBoss))
boss = (ds_list_find_value(global.players,global.vshBoss)).object;
else
boss = -1;
if (boss != -1) {
draw_healthbar(view_xview+120, view_yview+20, view_xview+240, view_yview+40, boss.hp*100/boss.maxHp, c_black, c_red, c_green, 0, true, false);
var superJump,canRage;
superJump = 0;
canRage = 0;
with (boss) {
if (variable_local_exists('vshSuperJump'))
if (vshSuperJump == 0)
superJump = 1;
if (player.class == CLASS_SPY or player.class == CLASS_ENGINEER or player.class == CLASS_HEAVY or player.class == CLASS_SNIPER)
superJump = 0;
if (variable_local_exists('vshRage'))
if (vshRage >= 700)
canRage = 1;
}
if (superJump)
draw_text(view_xview+180, view_yview+60, 'Super jump ready!');
if (canRage)
draw_text(view_xview+180, view_yview+80, 'Rage ready!');
}
}
");
object_event_add(PlayerControl , ev_step, ev_step_begin, "
//DETECT VS HALE MAPS//
if (global.vsh == 0 and string_copy(global.currentMap, 0, 4) == 'vsh_' and instance_exists(ArenaHUD))
global.vsh = 1;
if (global.vsh > 0 and (string_copy(global.currentMap, 0, 4) != 'vsh_' or !instance_exists(ArenaHUD)))
global.vsh = 0;
");
object_event_add(GameServer, ev_step, ev_step_begin, "
//RESTART//
if (global.vsh == 2)
if (ArenaHUD.roundStart == 299)
global.vsh = 1;
//PICK BOSS//
if (!ds_list_find_value(global.players, global.vshBoss) or global.vsh == 1) {
global.vshBoss = floor(random(ds_list_size(global.players)));
if (ArenaHUD.roundStart > 0)
global.vsh = 1;
}
//I DONT WANNA BE THE BOSS//
//not gonna happen but i'll keep it here any way
if (ds_list_find_value(global.players, global.vshBoss))
if ((ds_list_find_value(global.players, global.vshBoss)).team == TEAM_RED) {
global.vshBoss = floor(random(ds_list_size(global.players)));
if (ArenaHUD.roundStart > 0)
global.vsh = 1;
}
//MORE THAN 1 BLUE//
//after the pick boss to prevent cheaters
if (global.vsh == 2)
if (ArenaHUD.roundStart > 0 and ds_list_find_value(global.players, global.vshBoss)) {
var i,noOfBlu;
noOfBlu = 0;
for (i = 0; i < ds_list_size(global.players); i += 1) {
if ((ds_list_find_value(global.players,i)).team == TEAM_BLUE)
noOfBlu += 1;
}
if (noOfBlu > 1)
global.vsh = 1;
}
//REARRANGE TEAM//
if (global.vsh == 1) {
global.vsh = 2;
var playerId;
with (Player) {
playerId = ds_list_find_index(global.players, id);
//fighters
if (team == TEAM_BLUE and global.vshBoss != playerId) {
if(object != -1) {
with(object) {
//not sure if i need this
sendEventPlayerDeath(player, player, noone, BID_FAREWELL);
doEventPlayerDeath(player, player, noone, BID_FAREWELL);
}
alarm[5] = global.Server_Respawntime;
}
else if(alarm[5]<=0)
alarm[5] = 1;
var newClass;
newClass = checkClasslimits(TEAM_RED, class);
if newClass != class {
class = newClass;
ServerPlayerChangeclass(playerId, class, global.sendBuffer);
}
team = TEAM_RED;
ServerPlayerChangeteam(playerId, TEAM_RED, global.sendBuffer);
}
//boss
if (team == TEAM_RED and global.vshBoss == playerId) {
if(object != -1) {
with(object) {
sendEventPlayerDeath(player, player, noone, BID_FAREWELL);
doEventPlayerDeath(player, player, noone, BID_FAREWELL);
}
alarm[5] = global.Server_Respawntime;
}
else if(alarm[5]<=0)
alarm[5] = 1;
var newClass;
newClass = checkClasslimits(TEAM_BLUE, class);
if newClass != class {
class = newClass;
ServerPlayerChangeclass(playerId, class, global.sendBuffer);
}
team = TEAM_BLUE;
ServerPlayerChangeteam(playerId, TEAM_BLUE, global.sendBuffer);
}
//increase cap time
with (ArenaControlPoint)
capTime = 900;
}
}
//SEND DATA TO CLIENT//
if (global.vsh > 0)
{
write_ubyte(global.vshBuffer, ds_list_size(global.players));
//humiliated, is boss
var i,tempbyte;
for (i = 0; i < ds_list_size(global.players); i += 1) {
tempbyte = 0;
if (ds_list_find_value(global.players,i).humiliated)
tempbyte |= 1;
if (global.vshBoss = i)
tempbyte |= 2;
write_ubyte(global.vshBuffer, tempbyte);
}
//boss's hp, super jump and rage
var boss;
if (ds_list_find_value(global.players,global.vshBoss))
boss = (ds_list_find_value(global.players,global.vshBoss)).object;
else
boss = -1;
if (boss != -1) {
with (boss) {
write_uint(global.vshBuffer, hp);
tempbyte = 0;
if (variable_local_exists('vshSuperJump'))
if (vshSuperJump == 0)
tempbyte |= 1;
if (variable_local_exists('vshRage'))
if (vshRage >= 700)
tempbyte |= 2;
write_ubyte(global.vshBuffer, tempbyte);
}
}
PluginPacketSend(argument1, global.vshBuffer);
buffer_clear(global.vshBuffer);
}
");
//normal step to override serialize state
//might cause delay for 1 step when a player leave
object_event_add(Client, ev_step, ev_step_normal, "
//RECEIVE DATA FROM SERVER//
if (global.vsh > 0) {
if (PluginPacketGetBuffer(argument1) != -1) {
global.vshBuffer = PluginPacketGetBuffer(argument1);
if (read_ubyte(global.vshBuffer) != ds_list_size(global.players)) {
buffer_clear(global.vshBuffer);
PluginPacketPop(argument1);
exit;
}
var i,tempbyte;
//humiliation, isBoss
for (i = 0; i < ds_list_size(global.players); i += 1) {
tempbyte = read_ubyte(global.vshBuffer);
(ds_list_find_value(global.players,i)).humiliated = tempbyte & 1;
if ((tempbyte & 2) > 0)
global.vshBoss = i;
}
//boss's hp, super jump and rage
var boss;
if (ds_list_find_value(global.players,global.vshBoss))
boss = (ds_list_find_value(global.players,global.vshBoss)).object;
else
boss = -1;
if (boss != -1) {
with (boss) {
hp = read_uint(global.vshBuffer);
tempbyte = read_ubyte(global.vshBuffer);
if (variable_local_exists('vshSuperJump')) {
if ((tempbyte & 1) > 0)
vshSuperJump = 0;
else
vshSuperJump = 30;
}
if (variable_local_exists('vshRage')) {
if ((tempbyte & 2) > 0)
vshRage = 700;
else
vshRage = 0;
}
}
}
buffer_clear(global.vshBuffer);
PluginPacketPop(argument1);
}
}
");
//BOSS//
object_event_add(Character, ev_create, 0, "
if (global.vsh > 0) {
if (team = TEAM_BLUE) {
//hp based on number of players
var i,noOfRed;
noOfRed = 0;
for (i = 0; i < ds_list_size(global.players); i += 1) {
if (ds_list_find_value(global.players,i).team == TEAM_RED)
noOfRed += 1;
}
maxHp = 250+200*noOfRed+50*(noOfRed+1)*(noOfRed/2);
//heavy and quote have metal skin
if (player.class == CLASS_HEAVY or player.class == CLASS_QUOTE)
maxHp = floor(maxHp*1.2);
//engi is fragile
if (player.class == CLASS_ENGINEER)
maxHp = floor(maxHp*0.7);
hp = maxHp;
runPower = 0.9;
if (player.class != CLASS_SNIPER)
currentWeapon.visible = false;
} else {
//increase sniper max damage
if (player.class == CLASS_SNIPER)
with (currentWeapon)
maxDamage = 110;
//nerf quote
if (player.class == CLASS_QUOTE)
with (currentWeapon) {
bladeLife = 4;
maxBubbles = 0;
}
//heal 1hp/s if not hurt for 3s
alarm[11] = 30;
}
}
");
//boss's sentry is invulnerable except against spy
object_event_add(Sentry, ev_step, ev_step_begin, "
if (global.vsh > 0) {
if (ownerPlayer.team == TEAM_BLUE) {
hp = maxHp;
}
}
");
object_event_add(Character, ev_step, ev_step_begin, "
if (global.vsh > 0) {
if (team == TEAM_BLUE) {
//recharge
if (!variable_local_exists('vshCoolDown'))
vshCoolDown = 0;
if (vshCoolDown > 0)
vshCoolDown -= 1;
if (!variable_local_exists('vshSuperJump'))
vshSuperJump = 0;
if (vshSuperJump > 0)
vshSuperJump -= 1;
if (!variable_local_exists('vshAttack'))
vshAttack = 0;
if (vshAttack > 0)
vshAttack -= 1;
currentWeapon.readyToShoot = 0;
currentWeapon.ammoCount = 0;
//super jump
if (player.class != CLASS_SPY and player.class != CLASS_ENGINEER and player.class != CLASS_HEAVY and player.class != CLASS_SNIPER
and !taunting and !omnomnomnom and !player.humiliated and (keyState | pressedKeys) & $08 and vshSuperJump == 0 and place_meeting(x,y+1,Obstacle)) {
vshSuperJump = 450;
motion_add(aimDirection, 15);
moveStatus = 1;
playsound(x,y,CompressionBlastSnd);
}
//attack
if (!invisible and cloakAlpha == 1 and !taunting and !omnomnomnom and !player.humiliated and (keyState | pressedKeys) & $10 and vshCoolDown == 0) {
//sniper use bow
if (player.class == CLASS_SNIPER) {
var shot;
shot = instance_create(x,y,Shot);
shot.direction = aimDirection;
shot.speed = 20;
shot.owner = id;
shot.ownerPlayer = player;
shot.team = team;
shot.hitDamage = currentWeapon.hitDamage;
shot.weapon = WEAPON_RIFLE_CHARGED;
with(shot)
speed += owner.hspeed*hspeed/15;
vshCoolDown = 45;
playsound(x,y,RevolverSnd);
}
else {
vshCoolDown = 30;
vshAttack = 4;
playsound(x,y,BladeSnd);
}
}
//HAXTON SAAAALLLEEEE!!!
if (!variable_local_exists('vshRage'))
vshRage = 0;
if (taunting and vshRage >= 700) {
vshRage = 0;
playsound(x,y,UberStartSnd);
with (Character) {
if ((point_distance(x,y,other.x,other.y) < 400 or (ds_list_find_value(global.players,global.vshBoss)).class == CLASS_SOLDIER) and team = TEAM_RED) {
player.humiliated = 1;
player.alarm[11] = 5*30+other.tauntlength/other.tauntspeed;
if ((ds_list_find_value(global.players,global.vshBoss)).class == CLASS_SOLDIER)
player.alarm[11] = 8*30+other.tauntlength/other.tauntspeed;
}
}
}
}
}
");
//melee attack
object_event_add(Character, ev_collision, Character, "
if (variable_local_exists('vshAttack') and global.vsh > 0) {
if (vshAttack > 0 and other.team != team and player.class != CLASS_SNIPER and other.ubered == 0) {
playsound(x,y,choose(DeathSnd1, DeathSnd2));
vshAttack = 0;
other.hp -= 75;
other.timeUnscathed = 0;
if (other.lastDamageDealer != player && other.lastDamageDealer != other.player) {
other.secondToLastDamageDealer = other.lastDamageDealer;
other.alarm[4] = other.alarm[3];
}
other.alarm[3] = ASSIST_TIME;
other.lastDamageDealer = player;
other.lastDamageSource = 0;
var blood;
if(global.gibLevel > 0) {
blood = instance_create(x,y,Blood);
blood.direction = direction-180;
}
with(other) {
motion_add(other.direction, other.speed*0.03);
cloakAlpha = max(cloakAlpha, 0.3);
cloakFlicker = true;
alarm[7] = 3;
}
//spy weak attack
if (player.class == CLASS_SPY)
other.hp += 40;
//pyro burning attack
if (!object_is_ancestor(other.object_index, Pyro) and player.class == CLASS_PYRO) {
other.burnDuration += 210;
other.burnIntensity += 9;
other.burnDuration = min(other.burnDuration, other.maxDuration);
other.burnIntensity = min(other.burnIntensity, other.maxIntensity);
other.burnedBy = player;
other.afterburnSource = 0;
other.alarm[0] = other.decayDelay;
}
//knock back
with (other)
motion_add(other.aimDirection, 12);
//demoman leech health and gain rage if kill
if (player.class == CLASS_DEMOMAN) {
hp += maxHp/50;
if (!variable_local_exists('vshRage'))
vshRage = 0;
if (other.hp <= 0)
vshRage += 50;
}
}
}
");
//attack sentry
object_event_add(Character, ev_collision, Sentry, "
if (variable_local_exists('vshAttack') and global.vsh > 0) {
if (vshAttack > 0 and other.team != team and player.class != CLASS_SNIPER) {
playsound(x,y,KnifeSnd);
other.hp -= 75;
vshAttack = 0;
//spy weak attack
if (player.class == CLASS_SPY)
other.hp += 40;
other.lastDamageDealer = player;
other.lastDamageSource = 0;
}
}
");
//attack sprite place holder
object_event_add(Character, ev_draw, 0, "
if (variable_local_exists('vshAttack') and global.vsh > 0) {
if (vshAttack > 0 and player.class != CLASS_SNIPER) {
draw_sprite(BladeProjectileS,vshAttack-1,x,y);
}
}
");
object_event_add(Character, ev_step, ev_step_end, "
if (global.vsh > 0) {
if (!variable_local_exists('oldHp'))
oldHp = hp;
if (team == TEAM_BLUE) {
if (!variable_local_exists('vshRage'))
vshRage = 0;
//equalizer
runPower = 1.5-0.6*(hp/maxHp);
//scout's speed maxed
if (player.class == CLASS_SCOUT)
runPower = 1.5-0.35*(hp/maxHp);
//spy stabbing
if (stabbing)
runPower *= 0.7;
//sniper zoom
if (zoomed)
runPower *= 0.7;
//heavy eating
if (omnomnomnom)
hp = min(maxHp,hp+maxHp/1000-1.6);
//hurt = slow, build rage
if (hp < oldHp) {
vshRage = vshRage+oldHp-hp;
speed *= 0.9;
//heavy block damage
if (player.class == CLASS_HEAVY)
hp = min(oldHp,hp+2);
}
//it's humiliating to be stabbed
if (lastDamageSource == WEAPON_BACKSTAB or lastDamageSource == WEAPON_KNIFE) {
player.humiliated = true;
player.alarm[11] = 45;
if (lastDamageDealer.object != -1)
lastDamageDealer.object.hp = maxHp; //reward for spy
}
}
oldHp = hp;
//humiliation slow
if (player.humiliated)
hspeed *= 0.8;
}
");
object_event_add(Character, ev_alarm, 11, "
if (global.vsh > 0 and team == TEAM_RED and timeUnscathed >= 90)
hp += 1;
if (global.vsh > 0 and team == TEAM_BLUE and player.class == CLASS_MEDIC)
hp += maxHp/400;
alarm[11] = 30;
");
object_event_add(Player, ev_alarm, 11, "
humiliated = false;
");
And I know that I'm a messy coder / grammar mistake maker, point out the mistakes if you spot themI will need suggestions to keep this plugin enjoyable. If there is someone out there who can make good sprites and willing to help, I will need a Haxton Sale sprite and a punching arm animation (length: 4 images) (Haven't decided about other classes though)