g_spawn.cpp 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725
  1. // Copyright (c) ZeniMax Media Inc.
  2. // Licensed under the GNU General Public License 2.0.
  3. #include "g_local.h"
  4. struct spawn_t
  5. {
  6. const char *name;
  7. void (*spawn)(edict_t *ent);
  8. };
  9. void SP_info_player_start(edict_t *ent);
  10. void SP_info_player_deathmatch(edict_t *ent);
  11. void SP_info_player_coop(edict_t *ent);
  12. void SP_info_player_intermission(edict_t *ent);
  13. void SP_func_plat(edict_t *ent);
  14. void SP_func_rotating(edict_t *ent);
  15. void SP_func_button(edict_t *ent);
  16. void SP_func_door(edict_t *ent);
  17. void SP_func_door_secret(edict_t *ent);
  18. void SP_func_door_rotating(edict_t *ent);
  19. void SP_func_water(edict_t *ent);
  20. void SP_func_train(edict_t *ent);
  21. void SP_func_conveyor(edict_t *self);
  22. void SP_func_wall(edict_t *self);
  23. void SP_func_object(edict_t *self);
  24. void SP_func_explosive(edict_t *self);
  25. void SP_func_timer(edict_t *self);
  26. void SP_func_areaportal(edict_t *ent);
  27. void SP_func_clock(edict_t *ent);
  28. void SP_func_killbox(edict_t *ent);
  29. void SP_func_eye(edict_t *ent); // [Paril-KEX]
  30. void SP_func_animation(edict_t *ent); // [Paril-KEX]
  31. void SP_func_spinning(edict_t *ent); // [Paril-KEX]
  32. void SP_trigger_always(edict_t *ent);
  33. void SP_trigger_once(edict_t *ent);
  34. void SP_trigger_multiple(edict_t *ent);
  35. void SP_trigger_relay(edict_t *ent);
  36. void SP_trigger_push(edict_t *ent);
  37. void SP_trigger_hurt(edict_t *ent);
  38. void SP_trigger_key(edict_t *ent);
  39. void SP_trigger_counter(edict_t *ent);
  40. void SP_trigger_elevator(edict_t *ent);
  41. void SP_trigger_gravity(edict_t *ent);
  42. void SP_trigger_monsterjump(edict_t *ent);
  43. void SP_trigger_flashlight(edict_t *self); // [Paril-KEX]
  44. void SP_trigger_fog(edict_t *self); // [Paril-KEX]
  45. void SP_trigger_coop_relay(edict_t *self); // [Paril-KEX]
  46. void SP_trigger_health_relay(edict_t *self); // [Paril-KEX]
  47. void SP_target_temp_entity(edict_t *ent);
  48. void SP_target_speaker(edict_t *ent);
  49. void SP_target_explosion(edict_t *ent);
  50. void SP_target_changelevel(edict_t *ent);
  51. void SP_target_secret(edict_t *ent);
  52. void SP_target_goal(edict_t *ent);
  53. void SP_target_splash(edict_t *ent);
  54. void SP_target_spawner(edict_t *ent);
  55. void SP_target_blaster(edict_t *ent);
  56. void SP_target_crosslevel_trigger(edict_t *ent);
  57. void SP_target_crosslevel_target(edict_t *ent);
  58. void SP_target_crossunit_trigger(edict_t *ent); // [Paril-KEX]
  59. void SP_target_crossunit_target(edict_t *ent); // [Paril-KEX]
  60. void SP_target_laser(edict_t *self);
  61. void SP_target_help(edict_t *ent);
  62. void SP_target_actor(edict_t *ent);
  63. void SP_target_lightramp(edict_t *self);
  64. void SP_target_earthquake(edict_t *ent);
  65. void SP_target_character(edict_t *ent);
  66. void SP_target_string(edict_t *ent);
  67. void SP_target_camera(edict_t* self); // [Sam-KEX]
  68. void SP_target_gravity(edict_t* self); // [Sam-KEX]
  69. void SP_target_soundfx(edict_t* self); // [Sam-KEX]
  70. void SP_target_light(edict_t *self); // [Paril-KEX]
  71. void SP_target_poi(edict_t *ent); // [Paril-KEX]
  72. void SP_target_music(edict_t *ent);
  73. void SP_target_healthbar(edict_t *self); // [Paril-KEX]
  74. void SP_target_autosave(edict_t *self); // [Paril-KEX]
  75. void SP_target_sky(edict_t *self); // [Paril-KEX]
  76. void SP_target_achievement(edict_t *self); // [Paril-KEX]
  77. void SP_target_story(edict_t *self); // [Paril-KEX]
  78. void SP_worldspawn(edict_t *ent);
  79. void SP_dynamic_light(edict_t* self);
  80. void SP_light(edict_t *self);
  81. void SP_light_mine1(edict_t *ent);
  82. void SP_light_mine2(edict_t *ent);
  83. void SP_info_null(edict_t *self);
  84. void SP_info_notnull(edict_t *self);
  85. void SP_info_landmark (edict_t* self); // [Paril-KEX]
  86. void SP_info_world_text(edict_t * self);
  87. void SP_misc_player_mannequin(edict_t * self);
  88. void SP_misc_model(edict_t *self); // [Paril-KEX]
  89. void SP_path_corner(edict_t *self);
  90. void SP_point_combat(edict_t *self);
  91. void SP_info_nav_lock(edict_t *self); // [Paril-KEX]
  92. void SP_misc_explobox(edict_t *self);
  93. void SP_misc_banner(edict_t *self);
  94. void SP_misc_satellite_dish(edict_t *self);
  95. void SP_misc_actor(edict_t *self);
  96. void SP_misc_gib_arm(edict_t *self);
  97. void SP_misc_gib_leg(edict_t *self);
  98. void SP_misc_gib_head(edict_t *self);
  99. void SP_misc_insane(edict_t *self);
  100. void SP_misc_deadsoldier(edict_t *self);
  101. void SP_misc_viper(edict_t *self);
  102. void SP_misc_viper_bomb(edict_t *self);
  103. void SP_misc_bigviper(edict_t *self);
  104. void SP_misc_strogg_ship(edict_t *self);
  105. void SP_misc_teleporter(edict_t *self);
  106. void SP_misc_teleporter_dest(edict_t *self);
  107. void SP_misc_blackhole(edict_t *self);
  108. void SP_misc_eastertank(edict_t *self);
  109. void SP_misc_easterchick(edict_t *self);
  110. void SP_misc_easterchick2(edict_t *self);
  111. void SP_misc_flare(edict_t* ent); // [Sam-KEX]
  112. void SP_misc_hologram(edict_t *ent);
  113. void SP_misc_lavaball(edict_t *ent);
  114. void SP_monster_berserk(edict_t *self);
  115. void SP_monster_gladiator(edict_t *self);
  116. void SP_monster_gunner(edict_t *self);
  117. void SP_monster_infantry(edict_t *self);
  118. void SP_monster_soldier_light(edict_t *self);
  119. void SP_monster_soldier(edict_t *self);
  120. void SP_monster_soldier_ss(edict_t *self);
  121. void SP_monster_tank(edict_t *self);
  122. void SP_monster_medic(edict_t *self);
  123. void SP_monster_flipper(edict_t *self);
  124. void SP_monster_chick(edict_t *self);
  125. void SP_monster_parasite(edict_t *self);
  126. void SP_monster_flyer(edict_t *self);
  127. void SP_monster_brain(edict_t *self);
  128. void SP_monster_floater(edict_t *self);
  129. void SP_monster_hover(edict_t *self);
  130. void SP_monster_mutant(edict_t *self);
  131. void SP_monster_supertank(edict_t *self);
  132. void SP_monster_boss2(edict_t *self);
  133. void SP_monster_jorg(edict_t *self);
  134. void SP_monster_boss3_stand(edict_t *self);
  135. void SP_monster_makron(edict_t *self);
  136. // Paril
  137. void SP_monster_tank_stand(edict_t *self);
  138. void SP_monster_guardian(edict_t *self);
  139. void SP_monster_arachnid(edict_t *self);
  140. void SP_monster_guncmdr(edict_t *self);
  141. void SP_monster_commander_body(edict_t *self);
  142. void SP_turret_breach(edict_t *self);
  143. void SP_turret_base(edict_t *self);
  144. void SP_turret_driver(edict_t *self);
  145. // RAFAEL 14-APR-98
  146. void SP_monster_soldier_hypergun(edict_t *self);
  147. void SP_monster_soldier_lasergun(edict_t *self);
  148. void SP_monster_soldier_ripper(edict_t *self);
  149. void SP_monster_fixbot(edict_t *self);
  150. void SP_monster_gekk(edict_t *self);
  151. void SP_monster_chick_heat(edict_t *self);
  152. void SP_monster_gladb(edict_t *self);
  153. void SP_monster_boss5(edict_t *self);
  154. void SP_rotating_light(edict_t *self);
  155. void SP_object_repair(edict_t *self);
  156. void SP_misc_crashviper(edict_t *ent);
  157. void SP_misc_viper_missile(edict_t *self);
  158. void SP_misc_amb4(edict_t *ent);
  159. void SP_target_mal_laser(edict_t *ent);
  160. void SP_misc_transport(edict_t *ent);
  161. // END 14-APR-98
  162. void SP_misc_nuke(edict_t *ent);
  163. //===========
  164. // ROGUE
  165. void SP_func_plat2(edict_t *ent);
  166. void SP_func_door_secret2(edict_t *ent);
  167. void SP_func_force_wall(edict_t *ent);
  168. void SP_info_player_coop_lava(edict_t *self);
  169. void SP_info_teleport_destination(edict_t *self);
  170. void SP_trigger_teleport(edict_t *self);
  171. void SP_trigger_disguise(edict_t *self);
  172. void SP_monster_stalker(edict_t *self);
  173. void SP_monster_turret(edict_t *self);
  174. void SP_target_steam(edict_t *self);
  175. void SP_target_anger(edict_t *self);
  176. void SP_target_killplayers(edict_t *self);
  177. // PMM - still experimental!
  178. void SP_target_blacklight(edict_t *self);
  179. void SP_target_orb(edict_t *self);
  180. // pmm
  181. void SP_hint_path(edict_t *self);
  182. void SP_monster_carrier(edict_t *self);
  183. void SP_monster_widow(edict_t *self);
  184. void SP_monster_widow2(edict_t *self);
  185. void SP_dm_tag_token(edict_t *self);
  186. void SP_dm_dball_goal(edict_t *self);
  187. void SP_dm_dball_ball(edict_t *self);
  188. void SP_dm_dball_team1_start(edict_t *self);
  189. void SP_dm_dball_team2_start(edict_t *self);
  190. void SP_dm_dball_ball_start(edict_t *self);
  191. void SP_dm_dball_speed_change(edict_t *self);
  192. void SP_monster_kamikaze(edict_t *self);
  193. void SP_turret_invisible_brain(edict_t *self);
  194. void SP_misc_nuke_core(edict_t *self);
  195. // ROGUE
  196. //===========
  197. // ZOID
  198. void SP_trigger_ctf_teleport(edict_t *self);
  199. void SP_info_ctf_teleport_destination(edict_t *self);
  200. // ZOID
  201. void SP_monster_shambler(edict_t* self);
  202. // clang-format off
  203. static const std::initializer_list<spawn_t> spawns = {
  204. { "info_player_start", SP_info_player_start },
  205. { "info_player_deathmatch", SP_info_player_deathmatch },
  206. { "info_player_coop", SP_info_player_coop },
  207. { "info_player_intermission", SP_info_player_intermission },
  208. { "func_plat", SP_func_plat },
  209. { "func_button", SP_func_button },
  210. { "func_door", SP_func_door },
  211. { "func_door_secret", SP_func_door_secret },
  212. { "func_door_rotating", SP_func_door_rotating },
  213. { "func_rotating", SP_func_rotating },
  214. { "func_train", SP_func_train },
  215. { "func_water", SP_func_water },
  216. { "func_conveyor", SP_func_conveyor },
  217. { "func_areaportal", SP_func_areaportal },
  218. { "func_clock", SP_func_clock },
  219. { "func_wall", SP_func_wall },
  220. { "func_object", SP_func_object },
  221. { "func_timer", SP_func_timer },
  222. { "func_explosive", SP_func_explosive },
  223. { "func_killbox", SP_func_killbox },
  224. { "func_eye", SP_func_eye },
  225. { "func_animation", SP_func_animation },
  226. { "func_spinning", SP_func_spinning },
  227. { "trigger_always", SP_trigger_always },
  228. { "trigger_once", SP_trigger_once },
  229. { "trigger_multiple", SP_trigger_multiple },
  230. { "trigger_relay", SP_trigger_relay },
  231. { "trigger_push", SP_trigger_push },
  232. { "trigger_hurt", SP_trigger_hurt },
  233. { "trigger_key", SP_trigger_key },
  234. { "trigger_counter", SP_trigger_counter },
  235. { "trigger_elevator", SP_trigger_elevator },
  236. { "trigger_gravity", SP_trigger_gravity },
  237. { "trigger_monsterjump", SP_trigger_monsterjump },
  238. { "trigger_flashlight", SP_trigger_flashlight }, // [Paril-KEX]
  239. { "trigger_fog", SP_trigger_fog }, // [Paril-KEX]
  240. { "trigger_coop_relay", SP_trigger_coop_relay }, // [Paril-KEX]
  241. { "trigger_health_relay", SP_trigger_health_relay }, // [Paril-KEX]
  242. { "target_temp_entity", SP_target_temp_entity },
  243. { "target_speaker", SP_target_speaker },
  244. { "target_explosion", SP_target_explosion },
  245. { "target_changelevel", SP_target_changelevel },
  246. { "target_secret", SP_target_secret },
  247. { "target_goal", SP_target_goal },
  248. { "target_splash", SP_target_splash },
  249. { "target_spawner", SP_target_spawner },
  250. { "target_blaster", SP_target_blaster },
  251. { "target_crosslevel_trigger", SP_target_crosslevel_trigger },
  252. { "target_crosslevel_target", SP_target_crosslevel_target },
  253. { "target_crossunit_trigger", SP_target_crossunit_trigger }, // [Paril-KEX]
  254. { "target_crossunit_target", SP_target_crossunit_target }, // [Paril-KEX]
  255. { "target_laser", SP_target_laser },
  256. { "target_help", SP_target_help },
  257. { "target_actor", SP_target_actor },
  258. { "target_lightramp", SP_target_lightramp },
  259. { "target_earthquake", SP_target_earthquake },
  260. { "target_character", SP_target_character },
  261. { "target_string", SP_target_string },
  262. { "target_camera", SP_target_camera }, // [Sam-KEX]
  263. { "target_gravity", SP_target_gravity }, // [Sam-KEX]
  264. { "target_soundfx", SP_target_soundfx }, // [Sam-KEX]
  265. { "target_light", SP_target_light }, // [Paril-KEX]
  266. { "target_poi", SP_target_poi }, // [Paril-KEX]
  267. { "target_music", SP_target_music },
  268. { "target_healthbar", SP_target_healthbar }, // [Paril-KEX]
  269. { "target_autosave", SP_target_autosave }, // [Paril-KEX]
  270. { "target_sky", SP_target_sky }, // [Paril-KEX]
  271. { "target_achievement", SP_target_achievement }, // [Paril-KEX]
  272. { "target_story", SP_target_story }, // [Paril-KEX]
  273. { "worldspawn", SP_worldspawn },
  274. { "dynamic_light", SP_dynamic_light },
  275. { "light", SP_light },
  276. { "light_mine1", SP_light_mine1 },
  277. { "light_mine2", SP_light_mine2 },
  278. { "info_null", SP_info_null },
  279. { "func_group", SP_info_null },
  280. { "info_notnull", SP_info_notnull },
  281. { "info_landmark", SP_info_landmark },
  282. { "info_world_text", SP_info_world_text },
  283. { "path_corner", SP_path_corner },
  284. { "point_combat", SP_point_combat },
  285. { "info_nav_lock", SP_info_nav_lock },
  286. { "misc_explobox", SP_misc_explobox },
  287. { "misc_banner", SP_misc_banner },
  288. { "misc_satellite_dish", SP_misc_satellite_dish },
  289. { "misc_actor", SP_misc_actor },
  290. { "misc_player_mannequin", SP_misc_player_mannequin },
  291. { "misc_model", SP_misc_model }, // [Paril-KEX]
  292. { "misc_gib_arm", SP_misc_gib_arm },
  293. { "misc_gib_leg", SP_misc_gib_leg },
  294. { "misc_gib_head", SP_misc_gib_head },
  295. { "misc_insane", SP_misc_insane },
  296. { "misc_deadsoldier", SP_misc_deadsoldier },
  297. { "misc_viper", SP_misc_viper },
  298. { "misc_viper_bomb", SP_misc_viper_bomb },
  299. { "misc_bigviper", SP_misc_bigviper },
  300. { "misc_strogg_ship", SP_misc_strogg_ship },
  301. { "misc_teleporter", SP_misc_teleporter },
  302. { "misc_teleporter_dest", SP_misc_teleporter_dest },
  303. { "misc_blackhole", SP_misc_blackhole },
  304. { "misc_eastertank", SP_misc_eastertank },
  305. { "misc_easterchick", SP_misc_easterchick },
  306. { "misc_easterchick2", SP_misc_easterchick2 },
  307. { "misc_flare", SP_misc_flare }, // [Sam-KEX]
  308. { "misc_hologram", SP_misc_hologram }, // Paril
  309. { "misc_lavaball", SP_misc_lavaball }, // Paril
  310. { "monster_berserk", SP_monster_berserk },
  311. { "monster_gladiator", SP_monster_gladiator },
  312. { "monster_gunner", SP_monster_gunner },
  313. { "monster_infantry", SP_monster_infantry },
  314. { "monster_soldier_light", SP_monster_soldier_light },
  315. { "monster_soldier", SP_monster_soldier },
  316. { "monster_soldier_ss", SP_monster_soldier_ss },
  317. { "monster_tank", SP_monster_tank },
  318. { "monster_tank_commander", SP_monster_tank },
  319. { "monster_medic", SP_monster_medic },
  320. { "monster_flipper", SP_monster_flipper },
  321. { "monster_chick", SP_monster_chick },
  322. { "monster_parasite", SP_monster_parasite },
  323. { "monster_flyer", SP_monster_flyer },
  324. { "monster_brain", SP_monster_brain },
  325. { "monster_floater", SP_monster_floater },
  326. { "monster_hover", SP_monster_hover },
  327. { "monster_mutant", SP_monster_mutant },
  328. { "monster_supertank", SP_monster_supertank },
  329. { "monster_boss2", SP_monster_boss2 },
  330. { "monster_boss3_stand", SP_monster_boss3_stand },
  331. { "monster_jorg", SP_monster_jorg },
  332. // Paril: allow spawning makron
  333. { "monster_makron", SP_monster_makron },
  334. // Paril: N64
  335. { "monster_tank_stand", SP_monster_tank_stand },
  336. // Paril: PSX
  337. { "monster_guardian", SP_monster_guardian },
  338. { "monster_arachnid", SP_monster_arachnid },
  339. { "monster_guncmdr", SP_monster_guncmdr },
  340. { "monster_commander_body", SP_monster_commander_body },
  341. { "turret_breach", SP_turret_breach },
  342. { "turret_base", SP_turret_base },
  343. { "turret_driver", SP_turret_driver },
  344. // RAFAEL
  345. { "func_object_repair", SP_object_repair },
  346. { "rotating_light", SP_rotating_light },
  347. { "target_mal_laser", SP_target_mal_laser },
  348. { "misc_crashviper", SP_misc_crashviper },
  349. { "misc_viper_missile", SP_misc_viper_missile },
  350. { "misc_amb4", SP_misc_amb4 },
  351. { "misc_transport", SP_misc_transport },
  352. { "misc_nuke", SP_misc_nuke },
  353. { "monster_soldier_hypergun", SP_monster_soldier_hypergun },
  354. { "monster_soldier_lasergun", SP_monster_soldier_lasergun },
  355. { "monster_soldier_ripper", SP_monster_soldier_ripper },
  356. { "monster_fixbot", SP_monster_fixbot },
  357. { "monster_gekk", SP_monster_gekk },
  358. { "monster_chick_heat", SP_monster_chick_heat },
  359. { "monster_gladb", SP_monster_gladb },
  360. { "monster_boss5", SP_monster_boss5 },
  361. // RAFAEL
  362. //==============
  363. // ROGUE
  364. { "func_plat2", SP_func_plat2 },
  365. { "func_door_secret2", SP_func_door_secret2 },
  366. { "func_force_wall", SP_func_force_wall },
  367. { "trigger_teleport", SP_trigger_teleport },
  368. { "trigger_disguise", SP_trigger_disguise },
  369. { "info_teleport_destination", SP_info_teleport_destination },
  370. { "info_player_coop_lava", SP_info_player_coop_lava },
  371. { "monster_stalker", SP_monster_stalker },
  372. { "monster_turret", SP_monster_turret },
  373. { "target_steam", SP_target_steam },
  374. { "target_anger", SP_target_anger },
  375. { "target_killplayers", SP_target_killplayers },
  376. // PMM - experiment
  377. { "target_blacklight", SP_target_blacklight },
  378. { "target_orb", SP_target_orb },
  379. // pmm
  380. { "monster_daedalus", SP_monster_hover },
  381. { "hint_path", SP_hint_path },
  382. { "monster_carrier", SP_monster_carrier },
  383. { "monster_widow", SP_monster_widow },
  384. { "monster_widow2", SP_monster_widow2 },
  385. { "monster_medic_commander", SP_monster_medic },
  386. { "dm_tag_token", SP_dm_tag_token },
  387. { "dm_dball_goal", SP_dm_dball_goal },
  388. { "dm_dball_ball", SP_dm_dball_ball },
  389. { "dm_dball_team1_start", SP_dm_dball_team1_start },
  390. { "dm_dball_team2_start", SP_dm_dball_team2_start },
  391. { "dm_dball_ball_start", SP_dm_dball_ball_start },
  392. { "dm_dball_speed_change", SP_dm_dball_speed_change },
  393. { "monster_kamikaze", SP_monster_kamikaze },
  394. { "turret_invisible_brain", SP_turret_invisible_brain },
  395. { "misc_nuke_core", SP_misc_nuke_core },
  396. // ROGUE
  397. //==============
  398. // ZOID
  399. { "trigger_ctf_teleport", SP_trigger_ctf_teleport },
  400. { "info_ctf_teleport_destination", SP_info_ctf_teleport_destination },
  401. { "misc_ctf_banner", SP_misc_ctf_banner },
  402. { "misc_ctf_small_banner", SP_misc_ctf_small_banner },
  403. { "info_player_team1", SP_info_player_team1 },
  404. { "info_player_team2", SP_info_player_team2 },
  405. // ZOID
  406. { "monster_shambler", SP_monster_shambler }
  407. };
  408. // clang-format on
  409. /*
  410. ===============
  411. ED_CallSpawn
  412. Finds the spawn function for the entity and calls it
  413. ===============
  414. */
  415. void ED_CallSpawn(edict_t *ent)
  416. {
  417. gitem_t *item;
  418. int i;
  419. if (!ent->classname)
  420. {
  421. gi.Com_Print("ED_CallSpawn: nullptr classname\n");
  422. G_FreeEdict(ent);
  423. return;
  424. }
  425. // PGM - do this before calling the spawn function so it can be overridden.
  426. ent->gravityVector[0] = 0.0;
  427. ent->gravityVector[1] = 0.0;
  428. ent->gravityVector[2] = -1.0;
  429. // PGM
  430. ent->sv.init = false;
  431. // FIXME - PMM classnames hack
  432. if (!strcmp(ent->classname, "weapon_nailgun"))
  433. ent->classname = GetItemByIndex(IT_WEAPON_ETF_RIFLE)->classname;
  434. if (!strcmp(ent->classname, "ammo_nails"))
  435. ent->classname = GetItemByIndex(IT_AMMO_FLECHETTES)->classname;
  436. if (!strcmp(ent->classname, "weapon_heatbeam"))
  437. ent->classname = GetItemByIndex(IT_WEAPON_PLASMABEAM)->classname;
  438. // pmm
  439. // check item spawn functions
  440. for (i = 0, item = itemlist; i < IT_TOTAL; i++, item++)
  441. {
  442. if (!item->classname)
  443. continue;
  444. if (!strcmp(item->classname, ent->classname))
  445. {
  446. // found it
  447. // before spawning, pick random item replacement
  448. if (g_dm_random_items->integer)
  449. {
  450. ent->item = item;
  451. item_id_t new_item = DoRandomRespawn(ent);
  452. if (new_item)
  453. {
  454. item = GetItemByIndex(new_item);
  455. ent->classname = item->classname;
  456. }
  457. }
  458. SpawnItem(ent, item);
  459. return;
  460. }
  461. }
  462. // check normal spawn functions
  463. for (auto &s : spawns)
  464. {
  465. if (!strcmp(s.name, ent->classname))
  466. { // found it
  467. s.spawn(ent);
  468. // Paril: swap classname with stored constant if we didn't change it
  469. if (strcmp(ent->classname, s.name) == 0)
  470. ent->classname = s.name;
  471. return;
  472. }
  473. }
  474. gi.Com_PrintFmt("{} doesn't have a spawn function\n", *ent);
  475. G_FreeEdict(ent);
  476. }
  477. /*
  478. =============
  479. ED_NewString
  480. =============
  481. */
  482. char *ED_NewString(const char *string)
  483. {
  484. char *newb, *new_p;
  485. int i;
  486. size_t l;
  487. l = strlen(string) + 1;
  488. newb = (char *) gi.TagMalloc(l, TAG_LEVEL);
  489. new_p = newb;
  490. for (i = 0; i < l; i++)
  491. {
  492. if (string[i] == '\\' && i < l - 1)
  493. {
  494. i++;
  495. if (string[i] == 'n')
  496. *new_p++ = '\n';
  497. else
  498. *new_p++ = '\\';
  499. }
  500. else
  501. *new_p++ = string[i];
  502. }
  503. return newb;
  504. }
  505. //
  506. // fields are used for spawning from the entity string
  507. //
  508. struct field_t
  509. {
  510. const char *name;
  511. void (*load_func) (edict_t *e, const char *s) = nullptr;
  512. };
  513. // utility template for getting the type of a field
  514. template<typename>
  515. struct member_object_container_type { };
  516. template<typename T1, typename T2>
  517. struct member_object_container_type<T1 T2::*> { using type = T2; };
  518. template<typename T>
  519. using member_object_container_type_t = typename member_object_container_type<std::remove_cv_t<T>>::type;
  520. struct type_loaders_t
  521. {
  522. template<typename T, std::enable_if_t<std::is_same_v<T, const char *>, int> = 0>
  523. static T load(const char *s)
  524. {
  525. return ED_NewString(s);
  526. }
  527. template<typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
  528. static T load(const char *s)
  529. {
  530. return atoi(s);
  531. }
  532. template<typename T, std::enable_if_t<std::is_same_v<T, spawnflags_t>, int> = 0>
  533. static T load(const char *s)
  534. {
  535. return spawnflags_t(atoi(s));
  536. }
  537. template<typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
  538. static T load(const char *s)
  539. {
  540. return atof(s);
  541. }
  542. template<typename T, std::enable_if_t<std::is_enum_v<T>, int> = 0>
  543. static T load(const char *s)
  544. {
  545. if constexpr (sizeof(T) > 4)
  546. return static_cast<T>(atoll(s));
  547. else
  548. return static_cast<T>(atoi(s));
  549. }
  550. template<typename T, std::enable_if_t<std::is_same_v<T, vec3_t>, int> = 0>
  551. static T load(const char *s)
  552. {
  553. vec3_t vec;
  554. static char vec_buffer[32];
  555. const char *token = COM_Parse(&s, vec_buffer, sizeof(vec_buffer));
  556. vec.x = atof(token);
  557. token = COM_Parse(&s);
  558. vec.y = atof(token);
  559. token = COM_Parse(&s);
  560. vec.z = atof(token);
  561. return vec;
  562. }
  563. };
  564. #define AUTO_LOADER_FUNC(M) \
  565. [](edict_t *e, const char *s) { \
  566. e->M = type_loaders_t::load<decltype(e->M)>(s); \
  567. }
  568. static int32_t ED_LoadColor(const char *value)
  569. {
  570. // space means rgba as values
  571. if (strchr(value, ' '))
  572. {
  573. static char color_buffer[32];
  574. std::array<float, 4> raw_values { 0, 0, 0, 1.0f };
  575. bool is_float = true;
  576. for (auto &v : raw_values)
  577. {
  578. const char *token = COM_Parse(&value, color_buffer, sizeof(color_buffer));
  579. if (*token)
  580. {
  581. v = atof(token);
  582. if (v > 1.0f)
  583. is_float = false;
  584. }
  585. }
  586. if (is_float)
  587. for (auto &v : raw_values)
  588. v *= 255.f;
  589. return ((int32_t) raw_values[3]) | (((int32_t) raw_values[2]) << 8) | (((int32_t) raw_values[1]) << 16) | (((int32_t) raw_values[0]) << 24);
  590. }
  591. // integral
  592. return atoi(value);
  593. }
  594. #define FIELD_COLOR(n, x) \
  595. { n, [](edict_t *e, const char *s) { \
  596. e->x = ED_LoadColor(s); \
  597. } }
  598. // clang-format off
  599. // fields that get copied directly to edict_t
  600. #define FIELD_AUTO(x) \
  601. { #x, AUTO_LOADER_FUNC(x) }
  602. #define FIELD_AUTO_NAMED(n, x) \
  603. { n, AUTO_LOADER_FUNC(x) }
  604. static const std::initializer_list<field_t> entity_fields = {
  605. FIELD_AUTO(classname),
  606. FIELD_AUTO(model),
  607. FIELD_AUTO(spawnflags),
  608. FIELD_AUTO(speed),
  609. FIELD_AUTO(accel),
  610. FIELD_AUTO(decel),
  611. FIELD_AUTO(target),
  612. FIELD_AUTO(targetname),
  613. FIELD_AUTO(pathtarget),
  614. FIELD_AUTO(deathtarget),
  615. FIELD_AUTO(healthtarget),
  616. FIELD_AUTO(itemtarget),
  617. FIELD_AUTO(killtarget),
  618. FIELD_AUTO(combattarget),
  619. FIELD_AUTO(message),
  620. FIELD_AUTO(team),
  621. FIELD_AUTO(wait),
  622. FIELD_AUTO(delay),
  623. FIELD_AUTO(random),
  624. FIELD_AUTO(move_origin),
  625. FIELD_AUTO(move_angles),
  626. FIELD_AUTO(style),
  627. FIELD_AUTO(style_on),
  628. FIELD_AUTO(style_off),
  629. FIELD_AUTO(crosslevel_flags),
  630. FIELD_AUTO(count),
  631. FIELD_AUTO(health),
  632. FIELD_AUTO(sounds),
  633. { "light" },
  634. FIELD_AUTO(dmg),
  635. FIELD_AUTO(mass),
  636. FIELD_AUTO(volume),
  637. FIELD_AUTO(attenuation),
  638. FIELD_AUTO(map),
  639. FIELD_AUTO_NAMED("origin", s.origin),
  640. FIELD_AUTO_NAMED("angles", s.angles),
  641. { "angle", [](edict_t *e, const char *value) {
  642. e->s.angles = {};
  643. e->s.angles[YAW] = atof(value);
  644. } },
  645. FIELD_COLOR("rgba", s.skinnum), // [Sam-KEX]
  646. FIELD_AUTO(hackflags), // [Paril-KEX] n64
  647. FIELD_AUTO_NAMED("alpha", s.alpha), // [Paril-KEX]
  648. FIELD_AUTO_NAMED("scale", s.scale), // [Paril-KEX]
  649. { "mangle" }, // editor field
  650. FIELD_AUTO_NAMED("dead_frame", monsterinfo.start_frame), // [Paril-KEX]
  651. FIELD_AUTO_NAMED("frame", s.frame),
  652. FIELD_AUTO_NAMED("effects", s.effects),
  653. FIELD_AUTO_NAMED("renderfx", s.renderfx),
  654. // [Paril-KEX] fog keys
  655. FIELD_AUTO_NAMED("fog_color", fog.color),
  656. FIELD_AUTO_NAMED("fog_color_off", fog.color_off),
  657. FIELD_AUTO_NAMED("fog_density", fog.density),
  658. FIELD_AUTO_NAMED("fog_density_off", fog.density_off),
  659. FIELD_AUTO_NAMED("fog_sky_factor", fog.sky_factor),
  660. FIELD_AUTO_NAMED("fog_sky_factor_off", fog.sky_factor_off),
  661. FIELD_AUTO_NAMED("heightfog_falloff", heightfog.falloff),
  662. FIELD_AUTO_NAMED("heightfog_density", heightfog.density),
  663. FIELD_AUTO_NAMED("heightfog_start_color", heightfog.start_color),
  664. FIELD_AUTO_NAMED("heightfog_start_dist", heightfog.start_dist),
  665. FIELD_AUTO_NAMED("heightfog_end_color", heightfog.end_color),
  666. FIELD_AUTO_NAMED("heightfog_end_dist", heightfog.end_dist),
  667. FIELD_AUTO_NAMED("heightfog_falloff_off", heightfog.falloff_off),
  668. FIELD_AUTO_NAMED("heightfog_density_off", heightfog.density_off),
  669. FIELD_AUTO_NAMED("heightfog_start_color_off", heightfog.start_color_off),
  670. FIELD_AUTO_NAMED("heightfog_start_dist_off", heightfog.start_dist_off),
  671. FIELD_AUTO_NAMED("heightfog_end_color_off", heightfog.end_color_off),
  672. FIELD_AUTO_NAMED("heightfog_end_dist_off", heightfog.end_dist_off),
  673. // [Paril-KEX] func_eye stuff
  674. FIELD_AUTO_NAMED("eye_position", move_origin),
  675. FIELD_AUTO_NAMED("vision_cone", yaw_speed),
  676. // [Paril-KEX] for trigger_coop_relay
  677. FIELD_AUTO_NAMED("message2", map),
  678. FIELD_AUTO(mins),
  679. FIELD_AUTO(maxs),
  680. // [Paril-KEX] customizable bmodel animations
  681. FIELD_AUTO_NAMED("bmodel_anim_start", bmodel_anim.start),
  682. FIELD_AUTO_NAMED("bmodel_anim_end", bmodel_anim.end),
  683. FIELD_AUTO_NAMED("bmodel_anim_style", bmodel_anim.style),
  684. FIELD_AUTO_NAMED("bmodel_anim_speed", bmodel_anim.speed),
  685. FIELD_AUTO_NAMED("bmodel_anim_nowrap", bmodel_anim.nowrap),
  686. FIELD_AUTO_NAMED("bmodel_anim_alt_start", bmodel_anim.alt_start),
  687. FIELD_AUTO_NAMED("bmodel_anim_alt_end", bmodel_anim.alt_end),
  688. FIELD_AUTO_NAMED("bmodel_anim_alt_style", bmodel_anim.alt_style),
  689. FIELD_AUTO_NAMED("bmodel_anim_alt_speed", bmodel_anim.alt_speed),
  690. FIELD_AUTO_NAMED("bmodel_anim_alt_nowrap", bmodel_anim.alt_nowrap),
  691. // [Paril-KEX] customizable power armor stuff
  692. FIELD_AUTO_NAMED("power_armor_power", monsterinfo.power_armor_power),
  693. { "power_armor_type", [](edict_t *s, const char *v)
  694. {
  695. int32_t type = atoi(v);
  696. if (type == 0)
  697. s->monsterinfo.power_armor_type = IT_NULL;
  698. else if (type == 1)
  699. s->monsterinfo.power_armor_type = IT_ITEM_POWER_SCREEN;
  700. else
  701. s->monsterinfo.power_armor_type = IT_ITEM_POWER_SHIELD;
  702. }
  703. },
  704. FIELD_AUTO_NAMED("monster_slots", monsterinfo.monster_slots)
  705. };
  706. #undef AUTO_LOADER_FUNC
  707. #define AUTO_LOADER_FUNC(M) \
  708. [](spawn_temp_t *e, const char *s) { \
  709. e->M = type_loaders_t::load<decltype(e->M)>(s); \
  710. }
  711. struct temp_field_t
  712. {
  713. const char *name;
  714. void (*load_func) (spawn_temp_t *e, const char *s) = nullptr;
  715. };
  716. // temp spawn vars -- only valid when the spawn function is called
  717. // (copied to `st`)
  718. static const std::initializer_list<temp_field_t> temp_fields = {
  719. FIELD_AUTO(lip),
  720. FIELD_AUTO(distance),
  721. FIELD_AUTO(height),
  722. FIELD_AUTO(noise),
  723. FIELD_AUTO(pausetime),
  724. FIELD_AUTO(item),
  725. FIELD_AUTO(gravity),
  726. FIELD_AUTO(sky),
  727. FIELD_AUTO(skyrotate),
  728. FIELD_AUTO(skyaxis),
  729. FIELD_AUTO(skyautorotate),
  730. FIELD_AUTO(minyaw),
  731. FIELD_AUTO(maxyaw),
  732. FIELD_AUTO(minpitch),
  733. FIELD_AUTO(maxpitch),
  734. FIELD_AUTO(nextmap),
  735. FIELD_AUTO(music), // [Edward-KEX]
  736. FIELD_AUTO(instantitems),
  737. FIELD_AUTO(radius), // [Paril-KEX]
  738. FIELD_AUTO(hub_map),
  739. FIELD_AUTO(achievement),
  740. FIELD_AUTO_NAMED("shadowlightradius", sl.data.radius),
  741. FIELD_AUTO_NAMED("shadowlightresolution", sl.data.resolution),
  742. FIELD_AUTO_NAMED("shadowlightintensity", sl.data.intensity),
  743. FIELD_AUTO_NAMED("shadowlightstartfadedistance", sl.data.fade_start),
  744. FIELD_AUTO_NAMED("shadowlightendfadedistance", sl.data.fade_end),
  745. FIELD_AUTO_NAMED("shadowlightstyle", sl.data.lightstyle),
  746. FIELD_AUTO_NAMED("shadowlightconeangle", sl.data.coneangle),
  747. FIELD_AUTO_NAMED("shadowlightstyletarget", sl.lightstyletarget),
  748. FIELD_AUTO(goals),
  749. FIELD_AUTO(image),
  750. FIELD_AUTO(fade_start_dist),
  751. FIELD_AUTO(fade_end_dist),
  752. FIELD_AUTO(start_items),
  753. FIELD_AUTO(no_grapple),
  754. FIELD_AUTO(health_multiplier),
  755. FIELD_AUTO(reinforcements),
  756. FIELD_AUTO(noise_start),
  757. FIELD_AUTO(noise_middle),
  758. FIELD_AUTO(noise_end),
  759. FIELD_AUTO(loop_count)
  760. };
  761. // clang-format on
  762. /*
  763. ===============
  764. ED_ParseField
  765. Takes a key/value pair and sets the binary values
  766. in an edict
  767. ===============
  768. */
  769. void ED_ParseField(const char *key, const char *value, edict_t *ent)
  770. {
  771. // check st first
  772. for (auto &f : temp_fields)
  773. {
  774. if (Q_strcasecmp(f.name, key))
  775. continue;
  776. st.keys_specified.emplace(f.name);
  777. // found it
  778. if (f.load_func)
  779. f.load_func(&st, value);
  780. return;
  781. }
  782. // now entity
  783. for (auto &f : entity_fields)
  784. {
  785. if (Q_strcasecmp(f.name, key))
  786. continue;
  787. st.keys_specified.emplace(f.name);
  788. // [Paril-KEX]
  789. if (!strcmp(f.name, "bmodel_anim_start") || !strcmp(f.name, "bmodel_anim_end"))
  790. ent->bmodel_anim.enabled = true;
  791. // found it
  792. if (f.load_func)
  793. f.load_func(ent, value);
  794. return;
  795. }
  796. gi.Com_PrintFmt("{} is not a valid field\n", key);
  797. }
  798. /*
  799. ====================
  800. ED_ParseEdict
  801. Parses an edict out of the given string, returning the new position
  802. ed should be a properly initialized empty edict.
  803. ====================
  804. */
  805. const char *ED_ParseEdict(const char *data, edict_t *ent)
  806. {
  807. bool init;
  808. char keyname[256];
  809. const char *com_token;
  810. init = false;
  811. st = {};
  812. // go through all the dictionary pairs
  813. while (1)
  814. {
  815. // parse key
  816. com_token = COM_Parse(&data);
  817. if (com_token[0] == '}')
  818. break;
  819. if (!data)
  820. gi.Com_Error("ED_ParseEntity: EOF without closing brace");
  821. Q_strlcpy(keyname, com_token, sizeof(keyname));
  822. // parse value
  823. com_token = COM_Parse(&data);
  824. if (!data)
  825. gi.Com_Error("ED_ParseEntity: EOF without closing brace");
  826. if (com_token[0] == '}')
  827. gi.Com_Error("ED_ParseEntity: closing brace without data");
  828. init = true;
  829. // keynames with a leading underscore are used for utility comments,
  830. // and are immediately discarded by quake
  831. if (keyname[0] == '_')
  832. {
  833. // [Sam-KEX] Hack for setting RGBA for shadow-casting lights
  834. if(!strcmp(keyname, "_color"))
  835. ent->s.skinnum = ED_LoadColor(com_token);
  836. continue;
  837. }
  838. ED_ParseField(keyname, com_token, ent);
  839. }
  840. if (!init)
  841. memset(ent, 0, sizeof(*ent));
  842. return data;
  843. }
  844. /*
  845. ================
  846. G_FindTeams
  847. Chain together all entities with a matching team field.
  848. All but the first will have the FL_TEAMSLAVE flag set.
  849. All but the last will have the teamchain field set to the next one
  850. ================
  851. */
  852. // adjusts teams so that trains that move their children
  853. // are in the front of the team
  854. void G_FixTeams()
  855. {
  856. edict_t *e, *e2, *chain;
  857. uint32_t i, j;
  858. uint32_t c;
  859. c = 0;
  860. for (i = 1, e = g_edicts + i; i < globals.num_edicts; i++, e++)
  861. {
  862. if (!e->inuse)
  863. continue;
  864. if (!e->team)
  865. continue;
  866. if (!strcmp(e->classname, "func_train") && e->spawnflags.has(SPAWNFLAG_TRAIN_MOVE_TEAMCHAIN))
  867. {
  868. if (e->flags & FL_TEAMSLAVE)
  869. {
  870. chain = e;
  871. e->teammaster = e;
  872. e->teamchain = nullptr;
  873. e->flags &= ~FL_TEAMSLAVE;
  874. e->flags |= FL_TEAMMASTER;
  875. c++;
  876. for (j = 1, e2 = g_edicts + j; j < globals.num_edicts; j++, e2++)
  877. {
  878. if (e2 == e)
  879. continue;
  880. if (!e2->inuse)
  881. continue;
  882. if (!e2->team)
  883. continue;
  884. if (!strcmp(e->team, e2->team))
  885. {
  886. chain->teamchain = e2;
  887. e2->teammaster = e;
  888. e2->teamchain = nullptr;
  889. chain = e2;
  890. e2->flags |= FL_TEAMSLAVE;
  891. e2->flags &= ~FL_TEAMMASTER;
  892. e2->movetype = MOVETYPE_PUSH;
  893. e2->speed = e->speed;
  894. }
  895. }
  896. }
  897. }
  898. }
  899. gi.Com_PrintFmt("{} teams repaired\n", c);
  900. }
  901. void G_FindTeams()
  902. {
  903. edict_t *e, *e2, *chain;
  904. uint32_t i, j;
  905. uint32_t c, c2;
  906. c = 0;
  907. c2 = 0;
  908. for (i = 1, e = g_edicts + i; i < globals.num_edicts; i++, e++)
  909. {
  910. if (!e->inuse)
  911. continue;
  912. if (!e->team)
  913. continue;
  914. if (e->flags & FL_TEAMSLAVE)
  915. continue;
  916. chain = e;
  917. e->teammaster = e;
  918. e->flags |= FL_TEAMMASTER;
  919. c++;
  920. c2++;
  921. for (j = i + 1, e2 = e + 1; j < globals.num_edicts; j++, e2++)
  922. {
  923. if (!e2->inuse)
  924. continue;
  925. if (!e2->team)
  926. continue;
  927. if (e2->flags & FL_TEAMSLAVE)
  928. continue;
  929. if (!strcmp(e->team, e2->team))
  930. {
  931. c2++;
  932. chain->teamchain = e2;
  933. e2->teammaster = e;
  934. chain = e2;
  935. e2->flags |= FL_TEAMSLAVE;
  936. }
  937. }
  938. }
  939. // ROGUE
  940. G_FixTeams();
  941. // ROGUE
  942. gi.Com_PrintFmt("{} teams with {} entities\n", c, c2);
  943. }
  944. // inhibit entities from game based on cvars & spawnflags
  945. inline bool G_InhibitEntity(edict_t *ent)
  946. {
  947. // dm-only
  948. if (deathmatch->integer)
  949. return ent->spawnflags.has(SPAWNFLAG_NOT_DEATHMATCH);
  950. // coop flags
  951. if (coop->integer && ent->spawnflags.has(SPAWNFLAG_NOT_COOP))
  952. return true;
  953. else if (!coop->integer && ent->spawnflags.has(SPAWNFLAG_COOP_ONLY))
  954. return true;
  955. // skill
  956. return ((skill->integer == 0) && ent->spawnflags.has(SPAWNFLAG_NOT_EASY)) ||
  957. ((skill->integer == 1) && ent->spawnflags.has(SPAWNFLAG_NOT_MEDIUM)) ||
  958. ((skill->integer >= 2) && ent->spawnflags.has(SPAWNFLAG_NOT_HARD));
  959. }
  960. void setup_shadow_lights();
  961. // [Paril-KEX]
  962. void G_PrecacheInventoryItems()
  963. {
  964. if (deathmatch->integer)
  965. return;
  966. for (size_t i = 0; i < game.maxclients; i++)
  967. {
  968. gclient_t *cl = g_edicts[i + 1].client;
  969. if (!cl)
  970. continue;
  971. for (item_id_t id = IT_NULL; id != IT_TOTAL; id = static_cast<item_id_t>(id + 1))
  972. if (cl->pers.inventory[id])
  973. PrecacheItem(GetItemByIndex(id));
  974. }
  975. }
  976. // [Paril-KEX]
  977. static void G_PrecacheStartItems()
  978. {
  979. if (!*g_start_items->string)
  980. return;
  981. char token_copy[MAX_TOKEN_CHARS];
  982. const char *token;
  983. const char *ptr = g_start_items->string;
  984. while (*(token = COM_ParseEx(&ptr, ";")))
  985. {
  986. Q_strlcpy(token_copy, token, sizeof(token_copy));
  987. const char *ptr_copy = token_copy;
  988. const char *item_name = COM_Parse(&ptr_copy);
  989. gitem_t *item = FindItemByClassname(item_name);
  990. if (!item || !item->pickup)
  991. gi.Com_ErrorFmt("Invalid g_start_item entry: {}\n", item_name);
  992. if (*ptr_copy)
  993. COM_Parse(&ptr_copy);
  994. PrecacheItem(item);
  995. }
  996. }
  997. /*
  998. ==============
  999. SpawnEntities
  1000. Creates a server's entity / program execution context by
  1001. parsing textual entity definitions out of an ent file.
  1002. ==============
  1003. */
  1004. void SpawnEntities(const char *mapname, const char *entities, const char *spawnpoint)
  1005. {
  1006. // clear cached indices
  1007. cached_soundindex::clear_all();
  1008. cached_modelindex::clear_all();
  1009. cached_imageindex::clear_all();
  1010. edict_t *ent;
  1011. int inhibit;
  1012. const char *com_token;
  1013. int skill_level = clamp(skill->integer, 0, 3);
  1014. if (skill->integer != skill_level)
  1015. gi.cvar_forceset("skill", G_Fmt("{}", skill_level).data());
  1016. SaveClientData();
  1017. gi.FreeTags(TAG_LEVEL);
  1018. memset(&level, 0, sizeof(level));
  1019. memset(g_edicts, 0, game.maxentities * sizeof(g_edicts[0]));
  1020. // all other flags are not important atm
  1021. globals.server_flags &= SERVER_FLAG_LOADING;
  1022. Q_strlcpy(level.mapname, mapname, sizeof(level.mapname));
  1023. // Paril: fixes a bug where autosaves will start you at
  1024. // the wrong spawnpoint if they happen to be non-empty
  1025. // (mine2 -> mine3)
  1026. if (!game.autosaved)
  1027. Q_strlcpy(game.spawnpoint, spawnpoint, sizeof(game.spawnpoint));
  1028. level.is_n64 = strncmp(level.mapname, "q64/", 4) == 0;
  1029. level.coop_scale_players = 0;
  1030. level.coop_health_scaling = clamp(g_coop_health_scaling->value, 0.f, 1.f);
  1031. // set client fields on player ents
  1032. for (uint32_t i = 0; i < game.maxclients; i++)
  1033. {
  1034. g_edicts[i + 1].client = game.clients + i;
  1035. // "disconnect" all players since the level is switching
  1036. game.clients[i].pers.connected = false;
  1037. game.clients[i].pers.spawned = false;
  1038. }
  1039. ent = nullptr;
  1040. inhibit = 0;
  1041. // reserve some spots for dead player bodies for coop / deathmatch
  1042. InitBodyQue();
  1043. // parse ents
  1044. while (1)
  1045. {
  1046. // parse the opening brace
  1047. com_token = COM_Parse(&entities);
  1048. if (!entities)
  1049. break;
  1050. if (com_token[0] != '{')
  1051. gi.Com_ErrorFmt("ED_LoadFromFile: found \"{}\" when expecting {{", com_token);
  1052. if (!ent)
  1053. ent = g_edicts;
  1054. else
  1055. ent = G_Spawn();
  1056. entities = ED_ParseEdict(entities, ent);
  1057. // remove things (except the world) from different skill levels or deathmatch
  1058. if (ent != g_edicts)
  1059. {
  1060. if (G_InhibitEntity(ent))
  1061. {
  1062. G_FreeEdict(ent);
  1063. inhibit++;
  1064. continue;
  1065. }
  1066. ent->spawnflags &= ~SPAWNFLAG_EDITOR_MASK;
  1067. }
  1068. if (!ent)
  1069. gi.Com_Error("invalid/empty entity string!");
  1070. // PGM - do this before calling the spawn function so it can be overridden.
  1071. ent->gravityVector[0] = 0.0;
  1072. ent->gravityVector[1] = 0.0;
  1073. ent->gravityVector[2] = -1.0;
  1074. // PGM
  1075. ED_CallSpawn(ent);
  1076. ent->s.renderfx |= RF_IR_VISIBLE; // PGM
  1077. }
  1078. gi.Com_PrintFmt("{} entities inhibited\n", inhibit);
  1079. // precache start_items
  1080. G_PrecacheStartItems();
  1081. // precache player inventory items
  1082. G_PrecacheInventoryItems();
  1083. G_FindTeams();
  1084. // ZOID
  1085. CTFSpawn();
  1086. // ZOID
  1087. // ROGUE
  1088. if (deathmatch->integer)
  1089. {
  1090. if (g_dm_random_items->integer)
  1091. PrecacheForRandomRespawn();
  1092. }
  1093. else
  1094. {
  1095. InitHintPaths(); // if there aren't hintpaths on this map, enable quick aborts
  1096. }
  1097. // ROGUE
  1098. // ROGUE -- allow dm games to do init stuff right before game starts.
  1099. if (deathmatch->integer && gamerules->integer)
  1100. {
  1101. if (DMGame.PostInitSetup)
  1102. DMGame.PostInitSetup();
  1103. }
  1104. // ROGUE
  1105. setup_shadow_lights();
  1106. }
  1107. //===================================================================
  1108. #include "g_statusbar.h"
  1109. // create & set the statusbar string for the current gamemode
  1110. static void G_InitStatusbar()
  1111. {
  1112. statusbar_t sb;
  1113. // ---- shared stuff that every gamemode uses ----
  1114. sb.yb(-24);
  1115. // health
  1116. sb.xv(0).hnum().xv(50).pic(STAT_HEALTH_ICON);
  1117. // ammo
  1118. sb.ifstat(STAT_AMMO_ICON).xv(100).anum().xv(150).pic(STAT_AMMO_ICON).endifstat();
  1119. // armor
  1120. sb.ifstat(STAT_ARMOR_ICON).xv(200).rnum().xv(250).pic(STAT_ARMOR_ICON).endifstat();
  1121. // selected item
  1122. sb.ifstat(STAT_SELECTED_ICON).xv(296).pic(STAT_SELECTED_ICON).endifstat();
  1123. sb.yb(-50);
  1124. // picked up item
  1125. sb.ifstat(STAT_PICKUP_ICON).xv(0).pic(STAT_PICKUP_ICON).xv(26).yb(-42).loc_stat_string(STAT_PICKUP_STRING).yb(-50).endifstat();
  1126. // selected item name
  1127. sb.ifstat(STAT_SELECTED_ITEM_NAME).yb(-34).xv(319).loc_stat_rstring(STAT_SELECTED_ITEM_NAME).yb(-58).endifstat();
  1128. // timer
  1129. sb.ifstat(STAT_TIMER_ICON).xv(262).num(2, STAT_TIMER).xv(296).pic(STAT_TIMER_ICON).endifstat();
  1130. sb.yb(-50);
  1131. // help / weapon icon
  1132. sb.ifstat(STAT_HELPICON).xv(150).pic(STAT_HELPICON).endifstat();
  1133. // ---- gamemode-specific stuff ----
  1134. if (!deathmatch->integer)
  1135. {
  1136. // SP/coop
  1137. // key display
  1138. // move up if the timer is active
  1139. // FIXME: ugly af
  1140. sb.ifstat(STAT_TIMER_ICON).yb(-76).endifstat();
  1141. sb.ifstat(STAT_SELECTED_ITEM_NAME)
  1142. .yb(-58)
  1143. .ifstat(STAT_TIMER_ICON)
  1144. .yb(-84)
  1145. .endifstat()
  1146. .endifstat();
  1147. sb.ifstat(STAT_KEY_A).xv(296).pic(STAT_KEY_A).endifstat();
  1148. sb.ifstat(STAT_KEY_B).xv(272).pic(STAT_KEY_B).endifstat();
  1149. sb.ifstat(STAT_KEY_C).xv(248).pic(STAT_KEY_C).endifstat();
  1150. if (coop->integer)
  1151. {
  1152. // top of screen coop respawn display
  1153. sb.ifstat(STAT_COOP_RESPAWN).xv(0).yt(0).loc_stat_cstring2(STAT_COOP_RESPAWN).endifstat();
  1154. // coop lives
  1155. sb.ifstat(STAT_LIVES).xr(-16).yt(2).lives_num(STAT_LIVES).xr(0).yt(28).loc_rstring("$g_lives").endifstat();
  1156. }
  1157. sb.ifstat(STAT_HEALTH_BARS).yt(24).health_bars().endifstat();
  1158. }
  1159. else if (G_TeamplayEnabled())
  1160. {
  1161. CTFPrecache();
  1162. // ctf/tdm
  1163. // red team
  1164. sb.yb(-110).ifstat(STAT_CTF_TEAM1_PIC).xr(-26).pic(STAT_CTF_TEAM1_PIC).endifstat().xr(-78).num(3, STAT_CTF_TEAM1_CAPS);
  1165. // joined overlay
  1166. sb.ifstat(STAT_CTF_JOINED_TEAM1_PIC).yb(-112).xr(-28).pic(STAT_CTF_JOINED_TEAM1_PIC).endifstat();
  1167. // blue team
  1168. sb.yb(-83).ifstat(STAT_CTF_TEAM2_PIC).xr(-26).pic(STAT_CTF_TEAM2_PIC).endifstat().xr(-78).num(3, STAT_CTF_TEAM2_CAPS);
  1169. // joined overlay
  1170. sb.ifstat(STAT_CTF_JOINED_TEAM2_PIC).yb(-85).xr(-28).pic(STAT_CTF_JOINED_TEAM2_PIC).endifstat();
  1171. if (ctf->integer)
  1172. {
  1173. // have flag graph
  1174. sb.ifstat(STAT_CTF_FLAG_PIC).yt(26).xr(-24).pic(STAT_CTF_FLAG_PIC).endifstat();
  1175. }
  1176. // id view state
  1177. sb.ifstat(STAT_CTF_ID_VIEW).xv(112).yb(-58).stat_pname(STAT_CTF_ID_VIEW).endifstat();
  1178. // id view color
  1179. sb.ifstat(STAT_CTF_ID_VIEW_COLOR).xv(96).yb(-58).pic(STAT_CTF_ID_VIEW_COLOR).endifstat();
  1180. if (ctf->integer)
  1181. {
  1182. // match
  1183. sb.ifstat(STAT_CTF_MATCH).xl(0).yb(-78).stat_string(STAT_CTF_MATCH).endifstat();
  1184. }
  1185. // team info
  1186. sb.ifstat(STAT_CTF_TEAMINFO).xl(0).yb(-88).stat_string(STAT_CTF_TEAMINFO).endifstat();
  1187. }
  1188. else
  1189. {
  1190. // dm
  1191. // frags
  1192. sb.xr(-50).yt(2).num(3, STAT_FRAGS);
  1193. // spectator
  1194. sb.ifstat(STAT_SPECTATOR).xv(0).yb(-58).string2("SPECTATOR MODE").endifstat();
  1195. // chase cam
  1196. sb.ifstat(STAT_CHASE).xv(0).yb(-68).string("CHASING").xv(64).stat_string(STAT_CHASE).endifstat();
  1197. }
  1198. // ---- more shared stuff ----
  1199. if (deathmatch->integer)
  1200. {
  1201. // tech
  1202. sb.ifstat(STAT_CTF_TECH).yb(-137).xr(-26).pic(STAT_CTF_TECH).endifstat();
  1203. }
  1204. else
  1205. {
  1206. sb.story();
  1207. }
  1208. gi.configstring(CS_STATUSBAR, sb.sb.str().c_str());
  1209. }
  1210. /*QUAKED worldspawn (0 0 0) ?
  1211. Only used for the world.
  1212. "sky" environment map name
  1213. "skyaxis" vector axis for rotating sky
  1214. "skyrotate" speed of rotation in degrees/second
  1215. "sounds" music cd track number
  1216. "gravity" 800 is default gravity
  1217. "message" text to print at user logon
  1218. */
  1219. void SP_worldspawn(edict_t *ent)
  1220. {
  1221. ent->movetype = MOVETYPE_PUSH;
  1222. ent->solid = SOLID_BSP;
  1223. ent->inuse = true; // since the world doesn't use G_Spawn()
  1224. ent->s.modelindex = MODELINDEX_WORLD;
  1225. ent->gravity = 1.0f;
  1226. if (st.hub_map)
  1227. {
  1228. level.hub_map = true;
  1229. // clear helps
  1230. game.help1changed = game.help2changed = 0;
  1231. *game.helpmessage1 = *game.helpmessage2 = '\0';
  1232. for (size_t i = 0; i < game.maxclients; i++)
  1233. {
  1234. game.clients[i].pers.game_help1changed = game.clients[i].pers.game_help2changed = 0;
  1235. game.clients[i].resp.coop_respawn.game_help1changed = game.clients[i].resp.coop_respawn.game_help2changed = 0;
  1236. }
  1237. }
  1238. if (st.achievement && st.achievement[0])
  1239. level.achievement = st.achievement;
  1240. //---------------
  1241. // set configstrings for items
  1242. SetItemNames();
  1243. if (st.nextmap)
  1244. Q_strlcpy(level.nextmap, st.nextmap, sizeof(level.nextmap));
  1245. // make some data visible to the server
  1246. if (ent->message && ent->message[0])
  1247. {
  1248. gi.configstring(CS_NAME, ent->message);
  1249. Q_strlcpy(level.level_name, ent->message, sizeof(level.level_name));
  1250. }
  1251. else
  1252. Q_strlcpy(level.level_name, level.mapname, sizeof(level.level_name));
  1253. if (st.sky && st.sky[0])
  1254. gi.configstring(CS_SKY, st.sky);
  1255. else
  1256. gi.configstring(CS_SKY, "unit1_");
  1257. gi.configstring(CS_SKYROTATE, G_Fmt("{} {}", st.skyrotate, st.skyautorotate).data());
  1258. gi.configstring(CS_SKYAXIS, G_Fmt("{}", st.skyaxis).data());
  1259. if (st.music && st.music[0])
  1260. {
  1261. gi.configstring(CS_CDTRACK, st.music);
  1262. }
  1263. else
  1264. {
  1265. gi.configstring(CS_CDTRACK, G_Fmt("{}", ent->sounds).data());
  1266. }
  1267. if (level.is_n64)
  1268. gi.configstring(CS_CD_LOOP_COUNT, "0");
  1269. else if (st.was_key_specified("loop_count"))
  1270. gi.configstring(CS_CD_LOOP_COUNT, G_Fmt("{}", st.loop_count).data());
  1271. else
  1272. gi.configstring(CS_CD_LOOP_COUNT, "");
  1273. if (st.instantitems > 0 || level.is_n64)
  1274. {
  1275. level.instantitems = true;
  1276. }
  1277. // [Paril-KEX]
  1278. if (!deathmatch->integer)
  1279. gi.configstring(CS_GAME_STYLE, G_Fmt("{}", (int32_t) game_style_t::GAME_STYLE_PVE).data());
  1280. else if (teamplay->integer || ctf->integer)
  1281. gi.configstring(CS_GAME_STYLE, G_Fmt("{}", (int32_t) game_style_t::GAME_STYLE_TDM).data());
  1282. else
  1283. gi.configstring(CS_GAME_STYLE, G_Fmt("{}", (int32_t) game_style_t::GAME_STYLE_FFA).data());
  1284. // [Paril-KEX]
  1285. if (st.goals)
  1286. {
  1287. level.goals = st.goals;
  1288. game.help1changed++;
  1289. }
  1290. if (st.start_items)
  1291. level.start_items = st.start_items;
  1292. if (st.no_grapple)
  1293. level.no_grapple = st.no_grapple;
  1294. gi.configstring(CS_MAXCLIENTS, G_Fmt("{}", game.maxclients).data());
  1295. if (level.is_n64 && !deathmatch->integer)
  1296. {
  1297. gi.configstring(CONFIG_N64_PHYSICS, "1");
  1298. pm_config.n64_physics = true;
  1299. }
  1300. // statusbar prog
  1301. G_InitStatusbar();
  1302. // [Paril-KEX] air accel handled by game DLL now, and allow
  1303. // it to be changed in sp/coop
  1304. gi.configstring(CS_AIRACCEL, G_Fmt("{}", sv_airaccelerate->integer).data());
  1305. pm_config.airaccel = sv_airaccelerate->integer;
  1306. game.airacceleration_modified = sv_airaccelerate->modified_count;
  1307. //---------------
  1308. // help icon for statusbar
  1309. gi.imageindex("i_help");
  1310. level.pic_health = gi.imageindex("i_health");
  1311. gi.imageindex("help");
  1312. gi.imageindex("field_3");
  1313. if (!st.gravity)
  1314. {
  1315. level.gravity = 800.f;
  1316. gi.cvar_set("sv_gravity", "800");
  1317. }
  1318. else
  1319. {
  1320. level.gravity = atof(st.gravity);
  1321. gi.cvar_set("sv_gravity", st.gravity);
  1322. }
  1323. snd_fry.assign("player/fry.wav"); // standing in lava / slime
  1324. PrecacheItem(GetItemByIndex(IT_ITEM_COMPASS));
  1325. PrecacheItem(GetItemByIndex(IT_WEAPON_BLASTER));
  1326. if (g_dm_random_items->integer)
  1327. for (item_id_t i = static_cast<item_id_t>(IT_NULL + 1); i < IT_TOTAL; i = static_cast<item_id_t>(i + 1))
  1328. PrecacheItem(GetItemByIndex(i));
  1329. gi.soundindex("player/lava1.wav");
  1330. gi.soundindex("player/lava2.wav");
  1331. gi.soundindex("misc/pc_up.wav");
  1332. gi.soundindex("misc/talk1.wav");
  1333. // gibs
  1334. gi.soundindex("misc/udeath.wav");
  1335. gi.soundindex("items/respawn1.wav");
  1336. gi.soundindex("misc/mon_power2.wav");
  1337. // sexed sounds
  1338. gi.soundindex("*death1.wav");
  1339. gi.soundindex("*death2.wav");
  1340. gi.soundindex("*death3.wav");
  1341. gi.soundindex("*death4.wav");
  1342. gi.soundindex("*fall1.wav");
  1343. gi.soundindex("*fall2.wav");
  1344. gi.soundindex("*gurp1.wav"); // drowning damage
  1345. gi.soundindex("*gurp2.wav");
  1346. gi.soundindex("*jump1.wav"); // player jump
  1347. gi.soundindex("*pain25_1.wav");
  1348. gi.soundindex("*pain25_2.wav");
  1349. gi.soundindex("*pain50_1.wav");
  1350. gi.soundindex("*pain50_2.wav");
  1351. gi.soundindex("*pain75_1.wav");
  1352. gi.soundindex("*pain75_2.wav");
  1353. gi.soundindex("*pain100_1.wav");
  1354. gi.soundindex("*pain100_2.wav");
  1355. gi.soundindex("*drown1.wav"); // [Paril-KEX]
  1356. // sexed models
  1357. for (auto &item : itemlist)
  1358. item.vwep_index = 0;
  1359. for (auto &item : itemlist)
  1360. {
  1361. if (!item.vwep_model)
  1362. continue;
  1363. for (auto &check : itemlist)
  1364. {
  1365. if (check.vwep_model && !Q_strcasecmp(item.vwep_model, check.vwep_model) && check.vwep_index)
  1366. {
  1367. item.vwep_index = check.vwep_index;
  1368. break;
  1369. }
  1370. }
  1371. if (item.vwep_index)
  1372. continue;
  1373. item.vwep_index = gi.modelindex(item.vwep_model);
  1374. if (!level.vwep_offset)
  1375. level.vwep_offset = item.vwep_index;
  1376. }
  1377. //-------------------
  1378. gi.soundindex("player/gasp1.wav"); // gasping for air
  1379. gi.soundindex("player/gasp2.wav"); // head breaking surface, not gasping
  1380. gi.soundindex("player/watr_in.wav"); // feet hitting water
  1381. gi.soundindex("player/watr_out.wav"); // feet leaving water
  1382. gi.soundindex("player/watr_un.wav"); // head going underwater
  1383. gi.soundindex("player/u_breath1.wav");
  1384. gi.soundindex("player/u_breath2.wav");
  1385. gi.soundindex("player/wade1.wav");
  1386. gi.soundindex("player/wade2.wav");
  1387. gi.soundindex("player/wade3.wav");
  1388. gi.soundindex("items/pkup.wav"); // bonus item pickup
  1389. gi.soundindex("world/land.wav"); // landing thud
  1390. gi.soundindex("misc/h2ohit1.wav"); // landing splash
  1391. gi.soundindex("items/damage.wav");
  1392. gi.soundindex("items/protect.wav");
  1393. gi.soundindex("items/protect4.wav");
  1394. gi.soundindex("weapons/noammo.wav");
  1395. gi.soundindex("weapons/lowammo.wav");
  1396. gi.soundindex("weapons/change.wav");
  1397. gi.soundindex("infantry/inflies1.wav");
  1398. sm_meat_index.assign("models/objects/gibs/sm_meat/tris.md2");
  1399. gi.modelindex("models/objects/gibs/arm/tris.md2");
  1400. gi.modelindex("models/objects/gibs/bone/tris.md2");
  1401. gi.modelindex("models/objects/gibs/bone2/tris.md2");
  1402. gi.modelindex("models/objects/gibs/chest/tris.md2");
  1403. gi.modelindex("models/objects/gibs/skull/tris.md2");
  1404. gi.modelindex("models/objects/gibs/head2/tris.md2");
  1405. gi.modelindex("models/objects/gibs/sm_metal/tris.md2");
  1406. level.pic_ping = gi.imageindex("loc_ping");
  1407. //
  1408. // Setup light animation tables. 'a' is total darkness, 'z' is doublebright.
  1409. //
  1410. // 0 normal
  1411. gi.configstring(CS_LIGHTS + 0, "m");
  1412. // 1 FLICKER (first variety)
  1413. gi.configstring(CS_LIGHTS + 1, "mmnmmommommnonmmonqnmmo");
  1414. // 2 SLOW STRONG PULSE
  1415. gi.configstring(CS_LIGHTS + 2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba");
  1416. // 3 CANDLE (first variety)
  1417. gi.configstring(CS_LIGHTS + 3, "mmmmmaaaaammmmmaaaaaabcdefgabcdefg");
  1418. // 4 FAST STROBE
  1419. gi.configstring(CS_LIGHTS + 4, "mamamamamama");
  1420. // 5 GENTLE PULSE 1
  1421. gi.configstring(CS_LIGHTS + 5, "jklmnopqrstuvwxyzyxwvutsrqponmlkj");
  1422. // 6 FLICKER (second variety)
  1423. gi.configstring(CS_LIGHTS + 6, "nmonqnmomnmomomno");
  1424. // 7 CANDLE (second variety)`map
  1425. gi.configstring(CS_LIGHTS + 7, "mmmaaaabcdefgmmmmaaaammmaamm");
  1426. // 8 CANDLE (third variety)
  1427. gi.configstring(CS_LIGHTS + 8, "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa");
  1428. // 9 SLOW STROBE (fourth variety)
  1429. gi.configstring(CS_LIGHTS + 9, "aaaaaaaazzzzzzzz");
  1430. // 10 FLUORESCENT FLICKER
  1431. gi.configstring(CS_LIGHTS + 10, "mmamammmmammamamaaamammma");
  1432. // 11 SLOW PULSE NOT FADE TO BLACK
  1433. gi.configstring(CS_LIGHTS + 11, "abcdefghijklmnopqrrqponmlkjihgfedcba");
  1434. // [Paril-KEX] 12 N64's 2 (fast strobe)
  1435. gi.configstring(CS_LIGHTS + 12, "zzazazzzzazzazazaaazazzza");
  1436. // [Paril-KEX] 13 N64's 3 (half of strong pulse)
  1437. gi.configstring(CS_LIGHTS + 13, "abcdefghijklmnopqrstuvwxyz");
  1438. // [Paril-KEX] 14 N64's 4 (fast strobe)
  1439. gi.configstring(CS_LIGHTS + 14, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba");
  1440. // styles 32-62 are assigned by the light program for switchable lights
  1441. // 63 testing
  1442. gi.configstring(CS_LIGHTS + 63, "a");
  1443. // coop respawn strings
  1444. if (coop->integer)
  1445. {
  1446. gi.configstring(CONFIG_COOP_RESPAWN_STRING + 0, "$g_coop_respawn_in_combat");
  1447. gi.configstring(CONFIG_COOP_RESPAWN_STRING + 1, "$g_coop_respawn_bad_area");
  1448. gi.configstring(CONFIG_COOP_RESPAWN_STRING + 2, "$g_coop_respawn_blocked");
  1449. gi.configstring(CONFIG_COOP_RESPAWN_STRING + 3, "$g_coop_respawn_waiting");
  1450. gi.configstring(CONFIG_COOP_RESPAWN_STRING + 4, "$g_coop_respawn_no_lives");
  1451. }
  1452. }