mirror of
https://github.com/UberGames/EF2GameSource.git
synced 2024-11-10 06:31:42 +00:00
6018 lines
130 KiB
C++
6018 lines
130 KiB
C++
//-----------------------------------------------------------------------------
|
|
//
|
|
// $Logfile:: /Code/DLLs/game/weapon.cpp $
|
|
// $Revision:: 263 $
|
|
// $Author:: Steven $
|
|
// $Date:: 10/13/03 9:43a $
|
|
//
|
|
// Copyright (C) 1997 by Ritual Entertainment, Inc.
|
|
// All rights reserved.
|
|
//
|
|
// This source is may not be distributed and/or modified without
|
|
// expressly written permission by Ritual Entertainment, Inc.
|
|
//
|
|
//
|
|
// DESCRIPTION:
|
|
// Source file for Weapon class. The weapon class is the base class for
|
|
// all weapons in the game. Any entity created from a class derived from the weapon
|
|
// class will be usable by any Sentient (players and monsters) as a weapon.
|
|
//
|
|
|
|
#include "_pch_cpp.h"
|
|
#include "entity.h"
|
|
#include "item.h"
|
|
#include "weapon.h"
|
|
#include "scriptmaster.h"
|
|
#include "sentient.h"
|
|
#include "misc.h"
|
|
#include "specialfx.h"
|
|
#include "actor.h"
|
|
#include "weaputils.h"
|
|
#include "player.h"
|
|
#include "decals.h"
|
|
#include "mp_manager.hpp"
|
|
#include <qcommon/gameplaymanager.h>
|
|
|
|
// for bot code
|
|
#include "g_local.h"
|
|
#include "botlib.h"
|
|
#include "be_aas.h"
|
|
#include "be_ea.h"
|
|
#include "be_ai_char.h"
|
|
#include "be_ai_chat.h"
|
|
#include "be_ai_gen.h"
|
|
#include "be_ai_goal.h"
|
|
#include "be_ai_move.h"
|
|
#include "be_ai_weap.h"
|
|
#include "ai_main.h"
|
|
extern bot_state_t *botstates[MAX_CLIENTS];
|
|
|
|
#define TargetIdleTime 0.2
|
|
|
|
Event EV_Weapon_Shoot
|
|
(
|
|
"shoot",
|
|
EV_DEFAULT,
|
|
"S",
|
|
"mode",
|
|
"Shoot the weapon"
|
|
);
|
|
Event EV_Weapon_DoneRaising
|
|
(
|
|
"ready",
|
|
EV_TIKIONLY,
|
|
NULL,
|
|
NULL,
|
|
"Signals the end of the ready animation so the weapon can be used"
|
|
);
|
|
Event EV_Weapon_DoneAnimating
|
|
(
|
|
"weapon_done_animate",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Signals the end of the ready animation so the weapon can be used"
|
|
);
|
|
Event EV_Weapon_DoneFiring
|
|
(
|
|
"donefiring",
|
|
EV_TIKIONLY,
|
|
NULL,
|
|
NULL,
|
|
"Signals the end of the fire animation"
|
|
);
|
|
Event EV_Weapon_Idle
|
|
(
|
|
"idle",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Puts the weapon into an idle state"
|
|
);
|
|
Event EV_Weapon_SecondaryUse
|
|
(
|
|
"secondaryuse",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Puts the weapon into its secondary mode of operation"
|
|
);
|
|
Event EV_Weapon_DoneReloading
|
|
(
|
|
"donereloading",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Signals the end of the reload animation"
|
|
);
|
|
Event EV_Weapon_DoneReloadingBurst
|
|
(
|
|
"doneReloadingBurst",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Signals the end of the reload animation for a burst"
|
|
);
|
|
Event EV_Weapon_SetAmmoClipSize
|
|
(
|
|
"clipsize",
|
|
EV_TIKIONLY,
|
|
"i",
|
|
"ammoClipSize",
|
|
"Set the amount of rounds a clip of the weapon holds"
|
|
);
|
|
Event EV_Weapon_SetAmmoInClip
|
|
(
|
|
"ammo_in_clip",
|
|
EV_TIKIONLY,
|
|
"i",
|
|
"ammoInClip",
|
|
"Set the amount of ammo in the clip"
|
|
);
|
|
Event EV_Weapon_ProcessModelCommands
|
|
(
|
|
"process_mdl_cmds",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Forces a processing of the init commands for the model"
|
|
);
|
|
Event EV_Weapon_SetMaxRange
|
|
(
|
|
"maxrange",
|
|
EV_TIKIONLY,
|
|
"f",
|
|
"maxRange",
|
|
"Set the maximum range of a weapon so the AI knows how to use it"
|
|
);
|
|
Event EV_Weapon_SetMinRange
|
|
(
|
|
"minrange",
|
|
EV_TIKIONLY,
|
|
"f",
|
|
"minRange",
|
|
"Set the minimum range of a weapon so the AI knows how to use it"
|
|
);
|
|
Event EV_Weapon_ActionIncrement
|
|
(
|
|
"actionincrement",
|
|
EV_TIKIONLY,
|
|
"i",
|
|
"actionLevelIncrement",
|
|
"Set the action level increment of the weapon.\n"
|
|
"When the weapon is fired, it will raise the action level by this amount"
|
|
);
|
|
Event EV_Weapon_NotDroppable
|
|
(
|
|
"notdroppable",
|
|
EV_TIKIONLY,
|
|
NULL,
|
|
NULL,
|
|
"Makes a weapon not droppable"
|
|
);
|
|
Event EV_Weapon_SetAimAnim
|
|
(
|
|
"setaimanim",
|
|
EV_TIKIONLY,
|
|
"si",
|
|
"aimAnimation aimFrame",
|
|
"Set the aim animation and frame for when a weapon fires"
|
|
);
|
|
Event EV_Weapon_SetFireType
|
|
(
|
|
"firetype",
|
|
EV_TIKIONLY,
|
|
"s",
|
|
"firingType",
|
|
"Set the firing type of the weapon (projectile or bullet)"
|
|
);
|
|
Event EV_Weapon_SetProjectile
|
|
(
|
|
"projectile",
|
|
EV_TIKIONLY,
|
|
"s",
|
|
"projectileModel",
|
|
"Set the model of the projectile that this weapon fires"
|
|
);
|
|
Event EV_Weapon_SetBulletDamage
|
|
(
|
|
"bulletdamage",
|
|
EV_TIKIONLY,
|
|
"f",
|
|
"bulletDamage",
|
|
"Set the damage that the bullet causes"
|
|
);
|
|
Event EV_Weapon_SetBulletKnockback
|
|
(
|
|
"bulletknockback",
|
|
EV_TIKIONLY,
|
|
"f",
|
|
"bulletKnockback",
|
|
"Set the knockback that the bullet causes"
|
|
);
|
|
Event EV_Weapon_SetBulletCount
|
|
(
|
|
"bulletcount",
|
|
EV_TIKIONLY,
|
|
"f",
|
|
"bulletCount",
|
|
"Set the number of bullets this weapon shoots when fired"
|
|
);
|
|
Event EV_Weapon_SetBulletRange
|
|
(
|
|
"bulletrange",
|
|
EV_TIKIONLY,
|
|
"f",
|
|
"bulletRange",
|
|
"Set the range of the bullets"
|
|
);
|
|
Event EV_Weapon_SetBulletSpread
|
|
(
|
|
"bulletspread",
|
|
EV_TIKIONLY,
|
|
"ffFFF",
|
|
"bulletSpreadX bulletSpreadY endSpreadX endSpreadY spreadTime",
|
|
"Set the max spread of the bullet in the x and y axis, optionally with a different end spread and time interval"
|
|
);
|
|
Event EV_Weapon_SetRange
|
|
(
|
|
"range",
|
|
EV_TIKIONLY,
|
|
"f",
|
|
"range",
|
|
"Set the range of the weapon"
|
|
);
|
|
Event EV_Weapon_Hand
|
|
(
|
|
"hand",
|
|
EV_TIKIONLY,
|
|
"s",
|
|
"weaponHand",
|
|
"Set the hand the weapon can be wielded in (lefthand, righthand, both, or any)"
|
|
);
|
|
Event EV_Weapon_Mode
|
|
(
|
|
"modeset",
|
|
EV_TIKIONLY,
|
|
"SSSSSSSSS",
|
|
"arg1 arg2 arg3 arg4 arg5 arg6 arg7 arg8 arg9",
|
|
"Set a value for a mode by passing commands through"
|
|
);
|
|
Event EV_Weapon_AmmoType
|
|
(
|
|
"ammotype",
|
|
EV_TIKIONLY,
|
|
"s",
|
|
"name",
|
|
"Set the type of ammo this weapon uses"
|
|
);
|
|
Event EV_Weapon_StartAmmo
|
|
(
|
|
"startammo",
|
|
EV_TIKIONLY,
|
|
"i",
|
|
"amount",
|
|
"Set the starting ammo of this weapon"
|
|
);
|
|
Event EV_Weapon_AmmoBoost
|
|
(
|
|
"ammoBoost",
|
|
EV_TIKIONLY,
|
|
"i",
|
|
"amount",
|
|
"Set the ammo given to a sentient that picks up this weapon but already had a weapon of this type."
|
|
);
|
|
Event EV_Weapon_AmmoRequired
|
|
(
|
|
"ammorequired",
|
|
EV_TIKIONLY,
|
|
"i",
|
|
"amount",
|
|
"Set the amount of ammo this weapon requires to fire"
|
|
);
|
|
Event EV_Weapon_MaxChargeTime
|
|
(
|
|
"maxchargetime",
|
|
EV_TIKIONLY,
|
|
"i",
|
|
"time",
|
|
"Set the maximum time the weapon may be charged up"
|
|
);
|
|
Event EV_Weapon_GiveStartingAmmo
|
|
(
|
|
"startingammotoowner",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Internal event used to give ammo to the owner of the weapon"
|
|
);
|
|
Event EV_Weapon_GiveAmmoBoost
|
|
(
|
|
"giveAmmoBoost",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Internal event used to give ammo boost to the player that just picked up this weapon."
|
|
);
|
|
Event EV_Weapon_AutoAim
|
|
(
|
|
"autoaim",
|
|
EV_TIKIONLY,
|
|
"FF",
|
|
"selection_angle lockon_angle",
|
|
"Turn on auto aiming for the weapon"
|
|
);
|
|
Event EV_Weapon_Crosshair
|
|
(
|
|
"crosshair",
|
|
EV_TIKIONLY,
|
|
"b",
|
|
"bool",
|
|
"Turn on/off the crosshair for this weapon"
|
|
);
|
|
Event EV_Weapon_TorsoAim
|
|
(
|
|
"torsoaim",
|
|
EV_DEFAULT,
|
|
"b",
|
|
"bool",
|
|
"Turn on/off the torsoaim for this weapon"
|
|
);
|
|
Event EV_Weapon_SetQuiet
|
|
(
|
|
"quiet",
|
|
EV_TIKIONLY,
|
|
NULL,
|
|
NULL,
|
|
"Makes the weapon make no noise."
|
|
);
|
|
Event EV_Weapon_SetLoopFire
|
|
(
|
|
"loopfire",
|
|
EV_TIKIONLY,
|
|
NULL,
|
|
NULL,
|
|
"Makes the weapon fire by looping the fire animation."
|
|
);
|
|
/*
|
|
Event EV_Weapon_FullAnimFire
|
|
(
|
|
"fullanimfire",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Makes the weapon play the full fire animation even if key is released"
|
|
);
|
|
*/
|
|
Event EV_Weapon_LeftAttachToTag
|
|
(
|
|
"leftattachtotag",
|
|
EV_TIKIONLY,
|
|
"s",
|
|
"tagname",
|
|
"Set the name of the tag to attach this to it's owner when wielded in the left hand."
|
|
);
|
|
Event EV_Weapon_RightAttachToTag
|
|
(
|
|
"rightattachtotag",
|
|
EV_TIKIONLY,
|
|
"s",
|
|
"tagname",
|
|
"Set the name of the tag to attach this to it's owner when wielded in the right hand."
|
|
);
|
|
Event EV_Weapon_DualAttachToTag
|
|
(
|
|
"dualattachtotag",
|
|
EV_TIKIONLY,
|
|
"s",
|
|
"tagname",
|
|
"Set the name of the tag to attach this to it's owner when wielded dual handed."
|
|
);
|
|
Event EV_Weapon_HolsterTagLeft
|
|
(
|
|
"leftholstertag",
|
|
EV_TIKIONLY,
|
|
"s",
|
|
"tagname",
|
|
"Set the name of the tag to attach this to when the weapon is put away from the left hand."
|
|
);
|
|
Event EV_Weapon_HolsterTagRight
|
|
(
|
|
"rightholstertag",
|
|
EV_TIKIONLY,
|
|
"s",
|
|
"tagname",
|
|
"Set the name of the tag to attach this to when the weapon is put away from the right hand."
|
|
);
|
|
Event EV_Weapon_HolsterTagDual
|
|
(
|
|
"dualholstertag",
|
|
EV_TIKIONLY,
|
|
"s",
|
|
"tagname",
|
|
"Set the name of the tag to attach this to when the weapon is put away from dual handed"
|
|
);
|
|
Event EV_Weapon_LeftHolsterAngles
|
|
(
|
|
"leftholsterangles",
|
|
EV_TIKIONLY,
|
|
"v",
|
|
"angles",
|
|
"Set the angles of this weapon when it's attached to the left holster"
|
|
);
|
|
Event EV_Weapon_RightHolsterAngles
|
|
(
|
|
"rightholsterangles",
|
|
EV_TIKIONLY,
|
|
"v",
|
|
"angles",
|
|
"Set the angles of this weapon when it's attached to the right holster"
|
|
);
|
|
Event EV_Weapon_DualHolsterAngles
|
|
(
|
|
"dualholsterangles",
|
|
EV_TIKIONLY,
|
|
"v",
|
|
"angles",
|
|
"Set the angles of this weapon when it's attached to the dual holster"
|
|
);
|
|
Event EV_Weapon_HolsterScale
|
|
(
|
|
"holsterscale",
|
|
EV_TIKIONLY,
|
|
"f",
|
|
"scale",
|
|
"Set the scale of the weapon when it's attached to the holster"
|
|
);
|
|
Event EV_Weapon_WeildedScale
|
|
(
|
|
"weildedScale",
|
|
EV_TIKIONLY,
|
|
"f",
|
|
"scale",
|
|
"Sets the scale of the weapon when it's weilded"
|
|
);
|
|
Event EV_Weapon_AutoPutaway
|
|
(
|
|
"autoputaway",
|
|
EV_TIKIONLY,
|
|
"b",
|
|
"bool",
|
|
"Set the weapon to be automatically put away when out of ammo"
|
|
);
|
|
Event EV_Weapon_UseNoAmmo
|
|
(
|
|
"usenoammo",
|
|
EV_TIKIONLY,
|
|
"b",
|
|
"bool",
|
|
"Set the weapon to be able to be used when it's out of ammo"
|
|
);
|
|
Event EV_Weapon_SetMeansOfDeath
|
|
(
|
|
"meansofdeath",
|
|
EV_TIKIONLY,
|
|
"s",
|
|
"meansOfDeath",
|
|
"Set the meansOfDeath of the weapon."
|
|
);
|
|
Event EV_Weapon_SetWorldHitSpawn
|
|
(
|
|
"worldhitspawn",
|
|
EV_TIKIONLY,
|
|
"s",
|
|
"modelname",
|
|
"Set a model to be spawned when the weapon strikes the world."
|
|
);
|
|
Event EV_Weapon_MakeNoise
|
|
(
|
|
"makenoise",
|
|
EV_TIKIONLY,
|
|
"FB",
|
|
"noise_radius force",
|
|
"Makes the weapon make noise that actors can hear."
|
|
);
|
|
Event EV_Weapon_SetViewModel
|
|
(
|
|
"weaponviewmodel",
|
|
EV_TIKIONLY,
|
|
"s",
|
|
"filename",
|
|
"Set the view model name"
|
|
);
|
|
Event EV_Weapon_DonePutaway
|
|
(
|
|
"doneputaway",
|
|
EV_TIKIONLY,
|
|
NULL,
|
|
NULL,
|
|
"Called when the weapon is done with it's putaway anim"
|
|
);
|
|
Event EV_Weapon_SetRegenAmmo
|
|
(
|
|
"regenammo",
|
|
EV_TIKIONLY,
|
|
"ii",
|
|
"regenamount regentime",
|
|
"Specifics that a weapon regenerates ammo over time"
|
|
);
|
|
Event EV_Weapon_SetRegenOnlyWhenIdle
|
|
(
|
|
"regenonlywhenidle",
|
|
EV_TIKIONLY,
|
|
NULL,
|
|
NULL,
|
|
"Specifics that the weapon only regenerates ammo when idle, must still use regen ammo to set how much."
|
|
);
|
|
Event EV_Weapon_ChangeIdle
|
|
(
|
|
"changeidle",
|
|
EV_TIKIONLY,
|
|
NULL,
|
|
NULL,
|
|
"Changes the idle animation"
|
|
);
|
|
Event EV_Weapon_DrawBowStrain
|
|
(
|
|
"drawbowstrain",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Starts the bow draw strain animation"
|
|
);
|
|
Event EV_Weapon_AltDrawBowStrain
|
|
(
|
|
"altdrawbowstrain",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Starts the alternate bow draw strain animation"
|
|
);
|
|
Event EV_Weapon_SetAccuracy
|
|
(
|
|
"setaccuracy",
|
|
EV_TIKIONLY,
|
|
"sfffff",
|
|
"firemode stoppedac acchange walkac runac crouchac",
|
|
"Sets the accuracy of the weapon"
|
|
);
|
|
Event EV_Weapon_SetReticuleTime
|
|
(
|
|
"setreticuletime",
|
|
EV_TIKIONLY,
|
|
"f",
|
|
"reticuletime",
|
|
"Reticule time"
|
|
);
|
|
Event EV_Weapon_SetZoomFOV
|
|
(
|
|
"setzoomfov",
|
|
EV_TIKIONLY,
|
|
"f",
|
|
"zoomfov",
|
|
"Zoom FOV"
|
|
);
|
|
Event EV_Weapon_IncrementZoomFOV
|
|
(
|
|
"inczoomfov",
|
|
EV_TIKIONLY,
|
|
NULL,
|
|
NULL,
|
|
"Increments the zoom fov"
|
|
);
|
|
Event EV_Weapon_SetZoomStage
|
|
(
|
|
"setzoomstage",
|
|
EV_TIKIONLY,
|
|
"ff",
|
|
"fov1 fov2",
|
|
"Sets the fov stage"
|
|
);
|
|
Event EV_Weapon_SetStartZoom
|
|
(
|
|
"setstartzoom",
|
|
EV_TIKIONLY,
|
|
"f",
|
|
"startzoom",
|
|
"Sets the start zoom fov"
|
|
);
|
|
Event EV_Weapon_SetEndZoom
|
|
(
|
|
"setendzoom",
|
|
EV_TIKIONLY,
|
|
"f",
|
|
"endzoom",
|
|
"Sets the end zoom fov"
|
|
);
|
|
Event EV_Weapon_SetZoomTime
|
|
(
|
|
"setzoomtime",
|
|
EV_TIKIONLY,
|
|
"f",
|
|
"zoomtime",
|
|
"Sets the time it takes to zoom from startzoom to endzoom"
|
|
);
|
|
Event EV_Weapon_SetAimType
|
|
(
|
|
"setaim",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"aimtype",
|
|
"Sets the aimtype of the weapon (changes according to player state)"
|
|
);
|
|
Event EV_Weapon_SetFireTimer
|
|
(
|
|
"setfiretimer",
|
|
EV_TIKIONLY,
|
|
"sf",
|
|
"mode mintime",
|
|
"Specifies the minimum time between shots"
|
|
);
|
|
Event EV_Weapon_UseSameClip
|
|
(
|
|
"usesameclip",
|
|
EV_TIKIONLY,
|
|
NULL,
|
|
NULL,
|
|
"Specifies that ammo comes out of the same clip in all fire modes"
|
|
);
|
|
Event EV_Weapon_SetMaxModes
|
|
(
|
|
"maxmode",
|
|
EV_TIKIONLY,
|
|
"s",
|
|
"maxmode",
|
|
"Overrides the maximum number of modes for this weapon (default is 2)"
|
|
);
|
|
Event EV_Weapon_SetSwitchMode
|
|
(
|
|
"switchmode",
|
|
EV_TIKIONLY,
|
|
NULL,
|
|
NULL,
|
|
"Specifies that this is a switch mode weapon (right button switches)"
|
|
);
|
|
Event EV_Weapon_DoneSwitching
|
|
(
|
|
"doneswitching",
|
|
EV_TIKIONLY,
|
|
NULL,
|
|
NULL,
|
|
"Signals the end of the switching to mode animation"
|
|
);
|
|
Event EV_Weapon_DoneSwitchToMiddle
|
|
(
|
|
"doneswitchtomiddle",
|
|
EV_TIKIONLY,
|
|
NULL,
|
|
NULL,
|
|
"Signals the end of the switching to 'neutral' animation"
|
|
);
|
|
Event EV_Weapon_TargetIdle
|
|
(
|
|
"targetidle",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"This weapon have a specific on-target idle"
|
|
);
|
|
Event EV_Weapon_TargetIdleThink
|
|
(
|
|
"targetidlethink",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Think event to check for target on target idle weapons"
|
|
);
|
|
Event EV_Weapon_SetBurstMode
|
|
(
|
|
"burstmode",
|
|
EV_TIKIONLY,
|
|
"i",
|
|
"burstcount",
|
|
"Set this mode to be burst mode, that uses burstcount ammo"
|
|
);
|
|
Event EV_Weapon_StartFiring
|
|
(
|
|
"startfiring",
|
|
EV_TIKIONLY,
|
|
NULL,
|
|
NULL,
|
|
"Sets the time that the weapon starts firing (for spread computations)"
|
|
);
|
|
Event EV_Weapon_FinishedFiring
|
|
(
|
|
"finishedfiring",
|
|
EV_TIKIONLY,
|
|
"i",
|
|
"finished_firing",
|
|
"Sets if the gun is finished firing"
|
|
);
|
|
Event EV_Weapon_Zoom
|
|
(
|
|
"zoom",
|
|
EV_TIKIONLY,
|
|
NULL,
|
|
NULL,
|
|
"Zooms in"
|
|
);
|
|
Event EV_Weapon_EndZoom
|
|
(
|
|
"endZoom",
|
|
EV_TIKIONLY,
|
|
NULL,
|
|
NULL,
|
|
"Ends the zoom"
|
|
);
|
|
Event EV_Weapon_Rezoom
|
|
(
|
|
"rezoom",
|
|
EV_TIKIONLY,
|
|
NULL,
|
|
NULL,
|
|
"Rezooms to the last zoom fov"
|
|
);
|
|
Event EV_Weapon_SetTargetingSkin
|
|
(
|
|
"targetingskin",
|
|
EV_TIKIONLY,
|
|
"i",
|
|
"skinNum",
|
|
"Sets the skin number to use when targeting something"
|
|
);
|
|
Event EV_Weapon_SetShootingSkin
|
|
(
|
|
"shootingskin",
|
|
EV_TIKIONLY,
|
|
"i",
|
|
"skinNum",
|
|
"Sets the skin number to use when shooting"
|
|
);
|
|
Event EV_Weapon_SetFullAmmoSkin
|
|
(
|
|
"fullAmmoSkin",
|
|
EV_TIKIONLY,
|
|
"ii",
|
|
"skinNum modeNum",
|
|
"Sets the skin number to use when the weapon has full ammo"
|
|
);
|
|
Event EV_Weapon_SetMoveSpeedModifier
|
|
(
|
|
"moveSpeedModifier",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"modifier",
|
|
"Sets the move speed modifier for this weapon (when not shooting)."
|
|
);
|
|
Event EV_Weapon_SetShootingMoveSpeedModifier
|
|
(
|
|
"shootingMoveSpeedModifier",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"modifier",
|
|
"Sets the move speed modifier for this weapon while shooting."
|
|
);
|
|
Event EV_Weapon_UseActorAiming
|
|
(
|
|
"useactoraiming",
|
|
EV_DEFAULT,
|
|
"B",
|
|
"flag",
|
|
"This weapon aims with it's tag_barrel. Regardless of who is holding it."
|
|
);
|
|
Event EV_Weapon_ViewShake
|
|
(
|
|
"viewShake",
|
|
EV_DEFAULT,
|
|
"fF",
|
|
"viewShakeMagnitude viewShakeDuration",
|
|
"Sets the magnitude & duration of the view shaking while firing this weapon.\n"
|
|
"Duration defaults to .05 if not set"
|
|
);
|
|
Event EV_Weapon_AdvancedViewShake
|
|
(
|
|
"advancedViewShake",
|
|
EV_DEFAULT,
|
|
"vvFB",
|
|
"minViewShake maxViewShake viewShakeDuration override",
|
|
"Sets the min shake vector, max shake vector, & duration of the view shaking while firing this weapon.\n"
|
|
"Duration defaults to .05 if not set"
|
|
);
|
|
Event EV_Weapon_ClearViewShake
|
|
(
|
|
"clearViewShake",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Clears the current view shake."
|
|
);
|
|
Event EV_Weapon_ReduceViewShake
|
|
(
|
|
"reduceViewShake",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Reduces the current view shake."
|
|
);
|
|
Event EV_Weapon_SetPowerRating
|
|
(
|
|
"powerrating",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"rating",
|
|
"Specifies how much damage is done per second by the weapon"
|
|
);
|
|
Event EV_Weapon_SetProjectileSpeed
|
|
(
|
|
"projectilespeed",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"proj_speed",
|
|
"Specifies the speed of the projectile -- Used by AI"
|
|
);
|
|
Event EV_Weapon_SetProjectileDamage
|
|
(
|
|
"projectiledamage",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"proj_damage",
|
|
"Specifies the damage of the projectile"
|
|
);
|
|
Event EV_Weapon_SetBurstModeDelay
|
|
(
|
|
"burstModeDelay",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"burstModeDelay",
|
|
"Specifies the length of time to use between bursts (do not use this if you want to use the animation timing)"
|
|
);
|
|
Event EV_Weapon_SetArcProjectile
|
|
(
|
|
"arcprojectile",
|
|
EV_DEFAULT,
|
|
"b",
|
|
"arc_bool",
|
|
"Specifies for actors if the projectile should arc"
|
|
);
|
|
Event EV_Weapon_SetLowArcRange
|
|
(
|
|
"lowarcrange",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"range",
|
|
"Specifies for actors the range at which to change from high trajectory to normal"
|
|
);
|
|
|
|
Event EV_Weapon_SetPlayMissSound
|
|
(
|
|
"playmisssound",
|
|
EV_DEFAULT,
|
|
"b",
|
|
"playsound",
|
|
"Sets whether or not to play a miss sound( snd_ricochet ) at the point of impact"
|
|
);
|
|
|
|
Event EV_Weapon_NoAmmoMode
|
|
(
|
|
"noAmmoMode",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Specifies that the current mode also has a no ammo mode."
|
|
);
|
|
Event EV_Weapon_NoDelay
|
|
(
|
|
"noDelay",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Specifies that this mode has no delay."
|
|
);
|
|
Event EV_Weapon_PauseRegen
|
|
(
|
|
"pauseRegen",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Pauses the regen of ammo for a little bit."
|
|
);
|
|
Event EV_Weapon_SetChargedModels
|
|
(
|
|
"chargedModels",
|
|
EV_DEFAULT,
|
|
"i",
|
|
"numChargedModels",
|
|
"Sets the number of charged models there are to use."
|
|
);
|
|
Event EV_Weapon_SetControllingProjectile
|
|
(
|
|
"controllingProjectile",
|
|
EV_DEFAULT,
|
|
"B",
|
|
"bool",
|
|
"Sets whether or not the weapon is currently controlling a projectile or not."
|
|
);
|
|
Event EV_Weapon_SetCanInterruptFiringState
|
|
(
|
|
"canInterruptFiringState",
|
|
EV_DEFAULT,
|
|
"B",
|
|
"bool",
|
|
"Sets whether or not the weapon can be interrupted during its firing state."
|
|
);
|
|
Event EV_Weapon_StartViewShake
|
|
(
|
|
"startViewShake",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Starts the weapons view shake."
|
|
);
|
|
Event EV_Weapon_SpreadAnimData
|
|
(
|
|
"spreadAnimData",
|
|
EV_DEFAULT,
|
|
"if",
|
|
"numAnims totalTime",
|
|
"Sets up the info for spread over time using different fire anims."
|
|
);
|
|
Event EV_Weapon_MaxViewShakeChange
|
|
(
|
|
"maxViewShakeChange",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"maxViewChange",
|
|
"Sets the max view change for this weapon."
|
|
);
|
|
Event EV_Weapon_ControlParms
|
|
(
|
|
"controlProjParms",
|
|
EV_DEFAULT,
|
|
"ss",
|
|
"emitterName soundName",
|
|
"Sets the paramaters to use when controlling a projectile."
|
|
);
|
|
Event EV_Weapon_ProjectileControlHidden
|
|
(
|
|
"controlProjHidden",
|
|
EV_DEFAULT,
|
|
"b",
|
|
"hiddenBool",
|
|
"Sets whether or not the projectile control is currently hidden."
|
|
);
|
|
|
|
Event EV_Weapon_MeleeParms
|
|
(
|
|
"meleeParms",
|
|
EV_DEFAULT,
|
|
"fff",
|
|
"width height length",
|
|
"Sets the parms of the melee attack."
|
|
);
|
|
Event EV_Weapon_FireOffset
|
|
(
|
|
"fireOffset",
|
|
EV_DEFAULT,
|
|
"v",
|
|
"fireOffset",
|
|
"Sets the offset where the weapon will fire from."
|
|
);
|
|
Event EV_Weapon_AutoReload
|
|
(
|
|
"autoReload",
|
|
EV_DEFAULT,
|
|
"b",
|
|
"autoReload",
|
|
"Specifies whether or not the weapon automatically reloads."
|
|
);
|
|
Event EV_Weapon_AllowAutoSwitch
|
|
(
|
|
"allowAutoSwitch",
|
|
EV_DEFAULT,
|
|
"b",
|
|
"allowAutoSwitch",
|
|
"Specifies whether or not the weapon automatically switches to another weapon when it's out of ammo."
|
|
);
|
|
Event EV_Weapon_ForceReload
|
|
(
|
|
"forceReload",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Forces a reload to occur."
|
|
);
|
|
Event EV_Weapon_NextSwitchTime
|
|
(
|
|
"nextSwitchTime",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"time",
|
|
"Sets the next switch time."
|
|
);
|
|
|
|
CLASS_DECLARATION( Item, Weapon, NULL )
|
|
{
|
|
{ &EV_Item_Pickup, &Weapon::PickupWeapon },
|
|
{ &EV_Weapon_DoneRaising, &Weapon::DoneRaising },
|
|
{ &EV_Weapon_DoneFiring, &Weapon::DoneFiring },
|
|
{ &EV_Weapon_DoneAnimating, &Weapon::DoneAnimating },
|
|
{ &EV_Weapon_Idle, &Weapon::Idle },
|
|
{ &EV_BroadcastSound, &Weapon::WeaponSound },
|
|
{ &EV_Weapon_DoneReloading, &Weapon::DoneReloading },
|
|
{ &EV_Weapon_DoneReloadingBurst, &Weapon::DoneReloadingBurst },
|
|
{ &EV_Weapon_SetAmmoClipSize, &Weapon::SetAmmoClipSize },
|
|
{ &EV_Weapon_SetAmmoInClip, &Weapon::SetAmmoInClip },
|
|
{ &EV_Weapon_ProcessModelCommands, &Weapon::ProcessWeaponCommandsEvent },
|
|
{ &EV_Weapon_SetMaxRange, &Weapon::SetMaxRangeEvent },
|
|
{ &EV_Weapon_SetMinRange, &Weapon::SetMinRangeEvent },
|
|
{ &EV_Weapon_ActionIncrement, &Weapon::SetActionLevelIncrement },
|
|
{ &EV_Weapon_NotDroppable, &Weapon::NotDroppableEvent },
|
|
{ &EV_Weapon_SetAimAnim, &Weapon::SetAimAnim },
|
|
{ &EV_Weapon_Shoot, &Weapon::Shoot },
|
|
{ &EV_Weapon_SetFireType, &Weapon::SetFireType },
|
|
{ &EV_Weapon_DonePutaway, &Weapon::DonePutaway },
|
|
{ &EV_Weapon_SetProjectile, &Weapon::SetProjectile },
|
|
{ &EV_Weapon_SetBulletDamage, &Weapon::SetBulletDamage },
|
|
{ &EV_Weapon_SetBulletCount, &Weapon::SetBulletCount },
|
|
{ &EV_Weapon_SetBulletKnockback, &Weapon::SetBulletKnockback },
|
|
{ &EV_Weapon_SetBulletRange, &Weapon::SetBulletRange },
|
|
{ &EV_Weapon_SetRange, &Weapon::SetRange },
|
|
{ &EV_Weapon_SetBulletSpread, &Weapon::SetBulletSpread },
|
|
{ &EV_Weapon_Hand, &Weapon::SetHand },
|
|
{ &EV_Weapon_Mode, &Weapon::ModeSet },
|
|
{ &EV_Weapon_AmmoType, &Weapon::SetAmmoType },
|
|
{ &EV_Weapon_StartAmmo, &Weapon::SetStartAmmo },
|
|
{ &EV_Weapon_AmmoBoost, &Weapon::setAmmoBoost },
|
|
{ &EV_Weapon_AmmoRequired, &Weapon::SetAmmoRequired },
|
|
{ &EV_Weapon_MaxChargeTime, &Weapon::SetMaxChargeTime },
|
|
{ &EV_Weapon_GiveStartingAmmo, &Weapon::GiveStartingAmmo },
|
|
{ &EV_Weapon_GiveAmmoBoost, &Weapon::giveAmmoBoost },
|
|
{ &EV_Weapon_AutoAim, &Weapon::AutoAim },
|
|
{ &EV_Weapon_Crosshair, &Weapon::Crosshair },
|
|
{ &EV_Weapon_TorsoAim, &Weapon::TorsoAim },
|
|
{ &EV_Weapon_LeftAttachToTag, &Weapon::LeftAttachToTag },
|
|
{ &EV_Weapon_RightAttachToTag, &Weapon::RightAttachToTag },
|
|
{ &EV_Weapon_DualAttachToTag, &Weapon::DualAttachToTag },
|
|
{ &EV_Weapon_HolsterTagLeft, &Weapon::LeftHolsterAttachToTag },
|
|
{ &EV_Weapon_HolsterTagRight, &Weapon::RightHolsterAttachToTag },
|
|
{ &EV_Weapon_HolsterTagDual, &Weapon::DualHolsterAttachToTag },
|
|
{ &EV_Weapon_RightHolsterAngles, &Weapon::SetRightHolsterAngles },
|
|
{ &EV_Weapon_LeftHolsterAngles, &Weapon::SetLeftHolsterAngles },
|
|
{ &EV_Weapon_DualHolsterAngles, &Weapon::SetDualHolsterAngles },
|
|
{ &EV_Weapon_HolsterScale, &Weapon::SetHolsterScale },
|
|
{ &EV_Weapon_WeildedScale, &Weapon::setWeildedScale },
|
|
{ &EV_Weapon_SetQuiet, &Weapon::SetQuiet },
|
|
{ &EV_Weapon_SetLoopFire, &Weapon::SetLoopFire },
|
|
// { &EV_Weapon_FullAnimFire, SetFullAnimFire },
|
|
{ &EV_Weapon_AutoPutaway, &Weapon::SetAutoPutaway },
|
|
{ &EV_Weapon_UseNoAmmo, &Weapon::SetUseNoAmmo },
|
|
{ &EV_Weapon_SetMeansOfDeath, &Weapon::SetMeansOfDeath },
|
|
{ &EV_Weapon_SetWorldHitSpawn, &Weapon::SetWorldHitSpawn },
|
|
{ &EV_Weapon_MakeNoise, &Weapon::MakeNoise },
|
|
{ &EV_Weapon_SetViewModel, &Weapon::SetViewModel },
|
|
{ &EV_Weapon_SetRegenAmmo, &Weapon::SetRegenAmmo },
|
|
{ &EV_Weapon_SetRegenOnlyWhenIdle, &Weapon::SetRegenOnlyWhenIdle },
|
|
{ &EV_Weapon_ChangeIdle, &Weapon::ChangeIdle },
|
|
{ &EV_Weapon_DrawBowStrain, &Weapon::DrawBowStrain },
|
|
{ &EV_Weapon_AltDrawBowStrain, &Weapon::AltDrawBowStrain },
|
|
{ &EV_Weapon_SetAccuracy, &Weapon::SetAccuracy },
|
|
{ &EV_Weapon_SetReticuleTime, &Weapon::SetReticuleTime },
|
|
{ &EV_Weapon_SetZoomFOV, &Weapon::SetZoomFOV },
|
|
{ &EV_Weapon_IncrementZoomFOV, &Weapon::IncrementZoom },
|
|
{ &EV_Weapon_SetZoomStage, &Weapon::setZoomStage },
|
|
{ &EV_Weapon_SetStartZoom, &Weapon::SetStartZoom },
|
|
{ &EV_Weapon_SetEndZoom, &Weapon::SetEndZoom },
|
|
{ &EV_Weapon_SetZoomTime, &Weapon::SetZoomTime },
|
|
{ &EV_Weapon_SetAimType, &Weapon::SetAimType },
|
|
{ &EV_Weapon_SetFireTimer, &Weapon::SetFireTimer },
|
|
{ &EV_Weapon_UseSameClip, &Weapon::UseSameClip },
|
|
{ &EV_Weapon_SetMaxModes, &Weapon::SetMaxModes },
|
|
{ &EV_Weapon_SetSwitchMode, &Weapon::SetSwitchMode },
|
|
{ &EV_Weapon_DoneSwitchToMiddle, &Weapon::DoneSwitchToMiddle },
|
|
{ &EV_Weapon_DoneSwitching, &Weapon::DoneSwitching },
|
|
{ &EV_Weapon_TargetIdle, &Weapon::TargetIdle },
|
|
{ &EV_Weapon_TargetIdleThink, &Weapon::TargetIdleThink },
|
|
{ &EV_Weapon_SetBurstMode, &Weapon::SetBurstMode },
|
|
{ &EV_Weapon_FinishedFiring, &Weapon::FinishedFiring },
|
|
{ &EV_Weapon_StartFiring, &Weapon::StartFiring },
|
|
{ &EV_Weapon_Zoom, &Weapon::Zoom },
|
|
{ &EV_Weapon_EndZoom, &Weapon::endZoom },
|
|
{ &EV_Weapon_Rezoom, &Weapon::rezoom },
|
|
{ &EV_Weapon_SetTargetingSkin, &Weapon::SetTargetingSkin },
|
|
{ &EV_Weapon_SetShootingSkin, &Weapon::SetShootingSkin },
|
|
{ &EV_Weapon_SetFullAmmoSkin, &Weapon::setFullAmmoSkin },
|
|
{ &EV_Weapon_SetMoveSpeedModifier, &Weapon::setMoveSpeedModifier },
|
|
{ &EV_Weapon_SetShootingMoveSpeedModifier, &Weapon::setShootingMoveSpeedModifier },
|
|
{ &EV_Weapon_UseActorAiming, &Weapon::UseActorAiming },
|
|
{ &EV_Weapon_SetPowerRating, &Weapon::SetPowerRating },
|
|
{ &EV_Weapon_SetProjectileSpeed, &Weapon::SetProjectileSpeed },
|
|
{ &EV_Weapon_SetProjectileDamage, &Weapon::SetProjectileDamage },
|
|
{ &EV_Weapon_ViewShake, &Weapon::setViewShakeInfo },
|
|
{ &EV_Weapon_AdvancedViewShake, &Weapon::setAdvancedViewShakeInfo },
|
|
{ &EV_Weapon_ReduceViewShake, &Weapon::reduceViewShake },
|
|
{ &EV_Weapon_ClearViewShake, &Weapon::clearViewShake },
|
|
{ &EV_ProcessGameplayData, &Weapon::processGameplayData },
|
|
|
|
{ &EV_Weapon_SetArcProjectile, &Weapon::SetArcProjectile },
|
|
{ &EV_Weapon_SetLowArcRange, &Weapon::SetLowArcRange },
|
|
|
|
{ &EV_Weapon_NoAmmoMode, &Weapon::noAmmoMode },
|
|
{ &EV_Weapon_NoDelay, &Weapon::setNoDelay },
|
|
{ &EV_Weapon_PauseRegen, &Weapon::pauseRegen },
|
|
|
|
{ &EV_Weapon_SetBurstModeDelay, &Weapon::setBurstModeDelay },
|
|
{ &EV_Weapon_SetChargedModels, &Weapon::setChargedModels },
|
|
{ &EV_Weapon_SetControllingProjectile, &Weapon::setControllingProjectile },
|
|
|
|
{ &EV_Weapon_SetCanInterruptFiringState, &Weapon::setCanInterruptFiringState },
|
|
|
|
{ &EV_Weapon_StartViewShake, &Weapon::startViewShake },
|
|
|
|
{ &EV_Weapon_SpreadAnimData, &Weapon::setSpreadAnimData },
|
|
|
|
{ &EV_Weapon_MaxViewShakeChange, &Weapon::setMaxViewShakeChange },
|
|
{ &EV_Weapon_ControlParms, &Weapon::setControlParms },
|
|
{ &EV_Weapon_ProjectileControlHidden, &Weapon::setProjectileControlHidden },
|
|
|
|
{ &EV_Weapon_MeleeParms, &Weapon::setMeleeParms },
|
|
{ &EV_Weapon_FireOffset, &Weapon::setFireOffset },
|
|
|
|
{ &EV_Weapon_AutoReload, &Weapon::setAutoReload },
|
|
{ &EV_Weapon_AllowAutoSwitch, &Weapon::setAllowAutoSwitch },
|
|
{ &EV_Weapon_ForceReload, &Weapon::forceReload },
|
|
{ &EV_Weapon_SetPlayMissSound, &Weapon::SetPlayMissSound },
|
|
|
|
{ &EV_Weapon_NextSwitchTime, &Weapon::setNextSwitchTime },
|
|
|
|
// These anim events are overridden from Entity
|
|
{ &EV_Anim, &Weapon::PassToAnimate },
|
|
{ &EV_NewAnim, &Weapon::PassToAnimate },
|
|
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
//======================
|
|
//Weapon::Weapon
|
|
//======================
|
|
Weapon::Weapon()
|
|
{
|
|
if ( LoadingSavegame )
|
|
{
|
|
// Archive function will setup all necessary data
|
|
return;
|
|
}
|
|
|
|
// Owner of the weapon
|
|
owner = NULL;
|
|
|
|
// Starting rank of the weapon
|
|
rank = 0;
|
|
|
|
// Amount of ammo required for weapon
|
|
INITIALIZE_WEAPONMODE_VAR( ammorequired, 0 );
|
|
|
|
// Starting ammo of the weapon
|
|
INITIALIZE_WEAPONMODE_VAR( startammo, 0 );
|
|
|
|
INITIALIZE_WEAPONMODE_VAR( _ammoBoost, 0 );
|
|
|
|
// Amount of ammo the clip can hold
|
|
INITIALIZE_WEAPONMODE_VAR( ammo_clip_size, 0 );
|
|
|
|
// Amount of ammo in clip
|
|
INITIALIZE_WEAPONMODE_VAR( ammo_in_clip, 0 );
|
|
|
|
// Amount of time to pass before broadcasting a weapon sound again
|
|
nextweaponsoundtime = 0;
|
|
|
|
// The initial state of the weapon
|
|
weaponstate = WEAPON_HOLSTERED;
|
|
|
|
// Is the weapon droppable when the owner is killed
|
|
notdroppable = false;
|
|
|
|
// Aim animation for behavior of monsters
|
|
aimanim = -1;
|
|
aimframe = 0;
|
|
|
|
// start off unattached
|
|
attached = false;
|
|
|
|
// maximum effective firing distance (for autoaim)
|
|
maxrange = 1000;
|
|
|
|
// minimum safe firing distance (for AI)
|
|
minrange = 0;
|
|
|
|
// speed of the projectile (0 == infinite speed)
|
|
memset( projectilespeed, 0, sizeof( projectilespeed ) );
|
|
|
|
// default action_level_increment
|
|
INITIALIZE_WEAPONMODE_VAR( action_level_increment, 2 );
|
|
|
|
// Weapons don't move
|
|
setMoveType( MOVETYPE_NONE );
|
|
|
|
// What type of ammo this weapon fires
|
|
INITIALIZE_WEAPONMODE_VAR( firetype, (firetype_t)0 );
|
|
|
|
// Init the bullet specs
|
|
INITIALIZE_WEAPONMODE_VAR( bulletdamage, 0 );
|
|
INITIALIZE_WEAPONMODE_VAR( bulletcount, 1 );
|
|
INITIALIZE_WEAPONMODE_VAR( bulletrange, 1024 );
|
|
INITIALIZE_WEAPONMODE_VAR( bulletknockback, 0 );
|
|
INITIALIZE_WEAPONMODE_VAR( ammo_type, "" );
|
|
INITIALIZE_WEAPONMODE_VAR( loopfire, false );
|
|
//INITIALIZE_WEAPONMODE_VAR( fullanimfire, false );
|
|
INITIALIZE_WEAPONMODE_VAR( burstmode, false);
|
|
burstcount = 0;
|
|
burstcountmax = 0;
|
|
|
|
// Init the max amount of time a weapon may be charged (5 seconds)
|
|
INITIALIZE_WEAPONMODE_VAR( max_charge_time, 5 );
|
|
charge_fraction = 1.0f;
|
|
|
|
// Tag to attach this weapon to on its owner when used in the left hand and in the right hand
|
|
left_attachToTag = "tag_lhand";
|
|
right_attachToTag = "tag_rhand";
|
|
dual_attachToTag = "tag_weapon_dual";
|
|
|
|
// putaway is flagged true when the weapon should be put away by state machine
|
|
putaway = false;
|
|
|
|
// Default to being able to use the weapon in any hand
|
|
hand = WEAPON_ANY;
|
|
|
|
// This is used for setting mode functionality when initializing stuff
|
|
firemodeindex = FIRE_MODE1;
|
|
|
|
// Name and index
|
|
setName( "Unnamed Weapon" );
|
|
|
|
// do better lighting on all weapons
|
|
edict->s.renderfx |= RF_EXTRALIGHT;
|
|
|
|
// make all weapons RF_WEAPONMODELs
|
|
edict->s.renderfx |= RF_WEAPONMODEL;
|
|
|
|
// Weapons do not auto aim automatically
|
|
autoAimTargetSelectionAngle = 0;
|
|
autoAimLockonAngle = 0;
|
|
// No crosshair visible
|
|
crosshair = false;
|
|
|
|
// Don't torsoaim
|
|
torsoaim = false;
|
|
|
|
// Weapons default to making noise
|
|
quiet = false;
|
|
next_noise_time = 0;
|
|
next_noammo_time = 0;
|
|
|
|
// Used to keep track of last angles and scale before holstering
|
|
lastValid = false;
|
|
lastScale = 1.0f;
|
|
holsterScale = 1.0f;
|
|
_weildedScale = 0.5f;
|
|
|
|
// Weapon will not be putaway by default when out of ammo
|
|
auto_putaway = false;
|
|
|
|
// Weapon will be able to be used when it has no ammo
|
|
use_no_ammo = true;
|
|
|
|
// Default accuracy value
|
|
for ( int i=0; i<MAX_FIREMODES; i++ )
|
|
{
|
|
for ( int j=0; j<MAX_ACCURACYTYPES; j++ )
|
|
{
|
|
accuracy[i][j] = 0.0; // Defaults to perfect accuracy
|
|
}
|
|
}
|
|
|
|
aimtype = ACCURACY_STOPPED;
|
|
|
|
// Reticule and zoom fov defaults
|
|
reticuletime = 0.0;
|
|
zoomfov = 90.0;
|
|
_lastZoomFov = 90.0f;
|
|
|
|
usesameclip = false;
|
|
|
|
curmode = FIRE_MODE1;
|
|
maxmode = FIRE_MODE2;
|
|
|
|
chargetime = 0.0;
|
|
|
|
switchmode = false;
|
|
targetidle = false;
|
|
targetidleflag = false;
|
|
|
|
chx = 0;
|
|
chy = 0;
|
|
|
|
donefiring = false;
|
|
|
|
zoomed = false;
|
|
useActorAiming = false;
|
|
|
|
INITIALIZE_WEAPONMODE_VAR(next_fire_time, 0.0f);
|
|
INITIALIZE_WEAPONMODE_VAR(fire_timer, 0.0f);
|
|
|
|
INITIALIZE_WEAPONMODE_VAR( meansofdeath, MOD_SWORD );
|
|
|
|
targetingSkin = 0;
|
|
shootingSkin = 0;
|
|
_fullAmmoSkin = 0;
|
|
_fullAmmoMode = FIRE_MODE1;
|
|
|
|
_powerRating = 0.0f;
|
|
_projectileDamage = 0.0f;
|
|
_projectileSpeed = 0.0f;
|
|
_arcProjectile = false;
|
|
_lowArcRange = 256.0f;
|
|
_playMissSound = false;
|
|
|
|
defaultMoveSpeedModifier = 1.0f;
|
|
INITIALIZE_WEAPONMODE_VAR( shootingMoveSpeedModifier, 1.0f );
|
|
|
|
INITIALIZE_WEAPONMODE_VAR( _viewShakeMagnitude, 0.0f );
|
|
INITIALIZE_WEAPONMODE_VAR( _viewShakeDuration, 0.0f );
|
|
|
|
_maxViewShakeChange = 10.0f;
|
|
|
|
INITIALIZE_WEAPONMODE_VAR( _burstModeDelay, 0.0f );
|
|
|
|
INITIALIZE_WEAPONMODE_VAR( _noAmmoMode, false );
|
|
|
|
INITIALIZE_WEAPONMODE_VAR( _noDelay, false );
|
|
|
|
INITIALIZE_WEAPONMODE_VAR( _chargedModels, 0 );
|
|
|
|
PostEvent( EV_Weapon_Idle, 0.0f );
|
|
|
|
_mpItemType = MP_ITEM_TYPE_WEAPON;
|
|
|
|
_controllingProjectile = false;
|
|
_controllingProjectileHidden = false;
|
|
|
|
startfiretime = 0.0f;
|
|
|
|
INITIALIZE_WEAPONMODE_VAR( _spreadAnims, 0 );
|
|
INITIALIZE_WEAPONMODE_VAR( _spreadTime, 0.0f );
|
|
|
|
INITIALIZE_WEAPONMODE_VAR( _meleeWidth, 15.0f );
|
|
INITIALIZE_WEAPONMODE_VAR( _meleeHeight , 45.0f );
|
|
INITIALIZE_WEAPONMODE_VAR( _meleeLength, 96.0f );
|
|
|
|
// Regen stuff
|
|
|
|
INITIALIZE_WEAPONMODE_VAR( _regenAmount, 0 );
|
|
INITIALIZE_WEAPONMODE_VAR( _regenTime, 0.0f );
|
|
INITIALIZE_WEAPONMODE_VAR( _regenOnlyWhenIdle, false );
|
|
INITIALIZE_WEAPONMODE_VAR( _nextRegenTime, 0.0f );
|
|
|
|
_zoomStage = ZOOM_STAGE_1;
|
|
|
|
setRespawnTime( 10 );
|
|
|
|
_autoReload = true;
|
|
|
|
_allowAutoSwitch = true;
|
|
|
|
edict->s.renderfx |= RF_CHILDREN_DONT_INHERIT_ALPHA;
|
|
|
|
_nextSwitchTime = 0.0f;
|
|
}
|
|
|
|
|
|
//======================
|
|
//Weapon::Weapon
|
|
//======================
|
|
Weapon::Weapon( const char *file )
|
|
{
|
|
// The tik file holds all the information available for a weapon
|
|
Weapon();
|
|
}
|
|
|
|
//======================
|
|
//Weapon::~Weapon
|
|
//======================
|
|
Weapon::~Weapon()
|
|
{
|
|
DetachGun();
|
|
}
|
|
|
|
//======================
|
|
//Weapon::GetRank
|
|
//======================
|
|
int Weapon::GetRank( void )
|
|
{
|
|
return rank;
|
|
}
|
|
|
|
//======================
|
|
//Weapon::GetOrder
|
|
//======================
|
|
int Weapon::GetOrder( void )
|
|
{
|
|
return order;
|
|
}
|
|
|
|
//======================
|
|
//Weapon::SetRank
|
|
//======================
|
|
void Weapon::SetRank( int order, int rank )
|
|
{
|
|
this->order = order;
|
|
this->rank = rank;
|
|
}
|
|
|
|
//======================
|
|
//Weapon::SetAutoPutaway
|
|
//======================
|
|
void Weapon::SetAutoPutaway( Event *ev )
|
|
{
|
|
auto_putaway = ev->GetBoolean( 1 );
|
|
}
|
|
|
|
//======================
|
|
//Weapon::SetUseNoAmmo
|
|
//======================
|
|
void Weapon::SetUseNoAmmo( Event *ev )
|
|
{
|
|
use_no_ammo = ev->GetBoolean( 1 );
|
|
}
|
|
|
|
//======================
|
|
//Weapon::SetStartAmmo
|
|
//======================
|
|
void Weapon::SetStartAmmo( Event *ev )
|
|
{
|
|
assert( ( firemodeindex >= 0 ) && ( firemodeindex < MAX_FIREMODES ) );
|
|
startammo[firemodeindex] = ev->GetInteger( 1 );
|
|
}
|
|
|
|
void Weapon::setAmmoBoost( Event *ev )
|
|
{
|
|
assert( ( firemodeindex >= 0 ) && ( firemodeindex < MAX_FIREMODES ) );
|
|
|
|
_ammoBoost[ firemodeindex ] = ev->GetInteger( 1 );
|
|
}
|
|
|
|
//======================
|
|
//Weapon::SetMaxChargeTime
|
|
//======================
|
|
void Weapon::SetMaxChargeTime( Event *ev )
|
|
{
|
|
assert( ( firemodeindex >= 0 ) && ( firemodeindex < MAX_FIREMODES ) );
|
|
max_charge_time[firemodeindex] = ev->GetFloat( 1 );
|
|
}
|
|
|
|
//======================
|
|
//Weapon::SetAmmoRequired
|
|
//======================
|
|
void Weapon::SetAmmoRequired( Event *ev )
|
|
{
|
|
assert( ( firemodeindex >= 0 ) && ( firemodeindex < MAX_FIREMODES ) );
|
|
ammorequired[firemodeindex] = ev->GetInteger( 1 );
|
|
}
|
|
|
|
//======================
|
|
//Weapon::GetStartAmmo
|
|
//======================
|
|
int Weapon::GetStartAmmo( firemode_t mode )
|
|
{
|
|
assert( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) );
|
|
|
|
if ( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) )
|
|
return startammo[mode];
|
|
else
|
|
{
|
|
warning( "Weapon::GetStartAmmo", "Invalid mode %d\n", mode );
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int Weapon::getAmmoBoost( firemode_t mode )
|
|
{
|
|
assert( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) );
|
|
|
|
if ( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) )
|
|
{
|
|
return _ammoBoost[ mode ];
|
|
}
|
|
else
|
|
{
|
|
warning( "Weapon::getAmmoBoost", "Invalid mode %d\n", mode );
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
//======================
|
|
//Weapon::GetAmmoType
|
|
//======================
|
|
str Weapon::GetAmmoType( firemode_t mode )
|
|
{
|
|
assert( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) );
|
|
|
|
if ( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) )
|
|
return ammo_type[mode];
|
|
else
|
|
{
|
|
warning( "Weapon::GetAmmoType", "Invalid mode %d\n", mode );
|
|
return "UnknownAmmo";
|
|
}
|
|
}
|
|
|
|
//======================
|
|
//Weapon::SetAmmoType
|
|
//======================
|
|
void Weapon::SetAmmoType( Event *ev )
|
|
{
|
|
assert( ( firemodeindex >= 0 ) && ( firemodeindex < MAX_FIREMODES ) );
|
|
|
|
if ( ( firemodeindex >= 0 ) && ( firemodeindex < MAX_FIREMODES ) )
|
|
ammo_type[firemodeindex] = ev->GetString( 1 );
|
|
else
|
|
{
|
|
warning( "Weapon::SetAmmoType", "Invalid mode %d\n", firemodeindex );
|
|
return;
|
|
}
|
|
}
|
|
|
|
//======================
|
|
//Weapon::SetAmmoAmount
|
|
//======================
|
|
void Weapon::SetAmmoAmount( int amount, firemode_t mode )
|
|
{
|
|
firemode_t clipToUse;
|
|
|
|
assert( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) );
|
|
|
|
if ( usesameclip )
|
|
clipToUse = FIRE_MODE1;
|
|
else
|
|
clipToUse = mode;
|
|
|
|
// If the clip can hold ammo, then set the amount in the clip to the specified amount
|
|
if ( ( clipToUse >= 0 ) && ( clipToUse < MAX_FIREMODES ) )
|
|
{
|
|
if ( ammo_clip_size[clipToUse] )
|
|
ammo_in_clip[clipToUse] = amount;
|
|
}
|
|
else
|
|
{
|
|
warning( "Weapon::SetAmmoAmount", "Invalid mode %d\n", clipToUse );
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name: GetRequiredAmmo
|
|
// Class: Weapon
|
|
//
|
|
// Description: Retrieves the required amount of ammo to fire one round
|
|
//
|
|
// Parameters: mode - the firing mode.
|
|
//
|
|
// Returns: None
|
|
//-----------------------------------------------------
|
|
int Weapon::GetRequiredAmmo( firemode_t mode )
|
|
{
|
|
assert( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) );
|
|
|
|
return ammorequired[mode];
|
|
}
|
|
|
|
|
|
//======================
|
|
//Weapon::GetClipSize
|
|
//======================
|
|
int Weapon::GetClipSize( firemode_t mode )
|
|
{
|
|
firemode_t clipToUse;
|
|
|
|
assert( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) );
|
|
|
|
if ( usesameclip )
|
|
clipToUse = FIRE_MODE1;
|
|
else
|
|
clipToUse = mode;
|
|
|
|
if ( ( clipToUse >= 0 ) && ( clipToUse < MAX_FIREMODES ) )
|
|
return ammo_clip_size[clipToUse];
|
|
else
|
|
{
|
|
warning( "Weapon::GetClipSize", "Invalid mode %d\n", clipToUse );
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
//======================
|
|
//Weapon::UseAmmo
|
|
//======================
|
|
void Weapon::UseAmmo( int amount, firemode_t mode )
|
|
{
|
|
firemode_t clipToUse;
|
|
|
|
if ( UnlimitedAmmo( mode ) )
|
|
return;
|
|
|
|
assert( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) );
|
|
|
|
if ( !( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) ) )
|
|
warning( "Weapon::UseAmmo", "Invalid mode %d\n", mode );
|
|
|
|
if ( !HasAmmo( mode ) && hasNoAmmoMode( mode ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Determine which clip to use
|
|
|
|
if ( usesameclip )
|
|
clipToUse = FIRE_MODE1;
|
|
else
|
|
clipToUse = mode;
|
|
|
|
// Remove ammo from the clip if it's available
|
|
|
|
if ( ammo_clip_size[clipToUse] )
|
|
{
|
|
ammo_in_clip[clipToUse] -= amount;
|
|
if (ammo_in_clip[clipToUse] < 0)
|
|
{
|
|
warning("UseAmmo","Used more ammo than in clip.\n");
|
|
ammo_in_clip[clipToUse] = 0;
|
|
}
|
|
owner->AmmoAmountInClipChanged( ammo_type[mode], ammo_in_clip[clipToUse] );
|
|
}
|
|
else
|
|
{
|
|
assert( owner );
|
|
if ( owner && owner->isClient() && !UnlimitedAmmo( mode ) )
|
|
{
|
|
// Remove ammo from the player's inventory
|
|
owner->UseAmmo( ammo_type[mode], ammorequired[mode] );
|
|
}
|
|
}
|
|
|
|
if ( burstmode[mode] )
|
|
{
|
|
burstcount--;
|
|
}
|
|
}
|
|
|
|
void Weapon::GetActorMuzzlePosition( Vector *position, Vector *forward, Vector *right, Vector *up, const char* tagname )
|
|
{
|
|
int tag_num;
|
|
|
|
// Using tag_name for convience since it's referenced several times
|
|
str tag_name;
|
|
if ( !tagname )
|
|
tag_name = "tag_barrel";
|
|
else
|
|
tag_name = tagname;
|
|
|
|
tag_num = gi.Tag_NumForName( edict->s.modelindex, tag_name );
|
|
|
|
if ( tag_num < 0 )
|
|
gi.Error( ERR_FATAL, "Weapon::GetActorMuzzlePosition, invalid tag name." );
|
|
|
|
//Test Stuff
|
|
setOrigin();
|
|
setAngles();
|
|
|
|
//GetTag( tag_num, &pos, &forward, &right, &up );
|
|
|
|
orientation_t weap_or, barrel_or, orn;
|
|
Vector pos;
|
|
vec3_t mat[3]={0,0,0,0,0,0,0,0,0};
|
|
vec3_t orient[3];
|
|
int i, mi, tagnum;
|
|
Sentient *owner;
|
|
owner = this->owner;
|
|
|
|
// Get the owner's weapon orientation ( this is custom code and doesn't use the GetTag function
|
|
// because we need to use the saved off fire_frame and fire_animation indexes from the owner
|
|
mi = owner->edict->s.modelindex;
|
|
|
|
tagnum = gi.Tag_NumForName( mi, current_attachToTag.c_str() );
|
|
|
|
|
|
// Get the orientation based on the frame and anim stored off in the owner.
|
|
// This is to prevent weird timing with getting orientations on different frames of firing
|
|
// animations and the orientations will not be consistent.
|
|
|
|
AnglesToAxis( owner->angles, owner->orientation );
|
|
|
|
orn = gi.Tag_OrientationEx( mi,
|
|
owner->CurrentAnim( legs ),
|
|
owner->CurrentFrame( legs ),
|
|
tagnum & TAG_MASK,
|
|
owner->edict->s.scale,
|
|
owner->edict->s.bone_tag,
|
|
owner->edict->s.bone_quat,
|
|
0,
|
|
0,
|
|
1.0f,
|
|
( owner->edict->s.anim & ANIM_BLEND ) != 0,
|
|
( owner->edict->s.torso_anim & ANIM_BLEND ) != 0,
|
|
owner->CurrentAnim( torso ),
|
|
owner->CurrentFrame( torso ),
|
|
0,
|
|
0,
|
|
1.0f
|
|
);
|
|
|
|
// Transform the weapon's orientation through the owner's orientation
|
|
// Player orientation is normally based on the player's view, but we need
|
|
// it to be based on the model's orientation, so we calculate it here.
|
|
AnglesToAxis( owner->angles, orient );
|
|
VectorCopy( owner->origin, weap_or.origin );
|
|
for ( i=0; i<3; i++ )
|
|
{
|
|
VectorMA( weap_or.origin, orn.origin[i], orient[i], weap_or.origin );
|
|
}
|
|
|
|
MatrixMultiply( orn.axis, orient, weap_or.axis );
|
|
|
|
if ( !this->GetRawTag( tag_name, &barrel_or ) )
|
|
{
|
|
pos = owner->centroid;
|
|
AnglesToAxis( owner->angles, mat );
|
|
return;
|
|
}
|
|
|
|
// Translate the barrel's orientation through the weapon's orientation
|
|
VectorCopy( weap_or.origin, pos );
|
|
|
|
for ( i = 0 ; i < 3 ; i++ )
|
|
{
|
|
VectorMA( pos, barrel_or.origin[i], weap_or.axis[i], pos );
|
|
}
|
|
|
|
MatrixMultiply( barrel_or.axis, weap_or.axis, mat );
|
|
|
|
if ( position )
|
|
*position = pos;
|
|
|
|
if ( forward )
|
|
*forward = mat[0];
|
|
|
|
if ( right )
|
|
*right = mat[1];
|
|
|
|
if ( up )
|
|
*up = mat[2];
|
|
}
|
|
|
|
//======================
|
|
//Weapon::GetMuzzlePosition
|
|
//======================
|
|
void Weapon::GetMuzzlePosition( Vector *position, Vector *forward, Vector *right, Vector *up )
|
|
{
|
|
Vector endpoint, vorg;
|
|
orientation_t barrel_or;
|
|
Vector f, r, u, viewWeapOrg, pview, pos;
|
|
Sentient *owner;
|
|
Player *player;
|
|
int tagnum;
|
|
|
|
owner = this->owner;
|
|
assert( owner );
|
|
|
|
if ( owner->isSubclassOf( Player ) )
|
|
player = ( Player * )owner;
|
|
else
|
|
{
|
|
warning("GetMuzzlePosition called from Weapon class for a non-player character.",NULL);
|
|
return;
|
|
}
|
|
|
|
// Assign player based variables
|
|
|
|
vorg = player->origin;
|
|
// Offset by the view since the origin is at the feet
|
|
vorg.z += player->client->ps.viewheight;
|
|
|
|
pview = player->GetVAngles();
|
|
|
|
/*
|
|
vec3_t new_vieworg;
|
|
vec3_t left;
|
|
|
|
if( player->client->ps.leanDelta != 0)
|
|
{
|
|
pview[2] -= player->client->ps.leanDelta / 2.0f;
|
|
|
|
AngleVectors( pview, NULL, left, NULL );
|
|
VectorMA( vorg, player->client->ps.leanDelta, left, new_vieworg );
|
|
VectorCopy( new_vieworg, vorg );
|
|
}
|
|
*/
|
|
// Assign player based variables
|
|
|
|
// Get our f, r, u vectors and set an endpoint
|
|
AngleVectors( pview, f, r, u );
|
|
|
|
// Create our point in worldspace. Lots of hardcoded crap here.
|
|
// This will only work correctly with the default FOV (since we don't have access any real numbers)
|
|
// We also don't have access to the znear value.
|
|
trace_t viewTrace;
|
|
player->GetViewTrace(viewTrace, MASK_SHOT);
|
|
endpoint = viewTrace.endpos;
|
|
Vector dir = endpoint - vorg;
|
|
float len = dir.length();
|
|
dir.normalize();
|
|
endpoint = vorg + dir * (len + 5.0f);
|
|
/*Vector p,s;
|
|
p.x = (float)chx * (-4.0f / 320.0f);
|
|
p.y = (float)chy * (-3.0f / 240.0f);
|
|
s = 4.0f * f + p.x * r + p.y * u;
|
|
s.normalize();
|
|
endpoint = vorg + (s * 3000);*/
|
|
|
|
// Now we get the origin of the weapon that the CLIENT knows (first person)
|
|
viewWeapOrg = vorg;
|
|
//setScale(0.5f); // Client scales the weapon to half-size
|
|
//VectorMA( viewWeapOrg, -9.0f, r, viewWeapOrg );
|
|
//VectorMA( viewWeapOrg, -7.5f, u, viewWeapOrg );
|
|
|
|
// Weapon is about at viewWeapOrg position, neglecting viewbob/pullback
|
|
|
|
// Do a trace to get our endpoint
|
|
|
|
trace_t trace;
|
|
|
|
if ( !multiplayerManager.inMultiplayer() || multiplayerManager.fullCollision() )
|
|
trace = G_FullTrace( vorg, vec_zero, vec_zero, endpoint, owner, MASK_SHOT, true, "Weapon::GetMuzzlePosition" );
|
|
else
|
|
trace = G_Trace( vorg, vec_zero, vec_zero, endpoint, owner, MASK_SHOT, true, "Weapon::GetMuzzlePosition" );
|
|
|
|
// Get the barrel tag from the viewmodel
|
|
|
|
tagnum = gi.Tag_NumForName( edict->s.viewmodelindex, "tag_barrel" );
|
|
|
|
if ( tagnum >= 0 )
|
|
{
|
|
barrel_or = gi.Tag_Orientation( edict->s.viewmodelindex, 0, 0, tagnum & TAG_MASK, 1.0f, edict->s.bone_tag, edict->s.bone_quat );
|
|
}
|
|
else
|
|
{
|
|
VectorClear( barrel_or.origin );
|
|
}
|
|
|
|
// Get the tag_barrel of the gun, otherwise use the owners centroid
|
|
/* if ( !this->GetRawTag( "tag_barrel", &barrel_or ) )
|
|
{
|
|
warning( "Weapon::GetMuzzlePosition", "Could not find tag \"%s\"", current_attachToTag.c_str() );
|
|
*position = owner->centroid;
|
|
}
|
|
else
|
|
*position = barrel_or.origin; */
|
|
|
|
// Translate the barrel's orientation through the weapon's orientation
|
|
|
|
pos = viewWeapOrg;
|
|
|
|
// Offset the fire position if the weapon tells us to
|
|
|
|
if ( _fireOffset[ curmode ] != vec_zero )
|
|
{
|
|
float viewOrientation[3][3];
|
|
|
|
AnglesToAxis( pview, viewOrientation );
|
|
MatrixTransformVector( _fireOffset[ curmode ], viewOrientation, pos );
|
|
pos += viewWeapOrg;
|
|
}
|
|
|
|
// For now lets shoot from the viewpoint not the weapon
|
|
//VectorMA( pos, barrel_or.origin[0], f, pos );
|
|
//VectorMA( pos, barrel_or.origin[1], r, pos );
|
|
//VectorMA( pos, barrel_or.origin[2] - 1.0f, u, pos );
|
|
|
|
// Final barrel position
|
|
*position = pos;
|
|
|
|
// Now set a NEW f,r,u vector based on changed needed to hit the center of the screen
|
|
Vector f2 = trace.endpos - *position;
|
|
AngleVectors( f2.toAngles(), f, r, u );
|
|
|
|
if ( forward )
|
|
*forward = f;
|
|
if ( right )
|
|
*right = r;
|
|
if ( up )
|
|
*up = u;
|
|
|
|
//G_DebugLine( *position, trace.endpos, 1,0,0,1 );
|
|
}
|
|
|
|
|
|
//======================
|
|
//Weapon::SetAmmoClipSize
|
|
//======================
|
|
void Weapon::SetAmmoClipSize( Event * ev )
|
|
{
|
|
assert( ( firemodeindex >= 0 ) && ( firemodeindex < MAX_FIREMODES ) );
|
|
ammo_clip_size[firemodeindex] = ev->GetInteger( 1 );
|
|
}
|
|
|
|
//======================
|
|
//Weapon::SetAmmoInClip
|
|
//======================
|
|
void Weapon::SetAmmoInClip( Event * ev )
|
|
{
|
|
assert( ( firemodeindex >= 0 ) && ( firemodeindex < MAX_FIREMODES ) );
|
|
ammo_in_clip[firemodeindex] = ev->GetInteger( 1 );
|
|
}
|
|
|
|
//======================
|
|
//Weapon::Shoot
|
|
//======================
|
|
// This function is called from the weapon tiki file
|
|
// With a loopfire weapon, this function may be called
|
|
// multiple times without having called "Fire", so we need
|
|
// to also call UseAmmo here for loopfire weapons
|
|
void Weapon::Shoot( Event *ev )
|
|
{
|
|
Vector pos, forward, right, up, delta;
|
|
firemode_t mode = FIRE_MODE1;
|
|
firemode_t realmode = FIRE_MODE1;
|
|
firemode_t regenMode;
|
|
|
|
if ( ev->NumArgs() > 0 )
|
|
{
|
|
mode = WeaponModeNameToNum( ev->GetString( 1 ) );
|
|
realmode = mode;
|
|
if ( mode == FIRE_ERROR )
|
|
return;
|
|
}
|
|
|
|
// Override the firemode if we're a switch weapon
|
|
if ( switchmode )
|
|
mode = curmode;
|
|
else
|
|
curmode = mode;
|
|
|
|
/* if ( next_fire_time[mode] > level.time )
|
|
return; */
|
|
|
|
// Set the fire timer if we have one
|
|
if ( fire_timer[mode] > 0.0 )
|
|
next_fire_time[mode] = fire_timer[mode] + level.time;
|
|
|
|
// Set accuracy spread
|
|
//bulletspread[mode].x = 50.0f * accuracy[mode][aimtype];
|
|
//bulletspread[mode].y = 50.0f * accuracy[mode][aimtype];
|
|
|
|
//if ( usesameclip )
|
|
// mode = FIRE_MODE1;
|
|
|
|
// If we are in loopfire, we need to keep checking ammo and using it up
|
|
if ( loopfire[mode] )
|
|
{
|
|
if ( HasAmmo( mode ) || hasNoAmmoMode( mode ) ||UnlimitedAmmo( mode ) )
|
|
{
|
|
// Use up the appropriate amount of ammo, it's already been checked that we have enough
|
|
UseAmmo( ammorequired[mode], mode );
|
|
/* if ( mode != realmode )
|
|
{
|
|
if ( burstmode[realmode] )
|
|
burstcount -= ammorequired[realmode];
|
|
} */
|
|
if ( switchmode )
|
|
mode = curmode;
|
|
}
|
|
else
|
|
{
|
|
if ( switchmode )
|
|
mode = curmode;
|
|
ForceIdle();
|
|
return;
|
|
}
|
|
}
|
|
|
|
mode = realmode;
|
|
|
|
if ( ( usesameclip ) || ( ammo_clip_size[ mode ] == 0 ) )
|
|
regenMode = FIRE_MODE1;
|
|
else
|
|
regenMode = mode;
|
|
|
|
if ( ( _regenOnlyWhenIdle[ regenMode ] ) && ( _regenAmount[ regenMode ] > 0 ) )
|
|
{
|
|
_nextRegenTime[ regenMode ] = level.time + _regenTime[ regenMode ] + 0.5f;
|
|
}
|
|
|
|
Sentient *owner;
|
|
owner = this->owner;
|
|
|
|
// If I am owned by a player, I need to get the muzzle position, otherwise, I just
|
|
// care about my barrel tag
|
|
if ( useActorAiming || !owner->isSubclassOf( Player ) )
|
|
{
|
|
/*
|
|
Actor *actorOwner;
|
|
actorOwner = (Actor*)owner;
|
|
|
|
Vector gunPos, gunForward, gunRight, gunUp;
|
|
actorOwner->combatSubsystem->AimWeaponTag(actorOwner->enemyManager->GetCurrentEnemy() );
|
|
actorOwner->combatSubsystem->GetGunPositionData( &gunPos, &gunForward, &gunRight, &gunUp );
|
|
forward = gunForward;
|
|
*/
|
|
owner->shotsFiredThisVolley++;
|
|
GetActorMuzzlePosition( &pos , &forward, &right, &up );
|
|
}
|
|
else if ( owner->isSubclassOf( Player ) )
|
|
{
|
|
Player *player = (Player *)owner;
|
|
|
|
GetMuzzlePosition( &pos, &forward, &right, &up );
|
|
if (g_aimviewangles->integer || ( player->client->ps.pm_type == PM_SECRET_MOVE_MODE ) ) // use viewangles to aim instead of player muzzle orientation thing
|
|
{
|
|
vec3_t fwd;
|
|
AngleVectors(owner->client->ps.viewangles,fwd,NULL,NULL);
|
|
forward = fwd;
|
|
}
|
|
// Apply spread
|
|
|
|
if ( firetype[mode] != FT_BULLET )
|
|
{
|
|
applySpread( &forward, &right, &up );
|
|
}
|
|
}
|
|
|
|
PostEvent( EV_Weapon_StartViewShake, level.frametime * 2 );
|
|
|
|
Vector testForward;
|
|
pos.AngleVectors( &testForward );
|
|
|
|
if ( firetype[mode] == FT_PROJECTILE )
|
|
{
|
|
// Temporary
|
|
// This is bad bad bad
|
|
//
|
|
/*if ( owner->isSubclassOf(Actor) )
|
|
{
|
|
Entity *target = NULL;
|
|
Actor *actor = NULL;
|
|
Vector actorToTarget;
|
|
|
|
actor = (Actor*)owner;
|
|
|
|
if ( actor )
|
|
{
|
|
target = actor->enemyManager->GetCurrentEnemy();
|
|
|
|
if ( target )
|
|
{
|
|
actorToTarget = target->centroid - actor->centroid;
|
|
actorToTarget.normalize();
|
|
forward = actorToTarget;
|
|
}
|
|
}
|
|
|
|
applySpread( pos, &forward, &right, &up );
|
|
}*/
|
|
|
|
str projectileModelName;
|
|
|
|
// Figure out the projectile name to shoot
|
|
|
|
if ( _chargedModels[ mode ] )
|
|
{
|
|
int modelIndexToUse;
|
|
|
|
// Build the projectile name - projectileModel + # + .tik
|
|
|
|
projectileModelName = projectileModel[mode];
|
|
|
|
modelIndexToUse = ( _chargedModels[ mode ] * charge_fraction ) + 1;
|
|
|
|
if ( modelIndexToUse > _chargedModels[ mode ] )
|
|
modelIndexToUse = _chargedModels[ mode ];
|
|
|
|
projectileModelName.CapLength( projectileModelName.length() - 4 );
|
|
projectileModelName += modelIndexToUse;
|
|
projectileModelName += ".tik";
|
|
}
|
|
else
|
|
{
|
|
projectileModelName = projectileModel[mode];
|
|
}
|
|
|
|
ProjectileAttack( pos,
|
|
forward,
|
|
owner,
|
|
projectileModelName,
|
|
charge_fraction
|
|
);
|
|
}
|
|
else if ( firetype[mode] == FT_BULLET )
|
|
{
|
|
Vector spread;
|
|
float range;
|
|
|
|
if ( owner->isSubclassOf( Player ) )
|
|
{
|
|
// Move the position to shoot from back a little ( 1 1/2 feet )
|
|
|
|
//pos = pos - forward * 24.0f;
|
|
|
|
spread = getSpread();
|
|
//range = bulletrange[mode] + 24.0f;
|
|
range = bulletrange[mode];
|
|
}
|
|
else
|
|
{
|
|
spread = bulletspread[ mode ];
|
|
range = bulletrange[mode];
|
|
}
|
|
|
|
BulletAttack( pos,
|
|
forward,
|
|
right,
|
|
up,
|
|
range,
|
|
bulletdamage[mode],
|
|
bulletknockback[mode],
|
|
0,
|
|
GetMeansOfDeath( mode ),
|
|
spread,
|
|
bulletcount[mode],
|
|
owner,
|
|
this
|
|
);
|
|
}
|
|
else if ( firetype[mode] == FT_EXPLOSION )
|
|
{
|
|
if ( owner && owner->isSubclassOf( Player ) )
|
|
{
|
|
Player *player = (Player *)owner;
|
|
|
|
player->shotFired();
|
|
}
|
|
|
|
ExplosionAttack( pos, owner, projectileModel[mode], forward, owner );
|
|
}
|
|
// Apparently the special_projectile stuff is no longer used
|
|
/* else if ( firetype[mode] == FT_SPECIAL_PROJECTILE )
|
|
{
|
|
this->SpecialFireProjectile( pos,
|
|
forward,
|
|
right,
|
|
up,
|
|
owner,
|
|
projectileModel[mode],
|
|
charge_fraction
|
|
);
|
|
} */
|
|
else if ( firetype[mode] == FT_MELEE ) // this is a weapon that fires like a sword
|
|
{
|
|
Vector melee_pos, melee_end;
|
|
Vector dir;
|
|
float damage;
|
|
meansOfDeath_t meansofdeath;
|
|
float knockback;
|
|
|
|
if ( owner->isSubclassOf( Player ) )
|
|
{
|
|
Vector forward;
|
|
|
|
Player *player = (Player *)owner;
|
|
melee_pos = player->origin + Vector( 0.0f, 0.0f, player->client->ps.viewheight );
|
|
|
|
player->GetVAngles().AngleVectors( &forward );
|
|
|
|
melee_end = melee_pos + forward * _meleeLength[ mode ];
|
|
}
|
|
else
|
|
{
|
|
melee_pos = owner->centroid;
|
|
melee_end = owner->centroid + Vector( owner->orientation[0] ) * _meleeLength[ mode ];
|
|
}
|
|
|
|
damage = bulletdamage[mode];
|
|
knockback = bulletknockback[mode];
|
|
|
|
meansofdeath = GetMeansOfDeath( mode );
|
|
|
|
if ( owner->isSubclassOf( Player ) )
|
|
{
|
|
Player *player = (Player *)(Sentient *)owner;
|
|
|
|
meansofdeath = player->changetMeansOfDeath( meansofdeath );
|
|
damage = player->getDamageDone( damage, meansofdeath, true );
|
|
|
|
knockback = (knockback + player->GetPlayerKnockback()) * player->GetKnockbackMultiplier();
|
|
}
|
|
|
|
Container<EntityPtr>victimlist;
|
|
|
|
if ( MeleeAttack( melee_pos, melee_end, damage, owner, meansofdeath, _meleeWidth[ mode ], -_meleeHeight[ mode ],
|
|
_meleeHeight[ mode ], knockback, true, &victimlist ) )
|
|
{
|
|
// Hit something
|
|
|
|
Sound( "impact_flesh", CHAN_VOICE );
|
|
}
|
|
else
|
|
{
|
|
// Didn't hit anything that took damage
|
|
|
|
// Try to hit the world since we didn't do any damage to anything
|
|
trace_t trace = G_Trace( melee_pos, Vector( -8.0f, -8.0f, -8.0f ), Vector( 8.0f, 8.0f, 8.0f ), melee_end, owner, MASK_MELEE, false, "Weapon::Shoot" );
|
|
|
|
Entity *victim = G_GetEntity( trace.entityNum );
|
|
|
|
if ( victim && ( ( victim == world ) || ( victim->takedamage == DAMAGE_NO ) ) )
|
|
{
|
|
vec3_t newangles;
|
|
vectoangles( trace.plane.normal, newangles );
|
|
WorldHitSpawn( mode, trace.endpos, newangles, 0.1f );
|
|
|
|
str realname = this->GetRandomAlias( "impact_world" );
|
|
if ( realname.length() > 1 )
|
|
this->Sound( realname, CHAN_VOICE );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !quiet )
|
|
{
|
|
if ( next_noise_time <= level.time )
|
|
{
|
|
BroadcastSound();
|
|
next_noise_time = level.time + 1.0f;
|
|
}
|
|
}
|
|
}
|
|
|
|
//======================
|
|
//Weapon::SetAimAnim
|
|
//======================
|
|
void Weapon::SetAimAnim( Event *ev )
|
|
{
|
|
str anim;
|
|
|
|
anim = ev->GetString( 1 );
|
|
aimanim = gi.Anim_NumForName( edict->s.modelindex, anim.c_str() );
|
|
aimframe = ev->GetInteger( 2 );
|
|
}
|
|
|
|
//======================
|
|
//Weapon::SetOwner
|
|
//======================
|
|
void Weapon::SetOwner( Sentient *ent )
|
|
{
|
|
assert( ent );
|
|
if ( !ent )
|
|
{
|
|
// return to avoid any buggy behaviour
|
|
return;
|
|
}
|
|
|
|
Item::SetOwner( ent );
|
|
|
|
setOrigin( vec_zero );
|
|
setAngles( vec_zero );
|
|
}
|
|
|
|
//======================
|
|
//Weapon::AmmoAvailable
|
|
//======================
|
|
int Weapon::AmmoAvailable( firemode_t mode )
|
|
{
|
|
// Returns the amount of ammo the owner has that is available for use
|
|
assert( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) );
|
|
|
|
if ( !( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) ) )
|
|
{
|
|
warning( "Weapon::AmmoAvailable", "Invalid mode %d\n", mode );
|
|
return 0;
|
|
}
|
|
|
|
// Make sure there is an owner before querying the amount of ammo
|
|
if ( owner )
|
|
{
|
|
return owner->AmmoCount( ammo_type[mode] );
|
|
}
|
|
else
|
|
{
|
|
warning( "Weapon::AmmoAvailable", "Weapon does not have an owner.\n" );
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
//======================
|
|
//Weapon::UnlimitedAmmo
|
|
//======================
|
|
qboolean Weapon::UnlimitedAmmo( firemode_t mode )
|
|
{
|
|
if ( !owner )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ( !ammorequired[mode] )
|
|
return true;
|
|
|
|
if ( !owner->isClient() || ( owner->flags & FL_GODMODE ) || multiplayerManager.checkFlag( MP_FLAG_INFINITE_AMMO ) )
|
|
{
|
|
return true;
|
|
}
|
|
else if ( !stricmp( ammo_type[mode], "None" ) )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//======================
|
|
//Weapon::HasInvAmmo
|
|
//======================
|
|
// Checks to see if we have any ammo in general
|
|
qboolean Weapon::HasInvAmmo( firemode_t mode )
|
|
{
|
|
if ( !ammorequired[mode] )
|
|
return false;
|
|
|
|
return ( AmmoAvailable( mode ) >= ammorequired[mode] );
|
|
}
|
|
|
|
//======================
|
|
//Weapon::HasAmmo
|
|
//======================
|
|
qboolean Weapon::HasAmmo( firemode_t mode, int numShots )
|
|
{
|
|
firemode_t clipToUse;
|
|
|
|
assert( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) );
|
|
|
|
if ( !( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) ) )
|
|
{
|
|
warning( "Weapon::HasAmmo", "Invalid mode %d\n", mode );
|
|
return false;
|
|
}
|
|
|
|
if ( !owner )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ( UnlimitedAmmo( mode ) )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if ( burstmode[mode] && burstcount <= 0 )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ( usesameclip )
|
|
{
|
|
clipToUse = FIRE_MODE1;
|
|
}
|
|
else
|
|
{
|
|
clipToUse = mode;
|
|
}
|
|
|
|
// If the weapon uses a clip, check for ammo in the right clip
|
|
if ( ammo_clip_size[clipToUse] )
|
|
{
|
|
return HasAmmoInClip( mode, numShots );
|
|
}
|
|
else // Otherwise check if ammo is available in general
|
|
{
|
|
if ( !ammorequired[mode] )
|
|
return false;
|
|
|
|
return ( AmmoAvailable( mode ) >= ammorequired[mode] * numShots );
|
|
}
|
|
}
|
|
|
|
//======================
|
|
//Weapon::HasAmmoInClip
|
|
//======================
|
|
qboolean Weapon::HasAmmoInClip( firemode_t mode, int numShots )
|
|
{
|
|
firemode_t clipToUse;
|
|
|
|
assert( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) );
|
|
|
|
if ( !( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) ) )
|
|
warning( "Weapon::HasAmmoInClip", "Invalid mode %d\n", mode );
|
|
|
|
if ( usesameclip )
|
|
{
|
|
clipToUse = FIRE_MODE1;
|
|
}
|
|
else
|
|
{
|
|
clipToUse = mode;
|
|
}
|
|
|
|
if ( ammo_clip_size[clipToUse] )
|
|
{
|
|
if ( ammo_in_clip[clipToUse] >= ammorequired[mode] * numShots )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//======================
|
|
//Weapon::ForceState
|
|
//======================
|
|
void Weapon::ForceState( weaponstate_t state )
|
|
{
|
|
weaponstate = state;
|
|
}
|
|
|
|
//======================
|
|
//Weapon::ReadyToFire
|
|
//======================
|
|
qboolean Weapon::ReadyToFire( firemode_t mode, qboolean playsound )
|
|
{
|
|
// Make sure the weapon is in a good state
|
|
|
|
if ( _canInterruptFiringState )
|
|
{
|
|
if ( weaponstate != WEAPON_READY && weaponstate != WEAPON_FIRING )
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if ( weaponstate != WEAPON_READY )
|
|
return false;
|
|
}
|
|
|
|
// If the weapon doesn't take ammo, we're always ready.
|
|
str ammotype = GetAmmoType( ( firemode_t )mode );
|
|
if ( ammotype == "None" )
|
|
return true;
|
|
|
|
//if ( usesameclip )
|
|
// mode = FIRE_MODE1;
|
|
|
|
if ( HasAmmo( mode ) )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if ( hasNoAmmoMode( mode ) )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if ( playsound && ( level.time > next_noammo_time ) && ( AmmoAvailable( mode ) < ammorequired[mode] ) )
|
|
{
|
|
Sound( "snd_noammo" );
|
|
next_noammo_time = level.time + 0.25f;
|
|
|
|
// If this is a bot, wipe out the rest of his useless ammo in the clip to prevent confusion
|
|
|
|
if ( owner && owner->isSubclassOf( Player ) )
|
|
{
|
|
/* if ( player->edict->svflags & SVF_BOT )
|
|
{
|
|
ammo_in_clip[ mode ] = 0;
|
|
}
|
|
else */
|
|
{
|
|
// Auto switch to phaser
|
|
|
|
if ( shouldAutoSwitch( mode ) )
|
|
{
|
|
autoSwitch();
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//======================
|
|
//Weapon::PutAway
|
|
//======================
|
|
void Weapon::PutAway( void )
|
|
{
|
|
// int i;
|
|
// int original_ammo_count;
|
|
// int new_ammo_count;
|
|
|
|
if ( owner && owner->isSubclassOf( Actor ) )
|
|
{
|
|
Event *newEvent = new Event( EV_DisplayEffect );
|
|
newEvent->AddString( "TransportOut" );
|
|
newEvent->AddString( "FederationWeapons" );
|
|
ProcessEvent( newEvent );
|
|
}
|
|
|
|
if ( _controllingProjectile )
|
|
{
|
|
toggleProjectileControl();
|
|
}
|
|
|
|
// set the putaway flag to true, so the state machine know to put this weapon away
|
|
putaway = true;
|
|
|
|
if ( !owner )
|
|
return;
|
|
|
|
Uninitialize();
|
|
|
|
// Give ammo back to owner
|
|
/*
|
|
for( i = 0 ; i < MAX_FIREMODES ; i++ )
|
|
{
|
|
if ( ammo_in_clip[ i ] )
|
|
{
|
|
// Add ammo to owner
|
|
original_ammo_count = owner->AmmoCount( ammo_type[ i ] );
|
|
owner->GiveAmmo( ammo_type[ i ], ammo_in_clip[ i ] );
|
|
new_ammo_count = owner->AmmoCount( ammo_type[ i ] );
|
|
|
|
// Subtract ammo from weapon
|
|
|
|
ammo_in_clip[ i ] = ammo_in_clip[ i ] - (new_ammo_count - original_ammo_count);
|
|
|
|
owner->AmmoAmountInClipChanged( ammo_type[ i ], ammo_in_clip[ i ] );
|
|
}
|
|
}*/
|
|
}
|
|
|
|
//======================
|
|
//Weapon::DetachFromOwner
|
|
//======================
|
|
void Weapon::DetachFromOwner( void )
|
|
{
|
|
if ( edict->s.renderfx | RF_DONTDRAW )
|
|
animate->StopAnimatingAtEnd();
|
|
else
|
|
animate->StopAnimating();
|
|
|
|
DetachGun();
|
|
weaponstate = WEAPON_HOLSTERED;
|
|
current_attachToTag = "";
|
|
|
|
Uninitialize();
|
|
}
|
|
|
|
//======================
|
|
//Weapon::AttachToOwner
|
|
//======================
|
|
void Weapon::AttachToOwner( weaponhand_t hand )
|
|
{
|
|
AttachGun( hand , false );
|
|
|
|
if ( targetidle )
|
|
PostEvent(EV_Weapon_TargetIdleThink, TargetIdleTime);
|
|
|
|
ForceIdle();
|
|
}
|
|
|
|
//======================
|
|
//Weapon::AttachToHolster
|
|
//======================
|
|
void Weapon::AttachToHolster( weaponhand_t hand )
|
|
{
|
|
AttachGun( hand, true );
|
|
animate->RandomAnimate( "holster", EV_Weapon_Idle );
|
|
}
|
|
|
|
//======================
|
|
//Weapon::Drop
|
|
//======================
|
|
qboolean Weapon::Drop( void )
|
|
{
|
|
float radius;
|
|
Vector temp;
|
|
int i;
|
|
|
|
if ( !owner )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ( !IsDroppable() )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ( multiplayerManager.inMultiplayer() && !multiplayerManager.checkRule( "weapon-candrop", true, NULL ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
DetachGun();
|
|
|
|
// Get rid of special effect stuff
|
|
|
|
CancelEventsOfType( EV_DisplayEffect );
|
|
CancelEventsOfType( EV_FadeIn );
|
|
clearCustomShader();
|
|
setAlpha( 1.0f );
|
|
edict->s.renderfx &= ~RF_FORCE_ALPHA_EFFECTS;
|
|
edict->s.renderfx &= ~RF_FORCE_ALPHA;
|
|
|
|
if ( _controllingProjectile )
|
|
{
|
|
toggleProjectileControl();
|
|
}
|
|
|
|
temp[ 1 ] = 64.0;
|
|
temp[ 2 ] = 48.0;
|
|
if ( owner )
|
|
{
|
|
setOrigin( owner->origin + temp );
|
|
}
|
|
else
|
|
{
|
|
setOrigin( origin + temp );
|
|
}
|
|
|
|
// hack to fix the bounds when the gun is dropped
|
|
// once dropped reset the rotated bounds
|
|
flags |= FL_ROTATEDBOUNDS;
|
|
|
|
if ( ( mins == vec_zero ) && ( maxs == vec_zero ) )
|
|
{
|
|
gi.CalculateBounds( edict->s.modelindex, edict->s.scale, mins, maxs );
|
|
radius = ( mins - maxs ).length() * 2.0f;
|
|
mins.x = mins.y = -radius;
|
|
maxs.x = maxs.y = radius;
|
|
setSize( mins, maxs );
|
|
}
|
|
|
|
// stop animating
|
|
ForceIdle();
|
|
animate->SetFrame( 0 );
|
|
|
|
// drop the weapon
|
|
PlaceItem();
|
|
if ( owner )
|
|
{
|
|
temp[ 0 ] = G_CRandom( 50.0f );
|
|
temp[ 1 ] = G_CRandom( 50.0f );
|
|
temp[ 2 ] = 250.0f;
|
|
velocity = owner->velocity * 0.5f + temp;
|
|
setAngles( owner->angles );
|
|
}
|
|
|
|
avelocity = Vector( 0.0f, G_CRandom( 360.0f ), 0.0f );
|
|
|
|
// Get rid of all of the ammo in the weapon
|
|
|
|
for ( i = 0 ; i < MAX_FIREMODES ; i++ )
|
|
{
|
|
ammo_in_clip[ i ] = 0;
|
|
}
|
|
|
|
// FIXME - Make this work right if we need it
|
|
/*
|
|
if ( owner && owner->isClient() )
|
|
{
|
|
spawnflags |= DROPPED_PLAYER_ITEM;
|
|
if ( ammo_clip_size )
|
|
startammo = ammo_in_clip;
|
|
else
|
|
startammo = 0;
|
|
|
|
// If owner is dead, put all his ammo of that type in the gun.
|
|
if ( owner->deadflag )
|
|
{
|
|
startammo = AmmoAvailable();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
spawnflags |= DROPPED_ITEM;
|
|
if ( ammo_clip_size && ammo_in_clip )
|
|
startammo = ammo_in_clip;
|
|
else
|
|
startammo >>= 2;
|
|
|
|
if ( startammo == 0 )
|
|
{
|
|
startammo = 1;
|
|
}
|
|
}
|
|
*/
|
|
|
|
// Wait some time before the last owner can pickup this weapon
|
|
last_owner = owner;
|
|
last_owner_trigger_time = level.time + 2.5f;
|
|
|
|
// Cancel reloading events
|
|
CancelEventsOfType( EV_Weapon_DoneReloading );
|
|
CancelEventsOfType( EV_Weapon_DoneReloadingBurst );
|
|
|
|
// Remove this from the owner's item list
|
|
if ( owner )
|
|
{
|
|
owner->RemoveItem( this );
|
|
}
|
|
|
|
owner = NULL;
|
|
|
|
if ( multiplayerManager.inMultiplayer() && gi.Anim_NumForName( edict->s.modelindex, "idle_onground" ) >= 0 )
|
|
{
|
|
animate->RandomAnimate( "idle_onground" );
|
|
edict->s.eType = ET_MODELANIM;
|
|
}
|
|
|
|
if ( multiplayerManager.inMultiplayer() )
|
|
{
|
|
edict->s.renderfx |= RF_FULLBRIGHT;
|
|
}
|
|
|
|
// Fade out dropped weapons, to keep down the clutter
|
|
PostEvent( EV_FadeOut, 30.0f );
|
|
|
|
Uninitialize();
|
|
return true;
|
|
}
|
|
|
|
//======================
|
|
//Weapon::Charge
|
|
//======================
|
|
void Weapon::Charge( firemode_t mode )
|
|
{
|
|
}
|
|
|
|
//======================
|
|
//Weapon::ReleaseFire
|
|
//======================
|
|
void Weapon::ReleaseFire( firemode_t mode, float charge_time )
|
|
{
|
|
// Calculate and store off the charge fraction to use when the weapon actually shoots
|
|
|
|
// Clamp to max_charge_time
|
|
if ( charge_time > max_charge_time[mode] )
|
|
charge_fraction = 1.0f;
|
|
else
|
|
charge_fraction = charge_time / max_charge_time[mode];
|
|
|
|
// Call regular fire function
|
|
Fire( mode );
|
|
}
|
|
|
|
//======================
|
|
//Weapon::Fire
|
|
//======================
|
|
// This function is called from the state machine
|
|
// to tell the tiki which weapon animation to play
|
|
// The tiki file will most likely post the "shoot" event
|
|
// shortly after this function is called
|
|
void Weapon::Fire( firemode_t mode )
|
|
{
|
|
Event *done_event=NULL;
|
|
firemode_t realmode;
|
|
Vector pos;
|
|
//char anim[128];
|
|
str fireAnimName;
|
|
|
|
// Sanity check the mode
|
|
assert( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) );
|
|
|
|
if ( !( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) ) )
|
|
warning( "Weapon::Fire", "Invalid mode %d\n", mode );
|
|
|
|
realmode = mode;
|
|
|
|
// Override the firemode if we're a switch weapon
|
|
if ( switchmode )
|
|
mode = curmode;
|
|
else
|
|
curmode = mode;
|
|
|
|
if ( next_fire_time[mode] > level.time )
|
|
return;
|
|
|
|
// Set the fire timer if we have one
|
|
if ( fire_timer[mode] > 0.0f )
|
|
next_fire_time[mode] = fire_timer[mode] + level.time;
|
|
|
|
// If we are in loopfire mode, then we don't pass a DoneFiring event
|
|
if ( !loopfire[mode] )
|
|
{
|
|
// The DoneFiring event requires to know the firing mode so save that off in the event
|
|
done_event = new Event( EV_Weapon_DoneFiring );
|
|
done_event->AddInteger( mode );
|
|
}
|
|
|
|
/*
|
|
if ( fullanimfire[mode] )
|
|
{
|
|
donefiring = false;
|
|
done_event = new Event ( EV_Weapon_DoneFiring );
|
|
done_event->AddInteger( mode );
|
|
}
|
|
*/
|
|
|
|
// Set the state of the weapon to FIRING
|
|
weaponstate = WEAPON_FIRING;
|
|
|
|
if ( shootingSkin )
|
|
ChangeSkin( shootingSkin, true );
|
|
|
|
// Cancel any old done firing events
|
|
CancelEventsOfType( EV_Weapon_DoneFiring );
|
|
|
|
// Play the correct animation
|
|
if ( !switchmode )
|
|
{
|
|
if ( mode == FIRE_MODE1 )
|
|
fireAnimName = "fire";
|
|
//animate->RandomAnimate( "fire", done_event );
|
|
else if ( mode == FIRE_MODE2 )
|
|
fireAnimName = "alternatefire";
|
|
//animate->RandomAnimate( "alternatefire", done_event );
|
|
}
|
|
else
|
|
{
|
|
//sprintf(anim,"fire_mode%d",(int)mode+1);
|
|
fireAnimName = "fire_mode";
|
|
fireAnimName += (int)mode+1;
|
|
//if ( animate->HasAnim( anim ) )
|
|
// animate->RandomAnimate( anim, done_event );
|
|
}
|
|
|
|
if ( world && world->isThingBroken( item_name.c_str() ) )
|
|
{
|
|
fireAnimName += "_broken";
|
|
animate->RandomAnimate( fireAnimName.c_str(), done_event );
|
|
return;
|
|
}
|
|
else if ( !HasAmmo( mode ) && hasNoAmmoMode( mode ) )
|
|
{
|
|
fireAnimName += "_noammo";
|
|
}
|
|
else if ( _spreadTime[ mode ] && _spreadAnims[ mode ] )
|
|
{
|
|
float firingTime;
|
|
int animNum;
|
|
|
|
firingTime = level.time - startfiretime;
|
|
|
|
animNum = 1 + ( firingTime / _spreadTime[ mode ] ) * ( _spreadAnims[ mode ] + 1 );
|
|
|
|
if ( animNum > _spreadAnims[ mode ] )
|
|
animNum = _spreadAnims[ mode ];
|
|
|
|
fireAnimName += "_spread";
|
|
fireAnimName += animNum;
|
|
}
|
|
|
|
animate->RandomAnimate( fireAnimName.c_str(), done_event );
|
|
|
|
// Use up the appropriate amount of ammo, it's already been checked that we have enough
|
|
//if ( usesameclip )
|
|
// mode = FIRE_MODE1;
|
|
|
|
if ( !loopfire[mode] )
|
|
{
|
|
if ( ammorequired[mode] != ammorequired[realmode] )
|
|
UseAmmo(ammorequired[realmode], mode);
|
|
else
|
|
UseAmmo( ammorequired[mode], mode );
|
|
if ( mode != realmode )
|
|
{
|
|
if ( burstmode[realmode] )
|
|
burstcount -= ammorequired[realmode];
|
|
}
|
|
}
|
|
}
|
|
|
|
//======================
|
|
//Weapon::DetachGun
|
|
//======================
|
|
void Weapon::DetachGun( void )
|
|
{
|
|
if ( attached )
|
|
{
|
|
StopSound( CHAN_WEAPONIDLE );
|
|
attached = false;
|
|
detach();
|
|
hideModel();
|
|
|
|
clearDisplayEffects();
|
|
|
|
if ( lastValid )
|
|
{
|
|
// Restore the last scale
|
|
|
|
setScale( lastScale );
|
|
lastValid = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
//======================
|
|
//Weapon::AttachGun
|
|
//======================
|
|
void Weapon::AttachGun( weaponhand_t hand, qboolean holstering )
|
|
{
|
|
int tag_num = 0;
|
|
|
|
if ( !owner )
|
|
{
|
|
current_attachToTag = "";
|
|
return;
|
|
}
|
|
|
|
if ( attached )
|
|
{
|
|
DetachGun();
|
|
}
|
|
|
|
if ( holstering )
|
|
{
|
|
// Save off these values if we are holstering the weapon. We will restore them when
|
|
// the users raises the weapons again.
|
|
lastAngles = this->angles;
|
|
lastScale = this->edict->s.scale;
|
|
lastValid = true;
|
|
}
|
|
else
|
|
{
|
|
lastScale = this->edict->s.scale;
|
|
lastValid = true;
|
|
|
|
if ( owner->isSubclassOf( Player ) )
|
|
{
|
|
if ( mp_bigGunMode->integer )
|
|
setScale( _weildedScale * 2.0f );
|
|
else
|
|
setScale( _weildedScale );
|
|
}
|
|
}
|
|
/* else if ( lastValid )
|
|
{
|
|
|
|
// Restore the last
|
|
setScale( lastScale );
|
|
setAngles( lastAngles );
|
|
lastValid = false;
|
|
} */
|
|
|
|
|
|
switch( hand )
|
|
{
|
|
case WEAPON_LEFT:
|
|
if ( holstering )
|
|
{
|
|
current_attachToTag = leftholster_attachToTag;
|
|
setAngles( leftHolsterAngles );
|
|
setScale( holsterScale );
|
|
}
|
|
else
|
|
{
|
|
current_attachToTag = left_attachToTag;
|
|
}
|
|
break;
|
|
case WEAPON_RIGHT:
|
|
case WEAPON_DUAL:
|
|
if ( holstering )
|
|
{
|
|
current_attachToTag = rightholster_attachToTag;
|
|
setAngles( rightHolsterAngles );
|
|
setScale( holsterScale );
|
|
}
|
|
else
|
|
{
|
|
current_attachToTag = right_attachToTag;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
warning( "Weapon::AttachGun", "Invalid hand for attachment of weapon specified" );
|
|
break;
|
|
}
|
|
|
|
if ( !current_attachToTag.length() )
|
|
return;
|
|
|
|
tag_num = gi.Tag_NumForName( owner->edict->s.modelindex, this->current_attachToTag.c_str() );
|
|
|
|
NoLerpThisFrame();
|
|
if ( tag_num >= 0 )
|
|
{
|
|
attached = true;
|
|
|
|
attach( owner->entnum, tag_num, false );
|
|
|
|
showModel();
|
|
setOrigin();
|
|
|
|
if ( owner && owner->isSubclassOf( Actor ) )
|
|
{
|
|
Event *newEvent = new Event( EV_DisplayEffect );
|
|
newEvent->AddString( "TransportIn" );
|
|
newEvent->AddString( "FederationWeapons" );
|
|
ProcessEvent( newEvent );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
warning( "Weapon::AttachGun", "Attachment of weapon to tag \"%s\": Tag Not Found\n", this->current_attachToTag.c_str() );
|
|
}
|
|
}
|
|
|
|
//======================
|
|
//Weapon::GiveStartingAmmo
|
|
//======================
|
|
void Weapon::GiveStartingAmmo( Event *ev )
|
|
{
|
|
str ammotype;
|
|
int mode;
|
|
Entity *entityToGiveAmmo;
|
|
Sentient *sentient;
|
|
|
|
if ( ev->NumArgs() > 0 )
|
|
entityToGiveAmmo = ev->GetEntity( 1 );
|
|
else
|
|
entityToGiveAmmo = owner;
|
|
|
|
if ( !entityToGiveAmmo || !entityToGiveAmmo->isSubclassOf( Sentient ) )
|
|
{
|
|
assert( entityToGiveAmmo );
|
|
|
|
warning( "Weapon::GiveStartingAmmo", "Could not give ammo\n" );
|
|
return;
|
|
}
|
|
|
|
sentient = reinterpret_cast<Sentient *>(entityToGiveAmmo);
|
|
|
|
// Give the player the starting ammo
|
|
|
|
for ( mode=FIRE_MODE1; mode<MAX_FIREMODES; mode++ )
|
|
{
|
|
ammotype = GetAmmoType( ( firemode_t )mode );
|
|
|
|
if ( ammotype.length() )
|
|
{
|
|
sentient->GiveAmmo( ammotype, this->GetStartAmmo( ( firemode_t )mode ), false );
|
|
}
|
|
}
|
|
}
|
|
|
|
void Weapon::giveAmmoBoost( Event *ev )
|
|
{
|
|
str ammotype;
|
|
int mode;
|
|
Entity *entityToGiveAmmo;
|
|
Sentient *sentient;
|
|
|
|
|
|
// Get the sentient to give the ammo boost to
|
|
|
|
entityToGiveAmmo = ev->GetEntity( 1 );
|
|
|
|
if ( !entityToGiveAmmo || !entityToGiveAmmo->isSubclassOf( Sentient ) )
|
|
{
|
|
assert( entityToGiveAmmo );
|
|
|
|
warning( "Weapon::GiveAmmoBoost", "Could not give ammo\n" );
|
|
return;
|
|
}
|
|
|
|
sentient = reinterpret_cast<Sentient *>(entityToGiveAmmo);
|
|
|
|
// Give the sentient the ammo boost
|
|
|
|
for ( mode = FIRE_MODE1 ; mode < MAX_FIREMODES ; mode++ )
|
|
{
|
|
ammotype = GetAmmoType( ( firemode_t )mode );
|
|
|
|
if ( ammotype.length() )
|
|
{
|
|
sentient->GiveAmmo( ammotype, this->getAmmoBoost( ( firemode_t )mode ), true );
|
|
}
|
|
}
|
|
}
|
|
|
|
//======================
|
|
//Weapon::PickupWeapon
|
|
//======================
|
|
void Weapon::PickupWeapon( Event *ev )
|
|
{
|
|
Sentient *sen;
|
|
Entity *other;
|
|
Weapon *weapon;
|
|
qboolean hasweapon;
|
|
//qboolean giveammo[MAX_FIREMODES];
|
|
//int mode;
|
|
|
|
other = ev->GetEntity( 1 );
|
|
|
|
if ( !other )
|
|
return;
|
|
|
|
if ( !other->isSubclassOf( Sentient ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
sen = ( Sentient * )other;
|
|
|
|
if ( !Pickupable( other ) )
|
|
return;
|
|
|
|
// If this is the last owner, check to see if he can pick it up
|
|
if ( ( sen == last_owner ) && ( level.time < last_owner_trigger_time ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
hasweapon = sen->HasItem( item_name );
|
|
|
|
|
|
if ( hasweapon && !multiplayerManager.checkFlag( MP_FLAG_WEAPONS_STAY ) )
|
|
{
|
|
Event *event;
|
|
|
|
event = new Event( EV_Weapon_GiveAmmoBoost );
|
|
event->AddEntity( other );
|
|
ProcessEvent( event );
|
|
|
|
ItemPickup( other, false );
|
|
}
|
|
else
|
|
{
|
|
weapon = ( Weapon * )ItemPickup( other );
|
|
|
|
if ( !weapon )
|
|
{
|
|
// Item Pickup failed, so don't give ammo either.
|
|
return;
|
|
}
|
|
}
|
|
/* else
|
|
{
|
|
for ( mode = FIRE_MODE1; mode < MAX_FIREMODES; mode++ )
|
|
{
|
|
giveammo[mode] = ( sen->isClient() && ammo_type[mode].length() && startammo[mode] );
|
|
|
|
if ( !giveammo[mode] )
|
|
{
|
|
return;
|
|
}
|
|
|
|
sen->GiveAmmo( ammo_type[mode].c_str(), startammo[mode] );
|
|
}
|
|
} */
|
|
}
|
|
|
|
//======================
|
|
//Weapon::ForceIdle
|
|
//======================
|
|
void Weapon::ForceIdle( void )
|
|
{
|
|
// Force the weapon to the idle animation
|
|
weaponstate = WEAPON_READY;
|
|
|
|
// Clear our fire timer
|
|
//INITIALIZE_WEAPONMODE_VAR(next_fire_time, 0.0);
|
|
|
|
float r = G_Random(100.0f);
|
|
char anim[128];
|
|
|
|
|
|
int animNum = gi.Anim_NumForName( edict->s.modelindex, "idle_onground" );
|
|
if ( multiplayerManager.inMultiplayer() && animNum >= 0 && animate->CurrentAnim() == animNum )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// If this is a switchmode weapon, we have a very different idle system
|
|
if ( switchmode )
|
|
{
|
|
if ( r < 5.0f )
|
|
{
|
|
sprintf(anim,"idle_rare_mode%d",(int)curmode+1);
|
|
if ( animate->HasAnim( anim ) )
|
|
{
|
|
animate->RandomAnimate( anim );
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ( r < 15.0f )
|
|
{
|
|
sprintf(anim,"idle_uncommon_mode%d",(int)curmode+1);
|
|
if ( animate->HasAnim( anim ) )
|
|
{
|
|
animate->RandomAnimate( anim );
|
|
return;
|
|
}
|
|
}
|
|
|
|
sprintf(anim,"idle_common_mode%d",(int)curmode+1);
|
|
if ( animate->HasAnim( anim ) )
|
|
{
|
|
animate->RandomAnimate( anim );
|
|
return;
|
|
}
|
|
|
|
// We shouldn't get here if the anims are set up correctly
|
|
// for the switch mode weapon
|
|
animate->RandomAnimate("idle");
|
|
return;
|
|
}
|
|
|
|
if ( r < 5.0f && animate->HasAnim("idle_rare") )
|
|
{
|
|
animate->RandomAnimate( "idle_rare" );
|
|
return;
|
|
}
|
|
|
|
if ( r < 15.0 && animate->HasAnim("idle_uncommon") )
|
|
{
|
|
animate->RandomAnimate("idle_uncommon");
|
|
return;
|
|
}
|
|
|
|
if ( animate->HasAnim("idle_common") )
|
|
{
|
|
animate->RandomAnimate( "idle_common" );
|
|
return;
|
|
}
|
|
|
|
// We shouldn't get here if the anims are set up correctly
|
|
animate->RandomAnimate("idle");
|
|
}
|
|
|
|
//======================
|
|
//Weapon::DoneRaising
|
|
//======================
|
|
void Weapon::DoneRaising( Event *ev )
|
|
{
|
|
Event *event;
|
|
|
|
weaponstate = WEAPON_READY;
|
|
ForceIdle();
|
|
|
|
if ( !owner )
|
|
{
|
|
PostEvent( EV_Remove, 0.0f );
|
|
return;
|
|
}
|
|
|
|
event = new Event( EV_Weapon_DoneReloading );
|
|
event->AddInteger( FIRE_MODE1 );
|
|
ProcessEvent( event );
|
|
|
|
event = new Event( EV_Weapon_DoneReloading );
|
|
event->AddInteger( FIRE_MODE2 );
|
|
ProcessEvent( event );
|
|
|
|
if ( targetidle )
|
|
PostEvent(EV_Weapon_TargetIdleThink, TargetIdleTime);
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: playAnim
|
|
// Class: Weapon
|
|
//
|
|
// Description: Plays the specified animation and marks its weapon state as animating
|
|
//
|
|
// Parameters: const str &animName - name of the animation to play
|
|
// bool animatingFlag - defaults to true
|
|
//
|
|
// Returns: none
|
|
//----------------------------------------------------------------
|
|
void Weapon::playAnim( const str &animName, bool animatingFlag )
|
|
{
|
|
if ( animate->HasAnim( animName.c_str() ) )
|
|
{
|
|
if ( animatingFlag )
|
|
weaponstate = WEAPON_ANIMATING;
|
|
|
|
SetAnim( animName, EV_Weapon_DoneAnimating );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//===============================================================
|
|
// Name: animName
|
|
// Class: Weapon
|
|
//
|
|
// Description: Sets the weapons animation.
|
|
//
|
|
// Parameters: const str& --
|
|
//
|
|
// Returns: None
|
|
//
|
|
//===============================================================
|
|
void Weapon::SetAnim( const str &animName, Event *endevent, bodypart_t bodypart )
|
|
{
|
|
assert( animate );
|
|
animate->RandomAnimate( animName.c_str(), endevent, bodypart );
|
|
AddEffectsAnims();
|
|
}
|
|
|
|
|
|
//===============================================================
|
|
// Name: animName
|
|
// Class: Weapon
|
|
//
|
|
// Description: Sets the weapons animation.
|
|
//
|
|
// Parameters: const str& --
|
|
//
|
|
// Returns: None
|
|
//
|
|
//===============================================================
|
|
void Weapon::SetAnim( const str &animName, const Event &endevent, bodypart_t bodypart )
|
|
{
|
|
assert( animate );
|
|
animate->RandomAnimate( animName.c_str(), endevent, bodypart );
|
|
AddEffectsAnims();
|
|
}
|
|
|
|
//===============================================================
|
|
// Name: PassToAnimate
|
|
// Class: Weapon
|
|
//
|
|
// Description: Passes the event to the animation object, and gives
|
|
// the weapon a chance to add additional special effects.
|
|
// If the animation object doesn't exist, creates it.
|
|
//
|
|
// Parameters: Event* -- an animation related event.
|
|
//
|
|
// Returns: None
|
|
//
|
|
//===============================================================
|
|
void Weapon::PassToAnimate( Event *ev )
|
|
{
|
|
if ( !animate )
|
|
{
|
|
animate = new Animate( this );
|
|
}
|
|
Event *new_event = new Event( ev );
|
|
animate->ProcessEvent( new_event );
|
|
AddEffectsAnims();
|
|
}
|
|
|
|
//===============================================================
|
|
// Name: AddEffectsAnims
|
|
// Class: Weapon
|
|
//
|
|
// Description: Adds the effect anims for a weapon.
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: None
|
|
//
|
|
//===============================================================
|
|
void Weapon::AddEffectsAnims( void )
|
|
{
|
|
}
|
|
|
|
//======================
|
|
//Weapon::DoneAnimating
|
|
//======================
|
|
void Weapon::DoneAnimating( Event *ev )
|
|
{
|
|
weaponstate = WEAPON_READY;
|
|
|
|
if ( !owner )
|
|
PostEvent( EV_Remove, 0.0f );
|
|
|
|
return;
|
|
}
|
|
|
|
//======================
|
|
//Weapon::ClientFireDone
|
|
//======================
|
|
void Weapon::ClientFireDone( void )
|
|
{
|
|
// This is called when the client's firing animation is done
|
|
}
|
|
|
|
//======================
|
|
//Weapon::DoneFiring
|
|
//======================
|
|
void Weapon::DoneFiring( Event *ev )
|
|
{
|
|
/*
|
|
firemode_t mode = (firemode_t)ev->GetInteger( 1 );
|
|
|
|
|
|
if ( fullanimfire[mode] )
|
|
{
|
|
donefiring = true;
|
|
return;
|
|
}
|
|
*/
|
|
|
|
if ( shootingSkin )
|
|
ChangeSkin( shootingSkin, false );
|
|
|
|
// This is called when the weapon's firing animation is done
|
|
// If this weapon has a fire_stop animation, play it (tiki will force us back to idle)
|
|
if ( animate->HasAnim("fire_stop") )
|
|
animate->RandomAnimate("fire_stop");
|
|
else
|
|
ForceIdle();
|
|
|
|
// Check to see if the auto_putaway flag is set, and the weapon is out of ammo. If so, then putaway the
|
|
// weapon.
|
|
if (
|
|
( !HasAmmo( FIRE_MODE1 ) || ( !stricmp( ammo_type[ FIRE_MODE1 ], "None" ) ) ) &&
|
|
( !HasAmmo( FIRE_MODE2 ) || ( !stricmp( ammo_type[ FIRE_MODE2 ], "None" ) ) ) &&
|
|
auto_putaway
|
|
)
|
|
{
|
|
PutAway();
|
|
}
|
|
}
|
|
|
|
//======================
|
|
//Weapon::DoneReloading
|
|
//======================
|
|
void Weapon::DoneReloading( Event *ev )
|
|
{
|
|
int amount;
|
|
int amount_used;
|
|
firemode_t mode;
|
|
firemode_t clipToUse;
|
|
|
|
// Get the mode from the passed in event
|
|
mode = (firemode_t)ev->GetInteger( 1 );
|
|
|
|
assert( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) );
|
|
|
|
if ( !( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) ) )
|
|
warning( "Weapon::DoneReloading", "Invalid mode %d\n", mode );
|
|
|
|
/* if ( regenAmount > 0 )
|
|
{
|
|
int tmpamount = 0;
|
|
Ammo *ammo;
|
|
ammo = owner->FindAmmoByName( ammo_type[mode] );
|
|
if ( ammo )
|
|
{
|
|
tmpamount = (ammo->getMaxAmount() / 2) - owner->AmmoCount( ammo_type[mode] );
|
|
owner->GiveAmmo( ammo_type[ mode ], tmpamount);
|
|
ForceIdle();
|
|
return;
|
|
}
|
|
} */
|
|
|
|
// If we need to do a REAL reload (not a burst reload) we skip the test
|
|
// altogether.
|
|
/* firemode_t realmode = mode;
|
|
if ( usesameclip )
|
|
mode = FIRE_MODE1;
|
|
if ( !(ammo_clip_size[mode] && !ammo_in_clip[mode] && AmmoAvailable(mode)) )
|
|
{
|
|
int tmp = 0;
|
|
if ( switchmode )
|
|
tmp = burstmode[curmode];
|
|
else
|
|
tmp = burstmode[realmode];
|
|
|
|
if ( tmp )
|
|
{
|
|
int tmpamount = 0;
|
|
Ammo *ammo;
|
|
ammo = owner->FindAmmoByName( ammo_type[mode] );
|
|
if ( ammo )
|
|
{
|
|
tmpamount = owner->AmmoCount( ammo_type[mode] );
|
|
|
|
// Try the clip ammo if we have none in our main inventory
|
|
if ( tmpamount == 0 )
|
|
tmpamount = ammo_in_clip[mode];
|
|
|
|
if ( tmpamount > burstcountmax )
|
|
burstcount = burstcountmax;
|
|
else
|
|
burstcount = tmpamount;
|
|
|
|
// We're out of ammo
|
|
if ( burstcount == 0 )
|
|
burstcount = -1;
|
|
|
|
ForceIdle();
|
|
return;
|
|
}
|
|
}
|
|
} */
|
|
|
|
if ( usesameclip )
|
|
clipToUse = FIRE_MODE1;
|
|
else
|
|
clipToUse = mode;
|
|
|
|
// Calc the amount the clip should get
|
|
amount = ammo_clip_size[clipToUse] - ammo_in_clip[clipToUse];
|
|
|
|
assert( owner );
|
|
if ( owner && owner->isClient() && !UnlimitedAmmo( mode ) )
|
|
{
|
|
// use up the ammo from the player
|
|
amount_used = owner->UseAmmo( ammo_type[mode], amount );
|
|
|
|
// Stick it in the clip
|
|
if ( ammo_clip_size[clipToUse] )
|
|
ammo_in_clip[clipToUse] = amount_used + ammo_in_clip[clipToUse];
|
|
|
|
assert( ammo_in_clip[clipToUse] <= ammo_clip_size[clipToUse] );
|
|
if ( ammo_in_clip[clipToUse] > ammo_clip_size[clipToUse] )
|
|
ammo_in_clip[clipToUse] = ammo_clip_size[clipToUse];
|
|
|
|
if ( burstmode[curmode] && ( ammo_in_clip[clipToUse] >= burstcountmax ) )
|
|
burstcount = burstcountmax;
|
|
}
|
|
owner->AmmoAmountInClipChanged( ammo_type[mode], ammo_in_clip[clipToUse] );
|
|
|
|
ForceIdle();
|
|
}
|
|
|
|
void Weapon::DoneReloadingBurst( Event *ev )
|
|
{
|
|
//int amount;
|
|
//int amount_used;
|
|
firemode_t mode;
|
|
int inBurstMode;
|
|
firemode_t clipToUse;
|
|
|
|
// Get the mode from the passed in event
|
|
mode = (firemode_t)ev->GetInteger( 1 );
|
|
|
|
assert( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) );
|
|
|
|
if ( !( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) ) )
|
|
warning( "Weapon::DoneReloading", "Invalid mode %d\n", mode );
|
|
|
|
// If we need to do a REAL reload (not a burst reload) we skip the test
|
|
// altogether.
|
|
firemode_t realmode = mode;
|
|
//if ( usesameclip )
|
|
// mode = FIRE_MODE1;
|
|
|
|
// Make sure we are actually in burst mode
|
|
|
|
inBurstMode = false;
|
|
|
|
if ( switchmode )
|
|
inBurstMode = burstmode[curmode];
|
|
else
|
|
inBurstMode = burstmode[realmode];
|
|
|
|
if ( !inBurstMode )
|
|
return;
|
|
|
|
// Add to the burst count
|
|
|
|
int tmpamount = 0;
|
|
Ammo *ammo;
|
|
|
|
ammo = owner->FindAmmoByName( ammo_type[mode] );
|
|
|
|
if ( ammo )
|
|
{
|
|
tmpamount = owner->AmmoCount( ammo_type[mode] );
|
|
|
|
// Try the clip ammo if we have none in our main inventory
|
|
|
|
if ( usesameclip )
|
|
clipToUse = FIRE_MODE1;
|
|
else
|
|
clipToUse = mode;
|
|
|
|
if ( tmpamount == 0 )
|
|
tmpamount = ammo_in_clip[clipToUse];
|
|
|
|
if ( tmpamount > burstcountmax )
|
|
burstcount = burstcountmax;
|
|
else
|
|
burstcount = tmpamount;
|
|
|
|
// We're out of ammo
|
|
|
|
if ( burstcount == 0 )
|
|
burstcount = -1;
|
|
|
|
ForceIdle();
|
|
return;
|
|
}
|
|
}
|
|
|
|
qboolean Weapon::CheckReload( void )
|
|
{
|
|
return CheckReload( curmode );
|
|
}
|
|
|
|
//======================
|
|
//Weapon::CheckReload - Checks to see if we NEED to reload the weapon
|
|
//======================
|
|
qboolean Weapon::CheckReload( firemode_t mode )
|
|
{
|
|
int inBurstMode;
|
|
firemode_t clipToUse;
|
|
|
|
// Check to see if the weapon needs to be reloaded
|
|
assert( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) );
|
|
|
|
if ( !( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) ) )
|
|
{
|
|
warning( "Weapon::CheckReload", "Invalid mode %d\n", mode );
|
|
return false;
|
|
}
|
|
|
|
if ( !_autoReload )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ( UnlimitedAmmo( mode ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ( putaway )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ( weaponstate != WEAPON_READY )
|
|
return false;
|
|
|
|
// If we're a burst mode weapon, see if we need to "reload"
|
|
|
|
inBurstMode = false;
|
|
|
|
if ( switchmode )
|
|
inBurstMode = burstmode[curmode];
|
|
else
|
|
inBurstMode = burstmode[mode];
|
|
|
|
firemode_t oldmode = mode;
|
|
|
|
if ( inBurstMode && ( weaponstate != WEAPON_RELOADING ) && ( burstcount <= 0 ) )
|
|
{
|
|
Event *doneReloadingEvent;
|
|
doneReloadingEvent = new Event( EV_Weapon_DoneReloadingBurst );
|
|
doneReloadingEvent->AddInteger( oldmode );
|
|
|
|
if ( _burstModeDelay[ mode ] > 0.0f )
|
|
{
|
|
animate->RandomAnimate( "reload_burst" );
|
|
PostEvent( doneReloadingEvent, _burstModeDelay[ mode ] );
|
|
}
|
|
else
|
|
{
|
|
animate->RandomAnimate( "reload_burst", doneReloadingEvent );
|
|
}
|
|
|
|
weaponstate = WEAPON_RELOADING;
|
|
return true;
|
|
}
|
|
|
|
mode = oldmode;
|
|
|
|
if ( usesameclip )
|
|
clipToUse = FIRE_MODE1;
|
|
else
|
|
clipToUse = mode;
|
|
|
|
if ( ammo_clip_size[clipToUse] && ( ammo_in_clip[clipToUse] < ammorequired[mode] ) && ( AmmoAvailable( mode ) >= ammorequired[mode] ) )
|
|
{
|
|
Event *ev1;
|
|
|
|
ev1 = new Event( EV_Weapon_DoneReloading );
|
|
ev1->AddInteger( mode );
|
|
|
|
if ( animate->HasAnim( "reload_normal" ) && !multiplayerManager.skipWeaponReloads() )
|
|
{
|
|
weaponstate = WEAPON_RELOADING;
|
|
animate->RandomAnimate( "reload_normal", ev1 );
|
|
}
|
|
else
|
|
{
|
|
ProcessEvent( ev1 );
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// We're a regenerating weapon out of ammo
|
|
/* if ( !AmmoAvailable(mode) && ( regenAmount > 0 ) )
|
|
{
|
|
Event *ev1;
|
|
|
|
ev1 = new Event( EV_Weapon_DoneReloading );
|
|
ev1->AddInteger( mode );
|
|
|
|
if ( animate->HasAnim( "idle_special" ) )
|
|
{
|
|
weaponstate = WEAPON_RELOADING;
|
|
animate->RandomAnimate( "idle_special", ev1 );
|
|
}
|
|
else
|
|
{
|
|
ProcessEvent( ev1 );
|
|
}
|
|
return true;
|
|
} */
|
|
|
|
return false;
|
|
}
|
|
|
|
//======================
|
|
//Weapon::ForceReload - Reload the clip if it's not full already
|
|
//======================
|
|
qboolean Weapon::ForceReload( void )
|
|
{
|
|
// Only primary mode can reload
|
|
firemode_t mode = FIRE_MODE1;
|
|
firemode_t clipToUse;
|
|
|
|
// Weapon has to be in the ready state
|
|
|
|
if ( !canReload() )
|
|
return false;
|
|
|
|
// Make sure it's not put away
|
|
if ( putaway )
|
|
return false;
|
|
|
|
// We can't reload regenerating weapons
|
|
if ( _regenAmount[ FIRE_MODE1 ] > 0 )
|
|
return false;
|
|
|
|
if ( usesameclip )
|
|
clipToUse = FIRE_MODE1;
|
|
else
|
|
clipToUse = mode;
|
|
|
|
// If our clip is not full and we have ammo available...
|
|
// HACK: targetidle is currently only used on the TOW weapon,
|
|
// so instead of making an entirely new event JUST for this, we use it here.
|
|
if ( ( ( ammo_clip_size[clipToUse] != ammo_in_clip[clipToUse] ) && AmmoAvailable( mode ) ) || targetidle)
|
|
{
|
|
Event *ev1;
|
|
|
|
ev1 = new Event( EV_Weapon_DoneReloading );
|
|
ev1->AddInteger( mode );
|
|
|
|
if ( animate->HasAnim( "reload_normal" ) )
|
|
{
|
|
weaponstate = WEAPON_RELOADING;
|
|
animate->RandomAnimate( "reload_normal", ev1 );
|
|
}
|
|
else
|
|
{
|
|
ProcessEvent( ev1 );
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//======================
|
|
//Weapon::Idle
|
|
//======================
|
|
void Weapon::Idle( Event *ev )
|
|
{
|
|
ForceIdle();
|
|
}
|
|
|
|
//======================
|
|
//Weapon::GetMaxRange
|
|
//======================
|
|
float Weapon::GetMaxRange( void )
|
|
{
|
|
return maxrange;
|
|
}
|
|
|
|
//======================
|
|
//Weapon::GetMinRange
|
|
//======================
|
|
float Weapon::GetMinRange( void )
|
|
{
|
|
return minrange;
|
|
}
|
|
|
|
//======================
|
|
//Weapon::SetMaxRangeEvent
|
|
//======================
|
|
void Weapon::SetMaxRangeEvent( Event *ev )
|
|
{
|
|
maxrange = ev->GetFloat( 1 );
|
|
}
|
|
|
|
//======================
|
|
//Weapon::SetMinRangeEvent
|
|
//======================
|
|
void Weapon::SetMinRangeEvent( Event *ev )
|
|
{
|
|
minrange = ev->GetFloat( 1 );
|
|
}
|
|
|
|
//======================
|
|
//Weapon::NotDroppableEvent
|
|
//======================
|
|
void Weapon::NotDroppableEvent( Event *ev )
|
|
{
|
|
notdroppable = true;
|
|
}
|
|
|
|
//======================
|
|
//Weapon::SetMaxRange
|
|
//======================
|
|
void Weapon::SetMaxRange( float val )
|
|
{
|
|
maxrange = val;
|
|
}
|
|
|
|
//======================
|
|
//Weapon::SetMinRange
|
|
//======================
|
|
void Weapon::SetMinRange( float val )
|
|
{
|
|
minrange = val;
|
|
}
|
|
|
|
//======================
|
|
//Weapon::WeaponSound
|
|
//======================
|
|
void Weapon::WeaponSound( Event *ev )
|
|
{
|
|
Event *e;
|
|
|
|
// Broadcasting a sound can be time consuming. Only do it once in a while on really fast guns.
|
|
if ( nextweaponsoundtime > level.time )
|
|
{
|
|
if ( owner )
|
|
{
|
|
owner->BroadcastSound(SOUND_RADIUS, SOUNDTYPE_WEAPONFIRE);;
|
|
}
|
|
else
|
|
{
|
|
BroadcastSound(SOUND_RADIUS, SOUNDTYPE_WEAPONFIRE);;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if ( owner )
|
|
{
|
|
e = new Event( ev );
|
|
owner->ProcessEvent( e );
|
|
}
|
|
else
|
|
{
|
|
Item::BroadcastSound();
|
|
}
|
|
|
|
// give us some breathing room
|
|
nextweaponsoundtime = level.time + 0.4f;
|
|
}
|
|
|
|
//======================
|
|
//Weapon::Removable
|
|
//======================
|
|
qboolean Weapon::Removable( void )
|
|
{
|
|
if ( multiplayerManager.checkFlag( MP_FLAG_WEAPONS_STAY ) && Respawnable() )
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
//======================
|
|
//Weapon::Pickupable
|
|
//======================
|
|
qboolean Weapon::Pickupable( Entity *other )
|
|
{
|
|
Sentient *sen;
|
|
|
|
if ( !other->isSubclassOf( Sentient ) )
|
|
{
|
|
return false;
|
|
}
|
|
else if ( !other->isClient() )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ( getSolidType() == SOLID_NOT )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if ( multiplayerManager.inMultiplayer() && other->isSubclassOf( Player ) )
|
|
{
|
|
if ( !multiplayerManager.canPickup( (Player *)other, getMultiplayerItemType(), getName().c_str() ) )
|
|
return false;
|
|
}
|
|
|
|
sen = ( Sentient * )other;
|
|
|
|
//FIXME
|
|
// This should be in player
|
|
|
|
// If we have the weapon and weapons stay, then don't pick it up
|
|
if ( ( multiplayerManager.checkFlag( MP_FLAG_WEAPONS_STAY ) ) && Respawnable() )
|
|
{
|
|
Weapon *weapon;
|
|
|
|
weapon = ( Weapon * )sen->FindItem( getName() );
|
|
|
|
if ( weapon )
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//======================
|
|
//Weapon::AutoChange
|
|
//======================
|
|
qboolean Weapon::AutoChange( void )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
//======================
|
|
//Weapon::ClipAmmo
|
|
//======================
|
|
int Weapon::ClipAmmo( firemode_t mode )
|
|
{
|
|
firemode_t clipToUse;
|
|
|
|
assert( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) );
|
|
|
|
if ( !( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) ) )
|
|
warning( "Weapon::ClipAmmo", "Invalid mode %d\n", mode );
|
|
|
|
if ( usesameclip )
|
|
clipToUse = FIRE_MODE1;
|
|
else
|
|
clipToUse = mode;
|
|
|
|
if (ammo_clip_size[clipToUse])
|
|
return ammo_in_clip[clipToUse];
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
//======================
|
|
//Weapon::ProcessWeaponCommandsEvent
|
|
//======================
|
|
void Weapon::ProcessWeaponCommandsEvent( Event *ev )
|
|
{
|
|
int index;
|
|
|
|
index = ev->GetInteger( 1 );
|
|
ProcessInitCommands( index );
|
|
}
|
|
|
|
//======================
|
|
//Weapon::SetActionLevelIncrement
|
|
//======================
|
|
void Weapon::SetActionLevelIncrement( Event *ev )
|
|
{
|
|
assert( ( firemodeindex >= 0 ) && ( firemodeindex < MAX_FIREMODES ) );
|
|
action_level_increment[firemodeindex] = ev->GetInteger( 1 );
|
|
}
|
|
|
|
//======================
|
|
//Weapon::ActionLevelIncrement
|
|
//======================
|
|
int Weapon::ActionLevelIncrement( firemode_t mode )
|
|
{
|
|
assert( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) );
|
|
|
|
if ( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) )
|
|
return action_level_increment[mode];
|
|
else
|
|
{
|
|
warning( "Weapon::ActionLevelIncrement", "Invalid mode %d\n", mode );
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
//======================
|
|
//Weapon::IsDroppable
|
|
//======================
|
|
qboolean Weapon::IsDroppable( void )
|
|
{
|
|
if ( notdroppable )
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
//======================
|
|
//Weapon::SetFireType
|
|
//======================
|
|
void Weapon::SetFireType( Event *ev )
|
|
{
|
|
str ftype;
|
|
|
|
ftype = ev->GetString( 1 );
|
|
|
|
assert( ( firemodeindex >= 0 ) && ( firemodeindex < MAX_FIREMODES ) );
|
|
|
|
if ( !ftype.icmp( "projectile" ) )
|
|
firetype[firemodeindex] = FT_PROJECTILE;
|
|
else if ( !ftype.icmp( "bullet" ) )
|
|
firetype[firemodeindex] = FT_BULLET;
|
|
else if ( !ftype.icmp( "melee" ) )
|
|
firetype[firemodeindex] = FT_MELEE;
|
|
else if ( !ftype.icmp( "special_projectile" ) )
|
|
firetype[firemodeindex] = FT_SPECIAL_PROJECTILE;
|
|
else if ( !ftype.icmp( "none" ) )
|
|
firetype[firemodeindex] = FT_NONE;
|
|
else if ( !ftype.icmp( "explosion" ) )
|
|
firetype[firemodeindex] = FT_EXPLOSION;
|
|
else if ( !ftype.icmp( "triggerProjectile" ) )
|
|
firetype[firemodeindex] = FT_TRIGGER_PROJECTILE;
|
|
else if ( !ftype.icmp( "controlProjectile" ) )
|
|
firetype[firemodeindex] = FT_CONTROL_PROJECTILE;
|
|
else if ( !ftype.icmp( "controlZoom" ) )
|
|
firetype[firemodeindex] = FT_CONTROL_ZOOM;
|
|
else
|
|
warning( "Weapon::SetFireType", "unknown firetype: %s\n", ftype.c_str() );
|
|
}
|
|
|
|
//======================
|
|
//Weapon::GetFireType
|
|
//======================
|
|
firetype_t Weapon::GetFireType( firemode_t mode )
|
|
{
|
|
return firetype[mode];
|
|
}
|
|
|
|
//======================
|
|
//Weapon::SetProjectile
|
|
//======================
|
|
void Weapon::SetProjectile( Event *ev )
|
|
{
|
|
assert( ( firemodeindex >= 0 ) && ( firemodeindex < MAX_FIREMODES ) );
|
|
projectileModel[firemodeindex] = ev->GetString( 1 );
|
|
CacheResource( projectileModel[firemodeindex].c_str(), this );
|
|
}
|
|
|
|
//======================
|
|
//Weapon::SetBulletDamage
|
|
//======================
|
|
void Weapon::SetBulletDamage( Event *ev )
|
|
{
|
|
assert( ( firemodeindex >= 0 ) && ( firemodeindex < MAX_FIREMODES ) );
|
|
bulletdamage[firemodeindex] = ev->GetFloat( 1 );
|
|
}
|
|
|
|
//======================
|
|
//Weapon::SetBulletKnockback
|
|
//======================
|
|
void Weapon::SetBulletKnockback( Event *ev )
|
|
{
|
|
assert( ( firemodeindex >= 0 ) && ( firemodeindex < MAX_FIREMODES ) );
|
|
bulletknockback[firemodeindex] = ev->GetFloat( 1 );
|
|
}
|
|
|
|
//======================
|
|
//Weapon::SetBulletRange
|
|
//======================
|
|
void Weapon::SetBulletRange( Event *ev )
|
|
{
|
|
assert( ( firemodeindex >= 0 ) && ( firemodeindex < MAX_FIREMODES ) );
|
|
bulletrange[firemodeindex] = ev->GetFloat( 1 );
|
|
}
|
|
|
|
//======================
|
|
//Weapon::SetRange
|
|
//======================
|
|
void Weapon::SetRange( Event *ev )
|
|
{
|
|
SetBulletRange( ev );
|
|
}
|
|
|
|
//======================
|
|
//Weapon::SetBulletCount
|
|
//======================
|
|
void Weapon::SetBulletCount( Event *ev )
|
|
{
|
|
assert( ( firemodeindex >= 0 ) && ( firemodeindex < MAX_FIREMODES ) );
|
|
bulletcount[firemodeindex] = ev->GetFloat( 1 );
|
|
}
|
|
|
|
void Weapon::SetBulletSpread( float spreadX , float spreadY )
|
|
{
|
|
assert( ( firemodeindex >= 0 ) && ( firemodeindex < MAX_FIREMODES ) );
|
|
bulletspread[firemodeindex].x = spreadX;
|
|
bulletspread[firemodeindex].y = spreadY;
|
|
}
|
|
|
|
//======================
|
|
//Weapon::SetBulletSpread
|
|
//======================
|
|
void Weapon::SetBulletSpread( Event *ev )
|
|
{
|
|
assert( ( firemodeindex >= 0 ) && ( firemodeindex < MAX_FIREMODES ) );
|
|
bulletspread[firemodeindex].x = ev->GetFloat( 1 );
|
|
if (ev->NumArgs() < 2) // this shouldn't happen, but there are assets that do it
|
|
bulletspread[firemodeindex].y = bulletspread[firemodeindex].x;
|
|
else
|
|
bulletspread[firemodeindex].y = ev->GetFloat( 2 );
|
|
if (ev->NumArgs() == 5) // expanding/shrinking spread
|
|
{
|
|
endbulletspread[firemodeindex].x = ev->GetFloat(3);
|
|
endbulletspread[firemodeindex].y = ev->GetFloat(4);
|
|
endbulletspread[firemodeindex].z = ev->GetFloat(5); // time interval
|
|
}
|
|
else
|
|
{
|
|
endbulletspread[firemodeindex].z = 0; // make sure spread is constant if it's not variable (duh)
|
|
}
|
|
}
|
|
|
|
//======================
|
|
//Weapon::SetHand
|
|
//======================
|
|
void Weapon::SetHand( Event *ev )
|
|
{
|
|
str side;
|
|
|
|
side = ev->GetString( 1 );
|
|
|
|
if ( !stricmp( side.c_str(), "righthand" ) || !stricmp( side.c_str(), "right" ) )
|
|
hand = WEAPON_RIGHT;
|
|
else if ( !stricmp( side.c_str(), "lefthand" ) || !stricmp( side.c_str(), "left" ) )
|
|
hand = WEAPON_LEFT;
|
|
else if ( !stricmp( side.c_str(), "dualhand" ) || !stricmp( side.c_str(), "dual" ) )
|
|
hand = WEAPON_DUAL;
|
|
else if ( !stricmp( side.c_str(), "any" ) )
|
|
hand = WEAPON_ANY;
|
|
else
|
|
{
|
|
warning( "Weapon::SetHand", "Unknown side %s\n", side.c_str() );
|
|
assert( 0 );
|
|
}
|
|
}
|
|
|
|
//======================
|
|
//Weapon::ModeSet
|
|
//======================
|
|
void Weapon::ModeSet( Event *ev )
|
|
{
|
|
int i;
|
|
str modestr;
|
|
|
|
Event *modeev = new Event( ev->GetToken( 2 ) );
|
|
|
|
modestr = ev->GetToken( 1 );
|
|
|
|
firemodeindex = WeaponModeNameToNum(modestr);
|
|
|
|
for( i=3; i<=ev->NumArgs(); i++ )
|
|
{
|
|
modeev->AddToken( ev->GetToken( i ) );
|
|
}
|
|
|
|
ProcessEvent( modeev );
|
|
firemodeindex = FIRE_MODE1;
|
|
}
|
|
|
|
//====================
|
|
//Weapon::AutoAim
|
|
//====================
|
|
void Weapon::AutoAim( Event *ev )
|
|
{
|
|
if ( ev->NumArgs() > 0 )
|
|
{
|
|
autoAimTargetSelectionAngle = ev->GetInteger( 1 );
|
|
autoAimLockonAngle = ev->GetInteger( 2 );
|
|
}
|
|
else
|
|
{
|
|
autoAimTargetSelectionAngle = 60;
|
|
autoAimLockonAngle = 15;
|
|
}
|
|
}
|
|
|
|
//====================
|
|
//Weapon::Crosshair
|
|
//====================
|
|
void Weapon::Crosshair( Event *ev )
|
|
{
|
|
crosshair = ev->GetBoolean( 1 );
|
|
}
|
|
|
|
//====================
|
|
//Weapon::TorsoAim
|
|
//====================
|
|
void Weapon::TorsoAim( Event *ev )
|
|
{
|
|
torsoaim = ev->GetBoolean( 1 );
|
|
}
|
|
|
|
//====================
|
|
//Weapon::LeftAttachToTag
|
|
//====================
|
|
void Weapon::LeftAttachToTag( Event *ev )
|
|
{
|
|
left_attachToTag = ev->GetString( 1 );
|
|
}
|
|
|
|
//====================
|
|
//Weapon::RightAttachToTag
|
|
//====================
|
|
void Weapon::RightAttachToTag( Event *ev )
|
|
{
|
|
right_attachToTag = ev->GetString( 1 );
|
|
}
|
|
|
|
//====================
|
|
//Weapon::DualAttachToTag
|
|
//====================
|
|
void Weapon::DualAttachToTag( Event *ev )
|
|
{
|
|
dual_attachToTag = ev->GetString( 1 );
|
|
}
|
|
|
|
//====================
|
|
//Weapon::LeftHolsterAttachToTag
|
|
//====================
|
|
void Weapon::LeftHolsterAttachToTag( Event *ev )
|
|
{
|
|
leftholster_attachToTag = ev->GetString( 1 );
|
|
}
|
|
|
|
//====================
|
|
//Weapon::RightHolsterAttachToTag
|
|
//====================
|
|
void Weapon::RightHolsterAttachToTag( Event *ev )
|
|
{
|
|
rightholster_attachToTag = ev->GetString( 1 );
|
|
}
|
|
|
|
//====================
|
|
//Weapon::DualHolsterAttachToTag
|
|
//====================
|
|
void Weapon::DualHolsterAttachToTag( Event *ev )
|
|
{
|
|
dualholster_attachToTag = ev->GetString( 1 );
|
|
}
|
|
|
|
//====================
|
|
//Weapon::SetLeftHolsterAngles
|
|
//====================
|
|
void Weapon::SetLeftHolsterAngles( Event *ev )
|
|
{
|
|
leftHolsterAngles = ev->GetVector( 1 );
|
|
}
|
|
|
|
//====================
|
|
//Weapon::SetRightHolsterAngles
|
|
//====================
|
|
void Weapon::SetRightHolsterAngles( Event *ev )
|
|
{
|
|
rightHolsterAngles = ev->GetVector( 1 );
|
|
}
|
|
|
|
//====================
|
|
//Weapon::SetDualHolsterAngles
|
|
//====================
|
|
void Weapon::SetDualHolsterAngles( Event *ev )
|
|
{
|
|
dualHolsterAngles = ev->GetVector( 1 );
|
|
}
|
|
|
|
//====================
|
|
//Weapon::SetHolsterScale
|
|
//====================
|
|
void Weapon::SetHolsterScale( Event *ev )
|
|
{
|
|
holsterScale = ev->GetFloat( 1 );
|
|
}
|
|
|
|
void Weapon::setWeildedScale( Event *ev )
|
|
{
|
|
_weildedScale = ev->GetFloat( 1 );
|
|
}
|
|
|
|
//====================
|
|
//Weapon::SetQuiet
|
|
//====================
|
|
void Weapon::SetQuiet( Event *ev )
|
|
{
|
|
quiet = true;
|
|
}
|
|
|
|
//====================
|
|
//Weapon::SetLoopFire
|
|
//====================
|
|
void Weapon::SetLoopFire( Event *ev )
|
|
{
|
|
assert( ( firemodeindex >= 0 ) && ( firemodeindex < MAX_FIREMODES ) );
|
|
loopfire[firemodeindex] = true;
|
|
}
|
|
/*
|
|
void Weapon::SetFullAnimFire( Event *ev )
|
|
{
|
|
assert( ( firemodeindex >= 0 ) && ( firemodeindex < MAX_FIREMODES ) );
|
|
fullanimfire[firemodeindex] = true;
|
|
}
|
|
*/
|
|
|
|
//======================
|
|
//Weapon::SetMeansOfDeath
|
|
//======================
|
|
void Weapon::SetMeansOfDeath( Event *ev )
|
|
{
|
|
assert( ( firemodeindex >= 0 ) && ( firemodeindex < MAX_FIREMODES ) );
|
|
meansofdeath[firemodeindex] = (meansOfDeath_t )MOD_NameToNum( ev->GetString( 1 ) );
|
|
}
|
|
|
|
//======================
|
|
//Weapon::GetMeansOfDeath
|
|
//======================
|
|
meansOfDeath_t Weapon::GetMeansOfDeath( firemode_t mode )
|
|
{
|
|
assert( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) );
|
|
|
|
if ( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) )
|
|
return meansofdeath[mode];
|
|
else
|
|
{
|
|
warning( "Weapon::GetMeansOfDeath", "Invalid mode %d\n", mode );
|
|
return MOD_NONE;
|
|
}
|
|
}
|
|
|
|
//======================
|
|
//Weapon::SetAimTarget
|
|
//======================
|
|
void Weapon::SetAimTarget( Entity *ent )
|
|
{
|
|
aim_target = ent;
|
|
}
|
|
|
|
//======================
|
|
//Weapon::WorldHitSpawn
|
|
//======================
|
|
void Weapon::WorldHitSpawn( firemode_t mode, const Vector &origin, const Vector &angles, float life )
|
|
{
|
|
if ( !worldhitspawn[mode].length() )
|
|
return;
|
|
|
|
Entity::SpawnEffect(worldhitspawn[mode], origin, angles, life);
|
|
}
|
|
|
|
//======================
|
|
//Weapon::SetWorldHitSpawn
|
|
//======================
|
|
void Weapon::SetWorldHitSpawn( Event *ev )
|
|
{
|
|
assert( ( firemodeindex >= 0 ) && ( firemodeindex < MAX_FIREMODES ) );
|
|
worldhitspawn[firemodeindex] = ev->GetString( 1 );
|
|
}
|
|
|
|
void Weapon::MakeNoise( Event *ev )
|
|
{
|
|
float radius = 500.0f;
|
|
qboolean force = false;
|
|
|
|
if ( ev->NumArgs() > 0 )
|
|
radius = ev->GetFloat( 1 );
|
|
|
|
if ( ev->NumArgs() > 1 )
|
|
force = ev->GetBoolean( 2 );
|
|
|
|
if ( attached && ( next_noise_time <= level.time || force ) )
|
|
{
|
|
BroadcastSound( radius , SOUNDTYPE_WEAPONFIRE );
|
|
next_noise_time = level.time + 1.0f;
|
|
}
|
|
}
|
|
|
|
void Weapon::SetViewModel( Event *ev )
|
|
{
|
|
if ( ev->NumArgs() > 0 )
|
|
{
|
|
viewmodel = ev->GetString( 1 );
|
|
|
|
gi.setviewmodel( edict, viewmodel );
|
|
//setViewModel( viewmodel );
|
|
}
|
|
}
|
|
|
|
void Weapon::DonePutaway( Event *ev )
|
|
{
|
|
//int i;
|
|
|
|
// Tell the state machine we're lowering the weapon
|
|
// so it will continue to do it's normal deactivate code
|
|
weaponstate = WEAPON_LOWERING;
|
|
|
|
if ( zoomed )
|
|
{
|
|
CancelEventsOfType( EV_Weapon_Zoom );
|
|
ProcessEvent( EV_Weapon_Zoom );
|
|
}
|
|
|
|
if ( _controllingProjectile )
|
|
{
|
|
toggleProjectileControl();
|
|
}
|
|
|
|
// No longer targeting anyone
|
|
|
|
//SetTargetedEntity( NULL );
|
|
|
|
if ( targetidle )
|
|
CancelEventsOfType( EV_Weapon_TargetIdleThink );
|
|
|
|
// Move ammo from weapon back to owner if possible
|
|
|
|
/* if ( owner )
|
|
{
|
|
for ( i = 0 ; i < MAX_FIREMODES ; i++ )
|
|
{
|
|
if ( ammo_in_clip[ i ] )
|
|
{
|
|
int maxAmount;
|
|
int amount;
|
|
|
|
maxAmount = owner->MaxAmmoCount( ammo_type[ i ] ) - owner->AmmoCount( ammo_type[ i ] );
|
|
|
|
if ( maxAmount > ammo_in_clip[ i ] )
|
|
amount = ammo_in_clip[ i ];
|
|
else
|
|
amount = maxAmount;
|
|
|
|
owner->GiveAmmo( ammo_type[ i ], amount, false );
|
|
ammo_in_clip[ i ] -= amount;
|
|
owner->AmmoAmountInClipChanged( ammo_type[ i ], ammo_in_clip[ i ] );
|
|
}
|
|
}
|
|
} */
|
|
}
|
|
|
|
void Weapon::SetRegenAmmo( Event *ev )
|
|
{
|
|
if ( ev->NumArgs() > 0 )
|
|
{
|
|
_regenAmount[ firemodeindex ] = ev->GetInteger( 1 );
|
|
|
|
_regenTime[ firemodeindex ] = 1.0; // default time
|
|
}
|
|
|
|
if ( ev->NumArgs() > 1 )
|
|
{
|
|
_regenTime[ firemodeindex ] = ev->GetFloat( 2 );
|
|
}
|
|
|
|
turnThinkOn();
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: SetRegenOnlyWhenIdle
|
|
// Class: Weapon
|
|
//
|
|
// Description: Specifies that this weapon only regenerates ammo when it is idle (not shooting)
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: none
|
|
//----------------------------------------------------------------
|
|
|
|
void Weapon::SetRegenOnlyWhenIdle( Event *ev )
|
|
{
|
|
_regenOnlyWhenIdle[ firemodeindex ] = true;
|
|
}
|
|
|
|
void Weapon::ChangeIdle( Event *ev )
|
|
{
|
|
ForceIdle();
|
|
|
|
if ( !owner )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
void Weapon::DrawBowStrain( Event *ev )
|
|
{
|
|
if ( animate->HasAnim( "draw_strain" ) )
|
|
animate->RandomAnimate( "draw_strain" );
|
|
}
|
|
|
|
void Weapon::AltDrawBowStrain( Event *ev )
|
|
{
|
|
if ( animate->HasAnim( "alternate_draw_strain" ) )
|
|
animate->RandomAnimate( "alternate_draw_strain" );
|
|
}
|
|
|
|
void Weapon::SetAccuracy( Event *ev )
|
|
{
|
|
if ( ev->NumArgs() < 6 )
|
|
{
|
|
gi.DPrintf("SetAccuracy: Too few parameters\n");
|
|
return;
|
|
}
|
|
firemode_t mode = WeaponModeNameToNum( ev->GetToken( 1 ) );
|
|
accuracy[mode][ACCURACY_STOPPED] = ev->GetFloat( 2 );
|
|
accuracy[mode][ACCURACY_CHANGE] = ev->GetFloat( 3 );
|
|
accuracy[mode][ACCURACY_WALK] = ev->GetFloat( 4 );
|
|
accuracy[mode][ACCURACY_RUN] = ev->GetFloat( 5 );
|
|
accuracy[mode][ACCURACY_CROUCH] = ev->GetFloat( 6 );
|
|
}
|
|
|
|
void Weapon::SetZoomFOV( Event *ev )
|
|
{
|
|
if ( ev->NumArgs() > 0 )
|
|
{
|
|
zoomfov = ev->GetFloat( 1 );
|
|
}
|
|
}
|
|
|
|
void Weapon::SetReticuleTime( Event *ev )
|
|
{
|
|
if ( ev->NumArgs() > 0 )
|
|
reticuletime = ev->GetFloat( 1 );
|
|
}
|
|
|
|
void Weapon::SetStartZoom( Event* ev )
|
|
{
|
|
if(ev == 0)
|
|
return;
|
|
|
|
startzoom = ev->GetFloat(1);
|
|
}
|
|
|
|
void Weapon::SetEndZoom( Event* ev )
|
|
{
|
|
if(ev == 0)
|
|
return;
|
|
|
|
endzoom = ev->GetFloat(1);
|
|
}
|
|
|
|
void Weapon::SetZoomTime( Event* ev )
|
|
{
|
|
if(ev == 0)
|
|
return;
|
|
|
|
zoomtime = ev->GetFloat(1);
|
|
}
|
|
|
|
void Weapon::SetAimType( Event *ev )
|
|
{
|
|
|
|
str aimstr;
|
|
|
|
Sentient *owner;
|
|
Player *player = NULL;
|
|
owner = this->owner;
|
|
assert( owner );
|
|
if ( owner->isSubclassOf( Player ) )
|
|
player = ( Player * )owner;
|
|
|
|
if ( ev->NumArgs() > 0 )
|
|
aimstr = ev->GetString( 1 );
|
|
|
|
// Crouching is a special case... you'll always have the "crouch" accuracy
|
|
// rating in your crouched, regardless of whether you're walking or not.
|
|
if ( player && player->GetCrouch() || ( aimstr == "crouch" ) )
|
|
aimtype = ACCURACY_CROUCH;
|
|
else
|
|
{
|
|
if ( aimstr == "stopped" )
|
|
aimtype = ACCURACY_STOPPED;
|
|
if ( aimstr == "walk" )
|
|
aimtype = ACCURACY_WALK;
|
|
if ( aimstr == "run" )
|
|
aimtype = ACCURACY_RUN;
|
|
if ( aimstr == "change" )
|
|
aimtype = ACCURACY_CHANGE;
|
|
}
|
|
|
|
if ( ( aimstr != "stopped" ) && ( aimstr != "walk" ) && ( aimstr != "run" ) && ( aimstr != "crouch" ) && ( aimstr != "change" ) )
|
|
{
|
|
warning("SetAimType: Invalid aimtype, %s, defaulting to stopped",aimstr);
|
|
aimtype = ACCURACY_STOPPED;
|
|
}
|
|
|
|
if ( g_showaccuracymod->integer )
|
|
gi.DPrintf("Accuracy Mod: %s = %f\n", aimstr.c_str(), accuracy[curmode][aimtype] );
|
|
}
|
|
|
|
void Weapon::SetFireTimer( Event *ev )
|
|
{
|
|
assert( ( firemodeindex >= 0 ) && ( firemodeindex < MAX_FIREMODES ) );
|
|
|
|
fire_timer[firemodeindex] = ev->GetFloat( 1 );
|
|
}
|
|
|
|
void Weapon::UseSameClip( Event *ev )
|
|
{
|
|
usesameclip = true;
|
|
}
|
|
|
|
qboolean Weapon::HasFullClip( void )
|
|
{
|
|
firemode_t mode = FIRE_MODE1;
|
|
firemode_t clipToUse;
|
|
|
|
if ( usesameclip )
|
|
clipToUse = FIRE_MODE1;
|
|
else
|
|
clipToUse = mode;
|
|
|
|
if ( ammo_in_clip[clipToUse] == ammo_clip_size[clipToUse] )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
void Weapon::SetMaxModes( Event *ev )
|
|
{
|
|
if ( ev->NumArgs() < 1 )
|
|
{
|
|
maxmode = FIRE_MODE2;
|
|
return;
|
|
}
|
|
|
|
maxmode = WeaponModeNameToNum( ev->GetToken( 1 ) );
|
|
}
|
|
|
|
void Weapon::SetSwitchMode( Event *ev )
|
|
{
|
|
switchmode = true;
|
|
}
|
|
|
|
// Target Idle Weapon functions
|
|
void Weapon::TargetIdle( Event *ev )
|
|
{
|
|
targetidle = true;
|
|
}
|
|
|
|
void Weapon::TargetIdleThink( Event *ev )
|
|
{
|
|
CancelEventsOfType( EV_Weapon_TargetIdleThink );
|
|
|
|
// HACK sortof: If the weapon is playing it's put away animation,
|
|
// we don't do this event. For some reason a CancelEventsOfType
|
|
// call in the Putaway function failed to cancel this event.
|
|
if ( animate->GetName() == "putaway" )
|
|
return;
|
|
|
|
PostEvent( EV_Weapon_TargetIdleThink, TargetIdleTime );
|
|
|
|
Sentient *owner;
|
|
Player *player;
|
|
owner = this->owner;
|
|
assert( owner );
|
|
|
|
if ( owner->isSubclassOf( Player ) )
|
|
{
|
|
player = ( Player * )owner;
|
|
Vector pos, forward, right, up, endpoint, vorg;
|
|
GetMuzzlePosition( &pos, &forward, &right, &up );
|
|
vorg = player->origin;
|
|
vorg.z += player->viewheight;
|
|
|
|
endpoint = vorg + (forward * 4000.0f);
|
|
trace_t trace = G_Trace( pos, vec_zero, vec_zero, endpoint, player, MASK_SHOT, true, "Weapon::TargetIdleThink" );
|
|
if ( trace.ent && ( trace.entityNum != ENTITYNUM_WORLD ) && trace.ent->entity->isSubclassOf( Sentient ))
|
|
{
|
|
if ( !trace.ent->entity->deadflag )
|
|
{
|
|
if ( !strstr(animate->GetName(), "idle_target") )
|
|
animate->RandomAnimate( "idle_target" );
|
|
targetidleflag = true;
|
|
}
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if ( targetidleflag )
|
|
{
|
|
targetidleflag = false;
|
|
ForceIdle();
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
// ****************************
|
|
|
|
// Weapon Mode switching functions
|
|
void Weapon::SwitchMode( void )
|
|
{
|
|
char anim[128];
|
|
|
|
Event *ev1;
|
|
ev1 = new Event( EV_Weapon_DoneSwitchToMiddle );
|
|
|
|
strcpy(anim,"");
|
|
sprintf(anim,"switch_mode%d_neutral",(int)curmode+1);
|
|
|
|
if ( animate->HasAnim( anim ) )
|
|
{
|
|
weaponstate = WEAPON_SWITCHINGMODE;
|
|
animate->RandomAnimate( anim, ev1 );
|
|
}
|
|
else
|
|
{
|
|
ProcessEvent( ev1 );
|
|
}
|
|
}
|
|
|
|
void Weapon::DoneSwitchToMiddle( Event *ev )
|
|
{
|
|
int mode;
|
|
char anim[128];
|
|
|
|
Event *ev1;
|
|
ev1 = new Event( EV_Weapon_DoneSwitching );
|
|
|
|
if ( curmode == maxmode )
|
|
mode = FIRE_MODE1;
|
|
else
|
|
mode = (int)curmode + 1;
|
|
|
|
strcpy(anim,"");
|
|
sprintf(anim,"switch_mode%d",mode);
|
|
|
|
if ( animate->HasAnim( anim ) )
|
|
{
|
|
weaponstate = WEAPON_SWITCHINGMODE;
|
|
animate->RandomAnimate( anim, ev1 );
|
|
}
|
|
else
|
|
{
|
|
ProcessEvent( ev1 );
|
|
}
|
|
}
|
|
|
|
void Weapon::DoneSwitching( Event *ev )
|
|
{
|
|
if ( curmode == maxmode )
|
|
curmode = FIRE_MODE1;
|
|
else
|
|
curmode = (firemode_t)((int)curmode + 1);
|
|
|
|
weaponstate = WEAPON_READY;
|
|
|
|
// Clear our fire timer
|
|
INITIALIZE_WEAPONMODE_VAR(next_fire_time, 0.0);
|
|
|
|
ForceIdle();
|
|
}
|
|
// *************
|
|
|
|
void Weapon::SetBurstMode( Event *ev )
|
|
{
|
|
burstmode[firemodeindex] = true;
|
|
if ( ev->NumArgs() > 0 )
|
|
burstcountmax = ev->GetInteger( 1 );
|
|
else
|
|
burstcountmax = 10; // Default to 10
|
|
|
|
burstcount = burstcountmax;
|
|
}
|
|
|
|
void Weapon::setBurstModeDelay( Event *ev )
|
|
{
|
|
_burstModeDelay[ firemodeindex ] = ev->GetFloat( 1 );
|
|
}
|
|
|
|
void Weapon::SetCHOffset(int chx, int chy)
|
|
{
|
|
this->chx = chx;
|
|
this->chy = chy;
|
|
}
|
|
|
|
|
|
|
|
// GetTargetedEntity
|
|
//
|
|
// Returns the entity that is targeted by the weapon.
|
|
// If there is not an entity, 0 is returned.
|
|
void Weapon::CheckForTargetedEntity( void )
|
|
{
|
|
|
|
}
|
|
|
|
void Weapon::SetRealViewOrigin( const Vector &rv )
|
|
{
|
|
realvieworg = rv;
|
|
}
|
|
|
|
void Weapon::SetThirdPerson( qboolean tp )
|
|
{
|
|
thirdperson = tp;
|
|
}
|
|
|
|
qboolean Weapon::IsDoneFiring()
|
|
{
|
|
return donefiring;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: StartFiring
|
|
// Class: Weapon
|
|
//
|
|
// Description: Sets the start time used for bullet spread (for repeating weapons, this should be set in a prefire state)
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: none
|
|
//----------------------------------------------------------------
|
|
void Weapon::StartFiring( Event *ev )
|
|
{
|
|
startfiretime = level.time;
|
|
}
|
|
|
|
void Weapon::FinishedFiring( Event *ev )
|
|
{
|
|
int oldDoneFiring;
|
|
|
|
oldDoneFiring = donefiring;
|
|
|
|
donefiring = ev->GetInteger( 1 );
|
|
|
|
if ( shootingSkin )
|
|
ChangeSkin( shootingSkin, false );
|
|
|
|
if ( donefiring && !oldDoneFiring )
|
|
{
|
|
CheckReload();
|
|
}
|
|
}
|
|
|
|
void Weapon::Zoom( Event *ev )
|
|
{
|
|
Player *player = NULL;
|
|
|
|
if ( owner && owner->isSubclassOf( Player ) )
|
|
player = (Player *)(Sentient *)owner;
|
|
|
|
if ( !player )
|
|
return;
|
|
|
|
if ( zoomed )
|
|
{
|
|
endZoom();
|
|
}
|
|
else
|
|
{
|
|
zoomfov = startzoom;
|
|
startzoomtime = level.time;
|
|
zoomed = true;
|
|
|
|
player->SetFov( zoomfov, true );
|
|
player->client->ps.pm_flags |= PMF_ZOOM;
|
|
|
|
}
|
|
}
|
|
|
|
void Weapon::endZoom( Event *ev )
|
|
{
|
|
if ( zoomed )
|
|
_lastZoomFov = zoomfov;
|
|
else
|
|
_lastZoomFov = sv_defaultFov->value;
|
|
|
|
endZoom();
|
|
}
|
|
|
|
void Weapon::rezoom( Event *ev )
|
|
{
|
|
Player *player = NULL;
|
|
|
|
if ( owner && owner->isSubclassOf( Player ) )
|
|
player = (Player *)(Sentient *)owner;
|
|
|
|
if ( !player )
|
|
return;
|
|
|
|
if ( _lastZoomFov < sv_defaultFov->value )
|
|
{
|
|
zoomed = true;
|
|
zoomfov = _lastZoomFov;
|
|
|
|
player->SetFov( zoomfov, true );
|
|
player->client->ps.pm_flags |= PMF_ZOOM;
|
|
}
|
|
}
|
|
|
|
void Weapon::endZoom( void )
|
|
{
|
|
Player *player = NULL;
|
|
float defaultFov;
|
|
|
|
if ( owner && owner->isSubclassOf( Player ) )
|
|
player = (Player *)(Sentient *)owner;
|
|
|
|
if ( !player )
|
|
return;
|
|
|
|
defaultFov = player->getDefaultFov();
|
|
|
|
player->SetFov( defaultFov, true );
|
|
|
|
//remove the player client zoom flag
|
|
player->client->ps.pm_flags &= ~PMF_ZOOM;
|
|
|
|
//gi.SendServerCommand(player->entnum, "stufftext \"ui_removehud zoomhud\"\n");
|
|
player->removeHud( "zoomhud" );
|
|
|
|
_zoomStage = ZOOM_NORMAL_FOV;
|
|
zoomed = false;
|
|
}
|
|
|
|
void Weapon::IncrementZoom( Event* ev )
|
|
{
|
|
|
|
if(!zoomed)
|
|
return;
|
|
|
|
Player *player = NULL;
|
|
|
|
if ( owner && owner->isSubclassOf( Player ) )
|
|
player = (Player *)(Sentient *)owner;
|
|
|
|
float zoomPercentage = ((float)level.time - startzoomtime) / zoomtime;
|
|
zoomfov = ((endzoom - startzoom) * zoomPercentage) + startzoom;
|
|
if(zoomfov < endzoom)
|
|
zoomfov = endzoom;
|
|
|
|
player->SetFov( zoomfov, true );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name: zoomFov
|
|
// Class: Weapon
|
|
//
|
|
// Description: Changes the zoom fov from Normal FOV to FOV 1 to FOV 2 then back to normal fov
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Returns:
|
|
//-----------------------------------------------------
|
|
void Weapon::setZoomStage( Event* ev )
|
|
{
|
|
changeZoomStage( ev->GetFloat( 1 ), ev->GetFloat( 2 ) );
|
|
}
|
|
|
|
void Weapon::changeZoomStage( float firstZoom, float secondZoom )
|
|
{
|
|
Player* player = NULL;
|
|
|
|
if ( owner && owner->isSubclassOf( Player ) )
|
|
player = (Player *)(Sentient *)owner;
|
|
|
|
if(player == NULL)
|
|
return;
|
|
|
|
// Move to next zoom stage
|
|
|
|
switch( _zoomStage )
|
|
{
|
|
case ZOOM_NORMAL_FOV:
|
|
_zoomStage = ZOOM_STAGE_1;
|
|
player->SetFov( firstZoom, true );
|
|
player->addHud( "zoomhud" );
|
|
break;
|
|
|
|
case ZOOM_STAGE_1:
|
|
_zoomStage = ZOOM_STAGE_2;
|
|
player->SetFov( secondZoom, true );
|
|
player->addHud( "zoomhud" );
|
|
break;
|
|
|
|
case ZOOM_STAGE_2:
|
|
_zoomStage = ZOOM_NORMAL_FOV;
|
|
endZoom();
|
|
return;
|
|
}
|
|
|
|
player->client->ps.pm_flags |= PMF_ZOOM;
|
|
}
|
|
|
|
|
|
void Weapon::SetTargetingSkin( Event *ev )
|
|
{
|
|
targetingSkin = ev->GetInteger( 1 );
|
|
}
|
|
|
|
void Weapon::SetShootingSkin( Event *ev )
|
|
{
|
|
shootingSkin = ev->GetInteger( 1 );
|
|
}
|
|
|
|
void Weapon::setFullAmmoSkin( Event *ev )
|
|
{
|
|
_fullAmmoSkin = ev->GetInteger( 1 );
|
|
|
|
_fullAmmoMode = WeaponModeNameToNum( ev->GetString( 2 ) );
|
|
|
|
turnThinkOn();
|
|
}
|
|
|
|
|
|
void Weapon::ProcessTargetedEntity( EntityPtr entity )
|
|
{
|
|
|
|
Player* player;
|
|
assert(owner);
|
|
|
|
if ( !owner )
|
|
return;
|
|
|
|
player = (Player*) (Sentient*)owner;
|
|
if(player == 0)
|
|
return;
|
|
|
|
if ( targetingSkin )
|
|
{
|
|
ChangeSkin( targetingSkin, false );
|
|
|
|
if ( entity && entity->isSubclassOf( Actor ) )
|
|
{
|
|
|
|
Actor *actor = (Actor *)entity.Pointer();
|
|
|
|
if ( !actor->deadflag && ( actor->actortype == IS_ENEMY ) )
|
|
ChangeSkin( targetingSkin, true );
|
|
|
|
}
|
|
}
|
|
|
|
if(entity != 0)
|
|
{
|
|
entity->edict->s.eFlags |= EF_DISPLAY_DESC1;
|
|
}
|
|
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: setMoveSpeedModifier
|
|
// Class: Weapon
|
|
//
|
|
// Description: Sets the move speed modifier (when not firing)
|
|
//
|
|
// Parameters: Event *ev - float, specifies modifier
|
|
//
|
|
// Returns: none
|
|
//----------------------------------------------------------------
|
|
void Weapon::Uninitialize(void)
|
|
{
|
|
if( _zoomStage == ZOOM_STAGE_1 || _zoomStage == ZOOM_STAGE_2 )
|
|
{
|
|
endZoom();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: setMoveSpeedModifier
|
|
// Class: Weapon
|
|
//
|
|
// Description: Sets the move speed modifier (when not firing)
|
|
//
|
|
// Parameters: Event *ev - float, specifies modifier
|
|
//
|
|
// Returns: none
|
|
//----------------------------------------------------------------
|
|
void Weapon::setMoveSpeedModifier( Event *ev )
|
|
{
|
|
defaultMoveSpeedModifier = ev->GetFloat( 1 );
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: setShootingMoveSpeedModifier
|
|
// Class: Weapon
|
|
//
|
|
// Description: Sets the move speed modified for a particular mode
|
|
//
|
|
// Parameters: Event *ev - float, specifies modifier
|
|
//
|
|
// Returns: none
|
|
//----------------------------------------------------------------
|
|
void Weapon::setShootingMoveSpeedModifier( Event *ev )
|
|
{
|
|
shootingMoveSpeedModifier[ firemodeindex ] = ev->GetFloat( 1 );
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: getMoveSpeedModifier
|
|
// Class: Weapon
|
|
//
|
|
// Description: Gets the current move speed modifier
|
|
//
|
|
// Parameters: none
|
|
//
|
|
// Returns: float - the move speed modifier
|
|
//----------------------------------------------------------------
|
|
float Weapon::getMoveSpeedModifier( void )
|
|
{
|
|
if ( weaponstate == WEAPON_FIRING )
|
|
return shootingMoveSpeedModifier[ curmode ];
|
|
else
|
|
return defaultMoveSpeedModifier;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: UseActorAiming
|
|
// Class: Weapon
|
|
//
|
|
// Description: Tells the weapon to use the tag_barrel for aiming, no matter who is holding it.
|
|
//
|
|
// Parameters: Event *ev
|
|
//
|
|
// Returns: None
|
|
//----------------------------------------------------------------
|
|
void Weapon::UseActorAiming( Event *ev )
|
|
{
|
|
if ( ev->NumArgs() > 0 )
|
|
useActorAiming = ev->GetBoolean( 1 );
|
|
else
|
|
useActorAiming = true;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: updateViewShake
|
|
// Class: Weapon
|
|
//
|
|
// Description: Updates the view shake angles
|
|
//
|
|
// Parameters: none
|
|
//
|
|
// Returns: none
|
|
//----------------------------------------------------------------
|
|
void Weapon::updateViewShake( void )
|
|
{
|
|
if ( _viewShakeMagnitude[ curmode ] > 0.0f )
|
|
{
|
|
// Apply simple view shake
|
|
|
|
viewShake[ PITCH ] = G_CRandom() * _viewShakeMagnitude[ curmode ];
|
|
viewShake[ YAW ] = G_CRandom() * _viewShakeMagnitude[ curmode ];
|
|
viewShake[ ROLL ] = G_CRandom() * _viewShakeMagnitude[ curmode ] * 1.5;
|
|
}
|
|
else if ( ( _viewMinShake[ curmode ] != vec_zero ) || ( _viewMaxShake[ curmode ] != vec_zero ) )
|
|
{
|
|
Vector minShake;
|
|
Vector maxShake;
|
|
|
|
// Apply advanced view shake
|
|
|
|
minShake = _viewMinShake[ curmode ];
|
|
maxShake = _viewMaxShake[ curmode ];
|
|
|
|
if ( _viewShakeOverride[ curmode ] )
|
|
{
|
|
viewShake[ PITCH ] = G_Random() * ( maxShake[ PITCH ] - minShake[ PITCH ] ) + minShake[ PITCH ];
|
|
viewShake[ YAW ] = G_Random() * ( maxShake[ YAW ] - minShake[ YAW ] ) + minShake[ YAW ];
|
|
viewShake[ ROLL ] = G_Random() * ( maxShake[ ROLL ] - minShake[ ROLL ] ) + minShake[ ROLL ];
|
|
}
|
|
else
|
|
{
|
|
viewShake[ PITCH ] += G_Random() * ( maxShake[ PITCH ] - minShake[ PITCH ] ) + minShake[ PITCH ];
|
|
viewShake[ YAW ] += G_Random() * ( maxShake[ YAW ] - minShake[ YAW ] ) + minShake[ YAW ];
|
|
viewShake[ ROLL ] += G_Random() * ( maxShake[ ROLL ] - minShake[ ROLL ] ) + minShake[ ROLL ];
|
|
}
|
|
|
|
for ( int i = 0 ; i < 3 ; i++ )
|
|
{
|
|
if ( viewShake[ i ] > _maxViewShakeChange )
|
|
viewShake[ i ] = _maxViewShakeChange;
|
|
else if ( viewShake[ i ] < -_maxViewShakeChange )
|
|
viewShake[ i ] = -_maxViewShakeChange;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
void Weapon::startViewShake( Event *ev )
|
|
{
|
|
startViewShake();
|
|
}
|
|
void Weapon::startViewShake( void )
|
|
{
|
|
if ( ( _viewShakeMagnitude[ curmode ] > 0.0f ) || ( _viewMinShake[ curmode ] != vec_zero ) || ( _viewMaxShake[ curmode ] != vec_zero ) )
|
|
{
|
|
//CancelEventsOfType( EV_Weapon_ClearViewShake );
|
|
|
|
updateViewShake();
|
|
|
|
//if ( _viewShakeDuration[ curmode ] > FRAMETIME )
|
|
{
|
|
CancelEventsOfType( EV_Weapon_ReduceViewShake );
|
|
PostEvent( EV_Weapon_ReduceViewShake, FRAMETIME );
|
|
//PostEvent( EV_Weapon_ReduceViewShake, 0.25 );
|
|
}
|
|
|
|
//PostEvent( EV_Weapon_ClearViewShake, _viewShakeDuration[ curmode ] );
|
|
}
|
|
}
|
|
|
|
void Weapon::reduceViewShake( Event *ev )
|
|
{
|
|
int i;
|
|
bool repost;
|
|
|
|
// Reduce the viewShake
|
|
|
|
viewShake *= 0.75;
|
|
|
|
// Determine if we should do reduce the viewShake next frame
|
|
|
|
repost = false;
|
|
|
|
for ( i = 0 ; i < 3 ; i++ )
|
|
{
|
|
if ( ( viewShake[ i ] > 0.1f ) || ( viewShake[ i ] < -0.1f ) )
|
|
{
|
|
repost = true;
|
|
}
|
|
}
|
|
|
|
if ( repost )
|
|
{
|
|
PostEvent( EV_Weapon_ReduceViewShake, FRAMETIME );
|
|
}
|
|
else
|
|
{
|
|
viewShake = vec_zero;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: clearViewShake
|
|
// Class: Weapon
|
|
//
|
|
// Description: Clears the view shake angles
|
|
//
|
|
// Parameters: none
|
|
//
|
|
// Returns: none
|
|
//----------------------------------------------------------------
|
|
void Weapon::clearViewShake( Event *ev )
|
|
{
|
|
viewShake = vec_zero;
|
|
CancelEventsOfType( EV_Weapon_ReduceViewShake );
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: getViewShake
|
|
// Class: Weapon
|
|
//
|
|
// Description: Gets the angles to shake the view
|
|
//
|
|
// Parameters: none
|
|
//
|
|
// Returns: Vector - angles to shake the view by
|
|
//----------------------------------------------------------------
|
|
Vector Weapon::getViewShake( void )
|
|
{
|
|
return viewShake;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: setViewShakeInfo
|
|
// Class: Weapon
|
|
//
|
|
// Description: Sets the magnitude and duration that the view should shake when firing the weapon
|
|
//
|
|
// Parameters: Event *ev - float, specifies the magnitude
|
|
// float, specifies the duration (optional)
|
|
//
|
|
// Returns: none
|
|
//----------------------------------------------------------------
|
|
void Weapon::setViewShakeInfo( Event *ev )
|
|
{
|
|
_viewShakeMagnitude[ firemodeindex ] = ev->GetFloat( 1 );
|
|
|
|
if ( ev->NumArgs() > 1 )
|
|
{
|
|
_viewShakeDuration[ firemodeindex ] = ev->GetFloat( 2 );
|
|
}
|
|
else
|
|
{
|
|
_viewShakeDuration[ firemodeindex ] = FRAMETIME;
|
|
}
|
|
}
|
|
|
|
void Weapon::setAdvancedViewShakeInfo( Event *ev )
|
|
{
|
|
_viewMinShake[ firemodeindex ] = ev->GetVector( 1 );
|
|
_viewMaxShake[ firemodeindex ] = ev->GetVector( 2 );
|
|
|
|
if ( ev->NumArgs() > 2 )
|
|
{
|
|
_viewShakeDuration[ firemodeindex ] = ev->GetFloat( 3 );
|
|
}
|
|
else
|
|
{
|
|
_viewShakeDuration[ firemodeindex ] = FRAMETIME;
|
|
}
|
|
|
|
if ( ev->NumArgs() > 3 )
|
|
{
|
|
_viewShakeOverride[ firemodeindex ] = ev->GetBoolean( 4 );
|
|
}
|
|
else
|
|
{
|
|
_viewShakeOverride[ firemodeindex ] = false;
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
// Name: SetPowerRating()
|
|
// Class: Weapon
|
|
//
|
|
// Description: Calls SetPowerRating()
|
|
//
|
|
// Parameters: Event *ev -- Event with the rating
|
|
//
|
|
// Returns: None
|
|
//--------------------------------------------------------------
|
|
void Weapon::SetPowerRating( Event *ev )
|
|
{
|
|
SetPowerRating( ev->GetFloat( 1 ) );
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
// Name: SetProjectileDamage()
|
|
// Class: Weapon
|
|
//
|
|
// Description: Calls SetProjectileDamage
|
|
//
|
|
// Parameters: Event *ev -- Event with the damage
|
|
//
|
|
// Returns: None
|
|
//--------------------------------------------------------------
|
|
void Weapon::SetProjectileDamage( Event *ev )
|
|
{
|
|
SetProjectileDamage(ev->GetFloat( 1 ) );
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
// Name: SetProjectileSpeed()
|
|
// Class: Weapon
|
|
//
|
|
// Description: Calls SetProjectileSpeed
|
|
//
|
|
// Parameters: Event *ev -- Event with the speed of the projectile
|
|
//
|
|
// Returns: None
|
|
//--------------------------------------------------------------
|
|
void Weapon::SetProjectileSpeed( Event *ev )
|
|
{
|
|
SetProjectileSpeed(ev->GetFloat( 1 ) );
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
// Name: AdvancedMeleeAttack
|
|
// Class: Weapon
|
|
//
|
|
// Description: Does some literal melee damage based on the weapon itself.
|
|
// Weapon angles (except Z) are taken into account, and we
|
|
// utilize the meleestart and meleeend events to apply damage
|
|
// properly to enemies in a single swipe. The melee trace goes
|
|
// between the two WEAPON tags passed in.
|
|
//
|
|
// Parameters: const char* tag1 -- The first tag to do the melee trace from
|
|
// const char* tag2 -- The second tag to do the melee trace from
|
|
//
|
|
// Returns: None
|
|
//--------------------------------------------------------------
|
|
void Weapon::AdvancedMeleeAttack(const char* tag1, const char* tag2, bool criticalHit)
|
|
{
|
|
Vector startpoint, endpoint;
|
|
Vector tagpos, tagpos2, vect;
|
|
float damage, knockback;
|
|
meansOfDeath_t meansofdeath;
|
|
|
|
// New Melee Combat code
|
|
GetActorMuzzlePosition(&tagpos, NULL, NULL, NULL, tag1); // Get the position of the first tag
|
|
GetActorMuzzlePosition(&tagpos2, NULL, NULL, NULL, tag2); // Get the position of the second tag
|
|
startpoint = tagpos2;
|
|
vect = tagpos - tagpos2;
|
|
vect.z = 0;
|
|
vect.normalize();
|
|
endpoint = startpoint + (vect*48);
|
|
|
|
// Debug line
|
|
//G_DebugLine(startpoint, endpoint, 0.5, 1.0, 0.5, 1.0);
|
|
|
|
damage = bulletdamage[FIRE_MODE1];
|
|
knockback = bulletknockback[FIRE_MODE1];
|
|
|
|
meansofdeath = GetMeansOfDeath( FIRE_MODE1 );
|
|
|
|
if ( owner->isSubclassOf( Player ) )
|
|
{
|
|
Player *player = (Player *)(Sentient *)owner;
|
|
|
|
meansofdeath = player->changetMeansOfDeath( meansofdeath );
|
|
|
|
damage = player->getDamageDone( damage, meansofdeath, true );
|
|
|
|
knockback = (knockback + player->GetPlayerKnockback()) * player->GetKnockbackMultiplier();
|
|
}
|
|
|
|
Sentient *owner;
|
|
Player *player;
|
|
owner = this->owner;
|
|
assert( owner );
|
|
if ( owner->isSubclassOf( Player ) )
|
|
{
|
|
player = ( Player * )owner;
|
|
if ( !player->in_melee_attack )
|
|
meleeVictims.ClearObjectList();
|
|
}
|
|
|
|
if ( !MeleeAttack( startpoint, endpoint, damage, owner, meansofdeath, 15.0f, -45.0f, 45.0f, knockback, true, &meleeVictims, this, criticalHit ) )
|
|
{
|
|
// Try to hit the world since we didn't do any damage to anything
|
|
trace_t trace = G_Trace( startpoint, Vector( -8.0f, -8.0f, -8.0f ), Vector( 8.0f, 8.0f, 8.0f ), endpoint, owner, MASK_MELEE, false, "Weapon::Shoot" );
|
|
|
|
Entity *victim = G_GetEntity( trace.entityNum );
|
|
|
|
if ( victim && ( ( victim == world ) || ( victim->takedamage == DAMAGE_NO ) ) )
|
|
{
|
|
vec3_t newangles;
|
|
vectoangles( trace.plane.normal, newangles );
|
|
WorldHitSpawn( FIRE_MODE1, trace.endpos, newangles, 0.1f );
|
|
str realname = this->GetRandomAlias( "impact_world" );
|
|
if ( realname.length() > 1 )
|
|
this->Sound( realname, CHAN_VOICE );
|
|
}
|
|
}
|
|
|
|
if ( !quiet )
|
|
{
|
|
if ( next_noise_time <= level.time )
|
|
{
|
|
BroadcastSound();
|
|
next_noise_time = level.time + 1.0f;
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Name: applySpread
|
|
// Class: Weapon
|
|
//
|
|
// Description: Applies the weapons spread to the angles
|
|
//
|
|
// Parameters: const Vector &pos - position of the muzzle
|
|
// Vector *forward - forward vector of the muzzle
|
|
// Vector *right - right vector of the muzzle
|
|
// Vector *up - up vector of the muzzle
|
|
//
|
|
// Returns: none
|
|
//----------------------------------------------------------------
|
|
|
|
void Weapon::applySpread( Vector *forward, Vector *right, Vector *up )
|
|
{
|
|
Vector spread;
|
|
|
|
|
|
if (( !forward ) || (!up) || (!right))
|
|
return;
|
|
|
|
spread = getSpread();
|
|
|
|
// figure the new projected impact point based upon computed spread
|
|
*forward = ( *forward * bulletrange[curmode]) +
|
|
( *right * G_CRandom( spread.x ) ) +
|
|
( *up * G_CRandom( spread.y ) );
|
|
|
|
// after figuring spread location, re-normalize vectors
|
|
forward->normalize();
|
|
*right = Vector::Cross(*forward,*up);
|
|
*up = Vector::Cross(*right,*forward);
|
|
}
|
|
|
|
Vector Weapon::getSpread( void )
|
|
{
|
|
Vector spread;
|
|
|
|
// compute the spread if it's time-variant
|
|
|
|
if ( endbulletspread[ curmode ].z )
|
|
{
|
|
float timemult = (level.time - startfiretime) / endbulletspread[curmode].z;
|
|
|
|
if (timemult > 1) // cap it so we don't get silly spread
|
|
timemult = 1;
|
|
|
|
spread.x = timemult * (endbulletspread[curmode].x - bulletspread[curmode].x) + bulletspread[curmode].x;
|
|
spread.y = timemult * (endbulletspread[curmode].y - bulletspread[curmode].y) + bulletspread[curmode].y;
|
|
}
|
|
else
|
|
{
|
|
spread.x = bulletspread[curmode].x;
|
|
spread.y = bulletspread[curmode].y;
|
|
}
|
|
|
|
return spread;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
//
|
|
// Name: processGameplayData
|
|
// Class: Weapon
|
|
//
|
|
// Description: Called usually from the tiki file after all other
|
|
// server side events are called.
|
|
//
|
|
// Parameters: Event *ev -- not used
|
|
//
|
|
// Returns: None
|
|
//
|
|
//--------------------------------------------------------------
|
|
void Weapon::processGameplayData( Event *ev )
|
|
{
|
|
GameplayManager *gpm = GameplayManager::getTheGameplayManager();
|
|
if ( !gpm->hasObject(getArchetype()) )
|
|
return;
|
|
|
|
str objname = getArchetype();
|
|
str useanim, usetype, usethread;
|
|
if ( gpm->hasProperty(objname, "useanim") )
|
|
useanim = gpm->getStringValue(objname, "useanim");
|
|
if ( gpm->hasProperty(objname, "usethread") )
|
|
usethread = gpm->getStringValue(objname, "usethread");
|
|
if ( gpm->hasProperty(objname + ".Pickup", "icon") )
|
|
usetype = gpm->getStringValue(objname + ".Pickup", "icon");
|
|
|
|
// If any of these strings were set, add to our UseData object.
|
|
if ( useanim.length() || usethread.length() || usetype.length() )
|
|
{
|
|
if ( !useData )
|
|
useData = new UseData();
|
|
|
|
useData->setUseAnim(useanim);
|
|
useData->setUseThread(usethread);
|
|
useData->setUseType(usetype);
|
|
}
|
|
}
|
|
|
|
float Weapon::RespawnTime( void )
|
|
{
|
|
if ( multiplayerManager.inMultiplayer() )
|
|
return respawntime * multiplayerManager.getWeaponRespawnMultiplayer();
|
|
else
|
|
return respawntime;
|
|
}
|
|
|
|
void Weapon::SetArcProjectile( Event *ev )
|
|
{
|
|
_arcProjectile = ev->GetBoolean( 1 );
|
|
}
|
|
|
|
void Weapon::SetLowArcRange( Event *ev )
|
|
{
|
|
_lowArcRange = ev->GetFloat( 1 );
|
|
}
|
|
|
|
void Weapon::SetPlayMissSound( Event *ev )
|
|
{
|
|
_playMissSound = ev->GetBoolean( 1 );
|
|
}
|
|
|
|
void Weapon::noAmmoMode( Event * )
|
|
{
|
|
_noAmmoMode[ firemodeindex ] = true;
|
|
}
|
|
|
|
bool Weapon::hasNoAmmoMode( firemode_t mode )
|
|
{
|
|
return _noAmmoMode[ mode ];
|
|
}
|
|
|
|
void Weapon::setNoDelay( Event *ev )
|
|
{
|
|
_noDelay[ firemodeindex ] = true;
|
|
}
|
|
|
|
bool Weapon::isModeNoDelay( firemode_t mode )
|
|
{
|
|
return _noDelay[ mode ];
|
|
}
|
|
|
|
void Weapon::pauseRegen( Event *ev )
|
|
{
|
|
int i;
|
|
|
|
for( i = 0 ; i < MAX_FIREMODES ; i++ )
|
|
{
|
|
if ( ( _regenAmount[ i ] > 0 ) )
|
|
{
|
|
_nextRegenTime[ i ] = level.time + _regenTime[ i ] + 0.5f;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Weapon::setChargedModels( Event *ev )
|
|
{
|
|
assert( ( firemodeindex >= 0 ) && ( firemodeindex < MAX_FIREMODES ) );
|
|
_chargedModels[ firemodeindex ] = ev->GetInteger( 1 );
|
|
}
|
|
|
|
void Weapon::setControllingProjectile( Event *ev )
|
|
{
|
|
if ( ev->NumArgs() > 0 )
|
|
{
|
|
_controllingProjectile = ev->GetBoolean( 1 );
|
|
}
|
|
else
|
|
{
|
|
_controllingProjectile = true;
|
|
}
|
|
}
|
|
|
|
bool Weapon::getControllingProjectile( void )
|
|
{
|
|
return _controllingProjectile;
|
|
}
|
|
|
|
void Weapon::setCanInterruptFiringState( Event *ev )
|
|
{
|
|
if ( ev->NumArgs() > 0 )
|
|
_canInterruptFiringState = ev->GetBoolean( 1 );
|
|
else
|
|
_canInterruptFiringState = true;
|
|
}
|
|
|
|
void Weapon::setSpreadAnimData( Event *ev )
|
|
{
|
|
_spreadAnims[ firemodeindex ] = ev->GetInteger( 1 );
|
|
_spreadTime[ firemodeindex ] = ev->GetFloat( 2 );
|
|
}
|
|
|
|
bool Weapon::canReload( void )
|
|
{
|
|
if ( weaponstate != WEAPON_READY )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
int Weapon::getAmmoInClip( firemode_t mode )
|
|
{
|
|
firemode_t clipToUse;
|
|
|
|
assert( ( mode >= 0 ) && ( mode < MAX_FIREMODES ) );
|
|
|
|
if ( usesameclip )
|
|
clipToUse = FIRE_MODE1;
|
|
else
|
|
clipToUse = mode;
|
|
|
|
if ( ( clipToUse >= 0 ) && ( clipToUse < MAX_FIREMODES ) )
|
|
{
|
|
if ( ammo_clip_size[ clipToUse ] )
|
|
{
|
|
return ammo_in_clip[ clipToUse ];
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void Weapon::setMaxViewShakeChange( Event *ev )
|
|
{
|
|
_maxViewShakeChange = ev->GetFloat( 1 );
|
|
}
|
|
|
|
void Weapon::setControlParms( Event *ev )
|
|
{
|
|
_controlEmitterName = ev->GetString( 1 );
|
|
_controlSoundName = ev->GetString( 2 );
|
|
}
|
|
|
|
void Weapon::toggleProjectileControl( void )
|
|
{
|
|
if ( _controllingProjectile )
|
|
{
|
|
// No longer control projectile
|
|
|
|
_controllingProjectile = false;
|
|
|
|
// Turn off sound
|
|
|
|
StopLoopSound();
|
|
|
|
// Turn off emitter
|
|
|
|
clearCustomEmitter( _controlEmitterName );
|
|
}
|
|
else
|
|
{
|
|
// Control projectile now
|
|
|
|
_controllingProjectile = true;
|
|
|
|
// Turn on sound
|
|
|
|
LoopSound( _controlSoundName );
|
|
|
|
if ( !_controllingProjectileHidden )
|
|
{
|
|
// Turn on emitter
|
|
|
|
setCustomEmitter( _controlEmitterName );
|
|
}
|
|
}
|
|
}
|
|
|
|
void Weapon::setProjectileControlHidden( Event *ev )
|
|
{
|
|
_controllingProjectileHidden = ev->GetBoolean( 1 );
|
|
|
|
if ( _controllingProjectileHidden && _controllingProjectile )
|
|
{
|
|
// Turn off emitter
|
|
|
|
clearCustomEmitter( _controlEmitterName );
|
|
}
|
|
else if ( !_controllingProjectileHidden && _controllingProjectile )
|
|
{
|
|
// Turn on emitter
|
|
|
|
setCustomEmitter( _controlEmitterName );
|
|
}
|
|
}
|
|
|
|
void Weapon::setMeleeParms( Event *ev )
|
|
{
|
|
_meleeWidth[ firemodeindex ] = ev->GetFloat( 1 );
|
|
_meleeHeight[ firemodeindex ] = ev->GetFloat( 2 );
|
|
_meleeLength[ firemodeindex ] = ev->GetFloat( 3 );
|
|
}
|
|
|
|
void Weapon::setFireOffset( Event *ev )
|
|
{
|
|
_fireOffset[ firemodeindex ] = ev->GetVector( 1 );
|
|
}
|
|
|
|
void Weapon::cacheStrings( void )
|
|
{
|
|
G_FindConfigstringIndex( va( "$$PickedUpThe$$ $$Weapon-%s$$\n", getName().c_str() ), CS_GENERAL_STRINGS, MAX_GENERAL_STRINGS, true );
|
|
}
|
|
|
|
void Weapon::setAutoReload( Event *ev )
|
|
{
|
|
_autoReload = ev->GetBoolean( 1 );
|
|
}
|
|
|
|
void Weapon::setAllowAutoSwitch( Event *ev )
|
|
{
|
|
_allowAutoSwitch = ev->GetBoolean( 1 );
|
|
}
|
|
|
|
void Weapon::forceReload( Event *ev )
|
|
{
|
|
ForceReload();
|
|
}
|
|
|
|
void Weapon::Think( void )
|
|
{
|
|
int i;
|
|
|
|
for( i = 0 ; i < MAX_FIREMODES ; i++ )
|
|
{
|
|
if ( owner && ( _regenAmount[ i ] > 0 ) && ( _nextRegenTime[ i ] < level.time ) )
|
|
//if ( ( attached ) && ( _regenAmount[ i ] > 0 ) && ( _nextRegenTime[ i ] < level.time ) )
|
|
{
|
|
owner->GiveAmmo( ammo_type[ i ], _regenAmount[ i ], false );
|
|
|
|
_nextRegenTime[ i ] = level.time + _regenTime[ i ];
|
|
}
|
|
}
|
|
|
|
if ( attached && _fullAmmoSkin )
|
|
{
|
|
bool full = false;
|
|
firemode_t modeToCheck;
|
|
|
|
if ( usesameclip )
|
|
modeToCheck = FIRE_MODE1;
|
|
else
|
|
modeToCheck = _fullAmmoMode;
|
|
|
|
if ( ammo_clip_size[ modeToCheck ] > 0 )
|
|
{
|
|
if ( ammo_in_clip[ modeToCheck ] == ammo_clip_size[ modeToCheck ] )
|
|
full = true;
|
|
}
|
|
else
|
|
{
|
|
if ( ( owner ) && ( owner->AmmoCount( ammo_type[ modeToCheck ] ) == owner->MaxAmmoCount( ammo_type[ modeToCheck ] ) ) )
|
|
full = true;
|
|
}
|
|
|
|
if ( full )
|
|
{
|
|
ChangeSkin( _fullAmmoSkin, true );
|
|
}
|
|
else
|
|
{
|
|
ChangeSkin( _fullAmmoSkin, false );
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Weapon::shouldAutoSwitch( firemode_t mode )
|
|
{
|
|
Player *player;
|
|
int i;
|
|
firemode_t modeToCheck;
|
|
|
|
|
|
if ( !owner || !owner->isSubclassOf( Player ) )
|
|
return false;
|
|
|
|
player = (Player *)(Sentient *)owner;
|
|
|
|
if ( HasAmmo( mode ) )
|
|
return false;
|
|
|
|
if ( !_allowAutoSwitch )
|
|
return false;
|
|
|
|
if ( player->edict->svflags & SVF_BOT )
|
|
return true;
|
|
|
|
if ( !player->getAutoSwitchWeapons() )
|
|
return false;
|
|
|
|
for ( i = 0 ; i < MAX_FIREMODES ; i++ )
|
|
{
|
|
if ( usesameclip )
|
|
modeToCheck = FIRE_MODE1;
|
|
else
|
|
modeToCheck = (firemode_t)i;
|
|
|
|
if ( HasAmmo( modeToCheck ) )
|
|
return false;
|
|
|
|
if ( firetype[ i ] == FT_TRIGGER_PROJECTILE )
|
|
{
|
|
if ( _nextSwitchTime > level.time )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
int Weapon::getWeaponPriority( void )
|
|
{
|
|
int priority;
|
|
str currentWeaponName;
|
|
|
|
for ( priority = 0 ; priority < 14 ; priority++ )
|
|
{
|
|
currentWeaponName = getWeaponByPriority( priority );
|
|
|
|
if ( currentWeaponName == getName() )
|
|
return priority;
|
|
}
|
|
|
|
return 100;
|
|
}
|
|
|
|
str Weapon::getWeaponByPriority( int priority )
|
|
{
|
|
str weaponName;
|
|
|
|
switch ( priority )
|
|
{
|
|
case 0 :
|
|
weaponName = "PhotonBurst";
|
|
break;
|
|
case 1 :
|
|
weaponName = "TetryonGatlingGun";
|
|
break;
|
|
case 2 :
|
|
weaponName = "FederationSniperRifle";
|
|
break;
|
|
case 3 :
|
|
weaponName = "RomulanRadGun";
|
|
break;
|
|
case 4 :
|
|
weaponName = "AttrexianRifle";
|
|
break;
|
|
case 5 :
|
|
weaponName = "BurstRifle";
|
|
break;
|
|
case 6 :
|
|
weaponName = "GrenadeLauncher";
|
|
break;
|
|
case 7 :
|
|
weaponName = "FieldAssaultRifle";
|
|
break;
|
|
case 8 :
|
|
weaponName = "I-Mod";
|
|
break;
|
|
case 9 :
|
|
weaponName = "CompressionRifle";
|
|
break;
|
|
case 10 :
|
|
weaponName = "RomulanDisruptor";
|
|
break;
|
|
case 11 :
|
|
weaponName = "DrullStaff";
|
|
break;
|
|
case 12 :
|
|
weaponName = "Phaser-stx";
|
|
break;
|
|
case 13 :
|
|
weaponName = "Phaser";
|
|
break;
|
|
}
|
|
|
|
return weaponName;
|
|
}
|
|
|
|
void Weapon::autoSwitch()
|
|
{
|
|
str weaponName;
|
|
Weapon *weapon;
|
|
Item *item;
|
|
int i;
|
|
Player *player;
|
|
int ammoAvailable;
|
|
|
|
if ( !owner || !owner->isSubclassOf( Player ) )
|
|
return;
|
|
|
|
player = (Player *)(Sentient *)owner;
|
|
|
|
for ( i = 0 ; i < 14 ; i++ )
|
|
{
|
|
weaponName = getWeaponByPriority( i );
|
|
|
|
if ( player->HasItem( weaponName ) )
|
|
{
|
|
item = player->FindItem( weaponName );
|
|
|
|
if ( item && item->isSubclassOf( Weapon ) )
|
|
{
|
|
weapon = (Weapon *)item;
|
|
|
|
ammoAvailable = weapon->getAmmoInClip( FIRE_MODE1 ) + weapon->AmmoAvailable( FIRE_MODE1 );
|
|
|
|
if ( ammoAvailable > weapon->ammorequired[ FIRE_MODE1 ] )
|
|
{
|
|
Event *newEvent = new Event( EV_Player_UseItem );
|
|
newEvent->AddString( weaponName );
|
|
player->ProcessEvent( newEvent );
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Weapon::setNextSwitchTime( float time )
|
|
{
|
|
_nextSwitchTime = level.time + time;
|
|
}
|
|
|
|
void Weapon::setNextSwitchTime( Event *ev )
|
|
{
|
|
setNextSwitchTime( ev->GetFloat( 1 ) );
|
|
}
|