Major work on item_tfgoal and info_tfgoal. We now got 2fort style maps

working functionally. A lot is still missing however. Especially visual
fluff.
This commit is contained in:
Marco Cawthorne 2021-05-25 08:32:11 +02:00
parent cd750cd5d8
commit a0a65b9843
14 changed files with 1222 additions and 315 deletions

View file

@ -16,6 +16,8 @@
class TFCGameRules:CGameRules
{
void(void) TFCGameRules;
virtual void(base_player) PlayerConnect;
virtual void(base_player) PlayerDisconnect;
virtual void(base_player) PlayerPostFrame;

View file

@ -82,3 +82,13 @@ TFCGameRules::PlayerSpawn(base_player pp)
forceinfokey(pl, "*spec", "2");
Spawn_ObserverCam(pl);
}
void
TFCGameRules::TFCGameRules(void)
{
forceinfokey(world, "teams", "2");
forceinfokey(world, "team_1", "Blue");
forceinfokey(world, "teamscore_1", "0");
forceinfokey(world, "team_2", "Red");
forceinfokey(world, "teamscore_2", "0");
}

View file

@ -14,32 +14,192 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* A lot of this has been sourced and verified via:
* http://www.bspquakeeditor.com/archive/planetfortress_com_factory/files/tfortmap.txt
*/
typedef enum
{
TFGOAL_ACTIVE, /* cannot be touched by a player */
TFGOAL_INACTIVE, /* will become ACTIVE when the toucher meets the criteria */
TFGOAL_REMOVED /* cannot be touched by players at all, only other events */
} tfgoal_state;
/* conditions under which the goal will activate */
typedef enumflags
{
TFACT_NONE,
TFACT_TOUCH,
TFACT_DETPACK,
TFACT_FAILURE,
TFACT_DROPTOGROUND = 2048
} tfgoal_activation;
typedef enumflags
{
TFEF_ACTIVATOR, /* single activator */
TFEF_ACTTEAM, /* activators team */
TFEF_NONACTTEAM, /* everyone elses but activators team */
TFEF_NONACTIVATORS, /* everyone but the activator */
TFEF_WALLOBSTRUCT, /* everyone not tracelineable? */
TFEF_PVS, /* everyone not in the same pvs? */
TFEF_CHECK, /* no idea */
} tfgoal_effects;
typedef enumflags
{
TFRESULT_NONE = 0,
TFRESULT_REMOVE = 1, /* remove right away */
TFRESULT_SUBGOAL_MODS = 2,
TFRESULT_SCORES = 4,
TFRESULT_SUBGOAL_NOMODS = 8,
TFRESULT_NODISGUISE = 16,
TFRESULT_FORCERESPAWN = 32,
TFRESULT_REMOVE_BUILDINGS = 64
} tfgoal_result;
/* point entity version */
class info_tfgoal:CBaseTrigger
{
string m_strName;
string m_strSound;
string m_strActivatedSound;
int m_iGoalID; /* goal identifer */
int m_iGoalGroupID; /* goal group ID */
tfgoal_state m_tfgState;
tfgoal_activation m_tfgActivation;
tfgoal_effects m_tfgEffects;
tfgoal_result m_tfgResult;
player m_Activator;
float m_dMustCarry; /* player must carry item of this ID */
float m_dRespawn; /* respawn after num seconds on TFRESULT_REMOVE */
float m_dTeamBlueGain;
float m_dTeamRedGain;
float m_dTeamYellowGain;
float m_dTeamGreenGain;
float m_dScore; /* score to be added to the activators' team score */
int m_iTeam; /* which team this belongs to */
int m_iHealth;
int m_iArmor;
int m_iShells;
int m_iNails;
int m_iCells;
int m_iMedikit;
int m_iRockets;
int m_iDetpack;
void(void) info_tfgoal;
virtual void(void) touch;
virtual void(void) Respawn;
virtual void(string, string) SpawnKey;
};
void
info_tfgoal::touch(void)
{
item_tfgoal findme = __NULL__;
if (other.classname != "player") {
return;
}
player pl = (player)other;
sound(this, CHAN_ITEM, m_strSound, 1.0f, ATTN_NORM);
/* check for state */
if (m_tfgState != TFGOAL_INACTIVE)
return;
/* check for team eligibility */
if (m_iTeam)
if (other.team != m_iTeam)
return;
/* check for the must-have carry */
if (m_dMustCarry) {
item_tfgoal findme = __NULL__;
/* find the needle in the haystack */
for (entity e = world; (e = find(e, ::classname, "item_tfgoal"));) {
item_tfgoal a = (item_tfgoal)e;
if (a.m_dItemID == m_dMustCarry)
findme = a;
}
if (!findme) {
printf("can't find the pickup\n");
return;
}
if (findme.solid != SOLID_NOT) {
printf("the item is not picked up.\n");
return;
}
if (findme.m_eActivator != pl) {
printf("you are not the items activator.\n");
return;
} else {
/* unset the activator and make it reappear */
findme.Respawn();
}
}
sound(this, CHAN_ITEM, m_strActivatedSound, 1.0f, ATTN_NORM);
Logging_Pickup(other, this, m_strName);
if (cvar("sv_playerslots") == 1) {
remove(self);
} else {
/* here we increase/decrease funstuff */
pl.health += m_iHealth;
pl.armor += m_iArmor;
pl.m_iAmmoShells += m_iShells;
pl.m_iAmmoNails += m_iNails;
pl.m_iAmmoCells += m_iCells;
pl.m_iAmmoRockets += m_iRockets;
pl.m_iAmmoMedikit += m_iMedikit;
pl.m_iAmmoDetpack += m_iDetpack;
/* clamp */
pl.health = bound(0, pl.health, pl.m_iMaxHealth);
pl.armor = bound(0, pl.armor, pl.m_iMaxArmor);
pl.m_iAmmoShells = bound(0, pl.m_iAmmoShells, pl.m_iMaxShells);
pl.m_iAmmoNails = bound(0, pl.m_iAmmoNails, pl.m_iMaxNails);
pl.m_iAmmoCells = bound(0, pl.m_iAmmoCells, pl.m_iMaxCells);
pl.m_iAmmoRockets = bound(0, pl.m_iAmmoRockets, pl.m_iMaxRockets);
pl.frags += frags;
string ts;
if (m_dScore) {
ts = sprintf("teamscore_%i", m_iTeam);
forceinfokey(world, ts, sprintf("%d", serverkeyfloat(ts) + m_dScore));
}
if (m_dTeamBlueGain) {
ts = "teamscore_1";
forceinfokey(world, ts, sprintf("%d", serverkeyfloat(ts) + m_dTeamBlueGain));
}
if (m_dTeamRedGain) {
ts = "teamscore_2";
forceinfokey(world, ts, sprintf("%d", serverkeyfloat(ts) + m_dTeamRedGain));
}
if (m_dTeamYellowGain) {
ts = "teamscore_3";
forceinfokey(world, ts, sprintf("%d", serverkeyfloat(ts) + m_dTeamYellowGain));
}
if (m_dTeamGreenGain) {
ts = "teamscore_4";
forceinfokey(world, ts, sprintf("%d", serverkeyfloat(ts) + m_dTeamGreenGain));
}
/* remove? */
if (m_tfgResult & TFRESULT_REMOVE) {
Hide();
think = Respawn;
nextthink = time + 30.0f;
if (m_dRespawn) {
think = Respawn;
nextthink = time + m_dRespawn;
}
}
}
@ -53,29 +213,129 @@ info_tfgoal::Respawn(void)
SetOrigin(m_oldOrigin);
}
void
info_tfgoal::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "netname":
netname = strValue;
break;
case "noise":
m_strActivatedSound = strValue;
break;
case "mdl":
model = strValue;
break;
case "goal_state":
m_tfgState = stof(strValue);
break;
case "g_a":
m_tfgActivation = stof(strValue);
break;
case "g_e":
m_tfgEffects = stof(strValue);
break;
case "goal_result":
m_tfgResult = stof(strValue);
break;
case "items_allowed":
m_dMustCarry = stof(strValue);
break;
case "team_no":
m_iTeam = stoi(strValue);
break;
case "count":
m_dScore = stof(strValue);
break;
case "wait":
m_dRespawn = stof(strValue);
break;
case "increase_team1":
m_dTeamBlueGain = stof(strValue);
break;
case "increase_team2":
m_dTeamRedGain = stof(strValue);
break;
case "increase_team3":
m_dTeamYellowGain = stof(strValue);
break;
case "increase_team4":
m_dTeamGreenGain = stof(strValue);
break;
/* AP manipulators */
case "health":
m_iHealth = stoi(strValue);
break;
case "armor":
m_iArmor = stoi(strValue);
break;
case "ammo_shells":
m_iShells = stoi(strValue);
break;
case "ammo_nails":
m_iNails = stoi(strValue);
break;
case "ammo_rockets":
m_iRockets = stoi(strValue);
break;
case "ammo_cells":
m_iCells = stoi(strValue);
break;
case "ammo_medikit":
m_iMedikit = stoi(strValue);
break;
default:
CBaseTrigger::SpawnKey(strKey, strValue);
break;
}
}
void
info_tfgoal::info_tfgoal(void)
{
m_tfgState = TFGOAL_INACTIVE;
m_tfgResult = TFRESULT_REMOVE;
for (int i = 1; i < (tokenize(__fullspawndata) - 1); i += 2) {
switch (argv(i)) {
case "netname":
m_strSound = argv(i+1);
netname = __NULL__;
break;
case "noise":
m_strSound = argv(i+1);
break;
case "mdl":
model = argv(i+1);
break;
default:
break;
}
SpawnKey(argv(i), argv(i+1));
}
precache_sound(m_strSound);
precache_sound(m_strActivatedSound);
CBaseEntity::CBaseEntity();
info_tfgoal::Respawn();
}
CLASSEXPORT(i_t_g, info_tfgoal)
class i_t_g:info_tfgoal
{
void(void) i_t_g;
virtual void(void) Respawn;
};
void
i_t_g::Respawn(void)
{
solid = SOLID_BSPTRIGGER;
movetype = MOVETYPE_NONE;
SetModel(m_oldModel);
SetOrigin(m_oldOrigin);
}
void
i_t_g::i_t_g(void)
{
classname = "info_tfgoal";
m_tfgState = TFGOAL_INACTIVE;
m_tfgResult = TFRESULT_NONE;
for (int i = 1; i < (tokenize(__fullspawndata) - 1); i += 2) {
SpawnKey(argv(i), argv(i+1));
}
CBaseEntity::CBaseEntity();
precache_sound(m_strActivatedSound);
Respawn();
}

