From 35bbae956b4d4e5d9580e459bf3756b1c5cd3133 Mon Sep 17 00:00:00 2001 From: Marco Cawthorne Date: Tue, 3 Sep 2024 12:21:03 -0700 Subject: [PATCH] Code fixups against latest Nuclide. Move gamerules into their own module. --- engine.h | 24 +-- src/Makefile | 4 +- src/client/cmds.qc | 2 +- src/client/hud.qc | 51 ++--- src/client/obituary.h | 5 +- src/client/obituary.qc | 118 ++--------- src/client/progs.src | 2 +- src/server/gamerules.h | 4 +- src/server/gamerules.qc | 23 -- src/server/gamerules_multiplayer.qc | 100 +++------ src/server/gamerules_singleplayer.qc | 6 +- src/server/progs.src | 2 +- src/server/server.qc | 10 +- src/shared/fx_corpse.qc | 3 +- src/shared/include.src | 2 +- src/shared/player.qc | 47 +++++ src/shared/w_tripmine.qc | 6 +- zpak001.pk3dir/cvar_defaults.cfg | 2 +- zpak001.pk3dir/decls/def/ammo/rpgclip.def | 2 +- zpak001.pk3dir/decls/def/player.def | 17 +- zpak001.pk3dir/decls/def/weapons/357.def | 1 + .../decls/def/weapons/handgrenade.def | 47 ++--- zpak001.pk3dir/eukara.cfg | 2 +- zpak001.pk3dir/maps/mp/gametypes/dm.qc | 198 ++++++++++++++++++ zpak001.pk3dir/maps/singleplayer.qc | 86 ++++++++ 25 files changed, 475 insertions(+), 289 deletions(-) create mode 100644 zpak001.pk3dir/maps/mp/gametypes/dm.qc create mode 100644 zpak001.pk3dir/maps/singleplayer.qc diff --git a/engine.h b/engine.h index bba6c10..cd9fa6c 100644 --- a/engine.h +++ b/engine.h @@ -29,7 +29,7 @@ /* disable quake specific hacks and overrides */ #define QUAKETC -#define NOBUILTINMENUS +//#define NOBUILTINMENUS #define NOLEGACY /* engine behaviour */ @@ -43,8 +43,11 @@ #define USEAREAGRID /* leave it on, improves performance */ #define AVAIL_DINPUT /* input for Windows */ #define AVAIL_FREETYPE /* for truetype font rendering */ -#define AVAIL_STBI /* avoid libpng/libjpeg dependancies */ +//#define AVAIL_STBI /* avoid libpng/libjpeg dependancies */ #define ENGINE_ROUTING /* engine-side, fast routing */ +#define HAVE_MEDIA_DECODER /* can play cin/roq, more with plugins */ +#define HAVE_MEDIA_ENCODER /* capture/capturedemo work */ +#define PACKAGEMANAGER /* enable/disable/download packages and plugins */ #ifndef LEGACY_GPU #define RTLIGHTS @@ -59,7 +62,7 @@ /* uncompressed textures */ #define IMAGEFMT_BMP /* sprays */ #define IMAGEFMT_TGA -#define IMAGEFMT_JPG +#define IMAGEFMT_JPG /* compressed textures */ #define IMAGEFMT_KTX @@ -95,14 +98,14 @@ #define TERRAIN /* audio */ -#undef AVAIL_DSOUND +#undef AVAIL_DSOUND #define AVAIL_OPENAL #define AVAIL_OGGVORBIS #define HAVE_OPUS #define VOICECHAT - -/* todo: make OpenAL only */ -#define HAVE_MIXER + +/* todo: make OpenAL only */ +#define HAVE_MIXER /* Model formats, IQM/VVM and HLMDL for legacy maps */ #define INTERQUAKEMODELS @@ -141,8 +144,8 @@ #undef HAVE_SPEEX /* .xz decompression */ #undef AVAIL_GZDEC /* .gz decompression */ #undef PACKAGE_DZIP /* .dzip special-case archive support */ -#undef AVAIL_PNGLIB /* .png image format support (read+screenshots) */ -#undef AVAIL_JPEGLIB /* .jpeg image format support (read+screenshots) */ +#define AVAIL_PNGLIB /* .png image format support (read+screenshots) */ +#define AVAIL_JPEGLIB /* .jpeg image format support (read+screenshots) */ #undef AVAIL_MP3_ACM /* .mp3 support (in windows). */ #undef IMAGEFMT_DDS #undef IMAGEFMT_PKM @@ -179,11 +182,8 @@ #undef HLSERVER /* regressed, unfinished */ #undef FTPSERVER #undef HAVE_JUKEBO /* includes built-in jukebox */ -#define HAVE_MEDIA_DECODER /* can play cin/roq, more with plugins */ -#undef HAVE_MEDIA_ENCODER /* capture/capturedemo work */ #undef HAVE_SPEECHTOTEXT /* Windows speech-to-text thing */ #undef SAVEDGAMES -#undef PACKAGEMANAGER /* enable/disable/download packages and plugins */ #undef HEADLESSQUAKE #undef WAYLANDQUAKE #undef SERVER_DEMO_PLAYBACK /* deprecated */ diff --git a/src/Makefile b/src/Makefile index 3580572..898169c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -3,4 +3,6 @@ QCC=fteqcc all: cd client && $(MAKE) cd server && $(MAKE) - cd menu && $(MAKE) \ No newline at end of file + cd menu && $(MAKE) + cd ../zpak001.pk3dir/maps/mp/gametypes/ && $(QCC) dm.qc + cd ../zpak001.pk3dir/maps/ && $(QCC) singleplayer.qc \ No newline at end of file diff --git a/src/client/cmds.qc b/src/client/cmds.qc index 949b621..e7807d8 100644 --- a/src/client/cmds.qc +++ b/src/client/cmds.qc @@ -24,7 +24,7 @@ ClientGame_ConsoleCommand(void) { switch(argv(0)) { case "chooseteam": - sendevent("HLDM_Chooseteam", "s", argv(1)); + localcmd(sprintf("cmd %s %s\n", argv(0), argv(1))); break; case "invnext": pSeatLocal->weaponSelectionHUD.SelectNext(false); diff --git a/src/client/hud.qc b/src/client/hud.qc index ea11be5..6835167 100644 --- a/src/client/hud.qc +++ b/src/client/hud.qc @@ -144,12 +144,6 @@ HUD_DrawHealth(void) pSeatLocal->m_flHealthAlpha = 1.0; } - if (pSeatLocal->m_flHealthAlpha >= HUD_ALPHA) { - pSeatLocal->m_flHealthAlpha -= clframetime * 0.5; - } else { - pSeatLocal->m_flHealthAlpha = HUD_ALPHA; - } - pos = g_hudmins + [88, g_hudres[1] - 42]; if (pl.health > 25) { drawsubpic( @@ -178,6 +172,12 @@ HUD_DrawHealth(void) } pSeatLocal->m_iHealthOld = pl.health; + + if (pSeatLocal->m_flHealthAlpha >= HUD_ALPHA) { + pSeatLocal->m_flHealthAlpha = bound(HUD_ALPHA, pSeatLocal->m_flHealthAlpha - (clframetime * 0.5), 1.0); + } else { + pSeatLocal->m_flHealthAlpha = HUD_ALPHA; + } } /* armor/suit charge */ @@ -193,12 +193,6 @@ HUD_DrawArmor(void) pSeatLocal->m_flArmorAlpha = 1.0; } - if (pSeatLocal->m_flArmorAlpha >= HUD_ALPHA) { - pSeatLocal->m_flArmorAlpha -= clframetime * 0.5; - } else { - pSeatLocal->m_flArmorAlpha = HUD_ALPHA; - } - drawsubpic( pos + [-80,-9], [40,40], @@ -226,6 +220,12 @@ HUD_DrawArmor(void) HUD_DrawNums(pl.armor, pos, pSeatLocal->m_flArmorAlpha, g_hud_color); pSeatLocal->m_iArmorOld = pl.armor; + + if (pSeatLocal->m_flArmorAlpha >= HUD_ALPHA) { + pSeatLocal->m_flArmorAlpha = bound(HUD_ALPHA, pSeatLocal->m_flArmorAlpha - (clframetime * 0.5), 1.0); + } else { + pSeatLocal->m_flArmorAlpha = HUD_ALPHA; + } } /* magazine/clip ammo */ @@ -240,15 +240,15 @@ HUD_DrawAmmo1(void) pSeatLocal->m_iAmmo1Old = pl.a_ammo1; } - if (pSeatLocal->m_flAmmo1Alpha >= HUD_ALPHA) { - pSeatLocal->m_flAmmo1Alpha -= clframetime * 0.5; - } else { - pSeatLocal->m_flAmmo1Alpha = HUD_ALPHA; - } - pos = g_hudmins + [g_hudres[0] - 152, g_hudres[1] - 42]; HUD_DrawNums(pl.a_ammo1, pos, pSeatLocal->m_flAmmo1Alpha, g_hud_color); HUD_DrawSeperator(pos + [30,0]); + + if (pSeatLocal->m_flAmmo1Alpha >= HUD_ALPHA) { + pSeatLocal->m_flAmmo1Alpha = bound(HUD_ALPHA, pSeatLocal->m_flAmmo1Alpha - (clframetime * 0.5), 1.0); + } else { + pSeatLocal->m_flAmmo1Alpha = HUD_ALPHA; + } } /* leftover type ammo */ @@ -263,14 +263,14 @@ HUD_DrawAmmo2(void) pSeatLocal->m_iAmmo2Old = pl.a_ammo2; } + pos = g_hudmins + [g_hudres[0] - 72, g_hudres[1] - 42]; + HUD_DrawNums(pl.a_ammo2, pos, pSeatLocal->m_flAmmo2Alpha, g_hud_color); + if (pSeatLocal->m_flAmmo2Alpha >= HUD_ALPHA) { - pSeatLocal->m_flAmmo2Alpha -= clframetime * 0.5; + pSeatLocal->m_flAmmo2Alpha = bound(HUD_ALPHA, pSeatLocal->m_flAmmo2Alpha - (clframetime * 0.5), 1.0); } else { pSeatLocal->m_flAmmo2Alpha = HUD_ALPHA; } - - pos = g_hudmins + [g_hudres[0] - 72, g_hudres[1] - 42]; - HUD_DrawNums(pl.a_ammo2, pos, pSeatLocal->m_flAmmo2Alpha, g_hud_color); } /* special ammo */ @@ -285,14 +285,15 @@ HUD_DrawAmmo3(void) pSeatLocal->m_iAmmo3Old = pl.a_ammo3; } + pos = g_hudmins + [g_hudres[0] - 72, g_hudres[1] - 74]; + HUD_DrawNums(pl.a_ammo3, pos, pSeatLocal->m_flAmmo3Alpha, g_hud_color); + if (pSeatLocal->m_flAmmo3Alpha >= HUD_ALPHA) { - pSeatLocal->m_flAmmo3Alpha -= clframetime * 0.5; + pSeatLocal->m_flAmmo3Alpha = bound(HUD_ALPHA, pSeatLocal->m_flAmmo3Alpha - (clframetime * 0.5), 1.0); } else { pSeatLocal->m_flAmmo3Alpha = HUD_ALPHA; } - pos = g_hudmins + [g_hudres[0] - 72, g_hudres[1] - 74]; - HUD_DrawNums(pl.a_ammo3, pos, pSeatLocal->m_flAmmo3Alpha, g_hud_color); } /* ammo bar */ diff --git a/src/client/obituary.h b/src/client/obituary.h index d3ce476..915c330 100644 --- a/src/client/obituary.h +++ b/src/client/obituary.h @@ -27,15 +27,12 @@ typedef struct { string src_sprite; /* precaching reasons */ } obituaryimg_t; -obituaryimg_t *g_obtypes; -int g_obtype_count; - /* actual obituary storage */ typedef struct { string attacker; string victim; - int icon; + string icon; } obituary_t; obituary_t g_obituary[OBITUARY_LINES]; diff --git a/src/client/obituary.qc b/src/client/obituary.qc index cbdd278..8b07daf 100644 --- a/src/client/obituary.qc +++ b/src/client/obituary.qc @@ -17,114 +17,38 @@ void Obituary_Init(void) { -#if 0 - int c; - int i; - filestream fh; - string line; - vector tmp; - - if (g_obtype_count > 0) { - return; - } - - g_obtype_count = 0; - i = 0; - - fh = fopen("sprites/hud.txt", FILE_READ); - if (fh < 0) { - return; - } - - /* count valid entries */ - while ((line = fgets(fh))) { - if (substring(line, 0, 2) == "d_") { - c = tokenize(line); - if (c == 7 && argv(1) == "640") { - g_obtype_count++; - } - } - } - - g_obtypes = memalloc(sizeof(obituaryimg_t) * g_obtype_count); - - fseek(fh, 0); - - /* read them in */ - while ((line = fgets(fh))) { - if (substring(line, 0, 2) == "d_") { - c = tokenize(line); - - /* we only care about the high-res (640) variants. the 320 - * HUD is useless to us. Just use the builtin scaler */ - if (c == 7 && argv(1) == "640") { - g_obtypes[i].name = substring(argv(0), 2, -1); - g_obtypes[i].src_sprite = sprintf("sprites/%s.spr", argv(2)); - precache_model(g_obtypes[i].src_sprite); - g_obtypes[i].sprite = spriteframe(sprintf("sprites/%s.spr", argv(2)), 0, 0.0f); - g_obtypes[i].size[0] = stof(argv(5)); - g_obtypes[i].size[1] = stof(argv(6)); - tmp = drawgetimagesize(g_obtypes[i].sprite); - g_obtypes[i].src_pos[0] = stof(argv(3)) / tmp[0]; - g_obtypes[i].src_pos[1] = stof(argv(4)) / tmp[1]; - g_obtypes[i].src_size[0] = g_obtypes[i].size[0] / tmp[0]; - g_obtypes[i].src_size[1] = g_obtypes[i].size[1] / tmp[1]; - i++; - } - } - } - - fclose(fh); -#endif } void Obituary_Precache(void) { - for (int i = 0; i < g_obtype_count; i++) - precache_model(g_obtypes[i].src_sprite); } -void -Obituary_KillIcon(int id, float w) -{ -#if 0 - if (w > 0) - for (int i = 0; i < g_obtype_count; i++) { - if (g_weapons[w].name == g_obtypes[i].name) { - g_obituary[id].icon = i; - return; - } - } - - /* look for skull instead */ - for (int i = 0; i < g_obtype_count; i++) { - if (g_obtypes[i].name == "skull") { - g_obituary[id].icon = i; - return; - } - } -#endif -} void -Obituary_Add(string attacker, string victim, float weapon, float flags) +Obituary_Add(string attacker, string victim, string weapon, float flags) { -#if 0 int i; int x, y; x = OBITUARY_LINES; + string weaponIcon = ""; if (attacker == "worldspawn" || attacker == victim) { attacker = ""; } + weaponIcon = EntityDef_GetKeyValue(weapon, "killIcon"); + + if (weaponIcon == "") { + weaponIcon = "d_skull"; + } + /* we're not full yet, so fill up the buffer */ if (g_obituary_count < x) { y = g_obituary_count; g_obituary[y].attacker = attacker; g_obituary[y].victim = victim; - Obituary_KillIcon(y, weapon); + g_obituary[y].icon = weaponIcon; g_obituary_count++; } else { for (i = 0; i < (x-1); i++) { @@ -135,11 +59,12 @@ Obituary_Add(string attacker, string victim, float weapon, float flags) /* after rearranging, add the newest to the bottom. */ g_obituary[x-1].attacker = attacker; g_obituary[x-1].victim = victim; - Obituary_KillIcon(x-1, weapon); + g_obituary[x-1].icon = weaponIcon; } g_obituary_time = OBITUARY_TIME; +#if 0 if (g_weapons[weapon].deathmsg) { string conprint = g_weapons[weapon].deathmsg(); @@ -191,18 +116,13 @@ Obituary_Draw(void) v = g_obituary[i].victim; drawstring_r(item + [0,2], v, [12,12], [1,1,1], 1.0f, 0); item[0] -= stringwidth(v, TRUE, [12,12]) + 4; - item[0] -= g_obtypes[g_obituary[i].icon].size[0]; - drawsubpic( - item, - [g_obtypes[g_obituary[i].icon].size[0], g_obtypes[g_obituary[i].icon].size[1]], - g_obtypes[g_obituary[i].icon].sprite, - [g_obtypes[g_obituary[i].icon].src_pos[0],g_obtypes[g_obituary[i].icon].src_pos[1]], - [g_obtypes[g_obituary[i].icon].src_size[0],g_obtypes[g_obituary[i].icon].src_size[1]], - g_hud_color, - 1.0f, - DRAWFLAG_ADDITIVE - ); + + //item[0] -= g_obtypes[g_obituary[i].icon].size[0]; + + HLSprite_Draw_RGBA(g_obituary[i].icon, item, g_hud_color, 1.0f, true); + + // draw g_obituary[i].icon a = g_obituary[i].attacker; drawstring_r(item + [-4,2], a, [12,12], [1,1,1], 1.0f, 0); @@ -217,12 +137,12 @@ Obituary_Parse(void) { string attacker; string victim; - float weapon; + string weapon; float flags; attacker = readstring(); victim = readstring(); - weapon = readbyte(); + weapon = readstring(); flags = readbyte(); if (!attacker) { diff --git a/src/client/progs.src b/src/client/progs.src index eb090b2..0360c16 100644 --- a/src/client/progs.src +++ b/src/client/progs.src @@ -1,5 +1,5 @@ #pragma target fte_5768 -#pragma progs_dat "../../zpak001.pk3dir/csprogs.dat" +#pragma progs_dat "../../csprogs.dat" #define CSQC #define CLIENT diff --git a/src/server/gamerules.h b/src/server/gamerules.h index 95ae9b4..d599a6b 100644 --- a/src/server/gamerules.h +++ b/src/server/gamerules.h @@ -33,7 +33,7 @@ class HLSingleplayerRules:HLGameRules { /* client */ virtual void(NSClientPlayer) PlayerSpawn; - virtual void(NSClientPlayer) PlayerDeath; + virtual void(NSClientPlayer, NSActor, NSDict) PlayerDeath; virtual bool(void) IsMultiplayer; virtual bool ImpulseCommand(NSClient, float); }; @@ -52,7 +52,7 @@ class HLMultiplayerRules:HLGameRules /* client */ virtual void(NSClientPlayer) PlayerSpawn; - virtual void(NSClientPlayer) PlayerDeath; + virtual void(NSClientPlayer, NSActor, NSDict) PlayerDeath; virtual bool(NSClientPlayer, string) ConsoleCommand; virtual bool(void) IsMultiplayer; virtual bool(void) IsTeamplay; diff --git a/src/server/gamerules.qc b/src/server/gamerules.qc index a8b8cb7..227d706 100644 --- a/src/server/gamerules.qc +++ b/src/server/gamerules.qc @@ -34,29 +34,6 @@ HLGameRules::LevelDecodeParms(NSClientPlayer pl) pl.g_items = parm10; pl.activeweapon = parm11; pl.flags = parm64; - -#if 0 - pl.ammo_9mm = parm12; - pl.ammo_357 = parm13; - pl.ammo_buckshot = parm14; - pl.ammo_m203_grenade = parm15; - pl.ammo_bolt = parm16; - pl.ammo_rocket = parm17; - pl.ammo_uranium = parm18; - pl.ammo_handgrenade = parm19; - pl.ammo_satchel = parm20; - pl.ammo_tripmine = parm21; - pl.ammo_snark = parm22; - pl.ammo_hornet = parm23; - - pl.glock_mag = parm24; - pl.mp5_mag = parm25; - pl.python_mag = parm26; - pl.shotgun_mag = parm27; - pl.crossbow_mag = parm28; - pl.rpg_mag = parm29; - pl.satchel_chg = parm30; -#endif } void diff --git a/src/server/gamerules_multiplayer.qc b/src/server/gamerules_multiplayer.qc index 7c56d8f..da76c95 100644 --- a/src/server/gamerules_multiplayer.qc +++ b/src/server/gamerules_multiplayer.qc @@ -93,31 +93,37 @@ HLMultiplayerRules::CheckRules(void) } void -HLMultiplayerRules::PlayerDeath(NSClientPlayer pl) +HLMultiplayerRules::PlayerDeath(NSClientPlayer pl, NSActor attacker, NSDict damageDecl) { + vector damageLocation = damageDecl.GetVector("location"); + int hitBody = (int)damageDecl.GetFloat("hitbody"); + int damagePoints = (int)damageDecl.GetFloat("damage"); + /* obituary networking */ WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, EV_OBITUARY); - WriteString(MSG_MULTICAST, (g_dmg_eAttacker.netname) ? g_dmg_eAttacker.netname : g_dmg_eAttacker.classname); + WriteString(MSG_MULTICAST, (attacker.netname) ? attacker.netname : attacker.classname); WriteString(MSG_MULTICAST, pl.netname); - WriteByte(MSG_MULTICAST, g_dmg_iWeapon); + WriteString(MSG_MULTICAST, damageDecl.GetString("weapon")); WriteByte(MSG_MULTICAST, 0); msg_entity = world; multicast([0,0,0], MULTICAST_ALL); - Plugin_PlayerObituary(g_dmg_eAttacker, g_dmg_eTarget, g_dmg_iWeapon, g_dmg_iHitBody, g_dmg_iDamage); + //Plugin_PlayerObituary(g_dmg_eAttacker, g_dmg_eTarget, g_dmg_iWeapon, g_dmg_iHitBody, g_dmg_iDamage); /* death-counter */ pl.deaths++; pl.SetInfoKey("*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++; + if (isPlayer(pl) || isAI(pl)) { + if (isPlayer(attacker)) { + if (pl == attacker) { + attacker.frags--; + } else { + attacker.frags++; + } + } } #ifdef VALVE @@ -129,14 +135,13 @@ HLMultiplayerRules::PlayerDeath(NSClientPlayer pl) /* either gib, or make a corpse */ if (pl.health < -50) { - vector gibDir = vectoangles(pl.origin - g_dmg_eAttacker.origin); - float gibStrength = g_dmg_iDamage * 2.0f; + vector gibDir = vectoangles(pl.origin - attacker.origin); + float gibStrength = damagePoints * 2.0f; BreakModel_Entity(pl, gibDir, gibStrength); } else { -#if 0 float deathAnimation = ANIM_DIESIMPLE; - switch (g_dmg_iHitBody) { + switch (hitBody) { case BODY_HEAD: deathAnimation = ANIM_DIEHEADSHOT; break; @@ -147,7 +152,7 @@ HLMultiplayerRules::PlayerDeath(NSClientPlayer pl) deathAnimation = ANIM_DIEGUTSHOT; break; default: - bool isFacing = pl.IsFacingPosition(g_dmg_vecLocation); + bool isFacing = pl.IsFacingPosition(damageLocation); /* we still want a change to play ANIM_DIESIMPLE */ if (random() < 0.5) @@ -166,11 +171,10 @@ HLMultiplayerRules::PlayerDeath(NSClientPlayer pl) if (pl.IsCrouching()) { newCorpse.SetSize(VEC_HULL_MIN, [16, 16, -16]); } -#endif } /* now let's make the real client invisible */ - pl.SetTakedamage(DAMAGE_NO); + pl.MakeInvulnerable(); pl.gflags &= ~GF_FLASHLIGHT; pl.gflags &= ~GF_EGONBEAM; @@ -192,14 +196,8 @@ HLMultiplayerRules::PlayerSpawn(NSClientPlayer pl) /* this is where the mods want to deviate */ entity spot; - pl.classname = "player"; - pl.SetMaxHealth(100); - pl.SetHealth(100); - pl.SetTakedamage(DAMAGE_YES); - pl.SetSolid(SOLID_SLIDEBOX); - pl.SetMovetype(MOVETYPE_WALK); - pl.AddFlags(FL_CLIENT); - pl.viewzoom = 1.0; + EntityDef_SwitchClass(pl, "player_mp"); + pl.MakePlayer(); /* player model selection */ if (IsTeamplay() == true) { @@ -229,28 +227,7 @@ HLMultiplayerRules::PlayerSpawn(NSClientPlayer pl) playerModel = "models/player.mdl"; } - pl.SetModel(playerModel); - 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.EnableBleeding(); - - LevelNewParms(); - LevelDecodeParms(pl); - -#if defined (VALVE) || defined (GEARBOX) - pl.GiveItem("item_suit"); - pl.GiveItem("weapon_9mmhandgun"); - pl.GiveItem("weapon_crowbar"); - //pl.ammo_9mm = 44; -#endif - + pl.SetModelindex(getmodelindex(playerModel)); /* keep OG size */ spot = Spawn_SelectRandom("info_player_deathmatch"); pl.Transport(spot.origin, spot.angles); Client_FixAngle(pl, pl.angles); @@ -287,32 +264,3 @@ HLMultiplayerRules::HLMultiplayerRules(void) autocvar(timelimit, 15, "Timelimit for multiplayer rounds"); autocvar(fraglimit, 15, "Points limit for multiplayer rounds"); } - -void -CSEv_HLDM_Chooseteam_s(string teamName) -{ - HLGameRules rules = (HLGameRules)g_grMode; - NSClientPlayer pl = (NSClientPlayer)self; - - if (!teamName) - return; - if (rules.IsMultiplayer() == false) - return; - if (rules.IsTeamplay() == false) - return; - if (pl.IsDead() == true) - return; - - HLMultiplayerRules mprules = (HLMultiplayerRules)rules; - int c = tokenizebyseparator(mprules.m_strTeamList, ";"); - - for (int i = 0; i < c; i++) { - if (argv(i) == teamName) { - pl.SetTeam((float)i + 1); - pl.SetHealth(-100); - pl.Death(pl, pl, 100i, g_vec_null, 0i); - //Damage_Apply(pl, pl, 100, 0, DMG_SKIP_ARMOR); - return; - } - } -} diff --git a/src/server/gamerules_singleplayer.qc b/src/server/gamerules_singleplayer.qc index 9068c67..ff9d1e6 100644 --- a/src/server/gamerules_singleplayer.qc +++ b/src/server/gamerules_singleplayer.qc @@ -21,11 +21,11 @@ HLSingleplayerRules::IsMultiplayer(void) } void -HLSingleplayerRules::PlayerDeath(NSClientPlayer pl) +HLSingleplayerRules::PlayerDeath(NSClientPlayer pl, NSActor attacker, NSDict damageDecl) { pl.SetMovetype(MOVETYPE_NONE); pl.SetSolid(SOLID_NOT); - pl.SetTakedamage(DAMAGE_NO); + pl.MakeInvulnerable(); pl.SetHealth(0); pl.StartSoundDef("Player.Death", CHAN_AUTO, true); @@ -63,7 +63,7 @@ HLSingleplayerRules::PlayerSpawn(NSClientPlayer pl) pl.classname = "player"; pl.SetHealth(100); pl.SetMaxHealth(100); - pl.SetTakedamage(DAMAGE_YES); + pl.MakeVulnerable(); pl.SetSolid(SOLID_SLIDEBOX); pl.SetMovetype(MOVETYPE_WALK); pl.AddFlags(FL_CLIENT); diff --git a/src/server/progs.src b/src/server/progs.src index 6c86331..f531a0f 100644 --- a/src/server/progs.src +++ b/src/server/progs.src @@ -1,6 +1,6 @@ #pragma target fte_5768 //#pragma flag enable assumeint -#pragma progs_dat "../../zpak001.pk3dir/progs.dat" +#pragma progs_dat "../../progs.dat" #define QWSSQC #define SERVER diff --git a/src/server/server.qc b/src/server/server.qc index 5f25a57..b517d5d 100644 --- a/src/server/server.qc +++ b/src/server/server.qc @@ -17,10 +17,13 @@ void Game_InitRules(void) { + Player_Precache(); + FX_Corpse_Init(); + if (cvar("sv_playerslots") == 1 || cvar("coop") == 1) { - g_grMode = spawn(HLSingleplayerRules); + g_grMode = NSGameRules::InitFromProgs("maps/singleplayer.dat"); } else { - g_grMode = spawn(HLMultiplayerRules); + g_grMode = NSGameRules::InitFromProgs("maps/mp/gametypes/dm.dat"); } } @@ -30,9 +33,6 @@ Game_Worldspawn(void) Sound_Precache("Player.FlashLightOff"); Sound_Precache("Player.FlashLightOn"); Sound_Precache("item_weaponbox.Pickup"); - precache_model("models/player.mdl"); precache_model("models/w_weaponbox.mdl"); - Player_Precache(); - FX_Corpse_Init(); } diff --git a/src/shared/fx_corpse.qc b/src/shared/fx_corpse.qc index dc68e85..604b456 100644 --- a/src/shared/fx_corpse.qc +++ b/src/shared/fx_corpse.qc @@ -60,7 +60,7 @@ FX_Corpse_Spawn(NSClientPlayer pl, float anim) NSRenderableEntity body_next = (NSRenderableEntity)FX_Corpse_Next(); body_next.SetMovetype(MOVETYPE_BOUNCE); body_next.SetSolid(SOLID_CORPSE); - body_next.SetModel(pl.GetModel()); + body_next.SetModelindex(pl.GetModelindex()); if (pl.IsCrouching()) { body_next.SetOrigin(pl.GetOrigin() + [0,0,32]); @@ -75,6 +75,7 @@ FX_Corpse_Spawn(NSClientPlayer pl, float anim) body_next.ScheduleThink(FX_Corpse_Update, 0.0f); body_next.colormap = pl.colormap; body_next.frame1time = 0.0f; + printf("CORPSE SPAWNED: modelindex %d; origin: %v\n", body_next.modelindex, body_next.origin); return (entity)body_next; } #endif diff --git a/src/shared/include.src b/src/shared/include.src index 09be3bb..7c8105b 100644 --- a/src/shared/include.src +++ b/src/shared/include.src @@ -3,11 +3,11 @@ ../../../valve/src/shared/events.h ../../../valve/src/shared/flags.h ../../../valve/src/shared/skeleton.h +../../../valve/src/shared/fx_corpse.qc ../../../valve/src/shared/player.qc ../../../valve/src/shared/animations.qc ../../../valve/src/shared/fx_blood.qc ../../../valve/src/shared/fx_gaussbeam.qc -../../../valve/src/shared/fx_corpse.qc ../../../valve/src/shared/HLGaussBeam.qc ../../../valve/src/shared/HLWeapon.qc ../../../valve/src/shared/w_tripmine.qc diff --git a/src/shared/player.qc b/src/shared/player.qc index a1c9fea..70c351a 100644 --- a/src/shared/player.qc +++ b/src/shared/player.qc @@ -45,6 +45,7 @@ class HLPlayer:NSClientPlayer virtual void UpdateAliveCam(void); virtual void ClientInputFrame(void); #else + virtual void Death(entity, entity, int, vector, int); virtual void EvaluateEntity(void); virtual float SendEntity(entity, float); virtual void Save(float); @@ -339,6 +340,52 @@ HLPlayer::EvaluateEntity(void) } +void +HLPlayer::Death(entity inflictor, entity attacker, int damagePoints, vector dir, int location) +{ + /* either gib, or make a corpse */ + if (GetHealth()< -50) { + vector gibDir = vectoangles(GetOrigin() - attacker.origin); + float gibStrength = damagePoints * 2.0f; + BreakModel_Entity(this, gibDir, gibStrength); + } else { + float deathAnimation = ANIM_DIESIMPLE; + + switch (location) { + case BODY_HEAD: + deathAnimation = ANIM_DIEHEADSHOT; + break; + case BODY_CHEST: + deathAnimation = ANIM_DIESPIN; + break; + case BODY_STOMACH: + deathAnimation = ANIM_DIEGUTSHOT; + break; + default: + bool isFacing = IsFacingPosition(GetOrigin() + (dir * 128)); + + /* we still want a change to play ANIM_DIESIMPLE */ + if (random() < 0.5) + if (isFacing == false) { + deathAnimation = ANIM_DIEFORWARD; + } else { + deathAnimation = random() < 0.5 ? ANIM_DIEBACKWARDS1 : ANIM_DIEBACKWARDS1; + } + + break; + } + + NSEntity newCorpse = (NSEntity)FX_Corpse_Spawn(this, deathAnimation); + + /* if we were crouching, adjust the bbox (thx 2 lack of crouch death animation) */ + if (IsCrouching()) { + newCorpse.SetSize(VEC_HULL_MIN, [16, 16, -16]); + } + } + + super::Death(inflictor, attacker, damagePoints, dir, location); +} + /* ================= HLPlayer::SendEntity diff --git a/src/shared/w_tripmine.qc b/src/shared/w_tripmine.qc index 4706b23..a17fdc7 100644 --- a/src/shared/w_tripmine.qc +++ b/src/shared/w_tripmine.qc @@ -84,7 +84,7 @@ HLTripmine::Spawned(void) { super::Spawned(); - SetTakedamage(DAMAGE_NO); + MakeInvulnerable(); SetSolid(SOLID_NOT); SetMovetype(MOVETYPE_NONE); SetSize([-8,-8,-8], [8,8,8]); @@ -105,7 +105,7 @@ HLTripmine::Death(entity inflictor, entity attacker, int damage, vector dir, int float explosionRadius = explosionDamage * 2.5f; /* This is to prevent infinite loops in Damage_Radius */ - SetTakedamage(DAMAGE_NO); + MakeInvulnerable(); pointparticles(particleeffectnum("fx_explosion.main"), GetOrigin(), [0,0,0], 1); @@ -130,7 +130,7 @@ HLTripmine::Ready(void) /* Laser calibrated to N units! */ m_vecEndPos = trace_endpos; SetHealth(1); - SetTakedamage(DAMAGE_YES); + MakeVulnerable(); StartSoundDef("weapon_tripmine.activate", CHAN_WEAPON, true); SetSolid(SOLID_BBOX); ForceNetworkUpdate(); diff --git a/zpak001.pk3dir/cvar_defaults.cfg b/zpak001.pk3dir/cvar_defaults.cfg index 1357e9e..3ae3823 100644 --- a/zpak001.pk3dir/cvar_defaults.cfg +++ b/zpak001.pk3dir/cvar_defaults.cfg @@ -9,7 +9,6 @@ set ai_enable "1" // Disable AI behaviour when set. set bot_aimless "0" // Bots will not set goals for themselves when set. set bot_backspeed "133" // Bots desired maximum backwards speed. set bot_crouch "0" // Bots are all forced to move crouched. -set bot_debug "0" // TODO: needs to be logLevel? set bot_developer "0" // TODO: remove? set bot_dont_shoot "0" // Bots never actually shoot. set bot_enable "1" // Bot support enabled when set. @@ -53,6 +52,7 @@ set dev_skyscale "" // Override for the sky_camera room scale. set dsp_soundscapes "1" // Enable the use of sound scapes. +set g_damageScale "1" // final damage scale on objects set g_logLevel "2" // Game console log levels. 0 = None, 1 = Errors, 2 = Warnings, 3 = Extra Messages set g_logTimestamps "0" // When 1, will print time stamps before the log message set g_gravity "800" // Global gravity setting. diff --git a/zpak001.pk3dir/decls/def/ammo/rpgclip.def b/zpak001.pk3dir/decls/def/ammo/rpgclip.def index 10b61cf..408efd2 100644 --- a/zpak001.pk3dir/decls/def/ammo/rpgclip.def +++ b/zpak001.pk3dir/decls/def/ammo/rpgclip.def @@ -2,5 +2,5 @@ entityDef ammo_rpgclip { "inherit" "ammo_base" "model" "models/w_rpgammo.mdl" - "inv_ammo_uranium" "1" + "inv_ammo_rocket" "1" } diff --git a/zpak001.pk3dir/decls/def/player.def b/zpak001.pk3dir/decls/def/player.def index 377bfce..6ce6d7e 100644 --- a/zpak001.pk3dir/decls/def/player.def +++ b/zpak001.pk3dir/decls/def/player.def @@ -1,4 +1,19 @@ entityDef player { - "spawnclass" "HLPlayer" + "spawnclass" "HLPlayer" + "health" "100" + "maxarmor" "100" + "bleeds" "1" + "propdata" "actor_human" + "armorProtection" "0.2" + "armorBonus" "0.5" +} + +entityDef player_mp +{ + "inherit" "player" + "ammo_9mm" "44" + "item" "item_suit" + "weapon" "weapon_crowbar,weapon_9mmhandgun" + "current_weapon" "1" } diff --git a/zpak001.pk3dir/decls/def/weapons/357.def b/zpak001.pk3dir/decls/def/weapons/357.def index de7aa8d..e2a2cdc 100644 --- a/zpak001.pk3dir/decls/def/weapons/357.def +++ b/zpak001.pk3dir/decls/def/weapons/357.def @@ -31,6 +31,7 @@ entityDef weapon_357 "hudSlot" "1" "hudSlotPos" "1" "weight" "15" + "killIcon" "d_357" } entityDef weapon_python diff --git a/zpak001.pk3dir/decls/def/weapons/handgrenade.def b/zpak001.pk3dir/decls/def/weapons/handgrenade.def index 3023346..179fc0d 100644 --- a/zpak001.pk3dir/decls/def/weapons/handgrenade.def +++ b/zpak001.pk3dir/decls/def/weapons/handgrenade.def @@ -1,22 +1,22 @@ entityDef weapon_handgrenade { - "editor_color" ".3 .3 1" - "editor_mins" "-16 -16 -16" - "editor_maxs" "16 16 16" - "editor_usage" "Hand Grenade" - "editor_rotatable" "1" + "editor_color" ".3 .3 1" + "editor_mins" "-16 -16 -16" + "editor_maxs" "16 16 16" + "editor_usage" "Hand Grenade" + "editor_rotatable" "1" - "spawnclass" "HLWeapon" - "model" "models/w_grenade.mdl" - "model_view" "models/v_grenade.mdl" - "snd_acquire" "weapon.pickup" - "snd_respawn" "item.respawn" + "spawnclass" "HLWeapon" + "model" "models/w_grenade.mdl" + "model_view" "models/v_grenade.mdl" + "snd_acquire" "weapon.pickup" + "snd_respawn" "item.respawn" "inv_name" "Hand Grenade" "inv_weapon" "weapon_handgrenade" "inv_ammo_handgrenade" "5" - "def_onRelease" "projectile_handgrenade" + "def_onRelease" "projectile_handgrenade" "def_explode_inhand" "env_handgrenade_explodeinhand" "def_damage_inhand" "damage_handgrenadeSplash" "ammoType" "ammo_handgrenade" @@ -25,17 +25,17 @@ entityDef weapon_handgrenade "primed_fuse" "4" "removeOnEmpty" "1" - "actIdle" "0,1" - "actDraw" "7" - "actHolster" "6" - "actFire" "2" - "actRelease" "3,4,5" + "actIdle" "0,1" + "actDraw" "7" + "actHolster" "6" + "actFire" "2" + "actRelease" "3,4,5" // HLWeapon specific - "hudSlot" "4" - "hudSlotPos" "0" - "weight" "5" - "crosshair" "none" + "hudSlot" "4" + "hudSlotPos" "0" + "weight" "5" + "crosshair" "none" } entityDef projectile_handgrenade @@ -52,7 +52,6 @@ entityDef projectile_handgrenade "snd_explode" "fx.explosion" "snd_bounce" "weapon_handgrenade.bounce" "decal_detonate" "ExplosionScorch" - "def_damage" "damage_handgrenadeDirect" "def_splash_damage" "damage_handgrenadeSplash" } @@ -67,9 +66,3 @@ entityDef damage_handgrenadeSplash "damage" "skill:plr_hand_grenade" "radius" "250" } - -entityDef env_handgrenade_explodeinhand -{ - "spawnclass" "idAnimatedEntity" - "model" "grenadeExplosion.prt" -} diff --git a/zpak001.pk3dir/eukara.cfg b/zpak001.pk3dir/eukara.cfg index df5d2bc..82f56af 100644 --- a/zpak001.pk3dir/eukara.cfg +++ b/zpak001.pk3dir/eukara.cfg @@ -36,7 +36,7 @@ bind u "messagemode2" bind v "impulse 100" bind w "+forward" bind x "goprone" -bind y "vote yes" +bind y "vote yes" bind z "toggle sv_gamespeed 0.5 1" seta brightness "0" seta cl_chatmode "2" diff --git a/zpak001.pk3dir/maps/mp/gametypes/dm.qc b/zpak001.pk3dir/maps/mp/gametypes/dm.qc new file mode 100644 index 0000000..7a3eac2 --- /dev/null +++ b/zpak001.pk3dir/maps/mp/gametypes/dm.qc @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2024 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. + */ + +#pragma PROGS_DAT "dm.dat" + +#include "../../../../../src/server/mapC.h" + +entity lastSpawn; +string g_strTeamList; +const string mp_teamlist_fallback = "scientist;hgrunt"; +var string autocvar_mp_teamlist = mp_teamlist_fallback; + +bool +IsTeamplay(void) +{ + return getCvarInt("mp_teamplay") ? (true) : (false); +} + +bool +AllowFlashlight(void) +{ + return getCvarInt("mp_flashlight") ? (true) : (false); +} + +void +CodeCallback_StartGameType(void) +{ + //MOTD_LoadDefault(); + + setServerInfo("scorepoints", "0"); + + if (IsTeamplay() == true) { + int c; + + /* get the segments from our cvar */ + g_strTeamList = autocvar_mp_teamlist; + c = tokenizebyseparator(g_strTeamList, ";"); + + /* if we've got less than 2 teams, use the fallback... */ + if (c < 2) { + g_strTeamList = mp_teamlist_fallback; + c = tokenizebyseparator(g_strTeamList, ";"); + } + + setServerInfo("teams", itos(c)); + + /* initialize all dem teams */ + for (int i = 0; i < c; i++) { + setServerInfo(sprintf("team_%i", i+1i), argv(i)); + setServerInfo(sprintf("teamscore_%i", i+1i), "0"); + } + } else { + setServerInfo("teams", "0"); + } +} + +void +CodeCallback_PlayerSpawn(void) +{ + string playerModel; + + changeClass(self, "player_mp"); + + if (IsTeamplay() == true) { + float teamCount = tokenizebyseparator(g_strTeamList, ";"); + float playerTeam = self.team; + string teamModel; + + /* not part of a team? pick one of the ones we have */ + /* TODO: this should sort us into the lowest team */ + if (playerTeam == 0) { + playerTeam = 1 + floor(random(0, teamCount)); /* teams start at 1 after all */ + sendInput(self, "SetTeam", ftos(playerTeam), self); + } + + teamModel = argv(playerTeam - 1); + playerModel = sprintf("models/player/%s/%s.mdl", teamModel, teamModel); + } else { + /* interpret the 'model' InfoKey */ + playerModel = getUserInfo(self, "model"); + + if (playerModel != "") { + playerModel = sprintf("models/player/%s/%s.mdl", playerModel, playerModel); + } + } + + /* fallback is always models/player.mdl for Half-Life */ + if (playerModel == "" || fileExists(playerModel) == false) { + playerModel = "models/player.mdl"; + } + + self.modelindex = getmodelindex(playerModel); /* keep OG size */ + lastSpawn = getSpawnpoint("info_player_deathmatch"); + setorigin(self, lastSpawn.origin); +} + +void +CodeCallback_PlayerDisconnect(void) +{ + +} + +bool +CodeCallback_PlayerRequestRespawn(void) +{ + CodeCallback_PlayerSpawn(); + return (true); +} + +void +CodeCallback_PlayerDamage(entity inflictor, entity attacker) +{ + +} + +void +CodeCallback_PlayerKilled(entity inflictor, entity attacker, string weapon) +{ + obituary(self.netname, attacker.netname, weapon, ""); + + /* death-counter */ + self.deaths++; + + /* update score-counter */ + if (isPlayer(attacker)) { + if (self == attacker) { + attacker.frags--; + } else { + attacker.frags++; + } + } +} + +bool +CodeCallback_ClientCommand(string command) +{ + float commandArgs = tokenize(command); + + switch (argv(0)) { + case "chooseteam": + string teamName = argv(1); + + /* wrong mode */ + if (IsTeamplay() == false) { + break; + } + + /* no team defined */ + if (!teamName) { + break; + } + + float c = tokenizebyseparator(g_strTeamList, ";"); + + for (float i = 0; i < c; i++) { + if (argv(i) == teamName) { + string newTeam = ftos(i + 1); + sendInput(self, "SetTeam", newTeam, self); + sendInput(self, "Damage", "1000", self); + break; + } + } + break; + default: + return (false); + } + + return (true); +} + +bool +CodeCallback_ImpulseCommand(float impulseNum) +{ + switch (impulseNum) { + case 100: + if (AllowFlashlight() == true) { + sendInput(self, "UseItem", "item_suit", self); + } + break; + default: + return (false); + } + + return (true); +} diff --git a/zpak001.pk3dir/maps/singleplayer.qc b/zpak001.pk3dir/maps/singleplayer.qc new file mode 100644 index 0000000..251864e --- /dev/null +++ b/zpak001.pk3dir/maps/singleplayer.qc @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2024 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. + */ + +#pragma PROGS_DAT "singleplayer.dat" + +#include "../../../src/server/mapC.h" + +void +CodeCallback_StartGameType(void) +{ +} + +void +CodeCallback_PlayerSpawn(void) +{ + changeClass(self, "player"); + + entity lastSpawn = getSpawnpoint("info_player_start"); + setorigin(self, lastSpawn.origin); +} + +bool +CodeCallback_PlayerRequestRespawn(void) +{ + localcmd("load quick\n"); + return (true); +} + + +bool +CodeCallback_ImpulseCommand(float impulseNum) +{ + switch (impulseNum) { + case 100: + sendInput(self, "UseItem", "item_suit", self); + break; + case 101: + sendInput(self, "SetHealth", "100", self); + sendInput(self, "SetArmor", "100", self); + sendInput(self, "GiveItem", "item_suit", self); + sendInput(self, "GiveItem", "weapon_357", self); + sendInput(self, "GiveItem", "weapon_9mmAR", self); + sendInput(self, "GiveItem", "weapon_9mmhandgun", self); + sendInput(self, "GiveItem", "weapon_crossbow", self); + sendInput(self, "GiveItem", "weapon_crowbar", self); + sendInput(self, "GiveItem", "weapon_egon", self); + sendInput(self, "GiveItem", "weapon_gauss", self); + sendInput(self, "GiveItem", "weapon_handgrenade", self); + sendInput(self, "GiveItem", "weapon_hornetgun", self); + sendInput(self, "GiveItem", "weapon_rpg", self); + sendInput(self, "GiveItem", "weapon_satchel", self); + sendInput(self, "GiveItem", "weapon_shotgun", self); + sendInput(self, "GiveItem", "weapon_snark", self); + sendInput(self, "GiveItem", "weapon_tripmine", self); + sendInput(self, "GiveAmmo", "ammo_9mm 255", self); + sendInput(self, "GiveAmmo", "ammo_357 255", self); + sendInput(self, "GiveAmmo", "ammo_buckshot 255", self); + sendInput(self, "GiveAmmo", "ammo_bolt 255", self); + sendInput(self, "GiveAmmo", "ammo_rocket 255", self); + sendInput(self, "GiveAmmo", "ammo_uranium 255", self); + sendInput(self, "GiveAmmo", "ammo_handgrenade 255", self); + sendInput(self, "GiveAmmo", "ammo_satchel 255", self); + sendInput(self, "GiveAmmo", "ammo_tripmine 255", self); + sendInput(self, "GiveAmmo", "ammo_snark 255", self); + sendInput(self, "GiveAmmo", "ammo_hornet 255", self); + sendInput(self, "GiveAmmo", "ammo_m203_grenade 255", self); + break; + default: + return (false); + } + + return (true); +} \ No newline at end of file