/* * Copyright (c) 2016-2020 Marco Cawthorne * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ void HHDMultiplayerRules::PlayerDeath(NSClientPlayer pl) { /* obituary networking */ WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, EV_OBITUARY); if (g_dmg_eAttacker.netname) WriteString(MSG_MULTICAST, g_dmg_eAttacker.netname); else WriteString(MSG_MULTICAST, g_dmg_eAttacker.classname); WriteString(MSG_MULTICAST, pl.netname); WriteByte(MSG_MULTICAST, g_dmg_iWeapon); WriteByte(MSG_MULTICAST, 0); msg_entity = world; multicast([0,0,0], MULTICAST_ALL); /* death-counter */ pl.deaths++; forceinfokey(pl, "*deaths", ftos(pl.deaths)); /* update score-counter */ if (pl.flags & FL_CLIENT || pl.flags & FL_MONSTER) if (g_dmg_eAttacker.flags & FL_CLIENT) { if (pl == g_dmg_eAttacker) g_dmg_eAttacker.frags--; else g_dmg_eAttacker.frags++; } pl.movetype = MOVETYPE_NONE; pl.solid = SOLID_NOT; pl.takedamage = DAMAGE_NO; pl.gflags &= ~GF_FLASHLIGHT; pl.armor = pl.activeweapon = pl.g_items = 0; pl.think = PutClientInServer; pl.nextthink = time + 4.0f; Sound_Play(pl, CHAN_AUTO, "player.die"); if (pl.health < -50) { vector gibDir = vectoangles(pl.origin - g_dmg_eAttacker.origin); float gibStrength = g_dmg_iDamage * 2.0f; BreakModel_Entity(pl, gibDir, gibStrength); pl.health = 0; return; } pl.health = 0; FX_Corpse_Spawn(pl, ANIM_DIESIMPLE); } void HHDMultiplayerRules::PlayerPain(NSClientPlayer pl) { /* Vampire Rune * steals health from enemies */ if (g_dmg_eAttacker.flags & RUNE_VAMPIRE) g_dmg_eAttacker.health += g_dmg_iDamage; /* This probably doesn't go here? * damage checks for vampire rune */ if (g_dmg_eAttacker == (entity)pl) return; if (!(g_dmg_eAttacker.flags & FL_CLIENT)) return; } void HHDMultiplayerRules::PlayerSpawn(NSClientPlayer pp) { player pl = (player)pp; /* this is where the mods want to deviate */ entity spot; pl.classname = "player"; pl.health = pl.max_health = 100; pl.takedamage = DAMAGE_YES; pl.solid = SOLID_SLIDEBOX; pl.movetype = MOVETYPE_WALK; pl.flags = FL_CLIENT; pl.viewzoom = 1.0; pl.model = "models/player.mdl"; string mymodel = infokey(pl, "model"); if (mymodel) { mymodel = sprintf("models/player/%s/%s.mdl", mymodel, mymodel); if (whichpack(mymodel)) { pl.model = mymodel; } } setmodel(pl, pl.model); pl.SetSize(VEC_HULL_MIN, VEC_HULL_MAX); pl.ClearVelocity(); pl.gravity = __NULL__; pl.SetFrame(1); pl.SendFlags = UPDATE_ALL; pl.SetInfoKey("*spec", "0"); pl.SetInfoKey("*dead", "0"); pl.SetInfoKey("*deaths", ftos(pl.deaths)); pl.SetPropData("actor_human"); pl.SetCanBleed(true); spot = Spawn_SelectRandom("info_player_deathmatch"); setorigin(pl, spot.origin); pl.angles = spot.angles; pl.g_items = ITEM_BROOM | ITEM_SUIT; pl.activeweapon = WEAPON_BROOM; Weapons_RefreshAmmo(pl); for (int i = 1; i < g_weapons.length; i++) { Weapons_AddItem(pl, i, -1); } Client_FixAngle(pl, pl.angles); } void HHDMultiplayerRules::LevelDecodeParms(NSClientPlayer pp) { player pl = (player)pp; g_landmarkpos[0] = parm1; g_landmarkpos[1] = parm2; g_landmarkpos[2] = parm3; pl.angles[0] = parm4; pl.angles[1] = parm5; pl.angles[2] = parm6; pl.velocity[0] = parm7; pl.velocity[1] = parm8; pl.velocity[2] = parm9; pl.g_items = parm10; pl.activeweapon = parm11; pl.flags = parm18; pl.ammo_forks = parm12; pl.ammo_knives = parm13; pl.ammo_legogrenade = parm14; pl.ammo_legos = parm15; pl.ammo_soda = parm16; pl.ammo_spray = parm17; if (pl.flags & FL_CROUCHING) { setsize(pl, VEC_CHULL_MIN, VEC_CHULL_MAX); } else { setsize(pl, VEC_HULL_MIN, VEC_HULL_MAX); } } void HHDMultiplayerRules::LevelChangeParms(NSClientPlayer pp) { player pl = (player)pp; parm1 = g_landmarkpos[0]; parm2 = g_landmarkpos[1]; parm3 = g_landmarkpos[2]; parm4 = pl.angles[0]; parm5 = pl.angles[1]; parm6 = pl.angles[2]; parm7 = pl.velocity[0]; parm8 = pl.velocity[1]; parm9 = pl.velocity[2]; parm64 = pl.flags; parm10 = pl.g_items; parm11 = pl.activeweapon; parm12 = pl.ammo_forks; parm13 = pl.ammo_knives; parm14 = pl.ammo_legogrenade; parm15 = pl.ammo_legos; parm16 = pl.ammo_soda; parm17 = pl.ammo_spray; } void HHDMultiplayerRules::LevelNewParms(void) { parm1 = parm2 = parm3 = parm4 = parm5 = parm6 = parm7 = parm8 = parm9 = parm10 = parm11 = parm12 = parm13 = parm14 = parm15 = parm16 = parm17 = 0; parm18 = FL_CLIENT; } /* we check what fields have changed over the course of the frame and network * only the ones that have actually changed */ void HHDMultiplayerRules::PlayerPostFrame(NSClientPlayer pp) { player pl = (player)pp; pl.powerup_time = bound(0.0f, pl.powerup_time - frametime, pl.powerup_time); /* and remove when time runs out ;) */ if (pl.powerup_time <= 0.0f) { pl.g_items &= ~ITEM_RUNE_HASTE; } } void HHDMultiplayerRules::PlayerConnect(NSClientPlayer pl) { entity a; bprint(PRINT_HIGH, sprintf("%s connected\n", pl.netname)); int playercount = 0; for (a = world; (a = find(a, ::classname, "player"));) { playercount++; } } void HHDMultiplayerRules::PlayerDisconnect(NSClientPlayer pl) { bprint(PRINT_HIGH, sprintf("%s disconnected\n", pl.netname)); /* Make this unusable */ pl.solid = SOLID_NOT; pl.movetype = MOVETYPE_NONE; pl.modelindex = 0; pl.health = 0; pl.takedamage = 0; pl.SendFlags = PLAYER_MODELINDEX; } void HHDMultiplayerRules::PlayerKill(NSClientPlayer pp) { player pl = (player)pp; Damage_Apply(pl, pl, pl.health, WEAPON_NONE, DMG_SKIP_ARMOR); }