/* =========================================================================== 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 =========================================================================== */ #include "scriptthread.h" #include "scriptmaster.h" #include "scriptclass.h" #include "scriptvariable.h" #include "scriptexception.h" #include "g_spawn.h" #include "level.h" #include "game.h" #include "camera.h" #include "dm_manager.h" #include "hud.h" #include "huddraw.h" #include "object.h" #include "weaputils.h" #include "consoleevent.h" #include "player.h" #include "lightstyleclass.h" #include "debuglines.h" #include "scriptflags.h" #include "slre.h" #include "md5.h" #ifdef WIN32 # include #else # include # include #endif #define scriptfiles sv_scriptfiles Event EV_ScriptThread_GetCvar ( "getcvar", EV_DEFAULT, "s", "name", "getcvar", EV_RETURN ); Event EV_ScriptThread_GetRandomFloat ( "randomfloat", EV_DEFAULT, "f", "max", "randomfloat", EV_RETURN ); Event EV_ScriptThread_GetRandomInt ( "randomint", EV_DEFAULT, "i", "max", "randomint", EV_RETURN ); Event EV_ScriptThread_GetAbs ( "abs", EV_DEFAULT, "f", "arg", "Absolute value of int or float", EV_RETURN ); ////////// // Added in 2.30 Event EV_ScriptThread_GetCos ( "cos", EV_DEFAULT, "f", "arg", "Cosine of float (expects degrees not radians)", EV_RETURN ); Event EV_ScriptThread_GetSin ( "sin", EV_DEFAULT, "f", "arg", "Sine of float (expects degrees not radians)", EV_RETURN ); Event EV_ScriptThread_GetTan ( "tan", EV_DEFAULT, "f", "arg", "Tangent of float (expects degrees not radians)", EV_RETURN ); Event EV_ScriptThread_GetATan ( "atan", EV_DEFAULT, "fF", "arg arg2", "ArcTangent of float (in degrees not radians)", EV_RETURN ); Event EV_ScriptThread_GetSqrt ( "sqrt", EV_DEFAULT, "f", "arg", "Sqrt of float", EV_RETURN ); ////////// Event EV_ScriptThread_GetSelf ( "self", EV_DEFAULT, NULL, NULL, "self", EV_GETTER ); Event EV_ScriptThread_Goto ( "goto", EV_DEFAULT, "s", "label", "Goes to the specified label.", EV_NORMAL ); Event EV_ScriptThread_Wait ( "wait", EV_DEFAULT, "f", "wait_time", "Wait for the specified amount of time.", EV_NORMAL ); Event EV_ScriptThread_WaitFrame ( "waitframe", EV_DEFAULT, NULL, NULL, "Wait for one server frame.", EV_NORMAL ); Event EV_ScriptThread_Pause ( "pause", EV_DEFAULT, NULL, NULL, "Pauses the thread.", EV_NORMAL ); Event EV_ScriptThread_End ( "end", EV_DEFAULT, NULL, NULL, "Ends the script", EV_NORMAL ); Event EV_ScriptThread_Print ( "print", EV_DEFAULT, "s", "string", "Prints a string.", EV_NORMAL ); Event EV_ScriptThread_Println ( "println", EV_DEFAULT, "s", "string", "Prints a string. followed by a newline.", EV_NORMAL ); Event EV_ScriptThread_DPrintln // Added in 2.0 ( "dprintln", EV_DEFAULT, "s", "string", "Prints a debug string.followed by a newline.", EV_NORMAL ); Event EV_ScriptThread_IPrintln ( "iprintln", EV_DEFAULT, "s", "string", "Prints a string. followed by a newline.", EV_NORMAL ); Event EV_ScriptThread_IPrintlnBold ( "iprintlnbold", EV_DEFAULT, "s", "string", "Prints a string.followed by a newline in a bold/important way.", EV_NORMAL ); Event EV_ScriptThread_IPrintln_NoLoc ( "iprintln_noloc", EV_DEFAULT, "s", "string", "Prints a string.followed by a newline with no localization conversion.", EV_NORMAL ); Event EV_ScriptThread_IPrintlnBold_NoLoc ( "iprintlnbold_noloc", EV_DEFAULT, "s", "string", "Prints a string.followed by a newline in a bold/important way with no localization conversion.", EV_NORMAL ); Event EV_ScriptThread_MPrint ( "mprint", EV_DEFAULT, "s", "string", "Prints a string.", EV_NORMAL ); Event EV_ScriptThread_MPrintln ( "mprintln", EV_DEFAULT, "s", "string", "Prints a string. followed by a newline", EV_NORMAL ); Event EV_ScriptThread_Assert ( "assert", EV_DEFAULT, "f", "value", "Assert if value is 0.", EV_NORMAL ); Event EV_ScriptThread_CastInt ( "int", EV_DEFAULT, "i", "value", "Casts value to an int.", EV_RETURN ); Event EV_ScriptThread_CastFloat ( "float", EV_DEFAULT, "i", "value", "Casts value to a float.", EV_RETURN ); Event EV_ScriptThread_CastString ( "string", EV_DEFAULT, "i", "value", "Casts value to a string.", EV_RETURN ); Event EV_ScriptThread_CastBoolean ( "bool", EV_DEFAULT, "i", "value", "Casts value to a bool.", EV_RETURN ); Event EV_ScriptThread_CastEntity ( "entity", EV_DEFAULT, "i", "value", "Casts value to an entity.", EV_RETURN ); Event EV_ScriptThread_Clear ( "clear", EV_DEFAULT, "s", "var_group", "Clears the specified var group." ); Event EV_ScriptThread_Trigger ( "trigger", EV_DEFAULT, "s", "name", "Trigger the specified target or entity." ); Event EV_ScriptThread_Spawn ( "spawn", EV_DEFAULT, "sSSSSSSSS", "entityname keyname1 value1 keyname2 value2 keyname3 value3 keyname4 value4", "Spawns an entity.", EV_NORMAL ); Event EV_ScriptThread_SpawnReturn ( "spawn", EV_DEFAULT, "sSSSSSSSS", "entityname keyname1 value1 keyname2 value2 keyname3 value3 keyname4 value4", "Spawns an entity.", EV_RETURN ); Event EV_ScriptThread_Map ( "map", EV_DEFAULT, "s", "map_name", "Starts the specified map." ); Event EV_ScriptThread_SetCvar ( "setcvar", EV_DEFAULT, "ss", "cvar_name value", "Sets the value of the specified cvar." ); Event EV_ScriptThread_DebugLine // Added in 2.0 ( "debugline", EV_DEFAULT, "vvFFFF", "start end red green blue alpha", "Draws a debug line from start to end using the given color and alpha for g_numdebuglinedelays server frames" ); Event EV_ScriptThread_CueCamera ( "cuecamera", EV_DEFAULT, "eF", "entity switchTime", "Cue the camera. If switchTime is specified, then the camera\n" "will switch over that length of time." ); Event EV_ScriptThread_CuePlayer ( "cueplayer", EV_DEFAULT, "F", "switchTime", "Go back to the normal camera. If switchTime is specified,\n" "then the camera will switch over that length of time." ); Event EV_ScriptThread_FreezePlayer ( "freezeplayer", EV_DEFAULT, NULL, NULL, "Freeze the player." ); Event EV_ScriptThread_ReleasePlayer ( "releaseplayer", EV_DEFAULT, NULL, NULL, "Release the player." ); Event EV_ScriptThread_KillEnt ( "killent", EV_CHEAT, "i", "ent_num", "Kill the specified entity." ); Event EV_ScriptThread_IsAlive ( "IsAlive", EV_DEFAULT, "e", "ent", "Returns true if the specified entity exists and has health > 0.", EV_RETURN ); Event EV_ScriptThread_KillClass ( "killclass", EV_CHEAT, "sI", "class_name except", "Kills everything in the specified class except for the specified entity (optional)." ); Event EV_ScriptThread_GetEntByEntnum // Added in 2.30 ( "getentbyentnum", EV_CHEAT, "i", "ent_num", "Gets the specified entity", EV_RETURN ); Event EV_ScriptThread_RemoveEnt ( "removeent", EV_CHEAT, "i", "ent_num", "Removes the specified entity." ); Event EV_ScriptThread_RemoveClass ( "removeclass", EV_CHEAT, "sI", "class_name except", "Removes everything in the specified class except for the specified entity (optional)." ); // client/server flow control Event EV_ScriptThread_ServerOnly ( "server", EV_DEFAULT, "SSSSSS", "arg1 arg2 arg3 arg4 arg5 arg6", "Server only command." ); Event EV_ScriptThread_StuffCommand ( "stuffcmd", EV_DEFAULT, "SSSSSS", "arg1 arg2 arg3 arg4 arg5 arg6", "Server only command." ); Event EV_ScriptThread_SetCinematic ( "cinematic", EV_DEFAULT, NULL, NULL, "Turns on cinematic." ); Event EV_ScriptThread_SetNonCinematic ( "noncinematic", EV_DEFAULT, NULL, NULL, "Turns off cinematic." ); Event EV_ScriptThread_AllAIOff ( "all_ai_off", EV_DEFAULT, NULL, NULL, "Turns all AI off." ); Event EV_ScriptThread_AllAIOn ( "all_ai_on", EV_DEFAULT, NULL, NULL, "Turns all AI on." ); // Precache specific Event EV_ScriptThread_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_ScriptThread_Precache_Cache ( "cache", EV_DEFAULT, "s", "resource_name", "Cache the specified resource." ); // fades for movies Event EV_ScriptThread_FadeIn ( "fadein", EV_DEFAULT, "fffffI", "time red green blue alpha mode", "Sets up fadein in values." ); Event EV_ScriptThread_FadeOut ( "fadeout", EV_DEFAULT, "fffffI", "time red green blue alpha mode", "Sets up fadeout values." ); Event EV_ScriptThread_FadeSound ( "fadesound", -1, "fFE", "time min_vol player", "Fades the sound out over the given time, optionally to one single player.\n" "min_vol being a 0-1 fraction is the minimum volume.", EV_NORMAL ); Event EV_ScriptThread_CameraCommand ( "cam", EV_DEFAULT, "sSSSSSS", "command arg1 arg2 arg3 arg4 arg5 arg6", "Processes a camera command." ); // music command Event EV_ScriptThread_MusicEvent ( "music", EV_DEFAULT, "sS", "current fallback", "Sets the current and fallback (optional) music moods." ); Event EV_ScriptThread_ForceMusicEvent ( "forcemusic", EV_DEFAULT, "sS", "current fallback", "Forces the current and fallback (optional) music moods." ); Event EV_ScriptThread_MusicVolumeEvent ( "musicvolume", EV_DEFAULT, "ff", "volume fade_time", "Sets the volume and fade time of the music." ); Event EV_ScriptThread_RestoreMusicVolumeEvent ( "restoremusicvolume", EV_DEFAULT, "f", "fade_time", "Restores the music volume to its previous value." ); Event EV_ScriptThread_SoundtrackEvent ( "soundtrack", EV_DEFAULT, "s", "soundtrack_name", "Changes the soundtrack." ); Event EV_ScriptThread_RestoreSoundtrackEvent ( "restoresoundtrack", EV_DEFAULT, NULL, NULL, "Restores the soundtrack to the previous one." ); Event EV_ScriptThread_ClearFade ( "clearfade", EV_DEFAULT, NULL, NULL, "Clear the fade from the screen" ); Event EV_ScriptThread_Letterbox ( "letterbox", EV_DEFAULT, "f", "time", "Puts the game in letterbox mode." ); Event EV_ScriptThread_ClearLetterbox ( "clearletterbox", EV_DEFAULT, "f", "time", "Clears letterbox mode." ); Event EV_ScriptThread_SetDialogScript ( "setdialogscript", EV_DEFAULT, "s", "dialog_script", "Set the script to be used when dialog:: is used" ); Event EV_ScriptThread_SetLightStyle ( "setlightstyle", EV_DEFAULT, "is", "lightstyleindex lightstyledata", "Set up the lightstyle with lightstyleindex to the specified data" ); Event EV_ScriptThread_CenterPrint ( "centerprint", EV_DEFAULT, "s", "stuffToPrint", "prints the included message in the middle of all player's screens" ); Event EV_ScriptThread_LocationPrint ( "locprint", EV_DEFAULT, "iis", "xoffset yoffset stuffToPrint", "prints the included message in the specified location of all player's screens" ); Event EV_ScriptThread_MissionFailed ( "missionfailed", EV_DEFAULT, NULL, NULL, "Makes the player fail their mission," "level restarts." ); Event EV_ScriptThread_Vector_Length ( "vector_length", EV_DEFAULT, "v", "vector", "Returns the length of the specified vector.", EV_RETURN ); Event EV_ScriptThread_Vector_Normalize ( "vector_normalize", EV_DEFAULT, "v", "vector", "Returns the normalized vector of the specified vector.", EV_RETURN ); Event EV_ScriptThread_Vector_Add ( "vector_add", EV_DEFAULT, "vv", "vector1 vector2", "Returns vector1 + vector2.", EV_RETURN ); Event EV_ScriptThread_Vector_Subtract ( "vector_subtract", EV_DEFAULT, "vv", "vector1 vector2", "Returns vector1 - vector2.", EV_RETURN ); Event EV_ScriptThread_Vector_Scale ( "vector_scale", EV_DEFAULT, "vf", "vector1 scale_factor", "Returns vector1 * scale_factor.", EV_RETURN ); Event EV_ScriptThread_Vector_DotProduct ( "vector_dot", EV_DEFAULT, "vv", "vector1 vector2", "Returns vector1 * vector2.", EV_RETURN ); Event EV_ScriptThread_Vector_CrossProduct ( "vector_cross", EV_DEFAULT, "vv", "vector1 vector2", "Returns vector1 x vector2.", EV_RETURN ); Event EV_ScriptThread_Vector_ToAngles ( "vector_toangles", EV_DEFAULT, "v", "vector1", "Returns vector1 converted to angles.", EV_RETURN ); Event EV_ScriptThread_Angles_ToForward ( "angles_toforward", EV_DEFAULT, "v", "angles", "Returns the forward vector of the specified angles", EV_RETURN ); Event EV_ScriptThread_Angles_ToLeft ( "angles_toleft", EV_DEFAULT, "v", "angles", "Returns the left vector of the specified angles", EV_RETURN ); Event EV_ScriptThread_Angles_ToUp ( "angles_toup", EV_DEFAULT, "v", "angles", "Returns the up vector of the specified angles", EV_RETURN ); Event EV_ScriptThread_Angles_PointAt ( "angles_pointat", EV_DEFAULT, "eee", "parent_entity entity target_entity", "Returns the angles that points at the target_entity given the base orientation of the parent_entity and the " "position of the entity.", EV_RETURN ); Event EV_ScriptThread_AIsCloserThanBToC ( "vector_closer", EV_DEFAULT, "vvv", "vec_a vec_b vec_c", "returns 1 if the first vector is closer than the second vector to the third vector.", EV_RETURN ); Event EV_ScriptThread_PointsWithinDist ( "vector_within", EV_DEFAULT, "vvf", "position1 position2 distance", "returns 1 if the two points are <= distance apart, or 0 if they are greater than distance apart.", EV_RETURN ); Event EV_ScriptThread_Popmenu ( "popmenu", EV_DEFAULT, "i", "index", "pop menu" ); Event EV_ScriptThread_Showmenu ( "showmenu", EV_DEFAULT, "sI", "name bForce", "show menu," "with option to force it on" ); Event EV_ScriptThread_Hidemenu ( "hidemenu", EV_DEFAULT, "sI", "name bForce", "hide menu," "with option to force it off" ); Event EV_ScriptThread_PlayMovie // Added in 2.0 ( "PlayMovie", EV_DEFAULT, "s", "name", "Play a Movie..." ); Event EV_ScriptThread_Pushmenu ( "pushmenu", EV_DEFAULT, "s", "name", "push menu" ); Event EV_ScriptThread_HideMouse ( "hidemouse", EV_DEFAULT, NULL, NULL, "hide mouse cursor" ); Event EV_ScriptThread_CreateListener ( "CreateListener", EV_DEFAULT, NULL, NULL, "Creates a Listener instance.", EV_RETURN ); Event EV_ScriptThread_Trace ( "trace", EV_DEFAULT, "vvIVV", "start end pass_entities mins maxs", "Performs a Trace Line from the start to the end, returns the end or the position it hit at.", EV_RETURN ); Event EV_ScriptThread_SightTrace ( "sighttrace", EV_DEFAULT, "vvIVV", "start end pass_entities mins maxs", "Performs a trace line from the start to the end, returns 0 if something was hit and 1 otherwise.", EV_RETURN ); Event EV_ScriptThread_Print3D ( "print3d", EV_DEFAULT, "vfs", "origin scale string", "prints a string in 3D space", EV_NORMAL ); Event EV_ScriptThread_HudDraw_3d ( "huddraw_3d", EV_DEFAULT, "iviiE", "index vector_or_offset always_show depth entity", "Sets this huddraw element to be a 3D world icon and can specify if this icon is always shown on-screen even if " "the player isn't looking at.\n" "Uses xy pos from huddraw_rect.\n" "If entity is specified, the vector will be an offset relative to the entity.\n" "depth specify if the icon is shown through walls.", EV_NORMAL ); Event EV_ScriptThread_HudDraw_Timer ( "huddraw_timer", EV_DEFAULT, "iff", "index duration fade_out_time", "Sets a timer to be displayed and fade within the given time in seconds. Clears the string value and the shader " "value of huddraw element.", EV_NORMAL ); Event EV_ScriptThread_HudDraw_Shader ( "huddraw_shader", EV_DEFAULT, "is", "index shader", "Sets the shader to use for a particular huddraw element for given player", EV_NORMAL ); Event EV_ScriptThread_HudDraw_Align ( "huddraw_align", EV_DEFAULT, "iss", "index h_align v_align", "Sets the alignment of a huddraw element for given player. Specified with 'left', 'center', or 'right'", EV_NORMAL ); Event EV_ScriptThread_HudDraw_Rect ( "huddraw_rect", EV_DEFAULT, "iiiii", "index x y width height", "Specifies the position of the upper left corner and size of a huddraw element for given player", EV_NORMAL ); Event EV_ScriptThread_HudDraw_VirtualSize ( "huddraw_virtualsize", EV_DEFAULT, "ii", "index virtual", "Sets if the huddraw element for given player should use virtual screen resolution for positioning and size", EV_NORMAL ); Event EV_ScriptThread_HudDraw_Color ( "huddraw_color", EV_DEFAULT, "ifff", "index red green blue", "Sets the color for a huddraw element for given player", EV_NORMAL ); Event EV_ScriptThread_HudDraw_Alpha ( "huddraw_alpha", EV_DEFAULT, "if", "index alpha", "Sets the alpha of a huddraw element for given player", EV_NORMAL ); Event EV_ScriptThread_HudDraw_String ( "huddraw_string", EV_DEFAULT, "is", "index string", "Sets a string to be displayed for given player. Clears the shader value", EV_NORMAL ); Event EV_ScriptThread_HudDraw_Font ( "huddraw_font", EV_DEFAULT, "is", "index fontname", "Sets the font to use for given player huddraw element", EV_NORMAL ); Event EV_ScriptThread_Error ( "error", EV_DEFAULT, NULL, NULL, "Ends the script", EV_NORMAL ); Event EV_ScriptThread_DebugInt3 // Added in 2.0 ( "debug_int3", EV_DEFAULT, NULL, NULL, "Generate an asm int 3", EV_NORMAL ); Event EV_ScriptThread_Timeout ( "timeout", EV_DEFAULT, "f", "time", "specifies script timeout time", EV_NORMAL ); Event EV_ScriptThread_RadiusDamage ( "radiusdamage", EV_DEFAULT, "viiI", "origin damage radius constant_damage", "radius damage at origin" ); Event EV_ScriptThread_LandmineDamage // Added in 2.30 ( "landminedamage", EV_DEFAULT, "eff", "landmine damage radius", "radius damage at landmine" ); Event EV_ScriptThread_BspTransition ( "bsptransition", EV_DEFAULT, "s", "next_map", "Transitions to the next BSP. Keeps player data," "and game data." ); Event EV_ScriptThread_LevelTransition ( "leveltransition", EV_DEFAULT, "s", "next_map", "Transitions to the next Level. Statistics to Map Loading," "does not keep player data or game data." ); Event EV_ScriptThread_MissionTransition ( "missiontransition", EV_DEFAULT, "s", "next_map", "Transitions to the next Mission. Statistics to Main Menu," "Next Level should be unlocked." ); Event EV_ScriptThread_Earthquake ( "earthquake", EV_DEFAULT, "ffff", "duration magnitude no_rampup no_rampdown", "Create an earthquake" ); Event EV_ScriptThread_TeamWin ( "teamwin", EV_DEFAULT, "s", "axis_or_allies", "Sets that the 'axis' or the 'allies' have won the map." ); Event EV_ScriptThread_StopTeamRespawn // Added in 2.30 ( "stopteamrespawn", EV_DEFAULT, "s", "team", "Stops a team (anerican, german, both) from spawning in non-wave deathmatches" ); Event EV_ScriptThread_GetBoundKey1 ( "getboundkey1", EV_DEFAULT, "s", "keyname", "return a string describing the key", EV_RETURN ); Event EV_ScriptThread_GetBoundKey2 ( "getboundkey2", EV_DEFAULT, "s", "keyname", "return a string describing the key", EV_RETURN ); Event EV_ScriptThread_LocConvertString ( "loc_convert_string", EV_DEFAULT, "s", "in", "returns a localized version of the string.", EV_RETURN ); Event EV_ScriptThread_SetScoreboardToggle // Added in 2.30 ( "setscoreboardtoggle", EV_DEFAULT, "si", "team value", "Sets the specified team's scoreboard toggle", EV_NORMAL ); Event EV_ScriptThread_AddObjective ( "addobjective", EV_DEFAULT, "iisv", "objective_number status text location", "Adds/Changes an Objective" ); Event EV_ScriptThread_SetCurrentObjective ( "setcurrentobjective", EV_DEFAULT, "i", "objective_number", "Sets the specified objective as the current objective" ); Event EV_ScriptThread_SetObjectiveLocation ( "set_objective_pos", EV_DEFAULT, "v", "pos", "Sets the position in the world of the current objective" ); Event EV_ScriptThread_ClearObjectiveLocation( "clear_objective_pos", EV_DEFAULT, NULL, NULL, "Clears the position of the current objective," "for when you don't have one" ); Event EV_ScriptThread_DrawHud ( "drawhud", EV_DEFAULT, "i", "value", "Specify if hud is to be drawn" ); Event EV_ScriptThread_RegisterCommand ( "registercmd", EV_DEFAULT, "ss", "name label", "Registers a command.", EV_NORMAL ); // // Added in OPM // Event EV_ScriptThread_CancelWaiting ( "_cancelwaiting", EV_CODEONLY, NULL, NULL, "internal event" ); Event EV_ScriptThread_CanSwitchTeams ( "canswitchteams", EV_DEFAULT, "bB", "allow_team_change allow_spectator", "Specify if players are allowed to switch teams and spectate. Override player's canswitchteams.", EV_NORMAL ); Event EV_ScriptThread_RemoveArchivedClass ( "removearchivedclass", EV_DEFAULT, "sI", "class except_entity_number", "Removes all of the simple archived entities in the specified class.", EV_NORMAL ); Event EV_ScriptThread_RestoreSound( "restoresound", -1, "fFE", "time max_vol player", "Fades the sound in over the given time, optionally to one single player.\n" "max_vol being a 0-1 fraction is the maximum volume.", EV_NORMAL ); Event EV_ScriptThread_Earthquake2 ( "earthquake2", EV_DEFAULT, "ffbbVF", "duration magnitude no_rampup no_rampdown location radius", "Create a smooth realistic earthquake. Requires sv_reborn to be set.", EV_NORMAL ); Event EV_ScriptThread_GetPlayerNetname ( "netname", EV_DEFAULT, "e", "player", "Gets player's netname", EV_RETURN ); Event EV_ScriptThread_GetPlayerIP ( "getip", EV_DEFAULT, "e", "player", "Gets player's ip", EV_RETURN ); Event EV_ScriptThread_ServerStufftext ( "stuffsrv", EV_DEFAULT, "s", "string", "Sends command to server", EV_NORMAL ); Event EV_ScriptThread_GetAreaEntities ( "getareaentities", EV_DEFAULT, "vvv", "origin mins maxs", "Get all entities around the origin", EV_RETURN ); Event EV_ScriptThread_GetPlayerPing ( "getping", EV_DEFAULT, "e", "player", "Gets player's ping", EV_RETURN ); Event EV_ScriptThread_GetPlayerClientNum ( "getclientnum", EV_DEFAULT, "e", "player", "Gets player's client number", EV_RETURN ); Event EV_ScriptThread_iHudDraw3d ( "ihuddraw_3d", EV_DEFAULT, "eiviiE", "player index vector_or_offset always_show depth entity", "Sets this huddraw element to be a 3D world icon for individual player and can specify if this icon is always " "shown on-screen even if the player isn't looking at.\n" "Uses xy pos from huddraw_rect.\n" "If entity is specified, the vector will be an offset relative to the entity.\n" "depth specify if the icon is shown through walls.", EV_NORMAL ); Event EV_ScriptThread_iHudDrawAlign ( "ihuddraw_align", EV_DEFAULT, "eiss", "player index h_align v_align", "Sets the alignment of a huddraw element for given player. Specified with 'left', 'center', or 'right'", EV_NORMAL ); Event EV_ScriptThread_iHudDrawAlpha ( "ihuddraw_alpha", EV_DEFAULT, "eif", "player index alpha", "Sets the alpha of a huddraw element for given player", EV_NORMAL ); Event EV_ScriptThread_iHudDrawColor ( "ihuddraw_color", EV_DEFAULT, "eifff", "player index red green blue", "Sets the color for a huddraw element for given player", EV_NORMAL ); Event EV_ScriptThread_iHudDrawFont ( "ihuddraw_font", EV_DEFAULT, "eis", "player index fontname", "Sets the font to use for given player huddraw element", EV_NORMAL ); Event EV_ScriptThread_iHudDrawRect ( "ihuddraw_rect", EV_DEFAULT, "eiiiii", "player index x y width height", "Specifies the position of the upper left corner and size of a huddraw element for given player", EV_NORMAL ); Event EV_ScriptThread_iHudDrawShader ( "ihuddraw_shader", EV_DEFAULT, "eis", "player index shader", "Sets the shader to use for a particular huddraw element for given player", EV_NORMAL ); Event EV_ScriptThread_iHudDrawString ( "ihuddraw_string", EV_DEFAULT, "eis", "player index string", "Sets a string to be displayed for given player. Clears the shader value", EV_NORMAL ); Event EV_ScriptThread_iHudDrawTimer ( "ihuddraw_timer", EV_DEFAULT, "eiff", "player index duration fade_out_time", "Sets a timer to be displayed and fade within the given time in seconds for given player. Clears the string value " "and the shader value of huddraw element.", EV_NORMAL ); Event EV_ScriptThread_iHudDrawVirtualSize ( "ihuddraw_virtualsize", EV_DEFAULT, "eii", "player index virtual", "Sets if the huddraw element for given player should use virtual screen resolution for positioning and size", EV_NORMAL ); Event EV_ScriptThread_IsArray ( "isarray", EV_DEFAULT, "s", "object", "Checks whether this variable is an array", EV_RETURN ); Event EV_ScriptThread_IsDefined ( "isdefined", EV_DEFAULT, "s", "object", "Checks whether this entity/variable is defined", EV_RETURN ); Event EV_ScriptThread_IsOnGround ( "isonground", EV_DEFAULT, "e", "entity", "Returns 1 if the entity is on ground. 0 otherwise", EV_RETURN ); Event EV_ScriptThread_IsOutOfBounds ( "isoutofbounds", EV_DEFAULT, "e", "entity", "Returns 1 if the entity is out of bounds. 0 otherwise", EV_RETURN ); Event EV_ScriptThread_FileOpen( "fopen", EV_DEFAULT, "ss", "filename accesstype", "Opens file," "returning it's handle", EV_RETURN ); Event EV_ScriptThread_FileWrite ( "fwrite", EV_DEFAULT, "eii", "player index virtual", "Writes binary buffer to file", EV_NORMAL ); Event EV_ScriptThread_FileRead ( "fread", EV_DEFAULT, "eii", "player index virtual", "Reads binary buffer from file", EV_NORMAL ); Event EV_ScriptThread_FileClose ( "fclose", EV_DEFAULT, "i", "filehandle", "Closes file of given file handle", EV_RETURN ); Event EV_ScriptThread_FileEof ( "feof", EV_DEFAULT, "i", "filehandle", "Checks for end of file", EV_RETURN ); Event EV_ScriptThread_FileSeek ( "fseek", EV_DEFAULT, "iii", "filehandle offset startpos", "Sets file carret at given position", EV_RETURN ); Event EV_ScriptThread_FileTell ( "ftell", EV_DEFAULT, "i", "filehandle", "Gets current file carret position", EV_RETURN ); Event EV_ScriptThread_FileRewind ( "frewind", EV_DEFAULT, "i", "filehandle", "Rewinds file carret to files beginning", EV_NORMAL ); Event EV_ScriptThread_FilePutc ( "fputc", EV_DEFAULT, "ii", "filehandle character", "Writes single character to file", EV_RETURN ); Event EV_ScriptThread_FilePuts ( "fputs", EV_DEFAULT, "is", "filehandle text", "Writes string line to file", EV_RETURN ); Event EV_ScriptThread_FileGetc ( "fgetc", EV_DEFAULT, "i", "filehandle", "Reads single character from file", EV_RETURN ); Event EV_ScriptThread_FileGets ( "fgets", EV_DEFAULT, "ii", "filehandle maxbuffsize", "Reads string line from file", EV_RETURN ); Event EV_ScriptThread_FileError ( "ferror", EV_DEFAULT, "i", "filehandle", "Checks for last file i/o error", EV_RETURN ); Event EV_ScriptThread_FileFlush ( "fflush", EV_DEFAULT, "i", "filehandle", "Flushes given stream. Writes all unsaved data from stream buffer to stream", EV_RETURN ); Event EV_ScriptThread_FlagClear ( "flag_clear", EV_DEFAULT, "s", "name", "Clears and deletes a flag.", EV_NORMAL ); Event EV_ScriptThread_FlagInit ( "flag_init", EV_DEFAULT, "s", "name", "Initializes a flag so it can be set. Flags MUST be initialized before they can be used for the first time.", EV_NORMAL ); Event EV_ScriptThread_FlagSet ( "flag_set", EV_DEFAULT, "s", "name", "Sets a flag which alerts all flag_wait()'s and changes are reflected in flag() checks thereafter.", EV_NORMAL ); Event EV_ScriptThread_FlagWait ( "flag_wait", EV_DEFAULT, "s", "name", "Pauses execution flow until a flag has been set.", EV_NORMAL ); Event EV_ScriptThread_Lock ( "lock", EV_DEFAULT, "l", "lock", "Lock the thread." ); Event EV_ScriptThread_UnLock ( "unlock", EV_DEFAULT, "l", "lock", "Unlock the thread." ); Event EV_ScriptThread_GetArrayKeys ( "getarraykeys", EV_DEFAULT, "s", "array", "Retrieves a full list containing the name of arrays", EV_RETURN ); Event EV_ScriptThread_GetArrayValues ( "getarrayvalues", EV_DEFAULT, "s", "array", "Retrieves the full list of an array that was set-up with name, such as local.array[ \"name\" ] and return their " "values", EV_RETURN ); Event EV_ScriptThread_GetEntArray ( "getentarray", EV_DEFAULT, "ss", "name key", "Gets an array of entities that have the given key, name pair (case sensitive)", EV_RETURN ); Event EV_ScriptThread_GetTime ( "gettime", EV_DEFAULT, NULL, NULL, "Gets current time", EV_RETURN ); Event EV_ScriptThread_GetTimeZone ( "gettimezone", EV_DEFAULT, NULL, NULL, "Gets current time zone", EV_RETURN ); Event EV_ScriptThread_PregMatch ( "preg_match", EV_DEFAULT, "ss", "pattern subject", "Searches subject for a match to the regular expression given in pattern.", EV_RETURN ); Event EV_ScriptThread_GetDate ( "getdate", EV_DEFAULT, NULL, NULL, "Gets current date", EV_RETURN ); Event EV_ScriptThread_RegisterEv ( "registerev", EV_DEFAULT, "ss", "eventname script", "Registers script callback handler for specified event", EV_RETURN ); Event EV_ScriptThread_UnregisterEv ( "unregisterev", EV_DEFAULT, "s", "eventname", "Unregisters script callback handler for specified event", EV_RETURN ); Event EV_ScriptThread_Conprintf ( "conprintf", EV_DEFAULT, "s", "text", "Prints to console", EV_NORMAL ); Event EV_ScriptThread_TeamSwitchDelay ( "teamswitchdelay", EV_DEFAULT, "f", "delay", "Sets delay between switching teams. [DEPRECATED]", EV_NORMAL ); Event EV_ScriptThread_CharToInt ( "chartoint", EV_DEFAULT, "s", "character", "Converts char to int", EV_RETURN ); Event EV_ScriptThread_FileExists ( "fexists", EV_DEFAULT, "s", "filename", "Checks if file exists", EV_RETURN ); Event EV_ScriptThread_FileReadAll ( "freadall", EV_DEFAULT, "i", "filehandle", "Reads whole file and returns it as string", EV_RETURN ); Event EV_ScriptThread_FileSaveAll ( "fsaveall", EV_DEFAULT, "is", "filehandle text", "Saves whole text to file", EV_RETURN ); Event EV_ScriptThread_FileRemove ( "fremove", EV_DEFAULT, "s", "filename", "Removes the file", EV_RETURN ); Event EV_ScriptThread_FileRename ( "frename", EV_DEFAULT, "ss", "oldfilename newfilename", "Renames the file", EV_RETURN ); Event EV_ScriptThread_FileCopy ( "fcopy", EV_DEFAULT, "ss", "filename copyfilename", "Copies the file", EV_RETURN ); Event EV_ScriptThread_FileReadPak ( "freadpak", EV_DEFAULT, "s", "filename", "Reads file from pak file", EV_RETURN ); Event EV_ScriptThread_FileList ( "flist", EV_DEFAULT, "ssi", "path extension wantSubs", "Returns the list of files with given extension", EV_RETURN ); Event EV_ScriptThread_FileNewDirectory ( "fnewdir", EV_DEFAULT, "s", "path", "Creates a new directory", EV_RETURN ); Event EV_ScriptThread_FileRemoveDirectory ( "fremovedir", EV_DEFAULT, "s", "path", "Removes a directory", EV_RETURN ); Event EV_ScriptThread_GetACos ( "acos", EV_DEFAULT, "f", "x", "Compute arc cosine", EV_RETURN ); Event EV_ScriptThread_GetASin ( "asin", EV_DEFAULT, "f", "x", "Compute arc sine", EV_RETURN ); Event EV_ScriptThread_GetATan2 ( "atan2", EV_DEFAULT, "ff", "x y", "Compute arc tangent with two parameters", EV_RETURN ); Event EV_ScriptThread_GetCosH ( "cosh", EV_DEFAULT, "f", "x", "Compute hyperbolic cosine", EV_RETURN ); Event EV_ScriptThread_GetSinH ( "sinh", EV_DEFAULT, "f", "x", "Compute hyperbolic sine", EV_RETURN ); Event EV_ScriptThread_GetTanH ( "tanh", EV_DEFAULT, "f", "x", "Compute hyperbolic tangent", EV_RETURN ); Event EV_ScriptThread_GetExp ( "exp", EV_DEFAULT, "f", "x", "Compute exponential function", EV_RETURN ); Event EV_ScriptThread_GetFrexp ( "frexp", EV_DEFAULT, "f", "x", "Get significand and exponent", EV_RETURN ); Event EV_ScriptThread_GetLdexp ( "ldexp", EV_DEFAULT, "f", "x", "Generate number from significand and exponent", EV_RETURN ); Event EV_ScriptThread_GetLog ( "log", EV_DEFAULT, "f", "x", "Compute natural logarithm", EV_RETURN ); Event EV_ScriptThread_GetLog10 ( "log10", EV_DEFAULT, "f", "x", "Compute common logarithm", EV_RETURN ); Event EV_ScriptThread_GetModf ( "modf", EV_DEFAULT, "f", "x", "Break into fractional and integral parts", EV_RETURN ); Event EV_ScriptThread_GetPow ( "pow", EV_DEFAULT, "ff", "x y", "Raise to power", EV_RETURN ); Event EV_ScriptThread_GetCeil ( "ceil", EV_DEFAULT, "f", "x", "Round up value", EV_RETURN ); Event EV_ScriptThread_GetFloor ( "floor", EV_DEFAULT, "f", "x", "Round down value", EV_RETURN ); Event EV_ScriptThread_GetFmod ( "fmod", EV_DEFAULT, "f", "x", "Compute remainder of division", EV_RETURN ); Event EV_ScriptThread_strncpy ( "strncpy", EV_DEFAULT, "is", "bytes source", "Returns the copied string with the specified bytes", EV_RETURN ); Event EV_ScriptThread_CreateHUD ( "newhud", EV_DEFAULT, "E", "player", "Create a new HUD element. Optionally for a particular client", EV_RETURN ); Event EV_ScriptThread_TraceDetails( "traced", EV_DEFAULT, "vvIVVI", "start end pass_entities mins maxs mask", "Performs a Trace Line from the start to the end, returns the array with detailed results", EV_RETURN ); Event EV_ScriptThread_TypeOf ( "typeof", EV_DEFAULT, "i", "variable", "Returns the type of variable", EV_RETURN ); Event EV_ScriptThread_Md5String ( "md5string", EV_DEFAULT, "s", "text", "generates MD5 hash of given text", EV_RETURN ); Event EV_ScriptThread_SetTimer ( "settimer", EV_DEFAULT, "is", "interval script", "Sets timer that will execute script after given interval.", EV_RETURN ); Event EV_ScriptThread_TeamGetScore ( "team_getscore", EV_DEFAULT, "s", "team", "Get a team's current score.", EV_NORMAL ); Event EV_ScriptThread_TeamSetScore ( "team_setscore", EV_DEFAULT, "siI", "team score bAdd", "Change/Add score to a team.", EV_NORMAL ); Event EV_ScriptThread_VisionGetNaked ( "visiongetnaked", EV_DEFAULT, NULL, NULL, "Gets players' global current naked-eye vision.", EV_NORMAL ); Event EV_ScriptThread_VisionSetNaked ( "visionsetnaked", EV_DEFAULT, "sF", "vision_name transition_time", "Sets players' naked-eye vision. Optionally give a transition time from the current vision. If vision_name is an " "empty string, it will be set to the current map's name.", EV_NORMAL ); CLASS_DECLARATION(Listener, ScriptThread, NULL) { {&EV_ScriptThread_GetCvar, &ScriptThread::Getcvar }, {&EV_ScriptThread_GetRandomFloat, &ScriptThread::GetRandomFloat }, {&EV_ScriptThread_GetRandomInt, &ScriptThread::GetRandomInt }, {&EV_ScriptThread_GetAbs, &ScriptThread::GetAbs }, {&EV_ScriptThread_GetSelf, &ScriptThread::GetSelf }, {&EV_ScriptThread_GetCos, &ScriptThread::EventCos }, {&EV_ScriptThread_GetSin, &ScriptThread::EventSin }, {&EV_ScriptThread_GetTan, &ScriptThread::EventTan }, {&EV_ScriptThread_GetATan, &ScriptThread::EventATan }, {&EV_ScriptThread_GetSqrt, &ScriptThread::EventSqrt }, {&EV_ScriptThread_Vector_Length, &ScriptThread::Vector_Length }, {&EV_ScriptThread_Vector_Normalize, &ScriptThread::Vector_Normalize }, {&EV_ScriptThread_Vector_Add, &ScriptThread::Vector_Add }, {&EV_ScriptThread_Vector_Subtract, &ScriptThread::Vector_Subtract }, {&EV_ScriptThread_Vector_Scale, &ScriptThread::Vector_Scale }, {&EV_ScriptThread_Vector_DotProduct, &ScriptThread::Vector_DotProduct }, {&EV_ScriptThread_Vector_CrossProduct, &ScriptThread::Vector_CrossProduct }, {&EV_ScriptThread_Vector_ToAngles, &ScriptThread::Vector_ToAngles }, {&EV_ScriptThread_AIsCloserThanBToC, &ScriptThread::EventAIsCloserThanBToC }, {&EV_ScriptThread_PointsWithinDist, &ScriptThread::EventPointsWithinDist }, {&EV_ScriptThread_Angles_ToForward, &ScriptThread::Angles_ToForward }, {&EV_ScriptThread_Angles_ToLeft, &ScriptThread::Angles_ToLeft }, {&EV_ScriptThread_Angles_ToUp, &ScriptThread::Angles_ToUp }, {&EV_ScriptThread_Angles_PointAt, &ScriptThread::Angles_PointAt }, {&EV_Listener_CreateThread, &ScriptThread::CreateThread }, {&EV_Listener_CreateReturnThread, &ScriptThread::CreateReturnThread }, {&EV_Listener_ExecuteScript, &ScriptThread::ExecuteScript }, {&EV_Listener_ExecuteReturnScript, &ScriptThread::ExecuteReturnScript }, {&EV_ScriptThread_Goto, &ScriptThread::EventGoto }, {&EV_Throw, &ScriptThread::EventThrow }, {&EV_DelayThrow, &ScriptThread::EventDelayThrow }, {&EV_ScriptThread_Wait, &ScriptThread::EventWait }, {&EV_ScriptThread_WaitFrame, &ScriptThread::EventWaitFrame }, {&EV_ScriptThread_Pause, &ScriptThread::EventPause }, {&EV_ScriptThread_End, &ScriptThread::EventEnd }, {&EV_ScriptThread_Print, &ScriptThread::Print }, {&EV_ScriptThread_Println, &ScriptThread::Println }, {&EV_ScriptThread_DPrintln, &ScriptThread::DPrintln }, {&EV_ScriptThread_IPrintln, &ScriptThread::IPrintln }, {&EV_ScriptThread_IPrintlnBold, &ScriptThread::IPrintlnBold }, {&EV_ScriptThread_IPrintln_NoLoc, &ScriptThread::IPrintln_NoLoc }, {&EV_ScriptThread_IPrintlnBold_NoLoc, &ScriptThread::IPrintlnBold_NoLoc }, {&EV_ScriptThread_MPrint, &ScriptThread::MPrint }, {&EV_ScriptThread_MPrintln, &ScriptThread::MPrintln }, {&EV_ScriptThread_Assert, &ScriptThread::Assert }, {&EV_ScriptThread_CastInt, &ScriptThread::CastInt }, {&EV_ScriptThread_CastFloat, &ScriptThread::CastFloat }, {&EV_ScriptThread_CastString, &ScriptThread::CastString }, {&EV_ScriptThread_CastBoolean, &ScriptThread::CastBoolean }, {&EV_ScriptThread_CastEntity, &ScriptThread::CastEntity }, {&EV_ScriptThread_Trigger, &ScriptThread::TriggerEvent }, {&EV_ScriptThread_ServerOnly, &ScriptThread::ServerEvent }, {&EV_ScriptThread_StuffCommand, &ScriptThread::StuffCommand }, {&EV_ScriptThread_Spawn, &ScriptThread::Spawn }, {&EV_ScriptThread_SpawnReturn, &ScriptThread::SpawnReturn }, {&EV_ScriptThread_Map, &ScriptThread::MapEvent }, {&EV_ScriptThread_AliasCache, &ScriptThread::RegisterAliasAndCache }, {&EV_ScriptThread_Precache_Cache, &ScriptThread::CacheResourceEvent }, {&EV_ScriptThread_SetCvar, &ScriptThread::SetCvarEvent }, {&EV_ScriptThread_DebugLine, &ScriptThread::EventDebugLine }, {&EV_ScriptThread_CueCamera, &ScriptThread::CueCamera }, {&EV_ScriptThread_CuePlayer, &ScriptThread::CuePlayer }, {&EV_ScriptThread_FreezePlayer, &ScriptThread::FreezePlayer }, {&EV_ScriptThread_ReleasePlayer, &ScriptThread::ReleasePlayer }, {&EV_ScriptThread_FadeIn, &ScriptThread::FadeIn }, {&EV_ScriptThread_FadeOut, &ScriptThread::FadeOut }, {&EV_ScriptThread_FadeSound, &ScriptThread::FadeSound }, {&EV_ScriptThread_ClearFade, &ScriptThread::ClearFade }, {&EV_ScriptThread_Letterbox, &ScriptThread::Letterbox }, {&EV_ScriptThread_ClearLetterbox, &ScriptThread::ClearLetterbox }, {&EV_ScriptThread_MusicEvent, &ScriptThread::MusicEvent }, {&EV_ScriptThread_ForceMusicEvent, &ScriptThread::ForceMusicEvent }, {&EV_ScriptThread_MusicVolumeEvent, &ScriptThread::MusicVolumeEvent }, {&EV_ScriptThread_RestoreMusicVolumeEvent, &ScriptThread::RestoreMusicVolumeEvent }, {&EV_ScriptThread_SoundtrackEvent, &ScriptThread::SoundtrackEvent }, {&EV_ScriptThread_RestoreSoundtrackEvent, &ScriptThread::RestoreSoundtrackEvent }, {&EV_ScriptThread_CameraCommand, &ScriptThread::CameraCommand }, {&EV_ScriptThread_SetCinematic, &ScriptThread::SetCinematic }, {&EV_ScriptThread_SetNonCinematic, &ScriptThread::SetNonCinematic }, {&EV_ScriptThread_AllAIOff, &ScriptThread::SetAllAIOff }, {&EV_ScriptThread_AllAIOn, &ScriptThread::SetAllAIOn }, {&EV_ScriptThread_KillEnt, &ScriptThread::KillEnt }, {&EV_ScriptThread_GetEntByEntnum, &ScriptThread::GetEntByEntnum }, {&EV_ScriptThread_RemoveEnt, &ScriptThread::RemoveEnt }, {&EV_ScriptThread_KillClass, &ScriptThread::KillClass }, {&EV_ScriptThread_RemoveClass, &ScriptThread::RemoveClass }, {&EV_ScriptThread_SetLightStyle, &ScriptThread::SetLightStyle }, {&EV_ScriptThread_CenterPrint, &ScriptThread::CenterPrint }, {&EV_ScriptThread_LocationPrint, &ScriptThread::LocationPrint }, {&EV_ScriptThread_MissionFailed, &ScriptThread::MissionFailed }, {&EV_ScriptThread_IsAlive, &ScriptThread::EventIsAlive }, {&EV_ScriptThread_Popmenu, &ScriptThread::EventPopmenu }, {&EV_ScriptThread_Showmenu, &ScriptThread::EventShowmenu }, {&EV_ScriptThread_Hidemenu, &ScriptThread::EventHidemenu }, {&EV_ScriptThread_PlayMovie, &ScriptThread::EventPlayMovie }, {&EV_ScriptThread_Pushmenu, &ScriptThread::EventPushmenu }, {&EV_ScriptThread_HideMouse, &ScriptThread::EventHideMouse }, {&EV_ScriptThread_CreateListener, &ScriptThread::EventCreateListener }, {&EV_ScriptThread_Trace, &ScriptThread::EventTrace }, {&EV_ScriptThread_SightTrace, &ScriptThread::EventSightTrace }, {&EV_ScriptThread_Print3D, &ScriptThread::EventPrint3D }, {&EV_ScriptThread_HudDraw_Shader, &ScriptThread::EventHudDrawShader }, {&EV_ScriptThread_HudDraw_Align, &ScriptThread::EventHudDrawAlign }, {&EV_ScriptThread_HudDraw_Rect, &ScriptThread::EventHudDrawRect }, {&EV_ScriptThread_HudDraw_VirtualSize, &ScriptThread::EventHudDrawVirtualSize }, {&EV_ScriptThread_HudDraw_Color, &ScriptThread::EventHudDrawColor }, {&EV_ScriptThread_HudDraw_Alpha, &ScriptThread::EventHudDrawAlpha }, {&EV_ScriptThread_HudDraw_String, &ScriptThread::EventHudDrawString }, {&EV_ScriptThread_HudDraw_Font, &ScriptThread::EventHudDrawFont }, {&EV_ScriptThread_Timeout, &ScriptThread::EventTimeout }, {&EV_ScriptThread_Error, &ScriptThread::EventError }, {&EV_ScriptThread_DebugInt3, &ScriptThread::EventDebugInt3 }, {&EV_ScriptThread_RadiusDamage, &ScriptThread::EventRadiusDamage }, {&EV_ScriptThread_LandmineDamage, &ScriptThread::EventLandmineDamage }, {&EV_ScriptThread_BspTransition, &ScriptThread::EventBspTransition }, {&EV_ScriptThread_LevelTransition, &ScriptThread::EventLevelTransition }, {&EV_ScriptThread_MissionTransition, &ScriptThread::EventMissionTransition }, {&EV_ScriptThread_Earthquake, &ScriptThread::EventEarthquake }, {&EV_ScriptThread_TeamWin, &ScriptThread::EventTeamWin }, {&EV_ScriptThread_StopTeamRespawn, &ScriptThread::EventStopTeamRespawn }, {&EV_ScriptThread_GetBoundKey1, &ScriptThread::EventGetBoundKey1 }, {&EV_ScriptThread_GetBoundKey2, &ScriptThread::EventGetBoundKey2 }, {&EV_ScriptThread_LocConvertString, &ScriptThread::EventLocConvertString }, {&EV_ScriptThread_SetScoreboardToggle, &ScriptThread::EventSetScoreboardToggle}, {&EV_ScriptThread_AddObjective, &ScriptThread::EventAddObjective }, {&EV_ScriptThread_SetCurrentObjective, &ScriptThread::EventSetCurrentObjective}, {&EV_ScriptThread_SetObjectiveLocation, &ScriptThread::SetObjectiveLocation }, {&EV_ScriptThread_ClearObjectiveLocation, &ScriptThread::ClearObjectiveLocation }, {&EV_ScriptThread_DrawHud, &ScriptThread::EventDrawHud }, {&EV_ScriptThread_RegisterCommand, &ScriptThread::EventRegisterCommand }, {&EV_ScriptThread_IsArray, &ScriptThread::EventIsArray }, {&EV_ScriptThread_IsDefined, &ScriptThread::EventIsDefined }, {&EV_ScriptThread_GetACos, &ScriptThread::EventACos }, {&EV_ScriptThread_GetASin, &ScriptThread::EventASin }, {&EV_ScriptThread_GetATan2, &ScriptThread::EventATan2 }, {&EV_ScriptThread_GetCeil, &ScriptThread::EventCeil }, {&EV_ScriptThread_GetCosH, &ScriptThread::EventCosH }, {&EV_ScriptThread_GetExp, &ScriptThread::EventExp }, {&EV_ScriptThread_GetFloor, &ScriptThread::EventFloor }, {&EV_ScriptThread_GetFmod, &ScriptThread::EventFmod }, {&EV_ScriptThread_GetFrexp, &ScriptThread::EventFrexp }, {&EV_ScriptThread_GetLdexp, &ScriptThread::EventLdexp }, {&EV_ScriptThread_GetLog, &ScriptThread::EventLog }, {&EV_ScriptThread_GetLog10, &ScriptThread::EventLog10 }, {&EV_ScriptThread_GetModf, &ScriptThread::EventModf }, {&EV_ScriptThread_GetPow, &ScriptThread::EventPow }, {&EV_ScriptThread_GetSinH, &ScriptThread::EventSinH }, {&EV_ScriptThread_GetTanH, &ScriptThread::EventTanH }, {&EV_ScriptThread_strncpy, &ScriptThread::StringBytesCopy }, {&EV_ScriptThread_Md5String, &ScriptThread::Md5String }, {&EV_ScriptThread_TypeOf, &ScriptThread::TypeOfVariable }, {&EV_ScriptThread_RegisterEv, &ScriptThread::RegisterEvent }, {&EV_ScriptThread_UnregisterEv, &ScriptThread::UnregisterEvent }, {&EV_ScriptThread_CancelWaiting, &ScriptThread::CancelWaiting }, {&EV_ScriptThread_GetTime, &ScriptThread::GetTime }, {&EV_ScriptThread_GetTimeZone, &ScriptThread::GetTimeZone }, {&EV_ScriptThread_PregMatch, &ScriptThread::PregMatch }, {&EV_ScriptThread_FlagClear, &ScriptThread::FlagClear }, {&EV_ScriptThread_FlagInit, &ScriptThread::FlagInit }, {&EV_ScriptThread_FlagSet, &ScriptThread::FlagSet }, {&EV_ScriptThread_FlagWait, &ScriptThread::FlagWait }, {&EV_ScriptThread_HudDraw_3d, &ScriptThread::EventHudDraw3d }, {&EV_ScriptThread_HudDraw_Timer, &ScriptThread::EventHudDrawTimer }, {&EV_ScriptThread_CanSwitchTeams, &ScriptThread::CanSwitchTeams }, {&EV_ScriptThread_CharToInt, &ScriptThread::CharToInt }, {&EV_ScriptThread_Conprintf, &ScriptThread::Conprintf }, {&EV_ScriptThread_CreateHUD, &ScriptThread::CreateHUD }, {&EV_ScriptThread_Earthquake2, &ScriptThread::Earthquake }, {&EV_ScriptThread_FadeSound, &ScriptThread::FadeSound }, {&EV_ScriptThread_FileClose, &ScriptThread::FileClose }, {&EV_ScriptThread_FileCopy, &ScriptThread::FileCopy }, {&EV_ScriptThread_FileEof, &ScriptThread::FileEof }, {&EV_ScriptThread_FileError, &ScriptThread::FileError }, {&EV_ScriptThread_FileExists, &ScriptThread::FileExists }, {&EV_ScriptThread_FileFlush, &ScriptThread::FileFlush }, {&EV_ScriptThread_FileGetc, &ScriptThread::FileGetc }, {&EV_ScriptThread_FileGets, &ScriptThread::FileGets }, {&EV_ScriptThread_FileList, &ScriptThread::FileList }, {&EV_ScriptThread_FileNewDirectory, &ScriptThread::FileNewDirectory }, {&EV_ScriptThread_FileOpen, &ScriptThread::FileOpen }, {&EV_ScriptThread_FilePutc, &ScriptThread::FilePutc }, {&EV_ScriptThread_FilePuts, &ScriptThread::FilePuts }, {&EV_ScriptThread_FileRead, &ScriptThread::FileRead }, {&EV_ScriptThread_FileReadAll, &ScriptThread::FileReadAll }, {&EV_ScriptThread_FileRemove, &ScriptThread::FileRemove }, {&EV_ScriptThread_FileRemoveDirectory, &ScriptThread::FileRemoveDirectory }, {&EV_ScriptThread_FileRename, &ScriptThread::FileRename }, {&EV_ScriptThread_FileRewind, &ScriptThread::FileRewind }, {&EV_ScriptThread_FileSaveAll, &ScriptThread::FileSaveAll }, {&EV_ScriptThread_FileSeek, &ScriptThread::FileSeek }, {&EV_ScriptThread_FileTell, &ScriptThread::FileTell }, {&EV_ScriptThread_FileWrite, &ScriptThread::FileWrite }, {&EV_ScriptThread_GetAreaEntities, &ScriptThread::GetAreaEntities }, {&EV_ScriptThread_GetArrayKeys, &ScriptThread::GetArrayKeys }, {&EV_ScriptThread_GetArrayValues, &ScriptThread::GetArrayValues }, {&EV_ScriptThread_GetDate, &ScriptThread::GetDate }, {&EV_ScriptThread_GetEntArray, &ScriptThread::GetEntArray }, {&EV_ScriptThread_GetPlayerClientNum, &ScriptThread::GetPlayerClientNum }, {&EV_ScriptThread_GetPlayerIP, &ScriptThread::GetPlayerIP }, {&EV_ScriptThread_GetPlayerNetname, &ScriptThread::GetPlayerNetname }, {&EV_ScriptThread_GetPlayerPing, &ScriptThread::GetPlayerPing }, {&EV_ScriptThread_iHudDraw3d, &ScriptThread::EventIHudDraw3d }, {&EV_ScriptThread_iHudDrawAlign, &ScriptThread::EventIHudDrawAlign }, {&EV_ScriptThread_iHudDrawAlpha, &ScriptThread::EventIHudDrawAlpha }, {&EV_ScriptThread_iHudDrawColor, &ScriptThread::EventIHudDrawColor }, {&EV_ScriptThread_iHudDrawFont, &ScriptThread::EventIHudDrawFont }, {&EV_ScriptThread_iHudDrawRect, &ScriptThread::EventIHudDrawRect }, {&EV_ScriptThread_iHudDrawShader, &ScriptThread::EventIHudDrawShader }, {&EV_ScriptThread_iHudDrawString, &ScriptThread::EventIHudDrawString }, {&EV_ScriptThread_iHudDrawTimer, &ScriptThread::EventIHudDrawTimer }, {&EV_ScriptThread_iHudDrawVirtualSize, &ScriptThread::EventIHudDrawVirtualSize}, {&EV_ScriptThread_IsOnGround, &ScriptThread::EventIsOnGround }, {&EV_ScriptThread_IsOutOfBounds, &ScriptThread::EventIsOutOfBounds }, {&EV_ScriptThread_RestoreSound, &ScriptThread::RestoreSound }, {&EV_ScriptThread_RemoveArchivedClass, &ScriptThread::RemoveArchivedClass }, {&EV_ScriptThread_ServerStufftext, &ScriptThread::ServerStufftext }, {&EV_ScriptThread_SetTimer, &ScriptThread::SetTimer }, {&EV_ScriptThread_TeamGetScore, &ScriptThread::TeamGetScore }, {&EV_ScriptThread_TeamSetScore, &ScriptThread::TeamSetScore }, {&EV_ScriptThread_TraceDetails, &ScriptThread::TraceDetails }, {&EV_ScriptThread_VisionGetNaked, &ScriptThread::VisionGetNaked }, {&EV_ScriptThread_VisionSetNaked, &ScriptThread::VisionSetNaked }, {NULL, NULL } }; MEM_BlockAlloc ScriptThread_allocator; void *ScriptThread::operator new(size_t size) { return ScriptThread_allocator.Alloc(); } void ScriptThread::operator delete(void *ptr) { ScriptThread_allocator.Free(ptr); } ScriptThread::ScriptThread() { m_ScriptVM = NULL; } ScriptThread::ScriptThread(ScriptClass *scriptClass, unsigned char *pCodePos) { m_ScriptVM = new ScriptVM(scriptClass, pCodePos, this); m_ScriptVM->m_ThreadState = THREAD_RUNNING; if (g_scripttrace->integer && CanScriptTracePrint()) { gi.DPrintf2("+++Constructor THREAD: %p %p\n", this, scriptClass); } } ScriptThread::~ScriptThread() { ScriptVM *vm; if (g_scripttrace->integer && CanScriptTracePrint()) { gi.DPrintf2("---Destructor THREAD: %p\n", this); } assert(m_ScriptVM); if (!m_ScriptVM) { // should never happen //throw ScriptException("Attempting to delete a dead thread."); gi.Error(ERR_DROP, "Attempting to delete a dead thread."); } vm = m_ScriptVM; m_ScriptVM = NULL; if (vm->ThreadState() == THREAD_WAITING) { vm->m_ThreadState = THREAD_RUNNING; Director.RemoveTiming(this); } else if (vm->ThreadState() == THREAD_SUSPENDED) { vm->m_ThreadState = THREAD_RUNNING; CancelWaitingAll(); } vm->NotifyDelete(); } ScriptClass *ScriptThread::GetScriptClass(void) { return m_ScriptVM->GetScriptClass(); } str ScriptThread::FileName(void) { return m_ScriptVM->Filename(); } void ScriptThread::StartedWaitFor(void) { Stop(); StartWaiting(); m_ScriptVM->Suspend(); } void ScriptThread::StoppedWaitFor(const_str name, bool bDeleting) { if (!m_ScriptVM) { return; } // The thread is deleted if the listener is deleting if (bDeleting) { delete this; return; } /////// // Openmohaa: allows waittill to timeout // CancelEventsOfType(EV_ScriptThread_CancelWaiting); /////// if (m_ScriptVM->m_ThreadState == THREAD_SUSPENDED) { if (name != 0) { if (m_ScriptVM->IsSuspended()) { Execute(); } else { m_ScriptVM->Resume(); } } else { StartTiming(); } } } void ScriptThread::StoppedNotify(void) { // This is invalid and we mustn't get here if (m_ScriptVM) { delete this; } } void ScriptThread::ScriptExecute(ScriptVariable *data, int dataSize, ScriptVariable& returnValue) { m_ScriptVM->m_ReturnValue = returnValue; ScriptExecuteInternal(data, dataSize); } void ScriptThread::ScriptExecuteInternal(ScriptVariable *data, int dataSize) { SafePtr currentThread; SafePtr previousThread; currentThread = Director.CurrentThread(); previousThread = this; Director.m_PreviousThread = Director.CurrentThread(); Director.m_CurrentThread = this; Stop(); m_ScriptVM->Execute(data, dataSize); // restore the previous values Director.m_CurrentThread = currentThread; Director.m_PreviousThread = previousThread; Director.ExecuteRunning(); } void ScriptThread::Execute(Event& ev) { Execute(&ev); } void ScriptThread::Execute(Event *ev) { assert(m_ScriptVM); try { if (ev == NULL) { ScriptExecuteInternal(); } else { ScriptVariable returnValue; returnValue.newPointer(); ScriptExecute(ev->data, ev->dataSize, returnValue); ev->AddValue(returnValue); } } catch (ScriptException& exc) { if (exc.bAbort) { gi.Error(ERR_DROP, "%s\n", exc.string.c_str()); } else { Com_Printf("^~^~^ Script Error: %s\n", exc.string.c_str()); } } } void ScriptThread::Execute(ScriptVariable *data, int dataSize) { ScriptExecuteInternal(data, dataSize); } void ScriptThread::Execute() { if (Director.iPaused > 0) { StartTiming(); } else { ScriptExecuteInternal(NULL, 0); } } ScriptThread *ScriptThread::CreateThreadInternal(const ScriptVariable& label) { return GetScriptClass()->CreateThreadInternal(label); } ScriptThread *ScriptThread::CreateScriptInternal(const ScriptVariable& label) { return GetScriptClass()->CreateScriptInternal(label); } void ScriptThread::StartTiming(void) { Stop(); m_ScriptVM->m_ThreadState = THREAD_WAITING; Director.AddTiming(this, level.inttime); } void ScriptThread::StartTiming(int time) { Stop(); m_ScriptVM->m_ThreadState = THREAD_WAITING; if (time < level.inttime) { time = level.inttime; } Director.AddTiming(this, time); } void ScriptThread::StartWaiting() { m_ScriptVM->m_ThreadState = THREAD_SUSPENDED; } void ScriptThread::Stop(void) { if (m_ScriptVM->ThreadState() == THREAD_WAITING) { m_ScriptVM->m_ThreadState = THREAD_RUNNING; Director.RemoveTiming(this); } else if (m_ScriptVM->ThreadState() == THREAD_SUSPENDED) { m_ScriptVM->m_ThreadState = THREAD_RUNNING; CancelWaitingAll(); } } void ScriptThread::Wait(float time) { StartTiming(level.inttime + time); m_ScriptVM->Suspend(); } void ScriptThread::Pause() { Stop(); m_ScriptVM->Suspend(); } void ScriptThread::Getcvar(Event *ev) { str varName = ev->GetString(1); str s = gi.Cvar_Get(varName.c_str(), "", 0)->string; if (strstr(s.c_str(), ".")) { for (int i = s.length() - 1; i >= 0; i--) { if (s[i] == '0') { s[i] = 0; } else { if (s[i] == '.') { s[i] = 0; } break; } } } ev->AddString(s); } void ScriptThread::GetRandomFloat(Event *ev) { ev->AddFloat(G_Random(ev->GetFloat(1))); } void ScriptThread::GetRandomInt(Event *ev) { ev->AddInteger(G_Random(ev->GetInteger(1))); } void ScriptThread::GetAbs(Event *ev) { ScriptVariable& val = ev->GetValue(1); if (val.GetType() == VARIABLE_INTEGER) { ev->AddInteger(ev->GetInteger(1)); } else { if (val.GetType() != VARIABLE_FLOAT) { throw ScriptException("abs applied to bad type '%s'", val.GetTypeName()); } ev->AddFloat(fabs(ev->GetFloat(1))); } } void ScriptThread::EventCos(Event *ev) { float arg; float value; arg = ev->GetFloat(1); value = cos(DEG2RAD(arg)); if (isnan(value)) { ScriptError("cos(%f) = NaN", arg); } ev->AddFloat(value); } void ScriptThread::EventSin(Event *ev) { float arg; float value; arg = ev->GetFloat(1); value = sin(DEG2RAD(arg)); if (isnan(value)) { ScriptError("sin(%f) = NaN", arg); } ev->AddFloat(value); } void ScriptThread::EventTan(Event *ev) { float arg; float value; arg = ev->GetFloat(1); value = tan(DEG2RAD(arg)); if (isnan(value)) { ScriptError("tan(%f) = NaN", arg); } ev->AddFloat(value); } void ScriptThread::EventATan(Event *ev) { float arg, arg2; float value; if (ev->NumArgs() > 1) { arg = ev->GetFloat(1); arg2 = ev->GetFloat(2); value = RAD2DEG(atan2(arg, arg2)); if (isnan(value)) { ScriptError("atan(%f, %f) = NaN", arg, arg2); } } else { arg = ev->GetFloat(1); value = RAD2DEG(atan(arg)); if (isnan(value)) { ScriptError("atan(%f) = NaN", arg); } } ev->AddFloat(value); } void ScriptThread::EventSqrt(Event *ev) { float arg; float value; arg = ev->GetFloat(1); value = sqrtf(DEG2RAD(arg)); if (isnan(value)) { ScriptError("sqrt(%f) = NaN", arg); } ev->AddFloat(value); } void ScriptThread::GetSelf(Event *ev) { ev->AddListener(m_ScriptVM->GetScriptClass()->GetSelf()); } void ScriptThread::CreateReturnThread(Event *ev) { m_ScriptVM->GetScriptClass()->CreateReturnThread(ev); } void ScriptThread::CreateThread(Event *ev) { m_ScriptVM->GetScriptClass()->CreateThread(ev); } void ScriptThread::ExecuteScript(Event *ev) { m_ScriptVM->GetScriptClass()->ExecuteScript(ev); } void ScriptThread::ExecuteReturnScript(Event *ev) { m_ScriptVM->GetScriptClass()->ExecuteReturnScript(ev); } void ScriptThread::EventGoto(Event *ev) { m_ScriptVM->EventGoto(ev); if (m_ScriptVM->IsSuspended()) { ScriptExecuteInternal(); } else { Stop(); m_ScriptVM->Resume(); } } void ScriptThread::EventThrow(Event *ev) { if (!m_ScriptVM->m_PrevCodePos) { return; } if (m_ScriptVM->EventThrow(ev)) { if (m_ScriptVM->IsSuspended()) { ScriptExecuteInternal(); } else { Stop(); m_ScriptVM->Resume(); } } else { // we make sure this won't get deleted SafePtr This = this; Stop(); if (!BroadcastEvent(0, *ev)) { m_ScriptVM->GetScriptClass()->EventThrow(ev); } if (This) { delete this; } } } // seems to work like EventThrow void ScriptThread::EventDelayThrow(Event *ev) { if (!m_ScriptVM->m_PrevCodePos) { return; } if (m_ScriptVM->EventThrow(ev)) { if (m_ScriptVM->IsSuspended()) { StartTiming(); } else { Stop(); m_ScriptVM->Resume(); } } else { // we make sure this won't get deleted SafePtr This = this; Stop(); if (!BroadcastEvent(0, *ev)) { m_ScriptVM->GetScriptClass()->EventDelayThrow(ev); } if (This) { delete this; } } } void ScriptThread::EventWait(Event *ev) { Wait((int)roundf(ev->GetFloat(1) * 1000.0f)); } void ScriptThread::EventWaitFrame(Event *ev) { Wait((int)roundf(level.frametime * 1000.0f)); } void ScriptThread::EventResume(Event *ev) { // Empty } void ScriptThread::EventPause(Event *ev) { Pause(); } void ScriptThread::EventEnd(Event *ev) { if (ev->NumArgs() > 0) { m_ScriptVM->End(ev->GetValue(1)); } else { m_ScriptVM->End(); } } void ScriptThread::Print(Event *ev) { if (!developer->integer) { return; } for (int i = 1; i <= ev->NumArgs(); i++) { gi.DPrintf2(ev->GetString(i).c_str()); } } void ScriptThread::Println(Event *ev) { if (!developer->integer) { return; } Print(ev); gi.DPrintf2("\n"); } void ScriptThread::DPrintln(Event *ev) { gentity_t *ent; int i; str message; if (!developer->integer) { return; } for (i = 1; i <= ev->NumArgs(); i++) { message += ev->GetString(i); } for (i = 0, ent = g_entities; i < game.maxclients; i++, ent++) { if (!ent->inuse || !ent->client) { continue; } gi.SendServerCommand(i, "print \"" HUD_MESSAGE_YELLOW "%s\n\"", message.c_str()); } } void ScriptThread::IPrintln(Event *ev) { str sString; int num = ev->NumArgs(); int i; for (i = 1; i <= ev->NumArgs(); i++) { sString += ev->GetString(i); } G_PrintToAllClients(gi.LV_ConvertString(sString), false); } void ScriptThread::IPrintlnBold(Event *ev) { str sString; int num = ev->NumArgs(); int i; for (i = 1; i <= ev->NumArgs(); i++) { sString += ev->GetString(i); } G_PrintToAllClients(gi.LV_ConvertString(sString), true); } void ScriptThread::IPrintln_NoLoc(Event *ev) { str sString; int num = ev->NumArgs(); int i; for (i = 1; i <= ev->NumArgs(); i++) { sString += ev->GetString(i); } G_PrintToAllClients(sString, false); } void ScriptThread::IPrintlnBold_NoLoc(Event *ev) { str sString; int num = ev->NumArgs(); int i; for (i = 1; i <= ev->NumArgs(); i++) { sString += ev->GetString(i); } G_PrintToAllClients(sString, true); } void ScriptThread::MPrint(Event *ev) { SimpleEntity *m_Self = (SimpleEntity *)m_ScriptVM->GetScriptClass()->GetSelf(); if (!m_Self || !m_Self->isSubclassOf(SimpleEntity)) { return; } for (int i = 1; i <= ev->NumArgs(); i++) { m_Self->MPrintf(ev->GetString(i)); } } void ScriptThread::MPrintln(Event *ev) { SimpleEntity *m_Self = (SimpleEntity *)m_ScriptVM->GetScriptClass()->GetSelf(); if (!m_Self || !m_Self->isSubclassOf(SimpleEntity)) { return; } MPrint(ev); m_Self->MPrintf("\n"); } void ScriptThread::Assert(Event *ev) { assert(ev->GetFloat(1)); } void ScriptThread::CastInt(Event *ev) { ev->AddInteger(ev->GetInteger(1)); } void ScriptThread::CastFloat(Event *ev) { ev->AddFloat(ev->GetFloat(1)); } void ScriptThread::CastString(Event *ev) { ev->AddString(ev->GetString(1)); } void ScriptThread::CastBoolean(Event *ev) { ev->AddInteger(ev->GetBoolean(1)); } void ScriptThread::CastEntity(Event *ev) { ev->AddListener((Listener *)ev->GetEntity(1)); } void ScriptThread::TriggerEvent(Event *ev) { ScriptVariable var; Entity *ent; var = ev->GetValue(1); var.CastConstArrayValue(); for (int i = var.arraysize(); i > 0; i--) { ent = var[i]->entityValue(); if (ent) { Event *event = new Event(EV_Activate); event->AddEntity(world); ent->ProcessEvent(event); } } } void ScriptThread::RegisterAliasAndCache(Event *ev) { //assert(!"ScriptThread::RegisterAliasAndCache needs to be implemented like ClientGameCommandManager::AliasCache"); gi.DPrintf("ScriptThread::RegisterAliasAndCache needs to be implemented like ClientGameCommandManager::AliasCache\n" ); } void ScriptThread::CacheResourceEvent(Event *ev) { CacheResource(ev->GetString(1)); } void ScriptThread::MapEvent(Event *ev) { if (level.mission_failed) { return; } G_BeginIntermission(ev->GetString(1), TRANS_BSP); } void ScriptThread::SetCvarEvent(Event *ev) { gi.cvar_set(ev->GetString(1), ev->GetString(2)); } void ScriptThread::EventDebugLine(Event *ev) { Vector start, end; float red, green, blue, alpha; red = 1; green = 1; blue = 1; alpha = 1; if (ev->NumArgs() == 5) { red = ev->GetFloat(3); green = ev->GetFloat(4); blue = ev->GetFloat(5); } else if (ev->NumArgs() == 6) { red = ev->GetFloat(3); green = ev->GetFloat(4); blue = ev->GetFloat(5); alpha = ev->GetFloat(6); } else if (ev->NumArgs() != 2) { ScriptError("debugline should have 2, 5, or 6 arguments"); } if (ev->IsVectorAt(1)) { start = ev->GetVector(1); } else if (ev->GetEntity(1)) { start = ev->GetEntity(1)->centroid; } else { ScriptError("argument 1 to debugline should be an entity or vector"); } if (ev->IsVectorAt(2)) { end = ev->GetVector(2); } else if (ev->GetEntity(2)) { end = ev->GetEntity(2)->centroid; } else { ScriptError("argument 2 to debugline should be an entity or vector"); } G_DebugLine(start, end, red, green, blue, alpha); } void ScriptThread::CueCamera(Event *ev) { float switchTime; Entity *ent; if (ev->NumArgs() > 1) { switchTime = ev->GetFloat(2); } else { switchTime = 0; } ent = ev->GetEntity(1); if (ent) { SetCamera(ent, switchTime); } else { throw ScriptException("Camera named %s not found", ev->GetString(1).c_str()); } } void ScriptThread::CuePlayer(Event *ev) { float switchTime; if (ev->NumArgs() > 0) { switchTime = ev->GetFloat(1); } else { switchTime = 0; } SetCamera(NULL, switchTime); } void ScriptThread::FreezePlayer(Event *ev) { level.playerfrozen = true; } void ScriptThread::ReleasePlayer(Event *ev) { level.playerfrozen = false; } Listener *ScriptThread::SpawnInternal(Event *ev) { SpawnArgs args; str classname; Listener *l; if (ev->NumArgs() <= 0) { throw ScriptException("Usage: spawn entityname [keyname] [value]..."); } classname = ev->GetString(1); if (getClassForID(classname) || getClass(classname)) { args.setArg("classname", classname); } else { if (!strstr(classname.c_str(), ".tik")) { classname.append(".tik"); } args.setArg("model", classname); } for (int i = 2; i < ev->NumArgs(); i += 2) { args.setArg(ev->GetString(i), ev->GetString(i + 1)); } if (!args.getClassDef()) { throw ScriptException("'%s' is not a valid entity name", classname.c_str()); } const char *spawntarget = args.getArg("spawntarget"); if (spawntarget) { SimpleEntity *target = G_FindTarget(NULL, spawntarget); if (!target) { throw ScriptException("Can't find targetname %s", spawntarget); } args.setArg("origin", va("%f %f %f", target->origin[0], target->origin[1], target->origin[2])); args.setArg("angle", va("%f", target->angles[1])); } level.spawnflags = 0; const char *s = args.getArg("spawnflags"); if (s) { level.spawnflags = atoi(s); } level.m_bScriptSpawn = true; l = args.Spawn(); level.m_bScriptSpawn = false; if (level.m_bRejectSpawn) { level.m_bRejectSpawn = false; throw ScriptException("Spawn command rejected for %s", classname.c_str()); } return l; } void ScriptThread::Spawn(Event *ev) { Listener *listener = SpawnInternal(ev); if (listener && checkInheritance(&Object::ClassInfo, listener->classinfo())) { throw ScriptException("You must specify an explicit classname for misc object tik models"); } } void ScriptThread::SpawnReturn(Event *ev) { Listener *listener = SpawnInternal(ev); ev->AddListener(listener); if (listener && checkInheritance(&Object::ClassInfo, listener->classinfo())) { throw ScriptException("You must specify an explicit classname for misc object tik models"); } } void ScriptThread::Letterbox(Event *ev) { level.m_letterbox_fraction = 1.0f / 8.0f; level.m_letterbox_time = ev->GetFloat(1); level.m_letterbox_time_start = ev->GetFloat(1); level.m_letterbox_dir = letterbox_in; if (ev->NumArgs() > 1) { level.m_letterbox_fraction = ev->GetFloat(2); } } void ScriptThread::ClearLetterbox(Event *ev) { level.m_letterbox_time = level.m_letterbox_time_start; level.m_letterbox_dir = letterbox_out; } void ScriptThread::SetLightStyle(Event *ev) { lightStyles.SetLightStyle(ev->GetInteger(1), ev->GetString(2)); } void ScriptThread::FadeIn(Event *ev) { level.m_fade_time_start = ev->GetFloat(1); level.m_fade_time = ev->GetFloat(1); level.m_fade_color[0] = ev->GetFloat(2); level.m_fade_color[1] = ev->GetFloat(3); level.m_fade_color[2] = ev->GetFloat(4); level.m_fade_alpha = ev->GetFloat(5); level.m_fade_type = fadein; level.m_fade_style = alphablend; if (ev->NumArgs() > 5) { level.m_fade_style = (fadestyle_t)ev->GetInteger(6); } } void ScriptThread::ClearFade(Event *ev) { level.m_fade_time = -1; level.m_fade_type = fadein; } void ScriptThread::FadeOut(Event *ev) { level.m_fade_time_start = ev->GetFloat(1); level.m_fade_time = ev->GetFloat(1); level.m_fade_color[0] = ev->GetFloat(2); level.m_fade_color[1] = ev->GetFloat(3); level.m_fade_color[2] = ev->GetFloat(4); level.m_fade_alpha = ev->GetFloat(5); level.m_fade_type = fadeout; level.m_fade_style = alphablend; if (ev->NumArgs() > 5) { level.m_fade_style = (fadestyle_t)ev->GetInteger(6); } } void ScriptThread::FadeSound(Event *ev) { // params float delaytime; float min_vol; Player *player; // variables float time; // code delaytime = ev->GetFloat(1); min_vol = ev->GetFloat(2); if (ev->NumArgs() > 2) { player = (Player *)ev->GetEntity(3); } else { player = NULL; } time = delaytime * 1000.0f; gi.SendServerCommand(player != nullptr ? player->edict - g_entities : 0, "fadesound2 %0.2f %f", time, min_vol); } void ScriptThread::MusicEvent(Event *ev) { const char *current; const char *fallback; current = NULL; fallback = NULL; current = ev->GetString(1); if (ev->NumArgs() > 1) { fallback = ev->GetString(2); } ChangeMusic(current, fallback, false); } void ScriptThread::MusicVolumeEvent(Event *ev) { float volume; float fade_time; volume = ev->GetFloat(1); fade_time = ev->GetFloat(2); ChangeMusicVolume(volume, fade_time); } void ScriptThread::RestoreMusicVolumeEvent(Event *ev) { float fade_time; fade_time = ev->GetFloat(1); RestoreMusicVolume(fade_time); } void ScriptThread::ForceMusicEvent(Event *ev) { const char *current; const char *fallback; current = NULL; fallback = NULL; current = ev->GetString(1); if (ev->NumArgs() > 1) { fallback = ev->GetString(2); } ChangeMusic(current, fallback, true); } void ScriptThread::SoundtrackEvent(Event *ev) { ChangeSoundtrack(ev->GetString(1)); } void ScriptThread::RestoreSoundtrackEvent(Event *ev) { RestoreSoundtrack(); } void ScriptThread::SetCinematic(Event *ev) { G_StartCinematic(); } void ScriptThread::SetNonCinematic(Event *ev) { G_StopCinematic(); } void ScriptThread::SetAllAIOff(Event *ev) { level.ai_on = qfalse; } void ScriptThread::SetAllAIOn(Event *ev) { level.ai_on = qtrue; } void ScriptThread::CenterPrint(Event *ev) { int j; gentity_t *other; for (j = 0; j < game.maxclients; j++) { other = &g_entities[j]; if (other->inuse && other->client) { gi.centerprintf(other, ev->GetString(1)); } } } void ScriptThread::LocationPrint(Event *ev) { int j; gentity_t *other; int x, y; x = ev->GetInteger(1); y = ev->GetInteger(2); for (j = 0; j < game.maxclients; j++) { other = &g_entities[j]; if (other->inuse && other->client) { gi.locationprintf(other, x, y, ev->GetString(3)); } } } void ScriptThread::ServerEvent(Event *ev) { Event *event = new Event(ev->GetString(1)); for (int i = 2; i <= ev->NumArgs(); i++) { event->AddValue(ev->GetValue(i)); } ProcessScriptEvent(event); } void ScriptThread::StuffCommand(Event *ev) { gi.SendConsoleCommand(va("%s\n", ev->GetString(1).c_str())); } void ScriptThread::KillEnt(Event *ev) { int num; Entity *ent; if (ev->NumArgs() != 1) { throw ScriptException("No args passed in"); } num = ev->GetInteger(1); if ((num < 0) || (num >= globals.max_entities)) { throw ScriptException("Value out of range. Possible values range from 0 to %d.\n", globals.max_entities); } ent = G_GetEntity(num); ent->Damage(world, world, ent->max_health + 25, vec_zero, vec_zero, vec_zero, 0, 0, 0); } void ScriptThread::GetEntByEntnum(Event *ev) { int entnum = -1; Entity *ent; entnum = ev->GetInteger(1); if (entnum < 0 || entnum > globals.max_entities) { throw ScriptException("Entity number %d out of scope!\n", entnum); } ent = G_GetEntity(entnum); ev->AddEntity(ent); } void ScriptThread::RemoveEnt(Event *ev) { int num; Entity *ent; if (ev->NumArgs() != 1) { throw ScriptException("No args passed in"); } num = ev->GetInteger(1); if ((num < 0) || (num >= globals.max_entities)) { throw ScriptException("Value out of range. Possible values range from 0 to %d.\n", globals.max_entities); } ent = G_GetEntity(num); ent->PostEvent(Event(EV_Remove), 0); } void ScriptThread::KillClass(Event *ev) { int except; str classname; gentity_t *from; Entity *ent; if (ev->NumArgs() < 1) { throw ScriptException("No args passed in"); } classname = ev->GetString(1); except = 0; if (ev->NumArgs() == 2) { except = ev->GetInteger(1); } for (from = &g_entities[game.maxclients]; from < &g_entities[globals.num_entities]; from++) { if (!from->inuse) { continue; } assert(from->entity); ent = from->entity; if (ent->entnum == except) { continue; } if (ent->inheritsFrom(classname.c_str())) { ent->Damage(world, world, ent->max_health + 25, vec_zero, vec_zero, vec_zero, 0, 0, 0); } } } void ScriptThread::RemoveClass(Event *ev) { int except; str classname; gentity_t *from; Entity *ent; if (ev->NumArgs() < 1) { throw ScriptException("No args passed in"); } classname = ev->GetString(1); except = 0; if (ev->NumArgs() == 2) { except = ev->GetInteger(1); } for (from = &g_entities[game.maxclients]; from < &g_entities[globals.num_entities]; from++) { if (!from->inuse) { continue; } assert(from->entity); ent = from->entity; if (ent->entnum == except) { continue; } if (ent->inheritsFrom(classname.c_str())) { ent->PostEvent(Event(EV_Remove), 0); } } } void ScriptThread::CameraCommand(Event *ev) { Event *e; str cmd; int i; int n; if (!ev->NumArgs()) { throw ScriptException("Usage: cam [command] [arg 1]...[arg n]"); } cmd = ev->GetString(1); if (Event::Exists(cmd)) { e = new ConsoleEvent(cmd); n = ev->NumArgs(); for (i = 2; i <= n; i++) { e->AddToken(ev->GetToken(i)); } CameraMan.ProcessEvent(e); } else { throw ScriptException("Unknown camera command '%s'.\n", cmd.c_str()); } } void ScriptThread::MissionFailed(Event *ev) { G_MissionFailed(); } void ScriptThread::Archive(Archiver& arc) {} void ScriptThread::ArchiveInternal(Archiver& arc) { Listener::Archive(arc); arc.ArchiveObjectPosition(this); m_ScriptVM->Archive(arc); } void ScriptThread::Vector_Add(Event *ev) { ev->AddVector(ev->GetVector(1) + ev->GetVector(2)); } void ScriptThread::Vector_Subtract(Event *ev) { ev->AddVector(ev->GetVector(1) - ev->GetVector(2)); } void ScriptThread::Vector_Length(Event *ev) { ev->AddFloat(ev->GetVector(1).length()); } void ScriptThread::Vector_Normalize(Event *ev) { Vector vector = ev->GetVector(1); vector.normalize(); ev->AddVector(vector); } void ScriptThread::Vector_Scale(Event *ev) { Vector vector = ev->GetVector(1); vector *= ev->GetFloat(2); ev->AddVector(vector); } void ScriptThread::Vector_DotProduct(Event *ev) { Vector vector1 = ev->GetVector(1), vector2 = ev->GetVector(2); ev->AddFloat(Vector::Dot(vector1, vector2)); } void ScriptThread::Vector_CrossProduct(Event *ev) { ev->AddVector(Vector::Cross(ev->GetVector(1), ev->GetVector(2))); } void ScriptThread::Vector_ToAngles(Event *ev) { Vector v1; Vector v3; v1 = ev->GetVector(1); vectoangles(v1, v3); ev->AddVector(v3); } void ScriptThread::Angles_ToForward(Event *ev) { Vector v1; Vector v3; v1 = ev->GetVector(1); AngleVectors(v1, v3, NULL, NULL); ev->AddVector(v3); } void ScriptThread::Angles_ToLeft(Event *ev) { Vector v1; Vector v3; v1 = ev->GetVector(1); AngleVectors(v1, NULL, v3, NULL); ev->AddVector(v3); } void ScriptThread::Angles_ToUp(Event *ev) { Vector v1; Vector v3; v1 = ev->GetVector(1); AngleVectors(v1, NULL, NULL, v3); ev->AddVector(v3); } void ScriptThread::Angles_PointAt(Event *ev) { Entity *pParent, *pEnt, *pTarget; Vector vDelta, vVec, vAngles; pParent = ev->GetEntity(1); pEnt = ev->GetEntity(2); pTarget = ev->GetEntity(3); if (pParent) { vDelta = pEnt->centroid - pTarget->centroid; vVec[0] = DotProduct(vDelta, pParent->orientation[0]); vVec[1] = DotProduct(vDelta, pParent->orientation[1]); vVec[2] = DotProduct(vDelta, pParent->orientation[2]); } else { vVec = pEnt->centroid - pTarget->centroid; } VectorNormalize(vVec); vectoangles(vVec, vAngles); ev->AddVector(vAngles); } void ScriptThread::EventIsAlive(Event *ev) { Entity *ent; if (!ev->IsEntityAt(1)) { ev->AddInteger(false); return; } ent = ev->GetEntity(1); if (!ent) { ev->AddInteger(false); return; } ev->AddInteger(ent->health > 0); } void ScriptThread::EventPopmenu(Event *ev) { gentity_t *ent; int i; int index; if (game.maxclients <= 0) { return; } index = ev->GetInteger(1); for (i = 0, ent = g_entities; i < game.maxclients; i++, ent++) { if (!ent->inuse || !ent->client) { continue; } gi.Popmenu(i, index); } } void Showmenu(const str& name, qboolean bForce) { gentity_t *ent; int i; if (game.maxclients <= 0) { return; } for (i = 0, ent = g_entities; i < game.maxclients; i++, ent++) { if (!ent->inuse || !ent->client) { continue; } gi.Showmenu(i, name.c_str(), bForce); } } void ScriptThread::EventShowmenu(Event *ev) { str name = ev->GetString(1); if (ev->NumArgs() > 1) { Showmenu(name, ev->GetBoolean(2)); } else { Showmenu(name, false); } Director.AddMenu(name); } void Hidemenu(const str& name, qboolean bForce) { gentity_t *ent; int i; if (game.maxclients <= 0) { return; } for (i = 0, ent = g_entities; i < game.maxclients; i++, ent++) { if (!ent->inuse || !ent->client) { continue; } gi.Hidemenu(i, name.c_str(), bForce); } } void ScriptThread::EventHidemenu(Event *ev) { str name = ev->GetString(1); Director.RemoveMenu(name); if (ev->NumArgs() > 1) { Hidemenu(name, ev->GetBoolean(2)); } else { Hidemenu(name, false); } } void ScriptThread::EventPlayMovie(Event *ev) { gi.SendConsoleCommand(va("cinematic %s", ev->GetString(1).c_str())); } void ScriptThread::EventPushmenu(Event *ev) { gentity_t *ent; int i; str name; if (game.maxclients <= 0) { return; } name = ev->GetString(1); for (i = 0, ent = g_entities; i < game.maxclients; i++, ent++) { if (!ent->inuse || !ent->client) { continue; } gi.Pushmenu(i, name.c_str()); } } void ScriptThread::EventHideMouse(Event *ev) { gentity_t *ent; int i; for (i = 0, ent = g_entities; i < game.maxclients; i++, ent++) { if (!ent->inuse || !ent->client) { continue; } gi.HideMouseCursor(i); } } void ScriptThread::EventCreateListener(Event *ev) { ev->AddListener(new Listener); } void ScriptThread::EventTrace(Event *ev) { int content_mask = MASK_LINE; Vector start; Vector mins; Vector maxs; Vector end; trace_t trace; mins = vec_zero; maxs = vec_zero; switch (ev->NumArgs()) { case 5: maxs = ev->GetVector(5); case 4: mins = ev->GetVector(4); case 3: if (ev->GetInteger(3)) { content_mask &= ~MASK_SCRIPT_SLAVE; } case 2: end = ev->GetVector(2); case 1: start = ev->GetVector(1); break; default: throw ScriptException("Wrong number of arguments for trace."); } // call trace trace = G_Trace(start, mins, maxs, end, NULL, content_mask, false, "ScriptThread::EventTrace"); ev->AddVector(trace.endpos); } void ScriptThread::EventSightTrace(Event *ev) { int content_mask = MASK_SOLID; Vector start; Vector mins; Vector maxs; Vector end; mins = vec_zero; maxs = vec_zero; switch (ev->NumArgs()) { case 5: maxs = ev->GetVector(5); case 4: mins = ev->GetVector(4); case 3: if (ev->GetInteger(3)) { content_mask &= ~MASK_IGNORE_ENTS; } case 2: end = ev->GetVector(2); case 1: start = ev->GetVector(1); break; default: throw ScriptException("Wrong number of arguments for sighttrace."); } // call trace ev->AddInteger(G_SightTrace( start, mins, maxs, end, (gentity_t *)NULL, (gentity_t *)NULL, content_mask, false, "ScriptThread::EventSightTrace" )); } void ScriptThread::EventPrint3D(Event *ev) { Vector origin; float scale; str string; origin = ev->GetVector(1); scale = ev->GetFloat(2); string = ev->GetString(3); G_DebugString(origin, scale, 1.0f, 1.0f, 1.0f, string); } void ScriptThread::EventHudDrawShader(Event *ev) { int index = -1; str shadername; index = ev->GetInteger(1); if (index < 0 && index > 255) { throw ScriptException("Wrong index for huddraw_shader!\n"); } shadername = ev->GetString(2); HudDrawShader(index, shadername); } void ScriptThread::EventHudDrawAlign(Event *ev) { int index = -1; int h_alignement = -1; int v_alignement = -1; str h_align; str v_align; index = ev->GetInteger(1); if (index < 0 && index > 255) { throw ScriptException("Wrong index for huddraw_align!\n"); } h_align = ev->GetString(2); if (!h_align) { throw ScriptException("h_align is NULL for huddraw_align!\n"); } v_align = ev->GetString(3); if (!v_align) { throw ScriptException("v_align is NULL for huddraw_align!\n"); } if (h_align == "left") { h_alignement = 0; } else if (h_align == "center") { h_alignement = 1; } else if (h_align == "right") { h_alignement = 2; } else { throw ScriptException("Wrong alignment h_align string for huddraw_align!\n"); } if (v_align == "top") { v_alignement = 0; } else if (v_align == "center") { v_alignement = 1; } else if (v_align == "bottom") { v_alignement = 2; } else { throw ScriptException("Wrong alignment v_align string for huddraw_align!\n"); } HudDrawAlign(index, h_alignement, v_alignement); } void ScriptThread::EventHudDrawRect(Event *ev) { int index = -1; int x = 0; int y = 0; int width = 0; int height = 0; index = ev->GetInteger(1); if (index < 0 && index > 255) { throw ScriptException("Wrong index for huddraw_rect!\n"); } x = ev->GetInteger(2); y = ev->GetInteger(3); width = ev->GetInteger(4); height = ev->GetInteger(5); HudDrawRect(index, x, y, width, height); } void ScriptThread::EventHudDrawVirtualSize(Event *ev) { int index = -1; int virt = -1; index = ev->GetInteger(1); if (index < 0 && index > 255) { throw ScriptException("Wrong index for huddraw_virtualsize!\n"); } virt = ev->GetInteger(2); if (virt != 0) { virt = 1; } HudDrawVirtualSize(index, virt); } void ScriptThread::EventHudDrawColor(Event *ev) { int numArgs = -1; int index = -1; Vector color; numArgs = ev->NumArgs(); index = ev->GetInteger(1); if (index < 0 && index > 255) { throw ScriptException("Wrong index for ihuddraw_color!\n"); } color[0] = ev->GetFloat(2); // red color[1] = ev->GetFloat(3); // green color[2] = ev->GetFloat(4); // blue Vector::Clamp(color, vec_zero, Vector(1, 1, 1)); HudDrawColor(index, color); } void ScriptThread::EventHudDrawAlpha(Event *ev) { int index = -1; float alpha = 0.0f; index = ev->GetInteger(1); if (index < 0 && index > 255) { throw ScriptException("Wrong index for ihuddraw_alpha!\n"); } alpha = ev->GetFloat(2); Q_clamp(alpha, 0, 1); HudDrawAlpha(index, alpha); } void ScriptThread::EventHudDrawString(Event *ev) { int index = -1; str string; index = ev->GetInteger(1); if (index < 0 && index > 255) { throw ScriptException("Wrong index for ihuddraw_string!\n"); } string = ev->GetString(2); HudDrawString(index, string); } void ScriptThread::EventHudDrawFont(Event *ev) { int index = -1; str fontname; index = ev->GetInteger(1); if (index < 0 && index > 255) { throw ScriptException("Wrong index for ihuddraw_font!\n"); } fontname = ev->GetString(2); HudDrawFont(index, fontname); } void ScriptThread::EventError(Event *ev) { if (ev->NumArgs() > 1) { ScriptException::next_abort = 0; } else { ScriptException::next_abort = ev->GetInteger(2); if (ScriptException::next_abort < 0) { ScriptException::next_abort = 0; } } throw ScriptException(ev->GetString(1)); } void ScriptThread::EventDebugInt3(Event *ev) { #ifdef _MSC_VER __debugbreak(); #endif // FIXME: break on other platforms? } void ScriptThread::EventTimeout(Event *ev) { Director.maxTime = roundf(ev->GetFloat(1) * 1000.0f); } void ScriptThread::EventLandmineDamage(Event *ev) { Entity *landmine; float damage; float radius; Entity *owner; landmine = ev->GetEntity(1); damage = ev->GetFloat(2); radius = ev->GetFloat(3); if (!landmine || !landmine->edict) { ScriptError("Landmine doesn't exist, yet explodes!.\n"); } owner = G_GetEntity(landmine->edict->r.ownerNum); RadiusDamage(landmine->origin, landmine, owner, damage, NULL, MOD_LANDMINE, radius); } void ScriptThread::EventRadiusDamage(Event *ev) { Vector origin; float damage; float radius; int constant_damage; origin = ev->GetVector(1); damage = ev->GetFloat(2); radius = ev->GetFloat(3); if (ev->NumArgs() > 3) { constant_damage = ev->GetInteger(4); } else { constant_damage = 0; } RadiusDamage(origin, world, world, damage, NULL, MOD_EXPLOSION, radius, 0, constant_damage); } void ScriptThread::EventBspTransition(Event *ev) { str map = ev->GetString(1); if (level.intermissiontime == 0.0f) { G_BeginIntermission(map, TRANS_BSP); } } void ScriptThread::EventLevelTransition(Event *ev) { str map = ev->GetString(1); if (level.intermissiontime == 0.0f) { G_BeginIntermission(map, TRANS_LEVEL); } } void ScriptThread::EventMissionTransition(Event *ev) { str map = ev->GetString(1); if (level.intermissiontime == 0.0f) { G_BeginIntermission(map, TRANS_MISSION); } } void ScriptThread::EventStopTeamRespawn(Event *ev) { const_str team = ev->GetConstString(1); switch (team) { case STRING_GERMAN: dmManager.StopTeamRespawn(CONTROLLER_AXIS); break; case STRING_AMERICAN: dmManager.StopTeamRespawn(CONTROLLER_ALLIES); break; case STRING_BOTH: dmManager.StopTeamRespawn(CONTROLLER_AXIS); dmManager.StopTeamRespawn(CONTROLLER_ALLIES); break; default: ScriptError("stopteamrespawn must belong to 'american' or 'german' or 'both'"); break; } } void ScriptThread::EventTeamWin(Event *ev) { const_str team; int teamnum; if (g_gametype->integer < GT_OBJECTIVE) { throw ScriptException("'teamwin' only valid for objective-based DM games"); } team = ev->GetConstString(1); if (team == STRING_ALLIES) { teamnum = TEAM_ALLIES; } else if (team == STRING_AXIS) { teamnum = TEAM_AXIS; } else if (team == STRING_DISGUISE_NONE) { teamnum = TEAM_NONE; } else { throw ScriptException("'teamwin' must be called with 'axis', 'allies' or 'none' as its argument"); } dmManager.TeamWin(teamnum); } void ScriptThread::EventEarthquake(Event *ev) { earthquake_t e; e.duration = (int)roundf(ev->GetFloat(1) * 1000.0f); if (e.duration <= 0) { return; } e.magnitude = ev->GetFloat(2); e.no_rampup = ev->GetBoolean(3); e.no_rampdown = ev->GetBoolean(4); e.starttime = level.inttime; e.endtime = level.inttime + e.duration; e.m_Thread = this; level.AddEarthquake(&e); } void ScriptThread::EventAIsCloserThanBToC(Event *ev) { Vector vA, vB, vC; vA = ev->GetVector(1); vB = ev->GetVector(2); vC = ev->GetVector(3); ev->AddInteger((vA - vC).lengthSquared() < (vB - vC).lengthSquared()); } void ScriptThread::EventPointsWithinDist(Event *ev) { Vector delta; Vector v1, v2; float fDistance; v1 = ev->GetVector(1); v2 = ev->GetVector(2); fDistance = ev->GetFloat(3); delta = v1 - v2; // check squared distance ev->AddInteger(delta.lengthSquared() < Square(fDistance)); } bool ScriptThread::CanScriptTracePrint(void) { return m_ScriptVM->CanScriptTracePrint(); } void ScriptThread::EventGetBoundKey1(Event *ev) { int iKey1; int iKey2; const char *pszKeyName; str sCommand = ev->GetString(1); gi.Key_GetKeysForCommand(sCommand, &iKey1, &iKey2); if (iKey1) { pszKeyName = gi.Key_KeynumToBindString(iKey1); } else { pszKeyName = ""; } ev->AddString(pszKeyName); } void ScriptThread::EventGetBoundKey2(Event *ev) { int iKey1; int iKey2; const char *pszKeyName; str sCommand = ev->GetString(1); gi.Key_GetKeysForCommand(sCommand, &iKey1, &iKey2); if (iKey2) { pszKeyName = gi.Key_KeynumToBindString(iKey2); } else { pszKeyName = ""; } ev->AddString(pszKeyName); } void ScriptThread::EventLocConvertString(Event *ev) { ev->AddString(gi.LV_ConvertString(ev->GetString(1))); } void ScriptThread::AddObjective(int index, int status, str text, Vector location) { static int last_time; int flags; char szSend[2048]; char *sTmp; flags = OBJ_FLAG_NONE; sTmp = gi.getConfigstring(CS_OBJECTIVES + index); switch (status) { case OBJ_STATUS_HIDDEN: flags = OBJ_FLAG_HIDDEN; break; case OBJ_STATUS_CURRENT: sTmp = Info_ValueForKey(sTmp, "flags"); if (!(atoi(sTmp) & OBJ_FLAG_CURRENT)) { if (last_time != level.inttime) { gi.Printf("An objective has been added!\n"); last_time = level.inttime; } } flags = OBJ_FLAG_CURRENT; break; case OBJ_STATUS_COMPLETED: if (last_time != level.inttime) { gi.Printf("An objective has been completed!\n"); last_time = level.inttime; } if (g_gametype->integer == GT_SINGLE_PLAYER) { if (g_entities->entity->IsSubclassOfPlayer()) { ((Player *)g_entities->entity)->m_iObjectivesCompleted++; } } flags = OBJ_FLAG_COMPLETED; break; } szSend[0] = 0; Info_SetValueForKey(szSend, "flags", va("%i", flags)); Info_SetValueForKey(szSend, "text", text.c_str()); Info_SetValueForKey(szSend, "loc", va("%f %f %f", location[0], location[1], location[2])); gi.setConfigstring(CS_OBJECTIVES + index, szSend); } void ScriptThread::SetCurrentObjective(int iObjective, int iTeam) { gi.setConfigstring(CS_CURRENT_OBJECTIVE, va("%i", iObjective)); if (iObjective == -1) { level.m_vObjectiveLocation = vec_zero; level.m_vAlliedObjectiveLocation = vec_zero; level.m_vAxisObjectiveLocation = vec_zero; } else { const char *s = gi.getConfigstring(CS_OBJECTIVES + iObjective); const char *loc = Info_ValueForKey(s, "loc"); Vector v; sscanf(loc, "%f %f %f", &v[0], &v[1], &v[2]); // // Since 2.0, allow objective location per team // switch (iTeam) { case TEAM_NONE: default: level.m_vObjectiveLocation = v; break; case TEAM_ALLIES: level.m_vAlliedObjectiveLocation = v; break; case TEAM_AXIS: level.m_vAxisObjectiveLocation = v; break; } } } void ScriptThread::EventAddObjective(Event *ev) { int index; int status; str text; Vector location; index = ev->GetInteger(1) - 1; status = ev->GetInteger(2); if (index >= MAX_OBJECTIVES) { throw ScriptException("Index Out Of Range"); } if (status > 3) { throw ScriptException("Invalid Status"); } if (ev->IsNilAt(3)) { text = Info_ValueForKey(gi.getConfigstring(index + CS_OBJECTIVES), "text"); } else { text = ev->GetString(3); } if (ev->IsNilAt(4)) { sscanf( Info_ValueForKey(gi.getConfigstring(index + CS_OBJECTIVES), "loc"), "%f %f %f", &location.x, &location.y, &location.z ); } else { location = ev->GetVector(4); } AddObjective(index, status, text, location); } void ScriptThread::EventSetScoreboardToggle(Event *ev) { int value; const_str team; if (ev->NumArgs() != 2) { ScriptError("wrong number of arguments: setscoreboardtoggle (axis|allies) (0|1)"); } value = ev->GetInteger(2); team = ev->GetConstString(1); switch (team) { case STRING_AXIS: gi.cvar_set("scoreboard_toggle2", va("%i", value)); break; case STRING_ALLIES: gi.cvar_set("scoreboard_toggle1", va("%i", value)); break; default: ScriptError("1st argument can only be \"axis\" or \"allies\""); break; } } void ScriptThread::EventSetCurrentObjective(Event *ev) { int iObjective = ev->GetInteger(1); int iTeam = 0; if (iObjective > MAX_OBJECTIVES) { ScriptError("Index Out Of Range"); } if (ev->NumArgs() >= 2) { const_str teamStr = ev->GetConstString(2); if (teamStr == STRING_ALLIES) { iTeam = TEAM_ALLIES; } else if (teamStr == STRING_AXIS) { iTeam = TEAM_AXIS; } else { ScriptError("Option 2nd argument can only be \"allies\" or \"axis\""); } } SetCurrentObjective(iObjective - 1, iTeam); } void ScriptThread::SetObjectiveLocation(Vector vLocation) { level.m_vObjectiveLocation = vLocation; } void ScriptThread::SetObjectiveLocation(Event *ev) { SetObjectiveLocation(ev->GetVector(1)); } void ScriptThread::ClearObjectiveLocation(void) { level.m_vObjectiveLocation = vec_zero; } void ScriptThread::ClearObjectiveLocation(Event *ev) { ClearObjectiveLocation(); } void ScriptThread::EventDrawHud(Event *ev) { int i; gentity_t *ent; // TRIVIA: in mohaa, drawhud worked only for the first player for (i = 0, ent = g_entities; i < game.maxclients; i++, ent++) { if (!ent->inuse || !ent->entity || !ent->client) { continue; } if (ev->GetBoolean(1)) { ent->client->ps.pm_flags &= ~PMF_NO_HUD; } else { ent->client->ps.pm_flags |= PMF_NO_HUD; } } } void ScriptThread::CancelWaiting(Event *ev) { CancelWaitingAll(); } void ScriptThread::DelayExecute(Event& ev) { DelayExecute(&ev); } void ScriptThread::DelayExecute(Event *ev) { assert(m_ScriptVM); if (ev) { ScriptVariable returnValue; m_ScriptVM->SetFastData(ev->data, ev->dataSize); returnValue.newPointer(); m_ScriptVM->m_ReturnValue = returnValue; ev->AddValue(returnValue); } Director.AddTiming(this, 0); } int ScriptThread::GetThreadState(void) { return m_ScriptVM->ThreadState(); } void ScriptThread::ServerStufftext(Event *ev) { gi.SendConsoleCommand(ev->GetString(1)); } void ScriptThread::RemoveArchivedClass(Event *ev) { str classname; int except_entity_number = -1; classname = ev->GetString(1); if (ev->NumArgs() > 1) { except_entity_number = ev->GetInteger(1); } for (int i = level.m_SimpleArchivedEntities.NumObjects(); i > 0; i--) { SimpleArchivedEntity *m_SimpleArchivedEntity = level.m_SimpleArchivedEntities.ObjectAt(i); if (m_SimpleArchivedEntity == NULL) { continue; } // If found, remove the simple archived entity if (m_SimpleArchivedEntity->inheritsFrom(classname)) { m_SimpleArchivedEntity->PostEvent(EV_Remove, EV_REMOVE); } } L_ProcessPendingEvents(); } void ScriptThread::SetTimer(Event *ev) { int interval = -1; void *scr_var = NULL; int i = 0; Event *event; if (ev->NumArgs() != 2) { throw ScriptException("Wrong arguments count for settimer!\n"); } interval = ev->GetInteger(1); if (interval <= 0) { ev->AddInteger(1); return; } event = new Event(EV_Listener_ExecuteScript); event->AddValue(ev->GetValue(2)); PostEvent(event, (float)interval / 1000.0f); } void ScriptThread::EventRegisterCommand(Event *ev) { ScriptThreadLabel scriptLabel; scriptLabel.SetThread(ev->GetValue(2)); m_scriptCmds.addKeyValue(ev->GetString(1)) = scriptLabel; } void ScriptThread::CreateHUD(Event *ev) { int clientNum = -1; if (ev->NumArgs() > 0) { Player *player = (Player *)ev->GetEntity(1); if (!player || !player->IsSubclassOfPlayer()) { throw ScriptException("Invalid player entity!\n"); } clientNum = player->client->ps.clientNum; } Hud *hud = new Hud(clientNum); ev->AddListener(hud); } void ScriptThread::Earthquake(Event *ev) { float duration = ev->GetFloat(1); float magnitude = ev->GetFloat(2); qboolean no_rampup = ev->GetBoolean(3); qboolean no_rampdown = ev->GetBoolean(4); if (ev->NumArgs() > 4) { Vector location = ev->GetVector(5); float radius = 1.0f; if (ev->NumArgs() > 5) { radius = ev->GetFloat(6); } gi.SendServerCommand( -1, "eq %f %f %d %d %f %f %f %f", duration, magnitude, no_rampup, no_rampdown, location[0], location[1], location[2], radius ); } else { gi.SendServerCommand(-1, "eq %f %f %d %d", duration, magnitude, no_rampup, no_rampdown); } } void ScriptThread::EventClearObjectives(Event *ev) {} void ScriptThread::SendObjective() {} void ScriptThread::SendObjectives() {} void ScriptThread::ClearObjectives() {} void ScriptThread::WaitSkip(Event *ev) {} void ScriptThread::ThreadSkip(Event *ev) {} void ScriptThread::RestoreSound(Event *ev) { // params float delaytime; float max_vol; Player *player; // variables float time; // code delaytime = ev->GetFloat(1); if (ev->NumArgs() > 1) { max_vol = ev->GetFloat(2); } else { max_vol = 1.0f; } if (ev->NumArgs() > 2) { player = (Player *)ev->GetEntity(3); } else { player = NULL; } time = delaytime * 1000.0f; gi.SendServerCommand(player != NULL ? player->edict - g_entities : 0, "restoresound %0.2f %f", time, max_vol); } void ScriptThread::EventHudDraw3d(Event *ev) { int index; float *tmp; vec3_t vector; int ent_num; qboolean bAlwaysShow, bDepth; index = ev->GetInteger(1); if (index < 0 && index > 255) { throw ScriptException("Wrong index for huddraw_3d!\n"); } tmp = ev->GetVector(2); memcpy(&vector, tmp, sizeof(vec3_t)); ent_num = ev->GetInteger(3); bAlwaysShow = ev->GetInteger(4); bDepth = ev->GetInteger(5); HudDraw3d(index, vector, ent_num, bAlwaysShow, bDepth); } void ScriptThread::EventHudDrawTimer(Event *ev) { int index; float duration; float fade_out_time; index = ev->GetInteger(1); if (index < 0 && index > 255) { throw ScriptException("Wrong index for huddraw_timer!\n"); } duration = ev->GetFloat(2); fade_out_time = ev->GetFloat(3); HudDrawTimer(index, duration, fade_out_time); } void ScriptThread::CanSwitchTeams(Event *ev) { qboolean bAllow = ev->GetBoolean(1); disable_team_change = !bAllow; if (ev->NumArgs() > 1) { qboolean bAllow2 = ev->GetBoolean(2); disable_team_spectate = !bAllow2; } } void ScriptThread::GetPlayerNetname(Event *ev) { Entity *ent = NULL; ent = (Entity *)ev->GetEntity(1); if (ent == NULL) { ev->AddString(""); return; } else if (ent->client == NULL) { ev->AddString(""); return; } ev->AddString(ent->client->pers.netname); } void ScriptThread::GetPlayerIP(Event *ev) { Entity *ent = NULL; char *ip = NULL; char ip_buff[65]; ent = (Entity *)ev->GetEntity(1); if (ent == NULL) { ev->AddString("NIL"); return; } else if (ent->client == NULL) { ev->AddString("NIL"); return; } ip = ent->client->pers.ip; Com_sprintf(ip_buff, sizeof(ip_buff), "%s:%i", ip, ent->client->pers.port); ev->AddString(ip_buff); } void ScriptThread::GetPlayerPing(Event *ev) { Entity *ent = NULL; int ping = -1; ent = (Entity *)ev->GetEntity(1); if (ent == NULL) { throw ScriptException("Player entity is NULL for getping!\n"); } else if (ent->client == NULL) { throw ScriptException("Entity is probably not of player type - getping\n"); } ping = ent->client->ps.ping; ev->AddInteger(ping); } void ScriptThread::GetPlayerClientNum(Event *ev) { Entity *ent = NULL; int cl_num = -1; ent = (Entity *)ev->GetEntity(1); if (ent == NULL) { throw ScriptException("Player entity is NULL for getclientnum!\n"); } else if (ent->client == NULL) { throw ScriptException("Entity is probably not of player type - getclientnum\n"); } cl_num = ent->client->ps.clientNum; ev->AddInteger(cl_num); } void ScriptThread::GetAreaEntities(Event *ev) { Vector origin; Vector mins; Vector maxs; Vector o_min; Vector o_max; int touch[MAX_GENTITIES]; int count; int j = 0; ScriptVariable *ref = new ScriptVariable, *array = new ScriptVariable; origin = ev->GetVector(1); mins = ev->GetVector(2); maxs = ev->GetVector(3); o_min = origin + mins; o_max = origin + maxs; count = gi.AreaEntities(o_min, o_max, touch, MAX_GENTITIES); ref->setRefValue(array); for (int i = 0; i < count; i++) { Entity *entity = G_GetEntity(touch[i]); if (entity == NULL) { continue; } ScriptVariable *index = new ScriptVariable, *value = new ScriptVariable; index->setIntValue(j); value->setListenerValue(entity); ref->setArrayAt(*index, *value); j++; } ev->AddValue(*array); } void ScriptThread::GetEntArray(Event *ev) { str name = ev->GetString(1); str key = ev->GetString(2); ScriptVariable array; ScriptVariable index, value; gentity_t *gentity = globals.gentities; Event *event = new Event(key, EV_GETTER); qboolean useEvent = event != NULL; qboolean createEvent = false; if (!event->eventnum) { delete event; useEvent = false; } int x = 0; for (int i = 0; i < globals.num_entities; i++, gentity++) { ScriptVariable returnValue; if (!gentity->inuse || gentity->entity == NULL) { continue; } if (createEvent) { event = new Event(key, EV_GETTER); createEvent = false; } Entity *entity = gentity->entity; if (useEvent) { createEvent = true; } if (!useEvent) { // Now look for variables if predefined keys are not specified ScriptVariableList *vars = entity->Vars(); if (vars == NULL) { continue; } // Get the variable from the key ScriptVariable *variable = vars->GetVariable(key); if (variable == NULL) { continue; } // Check if it matches with the name if (variable->stringValue() == name) { continue; } } else { const char *value = NULL; returnValue = entity->ProcessEventReturn(event); if (!event->NumArgs()) { continue; } value = returnValue.stringValue(); if (value == NULL) { continue; } if (strcmp(value, name) != 0) { continue; } } index.setIntValue(x); value.setListenerValue(entity); array.setArrayAt(index, value); x++; } ev->AddValue(array); } void ScriptThread::EventIHudDraw3d(Event *ev) { Player *player; int index; float *tmp; vec3_t vector; int ent_num; qboolean bAlwaysShow, bDepth; player = (Player *)ev->GetEntity(1); if (player == NULL) { throw ScriptException("Player entity is NULL for ihuddraw_3d!\n"); } index = ev->GetInteger(2); if (index < 0 && index > 255) { throw ScriptException("Wrong index for ihuddraw_3d!\n"); } tmp = ev->GetVector(3); memcpy(&vector, tmp, sizeof(vec3_t)); ent_num = ev->GetInteger(4); bAlwaysShow = ev->GetInteger(5); bDepth = ev->GetInteger(6); iHudDraw3d(player->edict - g_entities, index, vector, ent_num, bAlwaysShow, bDepth); } void ScriptThread::EventIHudDrawTimer(Event *ev) { Player *player; int index; float duration; float fade_out_time; player = (Player *)ev->GetEntity(1); if (player == NULL) { throw ScriptException("Player entity is NULL for ihuddraw_timer!\n"); } index = ev->GetInteger(2); if (index < 0 && index > 255) { throw ScriptException("Wrong index for ihuddraw_timer!\n"); } duration = ev->GetFloat(3); fade_out_time = ev->GetFloat(4); iHudDrawTimer(player->edict - g_entities, index, duration, fade_out_time); } void ScriptThread::EventIHudDrawShader(Event *ev) { int numArgs = -1; int index = -1; Entity *player = NULL; str shadername; numArgs = ev->NumArgs(); if (numArgs != 3) { throw ScriptException("Wrong arguments count for ihuddraw_shader!\n"); } player = (Entity *)ev->GetEntity(1); if (player == NULL) { throw ScriptException("Player entity is NULL for ihuddraw_shader!\n"); } index = ev->GetInteger(2); if (index < 0 && index > 255) { throw ScriptException("Wrong index for ihuddraw_shader!\n"); } shadername = ev->GetString(3); iHudDrawShader(player->edict - g_entities, index, shadername); } void ScriptThread::EventIHudDrawAlign(Event *ev) { int numArgs = -1; int index = -1; int h_alignement = -1; int v_alignement = -1; Entity *player = NULL; str h_align; str v_align; numArgs = ev->NumArgs(); if (numArgs != 4) { throw ScriptException("Wrong arguments count for ihuddraw_align!\n"); } player = (Entity *)ev->GetEntity(1); if (player == NULL) { throw ScriptException("Player entity is NULL for ihuddraw_align!\n"); } index = ev->GetInteger(2); if (index < 0 && index > 255) { throw ScriptException("Wrong index for ihuddraw_align!\n"); } h_align = ev->GetString(3); if (!h_align) { throw ScriptException("h_align is NULL for ihuddraw_align!\n"); } v_align = ev->GetString(4); if (!v_align) { throw ScriptException("v_align is NULL for ihuddraw_align!\n"); } if (h_align == "left") { h_alignement = 0; } else if (h_align == "center") { h_alignement = 1; } else if (h_align == "right") { h_alignement = 2; } else { throw ScriptException("Wrong alignment h_align string for ihuddraw_align!\n"); } if (v_align == "top") { v_alignement = 0; } else if (v_align == "center") { v_alignement = 1; } else if (v_align == "bottom") { v_alignement = 2; } else { throw ScriptException("Wrong alignment v_align string for ihuddraw_align!\n"); } iHudDrawAlign(player->edict - g_entities, index, h_alignement, v_alignement); } void ScriptThread::EventIHudDrawRect(Event *ev) { int numArgs = -1; int index = -1; Entity *player = NULL; int x = 0; int y = 0; int width = 0; int height = 0; numArgs = ev->NumArgs(); if (numArgs != 6) { throw ScriptException("Wrong arguments count for ihuddraw_rect!\n"); } player = (Entity *)ev->GetEntity(1); if (player == NULL) { throw ScriptException("Player entity is NULL for ihuddraw_rect!\n"); } index = ev->GetInteger(2); if (index < 0 && index > 255) { throw ScriptException("Wrong index for ihuddraw_rect!\n"); } x = ev->GetInteger(3); y = ev->GetInteger(4); width = ev->GetInteger(5); height = ev->GetInteger(6); iHudDrawRect(player->edict - g_entities, index, x, y, width, height); } void ScriptThread::EventIHudDrawVirtualSize(Event *ev) { int numArgs = -1; int index = -1; Entity *player = NULL; int virt = -1; numArgs = ev->NumArgs(); if (numArgs != 3) { throw ScriptException("Wrong arguments count for ihuddraw_virtualsize!\n"); } player = (Entity *)ev->GetEntity(1); if (player == NULL) { throw ScriptException("Player entity is NULL for ihuddraw_virtualsize!\n"); } index = ev->GetInteger(2); if (index < 0 && index > 255) { throw ScriptException("Wrong index for ihuddraw_virtualsize!\n"); } virt = ev->GetInteger(3); if (virt != 0) { virt = 1; } iHudDrawVirtualSize(player->edict - g_entities, index, virt); } void ScriptThread::EventIHudDrawColor(Event *ev) { int numArgs = -1; int index = -1; Entity *player = NULL; float color[3] = {0.0f, 0.0f, 0.0f}; numArgs = ev->NumArgs(); if (numArgs != 5) { throw ScriptException("Wrong arguments count for ihuddraw_color!\n"); } player = (Entity *)ev->GetEntity(1); if (player == NULL) { throw ScriptException("Player entity is NULL for ihuddraw_color!\n"); } index = ev->GetInteger(2); if (index < 0 && index > 255) { throw ScriptException("Wrong index for ihuddraw_color!\n"); } color[0] = ev->GetFloat(3); // red color[1] = ev->GetFloat(4); // green color[2] = ev->GetFloat(5); // blue iHudDrawColor(player->edict - g_entities, index, color); } void ScriptThread::EventIHudDrawAlpha(Event *ev) { int numArgs = -1; int index = -1; Entity *player = NULL; float alpha = 0.0f; numArgs = ev->NumArgs(); if (numArgs != 3) { throw ScriptException("Wrong arguments count for ihuddraw_alpha!\n"); } player = (Entity *)ev->GetEntity(1); if (player == NULL) { throw ScriptException("Player entity is NULL for ihuddraw_alpha!\n"); } index = ev->GetInteger(2); if (index < 0 && index > 255) { throw ScriptException("Wrong index for ihuddraw_alpha!\n"); } alpha = ev->GetFloat(3); iHudDrawAlpha(player->edict - g_entities, index, alpha); } void ScriptThread::EventIHudDrawString(Event *ev) { int numArgs = -1; int index = -1; Entity *player = NULL; str string; numArgs = ev->NumArgs(); if (numArgs != 3) { throw ScriptException("Wrong arguments count for ihuddraw_string!\n"); } player = (Entity *)ev->GetEntity(1); if (player == NULL) { throw ScriptException("Player entity is NULL for ihuddraw_string!\n"); } index = ev->GetInteger(2); if (index < 0 && index > 255) { throw ScriptException("Wrong index for ihuddraw_string!\n"); } string = ev->GetString(3); iHudDrawString(player->edict - g_entities, index, string); } void ScriptThread::EventIHudDrawFont(Event *ev) { int index; Entity *player = NULL; str fontname; if (ev->NumArgs() != 3) { throw ScriptException("Wrong arguments count for ihuddraw_font!\n"); } player = (Entity *)ev->GetEntity(1); if (player == NULL) { throw ScriptException("Player entity is NULL for ihuddraw_font!\n"); } index = ev->GetInteger(2); if (index < 0 && index > 255) { throw ScriptException("Wrong index for ihuddraw_font!\n"); } fontname = ev->GetString(3); iHudDrawFont(player->edict - g_entities, index, fontname); } void ScriptThread::EventIsOnGround(Event *ev) { Entity *entity = ev->GetEntity(1); ev->AddInteger(entity->groundentity != NULL); } void ScriptThread::EventIsOutOfBounds(Event *ev) { Entity *entity = ev->GetEntity(1); int areanum = gi.AreaForPoint(entity->origin); if (areanum == -1) { ev->AddInteger(1); } else { ev->AddInteger(0); } } void ScriptThread::TeamGetScore(Event *ev) { str teamname = ev->GetString(1); DM_Team *team = dmManager.GetTeam(teamname); if (!team) { throw ScriptException("Invalid team \"%s\"", teamname.c_str()); } if (team) { ev->AddInteger(team->m_teamwins); } } void ScriptThread::TeamSetScore(Event *ev) { str teamname; DM_Team *team; int score; qboolean bAdd = false; teamname = ev->GetString(1); team = dmManager.GetTeam(teamname); if (!team) { throw ScriptException("Invalid team \"%s\"", teamname.c_str()); } score = ev->GetInteger(2); if (ev->NumArgs() > 2) { bAdd = ev->GetInteger(3); } if (bAdd) { team->m_iKills += score; if (g_gametype->integer < 3) { team->m_teamwins += score; } } else { team->m_iKills = score; if (g_gametype->integer < 3) { team->m_teamwins = score; } } } void ScriptThread::CharToInt(Event *ev) { str c = ev->GetString(1); ev->AddInteger(c[0]); } void ScriptThread::Conprintf(Event *ev) { gi.Printf("%s", ev->GetString(1).c_str()); } void ScriptThread::FileOpen(Event *ev) { int numArgs = -1; str filename; str accesstype; FILE *f = NULL; char buf[16] = {0}; numArgs = ev->NumArgs(); if (numArgs != 2) { throw ScriptException("Wrong arguments count for fopen!\n"); } if (scriptfiles->integer == 32) { throw ScriptException( "Maximum count (32) of opened files is reached. Close at least one of them, to open new file - fopen!\n" ); } filename = ev->GetString(1); accesstype = ev->GetString(2); f = fopen(filename, accesstype); if (f == NULL) { ev->AddInteger(0); return; } else { ev->AddInteger((int)(size_t)f); Com_sprintf(buf, sizeof(buf), "%i", scriptfiles->integer + 1); gi.cvar_set("sv_scriptfiles", buf); return; } } void ScriptThread::FileWrite(Event *ev) {} void ScriptThread::FileRead(Event *ev) {} void ScriptThread::FileClose(Event *ev) { int id = 0; int numArgs = 0; int ret = 0; FILE *f = NULL; char buf[16] = {0}; numArgs = ev->NumArgs(); if (numArgs != 1) { throw ScriptException("Wrong arguments count for fclose!\n"); } id = ev->GetInteger(1); /*if( (int)scriptFiles[0].f != id && (int)scriptFiles[1].f != id ) { gi.Printf("Wrong file handle for fclose!\n"); return; } if( (int)scriptFiles[0].f == id ) { scriptFiles[0].inUse = 0; fclose( scriptFiles[0].f ); return; } else if( (int)scriptFiles[1].f == id ) { scriptFiles[1].inUse = 0; fclose( scriptFiles[1].f ); return; } else { gi.Printf("Unknown error while closing file - fclose!\n"); return; }*/ f = (FILE *)id; if (f == NULL) { throw ScriptException("File handle is NULL for fclose!\n"); } ret = fclose(f); if (ret == 0) { ev->AddInteger(0); Com_sprintf(buf, sizeof(buf), "%i", scriptfiles->integer - 1); gi.cvar_set("sv_scriptfiles", buf); return; } else { ev->AddInteger(ret); return; } } void ScriptThread::FileEof(Event *ev) { int id = 0; int numArgs = 0; int ret = 0; FILE *f = NULL; numArgs = ev->NumArgs(); if (numArgs != 1) { throw ScriptException("Wrong arguments count for feof!\n"); } id = ev->GetInteger(1); f = (FILE *)id; ret = feof(f); ev->AddInteger(ret); } void ScriptThread::FileSeek(Event *ev) { int id = 0; int numArgs = 0; int pos = 0; long int offset = 0; int ret = 0; FILE *f = NULL; numArgs = ev->NumArgs(); if (numArgs != 3) { throw ScriptException("Wrong arguments count for fseek!\n"); } id = ev->GetInteger(1); f = (FILE *)id; offset = ev->GetInteger(2); if (offset < 0) { throw ScriptException("Wrong file offset! Should be starting from 0. - fseek\n"); } pos = ev->GetInteger(3); if (pos != 0 && pos != 1 && pos != 2) { throw ScriptException("Wrong file offset start! Should be between 0 - 2! - fseek\n"); } ret = fseek(f, offset, pos); ev->AddInteger(ret); } void ScriptThread::FileTell(Event *ev) { int id = 0; int numArgs = 0; long int ret = 0; FILE *f = NULL; numArgs = ev->NumArgs(); if (numArgs != 1) { throw ScriptException("Wrong arguments count for ftell!\n"); } id = ev->GetInteger(1); f = (FILE *)id; ret = ftell(f); ev->AddInteger(ret); } void ScriptThread::FileRewind(Event *ev) { int id = 0; int numArgs = 0; long int ret = 0; FILE *f = NULL; numArgs = ev->NumArgs(); if (numArgs != 1) { throw ScriptException("Wrong arguments count for frewind!\n"); } id = ev->GetInteger(1); f = (FILE *)id; rewind(f); } void ScriptThread::FilePutc(Event *ev) { int id = 0; int numArgs = 0; int ret = 0; FILE *f = NULL; int c = 0; numArgs = ev->NumArgs(); if (numArgs != 2) { throw ScriptException("Wrong arguments count for fputc!\n"); } id = ev->GetInteger(1); f = (FILE *)id; c = ev->GetInteger(2); ret = fputc((char)c, f); ev->AddInteger(ret); } void ScriptThread::FilePuts(Event *ev) { int id = 0; int numArgs = 0; int ret = 0; FILE *f = NULL; str c; numArgs = ev->NumArgs(); if (numArgs != 2) { throw ScriptException("Wrong arguments count for fputs!\n"); } id = ev->GetInteger(1); f = (FILE *)id; c = ev->GetString(2); //gi.Printf("Putting line into a file\n"); ret = fputs(c, f); //gi.Printf("Ret val: %i\n", ret); ev->AddInteger(ret); } void ScriptThread::FileGetc(Event *ev) { int id = 0; int numArgs = 0; int ret = 0; FILE *f = NULL; numArgs = ev->NumArgs(); if (numArgs != 1) { throw ScriptException("Wrong arguments count for fgetc!\n"); } id = ev->GetInteger(1); f = (FILE *)id; ret = fgetc(f); ev->AddInteger(ret); } void ScriptThread::FileGets(Event *ev) { int id = 0; int numArgs = 0; int maxCount = 0; FILE *f = NULL; char *c = NULL; char *buff = NULL; numArgs = ev->NumArgs(); if (numArgs != 2) { throw ScriptException("Wrong arguments count for fgets!\n"); } id = ev->GetInteger(1); f = (FILE *)id; maxCount = ev->GetInteger(2); if (maxCount <= 0) { throw ScriptException("Maximum buffer size should be higher than 0! - fgets\n"); } buff = (char *)gi.Malloc(maxCount + 1); if (buff == NULL) { throw ScriptException( "Failed to allocate memory during fputs scriptCommand text buffer initialization! Try setting maximum " "buffer length lower.\n" ); ev->AddInteger(-1); } memset(buff, 0, maxCount + 1); c = fgets(buff, maxCount, f); if (c == NULL) { ev->AddString(""); } else { ev->AddString(c); } gi.Free(buff); } void ScriptThread::FileError(Event *ev) { int id = 0; int numArgs = 0; int ret = 0; FILE *f = NULL; numArgs = ev->NumArgs(); if (numArgs != 1) { throw ScriptException("Wrong arguments count for ferror!\n"); } id = ev->GetInteger(1); f = (FILE *)id; ret = ferror(f); ev->AddInteger(ret); } void ScriptThread::FileFlush(Event *ev) { int id = 0; int numArgs = 0; int ret = 0; FILE *f = NULL; numArgs = ev->NumArgs(); if (numArgs != 1) { throw ScriptException("Wrong arguments count for fflush!\n"); } id = ev->GetInteger(1); f = (FILE *)id; ret = fflush(f); ev->AddInteger(ret); } void ScriptThread::FileExists(Event *ev) { int id = 0; int numArgs = 0; FILE *f = 0; str filename; numArgs = ev->NumArgs(); if (numArgs != 1) { throw ScriptException("Wrong arguments count for fexists!\n"); } filename = ev->GetString(1); if (filename == NULL) { throw ScriptException("Empty file name passed to fexists!\n"); } f = fopen(filename, "r"); if (f) { fclose(f); ev->AddInteger(1); } else { ev->AddInteger(0); } } void ScriptThread::FileReadAll(Event *ev) { int id = 0; int numArgs = 0; FILE *f = NULL; char *ret = NULL; long currentPos = 0; size_t size = 0; size_t sizeRead = 0; numArgs = ev->NumArgs(); if (numArgs != 1) { throw ScriptException("Wrong arguments count for freadall!\n"); } id = ev->GetInteger(1); f = (FILE *)id; currentPos = ftell(f); fseek(f, 0, SEEK_END); size = ftell(f); fseek(f, currentPos, SEEK_SET); ret = (char *)gi.Malloc(sizeof(char) * size + 1); if (ret == NULL) { ev->AddInteger(-1); throw ScriptException("Error while allocating memory buffer for file content - freadall!\n"); } sizeRead = fread(ret, 1, size, f); ret[sizeRead] = '\0'; ev->AddString(ret); gi.Free(ret); } void ScriptThread::FileSaveAll(Event *ev) { int id = 0; int numArgs = 0; FILE *f = NULL; size_t sizeWrite = 0; str text; numArgs = ev->NumArgs(); if (numArgs != 2) { throw ScriptException("Wrong arguments count for fsaveall!\n"); } id = ev->GetInteger(1); f = (FILE *)id; text = ev->GetString(2); if (text == NULL) { ev->AddInteger(-1); throw ScriptException("Text to be written is NULL - fsaveall!\n"); } sizeWrite = fwrite(text, 1, strlen(text), f); ev->AddInteger((int)sizeWrite); } void ScriptThread::FileRemove(Event *ev) { int id = 0; int numArgs = 0; int ret = 0; str filename; numArgs = ev->NumArgs(); if (numArgs != 1) { throw ScriptException("Wrong arguments count for fremove!\n"); } filename = ev->GetString(1); if (filename == NULL) { throw ScriptException("Empty file name passed to fremove!\n"); } ret = remove(filename); ev->AddInteger(ret); } void ScriptThread::FileRename(Event *ev) { int id = 0; int numArgs = 0; int ret = 0; str oldfilename, newfilename; numArgs = ev->NumArgs(); if (numArgs != 2) { throw ScriptException("Wrong arguments count for frename!\n"); } oldfilename = ev->GetString(1); newfilename = ev->GetString(2); if (!oldfilename) { throw ScriptException("Empty old file name passed to frename!\n"); } if (!newfilename) { throw ScriptException("Empty new file name passed to frename!\n"); } ret = rename(oldfilename, newfilename); ev->AddInteger(ret); } void ScriptThread::FileCopy(Event *ev) { size_t n = 0; int numArgs = 0; unsigned int ret = 0; str filename, copyfilename; FILE *f = NULL, *fCopy = NULL; char buffer[4096]; numArgs = ev->NumArgs(); if (numArgs != 2) { throw ScriptException("Wrong arguments count for fcopy!\n"); } filename = ev->GetString(1); copyfilename = ev->GetString(2); if (!filename) { throw ScriptException("Empty file name passed to fcopy!\n"); } if (copyfilename) { throw ScriptException("Empty copy file name passed to fcopy!\n"); } f = fopen(filename, "rb"); if (f == NULL) { ev->AddInteger(-1); throw ScriptException("Could not open \"%s\" for copying - fcopy!\n", filename.c_str()); } fCopy = fopen(copyfilename, "wb"); if (fCopy == NULL) { fclose(f); ev->AddInteger(-2); throw ScriptException("Could not open \"%s\" for copying - fcopy!\n", copyfilename.c_str()); } while ((n = fread(buffer, sizeof(char), sizeof(buffer), f)) > 0) { if (fwrite(buffer, sizeof(char), n, fCopy) != n) { fclose(f); fflush(fCopy); fclose(fCopy); ev->AddInteger(-3); throw ScriptException("There was an error while copying files - fcopy!\n"); } } fclose(f); fflush(fCopy); fclose(fCopy); ev->AddInteger(0); } void ScriptThread::FileReadPak(Event *ev) { str filename; char *content = NULL; int numArgs = 0; int ret = 0; numArgs = ev->NumArgs(); if (numArgs != 1) { throw ScriptException("Wrong arguments count for freadpak!\n"); } filename = ev->GetString(1); if (filename == NULL) { throw ScriptException("Filename is NULL - freadpak!\n"); } ret = gi.FS_ReadFile(filename, (void **)&content, qtrue); if (content == NULL) { ev->AddInteger(-1); throw ScriptException("Error while reading pak file content - freadpak!\n"); } ev->AddString(content); } void ScriptThread::FileList(Event *ev) { int i = 0, numArgs = 0; const char *path = NULL; str extension; int wantSubs = 0; int numFiles = 0; char **list = NULL; ScriptVariable *ref = new ScriptVariable; ScriptVariable *array = new ScriptVariable; numArgs = ev->NumArgs(); if (numArgs != 3) { throw ScriptException("Wrong arguments count for flist!\n"); } path = ev->GetString(1); extension = ev->GetString(2); wantSubs = ev->GetInteger(3); list = gi.FS_ListFiles(path, extension, wantSubs, &numFiles); if (numFiles == 0) { gi.FS_FreeFileList(list); return; } ref->setRefValue(array); for (i = 0; i < numFiles; i++) { ScriptVariable *indexes = new ScriptVariable; ScriptVariable *values = new ScriptVariable; indexes->setIntValue(i); values->setStringValue(list[i]); ref->setArrayAt(*indexes, *values); } gi.FS_FreeFileList(list); ev->AddValue(*array); return; } void ScriptThread::FileNewDirectory(Event *ev) { str path; int numArgs = 0; int ret = 0; numArgs = ev->NumArgs(); if (numArgs != 1) { throw ScriptException("Wrong arguments count for fnewdir!\n"); } path = ev->GetString(1); if (path == NULL) { throw ScriptException("Path is NULL - fnewdir!\n"); } #ifdef WIN32 ret = _mkdir(path); #else ret = mkdir(path, 0777); #endif ev->AddInteger(ret); return; } void ScriptThread::FileRemoveDirectory(Event *ev) { str path; int numArgs = 0; int ret = 0; numArgs = ev->NumArgs(); if (numArgs != 1) { throw ScriptException("Wrong arguments count for fremovedir!\n"); } path = ev->GetString(1); if (path == NULL) { throw ScriptException("Path is NULL - fremovedir!\n"); } #ifdef WIN32 ret = _rmdir(path); #else ret = rmdir(path); #endif ev->AddInteger(ret); return; } void ScriptThread::GetArrayKeys(Event *ev) { Entity *ent = NULL; ScriptVariable array; ScriptVariable *value; int i = 0; int arraysize; /* Retrieve the array */ array = ev->GetValue(1); /* Cast the array */ array.CastConstArrayValue(); arraysize = array.arraysize(); if (arraysize < 1) { return; } ScriptVariable *ref = new ScriptVariable, *newArray = new ScriptVariable; ref->setRefValue(newArray); for (int i = 1; i <= arraysize; i++) { value = array[i]; /* Get the array's name */ //str name = value->getName(); gi.Printf("name = %s\n", value->GetTypeName()); ScriptVariable *newIndex = new ScriptVariable, *newValue = new ScriptVariable; newIndex->setIntValue(i); newValue->setStringValue("NIL"); //name.removeRef(); ref->setArrayAt(*newIndex, *newValue); } ev->AddValue(*newArray); } void ScriptThread::GetArrayValues(Event *ev) { Entity *ent = NULL; ScriptVariable array; ScriptVariable *value; int i = 0; int arraysize; /* Retrieve the array */ array = ev->GetValue(1); if (array.GetType() == VARIABLE_NONE) { return; } /* Cast the array */ array.CastConstArrayValue(); arraysize = array.arraysize(); if (arraysize < 1) { return; } ScriptVariable *ref = new ScriptVariable, *newArray = new ScriptVariable; ref->setRefValue(newArray); for (int i = 1; i <= arraysize; i++) { value = array[i]; ScriptVariable *newIndex = new ScriptVariable; newIndex->setIntValue(i - 1); ref->setArrayAt(*newIndex, *value); } ev->AddValue(*newArray); } void ScriptThread::GetDate(Event *ev) { char buff[1024]; time_t rawtime; struct tm *timeinfo; time(&rawtime); timeinfo = localtime(&rawtime); strftime(buff, 64, "%d.%m.%Y %r", timeinfo); ev->AddString(buff); } void ScriptThread::GetTimeZone(Event *ev) { int gmttime; int local; time_t rawtime; struct tm *timeinfo, *ptm; int timediff; int tmp; tmp = ev->GetInteger(1); time(&rawtime); timeinfo = localtime(&rawtime); local = timeinfo->tm_hour; ptm = gmtime(&rawtime); gmttime = ptm->tm_hour; timediff = local - gmttime; ev->AddInteger(timediff); } // IMPORTANT NOTE: // SLRE is buggy, consider switch to Boost.Regex or .xpressive void ScriptThread::PregMatch(Event *ev) { slre_cap sl_cap[32]; int i, j; size_t iMaxLength; size_t iLength; size_t iFoundLength = 0; str pattern, subject; ScriptVariable index, value, subindex, subvalue; ScriptVariable array, subarray; memset(sl_cap, 0, sizeof(sl_cap)); pattern = ev->GetString(1); subject = ev->GetString(2); iMaxLength = strlen(subject); iLength = 0; i = 0; while ( iLength < iMaxLength && (iFoundLength = slre_match( pattern, subject.c_str() + iLength, iMaxLength - iLength, sl_cap, sizeof(sl_cap) / sizeof(sl_cap[0]), 0 )) > 0 ) { subarray.Clear(); for (j = 0; sl_cap[j].ptr != NULL; j++) { char *buffer; buffer = (char *)gi.Malloc(sl_cap[j].len + 1); buffer[sl_cap[j].len] = 0; strncpy(buffer, sl_cap[j].ptr, sl_cap[j].len); subindex.setIntValue(j); subvalue.setStringValue(buffer); subarray.setArrayAtRef(subindex, subvalue); gi.Free(buffer); iLength += sl_cap[j].ptr - subject.c_str(); } index.setIntValue(i); array.setArrayAtRef(index, subarray); i++; } ev->AddValue(array); } void ScriptThread::EventIsArray(Event *ev) { ScriptVariable *value = &ev->GetValue(1); if (value == NULL) { return ev->AddInteger(0); } ev->AddInteger( value->type == VARIABLE_ARRAY || value->type == VARIABLE_CONSTARRAY || value->type == VARIABLE_SAFECONTAINER ); } void ScriptThread::EventIsDefined(Event *ev) { ev->AddInteger(!ev->IsNilAt(1)); } void ScriptThread::FlagClear(Event *ev) { str name; Flag *flag; name = ev->GetString(1); flag = flags.FindFlag(name); if (flag == NULL) { throw ScriptException("Invalid flag '%s'\n", name.c_str()); } delete flag; } void ScriptThread::FlagInit(Event *ev) { str name; Flag *flag; name = ev->GetString(1); flag = flags.FindFlag(name); if (flag != NULL) { flag->Reset(); return; } flag = new Flag; flag->bSignaled = false; Q_strncpyz(flag->flagName, name, sizeof(flag->flagName)); } void ScriptThread::FlagSet(Event *ev) { str name; Flag *flag; name = ev->GetString(1); flag = flags.FindFlag(name); if (flag == NULL) { throw ScriptException("Invalid flag '%s'.\n", name.c_str()); } flag->Set(); } void ScriptThread::FlagWait(Event *ev) { str name; Flag *flag; name = ev->GetString(1); flag = flags.FindFlag(name); if (flag == NULL) { throw ScriptException("Invalid flag '%s'.\n", name.c_str()); } flag->Wait(this); } void ScriptThread::EventATan2(Event *ev) { int numArgs = 0; double x = 0.0f, y = 0.0f, res = 0.0f; numArgs = ev->NumArgs(); if (numArgs != 2) { throw ScriptException("Wrong arguments count for atan2!\n"); } y = ev->GetFloat(1); x = ev->GetFloat(2); res = atan2(y, x); ev->AddFloat((float)res); } void ScriptThread::EventCosH(Event *ev) { int numArgs = 0; double x = 0.0f, res = 0.0f; numArgs = ev->NumArgs(); if (numArgs != 1) { throw ScriptException("Wrong arguments count for cosh!\n"); } x = ev->GetFloat(1); res = cosh(x); ev->AddFloat((float)res); } void ScriptThread::EventSinH(Event *ev) { int numArgs = 0; double x = 0.0f, res = 0.0f; numArgs = ev->NumArgs(); if (numArgs != 1) { throw ScriptException("Wrong arguments count for sinh!\n"); } x = ev->GetFloat(1); res = sinh(x); ev->AddFloat((float)res); } void ScriptThread::EventTanH(Event *ev) { int numArgs = 0; double x = 0.0f, res = 0.0f; numArgs = ev->NumArgs(); if (numArgs != 1) { throw ScriptException("Wrong arguments count for tanh!\n"); } x = ev->GetFloat(1); res = tanh(x); ev->AddFloat((float)res); } void ScriptThread::EventExp(Event *ev) { int numArgs = 0; double x = 0.0f, res = 0.0f; numArgs = ev->NumArgs(); if (numArgs != 1) { throw ScriptException("Wrong arguments count for exp!\n"); } x = ev->GetFloat(1); res = exp(x); ev->AddFloat((float)res); } void ScriptThread::EventFrexp(Event *ev) { int numArgs = 0; double x = 0.0f, res = 0.0f; int exp = 0; ScriptVariable *ref = new ScriptVariable; ScriptVariable *array = new ScriptVariable; ScriptVariable *SignificandIndex = new ScriptVariable; ScriptVariable *ExponentIndex = new ScriptVariable; ScriptVariable *SignificandVal = new ScriptVariable; ScriptVariable *ExponentVal = new ScriptVariable; numArgs = ev->NumArgs(); if (numArgs != 1) { throw ScriptException("Wrong arguments count for frexp!\n"); } x = ev->GetFloat(1); res = frexp(x, &exp); ref->setRefValue(array); SignificandIndex->setStringValue("significand"); ExponentIndex->setStringValue("exponent"); SignificandVal->setFloatValue((float)res); ExponentVal->setIntValue(exp); ref->setArrayAt(*SignificandIndex, *SignificandVal); ref->setArrayAt(*ExponentIndex, *ExponentVal); ev->AddValue(*array); } void ScriptThread::EventLdexp(Event *ev) { int numArgs = 0; double x = 0.0f, res = 0.0f; int exp = 0; numArgs = ev->NumArgs(); if (numArgs != 2) { throw ScriptException("Wrong arguments count for ldexp!\n"); } x = ev->GetFloat(1); exp = ev->GetInteger(2); res = ldexp(x, exp); ev->AddFloat((float)res); } void ScriptThread::EventLog(Event *ev) { int numArgs = 0; double x = 0.0f, res = 0.0f; numArgs = ev->NumArgs(); if (numArgs != 1) { throw ScriptException("Wrong arguments count for log!\n"); } x = ev->GetFloat(1); res = log(x); ev->AddFloat((float)res); } void ScriptThread::EventLog10(Event *ev) { int numArgs = 0; double x = 0.0f, res = 0.0f; numArgs = ev->NumArgs(); if (numArgs != 1) { throw ScriptException("Wrong arguments count for log10!\n"); } x = ev->GetFloat(1); res = log10(x); ev->AddFloat((float)res); } void ScriptThread::EventModf(Event *ev) { int numArgs = 0; double x = 0.0f, res = 0.0f; double intpart = 0; //char varIntpartIndex[16] = { 0 }, varFractionalIndex[16] = { 0 }, varIntpartVal[16] = { 0 }, varFractionalVal[16] = { 0 }, varArray[16] = { 0 }, varRef[16] = { 0 }; ScriptVariable *array = new ScriptVariable; ScriptVariable *ref = new ScriptVariable; ScriptVariable *IntpartIndex = new ScriptVariable; ScriptVariable *FractionalIndex = new ScriptVariable; ScriptVariable *FractionalVal = new ScriptVariable; ScriptVariable *IntpartVal = new ScriptVariable; numArgs = ev->NumArgs(); if (numArgs != 1) { throw ScriptException("Wrong arguments count for modf!\n"); } x = ev->GetFloat(1); res = modf(x, &intpart); ref->setRefValue(array); IntpartIndex->setStringValue("intpart"); FractionalIndex->setStringValue("fractional"); FractionalVal->setFloatValue((float)res); IntpartVal->setFloatValue((float)intpart); ref->setArrayAt(*IntpartIndex, *IntpartVal); ref->setArrayAt(*FractionalIndex, *FractionalVal); ev->AddValue(*array); } void ScriptThread::EventPow(Event *ev) { int numArgs = 0; double base = 0.0f, res = 0.0f; int exponent = 0; numArgs = ev->NumArgs(); if (numArgs != 2) { throw ScriptException("Wrong arguments count for pow!\n"); } base = ev->GetFloat(1); exponent = ev->GetInteger(2); res = pow(base, exponent); ev->AddFloat((float)res); } void ScriptThread::EventACos(Event *ev) { int numArgs = 0; double x = 0.0f, res = 0.0f; numArgs = ev->NumArgs(); if (numArgs != 1) { throw ScriptException("Wrong arguments count for acos!\n"); } x = ev->GetFloat(1); res = acos(x); ev->AddFloat((float)res); } void ScriptThread::EventASin(Event *ev) { int numArgs = 0; double x = 0.0f, res = 0.0f; numArgs = ev->NumArgs(); if (numArgs != 1) { throw ScriptException("Wrong arguments count for asin!\n"); } x = ev->GetFloat(1); res = asin(x); ev->AddFloat((float)res); } void ScriptThread::EventCeil(Event *ev) { int numArgs = 0; double x = 0.0f, res = 0.0f; numArgs = ev->NumArgs(); if (numArgs != 1) { throw ScriptException("Wrong arguments count for ceil!\n"); } x = ev->GetFloat(1); res = ceil(x); ev->AddFloat((float)res); } void ScriptThread::EventFloor(Event *ev) { int numArgs = 0; double x = 0.0f, res = 0.0f; numArgs = ev->NumArgs(); if (numArgs != 1) { throw ScriptException("Wrong arguments count for floor!\n"); } x = ev->GetFloat(1); res = floor(x); ev->AddFloat((float)res); } void ScriptThread::EventFmod(Event *ev) { int numArgs = 0; double numerator = 0.0f, denominator = 0.0f, res = 0.0f; numArgs = ev->NumArgs(); if (numArgs != 2) { throw ScriptException("Wrong arguments count for fmod!\n"); } numerator = ev->GetFloat(1); denominator = ev->GetFloat(2); res = fmod(numerator, denominator); ev->AddFloat((float)res); } int checkMD5(const char *filepath, char *md5Hash, size_t destSize) { md5_state_t state; md5_byte_t digest[16]; int di; FILE *f = NULL; char *buff = NULL; size_t filesize = 0; size_t bytesread = 0; f = fopen(filepath, "rb"); if (f == NULL) { return -1; } fseek(f, 0, SEEK_END); filesize = ftell(f); rewind(f); //gi.Printf("Size: %i\n", filesize); buff = (char *)gi.Malloc(filesize + 1); if (buff == NULL) { fclose(f); Com_Printf("error0\n"); return -2; } buff[filesize] = '\0'; bytesread = fread(buff, 1, filesize, f); if (bytesread < filesize) { gi.Free(buff); fclose(f); Com_Printf("error1: %zi\n", bytesread); return -3; } fclose(f); md5_init(&state); md5_append(&state, (const md5_byte_t *)buff, filesize); md5_finish(&state, digest); for (di = 0; di < 16; ++di) { Com_sprintf(md5Hash + di * 2, destSize - di * 2, "%02x", digest[di]); } gi.Free(buff); return 0; } int checkMD5String(const char *string, char *md5Hash, size_t destSize) { md5_state_t state; md5_byte_t digest[16]; int di; char *buff = NULL; size_t stringlen = 0; stringlen = strlen(string); buff = (char *)gi.Malloc(stringlen + 1); if (buff == NULL) { return -1; } buff[stringlen] = '\0'; memcpy(buff, string, stringlen); md5_init(&state); md5_append(&state, (const md5_byte_t *)buff, stringlen); md5_finish(&state, digest); for (di = 0; di < 16; ++di) { Com_sprintf(md5Hash + di * 2, destSize - di * 2, "%02x", digest[di]); } gi.Free(buff); return 0; } void ScriptThread::Md5File(Event *ev) { char hash[64]; str filename; int ret = 0; if (ev->NumArgs() != 1) { throw ScriptException("Wrong arguments count for md5file!\n"); } filename = ev->GetString(1); ret = checkMD5(filename, hash, sizeof(hash)); if (ret != 0) { ev->AddInteger(-1); throw ScriptException("Error while generating MD5 checksum for file - md5file!\n"); } ev->AddString(hash); } void ScriptThread::StringBytesCopy(Event *ev) { int bytes = ev->GetInteger(1); str source = ev->GetString(2); char *buffer; buffer = (char *)gi.Malloc(bytes + 1); strncpy(buffer, source, bytes); buffer[bytes] = 0; ev->AddString(buffer); gi.Free(buffer); } void ScriptThread::Md5String(Event *ev) { char hash[64]; str text; int ret = 0; if (ev->NumArgs() != 1) { throw ScriptException("Wrong arguments count for md5string!\n"); } text = ev->GetString(1); ret = checkMD5String(text, hash, sizeof(hash)); if (ret != 0) { ev->AddInteger(-1); throw ScriptException("Error while generating MD5 checksum for strin!\n"); } ev->AddString(hash); } scriptedEvType_t EventNameToType(const char *eventname, char *fullname) { scriptedEvType_t evType; const char *eventname_full; if (strcmp(eventname, "connected") == 0) { eventname_full = "ConnectedEvent"; evType = SE_CONNECTED; } else if (strcmp(eventname, "disconnected") == 0) { eventname_full = "DisconnectedEvent"; evType = SE_DISCONNECTED; } else if (strcmp(eventname, "spawn") == 0) { eventname_full = "SpawnEvent"; evType = SE_SPAWN; } else if (strcmp(eventname, "damage") == 0) { eventname_full = "DamageEvent"; evType = SE_DAMAGE; } else if (strcmp(eventname, "kill") == 0) { eventname_full = "KillEvent"; evType = SE_KILL; } else if (strcmp(eventname, "keypress") == 0) { eventname_full = "KeypressEvent"; evType = SE_KEYPRESS; } else if (strcmp(eventname, "intermission") == 0) { eventname_full = "IntermissionEvent"; evType = SE_INTERMISSION; } else if (strcmp(eventname, "servercommand") == 0) { eventname_full = "ServerCommandEvent"; evType = SE_SERVERCOMMAND; } else if (strcmp(eventname, "changeteam") == 0) { eventname_full = "ChangeTeamEvent"; evType = SE_CHANGETEAM; } else { return SE_DEFAULT; } if (fullname != NULL) { strcpy(fullname, eventname_full); } return evType; } void ScriptThread::RegisterEvent(Event *ev) { str eventname; char eventname_full[64]; scriptedEvType_t evType; eventname = ev->GetString(1); evType = EventNameToType(eventname, eventname_full); if (evType == SE_DEFAULT) { ev->AddInteger(0); throw ScriptException("Wrong event type name for registerev!\n"); } if (scriptedEvents[evType].IsRegistered()) { ev->AddInteger(1); throw ScriptException("Scripted event '%s' is already registered\n", eventname.c_str()); } scriptedEvents[evType].label.SetThread(ev->GetValue(2)); if (evType == SE_KEYPRESS) { gi.cvar_set("sv_keypressevents", "1"); } else if (evType == SE_SERVERCOMMAND) { gi.cvar_set("sv_servercmdevents", "1"); } ev->AddInteger(0); } void ScriptThread::UnregisterEvent(Event *ev) { str eventname; int numArgs = 0; scriptedEvType_t evType; eventname = ev->GetString(1); evType = EventNameToType(eventname, NULL); if (evType == scriptedEvType_t(~0u)) { ev->AddInteger(0); throw ScriptException("Wrong event type name for unregisterev!\n"); } numArgs = ev->NumArgs(); if (numArgs != 1) { throw ScriptException("Wrong arguments count for unregisterev!\n"); } eventname = ev->GetString(1); if (!scriptedEvents[evType].IsRegistered()) { ev->AddInteger(1); return; } scriptedEvents[evType].label.Set(""); if (evType == SE_KEYPRESS) { gi.cvar_set("sv_keypressevents", "0"); } else if (evType == SE_SERVERCOMMAND) { gi.cvar_set("sv_servercmdevents", "0"); } ev->AddInteger(0); } void ScriptThread::TypeOfVariable(Event *ev) { int numArgs = 0; char *type = NULL; ScriptVariable *variable; numArgs = ev->NumArgs(); if (numArgs != 1) { throw ScriptException("Wrong arguments count for typeof!\n"); } variable = (ScriptVariable *)&ev->GetValue(1); type = (char *)variable->GetTypeName(); ev->AddString(type); } void ScriptThread::VisionGetNaked(Event *ev) { ev->AddString(vision_current); } void ScriptThread::VisionSetNaked(Event *ev) { str vision = ev->GetString(1); float fade_time; cvar_t *mapname = gi.Cvar_Get("mapname", "", 0); if (ev->NumArgs() > 1) { fade_time = ev->GetFloat(2); } else { fade_time = 0.0f; } if (!vision.length()) { vision = mapname->string; } // We won't malicously overflow client commands :) if (vision.length() >= MAX_STRING_TOKENS) { throw ScriptException("vision_name exceeds the maximum vision name limit (256) !\n"); } vision_current = vision; gi.SendServerCommand(-1, "vsn %s %f", vision.c_str(), fade_time); } void ScriptThread::GetTime(Event *ev) { int timearray[3], gmttime; char buff[1024]; time_t rawtime; struct tm *timeinfo, *ptm; int timediff; time(&rawtime); timeinfo = localtime(&rawtime); timearray[0] = timeinfo->tm_hour; timearray[1] = timeinfo->tm_min; timearray[2] = timeinfo->tm_sec; ptm = gmtime(&rawtime); gmttime = ptm->tm_hour; timediff = timearray[0] - gmttime; Com_sprintf(buff, sizeof(buff), "%02i:%02i:%02i", (int)timearray[0], (int)timearray[1], (int)timearray[2]); ev->AddString(buff); } void ScriptThread::TraceDetails(Event *ev) { int numArgs = 0; int pass_entity = 0; int mask = 0x2000B01; trace_t trace; Vector vecStart, vecEnd, vecMins, vecMaxs; Entity *entity; //todo : remove all these vars and add one for index and one for value ScriptVariable array; ScriptVariable allSolidIndex, allSolidValue; ScriptVariable startSolidIndex, startSolidValue; ScriptVariable fractionIndex, fractionValue; ScriptVariable endPosIndex, endPosValue; ScriptVariable surfaceFlagsIndex, surfaceFlagsValue; ScriptVariable shaderNumIndex, shaderNumValue; ScriptVariable contentsIndex, contentsValue; ScriptVariable entityNumIndex, entityNumValue; ScriptVariable locationIndex, locationValue; ScriptVariable entityIndex, entityValue; numArgs = ev->NumArgs(); if (numArgs < 2 || numArgs > 6) { throw ScriptException("Wrong arguments count for traced!\n"); } vecStart = ev->GetVector(1); vecEnd = ev->GetVector(2); if (numArgs >= 3) { pass_entity = ev->GetInteger(3); } if (numArgs >= 4) { vecMins = ev->GetVector(4); } if (numArgs >= 5) { vecMaxs = ev->GetVector(5); } if (numArgs == 6) { mask = ev->GetInteger(6); } gi.trace(&trace, vecStart, vecMins, vecMaxs, vecEnd, pass_entity, mask, 0, 0); allSolidIndex.setStringValue("allSolid"); startSolidIndex.setStringValue("startSolid"); fractionIndex.setStringValue("fraction"); endPosIndex.setStringValue("endpos"); surfaceFlagsIndex.setStringValue("surfaceFlags"); shaderNumIndex.setStringValue("shaderNum"); contentsIndex.setStringValue("contents"); entityNumIndex.setStringValue("entityNum"); locationIndex.setStringValue("location"); entityIndex.setStringValue("entity"); allSolidValue.setIntValue(trace.allsolid); startSolidValue.setIntValue(trace.startsolid); fractionValue.setFloatValue(trace.fraction); endPosValue.setVectorValue(trace.endpos); surfaceFlagsValue.setIntValue(trace.surfaceFlags); shaderNumValue.setIntValue(trace.shaderNum); contentsValue.setIntValue(trace.contents); entityNumValue.setIntValue(trace.entityNum); locationValue.setIntValue(trace.location); entity = G_GetEntity(trace.entityNum); // Have to use G_GetEntity instead otherwise it won't work if (entity != NULL) { entityValue.setListenerValue(entity); } array.setArrayAtRef(allSolidIndex, allSolidValue); array.setArrayAtRef(startSolidIndex, startSolidValue); array.setArrayAtRef(fractionIndex, fractionValue); array.setArrayAtRef(endPosIndex, endPosValue); array.setArrayAtRef(surfaceFlagsIndex, surfaceFlagsValue); array.setArrayAtRef(shaderNumIndex, shaderNumValue); array.setArrayAtRef(contentsIndex, contentsValue); array.setArrayAtRef(entityNumIndex, entityNumValue); array.setArrayAtRef(locationIndex, locationValue); array.setArrayAtRef(entityIndex, entityValue); ev->AddValue(array); }