From 7469c7982d93f2ad922230d712f586a353dc1a42 Mon Sep 17 00:00:00 2001 From: Jake-NotTheMuss <90179752+Jake-NotTheMuss@users.noreply.github.com> Date: Thu, 10 Feb 2022 01:53:58 -0800 Subject: [PATCH] Add GSC (#5634) * Add GSC * Change GSC color * Add heuristic tests * heuristics: Fix wrong alphabetical sorting * Put smaller GSC samples * heuristics: fix regexes Co-authored-by: John Gardner --- .gitmodules | 3 + grammars.yml | 2 + lib/linguist/heuristics.yml | 17 + lib/linguist/languages.yml | 12 + samples/GSC/_spiderbot_ride.csc | 48 ++ samples/GSC/array_override_common.gsc | 209 +++++++ samples/GSC/array_override_common.gsh | 116 ++++ samples/GSC/math_shared.gsc | 546 ++++++++++++++++++ samples/GSC/struct.gsc | 82 +++ samples/GSC/zm_init.gsc | 260 +++++++++ test/test_heuristics.rb | 18 + vendor/README.md | 1 + vendor/grammars/CoDT7-Sublime | 1 + .../git_submodule/CoDT7-Sublime.dep.yml | 34 ++ 14 files changed, 1349 insertions(+) create mode 100644 samples/GSC/_spiderbot_ride.csc create mode 100644 samples/GSC/array_override_common.gsc create mode 100644 samples/GSC/array_override_common.gsh create mode 100644 samples/GSC/math_shared.gsc create mode 100644 samples/GSC/struct.gsc create mode 100644 samples/GSC/zm_init.gsc create mode 160000 vendor/grammars/CoDT7-Sublime create mode 100644 vendor/licenses/git_submodule/CoDT7-Sublime.dep.yml diff --git a/.gitmodules b/.gitmodules index 71e11b8f72..d64f4b9ed7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,6 +22,9 @@ [submodule "vendor/grammars/CUE-Sheet_sublime"] path = vendor/grammars/CUE-Sheet_sublime url = https://github.com/relikd/CUE-Sheet_sublime +[submodule "vendor/grammars/CoDT7-Sublime"] + path = vendor/grammars/CoDT7-Sublime + url = https://github.com/Jake-NotTheMuss/CoDT7-Sublime.git [submodule "vendor/grammars/ColdFusion"] path = vendor/grammars/ColdFusion url = https://github.com/SublimeText/ColdFusion diff --git a/grammars.yml b/grammars.yml index b90769b53f..436721a32c 100644 --- a/grammars.yml +++ b/grammars.yml @@ -15,6 +15,8 @@ vendor/grammars/BrightScript.tmbundle: - source.brightscript vendor/grammars/CUE-Sheet_sublime: - source.cuesheet +vendor/grammars/CoDT7-Sublime: +- source.gsc vendor/grammars/ColdFusion: - source.cfscript - source.cfscript.cfc diff --git a/lib/linguist/heuristics.yml b/lib/linguist/heuristics.yml index 4b4d2921b1..528558e3d2 100644 --- a/lib/linguist/heuristics.yml +++ b/lib/linguist/heuristics.yml @@ -130,6 +130,10 @@ disambiguations: pattern: '![\w\s]+methodsFor: ' - language: 'C#' pattern: '^(\s*namespace\s*[\w\.]+\s*{|\s*\/\/)' +- extensions: ['.csc'] + rules: + - language: GSC + named_pattern: gsc - extensions: ['.csl'] rules: - language: XML @@ -229,6 +233,14 @@ disambiguations: pattern: '^uses (java|gw)\.' - language: Genie pattern: '^\[indent=[0-9]+\]' +- extensions: ['.gsc'] + rules: + - language: GSC + named_pattern: gsc +- extensions: ['.gsh'] + rules: + - language: GSC + named_pattern: gsc - extensions: ['.h'] rules: - language: Objective-C @@ -633,6 +645,11 @@ named_patterns: - '^[ \t]*(private|public|protected):$' - 'std::\w+' fortran: '^(?i:[c*][^abd-z]| (subroutine|program|end|data)\s|\s*!)' + gsc: + - '^\s*#\s*(?:using|insert|include|define|namespace)[ \t]+\w' + - '^\s*(?>(?:autoexec|private)\s+){0,2}function\s+(?>(?:autoexec|private)\s+){0,2}\w+\s*\(' + - '\b(?:level|self)[ \t]+thread[ \t]+(?:\[\[[ \t]*(?>\w+\.)*\w+[ \t]*\]\]|\w+)[ \t]*\([^\r\n\)]*\)[ \t]*;' + - '^[ \t]*#[ \t]*(?:precache|using_animtree)[ \t]*\(' key_equals_value: '^[^#!;][^=]*=' m68k: - '(?im)\bmoveq(?:\.l)?\s+#(?:\$-?[0-9a-f]{1,3}|%[0-1]{1,8}|-?[0-9]{1,3}),\s*d[0-7]\b' diff --git a/lib/linguist/languages.yml b/lib/linguist/languages.yml index 9e338be68d..de337607a3 100644 --- a/lib/linguist/languages.yml +++ b/lib/linguist/languages.yml @@ -1949,6 +1949,18 @@ GN: codemirror_mode: python codemirror_mime_type: text/x-python language_id: 302957008 +GSC: + type: programming + color: "#FF6800" + extensions: + - ".gsc" + - ".csc" + - ".gsh" + tm_scope: source.gsc + ace_mode: c_cpp + codemirror_mode: clike + codemirror_mime_type: text/x-csrc + language_id: 257856279 Game Maker Language: type: programming color: "#71b417" diff --git a/samples/GSC/_spiderbot_ride.csc b/samples/GSC/_spiderbot_ride.csc new file mode 100644 index 0000000000..9ed541d016 --- /dev/null +++ b/samples/GSC/_spiderbot_ride.csc @@ -0,0 +1,48 @@ +#include clientscripts\_utility; +#include clientscripts\_filter; + +#using_animtree("player"); + + +init() +{ + clientscripts\_driving_fx::add_vehicletype_callback( "spiderbot_large", ::drive_spiderbot ); +} + + +// +// +drive_spiderbot( localClientNum ) +{ + self endon( "entityshutdown" ); + + while( 1 ) + { + self waittill( "enter_vehicle", player ); + + init_filter_karma_spiderbot( player ); + enable_filter_karma_spiderbot( player, 0 ); + SetSavedDvar( "r_stereo3DEyeSeparationScaler", 0.01); + + + //TODO: Get this to work in the vehicle GDT, somehow overcoming the lack of wheels + if( isdefined( level._audio_spiderbot_override ) ) + { + self thread [[level._audio_spiderbot_override]](player); + } + + // This compass isn't working they way it needs to. + // Create the compass +// spider_compass = Spawn( player GetLocalClientNumber(), player GetOrigin(), "script_model" ); +// spider_compass SetModel( "p6_3d_gizmo" ); +// spider_compass SetViewmodelRenderflag( true ); +// spider_compass LinkToCamera( 5, (16, 0, 12) ); // in/out, left/right, up/down + + self waittill( "exit_vehicle" ); + + disable_filter_karma_spiderbot( player, 0 ); + SetSavedDvar( "r_stereo3DEyeSeparationScaler", 1); + +// spider_compass delete(); + } +} diff --git a/samples/GSC/array_override_common.gsc b/samples/GSC/array_override_common.gsc new file mode 100644 index 0000000000..bf9b08bd50 --- /dev/null +++ b/samples/GSC/array_override_common.gsc @@ -0,0 +1,209 @@ +#using scripts\shared\array_shared; +#using scripts\shared\callbacks_shared; +#using scripts\shared\flag_shared; +#using scripts\shared\util_shared; +#insert scripts\shared\shared.gsh; +#insert scripts\zm\array_override\array_override_common.gsh; + +#namespace array_override; + +#define NOTIFY_SELF(n_add) self notify("override_state_change",n_type,str_name,n_add,is_override_exluded_from_notif(str_name)) + +function register(str_name,n_type,func) +{ + switch(n_type) + { + case ARRAY_RANDOM: + DEFAULT(self.array_random_override,array()); + self.array_random_override[str_name] = func; + break; + case ARRAY_RANDOMIZE: + DEFAULT(self.array_randomize_override,array()); + self.array_randomize_override[str_name] = func; + break; + } + NOTIFY_SELF(1); +} + +function unregister(str_name,n_type) +{ + switch(n_type) + { + case ARRAY_RANDOM: + ArrayRemoveIndex(self.array_random_override,str_name,1); + break; + case ARRAY_RANDOMIZE: + ArrayRemoveIndex(self.array_randomize_override,str_name,1); + break; + } + NOTIFY_SELF(-1); +} + +function private reregister(str_name,n_type) +{ + switch(n_type) + { + case ARRAY_RANDOM: + func = self.array_random_override[str_name]; + break; + case ARRAY_RANDOMIZE: + func = self.array_randomize_override[str_name]; + break; + } + if (!isdefined(func)) return; + increment_exclude_from_notif(str_name); + unregister(str_name,n_type); + register(str_name,n_type,func); + decrement_exclude_from_notif(str_name); +} + +#define EXCLUDE_FROM_NOTIF_DEFAULTS MAKE_ARRAY(self.override_notif_exclude) DEFAULT(self.override_notif_exclude[str_name],0); +function increment_exclude_from_notif(str_name) +{ + EXCLUDE_FROM_NOTIF_DEFAULTS + self.override_notif_exclude[str_name]++; +} + +function decrement_exclude_from_notif(str_name) +{ + EXCLUDE_FROM_NOTIF_DEFAULTS + self.override_notif_exclude[str_name]--; + if (self.override_notif_exclude[str_name] <= 0) ArrayRemoveIndex(self.override_notif_exclude,str_name,1); +} + +function private is_override_exluded_from_notif(str_name) +{ + MAKE_ARRAY(self.override_notif_exclude) + return IS_TRUE(self.override_notif_exclude[str_name]); +} + +function autoexec init_player_overrides() +{ + callback::on_connect(&on_player_connect); +} + +function private on_player_connect() +{ + self.array_random_override = array(); + self.array_randomize_override = array(); +} + +function register_recursive(str_name,n_type,func,b_ex_notif = false) +{ + switch(n_type) + { + case ARRAY_RANDOM: + DEFAULT(level.recursive_random_override,array()); + level.recursive_random_override[str_name] = SpawnStruct(); + struct = level.recursive_random_override[str_name]; + break; + case ARRAY_RANDOMIZE: + DEFAULT(level.recursive_randomize_override,array()); + level.recursive_randomize_override[str_name] = SpawnStruct(); + struct = level.recursive_randomize_override[str_name]; + break; + } + struct.func = func; + struct.b_ex_notif = b_ex_notif; + struct.count = 0; + struct.a_flag = array(); +} + +#define RECURSIVE_SWITCHBLOCK switch(n_type){\ + case ARRAY_RANDOM: struct = level.recursive_random_override[str_name];break;\ + case ARRAY_RANDOMIZE: struct = level.recursive_randomize_override[str_name];break;}\ + if (!isdefined(struct)) return; + +function increment_register(str_name,n_type) +{ + RECURSIVE_SWITCHBLOCK + if (struct.count <= 0) + { + struct.count = 0; + if (struct.b_ex_notif) level increment_exclude_from_notif(str_name); + level register(str_name,n_type,struct.func); + } + struct.count++; + thread update_recursive_flags(struct); +} + +function decrement_register(str_name,n_type,b_unregister = false) +{ + RECURSIVE_SWITCHBLOCK + struct.count--; + if (b_unregister || struct.count <= 0) + { + level unregister(str_name,n_type); + if (struct.b_ex_notif) level decrement_exclude_from_notif(str_name); + struct.count = 0; + } + thread update_recursive_flags(struct); +} + +function run_recursive_override_instance(str_name,n_type,func) +{ + //fix this + id = self GetEntityNumber() + 1; + wait(.05 * id); + // + increment_register(str_name,n_type); + [[func]](); + decrement_register(str_name,n_type); +} + +function add_recursive_override_flag(str_name,n_type,a_flags) +{ + RECURSIVE_SWITCHBLOCK + DEFAULT(struct.a_flag,array()); + foreach (flag in a_flags) + { + if (!IsArray(flag)) flag_array = array(flag); + else flag_array = flag; + str_flag = flag_array[0]; + if (!IsString(str_flag)) continue; + n_count = VAL(flag_array[1],0); + flag_struct = SpawnStruct(); + flag_struct.flag = str_flag; + flag_struct.required_count = n_count; + flag_struct.comparison = flag_array[2]; + struct.a_flag[struct.a_flag.size] = flag_struct; + level flag::init(str_flag); + update_specific_flag(flag_struct,struct.count); + } +} + +function update_recursive_flags(struct) +{ + foreach (flag_struct in struct.a_flag) + { + update_specific_flag(flag_struct,struct.count); + } +} + +function private update_specific_flag(flag_struct,n_count) +{ + if (IsFunctionPtr(flag_struct.required_count)) required_count = [[flag_struct.required_count]](); + else required_count = flag_struct.required_count; + + if (IsFunctionPtr(flag_struct.comparison)) b_val = [[flag_struct.comparison]](n_count,required_count); + else b_val = n_count === required_count; + + if (isdefined(b_val)) level flag::set_val(flag_struct.flag,b_val); +} + +function link_to_recursive_flag(str_name,n_type,a_flag,b_waitForAll = false) +{ + level endon("end_game"); + if (!isdefined(a_flag)) return; + if (!IsArray(a_flag)) a_flag = array(a_flag); + if (b_waitForAll) {waitFunc = &flag::wait_till_all; waitClearFunc = &flag::wait_till_clear_all;} + else {waitFunc = &flag::wait_till_any; waitClearFunc = &flag::wait_till_clear_all;} + + while(1) + { + level [[waitFunc]](a_flag); + level [[waitClearFunc]](a_flag); + wait .05; + level reregister(str_name,n_type); + } +} \ No newline at end of file diff --git a/samples/GSC/array_override_common.gsh b/samples/GSC/array_override_common.gsh new file mode 100644 index 0000000000..7ec539ea41 --- /dev/null +++ b/samples/GSC/array_override_common.gsh @@ -0,0 +1,116 @@ + +#define NUM_TYPES 2 +#define ARRAY_RANDOM 0 +#define ARRAY_RANDOMIZE 1 + +#define REGISTER_OVERRIDE(str_name,n_type,func) array_override::register(str_name,n_type,func) +#define UNREGISTER_OVERRIDE(str_name,n_type) array_override::unregister(str_name,n_type) +#define NOTIF_EXLUDE(str_name) array_override::increment_exclude_from_notif(str_name) +#define REMOVE_NOTIF_EXCLUDE(str_name) array_override::decrement_exclude_from_notif(str_name) +#define REGISTER_OVERRIDE_EX_NOTIF(str_name,n_type,func) NOTIF_EXLUDE(str_name);REGISTER_OVERRIDE(str_name,n_type,func) +#define UNREGISTER_OVERRIDE_EX_NOTIF(str_name,n_type) UNREGISTER_OVERRIDE(str_name,n_type);REMOVE_NOTIF_EXCLUDE(str_name) + +#define REGISTER_RECURSIVE(str_name,n_type,func) array_override::register_recursive(str_name,n_type,func) +#define REGISTER_RECURSIVE_EX_NOTIF(str_name,n_type,func) array_override::register_recursive(str_name,n_type,func,true) +#define INCREMENT_REGISTER(str_name,n_type) array_override::increment_register(str_name,n_type) +#define DECREMENT_REGISTER(str_name,n_type) array_override::decrement_register(str_name,n_type) +#define RESET_RECURSIVE(str_name,n_type) array_override::decrement_register(str_name,n_type,true) +#define RUN_RECURSIVE(str_name,n_type,func) array_override::run_recursive_override_instance(str_name,n_type,func) +#define ADD_RECURSIVE_FLAG(str_name,n_type,a_flag) array_override::add_recursive_override_flag(str_name,n_type,a_flag) +#define LINK_TO_RECURSIVE_FLAG(str_name,n_type,a_flag) thread array_override::link_to_recursive_flag(str_name,n_type,a_flag) +#define RECURSIVE_ENDON self endon("disconnect"); + +#define CALL_ONCE_FLAG(__name) if (isdefined(level.__name)) return; level.__name = 1; + +#define IS_FIELD_OBJECT(_val) (isdefined(_val) && (IsEntity(_val) || (!IsInt(_val) && !IsFloat(_val) && !IsString(_val) && !IsArray(_val) && !IsFunctionPtr(_val) && !IsVec(_val)))) +#define IF_KVP_MATCH(__key,__val,__ent) struct_or_ent = __ent; if (!IS_FIELD_OBJECT(struct_or_ent)) return; if (struct_or_ent.__key === __val) +#define IF_TARGETNAME_MATCH(__targetname,__ent) IF_KVP_MATCH(targetname,__targetname,__ent) +#define IF_NOTEWORTHY_MATCH(__noteworthy,__ent) IF_KVP_MATCH(script_noteworthy,__noteworthy,__ent) + +#define RETURN_IF_ARRAY(__ret) if (IsArray(__ret)) return __ret; +#define ARRAY_SAFE_RETURN(__listName) i = self GetEntityNumber();\ + RETURN_IF_ARRAY(__listName[i])\ + RETURN_IF_ARRAY(__listName[0])\ + RETURN_IF_ARRAY(__listName)\ + return array(); + +// for entries which specify which category it should be valid for (spawn requests, forced drops, dig rewards) +#define BGB_CLASSIC 0 +#define BGB_MEGA 1 +#define BGB_ALL 2 + +#define MAP_ASSIGN_LIST(varname) switch(GetDvarString("mapname")){\ + case "zm_zod":varname = ZOD;break;\ + case "zm_factory":varname = FACTORY;break;\ + case "zm_castle":varname = CASTLE;break;\ + case "zm_island":varname = ISLAND;break;\ + case "zm_stalingrad":varname = STALINGRAD;break;\ + case "zm_genesis":varname = GENESIS;break;\ + case "zm_prototype":varname = PROTOTYPE;break;\ + case "zm_asylum":varname = ASYLUM;break;\ + case "zm_sumpf":varname = SUMPF;break;\ + case "zm_theater":varname = THEATER;break;\ + case "zm_cosmodrome":varname = COSMODROME;break;\ + case "zm_temple":varname = TEMPLE;break;\ + case "zm_moon":varname = MOON;break;\ + case "zm_tomb":varname = TOMB;break;\ + default:return;} + +#define MAP_ASSIGN_LIST_RETURN(varname) MAP_ASSIGN_LIST(varname) if(!isdefined(varname)) return; + +#define MAP_ASSIGN_LIST_2(varname1,varname2) switch(GetDvarString("mapname")){\ + case "zm_zod":varname1 = ZOD;varname2 = ZOD_2;break;\ + case "zm_factory":varname1 = FACTORY;varname2 = FACTORY_2;break;\ + case "zm_castle":varname1 = CASTLE;varname2 = CASTLE_2;break;\ + case "zm_island":varname1 = ISLAND;varname2 = ISLAND_2;break;\ + case "zm_stalingrad":varname1 = STALINGRAD;varname2 = STALINGRAD_2;break;\ + case "zm_genesis":varname1 = GENESIS;varname2 = GENESIS_2;break;\ + case "zm_prototype":varname1 = PROTOTYPE;varname2 = PROTOTYPE_2;break;\ + case "zm_asylum":varname1 = ASYLUM;varname2 = ASYLUM_2;break;\ + case "zm_sumpf":varname1 = SUMPF;varname2 = SUMPF_2;break;\ + case "zm_theater":varname1 = THEATER;varname2 = THEATER_2;break;\ + case "zm_cosmodrome":varname1 = COSMODROME;varname2 = COSMODROME_2;break;\ + case "zm_temple":varname1 = TEMPLE;varname2 = TEMPLE_2;break;\ + case "zm_moon":varname1 = MOON;varname2 = MOON_2;break;\ + case "zm_tomb":varname1 = TOMB;varname2 = TOMB_2;break;\ + default:return;} + +#define MAP_ASSIGN_LIST_2_RETURN(varname1,varname2) MAP_ASSIGN_LIST_2(varname1,varname2) if(!isdefined(varname1)) return; + +#define MAP_ASSIGN_FUNC(varname) switch(GetDvarString("mapname")){\ + case "zm_zod":varname = ZOD_FUNC;break;\ + case "zm_factory":varname = FACTORY_FUNC;break;\ + case "zm_castle":varname = CASTLE_FUNC;break;\ + case "zm_island":varname = ISLAND_FUNC;break;\ + case "zm_stalingrad":varname = STALINGRAD_FUNC;break;\ + case "zm_genesis":varname = GENESIS_FUNC;break;\ + case "zm_prototype":varname = PROTOTYPE_FUNC;break;\ + case "zm_asylum":varname = ASYLUM_FUNC;break;\ + case "zm_sumpf":varname = SUMPF_FUNC;break;\ + case "zm_theater":varname = THEATER_FUNC;break;\ + case "zm_cosmodrome":varname = COSMODROME_FUNC;break;\ + case "zm_temple":varname = TEMPLE_FUNC;break;\ + case "zm_moon":varname = MOON_FUNC;break;\ + case "zm_tomb":varname = TOMB_FUNC;break;\ + default:return;} + +#define MAP_ASSIGN_FUNC_RETURN(varname) MAP_ASSIGN_FUNC(varname) if (!isdefined(varname)) return; + +#define MAP_ASSIGN_FUNC_2(varname1,varname2) switch(GetDvarString("mapname")){\ + case "zm_zod":varname1 = ZOD_FUNC;varname2 = ZOD_FUNC_2;break;\ + case "zm_factory":varname1 = FACTORY_FUNC;varname2 = FACTORY_FUNC_2;break;\ + case "zm_castle":varname1 = CASTLE_FUNC;varname2 = CASTLE_FUNC_2;break;\ + case "zm_island":varname1 = ISLAND_FUNC;varname2 = ISLAND_FUNC_2;break;\ + case "zm_stalingrad":varname1 = STALINGRAD_FUNC;varname2 = STALINGRAD_FUNC_2;break;\ + case "zm_genesis":varname1 = GENESIS_FUNC;varname2 = GENESIS_FUNC_2;break;\ + case "zm_prototype":varname1 = PROTOTYPE_FUNC;varname2 = PROTOTYPE_FUNC_2;break;\ + case "zm_asylum":varname1 = ASYLUM_FUNC;varname2 = ASYLUM_FUNC_2;break;\ + case "zm_sumpf":varname1 = SUMPF_FUNC;varname2 = SUMPF_FUNC_2;break;\ + case "zm_theater":varname1 = THEATER_FUNC;varname2 = THEATER_FUNC_2;break;\ + case "zm_cosmodrome":varname1 = COSMODROME_FUNC;varname2 = COSMODROME_FUNC_2;break;\ + case "zm_temple":varname1 = TEMPLE_FUNC;varname2 = TEMPLE_FUNC_2;break;\ + case "zm_moon":varname1 = MOON_FUNC;varname2 = MOON_FUNC_2;break;\ + case "zm_tomb":varname1 = TOMB_FUNC;varname2 = TOMB_FUNC_2;break;\ + default:return;} + +#define MAP_ASSIGN_FUNC_2_RETURN(varname1,varname2) MAP_ASSIGN_FUNC_2(varname1,varname2) if (!isdefined(varname1)) return; \ No newline at end of file diff --git a/samples/GSC/math_shared.gsc b/samples/GSC/math_shared.gsc new file mode 100644 index 0000000000..efa9b8f52e --- /dev/null +++ b/samples/GSC/math_shared.gsc @@ -0,0 +1,546 @@ +#using scripts\shared\util_shared; + +#insert scripts\shared\shared.gsh; + +#namespace math; + +function cointoss() +{ + return RandomInt( 100 ) >= 50; +} + +/@ +"Name: clamp(val, val_min, val_max)" +"Summary: Clamps a value between a min and max value." +"Module: Math" +"MandatoryArg: val: the value to clamp." +"MandatoryArg: val_min: the min value to clamp to." +"MandatoryArg: val_max: the mac value to clamp to." +"Example: clamped_val = clamp(8, 0, 5); // returns 5 * clamped_val = clamp(-1, 0, 5); // returns 0" +"SPMP: both" +@/ +function clamp( val, val_min, val_max ) +{ + DEFAULT( val_max, val ); + + if (val < val_min) + { + val = val_min; + } + else if (val > val_max) + { + val = val_max; + } + + return val; +} + +/@ +"Name: linear_map(val, min_a, max_a, min_b, max_b)" +"Summary: Maps a value within one range to a value in another range." +"Module: Math" +"MandatoryArg: val: the value to map." +"MandatoryArg: min_a: the min value of the range in which exists." +"MandatoryArg: max_a: the max value of the range in which exists." +"MandatoryArg: min_b: the min value of the range in which the return value should exist." +"MandatoryArg: max_b: the max value of the range in which the return value should exist." +"Example: fov = linear_map(speed, min_speed, max_speed, min_fov, max_fov);" +"SPMP: both" +@/ +function linear_map(num, min_a, max_a, min_b, max_b) +{ + return clamp(( (num - min_a) / (max_a - min_a) * (max_b - min_b) + min_b ), min_b, max_b); +} + +/@ +"Name: lag(desired, curr, k, dt)" +"Summary: Changes a value from current to desired using 1st order differential lag." +"Module: Math" +"MandatoryArg: desired: desired value." +"MandatoryArg: curr: the current value." +"MandatoryArg: k: the strength of the lag ( lower = slower, higher = faster)." +"MandatoryArg: dt: time step to lag over ( usually 1 server frame )." +"Example: speed = lag(max_speed, speed, 1, 0.05);" +"SPMP: both" +@/ +function lag(desired, curr, k, dt) +{ + r = 0.0; + + if (((k * dt) >= 1.0) || (k <= 0.0)) + { + r = desired; + } + else + { + err = desired - curr; + r = curr + k * err * dt; + } + + return r; +} + +function find_box_center( mins, maxs ) +{ + center = ( 0, 0, 0 ); + center = maxs - mins; + center = ( center[0]/2, center[1]/2, center[2]/2 ) + mins; + return center; +} + +function expand_mins( mins, point ) +{ + if ( mins[0] > point[0] ) + { + mins = ( point[0], mins[1], mins[2] ); + } + + if ( mins[1] > point[1] ) + { + mins = ( mins[0], point[1], mins[2] ); + } + + if ( mins[2] > point[2] ) + { + mins = ( mins[0], mins[1], point[2] ); + } + + return mins; +} + +function expand_maxs( maxs, point ) +{ + if ( maxs[0] < point[0] ) + { + maxs = ( point[0], maxs[1], maxs[2] ); + } + + if ( maxs[1] < point[1] ) + { + maxs = ( maxs[0], point[1], maxs[2] ); + } + + if ( maxs[2] < point[2] ) + { + maxs = ( maxs[0], maxs[1], point[2] ); + } + + return maxs; +} + +// ---------------------------------------------------------------------------------------------------- +// -- Vectors ----------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------------------- + +/@ +"Name: vector_compare( , )" +"Summary: For 3D vectors. Returns true if the vectors are the same" +"MandatoryArg: : A 3D vector (origin)" +"MandatoryArg: : A 3D vector (origin)" +"Example: if (vector_compare(self.origin, node.origin){print(\"yay, i'm on the node!\");}" +"SPMP: both" +@/ +function vector_compare(vec1, vec2) +{ + return (abs(vec1[0] - vec2[0]) < .001) && (abs(vec1[1] - vec2[1]) < .001) && (abs(vec1[2] - vec2[2]) < .001); +} + +function random_vector(max_length) +{ + return (RandomFloatRange(-1 * max_length, max_length), RandomFloatRange(-1 * max_length, max_length), RandomFloatRange(-1 * max_length, max_length)); +} + +function angle_dif(oldangle, newangle) +{ + outvalue = ( oldangle - newangle ) % 360; + + if ( outvalue < 0 ) + { + outvalue+=360; + } + + if ( outvalue > 180 ) + { + outvalue=(outvalue-360)*-1; + } + + return outvalue; +} + +function sign( x ) +{ + return ( x >= 0 ? 1 : -1 ); +} + +function randomSign() +{ + return ( RandomIntRange( -1, 1 ) >= 0 ? 1 : -1 ); +} + +/@ +"Name: get_dot_direction( , [b_ignore_z], [b_normalize], [str_direction], [ b_use_eye] )" +"Summary: Calculates and returns dot between an entity's directional vector and a point." +"Module: Math" +"CallOn: Entity. Must have origin and angles parameters." +"MandatoryArg: vector position to check against entity origin and angles" +"OptionalArg: specify if get_dot should consider 2d or 3d dot. Defaults to false for 3d dot." +"OptionalArg: specify which vector type to use on angles. Valid options are "forward", "backward", "right", "left", "up" and "down". Defaults to "forward"." +"OptionalArg: specify if the function should normalize the vector to target point. Defaults to true." +"OptionalArg: if self a player or AI, use tag_eye rather than .angles. Defaults to true on players, defaults to false on everything else. +"Example: n_dot = player get_dot_direction( woods.origin );" +"SPMP: singleplayer" +@/ +function get_dot_direction( v_point, b_ignore_z, b_normalize, str_direction, b_use_eye ) +{ + assert( isdefined( v_point ), "v_point is a required parameter for get_dot" ); + + if ( !isdefined( b_ignore_z ) ) + { + b_ignore_z = false; + } + + if ( !isdefined( b_normalize ) ) + { + b_normalize = true; + } + + if ( !isdefined( str_direction ) ) + { + str_direction = "forward"; + } + + if ( !isdefined( b_use_eye ) ) + { + b_use_eye = false; + + if ( IsPlayer( self ) ) + { + b_use_eye = true; + } + } + + v_angles = self.angles; + v_origin = self.origin; + + if ( b_use_eye ) + { + v_origin = self util::get_eye(); + } + + if ( IsPlayer( self ) ) + { + v_angles = self GetPlayerAngles(); + if ( level.wiiu ) + { + v_angles = self GetGunAngles(); + } + } + + if ( b_ignore_z ) + { + v_angles = ( v_angles[ 0 ], v_angles[ 1 ], 0 ); + v_point = ( v_point[ 0 ], v_point[ 1 ], 0 ); + v_origin = ( v_origin[ 0 ], v_origin[ 1 ], 0 ); + } + + switch ( str_direction ) + { + case "forward": + v_direction = AnglesToForward( v_angles ); + break; + + case "backward": + v_direction = AnglesToForward( v_angles ) * ( -1 ); + break; + + case "right": + v_direction = AnglesToRight( v_angles ); + break; + + case "left": + v_direction = AnglesToRight( v_angles ) * ( -1 ); + break; + + case "up": + v_direction = AnglesToUp( v_angles ); + break; + + case "down": + v_direction = AnglesToUp( v_angles ) * ( -1 ); + break; + + default: + AssertMsg( str_direction + " is not a valid str_direction for get_dot!" ); + v_direction = AnglesToForward( v_angles ); // have to initialize variable for default case + break; + } + + v_to_point = v_point - v_origin; + + if ( b_normalize ) + { + v_to_point = VectorNormalize( v_to_point ); + } + + n_dot = VectorDot( v_direction, v_to_point ); + + return n_dot; +} + +/@ +"Name: get_dot_right( , [b_ignore_z], [b_normalize] )" +"Summary: Calculates and returns dot between an entity's right vector and a point." +"Module: Math" +"CallOn: Entity. Must have origin and angles parameters." +"MandatoryArg: vector position to check against entity origin and angles" +"OptionalArg: specify if get_dot should consider 2d or 3d dot. Defaults to false for 3d dot." +"OptionalArg: specify if the function should normalize the vector to target point. Defaults to true." +"Example: n_dot = player get_dot_direction( woods.origin );" +"SPMP: singleplayer" +@/ +function get_dot_right( v_point, b_ignore_z, b_normalize ) +{ + // get_dot will assert if missing, but scripter should know it's coming from get_dot_right + assert( isdefined( v_point ), "v_point is a required parameter for get_dot_right" ); + + n_dot = get_dot_direction( v_point, b_ignore_z, b_normalize, "right" ); + + return n_dot; +} + +/@ +"Name: get_dot_up( , [b_ignore_z], [b_normalize] )" +"Summary: Calculates and returns dot between an entity's up vector and a point." +"Module: Math" +"CallOn: Entity. Must have origin and angles parameters." +"MandatoryArg: vector position to check against entity origin and angles" +"OptionalArg: specify if get_dot should consider 2d or 3d dot. Defaults to false for 3d dot." +"OptionalArg: specify if the function should normalize the vector to target point. Defaults to true." +"Example: n_dot = player get_dot_direction( woods.origin );" +"SPMP: singleplayer" +@/ +function get_dot_up( v_point, b_ignore_z, b_normalize ) +{ + // get_dot will assert if missing, but scripter should know it's coming from get_dot_up + assert( isdefined( v_point ), "v_point is a required parameter for get_dot_up" ); + + n_dot = get_dot_direction( v_point, b_ignore_z, b_normalize, "up" ); + + return n_dot; +} + +/@ +"Name: get_dot_forward( , [b_ignore_z], [b_normalize] )" +"Summary: Calculates and returns dot between an entity's forward vector and a point." +"Module: Math" +"CallOn: Entity. Must have origin and angles parameters." +"MandatoryArg: vector position to check against entity origin and angles" +"OptionalArg: specify if get_dot should consider 2d or 3d dot. Defaults to false for 3d dot." +"OptionalArg: specify if the function should normalize the vector to target point. Defaults to true." +"Example: n_dot = player get_dot_direction( woods.origin );" +"SPMP: singleplayer" +@/ +function get_dot_forward( v_point, b_ignore_z, b_normalize ) +{ + // get_dot will assert if missing, but scripter should know it's coming from get_dot_forward + assert( isdefined( v_point ), "v_point is a required parameter for get_dot_forward" ); + + n_dot = get_dot_direction( v_point, b_ignore_z, b_normalize, "forward" ); + + return n_dot; +} + +/@ +"Name: get_dot_from_eye( , [b_ignore_z], [b_normalize], [str_direction] )" +"Summary: Calculates and returns dot between an entity's forward vector and a point based on tag_eye. Only use on players or AI" +"Module: Math" +"CallOn: Entity. Must have origin and angles parameters." +"MandatoryArg: vector position to check against entity origin and angles" +"OptionalArg: [b_ignore_z] specify if get_dot should consider 2d or 3d dot. Defaults to false for 3d dot." +"OptionalArg: [b_normalize] specify if the function should normalize the vector to target point. Defaults to true." +"OptionalArg: [str_direction] specify which vector type to use on angles. Valid options are "forward", "backward", "right", "left", "up" and "down". Defaults to "forward"." +"Example: n_dot = player get_dot_from_eye( woods.origin );" +"SPMP: singleplayer" +@/ +function get_dot_from_eye( v_point, b_ignore_z, b_normalize, str_direction ) +{ + assert( isdefined( v_point ), "v_point is a required parameter for get_dot_forward" ); + Assert( ( IsPlayer( self ) || IsAI( self ) ), "get_dot_from_eye was used on a " + self.classname + ". Valid ents are players and AI, since they have tag_eye." ); + + n_dot = get_dot_direction( v_point, b_ignore_z, b_normalize, str_direction, true ); + + return n_dot; +} + +// ---------------------------------------------------------------------------------------------------- +// -- Arrays ------------------------------------------------------------------------------------------ +// ---------------------------------------------------------------------------------------------------- + +/@ +"Name: array_average( )" +"Summary: Given an array of numbers, returns the average (mean) value of the array" +"Module: Utility" +"MandatoryArg: : the array of numbers which will be averaged" +"Example: array_average( numbers );" +"SPMP: both" +@/ +function array_average( array ) +{ + assert( IsArray( array ) ); + assert( array.size > 0 ); + + total = 0; + + for ( i = 0; i < array.size; i++ ) + { + total += array[i]; + } + + return ( total / array.size ); +} + +/@ +"Name: array_std_deviation( , )" +"Summary: Given an array of numbers and the average of the array, returns the standard deviation value of the array" +"Module: Utility" +"MandatoryArg: : the array of numbers" +"MandatoryArg: : the average (mean) value of the array" +"Example: array_std_deviation( numbers, avg );" +"SPMP: both" +@/ +function array_std_deviation( array, mean ) +{ + assert( IsArray( array ) ); + assert( array.size > 0 ); + + tmp = []; + for ( i = 0; i < array.size; i++ ) + { + tmp[i] = ( array[i] - mean ) * ( array[i] - mean ); + } + + total = 0; + for ( i = 0; i < tmp.size; i++ ) + { + total = total + tmp[i]; + } + + return Sqrt( total / array.size ); +} + +/@ +"Name: random_normal_distribution( , , , )" +"Summary: Given the mean and std deviation of a set of numbers, returns a random number from the normal distribution" +"Module: Utility" +"MandatoryArg: : the average (mean) value of the array" +"MandatoryArg: : the standard deviation value of the array" +"OptionalArg: the minimum value that will be returned" +"OptionalArg: the maximum value that will be returned" +"Example: random_normal_distribution( avg, std_deviation );" +"SPMP: both" +@/ +function random_normal_distribution( mean, std_deviation, lower_bound, upper_bound ) +{ + //pixbeginevent( "random_normal_distribution" ); + + // implements the Box-Muller transform for Gaussian random numbers (http://en.wikipedia.org/wiki/Box-Muller_transform) + x1 = 0; + x2 = 0; + w = 1; + y1 = 0; + + while ( w >= 1 ) + { + x1 = 2 * RandomFloatRange( 0, 1 ) - 1; + x2 = 2 * RandomFloatRange( 0, 1 ) - 1; + w = x1 * x1 + x2 * x2; + } + + w = Sqrt( ( -2.0 * Log( w ) ) / w ); + y1 = x1 * w; + + number = mean + y1 * std_deviation; + + if ( isdefined( lower_bound ) && number < lower_bound ) + { + number = lower_bound; + } + + if ( isdefined( upper_bound ) && number > upper_bound ) + { + number = upper_bound; + } + + //pixendevent(); + + return( number ); +} + +function closest_point_on_line( point, lineStart, lineEnd ) +{ + lineMagSqrd = lengthsquared(lineEnd - lineStart); + + t = ( ( ( point[0] - lineStart[0] ) * ( lineEnd[0] - lineStart[0] ) ) + + ( ( point[1] - lineStart[1] ) * ( lineEnd[1] - lineStart[1] ) ) + + ( ( point[2] - lineStart[2] ) * ( lineEnd[2] - lineStart[2] ) ) ) / + ( lineMagSqrd ); + + if( t < 0.0 ) + { + return lineStart; + } + else if( t > 1.0 ) + { + return lineEnd; + } + + start_x = lineStart[0] + t * ( lineEnd[0] - lineStart[0] ); + start_y = lineStart[1] + t * ( lineEnd[1] - lineStart[1] ); + start_z = lineStart[2] + t * ( lineEnd[2] - lineStart[2] ); + + return (start_x,start_y,start_z); +} + +function get_2d_yaw( start, end ) +{ + vector = (end[0] - start[0], end[1] - start[1], 0); + + return vec_to_angles( vector ); +} + +function vec_to_angles( vector ) +{ + yaw = 0; + + vecX = vector[0]; + vecY = vector[1]; + + if ( vecX == 0 && vecY == 0 ) + return 0; + + if ( vecY < 0.001 && vecY > -0.001 ) + vecY = 0.001; + + yaw = atan( vecX / vecY ); + + if ( vecY < 0 ) + yaw += 180; + + return ( 90 - yaw ); +} + +function pow( base, exp ) +{ + if( exp == 0 ) + { + return 1; + } + + result = base; + for( i = 0; i < ( exp - 1 ); i++ ) + { + result *= base; + } + + return result; +} diff --git a/samples/GSC/struct.gsc b/samples/GSC/struct.gsc new file mode 100644 index 0000000000..e1b9652e9e --- /dev/null +++ b/samples/GSC/struct.gsc @@ -0,0 +1,82 @@ + +function init() {} +function delete() {} + +/@ +"Name: get( , [kvp_key] )" +"Summary: Returns a struct with the specified kvp." +"MandatoryArg: : kvp value" +"OptionalArg: [kvp_key] : defaults to targetname" +"Example: struct::get( "some_value", "targetname" );" +"SPMP: both" +@/ +function get( kvp_value, kvp_key = "targetname" ){} + +/@ +"Name: spawn( [v_origin], [v_angles] )" +"Summary: Returns a new struct." +"OptionalArg: [v_origin] : optional origin" +"OptionalArg: [v_angles] : optional angles" +"Example: s = struct::spawn( self GetTagOrigin( "tag_origin" ) );" +@/ +function spawn( v_origin = (0, 0, 0), v_angles = (0, 0, 0) ){} + +/@ +"Name: get_array( , [kvp_key] )" +"Summary: Returns an array of structs with the specified kvp." +"MandatoryArg: : kvp value" +"OptionalArg: [kvp_key] : defaults to targetname" +"Example: fxemitters = struct::get_array( "streetlights", "targetname" )" +"SPMP: both" +@/ +function get_array( kvp_value, kvp_key = "targetname" ){} + +/@ +"Name: get_script_bundle( , )" +"Summary: Returns a struct with the specified script bundle definition. This is the GDT data for the bundle." +"MandatoryArg: : The type of the script bundle" +"MandatoryArg: : The name of the script bundle" +"Example: struct::get_script_bundle( "scene", "my_scene" );" +"SPMP: both" +@/ +function get_script_bundle( str_type, str_name ){} + +/@ +"Name: delete_script_bundle( , )" +"Summary: Deletes the specified script bundle definition. This is the GDT data for the bundle." +"MandatoryArg: : The type of the script bundle" +"MandatoryArg: : The name of the script bundle" +"Example: struct::delete_script_bundle( "scene", "my_scene" );" +"SPMP: both" +@/ +function delete_script_bundle( str_type, str_name ){} + +/@ +"Name: get_script_bundles( )" +"Summary: Returns all of the script bundle definition structs for the specified type." +"MandatoryArg: : The type of the script bundle" +"Example: struct::get_script_bundles( "scene" );" +"SPMP: both" +@/ +function get_script_bundles( str_type ){} + +/@ +"Name: get_script_bundle_list( , )" +"Summary: Returns a string array with the items specified by the script bundle list." +"MandatoryArg: : The type of the script bundle in the list" +"MandatoryArg: : The name of the script bundle list" +"Example: struct::get_script_bundle_list( "collectible", "completecollectibleslist" );" +"SPMP: both" +@/ +function get_script_bundle_list( str_type, str_name ){} + +/@ +"Name: get_script_bundle_instances( , [str_name] )" +"Summary: Returns an array of all the script bundle instances with the specified script bundle definition and name." +"MandatoryArg: : The type of the script bundle" +"MandatoryArg: [str_name] : The name of the script bundle" +"Example: struct::get_script_bundle_instances( "scene", "my_scene" );" +"SPMP: both" +@/ +function get_script_bundle_instances( str_type, str_name = "" ){} + diff --git a/samples/GSC/zm_init.gsc b/samples/GSC/zm_init.gsc new file mode 100644 index 0000000000..d5fa6d6ce4 --- /dev/null +++ b/samples/GSC/zm_init.gsc @@ -0,0 +1,260 @@ +// Notes about scripts +//===================== +// +// Anim variables +// -------------- +// Anim variables keep track of what the character is doing with respect to his +// animations. They know if he's standing, crouching, kneeling, walking, running, etc, +// so that he can play appropriate transitions to get to the animation he wants. +// anim_movement - "stop", "walk", "run" +// anim_pose - "stand", "crouch", some others for pain poses. +// I'm putting functions to do the basic animations to change these variables in +// zombie_SetPoseMovement.gsc, +// +// Error Reporting +// --------------- +// To report a script error condition (similar to assert(0)), I assign a non-existent variable to +// the variable homemade_error I use the name of the non-existent variable to try to explain the +// error. For example: +// homemade_error = Unexpected_anim_pose_value + self.a.pose; +// I also have a kind of assert, called as follows: +// [[anim.assert(condition, message_string); +// If condition evaluates to 0, the assert fires, prints message_string and stops the server. Since +// I don't have stack traces of any kind, the message string needs to say from where the assert was +// called. + +// #include maps\mp\animscripts\zm_utility; +// #include maps\_utility; +// #include animscripts\Combat_utility; +// #include common_scripts\Utility; +// + +#include common_scripts\utility; +#include maps\mp\animscripts\shared; +#include maps\mp\animscripts\utility; +#include maps\mp\animscripts\zm_utility; + + + +main() +{ + self.a = SpawnStruct(); + + self.team = level.zombie_team; + + + firstInit(); + + // Set initial states for poses + self.a.pose = "stand"; + self.a.movement = "stop"; + self.a.state = "stop"; + self.a.special = "none"; + + self.a.combatEndTime = GetTime(); + self.a.script = "init"; + self.a.alertness = "casual"; // casual, alert, aiming + self.a.lastEnemyTime = GetTime(); + self.a.forced_cover = "none"; + self.a.desired_script = "none"; + self.a.current_script = "none"; + self.a.lookangle = 0; + self.a.painTime = 0; + self.a.nextGrenadeTryTime = 0; + + // setup the speed variables + self.walk = false; + self.sprint = false; + + // WW (11/16/2010): Setting variable for run blend speed. This allows the black hole bomb to snap guys 180 with less pop. + self.a.runBlendTime = 0.2; + + // MikeD (9/28/2007): Flame pain time... Tracks when the AI gets hit with flame. + self.a.flamepainTime = 0; + + self.a.postScriptFunc = undefined; + self.a.stance = "stand"; + + self._animActive = 0; + + self thread deathNotify(); + + // use the GDT settings to start with + self.baseAccuracy = self.accuracy; + + // set default accuracy mod + if( !IsDefined(self.script_accuracy) ) + { + self.script_accuracy = 1; + } + + self.a.missTime = 0; + + self.a.yawTransition = "none"; + self.a.nodeath = false; + self.a.missTime = 0; + self.a.missTimeDebounce = 0; + self.a.disablePain = false; + + self.accuracyStationaryMod = 1; + self.chatInitialized = false; + self.sightPosTime = 0; + self.sightPosLeft = true; + self.preCombatRunEnabled = true; + self.is_zombie = true; + + self.a.crouchpain = false; // for dying pain guys + self.a.nextStandingHitDying = false; + + // Makes AI able to throw grenades at other AI. + if (!IsDefined (self.script_forcegrenade)) + { + self.script_forcegrenade = 0; + } + +/# + self.a.lastDebugPrint = ""; +#/ + + // state tracking + self.lastEnemySightTime = 0; // last time we saw our current enemy + self.combatTime = 0; // how long we've been in/out of combat + + // Random range makes the grenades less accurate and do less damage, but also makes it difficult to throw back. +// if ( self.team == "allies" ) +// { +// self.randomGrenadeRange = 0; +// } +// else +// { +// self.randomGrenadeRange = 128; +// } + + self.coverIdleSelectTime = -696969; + + self.old = SpawnStruct(); + + self.reacquire_state = 0; + + self.a.allow_shooting = false; +} + +DoNothing() +{ +} + +empty(one, two, three, whatever) +{ +} + +clearEnemy() +{ + self notify ("stop waiting for enemy to die"); + self endon ("stop waiting for enemy to die"); + self.sightEnemy waittill ("death"); + self.sightpos = undefined; + self.sightTime = 0; + self.sightEnemy = undefined; +} + +// Cleans up scripts on death +deathNotify() +{ + self waittill( "death", other ); + self notify( anim.scriptChange ); +} + +firstInit() +{ + // Initialization that should happen once per level + if ( IsDefined (anim.NotFirstTime) ) // Use this to trigger the first init + { + return; + } + + anim.NotFirstTime = true; + + anim.useFacialAnims = false; // remove me when facial anims are fixed + + if ( !IsDefined( anim.dog_health ) ) + { + anim.dog_health = 1; + } + + if ( !IsDefined( anim.dog_presstime ) ) + { + anim.dog_presstime = 350; + } + + if ( !IsDefined( anim.dog_hits_before_kill ) ) + { + anim.dog_hits_before_kill = 1; + } + + level.nextGrenadeDrop = RandomInt(3); + level.lastPlayerSighted = 100; + anim.defaultException = maps\mp\animscripts\zm_init::empty; + + SetDvar( "scr_expDeathMayMoveCheck", "on" ); + + // Global constants + anim.lastSideStepAnim = 0; + anim.meleeRange = 64; + anim.meleeRangeSq = anim.meleeRange * anim.meleeRange; + anim.standRangeSq = 512*512; + anim.chargeRangeSq = 200*200; + anim.chargeLongRangeSq = 512*512; + anim.aiVsAiMeleeRangeSq = 400*400; + + anim.combatMemoryTimeConst = 10000; + anim.combatMemoryTimeRand = 6000; + anim.scriptChange = "script_change"; + + // MikeD (10/23/2007 10:38:58): Gib Support + anim.lastGibTime = 0; + anim.gibDelay = 3 * 1000; // 3 seconds + anim.minGibs = 2; + anim.maxGibs = 4; + anim.totalGibs = RandomIntRange( anim.minGibs, anim.maxGibs ); + + anim.corner_straight_yaw_limit = 36; + + if (!IsDefined(anim.optionalStepEffectFunction)) + { + anim.optionalStepEffects = []; + anim.optionalStepEffectFunction = ::empty; + } + + // string based array for notetracks + anim.notetracks = []; + maps\mp\animscripts\zm_shared::registerNoteTracks(); + + if ( !IsDefined( level.flag ) ) + { + level.flag = []; + level.flags_lock = []; + } + + level.painAI = undefined; + + + anim.maymoveCheckEnabled = true; // corner_axis doesnt do the check if this is false, for credits + + anim.badPlaces = []; // queue for animscript badplaces + anim.badPlaceInt = 0; // assigns unique names to animscript badplaces since we cant save a badplace as an entity + + anim.coverCrouchLeanPitch = -55; + + anim.lastCarExplosionTime = -100000; +} + +onPlayerConnect() +{ + player = self; + + // make sure the init has been called + firstInit(); + + player.invul = false; +} + diff --git a/test/test_heuristics.rb b/test/test_heuristics.rb index a16e12aac9..05658b7901 100755 --- a/test/test_heuristics.rb +++ b/test/test_heuristics.rb @@ -326,6 +326,12 @@ def test_cs_by_heuristics }) end + def test_csc_by_heuristics + assert_heuristics({ + "GSC" => all_fixtures("GSC", "*.csc") + }) + end + def test_csl_by_heuristics assert_heuristics({ "Kusto" => all_fixtures("Kusto", "*.csl"), @@ -430,6 +436,18 @@ def test_gs_by_heuristics }, alt_name="test.gs") end + def test_gsc_by_heuristics + assert_heuristics({ + "GSC" => all_fixtures("GSC", "*.gsc") + }) + end + + def test_gsh_by_heuristics + assert_heuristics({ + "GSC" => all_fixtures("GSC", "*.gsh") + }) + end + def test_h_by_heuristics assert_heuristics({ "Objective-C" => all_fixtures("Objective-C", "*.h"), diff --git a/vendor/README.md b/vendor/README.md index cd9d7f6ea8..931500574c 100644 --- a/vendor/README.md +++ b/vendor/README.md @@ -164,6 +164,7 @@ This is a list of grammars that Linguist selects to provide syntax highlighting - **GEDCOM:** [fguitton/vscode-gedcom](https://github.com/fguitton/vscode-gedcom) - **GLSL:** [euler0/sublime-glsl](https://github.com/euler0/sublime-glsl) - **GN:** [devoncarew/language-gn](https://github.com/devoncarew/language-gn) +- **GSC:** [Jake-NotTheMuss/CoDT7-Sublime](https://github.com/Jake-NotTheMuss/CoDT7-Sublime) - **Game Maker Language:** [textmate/c.tmbundle](https://github.com/textmate/c.tmbundle) - **Gemfile.lock:** [hmarr/gemfile-lock-tmlanguage](https://github.com/hmarr/gemfile-lock-tmlanguage) - **Genshi:** [genshi.edgewall.org/query](https://genshi.edgewall.org/query) diff --git a/vendor/grammars/CoDT7-Sublime b/vendor/grammars/CoDT7-Sublime new file mode 160000 index 0000000000..0221bba3a1 --- /dev/null +++ b/vendor/grammars/CoDT7-Sublime @@ -0,0 +1 @@ +Subproject commit 0221bba3a10e4656c94bf23d3f88f3a98dadd295 diff --git a/vendor/licenses/git_submodule/CoDT7-Sublime.dep.yml b/vendor/licenses/git_submodule/CoDT7-Sublime.dep.yml new file mode 100644 index 0000000000..0cf1f5b5f5 --- /dev/null +++ b/vendor/licenses/git_submodule/CoDT7-Sublime.dep.yml @@ -0,0 +1,34 @@ +--- +name: CoDT7-Sublime +version: 0221bba3a10e4656c94bf23d3f88f3a98dadd295 +type: git_submodule +homepage: https://github.com/Jake-NotTheMuss/CoDT7-Sublime.git +license: unlicense +licenses: +- sources: LICENSE + text: | + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + For more information, please refer to +notices: []