openmohaa/code/cgame/cg_commands.cpp

5855 lines
164 KiB
C++
Raw Normal View History

2023-04-30 00:02:16 +02:00
/*
===========================================================================
Copyright (C) 2023 the OpenMoHAA team
This file is part of OpenMoHAA source code.
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// DESCRIPTION:
2023-07-05 21:24:23 +02:00
// Client side command events. These are in the .TIK files and
2023-04-30 00:02:16 +02:00
// are processed when the animation specifies it to.
#include "cg_commands.h"
2023-05-06 23:37:05 +02:00
#include "cg_specialfx.h"
2023-04-30 20:20:58 +02:00
#include "scriptexception.h"
#include "tiki.h"
#include "cg_archive.h"
#include "memarchiver.h"
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
refEntity_t *current_entity = NULL;
int current_entity_number = -1;
centity_t *current_centity = NULL;
float current_scale = -1;
dtiki_t *current_tiki = nullptr;
cvar_t *cg_showemitters;
cvar_t *cg_physics_fps;
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
Vector last_trace_end;
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
void CacheResource(const char *stuff);
2023-04-30 00:02:16 +02:00
ClientGameCommandManager commandManager;
2023-07-05 21:24:23 +02:00
Event EV_Client_StartBlock("(", EV_DEFAULT, NULL, NULL, "Signals the beginning of a block of commands");
Event EV_Client_EndBlock(")", EV_DEFAULT, NULL, NULL, "Signals the end of a block of commands");
Event EV_Client_EmitterStartOff(
"startoff", EV_DEFAULT, NULL, NULL, "Signals an emitter to start in the off state (no tempmodels are emitted)"
);
Event EV_Client_SetAlpha("alpha", EV_DEFAULT, "f", "alpha", "Set the alpha of the spawned tempmodel");
Event EV_Client_SetDieTouch(
"dietouch", EV_DEFAULT, NULL, NULL, "Set the spawned tempmodels to die when they touch a solid"
);
Event EV_Client_SetBounceFactor(
"bouncefactor",
EV_DEFAULT,
"f",
"factor",
"Set the bounciness of a tempmodel when it hits a solid.\n"
"A factor > 1 will make the model bounce higher and higher on each hit"
);
Event EV_Client_SetBounceSound(
"bouncesound",
EV_DEFAULT,
"sF",
"sound [delay]",
"When bouncing, what sound to play on impact and an option delay (default is 1 second) between playing this sound"
);
Event EV_Client_SetBounceSoundOnce(
"bouncesoundonce", EV_DEFAULT, "s", "sound", "When bouncing, what sound to play on impact one time"
);
Event EV_Client_SetScale("scale", EV_DEFAULT, "f", "scale", "Set the scale of a spawned tempmodel");
Event EV_Client_SetScaleUpDown(
"scaleupdown", EV_DEFAULT, NULL, NULL, "Set the tempmodel to scale up to scale value and then down."
);
Event EV_Client_SetScaleMin("scalemin", EV_DEFAULT, "f", "scalemin", "Set the minimum scale of a spawned tempmodel");
Event EV_Client_SetScaleMax("scalemax", EV_DEFAULT, "f", "scalemax", "Set the maximum scale of a spawned tempmodel");
Event EV_Client_SetModel(
"model",
EV_DEFAULT,
"sSSSSS",
"modelname1 modelname2 modelname3 modelname4 modelname5 modelname6",
"Set the modelname of the tempmodel. If more than 1 model is specified, it will\n"
"be randomly chosen when spawned"
);
Event EV_Client_SetLife("life", EV_DEFAULT, "f", "life", "Set the life (in seconds) of the spawned tempmodel");
Event EV_Client_SetColor(
"color", EV_DEFAULT, "fffF", "red green blue alpha", "Set the color (modulate) of the spawned tempmodel."
);
Event EV_Client_SetRadialVelocity(
"radialvelocity",
EV_DEFAULT,
"fff",
"scale min_additional max_additional",
"Subtracts the particle origin from origin and multiplies by scale, then adds additional velocity\n"
"between min and max... negative values bring toward origin\n"
);
Event EV_Client_SetVelocity(
"velocity", EV_DEFAULT, "f", "forwardVelocity", "Set the forward velocity of the spawned tempmodel"
);
Event EV_Client_SetAngularVelocity(
"avelocity", EV_DEFAULT, "fff", "yawVel pitchVel rollVel", "Set the angular velocity of the spawned tempmodel"
);
Event EV_Client_SetColorVelocity(
"colorvelocity", EV_DEFAULT, "fff", "rVel gVel bVel", "Set the color velocity of the spawned dlight tempmodel"
);
Event EV_Client_SetRandomVelocity(
"randvel",
EV_DEFAULT,
"SfFSfFSfF",
"[random|crandom|range] xVel [xVel2] [random|crandom|range] yVel [yVel2] [random|crandom|range] zVel [zVel2]",
"Add a random component to the regular velocity.\n"
"If random is specified, the component will range from 0 to specified velocity.\n"
"If crandom is specified, the component will range from -specified to +specified velocity.\n"
"If range is specified, the component needs two values; it will randomly pick a number in the range\n"
"from the first number to the first number plus the second number.\n"
"If no keyword is explicitly specified, then the component will just be added on\n"
"without randomness.\n"
"This velocity is applied using the world axis"
);
Event EV_Client_SetRandomVelocityAlongAxis(
"randvelaxis",
EV_DEFAULT,
"SfFSfFSfF",
"[random|crandom|range] forwardVel [forwardVel2] [random|crandom|range] rightVel [rightVel2] [random|crandom|rang"
"e] upVel [upVel2]",
"Add a random component to the regular velocity.\n"
"If random is specified, the component will range from 0 to specified velocity.\n"
"If crandom is specified, the component will range from -specified to +specified velocity.\n"
"If range is specified, the component needs two values; it will randomly pick a number in the range\n"
"from the first number to the first number plus the second number.\n"
"If no keyword is explicitly specified, then the component will just be added on\n"
"without randomness.\n"
"This velocity is applied using the parent axis"
);
Event EV_Client_SetAccel(
"accel",
EV_DEFAULT,
"fff",
"xAcc yAcc zAcc",
"Set the acceleration of the spawned tempmodel.\n"
"This acceleration is applied using the world axis"
);
Event EV_Client_SetFriction(
"friction",
EV_DEFAULT,
"f",
"friction",
"Set the friction as a fraction of velocity per second... exact effect depends on physics rate:\n"
"slowdown per second = [1 - (friction / physicsrate)] ^ physicsrate; physicsrate defaults to 10"
);
Event EV_Client_SetSpin(
"spin",
EV_DEFAULT,
"f",
"rotations_per_second",
"Sets counterclockwise rotations per second at which the emitter's x/y-axes rotate around its z-axis"
);
Event EV_Client_SetVaryColor(
"varycolor", EV_DEFAULT, NULL, NULL, "Sets the color to vary by 0 to -20% of specified color"
);
Event EV_Client_SetSmokeParms(
"smokeparms", EV_DEFAULT, "fff", "typeinfo fademult scalemult", "Sets some misc parms for smoke"
);
Event EV_Client_SetCount(
"count",
EV_DEFAULT,
"i",
"count",
"Set the number of tempmodels that are spawned\n"
"This is only used for the originspawn and tagspawn commands,\n"
"and not for emitters, use spawnrate instead"
);
Event EV_Client_SetFade("fade", EV_DEFAULT, NULL, NULL, "Set the tempmodel to fade out over it's life");
Event EV_Client_SetFadeDelay("fadedelay", EV_DEFAULT, "f", "time", "Set the amount of time to delay a fade");
Event EV_Client_SetFadeIn("fadein", EV_DEFAULT, "f", "time", "Set the tempmodel to fade in over the specified time");
Event EV_Client_SetTwinkle(
"twinkle",
EV_DEFAULT,
"ffff",
"mintimeoff maxtimeoff mintimeon maxtimeon",
"Set the tempmodel to twinkle with the specified settings"
);
Event EV_Client_SetTrail(
"trail", EV_DEFAULT, "sssf", "shader startTag endTag life", "Set the tempmodel to have a swipe that follows it"
);
Event EV_Client_SetSpawnRange(
"spawnrange",
EV_DEFAULT,
"iI",
"range1 range2",
"Sets the range in which this effect will spawn tempmodels. If one number is specified, it is the max range\n"
"and 0 is the min range; if two numbers are specified, the larger is the max range.\n"
);
Event EV_Client_SetSpawnRate(
"spawnrate",
EV_DEFAULT,
"f",
"rate",
"Set the spawnrate of the emitter (models per second).\n"
"This is only used for emitters and not for the originspawn and tagspawn commands"
);
Event EV_Client_SetOriginOffset(
"offset",
EV_DEFAULT,
"SfFSfFSfF",
"[random|crandom|range] offsetX [offsetX2] [random|crandom|range] offsetY [offsetY2] [random|crandom|range] "
"offsetZ [offsetZ2]",
"If random is specified, the component will range from 0 to +specified offset.\n"
"If crandom is specified, the component will range from -specified to +specified offset.\n"
"If range is specified, the component needs two values; it will randomly pick a number in the range\n"
"from the first number to the first number plus the second number.\n"
"If no keyword is explicitly specified, then the component will just be added on\n"
"without randomness.\n"
"This offset is applied using the world axis."
);
Event EV_Client_SetScaleRate(
"scalerate",
EV_DEFAULT,
"f",
"rate",
"Set the scaling rate of the spawned tempmodel\n"
"If a negative rate is used, the model will shrink"
);
Event EV_Client_SetCircle(
"circle",
EV_DEFAULT,
NULL,
NULL,
"Set the tempmodels to be spawned in a circle around the origin\n"
"This circle will be generated in the X/Y axis of the model"
);
Event EV_Client_SetSphere(
"sphere",
EV_DEFAULT,
NULL,
NULL,
"Set the tempmodels to spawn in a sphere around the origin.\n"
"If sphereradius is set, the tempmodels will spawn at the radius distance from\n"
"the origin"
);
Event EV_Client_SetInwardSphere(
"inwardsphere",
EV_DEFAULT,
NULL,
NULL,
"Create the tempmodels in a sphere around the origin, and adjust their\n"
"angle so they point toward the center of the sphere. This is best used with a\n"
"spehere radius and some velocity so the models look like they're heading toward the\n"
"center of the sphere."
);
Event EV_Client_SetRadius(
"radius", EV_DEFAULT, "f", "radius", "Set the radius of the sphere for the inwardsphere amd sphere settings"
);
Event EV_Client_SetSwarm(
"swarm",
EV_DEFAULT,
"iff",
"frequency maxspeed delta",
"Create a swarm like effect that the tempmodels follow when they are spawned\n"
"frequency is how often they change direction\n"
"maxspeed is how fast the tempmodel will move (it's randomly generated every\n"
"time the frequency is hit\n"
"delta is how much the tempmodel moves toward the origin every frame"
);
Event EV_Client_SetWavy(
"wavy",
EV_DEFAULT,
"SF",
"[random|crandom] distance",
"Set the tempmodel to move in a wavy path to a maxmimun of the distance specified\n"
"If random is specified, the distance is between 0 and +specified distance\n"
"If crandom is specified, the distance is between -specified and +specified distance"
);
Event EV_Client_SetAlign("align", EV_DEFAULT, NULL, NULL, "Align the tempmodels to the direction they are traveling");
Event EV_Client_SetAlignOnce(
"alignonce",
EV_DEFAULT,
NULL,
NULL,
"Align the tempmodels to the direction they are traveling at the time they are initialized"
);
Event EV_Client_SetFlickerAlpha(
"flicker",
EV_DEFAULT,
NULL,
NULL,
"Set the tempmodel to change it's alpha every frame. Creates a flickering effect"
);
Event EV_Client_SetCollision(
"collision",
EV_DEFAULT,
"S",
"water",
"Turn on collision for the tempmodel.\n"
"If the keyword water is specified, then the tempmodel will collide with water"
);
Event EV_Client_TagSpawn(
"tagspawn",
EV_DEFAULT,
"s",
"tagName",
"Spawn tempmodels from the specified tag.\n"
"This command is followed by a ( to specify a block of commands that modify the tempmodels"
);
Event EV_Client_TagSpawnLinked(
"tagspawnlinked",
EV_DEFAULT,
"s",
"tagName",
"Spawn tempmodels from the specified tag, linked to the entity at the tag.\n"
"This command is followed by a ( to specify a block of commands that modify the tempmodels"
);
Event EV_Client_OriginSpawn(
"originspawn",
EV_DEFAULT,
NULL,
NULL,
"Spawn tempmodels from the origin.\n"
"This command is followed by a ( to specify a block of commands that modify the tempmodels"
);
Event EV_Client_OriginBeamSpawn(
"originbeamspawn",
EV_DEFAULT,
NULL,
NULL,
"Spawn a beam from the origin.\n"
"This command is followed by a ( to specify a block of commands that modify the beam"
);
Event EV_Client_OriginBeamEmitter(
"originbeamemitter",
EV_DEFAULT,
NULL,
NULL,
"Spawn beams from the origin.\n"
"This command is followed by a ( to specify a block of commands that modify the beam"
);
Event EV_Client_TagEmitter(
"tagemitter",
EV_DEFAULT,
"ss",
"tagName emitterName",
"Create an emitter that spawns tempmodels from the specified tag.\n"
"This command is followed by a ( to specify a block of commands that modify the tempmodels"
);
Event EV_Client_OriginEmitter(
"originemitter",
EV_DEFAULT,
"s",
"emitterName",
"Create an emitter that spawns tempmodels from the origin.\n"
"This command is followed by a ( to specify a block of commands that modify the tempmodels"
);
Event EV_Client_EmitterOn("emitteron", EV_DEFAULT, "s", "emitterName", "Turn the specified emitter on");
Event EV_Client_EmitterOff("emitteroff", EV_DEFAULT, "s", "emitterName", "Turn the specified emitter off");
Event EV_Client_Sound(
"sound",
EV_DEFAULT,
"sSFFFFS",
"soundName channelName volume min_distance pitch randompitch randomvolume argstype",
"Play the specified sound"
);
Event EV_Set_Current_Tiki(
"settiki",
EV_DEFAULT,
"s",
"settiki tikiname - all subsequent events are applied to this tiki",
"sets the tiki the aliases should be on in the sound uberfile"
);
Event EV_Client_StopSound("stopsound", EV_DEFAULT, "i", "channel", "Stops the sound on the specified channel.");
Event EV_Client_StopAliasChannel(
"stopaliaschannel", EV_DEFAULT, "s", "alias", "Stops the sound channel used by the specified alias."
);
Event EV_Client_LoopSound(
"loopsound", EV_DEFAULT, "sFFf", "soundName volume min_distance pitch", "Play the specifed sound as a looping sound"
);
Event EV_Client_Cache("cache", EV_CACHE, "s", "resourceName", "Cache the specified resource");
Event EV_Client_CacheImage(
"cacheimage",
EV_CACHE,
"s",
"imageName",
"Cache the specified image (For menu graphics that should never be picmiped)"
);
Event EV_Client_CacheFont("cachefont", EV_CACHE, "s", "resourceName", "Cache the specified resource");
Event EV_Client_AliasCache(
"aliascache",
EV_DEFAULT,
"ssSSSSSS",
"alias realPath arg1 arg2 arg3 arg4 arg5 arg6",
"Create an alias to the specified path and cache the resource"
);
Event EV_Client_Alias(
"alias",
EV_DEFAULT,
"ssSSSSSS",
"alias realPath arg1 arg2 arg3 arg4 arg5 arg6",
"Create an alias to the specified path"
);
Event EV_Client_CacheAlias(
"cachefromalias", EV_DEFAULT, "s", "alias", "Caches all data matching a previously specified alias"
);
Event EV_Client_Footstep(
"footstep",
EV_DEFAULT,
"ssI",
"tag sRunning iEquipment",
"Play a footstep sound that is appropriate to the surface we are currently stepping on\n"
"sRunning should be set to run, walk, or ladder"
);
Event EV_Client_Landing(
2023-09-03 00:07:06 +02:00
"landing",
2023-07-05 21:24:23 +02:00
EV_DEFAULT,
"FI",
"fVolume iEquipment",
"Play a landing sound that is appropriate to the surface we are landing on\n"
);
Event EV_Client_BodyFall(
"bodyfall",
EV_DEFAULT,
"F",
"fVolume",
"Play a body fall sound that is appropriate to the surface we are falling on\n"
);
Event EV_Client_Client(
"client", EV_DEFAULT, "SSSSSS", "arg1 arg2 arg3 arg4 arg5 arg6", "Execute the specified command arg string"
);
Event EV_Client_OriginDynamicLight(
"origindlight",
EV_DEFAULT,
"fffffSS",
"red green blue intensity life type1 type2",
"Spawn a dynamic light from the origin of the model\n"
"The red,green,blue parms are the color of the light\n"
"The intensity is the radius of the light\n"
"type is the type of light to create (lensflare,viewlensflare,additive)"
);
Event EV_Client_TagDynamicLight(
"tagdlight",
EV_DEFAULT,
"sfffffSS",
"tagName red green blue intensity life type1 type2",
"Spawn a dynamic light from the specified tag\n"
"The red,green,blue parms are the color of the light\n"
"The intensity is the radius of the light\n"
"type is the type of light to create (lensflare,viewlensflare,additive)"
);
Event EV_Client_DynamicLight(
"dlight",
EV_DEFAULT,
"ffffSS",
"red green blue intensity type1 type2",
"This makes the emitter itself a dynamic light"
"The red,green,blue parms are the color of the light\n"
"The intensity is the radius of the light\n"
"type is the type of light to create (lensflare,viewlensflare,additive)"
);
Event EV_Client_BlockDynamicLight(
"blockdlight",
EV_DEFAULT,
"ffSS",
"intensity life type1 type2",
"Spawn a dynamic light from the origin of the model\n"
"An additional commands block allows the specification of moving & varying dlights\n"
"The intensity is the radius of the light\n"
"type is the type of light to create (lensflare,viewlensflare,additive)"
);
Event EV_Client_SetEntityColor(
"entcolor", EV_DEFAULT, "fffF", "red green blue alpha", "Set the color(modulate) of this entity"
);
Event EV_Client_SetTexAnimTime("texanimtime", EV_DEFAULT, "f", "time", "Set the texture animation speed");
Event EV_Client_SetGlobalFade(
"globalfade", EV_DEFAULT, "S", "[in|out]", "Set the tempmodels to globally fade in or out together"
);
Event EV_Client_SetParentLink(
"parentlink", EV_DEFAULT, NULL, NULL, "Set the tempmodels linked to the parent, so they move with the parent model"
);
Event EV_Client_SetHardLink(
"hardlink",
EV_DEFAULT,
NULL,
NULL,
"Set the tempmodels linked to the model they are spawned from, so they move with it"
);
Event EV_Client_SetRandomRoll(
"randomroll", EV_DEFAULT, NULL, NULL, "Set the tempmodels so they pick a random roll value every frame"
);
Event EV_Client_ParentAngles("parentangles", EV_DEFAULT, NULL, NULL, "Set the tempmodels angles to that of its parent");
Event EV_Client_EmitterAngles(
"emitterangles",
EV_DEFAULT,
"FFF",
"pitchofs yawofs rollofs",
"Set the tempmodels angles to that of the emitter\n"
"The three optional parameters are for setting an angle offset from the emitter"
);
Event EV_Client_SetAngles(
"angles",
EV_DEFAULT,
"SfFSfFSfF",
"[random|crandom|range] pitch [pitch2] [random|crandom|range] yaw [yaw2] [random|crandom|range] roll [roll2]",
"If random is specified, the component will range from 0 to +specified value.\n"
"If crandom is specified, the component will range from -specified to +specified value.\n"
"If range is specified, the component needs two values; it will randomly pick a number in the range\n"
"from the first number to the first number plus the second number.\n"
"If no keyword is explicitly specified, then the component will be just set\n"
);
Event EV_Client_SetRelativeAngles(
"relativeangles",
EV_DEFAULT,
"",
"",
"makes the spawn angles get applied relative to the orientation of the model"
);
2023-07-05 21:24:23 +02:00
Event EV_Client_Swipe("swipe", EV_DEFAULT, "V", "origin", "Do a swipe and add it on to the swipe rendering list.");
Event EV_Client_SwipeOn(
"swipeon",
EV_DEFAULT,
"ssff",
"shader startTagName endTagNamelife life",
"Signal the start of a swipe from the current tag"
);
Event EV_Client_SwipeOff("swipeoff", EV_DEFAULT, NULL, NULL, "Signal the end of a swipe");
Event EV_Client_BeginTagBeamEmitter(
"tagbeamemitter",
EV_DEFAULT,
"sss",
"tagstart tagend name",
"Create a beam emitter that uses 2 tags to determine it's start and end position"
);
Event EV_Client_BeginTagBeamSpawn(
"tagbeamspawn",
EV_DEFAULT,
"sf",
"tagstart name",
"Create a beam emitter that uses the tag to determine it's starting position."
);
Event EV_Client_AnimateOnce(
"animateonce", EV_DEFAULT, NULL, NULL, "Set a tempmodel to animate once and then get removed"
);
Event EV_Client_SetAnim("anim", EV_DEFAULT, "s", "animation", "Set a tempmodel the the specified animation");
Event EV_Client_SetSubdivisions("numsegments", EV_DEFAULT, "i", "numsegments", "Set the number of segments in a beam");
Event EV_Client_SetMinOffset("minoffset", EV_DEFAULT, "f", "minoffset", "Set the minimum offset from center in a beam");
Event EV_Client_SetMaxOffset("maxoffset", EV_DEFAULT, "f", "maxoffset", "Set the maximum offset from center in a beam");
Event EV_Client_SetBeamShader("beamshader", EV_DEFAULT, "s", "shadername", "Set the shader to use for the beam");
Event EV_Client_SetBeamLength(
"beamlength", EV_DEFAULT, "f", "length", "Set the length of the beam or trace length (for decals)"
);
Event EV_Client_SetBeamDelay(
"beamdelay",
EV_DEFAULT,
"SF",
"[random] delay",
"Set the delay time between creating new beams.\n"
"If the keyword random is specified, the delay between beams will occur randomly between 0 and the time specified"
);
Event EV_Client_SetBeamToggleDelay(
"beamtoggledelay",
EV_DEFAULT,
"SF",
"[random] delay",
"Set a delay between toggling the beams on and off.\n"
"If the keyword random is specified, the delay between toggling will occur randomly between 0 and the time "
"specified"
);
Event EV_Client_SetBeamPersist("beampersist", EV_DEFAULT, NULL, NULL, "Make the beams persist instead of blinking out");
Event EV_Client_SetBeamOffsetEndpoints(
"beam_offset_endpoints", EV_DEFAULT, NULL, NULL, "Make the beams endpoints offset to reduce the bunching up effect"
);
Event EV_Client_BeamSphere(
"beamsphere",
EV_DEFAULT,
"i",
"count",
"Create a sphere shaped beam effect from the origin. Count is the number of beams"
);
Event EV_Client_Spread(
"spread",
EV_DEFAULT,
"ff",
"spreadx spready",
"Add a random variance in the spawned beam in the forward direction by the amound specified in spreadx and spready"
);
Event EV_Client_UseLastTraceEnd(
"uselasttraceend", EV_DEFAULT, NULL, NULL, "Makes this trace command use the end results of the last trace command"
);
Event EV_Client_OffsetAlongAxis(
"offsetalongaxis",
EV_DEFAULT,
"SfFSfFSfF",
"[crandom|random|range] offsetx [offsetx2] [crandom|random|range] offsety [offsety2] [crandom|random|range] "
"offsetz [offsetz2]",
"If random is specified, the component will range from 0 to specified offset.\n"
"If crandom is specified, the component will range from -specified to +specified offset.\n"
"If range is specified, the component needs two values; it will randomly pick a number in the range\n"
"from the first number to the first number plus the second number.\n"
"If no keyword is explicitly specified, then the component will just be added on\n"
"without randomness.\n"
"This offset is applied using the model's local axis"
);
Event EV_Client_Cone(
"cone",
EV_DEFAULT,
"ff",
"height radius",
"Randomly spawns the particle somewhere inside a cone along the model's local x axis"
);
Event EV_Client_SetEndAlpha("endalpha", EV_DEFAULT, "f", "alpha", "Set the alpha of the beam's endpoint");
Event EV_Client_RandomChance(
"randomchance",
EV_DEFAULT,
"fSSSSSS",
"percentage [arg1] [arg2] [arg3] [arg4] [arg5] [arg6]",
"Set the percentage chance that command will occur"
);
Event EV_Client_DelayedRepeat(
"delayedrepeat",
EV_DEFAULT,
"fiSSSSSS",
"time commandnumber [arg1] [arg2] [arg3] [arg4] [arg5] [arg6]",
"Set the time delay between this command getting executed. This requires a command number to be assigned here.\n"
"This is internally used to keep track of the commands this entity executes and will resolve naming conflicts.\n"
"This is only useful if the command gets called continuously but must execute at regular intervals.\n"
);
Event EV_Client_CommandDelay(
"commanddelay",
EV_DEFAULT,
"fiSSSSSS",
"time commandnumber [arg1] [arg2] [arg3] [arg4] [arg5] [arg6]",
"Set the time delay between this command getting executed. This requires a command number to be assigned here.\n"
"This is internally used to keep track of the commands this entity executes and will resolve naming conflicts."
);
Event EV_Client_BounceDecal(
"bouncedecal",
EV_DEFAULT,
"iI",
"maxamount temporary",
"Put a mark when the tempmodel bounces and hits a surface\n"
"maxamount = Max amount of decals to make when bouncing\n"
"temporary = specify 1 for a temporary mark that only appears for a short time, 0 for a decal that stays aroung "
"longer (default is 0)\n"
);
Event EV_Client_SetDecalRadius("decalradius", EV_DEFAULT, "f", "radius", "Set the radius of the decal");
Event EV_Client_SetDecalOrientation(
"orientation",
EV_DEFAULT,
"f",
"degrees",
"Set the degrees to orient the decal. Specify 'random' to use a random orientation"
);
Event EV_Client_SetDecalShader(
"decalshader", EV_DEFAULT, "s", "shadername", "Set the shader to use for the impact decal"
);
Event EV_Client_SetTraceLength("tracelength", EV_DEFAULT, "f", "length", "Set the length of the trace for the decal");
Event EV_Client_TraceSpawn(
"tracespawn", EV_DEFAULT, "s", "modelname", "Spawn the specified model when the trace hits a solid object"
);
Event EV_Client_TagList(
"taglist",
EV_DEFAULT,
"ssSSSSSS",
"arg1 arg2 arg3 arg4 arg5 arg6 arg7 arg8",
"Set the tag list to create a beam that travels between all the tags"
);
Event EV_Client_Lightstyle(
"lightstyle",
EV_DEFAULT,
"s",
"nameOfImage",
"Set a lightstyle to determine the color of this tempmodel, the image\n"
"specified is used to determine the look of the light style"
);
Event EV_Client_PhysicsRate(
"physicsrate",
EV_DEFAULT,
"s",
"rate",
"Set the rate (in updates per second) for the tempmodel's physics to be updated"
);
Event EV_Client_Parallel("parallel", EV_DEFAULT, NULL, NULL, "Set tempmodel to be parallel to the viewer");
Event EV_Client_AlwaysDraw(
"alwaysdraw",
EV_DEFAULT,
NULL,
NULL,
"Set emitter/tempmodel to be alwaysdraw. Which can be turned off by alwaysdraw"
);
Event EV_Client_Detail(
"detail", EV_DEFAULT, NULL, NULL, "Set emitter/tempmodel to be detail. Which can be turned off by detail"
);
Event EV_Client_Print("print", EV_DEFAULT, "s", "string", "Prints a string.");
Event EV_Client_SetVolumetric(
"volumetric", EV_DEFAULT, NULL, NULL, "Set the effect to spawn volumetric sources rather than tempmodels"
);
Event EV_Client_Wind("wind", EV_DEFAULT, NULL, NULL, "Makes the temp model be affected by wind");
Event
EV_Client_SpriteGridLighting("spritegridlighting", EV_DEFAULT, NULL, NULL, "Calculates grid lighting for a sprite");
Event EV_Client_WaterOnly("wateronly", EV_DEFAULT, NULL, NULL, "makes the temp model remove itself if it leaves water");
Event EV_Client_SetAlignStretch(
"alignstretch",
EV_DEFAULT,
"F",
"scaleMultiplier",
"Aligns the temp model to the direction of travel, and stretches it betwen the last and current positions.\n"
);
Event EV_Client_SetClampVelocity(
"clampvel",
EV_DEFAULT,
"ffffff",
"minX maxX minY maxY minZ maxZ",
"sets the valid range for velocities along global axes. Cannot be used with clampvelaxis."
);
Event EV_Client_SetClampVelocityAxis(
"clampvelaxis",
EV_DEFAULT,
"ffffff",
"minX maxX minY maxY minZ maxZ",
"sets the valid range for velocities along oriented axes. Cannot be used with clampvel."
);
Event EV_Client_Treads(
"treads",
EV_DEFAULT,
"ssi",
"tagName shader localrefnumber",
"Spawn treads from the specified tag using the specified tread type."
);
Event EV_Client_Treads_Off(
"treadsoff", EV_DEFAULT, "si", "tagName localrefnumber", "Stops spawning treads from the specified tag."
);
Event EV_Client_ViewKick(
"viewkick",
EV_DEFAULT,
"fffffsff",
"pitchmin pitchmax yawmin yawmax recenterspeed patters pitchmax yawmax scatterpitchmax",
"Adds kick to the view of the owner when fired."
);
Event EV_Client_EyeLimits(
"eyelimits",
EV_DEFAULT,
"fff",
"fPitchmax fYawmax fRollmax",
"Set the max angle offsets for the eyes from the model's head"
);
Event EV_Client_EyeMovement(
"eyemovement",
EV_DEFAULT,
"f",
"fMovement",
"Sets the amount of the head's movement to apply to the players view. 1 is full, 0 is none"
);
Event EV_Client_SFXStart(
"sfx",
EV_DEFAULT,
"sSSSSSSSS",
"sCommand arg1 arg2 arg3 arg4 arg5 arg6 arg7 arg8",
"Used for adding commands to a special effect"
);
Event EV_Client_SFXStartDelayed(
"delayedsfx",
EV_DEFAULT,
"fsSSSSSSSS",
"fDelay sCommand arg1 arg2 arg3 arg4 arg5 arg6 arg7 arg8",
"Used for adding commands to a special effect with a time delay"
);
2023-04-30 00:02:16 +02:00
EffectsEventQueueNode EffectsEventQueue;
2023-07-05 21:24:23 +02:00
CLASS_DECLARATION(Listener, ClientGameCommandManager, NULL) {
{&EV_Client_StartBlock, &ClientGameCommandManager::StartBlock },
{&EV_Client_EndBlock, &ClientGameCommandManager::EndBlock },
{&EV_Client_EmitterStartOff, &ClientGameCommandManager::EmitterStartOff },
{&EV_Client_OriginSpawn, &ClientGameCommandManager::BeginOriginSpawn },
{&EV_Client_OriginBeamSpawn, &ClientGameCommandManager::BeginOriginBeamSpawn },
{&EV_Client_OriginBeamEmitter, &ClientGameCommandManager::BeginOriginBeamEmitter },
{&EV_Client_TagSpawn, &ClientGameCommandManager::BeginTagSpawn },
{&EV_Client_TagSpawnLinked, &ClientGameCommandManager::BeginTagSpawnLinked },
{&EV_Client_TagEmitter, &ClientGameCommandManager::BeginTagEmitter },
{&EV_Client_BeginTagBeamEmitter, &ClientGameCommandManager::BeginTagBeamEmitter },
{&EV_Client_BeginTagBeamSpawn, &ClientGameCommandManager::BeginTagBeamSpawn },
{&EV_Client_OriginEmitter, &ClientGameCommandManager::BeginOriginEmitter },
{&EV_Client_EmitterOn, &ClientGameCommandManager::EmitterOn },
{&EV_Client_EmitterOff, &ClientGameCommandManager::EmitterOff },
{&EV_Client_SetAlpha, &ClientGameCommandManager::SetAlpha },
{&EV_Client_SetDieTouch, &ClientGameCommandManager::SetDieTouch },
{&EV_Client_SetBounceFactor, &ClientGameCommandManager::SetBounceFactor },
{&EV_Client_SetBounceSound, &ClientGameCommandManager::SetBounceSound },
{&EV_Client_SetBounceSoundOnce, &ClientGameCommandManager::SetBounceSoundOnce },
{&EV_Client_SetScale, &ClientGameCommandManager::SetScale },
{&EV_Client_SetScaleUpDown, &ClientGameCommandManager::SetScaleUpDown },
{&EV_Client_SetScaleMin, &ClientGameCommandManager::SetScaleMin },
{&EV_Client_SetScaleMax, &ClientGameCommandManager::SetScaleMax },
{&EV_Client_SetModel, &ClientGameCommandManager::SetModel },
{&EV_Client_SetLife, &ClientGameCommandManager::SetLife },
{&EV_Client_SetColor, &ClientGameCommandManager::SetColor },
{&EV_Client_SetRadialVelocity, &ClientGameCommandManager::SetRadialVelocity },
{&EV_Client_SetVelocity, &ClientGameCommandManager::SetVelocity },
{&EV_Client_SetAngularVelocity, &ClientGameCommandManager::SetAngularVelocity },
{&EV_Client_SetColorVelocity, &ClientGameCommandManager::SetAngularVelocity },
{&EV_Client_SetRandomVelocity, &ClientGameCommandManager::SetRandomVelocity },
{&EV_Client_SetRandomVelocityAlongAxis, &ClientGameCommandManager::SetRandomVelocityAlongAxis},
{&EV_Client_SetAccel, &ClientGameCommandManager::SetAccel },
{&EV_Client_SetFriction, &ClientGameCommandManager::SetFriction },
{&EV_Client_SetSpin, &ClientGameCommandManager::SetSpin },
{&EV_Client_SetVaryColor, &ClientGameCommandManager::SetVaryColor },
{&EV_Client_SetSmokeParms, &ClientGameCommandManager::SetAccel },
{&EV_Client_SetCount, &ClientGameCommandManager::SetCount },
{&EV_Client_SetFade, &ClientGameCommandManager::SetFade },
{&EV_Client_SetFadeDelay, &ClientGameCommandManager::SetFadeDelay },
{&EV_Client_SetFadeIn, &ClientGameCommandManager::SetFadeIn },
{&EV_Client_SetTwinkle, &ClientGameCommandManager::SetTwinkle },
{&EV_Client_SetTrail, &ClientGameCommandManager::SetTrail },
{&EV_Client_SetSpawnRange, &ClientGameCommandManager::SetSpawnRange },
{&EV_Client_SetSpawnRate, &ClientGameCommandManager::SetSpawnRate },
{&EV_Client_SetScaleRate, &ClientGameCommandManager::SetScaleRate },
{&EV_Client_SetOriginOffset, &ClientGameCommandManager::SetOriginOffset },
{&EV_Client_SetSphere, &ClientGameCommandManager::SetSphere },
{&EV_Client_SetCircle, &ClientGameCommandManager::SetCircle },
{&EV_Client_SetInwardSphere, &ClientGameCommandManager::SetInwardSphere },
{&EV_Client_SetRadius, &ClientGameCommandManager::SetRadius },
{&EV_Client_SetSwarm, &ClientGameCommandManager::SetSwarm },
{&EV_Client_SetAlign, &ClientGameCommandManager::SetAlign },
{&EV_Client_SetAlignOnce, &ClientGameCommandManager::SetAlignOnce },
{&EV_Client_SetCollision, &ClientGameCommandManager::SetCollision },
{&EV_Client_SetFlickerAlpha, &ClientGameCommandManager::SetFlickerAlpha },
{&EV_Client_Sound, &ClientGameCommandManager::Sound },
{&EV_Set_Current_Tiki, &ClientGameCommandManager::SetCurrentTiki },
{&EV_Client_StopSound, &ClientGameCommandManager::StopSound },
{&EV_Client_StopAliasChannel, &ClientGameCommandManager::StopAliasChannel },
{&EV_Client_LoopSound, &ClientGameCommandManager::LoopSound },
{&EV_Client_Cache, &ClientGameCommandManager::Cache },
{&EV_Client_CacheImage, &ClientGameCommandManager::CacheImage },
{&EV_Client_CacheFont, &ClientGameCommandManager::CacheFont },
{&EV_Client_AliasCache, &ClientGameCommandManager::AliasCache },
{&EV_Client_Alias, &ClientGameCommandManager::Alias },
{&EV_Client_CacheAlias, &ClientGameCommandManager::CacheAlias },
{&EV_Client_Footstep, &ClientGameCommandManager::Footstep },
{&EV_Client_Landing, &ClientGameCommandManager::LandingSound },
{&EV_Client_BodyFall, &ClientGameCommandManager::BodyFallSound },
{&EV_Client_Client, &ClientGameCommandManager::Client },
{&EV_Client_TagDynamicLight, &ClientGameCommandManager::TagDynamicLight },
{&EV_Client_OriginDynamicLight, &ClientGameCommandManager::OriginDynamicLight },
{&EV_Client_DynamicLight, &ClientGameCommandManager::DynamicLight },
{&EV_Client_BlockDynamicLight, &ClientGameCommandManager::BlockDynamicLight },
{&EV_Client_SetEntityColor, &ClientGameCommandManager::SetEntityColor },
{&EV_Client_SetGlobalFade, &ClientGameCommandManager::SetGlobalFade },
{&EV_Client_SetParentLink, &ClientGameCommandManager::SetParentLink },
{&EV_Client_SetHardLink, &ClientGameCommandManager::SetHardLink },
{&EV_Client_SetRandomRoll, &ClientGameCommandManager::SetRandomRoll },
{&EV_Client_SetVolumetric, &ClientGameCommandManager::SetVolumetric },
{&EV_Client_SetAngles, &ClientGameCommandManager::SetAngles },
{&EV_Client_SetRelativeAngles, &ClientGameCommandManager::SetRelativeAngles },
2023-07-05 21:24:23 +02:00
{&EV_Client_ParentAngles, &ClientGameCommandManager::ParentAngles },
{&EV_Client_Swipe, &ClientGameCommandManager::Swipe },
{&EV_Client_SwipeOn, &ClientGameCommandManager::SwipeOn },
{&EV_Client_SwipeOff, &ClientGameCommandManager::SwipeOff },
{&EV_Client_SetAnim, &ClientGameCommandManager::SetAnim },
{&EV_Client_AnimateOnce, &ClientGameCommandManager::AnimateOnce },
{&EV_Client_SetSubdivisions, &ClientGameCommandManager::SetSubdivisions },
{&EV_Client_SetMinOffset, &ClientGameCommandManager::SetMinOffset },
{&EV_Client_SetMaxOffset, &ClientGameCommandManager::SetMaxOffset },
{&EV_Client_SetBeamShader, &ClientGameCommandManager::SetShader },
{&EV_Client_SetBeamLength, &ClientGameCommandManager::SetLength },
{&EV_Client_SetDecalShader, &ClientGameCommandManager::SetShader },
{&EV_Client_SetTraceLength, &ClientGameCommandManager::SetLength },
{&EV_Client_SetBeamDelay, &ClientGameCommandManager::SetBeamDelay },
{&EV_Client_SetBeamToggleDelay, &ClientGameCommandManager::SetBeamToggleDelay },
{&EV_Client_SetBeamPersist, &ClientGameCommandManager::SetBeamPersist },
{&EV_Client_SetBeamOffsetEndpoints, &ClientGameCommandManager::SetBeamOffsetEndpoints },
{&EV_Client_BeamSphere, &ClientGameCommandManager::SetBeamSphere },
{&EV_Client_Spread, &ClientGameCommandManager::SetSpread },
{&EV_Client_UseLastTraceEnd, &ClientGameCommandManager::SetUseLastTraceEnd },
{&EV_Client_OffsetAlongAxis, &ClientGameCommandManager::SetOffsetAlongAxis },
{&EV_Client_Cone, &ClientGameCommandManager::SetCone },
{&EV_Client_SetEndAlpha, &ClientGameCommandManager::SetEndAlpha },
{&EV_Client_RandomChance, &ClientGameCommandManager::RandomChance },
{&EV_Client_CommandDelay, &ClientGameCommandManager::CommandDelay },
{&EV_Client_BounceDecal, &ClientGameCommandManager::SetBounceDecal },
{&EV_Client_SetDecalRadius, &ClientGameCommandManager::SetDecalRadius },
{&EV_Client_SetDecalOrientation, &ClientGameCommandManager::SetDecalOrientation },
{&EV_Client_TagList, &ClientGameCommandManager::TagList },
{&EV_Client_Lightstyle, &ClientGameCommandManager::SetLightstyle },
{&EV_Client_PhysicsRate, &ClientGameCommandManager::SetPhysicsRate },
{&EV_Client_Parallel, &ClientGameCommandManager::SetParallel },
{&EV_Client_Detail, &ClientGameCommandManager::SetDetail },
{&EV_Client_Wind, &ClientGameCommandManager::SetWindAffect },
{&EV_Client_SpriteGridLighting, &ClientGameCommandManager::SpriteGridLighting },
{&EV_Client_WaterOnly, &ClientGameCommandManager::SetWaterOnly },
{&EV_Client_SetAlignStretch, &ClientGameCommandManager::SetAlignStretch },
{&EV_Client_SetClampVelocity, &ClientGameCommandManager::SetClampVel },
{&EV_Client_SetClampVelocityAxis, &ClientGameCommandManager::SetClampVelAxis },
{&EV_Client_Print, &ClientGameCommandManager::Print },
{&EV_Client_EyeLimits, &ClientGameCommandManager::SetEyeLimits },
{&EV_Client_EyeMovement, &ClientGameCommandManager::SetEyeMovement },
{&EV_Client_SFXStart, &ClientGameCommandManager::StartSFX },
{&EV_Client_SFXStartDelayed, &ClientGameCommandManager::StartSFXDelayed },
{&EV_Client_Treads, &ClientGameCommandManager::SpawnTreads },
{&EV_Client_Treads_Off, &ClientGameCommandManager::TreadsOff },
{&EV_Client_ViewKick, &ClientGameCommandManager::EventViewKick },
{NULL, NULL }
};
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
static int DLightNameToNum(str s)
{
if (!s.icmp("normal")) {
return 0;
} else if (!s.icmp("lensflare")) {
return lensflare;
} else if (!s.icmp("viewlensflare")) {
return viewlensflare;
} else if (!s.icmp("additive")) {
return additive;
} else {
return 0;
}
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
float RandomizeRange(float start, float end)
{
float t;
if (start > end) {
return start;
}
t = start + ((end - start) * random());
return t;
}
2023-04-30 00:02:16 +02:00
2023-05-01 15:49:45 +02:00
void ClientGameCommandManager::ProcessPendingEventsForEntity()
{
2023-07-05 21:24:23 +02:00
EffectsEventQueueNode *event;
int t;
2023-07-05 21:24:23 +02:00
t = cg.time;
event = EffectsEventQueue.next;
2023-07-05 21:24:23 +02:00
while (event != &EffectsEventQueue && event->inttime <= t) {
if (event->GetEntityNum() == current_entity_number) {
// the event is removed from its list and temporarily added to the active list
LL_Remove(event, next, prev);
// ProcessEvent will dispose of this event when it is done
ProcessEvent(event->event);
// free up the node
delete event;
// start over, since can't guarantee that we didn't process any previous or following events
event = EffectsEventQueue.next;
2023-07-05 21:24:23 +02:00
} else {
event = event->next;
}
}
2023-05-01 15:49:45 +02:00
}
2023-07-05 21:24:23 +02:00
qboolean ClientGameCommandManager::PostEventForEntity(Event *ev, float fWait)
2023-05-01 15:49:45 +02:00
{
2023-07-05 21:24:23 +02:00
unsigned short evnum;
ClassDef *c;
EffectsEventQueueNode *event;
EffectsEventQueueNode *node;
int inttime;
2023-07-05 21:24:23 +02:00
if (!m_fEventWait || current_entity_number < 0) {
if (!str::icmp(ev->getName(), ")")) {
m_fEventWait = 0.0;
}
delete ev;
return qfalse;
}
evnum = ev->eventnum;
2023-07-05 21:24:23 +02:00
c = classinfo();
if (!c->responseLookup[evnum]) {
delete ev;
return qfalse;
}
2023-07-05 21:24:23 +02:00
event = EffectsEventQueue.next;
inttime = EVENT_msec + (fWait * 1000.0f + 0.5f);
2023-07-05 21:24:23 +02:00
while (event != &EffectsEventQueue && inttime > event->inttime) {
event = event->next;
}
2023-07-05 21:24:23 +02:00
if (m_fEventWait != 0.0) {
if (!str::icmp(ev->getName(), ")")) {
m_fEventWait = 0.0;
}
}
node = new EffectsEventQueueNode(ev, inttime, 0, current_entity_number);
LL_Add(event, node, next, prev);
return qtrue;
2023-05-01 15:49:45 +02:00
}
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetBaseAndAmplitude(Event *ev, Vector& base, Vector& amplitude)
2023-04-30 20:20:58 +02:00
{
int i = 1;
int j = 0;
2023-07-05 21:24:23 +02:00
for (j = 0; j < 3; j++) {
2023-04-30 20:20:58 +02:00
str org;
org = ev->GetString(i++);
if (org == "crandom") {
2023-07-05 21:24:23 +02:00
float value = ev->GetFloat(i++);
base[j] = -value;
2023-04-30 20:20:58 +02:00
amplitude[j] = value + value;
} else if (org == "random") {
2023-07-05 21:24:23 +02:00
base[j] = 0.0;
2023-04-30 20:20:58 +02:00
amplitude[j] = ev->GetFloat(i++);
} else if (org == "range") {
2023-07-05 21:24:23 +02:00
base[j] = ev->GetFloat(i++);
2023-04-30 20:20:58 +02:00
amplitude[j] = ev->GetFloat(i++);
} else {
2023-07-05 21:24:23 +02:00
base[j] = 0.0;
amplitude[j] = atof(org.c_str());
2023-04-30 20:20:58 +02:00
}
}
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// ClientGameCommandManager
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
ClientGameCommandManager::ClientGameCommandManager()
{
m_seed = 0;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
InitializeTempModels();
InitializeEmitters();
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::Print(Event *ev)
2023-04-30 20:20:58 +02:00
{
if (current_entity) {
2023-05-11 22:48:13 +02:00
cgi.DPrintf("%d:%s\n", current_entity->entityNumber, ev->GetString(1).c_str());
2023-04-30 20:20:58 +02:00
}
}
2023-04-30 00:02:16 +02:00
qboolean ClientGameCommandManager::IsBlockCommand(const str& name)
{
if (!str::icmp(name, "originspawn")) {
return true;
} else if (!str::icmp(name, "originbeamspawn")) {
return true;
} else if (!str::icmp(name, "tagspawn")) {
return true;
} else if (!str::icmp(name, "tagbeamspawn")) {
return true;
} else if (!str::icmp(name, "blockdlight")) {
return true;
}
return false;
}
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::DelayedRepeat(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
int i;
2023-05-06 23:37:05 +02:00
float delay;
2023-04-30 20:20:58 +02:00
2023-05-06 23:37:05 +02:00
delay = ev->GetFloat(1) * 1000.0;
2023-07-05 21:24:23 +02:00
if (current_entity) {
commandtime_t *ct = m_command_time_manager.GetLastCommandTime(current_entity->entityNumber, ev->GetInteger(2));
2023-04-30 20:20:58 +02:00
if (!ct->last_command_time) {
ct->last_command_time = cg.time + delay;
return;
}
if (ct->last_command_time > cg.time) {
return;
2023-07-05 21:24:23 +02:00
} else {
2023-04-30 20:20:58 +02:00
ct->last_command_time = cg.time + delay;
}
2023-07-05 21:24:23 +02:00
} else {
2023-05-06 23:37:05 +02:00
Class::warning("CCM:DelayedRepeat", "Cannot perform delayed repeat on spawned tempmodels");
2023-07-05 21:24:23 +02:00
2023-05-06 23:37:05 +02:00
Event ev1(ev->GetString(3));
2023-04-30 20:20:58 +02:00
2023-07-05 21:24:23 +02:00
for (i = 4; i <= ev->NumArgs(); i++) {
2023-05-06 23:37:05 +02:00
ev1.AddToken(ev->GetToken(i));
}
ProcessEvent(ev1);
return;
}
Event ev1(ev->GetString(3));
2023-04-30 20:20:58 +02:00
for (i = 4; i <= ev->NumArgs(); i++) {
2023-05-06 23:37:05 +02:00
ev1.AddToken(ev->GetToken(i));
2023-04-30 20:20:58 +02:00
}
ProcessEvent(ev1);
}
2023-04-30 00:02:16 +02:00
2023-05-06 23:37:05 +02:00
//===============
// CommandDelay
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::CommandDelay(Event *ev)
2023-05-06 23:37:05 +02:00
{
2023-07-05 21:24:23 +02:00
int i;
int num;
float fWait;
str eventName;
int delay;
Event *ev1;
2023-05-06 23:37:05 +02:00
2023-07-05 21:24:23 +02:00
fWait = ev->GetFloat(1);
2023-05-06 23:37:05 +02:00
eventName = ev->GetString(2);
ev1 = new Event(eventName);
num = ev->NumArgs();
for (i = 3; i <= num; i++) {
ev1->AddValue(ev->GetValue(i));
}
delay = ev->GetFloat(1) * 1000;
if (current_entity_number != -1) {
PostEventForEntity(ev1, fWait);
} else {
2023-07-05 21:24:23 +02:00
warning(
"CCM:CommandDelay",
2023-05-06 23:37:05 +02:00
"Can't use commanddelay in temp models. Found illegal commanddelay in '%s'\n",
2023-07-05 21:24:23 +02:00
current_tiki->name
);
2023-05-06 23:37:05 +02:00
}
}
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::StartSFX(Event *ev)
{
StartSFXCommand(ev, qfalse);
}
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::StartSFXDelayed(Event *ev)
{
StartSFXCommand(ev, qtrue);
}
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::StartSFXCommand(Event *ev, qboolean bDelayed)
{
2023-07-05 21:24:23 +02:00
qboolean bBlockCommand;
int i;
int iArgOfs;
float delay;
str sCommandName;
specialeffectcommand_t *pCommand;
2023-05-06 23:37:05 +02:00
2023-07-05 21:24:23 +02:00
if (bDelayed) {
delay = ev->GetFloat(1);
2023-05-06 23:37:05 +02:00
iArgOfs = 1;
2023-07-05 21:24:23 +02:00
} else {
delay = 0.0;
2023-05-06 23:37:05 +02:00
iArgOfs = 0;
}
2023-07-05 21:24:23 +02:00
sCommandName = ev->GetString(iArgOfs + 1);
2023-05-06 23:37:05 +02:00
bBlockCommand = IsBlockCommand(sCommandName);
2023-07-05 21:24:23 +02:00
if (!m_pCurrentSfx) {
if (bBlockCommand) {
2023-05-06 23:37:05 +02:00
m_spawnthing = &m_localemitter;
2023-07-05 21:24:23 +02:00
endblockfcn = &ClientGameCommandManager::EndIgnoreSfxBlock;
2023-05-06 23:37:05 +02:00
}
return;
}
if (!current_entity) {
return;
}
pCommand = m_pCurrentSfx->AddNewCommand();
if (!pCommand) {
return;
}
2023-07-05 21:24:23 +02:00
if (bBlockCommand) {
m_spawnthing = new spawnthing_t;
2023-05-06 23:37:05 +02:00
pCommand->emitter = m_spawnthing;
}
pCommand->fCommandTime = delay;
2023-07-05 21:24:23 +02:00
Event *ev1 = new Event(sCommandName);
2023-05-06 23:37:05 +02:00
for (i = iArgOfs + 2; i <= ev->NumArgs(); i++) {
ev1->AddToken(ev->GetToken(i));
}
if (bBlockCommand) {
ProcessEvent(ev1);
pCommand->endfcn = endblockfcn;
endblockfcn = NULL;
2023-07-05 21:24:23 +02:00
} else {
2023-05-06 23:37:05 +02:00
pCommand->pEvent = ev1;
}
}
void ClientGameCommandManager::EndIgnoreSfxBlock()
{
endblockfcn = NULL;
}
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetCurrentSFX(specialeffect_t *pSFX)
2023-05-01 15:49:45 +02:00
{
m_pCurrentSfx = pSFX;
2023-05-01 15:49:45 +02:00
}
void ClientGameCommandManager::ClearCurrentSFX()
{
m_pCurrentSfx = NULL;
2023-05-01 15:49:45 +02:00
}
2023-04-30 00:02:16 +02:00
//===============
// RandomChance
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::RandomChance(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
int i;
2023-04-30 20:20:58 +02:00
float percentage = ev->GetFloat(1);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if ((random() < percentage) && (ev->NumArgs() >= 2)) {
2023-07-05 21:24:23 +02:00
Event *ev1;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
ev1 = new Event(ev->GetString(2));
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
for (i = 3; i <= ev->NumArgs(); i++) {
ev1->AddToken(ev->GetToken(i));
}
ProcessEvent(ev1);
}
}
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetAlwaysDraw(Event *ev)
{
if (!m_spawnthing) {
return;
}
m_spawnthing->cgd.flags2 |= T2_ALWAYSDRAW;
}
2023-04-30 00:02:16 +02:00
//===============
// SetDetail
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetDetail(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags |= T_DETAIL;
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetWindAffect(Event *ev)
{
if (!m_spawnthing) {
return;
}
m_spawnthing->cgd.flags2 |= T2_WIND_AFFECT;
}
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SpriteGridLighting(Event *ev)
{
if (!m_spawnthing) {
return;
}
m_spawnthing->cgd.flags2 |= T2_SPRITEGRIDLIGHTING;
}
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetWaterOnly(Event *ev)
{
if (!m_spawnthing) {
return;
}
m_spawnthing->cgd.flags2 |= T2_WATERONLY;
}
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetClampVel(Event *ev)
{
if (!m_spawnthing) {
return;
}
if (ev->NumArgs() != 6) {
cgi.Printf("clampvel has 6 arguments\n");
return;
}
m_spawnthing->cgd.flags2 |= T2_CLAMP_VEL;
// cannot be both clamp vel and clamp vel axis
m_spawnthing->cgd.flags2 &= ~T2_CLAMP_VEL_AXIS;
m_spawnthing->cgd.minVel[0] = ev->GetFloat(1);
m_spawnthing->cgd.maxVel[0] = ev->GetFloat(2);
m_spawnthing->cgd.minVel[1] = ev->GetFloat(3);
m_spawnthing->cgd.maxVel[1] = ev->GetFloat(4);
m_spawnthing->cgd.minVel[2] = ev->GetFloat(5);
m_spawnthing->cgd.maxVel[2] = ev->GetFloat(6);
}
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetClampVelAxis(Event *ev)
{
if (!m_spawnthing) {
return;
}
if (ev->NumArgs() != 6) {
cgi.Printf("clampvel has 6 arguments\n");
return;
}
m_spawnthing->cgd.flags2 |= T2_CLAMP_VEL_AXIS;
// cannot be both clamp vel and clamp vel axis
m_spawnthing->cgd.flags2 &= ~T2_CLAMP_VEL;
m_spawnthing->cgd.minVel[0] = ev->GetFloat(1);
m_spawnthing->cgd.maxVel[0] = ev->GetFloat(2);
m_spawnthing->cgd.minVel[1] = ev->GetFloat(3);
m_spawnthing->cgd.maxVel[1] = ev->GetFloat(4);
m_spawnthing->cgd.minVel[2] = ev->GetFloat(5);
m_spawnthing->cgd.maxVel[2] = ev->GetFloat(6);
}
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetAlignStretch(Event *ev)
{
if (!m_spawnthing) {
return;
}
m_spawnthing->cgd.flags |= T_ALIGN;
m_spawnthing->cgd.flags2 |= T2_ALIGNSTRETCH;
if (ev->NumArgs() > 0) {
m_spawnthing->cgd.scale2 = ev->GetFloat(1);
2023-07-05 21:24:23 +02:00
} else {
m_spawnthing->cgd.scale2 = 1.0;
}
}
2023-04-30 00:02:16 +02:00
//===============
// SetDecalRadius
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetDecalRadius(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
if (!m_spawnthing) {
return;
}
2023-05-20 14:38:54 +02:00
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.decal_radius = ev->GetFloat(1);
}
2023-04-30 00:02:16 +02:00
//===============
// SetDecalOrientation
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetDecalOrientation(Event *ev)
2023-04-30 20:20:58 +02:00
{
str deg;
2023-07-05 21:24:23 +02:00
if (!m_spawnthing) {
return;
}
2023-05-20 14:38:54 +02:00
2023-04-30 20:20:58 +02:00
deg = ev->GetString(1);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (!deg.icmp("random")) {
m_spawnthing->cgd.decal_orientation = random() * 360;
} else {
m_spawnthing->cgd.decal_orientation = ev->GetFloat(1);
}
}
2023-04-30 00:02:16 +02:00
//===============
// SetBounceDecal
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetBounceDecal(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
if (!m_spawnthing) {
return;
}
2023-05-20 14:38:54 +02:00
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags2 |= T2_BOUNCE_DECAL;
if (ev->NumArgs() > 1) {
m_spawnthing->cgd.maxbouncecount = ev->GetInteger(1);
if (ev->NumArgs() > 2) {
qboolean b = ev->GetBoolean(2);
if (b) {
m_spawnthing->cgd.flags2 |= T2_TEMPORARY_DECAL;
2023-04-30 00:02:16 +02:00
}
2023-04-30 20:20:58 +02:00
}
}
}
2023-04-30 00:02:16 +02:00
//===============
// SetParallel
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetParallel(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
if (!m_spawnthing) {
return;
}
2023-05-20 14:38:54 +02:00
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags2 |= T2_PARALLEL;
}
2023-04-30 00:02:16 +02:00
//===============
// PhysicsRate
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetPhysicsRate(Event *ev)
2023-04-30 20:20:58 +02:00
{
str rate;
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
if (!m_spawnthing) {
return;
}
2023-05-20 14:38:54 +02:00
2023-04-30 20:20:58 +02:00
rate = ev->GetString(1);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (!rate.icmp(rate, "every")) {
m_spawnthing->cgd.flags2 |= T2_PHYSICS_EVERYFRAME;
} else {
m_spawnthing->cgd.physicsRate = atof(rate);
}
}
2023-04-30 00:02:16 +02:00
//===============
// SetLightstyle
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetLightstyle(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
if (!m_spawnthing) {
return;
}
2023-05-20 14:38:54 +02:00
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.lightstyle = CG_RegisterLightStyle(ev->GetString(1));
}
2023-04-30 00:02:16 +02:00
//===============
// SetBeamSphere
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetBeamSphere(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
if (!m_spawnthing) {
return;
}
2023-05-20 14:38:54 +02:00
2023-04-30 20:20:58 +02:00
m_spawnthing->numspherebeams = ev->GetInteger(1);
2023-07-05 21:24:23 +02:00
m_spawnthing->beamflags = BEAM_SPHERE_EFFECT;
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
//===============
// SetBeamSpread
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetSpread(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
if (!m_spawnthing) {
return;
}
2023-05-20 14:38:54 +02:00
2023-04-30 20:20:58 +02:00
m_spawnthing->spreadx = ev->GetFloat(1);
m_spawnthing->spready = ev->GetFloat(2);
}
2023-04-30 00:02:16 +02:00
//===============
// SetUseLastTraceEnd
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetUseLastTraceEnd(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
if (!m_spawnthing) {
return;
}
2023-05-20 14:38:54 +02:00
2023-04-30 20:20:58 +02:00
m_spawnthing->use_last_trace_end = qtrue;
}
2023-04-30 00:02:16 +02:00
//===============
// SetSubdivisions
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetSubdivisions(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
if (!m_spawnthing) {
return;
}
2023-05-20 14:38:54 +02:00
2023-04-30 20:20:58 +02:00
m_spawnthing->numSubdivisions = ev->GetInteger(1);
}
2023-04-30 00:02:16 +02:00
//===============
// SetBeamPersist
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetBeamPersist(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
if (!m_spawnthing) {
return;
}
2023-05-20 14:38:54 +02:00
2023-04-30 20:20:58 +02:00
m_spawnthing->beamflags |= BEAM_PERSIST_EFFECT;
}
2023-04-30 00:02:16 +02:00
//===============
// SetBeamOffsetEndponts
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetBeamOffsetEndpoints(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
if (!m_spawnthing) {
return;
}
2023-05-20 14:38:54 +02:00
2023-04-30 20:20:58 +02:00
m_spawnthing->beamflags |= BEAM_OFFSET_ENDPOINTS;
}
2023-04-30 00:02:16 +02:00
//===============
// SetBeamDelay
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetBeamDelay(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
if (!m_spawnthing) {
return;
}
2023-05-20 14:38:54 +02:00
2023-04-30 20:20:58 +02:00
if (ev->NumArgs() > 1) {
str r = ev->GetString(1);
if (r.icmp("random")) {
m_spawnthing->beamflags |= BEAM_RANDOM_DELAY;
}
m_spawnthing->delay = ev->GetFloat(2) * 1000.0f;
} else {
m_spawnthing->delay = ev->GetFloat(1) * 1000.0f;
}
}
2023-04-30 00:02:16 +02:00
//===============
// SetBeamToggleDelay
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetBeamToggleDelay(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
if (!m_spawnthing) {
return;
}
2023-05-20 14:38:54 +02:00
2023-04-30 20:20:58 +02:00
m_spawnthing->beamflags |= BEAM_TOGGLE;
if (ev->NumArgs() > 1) {
str r = ev->GetString(1);
if (!r.icmp("random")) {
m_spawnthing->beamflags |= BEAM_RANDOM_TOGGLEDELAY;
}
m_spawnthing->toggledelay = ev->GetFloat(2) * 1000.0f;
} else {
m_spawnthing->toggledelay = ev->GetFloat(1) * 1000.0f;
}
}
2023-04-30 00:02:16 +02:00
//===============
// SetBeamLength
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetLength(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
if (!m_spawnthing) {
return;
}
2023-05-20 14:38:54 +02:00
2023-04-30 20:20:58 +02:00
m_spawnthing->length = ev->GetFloat(1);
}
2023-04-30 00:02:16 +02:00
//===============
// SetShader
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetShader(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
if (!m_spawnthing) {
return;
}
2023-05-20 14:38:54 +02:00
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.shadername = ev->GetString(1);
}
2023-04-30 00:02:16 +02:00
//===============
// SetMinOffset
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetMinOffset(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
if (!m_spawnthing) {
return;
}
2023-05-20 14:38:54 +02:00
2023-04-30 20:20:58 +02:00
m_spawnthing->min_offset = ev->GetInteger(1);
}
2023-04-30 00:02:16 +02:00
//===============
// SetSubdivisions
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetMaxOffset(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
if (!m_spawnthing) {
return;
}
2023-05-20 14:38:54 +02:00
2023-04-30 20:20:58 +02:00
m_spawnthing->max_offset = ev->GetInteger(1);
}
2023-04-30 00:02:16 +02:00
//===============
// SetAnim
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetAnim(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
if (!m_spawnthing) {
return;
}
2023-05-20 14:38:54 +02:00
2023-04-30 20:20:58 +02:00
m_spawnthing->animName = ev->GetString(1);
}
2023-04-30 00:02:16 +02:00
//===============
// AnimateOnce
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::AnimateOnce(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
if (!m_spawnthing) {
return;
}
2023-05-20 14:38:54 +02:00
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags |= T_ANIMATEONCE;
}
2023-04-30 00:02:16 +02:00
//===============
// EmitterStartOff
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::EmitterStartOff(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
if (!m_spawnthing) {
return;
}
2023-05-20 14:38:54 +02:00
2023-04-30 20:20:58 +02:00
m_spawnthing->startoff = qtrue;
}
2023-04-30 00:02:16 +02:00
//===============
// StartBlock
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::StartBlock(Event *ev)
2023-04-30 20:20:58 +02:00
{
// Make sure there are no more args on this line, because
// they will be lost
if (ev->NumArgs() > 1) {
cgi.DPrintf("CCM::StartBlock : Invalid commands on start block '{'\n");
}
}
2023-04-30 00:02:16 +02:00
//===============
// EndBlock
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::EndBlock(Event *ev)
2023-04-30 20:20:58 +02:00
{
// Make sure there are no more args on this line, because
// they will be lost
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (ev->NumArgs() > 1) {
cgi.DPrintf("CCM::StartBlock : Invalid commands on end block '{'\n");
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (endblockfcn) {
(this->*endblockfcn)();
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
endblockfcn = NULL;
// Fixed since version 2.0
m_spawnthing = NULL;
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetSwarm
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetSwarm(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-06 21:10:36 +02:00
if (!m_spawnthing) {
return;
}
2023-07-05 21:24:23 +02:00
m_spawnthing->cgd.swarmfreq = ev->GetInteger(1);
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.swarmmaxspeed = ev->GetFloat(2);
2023-07-05 21:24:23 +02:00
m_spawnthing->cgd.swarmdelta = ev->GetFloat(3);
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags |= T_SWARM;
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetCircle
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetCircle(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-06 21:10:36 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags |= T_CIRCLE;
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetSphere
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetSphere(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-06 21:10:36 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags |= T_SPHERE;
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetSphere
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetRadius(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-06 21:10:36 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->sphereRadius = ev->GetFloat(1);
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetInwardSphere
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetInwardSphere(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-06 21:10:36 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags |= T_INWARDSPHERE;
m_spawnthing->sphereRadius = ev->GetFloat(1);
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetAlign
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetAlign(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-06 21:10:36 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags |= T_ALIGN;
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetAlignOnce
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetAlignOnce(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-06 21:10:36 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags |= T_ALIGNONCE;
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetRandomRoll
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetRandomRoll(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-06 21:10:36 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags |= T_RANDOMROLL;
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetVolumetric(Event *ev)
{
2023-05-06 21:10:36 +02:00
if (!m_spawnthing) {
return;
}
m_spawnthing->cgd.flags2 |= T2_VOLUMETRIC;
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetCollision
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetCollision(Event *ev)
2023-04-30 20:20:58 +02:00
{
str mask;
2023-04-30 00:02:16 +02:00
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags |= T_COLLISION;
m_spawnthing->cgd.collisionmask = (CONTENTS_SOLID);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (ev->NumArgs() > 1) {
mask = ev->GetString(1);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (mask == "water") {
m_spawnthing->cgd.collisionmask = (CONTENTS_SOLID | CONTENTS_WATER);
}
}
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetFlickerAlpha
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetFlickerAlpha(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-06 21:10:36 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags |= T_FLICKERALPHA;
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetEndAlpha
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetEndAlpha(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->endalpha = ev->GetFloat(1);
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetOffsetAlongAxis
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetOffsetAlongAxis(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
2023-04-30 20:20:58 +02:00
}
2023-05-09 21:21:16 +02:00
SetBaseAndAmplitude(ev, m_spawnthing->axis_offset_base, m_spawnthing->axis_offset_amplitude);
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetCone(Event *ev)
{
2023-05-06 21:10:36 +02:00
if (!m_spawnthing) {
return;
}
m_spawnthing->cgd.flags2 |= T2_CONE;
2023-07-05 21:24:23 +02:00
m_spawnthing->coneHeight = ev->GetFloat(1);
2023-05-06 21:10:36 +02:00
m_spawnthing->sphereRadius = ev->GetFloat(2);
}
2023-04-30 20:20:58 +02:00
//=============
// SetOriginOffset
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetOriginOffset(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
2023-04-30 20:20:58 +02:00
}
2023-05-09 21:21:16 +02:00
2023-07-05 21:24:23 +02:00
SetBaseAndAmplitude(ev, m_spawnthing->origin_offset_base, m_spawnthing->origin_offset_amplitude);
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetAlpha
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetAlpha(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.alpha = ev->GetFloat(1);
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetDieTouch
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetDieTouch(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags |= T_DIETOUCH;
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetBounceFactor
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetBounceFactor(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.bouncefactor = ev->GetFloat(1);
m_spawnthing->cgd.flags |= T_COLLISION;
m_spawnthing->cgd.collisionmask = (CONTENTS_SOLID);
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetBounceSound
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetBounceSound(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.bouncesound = ev->GetString(1);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (ev->NumArgs() == 2) {
m_spawnthing->cgd.bouncesound_delay = ev->GetFloat(1) * 1000;
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags |= T_BOUNCESOUND;
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetBounceSoundOnce
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetBounceSoundOnce(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags |= T_BOUNCESOUNDONCE;
SetBounceSound(ev);
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetScale
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetScale(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.scale = ev->GetFloat(1);
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetScaleUpDown
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetScaleUpDown(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags |= T_SCALEUPDOWN;
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetScaleMin
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetScaleMin(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags |= T_RANDSCALE;
m_spawnthing->cgd.scalemin = ev->GetFloat(1);
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetScaleMax
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetScaleMax(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags |= T_RANDSCALE;
m_spawnthing->cgd.scalemax = ev->GetFloat(1);
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetScaleRate
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetScaleRate(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.scaleRate = ev->GetFloat(1);
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetFade
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetFade(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags |= T_FADE;
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetFadeDelay
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetFadeDelay(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.fadedelay = ev->GetFloat(1) * 1000;
m_spawnthing->cgd.flags |= T_FADE;
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetSpawnRange(Event *ev)
{
2023-05-06 23:37:05 +02:00
float fVal1, fVal2;
if (!m_spawnthing) {
return;
}
2023-07-05 21:24:23 +02:00
if (ev->NumArgs() < 1) {
2023-05-06 23:37:05 +02:00
cgi.DPrintf("too few arguments to spawnrange");
return;
}
fVal1 = ev->GetFloat(1);
if (ev->NumArgs() > 1) {
fVal2 = ev->GetFloat(2);
2023-07-05 21:24:23 +02:00
} else {
2023-05-07 14:45:23 +02:00
fVal2 = 0.0;
}
2023-05-06 23:37:05 +02:00
2023-07-05 21:24:23 +02:00
if (fVal1 * fVal1 > fVal2 * fVal2) {
2023-05-06 23:37:05 +02:00
m_spawnthing->fMinRangeSquared = fVal2 * fVal2;
m_spawnthing->fMaxRangeSquared = fVal1 * fVal1;
2023-07-05 21:24:23 +02:00
} else {
2023-05-06 23:37:05 +02:00
m_spawnthing->fMinRangeSquared = fVal1 * fVal1;
m_spawnthing->fMaxRangeSquared = fVal2 * fVal2;
}
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetFadeIn
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetFadeIn(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags |= T_FADEIN;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (ev->NumArgs() > 0) {
m_spawnthing->cgd.fadeintime = ev->GetFloat(1) * 1000;
}
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetTwinkle
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetTwinkle(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags |= T_TWINKLE;
m_spawnthing->cgd.min_twinkletimeoff = ev->GetFloat(1) * 1000;
m_spawnthing->cgd.max_twinkletimeoff = ev->GetFloat(2) * 1000;
2023-07-05 21:24:23 +02:00
m_spawnthing->cgd.min_twinkletimeon = ev->GetFloat(3) * 1000;
m_spawnthing->cgd.max_twinkletimeon = ev->GetFloat(4) * 1000;
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetSwipe
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetTrail(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags2 |= T2_TRAIL;
2023-07-05 21:24:23 +02:00
m_spawnthing->cgd.swipe_shader = ev->GetString(1);
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.swipe_tag_start = ev->GetString(2);
2023-07-05 21:24:23 +02:00
m_spawnthing->cgd.swipe_tag_end = ev->GetString(3);
m_spawnthing->cgd.swipe_life = ev->GetFloat(4);
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetSpawnRate
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetSpawnRate(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->spawnRate = (1.0f / ev->GetFloat(1)) * 1000;
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetParentLink
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetParentLink(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags |= T_PARENTLINK;
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetHardLink
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetHardLink(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags |= T_HARDLINK;
m_spawnthing->cgd.parent = current_entity_number;
if (current_entity) {
2023-07-05 21:24:23 +02:00
m_spawnthing->cgd.origin = m_spawnthing->cgd.origin - current_entity->origin;
2023-04-30 20:20:58 +02:00
}
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetColor
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetColor(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
m_spawnthing->cgd.color[0] = ev->GetFloat(1);
m_spawnthing->cgd.color[1] = ev->GetFloat(2);
m_spawnthing->cgd.color[2] = ev->GetFloat(3);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (ev->NumArgs() == 4) {
m_spawnthing->cgd.color[3] = ev->GetFloat(4);
2023-07-05 21:24:23 +02:00
m_spawnthing->cgd.alpha = ev->GetFloat(4);
2023-04-30 20:20:58 +02:00
}
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetColorRange(Event *ev)
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-05-06 23:37:05 +02:00
// FIXME: unused stub??
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetEntityColor
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetEntityColor(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
if (current_centity) {
current_centity->client_color[0] = ev->GetFloat(1);
current_centity->client_color[1] = ev->GetFloat(2);
current_centity->client_color[2] = ev->GetFloat(3);
if (ev->NumArgs() == 4) {
current_centity->client_color[3] = ev->GetFloat(4);
}
}
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetGlobalFade
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetGlobalFade(Event *ev)
2023-04-30 20:20:58 +02:00
{
str mode;
2023-04-30 00:02:16 +02:00
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
mode = ev->GetString(1);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (mode == "in") {
m_spawnthing->cgd.flags |= T_GLOBALFADEIN;
} else if (mode == "out") {
m_spawnthing->cgd.flags |= T_GLOBALFADEOUT;
} else {
cgi.DPrintf("Illegal globalfade parm: %s\n", mode.c_str());
}
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetRandomVelocity
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetRandomVelocity(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
int i = 1;
int j = 0;
2023-04-30 20:20:58 +02:00
Vector randval;
2023-07-05 21:24:23 +02:00
str vel;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (ev->NumArgs() < 3) {
2023-07-05 21:24:23 +02:00
warning("ClientGameCommandManager::SetRandomVelocity", "Expecting at least 3 args for command randvel");
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
SetBaseAndAmplitude(ev, m_spawnthing->randvel_base, m_spawnthing->randvel_amplitude);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags2 |= T2_MOVE;
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetRandomVelocityAlongAxis
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetRandomVelocityAlongAxis(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags |= T_RANDVELAXIS;
SetRandomVelocity(ev);
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetRadialVelocity(Event *ev)
{
2023-05-06 23:37:05 +02:00
if (!m_spawnthing) {
return;
}
if (ev->NumArgs() < 3) {
warning("ClientGameCommandManager::SetRadialVelocity", "Missing parameters for command radialvelocity");
}
m_spawnthing->cgd.velocity[0] = ev->GetFloat(1);
m_spawnthing->cgd.velocity[1] = ev->GetFloat(2);
m_spawnthing->cgd.velocity[2] = ev->GetFloat(3);
m_spawnthing->cgd.velocity[2] -= m_spawnthing->cgd.velocity[1];
m_spawnthing->cgd.flags2 |= T2_RADIALVELOCITY | T2_MOVE;
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetVelocity
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetVelocity(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->forwardVelocity = ev->GetFloat(1);
m_spawnthing->cgd.flags2 |= T2_MOVE;
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetAngularVelocity
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetAngularVelocity(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
int i = 1;
int j = 0;
2023-04-30 20:20:58 +02:00
Vector randval;
2023-07-05 21:24:23 +02:00
str vel;
2023-04-30 20:20:58 +02:00
if (!m_spawnthing) {
return;
}
if (ev->NumArgs() < 3) {
2023-07-05 21:24:23 +02:00
warning("ClientGameCommandManager::SetAngularVelocity", "Expecting at least 3 args for command randvel");
2023-04-30 20:20:58 +02:00
}
2023-07-05 21:24:23 +02:00
SetBaseAndAmplitude(ev, m_spawnthing->avelocity_base, m_spawnthing->avelocity_amplitude);
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.flags2 |= T2_AMOVE;
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetAngles
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetAngles(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
int i = 1;
int j = 0;
2023-04-30 20:20:58 +02:00
Vector randval;
2023-07-05 21:24:23 +02:00
str vel;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (!m_spawnthing) {
return;
}
if (ev->NumArgs() < 3) {
2023-07-05 21:24:23 +02:00
warning("ClientGameCommandManager::SetAngles", "Expecting at least 3 args for command randvel");
2023-04-30 20:20:58 +02:00
}
2023-07-05 21:24:23 +02:00
SetBaseAndAmplitude(ev, m_spawnthing->cgd.angles, m_spawnthing->angles_amplitude);
2023-04-30 20:20:58 +02:00
// Set the tag axis
m_spawnthing->cgd.flags |= T_ANGLES;
}
2023-04-30 00:02:16 +02:00
//=============
// SetRelativeAngles
//=============
void ClientGameCommandManager::SetRelativeAngles(Event* ev)
{
if (!m_spawnthing) {
return;
}
m_spawnthing->cgd.flags2 |= T2_RELATIVEANGLES;
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// ParentAngles
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::ParentAngles(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
if (current_centity) {
m_spawnthing->cgd.angles = Vector(current_centity->currentState.angles);
}
m_spawnthing->cgd.flags |= T_ANGLES;
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::EmitterAngles(Event *ev)
{
2023-05-06 23:37:05 +02:00
if (!m_spawnthing) {
return;
}
MatrixToEulerAngles(m_spawnthing->tag_axis, m_spawnthing->cgd.angles);
2023-07-05 21:24:23 +02:00
if (ev->NumArgs() > 0) {
m_spawnthing->cgd.angles[0] = ev->GetFloat(1);
}
if (ev->NumArgs() > 1) {
m_spawnthing->cgd.angles[1] = ev->GetFloat(2);
}
if (ev->NumArgs() > 2) {
m_spawnthing->cgd.angles[2] = ev->GetFloat(3);
}
2023-05-06 23:37:05 +02:00
m_spawnthing->cgd.flags |= T_ANGLES;
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetAccel
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetAccel(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.accel[0] = ev->GetFloat(1);
m_spawnthing->cgd.accel[1] = ev->GetFloat(2);
m_spawnthing->cgd.accel[2] = ev->GetFloat(3);
m_spawnthing->cgd.flags2 |= T2_ACCEL;
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetFriction(Event *ev)
{
2023-05-06 23:37:05 +02:00
if (!m_spawnthing) {
return;
}
m_spawnthing->cgd.friction = ev->GetFloat(1);
m_spawnthing->cgd.flags2 |= T2_FRICTION;
}
//=============
// SetSpin
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetSpin(Event *ev)
{
if (ev->NumArgs() != 1) {
throw ScriptException("spin needs rotations per second specified\n");
}
if (!m_spawnthing) {
return;
}
m_spawnthing->cgd.spin_rotation = ev->GetFloat(1);
m_spawnthing->cgd.flags2 |= T2_SPIN;
}
//=============
// SetVaryColor
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetVaryColor(Event *ev)
{
2023-05-06 23:37:05 +02:00
if (!m_spawnthing) {
return;
}
m_spawnthing->cgd.flags2 |= T2_VARYCOLOR;
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetCount
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetCount(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
m_spawnthing->count = ev->GetInteger(1);
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetLife
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetLife(Event *ev)
2023-04-30 20:20:58 +02:00
{
str life;
2023-04-30 00:02:16 +02:00
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
life = ev->GetString(1);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (!life.icmp("autocalc")) {
m_spawnthing->cgd.flags |= T_AUTOCALCLIFE;
} else {
m_spawnthing->cgd.life = atof(life) * 1000;
2023-07-22 15:49:44 +02:00
if (ev->NumArgs() > 1) {
m_spawnthing->life_random = ev->GetFloat(2) * 1000;
}
2023-04-30 20:20:58 +02:00
}
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// SetModel
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetModel(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
int i;
int num = ev->NumArgs();
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
for (i = 1; i <= num; i++) {
str s_arg(ev->GetString(i));
m_spawnthing->m_modellist.AddObject(s_arg);
CacheResource(ev->GetString(i));
}
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// TagList
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::TagList(Event *ev)
2023-04-30 20:20:58 +02:00
{
int i;
int num = ev->NumArgs();
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
if (num < 2) {
2023-07-05 21:24:23 +02:00
warning(
"CCG::TagList",
"Invalid number of tags specified in taglist. "
"Minimum set of tags is 2.\n"
);
2023-04-30 20:20:58 +02:00
return;
}
for (i = 1; i <= num; i++) {
str s_arg(ev->GetString(i));
m_spawnthing->m_taglist.AddObject(s_arg);
}
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetEyeLimits(Event *ev)
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-07-05 21:24:23 +02:00
if (ev->NumArgs() < 3) {
2023-05-06 23:37:05 +02:00
warning("CCG::SetEyeLimits", "Invalid number of parameters.\n");
return;
}
cg.vEyeOffsetMax[0] = ev->GetFloat(1);
cg.vEyeOffsetMax[2] = ev->GetFloat(2);
2023-07-05 21:24:23 +02:00
cg.fEyeOffsetFrac = ev->GetFloat(3);
}
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetEyeMovement(Event *ev)
{
2023-05-09 21:21:16 +02:00
if (!m_spawnthing) {
return;
}
2023-07-05 21:24:23 +02:00
if (ev->NumArgs() < 1) {
2023-05-06 23:37:05 +02:00
warning("CCG::SetEyeMovement", "No parameters specified.\n");
return;
}
cg.fEyeOffsetFrac = ev->GetFloat(1);
}
2023-04-30 00:02:16 +02:00
//=============
2023-04-30 20:20:58 +02:00
// InitializeSpawnthing
2023-04-30 00:02:16 +02:00
//=============
2023-07-05 21:24:23 +02:00
spawnthing_t *ClientGameCommandManager::InitializeSpawnthing(spawnthing_t *sp)
2023-04-30 20:20:58 +02:00
{
int i;
// Initalize m_spawnthing - these can be overidden with other commands
sp->m_modellist.ClearObjectList();
AxisClear(sp->axis);
AxisClear(sp->tag_axis);
2023-07-05 21:24:23 +02:00
sp->startoff = qfalse;
sp->origin_offset_base = Vector(0, 0, 0);
2023-04-30 20:20:58 +02:00
sp->origin_offset_amplitude = Vector(0, 0, 0);
2023-07-05 21:24:23 +02:00
sp->axis_offset_base = Vector(0, 0, 0);
sp->axis_offset_amplitude = Vector(0, 0, 0);
sp->randvel_base = Vector(0, 0, 0);
sp->randvel_amplitude = Vector(0, 0, 0);
sp->avelocity_base = Vector(0, 0, 0);
sp->avelocity_amplitude = Vector(0, 0, 0);
sp->angles_amplitude = Vector(0, 0, 0);
sp->life_random = 0;
sp->forwardVelocity = 0;
sp->sphereRadius = 0;
sp->coneHeight = 0;
sp->spawnRate = 0.1f;
sp->count = 1;
sp->length = 1000;
sp->max_offset = 0;
sp->min_offset = 0;
sp->overlap = 0;
sp->numSubdivisions = 1;
sp->delay = 0;
sp->toggledelay = 0;
sp->endalpha = 1.0f;
sp->spreadx = 0;
sp->spready = 0;
sp->beamflags = 0;
sp->startoff = 0;
sp->numspherebeams = 0;
sp->use_last_trace_end = qfalse;
sp->tagnum = -1;
sp->numtempmodels = 0;
sp->entnum = ENTITYNUM_NONE;
sp->cgd.scale = 1.0f;
sp->cgd.createTime = cg.time;
sp->cgd.life = EMITTER_DEFAULT_LIFE;
sp->cgd.avelocity = Vector(0, 0, 0);
sp->cgd.accel = Vector(0, 0, 0);
sp->cgd.origin = Vector(0, 0, 0);
sp->cgd.oldorigin = Vector(0, 0, 0);
sp->cgd.angles = Vector(0, 0, 0);
sp->cgd.alpha = 1.0f;
sp->cgd.scalemin = 0;
sp->cgd.scalemax = 999999.0f;
sp->cgd.scaleRate = 0;
sp->cgd.bouncefactor = 0.3f;
sp->cgd.bouncesound = "";
sp->cgd.bouncesound_delay = 1000;
sp->cgd.bouncecount = 0;
sp->cgd.maxbouncecount = 3;
sp->cgd.flags = 0;
sp->cgd.flags2 = 0;
sp->cgd.swarmfreq = 0;
sp->cgd.swarmdelta = 0;
sp->cgd.swarmmaxspeed = 0;
sp->cgd.fadeintime = 0;
sp->cgd.fadedelay = 0;
sp->cgd.lightIntensity = 0;
sp->cgd.lightType = 0;
sp->cgd.collisionmask = MASK_AUTOCALCLIFE;
sp->cgd.parent = -1;
sp->cgd.tiki = nullptr;
sp->cgd.lightstyle = -1;
sp->cgd.physicsRate = 10;
sp->cgd.shadername = "beamshader";
sp->cgd.decal_orientation = 0;
sp->cgd.decal_radius = 10;
2023-04-30 20:20:58 +02:00
sp->cgd.max_twinkletimeoff = 0;
sp->cgd.min_twinkletimeoff = 0;
2023-07-05 21:24:23 +02:00
sp->cgd.max_twinkletimeon = 0;
sp->cgd.min_twinkletimeon = 0;
sp->cgd.swipe_life = 0;
sp->cgd.scale2 = 1;
sp->cgd.spin_rotation = 0;
2023-07-05 21:24:23 +02:00
sp->fMinRangeSquared = 0;
sp->fMaxRangeSquared = 9.9999997e37f;
2023-04-30 20:20:58 +02:00
for (i = 0; i < 3; i++) {
2023-07-05 21:24:23 +02:00
sp->dcolor[i] = 1.0f;
2023-04-30 20:20:58 +02:00
sp->cgd.color[i] = 1.0;
}
sp->cgd.color[3] = 1.0;
return sp;
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SpawnEffect(int count, spawnthing_t *sp)
{
2023-05-06 21:10:36 +02:00
m_spawnthing = sp;
2023-07-05 21:24:23 +02:00
if (m_spawnthing->cgd.flags2 & T2_VOLUMETRIC) {
2023-05-06 21:10:36 +02:00
// volumetric smoke
SpawnVSSSource(count, 0);
2023-07-05 21:24:23 +02:00
} else {
2023-05-06 21:10:36 +02:00
SpawnTempModel(count);
}
m_spawnthing = NULL;
2023-05-06 21:10:36 +02:00
}
void ClientGameCommandManager::SpawnEffect(int count, int timealive)
{
if (!m_spawnthing) {
return;
}
2023-07-05 21:24:23 +02:00
if (m_spawnthing->cgd.flags2 & T2_VOLUMETRIC) {
2023-05-06 21:10:36 +02:00
// volumetric smoke
SpawnVSSSource(count, 0);
2023-07-05 21:24:23 +02:00
} else {
2023-05-06 21:10:36 +02:00
SpawnTempModel(count);
}
}
2023-04-30 00:02:16 +02:00
//==================
2023-04-30 20:20:58 +02:00
// GetEmitterByName
2023-04-30 00:02:16 +02:00
//==================
2023-07-05 21:24:23 +02:00
spawnthing_t *ClientGameCommandManager::GetEmitterByName(str name)
2023-04-30 20:20:58 +02:00
{
int i;
for (i = 1; i <= m_emitters.NumObjects(); i++) {
2023-07-05 21:24:23 +02:00
spawnthing_t *st = m_emitters.ObjectAt(i);
2023-04-30 20:20:58 +02:00
if (st->emittername == name) {
return st;
}
}
return NULL;
}
2023-04-30 00:02:16 +02:00
//==================
2023-04-30 20:20:58 +02:00
// CreateNewEmitter
2023-04-30 00:02:16 +02:00
//==================
2023-07-05 21:24:23 +02:00
spawnthing_t *ClientGameCommandManager::CreateNewEmitter(str name)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
spawnthing_t *st;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
st = new spawnthing_t;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
// Init the emitter and set the internal pointer at it
InitializeSpawnthing(st);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
// Set the emitter's name
st->emittername = name;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
// Store it in the container
m_emitters.AddObject(st);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
return st;
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::DeleteEmitters(dtiki_t *tiki)
{
2023-07-05 21:24:23 +02:00
int i;
spawnthing_t *spawnthing;
2023-07-05 21:24:23 +02:00
for (i = m_emitters.NumObjects(); i > 0; i--) {
spawnthing = m_emitters.ObjectAt(i);
2023-07-05 21:24:23 +02:00
if (spawnthing->cgd.tiki == tiki) {
FreeSpawnthing(spawnthing);
}
}
}
2023-07-05 21:24:23 +02:00
void CG_DeleteEmitters(dtiki_t *tiki)
{
commandManager.DeleteEmitters(tiki);
}
2023-04-30 00:02:16 +02:00
//==================
2023-04-30 20:20:58 +02:00
// CreateNewEmitter
2023-04-30 00:02:16 +02:00
//==================
2023-07-05 21:24:23 +02:00
spawnthing_t *ClientGameCommandManager::CreateNewEmitter(void)
2023-04-30 20:20:58 +02:00
{
return CreateNewEmitter("");
}
2023-04-30 00:02:16 +02:00
//===============
2023-04-30 20:20:58 +02:00
// BeginOriginSpawn
2023-04-30 00:02:16 +02:00
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::BeginOriginSpawn(Event *ev)
2023-04-30 20:20:58 +02:00
{
if (!current_entity) {
m_spawnthing = NULL;
2023-04-30 20:20:58 +02:00
return;
}
2023-04-30 00:02:16 +02:00
// Setup ending function
endblockfcn = &ClientGameCommandManager::EndOriginSpawn;
if (!m_pCurrentSfx) {
m_spawnthing = &m_localemitter;
}
2023-07-23 13:46:32 +02:00
if (!m_spawnthing) return;
InitializeSpawnthing(m_spawnthing);
2023-04-30 20:20:58 +02:00
// Set the origin based on the entity's origin
m_spawnthing->cgd.origin = current_entity->origin;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
// Set the axis based on the entity's axis
AxisCopy(current_entity->axis, m_spawnthing->axis);
AxisCopy(current_entity->axis, m_spawnthing->tag_axis);
MatrixToEulerAngles(m_spawnthing->axis, m_spawnthing->cgd.angles);
}
2023-04-30 00:02:16 +02:00
//===============
// EndOriginSpawn
//===============
2023-04-30 20:20:58 +02:00
void ClientGameCommandManager::EndOriginSpawn(void)
{
if (m_spawnthing) {
SpawnEffect(m_spawnthing->count, 0);
}
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
2023-05-01 15:49:45 +02:00
void ClientGameCommandManager::TestEffectEndFunc()
{
2023-05-06 21:10:36 +02:00
if (!m_spawnthing) {
return;
}
SpawnEffect(m_spawnthing->count, 0);
2023-05-01 15:49:45 +02:00
}
2023-04-30 00:02:16 +02:00
//===============
2023-04-30 20:20:58 +02:00
// UpdateSpawnThing
2023-04-30 00:02:16 +02:00
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::UpdateSpawnThing(spawnthing_t *ep)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
int i;
2023-04-30 20:20:58 +02:00
orientation_t orientation;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
VectorCopy(current_entity->origin, ep->cgd.origin);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
for (i = 0; i < 3; i++) {
2023-07-05 21:24:23 +02:00
VectorMA(ep->cgd.origin, orientation.origin[i], current_entity->axis[i], ep->cgd.origin);
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
MatrixMultiply(orientation.axis, current_entity->axis, ep->axis);
}
2023-04-30 00:02:16 +02:00
//===============
2023-04-30 20:20:58 +02:00
// BeginTagEmitter
2023-04-30 00:02:16 +02:00
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::BeginTagEmitter(Event *ev)
2023-04-30 20:20:58 +02:00
{
str tagname;
int tagnum;
2023-04-30 00:02:16 +02:00
if (current_entity) {
m_spawnthing = NULL;
return;
}
2023-04-30 20:20:58 +02:00
// Get the tagname and orientation
tagname = ev->GetString(1);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (!tagname.length()) {
2023-07-05 21:24:23 +02:00
warning(
"CCM::BeginTagEmitter", "Tagname not specified for tagemitter in model: '%s'\n", cgi.TIKI_Name(current_tiki)
);
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
tagnum = cgi.Tag_NumForName(current_tiki, tagname.c_str());
if (tagnum == -1) {
throw ScriptException("Tagname '%s' does not exist", tagname.c_str());
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
// Setup ending function
endblockfcn = &ClientGameCommandManager::EndTagEmitter;
// Init the emitter
2023-07-05 21:24:23 +02:00
m_spawnthing = CreateNewEmitter();
m_spawnthing->tagnum = tagnum;
2023-04-30 20:20:58 +02:00
m_spawnthing->emittername = ev->GetString(2);
if (!m_spawnthing->emittername.length()) {
2023-07-05 21:24:23 +02:00
warning(
"CCM::BeginTagEmitter",
"Emittername not specified for tagemitter in model: '%s'\n",
cgi.TIKI_Name(current_tiki)
);
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.tiki = current_tiki;
}
2023-04-30 00:02:16 +02:00
//===============
// EndTagEmitter
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::EndTagEmitter(void)
{
endblockfcn = NULL;
}
2023-04-30 00:02:16 +02:00
//===============
2023-04-30 20:20:58 +02:00
// BeginTagBeamEmitter
2023-04-30 00:02:16 +02:00
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::BeginTagBeamEmitter(Event *ev)
2023-04-30 20:20:58 +02:00
{
if (current_entity) {
m_spawnthing = NULL;
return;
}
2023-04-30 20:20:58 +02:00
// Setup ending function
endblockfcn = &ClientGameCommandManager::EndTagBeamEmitter;
// Init the emitter
m_spawnthing = CreateNewEmitter();
m_spawnthing->cgd.flags |= T_BEAMTHING;
// Get the tagname and orientation
m_spawnthing->startTag = ev->GetString(1);
if (m_spawnthing->startTag == "USE_TAGLIST") {
if (ev->NumArgs() == 2) {
m_spawnthing->emittername = ev->GetString(2);
}
} else {
if (ev->NumArgs() == 3) {
2023-07-05 21:24:23 +02:00
m_spawnthing->endTag = ev->GetString(2);
2023-04-30 20:20:58 +02:00
m_spawnthing->emittername = ev->GetString(3);
} else if (ev->NumArgs() == 2) {
m_spawnthing->emittername = ev->GetString(2);
}
}
m_spawnthing->cgd.tiki = current_tiki;
}
2023-04-30 00:02:16 +02:00
//===============
// EndTagBeamEmitter
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::EndTagBeamEmitter(void)
{
endblockfcn = NULL;
}
2023-04-30 00:02:16 +02:00
//===============
2023-04-30 20:20:58 +02:00
// BeginOriginEmitter
2023-04-30 00:02:16 +02:00
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::BeginOriginEmitter(Event *ev)
2023-04-30 20:20:58 +02:00
{
if (current_entity) {
m_spawnthing = NULL;
return;
}
2023-04-30 20:20:58 +02:00
// Setup ending function
endblockfcn = &ClientGameCommandManager::EndOriginEmitter;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
// Init the emitter
m_spawnthing = CreateNewEmitter();
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
// Get the emitter's name
m_spawnthing->emittername = ev->GetString(1);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (!m_spawnthing->emittername.length()) {
2023-07-05 21:24:23 +02:00
warning(
"CCM::BeginOriginEmitter",
"Emittername not specified for originemitter in model: '%s'\n",
cgi.TIKI_Name(current_tiki)
);
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.tiki = current_tiki;
}
2023-04-30 00:02:16 +02:00
//===============
2023-04-30 20:20:58 +02:00
// EndOriginEmitter
2023-04-30 00:02:16 +02:00
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::EndOriginEmitter(void)
{
endblockfcn = NULL;
}
2023-04-30 00:02:16 +02:00
//===============
2023-04-30 20:20:58 +02:00
// BeginOriginBeamEmitter
2023-04-30 00:02:16 +02:00
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::BeginOriginBeamEmitter(Event *ev)
2023-04-30 20:20:58 +02:00
{
// Init the emitter
if (current_entity) {
m_spawnthing = NULL;
2023-04-30 20:20:58 +02:00
return;
}
2023-04-30 00:02:16 +02:00
// Setup ending function
endblockfcn = &ClientGameCommandManager::EndOriginBeamEmitter;
m_spawnthing = CreateNewEmitter();
2023-04-30 20:20:58 +02:00
// Get the emitter's name
m_spawnthing->emittername = ev->GetString(1);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (!m_spawnthing->emittername.length()) {
2023-07-05 21:24:23 +02:00
warning(
"CCM::BeginOriginEmitter",
"Emittername not specified for originemitter in model: '%s'\n",
cgi.TIKI_Name(current_tiki)
);
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.tiki = current_tiki;
m_spawnthing->cgd.flags |= T_BEAMTHING;
}
2023-04-30 00:02:16 +02:00
//===============
2023-04-30 20:20:58 +02:00
// EndOriginBeamEmitter
2023-04-30 00:02:16 +02:00
//===============
2023-04-30 20:20:58 +02:00
void ClientGameCommandManager::EndOriginBeamEmitter(void)
{
endblockfcn = NULL;
}
2023-04-30 00:02:16 +02:00
//===============
2023-04-30 20:20:58 +02:00
// GetOrientation - Calculates the orientation of a tag
2023-04-30 00:02:16 +02:00
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::GetOrientation(int tagnum, spawnthing_t *sp)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
int i;
2023-05-11 22:48:13 +02:00
orientation_t _or;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
assert(current_entity);
assert(current_tiki);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (!current_entity || !current_tiki) {
return;
}
2023-04-30 00:02:16 +02:00
2023-05-11 22:48:13 +02:00
_or = cgi.TIKI_Orientation(current_entity, tagnum);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
VectorCopy(current_entity->origin, sp->cgd.origin);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
for (i = 0; i < 3; i++) {
2023-07-05 21:24:23 +02:00
VectorMA(sp->cgd.origin, _or.origin[i], current_entity->axis[i], sp->cgd.origin);
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
2023-05-11 22:48:13 +02:00
MatrixMultiply(_or.axis, current_entity->axis, sp->axis);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
// If angles are not set, then use the angles from the tag
if (!(sp->cgd.flags & T_ANGLES)) {
vectoangles(sp->axis[0], sp->cgd.angles);
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
AxisCopy(sp->axis, sp->tag_axis);
}
2023-04-30 00:02:16 +02:00
//===============
// BeginTagSpawnLinked
//===============
void ClientGameCommandManager::BeginTagSpawnLinked(Event *ev) {
str tagname;
int tagnum;
int i;
orientation_t ori;
// Get the tagname and orientation
tagname = ev->GetString(1);
tagnum = cgi.Tag_NumForName(current_tiki, tagname.c_str());
if (tagnum == -1) {
throw ScriptException("Tagname '%s' does not exist", tagname.c_str());
}
// Setup ending function
endblockfcn = &ClientGameCommandManager::EndTagSpawn;
// Create a new emitter
m_spawnthing = CreateNewEmitter();
m_spawnthing->tagnum = tagnum;
m_spawnthing->entnum = current_entity->entityNumber;
m_spawnthing->cgd.tiki = current_tiki;
m_spawnthing->cgd.flags |= T_WAVE;
m_spawnthing->cgd.origin = Vector(0, 0, 0);
ori = cgi.TIKI_Orientation(current_entity, tagnum);
VectorCopy(current_entity->origin, m_spawnthing->linked_origin);
for (i = 0; i < 3; i++) {
VectorMA(m_spawnthing->linked_origin, ori.origin[i], current_entity->axis[i], m_spawnthing->linked_origin);
}
MatrixMultiply(ori.axis, current_entity->axis, m_spawnthing->linked_axis);
}
2023-05-05 23:43:27 +02:00
2023-04-30 00:02:16 +02:00
//===============
2023-04-30 20:20:58 +02:00
// BeginTagSpawn
2023-04-30 00:02:16 +02:00
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::BeginTagSpawn(Event *ev)
2023-04-30 20:20:58 +02:00
{
str tagname;
int tagnum;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
// Get the tagname and orientation
tagname = ev->GetString(1);
2023-07-05 21:24:23 +02:00
tagnum = cgi.Tag_NumForName(current_tiki, tagname.c_str());
2023-04-30 20:20:58 +02:00
if (tagnum == -1) {
throw ScriptException("Tagname '%s' does not exist", tagname.c_str());
}
// Setup ending function
endblockfcn = &ClientGameCommandManager::EndTagSpawn;
if (!m_pCurrentSfx) {
// Init the thing we are going to spawn
m_spawnthing = &m_localemitter;
}
InitializeSpawnthing(m_spawnthing);
2023-04-30 20:20:58 +02:00
GetOrientation(tagnum, m_spawnthing);
}
2023-04-30 00:02:16 +02:00
//===============
// EndTagSpawn
//===============
2023-04-30 20:20:58 +02:00
void ClientGameCommandManager::EndTagSpawn(void)
{
// Okay we should have a valid spawnthing, let's create a render entity
SpawnEffect(m_spawnthing->count, 0);
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
//===============
2023-04-30 20:20:58 +02:00
// BeginTagBeamShoot
2023-04-30 00:02:16 +02:00
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::BeginTagBeamSpawn(Event *ev)
2023-04-30 20:20:58 +02:00
{
str tagname;
int tagnum;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
// Get the tagname and orientation
tagname = ev->GetString(1);
2023-07-05 21:24:23 +02:00
tagnum = cgi.Tag_NumForName(current_tiki, tagname.c_str());
2023-04-30 20:20:58 +02:00
if (tagnum == -1) {
throw ScriptException("Tagname '%s' does not exist", tagname.c_str());
}
// Setup ending function
endblockfcn = &ClientGameCommandManager::EndTagBeamSpawn;
if (!m_pCurrentSfx) {
// Init the thing we are going to spawn
m_spawnthing = &m_localemitter;
}
InitializeSpawnthing(m_spawnthing);
2023-04-30 20:20:58 +02:00
GetOrientation(tagnum, m_spawnthing);
}
2023-04-30 00:02:16 +02:00
//===============
// EndTagSpawn
//===============
2023-04-30 20:20:58 +02:00
void ClientGameCommandManager::EndTagBeamSpawn(void)
{
// Okay we should have a valid spawnthing, let's create the beam now
2023-07-05 21:24:23 +02:00
int i;
int renderfx;
Vector end;
2023-04-30 20:20:58 +02:00
trace_t trace;
2023-07-05 21:24:23 +02:00
float scale = 1.0f;
2023-04-30 20:20:58 +02:00
if (current_entity) {
scale = current_entity->scale;
}
for (i = 0; i < 3; i++) {
2023-07-05 21:24:23 +02:00
m_spawnthing->cgd.origin +=
Vector(m_spawnthing->tag_axis[i])
* (m_spawnthing->axis_offset_base[i] + m_spawnthing->axis_offset_amplitude[i] * random());
2023-04-30 20:20:58 +02:00
}
if (m_spawnthing->use_last_trace_end) {
end = last_trace_end;
} else {
2023-07-05 21:24:23 +02:00
end = m_spawnthing->cgd.origin + Vector(m_spawnthing->axis[0]) * m_spawnthing->length
+ Vector(m_spawnthing->axis[1]) * crandom() * m_spawnthing->spreadx
+ Vector(m_spawnthing->axis[2]) * crandom() * m_spawnthing->spready;
2023-04-30 20:20:58 +02:00
last_trace_end = end;
}
2023-07-05 21:24:23 +02:00
CG_Trace(
&trace,
m_spawnthing->cgd.origin,
vec_zero,
vec_zero,
end,
ENTITYNUM_NONE,
MASK_SHOT,
qfalse,
qtrue,
"EndTagBeamSpawn"
);
2023-04-30 20:20:58 +02:00
if (current_entity) {
2023-07-05 21:24:23 +02:00
renderfx = (current_entity->renderfx & ~(RF_FLAGS_NOT_INHERITED | RF_LIGHTING_ORIGIN));
2023-04-30 20:20:58 +02:00
} else {
renderfx = 0;
}
2023-07-05 21:24:23 +02:00
CG_CreateBeam(
m_spawnthing->cgd.origin,
vec_zero,
current_entity_number,
1,
m_spawnthing->cgd.alpha,
m_spawnthing->cgd.scale * scale,
(m_spawnthing->beamflags | BEAM_LIGHTNING_EFFECT),
m_spawnthing->length,
m_spawnthing->cgd.life,
qfalse,
trace.endpos,
m_spawnthing->min_offset,
m_spawnthing->max_offset,
m_spawnthing->overlap,
m_spawnthing->numSubdivisions,
m_spawnthing->delay,
m_spawnthing->cgd.shadername,
m_spawnthing->cgd.color,
m_spawnthing->numspherebeams,
m_spawnthing->sphereRadius,
m_spawnthing->toggledelay,
m_spawnthing->endalpha,
renderfx,
m_spawnthing->emittername
);
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
//===============
// BeginOriginBeamSpawn
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::BeginOriginBeamSpawn(Event *ev)
2023-04-30 20:20:58 +02:00
{
if (!m_pCurrentSfx) {
m_spawnthing = &m_localemitter;
2023-04-30 20:20:58 +02:00
}
// Init the emitter
InitializeSpawnthing(m_spawnthing);
2023-04-30 20:20:58 +02:00
// Set the origin based on the entity's origin
m_spawnthing->cgd.origin = current_entity->origin;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
// Set the axis based on the entity's axis
AxisCopy(current_entity->axis, m_spawnthing->axis);
AxisCopy(current_entity->axis, m_spawnthing->tag_axis);
MatrixToEulerAngles(m_spawnthing->axis, m_spawnthing->cgd.angles);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
// Setup ending function
endblockfcn = &ClientGameCommandManager::EndOriginBeamSpawn;
}
2023-04-30 00:02:16 +02:00
//===============
// EndOriginBeamSpawn
//===============
2023-04-30 20:20:58 +02:00
void ClientGameCommandManager::EndOriginBeamSpawn(void)
{
// Okay we should have a valid spawnthing, let's create the beam now
2023-07-05 21:24:23 +02:00
int i, renderfx, c, count;
Vector end;
2023-04-30 20:20:58 +02:00
trace_t trace;
2023-07-05 21:24:23 +02:00
float scale = 1.0f;
2023-04-30 20:20:58 +02:00
if (current_entity) {
scale = current_entity->scale;
}
count = m_spawnthing->count * cg_effectdetail->value;
for (c = 0; c <= count; c++) {
Vector angles;
for (i = 0; i < 3; i++) {
// Randomize angles or set absolute
2023-07-05 21:24:23 +02:00
angles[i] = m_spawnthing->cgd.angles[i] + random() * m_spawnthing->angles_amplitude[i];
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.origin +=
2023-07-05 21:24:23 +02:00
Vector(m_spawnthing->tag_axis[i])
* (m_spawnthing->axis_offset_base[i] + m_spawnthing->axis_offset_amplitude[i] * random());
2023-04-30 20:20:58 +02:00
}
AnglesToAxis(angles, m_spawnthing->axis);
2023-07-05 21:24:23 +02:00
end = m_spawnthing->cgd.origin + Vector(m_spawnthing->axis[0]) * m_spawnthing->length
+ Vector(m_spawnthing->axis[1]) * crandom() * m_spawnthing->spreadx
+ Vector(m_spawnthing->axis[2]) * crandom() * m_spawnthing->spready;
CG_Trace(
&trace,
m_spawnthing->cgd.origin,
vec_zero,
vec_zero,
end,
ENTITYNUM_NONE,
MASK_SHOT,
qfalse,
qtrue,
"EndOriginBeamSpawn"
);
2023-04-30 20:20:58 +02:00
if (current_entity) {
2023-07-05 21:24:23 +02:00
renderfx = (current_entity->renderfx & ~(RF_FLAGS_NOT_INHERITED | RF_LIGHTING_ORIGIN));
2023-04-30 20:20:58 +02:00
} else {
renderfx = 0;
}
CG_CreateBeam(
2023-07-05 21:24:23 +02:00
m_spawnthing->cgd.origin,
vec_zero,
current_entity_number,
1,
m_spawnthing->cgd.alpha,
m_spawnthing->cgd.scale * scale,
2023-04-30 20:20:58 +02:00
(m_spawnthing->beamflags | BEAM_LIGHTNING_EFFECT),
2023-07-05 21:24:23 +02:00
m_spawnthing->length,
m_spawnthing->cgd.life,
qtrue,
trace.endpos,
m_spawnthing->min_offset,
m_spawnthing->max_offset,
m_spawnthing->overlap,
m_spawnthing->numSubdivisions,
m_spawnthing->delay,
m_spawnthing->cgd.shadername,
m_spawnthing->cgd.color,
m_spawnthing->numspherebeams,
m_spawnthing->sphereRadius,
m_spawnthing->toggledelay,
m_spawnthing->endalpha,
renderfx,
m_spawnthing->emittername
);
2023-04-30 20:20:58 +02:00
}
}
2023-04-30 00:02:16 +02:00
//=============
// InitializeEmitters
//=============
void ClientGameCommandManager::InitializeEmitters(void) {}
2023-04-30 00:02:16 +02:00
//===============
2023-04-30 20:20:58 +02:00
// EmitterOn
2023-04-30 00:02:16 +02:00
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::EmitterOn(Event *ev)
2023-04-30 20:20:58 +02:00
{
int i;
str name;
name = ev->GetString(1);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
for (i = 1; i <= m_emitters.NumObjects(); i++) {
2023-07-05 21:24:23 +02:00
spawnthing_t *st = m_emitters.ObjectAt(i);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (st->emittername == name) {
2023-07-05 21:24:23 +02:00
emittertime_t *et;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
et = st->GetEmitTime(current_entity_number);
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
et->active = qtrue;
2023-04-30 20:20:58 +02:00
et->last_emit_time = cg.time;
2023-07-05 21:24:23 +02:00
et->lerp_emitter = qfalse;
2023-04-30 20:20:58 +02:00
}
}
}
2023-04-30 00:02:16 +02:00
//===============
2023-04-30 20:20:58 +02:00
// EmitterOff
2023-04-30 00:02:16 +02:00
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::EmitterOff(Event *ev)
2023-04-30 20:20:58 +02:00
{
int i;
str name;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
name = ev->GetString(1);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
for (i = 1; i <= m_emitters.NumObjects(); i++) {
2023-07-05 21:24:23 +02:00
spawnthing_t *st = m_emitters.ObjectAt(i);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (st->emittername == name) {
2023-07-05 21:24:23 +02:00
emittertime_t *et;
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
et = st->GetEmitTime(current_entity_number);
2023-04-30 20:20:58 +02:00
et->active = qfalse;
if (st->cgd.flags & T_BEAMTHING) {
// Kill any active beams emitted from this thing
CG_KillBeams(current_entity_number);
2023-04-30 00:02:16 +02:00
}
2023-04-30 20:20:58 +02:00
}
}
}
2023-04-30 00:02:16 +02:00
//===============
// Sound
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::PlaySound(
2023-07-10 21:09:56 +02:00
str sound_name, const vec3_t origin, int channel, float volume, float min_distance, float pitch, int argstype
2023-07-05 21:24:23 +02:00
)
{
int aliaschannel;
float aliasvolume;
float aliasmin_distance;
float aliaspitch;
const char *name = NULL;
static cvar_t *g_subtitle = cgi.Cvar_Get("g_subtitle", "0", CVAR_ARCHIVE);
static cvar_t *debugSound = cgi.Cvar_Get("debugSound", "0", 0);
float maxDist;
AliasListNode_t *soundAlias = NULL;
2023-04-30 20:20:58 +02:00
// FIXME
// TODO: Pitch modulation
// TODO: Alias enhancement
// Get the real sound to play
if (current_tiki && current_tiki->a->alias_list) {
2023-07-05 21:24:23 +02:00
name = cgi.Alias_ListFindRandom((AliasList_t *)current_tiki->a->alias_list, sound_name.c_str(), &soundAlias);
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (!name) {
name = cgi.Alias_FindRandom(sound_name.c_str(), &soundAlias);
}
2023-04-30 00:02:16 +02:00
if (!name || !soundAlias) {
2023-07-05 21:24:23 +02:00
Com_Printf(
"\nERROR PlaySound: %s needs an alias in ubersound.scr or uberdialog.scr - Please fix.\n",
sound_name.c_str()
);
return;
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
aliasvolume = soundAlias->volumeMod * random() + soundAlias->volume;
aliaspitch = soundAlias->pitchMod * random() + soundAlias->pitch;
aliasmin_distance = soundAlias->dist;
2023-07-05 21:24:23 +02:00
aliaschannel = soundAlias->channel;
maxDist = soundAlias->maxDist;
if (soundAlias->subtitle) {
if (g_subtitle->integer || !sound_name.icmpn("den", 3) || !sound_name.icmpn("snd_den", 6)) {
// show subtitles if near the sound
if (origin
2023-07-05 21:24:23 +02:00
&& (g_subtitle->integer == 2 || DistanceSquared(origin, cg.refdef.vieworg) < (maxDist * maxDist))) {
int curSub;
// also put subtitles if it's from a german dialogue
curSub = cgi.Cvar_Get("curSubtitle", "0", 0)->integer;
cgi.Cvar_Set(va("subtitle%d", curSub), va("%s", soundAlias->subtitle));
// increment the subtitle
cgi.Cvar_Set("curSubtitle", va("%d", (curSub + 1) % 4));
}
}
}
2023-07-05 21:24:23 +02:00
if (argstype) {
if (argstype == 1) {
if (debugSound->integer) {
Com_Printf("WARNING: Sound %s had its parm modified by code.\n", sound_name.c_str());
}
if (volume >= 0.0) {
volume = volume * aliasvolume;
2023-07-05 21:24:23 +02:00
} else {
volume = aliasvolume;
}
if (pitch >= 0.0) {
pitch = pitch * aliaspitch;
2023-07-05 21:24:23 +02:00
} else {
pitch = aliaspitch;
}
if (min_distance < 0.0) {
min_distance = aliasmin_distance;
}
if (channel < 0) {
channel = aliaschannel;
}
2023-07-05 21:24:23 +02:00
} else {
if (debugSound->integer) {
2023-07-05 21:24:23 +02:00
Com_Printf(
"\nWARNING: OVERRIDE OVERRIDE OVERRIDESound %s had all its parm overriden by code.\n\n",
sound_name.c_str()
);
}
if (volume < 0.0) {
volume = aliasvolume;
}
if (pitch < 0.0) {
pitch = aliaspitch;
}
if (min_distance < 0.0) {
min_distance = aliasmin_distance;
}
if (channel < 0) {
channel = aliaschannel;
}
}
2023-07-05 21:24:23 +02:00
} else {
volume = aliasvolume;
pitch = aliaspitch;
min_distance = aliasmin_distance;
2023-07-05 21:24:23 +02:00
channel = aliaschannel;
}
if (current_entity_number == -1) {
2023-07-05 21:24:23 +02:00
cgi.S_StartSound(
origin,
ENTITYNUM_NONE,
channel,
cgi.S_RegisterSound(name, soundAlias->streamed),
2023-07-05 21:24:23 +02:00
volume,
min_distance,
pitch,
soundAlias->maxDist,
soundAlias->streamed
);
} else {
cgi.S_StartSound(
origin,
current_entity_number,
channel,
cgi.S_RegisterSound(name, soundAlias->streamed),
volume,
min_distance,
pitch,
soundAlias->maxDist,
soundAlias->streamed
);
2023-04-30 20:20:58 +02:00
}
}
2023-04-30 00:02:16 +02:00
//===============
// Sound
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::Sound(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
int channel = CHAN_AUTO;
str sound_name;
float volume = -1.0;
2023-04-30 20:20:58 +02:00
float min_distance = -1.0;
2023-04-30 00:02:16 +02:00
if (!current_entity) {
// don't play sound for nonexistent entities
return;
}
2023-04-30 20:20:58 +02:00
if (ev->NumArgs() < 1) {
return;
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
// Get all of the parameters
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
sound_name = ev->GetString(1);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (ev->NumArgs() > 1) {
channel = ev->GetInteger(2);
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (ev->NumArgs() > 2) {
volume = ev->GetFloat(3);
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (ev->NumArgs() > 3) {
min_distance = ev->GetFloat(4);
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
// play the sound
if (current_entity) {
2023-07-05 21:24:23 +02:00
PlaySound(sound_name, current_entity->origin, channel, volume, min_distance);
2023-04-30 20:20:58 +02:00
} else {
PlaySound(sound_name, NULL, channel, volume, min_distance);
}
}
2023-04-30 00:02:16 +02:00
//===============
// StopSound
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::StopSound(Event *ev)
2023-04-30 20:20:58 +02:00
{
int channel;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (ev->NumArgs() > 0) {
channel = ev->GetInteger(1);
} else {
return;
}
cgi.S_StopSound(current_entity_number, channel);
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::StopAliasChannel(Event *ev)
{
2023-07-05 21:24:23 +02:00
str sound_name;
const char *name;
AliasListNode_t *soundAlias;
2023-05-06 23:37:05 +02:00
2023-07-05 21:24:23 +02:00
name = NULL;
2023-05-07 14:45:23 +02:00
soundAlias = NULL;
2023-05-06 23:37:05 +02:00
if (ev->NumArgs() < 1) {
return;
}
sound_name = ev->GetString(1);
2023-07-05 21:24:23 +02:00
if (current_tiki) {
2023-05-06 23:37:05 +02:00
if (current_tiki->a->alias_list) {
2023-07-05 21:24:23 +02:00
name =
cgi.Alias_ListFindRandom((AliasList_t *)current_tiki->a->alias_list, sound_name.c_str(), &soundAlias);
2023-05-06 23:37:05 +02:00
}
}
if (!name) {
name = cgi.Alias_FindRandom(sound_name.c_str(), &soundAlias);
}
2023-07-05 21:24:23 +02:00
if (!name || !soundAlias) {
2023-05-06 23:37:05 +02:00
Com_Printf("\nERROR stopaliaschannel: couldn't find alias %s\n", sound_name.c_str());
return;
}
cgi.S_StopSound(current_entity_number, soundAlias->channel);
}
2023-04-30 00:02:16 +02:00
//===============
// LoopSound
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::LoopSound(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
str sound_name;
float volume = -1.0;
float min_dist = -1.0;
float max_dist = -1.0;
float pitch = 1.0;
const char *name = NULL;
AliasListNode_t *soundAlias = NULL;
2023-04-30 20:20:58 +02:00
if (!current_centity) {
2023-07-05 21:24:23 +02:00
cgi.DPrintf("CCM::LoopSound : LoopSound in %s without current_centity\n", cgi.TIKI_Name(current_tiki));
2023-04-30 20:20:58 +02:00
return;
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (ev->NumArgs() < 1) {
return;
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
sound_name = ev->GetString(1);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (ev->NumArgs() > 1) {
volume = ev->GetFloat(2);
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (ev->NumArgs() > 2) {
min_dist = ev->GetFloat(3);
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (ev->NumArgs() > 3) {
max_dist = ev->GetFloat(4);
}
if (ev->NumArgs() > 4) {
pitch = ev->GetFloat(5);
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
// Get the real sound to play
2023-04-30 00:02:16 +02:00
if (current_tiki && current_tiki->a->alias_list) {
2023-07-05 21:24:23 +02:00
name = cgi.Alias_ListFindRandom((AliasList_t *)current_tiki->a->alias_list, sound_name.c_str(), &soundAlias);
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (!name) {
name = cgi.Alias_FindRandom(sound_name.c_str(), &soundAlias);
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (!name) {
name = sound_name.c_str();
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
current_centity->tikiLoopSound = cgi.S_RegisterSound(name, qfalse);
current_centity->tikiLoopSoundVolume = volume;
2023-04-30 20:20:58 +02:00
current_centity->tikiLoopSoundMinDist = min_dist;
current_centity->tikiLoopSoundMaxDist = max_dist;
2023-07-05 21:24:23 +02:00
current_centity->tikiLoopSoundPitch = pitch;
current_centity->tikiLoopSoundFlags = 0;
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
//===============
// CacheResource
//===============
2023-07-05 21:24:23 +02:00
void CacheResource(const char *stuff)
2023-04-30 20:20:58 +02:00
{
str real_stuff;
2023-04-30 00:02:16 +02:00
if (!stuff || !stuff[0]) {
2023-04-30 20:20:58 +02:00
return;
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
real_stuff = stuff;
real_stuff.tolower();
if (strstr(real_stuff.c_str(), ".wav")) {
cgi.S_RegisterSound(real_stuff.c_str(), qfalse);
} else if (strstr(real_stuff.c_str(), ".mp3")) {
cgi.S_RegisterSound(real_stuff.c_str(), qfalse);
} else if (strstr(real_stuff.c_str(), ".tik")) {
cgi.R_RegisterServerModel(real_stuff.c_str());
} else if (strstr(real_stuff.c_str(), ".spr")) {
cgi.R_RegisterShader(real_stuff.c_str());
}
}
//===============
// Cache
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::Cache(Event *ev)
2023-04-30 20:20:58 +02:00
{
if (ev->NumArgs() < 1) {
return;
}
CacheResource(ev->GetString(1));
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::CacheImage(Event *ev)
{
// FIXME: stub
}
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::CacheFont(Event *ev)
{
// FIXME: stub
}
2023-04-30 00:02:16 +02:00
//===============
// AliasResource
//===============
2023-07-05 21:24:23 +02:00
void AliasResource(dtiki_t *pmdl, const char *alias, const char *realname, const char *parameters)
2023-04-30 20:20:58 +02:00
{
if (pmdl) {
if (!pmdl->a->alias_list) {
pmdl->a->alias_list = cgi.AliasList_New(pmdl->a->name);
}
2023-07-05 21:24:23 +02:00
cgi.Alias_ListAdd((AliasList_t *)pmdl->a->alias_list, alias, realname, parameters);
2023-04-30 20:20:58 +02:00
} else {
cgi.Alias_Add(alias, realname, parameters);
}
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
qboolean bLoadForMap(const char *psMapsBuffer, const char *name)
{
2023-07-05 21:24:23 +02:00
const char *token;
const char *mapname;
const char *override;
// ignore the "maps/"
mapname = cgs.mapname + strlen("maps/");
if (!strncmp("test", mapname, strlen("test"))) {
return true;
}
2023-07-05 21:24:23 +02:00
token = COM_GetToken((char **)&psMapsBuffer, qtrue);
if (!psMapsBuffer) {
return false;
}
if (!token || !token[0]) {
Com_Printf("ERROR bLoadForMap: %s alias with empty maps specification.\n", name);
return false;
}
override = token;
2023-07-05 21:24:23 +02:00
while (token && token[0]) {
if (!Q_stricmpn(token, mapname, strlen(token))) {
// found the map
return true;
}
2023-07-05 21:24:23 +02:00
token = COM_GetToken((char **)&psMapsBuffer, qtrue);
}
return false;
}
2023-04-30 00:02:16 +02:00
//===============
2023-04-30 20:20:58 +02:00
// AliasCache
2023-04-30 00:02:16 +02:00
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::AliasCache(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
int i;
char parmbuffer[2048]; // this holds the parameters to be passed into the
2023-07-05 21:24:23 +02:00
// alias command
const char *psMapsBuffer;
bool bAlwaysLoaded = false;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (ev->NumArgs() < 2) {
return;
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
// alias is in argument 1
// real path is argument 2
// any additional parameters are in arguments 3-n
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
parmbuffer[0] = 0;
2023-07-05 21:24:23 +02:00
psMapsBuffer = NULL;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
for (i = 3; i <= ev->NumArgs(); i++) {
2023-05-28 20:59:42 +02:00
if (!strcmp(ev->GetToken(i).c_str(), "maps")) {
i++;
psMapsBuffer = ev->GetToken(i);
2023-07-05 21:24:23 +02:00
} else if (!strcmp(ev->GetToken(i).c_str(), "always")) {
2023-05-28 20:59:42 +02:00
bAlwaysLoaded = true;
2023-07-05 21:24:23 +02:00
} else {
2023-05-28 20:59:42 +02:00
strcat(parmbuffer, ev->GetToken(i));
strcat(parmbuffer, " ");
}
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
if (bAlwaysLoaded || bLoadForMap(psMapsBuffer, ev->GetString(1))) {
AliasResource(current_tiki, ev->GetString(1), ev->GetString(2), parmbuffer);
CacheResource(ev->GetString(2));
}
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
//===============
2023-04-30 20:20:58 +02:00
// Alias
2023-04-30 00:02:16 +02:00
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::Alias(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
int i;
char parmbuffer[2048]; // this holds the parameters to be passed into the
2023-07-05 21:24:23 +02:00
// alias command
qboolean subtitle;
const char *psMapsBuffer;
bool bAlwaysLoaded = false;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (ev->NumArgs() < 2) {
return;
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
// alias is in argument 1
// real path is argument 2
// any additional parameters are in arguments 3-n
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
parmbuffer[0] = 0;
subtitle = qfalse;
psMapsBuffer = NULL;
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
for (i = 3; i <= ev->NumArgs(); i++) {
if (!strcmp(ev->GetToken(i).c_str(), "maps")) {
i++;
psMapsBuffer = ev->GetToken(i);
2023-07-05 21:24:23 +02:00
} else if (!strcmp(ev->GetToken(i).c_str(), "always")) {
2023-05-28 20:59:42 +02:00
bAlwaysLoaded = true;
2023-07-05 21:24:23 +02:00
} else {
if (!subtitle) {
2023-05-28 20:59:42 +02:00
if (!Q_stricmp(ev->GetToken(i), "subtitle") || !Q_stricmp(ev->GetToken(i), "forcesubtitle")) {
2023-07-05 21:24:23 +02:00
subtitle = qtrue;
strcat(parmbuffer, ev->GetToken(i));
} else {
strcat(parmbuffer, ev->GetToken(i));
}
2023-07-05 21:24:23 +02:00
} else {
strcat(parmbuffer, "\"");
strcat(parmbuffer, ev->GetToken(i));
strcat(parmbuffer, "\"");
subtitle = qfalse;
2023-07-05 21:24:23 +02:00
}
2023-07-05 21:24:23 +02:00
strcat(parmbuffer, " ");
}
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
if (bAlwaysLoaded || bLoadForMap(psMapsBuffer, ev->GetString(1))) {
AliasResource(current_tiki, ev->GetString(1), ev->GetString(2), parmbuffer);
}
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
void CacheAliasList(AliasList_t *alias_list, str& name)
{
2023-05-06 23:37:05 +02:00
if (!alias_list) {
return;
}
2023-07-05 21:24:23 +02:00
int i;
int iFirst, iLast;
2023-05-06 23:37:05 +02:00
float fTotalWeight;
2023-07-05 21:24:23 +02:00
cgi.Alias_ListFindRandomRange((AliasList_t *)alias_list, name.c_str(), &iFirst, &iLast, &fTotalWeight);
if (iFirst >= 0 && iLast >= iFirst) {
2023-05-06 23:37:05 +02:00
for (i = iFirst; i <= iLast; ++i) {
CacheResource(alias_list->sorted_list[i]->real_name);
}
}
}
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::CacheAlias(Event *ev)
{
2023-05-06 23:37:05 +02:00
if (ev->NumArgs() < 1) {
return;
}
str name = ev->GetString(1);
if (current_tiki) {
2023-07-05 21:24:23 +02:00
CacheAliasList((AliasList_t *)current_tiki->a->alias_list, name);
2023-05-06 23:37:05 +02:00
}
CacheAliasList(cgi.Alias_GetGlobalList(), name);
}
2023-04-30 00:02:16 +02:00
//===============
2023-04-30 20:20:58 +02:00
// Footstep
2023-04-30 00:02:16 +02:00
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::Footstep(Event *ev)
2023-04-30 20:20:58 +02:00
{
int iRunning, iEquipment;
str sTagName;
2023-04-30 00:02:16 +02:00
sTagName = ev->GetString(1);
iRunning = 1;
2023-07-05 21:24:23 +02:00
if (ev->NumArgs() > 1) {
str sType = ev->GetString(2);
2023-07-05 21:24:23 +02:00
if (!str::icmp(sType, "walk")) {
// walking
iRunning = 0;
2023-07-05 21:24:23 +02:00
} else if (!str::icmp(sType, "ladder")) {
// on ladder
iRunning = -1;
2023-07-05 21:24:23 +02:00
} else {
// running
iRunning = 1;
}
}
if (ev->NumArgs() > 2) {
iEquipment = ev->GetInteger(3);
2023-07-05 21:24:23 +02:00
} else {
iEquipment = 1;
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
2023-05-01 19:22:05 +02:00
if (current_centity && current_entity) {
2023-07-05 21:24:23 +02:00
CG_Footstep(sTagName.c_str(), current_centity, current_entity, iRunning, iEquipment);
2023-04-30 20:20:58 +02:00
}
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::LandingSound(Event *ev)
{
2023-07-05 21:24:23 +02:00
int iEquipment;
float fVolume;
if (ev->NumArgs() <= 0) {
fVolume = 1.0;
2023-07-05 21:24:23 +02:00
} else {
fVolume = ev->GetFloat(1);
}
if (ev->NumArgs() <= 1) {
iEquipment = 1;
2023-07-05 21:24:23 +02:00
} else {
iEquipment = ev->GetInteger(2);
}
if (current_centity && current_entity) {
CG_LandingSound(current_centity, current_entity, fVolume, iEquipment);
}
}
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::BodyFallSound(Event *ev)
{
float fVolume;
if (ev->NumArgs() <= 0) {
fVolume = 1.0;
2023-07-05 21:24:23 +02:00
} else {
fVolume = ev->GetFloat(1);
}
if (current_centity && current_entity) {
CG_BodyFallSound(current_centity, current_entity, fVolume);
}
}
2023-04-30 20:20:58 +02:00
//===============
// Client
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::Client(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
Event *event;
const char *eventname;
int i;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
// see if it was a dummy command
if (ev->NumArgs() < 1) {
return;
}
eventname = ev->GetString(1);
2023-07-05 21:24:23 +02:00
event = new Event(eventname);
2023-04-30 20:20:58 +02:00
for (i = 2; i <= ev->NumArgs(); i++) {
event->AddToken(ev->GetToken(i));
}
ProcessEvent(event);
}
2023-04-30 00:02:16 +02:00
//===============
2023-04-30 20:20:58 +02:00
// TagDynamicLight
2023-04-30 00:02:16 +02:00
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::TagDynamicLight(Event *ev)
2023-04-30 20:20:58 +02:00
{
str tagname;
int tagnum;
2023-04-30 00:02:16 +02:00
if (!m_pCurrentSfx) {
// Spawn a single tempmodel that is a dynamic light
m_spawnthing = &m_localemitter;
}
InitializeSpawnthing(m_spawnthing);
2023-04-30 20:20:58 +02:00
tagname = ev->GetString(1);
2023-07-05 21:24:23 +02:00
tagnum = cgi.Tag_NumForName(current_tiki, tagname.c_str());
2023-04-30 20:20:58 +02:00
if (tagnum == -1) {
throw ScriptException("Tagname '%s' does not exist", tagname.c_str());
}
GetOrientation(tagnum, m_spawnthing);
m_spawnthing->cgd.flags |= T_DLIGHT;
2023-07-05 21:24:23 +02:00
m_spawnthing->cgd.color[0] = ev->GetFloat(2);
m_spawnthing->cgd.color[1] = ev->GetFloat(3);
m_spawnthing->cgd.color[2] = ev->GetFloat(4);
m_spawnthing->cgd.color[3] = 1.0;
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.lightIntensity = ev->GetFloat(5);
2023-07-05 21:24:23 +02:00
m_spawnthing->cgd.life = ev->GetFloat(6) * 1000;
2023-04-30 20:20:58 +02:00
if (ev->NumArgs() > 6) {
m_spawnthing->cgd.lightType |= DLightNameToNum(ev->GetString(7));
if (ev->NumArgs() > 7) {
m_spawnthing->cgd.lightType |= DLightNameToNum(ev->GetString(8));
}
} else {
m_spawnthing->cgd.lightType = 0;
}
SpawnEffect(1, m_spawnthing);
2023-04-30 20:20:58 +02:00
}
//===============
// OriginDynamicLight
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::OriginDynamicLight(Event *ev)
2023-04-30 20:20:58 +02:00
{
str tagname;
if (!current_entity) {
m_spawnthing = NULL;
2023-04-30 20:20:58 +02:00
return;
}
2023-04-30 00:02:16 +02:00
if (!m_pCurrentSfx) {
// Spawn a single tempmodel that is a dynamic light
m_spawnthing = &m_localemitter;
}
InitializeSpawnthing(m_spawnthing);
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.origin = current_entity->origin;
m_spawnthing->cgd.flags |= T_DLIGHT;
2023-07-05 21:24:23 +02:00
m_spawnthing->cgd.color[0] = ev->GetFloat(1);
m_spawnthing->cgd.color[1] = ev->GetFloat(2);
m_spawnthing->cgd.color[2] = ev->GetFloat(3);
m_spawnthing->cgd.color[3] = 1.0;
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.lightIntensity = ev->GetFloat(4);
2023-07-05 21:24:23 +02:00
m_spawnthing->cgd.life = ev->GetFloat(5) * 1000;
2023-04-30 20:20:58 +02:00
if (ev->NumArgs() > 5) {
m_spawnthing->cgd.lightType |= DLightNameToNum(ev->GetString(6));
if (ev->NumArgs() > 6) {
m_spawnthing->cgd.lightType |= DLightNameToNum(ev->GetString(7));
}
} else {
m_spawnthing->cgd.lightType = 0;
}
SpawnEffect(1, m_spawnthing);
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
//===============
// DynamicLight
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::DynamicLight(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-06-11 12:41:34 +02:00
if (!m_spawnthing) {
return;
}
2023-04-30 20:20:58 +02:00
// The emitter itself has a dynamic light
m_spawnthing->cgd.flags |= T_DLIGHT;
2023-07-05 21:24:23 +02:00
m_spawnthing->dcolor[0] = ev->GetFloat(1);
m_spawnthing->dcolor[1] = ev->GetFloat(2);
m_spawnthing->dcolor[2] = ev->GetFloat(3);
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.lightIntensity = ev->GetFloat(4);
if (ev->NumArgs() > 4) {
m_spawnthing->cgd.lightType |= (dlighttype_t)ev->GetInteger(5);
if (ev->NumArgs() > 5) {
m_spawnthing->cgd.lightType |= DLightNameToNum(ev->GetString(6));
}
} else {
m_spawnthing->cgd.lightType = 0;
}
}
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::BlockDynamicLight(Event *ev)
{
2023-07-05 21:24:23 +02:00
if (!current_entity) {
2023-05-06 23:37:05 +02:00
m_spawnthing = NULL;
return;
}
endblockfcn = &ClientGameCommandManager::EndBlockDynamicLight;
if (!m_pCurrentSfx) {
m_spawnthing = &m_localemitter;
}
InitializeSpawnthing(m_spawnthing);
m_spawnthing->cgd.origin = current_entity->origin;
m_spawnthing->cgd.flags |= T_DLIGHT;
m_spawnthing->cgd.lightIntensity = ev->GetFloat(1);
2023-07-05 21:24:23 +02:00
m_spawnthing->cgd.life = ev->GetFloat(2);
2023-05-06 23:37:05 +02:00
if (ev->NumArgs() > 2) {
m_spawnthing->cgd.lightType |= DLightNameToNum(ev->GetString(3));
if (ev->NumArgs() > 3) {
m_spawnthing->cgd.lightType |= DLightNameToNum(ev->GetString(4));
}
2023-07-05 21:24:23 +02:00
} else {
2023-05-06 23:37:05 +02:00
m_spawnthing->cgd.lightType = 0;
}
AxisCopy(current_entity->axis, m_spawnthing->axis);
AxisCopy(current_entity->axis, m_spawnthing->tag_axis);
}
2023-05-06 23:37:05 +02:00
void ClientGameCommandManager::EndBlockDynamicLight()
{
2023-05-06 23:37:05 +02:00
if (!m_spawnthing) {
return;
}
SpawnEffect(m_spawnthing->count, 0);
}
2023-04-30 20:20:58 +02:00
static int emittercount = 0;
2023-04-30 00:02:16 +02:00
//===============
2023-04-30 20:20:58 +02:00
// UpdateBeam
2023-04-30 00:02:16 +02:00
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::UpdateBeam(dtiki_t *tiki, int entity_number, spawnthing_t *beamthing)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
Vector start, end;
int renderfx;
int iLife;
qboolean addstartpoint;
float scale, alpha;
emittertime_t *et;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
et = beamthing->GetEmitTime(entity_number);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (!et->active) {
return;
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (current_entity) {
2023-07-05 21:24:23 +02:00
renderfx = (current_entity->renderfx & ~(RF_FLAGS_NOT_INHERITED | RF_LIGHTING_ORIGIN));
scale = current_entity->scale;
alpha = (float)current_entity->shaderRGBA[3] / 255.0f;
2023-04-30 20:20:58 +02:00
} else {
renderfx = 0;
2023-07-05 21:24:23 +02:00
scale = 1.0f;
alpha = 1.0f;
2023-04-30 20:20:58 +02:00
}
2023-05-07 17:45:07 +02:00
iLife = m_spawnthing->cgd.life;
if (m_spawnthing->life_random != 0.0) {
iLife = (int)(random() * m_spawnthing->life_random + (float)iLife);
}
2023-04-30 20:20:58 +02:00
if (beamthing->startTag == "USE_TAGLIST") {
2023-07-05 21:24:23 +02:00
int i, count;
str startTag, endTag;
int tagnum;
2023-04-30 20:20:58 +02:00
Vector dir;
count = beamthing->m_taglist.NumObjects();
if (!count) {
return;
}
startTag = beamthing->m_taglist.ObjectAt(1);
2023-07-05 21:24:23 +02:00
tagnum = cgi.Tag_NumForName(current_tiki, startTag.c_str());
2023-04-30 20:20:58 +02:00
if (tagnum == -1) {
2023-07-05 21:24:23 +02:00
throw ScriptException("Tagname '%s' does not exist", startTag.c_str());
2023-04-30 20:20:58 +02:00
}
GetOrientation(tagnum, beamthing);
start = beamthing->cgd.origin;
if (beamthing->beamflags & BEAM_OFFSET_ENDPOINTS) {
dir = Vector(crandom(), crandom(), crandom());
2023-07-05 21:24:23 +02:00
start += (crandom() * beamthing->min_offset * dir) + (crandom() * beamthing->max_offset * dir);
2023-04-30 20:20:58 +02:00
}
CG_MultiBeamBegin();
addstartpoint = qtrue;
for (i = 2; i <= count; i++) {
str s;
s = va("%d", i);
endTag = beamthing->m_taglist.ObjectAt(i);
tagnum = cgi.Tag_NumForName(current_tiki, endTag.c_str());
if (tagnum == -1) {
2023-07-05 21:24:23 +02:00
throw ScriptException("Tagname '%s' does not exist", endTag.c_str());
2023-04-30 00:02:16 +02:00
}
2023-04-30 20:20:58 +02:00
GetOrientation(tagnum, beamthing);
end = beamthing->cgd.origin;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (beamthing->beamflags & BEAM_OFFSET_ENDPOINTS) {
dir = Vector(crandom(), crandom(), crandom());
2023-07-05 21:24:23 +02:00
end += (crandom() * beamthing->min_offset * dir) + (crandom() * beamthing->max_offset * dir);
2023-04-30 20:20:58 +02:00
}
2023-07-05 21:24:23 +02:00
CG_MultiBeamAddPoints(
start,
end,
beamthing->numSubdivisions,
beamthing->beamflags,
beamthing->min_offset,
beamthing->max_offset,
addstartpoint
);
2023-04-30 20:20:58 +02:00
addstartpoint = qfalse;
2023-07-05 21:24:23 +02:00
startTag = endTag;
start = end;
2023-04-30 20:20:58 +02:00
}
byte newcolor[4];
newcolor[0] = (byte)(beamthing->cgd.color[0] * alpha * 255.0);
newcolor[1] = (byte)(beamthing->cgd.color[1] * alpha * 255.0);
newcolor[2] = (byte)(beamthing->cgd.color[2] * alpha * 255.0);
newcolor[3] = (byte)(beamthing->cgd.color[3] * alpha * 255.0);
2023-04-30 20:20:58 +02:00
CG_MultiBeamEnd(
2023-07-05 21:24:23 +02:00
beamthing->cgd.scale * scale,
renderfx,
beamthing->cgd.shadername,
newcolor,
beamthing->beamflags,
entity_number,
beamthing->cgd.life
);
2023-04-30 20:20:58 +02:00
} else {
if (beamthing->startTag.length()) {
int tagnum = cgi.Tag_NumForName(current_tiki, beamthing->startTag.c_str());
if (tagnum == -1) {
2023-07-05 21:24:23 +02:00
throw ScriptException("Tagname '%s' does not exist", beamthing->startTag.c_str());
2023-04-30 20:20:58 +02:00
}
// Use a dummy sp to get the orientation
GetOrientation(tagnum, beamthing);
start = beamthing->cgd.origin;
} else {
start = beamthing->cgd.origin;
}
if (beamthing->endTag.length()) {
int tagnum = cgi.Tag_NumForName(current_tiki, beamthing->endTag.c_str());
if (tagnum == -1) {
2023-07-05 21:24:23 +02:00
throw ScriptException("Tagname '%s' does not exist", beamthing->endTag.c_str());
2023-04-30 20:20:58 +02:00
}
// Use a dummy sp to get the orientation
GetOrientation(tagnum, beamthing);
end = beamthing->cgd.origin;
} else {
end = start + Vector(beamthing->axis[0]) * beamthing->length;
}
2023-07-05 21:24:23 +02:00
CG_CreateBeam(
start,
vec_zero,
entity_number,
1,
beamthing->cgd.alpha * alpha,
beamthing->cgd.scale * scale,
(beamthing->beamflags | BEAM_LIGHTNING_EFFECT),
beamthing->length,
iLife,
qfalse,
end,
beamthing->min_offset,
beamthing->max_offset,
beamthing->overlap,
beamthing->numSubdivisions,
beamthing->delay,
beamthing->cgd.shadername,
beamthing->cgd.color,
beamthing->numspherebeams,
beamthing->sphereRadius,
beamthing->toggledelay,
beamthing->endalpha,
renderfx,
beamthing->emittername
);
2023-04-30 20:20:58 +02:00
}
}
//===============
// UpdateEmitter
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::UpdateEmitter(
dtiki_t *tiki, vec3_t axis[3], int entity_number, int parent_number, Vector entity_origin
)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
int parent, lastparent, i;
emittertime_t *et = NULL;
centity_t *pc;
int count = 0;
float scale = 1.0f;
int entnum;
2023-04-30 20:20:58 +02:00
if (current_entity)
{
2023-04-30 20:20:58 +02:00
scale = current_entity->scale;
entnum = current_entity->entityNumber;
}
else
{
entnum = 1023;
2023-04-30 20:20:58 +02:00
}
// Find the emitter associated with this model
for (i = 1; i <= m_emitters.NumObjects(); i++) {
m_spawnthing = m_emitters.ObjectAt(i);
if (m_spawnthing->cgd.tiki != tiki) {
continue;
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
et = m_spawnthing->GetEmitTime(entity_number);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (!et->active) {
continue;
}
if ((m_spawnthing->cgd.flags & T_DETAIL) && !cg_detail->integer) {
et->last_emit_time = 0;
continue;
}
if (m_spawnthing->cgd.flags & T_WAVE) {
if (m_spawnthing->entnum == entnum) {
orientation_t ori;
int j;
// Set the default origin (spawn from the parent's origin)
VectorCopy(entity_origin, m_spawnthing->cgd.origin);
ori = cgi.TIKI_Orientation(current_entity, m_spawnthing->tagnum);
VectorCopy(current_entity->origin, m_spawnthing->linked_origin);
for (j = 0; j < 3; j++) {
VectorMA(m_spawnthing->linked_origin, ori.origin[i], current_entity->axis[j], m_spawnthing->linked_origin);
}
MatrixMultiply(ori.axis, current_entity->axis, m_spawnthing->linked_axis);
}
continue;
}
2023-04-30 20:20:58 +02:00
// Set the default origin (spawn from the parent's origin)
VectorCopy(entity_origin, m_spawnthing->cgd.origin);
if (m_spawnthing->cgd.flags & T_BEAMTHING) {
if (m_spawnthing->cgd.flags & T_ANGLES) {
vec3_t axis[3];
AnglesToAxis(m_spawnthing->cgd.angles, axis);
AxisCopy(axis, m_spawnthing->axis);
}
UpdateBeam(tiki, entity_number, m_spawnthing);
continue;
}
if (m_spawnthing->tagnum != -1) {
2023-04-30 20:20:58 +02:00
// Set the axis and origin based on the tag's axis and origin
GetOrientation(m_spawnthing->tagnum, m_spawnthing);
} else if (axis) {
// Set the axis based on the entity's axis.
AxisCopy(axis, m_spawnthing->axis);
} else {
AxisClear(m_spawnthing->axis);
}
// If we are HARDLINKed then subtract off the parent's origin
if (m_spawnthing->cgd.flags & T_HARDLINK) {
m_spawnthing->cgd.parent = entity_number;
m_spawnthing->cgd.origin -= entity_origin;
} else if (m_spawnthing->cgd.flags & T_PARENTLINK) {
lastparent = ENTITYNUM_NONE;
parent = parent_number;
// Find the topmost parent
while (parent != ENTITYNUM_NONE) {
2023-07-05 21:24:23 +02:00
pc = &cg_entities[parent];
2023-04-30 20:20:58 +02:00
lastparent = parent;
2023-07-05 21:24:23 +02:00
parent = pc->currentState.parent;
2023-04-30 00:02:16 +02:00
}
2023-04-30 20:20:58 +02:00
// The lastparent is the "real" parent
if (lastparent != ENTITYNUM_NONE) {
pc = &cg_entities[lastparent];
m_spawnthing->cgd.origin -= pc->lerpOrigin;
m_spawnthing->cgd.parent = lastparent;
2023-04-30 00:02:16 +02:00
}
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
m_spawnthing->cgd.createTime = cg.time;
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.parentOrigin = Vector(entity_origin);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (m_spawnthing->cgd.flags & T_DLIGHT) {
cgi.R_AddLightToScene(
m_spawnthing->cgd.origin,
m_spawnthing->cgd.lightIntensity * scale,
2023-07-05 21:24:23 +02:00
m_spawnthing->dcolor[0],
m_spawnthing->dcolor[1],
m_spawnthing->dcolor[2],
m_spawnthing->cgd.lightType
);
2023-04-30 20:20:58 +02:00
continue;
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
Vector save_origin = m_spawnthing->cgd.origin;
2023-07-05 21:24:23 +02:00
Vector delta = m_spawnthing->cgd.origin - et->oldorigin;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (m_spawnthing->spawnRate < 0) {
2023-07-05 21:24:23 +02:00
warning("ClientGameCommandManager::UpdateEmitter", "Invalid spawnrate (negative)");
2023-04-30 00:02:16 +02:00
continue;
2023-04-30 20:20:58 +02:00
}
if (paused->integer) {
et->last_emit_time = 0;
} else if ((et->last_emit_time > 0) && (m_spawnthing->spawnRate)) {
2023-07-05 21:24:23 +02:00
int dtime = cg.time - et->last_emit_time;
2023-04-30 20:20:58 +02:00
float lerp, lerpfrac;
if (et->last_emit_time > cg.time) {
et->last_emit_time = cg.time;
2023-04-30 00:02:16 +02:00
}
2023-04-30 20:20:58 +02:00
2023-07-05 21:24:23 +02:00
count = dtime / (m_spawnthing->spawnRate * (1.0f / cg_effectdetail->value));
2023-04-30 20:20:58 +02:00
// This is kind of a nasty bit of code. If the count is 1, just
// spawn a single tempmodel, if it's greater than 1, then spawn the
// number of tempmodels over a period of time, and adjust their
// create times accordingly. Also lerp the origins so they appear
// where they are supposed to. This helps smoothing out low frame
// rate situations where this is only get called a few times a
// second, but the spawn rate is high, and it will look a lot
// smoother.
if (!count) {
continue;
} else if (count == 1) {
SpawnEffect(1, 0);
2023-04-30 20:20:58 +02:00
et->last_emit_time = cg.time;
} else {
lerpfrac = 1.0f / (float)count;
lerp = 0;
2023-07-05 21:24:23 +02:00
while (dtime > (m_spawnthing->spawnRate * (1.0f / cg_effectdetail->value))) {
2023-04-30 20:20:58 +02:00
et->last_emit_time = cg.time;
2023-07-05 21:24:23 +02:00
dtime -= m_spawnthing->spawnRate * (1.0f / cg_effectdetail->value);
2023-04-30 20:20:58 +02:00
if (et->lerp_emitter) {
2023-07-05 21:24:23 +02:00
m_spawnthing->cgd.origin = et->oldorigin + (delta * lerp);
2023-04-30 20:20:58 +02:00
}
SpawnEffect(1, dtime);
2023-04-30 20:20:58 +02:00
lerp += lerpfrac;
}
2023-04-30 00:02:16 +02:00
}
2023-04-30 20:20:58 +02:00
} else {
et->last_emit_time = cg.time;
}
if (cg_showemitters->integer) {
if (count) {
2023-07-05 21:24:23 +02:00
cgi.DPrintf("%d:%s:%d tempmodels emitted\n", entity_number, m_spawnthing->emittername.c_str(), count);
2023-04-30 00:02:16 +02:00
}
2023-04-30 20:20:58 +02:00
}
// Since we have an oldorigin, now we can do lerping
m_spawnthing->cgd.origin = save_origin;
2023-07-05 21:24:23 +02:00
et->oldorigin = save_origin;
et->lerp_emitter = qtrue;
2023-04-30 20:20:58 +02:00
}
}
2023-04-30 00:02:16 +02:00
//===============
// RemoveClientEntity - Removes an entity from being
// updated if it has emitters attached
//===============
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::RemoveClientEntity(int number, dtiki_t *tiki, centity_t *cent, ctempmodel_t *p)
2023-04-30 20:20:58 +02:00
{
int i;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
// Kill the emitters if they are attached to this tiki
if (number != -1) {
for (i = 1; i <= m_emitters.NumObjects(); i++) {
2023-07-05 21:24:23 +02:00
spawnthing_t *st = m_emitters.ObjectAt(i);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (st->cgd.tiki == tiki) {
st->RemoveEntity(number);
}
}
}
// Turn off any swiping for this entity number
2023-07-05 21:24:23 +02:00
int oldnum = current_entity_number;
centity_t *oldcent = current_centity;
2023-04-30 20:20:58 +02:00
2023-07-05 21:24:23 +02:00
current_centity = cent;
2023-04-30 20:20:58 +02:00
current_entity_number = number;
ProcessEvent(EV_Client_SwipeOff);
current_entity_number = oldnum;
2023-07-05 21:24:23 +02:00
current_centity = oldcent;
2023-04-30 20:20:58 +02:00
// If this tempmodel was assigned a temporary number then remove it from the
// command_time_manager
if (p && p->cgd.flags & T_ASSIGNED_NUMBER) {
m_command_time_manager.RemoveEntity(number);
}
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
bool ClientGameCommandManager::GetTagPositionAndOrientation(int tagnum, orientation_t *new_or)
{
2023-07-05 21:24:23 +02:00
int i;
orientation_t tag_or;
if (!current_tiki || !current_entity) {
return 0;
}
tag_or = cgi.TIKI_Orientation(current_entity, tagnum & TAG_MASK);
new_or->origin[0] = current_entity->origin[0];
new_or->origin[1] = current_entity->origin[1];
new_or->origin[2] = current_entity->origin[2];
for (i = 0; i < 3; ++i) {
VectorMA(new_or->origin, tag_or.origin[i], current_entity->axis[i], new_or->origin);
}
MatrixMultiply(tag_or.axis, current_entity->axis, new_or->axis);
return true;
}
2023-07-05 21:24:23 +02:00
bool ClientGameCommandManager::GetTagPositionAndOrientation(str tagname, orientation_t *new_or)
{
int tagnum;
tagnum = cgi.Tag_NumForName(current_tiki, tagname.c_str());
2023-07-05 21:24:23 +02:00
if (tagnum < 0) {
Class::warning(
2023-07-05 21:24:23 +02:00
"ClientGameCommandManager::GetTagPositionAndOrientation", "Could not find tag \"%s\"", tagname.c_str()
);
return false;
}
return ClientGameCommandManager::GetTagPositionAndOrientation(tagnum, new_or);
}
2023-04-30 00:02:16 +02:00
//===============
// FreeAllEmitters
//===============
void ClientGameCommandManager::RestartAllEmitters(void)
2023-04-30 20:20:58 +02:00
{
// FIXME: stub??
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
//===============
2023-04-30 20:20:58 +02:00
// CG_RestartCommandManager
2023-04-30 00:02:16 +02:00
//===============
void CG_RestartCommandManager()
2023-04-30 20:20:58 +02:00
{
commandManager.FreeAllTempModels();
}
2023-04-30 00:02:16 +02:00
//=================
// CG_CleanUpTempModels
//=================
void CG_CleanUpTempModels()
{
commandManager.FreeSomeTempModels();
}
2023-04-30 00:02:16 +02:00
//=================
2023-04-30 20:20:58 +02:00
// CG_ProcessInitCommands
2023-04-30 00:02:16 +02:00
//=================
2023-07-05 21:24:23 +02:00
void CG_ProcessInitCommands(dtiki_t *tiki, refEntity_t *ent)
2023-04-30 14:47:18 +02:00
{
2023-07-05 21:24:23 +02:00
int i, j;
int num_args;
refEntity_t *old_entity;
dtiki_t *old_tiki;
dtikicmd_t *pcmd;
if (!tiki) {
return;
}
2023-07-05 21:24:23 +02:00
old_entity = current_entity;
old_tiki = current_tiki;
current_entity = ent;
2023-07-05 21:24:23 +02:00
current_tiki = tiki;
2023-07-05 21:24:23 +02:00
for (i = 0; i < tiki->a->num_client_initcmds; i++) {
Event *ev;
2023-07-05 21:24:23 +02:00
pcmd = &tiki->a->client_initcmds[i];
num_args = pcmd->num_args;
// Create the event and Process it.
ev = new Event(pcmd->args[0]);
for (j = 1; j < num_args; j++) {
ev->AddToken(pcmd->args[j]);
}
2023-07-05 21:24:23 +02:00
if (!commandManager.SelectProcessEvent(ev)) {
Com_Printf(
2023-07-05 21:24:23 +02:00
"^~^~^ CG_ProcessInitCommands: Bad init client command '%s' in '%s'\n", pcmd->args[0], tiki->name
);
}
}
current_entity = old_entity;
2023-07-05 21:24:23 +02:00
current_tiki = old_tiki;
}
//=================
// CG_ProcessCacheInitCommands
//=================
2023-07-05 21:24:23 +02:00
void CG_ProcessCacheInitCommands(dtiki_t *tiki)
{
2023-07-05 21:24:23 +02:00
int i, j;
int num_args;
refEntity_t *old_entity;
dtiki_t *old_tiki;
dtikicmd_t *pcmd;
if (!tiki) {
return;
}
2023-07-05 21:24:23 +02:00
old_entity = current_entity;
old_tiki = current_tiki;
current_entity = NULL;
2023-07-05 21:24:23 +02:00
current_tiki = tiki;
2023-07-05 21:24:23 +02:00
for (i = 0; i < tiki->a->num_client_initcmds; i++) {
Event *ev;
2023-07-05 21:24:23 +02:00
pcmd = &tiki->a->client_initcmds[i];
num_args = pcmd->num_args;
// Create the event and Process it.
ev = new Event(pcmd->args[0]);
2023-07-05 21:24:23 +02:00
if (commandManager.GetFlags(ev) & EV_CACHE) {
// only process even in which the cache flag is set
for (j = 1; j < num_args; j++) {
ev->AddToken(pcmd->args[j]);
}
2023-07-05 21:24:23 +02:00
if (!commandManager.SelectProcessEvent(ev)) {
Com_Printf(
2023-07-05 21:24:23 +02:00
"^~^~^ CG_ProcessInitCommands: Bad init client command '%s' in '%s'\n", pcmd->args[0], tiki->name
);
}
2023-07-05 21:24:23 +02:00
} else {
// no cache flags
delete ev;
}
}
current_entity = old_entity;
2023-07-05 21:24:23 +02:00
current_tiki = old_tiki;
}
2023-07-05 21:24:23 +02:00
void CG_EndTiki(dtiki_t *tiki)
{
CG_DeleteEmitters(tiki);
2023-04-30 14:47:18 +02:00
}
2023-04-30 00:02:16 +02:00
//=================
2023-04-30 20:20:58 +02:00
// CG_UpdateEntity
2023-04-30 00:02:16 +02:00
//=================
2023-07-05 21:24:23 +02:00
void CG_UpdateEntityEmitters(int entnum, refEntity_t *ent, centity_t *cent)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
refEntity_t *old_entity = current_entity;
dtiki_t *old_tiki = current_tiki;
int oldnum = current_entity_number;
centity_t *oldcent = current_centity;
2023-04-30 01:42:57 +02:00
2023-04-30 20:20:58 +02:00
// Check to see if this model has any emitters
2023-07-05 21:24:23 +02:00
current_entity = ent;
current_tiki = ent->tiki;
current_centity = cent;
2023-04-30 20:20:58 +02:00
current_entity_number = entnum;
if (cent->currentState.parent != ENTITYNUM_NONE) {
2023-07-05 21:24:23 +02:00
commandManager.UpdateEmitter(
ent->tiki, ent->axis, cent->currentState.number, cent->currentState.parent, ent->origin
);
2023-04-30 20:20:58 +02:00
} else {
commandManager.UpdateEmitter(
2023-07-05 21:24:23 +02:00
ent->tiki, ent->axis, cent->currentState.number, cent->currentState.parent, cent->lerpOrigin
);
2023-04-30 20:20:58 +02:00
}
2023-07-05 21:24:23 +02:00
current_entity = old_entity;
current_tiki = old_tiki;
current_centity = oldcent;
2023-04-30 20:20:58 +02:00
current_entity_number = oldnum;
}
extern "C" {
2023-07-05 21:24:23 +02:00
void CG_AnimationDebugMessage(int number, const char *fmt, ...);
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
//=================
2023-04-30 20:20:58 +02:00
// CG_ProcessEntityCommands
2023-04-30 00:02:16 +02:00
//=================
2023-07-05 21:24:23 +02:00
qboolean CG_ProcessEntityCommands(int frame, int anim, int entnum, refEntity_t *ent, centity_t *cent)
2023-04-30 20:20:58 +02:00
{
int i, j;
int num_args;
tiki_cmd_t tikicmds;
if (cgi.Frame_Commands(ent->tiki, anim, frame, &tikicmds)) {
2023-07-05 21:24:23 +02:00
current_entity = ent;
current_centity = cent;
2023-04-30 20:20:58 +02:00
current_entity_number = entnum;
2023-07-05 21:24:23 +02:00
current_tiki = ent->tiki;
CG_AnimationDebugMessage(entnum, "Processing Ent Commands: Entity: %3d Anim:#(%i) Frame:#(%i)\n", anim, frame);
2023-04-30 20:20:58 +02:00
for (i = 0; i < tikicmds.num_cmds; i++) {
2023-07-05 21:24:23 +02:00
Event *ev;
2023-04-30 20:20:58 +02:00
num_args = tikicmds.cmds[i].num_args;
if (num_args > 0) {
// Create the event and Process it.
ev = new Event(tikicmds.cmds[i].args[0]);
for (j = 1; j < num_args; j++) {
ev->AddToken(tikicmds.cmds[i].args[j]);
}
commandManager.SelectProcessEvent(ev);
2023-04-30 00:02:16 +02:00
}
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
current_tiki = NULL;
2023-04-30 20:20:58 +02:00
current_entity_number = -1;
2023-07-05 21:24:23 +02:00
current_entity = NULL;
current_centity = NULL;
2023-04-30 20:20:58 +02:00
}
return qtrue;
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
//=================
2023-04-30 20:20:58 +02:00
// CG_ClientCommandDebugMessage
2023-04-30 00:02:16 +02:00
//=================
2023-07-05 21:24:23 +02:00
void CG_ClientCommandDebugMessage(centity_t *cent, const char *fmt, ...)
2023-04-30 20:20:58 +02:00
{
2023-04-30 00:02:16 +02:00
#ifndef NDEBUG
2023-04-30 20:20:58 +02:00
if (cg_debugAnim->integer) {
va_list argptr;
2023-07-05 21:24:23 +02:00
char msg[1024];
2023-04-30 20:20:58 +02:00
va_start(argptr, fmt);
vsprintf(msg, fmt, argptr);
va_end(argptr);
2023-07-05 21:24:23 +02:00
if ((!cg_debugAnimWatch->integer) || ((cg_debugAnimWatch->integer - 1) == cent->currentState.number)) {
2023-04-30 20:20:58 +02:00
if (cg_debugAnim->integer == 2) {
cgi.DebugPrintf(msg);
} else {
cgi.Printf(msg);
2023-04-30 00:02:16 +02:00
}
2023-04-30 20:20:58 +02:00
}
}
2023-04-30 00:02:16 +02:00
#endif
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
//=================
2023-04-30 20:20:58 +02:00
// CG_ClientCommands
2023-04-30 00:02:16 +02:00
//=================
2023-07-05 21:24:23 +02:00
void CG_ClientCommands(refEntity_t *ent, centity_t *cent, int slot)
2023-04-30 20:20:58 +02:00
{
#if 0
2023-04-30 20:20:58 +02:00
int anim;
int frame;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (!tiki) {
return;
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (paused->integer) {
return;
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (cent->currentState.eFlags & EF_DONT_PROCESS_COMMANDS) {
return;
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
assert(cent);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
// don't do anything if the frame is illegal
if ((new_frame < 0) || (new_frame >= state->numframes)) {
return;
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
# if 0
# ifndef NDEBUG
2023-04-30 00:02:16 +02:00
CG_ClientCommandDebugMessage(
cent,
"Client Commands: cg.time %d checking Entity %d anim %d frame %d\n",
cg.time,
cent->currentState.number,
new_anim,
new_frame
);
2023-07-05 21:24:23 +02:00
# endif
# endif
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
anim = state->last_cmd_anim - 1;
frame = state->last_cmd_frame;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
// if we had a last anim and it it wasn't same as ours then
// we need to run any exit commands from the last animation
if ((anim != new_anim) && (anim >= 0)) {
// play the exit command
CG_ProcessEntityCommands(TIKI_FRAME_EXIT, anim,
cent->currentState.number, ent, cent);
2023-07-05 21:24:23 +02:00
# ifndef NDEBUG
2023-04-30 20:20:58 +02:00
CG_ClientCommandDebugMessage(
cent, "Client Commands: Entity %d Exiting Anim: %s\n",
cent->currentState.number, cgi.Anim_NameForNum(tiki, anim));
2023-07-05 21:24:23 +02:00
# endif
2023-04-30 20:20:58 +02:00
frame = 0;
// Reset the tiki looping sound if changing animation
cent->tikiLoopSound = NULL;
}
if (state->has_commands) {
// if we are entering a new animation, than
// we need to run any entry commands for the new animation
if (anim != new_anim) {
// play the exit command
CG_ProcessEntityCommands(TIKI_FRAME_ENTRY, new_anim,
cent->currentState.number, ent, cent);
2023-07-05 21:24:23 +02:00
# ifndef NDEBUG
2023-04-30 20:20:58 +02:00
CG_ClientCommandDebugMessage(
cent, "Client Commands: Entity %d Entering Anim: %s\n",
cent->currentState.number,
cgi.Anim_NameForNum(tiki, new_anim));
2023-07-05 21:24:23 +02:00
# endif
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (state->driven) {
// make sure we process this frame if we are on a new frame
// although this is a hack, it guarantees that the frame will be
// processed below.
frame %= state->numframes;
if (frame < new_frame) {
frame = new_frame;
}
} else {
//
// we need to catch up on the frames we haven't played yet
//
if ((new_frame != (frame - 1)) && (state->numframes > 1)) {
// and frame number so that it wraps properly
frame %= state->numframes;
// lerp to one minus the current frame
while (frame != new_frame) {
2023-07-05 21:24:23 +02:00
# ifndef NDEBUG
2023-04-30 20:20:58 +02:00
CG_ClientCommandDebugMessage(
cent,
"Client Commands: cg.time %d Catching up Entity: %d "
"Anim: %s frame: %d numframes: %d\n",
cg.time, cent->currentState.number,
cgi.Anim_NameForNum(tiki, new_anim), frame,
state->numframes);
2023-07-05 21:24:23 +02:00
# endif
2023-04-30 20:20:58 +02:00
state->last_cmd_time =
cg.time + TIKI_FRAME_MAXFRAMERATE;
CG_ProcessEntityCommands(frame, new_anim,
cent->currentState.number, ent,
cent);
frame = (frame + 1) % state->numframes;
}
2023-04-30 00:02:16 +02:00
}
2023-04-30 20:20:58 +02:00
}
//
// handle the single frame and every frame case
//
if ((frame == new_frame) ||
((cg.time > state->last_cmd_time) &&
(cent->currentState.eFlags & EF_EVERYFRAME))) {
2023-07-05 21:24:23 +02:00
# ifndef NDEBUG
2023-04-30 20:20:58 +02:00
CG_ClientCommandDebugMessage(
cent,
"Client Commands: cg.time %d Processing Entity: %d Anim: %s "
"frame: %d numframes: %d\n",
cg.time, cent->currentState.number,
cgi.Anim_NameForNum(tiki, new_anim), new_frame,
state->numframes);
2023-07-05 21:24:23 +02:00
# endif
2023-04-30 20:20:58 +02:00
state->last_cmd_time = cg.time + TIKI_FRAME_MAXFRAMERATE;
CG_ProcessEntityCommands(new_frame, new_anim,
cent->currentState.number, ent, cent);
}
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (cent->clientFlags & CF_UPDATESWIPE) {
current_entity = ent;
current_centity = cent;
current_entity_number = cent->currentState.number;
current_tiki = tiki;
commandManager.ProcessEvent(EV_Client_Swipe);
current_tiki = NULL;
current_entity_number = -1;
current_entity = NULL;
current_centity = NULL;
}
state->last_cmd_anim = new_anim + 1;
state->last_cmd_frame = new_frame + 1;
#endif
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
//===============
// CG_InitializeCommandManager
//===============
void CG_InitializeCommandManager(void)
{
cg_showemitters = cgi.Cvar_Get("cg_showemitters", "0", 0);
2023-05-01 17:06:15 +02:00
commandManager.InitializeTempModelCvars();
commandManager.InitializeVSSCvars();
2023-04-30 20:20:58 +02:00
commandManager.InitializeTempModels();
2023-05-01 17:06:15 +02:00
commandManager.InitializeVSSSources();
2023-04-30 20:20:58 +02:00
commandManager.InitializeEmitters();
2023-05-01 17:06:15 +02:00
commandManager.InitializeRainCvars();
commandManager.InitializeBeams();
2023-04-30 20:20:58 +02:00
CG_InitTestEmitter();
CG_InitTestTreadMark();
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
//===============
2023-04-30 20:20:58 +02:00
// CG_RemoveClientEntity
2023-04-30 00:02:16 +02:00
//===============
2023-07-05 21:24:23 +02:00
void CG_RemoveClientEntity(int number, dtiki_t *tiki, centity_t *cent)
2023-04-30 20:20:58 +02:00
{
commandManager.RemoveClientEntity(number, tiki, cent);
// Remove the beam list associated with this entity
RemoveBeamList(number);
}
2023-04-30 00:02:16 +02:00
//=================
2023-04-30 20:20:58 +02:00
// CG_Command_ProcessFile
2023-04-30 00:02:16 +02:00
//=================
2023-07-05 21:24:23 +02:00
qboolean CG_Command_ProcessFile(const char *filename, qboolean quiet, dtiki_t *curTiki)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
char *buffer;
const char *bufstart;
char com_token[MAX_STRING_CHARS];
char tempName[MAX_QPATH + 1];
2023-04-30 20:20:58 +02:00
2023-07-05 21:24:23 +02:00
if (cgi.FS_ReadFile(filename, (void **)&buffer, quiet) == -1) {
2023-04-30 20:20:58 +02:00
return qfalse;
}
if (!quiet) {
cgi.DPrintf("CG_Command_ProcessFile: %s\n", filename);
}
// we are not setting up for a tiki
current_tiki = NULL;
2023-04-30 00:02:16 +02:00
// Update the loading screen
2023-07-05 21:24:23 +02:00
sprintf(tempName, "m%s", filename);
cgi.LoadResource(tempName);
2023-04-30 20:20:58 +02:00
bufstart = buffer;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
while (1) {
2023-07-05 21:24:23 +02:00
Event *ev;
2023-04-30 20:20:58 +02:00
// grab each line as we go
strcpy(com_token, COM_ParseExt(&buffer, qtrue));
if (!com_token[0]) {
2023-04-30 00:02:16 +02:00
break;
2023-04-30 20:20:58 +02:00
}
2023-05-11 22:48:13 +02:00
if (!Q_stricmp(com_token, "end") || !Q_stricmp(com_token, "server")) {
2023-04-30 20:20:58 +02:00
// skip the line
while (1) {
strcpy(com_token, COM_ParseExt(&buffer, qfalse));
if (!com_token[0]) {
break;
}
}
continue;
}
// Create the event
ev = new Event(com_token);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
// get the rest of the line
while (1) {
strcpy(com_token, COM_ParseExt(&buffer, qfalse));
if (!com_token[0]) {
break;
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
ev->AddToken(com_token);
}
commandManager.SelectProcessEvent(ev);
2023-04-30 20:20:58 +02:00
}
2023-07-05 21:24:23 +02:00
cgi.FS_FreeFile((void *)bufstart);
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
// Update the loading screen
sprintf(tempName, "o%s", filename);
cgi.LoadResource(tempName);
2023-04-30 20:20:58 +02:00
return qtrue;
}
2023-04-30 00:02:16 +02:00
//===========================
2023-04-30 20:20:58 +02:00
// CG_ConsoleCommand Functions
2023-04-30 00:02:16 +02:00
//===========================
2023-04-30 20:20:58 +02:00
void CG_EventList_f(void)
{
2023-07-05 21:24:23 +02:00
const char *mask;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
mask = NULL;
if (cgi.Argc() > 1) {
mask = cgi.Argv(1);
}
Event::ListCommands(mask);
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
void CG_EventHelp_f(void)
{
2023-07-05 21:24:23 +02:00
const char *mask;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
mask = NULL;
if (cgi.Argc() > 1) {
mask = cgi.Argv(1);
}
Event::ListDocumentation(mask);
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
void CG_DumpEventHelp_f(void)
{
2023-07-05 21:24:23 +02:00
const char *mask;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
mask = NULL;
if (cgi.Argc() > 1) {
mask = cgi.Argv(1);
}
Event::ListDocumentation(mask, true);
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
void CG_PendingEvents_f(void)
{
2023-07-05 21:24:23 +02:00
const char *mask;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
mask = NULL;
if (cgi.Argc() > 1) {
mask = cgi.Argv(1);
}
Event::PendingEvents(mask);
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
void CG_ClassList_f(void)
{
listAllClasses();
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
void CG_ClassTree_f(void)
{
if (cgi.Argc() > 1) {
listInheritanceOrder(cgi.Argv(1));
} else {
cgi.Printf("Syntax: cg_classtree [classname].\n");
}
}
void CG_ClassEvents_f(void)
{
if (cgi.Argc() > 1) {
ClassEvents(cgi.Argv(1), qfalse);
} else {
Com_Printf("Syntax: cg_classevents [classname].\n");
}
}
void CG_DumpClassEvents_f(void)
{
if (cgi.Argc() > 1) {
ClassEvents(cgi.Argv(1), qtrue);
} else {
Com_Printf("Syntax: cg_dumpclassevents [classname].\n");
}
}
2023-07-05 21:24:23 +02:00
void CG_DumpAllClasses_f(void)
{
DumpAllClasses();
}
2023-04-30 20:20:58 +02:00
#define throw_assert assert(0), throw
2023-04-30 00:02:16 +02:00
EmitterLoader emitterLoader;
2023-07-05 21:24:23 +02:00
Event EV_EmitterLoader_Emitter("emitter", EV_DEFAULT, "s", "emittername", "Create a new emitter");
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
CLASS_DECLARATION(Listener, EmitterLoader, NULL) {
2023-04-30 20:20:58 +02:00
{&EV_EmitterLoader_Emitter, &EmitterLoader::Emitter},
2023-07-05 21:24:23 +02:00
{NULL, NULL }
2023-04-30 20:20:58 +02:00
};
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
EmitterLoader::EmitterLoader()
{
emitterActive = false;
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
void EmitterLoader::Emitter(Event *ev)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
spawnthing_t *st;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
st = commandManager.CreateNewEmitter(ev->GetString(1));
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (st) {
emitterActive = true;
commandManager.SetSpawnthing(st);
}
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
void EmitterLoader::ProcessEmitter(Script& script)
{
str token;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
while (script.TokenAvailable(true)) {
2023-07-05 21:24:23 +02:00
Event *ev = NULL;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
token = script.GetToken(true);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (!str::cmp("}", token)) {
break;
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
ev = new Event(token);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
while (script.TokenAvailable(false)) {
ev->AddToken(script.GetToken(false));
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (emitterActive) {
commandManager.ProcessEvent(ev);
}
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
commandManager.SetSpawnthing(NULL);
2023-05-11 22:48:13 +02:00
emitterActive = false;
2023-04-30 20:20:58 +02:00
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
bool EmitterLoader::Load(Script& script)
{
str token;
str errortext;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
try {
while (script.TokenAvailable(true)) {
2023-07-05 21:24:23 +02:00
Event *ev = NULL;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
token = script.GetToken(true);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (!str::cmp("{", token)) {
ProcessEmitter(script);
} else if (!token.length() || !ValidEvent(token)) {
throw_assert "invalid token";
} else {
ev = new Event(token);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
while (script.TokenAvailable(false)) {
ev->AddToken(script.GetToken(false));
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
ProcessEvent(ev);
2023-04-30 00:02:16 +02:00
}
2023-04-30 20:20:58 +02:00
}
2023-07-05 21:24:23 +02:00
} catch (const char *s) {
cgi.DPrintf("emitter: error on line %d: %s\n", script.GetLineNumber(), s);
2023-04-30 20:20:58 +02:00
return false;
}
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
return true;
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
void CG_Emitter(centity_t *cent)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
spawnthing_t *emitter;
float dtime;
emittertime_t *et;
vec3_t mins, maxs;
2023-04-30 20:20:58 +02:00
2023-07-05 21:24:23 +02:00
emitter = commandManager.GetEmitterByName(CG_ConfigString(CS_IMAGES + cent->currentState.tag_num));
2023-04-30 20:20:58 +02:00
if (emitter) {
vec3_t axis[3];
2023-07-05 21:24:23 +02:00
cgi.R_ModelBounds(cgs.inlineDrawModel[cent->currentState.modelindex], mins, maxs);
emitter->cgd.origin[0] = cent->lerpOrigin[0] + mins[0] + (random() * (maxs[0] - mins[0]));
emitter->cgd.origin[1] = cent->lerpOrigin[1] + mins[1] + (random() * (maxs[1] - mins[1]));
emitter->cgd.origin[2] = cent->lerpOrigin[2] + maxs[2];
emitter->cgd.parentOrigin = Vector(cent->lerpOrigin);
2023-04-30 20:20:58 +02:00
emitter->cgd.parentOrigin[2] = cent->lerpOrigin[2] + maxs[2];
2023-07-05 21:24:23 +02:00
emitter->cgd.parentMins = mins;
emitter->cgd.parentMaxs = maxs;
2023-04-30 20:20:58 +02:00
AnglesToAxis(cent->lerpAngles, axis);
// Update the emitter time and spawn the tempmodels
et = emitter->GetEmitTime(cent->currentState.number);
if (et->last_emit_time > 0) {
dtime = cg.time - et->last_emit_time;
while (dtime > emitter->spawnRate) {
dtime -= emitter->spawnRate;
commandManager.SpawnEffect(1, emitter);
2023-04-30 20:20:58 +02:00
et->last_emit_time = cg.time;
2023-04-30 00:02:16 +02:00
}
2023-04-30 20:20:58 +02:00
}
}
}
2023-04-30 00:02:16 +02:00
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::CGEvent(centity_t *cent)
2023-04-30 20:20:58 +02:00
{
2023-07-05 21:24:23 +02:00
str modelname;
2023-04-30 20:20:58 +02:00
dtiki_t *tiki;
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
tiki = cgi.R_Model_GetHandle(cgs.model_draw[cent->currentState.modelindex]);
2023-04-30 00:02:16 +02:00
2023-04-30 20:20:58 +02:00
if (!tiki) {
return;
}
CG_EntityEffects(cent);
2023-07-05 21:24:23 +02:00
modelname = cgi.TIKI_Name(tiki);
2023-04-30 20:20:58 +02:00
m_spawnthing = InitializeSpawnthing(&m_localemitter);
AnglesToAxis(cent->lerpAngles, m_spawnthing->axis);
m_spawnthing->cgd.angles = cent->lerpAngles;
m_spawnthing->cgd.origin = cent->lerpOrigin;
2023-07-05 21:24:23 +02:00
m_spawnthing->cgd.scale = cent->currentState.scale;
m_spawnthing->cgd.alpha = cent->currentState.alpha;
2023-04-30 20:20:58 +02:00
m_spawnthing->cgd.color[0] = cent->color[0];
m_spawnthing->cgd.color[1] = cent->color[1];
m_spawnthing->cgd.color[2] = cent->color[2];
m_spawnthing->cgd.color[3] = cent->color[3];
2023-04-30 20:20:58 +02:00
2023-07-05 21:24:23 +02:00
Event *ev;
2023-04-30 20:20:58 +02:00
ev = new Event("model");
ev->AddString(modelname);
ProcessEvent(ev);
ev = new Event("anim");
ev->AddString("idle");
ProcessEvent(ev);
SpawnEffect(1, 0);
2023-04-30 20:20:58 +02:00
}
2023-07-05 21:24:23 +02:00
qboolean ClientGameCommandManager::SelectProcessEvent(Event *ev)
2023-05-01 15:49:45 +02:00
{
if (!m_fEventWait) {
return ProcessEvent(ev);
2023-07-05 21:24:23 +02:00
} else {
return PostEventForEntity(ev, m_fEventWait);
}
2023-05-01 15:49:45 +02:00
}
void ClientGameCommandManager::AddTreadMarkSources()
{
2023-05-06 23:37:05 +02:00
// stub
2023-05-01 15:49:45 +02:00
}
void ClientGameCommandManager::InitializeTreadMarkCvars()
{
2023-05-06 23:37:05 +02:00
// stub
2023-05-01 15:49:45 +02:00
}
void ClientGameCommandManager::InitializeTreadMarkSources()
{
2023-05-06 23:37:05 +02:00
// stub
2023-05-01 15:49:45 +02:00
}
void ClientGameCommandManager::ResetTreadMarkSources()
{
2023-05-06 23:37:05 +02:00
// stub
2023-05-01 15:49:45 +02:00
}
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::ResetTreadMarkSources(Event *ev)
2023-05-01 15:49:45 +02:00
{
2023-05-06 23:37:05 +02:00
// stub
2023-05-01 15:49:45 +02:00
}
2023-07-05 21:24:23 +02:00
void CG_Event(centity_t *cent)
{
commandManager.CGEvent(cent);
}
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::SetCurrentTiki(Event *ev)
{
2023-05-06 21:10:36 +02:00
str tikiName;
2023-07-05 21:24:23 +02:00
if (ev->NumArgs() != 1) {
2023-05-06 21:10:36 +02:00
Com_Printf("ERROR: settiki command takes 1 parameter.\n");
return;
}
tikiName = ev->GetString(1);
2023-05-29 22:06:13 +02:00
if (str::icmp(tikiName.c_str(), "none")) {
2023-05-06 21:10:36 +02:00
current_tiki = cgi.TIKI_FindTiki(tikiName.c_str());
2023-05-29 22:06:13 +02:00
} else {
2023-05-06 21:10:36 +02:00
current_tiki = NULL;
}
}
2023-07-05 21:24:23 +02:00
void ClientGameCommandManager::EventViewKick(Event *ev)
{
2023-05-06 16:15:28 +02:00
float vkmin[2], vkmax[2];
float fPitchMax, fYawMax, fScatterPitchMax;
2023-07-05 21:24:23 +02:00
str sPattern;
2023-05-06 16:15:28 +02:00
if (current_centity->currentState.parent != cg.snap->ps.clientNum) {
return;
}
if (ev->NumArgs() < 9) {
throw ScriptException("Wrong number of arguments for viewkick, should be 9\n");
}
vkmin[0] = ev->GetFloat(1);
vkmax[0] = ev->GetFloat(2);
vkmin[1] = ev->GetFloat(3);
vkmax[1] = ev->GetFloat(4);
cg.viewkickRecenter = ev->GetFloat(5);
2023-07-05 21:24:23 +02:00
sPattern = ev->GetString(6);
2023-05-06 16:15:28 +02:00
2023-07-05 21:24:23 +02:00
fPitchMax = ev->GetFloat(7);
fYawMax = ev->GetFloat(8);
2023-05-06 16:15:28 +02:00
fScatterPitchMax = ev->GetFloat(9);
if (ev->NumArgs() > 9) {
cg.viewkickMinDecay = ev->GetFloat(10);
2023-07-05 21:24:23 +02:00
} else {
2023-05-06 16:15:28 +02:00
cg.viewkickMinDecay = 12.0;
}
if (ev->NumArgs() > 10) {
cg.viewkickMaxDecay = ev->GetFloat(11);
2023-07-05 21:24:23 +02:00
} else {
2023-05-06 17:50:41 +02:00
cg.viewkickMaxDecay = 25.0;
2023-05-06 16:15:28 +02:00
}
cg.viewkick[0] += vkmin[0] + random() * (vkmax[0] - vkmin[0]);
2023-07-05 21:24:23 +02:00
if (sPattern == "T") {
2023-05-06 16:15:28 +02:00
cg.viewkick[1] += vkmin[1] + random() * (vkmax[1] - vkmin[1]);
2023-07-05 21:24:23 +02:00
} else if (sPattern == "V") {
2023-05-06 16:15:28 +02:00
cg.viewkick[1] += cg.viewkick[0] * (vkmin[1] + random() * (vkmax[1] - vkmin[1]));
}
2023-07-05 21:24:23 +02:00
if (cg.viewkick[0] < fScatterPitchMax) {
if (cg.viewkick[0] <= -fScatterPitchMax) {
2023-05-06 16:15:28 +02:00
cg.viewkick[0] += crandom() * 0.25;
cg.viewkick[1] += crandom() * 0.25;
}
2023-07-05 21:24:23 +02:00
} else {
2023-05-06 16:15:28 +02:00
cg.viewkick[0] -= crandom() * 0.25;
cg.viewkick[1] += crandom() * 3.5;
}
if (cg.viewkick[0] > fPitchMax) {
cg.viewkick[0] = fPitchMax;
} else if (cg.viewkick[0] < -fPitchMax) {
cg.viewkick[0] = -fPitchMax;
}
if (cg.viewkick[1] > fYawMax) {
cg.viewkick[1] = fYawMax;
2023-07-05 21:24:23 +02:00
} else if (cg.viewkick[1] < -fYawMax) {
2023-05-06 16:15:28 +02:00
cg.viewkick[1] = -fYawMax;
}
}
int ClientGameCommandManager::IdForTempModel(const ctempmodel_t* model)
{
int index;
if (model == &m_active_tempmodels) {
return -1;
}
if (!model) {
return -2;
}
index = model - m_tempmodels;
if (index >= MAX_TEMPMODELS) {
return -2;
}
if (model != &m_tempmodels[index]) {
return -2;
}
return model - m_tempmodels;
}
ctempmodel_t* ClientGameCommandManager::TempModelForId(int id)
{
if (id == -1) {
return &m_active_tempmodels;
}
if (id == -2) {
return NULL;
}
return &m_tempmodels[id];
}
int ClientGameCommandManager::IdForSpawnThing(const spawnthing_t* sp)
{
int i;
if (!sp) {
return 0;
}
for (i = 1; i <= m_emitters.NumObjects(); i++) {
if (sp == m_emitters.ObjectAt(i)) {
return i;
}
}
return 0;
}
spawnthing_t* ClientGameCommandManager::SpawnThingForId(int id)
{
if (!id) {
return 0;
}
return m_emitters.ObjectAt(id);
}
int ClientGameCommandManager::IdForVssSource(const cvssource_t* source)
{
int index;
if (source == &m_active_vsssources) {
return -1;
}
if (!source) {
return -2;
}
index = source - m_vsssources;
if (index < 0 || index >= m_iAllocatedvsssources) {
return -2;
}
if (source != &m_vsssources[index]) {
return -2;
}
return source - m_vsssources;
}
cvssource_t* ClientGameCommandManager::VssSourceForId(int id)
{
if (id == -1) {
return &m_active_vsssources;
}
if (id == -2) {
return 0;
}
return &m_vsssources[id];
}
void ClientGameCommandManager::ArchiveTempModelPointerToMemory(MemArchiver& archiver, ctempmodel_t** model)
{
int id;
if (archiver.IsReading()) {
archiver.ArchiveInteger(&id);
*model = TempModelForId(id);
} else {
id = IdForTempModel(*model);
archiver.ArchiveInteger(&id);
}
}
void ClientGameCommandManager::ArchiveSpawnThingPointerToMemory(MemArchiver& archiver, spawnthing_t** sp)
{
int id;
if (archiver.IsReading()) {
archiver.ArchiveInteger(&id);
*sp = SpawnThingForId(id);
} else {
id = IdForSpawnThing(*sp);
archiver.ArchiveInteger(&id);
}
}
void ClientGameCommandManager::ArchiveVssSourcePointerToMemory(MemArchiver& archiver, cvssource_t** source)
{
int id;
if (archiver.IsReading()) {
archiver.ArchiveInteger(&id);
*source = VssSourceForId(id);
} else {
id = IdForVssSource(*source);
archiver.ArchiveInteger(&id);
}
}
void ClientGameCommandManager::ArchiveToMemory(MemArchiver& archiver)
{
spawnthing_t* sp;
int num;
int i;
m_localemitter.ArchiveToMemory(archiver);
if (archiver.IsReading()) {
archiver.ArchiveInteger(&num);
for (i = 0; i < num; i++) {
sp = new spawnthing_t();
sp->ArchiveToMemory(archiver);
m_emitters.AddObjectAt(i + 1, sp);
}
} else {
num = m_emitters.NumObjects();
archiver.ArchiveInteger(&num);
for (i = 0; i < num; i++) {
sp = m_emitters.ObjectAt(i);
sp->ArchiveToMemory(archiver);
}
}
ArchiveTempModelPointerToMemory(archiver, &m_active_tempmodels.prev);
ArchiveTempModelPointerToMemory(archiver, &m_active_tempmodels.next);
ArchiveTempModelPointerToMemory(archiver, &m_free_tempmodels);
for (i = 0; i < MAX_TEMPMODELS; i++) {
m_tempmodels[i].ArchiveToMemory(archiver);
}
if (archiver.IsReading()) {
archiver.ArchiveInteger(&num);
if (m_iAllocatedvsssources != num) {
m_iAllocatedvsssources = num;
m_vsssources = (cvssource_t*)cgi.Malloc(m_iAllocatedvsssources * sizeof(cvssource_t));
// instead of using memset, call the constructor
for (i = 0; i < m_iAllocatedvsssources; i++) {
new (&m_vsssources[i]) cvssource_t();
}
}
} else {
archiver.ArchiveInteger(&m_iAllocatedvsssources);
}
ArchiveVssSourcePointerToMemory(archiver, &m_active_vsssources.prev);
ArchiveVssSourcePointerToMemory(archiver, &m_active_vsssources.next);
ArchiveVssSourcePointerToMemory(archiver, &m_free_vsssources);
for (i = 0; i < m_iAllocatedvsssources; i++) {
m_vsssources[i].ArchiveToMemory(archiver);
}
archiver.ArchiveTime(&m_iLastVSSRepulsionTime);
m_command_time_manager.ArchiveToMemory(archiver);
archiver.ArchiveInteger(&m_seed);
archiver.ArchiveFloat(&m_fEventWait);
m_pCurrentSfx = NULL;
}
void commandthing_t::ArchiveToMemory(MemArchiver& archiver)
{
int num;
int i;
enttracker_t::ArchiveToMemory(archiver);
if (archiver.IsReading()) {
archiver.ArchiveInteger(&num);
for (i = 0; i < num; i++) {
commandtime_t ct;
ct.ArchiveToMemory(archiver);
m_commandtimes.AddObject(ct);
}
} else {
archiver.ArchiveInteger(&num);
m_commandtimes.ClearObjectList();
for (i = 0; i < num; i++) {
commandtime_t& ct = m_commandtimes.ObjectAt(i);
ct.ArchiveToMemory(archiver);
}
}
// FIXME: unimplemented
}
void cvssource_t::ArchiveToMemory(MemArchiver& archiver)
{
commandManager.ArchiveVssSourcePointerToMemory(archiver, &next);
commandManager.ArchiveVssSourcePointerToMemory(archiver, &prev);
commandManager.ArchiveVssSourcePointerToMemory(archiver, &stnext);
archiver.ArchiveInteger(&stindex);
archiver.ArchiveVector(&lastOrigin);
archiver.ArchiveFloat(&lastRadius);
archiver.ArchiveFloat(&lastDensity);
archiver.ArchiveVec3(lastColor);
archiver.ArchiveVec3(lastLighting);
archiver.ArchiveVector(&newOrigin);
archiver.ArchiveFloat(&newRadius);
archiver.ArchiveFloat(&newDensity);
archiver.ArchiveVec3(newColor);
archiver.ArchiveVec3(newLighting);
archiver.ArchiveFloat(&ooRadius);
archiver.ArchiveVector(&velocity);
archiver.ArchiveFloat(&startAlpha);
archiver.ArchiveInteger(&roll);
archiver.ArchiveVector(&repulsion);
archiver.ArchiveInteger(&lifeTime);
archiver.ArchiveInteger(&collisionmask);
archiver.ArchiveInteger(&parent);
archiver.ArchiveInteger(&flags);
archiver.ArchiveInteger(&flags2);
archiver.ArchiveInteger(&smokeType);
archiver.ArchiveFloat(&typeInfo);
archiver.ArchiveFloat(&fadeMult);
archiver.ArchiveFloat(&scaleMult);
archiver.ArchiveTime(&lastPhysicsTime);
archiver.ArchiveTime(&lastLightingTime);
archiver.ArchiveBoolean(&lastValid);
}
void ctempmodel_t::ArchiveToMemory(MemArchiver& archiver)
{
commandManager.ArchiveTempModelPointerToMemory(archiver, &next);
commandManager.ArchiveTempModelPointerToMemory(archiver, &prev);
cgd.ArchiveToMemory(archiver);
archiver.ArchiveString(&modelname);
CG_ArchiveRefEntity(archiver, &lastEnt);
CG_ArchiveRefEntity(archiver, &ent);
archiver.ArchiveInteger(&number);
archiver.ArchiveTime(&lastAnimTime);
archiver.ArchiveTime(&lastPhysicsTime);
archiver.ArchiveTime(&killTime);
archiver.ArchiveTime(&next_bouncesound_time);
archiver.ArchiveInteger(&seed);
archiver.ArchiveInteger(&twinkleTime);
archiver.ArchiveInteger(&aliveTime);
archiver.ArchiveBoolean(&addedOnce);
archiver.ArchiveBoolean(&lastEntValid);
commandManager.ArchiveSpawnThingPointerToMemory(archiver, &m_spawnthing);
}
void enttracker_t::ArchiveToMemory(MemArchiver& archiver)
{
archiver.ArchiveRaw(usedNumbers, sizeof(usedNumbers));
}
void emittertime_t::ArchiveToMemory(MemArchiver& archiver)
{
archiver.ArchiveInteger(&entity_number);
archiver.ArchiveTime(&last_emit_time);
archiver.ArchiveVector(&oldorigin);
archiver.ArchiveBoolean(&active);
archiver.ArchiveBoolean(&lerp_emitter);
}
void emitterthing_t::ArchiveToMemory(MemArchiver& archiver)
{
int num;
int i;
enttracker_t::ArchiveToMemory(archiver);
if (archiver.IsReading()) {
emittertime_t et;
archiver.ArchiveInteger(&num);
for (i = 0; i < num; i++) {
et.ArchiveToMemory(archiver);
m_emittertimes.AddObject(et);
}
} else {
num = m_emittertimes.NumObjects();
archiver.ArchiveInteger(&num);
for (i = 0; i < num; i++) {
emittertime_t& et = m_emittertimes[i];
et.ArchiveToMemory(archiver);
}
}
archiver.ArchiveBoolean(&startoff);
}
void cg_common_data::ArchiveToMemory(MemArchiver& archiver)
{
archiver.ArchiveInteger(&life);
archiver.ArchiveTime(&createTime);
archiver.ArchiveVector(&origin);
archiver.ArchiveVector(&oldorigin);
archiver.ArchiveVector(&accel);
archiver.ArchiveVector(&angles);
archiver.ArchiveVector(&velocity);
archiver.ArchiveVector(&avelocity);
archiver.ArchiveVector(&parentOrigin);
archiver.ArchiveVector(&parentMins);
archiver.ArchiveVector(&parentMaxs);
archiver.ArchiveVector(&minVel);
archiver.ArchiveVector(&maxVel);
archiver.ArchiveFloat(color);
archiver.ArchiveFloat(&color[1]);
archiver.ArchiveFloat(&color[2]);
archiver.ArchiveFloat(&color[3]);
archiver.ArchiveFloat(&alpha);
archiver.ArchiveFloat(&scaleRate);
archiver.ArchiveFloat(&scalemin);
archiver.ArchiveFloat(&scalemax);
archiver.ArchiveFloat(&bouncefactor);
archiver.ArchiveInteger(&bouncecount);
archiver.ArchiveInteger(&maxbouncecount);
archiver.ArchiveString(&bouncesound);
archiver.ArchiveInteger(&bouncesound_delay);
archiver.ArchiveInteger(&flags);
archiver.ArchiveInteger(&flags2);
CG_ArchiveTikiPointer(archiver, &tiki);
archiver.ArchiveInteger(&swarmfreq);
archiver.ArchiveFloat(&swarmmaxspeed);
archiver.ArchiveFloat(&swarmdelta);
archiver.ArchiveFloat(&lightIntensity);
archiver.ArchiveInteger(&lightType);
archiver.ArchiveInteger(&fadeintime);
archiver.ArchiveInteger(&fadedelay);
archiver.ArchiveInteger(&parent);
archiver.ArchiveInteger(&collisionmask);
archiver.ArchiveInteger(&min_twinkletimeoff);
archiver.ArchiveInteger(&max_twinkletimeoff);
archiver.ArchiveInteger(&min_twinkletimeon);
archiver.ArchiveInteger(&max_twinkletimeon);
archiver.ArchiveInteger(&lightstyle);
archiver.ArchiveInteger(&physicsRate);
archiver.ArchiveFloat(&scale);
archiver.ArchiveFloat(&scale2);
archiver.ArchiveString(&swipe_shader);
archiver.ArchiveString(&swipe_tag_start);
archiver.ArchiveString(&swipe_tag_end);
archiver.ArchiveString(&shadername);
archiver.ArchiveFloat(&swipe_life);
archiver.ArchiveFloat(&friction);
archiver.ArchiveFloat(&spin_rotation);
archiver.ArchiveFloat(&decal_orientation);
archiver.ArchiveFloat(&decal_radius);
}
void spawnthing_t::ArchiveToMemory(MemArchiver& archiver)
{
emitterthing_t::ArchiveToMemory(archiver);
CG_ArchiveStringContainer(archiver, &m_modellist);
CG_ArchiveStringContainer(archiver, &m_taglist);
cgd.ArchiveToMemory(archiver);
archiver.ArchiveInteger(&entnum);
archiver.ArchiveVector(&origin_offset_base);
archiver.ArchiveVector(&origin_offset_amplitude);
archiver.ArchiveVector(&axis_offset_base);
archiver.ArchiveVector(&axis_offset_amplitude);
archiver.ArchiveVector(&randvel_base);
archiver.ArchiveVector(&randvel_amplitude);
archiver.ArchiveVector(&avelocity_base);
archiver.ArchiveVector(&avelocity_amplitude);
archiver.ArchiveVector(&angles_amplitude);
archiver.ArchiveVec3(axis[0]);
archiver.ArchiveVec3(axis[1]);
archiver.ArchiveVec3(axis[2]);
archiver.ArchiveVec3(tag_axis[0]);
archiver.ArchiveVec3(tag_axis[1]);
archiver.ArchiveVec3(tag_axis[2]);
archiver.ArchiveFloat(&life_random);
archiver.ArchiveFloat(&forwardVelocity);
archiver.ArchiveFloat(&sphereRadius);
archiver.ArchiveFloat(&coneHeight);
archiver.ArchiveFloat(&spawnRate);
archiver.ArchiveTime(&lastTime);
archiver.ArchiveInteger(&count);
archiver.ArchiveInteger(&tagnum);
archiver.ArchiveString(&emittername);
archiver.ArchiveString(&animName);
archiver.ArchiveFloat(dcolor);
archiver.ArchiveFloat(&dcolor[1]);
archiver.ArchiveFloat(&dcolor[2]);
archiver.ArchiveBoolean(&dlight);
archiver.ArchiveInteger(&numtempmodels);
archiver.ArchiveVec3(linked_origin);
archiver.ArchiveVec3(linked_axis[0]);
archiver.ArchiveVec3(linked_axis[1]);
archiver.ArchiveVec3(linked_axis[2]);
archiver.ArchiveFloat(&fMinRangeSquared);
archiver.ArchiveFloat(&fMaxRangeSquared);
archiver.ArchiveString(&startTag);
archiver.ArchiveString(&endTag);
archiver.ArchiveFloat(&length);
archiver.ArchiveFloat(&min_offset);
archiver.ArchiveFloat(&max_offset);
archiver.ArchiveFloat(&overlap);
archiver.ArchiveFloat(&numSubdivisions);
archiver.ArchiveFloat(&delay);
archiver.ArchiveFloat(&toggledelay);
archiver.ArchiveInteger(&beamflags);
archiver.ArchiveInteger(&numspherebeams);
archiver.ArchiveFloat(&endalpha);
archiver.ArchiveFloat(&spreadx);
archiver.ArchiveFloat(&spready);
archiver.ArchiveBoolean(&use_last_trace_end);
}
void commandtime_t::ArchiveToMemory(MemArchiver& archiver)
{
archiver.ArchiveInteger(&entity_number);
archiver.ArchiveInteger(&command_number);
archiver.ArchiveTime(&last_command_time);
}