View file

@ -16,7 +16,14 @@
class item_tfgoal:CBaseTrigger
{
float m_dItemID;
int m_iTeamUses;
string m_strSound;
string m_voxTeam;
string m_voxOtherTeam;
string m_voxActivator;
player m_eActivator;
void(void) item_tfgoal;
virtual void(void) touch;
@ -30,12 +37,35 @@ item_tfgoal::touch(void)
return;
}
if (cvar("sv_playerslots") == 1) {
remove(self);
} else {
Hide();
think = Respawn;
nextthink = time + 20.0f;
player pl = (player)other;
/* team filter */
if (m_iTeamUses)
if (m_iTeamUses != pl.team)
return;
Hide();
pl.g_items |= ITEM_GOALITEM;
m_eActivator = pl;
sound(this, CHAN_ITEM, m_strSound, 1.0f, ATTN_NONE);
/* broadcast via VOX that this was taken from us */
for (entity e = world; (e = find(e, ::classname, "player")); ) {
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_CHAT_VOX);
if (e.team != m_iTeamUses) {
WriteString(MSG_MULTICAST, m_voxOtherTeam);
} else {
if (e == pl)
WriteString(MSG_MULTICAST, m_voxActivator);
else
WriteString(MSG_MULTICAST, m_voxTeam);
}
msg_entity = e;
multicast([0,0,0], MULTICAST_ONE);
}
}
@ -47,6 +77,7 @@ item_tfgoal::Respawn(void)
SetModel(m_oldModel);
setsize(this, VEC_HULL_MIN, VEC_HULL_MAX);
SetOrigin(m_oldOrigin);
m_eActivator = __NULL__;
}
void
@ -60,6 +91,21 @@ item_tfgoal::item_tfgoal(void)
case "mdl":
model = argv(i+1);
break;
case "goal_no":
m_dItemID = stof(argv(i+1));
break;
case "team_no":
m_iTeamUses = stoi(argv(i+1));
break;
case "AP_speak":
m_voxActivator = argv(i+1);
break;
case "team_speak":
m_voxTeam = argv(i+1);
break;
case "non_team_speak":
m_voxOtherTeam = argv(i+1);
break;
default:
break;
}

View file

@ -25,8 +25,8 @@ defs.h
../../../valve/src/server/items.qc
info_player_teamspawn.qc
info_tfgoal.qc
item_tfgoal.qc
info_tfgoal.qc
gamerules.qc
../../../valve/src/server/client.qc

View file

