123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725 |
- // Copyright (c) ZeniMax Media Inc.
- // Licensed under the GNU General Public License 2.0.
- #include "g_local.h"
- struct spawn_t
- {
- const char *name;
- void (*spawn)(edict_t *ent);
- };
- void SP_info_player_start(edict_t *ent);
- void SP_info_player_deathmatch(edict_t *ent);
- void SP_info_player_coop(edict_t *ent);
- void SP_info_player_intermission(edict_t *ent);
- void SP_func_plat(edict_t *ent);
- void SP_func_rotating(edict_t *ent);
- void SP_func_button(edict_t *ent);
- void SP_func_door(edict_t *ent);
- void SP_func_door_secret(edict_t *ent);
- void SP_func_door_rotating(edict_t *ent);
- void SP_func_water(edict_t *ent);
- void SP_func_train(edict_t *ent);
- void SP_func_conveyor(edict_t *self);
- void SP_func_wall(edict_t *self);
- void SP_func_object(edict_t *self);
- void SP_func_explosive(edict_t *self);
- void SP_func_timer(edict_t *self);
- void SP_func_areaportal(edict_t *ent);
- void SP_func_clock(edict_t *ent);
- void SP_func_killbox(edict_t *ent);
- void SP_func_eye(edict_t *ent); // [Paril-KEX]
- void SP_func_animation(edict_t *ent); // [Paril-KEX]
- void SP_func_spinning(edict_t *ent); // [Paril-KEX]
- void SP_trigger_always(edict_t *ent);
- void SP_trigger_once(edict_t *ent);
- void SP_trigger_multiple(edict_t *ent);
- void SP_trigger_relay(edict_t *ent);
- void SP_trigger_push(edict_t *ent);
- void SP_trigger_hurt(edict_t *ent);
- void SP_trigger_key(edict_t *ent);
- void SP_trigger_counter(edict_t *ent);
- void SP_trigger_elevator(edict_t *ent);
- void SP_trigger_gravity(edict_t *ent);
- void SP_trigger_monsterjump(edict_t *ent);
- void SP_trigger_flashlight(edict_t *self); // [Paril-KEX]
- void SP_trigger_fog(edict_t *self); // [Paril-KEX]
- void SP_trigger_coop_relay(edict_t *self); // [Paril-KEX]
- void SP_trigger_health_relay(edict_t *self); // [Paril-KEX]
- void SP_target_temp_entity(edict_t *ent);
- void SP_target_speaker(edict_t *ent);
- void SP_target_explosion(edict_t *ent);
- void SP_target_changelevel(edict_t *ent);
- void SP_target_secret(edict_t *ent);
- void SP_target_goal(edict_t *ent);
- void SP_target_splash(edict_t *ent);
- void SP_target_spawner(edict_t *ent);
- void SP_target_blaster(edict_t *ent);
- void SP_target_crosslevel_trigger(edict_t *ent);
- void SP_target_crosslevel_target(edict_t *ent);
- void SP_target_crossunit_trigger(edict_t *ent); // [Paril-KEX]
- void SP_target_crossunit_target(edict_t *ent); // [Paril-KEX]
- void SP_target_laser(edict_t *self);
- void SP_target_help(edict_t *ent);
- void SP_target_actor(edict_t *ent);
- void SP_target_lightramp(edict_t *self);
- void SP_target_earthquake(edict_t *ent);
- void SP_target_character(edict_t *ent);
- void SP_target_string(edict_t *ent);
- void SP_target_camera(edict_t* self); // [Sam-KEX]
- void SP_target_gravity(edict_t* self); // [Sam-KEX]
- void SP_target_soundfx(edict_t* self); // [Sam-KEX]
- void SP_target_light(edict_t *self); // [Paril-KEX]
- void SP_target_poi(edict_t *ent); // [Paril-KEX]
- void SP_target_music(edict_t *ent);
- void SP_target_healthbar(edict_t *self); // [Paril-KEX]
- void SP_target_autosave(edict_t *self); // [Paril-KEX]
- void SP_target_sky(edict_t *self); // [Paril-KEX]
- void SP_target_achievement(edict_t *self); // [Paril-KEX]
- void SP_target_story(edict_t *self); // [Paril-KEX]
- void SP_worldspawn(edict_t *ent);
- void SP_dynamic_light(edict_t* self);
- void SP_light(edict_t *self);
- void SP_light_mine1(edict_t *ent);
- void SP_light_mine2(edict_t *ent);
- void SP_info_null(edict_t *self);
- void SP_info_notnull(edict_t *self);
- void SP_info_landmark (edict_t* self); // [Paril-KEX]
- void SP_info_world_text(edict_t * self);
- void SP_misc_player_mannequin(edict_t * self);
- void SP_misc_model(edict_t *self); // [Paril-KEX]
- void SP_path_corner(edict_t *self);
- void SP_point_combat(edict_t *self);
- void SP_info_nav_lock(edict_t *self); // [Paril-KEX]
- void SP_misc_explobox(edict_t *self);
- void SP_misc_banner(edict_t *self);
- void SP_misc_satellite_dish(edict_t *self);
- void SP_misc_actor(edict_t *self);
- void SP_misc_gib_arm(edict_t *self);
- void SP_misc_gib_leg(edict_t *self);
- void SP_misc_gib_head(edict_t *self);
- void SP_misc_insane(edict_t *self);
- void SP_misc_deadsoldier(edict_t *self);
- void SP_misc_viper(edict_t *self);
- void SP_misc_viper_bomb(edict_t *self);
- void SP_misc_bigviper(edict_t *self);
- void SP_misc_strogg_ship(edict_t *self);
- void SP_misc_teleporter(edict_t *self);
- void SP_misc_teleporter_dest(edict_t *self);
- void SP_misc_blackhole(edict_t *self);
- void SP_misc_eastertank(edict_t *self);
- void SP_misc_easterchick(edict_t *self);
- void SP_misc_easterchick2(edict_t *self);
- void SP_misc_flare(edict_t* ent); // [Sam-KEX]
- void SP_misc_hologram(edict_t *ent);
- void SP_misc_lavaball(edict_t *ent);
- void SP_monster_berserk(edict_t *self);
- void SP_monster_gladiator(edict_t *self);
- void SP_monster_gunner(edict_t *self);
- void SP_monster_infantry(edict_t *self);
- void SP_monster_soldier_light(edict_t *self);
- void SP_monster_soldier(edict_t *self);
- void SP_monster_soldier_ss(edict_t *self);
- void SP_monster_tank(edict_t *self);
- void SP_monster_medic(edict_t *self);
- void SP_monster_flipper(edict_t *self);
- void SP_monster_chick(edict_t *self);
- void SP_monster_parasite(edict_t *self);
- void SP_monster_flyer(edict_t *self);
- void SP_monster_brain(edict_t *self);
- void SP_monster_floater(edict_t *self);
- void SP_monster_hover(edict_t *self);
- void SP_monster_mutant(edict_t *self);
- void SP_monster_supertank(edict_t *self);
- void SP_monster_boss2(edict_t *self);
- void SP_monster_jorg(edict_t *self);
- void SP_monster_boss3_stand(edict_t *self);
- void SP_monster_makron(edict_t *self);
- // Paril
- void SP_monster_tank_stand(edict_t *self);
- void SP_monster_guardian(edict_t *self);
- void SP_monster_arachnid(edict_t *self);
- void SP_monster_guncmdr(edict_t *self);
- void SP_monster_commander_body(edict_t *self);
- void SP_turret_breach(edict_t *self);
- void SP_turret_base(edict_t *self);
- void SP_turret_driver(edict_t *self);
- // RAFAEL 14-APR-98
- void SP_monster_soldier_hypergun(edict_t *self);
- void SP_monster_soldier_lasergun(edict_t *self);
- void SP_monster_soldier_ripper(edict_t *self);
- void SP_monster_fixbot(edict_t *self);
- void SP_monster_gekk(edict_t *self);
- void SP_monster_chick_heat(edict_t *self);
- void SP_monster_gladb(edict_t *self);
- void SP_monster_boss5(edict_t *self);
- void SP_rotating_light(edict_t *self);
- void SP_object_repair(edict_t *self);
- void SP_misc_crashviper(edict_t *ent);
- void SP_misc_viper_missile(edict_t *self);
- void SP_misc_amb4(edict_t *ent);
- void SP_target_mal_laser(edict_t *ent);
- void SP_misc_transport(edict_t *ent);
- // END 14-APR-98
- void SP_misc_nuke(edict_t *ent);
- //===========
- // ROGUE
- void SP_func_plat2(edict_t *ent);
- void SP_func_door_secret2(edict_t *ent);
- void SP_func_force_wall(edict_t *ent);
- void SP_info_player_coop_lava(edict_t *self);
- void SP_info_teleport_destination(edict_t *self);
- void SP_trigger_teleport(edict_t *self);
- void SP_trigger_disguise(edict_t *self);
- void SP_monster_stalker(edict_t *self);
- void SP_monster_turret(edict_t *self);
- void SP_target_steam(edict_t *self);
- void SP_target_anger(edict_t *self);
- void SP_target_killplayers(edict_t *self);
- // PMM - still experimental!
- void SP_target_blacklight(edict_t *self);
- void SP_target_orb(edict_t *self);
- // pmm
- void SP_hint_path(edict_t *self);
- void SP_monster_carrier(edict_t *self);
- void SP_monster_widow(edict_t *self);
- void SP_monster_widow2(edict_t *self);
- void SP_dm_tag_token(edict_t *self);
- void SP_dm_dball_goal(edict_t *self);
- void SP_dm_dball_ball(edict_t *self);
- void SP_dm_dball_team1_start(edict_t *self);
- void SP_dm_dball_team2_start(edict_t *self);
- void SP_dm_dball_ball_start(edict_t *self);
- void SP_dm_dball_speed_change(edict_t *self);
- void SP_monster_kamikaze(edict_t *self);
- void SP_turret_invisible_brain(edict_t *self);
- void SP_misc_nuke_core(edict_t *self);
- // ROGUE
- //===========
- // ZOID
- void SP_trigger_ctf_teleport(edict_t *self);
- void SP_info_ctf_teleport_destination(edict_t *self);
- // ZOID
- void SP_monster_shambler(edict_t* self);
- // clang-format off
- static const std::initializer_list<spawn_t> spawns = {
- { "info_player_start", SP_info_player_start },
- { "info_player_deathmatch", SP_info_player_deathmatch },
- { "info_player_coop", SP_info_player_coop },
- { "info_player_intermission", SP_info_player_intermission },
- { "func_plat", SP_func_plat },
- { "func_button", SP_func_button },
- { "func_door", SP_func_door },
- { "func_door_secret", SP_func_door_secret },
- { "func_door_rotating", SP_func_door_rotating },
- { "func_rotating", SP_func_rotating },
- { "func_train", SP_func_train },
- { "func_water", SP_func_water },
- { "func_conveyor", SP_func_conveyor },
- { "func_areaportal", SP_func_areaportal },
- { "func_clock", SP_func_clock },
- { "func_wall", SP_func_wall },
- { "func_object", SP_func_object },
- { "func_timer", SP_func_timer },
- { "func_explosive", SP_func_explosive },
- { "func_killbox", SP_func_killbox },
- { "func_eye", SP_func_eye },
- { "func_animation", SP_func_animation },
- { "func_spinning", SP_func_spinning },
- { "trigger_always", SP_trigger_always },
- { "trigger_once", SP_trigger_once },
- { "trigger_multiple", SP_trigger_multiple },
- { "trigger_relay", SP_trigger_relay },
- { "trigger_push", SP_trigger_push },
- { "trigger_hurt", SP_trigger_hurt },
- { "trigger_key", SP_trigger_key },
- { "trigger_counter", SP_trigger_counter },
- { "trigger_elevator", SP_trigger_elevator },
- { "trigger_gravity", SP_trigger_gravity },
- { "trigger_monsterjump", SP_trigger_monsterjump },
- { "trigger_flashlight", SP_trigger_flashlight }, // [Paril-KEX]
- { "trigger_fog", SP_trigger_fog }, // [Paril-KEX]
- { "trigger_coop_relay", SP_trigger_coop_relay }, // [Paril-KEX]
- { "trigger_health_relay", SP_trigger_health_relay }, // [Paril-KEX]
- { "target_temp_entity", SP_target_temp_entity },
- { "target_speaker", SP_target_speaker },
- { "target_explosion", SP_target_explosion },
- { "target_changelevel", SP_target_changelevel },
- { "target_secret", SP_target_secret },
- { "target_goal", SP_target_goal },
- { "target_splash", SP_target_splash },
- { "target_spawner", SP_target_spawner },
- { "target_blaster", SP_target_blaster },
- { "target_crosslevel_trigger", SP_target_crosslevel_trigger },
- { "target_crosslevel_target", SP_target_crosslevel_target },
- { "target_crossunit_trigger", SP_target_crossunit_trigger }, // [Paril-KEX]
- { "target_crossunit_target", SP_target_crossunit_target }, // [Paril-KEX]
- { "target_laser", SP_target_laser },
- { "target_help", SP_target_help },
- { "target_actor", SP_target_actor },
- { "target_lightramp", SP_target_lightramp },
- { "target_earthquake", SP_target_earthquake },
- { "target_character", SP_target_character },
- { "target_string", SP_target_string },
- { "target_camera", SP_target_camera }, // [Sam-KEX]
- { "target_gravity", SP_target_gravity }, // [Sam-KEX]
- { "target_soundfx", SP_target_soundfx }, // [Sam-KEX]
- { "target_light", SP_target_light }, // [Paril-KEX]
- { "target_poi", SP_target_poi }, // [Paril-KEX]
- { "target_music", SP_target_music },
- { "target_healthbar", SP_target_healthbar }, // [Paril-KEX]
- { "target_autosave", SP_target_autosave }, // [Paril-KEX]
- { "target_sky", SP_target_sky }, // [Paril-KEX]
- { "target_achievement", SP_target_achievement }, // [Paril-KEX]
- { "target_story", SP_target_story }, // [Paril-KEX]
- { "worldspawn", SP_worldspawn },
- { "dynamic_light", SP_dynamic_light },
- { "light", SP_light },
- { "light_mine1", SP_light_mine1 },
- { "light_mine2", SP_light_mine2 },
- { "info_null", SP_info_null },
- { "func_group", SP_info_null },
- { "info_notnull", SP_info_notnull },
- { "info_landmark", SP_info_landmark },
- { "info_world_text", SP_info_world_text },
- { "path_corner", SP_path_corner },
- { "point_combat", SP_point_combat },
- { "info_nav_lock", SP_info_nav_lock },
- { "misc_explobox", SP_misc_explobox },
- { "misc_banner", SP_misc_banner },
- { "misc_satellite_dish", SP_misc_satellite_dish },
- { "misc_actor", SP_misc_actor },
- { "misc_player_mannequin", SP_misc_player_mannequin },
- { "misc_model", SP_misc_model }, // [Paril-KEX]
- { "misc_gib_arm", SP_misc_gib_arm },
- { "misc_gib_leg", SP_misc_gib_leg },
- { "misc_gib_head", SP_misc_gib_head },
- { "misc_insane", SP_misc_insane },
- { "misc_deadsoldier", SP_misc_deadsoldier },
- { "misc_viper", SP_misc_viper },
- { "misc_viper_bomb", SP_misc_viper_bomb },
- { "misc_bigviper", SP_misc_bigviper },
- { "misc_strogg_ship", SP_misc_strogg_ship },
- { "misc_teleporter", SP_misc_teleporter },
- { "misc_teleporter_dest", SP_misc_teleporter_dest },
- { "misc_blackhole", SP_misc_blackhole },
- { "misc_eastertank", SP_misc_eastertank },
- { "misc_easterchick", SP_misc_easterchick },
- { "misc_easterchick2", SP_misc_easterchick2 },
- { "misc_flare", SP_misc_flare }, // [Sam-KEX]
- { "misc_hologram", SP_misc_hologram }, // Paril
- { "misc_lavaball", SP_misc_lavaball }, // Paril
- { "monster_berserk", SP_monster_berserk },
- { "monster_gladiator", SP_monster_gladiator },
- { "monster_gunner", SP_monster_gunner },
- { "monster_infantry", SP_monster_infantry },
- { "monster_soldier_light", SP_monster_soldier_light },
- { "monster_soldier", SP_monster_soldier },
- { "monster_soldier_ss", SP_monster_soldier_ss },
- { "monster_tank", SP_monster_tank },
- { "monster_tank_commander", SP_monster_tank },
- { "monster_medic", SP_monster_medic },
- { "monster_flipper", SP_monster_flipper },
- { "monster_chick", SP_monster_chick },
- { "monster_parasite", SP_monster_parasite },
- { "monster_flyer", SP_monster_flyer },
- { "monster_brain", SP_monster_brain },
- { "monster_floater", SP_monster_floater },
- { "monster_hover", SP_monster_hover },
- { "monster_mutant", SP_monster_mutant },
- { "monster_supertank", SP_monster_supertank },
- { "monster_boss2", SP_monster_boss2 },
- { "monster_boss3_stand", SP_monster_boss3_stand },
- { "monster_jorg", SP_monster_jorg },
- // Paril: allow spawning makron
- { "monster_makron", SP_monster_makron },
- // Paril: N64
- { "monster_tank_stand", SP_monster_tank_stand },
- // Paril: PSX
- { "monster_guardian", SP_monster_guardian },
- { "monster_arachnid", SP_monster_arachnid },
- { "monster_guncmdr", SP_monster_guncmdr },
- { "monster_commander_body", SP_monster_commander_body },
- { "turret_breach", SP_turret_breach },
- { "turret_base", SP_turret_base },
- { "turret_driver", SP_turret_driver },
- // RAFAEL
- { "func_object_repair", SP_object_repair },
- { "rotating_light", SP_rotating_light },
- { "target_mal_laser", SP_target_mal_laser },
- { "misc_crashviper", SP_misc_crashviper },
- { "misc_viper_missile", SP_misc_viper_missile },
- { "misc_amb4", SP_misc_amb4 },
- { "misc_transport", SP_misc_transport },
- { "misc_nuke", SP_misc_nuke },
- { "monster_soldier_hypergun", SP_monster_soldier_hypergun },
- { "monster_soldier_lasergun", SP_monster_soldier_lasergun },
- { "monster_soldier_ripper", SP_monster_soldier_ripper },
- { "monster_fixbot", SP_monster_fixbot },
- { "monster_gekk", SP_monster_gekk },
- { "monster_chick_heat", SP_monster_chick_heat },
- { "monster_gladb", SP_monster_gladb },
- { "monster_boss5", SP_monster_boss5 },
- // RAFAEL
- //==============
- // ROGUE
- { "func_plat2", SP_func_plat2 },
- { "func_door_secret2", SP_func_door_secret2 },
- { "func_force_wall", SP_func_force_wall },
- { "trigger_teleport", SP_trigger_teleport },
- { "trigger_disguise", SP_trigger_disguise },
- { "info_teleport_destination", SP_info_teleport_destination },
- { "info_player_coop_lava", SP_info_player_coop_lava },
- { "monster_stalker", SP_monster_stalker },
- { "monster_turret", SP_monster_turret },
- { "target_steam", SP_target_steam },
- { "target_anger", SP_target_anger },
- { "target_killplayers", SP_target_killplayers },
- // PMM - experiment
- { "target_blacklight", SP_target_blacklight },
- { "target_orb", SP_target_orb },
- // pmm
- { "monster_daedalus", SP_monster_hover },
- { "hint_path", SP_hint_path },
- { "monster_carrier", SP_monster_carrier },
- { "monster_widow", SP_monster_widow },
- { "monster_widow2", SP_monster_widow2 },
- { "monster_medic_commander", SP_monster_medic },
- { "dm_tag_token", SP_dm_tag_token },
- { "dm_dball_goal", SP_dm_dball_goal },
- { "dm_dball_ball", SP_dm_dball_ball },
- { "dm_dball_team1_start", SP_dm_dball_team1_start },
- { "dm_dball_team2_start", SP_dm_dball_team2_start },
- { "dm_dball_ball_start", SP_dm_dball_ball_start },
- { "dm_dball_speed_change", SP_dm_dball_speed_change },
- { "monster_kamikaze", SP_monster_kamikaze },
- { "turret_invisible_brain", SP_turret_invisible_brain },
- { "misc_nuke_core", SP_misc_nuke_core },
- // ROGUE
- //==============
- // ZOID
- { "trigger_ctf_teleport", SP_trigger_ctf_teleport },
- { "info_ctf_teleport_destination", SP_info_ctf_teleport_destination },
- { "misc_ctf_banner", SP_misc_ctf_banner },
- { "misc_ctf_small_banner", SP_misc_ctf_small_banner },
- { "info_player_team1", SP_info_player_team1 },
- { "info_player_team2", SP_info_player_team2 },
- // ZOID
- { "monster_shambler", SP_monster_shambler }
- };
- // clang-format on
- /*
- ===============
- ED_CallSpawn
- Finds the spawn function for the entity and calls it
- ===============
- */
- void ED_CallSpawn(edict_t *ent)
- {
- gitem_t *item;
- int i;
- if (!ent->classname)
- {
- gi.Com_Print("ED_CallSpawn: nullptr classname\n");
- G_FreeEdict(ent);
- return;
- }
- // PGM - do this before calling the spawn function so it can be overridden.
- ent->gravityVector[0] = 0.0;
- ent->gravityVector[1] = 0.0;
- ent->gravityVector[2] = -1.0;
- // PGM
- ent->sv.init = false;
- // FIXME - PMM classnames hack
- if (!strcmp(ent->classname, "weapon_nailgun"))
- ent->classname = GetItemByIndex(IT_WEAPON_ETF_RIFLE)->classname;
- if (!strcmp(ent->classname, "ammo_nails"))
- ent->classname = GetItemByIndex(IT_AMMO_FLECHETTES)->classname;
- if (!strcmp(ent->classname, "weapon_heatbeam"))
- ent->classname = GetItemByIndex(IT_WEAPON_PLASMABEAM)->classname;
- // pmm
- // check item spawn functions
- for (i = 0, item = itemlist; i < IT_TOTAL; i++, item++)
- {
- if (!item->classname)
- continue;
- if (!strcmp(item->classname, ent->classname))
- {
- // found it
- // before spawning, pick random item replacement
- if (g_dm_random_items->integer)
- {
- ent->item = item;
- item_id_t new_item = DoRandomRespawn(ent);
- if (new_item)
- {
- item = GetItemByIndex(new_item);
- ent->classname = item->classname;
- }
- }
- SpawnItem(ent, item);
- return;
- }
- }
- // check normal spawn functions
- for (auto &s : spawns)
- {
- if (!strcmp(s.name, ent->classname))
- { // found it
- s.spawn(ent);
- // Paril: swap classname with stored constant if we didn't change it
- if (strcmp(ent->classname, s.name) == 0)
- ent->classname = s.name;
- return;
- }
- }
- gi.Com_PrintFmt("{} doesn't have a spawn function\n", *ent);
- G_FreeEdict(ent);
- }
- /*
- =============
- ED_NewString
- =============
- */
- char *ED_NewString(const char *string)
- {
- char *newb, *new_p;
- int i;
- size_t l;
- l = strlen(string) + 1;
- newb = (char *) gi.TagMalloc(l, TAG_LEVEL);
- new_p = newb;
- for (i = 0; i < l; i++)
- {
- if (string[i] == '\\' && i < l - 1)
- {
- i++;
- if (string[i] == 'n')
- *new_p++ = '\n';
- else
- *new_p++ = '\\';
- }
- else
- *new_p++ = string[i];
- }
- return newb;
- }
- //
- // fields are used for spawning from the entity string
- //
- struct field_t
- {
- const char *name;
- void (*load_func) (edict_t *e, const char *s) = nullptr;
- };
- // utility template for getting the type of a field
- template<typename>
- struct member_object_container_type { };
- template<typename T1, typename T2>
- struct member_object_container_type<T1 T2::*> { using type = T2; };
- template<typename T>
- using member_object_container_type_t = typename member_object_container_type<std::remove_cv_t<T>>::type;
- struct type_loaders_t
- {
- template<typename T, std::enable_if_t<std::is_same_v<T, const char *>, int> = 0>
- static T load(const char *s)
- {
- return ED_NewString(s);
- }
- template<typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
- static T load(const char *s)
- {
- return atoi(s);
- }
- template<typename T, std::enable_if_t<std::is_same_v<T, spawnflags_t>, int> = 0>
- static T load(const char *s)
- {
- return spawnflags_t(atoi(s));
- }
- template<typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
- static T load(const char *s)
- {
- return atof(s);
- }
- template<typename T, std::enable_if_t<std::is_enum_v<T>, int> = 0>
- static T load(const char *s)
- {
- if constexpr (sizeof(T) > 4)
- return static_cast<T>(atoll(s));
- else
- return static_cast<T>(atoi(s));
- }
- template<typename T, std::enable_if_t<std::is_same_v<T, vec3_t>, int> = 0>
- static T load(const char *s)
- {
- vec3_t vec;
- static char vec_buffer[32];
- const char *token = COM_Parse(&s, vec_buffer, sizeof(vec_buffer));
- vec.x = atof(token);
- token = COM_Parse(&s);
- vec.y = atof(token);
- token = COM_Parse(&s);
- vec.z = atof(token);
- return vec;
- }
- };
- #define AUTO_LOADER_FUNC(M) \
- [](edict_t *e, const char *s) { \
- e->M = type_loaders_t::load<decltype(e->M)>(s); \
- }
- static int32_t ED_LoadColor(const char *value)
- {
- // space means rgba as values
- if (strchr(value, ' '))
- {
- static char color_buffer[32];
- std::array<float, 4> raw_values { 0, 0, 0, 1.0f };
- bool is_float = true;
- for (auto &v : raw_values)
- {
- const char *token = COM_Parse(&value, color_buffer, sizeof(color_buffer));
- if (*token)
- {
- v = atof(token);
- if (v > 1.0f)
- is_float = false;
- }
- }
- if (is_float)
- for (auto &v : raw_values)
- v *= 255.f;
- return ((int32_t) raw_values[3]) | (((int32_t) raw_values[2]) << 8) | (((int32_t) raw_values[1]) << 16) | (((int32_t) raw_values[0]) << 24);
- }
- // integral
- return atoi(value);
- }
- #define FIELD_COLOR(n, x) \
- { n, [](edict_t *e, const char *s) { \
- e->x = ED_LoadColor(s); \
- } }
- // clang-format off
- // fields that get copied directly to edict_t
- #define FIELD_AUTO(x) \
- { #x, AUTO_LOADER_FUNC(x) }
- #define FIELD_AUTO_NAMED(n, x) \
- { n, AUTO_LOADER_FUNC(x) }
- static const std::initializer_list<field_t> entity_fields = {
- FIELD_AUTO(classname),
- FIELD_AUTO(model),
- FIELD_AUTO(spawnflags),
- FIELD_AUTO(speed),
- FIELD_AUTO(accel),
- FIELD_AUTO(decel),
- FIELD_AUTO(target),
- FIELD_AUTO(targetname),
- FIELD_AUTO(pathtarget),
- FIELD_AUTO(deathtarget),
- FIELD_AUTO(healthtarget),
- FIELD_AUTO(itemtarget),
- FIELD_AUTO(killtarget),
- FIELD_AUTO(combattarget),
- FIELD_AUTO(message),
- FIELD_AUTO(team),
- FIELD_AUTO(wait),
- FIELD_AUTO(delay),
- FIELD_AUTO(random),
- FIELD_AUTO(move_origin),
- FIELD_AUTO(move_angles),
- FIELD_AUTO(style),
- FIELD_AUTO(style_on),
- FIELD_AUTO(style_off),
- FIELD_AUTO(crosslevel_flags),
- FIELD_AUTO(count),
- FIELD_AUTO(health),
- FIELD_AUTO(sounds),
- { "light" },
- FIELD_AUTO(dmg),
- FIELD_AUTO(mass),
- FIELD_AUTO(volume),
- FIELD_AUTO(attenuation),
- FIELD_AUTO(map),
- FIELD_AUTO_NAMED("origin", s.origin),
- FIELD_AUTO_NAMED("angles", s.angles),
- { "angle", [](edict_t *e, const char *value) {
- e->s.angles = {};
- e->s.angles[YAW] = atof(value);
- } },
- FIELD_COLOR("rgba", s.skinnum), // [Sam-KEX]
- FIELD_AUTO(hackflags), // [Paril-KEX] n64
- FIELD_AUTO_NAMED("alpha", s.alpha), // [Paril-KEX]
- FIELD_AUTO_NAMED("scale", s.scale), // [Paril-KEX]
- { "mangle" }, // editor field
- FIELD_AUTO_NAMED("dead_frame", monsterinfo.start_frame), // [Paril-KEX]
- FIELD_AUTO_NAMED("frame", s.frame),
- FIELD_AUTO_NAMED("effects", s.effects),
- FIELD_AUTO_NAMED("renderfx", s.renderfx),
- // [Paril-KEX] fog keys
- FIELD_AUTO_NAMED("fog_color", fog.color),
- FIELD_AUTO_NAMED("fog_color_off", fog.color_off),
- FIELD_AUTO_NAMED("fog_density", fog.density),
- FIELD_AUTO_NAMED("fog_density_off", fog.density_off),
- FIELD_AUTO_NAMED("fog_sky_factor", fog.sky_factor),
- FIELD_AUTO_NAMED("fog_sky_factor_off", fog.sky_factor_off),
-
- FIELD_AUTO_NAMED("heightfog_falloff", heightfog.falloff),
- FIELD_AUTO_NAMED("heightfog_density", heightfog.density),
- FIELD_AUTO_NAMED("heightfog_start_color", heightfog.start_color),
- FIELD_AUTO_NAMED("heightfog_start_dist", heightfog.start_dist),
- FIELD_AUTO_NAMED("heightfog_end_color", heightfog.end_color),
- FIELD_AUTO_NAMED("heightfog_end_dist", heightfog.end_dist),
- FIELD_AUTO_NAMED("heightfog_falloff_off", heightfog.falloff_off),
- FIELD_AUTO_NAMED("heightfog_density_off", heightfog.density_off),
- FIELD_AUTO_NAMED("heightfog_start_color_off", heightfog.start_color_off),
- FIELD_AUTO_NAMED("heightfog_start_dist_off", heightfog.start_dist_off),
- FIELD_AUTO_NAMED("heightfog_end_color_off", heightfog.end_color_off),
- FIELD_AUTO_NAMED("heightfog_end_dist_off", heightfog.end_dist_off),
- // [Paril-KEX] func_eye stuff
- FIELD_AUTO_NAMED("eye_position", move_origin),
- FIELD_AUTO_NAMED("vision_cone", yaw_speed),
- // [Paril-KEX] for trigger_coop_relay
- FIELD_AUTO_NAMED("message2", map),
- FIELD_AUTO(mins),
- FIELD_AUTO(maxs),
- // [Paril-KEX] customizable bmodel animations
- FIELD_AUTO_NAMED("bmodel_anim_start", bmodel_anim.start),
- FIELD_AUTO_NAMED("bmodel_anim_end", bmodel_anim.end),
- FIELD_AUTO_NAMED("bmodel_anim_style", bmodel_anim.style),
- FIELD_AUTO_NAMED("bmodel_anim_speed", bmodel_anim.speed),
- FIELD_AUTO_NAMED("bmodel_anim_nowrap", bmodel_anim.nowrap),
- FIELD_AUTO_NAMED("bmodel_anim_alt_start", bmodel_anim.alt_start),
- FIELD_AUTO_NAMED("bmodel_anim_alt_end", bmodel_anim.alt_end),
- FIELD_AUTO_NAMED("bmodel_anim_alt_style", bmodel_anim.alt_style),
- FIELD_AUTO_NAMED("bmodel_anim_alt_speed", bmodel_anim.alt_speed),
- FIELD_AUTO_NAMED("bmodel_anim_alt_nowrap", bmodel_anim.alt_nowrap),
- // [Paril-KEX] customizable power armor stuff
- FIELD_AUTO_NAMED("power_armor_power", monsterinfo.power_armor_power),
- { "power_armor_type", [](edict_t *s, const char *v)
- {
- int32_t type = atoi(v);
- if (type == 0)
- s->monsterinfo.power_armor_type = IT_NULL;
- else if (type == 1)
- s->monsterinfo.power_armor_type = IT_ITEM_POWER_SCREEN;
- else
- s->monsterinfo.power_armor_type = IT_ITEM_POWER_SHIELD;
- }
- },
- FIELD_AUTO_NAMED("monster_slots", monsterinfo.monster_slots)
- };
- #undef AUTO_LOADER_FUNC
- #define AUTO_LOADER_FUNC(M) \
- [](spawn_temp_t *e, const char *s) { \
- e->M = type_loaders_t::load<decltype(e->M)>(s); \
- }
- struct temp_field_t
- {
- const char *name;
- void (*load_func) (spawn_temp_t *e, const char *s) = nullptr;
- };
- // temp spawn vars -- only valid when the spawn function is called
- // (copied to `st`)
- static const std::initializer_list<temp_field_t> temp_fields = {
- FIELD_AUTO(lip),
- FIELD_AUTO(distance),
- FIELD_AUTO(height),
- FIELD_AUTO(noise),
- FIELD_AUTO(pausetime),
- FIELD_AUTO(item),
- FIELD_AUTO(gravity),
- FIELD_AUTO(sky),
- FIELD_AUTO(skyrotate),
- FIELD_AUTO(skyaxis),
- FIELD_AUTO(skyautorotate),
- FIELD_AUTO(minyaw),
- FIELD_AUTO(maxyaw),
- FIELD_AUTO(minpitch),
- FIELD_AUTO(maxpitch),
- FIELD_AUTO(nextmap),
- FIELD_AUTO(music), // [Edward-KEX]
- FIELD_AUTO(instantitems),
- FIELD_AUTO(radius), // [Paril-KEX]
- FIELD_AUTO(hub_map),
- FIELD_AUTO(achievement),
- FIELD_AUTO_NAMED("shadowlightradius", sl.data.radius),
- FIELD_AUTO_NAMED("shadowlightresolution", sl.data.resolution),
- FIELD_AUTO_NAMED("shadowlightintensity", sl.data.intensity),
- FIELD_AUTO_NAMED("shadowlightstartfadedistance", sl.data.fade_start),
- FIELD_AUTO_NAMED("shadowlightendfadedistance", sl.data.fade_end),
- FIELD_AUTO_NAMED("shadowlightstyle", sl.data.lightstyle),
- FIELD_AUTO_NAMED("shadowlightconeangle", sl.data.coneangle),
- FIELD_AUTO_NAMED("shadowlightstyletarget", sl.lightstyletarget),
- FIELD_AUTO(goals),
- FIELD_AUTO(image),
- FIELD_AUTO(fade_start_dist),
- FIELD_AUTO(fade_end_dist),
- FIELD_AUTO(start_items),
- FIELD_AUTO(no_grapple),
- FIELD_AUTO(health_multiplier),
- FIELD_AUTO(reinforcements),
- FIELD_AUTO(noise_start),
- FIELD_AUTO(noise_middle),
- FIELD_AUTO(noise_end),
- FIELD_AUTO(loop_count)
- };
- // clang-format on
- /*
- ===============
- ED_ParseField
- Takes a key/value pair and sets the binary values
- in an edict
- ===============
- */
- void ED_ParseField(const char *key, const char *value, edict_t *ent)
- {
- // check st first
- for (auto &f : temp_fields)
- {
- if (Q_strcasecmp(f.name, key))
- continue;
- st.keys_specified.emplace(f.name);
- // found it
- if (f.load_func)
- f.load_func(&st, value);
-
- return;
- }
- // now entity
- for (auto &f : entity_fields)
- {
- if (Q_strcasecmp(f.name, key))
- continue;
- st.keys_specified.emplace(f.name);
- // [Paril-KEX]
- if (!strcmp(f.name, "bmodel_anim_start") || !strcmp(f.name, "bmodel_anim_end"))
- ent->bmodel_anim.enabled = true;
- // found it
- if (f.load_func)
- f.load_func(ent, value);
- return;
- }
- gi.Com_PrintFmt("{} is not a valid field\n", key);
- }
- /*
- ====================
- ED_ParseEdict
- Parses an edict out of the given string, returning the new position
- ed should be a properly initialized empty edict.
- ====================
- */
- const char *ED_ParseEdict(const char *data, edict_t *ent)
- {
- bool init;
- char keyname[256];
- const char *com_token;
- init = false;
- st = {};
-
- // go through all the dictionary pairs
- while (1)
- {
- // parse key
- com_token = COM_Parse(&data);
- if (com_token[0] == '}')
- break;
- if (!data)
- gi.Com_Error("ED_ParseEntity: EOF without closing brace");
- Q_strlcpy(keyname, com_token, sizeof(keyname));
- // parse value
- com_token = COM_Parse(&data);
- if (!data)
- gi.Com_Error("ED_ParseEntity: EOF without closing brace");
- if (com_token[0] == '}')
- gi.Com_Error("ED_ParseEntity: closing brace without data");
- init = true;
- // keynames with a leading underscore are used for utility comments,
- // and are immediately discarded by quake
- if (keyname[0] == '_')
- {
- // [Sam-KEX] Hack for setting RGBA for shadow-casting lights
- if(!strcmp(keyname, "_color"))
- ent->s.skinnum = ED_LoadColor(com_token);
- continue;
- }
- ED_ParseField(keyname, com_token, ent);
- }
- if (!init)
- memset(ent, 0, sizeof(*ent));
- return data;
- }
- /*
- ================
- G_FindTeams
- Chain together all entities with a matching team field.
- All but the first will have the FL_TEAMSLAVE flag set.
- All but the last will have the teamchain field set to the next one
- ================
- */
- // adjusts teams so that trains that move their children
- // are in the front of the team
- void G_FixTeams()
- {
- edict_t *e, *e2, *chain;
- uint32_t i, j;
- uint32_t c;
- c = 0;
- for (i = 1, e = g_edicts + i; i < globals.num_edicts; i++, e++)
- {
- if (!e->inuse)
- continue;
- if (!e->team)
- continue;
- if (!strcmp(e->classname, "func_train") && e->spawnflags.has(SPAWNFLAG_TRAIN_MOVE_TEAMCHAIN))
- {
- if (e->flags & FL_TEAMSLAVE)
- {
- chain = e;
- e->teammaster = e;
- e->teamchain = nullptr;
- e->flags &= ~FL_TEAMSLAVE;
- e->flags |= FL_TEAMMASTER;
- c++;
- for (j = 1, e2 = g_edicts + j; j < globals.num_edicts; j++, e2++)
- {
- if (e2 == e)
- continue;
- if (!e2->inuse)
- continue;
- if (!e2->team)
- continue;
- if (!strcmp(e->team, e2->team))
- {
- chain->teamchain = e2;
- e2->teammaster = e;
- e2->teamchain = nullptr;
- chain = e2;
- e2->flags |= FL_TEAMSLAVE;
- e2->flags &= ~FL_TEAMMASTER;
- e2->movetype = MOVETYPE_PUSH;
- e2->speed = e->speed;
- }
- }
- }
- }
- }
- gi.Com_PrintFmt("{} teams repaired\n", c);
- }
- void G_FindTeams()
- {
- edict_t *e, *e2, *chain;
- uint32_t i, j;
- uint32_t c, c2;
- c = 0;
- c2 = 0;
- for (i = 1, e = g_edicts + i; i < globals.num_edicts; i++, e++)
- {
- if (!e->inuse)
- continue;
- if (!e->team)
- continue;
- if (e->flags & FL_TEAMSLAVE)
- continue;
- chain = e;
- e->teammaster = e;
- e->flags |= FL_TEAMMASTER;
- c++;
- c2++;
- for (j = i + 1, e2 = e + 1; j < globals.num_edicts; j++, e2++)
- {
- if (!e2->inuse)
- continue;
- if (!e2->team)
- continue;
- if (e2->flags & FL_TEAMSLAVE)
- continue;
- if (!strcmp(e->team, e2->team))
- {
- c2++;
- chain->teamchain = e2;
- e2->teammaster = e;
- chain = e2;
- e2->flags |= FL_TEAMSLAVE;
- }
- }
- }
- // ROGUE
- G_FixTeams();
- // ROGUE
- gi.Com_PrintFmt("{} teams with {} entities\n", c, c2);
- }
- // inhibit entities from game based on cvars & spawnflags
- inline bool G_InhibitEntity(edict_t *ent)
- {
- // dm-only
- if (deathmatch->integer)
- return ent->spawnflags.has(SPAWNFLAG_NOT_DEATHMATCH);
- // coop flags
- if (coop->integer && ent->spawnflags.has(SPAWNFLAG_NOT_COOP))
- return true;
- else if (!coop->integer && ent->spawnflags.has(SPAWNFLAG_COOP_ONLY))
- return true;
- // skill
- return ((skill->integer == 0) && ent->spawnflags.has(SPAWNFLAG_NOT_EASY)) ||
- ((skill->integer == 1) && ent->spawnflags.has(SPAWNFLAG_NOT_MEDIUM)) ||
- ((skill->integer >= 2) && ent->spawnflags.has(SPAWNFLAG_NOT_HARD));
- }
- void setup_shadow_lights();
- // [Paril-KEX]
- void G_PrecacheInventoryItems()
- {
- if (deathmatch->integer)
- return;
- for (size_t i = 0; i < game.maxclients; i++)
- {
- gclient_t *cl = g_edicts[i + 1].client;
- if (!cl)
- continue;
- for (item_id_t id = IT_NULL; id != IT_TOTAL; id = static_cast<item_id_t>(id + 1))
- if (cl->pers.inventory[id])
- PrecacheItem(GetItemByIndex(id));
- }
- }
- // [Paril-KEX]
- static void G_PrecacheStartItems()
- {
- if (!*g_start_items->string)
- return;
- char token_copy[MAX_TOKEN_CHARS];
- const char *token;
- const char *ptr = g_start_items->string;
- while (*(token = COM_ParseEx(&ptr, ";")))
- {
- Q_strlcpy(token_copy, token, sizeof(token_copy));
- const char *ptr_copy = token_copy;
- const char *item_name = COM_Parse(&ptr_copy);
- gitem_t *item = FindItemByClassname(item_name);
- if (!item || !item->pickup)
- gi.Com_ErrorFmt("Invalid g_start_item entry: {}\n", item_name);
- if (*ptr_copy)
- COM_Parse(&ptr_copy);
- PrecacheItem(item);
- }
- }
- /*
- ==============
- SpawnEntities
- Creates a server's entity / program execution context by
- parsing textual entity definitions out of an ent file.
- ==============
- */
- void SpawnEntities(const char *mapname, const char *entities, const char *spawnpoint)
- {
- // clear cached indices
- cached_soundindex::clear_all();
- cached_modelindex::clear_all();
- cached_imageindex::clear_all();
- edict_t *ent;
- int inhibit;
- const char *com_token;
- int skill_level = clamp(skill->integer, 0, 3);
- if (skill->integer != skill_level)
- gi.cvar_forceset("skill", G_Fmt("{}", skill_level).data());
- SaveClientData();
- gi.FreeTags(TAG_LEVEL);
- memset(&level, 0, sizeof(level));
- memset(g_edicts, 0, game.maxentities * sizeof(g_edicts[0]));
- // all other flags are not important atm
- globals.server_flags &= SERVER_FLAG_LOADING;
- Q_strlcpy(level.mapname, mapname, sizeof(level.mapname));
- // Paril: fixes a bug where autosaves will start you at
- // the wrong spawnpoint if they happen to be non-empty
- // (mine2 -> mine3)
- if (!game.autosaved)
- Q_strlcpy(game.spawnpoint, spawnpoint, sizeof(game.spawnpoint));
- level.is_n64 = strncmp(level.mapname, "q64/", 4) == 0;
- level.coop_scale_players = 0;
- level.coop_health_scaling = clamp(g_coop_health_scaling->value, 0.f, 1.f);
- // set client fields on player ents
- for (uint32_t i = 0; i < game.maxclients; i++)
- {
- g_edicts[i + 1].client = game.clients + i;
- // "disconnect" all players since the level is switching
- game.clients[i].pers.connected = false;
- game.clients[i].pers.spawned = false;
- }
- ent = nullptr;
- inhibit = 0;
- // reserve some spots for dead player bodies for coop / deathmatch
- InitBodyQue();
- // parse ents
- while (1)
- {
- // parse the opening brace
- com_token = COM_Parse(&entities);
- if (!entities)
- break;
- if (com_token[0] != '{')
- gi.Com_ErrorFmt("ED_LoadFromFile: found \"{}\" when expecting {{", com_token);
- if (!ent)
- ent = g_edicts;
- else
- ent = G_Spawn();
- entities = ED_ParseEdict(entities, ent);
- // remove things (except the world) from different skill levels or deathmatch
- if (ent != g_edicts)
- {
- if (G_InhibitEntity(ent))
- {
- G_FreeEdict(ent);
- inhibit++;
- continue;
- }
- ent->spawnflags &= ~SPAWNFLAG_EDITOR_MASK;
- }
- if (!ent)
- gi.Com_Error("invalid/empty entity string!");
- // PGM - do this before calling the spawn function so it can be overridden.
- ent->gravityVector[0] = 0.0;
- ent->gravityVector[1] = 0.0;
- ent->gravityVector[2] = -1.0;
- // PGM
- ED_CallSpawn(ent);
- ent->s.renderfx |= RF_IR_VISIBLE; // PGM
- }
- gi.Com_PrintFmt("{} entities inhibited\n", inhibit);
- // precache start_items
- G_PrecacheStartItems();
- // precache player inventory items
- G_PrecacheInventoryItems();
- G_FindTeams();
- // ZOID
- CTFSpawn();
- // ZOID
- // ROGUE
- if (deathmatch->integer)
- {
- if (g_dm_random_items->integer)
- PrecacheForRandomRespawn();
- }
- else
- {
- InitHintPaths(); // if there aren't hintpaths on this map, enable quick aborts
- }
- // ROGUE
- // ROGUE -- allow dm games to do init stuff right before game starts.
- if (deathmatch->integer && gamerules->integer)
- {
- if (DMGame.PostInitSetup)
- DMGame.PostInitSetup();
- }
- // ROGUE
- setup_shadow_lights();
- }
- //===================================================================
- #include "g_statusbar.h"
- // create & set the statusbar string for the current gamemode
- static void G_InitStatusbar()
- {
- statusbar_t sb;
- // ---- shared stuff that every gamemode uses ----
- sb.yb(-24);
- // health
- sb.xv(0).hnum().xv(50).pic(STAT_HEALTH_ICON);
- // ammo
- sb.ifstat(STAT_AMMO_ICON).xv(100).anum().xv(150).pic(STAT_AMMO_ICON).endifstat();
- // armor
- sb.ifstat(STAT_ARMOR_ICON).xv(200).rnum().xv(250).pic(STAT_ARMOR_ICON).endifstat();
- // selected item
- sb.ifstat(STAT_SELECTED_ICON).xv(296).pic(STAT_SELECTED_ICON).endifstat();
- sb.yb(-50);
- // picked up item
- sb.ifstat(STAT_PICKUP_ICON).xv(0).pic(STAT_PICKUP_ICON).xv(26).yb(-42).loc_stat_string(STAT_PICKUP_STRING).yb(-50).endifstat();
- // selected item name
- sb.ifstat(STAT_SELECTED_ITEM_NAME).yb(-34).xv(319).loc_stat_rstring(STAT_SELECTED_ITEM_NAME).yb(-58).endifstat();
- // timer
- sb.ifstat(STAT_TIMER_ICON).xv(262).num(2, STAT_TIMER).xv(296).pic(STAT_TIMER_ICON).endifstat();
-
- sb.yb(-50);
- // help / weapon icon
- sb.ifstat(STAT_HELPICON).xv(150).pic(STAT_HELPICON).endifstat();
- // ---- gamemode-specific stuff ----
- if (!deathmatch->integer)
- {
- // SP/coop
- // key display
- // move up if the timer is active
- // FIXME: ugly af
- sb.ifstat(STAT_TIMER_ICON).yb(-76).endifstat();
- sb.ifstat(STAT_SELECTED_ITEM_NAME)
- .yb(-58)
- .ifstat(STAT_TIMER_ICON)
- .yb(-84)
- .endifstat()
- .endifstat();
- sb.ifstat(STAT_KEY_A).xv(296).pic(STAT_KEY_A).endifstat();
- sb.ifstat(STAT_KEY_B).xv(272).pic(STAT_KEY_B).endifstat();
- sb.ifstat(STAT_KEY_C).xv(248).pic(STAT_KEY_C).endifstat();
- if (coop->integer)
- {
- // top of screen coop respawn display
- sb.ifstat(STAT_COOP_RESPAWN).xv(0).yt(0).loc_stat_cstring2(STAT_COOP_RESPAWN).endifstat();
- // coop lives
- sb.ifstat(STAT_LIVES).xr(-16).yt(2).lives_num(STAT_LIVES).xr(0).yt(28).loc_rstring("$g_lives").endifstat();
- }
- sb.ifstat(STAT_HEALTH_BARS).yt(24).health_bars().endifstat();
- }
- else if (G_TeamplayEnabled())
- {
- CTFPrecache();
- // ctf/tdm
- // red team
- sb.yb(-110).ifstat(STAT_CTF_TEAM1_PIC).xr(-26).pic(STAT_CTF_TEAM1_PIC).endifstat().xr(-78).num(3, STAT_CTF_TEAM1_CAPS);
- // joined overlay
- sb.ifstat(STAT_CTF_JOINED_TEAM1_PIC).yb(-112).xr(-28).pic(STAT_CTF_JOINED_TEAM1_PIC).endifstat();
- // blue team
- sb.yb(-83).ifstat(STAT_CTF_TEAM2_PIC).xr(-26).pic(STAT_CTF_TEAM2_PIC).endifstat().xr(-78).num(3, STAT_CTF_TEAM2_CAPS);
- // joined overlay
- sb.ifstat(STAT_CTF_JOINED_TEAM2_PIC).yb(-85).xr(-28).pic(STAT_CTF_JOINED_TEAM2_PIC).endifstat();
- if (ctf->integer)
- {
- // have flag graph
- sb.ifstat(STAT_CTF_FLAG_PIC).yt(26).xr(-24).pic(STAT_CTF_FLAG_PIC).endifstat();
- }
- // id view state
- sb.ifstat(STAT_CTF_ID_VIEW).xv(112).yb(-58).stat_pname(STAT_CTF_ID_VIEW).endifstat();
- // id view color
- sb.ifstat(STAT_CTF_ID_VIEW_COLOR).xv(96).yb(-58).pic(STAT_CTF_ID_VIEW_COLOR).endifstat();
- if (ctf->integer)
- {
- // match
- sb.ifstat(STAT_CTF_MATCH).xl(0).yb(-78).stat_string(STAT_CTF_MATCH).endifstat();
- }
- // team info
- sb.ifstat(STAT_CTF_TEAMINFO).xl(0).yb(-88).stat_string(STAT_CTF_TEAMINFO).endifstat();
- }
- else
- {
- // dm
- // frags
- sb.xr(-50).yt(2).num(3, STAT_FRAGS);
- // spectator
- sb.ifstat(STAT_SPECTATOR).xv(0).yb(-58).string2("SPECTATOR MODE").endifstat();
- // chase cam
- sb.ifstat(STAT_CHASE).xv(0).yb(-68).string("CHASING").xv(64).stat_string(STAT_CHASE).endifstat();
- }
- // ---- more shared stuff ----
- if (deathmatch->integer)
- {
- // tech
- sb.ifstat(STAT_CTF_TECH).yb(-137).xr(-26).pic(STAT_CTF_TECH).endifstat();
- }
- else
- {
- sb.story();
- }
- gi.configstring(CS_STATUSBAR, sb.sb.str().c_str());
- }
- /*QUAKED worldspawn (0 0 0) ?
- Only used for the world.
- "sky" environment map name
- "skyaxis" vector axis for rotating sky
- "skyrotate" speed of rotation in degrees/second
- "sounds" music cd track number
- "gravity" 800 is default gravity
- "message" text to print at user logon
- */
- void SP_worldspawn(edict_t *ent)
- {
- ent->movetype = MOVETYPE_PUSH;
- ent->solid = SOLID_BSP;
- ent->inuse = true; // since the world doesn't use G_Spawn()
- ent->s.modelindex = MODELINDEX_WORLD;
- ent->gravity = 1.0f;
- if (st.hub_map)
- {
- level.hub_map = true;
- // clear helps
- game.help1changed = game.help2changed = 0;
- *game.helpmessage1 = *game.helpmessage2 = '\0';
- for (size_t i = 0; i < game.maxclients; i++)
- {
- game.clients[i].pers.game_help1changed = game.clients[i].pers.game_help2changed = 0;
- game.clients[i].resp.coop_respawn.game_help1changed = game.clients[i].resp.coop_respawn.game_help2changed = 0;
- }
- }
- if (st.achievement && st.achievement[0])
- level.achievement = st.achievement;
- //---------------
- // set configstrings for items
- SetItemNames();
- if (st.nextmap)
- Q_strlcpy(level.nextmap, st.nextmap, sizeof(level.nextmap));
- // make some data visible to the server
- if (ent->message && ent->message[0])
- {
- gi.configstring(CS_NAME, ent->message);
- Q_strlcpy(level.level_name, ent->message, sizeof(level.level_name));
- }
- else
- Q_strlcpy(level.level_name, level.mapname, sizeof(level.level_name));
- if (st.sky && st.sky[0])
- gi.configstring(CS_SKY, st.sky);
- else
- gi.configstring(CS_SKY, "unit1_");
- gi.configstring(CS_SKYROTATE, G_Fmt("{} {}", st.skyrotate, st.skyautorotate).data());
- gi.configstring(CS_SKYAXIS, G_Fmt("{}", st.skyaxis).data());
- if (st.music && st.music[0])
- {
- gi.configstring(CS_CDTRACK, st.music);
- }
- else
- {
- gi.configstring(CS_CDTRACK, G_Fmt("{}", ent->sounds).data());
- }
- if (level.is_n64)
- gi.configstring(CS_CD_LOOP_COUNT, "0");
- else if (st.was_key_specified("loop_count"))
- gi.configstring(CS_CD_LOOP_COUNT, G_Fmt("{}", st.loop_count).data());
- else
- gi.configstring(CS_CD_LOOP_COUNT, "");
- if (st.instantitems > 0 || level.is_n64)
- {
- level.instantitems = true;
- }
- // [Paril-KEX]
- if (!deathmatch->integer)
- gi.configstring(CS_GAME_STYLE, G_Fmt("{}", (int32_t) game_style_t::GAME_STYLE_PVE).data());
- else if (teamplay->integer || ctf->integer)
- gi.configstring(CS_GAME_STYLE, G_Fmt("{}", (int32_t) game_style_t::GAME_STYLE_TDM).data());
- else
- gi.configstring(CS_GAME_STYLE, G_Fmt("{}", (int32_t) game_style_t::GAME_STYLE_FFA).data());
- // [Paril-KEX]
- if (st.goals)
- {
- level.goals = st.goals;
- game.help1changed++;
- }
- if (st.start_items)
- level.start_items = st.start_items;
- if (st.no_grapple)
- level.no_grapple = st.no_grapple;
- gi.configstring(CS_MAXCLIENTS, G_Fmt("{}", game.maxclients).data());
- if (level.is_n64 && !deathmatch->integer)
- {
- gi.configstring(CONFIG_N64_PHYSICS, "1");
- pm_config.n64_physics = true;
- }
- // statusbar prog
- G_InitStatusbar();
- // [Paril-KEX] air accel handled by game DLL now, and allow
- // it to be changed in sp/coop
- gi.configstring(CS_AIRACCEL, G_Fmt("{}", sv_airaccelerate->integer).data());
- pm_config.airaccel = sv_airaccelerate->integer;
- game.airacceleration_modified = sv_airaccelerate->modified_count;
- //---------------
- // help icon for statusbar
- gi.imageindex("i_help");
- level.pic_health = gi.imageindex("i_health");
- gi.imageindex("help");
- gi.imageindex("field_3");
- if (!st.gravity)
- {
- level.gravity = 800.f;
- gi.cvar_set("sv_gravity", "800");
- }
- else
- {
- level.gravity = atof(st.gravity);
- gi.cvar_set("sv_gravity", st.gravity);
- }
- snd_fry.assign("player/fry.wav"); // standing in lava / slime
-
- PrecacheItem(GetItemByIndex(IT_ITEM_COMPASS));
- PrecacheItem(GetItemByIndex(IT_WEAPON_BLASTER));
- if (g_dm_random_items->integer)
- for (item_id_t i = static_cast<item_id_t>(IT_NULL + 1); i < IT_TOTAL; i = static_cast<item_id_t>(i + 1))
- PrecacheItem(GetItemByIndex(i));
- gi.soundindex("player/lava1.wav");
- gi.soundindex("player/lava2.wav");
- gi.soundindex("misc/pc_up.wav");
- gi.soundindex("misc/talk1.wav");
- // gibs
- gi.soundindex("misc/udeath.wav");
- gi.soundindex("items/respawn1.wav");
- gi.soundindex("misc/mon_power2.wav");
- // sexed sounds
- gi.soundindex("*death1.wav");
- gi.soundindex("*death2.wav");
- gi.soundindex("*death3.wav");
- gi.soundindex("*death4.wav");
- gi.soundindex("*fall1.wav");
- gi.soundindex("*fall2.wav");
- gi.soundindex("*gurp1.wav"); // drowning damage
- gi.soundindex("*gurp2.wav");
- gi.soundindex("*jump1.wav"); // player jump
- gi.soundindex("*pain25_1.wav");
- gi.soundindex("*pain25_2.wav");
- gi.soundindex("*pain50_1.wav");
- gi.soundindex("*pain50_2.wav");
- gi.soundindex("*pain75_1.wav");
- gi.soundindex("*pain75_2.wav");
- gi.soundindex("*pain100_1.wav");
- gi.soundindex("*pain100_2.wav");
- gi.soundindex("*drown1.wav"); // [Paril-KEX]
- // sexed models
- for (auto &item : itemlist)
- item.vwep_index = 0;
- for (auto &item : itemlist)
- {
- if (!item.vwep_model)
- continue;
- for (auto &check : itemlist)
- {
- if (check.vwep_model && !Q_strcasecmp(item.vwep_model, check.vwep_model) && check.vwep_index)
- {
- item.vwep_index = check.vwep_index;
- break;
- }
- }
- if (item.vwep_index)
- continue;
- item.vwep_index = gi.modelindex(item.vwep_model);
- if (!level.vwep_offset)
- level.vwep_offset = item.vwep_index;
- }
- //-------------------
- gi.soundindex("player/gasp1.wav"); // gasping for air
- gi.soundindex("player/gasp2.wav"); // head breaking surface, not gasping
- gi.soundindex("player/watr_in.wav"); // feet hitting water
- gi.soundindex("player/watr_out.wav"); // feet leaving water
- gi.soundindex("player/watr_un.wav"); // head going underwater
- gi.soundindex("player/u_breath1.wav");
- gi.soundindex("player/u_breath2.wav");
- gi.soundindex("player/wade1.wav");
- gi.soundindex("player/wade2.wav");
- gi.soundindex("player/wade3.wav");
- gi.soundindex("items/pkup.wav"); // bonus item pickup
- gi.soundindex("world/land.wav"); // landing thud
- gi.soundindex("misc/h2ohit1.wav"); // landing splash
- gi.soundindex("items/damage.wav");
- gi.soundindex("items/protect.wav");
- gi.soundindex("items/protect4.wav");
- gi.soundindex("weapons/noammo.wav");
- gi.soundindex("weapons/lowammo.wav");
- gi.soundindex("weapons/change.wav");
- gi.soundindex("infantry/inflies1.wav");
- sm_meat_index.assign("models/objects/gibs/sm_meat/tris.md2");
- gi.modelindex("models/objects/gibs/arm/tris.md2");
- gi.modelindex("models/objects/gibs/bone/tris.md2");
- gi.modelindex("models/objects/gibs/bone2/tris.md2");
- gi.modelindex("models/objects/gibs/chest/tris.md2");
- gi.modelindex("models/objects/gibs/skull/tris.md2");
- gi.modelindex("models/objects/gibs/head2/tris.md2");
- gi.modelindex("models/objects/gibs/sm_metal/tris.md2");
- level.pic_ping = gi.imageindex("loc_ping");
- //
- // Setup light animation tables. 'a' is total darkness, 'z' is doublebright.
- //
- // 0 normal
- gi.configstring(CS_LIGHTS + 0, "m");
- // 1 FLICKER (first variety)
- gi.configstring(CS_LIGHTS + 1, "mmnmmommommnonmmonqnmmo");
- // 2 SLOW STRONG PULSE
- gi.configstring(CS_LIGHTS + 2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba");
- // 3 CANDLE (first variety)
- gi.configstring(CS_LIGHTS + 3, "mmmmmaaaaammmmmaaaaaabcdefgabcdefg");
- // 4 FAST STROBE
- gi.configstring(CS_LIGHTS + 4, "mamamamamama");
- // 5 GENTLE PULSE 1
- gi.configstring(CS_LIGHTS + 5, "jklmnopqrstuvwxyzyxwvutsrqponmlkj");
- // 6 FLICKER (second variety)
- gi.configstring(CS_LIGHTS + 6, "nmonqnmomnmomomno");
- // 7 CANDLE (second variety)`map
- gi.configstring(CS_LIGHTS + 7, "mmmaaaabcdefgmmmmaaaammmaamm");
- // 8 CANDLE (third variety)
- gi.configstring(CS_LIGHTS + 8, "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa");
- // 9 SLOW STROBE (fourth variety)
- gi.configstring(CS_LIGHTS + 9, "aaaaaaaazzzzzzzz");
- // 10 FLUORESCENT FLICKER
- gi.configstring(CS_LIGHTS + 10, "mmamammmmammamamaaamammma");
- // 11 SLOW PULSE NOT FADE TO BLACK
- gi.configstring(CS_LIGHTS + 11, "abcdefghijklmnopqrrqponmlkjihgfedcba");
- // [Paril-KEX] 12 N64's 2 (fast strobe)
- gi.configstring(CS_LIGHTS + 12, "zzazazzzzazzazazaaazazzza");
- // [Paril-KEX] 13 N64's 3 (half of strong pulse)
- gi.configstring(CS_LIGHTS + 13, "abcdefghijklmnopqrstuvwxyz");
- // [Paril-KEX] 14 N64's 4 (fast strobe)
- gi.configstring(CS_LIGHTS + 14, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba");
- // styles 32-62 are assigned by the light program for switchable lights
- // 63 testing
- gi.configstring(CS_LIGHTS + 63, "a");
- // coop respawn strings
- if (coop->integer)
- {
- gi.configstring(CONFIG_COOP_RESPAWN_STRING + 0, "$g_coop_respawn_in_combat");
- gi.configstring(CONFIG_COOP_RESPAWN_STRING + 1, "$g_coop_respawn_bad_area");
- gi.configstring(CONFIG_COOP_RESPAWN_STRING + 2, "$g_coop_respawn_blocked");
- gi.configstring(CONFIG_COOP_RESPAWN_STRING + 3, "$g_coop_respawn_waiting");
- gi.configstring(CONFIG_COOP_RESPAWN_STRING + 4, "$g_coop_respawn_no_lives");
- }
- }
|