well, it's been a long time and I got some interest in GG2 back (especially at the plugin system)
so I decided to do something cool! like...
DEAD RINGER!
100% compatible with vanilla clients
Host only
still a WIP project and since I'm busy, these bugs might not be fixed soon
how to use:-put the file in the "Plugins" folder
-press P to send information to clients
-stand in the spawn (uncloak)
-press

then

to switch between weapons
-active: feign dead on hit, can't shoot, cloak for 9 second
-while cloaking: give some resistant to damage, can stab, can't heal
-after cloak: recharge 9 sec, there will be messages in order to keep track
issues:-Due to the lack of instant cloak, player will be teleport back to base and forth to war after fully cloaked
(I can do a FULL_UPDATE to everyone to fix it but it might be laggy (will it?), teleporting also help spy to evade for 0.66 second)
-Sometimes player can't activate dead ringer, sometimes they're not teleported back to old position can't reproduce
-Host won't see the gib/dead body effects, i can fix it, it just taking too much space
-Oh and the score system completely messed up, but I don't think it matter anyway
this is a
WIP and I'm not a good programmer, if you can improve this in anyway or find any bugs, post here please!
Source:copy-paste into a text file, save as, set file type: all files and name: "wateveryouwantthistobe.gml"
V1.2
//ALTERNATIVE WEAPON PLUGIN
global.awpBuffer = buffer_create();
global.temp2Buffer = buffer_create();
//DEAD RINGER//
object_event_add(PlayerControl,ev_step,ev_step_normal,"
if keyboard_check_pressed(ord('P'))
{
var message;
message = 'sit in spawn as spy uncloaked with full hp, press c,8,c,9 to switch cloak type'
ServerMessageString(message,global.eventBuffer);
var notice;
with NoticeO instance_destroy();
notice = instance_create(0, 0, NoticeO);
notice.notice = NOTICE_CUSTOM;
notice.message = message;
}
");
//declare variables
object_event_add(Character,ev_other,ev_user0,"
awp = player.awp;//get load out
selecting = 0;
msg = '';//personal message
oldHp = 0;
cloakTimer = 0;
oldX = 0;
oldY = 0;
wait = 0;
//0: nothing -1: actived > 0: count down till reveal < -1: recharging
");
object_event_add(Player,ev_create,0,"
awp = 0;// is using plugin?
");
//switch to alternative weapon
object_event_add(Character,ev_step,ev_step_normal,"
if bubble.image_index == 43
selecting = 1;
else if bubble.image_index == 44
{
if selecting == 1 and !cloak
and (place_meeting(x,y,HealingCabinet) or place_meeting(x,y,SpawnRoom))
and player.class == CLASS_SPY
{
awp = 1-awp;
if awp == 1
msg = 'Dead Ringer selected!';
if awp == 0
msg = 'Cloak and Dagger selected!';
event_user(2);
selecting = 0;
player.awp = awp;
}
selecting = 0;
}
else
selecting = 0;
");
//self-message(conflict with other plugin that use event user 2)
object_event_add(Character,ev_other,ev_user2,"
if global.isHost
{
//send to self
if player == global.myself
{
var notice;
with NoticeO instance_destroy();
notice = instance_create(0, 0, NoticeO);
notice.notice = NOTICE_CUSTOM;
notice.message = msg;
}
//send to client
write_ubyte(global.temp2Buffer, MESSAGE_STRING);
write_ubyte(global.temp2Buffer, string_length(msg));
write_string(global.temp2Buffer, msg);
write_buffer(player.socket, global.temp2Buffer);
buffer_clear(global.temp2Buffer);
}
");
//CLOAK MECHANISM
object_event_add(Character,ev_step,ev_step_end,"
//set hp to normal, if hp < 1000 mean have just spawn/change weapon
if maxHp > 1000
{
maxHp -= 1000;
hp -= 1000;
}
//turn on/off cloak
if cloak and (cloakTimer <= 0) and awp == 1
{
cloak = false;
if (cloakTimer == 0 or cloakTimer == -1)
{
cloakTimer = -(cloakTimer+1);
//disable/enable weapon
if cloakTimer == -1
{
currentWeapon.readyToShoot = false;
currentWeapon.alarm[0] = 0;
}
if cloakTimer == 0
currentWeapon.alarm[0] = 10;
//announce
if global.isHost
{
if cloakTimer == -1
msg = 'Dead Ringer activated!';
if cloakTimer == 0
msg = 'Dead Ringer deactivated!';
event_user(2);
}
}
}
//fully cloaked, return!
if wait > 0
{
wait -= 1;
if wait == 0
{
x = oldX;
y = oldY;
}
}
//if hit: trigger effect
if (oldHp > hp) and (cloakTimer == -1) and (!cloak) and awp == 1
{
//instant cloak
cloak = true;
cloakTimer = 9*30+20;
//put off fire
if (burnIntensity > 0 or burnDuration > 0)
{
burnIntensity = 0;
burnDuration = 0;
burnedBy = -1;
afterburnSource = -1;
}
//wait cloak 100% then come back
oldX = x;
oldY = y;
if (9*oldHp+hp)/10 > 0
{
x = xstart;
y = ystart;
}
wait = 20;
currentWeapon.readyToShoot = true;
currentWeapon.readyToStab = false;
currentWeapon.alarm[2] = 20;
//FEIGN DEATH
if global.isHost
{
var i,playerId;
//write the fake death message
write_ubyte(global.awpBuffer, PLAYER_DEATH);
write_ubyte(global.awpBuffer, ds_list_find_index(global.players, player));
if secondToLastDamageDealer and instance_exists(secondToLastDamageDealer)
i = secondToLastDamageDealer;
else
i = -1;
if instance_exists(lastDamageDealer) and lastDamageDealer
{
write_ubyte(global.awpBuffer, ds_list_find_index(global.players, lastDamageDealer));
if lastDamageDealer.object
if lastDamageDealer.object.healer
i = lastDamageDealer.object.healer;
}
else
write_ubyte(global.awpBuffer, 255);
if i and instance_exists(i)
write_ubyte(global.awpBuffer, ds_list_find_index(global.players, i));
else
write_ubyte(global.awpBuffer, 255);
write_ubyte(global.awpBuffer, lastDamageSource);
//write the fake respawn message
write_ubyte(global.awpBuffer, PLAYER_SPAWN);
write_ubyte(global.awpBuffer, ds_list_find_index(global.players, player));
write_ubyte(global.awpBuffer, 0);
write_ubyte(global.awpBuffer, selectSpawnGroup(team));
//send fake message to every one except user
for(i=1; i<ds_list_size(global.players); i+=1)
{
playerId = ds_list_find_value(global.players, i);
if playerId != player
write_buffer(playerId.socket, global.awpBuffer);
}
buffer_clear(global.awpBuffer);
}
}
//set oldHp, if feigning death: 90% resistant and can't heal
if cloak and awp == 1
{
if oldHp > hp and !stabbing
hp = (9*oldHp+hp)/10;
if oldHp < hp
hp = oldHp;
}
//decloak and recharge when time run out or manual decloak
if cloakTimer > 0 and awp == 1
{
cloakTimer -= 1;
if cloakTimer == 0 or !cloak
{
msg = 'Dead Ringer stopped!';
event_user(2);
//might +cloakTimer/2 for early decloak
cloakTimer = -9*30-1;
cloak = false;
}
}
//recharge: turn off when done
if cloakTimer < -1 and awp == 1
{
cloakTimer += 1;
if place_meeting(x,y,HealingCabinet)
cloakTimer = -1;
if cloakTimer == -1
{
msg = 'Dead Ringer ready!';
event_user(2);
cloakTimer = 0;
}
}
//carry intel? deactivate!
if intel and cloakTimer == -1 and awp == 1
{
cloakTimer = 0;
currentWeapon.alarm[0] = 10;
msg = 'Dead Ringer deactivated!';
event_user(2);
}
//other calculation
oldHp = hp;
");
//fix the not-reduce-instant-kill-damage
//loop( beginstep +1000 col -hp endstep check hp endendstep dead ringer -1000+reducion draw )
object_event_add(Character,ev_step,ev_step_begin,"
//maxHp have not changed, if not dead raise hp+maxHp
if maxHp < 1000 and hp > 0
{
maxHp += 1000;
hp += 1000;
}
");