@ -80,6 +80,7 @@ CSEv_TeamJoin_f(float f)
forceinfokey(pl, "bottomcolor", "0x3bff00");
}
forceinfokey(pl, "*team", ftos(pl.team));
pl.model = g_teammodels[f];
setmodel(pl, pl.model);
setsize(pl, VEC_HULL_MIN, VEC_HULL_MAX);
@ -119,6 +120,18 @@ CSEv_TeamJoin_f(float f)
Weapons_AddItem(pl, WEAPON_CROWBAR, -1);
Weapons_AddItem(pl, WEAPON_SBS, -1);
Weapons_AddItem(pl, WEAPON_NAILGUN, -1);
pl.m_iAmmoShells = 17;
pl.m_iAmmoNails = 100;
pl.m_iMaxHealth = 75;
pl.m_iMaxArmor = 50;
pl.health = pl.m_iMaxHealth;
pl.armor = 25;
pl.m_iMaxShells = 50;
pl.m_iMaxNails = 200;
pl.m_iMaxCells = 100;
pl.m_iMaxRockets = 25;
env_message_single(pl, "HELP_SCOUT");
break;
case CLASS_SNIPER:
@ -126,6 +139,18 @@ CSEv_TeamJoin_f(float f)
Weapons_AddItem(pl, WEAPON_SNIPER, -1);
Weapons_AddItem(pl, WEAPON_AUTORIFLE, -1);
Weapons_AddItem(pl, WEAPON_NAILGUN, -1);
pl.m_iAmmoShells = 60; /* sniper rifles use shells */
pl.m_iAmmoNails = 50;
pl.m_iMaxHealth = 90;
pl.m_iMaxArmor = 50;
pl.health = pl.m_iMaxHealth;
pl.armor = 0;
pl.m_iMaxShells = 75;
pl.m_iMaxNails = 100;
pl.m_iMaxCells = 50;
pl.m_iMaxRockets = 25;
env_message_single(pl, "HELP_SNIPER");
break;
case CLASS_SOLDIER:
@ -133,6 +158,18 @@ CSEv_TeamJoin_f(float f)
Weapons_AddItem(pl, WEAPON_SBS, -1);
Weapons_AddItem(pl, WEAPON_DBS, -1);
Weapons_AddItem(pl, WEAPON_RPG, -1);
pl.m_iAmmoShells = 26;
pl.m_iAmmoRockets = 6;
pl.m_iMaxHealth = 100;
pl.m_iMaxArmor = 200;
pl.health = pl.m_iMaxHealth;
pl.armor = 100;
pl.m_iMaxShells = 100;
pl.m_iMaxNails = 100;
pl.m_iMaxCells = 50;
pl.m_iMaxRockets = 50;
env_message_single(pl, "HELP_SOLDIER");
break;
case CLASS_DEMO:
@ -140,6 +177,18 @@ CSEv_TeamJoin_f(float f)
Weapons_AddItem(pl, WEAPON_SBS, -1);
Weapons_AddItem(pl, WEAPON_GLAUNCHER, -1);
Weapons_AddItem(pl, WEAPON_PIPEBOMB, -1);
pl.m_iAmmoShells = 22;
pl.m_iAmmoRockets = 14;
pl.m_iMaxHealth = 90;
pl.m_iMaxArmor = 100;
pl.health = pl.m_iMaxHealth;
pl.armor = 50;
pl.m_iMaxShells = 75;
pl.m_iMaxNails = 50;
pl.m_iMaxCells = 50;
pl.m_iMaxRockets = 50;
env_message_single(pl, "HELP_DEMOMAN");
break;
case CLASS_MEDIC:
@ -147,6 +196,18 @@ CSEv_TeamJoin_f(float f)
Weapons_AddItem(pl, WEAPON_SBS, -1);
Weapons_AddItem(pl, WEAPON_DBS, -1);
Weapons_AddItem(pl, WEAPON_SUPERNAIL, -1);
pl.m_iAmmoShells = 26;
pl.m_iAmmoNails = 50;
pl.m_iMaxHealth = 90;
pl.m_iMaxArmor = 100;
pl.health = pl.m_iMaxHealth;
pl.armor = 50;
pl.m_iMaxShells = 75;
pl.m_iMaxNails = 150;
pl.m_iMaxCells = 50;
pl.m_iMaxRockets = 25;
env_message_single(pl, "HELP_MEDIC");
break;
case CLASS_HVYWEAPON:
@ -154,6 +215,17 @@ CSEv_TeamJoin_f(float f)
Weapons_AddItem(pl, WEAPON_SBS, -1);
Weapons_AddItem(pl, WEAPON_DBS, -1);
Weapons_AddItem(pl, WEAPON_ASSCAN, -1);
pl.m_iAmmoShells = 176; /* all of the heavy's weapons use shells */
pl.m_iMaxHealth = 100;
pl.m_iMaxArmor = 250;
pl.health = pl.m_iMaxHealth;
pl.armor = 150;
pl.m_iMaxShells = 200;
pl.m_iMaxNails = 200;
pl.m_iMaxCells = 50;
pl.m_iMaxRockets = 25;
env_message_single(pl, "HELP_HWGUY");
break;
case CLASS_PYRO:
@ -161,6 +233,19 @@ CSEv_TeamJoin_f(float f)
Weapons_AddItem(pl, WEAPON_SBS, -1);
Weapons_AddItem(pl, WEAPON_FLAMER, -1);
Weapons_AddItem(pl, WEAPON_INCENDIARY, -1);
pl.m_iAmmoShells = 12;
pl.m_iAmmoCells = 120;
pl.m_iAmmoRockets = 5;
pl.m_iMaxHealth = 100;
pl.m_iMaxArmor = 150;
pl.health = pl.m_iMaxHealth;
pl.armor = 50;
pl.m_iMaxShells = 40;
pl.m_iMaxNails = 50;
pl.m_iMaxCells = 200;
pl.m_iMaxRockets = 60;
env_message_single(pl, "HELP_PYRO");
break;
case CLASS_SPY:
@ -168,12 +253,37 @@ CSEv_TeamJoin_f(float f)
Weapons_AddItem(pl, WEAPON_TRANQUIL, -1);
Weapons_AddItem(pl, WEAPON_DBS, -1);
Weapons_AddItem(pl, WEAPON_NAILGUN, -1);
pl.m_iAmmoShells = 24; /* tranquil and dbs use shells */
pl.m_iAmmoNails = 50;
pl.m_iMaxHealth = 90;
pl.m_iMaxArmor = 100;
pl.health = pl.m_iMaxHealth;
pl.armor = 25;
pl.m_iMaxShells = 40;
pl.m_iMaxNails = 50;
pl.m_iMaxCells = 30;
pl.m_iMaxRockets = 15;
env_message_single(pl, "HELP_SPY");
break;
case CLASS_ENGINEER:
Weapons_AddItem(pl, WEAPON_WRENCH, -1);
Weapons_AddItem(pl, WEAPON_RAILGUN, -1);
Weapons_AddItem(pl, WEAPON_DBS, -1);
pl.m_iAmmoCells = 100;
pl.m_iAmmoNails = 25;
pl.m_iAmmoShells = 4;
pl.m_iMaxHealth = 80;
pl.m_iMaxArmor = 50;
pl.health = pl.m_iMaxHealth;
pl.armor = 25;
pl.m_iMaxShells = 50;
pl.m_iMaxNails = 50;
pl.m_iMaxCells = 200;
pl.m_iMaxRockets = 30;
env_message_single(pl, "HELP_ENGINEER");
break;
}

View file

@ -1,6 +1,6 @@
#includelist
../../../valve/src/shared/flags.h
../../../valve/src/shared/player.qc
player.qc
../../../base/src/shared/weapon_common.h
../../../valve/src/shared/animations.h
../../../valve/src/shared/animations.qc
@ -16,6 +16,13 @@
items.h
weapons.h
../../../base/src/shared/weapon_basesemi.qc
../../../base/src/shared/weapon_basemelee.qc
../../../base/src/shared/weapon_baseshotgun.qc
../../../base/src/shared/weapon_baseprojectile.qc
../../../base/src/shared/weapon_baseautomatic.qc
w_asscan.qc
w_autorifle.qc
w_crowbar.qc

View file

@ -47,4 +47,4 @@
#define ITEM_UNUSED29 0x10000000
#define ITEM_UNUSED30 0x20000000
#define ITEM_UNUSED31 0x40000000
#define ITEM_UNUSED32 0x80000000
#define ITEM_GOALITEM 0x80000000

340
src/shared/player.qc Normal file
View file

