mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 21:57:57 +03:00
2384 lines
57 KiB
C++
2384 lines
57 KiB
C++
/*
|
|
===========================================================================
|
|
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
|
|
===========================================================================
|
|
*/
|
|
|
|
// scriptslave.cpp: Standard scripted objects. Controlled by ScriptThread. These objects
|
|
// are bmodel objects created in the editor and controlled by an external
|
|
// text based script. Commands are interpretted on by one and executed
|
|
// upon a signal from the script master. The base script object can
|
|
// perform several different relative and specific rotations and translations
|
|
// and can cause other parts of the script to be executed when touched, damaged,
|
|
// touched, or used.
|
|
//
|
|
|
|
#include "g_local.h"
|
|
#include "g_phys.h"
|
|
#include "class.h"
|
|
#include "mover.h"
|
|
#include "scriptmaster.h"
|
|
#include "scriptthread.h"
|
|
#include "scriptslave.h"
|
|
#include "scriptexception.h"
|
|
#include "sentient.h"
|
|
#include "weapon.h"
|
|
#include "gibs.h"
|
|
#include "explosion.h"
|
|
#include "game.h"
|
|
#include "debuglines.h"
|
|
#include "weaputils.h"
|
|
#include "parm.h"
|
|
|
|
/*****************************************************************************/
|
|
/*QUAKED script_object (0 0.5 1) ? NOT_SOLID
|
|
|
|
******************************************************************************/
|
|
|
|
Event EV_ScriptSlave_DoMove
|
|
(
|
|
"move",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Move the script slave.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_WaitMove
|
|
(
|
|
"waitmove",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Move the script slave and wait until finished.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_Angles
|
|
(
|
|
"angles",
|
|
EV_DEFAULT,
|
|
"v",
|
|
"angles",
|
|
"Sets the angles.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_Trigger
|
|
(
|
|
"trigger",
|
|
EV_DEFAULT,
|
|
"e",
|
|
"ent",
|
|
"Trigger entities target.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_Next
|
|
(
|
|
"next",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Goto the next waypoint.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_JumpTo
|
|
(
|
|
"jumpto",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"vector_or_entity",
|
|
"Jump to specified vector or entity.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_MoveTo
|
|
(
|
|
"moveto",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"vector_or_entity",
|
|
"Move to the specified vector or entity.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_Speed
|
|
(
|
|
"speed",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"speed",
|
|
"Sets the speed.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_Time
|
|
(
|
|
"time",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"travel_time",
|
|
"Sets the travel time.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_MoveUp
|
|
(
|
|
"moveUp",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"dist",
|
|
"Move the position up.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_MoveDown
|
|
(
|
|
"moveDown",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"dist",
|
|
"Move the position down.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_MoveNorth
|
|
(
|
|
"moveNorth",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"dist",
|
|
"Move the position north.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_MoveSouth
|
|
(
|
|
"moveSouth",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"dist",
|
|
"Move the position south.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_MoveEast
|
|
(
|
|
"moveEast",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"dist",
|
|
"Move the position east.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_MoveWest
|
|
(
|
|
"moveWest",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"dist",
|
|
"Move the position west.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_MoveForward
|
|
(
|
|
"moveForward",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"dist",
|
|
"Move the position forward.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_MoveBackward
|
|
(
|
|
"moveBackward",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"dist",
|
|
"Move the position backward.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_MoveLeft
|
|
(
|
|
"moveLeft",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"dist",
|
|
"Move the position left.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_MoveRight
|
|
(
|
|
"moveRight",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"dist",
|
|
"Move the position right.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_RotateXDownTo
|
|
(
|
|
"rotateXdownto",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"angle",
|
|
"Rotate the x down to angle.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_RotateYDownTo
|
|
(
|
|
"rotateYdownto",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"angle",
|
|
"Rotate the y down to angle.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_RotateZDownTo
|
|
(
|
|
"rotateZdownto",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"angle",
|
|
"Rotate the z down to angle.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_RotateAxisDownTo
|
|
(
|
|
"rotateaxisdownto",
|
|
EV_DEFAULT,
|
|
"if",
|
|
"axis angle",
|
|
"Rotate the specified axis down to angle.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_RotateXUpTo
|
|
(
|
|
"rotateXupto",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"angle",
|
|
"Rotate the x up to angle.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_RotateYUpTo
|
|
(
|
|
"rotateYupto",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"angle",
|
|
"Rotate the y up to angle.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_RotateZUpTo
|
|
(
|
|
"rotateZupto",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"angle",
|
|
"Rotate the z up to angle.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_RotateAxisUpTo
|
|
(
|
|
"rotateaxisupto",
|
|
EV_DEFAULT,
|
|
"if",
|
|
"axis angle",
|
|
"Rotate the specified axis up to angle.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_RotateXDown
|
|
(
|
|
"rotateXdown",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"angle",
|
|
"Rotate the x down by the specified amount.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_RotateYDown
|
|
(
|
|
"rotateYdown",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"angle",
|
|
"Rotate the y down by the specified amount.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_RotateZDown
|
|
(
|
|
"rotateZdown",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"angle",
|
|
"Rotate the z down by the specified amount.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_RotateAxisDown
|
|
(
|
|
"rotateaxisdown",
|
|
EV_DEFAULT,
|
|
"if",
|
|
"axis angle",
|
|
"Rotate the specified axis down by the specified amount.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_RotateXUp
|
|
(
|
|
"rotateXup",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"angle",
|
|
"Rotate the x up by the specified amount.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_RotateYUp
|
|
(
|
|
"rotateYup",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"angle",
|
|
"Rotate the y up by the specified amount.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_RotateZUp
|
|
(
|
|
"rotateZup",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"angle",
|
|
"Rotate the z up by the specified amount.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_RotateAxisUp
|
|
(
|
|
"rotateaxisup",
|
|
EV_DEFAULT,
|
|
"if",
|
|
"axis angle",
|
|
"Rotate the specified axis up by the specified amount.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_RotateX
|
|
(
|
|
"rotateX",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"avelocity",
|
|
"Rotate about the x axis at the specified angular velocity.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_RotateY
|
|
(
|
|
"rotateY",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"avelocity",
|
|
"Rotate about the y axis at the specified angular velocity.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_RotateZ
|
|
(
|
|
"rotateZ",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"avelocity",
|
|
"Rotate about the z axis at the specified angular velocity.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_RotateAxis
|
|
(
|
|
"rotateaxis",
|
|
EV_DEFAULT,
|
|
"if",
|
|
"axis avelocity",
|
|
"Rotate about the specified axis at the specified angular velocity.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_RotateDownTo
|
|
(
|
|
"rotatedownto",
|
|
EV_DEFAULT,
|
|
"v",
|
|
"direction",
|
|
"Rotate down to the specified direction.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_RotateUpTo
|
|
(
|
|
"rotateupto",
|
|
EV_DEFAULT,
|
|
"v",
|
|
"direction",
|
|
"Rotate up to the specified direction.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_RotateTo
|
|
(
|
|
"rotateto",
|
|
EV_DEFAULT,
|
|
"v",
|
|
"direction",
|
|
"Rotate to the specified direction.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_SetDamage
|
|
(
|
|
"setdamage",
|
|
EV_DEFAULT,
|
|
"i",
|
|
"damage",
|
|
"Set the damage.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_SetMeansOfDeath
|
|
(
|
|
"setmeansofdeath",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"means_of_death",
|
|
"Set the damage means of death.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_SetDamageSpawn
|
|
(
|
|
"dmg",
|
|
EV_DEFAULT,
|
|
"i",
|
|
"damage",
|
|
"Set the damage.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_FollowPath
|
|
(
|
|
"followpath",
|
|
EV_DEFAULT,
|
|
"eSSSSSS",
|
|
"path arg1 arg2 arg3 arg4 arg5 arg6",
|
|
"Makes the script slave follow the specified path. The allowable arguments are ignoreangles,\n"
|
|
"ignorevelocity, normalangles, loop, and a number specifying the start time.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_FollowPath_RelativeYaw
|
|
(
|
|
"path_relativeyaw",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"relativeYaw",
|
|
"Makes the script slave follow the specified path with a yaw offset,",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_EndPath
|
|
(
|
|
"endpath",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Stop following the path",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_MoveDone
|
|
(
|
|
"scriptslave_movedone",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Called when the script slave is doen moving",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_FollowingPath
|
|
(
|
|
"scriptslave_followingpath",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Called every frame to actually follow the path",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_Explode
|
|
(
|
|
"explode",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"damage",
|
|
"Creates an explosion at the script slave's position",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSlave_NotShootable
|
|
(
|
|
"notshootable",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Makes the script slave not shootable",
|
|
EV_NORMAL
|
|
);
|
|
|
|
Event EV_ScriptSlave_OpenAreaPortal
|
|
(
|
|
"openportal",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Open the area portal enclosed in this object",
|
|
EV_NORMAL
|
|
);
|
|
|
|
Event EV_ScriptSlave_CloseAreaPortal
|
|
(
|
|
"closeportal",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Close the area portal enclosed in this object",
|
|
EV_NORMAL
|
|
);
|
|
|
|
Event EV_ScriptSlave_PhysicsOn
|
|
(
|
|
"physics_on",
|
|
EV_DEFAULT,
|
|
"I",
|
|
"no_collide_entity",
|
|
"Turn physics on this script object on\n"
|
|
"If no_collide_entity is set to 1 then the script slave will not collide with other entities",
|
|
EV_NORMAL
|
|
);
|
|
|
|
Event EV_ScriptSlave_PhysicsOff
|
|
(
|
|
"physics_off",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Turn physics off this script object on",
|
|
EV_NORMAL
|
|
);
|
|
|
|
Event EV_ScriptSlave_PhysicsVelocity
|
|
(
|
|
"physics_velocity",
|
|
EV_DEFAULT,
|
|
"v",
|
|
"impulseVector",
|
|
"Add a physical impulse to an object when it is being physically simulated",
|
|
EV_NORMAL
|
|
);
|
|
|
|
Event EV_ScriptSlave_FlyPath
|
|
(
|
|
"flypath",
|
|
EV_DEFAULT,
|
|
"efff",
|
|
"array speed acceleration look_ahead",
|
|
"Makes the script slave fly the specified path with speed and acceleration until reached_distance close to "
|
|
"position",
|
|
EV_NORMAL
|
|
);
|
|
|
|
Event EV_ScriptSlave_ModifyFlyPath
|
|
(
|
|
"modifyflypath",
|
|
EV_DEFAULT,
|
|
"efff",
|
|
"array speed acceleration look_ahead",
|
|
"Makes the script slave fly the specified path with speed and acceleration until reached_distance close to "
|
|
"position",
|
|
EV_NORMAL
|
|
);
|
|
|
|
Event EV_ScriptSlave_NormalAngles
|
|
(
|
|
"normalangles",
|
|
EV_DEFAULT,
|
|
"b",
|
|
"bUseNormalAngles",
|
|
"Sets the object to use normal angles when travelling on a spline path",
|
|
EV_NORMAL
|
|
);
|
|
|
|
CLASS_DECLARATION(Mover, ScriptSlave, "script_object") {
|
|
{&EV_Bind, &ScriptSlave::BindEvent },
|
|
{&EV_Unbind, &ScriptSlave::EventUnbind },
|
|
{&EV_ScriptSlave_DoMove, &ScriptSlave::DoMove },
|
|
{&EV_ScriptSlave_WaitMove, &ScriptSlave::WaitMove },
|
|
{&EV_ScriptSlave_Angles, &ScriptSlave::SetAnglesEvent },
|
|
{&EV_SetAngle, &ScriptSlave::SetAngleEvent },
|
|
{&EV_Model, &ScriptSlave::SetModelEvent },
|
|
{&EV_ScriptSlave_Trigger, &ScriptSlave::TriggerEvent },
|
|
{&EV_ScriptSlave_Next, &ScriptSlave::GotoNextWaypoint },
|
|
{&EV_ScriptSlave_JumpTo, &ScriptSlave::JumpTo },
|
|
{&EV_ScriptSlave_MoveTo, &ScriptSlave::MoveToEvent },
|
|
{&EV_ScriptSlave_Speed, &ScriptSlave::SetSpeed },
|
|
{&EV_ScriptSlave_Time, &ScriptSlave::SetTime },
|
|
{&EV_ScriptSlave_MoveUp, &ScriptSlave::MoveUp },
|
|
{&EV_ScriptSlave_MoveDown, &ScriptSlave::MoveDown },
|
|
{&EV_ScriptSlave_MoveNorth, &ScriptSlave::MoveNorth },
|
|
{&EV_ScriptSlave_MoveSouth, &ScriptSlave::MoveSouth },
|
|
{&EV_ScriptSlave_MoveEast, &ScriptSlave::MoveEast },
|
|
{&EV_ScriptSlave_MoveWest, &ScriptSlave::MoveWest },
|
|
{&EV_ScriptSlave_MoveForward, &ScriptSlave::MoveForward },
|
|
{&EV_ScriptSlave_MoveBackward, &ScriptSlave::MoveBackward },
|
|
{&EV_ScriptSlave_MoveLeft, &ScriptSlave::MoveLeft },
|
|
{&EV_ScriptSlave_MoveRight, &ScriptSlave::MoveRight },
|
|
{&EV_ScriptSlave_RotateXDownTo, &ScriptSlave::RotateXdownto },
|
|
{&EV_ScriptSlave_RotateYDownTo, &ScriptSlave::RotateYdownto },
|
|
{&EV_ScriptSlave_RotateZDownTo, &ScriptSlave::RotateZdownto },
|
|
{&EV_ScriptSlave_RotateXUpTo, &ScriptSlave::RotateXupto },
|
|
{&EV_ScriptSlave_RotateYUpTo, &ScriptSlave::RotateYupto },
|
|
{&EV_ScriptSlave_RotateZUpTo, &ScriptSlave::RotateZupto },
|
|
{&EV_ScriptSlave_RotateXDown, &ScriptSlave::RotateXdown },
|
|
{&EV_ScriptSlave_RotateYDown, &ScriptSlave::RotateYdown },
|
|
{&EV_ScriptSlave_RotateZDown, &ScriptSlave::RotateZdown },
|
|
{&EV_ScriptSlave_RotateXUp, &ScriptSlave::RotateXup },
|
|
{&EV_ScriptSlave_RotateYUp, &ScriptSlave::RotateYup },
|
|
{&EV_ScriptSlave_RotateZUp, &ScriptSlave::RotateZup },
|
|
{&EV_ScriptSlave_RotateX, &ScriptSlave::RotateX },
|
|
{&EV_ScriptSlave_RotateY, &ScriptSlave::RotateY },
|
|
{&EV_ScriptSlave_RotateZ, &ScriptSlave::RotateZ },
|
|
{&EV_ScriptSlave_RotateAxisDownTo, &ScriptSlave::RotateAxisdownto },
|
|
{&EV_ScriptSlave_RotateAxisUpTo, &ScriptSlave::RotateAxisupto },
|
|
{&EV_ScriptSlave_RotateAxisDown, &ScriptSlave::RotateAxisdown },
|
|
{&EV_ScriptSlave_RotateAxisUp, &ScriptSlave::RotateAxisup },
|
|
{&EV_ScriptSlave_RotateAxis, &ScriptSlave::RotateZ },
|
|
{&EV_ScriptSlave_SetDamage, &ScriptSlave::SetDamage },
|
|
{&EV_ScriptSlave_SetMeansOfDeath, &ScriptSlave::SetMeansOfDeath },
|
|
{&EV_ScriptSlave_SetDamageSpawn, &ScriptSlave::SetDamage },
|
|
{&EV_ScriptSlave_FollowPath, &ScriptSlave::FollowPath },
|
|
{&EV_ScriptSlave_FollowPath_RelativeYaw, &ScriptSlave::FollowPathRelativeYaw},
|
|
{&EV_ScriptSlave_EndPath, &ScriptSlave::EndPath },
|
|
{&EV_ScriptSlave_FollowingPath, &ScriptSlave::FollowingPath },
|
|
{&EV_Touch, &ScriptSlave::TouchFunc },
|
|
{&EV_Blocked, &ScriptSlave::BlockFunc },
|
|
{&EV_Activate, &ScriptSlave::TriggerFunc },
|
|
{&EV_Use, &ScriptSlave::UseFunc },
|
|
{&EV_ScriptSlave_MoveDone, &ScriptSlave::MoveEnd },
|
|
{&EV_Damage, &ScriptSlave::DamageFunc },
|
|
{&EV_ScriptSlave_RotateDownTo, &ScriptSlave::Rotatedownto },
|
|
{&EV_ScriptSlave_RotateUpTo, &ScriptSlave::Rotateupto },
|
|
{&EV_ScriptSlave_RotateTo, &ScriptSlave::Rotateto },
|
|
{&EV_ScriptSlave_Explode, &ScriptSlave::Explode },
|
|
{&EV_ScriptSlave_NotShootable, &ScriptSlave::NotShootable },
|
|
{&EV_ScriptSlave_OpenAreaPortal, &ScriptSlave::OpenPortal },
|
|
{&EV_ScriptSlave_CloseAreaPortal, &ScriptSlave::ClosePortal },
|
|
{&EV_ScriptSlave_PhysicsOn, &ScriptSlave::PhysicsOn },
|
|
{&EV_ScriptSlave_PhysicsOff, &ScriptSlave::PhysicsOff },
|
|
{&EV_ScriptSlave_PhysicsVelocity, &ScriptSlave::PhysicsVelocity },
|
|
{&EV_ScriptSlave_FlyPath, &ScriptSlave::EventFlyPath },
|
|
{&EV_ScriptSlave_ModifyFlyPath, &ScriptSlave::EventModifyFlyPath },
|
|
{&EV_ScriptSlave_NormalAngles, &ScriptSlave::EventNormalAngles },
|
|
{NULL, NULL }
|
|
};
|
|
|
|
cvar_t *g_showflypath;
|
|
|
|
ScriptSlave::ScriptSlave()
|
|
{
|
|
g_showflypath = gi.Cvar_Get("g_showflypath", "0", 0);
|
|
|
|
AddWaitTill(STRING_TOUCH);
|
|
AddWaitTill(STRING_BLOCK);
|
|
AddWaitTill(STRING_TRIGGER);
|
|
AddWaitTill(STRING_USE);
|
|
AddWaitTill(STRING_DAMAGE);
|
|
|
|
if (LoadingSavegame) {
|
|
// Archive function will setup all necessary data
|
|
return;
|
|
}
|
|
|
|
// this is a normal entity
|
|
edict->s.eType = ET_GENERAL;
|
|
|
|
splineTime = 0;
|
|
|
|
ignoreangles = false;
|
|
ignorevelocity = false;
|
|
moving = false;
|
|
|
|
speed = 100;
|
|
takedamage = DAMAGE_YES;
|
|
waypoint = NULL;
|
|
traveltime = 0;
|
|
commandswaiting = false;
|
|
|
|
splinePath = NULL;
|
|
splineangles = false;
|
|
m_fFollowRelativeYaw = 0;
|
|
|
|
attack_finished = 0;
|
|
dmg = 2;
|
|
dmg_means_of_death = MOD_CRUSH;
|
|
|
|
setMoveType(MOVETYPE_PUSH);
|
|
|
|
if (spawnflags & 2) {
|
|
edict->s.renderfx = RF_ALWAYSDRAW;
|
|
}
|
|
|
|
setSolidType(SOLID_NOT);
|
|
|
|
m_pCurPath = NULL;
|
|
m_iCurNode = 0;
|
|
m_fCurSpeed = 0;
|
|
m_fLookAhead = 0;
|
|
m_fIdealSpeed = 0;
|
|
m_fIdealAccel = 0;
|
|
m_fIdealDistance = 100;
|
|
|
|
if (spawnflags & 1) {
|
|
PostEvent(EV_BecomeNonSolid, EV_POSTSPAWN);
|
|
}
|
|
|
|
edict->s.eFlags |= EF_LINKANGLES;
|
|
}
|
|
|
|
ScriptSlave::~ScriptSlave()
|
|
{
|
|
if (splinePath) {
|
|
delete splinePath;
|
|
splinePath = NULL;
|
|
}
|
|
}
|
|
|
|
void ScriptSlave::CheckNewOrders(void)
|
|
{
|
|
// make sure position and angles are current
|
|
if (!commandswaiting) {
|
|
commandswaiting = true;
|
|
NewAngles = localangles;
|
|
NewPos = localorigin;
|
|
}
|
|
}
|
|
|
|
void ScriptSlave::NewMove(void)
|
|
{
|
|
float dist;
|
|
|
|
CheckNewOrders();
|
|
|
|
commandswaiting = false;
|
|
|
|
if (RegisterSize(0)) {
|
|
Event ev = Event(EV_DelayThrow);
|
|
ev.AddConstString(STRING_FAIL);
|
|
BroadcastEvent(0, ev);
|
|
}
|
|
|
|
if (m_pCurPath || splinePath) {
|
|
PostEvent(EV_ScriptSlave_FollowingPath, 0);
|
|
} else {
|
|
float t = traveltime;
|
|
if (t == 0) {
|
|
dist = Vector(NewPos - localorigin).length();
|
|
t = dist / speed;
|
|
}
|
|
LinearInterpolate(NewPos, NewAngles, t, EV_ScriptSlave_MoveDone);
|
|
}
|
|
}
|
|
|
|
void ScriptSlave::BindEvent(Event *ev)
|
|
{
|
|
Entity *ent;
|
|
|
|
ent = ev->GetEntity(1);
|
|
if (ent) {
|
|
bind(ent);
|
|
}
|
|
|
|
// make sure position and angles are current
|
|
NewAngles = localangles;
|
|
NewPos = localorigin;
|
|
}
|
|
|
|
void ScriptSlave::EventUnbind(Event *ev)
|
|
{
|
|
unbind();
|
|
|
|
// make sure position and angles are current
|
|
NewAngles = localangles;
|
|
NewPos = localorigin;
|
|
}
|
|
|
|
void ScriptSlave::DoMove(Event *ev)
|
|
{
|
|
NewMove();
|
|
}
|
|
|
|
void ScriptSlave::WaitMove(Event *ev)
|
|
{
|
|
NewMove();
|
|
Register(0, Director.CurrentScriptThread());
|
|
}
|
|
|
|
void ScriptSlave::MoveEnd(Event *ev)
|
|
{
|
|
Unregister(0);
|
|
}
|
|
|
|
void ScriptSlave::SetAnglesEvent(Event *ev)
|
|
{
|
|
CheckNewOrders();
|
|
SetAngles(ev);
|
|
NewAngles = localangles;
|
|
}
|
|
|
|
void ScriptSlave::SetAngleEvent(Event *ev)
|
|
{
|
|
float angle;
|
|
|
|
angle = ev->GetFloat(1);
|
|
if (angle == -1) {
|
|
ForwardDir = Vector(0, 0, 90);
|
|
} else if (angle == -2) {
|
|
ForwardDir = Vector(0, 0, -90);
|
|
} else {
|
|
ForwardDir = Vector(0, angle, 0);
|
|
}
|
|
}
|
|
|
|
void ScriptSlave::SetModelEvent(Event *ev)
|
|
{
|
|
str m;
|
|
|
|
m = ev->GetString(1);
|
|
|
|
edict->r.svFlags &= ~SVF_NOCLIENT;
|
|
|
|
if (!m || strstr(m, ".tik")) {
|
|
setSolidType(SOLID_BBOX);
|
|
setModel(m);
|
|
if (!edict->s.modelindex) {
|
|
hideModel();
|
|
setSolidType(SOLID_NOT);
|
|
}
|
|
} else if (strstr(m, ".spr")) {
|
|
setModel(m);
|
|
if (!edict->s.modelindex) {
|
|
hideModel();
|
|
}
|
|
setSolidType(SOLID_NOT);
|
|
} else {
|
|
setModel(m);
|
|
if (edict->s.modelindex) {
|
|
setSolidType(SOLID_BSP);
|
|
} else {
|
|
hideModel();
|
|
setSolidType(SOLID_NOT);
|
|
}
|
|
}
|
|
|
|
if (!edict->s.modelindex) {
|
|
hideModel();
|
|
setSolidType(SOLID_NOT);
|
|
}
|
|
}
|
|
|
|
void ScriptSlave::TriggerEvent(Event *ev)
|
|
{
|
|
Entity *ent;
|
|
Event *e;
|
|
|
|
ent = ev->GetEntity(1);
|
|
if (ent) {
|
|
target = ent->TargetName();
|
|
|
|
e = new Event(EV_Trigger_ActivateTargets);
|
|
//fixme
|
|
//get "other"
|
|
e->AddEntity(world);
|
|
ProcessEvent(e);
|
|
}
|
|
}
|
|
|
|
void ScriptSlave::GotoNextWaypoint(Event *ev)
|
|
{
|
|
CheckNewOrders();
|
|
|
|
if (!waypoint) {
|
|
ScriptError("%s is currently not at a waypoint", TargetName().c_str());
|
|
return;
|
|
}
|
|
|
|
waypoint = (Waypoint *)G_FindTarget(NULL, waypoint->Target());
|
|
if (!waypoint) {
|
|
ScriptError("%s could not find waypoint %s", TargetName().c_str(), waypoint->Target().c_str());
|
|
return;
|
|
} else {
|
|
NewPos = waypoint->origin;
|
|
}
|
|
}
|
|
|
|
void ScriptSlave::JumpTo(Event *ev)
|
|
{
|
|
Entity *part;
|
|
|
|
//
|
|
// see if it is a vector
|
|
//
|
|
if (ev->IsVectorAt(1)) {
|
|
NewPos = ev->GetVector(1);
|
|
if (bindmaster) {
|
|
localorigin = bindmaster->getLocalVector(NewPos - bindmaster->origin);
|
|
} else {
|
|
localorigin = NewPos;
|
|
}
|
|
|
|
for (part = this; part; part = part->teamchain) {
|
|
part->setOrigin();
|
|
part->origin.copyTo(part->edict->s.origin2);
|
|
part->edict->s.renderfx |= RF_FRAMELERP;
|
|
}
|
|
} else {
|
|
waypoint = ev->GetWaypoint(1);
|
|
if (waypoint) {
|
|
NewPos = waypoint->origin;
|
|
if (bindmaster) {
|
|
localorigin = bindmaster->getLocalVector(NewPos - bindmaster->origin);
|
|
} else {
|
|
localorigin = NewPos;
|
|
}
|
|
|
|
for (part = this; part; part = part->teamchain) {
|
|
part->setOrigin();
|
|
part->origin.copyTo(part->edict->s.origin2);
|
|
part->edict->s.renderfx |= RF_FRAMELERP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ScriptSlave::MoveToEvent(Event *ev)
|
|
{
|
|
CheckNewOrders();
|
|
|
|
//
|
|
// see if it is a vector
|
|
//
|
|
if (ev->IsVectorAt(1)) {
|
|
NewPos = ev->GetVector(1);
|
|
} else {
|
|
SimpleEntity* ent;
|
|
|
|
ent = ev->GetSimpleEntity(1);
|
|
if (ent) {
|
|
//
|
|
// see if it is a waypoint
|
|
//
|
|
if (ent->IsSubclassOfWaypoint()) {
|
|
waypoint = static_cast<Waypoint*>(ent);
|
|
}
|
|
// use the entity's origin
|
|
NewPos = ent->origin;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ScriptSlave::SetSpeed(Event *ev)
|
|
{
|
|
speed = ev->GetFloat(1);
|
|
traveltime = 0;
|
|
}
|
|
|
|
void ScriptSlave::SetTime(Event *ev)
|
|
{
|
|
traveltime = ev->GetFloat(1);
|
|
}
|
|
|
|
// Relative move commands
|
|
|
|
void ScriptSlave::MoveUp(Event *ev)
|
|
{
|
|
CheckNewOrders();
|
|
NewPos[2] += ev->GetFloat(1);
|
|
}
|
|
|
|
void ScriptSlave::MoveDown(Event *ev)
|
|
{
|
|
CheckNewOrders();
|
|
NewPos[2] -= ev->GetFloat(1);
|
|
}
|
|
|
|
void ScriptSlave::MoveNorth(Event *ev)
|
|
{
|
|
CheckNewOrders();
|
|
NewPos[1] += ev->GetFloat(1);
|
|
}
|
|
|
|
void ScriptSlave::MoveSouth(Event *ev)
|
|
{
|
|
CheckNewOrders();
|
|
NewPos[1] -= ev->GetFloat(1);
|
|
}
|
|
|
|
void ScriptSlave::MoveEast(Event *ev)
|
|
{
|
|
CheckNewOrders();
|
|
NewPos[0] += ev->GetFloat(1);
|
|
}
|
|
|
|
void ScriptSlave::MoveWest(Event *ev)
|
|
{
|
|
CheckNewOrders();
|
|
NewPos[0] -= ev->GetFloat(1);
|
|
}
|
|
|
|
void ScriptSlave::MoveForward(Event *ev)
|
|
{
|
|
Vector v;
|
|
Vector t;
|
|
|
|
CheckNewOrders();
|
|
|
|
t = NewAngles + ForwardDir;
|
|
t.AngleVectorsLeft(&v, NULL, NULL);
|
|
|
|
NewPos += v * ev->GetFloat(1);
|
|
}
|
|
|
|
void ScriptSlave::MoveBackward(Event *ev)
|
|
{
|
|
Vector v;
|
|
Vector t;
|
|
|
|
CheckNewOrders();
|
|
|
|
t = NewAngles + ForwardDir;
|
|
t.AngleVectorsLeft(&v, NULL, NULL);
|
|
|
|
NewPos -= v * ev->GetFloat(1);
|
|
}
|
|
|
|
void ScriptSlave::MoveLeft(Event *ev)
|
|
{
|
|
Vector v;
|
|
Vector t;
|
|
|
|
CheckNewOrders();
|
|
|
|
t = NewAngles + ForwardDir;
|
|
t.AngleVectorsLeft(NULL, &v, NULL);
|
|
|
|
NewPos += v * ev->GetFloat(1);
|
|
}
|
|
|
|
void ScriptSlave::MoveRight(Event *ev)
|
|
{
|
|
Vector t;
|
|
Vector v;
|
|
|
|
CheckNewOrders();
|
|
|
|
t = NewAngles + ForwardDir;
|
|
t.AngleVectorsLeft(NULL, &v, NULL);
|
|
|
|
NewPos -= v * ev->GetFloat(1);
|
|
}
|
|
|
|
// exact rotate commands
|
|
|
|
void ScriptSlave::RotateXdownto(Event *ev)
|
|
{
|
|
CheckNewOrders();
|
|
|
|
NewAngles[0] = ev->GetFloat(1);
|
|
if (NewAngles[0] > localangles[0]) {
|
|
NewAngles[0] -= 360;
|
|
}
|
|
}
|
|
|
|
void ScriptSlave::RotateYdownto(Event *ev)
|
|
{
|
|
CheckNewOrders();
|
|
|
|
NewAngles[1] = ev->GetFloat(1);
|
|
if (NewAngles[1] > localangles[1]) {
|
|
NewAngles[1] -= 360;
|
|
}
|
|
}
|
|
|
|
void ScriptSlave::RotateZdownto(Event *ev)
|
|
{
|
|
CheckNewOrders();
|
|
|
|
NewAngles[2] = ev->GetFloat(1);
|
|
if (NewAngles[2] > localangles[2]) {
|
|
NewAngles[2] -= 360;
|
|
}
|
|
}
|
|
|
|
void ScriptSlave::RotateAxisdownto(Event *ev)
|
|
{
|
|
int axis;
|
|
CheckNewOrders();
|
|
|
|
axis = ev->GetInteger(1);
|
|
NewAngles[axis] = ev->GetFloat(2);
|
|
if (NewAngles[axis] > localangles[axis]) {
|
|
NewAngles[axis] -= 360;
|
|
}
|
|
}
|
|
|
|
void ScriptSlave::RotateXupto(Event *ev)
|
|
{
|
|
CheckNewOrders();
|
|
|
|
NewAngles[0] = ev->GetFloat(1);
|
|
if (NewAngles[0] < localangles[0]) {
|
|
NewAngles[0] += 360;
|
|
}
|
|
}
|
|
|
|
void ScriptSlave::RotateYupto(Event *ev)
|
|
{
|
|
CheckNewOrders();
|
|
|
|
NewAngles[1] = ev->GetFloat(1);
|
|
if (NewAngles[1] < localangles[1]) {
|
|
NewAngles[1] += 360;
|
|
}
|
|
}
|
|
|
|
void ScriptSlave::RotateZupto(Event *ev)
|
|
{
|
|
CheckNewOrders();
|
|
|
|
NewAngles[2] = ev->GetFloat(1);
|
|
if (NewAngles[2] < localangles[2]) {
|
|
NewAngles[2] += 360;
|
|
}
|
|
}
|
|
|
|
void ScriptSlave::RotateAxisupto(Event *ev)
|
|
{
|
|
int axis;
|
|
CheckNewOrders();
|
|
|
|
axis = ev->GetInteger(1);
|
|
NewAngles[axis] = ev->GetFloat(2);
|
|
if (NewAngles[axis] < localangles[axis]) {
|
|
NewAngles[axis] += 360;
|
|
}
|
|
}
|
|
|
|
// full vector rotation
|
|
|
|
void ScriptSlave::Rotatedownto(Event *ev)
|
|
{
|
|
Vector ang;
|
|
|
|
CheckNewOrders();
|
|
|
|
ang = ev->GetVector(1);
|
|
|
|
NewAngles[0] = ang[0];
|
|
if (NewAngles[0] > localangles[0]) {
|
|
NewAngles[0] -= 360;
|
|
}
|
|
NewAngles[1] = ang[1];
|
|
if (NewAngles[1] > localangles[1]) {
|
|
NewAngles[1] -= 360;
|
|
}
|
|
NewAngles[2] = ang[2];
|
|
if (NewAngles[2] > localangles[2]) {
|
|
NewAngles[2] -= 360;
|
|
}
|
|
}
|
|
|
|
void ScriptSlave::Rotateupto(Event *ev)
|
|
{
|
|
Vector ang;
|
|
|
|
CheckNewOrders();
|
|
|
|
ang = ev->GetVector(1);
|
|
|
|
NewAngles[0] = ang[0];
|
|
if (NewAngles[0] < localangles[0]) {
|
|
NewAngles[0] += 360;
|
|
}
|
|
NewAngles[1] = ang[1];
|
|
if (NewAngles[1] < localangles[1]) {
|
|
NewAngles[1] += 360;
|
|
}
|
|
NewAngles[2] = ang[2];
|
|
if (NewAngles[2] < localangles[2]) {
|
|
NewAngles[2] += 360;
|
|
}
|
|
}
|
|
|
|
void ScriptSlave::Rotateto(Event *ev)
|
|
{
|
|
Vector ang;
|
|
|
|
CheckNewOrders();
|
|
|
|
ang = ev->GetVector(1);
|
|
|
|
NewAngles = ang;
|
|
}
|
|
|
|
// Relative rotate commands
|
|
|
|
void ScriptSlave::RotateXdown(Event *ev)
|
|
{
|
|
CheckNewOrders();
|
|
NewAngles[0] = localangles[0] - ev->GetFloat(1);
|
|
}
|
|
|
|
void ScriptSlave::RotateYdown(Event *ev)
|
|
{
|
|
CheckNewOrders();
|
|
NewAngles[1] = localangles[1] - ev->GetFloat(1);
|
|
}
|
|
|
|
void ScriptSlave::RotateZdown(Event *ev)
|
|
{
|
|
CheckNewOrders();
|
|
NewAngles[2] = localangles[2] - ev->GetFloat(1);
|
|
}
|
|
|
|
void ScriptSlave::RotateAxisdown(Event *ev)
|
|
{
|
|
int axis;
|
|
CheckNewOrders();
|
|
|
|
axis = ev->GetInteger(1);
|
|
NewAngles[axis] = localangles[axis] - ev->GetFloat(2);
|
|
}
|
|
|
|
void ScriptSlave::RotateXup(Event *ev)
|
|
{
|
|
CheckNewOrders();
|
|
NewAngles[0] = localangles[0] + ev->GetFloat(1);
|
|
}
|
|
|
|
void ScriptSlave::RotateYup(Event *ev)
|
|
{
|
|
CheckNewOrders();
|
|
NewAngles[1] = localangles[1] + ev->GetFloat(1);
|
|
}
|
|
|
|
void ScriptSlave::RotateZup(Event *ev)
|
|
{
|
|
CheckNewOrders();
|
|
NewAngles[2] = localangles[2] + ev->GetFloat(1);
|
|
}
|
|
|
|
void ScriptSlave::RotateAxisup(Event *ev)
|
|
{
|
|
int axis;
|
|
CheckNewOrders();
|
|
|
|
axis = ev->GetInteger(1);
|
|
NewAngles[axis] = localangles[axis] + ev->GetFloat(2);
|
|
}
|
|
|
|
void ScriptSlave::RotateX(Event *ev)
|
|
{
|
|
avelocity[0] = ev->GetFloat(1);
|
|
}
|
|
|
|
void ScriptSlave::RotateY(Event *ev)
|
|
{
|
|
avelocity[1] = ev->GetFloat(1);
|
|
}
|
|
|
|
void ScriptSlave::RotateZ(Event *ev)
|
|
{
|
|
avelocity[2] = ev->GetFloat(1);
|
|
}
|
|
|
|
void ScriptSlave::RotateAxis(Event *ev)
|
|
{
|
|
int axis;
|
|
|
|
axis = ev->GetInteger(1);
|
|
avelocity[axis] = ev->GetFloat(2);
|
|
}
|
|
|
|
void ScriptSlave::TouchFunc(Event* ev)
|
|
{
|
|
parm.other = ev->GetEntity(1);
|
|
parm.owner = parm.other;
|
|
Unregister(STRING_TOUCH);
|
|
}
|
|
|
|
void ScriptSlave::BlockFunc(Event* ev)
|
|
{
|
|
Entity* other;
|
|
|
|
other = ev->GetEntity(1);
|
|
if (level.time >= attack_finished) {
|
|
attack_finished = level.time + 0.5;
|
|
if (dmg) {
|
|
other->Damage(this, this, dmg, origin, vec_zero, vec_zero, 0, 0, dmg_means_of_death);
|
|
}
|
|
}
|
|
|
|
parm.other = ev->GetEntity(1);
|
|
parm.owner = parm.other;
|
|
Unregister(STRING_BLOCK);
|
|
}
|
|
|
|
void ScriptSlave::TriggerFunc(Event* ev)
|
|
{
|
|
parm.other = ev->GetEntity(1);
|
|
parm.owner = parm.other;
|
|
Unregister(STRING_TRIGGER);
|
|
}
|
|
|
|
void ScriptSlave::UseFunc(Event* ev)
|
|
{
|
|
parm.other = ev->GetEntity(1);
|
|
parm.owner = parm.other;
|
|
Unregister(STRING_USE);
|
|
}
|
|
|
|
void ScriptSlave::DamageFunc(Event *ev)
|
|
{
|
|
Unregister(STRING_DAMAGE);
|
|
}
|
|
|
|
void ScriptSlave::SetDamage(Event *ev)
|
|
{
|
|
dmg = ev->GetInteger(1);
|
|
}
|
|
|
|
void ScriptSlave::SetMeansOfDeath(Event *ev)
|
|
{
|
|
dmg_means_of_death = MOD_string_to_int(ev->GetString(1));
|
|
}
|
|
|
|
void ScriptSlave::CreatePath(SplinePath *path, splinetype_t type)
|
|
{
|
|
SplinePath *node;
|
|
|
|
if (!splinePath) {
|
|
splinePath = new BSpline;
|
|
}
|
|
|
|
splinePath->Clear();
|
|
splinePath->SetType(type);
|
|
|
|
node = path;
|
|
while (node != NULL) {
|
|
splinePath->AppendControlPoint(node->origin, node->angles, node->speed);
|
|
node = node->GetNext();
|
|
|
|
if (node == path) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ScriptSlave::FollowPath(Event *ev)
|
|
{
|
|
int i, argnum;
|
|
SimpleEntity *ent;
|
|
str token;
|
|
SplinePath *path;
|
|
qboolean clamp;
|
|
float starttime;
|
|
|
|
ent = ev->GetSimpleEntity(1);
|
|
argnum = 2;
|
|
starttime = -2;
|
|
clamp = true;
|
|
ignoreangles = false;
|
|
ignorevelocity = false;
|
|
splineangles = true;
|
|
for (i = argnum; i <= ev->NumArgs(); i++) {
|
|
token = ev->GetString(i);
|
|
if (!Q_stricmp(token, "ignoreangles")) {
|
|
ignoreangles = true;
|
|
} else if (!Q_stricmp(token, "ignorevelocity")) {
|
|
ignorevelocity = true;
|
|
} else if (!Q_stricmp(token, "normalangles")) {
|
|
splineangles = false;
|
|
} else if (!Q_stricmp(token, "loop")) {
|
|
clamp = false;
|
|
} else if (IsNumeric(token)) {
|
|
starttime = atof(token);
|
|
// Fixed in OPM
|
|
// HACKHACK
|
|
//
|
|
// There is a bug in mohaa where the token's raw pointer is directly used
|
|
// but then the token can be freed before comparison, which cause
|
|
// starttime to be always 0.
|
|
// OPM is correct here but for compatibility purpose the bug have to be reproduced.
|
|
// Otherwise, for example the final bomber plane in t3l2 will not fly.
|
|
if (!ev->IsStringAt(i)) {
|
|
starttime = 0;
|
|
}
|
|
} else {
|
|
ScriptError("Unknown followpath command %s.", token.c_str());
|
|
}
|
|
}
|
|
|
|
if (ent && ent->IsSubclassOfSplinePath()) {
|
|
path = (SplinePath *)ent;
|
|
if (clamp) {
|
|
CreatePath(path, SPLINE_CLAMP);
|
|
} else {
|
|
CreatePath(path, SPLINE_LOOP);
|
|
}
|
|
splineTime = starttime;
|
|
CancelEventsOfType(EV_ScriptSlave_FollowingPath);
|
|
if (!ignoreangles) {
|
|
avelocity = vec_zero;
|
|
}
|
|
if (!ignorevelocity) {
|
|
velocity = vec_zero;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ScriptSlave::FollowPathRelativeYaw(Event *ev)
|
|
{
|
|
m_fFollowRelativeYaw = ev->GetFloat(1);
|
|
}
|
|
|
|
void ScriptSlave::EndPath(Event *ev)
|
|
{
|
|
if (!splinePath) {
|
|
return;
|
|
}
|
|
|
|
delete splinePath;
|
|
splinePath = NULL;
|
|
if (!ignorevelocity) {
|
|
velocity = vec_zero;
|
|
}
|
|
if (!ignoreangles) {
|
|
avelocity = vec_zero;
|
|
}
|
|
}
|
|
|
|
void ScriptSlave::FollowingPath(Event *ev)
|
|
{
|
|
Vector pos;
|
|
Vector orient;
|
|
float speed_multiplier;
|
|
|
|
if (m_pCurPath && m_pCurPath->m_iPoints) {
|
|
Vector vAngles;
|
|
Vector vDeltaAngles;
|
|
Vector vDelta;
|
|
float *vTmp;
|
|
Vector vPrev;
|
|
Vector vCur;
|
|
Vector vTotal;
|
|
float fCoef;
|
|
Vector vWishPosition;
|
|
Vector vWishAngles;
|
|
Vector vNextWishAngles;
|
|
Vector primal_angles;
|
|
Vector n_angles;
|
|
|
|
if (g_showflypath && g_showflypath->integer) {
|
|
for (int i = 0; i < m_pCurPath->m_iPoints; i++) {
|
|
vTmp = m_pCurPath->GetByNode(i, NULL);
|
|
VectorCopy((vTmp + 1), vCur);
|
|
|
|
G_DebugBBox(vCur, Vector(-32, -32, -32), Vector(32, 32, 32), 0, 1, 1, 1);
|
|
|
|
for (int ii = 0; ii <= 8; ii++) {
|
|
vTmp = m_pCurPath->GetByNode(i + ii / 10.0, NULL);
|
|
VectorCopy((vTmp + 1), vPrev);
|
|
vTmp = m_pCurPath->GetByNode(i + ii / 10.0 + m_fLookAhead, NULL);
|
|
VectorCopy((vTmp + 1), vCur);
|
|
|
|
G_DebugLine(vPrev, vCur, 0, 1, 0, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_iCurNode > 0) {
|
|
// Get previous node
|
|
vTmp = m_pCurPath->GetByNode(m_iCurNode - 1, NULL);
|
|
vPrev = (vTmp + 1);
|
|
// Get current node
|
|
vTmp = m_pCurPath->GetByNode(m_iCurNode, NULL);
|
|
vCur = (vTmp + 1);
|
|
|
|
vDelta = vCur - vPrev;
|
|
m_vIdealDir = vDelta;
|
|
VectorNormalize(m_vIdealDir);
|
|
angles.AngleVectorsLeft(&vWishAngles);
|
|
|
|
fCoef = ProjectLineOnPlane(vWishAngles, DotProduct(origin, vWishAngles), vPrev, vCur, NULL);
|
|
|
|
vTmp = m_pCurPath->GetByNode(m_iCurNode - (1.0 - fCoef), NULL);
|
|
vTmp = m_pCurPath->Get(vTmp[0] + m_fLookAhead, NULL);
|
|
vWishPosition = (vTmp + 1);
|
|
|
|
if (fCoef > 1.0f) {
|
|
m_iCurNode++;
|
|
|
|
if (m_iCurNode >= m_pCurPath->m_iPoints) {
|
|
velocity = vec_zero;
|
|
avelocity = vec_zero;
|
|
|
|
delete m_pCurPath;
|
|
m_pCurPath = NULL;
|
|
m_iCurNode = 0;
|
|
moving = false;
|
|
|
|
ProcessEvent(EV_ScriptSlave_MoveDone);
|
|
return;
|
|
}
|
|
}
|
|
} else {
|
|
vTmp = m_pCurPath->GetByNode(m_iCurNode, NULL);
|
|
vWishPosition = (vTmp + 1);
|
|
vDelta = vWishPosition - origin;
|
|
|
|
if (vDelta.length() <= 32.0f) {
|
|
m_iCurNode++;
|
|
|
|
if (m_iCurNode >= m_pCurPath->m_iPoints) {
|
|
velocity = vec_zero;
|
|
avelocity = vec_zero;
|
|
|
|
delete m_pCurPath;
|
|
m_pCurPath = NULL;
|
|
m_iCurNode = 0;
|
|
moving = false;
|
|
ProcessEvent(EV_ScriptSlave_MoveDone);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
vDelta = vWishPosition - origin;
|
|
|
|
if (vDelta.length() > 0.0f) {
|
|
vDelta.normalize();
|
|
VectorToAngles(vDelta, vNextWishAngles);
|
|
|
|
//
|
|
// Added in 2.0
|
|
// Relative yaw
|
|
vNextWishAngles[1] += m_fFollowRelativeYaw;
|
|
if (m_fFollowRelativeYaw == 180) {
|
|
vNextWishAngles[0] *= -1;
|
|
}
|
|
} else {
|
|
vNextWishAngles = angles;
|
|
AngleVectorsLeft(angles, vDelta, NULL, NULL);
|
|
}
|
|
|
|
vAngles = angles;
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
float change, error;
|
|
|
|
n_angles[i] = vNextWishAngles[i] - angles[i];
|
|
|
|
if (n_angles[i] > 180) {
|
|
n_angles[i] -= 360;
|
|
} else if (n_angles[i] < -180) {
|
|
n_angles[i] += 360;
|
|
}
|
|
|
|
change = level.frametime * 360.0f;
|
|
error = 0.33f * n_angles[i];
|
|
|
|
if (error < -change) {
|
|
error = -change;
|
|
} else if (error > change) {
|
|
error = change;
|
|
}
|
|
|
|
primal_angles[i] = angles[i] + error;
|
|
}
|
|
|
|
setAngles(primal_angles);
|
|
|
|
vDeltaAngles = (angles - vAngles) * level.frametime;
|
|
|
|
if (vDeltaAngles[0] > 180.0f || vDeltaAngles[0] <= -180.0f) {
|
|
vDeltaAngles[0] = 0.0f;
|
|
}
|
|
|
|
if (vDeltaAngles[1] > 180.0f || vDeltaAngles[1] <= -180.0f) {
|
|
vDeltaAngles[1] = 0.0f;
|
|
}
|
|
|
|
if (vDeltaAngles[2] > 180.0f || vDeltaAngles[2] <= -180.0f) {
|
|
vDeltaAngles[2] = 0.0f;
|
|
}
|
|
|
|
if (vDeltaAngles[0] > -1.0f || vDeltaAngles[0] < 1.0f) {
|
|
vDeltaAngles[0] = 0.0f;
|
|
}
|
|
|
|
if (vDeltaAngles[1] > -1.0f || vDeltaAngles[1] < 1.0f) {
|
|
vDeltaAngles[1] = 0.0f;
|
|
}
|
|
|
|
if (vDeltaAngles[2] > -1.0f || vDeltaAngles[2] < 1.0f) {
|
|
vDeltaAngles[2] = 0.0f;
|
|
}
|
|
|
|
avelocity = vDeltaAngles;
|
|
velocity = vDelta * m_fCurSpeed;
|
|
|
|
if (m_fIdealSpeed > m_fCurSpeed) {
|
|
m_fCurSpeed += m_fIdealAccel * level.frametime;
|
|
|
|
if (m_fCurSpeed > m_fIdealSpeed) {
|
|
m_fCurSpeed = m_fIdealSpeed;
|
|
}
|
|
} else if (m_fIdealSpeed < m_fCurSpeed) {
|
|
m_fCurSpeed -= m_fIdealAccel * level.frametime;
|
|
|
|
if (m_fCurSpeed < m_fIdealSpeed) {
|
|
m_fCurSpeed = m_fIdealSpeed;
|
|
}
|
|
}
|
|
} else {
|
|
if (!splinePath) {
|
|
return;
|
|
}
|
|
|
|
if ((splinePath->GetType() == SPLINE_CLAMP) && (splineTime > (splinePath->EndPoint() - 2))) {
|
|
delete splinePath;
|
|
splinePath = NULL;
|
|
if (!ignorevelocity) {
|
|
velocity = vec_zero;
|
|
}
|
|
if (!ignoreangles) {
|
|
avelocity = vec_zero;
|
|
}
|
|
moving = false;
|
|
ProcessEvent(EV_ScriptSlave_MoveDone);
|
|
return;
|
|
}
|
|
|
|
speed_multiplier = splinePath->Eval(splineTime, pos, orient);
|
|
|
|
splineTime += level.frametime * speed_multiplier;
|
|
|
|
velocity = (pos - origin) * (1 / level.frametime);
|
|
if (!ignoreangles) {
|
|
if (splineangles) {
|
|
avelocity = (orient - angles) * (1 / level.frametime);
|
|
} else {
|
|
float len;
|
|
|
|
len = velocity.length();
|
|
if (len > 0.05) {
|
|
Vector ang;
|
|
Vector dir;
|
|
float aroll;
|
|
|
|
aroll = avelocity[ROLL];
|
|
dir = velocity * (1 / len);
|
|
ang = dir.toAngles();
|
|
avelocity = (ang - angles) * (1 / level.frametime);
|
|
avelocity[ROLL] = aroll;
|
|
} else {
|
|
avelocity = vec_zero;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
PostEvent(EV_ScriptSlave_FollowingPath, level.frametime);
|
|
}
|
|
|
|
void ScriptSlave::Explode(Event *ev)
|
|
{
|
|
float damage;
|
|
|
|
if (ev->NumArgs()) {
|
|
damage = ev->GetFloat(1);
|
|
} else {
|
|
damage = 120.0f;
|
|
}
|
|
|
|
CreateExplosion(origin, damage, this, this, this);
|
|
}
|
|
|
|
void ScriptSlave::NotShootable(Event *ev)
|
|
{
|
|
setContents(0);
|
|
}
|
|
|
|
void ScriptSlave::OpenPortal(Event *ev)
|
|
{
|
|
gi.AdjustAreaPortalState(this->edict, true);
|
|
}
|
|
|
|
void ScriptSlave::ClosePortal(Event *ev)
|
|
{
|
|
gi.AdjustAreaPortalState(this->edict, false);
|
|
}
|
|
|
|
void ScriptSlave::PhysicsOn(Event *ev)
|
|
{
|
|
commandswaiting = false;
|
|
setMoveType(MOVETYPE_BOUNCE);
|
|
setSolidType(SOLID_BBOX);
|
|
velocity = Vector(0, 0, 1);
|
|
edict->clipmask = MASK_SOLID | CONTENTS_BODY;
|
|
if (ev->NumArgs() == 1 && ev->GetInteger(1)) {
|
|
edict->clipmask &= ~MASK_SCRIPT_SLAVE;
|
|
}
|
|
}
|
|
|
|
void ScriptSlave::PhysicsOff(Event *ev)
|
|
{
|
|
Event *event;
|
|
|
|
commandswaiting = false;
|
|
setMoveType(MOVETYPE_PUSH);
|
|
edict->clipmask = 0;
|
|
// become solid again
|
|
event = new Event(EV_Model);
|
|
event->AddString(model);
|
|
PostEvent(event, 0);
|
|
}
|
|
|
|
void ScriptSlave::PhysicsVelocity(Event *ev)
|
|
{
|
|
velocity += ev->GetVector(1);
|
|
}
|
|
|
|
void ScriptSlave::EventFlyPath(Event *ev)
|
|
{
|
|
SimpleEntity *path;
|
|
|
|
m_fIdealDistance = 100.0f;
|
|
m_fLookAhead = 256.0f;
|
|
m_fIdealAccel = 35.0f;
|
|
m_fIdealSpeed = 250.0f;
|
|
|
|
if (ev->NumArgs() != 1 && ev->NumArgs() != 2 && ev->NumArgs() != 3 && ev->NumArgs() != 4) {
|
|
ScriptError("wrong number of arguments");
|
|
}
|
|
|
|
if (ev->NumArgs() > 1) {
|
|
m_fIdealSpeed = ev->GetFloat(2);
|
|
}
|
|
|
|
if (ev->NumArgs() > 2) {
|
|
m_fIdealAccel = ev->GetFloat(3);
|
|
}
|
|
|
|
if (ev->NumArgs() > 3) {
|
|
m_fLookAhead = ev->GetFloat(4);
|
|
}
|
|
|
|
path = ev->GetSimpleEntity(1);
|
|
|
|
if (!path) {
|
|
ScriptError("ScriptSlave Given FlyPath Command with NULL path.");
|
|
}
|
|
|
|
if (m_pCurPath) {
|
|
delete m_pCurPath;
|
|
}
|
|
|
|
m_pCurPath = new cSpline<4, 512>;
|
|
|
|
SetupPath(m_pCurPath, path);
|
|
m_iCurNode = 0;
|
|
CancelEventsOfType(EV_ScriptSlave_FollowingPath);
|
|
}
|
|
|
|
void ScriptSlave::EventModifyFlyPath(Event *ev)
|
|
{
|
|
m_fIdealDistance = 100.0f;
|
|
|
|
if (ev->NumArgs() != 1 && ev->NumArgs() != 2 && ev->NumArgs() != 3) {
|
|
ScriptError("wrong number of arguments");
|
|
}
|
|
|
|
if (ev->NumArgs() > 0) {
|
|
m_fIdealSpeed = ev->GetFloat(1);
|
|
}
|
|
|
|
if (ev->NumArgs() > 1) {
|
|
m_fIdealAccel = ev->GetFloat(2);
|
|
}
|
|
|
|
if (ev->NumArgs() > 2) {
|
|
m_fLookAhead = ev->GetFloat(3);
|
|
}
|
|
}
|
|
|
|
void ScriptSlave::EventNormalAngles(Event *ev)
|
|
{
|
|
splineangles = !ev->GetBoolean(1);
|
|
ignoreangles = false;
|
|
}
|
|
|
|
void ScriptSlave::SetupPath(cSpline<4, 512> *pPath, SimpleEntity *se)
|
|
{
|
|
str name;
|
|
int iObjNum = 0;
|
|
Vector vLastOrigin;
|
|
SimpleEntity *ent;
|
|
int i = 1;
|
|
static cSpline<4, 512> *pTmpPath = new cSpline<4, 512>;
|
|
|
|
if (!pPath) {
|
|
return;
|
|
}
|
|
|
|
pPath->Reset();
|
|
pTmpPath->Reset();
|
|
|
|
vLastOrigin = se->origin;
|
|
|
|
name = se->Target();
|
|
|
|
if (name.length()) {
|
|
for(ent = se; ent; ent = ent->Next()) {
|
|
Vector vDelta;
|
|
vec4_t vTmp;
|
|
|
|
vDelta = vLastOrigin - ent->origin;
|
|
|
|
if (vDelta.length() == 0 && i > 1) {
|
|
Com_Printf("^~^~^Warning: ScriptSlave Flying with a Path that contains 2 equal points\n");
|
|
} else {
|
|
vTmp[0] = iObjNum++;
|
|
vTmp[1] = ent->origin[0];
|
|
vTmp[2] = ent->origin[1];
|
|
vTmp[3] = ent->origin[2];
|
|
pTmpPath->Add(vTmp, 0);
|
|
vLastOrigin = ent->origin;
|
|
}
|
|
|
|
if (ent == se && i > 1) {
|
|
break;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (pTmpPath->m_iPoints > 2) {
|
|
float* vTmp;
|
|
float fCurLength = 0;
|
|
vec3_t vLastOrigin;
|
|
vec3_t origin;
|
|
vec3_t vDelta;
|
|
|
|
pPath->Reset();
|
|
|
|
vTmp = pTmpPath->GetByNode(0, NULL);
|
|
VectorCopy((vTmp + 1), vLastOrigin);
|
|
VectorCopy((vTmp + 1), origin);
|
|
|
|
for (i = 0; i < pTmpPath->m_iPoints; i++) {
|
|
vec4_t vTmp2;
|
|
|
|
vTmp = pTmpPath->GetByNode(i, NULL);
|
|
|
|
VectorCopy((vTmp + 1), vLastOrigin);
|
|
VectorSubtract(vLastOrigin, origin, vDelta);
|
|
|
|
fCurLength += VectorLength(vDelta);
|
|
vTmp2[0] = fCurLength;
|
|
vTmp2[1] = vLastOrigin[0];
|
|
vTmp2[2] = vLastOrigin[1];
|
|
vTmp2[3] = vLastOrigin[2];
|
|
|
|
pPath->Add(vTmp2, 0);
|
|
VectorCopy(vLastOrigin, origin);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*QUAKED script_model (0 0.5 1) (0 0 0) (0 0 0) NOT_SOLID
|
|
|
|
******************************************************************************/
|
|
|
|
Event EV_ScriptModel_SetAnim
|
|
(
|
|
"anim",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"anim_name",
|
|
"Sets the script model's animation",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptModel_AnimDone
|
|
(
|
|
"animdone",
|
|
EV_ZERO,
|
|
NULL,
|
|
NULL,
|
|
"Script model animation has finished.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptModel_MoveAnim
|
|
(
|
|
"moveanim",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"animName",
|
|
"Makes the script model play an animation and move with the deltas contained in the animation",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptModel_MovingAnim
|
|
(
|
|
"moving_from_anim",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"The script model is moving based on an animation",
|
|
EV_NORMAL
|
|
);
|
|
|
|
CLASS_DECLARATION(ScriptSlave, ScriptModel, "script_model") {
|
|
{&EV_SetAngle, &ScriptModel::SetAngleEvent },
|
|
{&EV_ScriptModel_SetAnim, &ScriptModel::SetAnimEvent },
|
|
{&EV_Model, &ScriptModel::SetModelEvent },
|
|
{&EV_ScriptModel_AnimDone, &ScriptModel::AnimDoneEvent },
|
|
{&EV_ScriptModel_MoveAnim, &ScriptModel::MoveAnimEvent },
|
|
{&EV_ScriptModel_MovingAnim, &ScriptModel::MovingFromAnimEvent},
|
|
{NULL, NULL },
|
|
};
|
|
|
|
ScriptModel::ScriptModel()
|
|
{
|
|
// this is a tiki model
|
|
edict->s.eType = ET_MODELANIM;
|
|
|
|
AddWaitTill(STRING_ANIMDONE);
|
|
}
|
|
|
|
void ScriptModel::SetModelEvent(Event *ev)
|
|
{
|
|
ScriptSlave::SetModelEvent(ev);
|
|
|
|
if (edict->tiki && !mins.length() && !maxs.length()) {
|
|
gi.TIKI_CalculateBounds(edict->tiki, edict->s.scale, mins, maxs);
|
|
}
|
|
}
|
|
|
|
void ScriptModel::SetAnimEvent(Event *ev)
|
|
{
|
|
str animname;
|
|
|
|
animname = ev->GetString(1);
|
|
if (animname.length() && edict->tiki) {
|
|
int animnum;
|
|
|
|
animnum = gi.Anim_NumForName(edict->tiki, animname);
|
|
if (animnum >= 0) {
|
|
NewAnim(animnum, EV_ScriptModel_AnimDone);
|
|
RestartAnimSlot(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ScriptModel::AnimDoneEvent(Event *ev)
|
|
{
|
|
CancelEventsOfType(EV_ScriptModel_MovingAnim);
|
|
Unregister(STRING_ANIMDONE);
|
|
}
|
|
|
|
void ScriptModel::MoveAnimEvent(Event *ev)
|
|
{
|
|
str animName;
|
|
int animNum;
|
|
|
|
animName = ev->GetString(1);
|
|
|
|
if (!animName.length()) {
|
|
return;
|
|
}
|
|
|
|
animNum = gi.Anim_NumForName(edict->tiki, animName.c_str());
|
|
if (animNum < 0) {
|
|
ScriptError("ScriptModel could not find animation %s.", animName.c_str());
|
|
}
|
|
|
|
NewAnim(animNum, EV_ScriptModel_AnimDone);
|
|
RestartAnimSlot(0);
|
|
PostEvent(EV_ScriptModel_MovingAnim, 0);
|
|
}
|
|
|
|
void ScriptModel::MovingFromAnimEvent(Event *ev)
|
|
{
|
|
Vector newOrigin;
|
|
Vector newAngles;
|
|
|
|
// calculate velocity
|
|
newOrigin = origin + frame_delta;
|
|
velocity = (newOrigin - origin) / level.frametime;
|
|
|
|
// calculate angular velocity
|
|
newAngles = angles + Vector(0, angular_delta, 0);
|
|
avelocity = (newAngles - angles) / level.frametime;
|
|
|
|
PostEvent(EV_ScriptModel_MovingAnim, level.frametime);
|
|
}
|
|
|
|
void ScriptModel::SetAngleEvent(Event *ev)
|
|
{
|
|
float angle;
|
|
|
|
angle = ev->GetFloat(1);
|
|
if (angle == -1) {
|
|
ForwardDir = Vector(0, 0, 90);
|
|
localangles = Vector(-90, 0, 0);
|
|
} else if (angle == -2) {
|
|
ForwardDir = Vector(0, 0, -90);
|
|
localangles = Vector(90, 0, 0);
|
|
} else {
|
|
ForwardDir = Vector(0, angle, 0);
|
|
localangles = Vector(0, angle, 0);
|
|
}
|
|
|
|
setAngles(localangles);
|
|
}
|
|
|
|
void ScriptModel::GibEvent(Event *ev)
|
|
{
|
|
int num, power;
|
|
float scale;
|
|
|
|
setSolidType(SOLID_NOT);
|
|
hideModel();
|
|
|
|
if (!com_blood->integer) {
|
|
PostEvent(EV_Remove, 0);
|
|
return;
|
|
}
|
|
|
|
num = ev->GetInteger(1);
|
|
power = ev->GetInteger(2);
|
|
scale = ev->GetFloat(3);
|
|
|
|
power = -power;
|
|
|
|
if (ev->NumArgs() > 3) {
|
|
CreateGibs(this, power, scale, num, ev->GetString(4));
|
|
} else {
|
|
CreateGibs(this, power, scale, num);
|
|
}
|
|
|
|
PostEvent(EV_Remove, 0);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*QUAKED script_model_realdamage (0 0.5 1) (0 0 0) (0 0 0) NOT_SOLID ALWAYS_DRAW
|
|
|
|
******************************************************************************/
|
|
/*****************************************************************************/
|
|
|
|
CLASS_DECLARATION(ScriptModel, ScriptModelRealDamage, "script_model_realdamage") {
|
|
{&EV_Damage, &ScriptModelRealDamage::EventDamage},
|
|
{NULL, NULL }
|
|
};
|
|
|
|
ScriptModelRealDamage::ScriptModelRealDamage()
|
|
{
|
|
RemoveWaitTill(STRING_DAMAGE);
|
|
}
|
|
|
|
void ScriptModelRealDamage::EventDamage(Event *ev)
|
|
{
|
|
Entity::DamageEvent(ev);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*QUAKED script_origin (1.0 0 0) (-8 -8 -8) (8 8 8)
|
|
|
|
Used as an alternate origin for objects. Bind the object to the script_origin
|
|
in order to simulate changing that object's origin.
|
|
******************************************************************************/
|
|
|
|
// Added in 2.30
|
|
Event EV_ScriptOrigin_SetAngle
|
|
(
|
|
"angle",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"newAngle",
|
|
"set the angles of the entity using just one value.\n"
|
|
"Sets the yaw of the entity or an up and down\n"
|
|
"direction if newAngle is [0-359] or -1 or -2"
|
|
);
|
|
|
|
// Added in 2.30
|
|
Event EV_ScriptOrigin_GetAngle
|
|
(
|
|
"angle",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"get the angles of the entity using just one value.\n"
|
|
"Gets the yaw of the entity or an up and down\n"
|
|
"direction if newAngle is [0-359] or -1 or -2",
|
|
EV_GETTER
|
|
);
|
|
|
|
CLASS_DECLARATION(ScriptSlave, ScriptOrigin, "script_origin") {
|
|
{&EV_Model, &ScriptOrigin::SetModelEvent},
|
|
|
|
//
|
|
// Added in 2.30
|
|
//
|
|
{&EV_ScriptOrigin_SetAngle, &ScriptOrigin::SetAngleEvent},
|
|
{&EV_ScriptOrigin_GetAngle, &ScriptOrigin::GetAngleEvent},
|
|
{NULL, NULL }
|
|
};
|
|
|
|
ScriptOrigin::ScriptOrigin()
|
|
{
|
|
setContents(0);
|
|
setSolidType(SOLID_NOT);
|
|
}
|
|
|
|
void ScriptOrigin::SetAngleEvent(Event* ev)
|
|
{
|
|
float angle;
|
|
|
|
if (g_target_game < target_game_e::TG_MOHTT) {
|
|
// Restore the old behavior on previous versions (below 2.30).
|
|
// For example, higgins rangers in m3l1a would not face forward
|
|
return ScriptSlave::SetAngleEvent(ev);
|
|
}
|
|
|
|
angle = ev->GetFloat(1);
|
|
if (angle == -1) {
|
|
ForwardDir = Vector(0, 0, 90);
|
|
localangles = Vector(-90, 0, 0);
|
|
} else if (angle == -2) {
|
|
ForwardDir = Vector(0, 0, -90);
|
|
localangles = Vector(90, 0, 0);
|
|
} else {
|
|
ForwardDir = Vector(0, angle, 0);
|
|
localangles = Vector(0, angle, 0);
|
|
}
|
|
|
|
setAngles(localangles);
|
|
}
|
|
|
|
void ScriptOrigin::GetAngleEvent(Event* ev)
|
|
{
|
|
Vector forward;
|
|
|
|
angles.AngleVectorsLeft(&forward);
|
|
ev->AddFloat(G_GetAngle(forward));
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*QUAKED script_skyorigin (1.0 0 0) ?
|
|
|
|
Used to specify the origin of a portal sky
|
|
******************************************************************************/
|
|
|
|
CLASS_DECLARATION(ScriptSlave, ScriptSkyOrigin, "script_skyorigin") {
|
|
{NULL, NULL}
|
|
};
|
|
|
|
ScriptSkyOrigin::ScriptSkyOrigin()
|
|
{
|
|
edict->s.renderfx |= RF_SKYORIGIN;
|
|
edict->r.svFlags &= ~SVF_NOCLIENT;
|
|
setContents(0);
|
|
setSolidType(SOLID_NOT);
|
|
}
|
|
|
|
Event EV_ScriptSimpleStrafingGunfire_On
|
|
(
|
|
"on",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Turn the gunfire on.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSimpleStrafingGunfire_Off
|
|
(
|
|
"off",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Turn the gunfire off.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSimpleStrafingGunfire_Fire
|
|
(
|
|
"fire",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Fire.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSimpleStrafingGunfire_TracerFreq
|
|
(
|
|
"tracerfreq",
|
|
EV_DEFAULT,
|
|
"f",
|
|
NULL,
|
|
"Set the frequency of the tracers",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ScriptSimpleStrafingGunfire_ProjectileModel
|
|
(
|
|
"projectile",
|
|
EV_DEFAULT,
|
|
"s",
|
|
NULL,
|
|
"Set the projectile model",
|
|
EV_NORMAL
|
|
);
|
|
|
|
CLASS_DECLARATION(ScriptSlave, ScriptSimpleStrafingGunfire, "script_simplestrafinggunfire") {
|
|
{&EV_ScriptSimpleStrafingGunfire_On, &ScriptSimpleStrafingGunfire::GunOn },
|
|
{&EV_ScriptSimpleStrafingGunfire_Off, &ScriptSimpleStrafingGunfire::GunOff },
|
|
{&EV_ScriptSimpleStrafingGunfire_Fire, &ScriptSimpleStrafingGunfire::GunFire },
|
|
{&EV_Weapon_FireDelay, &ScriptSimpleStrafingGunfire::SetFireDelay },
|
|
{&EV_Weapon_SetBulletRange, &ScriptSimpleStrafingGunfire::SetRange },
|
|
{&EV_Weapon_SetBulletSpread, &ScriptSimpleStrafingGunfire::SetSpread },
|
|
{&EV_Weapon_SetBulletDamage, &ScriptSimpleStrafingGunfire::SetDamage },
|
|
{&EV_Weapon_SetBulletKnockback, &ScriptSimpleStrafingGunfire::SetKnockback },
|
|
{&EV_Weapon_SetBulletThroughWood, &ScriptSimpleStrafingGunfire::SetThroughWood },
|
|
{&EV_Weapon_SetBulletThroughMetal, &ScriptSimpleStrafingGunfire::SetThroughMetal },
|
|
{&EV_Weapon_SetBulletCount, &ScriptSimpleStrafingGunfire::SetBulletCount },
|
|
{&EV_ScriptSimpleStrafingGunfire_TracerFreq, &ScriptSimpleStrafingGunfire::SetTracerFreq },
|
|
{&EV_ScriptSimpleStrafingGunfire_ProjectileModel, &ScriptSimpleStrafingGunfire::SetProjectileModel},
|
|
{NULL, NULL }
|
|
};
|
|
|
|
ScriptSimpleStrafingGunfire::ScriptSimpleStrafingGunfire()
|
|
{
|
|
isOn = false;
|
|
fireDelay = 0.05f;
|
|
range = 4000;
|
|
spread = Vector(100, 100, 0);
|
|
damage = 100;
|
|
knockback = 0;
|
|
throughWood = 0;
|
|
throughMetal = 0;
|
|
bulletCount = 1;
|
|
tracerCount = 0;
|
|
tracerFrequency = 0;
|
|
projectileModel = "models/projectiles/stukaround.tik";
|
|
}
|
|
|
|
void ScriptSimpleStrafingGunfire::GunOn(Event *ev)
|
|
{
|
|
isOn = true;
|
|
|
|
CancelEventsOfType(&EV_ScriptSimpleStrafingGunfire_Fire);
|
|
PostEvent(EV_ScriptSimpleStrafingGunfire_Fire, 0.05f);
|
|
}
|
|
|
|
void ScriptSimpleStrafingGunfire::GunOff(Event *ev)
|
|
{
|
|
isOn = false;
|
|
|
|
CancelEventsOfType(&EV_ScriptSimpleStrafingGunfire_Fire);
|
|
}
|
|
|
|
void ScriptSimpleStrafingGunfire::GunFire(Event *ev)
|
|
{
|
|
Vector dir, right, up;
|
|
Vector horzAngles;
|
|
|
|
AngleVectors(angles, NULL, NULL, up);
|
|
dir = -1 * up;
|
|
|
|
VectorToAngles(dir, horzAngles);
|
|
AngleVectors(horzAngles, NULL, right, up);
|
|
|
|
dir = dir * range + right * grandom() * spread.x;
|
|
dir += up * grandom() * spread.y;
|
|
dir.normalize();
|
|
|
|
ProjectileAttack(origin, dir, this, projectileModel, 1, 0, NULL);
|
|
// continue firing
|
|
PostEvent(EV_ScriptSimpleStrafingGunfire_Fire, fireDelay);
|
|
}
|
|
|
|
void ScriptSimpleStrafingGunfire::Archive(Archiver& arc)
|
|
{
|
|
ScriptSlave::Archive(arc);
|
|
|
|
arc.ArchiveBoolean(&isOn);
|
|
arc.ArchiveFloat(&fireDelay);
|
|
arc.ArchiveFloat(&range);
|
|
arc.ArchiveVector(&spread);
|
|
arc.ArchiveFloat(&damage);
|
|
arc.ArchiveFloat(&knockback);
|
|
arc.ArchiveFloat(&throughWood);
|
|
arc.ArchiveFloat(&throughMetal);
|
|
arc.ArchiveInteger(&bulletCount);
|
|
arc.ArchiveInteger(&tracerCount);
|
|
arc.ArchiveInteger(&tracerFrequency);
|
|
arc.ArchiveString(&projectileModel);
|
|
}
|
|
|
|
Event EV_ScriptAimedStrafingGunfire_AimTarget
|
|
(
|
|
"aimtarget",
|
|
EV_DEFAULT,
|
|
"e",
|
|
NULL,
|
|
"Set the aim target.",
|
|
EV_NORMAL
|
|
);
|
|
|
|
CLASS_DECLARATION(ScriptSimpleStrafingGunfire, ScriptAimedStrafingGunfire, "script_aimedstrafinggunfire") {
|
|
{&EV_ScriptAimedStrafingGunfire_AimTarget, &ScriptAimedStrafingGunfire::SetAimTarget},
|
|
{&EV_ScriptSimpleStrafingGunfire_Fire, &ScriptAimedStrafingGunfire::GunFire },
|
|
{NULL, NULL }
|
|
};
|
|
|
|
ScriptAimedStrafingGunfire::ScriptAimedStrafingGunfire()
|
|
{
|
|
aimTarget = NULL;
|
|
}
|
|
|
|
void ScriptAimedStrafingGunfire::GunFire(Event *ev)
|
|
{
|
|
if (!aimTarget) {
|
|
ScriptSimpleStrafingGunfire::GunFire(ev);
|
|
return;
|
|
}
|
|
|
|
Vector dir, right, up;
|
|
Vector horzAngles;
|
|
|
|
dir = aimTarget->origin - origin;
|
|
dir.normalize();
|
|
|
|
VectorToAngles(dir, horzAngles);
|
|
AngleVectors(horzAngles, NULL, right, up);
|
|
|
|
dir = dir * range + right * grandom() * spread.x;
|
|
dir += up * grandom() * spread.y;
|
|
dir.normalize();
|
|
|
|
ProjectileAttack(origin, dir, this, projectileModel, 1, 0, NULL);
|
|
// continue firing
|
|
PostEvent(EV_ScriptSimpleStrafingGunfire_Fire, fireDelay);
|
|
}
|
|
|
|
void ScriptAimedStrafingGunfire::Archive(Archiver& arc)
|
|
{
|
|
ScriptSimpleStrafingGunfire::Archive(arc);
|
|
|
|
arc.ArchiveObjectPointer((Class **)&aimTarget);
|
|
}
|