@ -0,0 +1,340 @@
/*
* Copyright (c) 2016-2021 Marco Hladik <marco@icculus.org>
*
* 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.
*/
/* all potential SendFlags bits we can possibly send */
enumflags
{
PLAYER_KEEPALIVE,
PLAYER_MODELINDEX,
PLAYER_ORIGIN,
PLAYER_ORIGIN_Z,
PLAYER_ANGLES_X,
PLAYER_ANGLES_Y,
PLAYER_COLORMAP,
PLAYER_VELOCITY,
PLAYER_VELOCITY_Z,
PLAYER_FLAGS,
PLAYER_WEAPON,
PLAYER_ITEMS,
PLAYER_HEALTH,
PLAYER_ARMOR,
PLAYER_MOVETYPE,
PLAYER_VIEWOFS,
PLAYER_TOPFRAME,
PLAYER_BOTTOMFRAME,
PLAYER_AMMO1,
PLAYER_AMMO2,
PLAYER_AMMO3,
PLAYER_UNUSED1,
PLAYER_UNUSED2
};
noref int input_sequence;
class player:base_player
{
/* animation */
PREDICTED_INT(anim_top);
PREDICTED_FLOAT(anim_top_time);
PREDICTED_FLOAT(anim_top_delay);
PREDICTED_INT(anim_bottom);
PREDICTED_FLOAT(anim_bottom_time);
/* ammo 1 */
PREDICTED_INT(mag_sbs);
PREDICTED_INT(mag_dbs);
PREDICTED_INT(mag_rpg);
/* ammo 2 */
PREDICTED_INT(m_iAmmoRockets);
PREDICTED_INT(m_iAmmoNails);
PREDICTED_INT(m_iAmmoCells);
PREDICTED_INT(m_iAmmoShells);
PREDICTED_INT(m_iAmmoDetpack);
PREDICTED_INT(m_iAmmoMedikit);
/* ammo 3 */
PREDICTED_INT(mode_tempstate);
#ifdef CLIENT
/* External model */
entity p_model;
int p_hand_bone;
int p_model_bone;
float lastweapon;
virtual void(void) draw;
virtual float() predraw;
virtual void(void) postdraw;
virtual void(float,float) ReceiveEntity;
virtual void(void) PredictPreFrame;
virtual void(void) PredictPostFrame;
#else
int m_iMaxHealth;
int m_iMaxArmor;
int m_iMaxShells;
int m_iMaxNails;
int m_iMaxRockets;
int m_iMaxCells;
int m_iMaxDetpack;
int m_iMaxMedikit;
virtual void(void) EvaluateEntity;
virtual float(entity, float) SendEntity;
#endif
};
#ifdef CLIENT
void Weapons_AmmoUpdate(entity);
/*
=================
player::ReceiveEntity
=================
*/
void
player::ReceiveEntity(float new, float fl)
{
/* the generic client attributes */
base_player::ReceiveEntity(new, fl);
/* animation */
if (fl & PLAYER_TOPFRAME) {
anim_top = readbyte();
anim_top_time = readfloat();
anim_top_delay = readfloat();
}
if (fl & PLAYER_BOTTOMFRAME) {
anim_bottom = readbyte();
anim_bottom_time = readfloat();
}
if (fl & PLAYER_AMMO1) {
mag_sbs = readbyte();
mag_dbs = readbyte();
mag_rpg = readbyte();
}
if (fl & PLAYER_AMMO2) {
m_iAmmoRockets = readbyte();
m_iAmmoNails = readbyte();
m_iAmmoCells = readbyte();
m_iAmmoShells = readbyte();
m_iAmmoDetpack = readbyte();
m_iAmmoMedikit = readbyte();
}
if (fl & PLAYER_AMMO3) {
mode_tempstate = readbyte();
}
if (fl & PLAYER_AMMO1 || fl & PLAYER_AMMO2 || fl & PLAYER_AMMO3)
Weapons_AmmoUpdate(this);
setorigin(this, origin);
}
/*
=================
player::PredictPostFrame
Save the last valid server values away in the _net variants of each field
so we can roll them back later.
=================
*/
void
player::PredictPreFrame(void)
{
/* the generic client attributes */
base_player::PredictPreFrame();
SAVE_STATE(anim_top);
SAVE_STATE(anim_top_delay);
SAVE_STATE(anim_top_time);
SAVE_STATE(anim_bottom);
SAVE_STATE(anim_bottom_time);
SAVE_STATE(mag_sbs);
SAVE_STATE(mag_dbs);
SAVE_STATE(mag_rpg);
SAVE_STATE(m_iAmmoRockets);
SAVE_STATE(m_iAmmoNails);
SAVE_STATE(m_iAmmoCells);
SAVE_STATE(m_iAmmoShells);
SAVE_STATE(m_iAmmoDetpack);
SAVE_STATE(m_iAmmoMedikit);
SAVE_STATE(mode_tempstate);
}
/*
=================
player::PredictPostFrame
Where we roll back our values to the ones last sent/verified by the server.
=================
*/
void
player::PredictPostFrame(void)
{
/* the generic client attributes */
base_player::PredictPostFrame();
ROLL_BACK(anim_top);
ROLL_BACK(anim_top_delay);
ROLL_BACK(anim_top_time);
ROLL_BACK(anim_bottom);
ROLL_BACK(anim_bottom_time);
ROLL_BACK(mag_sbs);
ROLL_BACK(mag_dbs);
ROLL_BACK(mag_rpg);
ROLL_BACK(m_iAmmoRockets);
ROLL_BACK(m_iAmmoNails);
ROLL_BACK(m_iAmmoCells);
ROLL_BACK(m_iAmmoShells);
ROLL_BACK(m_iAmmoDetpack);
ROLL_BACK(m_iAmmoMedikit);
ROLL_BACK(mode_tempstate);
}
#else
void
player::EvaluateEntity(void)
{
/* the generic client attributes */
base_player::EvaluateEntity();
/* animation */
if (ATTR_CHANGED(anim_bottom) || ATTR_CHANGED(anim_bottom_time))
SendFlags |= PLAYER_BOTTOMFRAME;
if (ATTR_CHANGED(anim_top) || ATTR_CHANGED(anim_top_time) || ATTR_CHANGED(anim_top_delay))
SendFlags |= PLAYER_TOPFRAME;
/* ammo 1 type updates */
if (ATTR_CHANGED(mag_sbs))
SendFlags |= PLAYER_AMMO1;
else if (ATTR_CHANGED(mag_dbs))
SendFlags |= PLAYER_AMMO1;
else if (ATTR_CHANGED(mag_rpg))
SendFlags |= PLAYER_AMMO1;
/* ammo 2 type updates */
if (ATTR_CHANGED(m_iAmmoRockets))
SendFlags |= PLAYER_AMMO2;
else if (ATTR_CHANGED(m_iAmmoNails))
SendFlags |= PLAYER_AMMO2;
else if (ATTR_CHANGED(m_iAmmoCells))
SendFlags |= PLAYER_AMMO2;
else if (ATTR_CHANGED(m_iAmmoShells))
SendFlags |= PLAYER_AMMO2;
else if (ATTR_CHANGED(m_iAmmoDetpack))
SendFlags |= PLAYER_AMMO2;
else if (ATTR_CHANGED(m_iAmmoMedikit))
SendFlags |= PLAYER_AMMO2;
if (ATTR_CHANGED(mode_tempstate))
SendFlags |= PLAYER_AMMO3;
SAVE_STATE(mag_sbs);
SAVE_STATE(mag_dbs);
SAVE_STATE(mag_rpg);
SAVE_STATE(m_iAmmoRockets);
SAVE_STATE(m_iAmmoNails);
SAVE_STATE(m_iAmmoCells);
SAVE_STATE(m_iAmmoShells);
SAVE_STATE(m_iAmmoDetpack);
SAVE_STATE(m_iAmmoMedikit);
SAVE_STATE(mode_tempstate);
SAVE_STATE(anim_top);
SAVE_STATE(anim_top_delay);
SAVE_STATE(anim_top_time);
SAVE_STATE(anim_bottom);
SAVE_STATE(anim_bottom_time);
}
/*
=================
player::SendEntity
=================
*/
float
player::SendEntity(entity ePEnt, float fChanged)
{
/* remove our entity to other clients if we're dead */
if (health <= 0 && ePEnt != this) {
return (0);
}
/* target client isn't real, they have no client-side. abandon */
if (clienttype(ePEnt) != CLIENTTYPE_REAL) {
return (0);
}
/* other players don't need to know about these attributes */
if (ePEnt != self) {
fChanged &= ~PLAYER_ITEMS;
fChanged &= ~PLAYER_HEALTH;
fChanged &= ~PLAYER_ARMOR;
fChanged &= ~PLAYER_VIEWOFS;
fChanged &= ~PLAYER_AMMO1;
fChanged &= ~PLAYER_AMMO2;
fChanged &= ~PLAYER_AMMO3;
}
WriteByte(MSG_ENTITY, ENT_PLAYER);
WriteFloat(MSG_ENTITY, fChanged);
/* the generic client attributes */
base_player::SendEntity(ePEnt, fChanged);
if (fChanged & PLAYER_TOPFRAME) {
WriteByte(MSG_ENTITY, anim_top);
WriteFloat(MSG_ENTITY, anim_top_time);
WriteFloat(MSG_ENTITY, anim_top_delay);
}
if (fChanged & PLAYER_BOTTOMFRAME) {
WriteByte(MSG_ENTITY, anim_bottom);
WriteFloat(MSG_ENTITY, anim_bottom_time);
}
if (fChanged & PLAYER_AMMO1) {
WriteByte(MSG_ENTITY, mag_sbs);
WriteByte(MSG_ENTITY, mag_dbs);
WriteByte(MSG_ENTITY, mag_rpg);
}
if (fChanged & PLAYER_AMMO2) {
WriteByte(MSG_ENTITY, m_iAmmoRockets);
WriteByte(MSG_ENTITY, m_iAmmoNails);
WriteByte(MSG_ENTITY, m_iAmmoCells);
WriteByte(MSG_ENTITY, m_iAmmoShells);
WriteByte(MSG_ENTITY, m_iAmmoDetpack);
WriteByte(MSG_ENTITY, m_iAmmoMedikit);
}
if (fChanged & PLAYER_AMMO3) {
WriteByte(MSG_ENTITY, mode_tempstate);
}
return (1);
}
#endif

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
* Copyright (c) 2016-2021 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -14,6 +14,15 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*QUAKED weapon_crowbar (0 0 1) (-16 -16 0) (16 16 32)
"model" "models/w_crowbar.mdl"
HALF-LIFE (1998) ENTITY
Crowbar Weapon
*/
enum
{
CBAR_IDLE,
@ -30,23 +39,21 @@ enum
void
w_crowbar_precache(void)
{
precache_sound("weapons/cbar_miss1.wav");
precache_sound("weapons/cbar_hit1.wav");
precache_sound("weapons/cbar_hit2.wav");
precache_sound("weapons/cbar_hitbod1.wav");
precache_sound("weapons/cbar_hitbod2.wav");
precache_sound("weapons/cbar_hitbod3.wav");
precache_model("models/v_tfc_crowbar.mdl");
#ifdef SERVER
Sound_Precache("weapon_crowbar.hit");
Sound_Precache("weapon_crowbar.miss");
Sound_Precache("weapon_crowbar.hitbody");
precache_model("models/w_crowbar.mdl");
#else
precache_model("models/v_crowbar.mdl");
precache_model("models/p_crowbar.mdl");
#endif
}
void
w_crowbar_updateammo(player pl)
{
#ifdef SERVER
Weapons_UpdateAmmo(pl, __NULL__, __NULL__, __NULL__);
#endif
}
string
@ -69,7 +76,7 @@ w_crowbar_deathmsg(void)
void
w_crowbar_draw(void)
{
Weapons_SetModel("models/v_tfc_crowbar.mdl");
Weapons_SetModel("models/v_crowbar.mdl");
Weapons_ViewAnimation(CBAR_DRAW);
}
@ -92,37 +99,39 @@ w_crowbar_primary(void)
Weapons_MakeVectors();
src = pl.origin + pl.view_ofs;
traceline(src, src + (v_forward * 32), FALSE, pl);
int r = (float)input_sequence % 3;
switch (r) {
case 0:
anim = trace_fraction >= 1 ? CBAR_ATTACK1MISS:CBAR_ATTACK1HIT;
break;
case 1:
anim = trace_fraction >= 1 ? CBAR_ATTACK2MISS:CBAR_ATTACK2HIT;
break;
default:
anim = trace_fraction >= 1 ? CBAR_ATTACK3MISS:CBAR_ATTACK3HIT;
}
Weapons_ViewAnimation(anim);
/* make sure we can gib corpses */
int oldhitcontents = self.hitcontentsmaski;
self.hitcontentsmaski = CONTENTBITS_POINTSOLID | CONTENTBIT_CORPSE;
traceline(src, src + (v_forward * 32), FALSE, pl);
self.hitcontentsmaski = oldhitcontents;
if (trace_fraction >= 1.0) {
pl.w_attack_next = 0.5f;
} else {
pl.w_attack_next = 0.25f;
}
pl.w_idle_next = 2.5f;
#ifdef SERVER
if (pl.flags & FL_CROUCHING) {
Animation_PlayerTop(pl, ANIM_SHOOTCROWBAR, 0.5f);
} else {
Animation_PlayerTop(pl, ANIM_CR_SHOOTCROWBAR, 0.42f);
int r = (float)input_sequence % 3;
switch (r) {
case 0:
Weapons_ViewAnimation(trace_fraction >= 1 ? CBAR_ATTACK1MISS:CBAR_ATTACK1HIT);
break;
case 1:
Weapons_ViewAnimation(trace_fraction >= 1 ? CBAR_ATTACK2MISS:CBAR_ATTACK2HIT);
break;
default:
Weapons_ViewAnimation(trace_fraction >= 1 ? CBAR_ATTACK3MISS:CBAR_ATTACK3HIT);
}
sound(pl, CHAN_WEAPON, "weapons/cbar_miss1.wav", 1, ATTN_NORM);
if (self.flags & FL_CROUCHING)
Animation_PlayerTop(pl, ANIM_CR_SHOOTCROWBAR, 0.41f);
else
Animation_PlayerTop(pl, ANIM_SHOOTCROWBAR, 0.5f);
#ifdef SERVER
Sound_Play(self, CHAN_WEAPON, "weapon_crowbar.miss");
if (trace_fraction >= 1.0) {
return;
@ -136,25 +145,12 @@ w_crowbar_primary(void)
}
if (trace_ent.takedamage) {
Damage_Apply(trace_ent, self, 10, WEAPON_CROWBAR, DMG_BLUNT);
if (!trace_ent.iBleeds) {
return;
}
if (random() < 0.33) {
sound(pl, 8, "weapons/cbar_hitbod1.wav", 1, ATTN_NORM);
} else if (random() < 0.66) {
sound(pl, 8, "weapons/cbar_hitbod2.wav", 1, ATTN_NORM);
} else {
sound(pl, 8, "weapons/cbar_hitbod3.wav", 1, ATTN_NORM);
Damage_Apply(trace_ent, pl, Skill_GetValue("plr_crowbar", 10), WEAPON_CROWBAR, DMG_BLUNT);
if (trace_ent.iBleeds) {
Sound_Play(self, CHAN_WEAPON, "weapon_crowbar.hitbody");
}
} else {
if (random() < 0.5) {
sound(pl, 8, "weapons/cbar_hit1.wav", 1, ATTN_NORM);
} else {
sound(pl, 8, "weapons/cbar_hit2.wav", 1, ATTN_NORM);
}
Sound_Play(self, CHAN_WEAPON, "weapon_crowbar.hit");
}
#endif
}
@ -186,7 +182,7 @@ w_crowbar_hudpic(int selected, vector pos, float a)
drawsubpic(
pos,
[170,45],
"sprites/640hud4.spr_0.tga",
g_hud4_spr,
[0,0],
[170/256,45/256],
g_hud_color,
@ -197,7 +193,7 @@ w_crowbar_hudpic(int selected, vector pos, float a)
drawsubpic(
pos,
[170,45],
"sprites/640hud1.spr_0.tga",
g_hud1_spr,
[0,0],
[170/256,45/256],
g_hud_color,
@ -214,6 +210,7 @@ weapon_t w_crowbar =
.id = ITEM_CROWBAR,
.slot = 0,
.slot_pos = 0,
.weight = 0,
.draw = w_crowbar_draw,
.holster = w_crowbar_holster,
.primary = w_crowbar_primary,

View file

@ -28,14 +28,6 @@ enum
DBS_IDLE3
};
enum
{
DBS_IDLE,
DBS_RELOAD_START,
DBS_RELOAD,
DBS_RELOAD_END
};
void
w_dbs_precache(void)
{
@ -51,9 +43,7 @@ w_dbs_precache(void)
void
w_dbs_updateammo(player pl)
{
#ifdef SERVER
Weapons_UpdateAmmo(pl, pl.shotgun_mag, pl.ammo_shells, __NULL__);
#endif
Weapons_UpdateAmmo(pl, pl.mag_dbs, pl.m_iAmmoShells, __NULL__);
}
string
@ -79,7 +69,7 @@ w_dbs_pickup(int new, int startammo)
{
#ifdef SERVER
player pl = (player)self;
pl.shotgun_mag = bound(0, pl.shotgun_mag + 8, 8);
pl.mag_dbs = bound(0, pl.mag_dbs + 16, 16);
#endif
return (1);
}
@ -89,10 +79,6 @@ w_dbs_draw(void)
{
Weapons_SetModel("models/v_tfc_shotgun.mdl");
Weapons_ViewAnimation(DBS_DRAW);
#ifdef SERVER
player pl = (player)self;
Weapons_UpdateAmmo(pl, pl.shotgun_mag, pl.ammo_shells, __NULL__);
#endif
}
void
@ -104,125 +90,79 @@ w_dbs_holster(void)
void
w_dbs_primary(void)
{
int s;
player pl = (player)self;
if (pl.w_attack_next) {
if (pl.mag_dbs != 1)
s = w_baseshotgun_fire(WEAPON_DBS, player::mag_dbs, 14, 4, [0.14, 0.08, 0]);
else
s = w_baseshotgun_fire(WEAPON_DBS, player::mag_dbs, 6, 4, [0.14, 0.08, 0]);
switch (s) {
case AUTO_FIRE_FAILED:
return;
break;
case AUTO_FIRED:
pl.mag_dbs--;
Weapons_ViewAnimation(DBS_FIRE1);
Weapons_ViewPunchAngle([-2,0,0]);
//Weapons_Sound(pl, CHAN_WEAPON, "weapon_mossberg.fire");
pl.w_attack_next = 0.7f;
break;
case AUTO_LAST:
Weapons_ViewAnimation(DBS_FIRE1);
Weapons_ViewPunchAngle([-2,0,0]);
//Weapons_Sound(pl, CHAN_WEAPON, "weapon_mossberg.fire");
pl.w_attack_next = 0.7f;
break;
case AUTO_EMPTY:
//Weapons_Sound(pl, CHAN_WEAPON, "weapon_mossberg.fire_empty");
pl.w_attack_next = 0.2f;
break;
}
if (pl.a_ammo3 > DBS_IDLE) {
return;
}
/* Ammo check */
#ifdef SERVER
if (pl.shotgun_mag <= 0) {
return;
}
#else
if (pl.a_ammo1 <= 0) {
return;
}
#endif
#ifdef SERVER
TraceAttack_FireBullets(4, pl.origin + pl.view_ofs, 14, [0.17365,0.04362], WEAPON_DBS);
sound(pl, CHAN_WEAPON, "weapons/sbarrel1.wav", 1, ATTN_NORM);
pl.shotgun_mag--;
Weapons_UpdateAmmo(pl, pl.shotgun_mag, pl.ammo_shells, __NULL__);
#else
View_SetMuzzleflash(MUZZLE_WEIRD);
Weapons_ViewPunchAngle([-5,0,0]);
pl.a_ammo1--;
#endif
Weapons_ViewAnimation(DBS_FIRE1);
pl.w_attack_next = 0.75;
pl.w_idle_next = 2.5f;
pl.w_idle_next = 1.5f;
}
void
w_dbs_reload(void)
{
player pl = (player)self;
#ifdef CLIENT
if (pl.a_ammo1 >= 8) {
return;
}
if (pl.a_ammo2 <= 0) {
return;
}
#else
if (pl.shotgun_mag >= 8) {
return;
}
if (pl.ammo_shells <= 0) {
return;
}
#endif
if (pl.a_ammo3 > DBS_IDLE) {
return;
}
pl.a_ammo3 = DBS_RELOAD_START;
pl.w_idle_next = 0.0f;
w_baseshotgun_reload(player::mag_dbs, player::m_iAmmoShells, 16);
}
void
w_dbs_release(void)
{
player pl = (player)self;
int s = w_baseshotgun_release(player::mag_dbs, player::m_iAmmoShells, 16);
if (pl.w_idle_next > 0.0) {
return;
}
if (pl.a_ammo3 == DBS_IDLE) {
int r = floor(random(0,3));
switch (r) {
case 0:
switch (s) {
case SHOTGUN_IDLE:
int r = (float)input_sequence % 3;
if (r == 1) {
Weapons_ViewAnimation(DBS_IDLE1);
break;
case 1:
} else if (r == 2) {
Weapons_ViewAnimation(DBS_IDLE2);
break;
case 2:
} else {
Weapons_ViewAnimation(DBS_IDLE3);
break;
}
pl.w_idle_next = 15.0f;
} else if (pl.a_ammo3 == DBS_RELOAD_START) {
pl.w_idle_next = 5.0f;
break;
case SHOTGUN_BUSY:
break;
case SHOTGUN_START_RELOAD:
Weapons_ViewAnimation(DBS_START_RELOAD);
pl.a_ammo3 = DBS_RELOAD;
pl.w_idle_next = 0.65f;
} else if (pl.a_ammo3 == DBS_RELOAD) {
break;
case SHOTGUN_RELOAD:
Weapons_ViewAnimation(DBS_ADDSHELL);
#ifdef CLIENT
pl.a_ammo1++;
pl.a_ammo2--;
if (pl.a_ammo2 <= 0 || pl.a_ammo1 >= 8) {
pl.a_ammo3 = DBS_RELOAD_END;
}
#else
pl.shotgun_mag++;
pl.ammo_shells--;
Weapons_UpdateAmmo(pl, pl.shotgun_mag, pl.ammo_shells, pl.a_ammo3);
sound(pl, CHAN_WEAPON, "weapons/reload3.wav", 1.0, ATTN_NORM);
if (pl.ammo_shells <= 0 || pl.shotgun_mag >= 8) {
pl.a_ammo3 = DBS_RELOAD_END;
}
#endif
pl.w_idle_next = 0.5f;
} else if (pl.a_ammo3 == DBS_RELOAD_END) {
break;
case SHOTGUN_END_RELOAD:
Weapons_ViewAnimation(DBS_PUMP);
#ifdef SERVER
sound(pl, CHAN_WEAPON, "weapons/scock1.wav", 1.0, ATTN_NORM);
#endif
pl.a_ammo3 = DBS_IDLE;
pl.w_idle_next = 10.0f;
pl.w_attack_next = 0.5f;
break;
}
}
void
w_dbs_crosshair(void)
{

View file

@ -14,20 +14,31 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
enum
{
NAILGUN_IDLE,
NAILGUN_FIDGET1,
NAILGUN_UNUSED1,
NAILGUN_UNUSED2,
NAILGUN_DEPLOY,
NAILGUN_SHOOT1,
NAILGUN_SHOOT2,
NAILGUN_SHOOT3,
};
void
w_nailgun_precache(void)
{
precache_model("models/v_tfc_nailgun.mdl");
precache_model("models/w_nailgun.mdl");
precache_model("models/p_nailgun.mdl");
precache_model("models/nail.mdl");
}
void
w_nailgun_updateammo(player pl)
{
#ifdef SERVER
Weapons_UpdateAmmo(pl, __NULL__, __NULL__, __NULL__);
#endif
Weapons_UpdateAmmo(pl, __NULL__, pl.m_iAmmoNails, __NULL__);
}
string
@ -51,7 +62,7 @@ void
w_nailgun_draw(void)
{
Weapons_SetModel("models/v_tfc_nailgun.mdl");
Weapons_ViewAnimation(0);
Weapons_ViewAnimation(NAILGUN_DEPLOY);
}
float
@ -60,6 +71,97 @@ w_nailgun_aimanim(void)
return self.flags & FL_CROUCHING ? ANIM_CR_AIMCROWBAR : ANIM_AIMCROWBAR;
}
void
w_nailgun_shootnail(void)
{
static void w_rpg_shootrocket_touch(void) {
remove(self);
}
Weapons_MakeVectors();
entity p = spawn();
setmodel(p, "models/nail.mdl");
setorigin(p, Weapons_GetCameraPos() + (v_forward * 8));
p.owner = self;
p.movetype = MOVETYPE_FLYMISSILE;
p.solid = SOLID_BBOX;
p.gravity = 0.5f;
p.velocity = (v_forward * 1000);
p.angles = vectoangles(p.velocity);
p.touch = w_rpg_shootrocket_touch;
p.think = Util_Destroy;
p.nextthink = time + 5.0f;
}
void
w_nailgun_primary(void)
{
player pl = (player)self;
int s = w_baseprojectile_fire(WEAPON_NAILGUN, player::m_iAmmoNails, w_nailgun_shootnail);
switch (s) {
case AUTO_FIRE_FAILED:
return;
break;
case AUTO_FIRED:
case AUTO_LAST:
int r = (float)input_sequence % 3;
if (r == 1) {
Weapons_ViewAnimation(NAILGUN_SHOOT1);
} else if (r == 2) {
Weapons_ViewAnimation(NAILGUN_SHOOT2);
} else {
Weapons_ViewAnimation(NAILGUN_SHOOT3);
}
Weapons_ViewAnimation(NAILGUN_SHOOT2);
Weapons_ViewPunchAngle([-1,0,0]);
pl.w_attack_next = 0.1f;
break;
case AUTO_EMPTY:
pl.w_attack_next = 0.2f;
break;
}
pl.w_idle_next = 1.5f;
}
void
w_nailgun_hud(void)
{
#ifdef CLIENT
player pl = (player)self;
vector cross_pos;
vector aicon_pos;
/* crosshair/laser */
cross_pos = g_hudmins + (g_hudres / 2) + [-12,-12];
drawsubpic(
cross_pos,
[24,24],
g_cross_spr,
[0.1875,0],
[0.1875, 0.1875],
[1,1,1],
1.0f,
DRAWFLAG_NORMAL
);
HUD_DrawAmmo2();
aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42];
drawsubpic(
aicon_pos,
[24,24],
g_hud7_spr,
[0,72/128],
[24/256, 24/128],
g_hud_color,
pSeatLocal->m_flAmmo2Alpha,
DRAWFLAG_ADDITIVE
);
#endif
}
void
w_nailgun_hudpic(int selected, vector pos, float a)
{
@ -98,11 +200,11 @@ weapon_t w_nailgun =
.slot_pos = 0,
.draw = w_nailgun_draw,
.holster = __NULL__,
.primary = __NULL__,
.primary = w_nailgun_primary,
.secondary = __NULL__,
.reload = __NULL__,
.release = __NULL__,
.crosshair = __NULL__,
.crosshair = w_nailgun_hud,
.precache = w_nailgun_precache,
.pickup = __NULL__,
.updateammo = w_nailgun_updateammo,

View file

@ -14,20 +14,47 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define TFC_RPG_ROCKET_SPEED 900.0f
enum
{
RPG_IDLE1,
RPG_FIDGET1,
RPG_FIRE,
RPG_HOLSTER1,
RPG_DRAW1,
RPG_HOLSTER2,
RPG_DRAW2,
RPG_RELOAD_START,
RPG_RELOAD,
RPG_RELOAD_END,
RPG_IDLE2,
RPG_FIDGET2
};
void
w_rpg_precache(void)
{
precache_model("models/v_tfc_rpg.mdl");
precache_model("models/w_rpg.mdl");
precache_model("models/p_rpg.mdl");
precache_model("models/rpgrocket.mdl");
}
int
w_rpg_pickup(int new, int startammo)
{
#ifdef SERVER
player pl = (player)self;
pl.mag_rpg = bound(0, pl.mag_rpg + 4, 4);
#endif
return (1);
}
void
w_rpg_updateammo(player pl)
{
#ifdef SERVER
Weapons_UpdateAmmo(pl, __NULL__, __NULL__, __NULL__);
#endif
Weapons_UpdateAmmo(pl, pl.mag_rpg, pl.m_iAmmoRockets, __NULL__);
}
string
@ -35,6 +62,7 @@ w_rpg_wmodel(void)
{
return "models/w_rpg.mdl";
}
string
w_rpg_pmodel(void)
{
@ -54,12 +82,143 @@ w_rpg_draw(void)
Weapons_ViewAnimation(0);
}
void
w_rpg_shootrocket(void)
{
static void w_rpg_shootrocket_touch(void) {
FX_Explosion(self.origin);
remove(self);
}
Weapons_MakeVectors();
entity p = spawn();
setmodel(p, "models/rpgrocket.mdl");
setorigin(p, Weapons_GetCameraPos() + (v_forward * 8));
p.owner = self;
p.movetype = MOVETYPE_FLYMISSILE;
p.solid = SOLID_BBOX;
p.gravity = 0.5f;
p.velocity = (v_forward * TFC_RPG_ROCKET_SPEED);
p.angles = vectoangles(p.velocity);
p.touch = w_rpg_shootrocket_touch;
p.think = Util_Destroy;
p.nextthink = time + 5.0f;
}
void
w_rpg_primary(void)
{
player pl = (player)self;
int s = w_baseprojectile_fire(WEAPON_RPG, player::mag_rpg, w_rpg_shootrocket);
switch (s) {
case AUTO_FIRE_FAILED:
return;
break;
case AUTO_FIRED:
Weapons_ViewAnimation(RPG_FIRE);
Weapons_ViewPunchAngle([-2,0,0]);
pl.w_attack_next = 0.8f;
break;
case AUTO_LAST:
Weapons_ViewAnimation(RPG_FIRE);
Weapons_ViewPunchAngle([-2,0,0]);
pl.w_attack_next = 0.8f;
break;
case AUTO_EMPTY:
pl.w_attack_next = 0.2f;
break;
}
pl.w_idle_next = 1.5f;
}
void
w_rpg_reload(void)
{
player pl = (player)self;
w_baseshotgun_reload(player::mag_rpg, player::m_iAmmoRockets, 4);
}
void
w_rpg_release(void)
{
player pl = (player)self;
int s = w_baseshotgun_release(player::mag_rpg, player::m_iAmmoRockets, 4);
switch (s) {
case SHOTGUN_IDLE:
int r = (float)input_sequence % 3;
if (r == 1) {
Weapons_ViewAnimation(RPG_IDLE1);
} else if (r == 2) {
Weapons_ViewAnimation(RPG_FIDGET1);
} else {
Weapons_ViewAnimation(RPG_FIDGET2);
}
pl.w_idle_next = 5.0f;
break;
case SHOTGUN_BUSY:
break;
case SHOTGUN_START_RELOAD:
Weapons_ViewAnimation(RPG_RELOAD_START);
break;
case SHOTGUN_RELOAD:
Weapons_ViewAnimation(RPG_RELOAD);
break;
case SHOTGUN_END_RELOAD:
Weapons_ViewAnimation(RPG_RELOAD_END);
break;
}
}
float
w_rpg_aimanim(void)
{
return self.flags & FL_CROUCHING ? ANIM_CR_AIMCROWBAR : ANIM_AIMCROWBAR;
}
void
w_rpg_hud(void)
{
#ifdef CLIENT
player pl = (player)self;
vector cross_pos;
vector aicon_pos;
/* crosshair/laser */
cross_pos = g_hudmins + (g_hudres / 2) + [-12,-12];
drawsubpic(
cross_pos,
[24,24],
g_cross_spr,
[0,0],
[0.1875, 0.1875],
[1,1,1],
1,
DRAWFLAG_NORMAL
);
/* ammo counters */
HUD_DrawAmmo1();
HUD_DrawAmmo2();
/* ammo icon */
aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42];
drawsubpic(
aicon_pos,
[24,24],
"sprites/640hud7.spr_0.tga",
[120/256,72/128],
[24/256, 24/128],
g_hud_color,
pSeatLocal->m_flAmmo2Alpha,
DRAWFLAG_ADDITIVE
);
#endif
}
void
w_rpg_hudpic(int selected, vector pos, float a)
{
@ -80,13 +239,13 @@ weapon_t w_rpg =
.slot_pos = 0,
.draw = w_rpg_draw,
.holster = __NULL__,
.primary = __NULL__,
.primary = w_rpg_primary,
.secondary = __NULL__,
.reload = __NULL__,
.release = __NULL__,
.crosshair = __NULL__,
.reload = w_rpg_reload,
.release = w_rpg_release,
.crosshair = w_rpg_hud,
.precache = w_rpg_precache,
.pickup = __NULL__,
.pickup = w_rpg_pickup,
.updateammo = w_rpg_updateammo,
.wmodel = w_rpg_wmodel,
.pmodel = w_rpg_pmodel,

View file

@ -28,14 +28,6 @@ enum
SBS_IDLE3
};
enum
{
SBS_IDLE,
SBS_RELOAD_START,
SBS_RELOAD,
SBS_RELOAD_END
};
void
w_sbs_precache(void)
{
@ -52,9 +44,7 @@ w_sbs_precache(void)
void
w_sbs_updateammo(player pl)
{
#ifdef SERVER
Weapons_UpdateAmmo(pl, pl.shotgun_mag, pl.ammo_shells, __NULL__);
#endif
Weapons_UpdateAmmo(pl, pl.mag_sbs, pl.m_iAmmoShells, __NULL__);
}
string w_sbs_wmodel(void)
{
@ -74,7 +64,7 @@ w_sbs_pickup(int new, int startammo)
{
#ifdef SERVER
player pl = (player)self;
pl.shotgun_mag = bound(0, pl.shotgun_mag + 8, 8);
pl.mag_sbs = bound(0, pl.mag_sbs + 8, 8);
#endif
return (1);
}
@ -84,10 +74,6 @@ w_sbs_draw(void)
{
Weapons_SetModel("models/v_tfc_12gauge.mdl");
Weapons_ViewAnimation(SBS_DRAW);
#ifdef SERVER
player pl = (player)self;
Weapons_UpdateAmmo(pl, pl.shotgun_mag, pl.ammo_shells, __NULL__);
#endif
}
void
@ -100,124 +86,72 @@ void
w_sbs_primary(void)
{
player pl = (player)self;
if (pl.w_attack_next) {
int s = w_baseshotgun_fire(WEAPON_SBS, player::mag_sbs, 6, 4, [0.04, 0.04, 0]);
switch (s) {
case AUTO_FIRE_FAILED:
return;
break;
case AUTO_FIRED:
Weapons_ViewAnimation(SBS_FIRE1);
Weapons_ViewPunchAngle([-2,0,0]);
//Weapons_Sound(pl, CHAN_WEAPON, "weapon_mossberg.fire");
pl.w_attack_next = 0.5f;
break;
case AUTO_LAST:
Weapons_ViewAnimation(SBS_FIRE1);
Weapons_ViewPunchAngle([-2,0,0]);
//Weapons_Sound(pl, CHAN_WEAPON, "weapon_mossberg.fire");
pl.w_attack_next = 0.5f;
break;
case AUTO_EMPTY:
//Weapons_Sound(pl, CHAN_WEAPON, "weapon_mossberg.fire_empty");
pl.w_attack_next = 0.2f;
break;
}
if (pl.a_ammo3 > SBS_IDLE) {
return;
}
/* Ammo check */
#ifdef SERVER
if (pl.shotgun_mag <= 0) {
return;
}
#else
if (pl.a_ammo1 <= 0) {
return;
}
#endif
#ifdef SERVER
TraceAttack_FireBullets(4, pl.origin + pl.view_ofs, 6, [0.17365,0.04362], WEAPON_SBS);
Sound_Play(pl, CHAN_WEAPON, "weapon_sbs.fire");
pl.shotgun_mag--;
Weapons_UpdateAmmo(pl, pl.shotgun_mag, pl.ammo_shells, __NULL__);
#else
View_SetMuzzleflash(MUZZLE_WEIRD);
Weapons_ViewPunchAngle([-5,0,0]);
pl.a_ammo1--;
#endif
Weapons_ViewAnimation(SBS_FIRE1);
pl.w_attack_next = 0.75;
pl.w_idle_next = 2.5f;
pl.w_idle_next = 1.5f;
}
void
w_sbs_reload(void)
{
player pl = (player)self;
#ifdef CLIENT
if (pl.a_ammo1 >= 8) {
return;
}
if (pl.a_ammo2 <= 0) {
return;
}
#else
if (pl.shotgun_mag >= 8) {
return;
}
if (pl.ammo_shells <= 0) {
return;
}
#endif
if (pl.a_ammo3 > SBS_IDLE) {
return;
}
pl.a_ammo3 = SBS_RELOAD_START;
pl.w_idle_next = 0.0f;
w_baseshotgun_reload(player::mag_sbs, player::m_iAmmoShells, 8);
}
void
w_sbs_release(void)
{
player pl = (player)self;
int s = w_baseshotgun_release(player::mag_sbs, player::m_iAmmoShells, 8);
if (pl.w_idle_next > 0.0) {
return;
}
if (pl.a_ammo3 == SBS_IDLE) {
int r = floor(random(0,3));
switch (r) {
case 0:
switch (s) {
case SHOTGUN_IDLE:
int r = (float)input_sequence % 3;
if (r == 1) {
Weapons_ViewAnimation(SBS_IDLE1);
break;
case 1:
} else if (r == 2) {
Weapons_ViewAnimation(SBS_IDLE2);
break;
case 2:
} else {
Weapons_ViewAnimation(SBS_IDLE3);
break;
}
pl.w_idle_next = 15.0f;
} else if (pl.a_ammo3 == SBS_RELOAD_START) {
pl.w_idle_next = 5.0f;
break;
case SHOTGUN_BUSY:
break;
case SHOTGUN_START_RELOAD:
Weapons_ViewAnimation(SBS_START_RELOAD);
pl.a_ammo3 = SBS_RELOAD;
pl.w_idle_next = 0.65f;
} else if (pl.a_ammo3 == SBS_RELOAD) {
break;
case SHOTGUN_RELOAD:
Weapons_ViewAnimation(SBS_ADDSHELL);
#ifdef CLIENT
pl.a_ammo1++;
pl.a_ammo2--;
if (pl.a_ammo2 <= 0 || pl.a_ammo1 >= 8) {
pl.a_ammo3 = SBS_RELOAD_END;
}
#else
pl.shotgun_mag++;
pl.ammo_shells--;
Weapons_UpdateAmmo(pl, pl.shotgun_mag, pl.ammo_shells, pl.a_ammo3);
Sound_Play(pl, CHAN_WEAPON, "weapon_sbs.reload");
if (pl.ammo_shells <= 0 || pl.shotgun_mag >= 8) {
pl.a_ammo3 = SBS_RELOAD_END;
}
#endif
pl.w_idle_next = 0.5f;
} else if (pl.a_ammo3 == SBS_RELOAD_END) {
break;
case SHOTGUN_END_RELOAD:
Weapons_ViewAnimation(SBS_PUMP);
#ifdef SERVER
Sound_Play(pl, CHAN_WEAPON, "weapon_sbs.cock");
#endif
pl.a_ammo3 = SBS_IDLE;
pl.w_idle_next = 10.0f;
pl.w_attack_next = 0.5f;
break;
}
}
void
w_sbs_crosshair(void)
{