From a39565b78308836c23a87fef9ecf12f5e47c5092 Mon Sep 17 00:00:00 2001 From: Walter Julius Hennecke Date: Sat, 4 Aug 2012 12:54:37 +0200 Subject: [PATCH] Integrated RPG-X2 rpgxEF edition into the rpgxEF repo ... not quite content with where the project files lie but it is ok for now. ... compiling works fine so far (only tested mingw32 right now) --- Makefile | 225 +- code/cgame/Makefile | 249 + code/cgame/Todo.txt | 3 + code/cgame/cg_anims.h | 1798 + code/cgame/cg_consolecmds.c | 1102 +- code/cgame/cg_draw.c | 4685 +- code/cgame/cg_drawtools.c | 1551 +- code/cgame/cg_effects.c | 757 +- code/cgame/cg_ents.c | 1034 +- code/cgame/cg_env.c | 2181 + code/cgame/cg_event.c | 1956 +- code/cgame/cg_info.c | 809 +- code/cgame/cg_lensflares.c | 25 + code/cgame/cg_local.h | 2066 +- code/cgame/cg_localents.c | 1349 +- code/cgame/cg_lua.c | 373 + code/cgame/cg_lua.h | 99 + code/cgame/cg_main.c | 2953 +- code/cgame/cg_main.c.orig | 1792 + code/cgame/cg_marks.c | 48 +- code/cgame/cg_motionblur.c | 84 + code/cgame/cg_newdraw.c | 1837 - code/cgame/cg_particles.c | 2041 - code/cgame/cg_players.c | 5335 +- code/cgame/cg_playerstate.c | 446 +- code/cgame/cg_predict.c | 253 +- code/cgame/cg_public.h | 38 +- code/cgame/cg_scoreboard.c | 2639 +- code/cgame/cg_screenfx.c | 434 + code/cgame/cg_screenfx.h | 28 + code/cgame/cg_servercmds.c | 1205 +- code/cgame/cg_snapshot.c | 76 +- code/cgame/cg_syscalls.asm | 152 +- code/cgame/cg_syscalls.c | 223 +- code/cgame/cg_text.h | 246 + code/cgame/cg_view.c | 1276 +- code/cgame/cg_weapons.c | 3126 +- code/cgame/cgame.def | 3 + code/cgame/cgame.dsp | 337 + code/cgame/cgame.dsw | 29 + code/cgame/cgame.opt | Bin 0 -> 48640 bytes code/cgame/cgame.plg | 147 + code/cgame/cgame.q3asm | 42 + code/cgame/cgame.vcproj | 1354 + code/cgame/cgame.vcxproj | 499 + code/cgame/cgame.vcxproj.filters | 195 + code/cgame/cgame.vcxproj.user | 3 + code/cgame/fx_compression.c | 434 + code/cgame/fx_disruptor.c | 296 + code/cgame/fx_grenade.c | 350 + code/cgame/fx_hypospray.c | 59 + code/cgame/fx_item.c | 306 + code/cgame/fx_lib.c | 1170 + code/cgame/fx_local.h | 180 + code/cgame/fx_misc.c | 286 + code/cgame/fx_phaser.c | 357 + code/cgame/fx_quantum.c | 356 + code/cgame/fx_tetrion.c | 56 + code/cgame/fx_transporter.c | 293 + code/cgame/lua_cent.c | 75 + code/cgame/lua_cfx.c | 19 + code/cgame/lua_refent.c | 475 + code/cgame/tr_types.h | 252 + code/game/Makefile | 281 + code/game/ToDo.txt | 4 + code/game/ai_chat.c | 390 +- code/game/ai_chat.h | 34 +- code/game/ai_cmd.c | 748 +- code/game/ai_cmd.h | 30 +- code/game/ai_dmnet.c | 1423 +- code/game/ai_dmnet.h | 52 +- code/game/ai_dmq3.c | 4459 +- code/game/ai_dmq3.c.orig | 2857 + code/game/ai_dmq3.h | 190 +- code/game/ai_main.c | 600 +- code/game/ai_main.h | 405 +- code/game/ai_team.c | 1871 +- code/game/ai_team.h | 36 +- code/game/ai_vcmd.c | 551 - code/game/ai_vcmd.h | 36 - code/game/be_aas.h | 165 + code/game/be_ai_char.h | 32 + code/game/be_ai_chat.h | 97 + code/game/be_ai_gen.h | 17 + code/game/be_ai_goal.h | 95 + code/game/be_ai_move.h | 108 + code/game/be_ai_weap.h | 88 + code/game/be_ea.h | 52 + code/game/bg_lib.c | 1764 +- code/game/bg_lib.h | 84 +- code/game/bg_local.h | 42 +- code/game/bg_misc.c | 2533 +- code/game/bg_oums.c | 2 + code/game/bg_oums.h | 4 + code/game/bg_panimate.c | 12 + code/game/bg_pmove.c | 3111 +- code/game/bg_public.h | 1142 +- code/game/bg_slidemove.c | 134 +- code/game/botai.h | 78 + code/game/botlib.h | 475 + code/game/chars.h | 73 +- code/game/fx_misc.c | 0 code/game/g_active.c | 2973 +- code/game/g_active.c.orig | 2470 + code/game/g_arenas.c | 410 +- code/game/g_bot.c | 252 +- code/game/g_breakable.c | 745 + code/game/g_breakable.h | 5 + code/game/g_cinematic.c | 63 + code/game/g_cinematic.cpp | 2 + code/game/g_cinematic.h | 10 + code/game/g_client.c | 2419 +- code/game/g_cmds.c | 8072 +- code/game/g_cmds_old.c | 7513 ++ code/game/g_combat.c | 2036 +- code/game/g_combat.c.old | 1374 + code/game/g_combat.h | 2 + code/game/g_forcefield2.c | 152 + code/game/g_fx.c | 2130 + code/game/g_groups.h | 18 + code/game/g_items.c | 987 +- code/game/g_local.h | 1717 +- code/game/g_log.c | 1814 + code/game/g_lua.c | 1083 + code/game/g_lua.h | 100 + code/game/g_main.c | 2805 +- code/game/g_mem.c | 24 +- code/game/g_misc.c | 516 +- code/game/g_missile.c | 1051 +- code/game/g_mover.c | 2509 +- code/game/g_public.h | 573 +- code/game/g_rankings.c | 1135 - code/game/g_rankings.h | 396 - code/game/g_roff.c | 198 + code/game/g_roff.h | 65 + code/game/g_session.c | 122 +- code/game/g_spawn.c | 641 +- code/game/g_spawn.h | 26 + code/game/g_sql.c | 619 + code/game/g_sql.h | 68 + code/game/g_svcmds.c | 629 +- code/game/g_syscalls.asm | 79 +- code/game/g_syscalls.c | 225 +- code/game/g_target.c | 2923 +- code/game/g_team.c | 1282 +- code/game/g_team.h | 50 +- code/game/g_trigger.c | 858 +- code/game/g_turrets.c | 1213 + code/game/g_ui.c | 176 + code/game/g_usable.c | 509 + code/game/g_usable.h | 2 + code/game/g_utils.c | 1193 +- code/game/g_weapon.c | 2581 +- code/game/g_weapon.h | 9 + code/game/g_xml.c | 4 + code/game/g_xml.h | 7 + code/game/game.def | 3 + code/game/game.dsp | 397 + code/game/game.dsw | 29 + code/game/game.opt | Bin 0 -> 52736 bytes code/game/game.plg | 140 + code/game/game.q3asm | 40 + code/game/game.vcproj | 1345 + code/game/game.vcxproj | 566 + code/game/game.vcxproj.filters | 475 + code/game/game.vcxproj.user | 3 + code/game/inv.h | 237 +- code/game/lapi.c | 1216 + code/game/lapi.h | 24 + code/game/lauxlib.c | 893 + code/game/lauxlib.h | 175 + code/game/lbaselib.c | 516 + code/game/lbitlib.c | 163 + code/game/lcode.c | 876 + code/game/lcode.h | 83 + code/game/lcorolib.c | 154 + code/game/lctype.c | 45 + code/game/lctype.h | 50 + code/game/ldblib.c | 405 + code/game/ldebug.c | 531 + code/game/ldebug.h | 31 + code/game/ldo.c | 655 + code/game/ldo.h | 45 + code/game/ldump.c | 172 + code/game/lfunc.c | 171 + code/game/lfunc.h | 34 + code/game/lgc.c | 1026 + code/game/lgc.h | 144 + code/game/linit.c | 67 + code/game/liolib.c | 645 + code/game/list.c | 147 + code/game/list.h | 98 + code/game/llex.c | 508 + code/game/llex.h | 78 + code/game/llimits.h | 281 + code/game/lmathlib.c | 284 + code/game/lmem.c | 120 + code/game/lmem.h | 50 + code/game/loadlib.c | 653 + code/game/lobject.c | 241 + code/game/lobject.h | 419 + code/game/lopcodes.c | 106 + code/game/lopcodes.h | 289 + code/game/loslib.c | 313 + code/game/lparser.c | 1421 + code/game/lparser.h | 97 + code/game/lstate.c | 285 + code/game/lstate.h | 218 + code/game/lstring.c | 113 + code/game/lstring.h | 37 + code/game/lstrlib.c | 942 + code/game/ltable.c | 588 + code/game/ltable.h | 39 + code/game/ltablib.c | 290 + code/game/ltm.c | 77 + code/game/ltm.h | 57 + code/game/lua.c | 477 + code/game/lua.h | 441 + code/game/lua.hpp | 9 + code/game/lua_cinematic.c | 70 + code/game/lua_cvar.c | 91 + code/game/lua_entity.c | 3021 + code/game/lua_game.c | 372 + code/game/lua_mover.c | 380 + code/game/lua_qmath.c | 284 + code/game/lua_sound.c | 40 + code/game/lua_trace.c | 209 + code/game/lua_vector.c | 388 + code/game/lua_weapons.c | 66 + code/game/luac.c | 447 + code/game/luaconf.h | 473 + code/game/lualib.h | 58 + code/game/lundump.c | 237 + code/game/lundump.h | 25 + code/game/lvm.c | 810 + code/game/lvm.h | 42 + code/game/lzio.c | 82 + code/game/lzio.h | 70 + code/game/match.h | 104 +- code/game/md5.c | 259 + code/game/md5.h | 58 + code/game/q_math.c | 1489 + code/game/q_math.c.orig | 1398 + code/game/q_shared.c | 1356 + code/game/q_shared.h | 1195 + code/game/q_shared.h.orig | 1189 + code/game/reds_bg_misc.c | 1647 + code/game/sqlite3.c | 119636 ++++++++++++++++++++++++++ code/game/sqlite3.h | 5963 ++ code/game/surfaceflags.h | 66 + code/game/syn.h | 36 +- code/game/tims_bg_misc.c | 1783 + code/q3_ui/ui_addbots.c | 412 - code/q3_ui/ui_atoms.c | 1264 - code/q3_ui/ui_cdkey.c | 291 - code/q3_ui/ui_cinematics.c | 350 - code/q3_ui/ui_confirm.c | 293 - code/q3_ui/ui_connect.c | 266 - code/q3_ui/ui_controls2.c | 1664 - code/q3_ui/ui_credits.c | 177 - code/q3_ui/ui_demo2.c | 304 - code/q3_ui/ui_display.c | 265 - code/q3_ui/ui_gameinfo.c | 815 - code/q3_ui/ui_ingame.c | 349 - code/q3_ui/ui_loadconfig.c | 274 - code/q3_ui/ui_local.h | 805 - code/q3_ui/ui_login.c | 208 - code/q3_ui/ui_main.c | 249 - code/q3_ui/ui_menu.c | 419 - code/q3_ui/ui_mods.c | 247 - code/q3_ui/ui_network.c | 281 - code/q3_ui/ui_options.c | 229 - code/q3_ui/ui_playermodel.c | 736 - code/q3_ui/ui_players.c | 1288 - code/q3_ui/ui_playersettings.c | 513 - code/q3_ui/ui_preferences.c | 416 - code/q3_ui/ui_qmenu.c | 1733 - code/q3_ui/ui_rankings.c | 420 - code/q3_ui/ui_rankstatus.c | 209 - code/q3_ui/ui_removebots.c | 342 - code/q3_ui/ui_saveconfig.c | 212 - code/q3_ui/ui_serverinfo.c | 273 - code/q3_ui/ui_servers2.c | 1660 - code/q3_ui/ui_setup.c | 327 - code/q3_ui/ui_signup.c | 286 - code/q3_ui/ui_sound.c | 450 - code/q3_ui/ui_sparena.c | 50 - code/q3_ui/ui_specifyleague.c | 333 - code/q3_ui/ui_specifyserver.c | 213 - code/q3_ui/ui_splevel.c | 1012 - code/q3_ui/ui_sppostgame.c | 644 - code/q3_ui/ui_spskill.c | 329 - code/q3_ui/ui_startserver.c | 1977 - code/q3_ui/ui_team.c | 200 - code/q3_ui/ui_video.c | 1225 - code/ui/Makefile | 172 + code/ui/ToDo.txt | 4 + code/ui/keycodes.h | 146 + code/ui/ui.def | 3 + code/ui/ui.dsp | 332 + code/ui/ui.plg | 178 + code/ui/ui.q3asm | 47 + code/ui/ui.vcproj | 1331 + code/ui/ui.vcproj.old | 313 + code/ui/ui.vcxproj | 520 + code/ui/ui.vcxproj.filters | 186 + code/ui/ui.vcxproj.user | 3 + code/ui/ui_addbots.c | 506 + code/ui/ui_admin.c | 2779 + code/ui/ui_atoms.c | 3185 +- code/ui/ui_atoms.c.orig | 2133 + code/ui/ui_cdkey.c | 494 + code/ui/ui_confirm.c | 331 + code/ui/ui_connect.c | 296 + code/ui/ui_controls2.c | 4216 + code/ui/ui_credits.c | 1060 + code/ui/ui_cvars.c | 183 + code/ui/ui_demo2.c | 548 + code/ui/ui_emotes.c | 1578 + code/ui/ui_fonts.c | 417 + code/ui/ui_gameinfo.c | 598 +- code/ui/ui_holodeck.c | 384 + code/ui/ui_ingame.c | 1276 + code/ui/ui_library.c | 1780 + code/ui/ui_local.h | 2307 +- code/ui/ui_login.c | 138 + code/ui/ui_main.c | 6425 +- code/ui/ui_menu.c | 4539 + code/{q3_ui => ui}/ui_mfield.c | 286 +- code/ui/ui_mods.c | 322 + code/ui/ui_motd.c | 275 + code/ui/ui_network.c | 268 + code/ui/ui_playermodel.c | 2153 + code/ui/ui_playermodel_bak.c | 1509 + code/ui/ui_players.c | 1304 +- code/ui/ui_playersettings.c | 1538 + code/ui/ui_preferences.c | 687 + code/ui/ui_public.h | 48 +- code/ui/ui_qmenu.c | 2698 + code/ui/ui_removebots.c | 335 + code/ui/ui_serverinfo.c | 427 + code/ui/ui_servers2.c | 2182 + code/ui/ui_shared.c | 5761 -- code/ui/ui_shared.h | 450 - code/ui/ui_sound.c | 451 + code/ui/ui_sparena.c | 30 + code/ui/ui_specifyserver.c | 269 + code/ui/ui_splevel.c | 1690 + code/ui/ui_sppostgame.c | 401 + code/{q3_ui => ui}/ui_spreset.c | 27 +- code/ui/ui_spskill.c | 488 + code/ui/ui_startserver.c | 4519 + code/ui/ui_syscalls.asm | 75 +- code/ui/ui_syscalls.c | 212 +- code/ui/ui_tactical.c | 422 + code/ui/ui_team.c | 549 + code/{q3_ui => ui}/ui_teamorders.c | 263 +- code/ui/ui_transporter.c | 476 + code/ui/ui_turbolift.c | 606 + code/ui/ui_video.c | 2333 + misc/msvc10/ioq3.sln | 104 +- 361 files changed, 319185 insertions(+), 74746 deletions(-) create mode 100644 code/cgame/Makefile create mode 100644 code/cgame/Todo.txt create mode 100644 code/cgame/cg_anims.h create mode 100644 code/cgame/cg_env.c create mode 100644 code/cgame/cg_lensflares.c create mode 100644 code/cgame/cg_lua.c create mode 100644 code/cgame/cg_lua.h create mode 100644 code/cgame/cg_main.c.orig create mode 100644 code/cgame/cg_motionblur.c delete mode 100644 code/cgame/cg_newdraw.c delete mode 100644 code/cgame/cg_particles.c create mode 100644 code/cgame/cg_screenfx.c create mode 100644 code/cgame/cg_screenfx.h create mode 100644 code/cgame/cg_text.h create mode 100644 code/cgame/cgame.def create mode 100644 code/cgame/cgame.dsp create mode 100644 code/cgame/cgame.dsw create mode 100644 code/cgame/cgame.opt create mode 100644 code/cgame/cgame.plg create mode 100644 code/cgame/cgame.q3asm create mode 100644 code/cgame/cgame.vcproj create mode 100644 code/cgame/cgame.vcxproj create mode 100644 code/cgame/cgame.vcxproj.filters create mode 100644 code/cgame/cgame.vcxproj.user create mode 100644 code/cgame/fx_compression.c create mode 100644 code/cgame/fx_disruptor.c create mode 100644 code/cgame/fx_grenade.c create mode 100644 code/cgame/fx_hypospray.c create mode 100644 code/cgame/fx_item.c create mode 100644 code/cgame/fx_lib.c create mode 100644 code/cgame/fx_local.h create mode 100644 code/cgame/fx_misc.c create mode 100644 code/cgame/fx_phaser.c create mode 100644 code/cgame/fx_quantum.c create mode 100644 code/cgame/fx_tetrion.c create mode 100644 code/cgame/fx_transporter.c create mode 100644 code/cgame/lua_cent.c create mode 100644 code/cgame/lua_cfx.c create mode 100644 code/cgame/lua_refent.c create mode 100644 code/cgame/tr_types.h create mode 100644 code/game/Makefile create mode 100644 code/game/ToDo.txt create mode 100644 code/game/ai_dmq3.c.orig delete mode 100644 code/game/ai_vcmd.c delete mode 100644 code/game/ai_vcmd.h create mode 100644 code/game/be_aas.h create mode 100644 code/game/be_ai_char.h create mode 100644 code/game/be_ai_chat.h create mode 100644 code/game/be_ai_gen.h create mode 100644 code/game/be_ai_goal.h create mode 100644 code/game/be_ai_move.h create mode 100644 code/game/be_ai_weap.h create mode 100644 code/game/be_ea.h create mode 100644 code/game/bg_oums.c create mode 100644 code/game/bg_oums.h create mode 100644 code/game/bg_panimate.c create mode 100644 code/game/botai.h create mode 100644 code/game/botlib.h create mode 100644 code/game/fx_misc.c create mode 100644 code/game/g_active.c.orig create mode 100644 code/game/g_breakable.c create mode 100644 code/game/g_breakable.h create mode 100644 code/game/g_cinematic.c create mode 100644 code/game/g_cinematic.cpp create mode 100644 code/game/g_cinematic.h create mode 100644 code/game/g_cmds_old.c create mode 100644 code/game/g_combat.c.old create mode 100644 code/game/g_combat.h create mode 100644 code/game/g_forcefield2.c create mode 100644 code/game/g_fx.c create mode 100644 code/game/g_groups.h create mode 100644 code/game/g_log.c create mode 100644 code/game/g_lua.c create mode 100644 code/game/g_lua.h delete mode 100644 code/game/g_rankings.c delete mode 100644 code/game/g_rankings.h create mode 100644 code/game/g_roff.c create mode 100644 code/game/g_roff.h create mode 100644 code/game/g_spawn.h create mode 100644 code/game/g_sql.c create mode 100644 code/game/g_sql.h create mode 100644 code/game/g_turrets.c create mode 100644 code/game/g_ui.c create mode 100644 code/game/g_usable.c create mode 100644 code/game/g_usable.h create mode 100644 code/game/g_weapon.h create mode 100644 code/game/g_xml.c create mode 100644 code/game/g_xml.h create mode 100644 code/game/game.def create mode 100644 code/game/game.dsp create mode 100644 code/game/game.dsw create mode 100644 code/game/game.opt create mode 100644 code/game/game.plg create mode 100644 code/game/game.q3asm create mode 100644 code/game/game.vcproj create mode 100644 code/game/game.vcxproj create mode 100644 code/game/game.vcxproj.filters create mode 100644 code/game/game.vcxproj.user create mode 100644 code/game/lapi.c create mode 100644 code/game/lapi.h create mode 100644 code/game/lauxlib.c create mode 100644 code/game/lauxlib.h create mode 100644 code/game/lbaselib.c create mode 100644 code/game/lbitlib.c create mode 100644 code/game/lcode.c create mode 100644 code/game/lcode.h create mode 100644 code/game/lcorolib.c create mode 100644 code/game/lctype.c create mode 100644 code/game/lctype.h create mode 100644 code/game/ldblib.c create mode 100644 code/game/ldebug.c create mode 100644 code/game/ldebug.h create mode 100644 code/game/ldo.c create mode 100644 code/game/ldo.h create mode 100644 code/game/ldump.c create mode 100644 code/game/lfunc.c create mode 100644 code/game/lfunc.h create mode 100644 code/game/lgc.c create mode 100644 code/game/lgc.h create mode 100644 code/game/linit.c create mode 100644 code/game/liolib.c create mode 100644 code/game/list.c create mode 100644 code/game/list.h create mode 100644 code/game/llex.c create mode 100644 code/game/llex.h create mode 100644 code/game/llimits.h create mode 100644 code/game/lmathlib.c create mode 100644 code/game/lmem.c create mode 100644 code/game/lmem.h create mode 100644 code/game/loadlib.c create mode 100644 code/game/lobject.c create mode 100644 code/game/lobject.h create mode 100644 code/game/lopcodes.c create mode 100644 code/game/lopcodes.h create mode 100644 code/game/loslib.c create mode 100644 code/game/lparser.c create mode 100644 code/game/lparser.h create mode 100644 code/game/lstate.c create mode 100644 code/game/lstate.h create mode 100644 code/game/lstring.c create mode 100644 code/game/lstring.h create mode 100644 code/game/lstrlib.c create mode 100644 code/game/ltable.c create mode 100644 code/game/ltable.h create mode 100644 code/game/ltablib.c create mode 100644 code/game/ltm.c create mode 100644 code/game/ltm.h create mode 100644 code/game/lua.c create mode 100644 code/game/lua.h create mode 100644 code/game/lua.hpp create mode 100644 code/game/lua_cinematic.c create mode 100644 code/game/lua_cvar.c create mode 100644 code/game/lua_entity.c create mode 100644 code/game/lua_game.c create mode 100644 code/game/lua_mover.c create mode 100644 code/game/lua_qmath.c create mode 100644 code/game/lua_sound.c create mode 100644 code/game/lua_trace.c create mode 100644 code/game/lua_vector.c create mode 100644 code/game/lua_weapons.c create mode 100644 code/game/luac.c create mode 100644 code/game/luaconf.h create mode 100644 code/game/lualib.h create mode 100644 code/game/lundump.c create mode 100644 code/game/lundump.h create mode 100644 code/game/lvm.c create mode 100644 code/game/lvm.h create mode 100644 code/game/lzio.c create mode 100644 code/game/lzio.h create mode 100644 code/game/md5.c create mode 100644 code/game/md5.h create mode 100644 code/game/q_math.c create mode 100644 code/game/q_math.c.orig create mode 100644 code/game/q_shared.c create mode 100644 code/game/q_shared.h create mode 100644 code/game/q_shared.h.orig create mode 100644 code/game/reds_bg_misc.c create mode 100644 code/game/sqlite3.c create mode 100644 code/game/sqlite3.h create mode 100644 code/game/surfaceflags.h create mode 100644 code/game/tims_bg_misc.c delete mode 100644 code/q3_ui/ui_addbots.c delete mode 100644 code/q3_ui/ui_atoms.c delete mode 100644 code/q3_ui/ui_cdkey.c delete mode 100644 code/q3_ui/ui_cinematics.c delete mode 100644 code/q3_ui/ui_confirm.c delete mode 100644 code/q3_ui/ui_connect.c delete mode 100644 code/q3_ui/ui_controls2.c delete mode 100644 code/q3_ui/ui_credits.c delete mode 100644 code/q3_ui/ui_demo2.c delete mode 100644 code/q3_ui/ui_display.c delete mode 100644 code/q3_ui/ui_gameinfo.c delete mode 100644 code/q3_ui/ui_ingame.c delete mode 100644 code/q3_ui/ui_loadconfig.c delete mode 100644 code/q3_ui/ui_local.h delete mode 100644 code/q3_ui/ui_login.c delete mode 100644 code/q3_ui/ui_main.c delete mode 100644 code/q3_ui/ui_menu.c delete mode 100644 code/q3_ui/ui_mods.c delete mode 100644 code/q3_ui/ui_network.c delete mode 100644 code/q3_ui/ui_options.c delete mode 100644 code/q3_ui/ui_playermodel.c delete mode 100644 code/q3_ui/ui_players.c delete mode 100644 code/q3_ui/ui_playersettings.c delete mode 100644 code/q3_ui/ui_preferences.c delete mode 100644 code/q3_ui/ui_qmenu.c delete mode 100644 code/q3_ui/ui_rankings.c delete mode 100644 code/q3_ui/ui_rankstatus.c delete mode 100644 code/q3_ui/ui_removebots.c delete mode 100644 code/q3_ui/ui_saveconfig.c delete mode 100644 code/q3_ui/ui_serverinfo.c delete mode 100644 code/q3_ui/ui_servers2.c delete mode 100644 code/q3_ui/ui_setup.c delete mode 100644 code/q3_ui/ui_signup.c delete mode 100644 code/q3_ui/ui_sound.c delete mode 100644 code/q3_ui/ui_sparena.c delete mode 100644 code/q3_ui/ui_specifyleague.c delete mode 100644 code/q3_ui/ui_specifyserver.c delete mode 100644 code/q3_ui/ui_splevel.c delete mode 100644 code/q3_ui/ui_sppostgame.c delete mode 100644 code/q3_ui/ui_spskill.c delete mode 100644 code/q3_ui/ui_startserver.c delete mode 100644 code/q3_ui/ui_team.c delete mode 100644 code/q3_ui/ui_video.c create mode 100644 code/ui/Makefile create mode 100644 code/ui/ToDo.txt create mode 100644 code/ui/keycodes.h create mode 100644 code/ui/ui.def create mode 100644 code/ui/ui.dsp create mode 100644 code/ui/ui.plg create mode 100644 code/ui/ui.q3asm create mode 100644 code/ui/ui.vcproj create mode 100644 code/ui/ui.vcproj.old create mode 100644 code/ui/ui.vcxproj create mode 100644 code/ui/ui.vcxproj.filters create mode 100644 code/ui/ui.vcxproj.user create mode 100644 code/ui/ui_addbots.c create mode 100644 code/ui/ui_admin.c create mode 100644 code/ui/ui_atoms.c.orig create mode 100644 code/ui/ui_cdkey.c create mode 100644 code/ui/ui_confirm.c create mode 100644 code/ui/ui_connect.c create mode 100644 code/ui/ui_controls2.c create mode 100644 code/ui/ui_credits.c create mode 100644 code/ui/ui_cvars.c create mode 100644 code/ui/ui_demo2.c create mode 100644 code/ui/ui_emotes.c create mode 100644 code/ui/ui_fonts.c create mode 100644 code/ui/ui_holodeck.c create mode 100644 code/ui/ui_ingame.c create mode 100644 code/ui/ui_library.c create mode 100644 code/ui/ui_login.c create mode 100644 code/ui/ui_menu.c rename code/{q3_ui => ui}/ui_mfield.c (57%) create mode 100644 code/ui/ui_mods.c create mode 100644 code/ui/ui_motd.c create mode 100644 code/ui/ui_network.c create mode 100644 code/ui/ui_playermodel.c create mode 100644 code/ui/ui_playermodel_bak.c create mode 100644 code/ui/ui_playersettings.c create mode 100644 code/ui/ui_preferences.c create mode 100644 code/ui/ui_qmenu.c create mode 100644 code/ui/ui_removebots.c create mode 100644 code/ui/ui_serverinfo.c create mode 100644 code/ui/ui_servers2.c delete mode 100644 code/ui/ui_shared.c delete mode 100644 code/ui/ui_shared.h create mode 100644 code/ui/ui_sound.c create mode 100644 code/ui/ui_sparena.c create mode 100644 code/ui/ui_specifyserver.c create mode 100644 code/ui/ui_splevel.c create mode 100644 code/ui/ui_sppostgame.c rename code/{q3_ui => ui}/ui_spreset.c (77%) create mode 100644 code/ui/ui_spskill.c create mode 100644 code/ui/ui_startserver.c create mode 100644 code/ui/ui_tactical.c create mode 100644 code/ui/ui_team.c rename code/{q3_ui => ui}/ui_teamorders.c (64%) create mode 100644 code/ui/ui_transporter.c create mode 100644 code/ui/ui_turbolift.c create mode 100644 code/ui/ui_video.c diff --git a/Makefile b/Makefile index 812bf4d..e788066 100644 --- a/Makefile +++ b/Makefile @@ -30,16 +30,16 @@ ifndef BUILD_STANDALONE BUILD_STANDALONE = endif ifndef BUILD_CLIENT - BUILD_CLIENT = + BUILD_CLIENT = 0 endif ifndef BUILD_CLIENT_SMP BUILD_CLIENT_SMP = endif ifndef BUILD_SERVER - BUILD_SERVER = + BUILD_SERVER = 0 endif ifndef BUILD_GAME_SO - BUILD_GAME_SO = 0 + BUILD_GAME_SO = 1 endif ifndef BUILD_GAME_QVM BUILD_GAME_QVM = 0 @@ -48,7 +48,7 @@ ifndef BUILD_BASEGAME BUILD_BASEGAME = endif ifndef BUILD_MISSIONPACK - BUILD_MISSIONPACK= + BUILD_MISSIONPACK= 0 endif BUILD_ELITEFORCE = 1 @@ -125,7 +125,7 @@ endif endif ifndef BASEGAME -BASEGAME=baseq3 +BASEGAME=rpgxEF endif ifndef BASEGAME_CFLAGS @@ -244,7 +244,7 @@ CGDIR=$(MOUNT_DIR)/cgame BLIBDIR=$(MOUNT_DIR)/botlib NDIR=$(MOUNT_DIR)/null UIDIR=$(MOUNT_DIR)/ui -Q3UIDIR=$(MOUNT_DIR)/q3_ui +Q3UIDIR=$(MOUNT_DIR)/ui JPDIR=$(MOUNT_DIR)/jpeg-8c SPEEXDIR=$(MOUNT_DIR)/libspeex ZDIR=$(MOUNT_DIR)/zlib @@ -384,7 +384,11 @@ ifneq (,$(findstring "$(PLATFORM)", "linux" "gnu_kfreebsd" "kfreebsd-gnu")) SHLIBEXT=so SHLIBCFLAGS=-fPIC -fvisibility=hidden - SHLIBLDFLAGS=-shared $(LDFLAGS) + SHLIBLDFLAGS=-shared $(LDFLAGS) -pthread + + ifeq ($(VM_USE_SQL), 1) + SHLIBCFLAGS+=-DSQL + endif THREAD_LIBS=-lpthread LIBS=-ldl -lm @@ -503,7 +507,11 @@ ifeq ($(PLATFORM),darwin) SHLIBEXT=dylib SHLIBCFLAGS=-fPIC -fno-common - SHLIBLDFLAGS=-dynamiclib $(LDFLAGS) -Wl,-U,_com_altivec + SHLIBLDFLAGS=-dynamiclib $(LDFLAGS) -Wl,-U,_com_altivec -pthread + + ifeq ($(VM_USE_SQL), 1) + SHLIBCFLAGS+=-DSQL + endif NOTSHLIBCFLAGS=-mdynamic-no-pic @@ -565,6 +573,10 @@ ifeq ($(PLATFORM),mingw32) SHLIBEXT=dll SHLIBCFLAGS= SHLIBLDFLAGS=-shared $(LDFLAGS) + + ifeq ($(VM_USE_SQL), 1) + SHLIBCFLAGS+=-DSQL + endif BINEXT=.exe @@ -653,7 +665,11 @@ ifeq ($(PLATFORM),freebsd) SHLIBEXT=so SHLIBCFLAGS=-fPIC - SHLIBLDFLAGS=-shared $(LDFLAGS) + SHLIBLDFLAGS=-shared $(LDFLAGS) -lpthread + + ifeq ($(VM_USE_SQL), 1) + SHLIBCFLAGS+=-DSQL + endif THREAD_LIBS=-lpthread # don't need -ldl (FreeBSD) @@ -721,8 +737,12 @@ ifeq ($(PLATFORM),openbsd) SHLIBEXT=so SHLIBNAME=.$(SHLIBEXT) SHLIBCFLAGS=-fPIC - SHLIBLDFLAGS=-shared $(LDFLAGS) + SHLIBLDFLAGS=-shared $(LDFLAGS) -lpthread + ifeq ($(VM_USE_SQL), 1) + SHLIBCFLAGS+=-DSQL + endif + THREAD_LIBS=-pthread LIBS=-lm @@ -762,8 +782,12 @@ ifeq ($(PLATFORM),netbsd) LIBS=-lm SHLIBEXT=so SHLIBCFLAGS=-fPIC - SHLIBLDFLAGS=-shared $(LDFLAGS) + SHLIBLDFLAGS=-shared $(LDFLAGS) -lpthread THREAD_LIBS=-lpthread + + ifeq ($(VM_USE_SQL), 1) + SHLIBCFLAGS+=-DSQL + endif BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes @@ -793,8 +817,12 @@ ifeq ($(PLATFORM),irix64) SHLIBEXT=so SHLIBCFLAGS= - SHLIBLDFLAGS=-shared + SHLIBLDFLAGS=-shared -lptrhead + ifeq ($(VM_USE_SQL), 1) + SHLIBCFLAGS+=-DSQL + endif + LIBS=-ldl -lm -lgen # FIXME: The X libraries probably aren't necessary? CLIENT_LIBS=-L/usr/X11/$(LIB) $(SDL_LIBS) \ @@ -853,8 +881,12 @@ ifeq ($(PLATFORM),sunos) SHLIBEXT=so SHLIBCFLAGS=-fPIC - SHLIBLDFLAGS=-shared $(LDFLAGS) + SHLIBLDFLAGS=-shared $(LDFLAGS) -pthread + ifeq ($(VM_USE_SQL), 1) + SHLIBCFLAGS+=-DSQL + endif + THREAD_LIBS=-lpthread LIBS=-lsocket -lnsl -ldl -lm @@ -1073,13 +1105,13 @@ endef define DO_GAME_CC $(echo_cmd) "GAME_CC $<" -$(Q)$(CC) $(BASEGAME_CFLAGS) -DQAGAME $(SHLIBCFLAGS) $(CFLAGS) $(OPTIMIZEVM) -o $@ -c $< +$(Q)$(CC) $(BASEGAME_CFLAGS) -DQAGAME -DLUA_COMPAT_ALL $(SHLIBCFLAGS) $(CFLAGS) $(OPTIMIZEVM) -o $@ -c $< $(Q)$(DO_QVM_DEP) endef define DO_CGAME_CC $(echo_cmd) "CGAME_CC $<" -$(Q)$(CC) $(BASEGAME_CFLAGS) -DCGAME $(SHLIBCFLAGS) $(CFLAGS) $(OPTIMIZEVM) -o $@ -c $< +$(Q)$(CC) $(BASEGAME_CFLAGS) -DCGAME -DLUA_COMPAT_ALL $(SHLIBCFLAGS) $(CFLAGS) $(OPTIMIZEVM) -o $@ -c $< $(Q)$(DO_QVM_DEP) endef @@ -1993,35 +2025,88 @@ $(B)/$(SERVERBIN)$(FULLBINEXT): $(Q3DOBJ) ## BASEQ3 CGAME ############################################################################# +CGLUAOBJ = \ + $(B)/$(BASEGAME)/cgame/lapi.o \ + $(B)/$(BASEGAME)/cgame/lauxlib.o \ + $(B)/$(BASEGAME)/cgame/lbaselib.o \ + $(B)/$(BASEGAME)/cgame/lbitlib.o \ + $(B)/$(BASEGAME)/cgame/lcode.o \ + $(B)/$(BASEGAME)/cgame/lcorolib.o \ + $(B)/$(BASEGAME)/cgame/lctype.o \ + $(B)/$(BASEGAME)/cgame/ldblib.o \ + $(B)/$(BASEGAME)/cgame/ldebug.o \ + $(B)/$(BASEGAME)/cgame/ldo.o \ + $(B)/$(BASEGAME)/cgame/ldump.o \ + $(B)/$(BASEGAME)/cgame/lfunc.o \ + $(B)/$(BASEGAME)/cgame/lgc.o \ + $(B)/$(BASEGAME)/cgame/linit.o \ + $(B)/$(BASEGAME)/cgame/liolib.o \ + $(B)/$(BASEGAME)/cgame/llex.o \ + $(B)/$(BASEGAME)/cgame/lmathlib.o \ + $(B)/$(BASEGAME)/cgame/lmem.o \ + $(B)/$(BASEGAME)/cgame/loadlib.o \ + $(B)/$(BASEGAME)/cgame/lobject.o \ + $(B)/$(BASEGAME)/cgame/lopcodes.o \ + $(B)/$(BASEGAME)/cgame/loslib.o \ + $(B)/$(BASEGAME)/cgame/lparser.o \ + $(B)/$(BASEGAME)/cgame/lstate.o \ + $(B)/$(BASEGAME)/cgame/lstring.o \ + $(B)/$(BASEGAME)/cgame/lstrlib.o \ + $(B)/$(BASEGAME)/cgame/ltable.o \ + $(B)/$(BASEGAME)/cgame/ltablib.o \ + $(B)/$(BASEGAME)/cgame/ltm.o \ + $(B)/$(BASEGAME)/cgame/lua.o \ + $(B)/$(BASEGAME)/cgame/luac.o \ + $(B)/$(BASEGAME)/cgame/lundump.o \ + $(B)/$(BASEGAME)/cgame/lvm.o \ + $(B)/$(BASEGAME)/cgame/lzio.o + Q3CGOBJ_ = \ $(B)/$(BASEGAME)/cgame/cg_main.o \ $(B)/$(BASEGAME)/cgame/bg_misc.o \ $(B)/$(BASEGAME)/cgame/bg_pmove.o \ $(B)/$(BASEGAME)/cgame/bg_slidemove.o \ - $(B)/$(BASEGAME)/cgame/bg_lib.o \ $(B)/$(BASEGAME)/cgame/cg_consolecmds.o \ $(B)/$(BASEGAME)/cgame/cg_draw.o \ $(B)/$(BASEGAME)/cgame/cg_drawtools.o \ $(B)/$(BASEGAME)/cgame/cg_effects.o \ $(B)/$(BASEGAME)/cgame/cg_ents.o \ $(B)/$(BASEGAME)/cgame/cg_event.o \ - $(B)/$(BASEGAME)/cgame/cg_info.o \ + $(B)/$(BASEGAME)/cgame/cg_env.o \ $(B)/$(BASEGAME)/cgame/cg_localents.o \ + $(B)/$(BASEGAME)/cgame/cg_info.o \ $(B)/$(BASEGAME)/cgame/cg_marks.o \ - $(B)/$(BASEGAME)/cgame/cg_particles.o \ $(B)/$(BASEGAME)/cgame/cg_players.o \ $(B)/$(BASEGAME)/cgame/cg_playerstate.o \ $(B)/$(BASEGAME)/cgame/cg_predict.o \ + $(B)/$(BASEGAME)/cgame/cg_screenfx.o \ $(B)/$(BASEGAME)/cgame/cg_scoreboard.o \ $(B)/$(BASEGAME)/cgame/cg_servercmds.o \ $(B)/$(BASEGAME)/cgame/cg_snapshot.o \ $(B)/$(BASEGAME)/cgame/cg_view.o \ $(B)/$(BASEGAME)/cgame/cg_weapons.o \ + $(B)/$(BASEGAME)/cgame/cg_lua.o \ + $(B)/$(BASEGAME)/cgame/lua_vector.o \ + $(B)/$(BASEGAME)/cgame/lua_qmath.o \ + $(B)/$(BASEGAME)/cgame/lua_cfx.o \ + $(B)/$(BASEGAME)/cgame/lua_cent.o \ + $(B)/$(BASEGAME)/cgame/lua_refent.o \ + $(B)/$(BASEGAME)/cgame/fx_transporter.o \ + $(B)/$(BASEGAME)/cgame/fx_tetrion.o \ + $(B)/$(BASEGAME)/cgame/fx_disruptor.o \ + $(B)/$(BASEGAME)/cgame/fx_hypospray.o \ + $(B)/$(BASEGAME)/cgame/fx_quantum.o \ + $(B)/$(BASEGAME)/cgame/fx_phaser.o \ + $(B)/$(BASEGAME)/cgame/fx_misc.o \ + $(B)/$(BASEGAME)/cgame/fx_lib.o \ + $(B)/$(BASEGAME)/cgame/fx_item.o \ + $(B)/$(BASEGAME)/cgame/fx_grenade.o \ + $(B)/$(BASEGAME)/cgame/fx_compression.o \ \ - $(B)/$(BASEGAME)/qcommon/q_math.o \ - $(B)/$(BASEGAME)/qcommon/q_shared.o + $(B)/$(BASEGAME)/cgame/q_math.o \ + $(B)/$(BASEGAME)/cgame/q_shared.o -Q3CGOBJ = $(Q3CGOBJ_) $(B)/$(BASEGAME)/cgame/cg_syscalls.o +Q3CGOBJ = $(Q3CGOBJ_) $(B)/$(BASEGAME)/cgame/cg_syscalls.o $(CGLUAOBJ) Q3CGVMOBJ = $(Q3CGOBJ_:%.o=%.asm) $(B)/$(BASEGAME)/cgame$(SHLIBNAME): $(Q3CGOBJ) @@ -2037,7 +2122,6 @@ $(B)/$(BASEGAME)/vm/cgame.qvm: $(Q3CGVMOBJ) $(CGDIR)/cg_syscalls.asm $(Q3ASM) ############################################################################# MPCGOBJ_ = \ - $(B)/$(MISSIONPACK)/cgame/cg_main.o \ $(B)/$(MISSIONPACK)/cgame/bg_misc.o \ $(B)/$(MISSIONPACK)/cgame/bg_pmove.o \ $(B)/$(MISSIONPACK)/cgame/bg_slidemove.o \ @@ -2052,6 +2136,7 @@ MPCGOBJ_ = \ $(B)/$(MISSIONPACK)/cgame/cg_info.o \ $(B)/$(MISSIONPACK)/cgame/cg_localents.o \ $(B)/$(MISSIONPACK)/cgame/cg_marks.o \ + $(B)/$(MISSIONPACK)/cgame/cg_main.o \ $(B)/$(MISSIONPACK)/cgame/cg_particles.o \ $(B)/$(MISSIONPACK)/cgame/cg_players.o \ $(B)/$(MISSIONPACK)/cgame/cg_playerstate.o \ @@ -2083,6 +2168,42 @@ $(B)/$(MISSIONPACK)/vm/cgame.qvm: $(MPCGVMOBJ) $(CGDIR)/cg_syscalls.asm $(Q3ASM) ## BASEQ3 GAME ############################################################################# +GLUAOBJ = \ + $(B)/$(BASEGAME)/game/lapi.o \ + $(B)/$(BASEGAME)/game/lauxlib.o \ + $(B)/$(BASEGAME)/game/lbaselib.o \ + $(B)/$(BASEGAME)/game/lbitlib.o \ + $(B)/$(BASEGAME)/game/lcode.o \ + $(B)/$(BASEGAME)/game/lcorolib.o \ + $(B)/$(BASEGAME)/game/lctype.o \ + $(B)/$(BASEGAME)/game/ldblib.o \ + $(B)/$(BASEGAME)/game/ldebug.o \ + $(B)/$(BASEGAME)/game/ldo.o \ + $(B)/$(BASEGAME)/game/ldump.o \ + $(B)/$(BASEGAME)/game/lfunc.o \ + $(B)/$(BASEGAME)/game/lgc.o \ + $(B)/$(BASEGAME)/game/linit.o \ + $(B)/$(BASEGAME)/game/liolib.o \ + $(B)/$(BASEGAME)/game/llex.o \ + $(B)/$(BASEGAME)/game/lmathlib.o \ + $(B)/$(BASEGAME)/game/lmem.o \ + $(B)/$(BASEGAME)/game/loadlib.o \ + $(B)/$(BASEGAME)/game/lobject.o \ + $(B)/$(BASEGAME)/game/lopcodes.o \ + $(B)/$(BASEGAME)/game/loslib.o \ + $(B)/$(BASEGAME)/game/lparser.o \ + $(B)/$(BASEGAME)/game/lstate.o \ + $(B)/$(BASEGAME)/game/lstring.o \ + $(B)/$(BASEGAME)/game/lstrlib.o \ + $(B)/$(BASEGAME)/game/ltable.o \ + $(B)/$(BASEGAME)/game/ltablib.o \ + $(B)/$(BASEGAME)/game/ltm.o \ + $(B)/$(BASEGAME)/game/lua.o \ + $(B)/$(BASEGAME)/game/luac.o \ + $(B)/$(BASEGAME)/game/lundump.o \ + $(B)/$(BASEGAME)/game/lvm.o \ + $(B)/$(BASEGAME)/game/lzio.o + Q3GOBJ_ = \ $(B)/$(BASEGAME)/game/g_main.o \ $(B)/$(BASEGAME)/game/ai_chat.o \ @@ -2091,11 +2212,10 @@ Q3GOBJ_ = \ $(B)/$(BASEGAME)/game/ai_dmq3.o \ $(B)/$(BASEGAME)/game/ai_main.o \ $(B)/$(BASEGAME)/game/ai_team.o \ - $(B)/$(BASEGAME)/game/ai_vcmd.o \ $(B)/$(BASEGAME)/game/bg_misc.o \ $(B)/$(BASEGAME)/game/bg_pmove.o \ $(B)/$(BASEGAME)/game/bg_slidemove.o \ - $(B)/$(BASEGAME)/game/bg_lib.o \ + $(B)/$(BASEGAME)/game/bg_oums.o \ $(B)/$(BASEGAME)/game/g_active.o \ $(B)/$(BASEGAME)/game/g_arenas.o \ $(B)/$(BASEGAME)/game/g_bot.o \ @@ -2115,11 +2235,33 @@ Q3GOBJ_ = \ $(B)/$(BASEGAME)/game/g_trigger.o \ $(B)/$(BASEGAME)/game/g_utils.o \ $(B)/$(BASEGAME)/game/g_weapon.o \ + $(B)/$(BASEGAME)/game/g_ui.o \ + $(B)/$(BASEGAME)/game/g_lua.o \ + $(B)/$(BASEGAME)/game/g_usable.o \ + $(B)/$(BASEGAME)/game/g_turrets.o \ + $(B)/$(BASEGAME)/game/g_log.o \ + $(B)/$(BASEGAME)/game/g_fx.o \ + $(B)/$(BASEGAME)/game/g_sql.o \ + $(B)/$(BASEGAME)/game/g_breakable.o \ + $(B)/$(BASEGAME)/game/g_cinematic.o \ + $(B)/$(BASEGAME)/game/lua_game.o \ + $(B)/$(BASEGAME)/game/lua_entity.o \ + $(B)/$(BASEGAME)/game/lua_vector.o \ + $(B)/$(BASEGAME)/game/lua_mover.o \ + $(B)/$(BASEGAME)/game/lua_qmath.o \ + $(B)/$(BASEGAME)/game/lua_cinematic.o \ + $(B)/$(BASEGAME)/game/lua_sound.o \ + $(B)/$(BASEGAME)/game/lua_weapons.o \ + $(B)/$(BASEGAME)/game/lua_trace.o \ + $(B)/$(BASEGAME)/game/lua_cvar.o \ + $(B)/$(BASEGAME)/game/sqlite3.o \ + $(B)/$(BASEGAME)/game/md5.o \ + $(B)/$(BASEGAME)/game/list.o \ \ - $(B)/$(BASEGAME)/qcommon/q_math.o \ - $(B)/$(BASEGAME)/qcommon/q_shared.o + $(B)/$(BASEGAME)/game/q_math.o \ + $(B)/$(BASEGAME)/game/q_shared.o -Q3GOBJ = $(Q3GOBJ_) $(B)/$(BASEGAME)/game/g_syscalls.o +Q3GOBJ = $(Q3GOBJ_) $(B)/$(BASEGAME)/game/g_syscalls.o $(GLUAOBJ) Q3GVMOBJ = $(Q3GOBJ_:%.o=%.asm) $(B)/$(BASEGAME)/qagame$(SHLIBNAME): $(Q3GOBJ) @@ -2190,35 +2332,28 @@ $(B)/$(MISSIONPACK)/vm/qagame.qvm: $(MPGVMOBJ) $(GDIR)/g_syscalls.asm $(Q3ASM) Q3UIOBJ_ = \ $(B)/$(BASEGAME)/ui/ui_main.o \ $(B)/$(BASEGAME)/ui/bg_misc.o \ - $(B)/$(BASEGAME)/ui/bg_lib.o \ $(B)/$(BASEGAME)/ui/ui_addbots.o \ $(B)/$(BASEGAME)/ui/ui_atoms.o \ $(B)/$(BASEGAME)/ui/ui_cdkey.o \ - $(B)/$(BASEGAME)/ui/ui_cinematics.o \ $(B)/$(BASEGAME)/ui/ui_confirm.o \ $(B)/$(BASEGAME)/ui/ui_connect.o \ $(B)/$(BASEGAME)/ui/ui_controls2.o \ $(B)/$(BASEGAME)/ui/ui_credits.o \ $(B)/$(BASEGAME)/ui/ui_demo2.o \ - $(B)/$(BASEGAME)/ui/ui_display.o \ $(B)/$(BASEGAME)/ui/ui_gameinfo.o \ $(B)/$(BASEGAME)/ui/ui_ingame.o \ - $(B)/$(BASEGAME)/ui/ui_loadconfig.o \ $(B)/$(BASEGAME)/ui/ui_menu.o \ $(B)/$(BASEGAME)/ui/ui_mfield.o \ $(B)/$(BASEGAME)/ui/ui_mods.o \ $(B)/$(BASEGAME)/ui/ui_network.o \ - $(B)/$(BASEGAME)/ui/ui_options.o \ $(B)/$(BASEGAME)/ui/ui_playermodel.o \ $(B)/$(BASEGAME)/ui/ui_players.o \ $(B)/$(BASEGAME)/ui/ui_playersettings.o \ $(B)/$(BASEGAME)/ui/ui_preferences.o \ $(B)/$(BASEGAME)/ui/ui_qmenu.o \ $(B)/$(BASEGAME)/ui/ui_removebots.o \ - $(B)/$(BASEGAME)/ui/ui_saveconfig.o \ $(B)/$(BASEGAME)/ui/ui_serverinfo.o \ $(B)/$(BASEGAME)/ui/ui_servers2.o \ - $(B)/$(BASEGAME)/ui/ui_setup.o \ $(B)/$(BASEGAME)/ui/ui_sound.o \ $(B)/$(BASEGAME)/ui/ui_sparena.o \ $(B)/$(BASEGAME)/ui/ui_specifyserver.o \ @@ -2229,9 +2364,16 @@ Q3UIOBJ_ = \ $(B)/$(BASEGAME)/ui/ui_team.o \ $(B)/$(BASEGAME)/ui/ui_teamorders.o \ $(B)/$(BASEGAME)/ui/ui_video.o \ + $(B)/$(BASEGAME)/ui/ui_turbolift.o \ + $(B)/$(BASEGAME)/ui/ui_transporter.o \ + $(B)/$(BASEGAME)/ui/ui_motd.o \ + $(B)/$(BASEGAME)/ui/ui_admin.o \ + $(B)/$(BASEGAME)/ui/ui_fonts.o \ + $(B)/$(BASEGAME)/ui/ui_emotes.o \ + $(B)/$(BASEGAME)/ui/ui_cvars.o \ \ - $(B)/$(BASEGAME)/qcommon/q_math.o \ - $(B)/$(BASEGAME)/qcommon/q_shared.o + $(B)/$(BASEGAME)/ui/q_math.o \ + $(B)/$(BASEGAME)/ui/q_shared.o Q3UIOBJ = $(Q3UIOBJ_) $(B)/$(MISSIONPACK)/ui/ui_syscalls.o Q3UIVMOBJ = $(Q3UIOBJ_:%.o=%.asm) @@ -2377,6 +2519,12 @@ endif $(B)/$(BASEGAME)/cgame/bg_%.o: $(GDIR)/bg_%.c $(DO_CGAME_CC) + +$(B)/$(BASEGAME)/cgame/l%.o: $(GDIR)/l%.c + $(DO_CGAME_CC) + +$(B)/$(BASEGAME)/cgame/q_%.o: $(GDIR)/q_%.c + $(DO_CGAME_CC) $(B)/$(BASEGAME)/cgame/%.o: $(CGDIR)/%.c $(DO_CGAME_CC) @@ -2399,6 +2547,8 @@ $(B)/$(MISSIONPACK)/cgame/bg_%.asm: $(GDIR)/bg_%.c $(Q3LCC) $(B)/$(MISSIONPACK)/cgame/%.asm: $(CGDIR)/%.c $(Q3LCC) $(DO_CGAME_Q3LCC_MISSIONPACK) +$(B)/$(BASEGAME)/game/q_%.o: $(GDIR)/q_%.c + $(DO_GAME_CC) $(B)/$(BASEGAME)/game/%.o: $(GDIR)/%.c $(DO_GAME_CC) @@ -2416,6 +2566,9 @@ $(B)/$(MISSIONPACK)/game/%.asm: $(GDIR)/%.c $(Q3LCC) $(B)/$(BASEGAME)/ui/bg_%.o: $(GDIR)/bg_%.c $(DO_UI_CC) +$(B)/$(BASEGAME)/ui/q_%.o: $(GDIR)/q_%.c + $(DO_UI_CC) + $(B)/$(BASEGAME)/ui/%.o: $(Q3UIDIR)/%.c $(DO_UI_CC) diff --git a/code/cgame/Makefile b/code/cgame/Makefile new file mode 100644 index 0000000..520fbf0 --- /dev/null +++ b/code/cgame/Makefile @@ -0,0 +1,249 @@ +default: so +so: build_so + +# determine arch and platform +ARCH=$(shell uname -m | sed -e s/i.86/i386/) +PLATFORM=$(shell uname|sed -e s/_.*//|tr '[:upper:]' '[:lower:]') + +# compiler to use for building shared objects +CC = gcc + +# cross compiling +ifneq ($(PLATFORM), mingw32) +ifeq ($(TARGET), win32) + PLATFORM=mingw32 + ARCH=x86 + CC=i686-w64-mingw32-gcc + CFLAGS+=-m32 +endif +ifeq ($(TARGET), win64) + PLATFORM=mingw32 + ARCH=x64 + CC=x86_64-w64-mingw32-gcc + CFLAGS+=-m64 +endif +else +# we are compiling on windows +ARCH=x86 +endif + +# cflags for the compiler +ifeq ($(PLATFORM), mingw32) +SOCFLAGS = $(CFLAGS) +else +SOCFLAGS = $(CFLAGS) -fPIC +endif + +# set extension +ifeq ($(PLATFORM), mingw32) +EXT=dll +else +EXT=so +endif + +# warning level +ifeq ($(DEBUG), 1) +WL=-Wall +else +WL=-Wall -Wno-unused-but-set-variable +endif + +# cgame objects +OBJ = \ + fx_transporter.o \ + fx_tetrion.o \ + fx_disruptor.o \ + fx_hypospray.o \ + fx_quantum.o \ + fx_phaser.o \ + fx_misc.o \ + fx_lib.o \ + fx_item.o \ + fx_grenade.o \ + fx_compression.o \ + cg_weapons.o \ + cg_view.o \ + cg_snapshot.o \ + cg_servercmds.o \ + cg_screenfx.o \ + cg_scoreboard.o \ + cg_predict.o \ + cg_playerstate.o \ + cg_players.o \ + cg_marks.o \ + cg_main.o \ + cg_localents.o \ + cg_info.o \ + cg_event.o \ + cg_env.o \ + cg_ents.o \ + cg_effects.o \ + cg_drawtools.o \ + cg_draw.o \ + cg_consolecmds.o \ + cg_lua.o \ + lua_vector.o \ + lua_qmath.o \ + lua_cfx.o \ + lua_cent.o \ + lua_refent.o \ + +# depency objects from game +OBJDEP = \ + q_shared.o \ + q_math.o \ + bg_misc.o \ + bg_pmove.o \ + bg_slidemove.o + + # object for syscalls to the engine +SOOBJ = \ + cg_syscalls.o + +# objects for lua +LUAOBJ = \ + lapi.o \ + lauxlib.o \ + lbaselib.o \ + lbitlib.o \ + lcode.o \ + lcorolib.o \ + lctype.o \ + ldblib.o \ + ldebug.o \ + ldo.o \ + ldump.o \ + lfunc.o \ + lgc.o \ + linit.o \ + liolib.o \ + llex.o \ + lmathlib.o \ + lmem.o \ + loadlib.o \ + lobject.o \ + lopcodes.o \ + loslib.o \ + lparser.o \ + lstate.o \ + lstring.o \ + lstrlib.o \ + ltable.o \ + ltablib.o \ + ltm.o \ + lua.o \ + luac.o \ + lundump.o \ + lvm.o \ + lzio.o + +# do cc for shared library +ifeq ($(DEBUG), 1) +DO_SOCC = $(CC) $(SOCFLAGS) $(WL) -g3 $(DEFINES) -o $@ -c $< +else +DO_SOCC = $(CC) $(SOCFLAGS) $(WL) $(DEFINES) -o $@ -c $< +endif +# do cc for lua +ifeq ($(DEBUG), 1) +DO_LUACC = $(CC) -O2 -Wall $(SOCFLAGS) -DLUA_COMPAT_ALL -o $@ -c $< +else +DO_LUACC = $(CC) -O2 -Wall -g3 $(SOCFLAGS) -DLUA_COMPAT_ALL -o $@ -c $< +endif + +build_so: DO_CC=$(DO_SOCC) + +# cgame +cg_consolecmds.o : cg_consolecmds.c; $(DO_CC) +cg_draw.o : cg_draw.c; $(DO_CC) +cg_drawtools.o : cg_drawtools.c; $(DO_CC) +cg_effects.o : cg_effects.c; $(DO_CC) +cg_ents.o : cg_ents.c; $(DO_CC) +cg_env.o : cg_env.c; $(DO_CC) +cg_event.o : cg_event.c; $(DO_CC) +cg_info.o : cg_info.c; $(DO_CC) +cg_localents.o : cg_localents.c; $(DO_CC) +cg_main.o : cg_main.c; $(DO_CC) +cg_marks.o : cg_marks.c; $(DO_CC) +cg_players.o : cg_players.c; $(DO_CC) +cg_playerstate.o : cg_playerstate.c; $(DO_CC) +cg_predict.o : cg_predict.c; $(DO_CC) +cg_scoreboard.o : cg_scoreboard.c; $(DO_CC) +cg_screenfx.o : cg_screenfx.c; $(DO_CC) +cg_servercmds.o : cg_servercmds.c; $(DO_CC) +cg_snapshot.o : cg_snapshot.c; $(DO_CC) +cg_view.o : cg_view.c; $(DO_CC) +cg_weapons.o : cg_weapons.c; $(DO_CC) +cg_lua.o : cg_lua.c; $(DO_CC) +fx_compression.o : fx_compression.c; $(DO_CC) +fx_grenade.o : fx_grenade.c; $(DO_CC) +fx_item.o : fx_item.c; $(DO_CC) +fx_lib.o : fx_lib.c; $(DO_CC) +fx_misc.o : fx_misc.c; $(DO_CC) +fx_phaser.o : fx_phaser.c; $(DO_CC) +fx_quantum.o : fx_quantum.c; $(DO_CC) +fx_hypospray.o : fx_hypospray.c; $(DO_CC) +fx_disruptor.o : fx_disruptor.c; $(DO_CC) +fx_tetrion.o : fx_tetrion.c; $(DO_CC) +fx_transporter.o : fx_transporter.c; $(DO_CC) +lua_qmath.o: ../game/lua_qmath.c; $(DO_CC) +lua_vector.o: ../game/lua_vector.c; $(DO_CC) +lua_cfx.o: lua_cfx.c; $(DO_CC) +lua_cent.o: lua_cent.c; $(DO_CC) +lua_refent.o: lua_refent.c; $(DO_CC); + + +# dependencies from game +q_shared.o: ../game/q_shared.c; $(DO_CC) +q_math.o: ../game/q_math.c; $(DO_CC) +bg_misc.o: ../game/bg_misc.c; $(DO_CC) +bg_pmove.o: ../game/bg_pmove.c; $(DO_CC) +bg_slidemove.o: ../game/bg_slidemove.c; $(DO_CC) + +# cgame syscalls +cg_syscalls.o : cg_syscalls.c; $(DO_CC) + +# lua +lapi.o: ../game/lapi.c; $(DO_LUACC) +lauxlib.o: ../game/lauxlib.c; $(DO_LUACC) +lbaselib.o: ../game/lbaselib.c; $(DO_LUACC) +lbitlib.o: ../game/lbitlib.c; $(DO_LUACC) +lcode.o: ../game/lcode.c; $(DO_LUACC) +lcorolib.o: ../game/lcorolib.c; $(DO_LUACC) +lctype.o: ../game/lctype.c; $(DO_LUACC) +ldblib.o: ../game/ldblib.c; $(DO_LUACC) +ldebug.o: ../game/ldebug.c; $(DO_LUACC) +ldo.o: ../game/ldo.c; $(DO_LUACC) +ldump.o: ../game/ldump.c; $(DO_LUACC) +lfunc.o: ../game/lfunc.c; $(DO_LUACC) +lgc.o: ../game/lgc.c; $(DO_LUACC) +linit.o: ../game/linit.c; $(DO_LUACC) +liolib.o: ../game/liolib.c; $(DO_LUACC) +llex.o: ../game/llex.c; $(DO_LUACC) +lmathlib.o: ../game/lmathlib.c; $(DO_LUACC) +lmem.o: ../game/lmem.c; $(DO_LUACC) +loadlib.o: ../game/loadlib.c; $(DO_LUACC) +lobject.o: ../game/lobject.c; $(DO_LUACC) +lopcodes.o: ../game/lopcodes.c; $(DO_LUACC) +loslib.o: ../game/loslib.c; $(DO_LUACC) +lparser.o: ../game/lparser.c; $(DO_LUACC) +lstate.o: ../game/lstate.c; $(DO_LUACC) +lstring.o: ../game/lstring.c; $(DO_LUACC) +lstrlib.o: ../game/lstrlib.c; $(DO_LUACC) +ltable.o: ../game/ltable.c; $(DO_LUACC) +ltablib.o: ../game/ltablib.c; $(DO_LUACC) +ltm.o: ../game/ltm.c; $(DO_LUACC) +lua.o: ../game/lua.c; $(DO_LUACC) +luac.o: ../game/luac.c; $(DO_LUACC) +lundump.o: ../game/lundump.c; $(DO_LUACC) +lvm.o: ../game/lvm.c; $(DO_LUACC) +lzio.o: ../game/lzio.c; $(DO_LUACC) + +build_so: $(OBJDEP) $(OBJ) $(SOOBJ) $(LUAOBJ) +ifeq ($(PLATFORM), mingw32) + $(CC) -shared -Wl,--export-all-symbols,-soname,cgame$(ARCH).$(EXT) -o cgame$(ARCH).$(EXT) $(OBJ) $(OBJDEP) $(SOOBJ) $(LUAOBJ) -lm +else + $(CC) -shared -Wl,--export-dynamic,-soname,cgame$(ARCH).$(EXT) -o cgame$(ARCH).$(EXT) $(OBJ) $(OBJDEP) $(SOOBJ) $(LUAOBJ) -lm -lpthread +endif + +clean: + rm -f *.o *.$(EXT) diff --git a/code/cgame/Todo.txt b/code/cgame/Todo.txt new file mode 100644 index 0000000..37ecf16 --- /dev/null +++ b/code/cgame/Todo.txt @@ -0,0 +1,3 @@ +- Find and remove unused things +- Run static code analysis and fix things +- Completely debug \ No newline at end of file diff --git a/code/cgame/cg_anims.h b/code/cgame/cg_anims.h new file mode 100644 index 0000000..0709fdf --- /dev/null +++ b/code/cgame/cg_anims.h @@ -0,0 +1,1798 @@ +/* IMPORTED FROM SINGLE PLAYER BY RPG-X J2J */ + +//Quiet the linker problems +#ifndef stringtableforanims +#define stringtableforanims + +//cg_players_c + +#include "../game/q_shared.h" +//#include "../game/bg_public.h" + +//This has to wait till the exe source :-( +/* +//This is New and shiny from single player +typedef enum //# animNumber_e +{ + //================================================= + //ANIMS IN WHICH UPPER AND LOWER OBJECTS ARE IN MD3 + //================================================= + //# #sep BOTH_ DEATHS + BOTH_DEATH1 = 0, //# First Death anim + BOTH_DEATH2, //# Second Death anim + BOTH_DEATH3, //# Third Death anim + BOTH_DEATH4, //# Fourth Death anim + BOTH_DEATH5, //# Fifth Death anim + BOTH_DEATH6, //# Sixth Death anim + BOTH_DEATH7, //# Seventh Death anim + + BOTH_DEATHFORWARD1, //# First Death in which they get thrown forward + BOTH_DEATHFORWARD2, //# Second Death in which they get thrown forward + BOTH_DEATHBACKWARD1, //# First Death in which they get thrown backward + BOTH_DEATHBACKWARD2, //# Second Death in which they get thrown backward + + BOTH_DEATH1IDLE, //# Idle while close to death + BOTH_LYINGDEATH1, //# Death to play when killed lying down + BOTH_STUMBLEDEATH1, //# Stumble forward and fall face first death + BOTH_FALLDEATH1, //# Fall forward off a high cliff and splat death - start + BOTH_FALLDEATH1INAIR, //# Fall forward off a high cliff and splat death - loop + BOTH_FALLDEATH1LAND, //# Fall forward off a high cliff and splat death - hit bottom + //# #sep BOTH_ DEAD POSES # Should be last frame of corresponding previous anims + BOTH_DEAD1, //# First Death finished pose + BOTH_DEAD2, //# Second Death finished pose + BOTH_DEAD3, //# Third Death finished pose + BOTH_DEAD4, //# Fourth Death finished pose + BOTH_DEAD5, //# Fifth Death finished pose + BOTH_DEAD6, //# Sixth Death finished pose + BOTH_DEAD7, //# Seventh Death finished pose + BOTH_DEADFORWARD1, //# First thrown forward death finished pose + BOTH_DEADFORWARD2, //# Second thrown forward death finished pose + BOTH_DEADBACKWARD1, //# First thrown backward death finished pose + BOTH_DEADBACKWARD2, //# Second thrown backward death finished pose + BOTH_LYINGDEAD1, //# Killed lying down death finished pose + BOTH_STUMBLEDEAD1, //# Stumble forward death finished pose + BOTH_FALLDEAD1LAND, //# Fall forward and splat death finished pose + //# #sep BOTH_ DEAD TWITCH/FLOP # React to being shot from death poses + BOTH_DEAD1_FLOP, //# React to being shot from First Death finished pose + BOTH_DEAD2_FLOP, //# React to being shot from Second Death finished pose + BOTH_DEAD3_FLOP, //# React to being shot from Third Death finished pose + BOTH_DEAD4_FLOP, //# React to being shot from Fourth Death finished pose + BOTH_DEAD5_FLOP, //# React to being shot from Fifth Death finished pose + BOTH_DEADFORWARD1_FLOP, //# React to being shot First thrown forward death finished pose + BOTH_DEADFORWARD2_FLOP, //# React to being shot Second thrown forward death finished pose + BOTH_DEADBACKWARD1_FLOP, //# React to being shot First thrown backward death finished pose + BOTH_DEADBACKWARD2_FLOP, //# React to being shot Second thrown backward death finished pose + BOTH_LYINGDEAD1_FLOP, //# React to being shot Killed lying down death finished pose + BOTH_STUMBLEDEAD1_FLOP, //# React to being shot Stumble forward death finished pose + BOTH_FALLDEAD1_FLOP, //# React to being shot Fall forward and splat death finished pose + //# #sep BOTH_ PAINS + BOTH_PAIN1, //# First take pain anim + BOTH_PAIN2, //# Second take pain anim + BOTH_PAIN3, //# Third take pain anim + BOTH_PAIN4, //# Fourth take pain anim + BOTH_PAIN5, //# Fifth take pain anim - from behind + BOTH_PAIN6, //# Sixth take pain anim - from behind + BOTH_PAIN7, //# Seventh take pain anim - from behind + BOTH_PAIN8, //# Eigth take pain anim - from behind + //# #sep BOTH_ ATTACKS + BOTH_ATTACK1, //# Attack with generic 1-handed weapon + BOTH_ATTACK2, //# Attack with generic 2-handed weapon + BOTH_ATTACK3, //# Attack with heavy 2-handed weapon + BOTH_ATTACK4, //# Attack with ??? + BOTH_ATTACK5, //# Attack with rocket launcher + BOTH_MELEE1, //# First melee attack + BOTH_MELEE2, //# Second melee attack + BOTH_MELEE3, //# Third melee attack + BOTH_MELEE4, //# Fourth melee attack + BOTH_MELEE5, //# Fifth melee attack + BOTH_MELEE6, //# Sixth melee attack + //# #sep BOTH_ STANDING + BOTH_STAND1, //# Standing idle, no weapon, hands down + BOTH_STAND1_RANDOM1, //# Random standing idle + BOTH_STAND1_RANDOM2, //# Random standing idle + BOTH_STAND1_RANDOM3, //# Random standing idle + BOTH_STAND1_RANDOM4, //# Random standing idle + BOTH_STAND1_RANDOM5, //# Random standing idle + BOTH_STAND1_RANDOM6, //# Random standing idle + BOTH_STAND1_RANDOM7, //# Random standing idle + BOTH_STAND1_RANDOM8, //# Random standing idle + BOTH_STAND1_RANDOM9, //# Random standing idle + BOTH_STAND1_RANDOM10, //# Random standing idle + BOTH_STAND1_RANDOM11, //# Random standing idle + BOTH_STAND1_RANDOM12, //# Random standing idle + BOTH_STAND1_RANDOM13, //# Random standing idle + BOTH_STAND1_RANDOM14, //# Random standing idle + BOTH_STAND2, //# Standing idle with a weapon + BOTH_STAND2_RANDOM1, //# Random standing idle + BOTH_STAND2_RANDOM2, //# Random standing idle + BOTH_STAND2_RANDOM3, //# Random standing idle + BOTH_STAND2_RANDOM4, //# Random standing idle + BOTH_STAND3, //# Standing hands behind back, at ease, etc. + BOTH_STAND4, //# two handed, gun down, relaxed stand + BOTH_STAND5, //# two handed, gun up, relaxed stand + BOTH_STAND6, //# one handed, gun at side, relaxed stand + BOTH_STAND7, //# (Chell) timid stance while looking around slightly and breathing + BOTH_STAND8, //# breathing after exherting oneself one handed + BOTH_STAND9, //# breathing after exherting oneself two handed + BOTH_STAND1TO3, //# Transition from stand1 to stand3 + BOTH_STAND3TO1, //# Transition from stand3 to stand1 + + BOTH_STAND2TO4, //# Transition from stand2 to stand4 + BOTH_STAND4TO2, //# Transition from stand4 to stand2 + BOTH_STANDTOWALK1, //# Transition from stand1 to walk1 + BOTH_STANDTOCONSOLE1, //# a transition from stand animations to console animations + BOTH_STANDUP1, //# standing up and stumbling + BOTH_TALKGESTURE1, //# standing up and talking + BOTH_TALKGESTURE2, //# standing up and talking + BOTH_TALKGESTURE3, //# standing up and talking + + BOTH_HELP1, //# helping hold injured4 man. + + BOTH_LEAN1, //# leaning on a railing + BOTH_LEAN1TODROPHELM, //# transition from LEAN1 to DROPHELM + + BOTH_CONSOLE1, //# Using a waist-high console with both hands + BOTH_CONSOLE1IDLE, //# Idle of CONSOLE1 + BOTH_CONSOLE1RIGHT, //# Reach right from CONSOLE1 + BOTH_CONSOLE1LEFT, //# Reach left from CONSOLE1 + BOTH_CONSOLE2, //# Using a head-high wall console with the right hand + BOTH_CONSOLE3, //# arms parallel to ground and typing similar to con.1 + BOTH_CONSOLE3IDLE, //# arms parallel to ground and typing similar to con.1 + BOTH_CONSOLE3RIGHT, //# arms parallel to ground and typing similar to con.1 + BOTH_CONSOLE3LEFT, //# arms parallel to ground and typing similar to con.1 + BOTH_CONSOLETOSTAND1, //# a transition from console animations to stand animations + + BOTH_GUARD_LOOKAROUND1, //# Cradling weapon and looking around + BOTH_GUARD_IDLE1, //# Cradling weapon and standing + BOTH_GUARD_LKRT1, //# cin17, quick glance right to sound of door slamming + BOTH_ALERT1, //# Startled by something while on guard + BOTH_GESTURE1, //# Generic gesture, non-specific + BOTH_GESTURE2, //# Generic gesture, non-specific + BOTH_GESTURE3, //# Generic gesture, non-specific + BOTH_CROWDLOOK1, //# Person staring out into space 1 + BOTH_CROWDLOOK2, //# Person staring out into space 2 + BOTH_CROWDLOOK3, //# Person staring out into space 3 + BOTH_CROWDLOOK4, //# Person staring out into space 4 + BOTH_GRAB1, //# Grabbing something from table + BOTH_GRAB2, //# Grabbing something from table + BOTH_GRAB3, //# Grabbing something from table + BOTH_GRABBED1, //# cin9.3 chell being grabbed 180 from munro, 28 pixels away + BOTH_GRABBED2, //# cin9.3 idle grabbed 180 from munro, 28 pixels away + BOTH_SURPRISED1, //# Surprised reaction 1 + BOTH_SURPRISED2, //# Surprised reaction 2 + BOTH_SURPRISED3, //# Surprised reaction 3 + BOTH_SURPRISED4, //# Surprised reaction 4 + BOTH_SURPRISED5, //# Surprised reaction 5 + BOTH_SCARED1, //# Scared reaction 1 + BOTH_SCARED2, //# Scared reaction 2 + BOTH_CATCH1, //# Reaching to catch something falling + BOTH_POSSESSED1, //# 7 of 9 possessed + BOTH_POSSESSED2, //# 7 of 9 possessed with hand out + BOTH_SNAPTO1, //# cin.23, 7o9 coming to from borg possession + BOTH_SNAPTO2, //# cin.23, 7o9 coming to from borg possession2 + BOTH_DROPANGERWEAP2, //# cin.23, Nelson lowering weapon in anger + BOTH_SHOCK1, //# telsia being zapped by electricity cinematic 9.2 + BOTH_PSYCHICSHOCK1, //# having visions of the boss + BOTH_PSYCHICSHOCK2, //# having visions of the boss + BOTH_ASSIMILATED1, //# Cin.18, Foster being assimilated by borg + BOTH_FALSEJUMP1, //# Biessman pretending to jump down on Chell + BOTH_LAUGH1, //# squat pose of Biessman laughing at Chell + BOTH_LAUGH2, //# standing laugh of mocking Biessman + BOTH_ACTIVATEBELT1, //# activating transport buffer on belt + + BOTH_GROUNDSHAKE1, //# Bracing self when ground shakes beneath him + BOTH_GROUNDSHAKE2, //# Falling to knees and shileding self, then standing + + BOTH_READYWEAPON1, //# cin17, comes from greeting, just before fighting + + BOTH_SPAWN1, //# Spawning in to the world + BOTH_TALK1, //# Generic talk anim + + BOTH_COVERUP1_LOOP, //# animation of getting in line of friendly fire + BOTH_COVERUP1_START, //# transitions from stand to coverup1_loop + BOTH_COVERUP1_END, //# transitions from coverup1_loop to stand + BOTH_HEROSTANCE1, //# Biessman in the final shootout + BOTH_GUILT1, //# Player has a guilty conscience after shooting a teammate. + + BOTH_INJURED4, //# Injured pose 4 + BOTH_INJURED4TO5, //# Transition from INJURED4 to INJURED5 + BOTH_INJURED5, //# Injured pose 5 + + //# #sep BOTH_ SITTING/CROUCHING + BOTH_SIT1STAND, //# Stand up from First sitting anim + BOTH_SIT1TO2, //# Trans from sit1 to sit2? + BOTH_SIT1TO3, //# Trans from sit1 to sit3? + BOTH_SIT2TO1, //# Trans from sit2 to sit1? + BOTH_SIT2TO3, //# Trans from sit2 to sit3? + BOTH_SIT3TO1, //# Trans from sit3 to sit1? + BOTH_SIT3TO2, //# Trans from sit3 to sit2? + + BOTH_SIT4TO5, //# Trans from sit4 to sit5 + BOTH_SIT4TO6, //# Trans from sit4 to sit6 + BOTH_SIT5TO4, //# Trans from sit5 to sit4 + BOTH_SIT5TO6, //# Trans from sit5 to sit6 + BOTH_SIT6TO4, //# Trans from sit6 to sit4 + BOTH_SIT6TO5, //# Trans from sit6 to sit5 + BOTH_SIT7, //# sitting with arms over knees, no weapon + BOTH_SIT7TOSTAND1, //# getting up from sit7 into stand1 + + BOTH_TABLE_EAT1, //# Sitting at a table eating + BOTH_TABLE_CHEW1, //# Sitting at a table chewing + BOTH_TABLE_WIPE1, //# Sitting at a table wiping mouth + BOTH_TABLE_DRINK1, //# Sitting at a table drinking + BOTH_TABLE_GETUP1, //# Getting up from table + BOTH_TABLE_DEATH1, //# Dying while sitting at a table + BOTH_TABLE_IDLE1, //# Sitting at table breathing + BOTH_TABLE_TALKGESTURE1,//# Sitting at table gesturing while talking + BOTH_TABLE_GESTURE1, //# Sitting at table gesturing + BOTH_TABLE_GESTURE2, //# Sitting at table gesturing + + BOTH_CROUCH1, //# Transition from standing to crouch + BOTH_CROUCH1IDLE, //# Crouching idle + BOTH_CROUCH1WALK, //# Walking while crouched + BOTH_UNCROUCH1, //# Transition from crouch to standing + BOTH_CROUCH2IDLE, //# crouch and resting on back righ heel, no weapon + BOTH_CROUCH2TOSTAND1, //# going from crouch2 to stand1 + BOTH_GET_UP1, //# Get up from the ground, face down + BOTH_GET_UP2, //# Get up from the ground, face up + + BOTH_BENCHSIT1_IDLE, //# sitting on haz-locker room benches + BOTH_BENCHSIT1TO2, //# Trans from benchsit1 to benchsit2 + BOTH_BENCHSIT2TO1, //# Trans from benchsit2 to benchsit1 + BOTH_BENCHSIT2STAND, //# Trans from benchsit to standing + BOTH_BENCHSIT2_IDLE, //# sitting on haz-locker room benches + BOTH_BENCHSIT1_2STAND, //# getting up to stand from sitting on haz-benches + BOTH_BENCHSIT1_FIXBOOT, //# sitting on bench - pulling on/adjusting boot top + BOTH_BENCHSTAND1TO2, //# transition from stand to benchstand2 + BOTH_BENCHSTAND2, //# standing with right foot up on bench + BOTH_BENCHSTAND2TO1, //# transition from benchstand2 to stand + + BOTH_COUCHSIT1_IDLE, //# sitting in couch - haz lounge area + BOTH_COUCHSIT1_TO2, //# sitting in couch - lean back to 2nd position + BOTH_COUCHSIT1_2STAND1, //# getting up from couchsit1 to stand1 + BOTH_COUCHSIT1_TALKGESTURE, //# sitting in couch - talking with hands + BOTH_COUCHSIT1_GESTURELEFT, //# sitting in couch - talk gesture to the left + BOTH_COUCHSIT1_GESTURERIGHT,//# sitting in couch - talk gesture to the right + + BOTH_KNEELHAND1, //# Jurot puts hand to Munro's face, then pulls away + + //# #sep BOTH_ MOVING + BOTH_WALK1, //# Normal walk + BOTH_WALK2, //# Normal walk + BOTH_WALK3, //# Goes with stand3 + BOTH_WALK4, //# Walk cycle goes to a stand4 + BOTH_WALKTORUN1, //# transition from walk to run + BOTH_RUN1, //# Full run + BOTH_RUN1START, //# Start into full run1 + BOTH_RUN1STOP, //# Stop from full run1 + BOTH_RUN2, //# Full run + BOTH_RUNINJURED1, //# Run with injured left leg + BOTH_STRAFE_LEFT1, //# Sidestep left, should loop + BOTH_STRAFE_RIGHT1, //# Sidestep right, should loop + BOTH_TURN_LEFT1, //# Turn left, should loop + BOTH_TURN_RIGHT1, //# Turn right, should loop + BOTH_RUNAWAY1, //# Running scared + BOTH_SWIM1, //# Swimming + BOTH_JUMP1, //# Jump - wind-up and leave ground + BOTH_INAIR1, //# In air loop (from jump) + BOTH_LAND1, //# Landing (from in air loop) + BOTH_LAND2, //# Landing Hard (from a great height) + BOTH_JUMPBACK1, //# Jump backwards - wind-up and leave ground + BOTH_INAIRBACK1, //# In air loop (from jump back) + BOTH_LANDBACK1, //# Landing backwards(from in air loop) + BOTH_DIVE1, //# Dive! + BOTH_ROLL1_LEFT, //# Roll to left side + BOTH_ROLL1_RIGHT, //# Roll to right side + BOTH_LADDER_UP1, //# Climbing up a ladder with rungs at 16 unit intervals + BOTH_LADDER_DWN1, //# Climbing down a ladder with rungs at 16 unit intervals + BOTH_LADDER_IDLE, //# Just sitting on the ladder + BOTH_ONLADDER_BOT1, //# Getting on the ladder at the bottom + BOTH_OFFLADDER_BOT1, //# Getting off the ladder at the bottom + BOTH_ONLADDER_TOP1, //# Getting on the ladder at the top + BOTH_OFFLADDER_TOP1, //# Getting off the ladder at the top + BOTH_LIFT1, //# Lifting someone/thing over their shoulder + BOTH_STEP1, //# telsia checking out lake cinematic9.2 + BOTH_HITWALL1, //# cin.18, Kenn hit by borg into wall 56 units away + BOTH_AMBUSHLAND1, //# landing from fall on victim + BOTH_BIRTH1, //# birth from jumping through walls + + BOTH_SHIELD1, //# cin.6, munro's initial reaction to explosion + BOTH_SHIELD2, //# cin.6, munro in shielding position looping + BOTH_WALKPUSH1, //# man pushing crate + BOTH_PUSHTOSTAND1, //# man coming from pushing crate to stand1 + BOTH_HALT1, //# munro being grabbed by telsia before going in core room + + //# #sep BOTH_ FLYING IDLE + BOTH_FLY_IDLE1, //# Flying Idle 1 + BOTH_FLY_IDLE2, //# Flying Idle 2 + + + //# #sep BOTH_ FLYING MOVING + BOTH_FLY_START1, //# Start flying + BOTH_FLY_STOP1, //# Stop flying + BOTH_FLY_LOOP1, //# Normal flying, should loop + BOTH_FLOAT1, //# Crew floating through space 1 + BOTH_FLOAT2, //# Crew floating through space 2 + BOTH_FLOATCONSOLE1, //# Crew floating and working on console + + //# #sep BOTH_ LYING + BOTH_LIE_DOWN1, //# From a stand position, get down on ground, face down + BOTH_LIE_DOWN2, //# From a stand position, get down on ground, face up + BOTH_LIE_DOWN3, //# reaction to local disnode being destroyed + BOTH_PAIN2WRITHE1, //# Transition from upright position to writhing on ground anim + BOTH_PRONE2RLEG, //# Lying on ground reach to grab right leg + BOTH_PRONE2LLEG, //# Lying on ground reach to grab left leg + BOTH_WRITHING1, //# Lying on ground on back writhing in pain + BOTH_WRITHING1RLEG, //# Lying on ground writhing in pain, holding right leg + BOTH_WRITHING1LLEG, //# Lying on ground writhing in pain, holding left leg + BOTH_WRITHING2, //# Lying on ground on front writhing in pain + BOTH_INJURED1, //# Lying down, against wall - can also be sleeping against wall + BOTH_INJURED2, //# Injured pose 2 + BOTH_INJURED3, //# Injured pose 3 + BOTH_INJURED6, //# Injured pose 6 + BOTH_INJURED6ATTACKSTART, //# Start attack while in injured 6 pose + BOTH_INJURED6ATTACKSTOP, //# End attack while in injured 6 pose + BOTH_INJURED6COMBADGE, //# Hit combadge while in injured 6 pose + BOTH_INJURED6POINT, //# Chang points to door while in injured state + BOTH_INJUREDTOSTAND1, //# Runinjured to stand1 + + BOTH_CRAWLBACK1, //# Lying on back, crawling backwards with elbows + BOTH_SITWALL1, //# Sitting against a wall + BOTH_SLEEP1, //# laying on back-rknee up-rhand on torso + BOTH_SLEEP2, //# on floor-back against wall-arms crossed + BOTH_SLEEP3, //# Sleeping in a chair + BOTH_SLEEP4, //# Sleeping slumped over table + BOTH_SLEEP5, //# Laying on side sleeping on flat sufrace + BOTH_SLEEP1GETUP, //# alarmed and getting up out of sleep1 pose to stand + BOTH_SLEEP1GETUP2, //# + BOTH_SLEEP2GETUP, //# alarmed and getting up out of sleep2 pose to stand + BOTH_SLEEP3GETUP, //# alarmed and getting up out of sleep3 pose to stand + BOTH_SLEEP3DEATH, //# death in chair, from sleep3 idle + BOTH_SLEEP3DEAD, //# death in chair, from sleep3 idle + + BOTH_SLEEP_IDLE1, //# rub face and nose while asleep from sleep pose 1 + BOTH_SLEEP_IDLE2, //# shift position while asleep - stays in sleep2 + BOTH_SLEEP_IDLE3, //# Idle anim from sleep pose 3 + BOTH_SLEEP_IDLE4, //# Idle anim from sleep pose 4 + BOTH_SLEEP1_NOSE, //# Scratch nose from SLEEP1 pose + BOTH_SLEEP2_SHIFT, //# Shift in sleep from SLEEP2 pose + BOTH_RESTRAINED1, //# Telsia tied to medical table + BOTH_RESTRAINED1POINT, //# Telsia tied to medical table pointing at Munro + BOTH_LIFTED1, //# Fits with BOTH_LIFT1, lifted on shoulder + BOTH_CARRIED1, //# Fits with TORSO_CARRY1, carried over shoulder + BOTH_CARRIED2, //# Laying over object + + //# #sep BOTH_ BORG-SPECIFIC + BOTH_PLUGIN1, //# Borg plugs self in to alcove + BOTH_PLUGGEDIN1, //# Last frame of Borg plug in sequence + BOTH_PLUGOUT1, //# Borg unplugs self from alcove + + //# #sep BOTH_ HUNTER-SEEKER BOT-SPECIFIC + BOTH_POWERUP1, //# Wakes up + + + //================================================= + //ANIMS IN WHICH ONLY THE UPPER OBJECTS ARE IN MD3 + //================================================= + //# #sep TORSO_ WEAPON-RELATED + TORSO_DROPWEAP1, //# Put weapon away + TORSO_DROPWEAP2, //# Put weapon away + TORSO_DROPWEAP3, //# Put weapon away + TORSO_RAISEWEAP1, //# Draw Weapon + TORSO_RAISEWEAP2, //# Draw Weapon + TORSO_RAISEWEAP3, //# Draw Weapon + TORSO_WEAPONREADY1, //# Ready to fire 1 handed weapon + TORSO_WEAPONREADY2, //# Ready to fire 2 handed weapon + TORSO_WEAPONREADY3, //# Ready to fire heavy 2 handed weapon + TORSO_WEAPONIDLE1, //# Holding 1 handed weapon + TORSO_WEAPONIDLE2, //# Holding 2 handed weapon + TORSO_WEAPONIDLE3, //# Holding heavy 2 handed weapon + + //# #sep TORSO_ USING NON-WEAPON OBJECTS + TORSO_TRICORDER1, //# Using a tricorder + TORSO_MEDICORDER1, //# Using a Medical Tricorder + TORSO_PADD1, //# Using a PADD + TORSO_EQUIPMENT1, //# Twisting pipe with both hands + TORSO_EQUIPMENT2, //# Fidgiting with cylinder with both hands + TORSO_EQUIPMENT3, //# Using equipment one handed + TORSO_WRIST1, //# cin.24, Chang detonating bomb with wrist device + + //# #sep TORSO_ MISC + TORSO_COMBADGE1, //# Touch right hand to left breast + TORSO_COMBADGE2, //# Touch left hand to left breast + TORSO_COMBADGE3, //# Combadge touch from stand4 + TORSO_REDALERT1, //# Hitting comm button on wall with hand (Kirk-like) + TORSO_HANDGESTURE1, //# gestures to left one hand + TORSO_HANDGESTURE2, //# gestures to right one hand + TORSO_HANDGESTURE3, //# gestures to the left both hands + TORSO_HANDGESTURE4, //# gestures to the right both hands + TORSO_HANDGESTURE5, //# ? + TORSO_HANDGESTURE6, //# pointing (flank right) while talking & holding a weapon + TORSO_HANDGESTURE7, //# pointing (forward) while talking & holding a weapon + TORSO_HANDGESTURE8, //# pointing (flank left) while talking & holding a weapon + TORSO_HANDGESTURE9, //# quick point right from stand 4 + TORSO_HANDGESTURE10, //# quick point forward from stand 4 + TORSO_HANDGESTURE11, //# quick point left from stand 4 + TORSO_HANDGESTURE12, //# gesturing with both hands forward + TORSO_HANDGESTURE13, //# gesturing a shrug as if not knowing answer + + TORSO_HEADNOD1, //# nod in affirmation + TORSO_HEADSHAKE1, //# head goes down while shaking left and right in dissapointment + TORSO_HYPOSPRAY1, //# man giving hypo to people + TORSO_HYPOSPRAY4, //# using hypospray on telsia in scav5 + + TORSO_HANDEXTEND1, //# doctor reaching for hypospray in scav5 + TORSO_HANDRETRACT1, //# doctor taking hypospray from player in scav5 + + TORSO_DROPHELMET1, //# Drop the helmet to the waist + TORSO_RAISEHELMET1, //# Bring the helmet to the head + TORSO_REACHHELMET1, //# reaching for helmet off of 60 tall cabinet + TORSO_GRABLBACKL, //# reach to lower back with left hand + TORSO_GRABUBACKL, //# reach to upper back with left hand + TORSO_GRABLBACKR, //# reach to lower back with right hand + TORSO_GRABUBACKR, //# reach to upper back with right hand + + TORSO_STAND2TOWEAPONREADY2, //# cin.23, Nelson raising weapon in alarm and ready to fire + + TORSO_HAND1, //# Exchanging items - giver + TORSO_HAND2, //# Exchanging items - receiver + + TORSO_POKERIDLE1, //# holding cards + TORSO_POKERIDLE2, //# re-arranging cards + TORSO_POKERIDLE3, //# put card on table + + TORSO_SPEECHLESS1, //# hanging head in grief 1 + TORSO_SPEECHLESS2, //# hanging head in grief 2 + + TORSO_SHOUT1, //# left hand to mouth + TORSO_CARRY1, //# Carrying someone/thing over their shoulder (can go from BOTH_LIFT1) + + + + //================================================= + //ANIMS IN WHICH ONLY THE LOWER OBJECTS ARE IN MD3 + //================================================= + //# #sep Legs-only anims + LEGS_WALKBACK1, //# Walk1 backwards + LEGS_WALKBACK2, //# Walk2 backwards + LEGS_RUNBACK1, //# Run1 backwards + LEGS_RUNBACK2, //# Run2 backwards + LEGS_TURN1, //# What legs do when you turn your lower body to match your upper body facing + LEGS_TURN2, //# Leg turning from stand2 + LEGS_LEAN_LEFT1, //# Lean left + LEGS_LEAN_RIGHT1, //# Lean Right + LEGS_KNEELDOWN1, //# Get down on one knee? + LEGS_KNEELUP1, //# Get up from one knee? + LEGS_CRLEAN_LEFT1, //# Crouch Lean left + LEGS_CRLEAN_RIGHT1, //# Crouch Lean Right + + //# #eol + MAX_ANIMATIONS, +} animNumber_t; + +*/ + + + +// animations +/*typedef enum { + BOTH_ACTIVATEBELT1, + BOTH_ACTIVATEMEDKIT1, + BOTH_ASSIMILATED1, + BOTH_ATTACK1, + BOTH_ATTACK3, + BOTH_BENCHSIT1TO2, + BOTH_BENCHSIT1_2STAND, + BOTH_BENCHSIT1_FIXBOOT, + BOTH_BENCHSIT1_IDLE, + BOTH_BENCHSIT2STAND, + BOTH_BENCHSIT2TO1, + BOTH_BENCHSTAND2, + BOTH_BENCHSTAND2TO1, + BOTH_CATCH1, + BOTH_CONSOLE1, + BOTH_CONSOLE1IDLE, + BOTH_CONSOLE1LEFT, + BOTH_CONSOLE1RIGHT, + BOTH_CONSOLE2, + BOTH_CONSOLE3, + BOTH_CONSOLE3IDLE, + BOTH_CONSOLE3LEFT, + BOTH_CONSOLE3RIGHT, + BOTH_CONSOLETOSTAND1, + BOTH_COUCHSIT1_2STAND1, + BOTH_COUCHSIT1_GESTURELEFT, + BOTH_COUCHSIT1_GESTURERIGHT, + BOTH_COUCHSIT1_IDLE, + BOTH_COUCHSIT1_TALKGESTURE, + BOTH_CRAWLBACK1, + BOTH_CROUCH1, + BOTH_CROUCH1IDLE, + BOTH_CROUCH1WALK, + BOTH_CROUCH2IDLE, + BOTH_CROUCH2TOSTAND1, + BOTH_CROWDLOOK1, + BOTH_CROWDLOOK2, + BOTH_CROWDLOOK3, + BOTH_CROWDLOOK4, + BOTH_DEATH1, + BOTH_DEAD1, + BOTH_DEATH2, + BOTH_DEAD2, + BOTH_DEATHBACKWARD1, + BOTH_DEADBACKWARD1, + BOTH_DEATHBACKWARD2, + BOTH_DEADBACKWARD2, + BOTH_DEATHFORWARD1, + BOTH_DEADFORWARD1, + BOTH_DEATHFORWARD2, + BOTH_DEADFORWARD2, + BOTH_DIVE1, + BOTH_DROPANGERWEAP2, + BOTH_FALLDEATH1, + BOTH_FALLDEATH1INAIR, + BOTH_FALLDEATH1LAND, + BOTH_FALLDEAD1LAND, + BOTH_FALSEJUMP1, + BOTH_FLOAT1, + BOTH_FLOAT2, + BOTH_FLOATCONSOLE1, + BOTH_GET_UP1, + BOTH_GRAB1, + BOTH_GRAB2, + BOTH_GRABBED1, + BOTH_GRABBED2, + BOTH_GROUNDSHAKE1, + BOTH_GROUNDSHAKE2, + BOTH_GUARD_IDLE1, + BOTH_GUARD_LKRT1, + BOTH_GUARD_LOOKAROUND1, + BOTH_HALT1, + BOTH_HITWALL1, + BOTH_INAIR1, + BOTH_INJURED1, + BOTH_INJURED2, + BOTH_INJURED3, + BOTH_INJURED6, + BOTH_INJURED6ATTACKSTART, + BOTH_INJURED6ATTACKSTOP, + BOTH_INJURED6COMBADGE, + BOTH_JUMP1, + BOTH_LADDER_DWN1, + BOTH_LADDER_UP1, + BOTH_LADDER_IDLE, + BOTH_LAND1, + BOTH_LAUGH1, + BOTH_LAUGH2, + BOTH_LEAN1, + BOTH_LEAN1TODROPHELM, + BOTH_LYINGDEATH1, + BOTH_LYINGDEAD1, + BOTH_OFFLADDER_BOT1, + BOTH_OFFLADDER_TOP1, + BOTH_ONLADDER_BOT1, + BOTH_ONLADDER_TOP1, + BOTH_PAIN1, + BOTH_PAIN2, + BOTH_PAIN2WRITHE1, + BOTH_PSYCHICSHOCK1, + BOTH_PUSHTOSTAND1, + BOTH_RUN1, + BOTH_RUN1STOP, + BOTH_RUN2, + BOTH_RUNINJURED1, + BOTH_SCARED1, + BOTH_SCARED2, + BOTH_SHIELD1, + BOTH_SHIELD2, + BOTH_SIT1STAND, + BOTH_SIT1TO2, + BOTH_SIT1TO3, + BOTH_SIT2TO1, + BOTH_SIT2TO3, + BOTH_SIT3TO1, + BOTH_SIT3TO2, + BOTH_SIT4TO5, + BOTH_SIT4TO6, + BOTH_SIT5TO4, + BOTH_SIT5TO6, + BOTH_SIT6TO4, + BOTH_SIT6TO5, + BOTH_SIT7, + BOTH_SIT7TOSTAND1, + BOTH_STAND1, + BOTH_STAND1_RANDOM1, + BOTH_STAND1_RANDOM11, + BOTH_STAND1_RANDOM12, + BOTH_STAND1_RANDOM13, + BOTH_STAND1_RANDOM2, + BOTH_STAND1_RANDOM3, + BOTH_STAND1_RANDOM4, + BOTH_STAND1_RANDOM5, + BOTH_STAND1_RANDOM6, + BOTH_STAND1_RANDOM7, + BOTH_STAND1_RANDOM8, + BOTH_STAND2TO4, + BOTH_STAND2_RANDOM1, + BOTH_STAND2_RANDOM2, + BOTH_STAND2_RANDOM3, + BOTH_STAND3, + BOTH_STAND4, + BOTH_STAND4TO2, + BOTH_STAND5, + BOTH_STAND6, + BOTH_STAND7, + BOTH_STAND8, + BOTH_STAND9, + BOTH_STANDTOCONSOLE1, + BOTH_STANDTOWALK1, + BOTH_SURPRISED1, + BOTH_SURPRISED2, + BOTH_SURPRISED3, + BOTH_SURPRISED4, + BOTH_TABLE_EAT1, + BOTH_TABLE_GETUP1, + BOTH_TABLE_IDLE1, + BOTH_TABLE_TALKGESTURE1, + BOTH_UNCROUCH1, + BOTH_WALK1, + BOTH_WALK2, + BOTH_WALK4, + BOTH_WALKPUSH1, + BOTH_WALKTORUN1, + BOTH_WRITHING1, + BOTH_INJURED6POINT, + BOTH_COVERUP1_START, + BOTH_COVERUP1_LOOP, + BOTH_COVERUP1_END, + BOTH_GESTURE3, + BOTH_GESTURE2, + BOTH_GESTURE1, + BOTH_SURPRISED5, + BOTH_HEROSTANCE1, + BOTH_BENCHSIT2_IDLE, + BOTH_LANDBACK1, + BOTH_JUMPBACK1, + BOTH_GUILT1, + BOTH_WRITHING2, + BOTH_WALK3, + BOTH_WALK7, + BOTH_STAND2, + TORSO_ATTACK2, + TORSO_WEAPONREADY2, + TORSO_COMBADGE1, + TORSO_COMBADGE2, + TORSO_COMBADGE3, + TORSO_DROPHELMET1, + TORSO_DROPWEAP1, + TORSO_EQUIPMENT1, + TORSO_EQUIPMENT2, + TORSO_GRABLBACKL, + TORSO_HAND1, + TORSO_HAND2, + TORSO_HANDGESTURE1, + TORSO_HANDGESTURE10, + TORSO_HANDGESTURE11, + TORSO_HANDGESTURE12, + TORSO_HANDGESTURE13, + TORSO_HANDGESTURE2, + TORSO_HANDGESTURE3, + TORSO_HANDGESTURE4, + TORSO_HANDGESTURE6, + TORSO_HANDGESTURE7, + TORSO_HANDGESTURE8, + TORSO_HANDGESTURE9, + TORSO_HEADNOD1, + TORSO_HEADSHAKE1, + TORSO_HYPOSPRAY1, + TORSO_MEDICORDER1, + TORSO_POKERIDLE1, + TORSO_POKERIDLE2, + TORSO_POKERIDLE3, + TORSO_RAISEHELMET1, + TORSO_RAISEWEAP1, + TORSO_REACHHELMET1, + TORSO_SHOUT1, + TORSO_SPEECHLESS1, + TORSO_SPEECHLESS2, + TORSO_STAND2TOWEAPONREADY2, + TORSO_TRICORDER1, + TORSO_WEAPONIDLE1, + TORSO_WRIST1, + TORSO_PADD1, + TORSO_WEAPONREADY1, + TORSO_COFFEE, + LEGS_KNEELDOWN1, + LEGS_KNEEL1, + LEGS_KNEELUP1, + LEGS_LEAN_LEFT1, + LEGS_LEAN_RIGHT1, + LEGS_TURN1, + LEGS_TURN2, + LEGS_WALKBACK1, + LEGS_BACK, + + MAX_ANIMATIONS +} animNumber_t;*/ + +typedef enum { + BOTH_ASSIMILATED1=0, + BOTH_ATTACK1, + BOTH_ATTACK2, + BOTH_ATTACK3, + BOTH_BENCHSIT1_2STAND, + BOTH_BENCHSIT1_FIXBOOT, + BOTH_BENCHSIT1_IDLE, + BOTH_BENCHSIT1TO2, + BOTH_BENCHSIT2_IDLE, + BOTH_BENCHSIT2TO1, + BOTH_BENCHSTAND1TO2, + BOTH_BENCHSTAND2, + BOTH_BENCHSTAND2TO1, + BOTH_CATCH1, + BOTH_CONSOLE1, + BOTH_CONSOLE1IDLE, + BOTH_CONSOLE1LEFT, + BOTH_CONSOLE1RIGHT, + BOTH_CONSOLE2, + BOTH_CONSOLE3, + BOTH_CONSOLE3IDLE, + BOTH_CONSOLE3LEFT, + BOTH_CONSOLE3RIGHT, + BOTH_CONSOLE4, + BOTH_CONSOLE5, + BOTH_COUCHSIT1_2STAND1, + BOTH_COUCHSIT1_GESTURELEFT, + BOTH_COUCHSIT1_GESTURERIGHT, + BOTH_COUCHSIT1_IDLE, + BOTH_COUCHSIT1_TALKGESTURE, + BOTH_COUCHSIT1_TO2, + BOTH_COUCHSIT2, + BOTH_COVERUP1_END, + BOTH_COVERUP1_LOOP, + BOTH_COVERUP1_START, + BOTH_COWAR1, + //BOTH_CROUCH1, + BOTH_CROUCH1IDLE, + BOTH_CROUCH1WALK, + BOTH_CROUCH2IDLE, + //BOTH_CROUCH2TOSTAND1, + BOTH_CROWDLOOK1, + BOTH_CROWDLOOK2, + BOTH_CROWDLOOK3, + BOTH_CROWDLOOK4, + //BOTH_DEAD1_FLOP, + //BOTH_DEAD2_FLOP, + //BOTH_DEADBACKWARD1_FLOP, + //BOTH_DEADBACKWARD2_FLOP, + //BOTH_DEADFORWARD1_FLOP, + //BOTH_DEADFORWARD2_FLOP, + BOTH_DEATH1, + BOTH_DEAD1, + BOTH_DEATH2, + BOTH_DEAD2, + BOTH_DEATHBACKWARD1, + BOTH_DEADBACKWARD1, + BOTH_DEATHBACKWARD2, + BOTH_DEADBACKWARD2, + BOTH_DEATHFORWARD1, + BOTH_DEADFORWARD1, + BOTH_DEATHFORWARD2, + BOTH_DEADFORWARD2, + BOTH_DIVE1, + //BOTH_FALLDEAD1_FLOP, + //BOTH_FALLDEATH1, + BOTH_FALLDEATH1INAIR, + BOTH_FALLDEATH1LAND, + BOTH_FALLDEAD1LAND, + BOTH_FLOAT1, + BOTH_FLOAT2, + //BOTH_GESTURE1, + BOTH_GESTURE2, + BOTH_GESTURE3, + BOTH_GET_UP1, + BOTH_GRAB1, + BOTH_GRAB2, + BOTH_GRAB3, + BOTH_GRAB4, + BOTH_GRABBED1, + BOTH_GRABBED2, + BOTH_GROUNDSHAKE1, + BOTH_GROUNDSHAKE1LOOP, + BOTH_GROUNDSHAKE2, + BOTH_GUARD_IDLE1, + BOTH_GUARD_LKRT1, + BOTH_GUARD_LOOKAROUND1, + BOTH_GUILT1, + BOTH_HITWALL1, + BOTH_HELP1, + BOTH_INJURED1, + BOTH_INJURED2, + BOTH_INJURED3, + BOTH_INJURED4, + BOTH_INJURED4TO5, + BOTH_INJURED5, + BOTH_INJURED6, + BOTH_INJURED6COMBADGE, + BOTH_INJURED6POINT, + //BOTH_INJUREDTOSTAND1, + BOTH_JUMP1, + BOTH_JUMPBACK1, + BOTH_KNEELHAND1, + BOTH_LADDER_DWN1, + BOTH_LADDER_UP1, + BOTH_LADDER_IDLE, + BOTH_LAND1, + BOTH_LANDBACK1, + BOTH_LAUGH1, + BOTH_LAUGH2, + BOTH_LEAN1, + //BOTH_LYINGDEAD1_FLOP, + BOTH_LYINGDEATH1, + BOTH_LYINGDEAD1, + BOTH_OFFLADDER_BOT1, + //BOTH_OFFLADDER_TOP1, + BOTH_ONLADDER_BOT1, + //BOTH_ONLADDER_TOP1, + BOTH_PAIN2WRITHE1, + BOTH_POSSESSED1, + BOTH_POSSESSED2, + BOTH_PSYCHICSHOCK1, + BOTH_PSYCHICSHOCK2, + BOTH_RUN1, + BOTH_RUN1STOP, + BOTH_RUN2, + BOTH_RUNAWAY1, + BOTH_RUNINJURED1, + BOTH_SCARED2, + BOTH_SHIELD1, + BOTH_SHIELD2, + BOTH_SIT1STAND, + BOTH_SIT1TO2, + BOTH_SIT1TO3, + BOTH_SIT1, + BOTH_SIT2TO1, + BOTH_SIT2TO3, + BOTH_SIT2, + BOTH_SIT3TO1, + BOTH_SIT3TO2, + BOTH_SIT3, + BOTH_SIT4TO5, + BOTH_SIT4TO6, + BOTH_SIT4, + BOTH_SIT5TO4, + BOTH_SIT5TO6, + BOTH_SIT5, + BOTH_SIT6TO4, + BOTH_SIT6TO5, + BOTH_SIT6, + BOTH_SIT7, + BOTH_SIT7TOSTAND1, + BOTH_SLEEP1, + BOTH_SLEEP1_NOSE, + BOTH_SLEEP1GETUP, + BOTH_SLEEP2, + BOTH_SLEEP2_SHIFT, + BOTH_SLEEP2GETUP, + BOTH_SLEEP3, + BOTH_SLEEP3DEATH, + BOTH_SLEEP3DEAD, + BOTH_SLEEP3GETUP, + BOTH_SNAPTO1, + BOTH_SNAPTO2, + BOTH_STAND1, + //BOTH_STAND1_RANDOM1, + BOTH_STAND1_RANDOM2, + BOTH_STAND1_RANDOM3, + BOTH_STAND1_RANDOM4, + BOTH_STAND1_RANDOM5, + BOTH_STAND1_RANDOM6, + BOTH_STAND1_RANDOM7, + BOTH_STAND1_RANDOM8, + BOTH_STAND1_RANDOM9, + BOTH_STAND1_RANDOM10, + BOTH_STAND1_RANDOM11, + BOTH_STAND2, + BOTH_STAND2_RANDOM1, + BOTH_STAND2_RANDOM2, + BOTH_STAND2_RANDOM3, + BOTH_STAND2_RANDOM4, + BOTH_STAND2_RANDOM5, + BOTH_STAND2_RANDOM6, + BOTH_STAND2_RANDOM7, + BOTH_STAND2_RANDOM8, + BOTH_STAND2_RANDOM9, + BOTH_STAND2_RANDOM10, + BOTH_STAND2_RANDOM11, + BOTH_STAND2_RANDOM12, + BOTH_STAND3, + BOTH_STAND4, + BOTH_STAND5, + BOTH_STAND6, + BOTH_STAND7, + BOTH_STAND8, + BOTH_STAND9, + BOTH_STANDUP1, + BOTH_SURPRISED1, + BOTH_SURPRISED2, + BOTH_SURPRISED3, + BOTH_SURPRISED4, + BOTH_SURPRISED5, + BOTH_TABLE_EAT1, + BOTH_TABLE_GETUP1, + BOTH_TABLE_IDLE1, + BOTH_TABLE_TALKGESTURE1, + BOTH_TALKGESTURE1, + BOTH_TALKGESTURE2, + //BOTH_TALKGESTURE3, + //BOTH_UNCROUCH1, + BOTH_WALK1, + BOTH_WALK2, + BOTH_WALK3, + BOTH_WALK4, + BOTH_WALK7, + BOTH_WRITHING1, + BOTH_SQUIRM1, + BOTH_SQUIRM1GETUP, + BOTH_SHAKE1, + BOTH_SHAKE2, + BOTH_WRITHING2, + TORSO_ACTIVATEMEDKIT1, + TORSO_COFFEE, + TORSO_COMBADGE1, + TORSO_COMBADGE2, + TORSO_COMBADGE3, + TORSO_COMBADGE4, + //TORSO_DROPHELMET1, + TORSO_DROPWEAP1, + TORSO_EQUIPMENT1, + TORSO_EQUIPMENT2, + TORSO_EQUIPMENT3, + TORSO_GRABLBACKL, + TORSO_HAND1, + TORSO_HAND2, + TORSO_HANDGESTURE1, + TORSO_HANDGESTURE2, + TORSO_HANDGESTURE3, + TORSO_HANDGESTURE4, + TORSO_HANDGESTURE5, + TORSO_HANDGESTURE6, + TORSO_HANDGESTURE7, + TORSO_HANDGESTURE8, + TORSO_HANDGESTURE9, + TORSO_HANDGESTURE10, + TORSO_HANDGESTURE11, + TORSO_HANDGESTURE12, + TORSO_HANDGESTURE13, + //TORSO_HEADNOD1, + //TORSO_HEADSHAKE1, + TORSO_HYPO1, + TORSO_HYPOSPRAY1, + TORSO_MEDICORDER1, + TORSO_PADD1, + TORSO_POKERIDLE1, + TORSO_POKERIDLE2, + TORSO_POKERIDLE3, + //TORSO_RAISEHELMET1, + TORSO_RAISEWEAP1, + //TORSO_REACHHELMET1, + TORSO_SHOUT1, + TORSO_SPEECHLESS1, + TORSO_SPEECHLESS2, + TORSO_TALKGESTURE4, + TORSO_TALKGESTURE5, + //TORSO_TALKGESTURE6, + TORSO_TRICORDER1, + TORSO_WEAPONIDLE1, + //TORSO_WEAPONIDLE2, + //TORSO_WEAPONIDLE3, + TORSO_WEAPONREADY1, + TORSO_WEAPONREADY2, + TORSO_WEAPONREADY3, + TORSO_WEAPONPOSE1, + TORSO_WRIST1, + TORSO_GESTURE, + LEGS_KNEEL1, + LEGS_RUNBACK2, + LEGS_TURN1, + LEGS_TURN2, + LEGS_WALKBACK1, + LEGS_SWIM, + + MAX_ANIMATIONS +} animNumber_t; + + +#ifndef cg_players_c +extern stringID_table_t animTable [MAX_ANIMATIONS+1]; +#else +stringID_table_t animTable[MAX_ANIMATIONS+1]= +{ + { ENUM2STRING(BOTH_ASSIMILATED1) }, + { ENUM2STRING(BOTH_ATTACK1) }, + { ENUM2STRING(BOTH_ATTACK2) }, + { ENUM2STRING(BOTH_ATTACK3) }, + { ENUM2STRING(BOTH_BENCHSIT1_2STAND) }, + { ENUM2STRING(BOTH_BENCHSIT1_FIXBOOT) }, + { ENUM2STRING(BOTH_BENCHSIT1_IDLE) }, + { ENUM2STRING(BOTH_BENCHSIT1TO2) }, + { ENUM2STRING(BOTH_BENCHSIT2_IDLE) }, + { ENUM2STRING(BOTH_BENCHSIT2TO1) }, + { ENUM2STRING(BOTH_BENCHSTAND1TO2) }, + { ENUM2STRING(BOTH_BENCHSTAND2) }, + { ENUM2STRING(BOTH_BENCHSTAND2TO1) }, + { ENUM2STRING(BOTH_CATCH1) }, + { ENUM2STRING(BOTH_CONSOLE1) }, + { ENUM2STRING(BOTH_CONSOLE1IDLE) }, + { ENUM2STRING(BOTH_CONSOLE1LEFT) }, + { ENUM2STRING(BOTH_CONSOLE1RIGHT) }, + { ENUM2STRING(BOTH_CONSOLE2) }, + { ENUM2STRING(BOTH_CONSOLE3) }, + { ENUM2STRING(BOTH_CONSOLE3IDLE) }, + { ENUM2STRING(BOTH_CONSOLE3LEFT) }, + { ENUM2STRING(BOTH_CONSOLE3RIGHT) }, + { ENUM2STRING(BOTH_CONSOLE4) }, + { ENUM2STRING(BOTH_CONSOLE5) }, + { ENUM2STRING(BOTH_COUCHSIT1_2STAND1) }, + { ENUM2STRING(BOTH_COUCHSIT1_GESTURELEFT) }, + { ENUM2STRING(BOTH_COUCHSIT1_GESTURERIGHT) }, + { ENUM2STRING(BOTH_COUCHSIT1_IDLE) }, + { ENUM2STRING(BOTH_COUCHSIT1_TALKGESTURE) }, + { ENUM2STRING(BOTH_COUCHSIT1_TO2) }, + { ENUM2STRING(BOTH_COUCHSIT2) }, + { ENUM2STRING(BOTH_COVERUP1_END) }, + { ENUM2STRING(BOTH_COVERUP1_LOOP) }, + { ENUM2STRING(BOTH_COVERUP1_START) }, + { ENUM2STRING(BOTH_COWAR1) }, + { ENUM2STRING(BOTH_CROUCH1IDLE) }, + { ENUM2STRING(BOTH_CROUCH1WALK) }, + { ENUM2STRING(BOTH_CROUCH2IDLE) }, + { ENUM2STRING(BOTH_CROWDLOOK1) }, + { ENUM2STRING(BOTH_CROWDLOOK2) }, + { ENUM2STRING(BOTH_CROWDLOOK3) }, + { ENUM2STRING(BOTH_CROWDLOOK4) }, + { ENUM2STRING(BOTH_DEATH1) }, + { ENUM2STRING(BOTH_DEAD1) }, + { ENUM2STRING(BOTH_DEATH2) }, + { ENUM2STRING(BOTH_DEAD2) }, + { ENUM2STRING(BOTH_DEATHBACKWARD1) }, + { ENUM2STRING(BOTH_DEADBACKWARD1) }, + { ENUM2STRING(BOTH_DEATHBACKWARD2) }, + { ENUM2STRING(BOTH_DEADBACKWARD2) }, + { ENUM2STRING(BOTH_DEATHFORWARD1) }, + { ENUM2STRING(BOTH_DEADFORWARD1) }, + { ENUM2STRING(BOTH_DEATHFORWARD2) }, + { ENUM2STRING(BOTH_DEADFORWARD2) }, + { ENUM2STRING(BOTH_DIVE1) }, + { ENUM2STRING(BOTH_FALLDEATH1INAIR) }, + { ENUM2STRING(BOTH_FALLDEATH1LAND) }, + { ENUM2STRING(BOTH_FALLDEAD1LAND) }, + { ENUM2STRING(BOTH_FLOAT1) }, + { ENUM2STRING(BOTH_FLOAT2) }, + { ENUM2STRING(BOTH_GESTURE2) }, + { ENUM2STRING(BOTH_GESTURE3) }, + { ENUM2STRING(BOTH_GET_UP1) }, + { ENUM2STRING(BOTH_GRAB1) }, + { ENUM2STRING(BOTH_GRAB2) }, + { ENUM2STRING(BOTH_GRAB3) }, + { ENUM2STRING(BOTH_GRAB4) }, + { ENUM2STRING(BOTH_GRABBED1) }, + { ENUM2STRING(BOTH_GRABBED2) }, + { ENUM2STRING(BOTH_GROUNDSHAKE1) }, + { ENUM2STRING(BOTH_GROUNDSHAKE2) }, + { ENUM2STRING(BOTH_GUARD_IDLE1) }, + { ENUM2STRING(BOTH_GUARD_LKRT1) }, + { ENUM2STRING(BOTH_GUARD_LOOKAROUND1) }, + { ENUM2STRING(BOTH_GUILT1) }, + { ENUM2STRING(BOTH_HITWALL1) }, + { ENUM2STRING(BOTH_HELP1) }, + { ENUM2STRING(BOTH_INJURED1) }, + { ENUM2STRING(BOTH_INJURED2) }, + { ENUM2STRING(BOTH_INJURED3) }, + { ENUM2STRING(BOTH_INJURED4) }, + { ENUM2STRING(BOTH_INJURED4TO5) }, + { ENUM2STRING(BOTH_INJURED5) }, + { ENUM2STRING(BOTH_INJURED6) }, + { ENUM2STRING(BOTH_INJURED6COMBADGE) }, + { ENUM2STRING(BOTH_INJURED6POINT) }, + { ENUM2STRING(BOTH_JUMP1) }, + { ENUM2STRING(BOTH_JUMPBACK1) }, + { ENUM2STRING(BOTH_KNEELHAND1) }, + { ENUM2STRING(BOTH_LADDER_DWN1) }, + { ENUM2STRING(BOTH_LADDER_UP1) }, + { ENUM2STRING(BOTH_LADDER_IDLE) }, + { ENUM2STRING(BOTH_LAND1) }, + { ENUM2STRING(BOTH_LANDBACK1) }, + { ENUM2STRING(BOTH_LAUGH1) }, + { ENUM2STRING(BOTH_LAUGH2) }, + { ENUM2STRING(BOTH_LEAN1) }, + { ENUM2STRING(BOTH_LYINGDEATH1) }, + { ENUM2STRING(BOTH_LYINGDEAD1) }, + { ENUM2STRING(BOTH_OFFLADDER_BOT1) }, + { ENUM2STRING(BOTH_ONLADDER_BOT1) }, + { ENUM2STRING(BOTH_PAIN2WRITHE1) }, + { ENUM2STRING(BOTH_POSSESSED1) }, + { ENUM2STRING(BOTH_POSSESSED2) }, + { ENUM2STRING(BOTH_PSYCHICSHOCK1) }, + { ENUM2STRING(BOTH_PSYCHICSHOCK2) }, + { ENUM2STRING(BOTH_RUN1) }, + { ENUM2STRING(BOTH_RUN1STOP) }, + { ENUM2STRING(BOTH_RUN2) }, + { ENUM2STRING(BOTH_RUNAWAY1) }, + { ENUM2STRING(BOTH_RUNINJURED1) }, + { ENUM2STRING(BOTH_SCARED2) }, + { ENUM2STRING(BOTH_SHIELD1) }, + { ENUM2STRING(BOTH_SHIELD2) }, + { ENUM2STRING(BOTH_SIT1STAND) }, + { ENUM2STRING(BOTH_SIT1TO2) }, + { ENUM2STRING(BOTH_SIT1TO3) }, + { ENUM2STRING(BOTH_SIT1) }, + { ENUM2STRING(BOTH_SIT2TO1) }, + { ENUM2STRING(BOTH_SIT2TO3) }, + { ENUM2STRING(BOTH_SIT2) }, + { ENUM2STRING(BOTH_SIT3TO1) }, + { ENUM2STRING(BOTH_SIT3TO2) }, + { ENUM2STRING(BOTH_SIT3) }, + { ENUM2STRING(BOTH_SIT4TO5) }, + { ENUM2STRING(BOTH_SIT4TO6) }, + { ENUM2STRING(BOTH_SIT4) }, + { ENUM2STRING(BOTH_SIT5TO4) }, + { ENUM2STRING(BOTH_SIT5TO6) }, + { ENUM2STRING(BOTH_SIT5) }, + { ENUM2STRING(BOTH_SIT6TO4) }, + { ENUM2STRING(BOTH_SIT6TO5) }, + { ENUM2STRING(BOTH_SIT6) }, + { ENUM2STRING(BOTH_SIT7) }, + { ENUM2STRING(BOTH_SIT7TOSTAND1) }, + { ENUM2STRING(BOTH_SLEEP1) }, + { ENUM2STRING(BOTH_SLEEP1_NOSE) }, + { ENUM2STRING(BOTH_SLEEP1GETUP) }, + { ENUM2STRING(BOTH_SLEEP2) }, + { ENUM2STRING(BOTH_SLEEP2_SHIFT) }, + { ENUM2STRING(BOTH_SLEEP2GETUP) }, + { ENUM2STRING(BOTH_SLEEP3) }, + { ENUM2STRING(BOTH_SLEEP3DEATH) }, + { ENUM2STRING(BOTH_SLEEP3DEAD) }, + { ENUM2STRING(BOTH_SLEEP3GETUP) }, + { ENUM2STRING(BOTH_SNAPTO1) }, + { ENUM2STRING(BOTH_SNAPTO2) }, + { ENUM2STRING(BOTH_STAND1) }, + { ENUM2STRING(BOTH_STAND1_RANDOM2) }, + { ENUM2STRING(BOTH_STAND1_RANDOM3) }, + { ENUM2STRING(BOTH_STAND1_RANDOM4) }, + { ENUM2STRING(BOTH_STAND1_RANDOM5) }, + { ENUM2STRING(BOTH_STAND1_RANDOM6) }, + { ENUM2STRING(BOTH_STAND1_RANDOM7) }, + { ENUM2STRING(BOTH_STAND1_RANDOM8) }, + { ENUM2STRING(BOTH_STAND1_RANDOM9) }, + { ENUM2STRING(BOTH_STAND1_RANDOM10) }, + { ENUM2STRING(BOTH_STAND1_RANDOM11) }, + { ENUM2STRING(BOTH_STAND2) }, + { ENUM2STRING(BOTH_STAND2_RANDOM1) }, + { ENUM2STRING(BOTH_STAND2_RANDOM2) }, + { ENUM2STRING(BOTH_STAND2_RANDOM3) }, + { ENUM2STRING(BOTH_STAND2_RANDOM4) }, + { ENUM2STRING(BOTH_STAND2_RANDOM5) }, + { ENUM2STRING(BOTH_STAND2_RANDOM6) }, + { ENUM2STRING(BOTH_STAND2_RANDOM7) }, + { ENUM2STRING(BOTH_STAND2_RANDOM8) }, + { ENUM2STRING(BOTH_STAND2_RANDOM9) }, + { ENUM2STRING(BOTH_STAND2_RANDOM10) }, + { ENUM2STRING(BOTH_STAND2_RANDOM11) }, + { ENUM2STRING(BOTH_STAND2_RANDOM12) }, + { ENUM2STRING(BOTH_STAND3) }, + { ENUM2STRING(BOTH_STAND4) }, + { ENUM2STRING(BOTH_STAND5) }, + { ENUM2STRING(BOTH_STAND6) }, + { ENUM2STRING(BOTH_STAND7) }, + { ENUM2STRING(BOTH_STAND8) }, + { ENUM2STRING(BOTH_STAND9) }, + { ENUM2STRING(BOTH_STANDUP1) }, + { ENUM2STRING(BOTH_SURPRISED1) }, + { ENUM2STRING(BOTH_SURPRISED2) }, + { ENUM2STRING(BOTH_SURPRISED3) }, + { ENUM2STRING(BOTH_SURPRISED4) }, + { ENUM2STRING(BOTH_SURPRISED5) }, + { ENUM2STRING(BOTH_TABLE_EAT1) }, + { ENUM2STRING(BOTH_TABLE_GETUP1) }, + { ENUM2STRING(BOTH_TABLE_IDLE1) }, + { ENUM2STRING(BOTH_TABLE_TALKGESTURE1) }, + { ENUM2STRING(BOTH_TALKGESTURE1) }, + { ENUM2STRING(BOTH_TALKGESTURE2) }, + { ENUM2STRING(BOTH_WALK1) }, + { ENUM2STRING(BOTH_WALK2) }, + { ENUM2STRING(BOTH_WALK3) }, + { ENUM2STRING(BOTH_WALK4) }, + { ENUM2STRING(BOTH_WALK7) }, + { ENUM2STRING(BOTH_WRITHING1) }, + { ENUM2STRING(BOTH_SQUIRM1) }, + { ENUM2STRING(BOTH_SQUIRM1GETUP) }, + { ENUM2STRING(BOTH_SHAKE1) }, + { ENUM2STRING(BOTH_SHAKE2) }, + { ENUM2STRING(BOTH_WRITHING2) }, + { ENUM2STRING(TORSO_ACTIVATEMEDKIT1) }, + { ENUM2STRING(TORSO_COFFEE) }, + { ENUM2STRING(TORSO_COMBADGE1) }, + { ENUM2STRING(TORSO_COMBADGE2) }, + { ENUM2STRING(TORSO_COMBADGE3) }, + { ENUM2STRING(TORSO_COMBADGE4) }, + { ENUM2STRING(TORSO_DROPWEAP1) }, + { ENUM2STRING(TORSO_EQUIPMENT1) }, + { ENUM2STRING(TORSO_EQUIPMENT2) }, + { ENUM2STRING(TORSO_EQUIPMENT3) }, + { ENUM2STRING(TORSO_GRABLBACKL) }, + { ENUM2STRING(TORSO_HAND1) }, + { ENUM2STRING(TORSO_HAND2) }, + { ENUM2STRING(TORSO_HANDGESTURE1) }, + { ENUM2STRING(TORSO_HANDGESTURE2) }, + { ENUM2STRING(TORSO_HANDGESTURE3) }, + { ENUM2STRING(TORSO_HANDGESTURE4) }, + { ENUM2STRING(TORSO_HANDGESTURE5) }, + { ENUM2STRING(TORSO_HANDGESTURE6) }, + { ENUM2STRING(TORSO_HANDGESTURE7) }, + { ENUM2STRING(TORSO_HANDGESTURE8) }, + { ENUM2STRING(TORSO_HANDGESTURE9) }, + { ENUM2STRING(TORSO_HANDGESTURE10) }, + { ENUM2STRING(TORSO_HANDGESTURE11) }, + { ENUM2STRING(TORSO_HANDGESTURE12) }, + { ENUM2STRING(TORSO_HANDGESTURE13) }, + { ENUM2STRING(TORSO_HYPO1) }, + { ENUM2STRING(TORSO_HYPOSPRAY1) }, + { ENUM2STRING(TORSO_MEDICORDER1) }, + { ENUM2STRING(TORSO_PADD1) }, + { ENUM2STRING(TORSO_POKERIDLE1) }, + { ENUM2STRING(TORSO_POKERIDLE2) }, + { ENUM2STRING(TORSO_POKERIDLE3) }, + { ENUM2STRING(TORSO_RAISEWEAP1) }, + { ENUM2STRING(TORSO_SHOUT1) }, + { ENUM2STRING(TORSO_SPEECHLESS1) }, + { ENUM2STRING(TORSO_SPEECHLESS2) }, + { ENUM2STRING(TORSO_TALKGESTURE4) }, + { ENUM2STRING(TORSO_TALKGESTURE5) }, + { ENUM2STRING(TORSO_TRICORDER1) }, + { ENUM2STRING(TORSO_WEAPONIDLE1) }, + { ENUM2STRING(TORSO_WEAPONREADY1) }, + { ENUM2STRING(TORSO_WEAPONREADY2) }, + { ENUM2STRING(TORSO_WEAPONREADY3) }, + { ENUM2STRING(TORSO_WEAPONPOSE1) }, + { ENUM2STRING(TORSO_WRIST1) }, + { ENUM2STRING(TORSO_GESTURE) }, + { ENUM2STRING(LEGS_KNEEL1) }, + { ENUM2STRING(LEGS_RUNBACK2) }, + { ENUM2STRING(LEGS_TURN1) }, + { ENUM2STRING(LEGS_TURN2) }, + { ENUM2STRING(LEGS_WALKBACK1) }, + { ENUM2STRING(LEGS_SWIM) }, + { NULL, -1 } +}; + +/* +typedef enum { + BOTH_DEATH1, + BOTH_DEAD1, + BOTH_DEATH2, + BOTH_DEAD2, + BOTH_DEATH3, + BOTH_DEAD3, + + TORSO_GESTURE, + + TORSO_ATTACK, + TORSO_ATTACK2, + + TORSO_DROP, + TORSO_RAISE, + + TORSO_STAND, + TORSO_STAND2, + + LEGS_WALKCR, + LEGS_WALK, + LEGS_RUN, + LEGS_BACK, + LEGS_SWIM, + + LEGS_JUMP, + LEGS_LAND, + + LEGS_JUMPB, + LEGS_LANDB, + + LEGS_IDLE, + LEGS_IDLECR, + + LEGS_TURN, + + MAX_ANIMATIONS +} animNumber_t; +*/ + +#endif + + +//RPG-X: J2J - Added to help solve LNK2005 errors (special case for cg_players.c) +//#ifndef cg_players_c +/* +extern stringID_table_t animTable [MAX_ANIMATIONS+1]; + +#else +///////////////////////////////////////////////////////////////////////////////// + +//And this is used to load in the animation.cfg file. +stringID_table_t animTable [MAX_ANIMATIONS+1] = +{ + //================================================= + //ANIMS IN WHICH UPPER AND LOWER OBJECTS ARE IN MD3 + //================================================= + //# DEATHS + ENUM2STRING(BOTH_DEATH1), //# First Death anim + ENUM2STRING(BOTH_DEATH2), //# Second Death anim + ENUM2STRING(BOTH_DEATH3), //# Third Death anim + ENUM2STRING(BOTH_DEATH4), //# Fourth Death anim + ENUM2STRING(BOTH_DEATH5), //# Fifth Death anim + ENUM2STRING(BOTH_DEATH6), //# Sixth Death anim + ENUM2STRING(BOTH_DEATH7), //# Seventh Death anim + + ENUM2STRING(BOTH_DEATH1IDLE), //# Idle while close to death + + ENUM2STRING(BOTH_DEATHFORWARD1), //# First Death in which they get thrown forward + ENUM2STRING(BOTH_DEATHFORWARD2), //# Second Death in which they get thrown forward + ENUM2STRING(BOTH_DEATHBACKWARD1), //# First Death in which they get thrown backward + ENUM2STRING(BOTH_DEATHBACKWARD2), //# Second Death in which they get thrown backward + ENUM2STRING(BOTH_LYINGDEATH1), //# Death to play when killed lying down + ENUM2STRING(BOTH_STUMBLEDEATH1), //# Stumble forward and fall face first death + ENUM2STRING(BOTH_FALLDEATH1), //# Fall forward off a high cliff and splat death - start + ENUM2STRING(BOTH_FALLDEATH1INAIR), //# Fall forward off a high cliff and splat death - loop + ENUM2STRING(BOTH_FALLDEATH1LAND), //# Fall forward off a high cliff and splat death - hit bottom + //# DEAD POSES # Should be last frame of corresponding previous anims + ENUM2STRING(BOTH_DEAD1), //# First Death finished pose + ENUM2STRING(BOTH_DEAD2), //# Second Death finished pose + ENUM2STRING(BOTH_DEAD3), //# Third Death finished pose + ENUM2STRING(BOTH_DEAD4), //# Fourth Death finished pose + ENUM2STRING(BOTH_DEAD5), //# Fifth Death finished pose + ENUM2STRING(BOTH_DEAD6), //# Sixth Death finished pose + ENUM2STRING(BOTH_DEAD7), //# Seventh Death finished pose + ENUM2STRING(BOTH_DEADFORWARD1), //# First thrown forward death finished pose + ENUM2STRING(BOTH_DEADFORWARD2), //# Second thrown forward death finished pose + ENUM2STRING(BOTH_DEADBACKWARD1), //# First thrown backward death finished pose + ENUM2STRING(BOTH_DEADBACKWARD2), //# Second thrown backward death finished pose + ENUM2STRING(BOTH_LYINGDEAD1), //# Killed lying down death finished pose + ENUM2STRING(BOTH_STUMBLEDEAD1), //# Stumble forward death finished pose + ENUM2STRING(BOTH_FALLDEAD1LAND), //# Fall forward and splat death finished pose + //# #sep BOTH_ DEAD TWITCH/FLOP # React to being shot from death poses + ENUM2STRING(BOTH_DEAD1_FLOP), //# React to being shot from First Death finished pose + ENUM2STRING(BOTH_DEAD2_FLOP), //# React to being shot from Second Death finished pose + ENUM2STRING(BOTH_DEAD3_FLOP), //# React to being shot from Third Death finished pose + ENUM2STRING(BOTH_DEAD4_FLOP), //# React to being shot from Fourth Death finished pose + ENUM2STRING(BOTH_DEAD5_FLOP), //# React to being shot from Fifth Death finished pose + ENUM2STRING(BOTH_DEADFORWARD1_FLOP), //# React to being shot First thrown forward death finished pose + ENUM2STRING(BOTH_DEADFORWARD2_FLOP), //# React to being shot Second thrown forward death finished pose + ENUM2STRING(BOTH_DEADBACKWARD1_FLOP), //# React to being shot First thrown backward death finished pose + ENUM2STRING(BOTH_DEADBACKWARD2_FLOP), //# React to being shot Second thrown backward death finished pose + ENUM2STRING(BOTH_LYINGDEAD1_FLOP), //# React to being shot Killed lying down death finished pose + ENUM2STRING(BOTH_STUMBLEDEAD1_FLOP), //# React to being shot Stumble forward death finished pose + ENUM2STRING(BOTH_FALLDEAD1_FLOP), //# React to being shot Fall forward and splat death finished pose + + //# PAINS + ENUM2STRING(BOTH_PAIN1), //# First take pain anim + ENUM2STRING(BOTH_PAIN2), //# Second take pain anim + ENUM2STRING(BOTH_PAIN3), //# Third take pain anim + ENUM2STRING(BOTH_PAIN4), //# First take pain anim + ENUM2STRING(BOTH_PAIN5), //# Second take pain anim + ENUM2STRING(BOTH_PAIN6), //# Third take pain anim + ENUM2STRING(BOTH_PAIN7), //# First take pain anim + ENUM2STRING(BOTH_PAIN8), //# Second take pain anim + + //# ATTACKS + ENUM2STRING(BOTH_ATTACK1), //# Attack with generic 1-handed weapon + ENUM2STRING(BOTH_ATTACK2), //# Attack with generic 2-handed weapon + ENUM2STRING(BOTH_ATTACK3), //# + ENUM2STRING(BOTH_ATTACK4), //# Attack with ??? + ENUM2STRING(BOTH_ATTACK5), //# Attack with rocket launcher + + ENUM2STRING(BOTH_MELEE1), //# First melee attack + ENUM2STRING(BOTH_MELEE2), //# Second melee attack + ENUM2STRING(BOTH_MELEE3), //# Third melee attack + ENUM2STRING(BOTH_MELEE4), //# Fourth melee attack + ENUM2STRING(BOTH_MELEE5), //# Fifth melee attack + ENUM2STRING(BOTH_MELEE6), //# Sixth melee attack + + //# STANDING + ENUM2STRING(BOTH_STAND1), //# Standing idle 1 + ENUM2STRING(BOTH_STAND1_RANDOM1), //# Random standing idle + ENUM2STRING(BOTH_STAND1_RANDOM2), //# Random standing idle + ENUM2STRING(BOTH_STAND1_RANDOM3), //# Random standing idle + ENUM2STRING(BOTH_STAND1_RANDOM4), //# Random standing idle + ENUM2STRING(BOTH_STAND1_RANDOM5), //# Random standing idle + ENUM2STRING(BOTH_STAND1_RANDOM6), //# Random standing idle + ENUM2STRING(BOTH_STAND1_RANDOM7), //# Random standing idle + ENUM2STRING(BOTH_STAND1_RANDOM8), //# Random standing idle + ENUM2STRING(BOTH_STAND1_RANDOM9), //# Random standing idle + ENUM2STRING(BOTH_STAND1_RANDOM10), //# Random standing idle + ENUM2STRING(BOTH_STAND1_RANDOM11), //# Random standing idle + ENUM2STRING(BOTH_STAND1_RANDOM12), //# Random standing idle + ENUM2STRING(BOTH_STAND1_RANDOM13), //# Random standing idle + ENUM2STRING(BOTH_STAND1_RANDOM14), //# Random standing idle + ENUM2STRING(BOTH_STAND2), //# Standing idle 2 + ENUM2STRING(BOTH_STAND2_RANDOM1), //# Random standing idle + ENUM2STRING(BOTH_STAND2_RANDOM2), //# Random standing idle + ENUM2STRING(BOTH_STAND2_RANDOM3), //# Random standing idle + ENUM2STRING(BOTH_STAND2_RANDOM4), //# Random standing idle + + ENUM2STRING(BOTH_STAND3), //# Standing idle 3 + ENUM2STRING(BOTH_STAND4), //# two handed, gun down, relaxed stand + ENUM2STRING(BOTH_STAND5), //# two handed, gun up, relaxed stand + ENUM2STRING(BOTH_STAND6), //# one handed, gun at side, relaxed stand + ENUM2STRING(BOTH_STAND7), //# (Chell) timid stance while looking around slightly and breathing + ENUM2STRING(BOTH_STAND8), //# breathing after exherting oneself one handed + ENUM2STRING(BOTH_STAND9), //# breathing after exherting oneself two handed + ENUM2STRING(BOTH_STAND1TO3), //# Transition from stand1 to stand3 + ENUM2STRING(BOTH_STAND3TO1), //# Transition from stand3 to stand1 + + ENUM2STRING(BOTH_STAND2TO4), //# Transition from stand2 to stand4 + ENUM2STRING(BOTH_STAND4TO2), //# Transition from stand4 to stand2 + ENUM2STRING(BOTH_STANDTOWALK1), //# Transition from stand1 to walk1 + ENUM2STRING(BOTH_STANDTOCONSOLE1), //# a transition from stand animations to console animations + ENUM2STRING(BOTH_STANDUP1), //# standing up and stumbling + ENUM2STRING(BOTH_TALKGESTURE1), //# standing up and talking + ENUM2STRING(BOTH_TALKGESTURE2), //# standing up and talking + ENUM2STRING(BOTH_TALKGESTURE3), //# standing up and talking + + ENUM2STRING(BOTH_HELP1), //# helping hold injured4 man. + + ENUM2STRING(BOTH_LEAN1), //# leaning on a railing + ENUM2STRING(BOTH_LEAN1TODROPHELM), //# transition from LEAN1 to DROPHELM + + ENUM2STRING(BOTH_CONSOLE1), //# Using a waist-high console with both hands + ENUM2STRING(BOTH_CONSOLE1IDLE), //# Idle of CONSOLE1 + ENUM2STRING(BOTH_CONSOLE1RIGHT), //# Reach right from CONSOLE1 + ENUM2STRING(BOTH_CONSOLE1LEFT), //# Reach left from CONSOLE1 + ENUM2STRING(BOTH_CONSOLE2), //# Using a head-high wall console with the right hand + ENUM2STRING(BOTH_CONSOLE3), //# arms parallel to ground and typing similar to con.1 + ENUM2STRING(BOTH_CONSOLE3IDLE), //# arms parallel to ground and typing similar to con.1 + ENUM2STRING(BOTH_CONSOLE3RIGHT), //# arms parallel to ground and typing similar to con.1 + ENUM2STRING(BOTH_CONSOLE3LEFT), //# arms parallel to ground and typing similar to con.1 + ENUM2STRING(BOTH_CONSOLETOSTAND1), //# a transition from console animations to stand animations + + ENUM2STRING(BOTH_GUARD_LOOKAROUND1),//# Cradling weapon and looking around + ENUM2STRING(BOTH_GUARD_IDLE1), //# Cradling weapon and standing + ENUM2STRING(BOTH_GUARD_LKRT1), //# cin17, quick glance right to sound of door slamming + + ENUM2STRING(BOTH_ALERT1), //# Startled by something when on guard + ENUM2STRING(BOTH_GESTURE1), //# Generic gesture, non-specific + ENUM2STRING(BOTH_GESTURE2), //# Generic gesture, non-specific + ENUM2STRING(BOTH_GESTURE3), //# Generic gesture, non-specific + + ENUM2STRING(BOTH_CROWDLOOK1), //# Person staring out into space 1 + ENUM2STRING(BOTH_CROWDLOOK2), //# Person staring out into space 2 + ENUM2STRING(BOTH_CROWDLOOK3), //# Person staring out into space 3 + ENUM2STRING(BOTH_CROWDLOOK4), //# Person staring out into space 4 + ENUM2STRING(BOTH_GRAB1), //# Grabbing something from table + ENUM2STRING(BOTH_GRAB2), //# Grabbing something + ENUM2STRING(BOTH_GRAB3), //# Grabbing something + + ENUM2STRING(BOTH_GRABBED1), //# cin9.3 chell being grabbed 180 from munro, 28 pixels away + ENUM2STRING(BOTH_GRABBED2), //# cin9.3 idle grabbed 180 from munro, 28 pixels away + + ENUM2STRING(BOTH_SURPRISED1), //# Surprised reaction 1 + ENUM2STRING(BOTH_SURPRISED2), //# Surprised reaction 2 + ENUM2STRING(BOTH_SURPRISED3), //# Surprised reaction 3 + ENUM2STRING(BOTH_SURPRISED4), //# Surprised reaction 4 + ENUM2STRING(BOTH_SURPRISED5), //# Surprised reaction 5 + + ENUM2STRING(BOTH_SCARED1), //# Scared reaction 1 + ENUM2STRING(BOTH_SCARED2), //# Scared reaction 2 + ENUM2STRING(BOTH_CATCH1), //# Reaching to catch something falling + ENUM2STRING(BOTH_POSSESSED1), //# 7 of 9 possessed + ENUM2STRING(BOTH_POSSESSED2), //# 7 of 9 possessed with hand out + + ENUM2STRING(BOTH_SNAPTO1), //# cin.23, 7o9 coming to from borg possession + ENUM2STRING(BOTH_SNAPTO2), //# cin.23, 7o9 coming to from borg possession2 + ENUM2STRING(BOTH_DROPANGERWEAP2), //# cin.23, Nelson lowering weapon in anger + ENUM2STRING(BOTH_SHOCK1), //# telsia being zapped by electricity cinematic 9.2 + + ENUM2STRING(BOTH_PSYCHICSHOCK1), //# having visions of the boss + ENUM2STRING(BOTH_PSYCHICSHOCK2), //# having visions of the boss + ENUM2STRING(BOTH_ASSIMILATED1), //# Cin.18, Foster being assimilated by borg + ENUM2STRING(BOTH_FALSEJUMP1), //# Biessman pretending to jump down on Chell + ENUM2STRING(BOTH_LAUGH1), //# squat pose of Biessman laughing at Chell + ENUM2STRING(BOTH_LAUGH2), //# standing laugh of mocking Biessman + ENUM2STRING(BOTH_ACTIVATEBELT1), //# activating transport buffer on belt + + ENUM2STRING(BOTH_GROUNDSHAKE1), //# Bracing self when ground shakes beneath him + ENUM2STRING(BOTH_GROUNDSHAKE2), //# Falling to knees and shileding self, then standing + + ENUM2STRING(BOTH_READYWEAPON1), //# cin17, comes from greeting, just before fighting + + ENUM2STRING(BOTH_SPAWN1), //# Spawning in to the world + ENUM2STRING(BOTH_TALK1), //# Generic talk anim + + ENUM2STRING(BOTH_COVERUP1_LOOP), //# animation of getting in line of friendly fire + ENUM2STRING(BOTH_COVERUP1_START), //# transitions from stand to coverup1_loop + ENUM2STRING(BOTH_COVERUP1_END), //# transitions from coverup1_loop to stand + ENUM2STRING(BOTH_HEROSTANCE1), //# Biessman in the final shootout + ENUM2STRING(BOTH_GUILT1), //# Player has a guilty conscience after shooting a teammate. + + //# SITTING/CROUCHING + ENUM2STRING(BOTH_SIT1STAND), //# Stand up from First sitting anim + ENUM2STRING(BOTH_SIT1TO2), //# Trans from sit1 to sit2? + ENUM2STRING(BOTH_SIT1TO3), //# Trans from sit1 to sit3? + ENUM2STRING(BOTH_SIT2TO1), //# Trans from sit2 to sit1? + ENUM2STRING(BOTH_SIT2TO3), //# Trans from sit2 to sit3? + ENUM2STRING(BOTH_SIT3TO1), //# Trans from sit3 to sit1? + ENUM2STRING(BOTH_SIT3TO2), //# Trans from sit3 to sit2? + + ENUM2STRING(BOTH_SIT4TO5), //# Trans from sit4 to sit5 + ENUM2STRING(BOTH_SIT4TO6), //# Trans from sit4 to sit6 + ENUM2STRING(BOTH_SIT5TO4), //# Trans from sit5 to sit4 + ENUM2STRING(BOTH_SIT5TO6), //# Trans from sit5 to sit6 + ENUM2STRING(BOTH_SIT6TO4), //# Trans from sit6 to sit4 + ENUM2STRING(BOTH_SIT6TO5), //# Trans from sit6 to sit5 + + ENUM2STRING(BOTH_SIT7), //# sitting with arms over knees, no weapon + ENUM2STRING(BOTH_SIT7TOSTAND1), //# getting up from sit7 into stand1 + + ENUM2STRING(BOTH_TABLE_EAT1), //# Sitting at a table eating + ENUM2STRING(BOTH_TABLE_CHEW1), //# Sitting at a table chewing + ENUM2STRING(BOTH_TABLE_WIPE1), //# Sitting at a table wiping mouth + ENUM2STRING(BOTH_TABLE_DRINK1), //# Sitting at a table drinking + ENUM2STRING(BOTH_TABLE_GETUP1), //# Getting up from table + ENUM2STRING(BOTH_TABLE_DEATH1), //# Dying while sitting at a table + ENUM2STRING(BOTH_TABLE_IDLE1), //# Sitting at table breathing + ENUM2STRING(BOTH_TABLE_TALKGESTURE1), //# Sitting at table gesturing while talking + ENUM2STRING(BOTH_TABLE_GESTURE1), //# Sitting at table gesturing + ENUM2STRING(BOTH_TABLE_GESTURE2), //# Sitting at table gesturing + + ENUM2STRING(BOTH_CROUCH1), //# Transition from standing to crouch + ENUM2STRING(BOTH_CROUCH1IDLE), //# Crouching idle + ENUM2STRING(BOTH_CROUCH1WALK), //# Walking while crouched + ENUM2STRING(BOTH_UNCROUCH1), //# Transition from crouch to standing + ENUM2STRING(BOTH_CROUCH2IDLE), //# crouch and resting on back righ heel, no weapon + ENUM2STRING(BOTH_CROUCH2TOSTAND1), //# going from crouch2 to stand1 + ENUM2STRING(BOTH_GET_UP1), //# Get up from ground, face down + ENUM2STRING(BOTH_GET_UP2), //# Get up from ground, face up + + ENUM2STRING(BOTH_BENCHSIT1_IDLE), //# sitting on haz-locker room benches + ENUM2STRING(BOTH_BENCHSIT1TO2), //# Trans from benchsit1 to benchsit2 + ENUM2STRING(BOTH_BENCHSIT2TO1), //# Trans from benchsit2 to benchsit1 + ENUM2STRING(BOTH_BENCHSIT2STAND), //# Trans from benchsit to standing + ENUM2STRING(BOTH_BENCHSIT2_IDLE), //# sitting on haz-locker room benches + ENUM2STRING(BOTH_BENCHSIT1_2STAND), //# getting up to stand from sitting on haz-benches + ENUM2STRING(BOTH_BENCHSIT1_FIXBOOT),//# sitting on bench - pulling on/adjusting boot top + ENUM2STRING(BOTH_BENCHSTAND1TO2), //# transition from stand to benchstand2 + ENUM2STRING(BOTH_BENCHSTAND2), //# standing with right foot up on bench + ENUM2STRING(BOTH_BENCHSTAND2TO1), //# transition from benchstand2 to stand + + ENUM2STRING(BOTH_COUCHSIT1_IDLE), //# sitting in couch - haz lounge area + ENUM2STRING(BOTH_COUCHSIT1_TO2), //# sitting in couch - lean back to 2nd position + ENUM2STRING(BOTH_COUCHSIT1_2STAND1),//# getting up from couchsit1 to stand1 + ENUM2STRING(BOTH_COUCHSIT1_TALKGESTURE),//# sitting in couch - talking with hands + ENUM2STRING(BOTH_COUCHSIT1_GESTURELEFT),//# sitting in couch - talk gesture to the left + ENUM2STRING(BOTH_COUCHSIT1_GESTURERIGHT),//# sitting in couch - talk gesture to the right + ENUM2STRING(BOTH_KNEELHAND1), //# Jurot puts hand to Munro's face, then pulls away + ENUM2STRING(BOTH_HALT1), //# munro being grabbed by telsia before going in core room + + //# MOVING + ENUM2STRING(BOTH_WALK1), //# Normal walk + ENUM2STRING(BOTH_WALK2), //# Normal walk + ENUM2STRING(BOTH_WALK3), //# Goes with stand 3 + ENUM2STRING(BOTH_WALK4), //# Walk cycle goes to a stand4 + ENUM2STRING(BOTH_WALKTORUN1), //# transition from walk to run + + ENUM2STRING(BOTH_RUN1), //# Full run + ENUM2STRING(BOTH_RUN1START), //# Start into full run1 + ENUM2STRING(BOTH_RUN1STOP), //# Stop from full run1 + ENUM2STRING(BOTH_RUN2), //# Full run + ENUM2STRING(BOTH_RUNINJURED1), //# Run with injured left leg + ENUM2STRING(BOTH_STRAFE_LEFT1), //# Sidestep left, should loop + ENUM2STRING(BOTH_STRAFE_RIGHT1), //# Sidestep right, should loop + ENUM2STRING(BOTH_TURN_LEFT1), //# Turn left, should loop + ENUM2STRING(BOTH_TURN_RIGHT1), //# Turn right, should loop + ENUM2STRING(BOTH_RUNAWAY1), //# Runningf scared + ENUM2STRING(BOTH_SWIM1), //# Swimming + ENUM2STRING(BOTH_JUMP1), //# Jump - wind-up and leave ground + ENUM2STRING(BOTH_INAIR1), //# In air loop (from jump) + ENUM2STRING(BOTH_LAND1), //# Landing (from in air loop) + ENUM2STRING(BOTH_LAND2), //# Landing Hard (from a great height) + + ENUM2STRING(BOTH_JUMPBACK1), //# Jump - wind-up and leave ground + ENUM2STRING(BOTH_INAIRBACK1), //# In air loop (from jump) + ENUM2STRING(BOTH_LANDBACK1), //# Landing (from in air loop) + ENUM2STRING(BOTH_DIVE1), //# Dive! + ENUM2STRING(BOTH_ROLL1_LEFT), //# Roll to left side + ENUM2STRING(BOTH_ROLL1_RIGHT), //# Roll to right side + ENUM2STRING(BOTH_LADDER_UP1), //# Climbing up a ladder with rungs at 16 unit intervals + ENUM2STRING(BOTH_LADDER_DWN1), //# Climbing down a ladder with rungs at 16 unit intervals + ENUM2STRING(BOTH_LADDER_IDLE), //# Holding onto ladder + ENUM2STRING(BOTH_ONLADDER_BOT1), //# Getting on the ladder at the bottom + ENUM2STRING(BOTH_OFFLADDER_BOT1), //# Getting off the ladder at the bottom + ENUM2STRING(BOTH_ONLADDER_TOP1), //# Getting on the ladder at the top + ENUM2STRING(BOTH_OFFLADDER_TOP1), //# Getting off the ladder at the top + ENUM2STRING(BOTH_LIFT1), //# Lifting someone/thing over their shoulder + ENUM2STRING(BOTH_STEP1), //# telsia checking out lake cinematic9.2 + ENUM2STRING(BOTH_HITWALL1), //# cin.18, Kenn hit by borg into wall 56 units away + ENUM2STRING(BOTH_AMBUSHLAND1), //# landing from fall on victim + ENUM2STRING(BOTH_BIRTH1), //# birth from jumping through walls + + ENUM2STRING(BOTH_SHIELD1), //# cin.6, munro's initial reaction to explosion + ENUM2STRING(BOTH_SHIELD2), //# cin.6, munro in shielding position looping + ENUM2STRING(BOTH_WALKPUSH1), //# man pushing crate + ENUM2STRING(BOTH_PUSHTOSTAND1), //# man coming from pushing crate to stand1 + + //# FLY - IDLE + ENUM2STRING(BOTH_FLY_IDLE1), //# Idle while flying + ENUM2STRING(BOTH_FLY_IDLE2), //# Idle while flying + + //# FLY - MOVING + ENUM2STRING(BOTH_FLY_START1), //# Start flying + ENUM2STRING(BOTH_FLY_STOP1), //# Stop flying + ENUM2STRING(BOTH_FLY_LOOP1), //# Normal flying, should loop + + ENUM2STRING(BOTH_FLOAT1), //# Crew floating through space 1 + ENUM2STRING(BOTH_FLOAT2), //# Crew floating through space 2 + ENUM2STRING(BOTH_FLOATCONSOLE1), //# Crew floating and working on console + + //# LYING + ENUM2STRING(BOTH_LIE_DOWN1), + ENUM2STRING(BOTH_LIE_DOWN2), + ENUM2STRING(BOTH_LIE_DOWN3), //# reaction to local disnode being destroyed + + ENUM2STRING(BOTH_PAIN2WRITHE1), //# Transition from upright position to writhing on ground anim + ENUM2STRING(BOTH_PRONE2RLEG), //# Lying on ground reach to grab right leg + ENUM2STRING(BOTH_PRONE2LLEG), //# Lying on ground reach to grab left leg + ENUM2STRING(BOTH_WRITHING1), //# Lying on ground writhing in pain + ENUM2STRING(BOTH_WRITHING1RLEG), //# Lying on ground writhing in pain, holding right leg + ENUM2STRING(BOTH_WRITHING1LLEG), //# Lying on ground writhing in pain, holding left leg + ENUM2STRING(BOTH_WRITHING2), //# Lying on ground writhing in pain in a different way + + ENUM2STRING(BOTH_INJURED1), //# Lying down), against wall - can also be sleeping + ENUM2STRING(BOTH_INJURED2), //# Injured pose 2 + ENUM2STRING(BOTH_INJURED3), //# Injured pose 3 + ENUM2STRING(BOTH_INJURED4), //# Injured pose 4 + ENUM2STRING(BOTH_INJURED4TO5), //# Transition from INJURED4 to INJURED5 + ENUM2STRING(BOTH_INJURED5), //# Injured pose 5 + ENUM2STRING(BOTH_INJURED6), //# Injured pose 5 + ENUM2STRING(BOTH_INJURED6ATTACKSTART), //# Start attack while in injured 6 pose + ENUM2STRING(BOTH_INJURED6ATTACKSTOP), //# End attack while in injured 6 pose + + ENUM2STRING(BOTH_INJURED6COMBADGE), //# Hit combadge while in injured 6 pose + + ENUM2STRING(BOTH_INJURED6POINT), //# Chang points to door while in injured state + + ENUM2STRING(BOTH_INJUREDTOSTAND1), //# Runinjured to stand1 + + ENUM2STRING(BOTH_CRAWLBACK1), //# Lying on back), crawling backwards with elbows + ENUM2STRING(BOTH_SITWALL1), //# Sitting against a wall + ENUM2STRING(BOTH_SLEEP1), //# laying on back-rknee up-rhand on torso + ENUM2STRING(BOTH_SLEEP2), //# on floor-back against wall-arms crossed + ENUM2STRING(BOTH_SLEEP3), //# Sleeping in a chair + ENUM2STRING(BOTH_SLEEP4), //# Slumped over table + ENUM2STRING(BOTH_SLEEP5), //# Laying on side sleeping on flat sufrace + ENUM2STRING(BOTH_SLEEP1GETUP), //# alarmed and getting up out of sleep1 pose to stand + ENUM2STRING(BOTH_SLEEP1GETUP2), //# + ENUM2STRING(BOTH_SLEEP2GETUP), //# alarmed and getting up out of sleep2 pose to stand + ENUM2STRING(BOTH_SLEEP3GETUP), //# alarmed and getting up out of sleep3 pose to stand + ENUM2STRING(BOTH_SLEEP3DEATH), //# death in chair, from sleep3 idle + ENUM2STRING(BOTH_SLEEP3DEAD), //# death in chair, from sleep3 idle + + ENUM2STRING(BOTH_SLEEP_IDLE1), //# rub face and nose while asleep + ENUM2STRING(BOTH_SLEEP_IDLE2), //# shift position while asleep - stays in sleep2 + ENUM2STRING(BOTH_SLEEP_IDLE3), //# Sleep idle 3 + ENUM2STRING(BOTH_SLEEP_IDLE4), //# Sleep idle 4 + ENUM2STRING(BOTH_SLEEP1_NOSE), //# Scratch nose from SLEEP1 pose + ENUM2STRING(BOTH_SLEEP2_SHIFT), //# Shift in sleep from SLEEP2 pose + ENUM2STRING(BOTH_RESTRAINED1), //# Telsia tied to medical table + ENUM2STRING(BOTH_RESTRAINED1POINT), //# Telsia tied to medical table pointing at Munro + + ENUM2STRING(BOTH_LIFTED1), //# + ENUM2STRING(BOTH_CARRIED1), //# Fits with TORSO_CARRY1, carried over shoulder + ENUM2STRING(BOTH_CARRIED2), //# Laying over object + + + //# BORG-SPECIFIC + ENUM2STRING(BOTH_PLUGIN1), //# Borg plugs self in to alcove + ENUM2STRING(BOTH_PLUGGEDIN1), //# Last frame of Borg plug in sequence + ENUM2STRING(BOTH_PLUGOUT1), //# Borg unplugs self from alcove + //# HUNTER-SEEKER BOT-SPECIFIC + ENUM2STRING(BOTH_POWERUP1), //# Wakes up + + //================================================= + //ANIMS IN WHICH ONLY THE UPPER OBJECTS ARE IN MD3 + //================================================= + //# WEAPON-RELATED + ENUM2STRING(TORSO_DROPWEAP1), //# Put weapon away + ENUM2STRING(TORSO_DROPWEAP2), //# Put weapon away + ENUM2STRING(TORSO_DROPWEAP3), //# Put weapon away + ENUM2STRING(TORSO_RAISEWEAP1), //# Draw Weapon + ENUM2STRING(TORSO_RAISEWEAP2), //# Draw Weapon + ENUM2STRING(TORSO_RAISEWEAP3), //# Draw Weapon + ENUM2STRING(TORSO_WEAPONREADY1), //# Ready to fire 1 handed weapon + ENUM2STRING(TORSO_WEAPONREADY2), //# Ready to fire 2 handed weapon + ENUM2STRING(TORSO_WEAPONREADY3), //# Ready to fire 2 handed weapon + ENUM2STRING(TORSO_WEAPONIDLE1), //# Holding 1 handed weapon + ENUM2STRING(TORSO_WEAPONIDLE2), //# Holding 2 handed weapon + ENUM2STRING(TORSO_WEAPONIDLE3), //# Holding 2 handed weapon + //# USING NON-WEAPON OBJECTS + ENUM2STRING(TORSO_TRICORDER1), //# Using a tricorder + ENUM2STRING(TORSO_MEDICORDER1), //# Using a Medical Tricorder + ENUM2STRING(TORSO_PADD1), //# Using a PADD + + ENUM2STRING(TORSO_EQUIPMENT1), //# Twisting pipe with both hands + ENUM2STRING(TORSO_EQUIPMENT2), //# Fidgiting with cylinder with both hands + ENUM2STRING(TORSO_EQUIPMENT3), //# Using equipment one handed + ENUM2STRING(TORSO_WRIST1), //# cin.24, Chang detonating bomb with wrist device + + + //# MISC + ENUM2STRING(TORSO_COMBADGE1), //# Right hand to left breast + ENUM2STRING(TORSO_COMBADGE2), //# Left hand to left breast + ENUM2STRING(TORSO_COMBADGE3), //# Combadge touch from stand4 + + ENUM2STRING(TORSO_REDALERT1), //# Hitting comm button on wall with hand (Kirk-like) + ENUM2STRING(TORSO_HANDGESTURE1), //# gestures to left one hand + ENUM2STRING(TORSO_HANDGESTURE2), //# gestures to right one hand + ENUM2STRING(TORSO_HANDGESTURE3), //# gestures to the left both hands + ENUM2STRING(TORSO_HANDGESTURE4), //# gestures to the right both hands + ENUM2STRING(TORSO_HANDGESTURE5), //# ? + ENUM2STRING(TORSO_HANDGESTURE6), //# pointing (flank right) while talking & holding a weapon + ENUM2STRING(TORSO_HANDGESTURE7), //# pointing (forward) while talking & holding a weapon + ENUM2STRING(TORSO_HANDGESTURE8), //# pointing (flank left) while talking & holding a weapon + ENUM2STRING(TORSO_HANDGESTURE9), //# quick point right from stand 4 + ENUM2STRING(TORSO_HANDGESTURE10), //# quick point forward from stand 4 + ENUM2STRING(TORSO_HANDGESTURE11), //# quick point left from stand 4 + ENUM2STRING(TORSO_HANDGESTURE12), //# gesturing with both hands forward + ENUM2STRING(TORSO_HANDGESTURE13), //# gesturing a shrug as if not knowing answer + + ENUM2STRING(TORSO_HEADNOD1), //# nod in affirmation + ENUM2STRING(TORSO_HEADSHAKE1), //# head goes down while shaking left and right in dissapointment + + ENUM2STRING(TORSO_HYPOSPRAY1), //# man giving hypo to people + ENUM2STRING(TORSO_HYPOSPRAY4), //# using hypospray on telsia in scav5 + + ENUM2STRING(TORSO_HANDEXTEND1), //# doctor reaching for hypospray in scav5 + ENUM2STRING(TORSO_HANDRETRACT1), //# doctor taking hypospray from player in scav5 + + ENUM2STRING(TORSO_DROPHELMET1), //# Drop the helmet to the waist + ENUM2STRING(TORSO_RAISEHELMET1), //# Bring the helmet to the head + ENUM2STRING(TORSO_REACHHELMET1), //# reaching for helmet off of 60 tall cabinet + ENUM2STRING(TORSO_GRABLBACKL), //# reach to lower back with left hand + ENUM2STRING(TORSO_GRABUBACKL), //# reach to upper back with left hand + ENUM2STRING(TORSO_GRABLBACKR), //# reach to lower back with right hand + ENUM2STRING(TORSO_GRABUBACKR), //# reach to upper back with right hand + + ENUM2STRING(TORSO_STAND2TOWEAPONREADY2), //# cin.23, Nelson raising weapon in alarm and ready to fire + + ENUM2STRING(TORSO_HAND1), //# Exchanging items - giver + ENUM2STRING(TORSO_HAND2), //# Exchanging items - receiver + + ENUM2STRING(TORSO_POKERIDLE1), //# holding cards + ENUM2STRING(TORSO_POKERIDLE2), //# re-arranging cards + ENUM2STRING(TORSO_POKERIDLE3), //# put card on table + + ENUM2STRING(TORSO_SPEECHLESS1), //# hanging head in grief 1 + ENUM2STRING(TORSO_SPEECHLESS2), //# hanging head in grief 2 + ENUM2STRING(TORSO_SHOUT1), //# left hand to mouth + ENUM2STRING(TORSO_CARRY1), //# Carrying someone/thing over their shoulder (can go from BOTH_LIFT1) + + //================================================= + //ANIMS IN WHICH ONLY THE LOWER OBJECTS ARE IN MD3 + //================================================= + ENUM2STRING(LEGS_WALKBACK1), //# Walk1 backwards + ENUM2STRING(LEGS_WALKBACK2), //# Walk2 backwards + ENUM2STRING(LEGS_RUNBACK1), //# Run1 backwards + ENUM2STRING(LEGS_RUNBACK2), //# Run2 backwards + ENUM2STRING(LEGS_TURN1), //# What legs do when you turn your lower body to match your upper body facing + ENUM2STRING(LEGS_TURN2), //# Leg turning from stand2 + ENUM2STRING(LEGS_LEAN_LEFT1), //# Lean left + ENUM2STRING(LEGS_LEAN_RIGHT1), //# Lean Right + ENUM2STRING(LEGS_KNEELDOWN1), //# Get down on one knee? + ENUM2STRING(LEGS_KNEELUP1), //# Get up from one knee? + + ENUM2STRING(LEGS_CRLEAN_LEFT1), //# Crouch Lean left + ENUM2STRING(LEGS_CRLEAN_RIGHT1), //# Crouch Lean Right + //must be terminated + NULL,-1 +};*/ +//#endif //cg_players_h + +#endif diff --git a/code/cgame/cg_consolecmds.c b/code/cgame/cg_consolecmds.c index c0421b5..fca3f57 100644 --- a/code/cgame/cg_consolecmds.c +++ b/code/cgame/cg_consolecmds.c @@ -1,35 +1,23 @@ /* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// -// cg_consolecmds.c -- text commands typed in at the local console, or -// executed by a key binding + * + * Copyright (C) 1999-2000 Id Software, Inc. + * + * cg_consolecmds.c -- text commands typed in at the local console, or + * executed by a key binding + */ #include "cg_local.h" -#include "../ui/ui_shared.h" -#ifdef MISSIONPACK -extern menuDef_t *menuScoreboard; -#endif +#define emotesDEF +static void CG_ObjectivesDown_f( void ) { + cg.showObjectives = qtrue; +} + +static void CG_ObjectivesUp_f( void ) +{ + cg.showObjectives = qfalse; +} void CG_TargetCommand_f( void ) { int targetNum; @@ -74,112 +62,58 @@ static void CG_SizeDown_f (void) { ============= CG_Viewpos_f -Debugging command to print the current position +Debugging command to print the current view position ============= */ static void CG_Viewpos_f (void) { - CG_Printf ("(%i %i %i) : %i\n", (int)cg.refdef.vieworg[0], + CG_Printf ("%s (%i %i %i) : %f\n", cgs.mapname, (int)cg.refdef.vieworg[0], (int)cg.refdef.vieworg[1], (int)cg.refdef.vieworg[2], (int)cg.refdefViewAngles[YAW]); } +/* +============= +CG_ClientPos_f + +Debugging command to print the current client position +============= +*/ +static void CG_ClientPos_f ( void ) +{ + CG_Printf( "OUTPUT: %s | ORIGIN( %f %f %f ) | ANGLES( %f %f %f )\n", cgs.mapname, + cg.snap->ps.origin[0], + cg.snap->ps.origin[1], + cg.snap->ps.origin[2], + cg.snap->ps.viewangles[0], + cg.snap->ps.viewangles[1], + cg.snap->ps.viewangles[2] ); +} static void CG_ScoresDown_f( void ) { - -#ifdef MISSIONPACK - CG_BuildSpectatorString(); -#endif if ( cg.scoresRequestTime + 2000 < cg.time ) { - // the scores are more than two seconds out of data, - // so request new ones + /* the scores are more than two seconds out of data, + so request new ones */ cg.scoresRequestTime = cg.time; trap_SendClientCommand( "score" ); - // leave the current scores up if they were already - // displayed, but if this is the first hit, clear them out + /* leave the current scores up if they were already + displayed, but if this is the first hit, clear them out */ if ( !cg.showScores ) { cg.showScores = qtrue; cg.numScores = 0; } } else { - // show the cached contents even if they just pressed if it - // is within two seconds + /* show the cached contents even if they just pressed if it + is within two seconds */ cg.showScores = qtrue; } } static void CG_ScoresUp_f( void ) { - if ( cg.showScores ) { - cg.showScores = qfalse; - cg.scoreFadeTime = cg.time; - } + cg.showScores = qfalse; + cg.scoreFadeTime = cg.time; } -#ifdef MISSIONPACK -extern menuDef_t *menuScoreboard; -void Menu_Reset( void ); // FIXME: add to right include file - -static void CG_LoadHud_f( void) { - char buff[1024]; - const char *hudSet; - memset(buff, 0, sizeof(buff)); - - String_Init(); - Menu_Reset(); - - trap_Cvar_VariableStringBuffer("cg_hudFiles", buff, sizeof(buff)); - hudSet = buff; - if (hudSet[0] == '\0') { - hudSet = "ui/hud.txt"; - } - - CG_LoadMenus(hudSet); - menuScoreboard = NULL; -} - - -static void CG_scrollScoresDown_f( void) { - if (menuScoreboard && cg.scoreBoardShowing) { - Menu_ScrollFeeder(menuScoreboard, FEEDER_SCOREBOARD, qtrue); - Menu_ScrollFeeder(menuScoreboard, FEEDER_REDTEAM_LIST, qtrue); - Menu_ScrollFeeder(menuScoreboard, FEEDER_BLUETEAM_LIST, qtrue); - } -} - - -static void CG_scrollScoresUp_f( void) { - if (menuScoreboard && cg.scoreBoardShowing) { - Menu_ScrollFeeder(menuScoreboard, FEEDER_SCOREBOARD, qfalse); - Menu_ScrollFeeder(menuScoreboard, FEEDER_REDTEAM_LIST, qfalse); - Menu_ScrollFeeder(menuScoreboard, FEEDER_BLUETEAM_LIST, qfalse); - } -} - - -static void CG_spWin_f( void) { - trap_Cvar_Set("cg_cameraOrbit", "2"); - trap_Cvar_Set("cg_cameraOrbitDelay", "35"); - trap_Cvar_Set("cg_thirdPerson", "1"); - trap_Cvar_Set("cg_thirdPersonAngle", "0"); - trap_Cvar_Set("cg_thirdPersonRange", "100"); - CG_AddBufferedSound(cgs.media.winnerSound); - //trap_S_StartLocalSound(cgs.media.winnerSound, CHAN_ANNOUNCER); - CG_CenterPrint("YOU WIN!", SCREEN_HEIGHT * .30, 0); -} - -static void CG_spLose_f( void) { - trap_Cvar_Set("cg_cameraOrbit", "2"); - trap_Cvar_Set("cg_cameraOrbitDelay", "35"); - trap_Cvar_Set("cg_thirdPerson", "1"); - trap_Cvar_Set("cg_thirdPersonAngle", "0"); - trap_Cvar_Set("cg_thirdPersonRange", "100"); - CG_AddBufferedSound(cgs.media.loserSound); - //trap_S_StartLocalSound(cgs.media.loserSound, CHAN_ANNOUNCER); - CG_CenterPrint("YOU LOSE...", SCREEN_HEIGHT * .30, 0); -} - -#endif - static void CG_TellTarget_f( void ) { int clientNum; char command[128]; @@ -210,240 +144,576 @@ static void CG_TellAttacker_f( void ) { trap_SendClientCommand( command ); } -static void CG_VoiceTellTarget_f( void ) { - int clientNum; - char command[128]; - char message[128]; +void CG_Cough_cmd( void ) +{ + CG_Printf(" ,. \n"); CG_Printf(" ..:, :Xt. ,:. \n"); + CG_Printf(" ,=+t: .IRX= :++=. \n"); CG_Printf(" .=iVt:. :RYYI. .itt+ \n"); + CG_Printf(" .:tXI=;. tRtiV; ,IYY:. \n"); CG_Printf(" .+;ii=;. ,XVi+Vt. :tIi+ \n"); + CG_Printf(" .;ti;;:. +RI++IY, ,+tt=. \n"); CG_Printf(" ,++YY;. ,XXi+++X= ;IYI=. \n"); + CG_Printf(" ;ttY+;. .,=iVRI++++YX+;. ;VYt; \n"); CG_Printf(" .;ii+=, .;IXRRXVi++++iVRXVi:. ,=iii. \n"); + CG_Printf(" .==;ti, .;YRRVVXYii+++++IVIVRXt, ,+=tI= \n"); CG_Printf(" .iitY=, .tRRVXXVRV+++ii++YRXVIYXV; :tYti, \n"); + CG_Printf(" .+iii=,,IBVVXYiiXViiiiiiitVtIXViVR= ,+t+I: \n"); CG_Printf(" =+=I:.tBVXVt=;tRIiiiiiiiiXi:=YXiIX; :+=It; \n"); + CG_Printf(" .;;tYt:;RVVV+=:,YRiiiiiiiiiYI,.:IXiVY..+IYi= \n"); CG_Printf(" .ti=t+;tRIXi;, :XViiiiiiiiiIV: ,YViX=.:titt. \n"); + CG_Printf(" iY++I;YVYY=: +BIiiiiiiiiiiX= +XiVi;i++Vi, \n"); CG_Printf(" ,+YYYI:VYYY;. .YRiiiiiiiiiiiVt. ;RIYt:IIVVi: \n"); + CG_Printf(" ,+tYXi;YVIX; ;RVtiiiiIXXtiiVI, iRIVt,=XVit: \n"); CG_Printf(" .+iiti++XiXI. iBIiiiiYXIIXtiIV: :XXIV++;i+iI;.\n"); + CG_Printf(" ;Ii=ii:VYtRi,VRtiiiVVi=;IXitX=;VBYXI=i+;iV+;.\n"); CG_Printf(" ;tYtVt;;XYIRXBVttiVV+;:.:VYiXVRBVXY+;+IYVt+, \n"); + CG_Printf(" =iiItii,=XVIRRIttXV+=:..,tRtVBXVRI+=i:iIit+. \n"); CG_Printf(" :t==++I:.=YXYIIiYBXYIttIVRBYtVXXI+;;t+;;+Y=, \n"); + CG_Printf(" +I=;+Y= .:IRItYIVXRRRBBRXXVIRY+=;.:i=;iVi;. \n"); CG_Printf(" .+IYVV+: +BYXXVXXXXXXXXXVRVVi;:.:;tVYY+=: \n"); + CG_Printf(" .+ttii+ .IBXY++ittIIIti++tXXi, .++=tI+;: \n"); CG_Printf(" ;YYtIY;;VBI+;:,::;;;;;:,:IBt,::tItYV=. \n"); + CG_Printf(" =IYYI++ti+;, ....... :Xt;i=iYYI+;. \n"); CG_Printf(" .:+i++ii;;. .=i=+i=t+;;:. \n"); + CG_Printf(" ,tYIVI==:,.. ..,;=+iYIVt:.. \n"); CG_Printf(" ,itt+iIYYti;. ,;itYIIt:iIi=;. \n"); + CG_Printf(" .:;;:+tIIVIi:.;iYYIii+=:,;;:. \n"); CG_Printf(" . ,:=itIXi.tXYit=;::, . \n"); + CG_Printf(" .+tti=,,iIt+;. \n"); CG_Printf(" .:;;:. ,;;;:. \n"); +} - clientNum = CG_CrosshairPlayer(); - if ( clientNum == -1 ) { +/* +========================= +CG_RankList_cmd +TiM: Scans the rank struct, and gets +the names of all the ranks we can use ATM +========================= +*/ +void CG_RankList_cmd( void ) { + int i; + + /* Print Titles */ + CG_Printf( S_COLOR_CYAN "RPG-X: Available Ranks\n"); + CG_Printf( S_COLOR_GREEN "Console Name \t - \t Formal Name\n" ); + + /* Loop thru each val and print them */ + for ( i = 0; i < MAX_RANKS; i++ ) { + /*if ( strlen( cgs.ranksData[i].consoleName ) < 1 || strlen( cgs.ranksData[i].formalName ) < 1 ) + return; */ + + if ( cgs.ranksData[i].consoleName[0] ) + CG_Printf( "%s \t - \t %s\n", cgs.ranksData[i].consoleName, cgs.ranksData[i].formalName ); + else + break; + } +} + +/* +========================= +CG_ClassList_cmd +TiM: Scans the class struct, and gets +the names of all the ranks we can use ATM +========================= +*/ +void CG_ClassList_cmd( void ) { + int i; + + /* Print Titles */ + CG_Printf( S_COLOR_CYAN "RPG-X: Available Classes\n"); + CG_Printf( S_COLOR_GREEN "Formal Name\n" ); + + /* Loop thru each val and print them */ + for ( i = 0; i < MAX_CLASSES; i++ ) { + /* if ( strlen( cgs.ranksData[i].consoleName ) < 1 || strlen( cgs.ranksData[i].formalName ) < 1 ) + return; */ + + if ( cgs.classData[i].formalName[0] ) + CG_Printf( "%s\n", cgs.classData[i].formalName[0] ); + else + break; + } +} + +/* +========================= +CG_BeamList_cmd +TiM: Returns a list showing +the index of each target_location +ent so people know the data needed +to beam to various locations. +========================= +*/ +void CG_BeamList_cmd( void ) { + const char *locStr; + int i; + + /* Print Titles */ + CG_Printf( S_COLOR_CYAN "RPG-X Current Beam Locations\n" ); + CG_Printf( S_COLOR_GREEN "Location Name \t - \t Location Index\n" ); + + /* Based off the string data that is transmitted to the CG on Init + Get the name and index of each location */ + for ( i = 1; i < MAX_LOCATIONS; i++ ) { + locStr = CG_ConfigString( CS_LOCATIONS + i ); + + if ( locStr[0] ) { + CG_Printf( "%s \t - \t%i\n", locStr, i ); + } + locStr = NULL; /* reset just in case */ + } +} + +/* +========================= +CG_Emote_f +TiM: The first portion of the +emote system. While JKA works +by storing a copy of animations +on the server (something we cannot +replicate easily here without +destroying user freedom futhur >.<), so it +automatically knows the length of time +each anim should run for, here, we'll +hacikly override this by calculating the +run length on the client as they have the data, +and then transmitting it to the server. +Hacky, I know. + +And if other players don't have the same model, +it could potentially show animation glitches. +Although not as bad as the alternative... +========================= +*/ + +void CG_Emote_f( void ) { + const char *argStr; + emoteList_t *emote = NULL; + int i; + animation_t *anims; + int animLength; + /* int animLengthUpper; + int animLengthLower; */ + qboolean emoteFound=qfalse; + + argStr = CG_Argv( 1 ); + if ( !argStr[0] ) { + CG_Printf( S_COLOR_RED "ERROR: No emote specified.\n" ); return; } - trap_Args( message, 128 ); - Com_sprintf( command, 128, "vtell %i %s", clientNum, message ); - trap_SendClientCommand( command ); -} - -static void CG_VoiceTellAttacker_f( void ) { - int clientNum; - char command[128]; - char message[128]; - - clientNum = CG_LastAttacker(); - if ( clientNum == -1 ) { + /* TiM: Hack override for eyes shut, angry eyes and alert mode. + No more data is needed */ + if ( !Q_stricmp( argStr, "eyes_shut" ) || !Q_stricmp( argStr, "eyes_frown" ) || !Q_stricmpn( argStr, "alert", 5 ) || !Q_stricmpn( argStr, "alert2", 6 ) ) + { + trap_SendClientCommand( va( "doEmote %s", argStr ) ); return; } - trap_Args( message, 128 ); - Com_sprintf( command, 128, "vtell %i %s", clientNum, message ); - trap_SendClientCommand( command ); + if ( cg.predictedPlayerEntity.currentState.eFlags & EF_DEAD ) { + CG_Printf( S_COLOR_RED "ERROR: Cannot play emotes when dead.\n" ); + return; + } + + /* find out emote in the list + value of numEmotes calced in bg_misc.c + or if an int was supplied as an arg, use that */ + /*if ( !argStr[0] >= '0' && argStr[0] <= '9' ) + { + i = atoi( argStr ); + + if ( i > 0 || i < bg_numEmotes ) { + emote = &bg_emoteList[i]; + emoteFound = qtrue; + } + else { + CG_Printf( S_COLOR_RED "ERROR: An invalid emote number was given.\n" ); + return; + } + } + else + {*/ + for ( i = 0; i < bg_numEmotes; i++ ) + { /* i < sizeof( emoteList ) / sizeof( emoteList[0] ) */ + emote = &bg_emoteList[i]; + + if ( emote && !Q_stricmp( emote->name, argStr ) ) + { + emoteFound = qtrue; + break; + } + } + /*} */ + + if ( !emoteFound ) { + CG_Printf( S_COLOR_RED "ERROR: Specified emote not found\n" ); + return; + } + + anims = &cg_animsList[cgs.clientinfo[ cg.predictedPlayerState.clientNum ].animIndex].animations[ emote->enumName ]; + + /* if anim num less than 0, then this is a stub anim */ + if ( !anims || anims->numFrames < 0 ) { + CG_Printf( S_COLOR_RED "ERROR: Current character cannot perform that emote.\n" ); + return; + } + + /* Anim length for lower model */ + if ( !( emote->animFlags & EMOTE_LOOP_UPPER ) && !( emote->animFlags & EMOTE_LOOP_LOWER ) ) { + /* numFrames * (1000 / fps = frameLerp ) = time length */ + animLength = anims->numFrames * anims->frameLerp; + } + else { + animLength = -1; + } + + /* send the command to the server */ + trap_SendClientCommand( va( "doEmote %i %i", i, animLength ) ); + + /* add this emote to the emotes recently played menu */ + { + int j; + char* cvar; + char buffer[256]; + qboolean foundSlot=qfalse; + + for ( j = 1; j <= NUM_CVAR_STORES; j++ ) { + cvar = va( "ui_recentEmote%i", j ); + + /* found a free slot */ + trap_Cvar_VariableStringBuffer( cvar, buffer, 256 ); + + /* oh this emote's already here... no point adding it again */ + if ( atoi(buffer) == i ) { + foundSlot = qtrue; + break; + } + + if ( atoi(buffer) == -1 ) { + trap_Cvar_Set( cvar, va( "%i", i ) ); + foundSlot = qtrue; + break; + } + } + + /* whup... no slot found. better push them all forward one */ + if ( !foundSlot ) { + char* cvar2; + + for ( j = 2; j <= NUM_CVAR_STORES; j++ ) { + cvar = va( "ui_recentEmote%i", j-1 ); + cvar2 = va( "ui_recentEmote%i", j ); + + trap_Cvar_VariableStringBuffer( cvar2, buffer, 256 ); + trap_Cvar_Set( cvar, va( "%i", atoi(buffer) ) ); + + if ( j == NUM_CVAR_STORES ) { + cvar = va( "ui_recentEmote%i", NUM_CVAR_STORES ); + trap_Cvar_Set( cvar, va( "%i", i ) ); + } + } + } + } } -#ifdef MISSIONPACK -static void CG_NextTeamMember_f( void ) { - CG_SelectNextPlayer(); -} -static void CG_PrevTeamMember_f( void ) { - CG_SelectPrevPlayer(); -} +/* +========================= +CG_LocEdit_f +========================= +*/ +static fileHandle_t f; +void CG_LocEdit_f(void) { + char path[MAX_QPATH]; + char buffer[MAX_STRING_CHARS]; + const char *argptr; + int i; -// ASS U ME's enumeration order as far as task specific orders, OFFENSE is zero, CAMP is last -// -static void CG_NextOrder_f( void ) { - clientInfo_t *ci = cgs.clientinfo + cg.snap->ps.clientNum; - if (ci) { - if (!ci->teamLeader && sortedTeamPlayers[cg_currentSelectedPlayer.integer] != cg.snap->ps.clientNum) { + argptr = CG_Argv(1); + + if(!Q_stricmpn(argptr, "start", 5)) { + Com_sprintf(path, sizeof(path), "%s", cgs.mapname); + + COM_StripExtension(path, path); + Com_sprintf(path, sizeof(path), "%s.locations"); + + trap_FS_FOpenFile(path, &f, FS_READ); + + if(f) { + CG_Printf(S_COLOR_RED "locedit: %s.locations already exist! Skipping.\n", path); + trap_FS_FCloseFile(f); return; } - } - if (cgs.currentOrder < TEAMTASK_CAMP) { - cgs.currentOrder++; - if (cgs.currentOrder == TEAMTASK_RETRIEVE) { - if (!CG_OtherTeamHasFlag()) { - cgs.currentOrder++; + trap_FS_FOpenFile(path, &f, FS_APPEND); + + if(f) { + if((argptr = CG_Argv(2)) != NULL) { + i = atoi(argptr); + if(i) { + trap_FS_Write("LocationsList2\n", 15, f); + } else { + trap_FS_Write("LocationsList\n", 14, f); + } + trap_FS_Write("{\n", 2, f); + CG_Printf(S_COLOR_YELLOW "locedit: file created...\n"); + CG_Printf(S_COLOR_YELLOW "locedit: writing file header...\n"); + } else { + CG_Printf(S_COLOR_RED "locedit: insufficent number of arguments.\n"); + trap_FS_FCloseFile(f); + return; } } - - if (cgs.currentOrder == TEAMTASK_ESCORT) { - if (!CG_YourTeamHasFlag()) { - cgs.currentOrder++; - } + } else if(!Q_stricmpn(argptr, "stop", 4)) { + if(!f) { + CG_Printf(S_COLOR_RED "locedit: no locations file loaded!\n"); + return; + } + trap_FS_Write("}", 1, f); + CG_Printf(S_COLOR_YELLOW "locedit: writing file end...\n"); + trap_FS_FCloseFile(f); + CG_Printf(S_COLOR_YELLOW "locedit: closed file.\n"); + } else if(!Q_stricmpn(argptr, "add", 3)) { + if(!f) { + CG_Printf(S_COLOR_RED "locedit: no locations file loaded!\n"); + return; } - } else { - cgs.currentOrder = TEAMTASK_OFFENSE; - } - cgs.orderPending = qtrue; - cgs.orderTime = cg.time + 3000; -} + memset(buffer, 0, sizeof(buffer)); + Com_sprintf(buffer, sizeof(buffer), "\t{ %f, %f, %f } { 0, %f, 0 } ", floor(cg.snap->ps.origin[0]), + floor(cg.snap->ps.origin[1]), + floor(cg.snap->ps.origin[2]), + floor(cg.snap->ps.viewangles[1] - 24.0f)); -static void CG_ConfirmOrder_f (void ) { - trap_SendConsoleCommand(va("cmd vtell %d %s\n", cgs.acceptLeader, VOICECHAT_YES)); - trap_SendConsoleCommand("+button5; wait; -button5"); - if (cg.time < cgs.acceptOrderTime) { - trap_SendClientCommand(va("teamtask %d\n", cgs.acceptTask)); - cgs.acceptOrderTime = 0; + argptr = CG_Argv(2); + Com_sprintf(buffer, sizeof(buffer), "%s \"%s\"", buffer, argptr); + argptr = CG_Argv(3); + if(argptr) { + Com_sprintf(buffer, sizeof(buffer), "%s \"%s\"", buffer, argptr); + } + Com_sprintf(buffer, sizeof(buffer), "%s;\n", buffer); + trap_FS_Write(buffer, strlen(buffer), f); + CG_Printf(S_COLOR_YELLOW "locedit - added location: %s\n", buffer); + } else if(!Q_stricmpn(argptr, "nl", 2)) { + if(!f) { + CG_Printf(S_COLOR_RED "locedit: no locations file loaded!\n"); + return; + } + + trap_FS_Write("\n", 1, f); + CG_Printf(S_COLOR_YELLOW "locedit: added an empty line.\n"); } } -static void CG_DenyOrder_f (void ) { - trap_SendConsoleCommand(va("cmd vtell %d %s\n", cgs.acceptLeader, VOICECHAT_NO)); - trap_SendConsoleCommand("+button6; wait; -button6"); - if (cg.time < cgs.acceptOrderTime) { - cgs.acceptOrderTime = 0; +/*================================================================================= +Third Person Camera View Commands +TiM : These commands activate code in the thirdperson rendering code to let players +zoom around their characters smoothly. +==================================================================================*/ + +void CG_ThirdPersonForwardDown_f ( void ) { + if ( !cg.zoomedForward ) { + cg.zoomedForward = qtrue; + } +} +void CG_ThirdPersonForwardUp_f ( void ) { + if ( cg.zoomedForward ) { + cg.zoomedForward = qfalse; } } -static void CG_TaskOffense_f (void ) { - if (cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF) { - trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONGETFLAG)); - } else { - trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONOFFENSE)); + + +void CG_ThirdPersonBackwardDown_f ( void ) { + if ( !cg.zoomedBackward ) { + cg.zoomedBackward = qtrue; + } +} +void CG_ThirdPersonBackwardUp_f ( void ) { + if ( cg.zoomedBackward ) { + cg.zoomedBackward = qfalse; } - trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_OFFENSE)); } -static void CG_TaskDefense_f (void ) { - trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONDEFENSE)); - trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_DEFENSE)); + + +void CG_ThirdPersonLeftDown_f ( void ) { + if ( !cg.zoomedLeft ) { + cg.zoomedLeft = qtrue; + } +} +void CG_ThirdPersonLeftUp_f ( void ) { + if ( cg.zoomedLeft ) { + cg.zoomedLeft = qfalse; + } } -static void CG_TaskPatrol_f (void ) { - trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONPATROL)); - trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_PATROL)); + + +void CG_ThirdPersonRightDown_f ( void ) { + if ( !cg.zoomedRight ) { + cg.zoomedRight = qtrue; + } +} +void CG_ThirdPersonRightUp_f ( void ) { + if ( cg.zoomedRight ) { + cg.zoomedRight = qfalse; + } } -static void CG_TaskCamp_f (void ) { - trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONCAMPING)); - trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_CAMP)); + + +void CG_ThirdPersonUpDown_f ( void ) { + if ( !cg.zoomedUp ) { + cg.zoomedUp = qtrue; + } +} +void CG_ThirdPersonUpUp_f ( void ) { + if ( cg.zoomedUp ) { + cg.zoomedUp = qfalse; + } } -static void CG_TaskFollow_f (void ) { - trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONFOLLOW)); - trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_FOLLOW)); + + +void CG_ThirdPersonDownDown_f ( void ) { + if ( !cg.zoomedDown ) { + cg.zoomedDown = qtrue; + } +} +void CG_ThirdPersonDownUp_f ( void ) { + if ( cg.zoomedDown ) { + cg.zoomedDown = qfalse; + } } -static void CG_TaskRetrieve_f (void ) { - trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONRETURNFLAG)); - trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_RETRIEVE)); + + +void CG_ThirdPersonAngleLeftDown_f ( void ) { + if ( !cg.zoomAngleLeft ) { + cg.zoomAngleLeft = qtrue; + } +} +void CG_ThirdPersonAngleLeftUp_f ( void ) { + if ( cg.zoomAngleLeft ) { + cg.zoomAngleLeft = qfalse; + } } -static void CG_TaskEscort_f (void ) { - trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONFOLLOWCARRIER)); - trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_ESCORT)); + + +void CG_ThirdPersonAngleRightDown_f ( void ) { + if ( !cg.zoomAngleRight ) { + cg.zoomAngleRight = qtrue; + } +} +void CG_ThirdPersonAngleRightUp_f ( void ) { + if ( cg.zoomAngleRight ) { + cg.zoomAngleRight = qfalse; + } } -static void CG_TaskOwnFlag_f (void ) { - trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_IHAVEFLAG)); + + +void CG_ThirdPersonPitchDownDown_f ( void ) { + if ( !cg.zoomPitchDown ) { + cg.zoomPitchDown = qtrue; + } +} +void CG_ThirdPersonPitchDownUp_f ( void ) { + if ( cg.zoomPitchDown ) { + cg.zoomPitchDown = qfalse; + } } -static void CG_TauntKillInsult_f (void ) { - trap_SendConsoleCommand("cmd vsay kill_insult\n"); + + +void CG_ThirdPersonPitchUpDown_f ( void ) { + if ( !cg.zoomPitchUp ) { + cg.zoomPitchUp = qtrue; + } +} +void CG_ThirdPersonPitchUpUp_f ( void ) { + if ( cg.zoomPitchUp ) { + cg.zoomPitchUp = qfalse; + } } -static void CG_TauntPraise_f (void ) { - trap_SendConsoleCommand("cmd vsay praise\n"); + +/*------------------------------------------------------------------------------*/ + +const char* cVars[] = { "cg_thirdPersonRange", "cg_thirdPersonAngle", + "cg_thirdPersonVertOffset", "cg_thirdPersonHorzOffset", + "cg_thirdPersonPitchOffset" }; + +vmCvar_t* TPSVars[] = { &cg_thirdPersonRange, &cg_thirdPersonAngle, + &cg_thirdPersonVertOffset, &cg_thirdPersonHorzOffset, + &cg_thirdPersonPitchOffset }; + +/* Set the third person values back to their hard-coded CVAR counter parts + Ie revert any temporary changes. */ +void CG_ThirdPersonRevert_f ( void ) { + + int i; + char value[MAX_TOKEN_CHARS]; + + for (i = 0; i < 5; i++ ){ + trap_Cvar_VariableStringBuffer ( cVars[i], value, sizeof( value ) ); + TPSVars[i]->value = atof( value ); + /* Q_strncpyz( TPSVars[i]->string, value, 256 ); */ + } } -static void CG_TauntTaunt_f (void ) { - trap_SendConsoleCommand("cmd vtaunt\n"); +/* + * TiM : If the default values for these CVARs are changed in cg_main.c, update them here. + * I would consider linking directly to the values, but with scope, and then locating them in the + * struct array, this is way faster. + * Resets the values to the game's defaults. Useful if you screwed up the view big time. + */ +void CG_ThirdPersonReset_f ( void ) { + int defValues[] = { 80, 0, 16, 0, 0 }; + int i; + + for (i = 0; i < 5; i++ ) { + TPSVars[i]->value = defValues[i]; + trap_Cvar_Set( cVars[i], va( "%i", defValues[i] ) ); + } } -static void CG_TauntDeathInsult_f (void ) { - trap_SendConsoleCommand("cmd vsay death_insult\n"); +/* + * Takes the current values from all of the thirdperson pointer variables, and sets the + * hard coded CVARs to the same value, effectively making them permanent + */ +void CG_ThirdPersonCommit_f ( void ) { + int i; + + for (i = 0; i < 5; i++ ) { + trap_Cvar_Set( cVars[i], va("%f", TPSVars[i]->value ) ); + } + CG_Printf( "Current Third Person CVAR values committed.\n" ); + //since no screen changes occur. Let the user know something happened. } -static void CG_TauntGauntlet_f (void ) { - trap_SendConsoleCommand("cmd vsay kill_guantlet\n"); +/* Toggles between first and third person */ +void CG_ToggleThirdPerson_f ( void ) { + int value; + + value = !( cg_thirdPerson.integer > 0 ); /* This is cool. It'll toggle the value each call. */ + + trap_Cvar_Set( "cg_thirdPerson", va( "%i", value ) ); } -static void CG_TaskSuicide_f (void ) { - int clientNum; - char command[128]; +/*TiM - Test the ability to handle binary data streams +void CG_LoadBinaryData( void ) +{ + const char *fileRoute = "rpgx.idkey"; + fileHandle_t f; + int len; + byte buffer[SECURITY_SIZE]; + rpgxSecurityFile_t *c; - clientNum = CG_CrosshairPlayer(); - if ( clientNum == -1 ) { + if (!fileRoute) return; - } - Com_sprintf( command, 128, "tell %i suicide", clientNum ); - trap_SendClientCommand( command ); -} + len = trap_FS_FOpenFile( fileRoute, &f, FS_READ ); - - -/* -================== -CG_TeamMenu_f -================== -*/ -/* -static void CG_TeamMenu_f( void ) { - if (trap_Key_GetCatcher() & KEYCATCH_CGAME) { - CG_EventHandling(CGAME_EVENT_NONE); - trap_Key_SetCatcher(0); - } else { - CG_EventHandling(CGAME_EVENT_TEAMMENU); - //trap_Key_SetCatcher(KEYCATCH_CGAME); - } -} -*/ - -/* -================== -CG_EditHud_f -================== -*/ -/* -static void CG_EditHud_f( void ) { - //cls.keyCatchers ^= KEYCATCH_CGAME; - //VM_Call (cgvm, CG_EVENT_HANDLING, (cls.keyCatchers & KEYCATCH_CGAME) ? CGAME_EVENT_EDITHUD : CGAME_EVENT_NONE); -} -*/ - -#endif - -/* -================== -CG_StartOrbit_f -================== -*/ - -static void CG_StartOrbit_f( void ) { - char var[MAX_TOKEN_CHARS]; - - trap_Cvar_VariableStringBuffer( "developer", var, sizeof( var ) ); - if ( !atoi(var) ) { + if ( !len ) return; - } - if (cg_cameraOrbit.value != 0) { - trap_Cvar_Set ("cg_cameraOrbit", "0"); - trap_Cvar_Set("cg_thirdPerson", "0"); - } else { - trap_Cvar_Set("cg_cameraOrbit", "5"); - trap_Cvar_Set("cg_thirdPerson", "1"); - trap_Cvar_Set("cg_thirdPersonAngle", "0"); - trap_Cvar_Set("cg_thirdPersonRange", "100"); - } -} -/* -static void CG_Camera_f( void ) { - char name[1024]; - trap_Argv( 1, name, sizeof(name)); - if (trap_loadCamera(name)) { - cg.cameraMode = qtrue; - trap_startCamera(cg.time); - } else { - CG_Printf ("Unable to load camera %s\n",name); - } -} -*/ + trap_FS_Read( buffer, len, f ); + trap_FS_FCloseFile( f ); + c = (rpgxSecurityFile_t *)((byte *)buffer); + + CG_Printf( "ID: %i, Hash: %i, PID: %i\n", c->ID, c->hash > 0xFFFF ? 1 : 0, c->playerID > 0xFFFF ? 1 : 0); + CG_Printf( "%i\n", (unsigned)atoi( sv_securityHash.string ) > 0xFFFF ? 1 : 0 ); +}*/ + +/*================================================================================*/ typedef struct { char *cmd; @@ -451,56 +721,66 @@ typedef struct { } consoleCommand_t; static consoleCommand_t commands[] = { - { "testgun", CG_TestGun_f }, - { "testmodel", CG_TestModel_f }, - { "nextframe", CG_TestModelNextFrame_f }, - { "prevframe", CG_TestModelPrevFrame_f }, - { "nextskin", CG_TestModelNextSkin_f }, - { "prevskin", CG_TestModelPrevSkin_f }, - { "viewpos", CG_Viewpos_f }, - { "+scores", CG_ScoresDown_f }, - { "-scores", CG_ScoresUp_f }, - { "+zoom", CG_ZoomDown_f }, - { "-zoom", CG_ZoomUp_f }, - { "sizeup", CG_SizeUp_f }, - { "sizedown", CG_SizeDown_f }, - { "weapnext", CG_NextWeapon_f }, - { "weapprev", CG_PrevWeapon_f }, - { "weapon", CG_Weapon_f }, - { "tell_target", CG_TellTarget_f }, - { "tell_attacker", CG_TellAttacker_f }, - { "vtell_target", CG_VoiceTellTarget_f }, - { "vtell_attacker", CG_VoiceTellAttacker_f }, - { "tcmd", CG_TargetCommand_f }, -#ifdef MISSIONPACK - { "loadhud", CG_LoadHud_f }, - { "nextTeamMember", CG_NextTeamMember_f }, - { "prevTeamMember", CG_PrevTeamMember_f }, - { "nextOrder", CG_NextOrder_f }, - { "confirmOrder", CG_ConfirmOrder_f }, - { "denyOrder", CG_DenyOrder_f }, - { "taskOffense", CG_TaskOffense_f }, - { "taskDefense", CG_TaskDefense_f }, - { "taskPatrol", CG_TaskPatrol_f }, - { "taskCamp", CG_TaskCamp_f }, - { "taskFollow", CG_TaskFollow_f }, - { "taskRetrieve", CG_TaskRetrieve_f }, - { "taskEscort", CG_TaskEscort_f }, - { "taskSuicide", CG_TaskSuicide_f }, - { "taskOwnFlag", CG_TaskOwnFlag_f }, - { "tauntKillInsult", CG_TauntKillInsult_f }, - { "tauntPraise", CG_TauntPraise_f }, - { "tauntTaunt", CG_TauntTaunt_f }, - { "tauntDeathInsult", CG_TauntDeathInsult_f }, - { "tauntGauntlet", CG_TauntGauntlet_f }, - { "spWin", CG_spWin_f }, - { "spLose", CG_spLose_f }, - { "scoresDown", CG_scrollScoresDown_f }, - { "scoresUp", CG_scrollScoresUp_f }, -#endif - { "startOrbit", CG_StartOrbit_f }, - //{ "camera", CG_Camera_f }, - { "loaddeferred", CG_LoadDeferredPlayers } + { "testgun", CG_TestGun_f }, + { "testmodel", CG_TestModel_f }, + { "nextframe", CG_TestModelNextFrame_f }, + { "prevframe", CG_TestModelPrevFrame_f }, + { "nextskin", CG_TestModelNextSkin_f }, + { "prevskin", CG_TestModelPrevSkin_f }, + { "viewpos", CG_Viewpos_f }, + { "+info", CG_ScoresDown_f }, + { "-info", CG_ScoresUp_f }, + { "+zoom", CG_ZoomDown_f }, + { "-zoom", CG_ZoomUp_f }, + + /* TiM : Modelview code */ + { "+thirdPersonForward", CG_ThirdPersonForwardDown_f }, /* moving the camera forward */ + { "-thirdPersonForward", CG_ThirdPersonForwardUp_f }, + { "+thirdPersonBackward", CG_ThirdPersonBackwardDown_f }, /* moving the camera backward */ + { "-thirdPersonBackward", CG_ThirdPersonBackwardUp_f }, + { "+thirdPersonLeft", CG_ThirdPersonLeftDown_f }, /* moving the camera left */ + { "-thirdPersonLeft", CG_ThirdPersonLeftUp_f }, + { "+thirdPersonRight", CG_ThirdPersonRightDown_f }, /* moving the camera right */ + { "-thirdPersonRight", CG_ThirdPersonRightUp_f }, + { "+thirdPersonUp", CG_ThirdPersonUpDown_f }, /* moving the camera up */ + { "-thirdPersonUp", CG_ThirdPersonUpUp_f }, + { "+thirdPersonDown", CG_ThirdPersonDownDown_f }, /* moving the camera down */ + { "-thirdPersonDown", CG_ThirdPersonDownUp_f }, + { "+thirdPersonAngleLeft", CG_ThirdPersonAngleLeftDown_f }, /* rotating the camera left */ + { "-thirdPersonAngleLeft", CG_ThirdPersonAngleLeftUp_f }, + { "+thirdPersonAngleRight", CG_ThirdPersonAngleRightDown_f }, /* rotating the camera right */ + { "-thirdPersonAngleRight", CG_ThirdPersonAngleRightUp_f }, + { "+thirdPersonPitchDown", CG_ThirdPersonPitchDownDown_f }, /* pitching the camera down */ + { "-thirdPersonPitchDown", CG_ThirdPersonPitchDownUp_f }, + { "+thirdPersonPitchUp", CG_ThirdPersonPitchUpDown_f }, /* pitching the camera up */ + { "-thirdPersonPitchUp", CG_ThirdPersonPitchUpUp_f }, + { "thirdPersonRevert", CG_ThirdPersonRevert_f }, /* revert current view to previous settings */ + { "thirdPersonReset", CG_ThirdPersonReset_f }, /* reset values to CVAR defaults */ + { "thirdPersonCommit", CG_ThirdPersonCommit_f }, /* set CVARs to current settings */ + { "thirdPerson", CG_ToggleThirdPerson_f }, /* Toggle the 3rd persn CVAR */ + /* TiM */ + + { "clientPos", CG_ClientPos_f }, + { "sizeup", CG_SizeUp_f }, + { "sizedown", CG_SizeDown_f }, + { "weapnext", CG_NextWeapon_f }, + { "weapprev", CG_PrevWeapon_f }, + { "weapon", CG_Weapon_f }, + { "tell_target", CG_TellTarget_f }, + { "tell_attacker", CG_TellAttacker_f }, + { "tcmd", CG_TargetCommand_f }, + { "loaddefered", CG_LoadDeferredPlayers }, /* spelled wrong, but not changing for demo... */ + { "+analysis", CG_ObjectivesDown_f }, + { "-analysis", CG_ObjectivesUp_f }, + /*{ "+shake", CG_ShakeCamera_cmd },*/ + { "iloverpg-x", CG_Cough_cmd }, + /*{ "commandList", CG_CmdList_cmd },*/ + { "rankList", CG_RankList_cmd }, + { "locationList", CG_BeamList_cmd }, + { "classList", CG_ClassList_cmd }, + { "emote", CG_Emote_f }, + { "locedit", CG_LocEdit_f }, + /*{ "fileID", CG_LoadBinaryData }*/ }; @@ -518,7 +798,7 @@ qboolean CG_ConsoleCommand( void ) { cmd = CG_Argv(0); - for ( i = 0 ; i < ARRAY_LEN( commands ) ; i++ ) { + for ( i = 0 ; i < sizeof( commands ) / sizeof( commands[0] ) ; i++ ) { if ( !Q_stricmp( cmd, commands[i].cmd ) ) { commands[i].function(); return qtrue; @@ -528,7 +808,6 @@ qboolean CG_ConsoleCommand( void ) { return qfalse; } - /* ================= CG_InitConsoleCommands @@ -540,39 +819,156 @@ so it can perform tab completion void CG_InitConsoleCommands( void ) { int i; - for ( i = 0 ; i < ARRAY_LEN( commands ) ; i++ ) { + for ( i = 0 ; i < sizeof( commands ) / sizeof( commands[0] ) ; i++ ) { trap_AddCommand( commands[i].cmd ); } - // - // the game server will interpret these commands, which will be automatically - // forwarded to the server after they are not recognized locally - // + /* + * the game server will interpret these commands, which will be automatically + * forwarded to the server after they are not recognized locally + * + * TiM: This trap command also adds the commands to the 'tab list' that users can + * use thru the console, so adding any and all game side commands (that we want the users to know about/access of course lol ;P ) + * would be a good idea too. :) + */ trap_AddCommand ("kill"); trap_AddCommand ("say"); trap_AddCommand ("say_team"); - trap_AddCommand ("tell"); - trap_AddCommand ("vsay"); - trap_AddCommand ("vsay_team"); - trap_AddCommand ("vtell"); - trap_AddCommand ("vtaunt"); - trap_AddCommand ("vosay"); - trap_AddCommand ("vosay_team"); - trap_AddCommand ("votell"); + /* START MOD */ + trap_AddCommand ("say_class"); + /*trap_AddCommand ("giveTo");*/ + trap_AddCommand ("forceName"); + trap_AddCommand ("forceKill"); + trap_AddCommand ("forceKillRadius"); + trap_AddCommand ("forceClass"); + trap_AddCommand ("kickTarget"); + /* END MOD */ trap_AddCommand ("give"); trap_AddCommand ("god"); trap_AddCommand ("notarget"); trap_AddCommand ("noclip"); trap_AddCommand ("team"); + trap_AddCommand ("class"); trap_AddCommand ("follow"); trap_AddCommand ("levelshot"); trap_AddCommand ("addbot"); trap_AddCommand ("setviewpos"); - trap_AddCommand ("callvote"); trap_AddCommand ("vote"); - trap_AddCommand ("callteamvote"); - trap_AddCommand ("teamvote"); - trap_AddCommand ("stats"); - trap_AddCommand ("teamtask"); - trap_AddCommand ("loaddefered"); // spelled wrong, but not changing for demo + trap_AddCommand ("callvote"); + trap_AddCommand ("loaddeferred"); /* spelled wrong, but not changing for demo */ + + /*TiM - uh START MOD AGAIN */ + trap_AddCommand("laser"); + trap_AddCommand("flashlight"); + trap_AddCommand("cloak"); + trap_AddCommand("flight"); + trap_AddCommand("EVASuit"); + trap_AddCommand("forceName"); + trap_AddCommand("forceKill"); + trap_AddCommand("forceKillRadius"); + trap_AddCommand("shake"); + trap_AddCommand("drag"); + trap_AddCommand("undrag"); + trap_AddCommand("flushTripmines"); /* disarm_tripmines */ + trap_AddCommand("rank"); + trap_AddCommand("forceRank"); + trap_AddCommand("forceModel"); + trap_AddCommand("forcePlayer"); + trap_AddCommand("adminLogin"); + trap_AddCommand("adminList"); + trap_AddCommand("revive"); + trap_AddCommand("n00b"); + trap_AddCommand("msg"); + trap_AddCommand("playMusic"); + trap_AddCommand("stopMusic"); + trap_AddCommand("playSound"); + trap_AddCommand("fxGun"); + trap_AddCommand("flushFX"); + trap_AddCommand("clampInfo"); + trap_AddCommand("spawnChar"); + trap_AddCommand("flushChars"); + trap_AddCommand("flushEmote"); + trap_AddCommand("beamToPlayer"); + trap_AddCommand("beamToLocation"); + + trap_AddCommand("kick2"); + trap_AddCommand("botlist"); + trap_AddCommand("addip"); + trap_AddCommand("removeip"); + trap_AddCommand("listip"); + trap_AddCommand("game_memory"); + trap_AddCommand("entitylist"); + trap_AddCommand("useEnt" ); + + trap_AddCommand("banUser"); + trap_AddCommand("findID"); + trap_AddCommand("removeID"); + + trap_AddCommand("me"); + trap_AddCommand("meLocal"); + + trap_AddCommand("mapsList"); + + /* + * END MOD AGAIN + * TiM - May I just say. WOAH! THAT'S A LOT!! O_O! + */ + + /* + * START MOD AGAIN - xD + * by Marcin - 04/12/2008 + */ + trap_AddCommand("drop"); + trap_AddCommand("flushDropped"); + /* END MOD */ + + /* + * START MOD ANOTHER TIME xD + * GSIO01 | 08/05/2009 + */ + trap_AddCommand("lock"); + trap_AddCommand("ffColor"); + trap_AddCommand("remodulate"); + trap_AddCommand("unlockAll"); + trap_AddCommand("lockAll"); + trap_AddCommand("changeFreq"); + trap_AddCommand("alert"); + trap_AddCommand("msg2"); + trap_AddCommand("forcevote"); + trap_AddCommand("listSPs"); + trap_AddCommand("getEntInfo"); + trap_AddCommand("getOrigin"); + trap_AddCommand("getEntByTargetname"); + trap_AddCommand("getEntByTarget"); + trap_AddCommand("getEntByBmodel"); + trap_AddCommand("setOrigin"); + trap_AddCommand("getBrushEntCount"); + trap_AddCommand("findEntitiesInRadius"); + trap_AddCommand("spawnTEnt"); + trap_AddCommand("flushTEnts"); + + /* temp */ + trap_AddCommand("ui_holodeck"); + + /* sql */ + /* TODO some might be removed */ + trap_AddCommand("userlogin"); + trap_AddCommand("userAdd"); + trap_AddCommand("sql_setup"); + trap_AddCommand("userMod"); + trap_AddCommand("userDel"); + + /* lua */ + #ifdef CG_LUA + trap_AddCommand("lua_status"); + #endif + + /* cinematic cam test */ + trap_AddCommand("camtest"); + trap_AddCommand("camtestend"); + + trap_AddCommand("selfdestruct"); + trap_AddCommand("shipdamage"); + trap_AddCommand("shiphealth"); } + diff --git a/code/cgame/cg_draw.c b/code/cgame/cg_draw.c index 9666083..24eb8d1 100644 --- a/code/cgame/cg_draw.c +++ b/code/cgame/cg_draw.c @@ -1,205 +1,628 @@ /* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// -// cg_draw.c -- draw all of the graphical elements during -// active (after loading) gameplay + * Copyright (C) 1999-2000 Id Software, Inc. + * + * cg_draw.c -- draw all of the graphical elements during + * active (after loading) gameplay + */ #include "cg_local.h" +#include "cg_text.h" +#include "cg_screenfx.h" -#ifdef MISSIONPACK -#include "../ui/ui_shared.h" - -// used for scoreboard -extern displayContextDef_t cgDC; -menuDef_t *menuScoreboard = NULL; -#else -int drawTeamOverlayModificationCount = -1; -#endif - +/* set in CG_ParseTeamInfo */ int sortedTeamPlayers[TEAM_MAXOVERLAY]; int numSortedTeamPlayers; +int drawTeamOverlayModificationCount = -1; -char systemChat[256]; -char teamChat1[256]; -char teamChat2[256]; +/* + * TiM: dCross + * qboolean CG_WorldCoordToScreenCoord(vec3_t worldCoord, float *x, float *y, qboolean clamp); + * end dCross + */ -#ifdef MISSIONPACK +/* TiM: Tricorder Parameters */ +vec3_t vfwd; +vec3_t vright; +vec3_t vup; +vec3_t vfwd_n; +vec3_t vright_n; +vec3_t vup_n; +int infoStringCount; -int CG_Text_Width(const char *text, float scale, int limit) { - int count,len; - float out; - glyphInfo_t *glyph; - float useScale; -// FIXME: see ui_main.c, same problem -// const unsigned char *s = text; - const char *s = text; - fontInfo_t *font = &cgDC.Assets.textFont; - if (scale <= cg_smallFont.value) { - font = &cgDC.Assets.smallFont; - } else if (scale > cg_bigFont.value) { - font = &cgDC.Assets.bigFont; - } - useScale = scale * font->glyphScale; - out = 0; - if (text) { - len = strlen(text); - if (limit > 0 && len > limit) { - len = limit; +static qboolean drawCrosshairName=qfalse; + +extern void InitPostGameMenuStruct(); + +static void CG_InterfaceStartup(); + +char *ingame_text[IGT_MAX]; /* Holds pointers to ingame text */ + +int zoomFlashTime=0; + +/*typedef enum { + RADAR_UP, + RADAR_MIDDLE, + RADAR_DOWN +} radarType_t;*/ + +interfacegraphics_s interface_graphics[IG_MAX] = +{ +/* type timer x y width height file/text graphic, min max color style ptr */ + { SG_VAR, 0.0, 0, 0, 0, 0, NULL, 0, 0, 0, CT_NONE, 0 }, /* IG_GROW */ + + { SG_VAR, 0.0, 0, 0, 0, 0, NULL, 0, 0, 0, CT_NONE, 0 }, /* IG_HEALTH_START */ + { SG_GRAPHIC, 0.0, 5, 429, 32, 64, "gfx/interface/rpgx_healthbar_leftcorner", 0, 0, 0, CT_DKBROWN1, 0 }, /* IG_HEALTH_BEGINCAP */ + { SG_GRAPHIC, 0.0, 64, 429, 6, 25, "gfx/interface/ammobar", 0, 0, 0, CT_DKBROWN1, 0 }, /* IG_HEALTH_BOX1 */ + { SG_GRAPHIC, 0.0, 72, 429, 0, 25, "gfx/interface/ammobar", 0, 0, 0, CT_LTBROWN1, 0 }, /* IG_HEALTH_SLIDERFULL */ + { SG_GRAPHIC, 0.0, 0, 429, 0, 25, "gfx/interface/ammobar", 0, 0, 0, CT_DKBROWN1, 0 }, /* IG_HEALTH_SLIDEREMPTY */ + { SG_GRAPHIC, 0.0, 72, 429, 16, 32, "gfx/interface/rpgx_healthbar_endcap", 0, 0, 147, CT_DKBROWN1, 0 }, /* IG_HEALTH_ENDCAP */ + { SG_NUMBER, 0.0, 23, 425, 16, 32, NULL, 0, 0, 0, CT_LTBROWN1, NUM_FONT_BIG }, /* IG_HEALTH_COUNT */ + { SG_VAR, 0.0, 0, 0, 0, 0, NULL, 0, 0, 0, CT_NONE, 0 }, /* IG_HEALTH_END */ + + { SG_VAR, 0.0, 0, 0, 0, 0, NULL, 0, 0, 0, CT_NONE, 0 }, /* IG_ARMOR_START */ + { SG_GRAPHIC, 0.0, 20, 458, 32, 16, "gfx/interface/armorcap1", 0, 0, 0, CT_DKPURPLE1, 0 }, /* IG_ARMOR_BEGINCAP */ + { SG_GRAPHIC, 0.0, 64, 458, 6, 12, "gfx/interface/ammobar", 0, 0, 0, CT_DKPURPLE1, 0 }, /* IG_ARMOR_BOX1 */ + { SG_GRAPHIC, 0.0, 72, 458, 0, 12, "gfx/interface/ammobar", 0, 0, 0, CT_LTPURPLE1, 0 }, /* IG_ARMOR_SLIDERFULL */ + { SG_GRAPHIC, 0.0, 0, 458, 0, 12, "gfx/interface/ammobar", 0, 0, 0, CT_DKPURPLE1, 0 }, /* IG_ARMOR_SLIDEREMPTY */ + { SG_GRAPHIC, 0.0, 72, 458, 16, 16, "gfx/interface/armorcap2", 0, 0, 147, CT_DKPURPLE1, 0 }, /* IG_ARMOR_ENDCAP */ + { SG_NUMBER, 0.0, 44, 458, 16, 16, NULL, 0, 0, 0, CT_LTPURPLE1, NUM_FONT_SMALL }, /* IG_ARMOR_COUNT */ + { SG_VAR, 0.0, 0, 0, 0, 0, NULL, 0, 0, 0, CT_NONE, 0 }, /* IG_ARMOR_END */ + + { SG_VAR, 0.0, 0, 0, 0, 0, NULL, 0, 0, 0, CT_NONE, 0 }, /* IG_AMMO_START */ + { SG_GRAPHIC, 0.0, 613, 429, 32, 64, "gfx/interface/ammouppercap1", 0, 0, 0, CT_LTPURPLE2, 0 }, /* IG_AMMO_UPPER_BEGINCAP */ + { SG_GRAPHIC, 0.0, 607, 429, 16, 32, "gfx/interface/ammouppercap2", 0, 0, 572, CT_LTPURPLE2, 0 }, /* IG_AMMO_UPPER_ENDCAP */ + { SG_GRAPHIC, 0.0, 613, 458, 16, 16, "gfx/interface/ammolowercap1", 0, 0, 0, CT_LTPURPLE2, 0 }, /* IG_AMMO_LOWER_BEGINCAP */ + { SG_GRAPHIC, 0.0, 578, 458, 0, 12, "gfx/interface/ammobar", 0, 0, 0, CT_LTPURPLE1, 0 }, /* IG_AMMO_SLIDERFULL */ + { SG_GRAPHIC, 0.0, 0, 458, 0, 12, "gfx/interface/ammobar", 0, 0, 0, CT_DKPURPLE1, 0 }, /* IG_AMMO_SLIDEREMPTY */ + { SG_GRAPHIC, 0.0, 607, 458, 16, 16, "gfx/interface/ammolowercap2", 0, 0, 572, CT_LTPURPLE2, 0 }, /* IG_AMMO_LOWER_ENDCAP */ + { SG_NUMBER, 0.0, 573, 425, 16, 32, NULL, 0, 0, 0, CT_LTPURPLE1, NUM_FONT_BIG }, /* IG_AMMO_COUNT */ + { SG_VAR, 0.0, 0, 0, 0, 0, NULL, 0, 0, 0, CT_NONE, 0 }, /* IG_AMMO_END */ + +}; + +#define LOWEROVERLAY_Y (SCREEN_HEIGHT - ICON_SIZE - 15) + +/*------------------------------------------------------*/ + +lensFlare_t lensFlare[MAX_LENS_FLARES]; + +lensReflec_s lensReflec[10] = +{ +/* width, height, offset, positive, color, shadername, shaders placeholder */ + { 23, 23, 0.192, qtrue, { 0.73, 0.50, 0.23 }, "gfx/effects/flares/flare_straight", 0 }, /* Brown1 5.2 */ + { 9, 9, 0.37, qtrue, { 0.37, 0.58, 0.55 }, "gfx/effects/flares/flare_straight", 0 }, /* Aqua1 2.7 */ + { 14, 14, 0.25, qfalse, { 0.37, 0.79, 0.76 }, "gfx/effects/flares/flare_radial", 0 }, /* Turquoise1 4.0 */ + { 86, 86, 0.556, qfalse, { 0.73, 0.50, 0.23 }, "gfx/effects/flares/flare_inverseradial", 0 }, /* BigBrownInverseRad 1.8 */ + { 49, 49, 0.476, qfalse, { 0.73, 0.50, 0.23 }, "gfx/effects/flares/flare_straight", 0 }, /* StraightBrown2 2.1 */ + { 35, 35, 0.667, qfalse, { 0.34, 0.40, 0.44 }, "gfx/effects/flares/flare_straight", 0 }, /* Grey1 1.5 */ + { 32, 32, 0.769, qfalse, { 0.20, 0.38, 0.62 }, "gfx/effects/flares/flare_radial", 0 }, /* BlueRad 1.3 */ + { 122, 122, 1.1, qfalse, { 0.31, 0.65, 0.36 }, "gfx/effects/flares/flare_inverseradial", 0 }, /* BigInverseGreen 0.9 */ + { 254, 254, 1.429, qfalse, { 1.00, 1.00, 1.00 }, "gfx/effects/flares/flare_chromadisc", 0 }, /* ChromaHoop 0.7 */ + { 52, 52, 1.429, qtrue, { 0.40, 0.56, 0.42 }, "gfx/effects/flares/flare_inverseradial", 0 }, /* Green offset 0.7 */ +}; + +#define HALF_SCREEN_WIDTH (SCREEN_WIDTH*0.5) +#define HALF_SCREEN_HEIGHT (SCREEN_HEIGHT*0.5) + +void CG_InitLensFlare( vec3_t worldCoord, + int w1, int h1, + vec3_t glowColor, float glowOffset, float hazeOffset, int minDist, int maxDist, + vec3_t streakColor, int streakDistMin, int streakDistMax, int streakW, int streakH, qboolean whiteStreaks, + int reflecDistMin, int reflecDistMax, qboolean reflecAnamorphic, qboolean defReflecs, + qboolean clamp, float maxAlpha, int startTime, int upTime, int holdTime, int downTime ) +{ + int i; + + /* First thing's first.... I understand if you hate flares :'( */ + if (!cg_dynamiclensflares.value) + return; + + for (i = 0; i < MAX_LENS_FLARES; i++) { /* find the next free slot */ + if ( !lensFlare[i].qfull ) { + /* VectorCopy(worldCoord, lensFlare[i].worldCoord); */ + lensFlare[i].worldCoord[0] = worldCoord[0]; + lensFlare[i].worldCoord[1] = worldCoord[1]; + lensFlare[i].worldCoord[2] = worldCoord[2]; + lensFlare[i].w1 = w1; + lensFlare[i].h1 = h1; + /* VectorCopy(glowColor, lensFlare[i].glowColor); */ + lensFlare[i].glowColor[0] = glowColor[0]; + lensFlare[i].glowColor[1] = glowColor[1]; + lensFlare[i].glowColor[2] = glowColor[2]; + lensFlare[i].glowOffset = glowOffset; + lensFlare[i].hazeOffset = hazeOffset; + lensFlare[i].minDist = minDist; + lensFlare[i].maxDist = maxDist; + /* VectorCopy(streakColor, lensFlare[i].streakColor); */ + lensFlare[i].streakColor[0] = streakColor[0]; + lensFlare[i].streakColor[1] = streakColor[1]; + lensFlare[i].streakColor[2] = streakColor[2]; + lensFlare[i].streakDistMin = streakDistMin; + lensFlare[i].streakDistMax = streakDistMax; + lensFlare[i].streakW = streakW; + lensFlare[i].streakH = streakH; + lensFlare[i].whiteStreaks = whiteStreaks; + lensFlare[i].reflecDistMin = reflecDistMin; + lensFlare[i].reflecDistMax = reflecDistMax; + lensFlare[i].reflecAnamorphic = reflecAnamorphic; + lensFlare[i].defReflecs = defReflecs; + lensFlare[i].clamp = clamp; + lensFlare[i].maxAlpha = maxAlpha; + lensFlare[i].startTime = startTime; + lensFlare[i].upTime = upTime; + lensFlare[i].holdTime = holdTime; + lensFlare[i].downTime = downTime; + lensFlare[i].qfull = qtrue; + + break; } - count = 0; - while (s && *s && count < len) { - if ( Q_IsColorString(s) ) { - s += 2; - continue; - } else { - glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build - out += glyph->xSkip; - s++; - count++; - } - } - } - return out * useScale; + } + } -int CG_Text_Height(const char *text, float scale, int limit) { - int len, count; - float max; - glyphInfo_t *glyph; - float useScale; -// TTimo: FIXME -// const unsigned char *s = text; - const char *s = text; - fontInfo_t *font = &cgDC.Assets.textFont; - if (scale <= cg_smallFont.value) { - font = &cgDC.Assets.smallFont; - } else if (scale > cg_bigFont.value) { - font = &cgDC.Assets.bigFont; - } - useScale = scale * font->glyphScale; - max = 0; - if (text) { - len = strlen(text); - if (limit > 0 && len > limit) { - len = limit; + +/* +================= +CG_WorldCoordToScreenCoord +**Blatently plagiarised from EF SP** + +OMFG this is some damn whacky maths! +It basically takes a vector variable and somehow +correlates that to an XY value on your screen!! O_o +================= +*/ + +static qboolean CG_WorldCoordToScreenCoord(vec3_t worldCoord, float *x, float *y, qboolean clamp) +{ + int xcenter, ycenter; + vec3_t local, transformed; + vec3_t fwd; + vec3_t right; + vec3_t up; + float xzi; + float yzi; + +/* xcenter = cg.refdef.width / 2;*//*gives screen coords adjusted for resolution*/ +/* ycenter = cg.refdef.height / 2;*//*gives screen coords adjusted for resolution*/ + + /* + * NOTE: did it this way because most draw functions expect virtual 640x480 coords + * and adjust them for current resolution + */ + /*xcenter = 640 * 0.5;*//*gives screen coords in virtual 640x480, to be adjusted when drawn*/ + /*ycenter = 480 * 0.5;*//*gives screen coords in virtual 640x480, to be adjusted when drawn*/ + xcenter = 640 >> 1; + ycenter = 480 >> 1; + + AngleVectors (cg.refdefViewAngles, fwd, right, up); + VectorSubtract (worldCoord, cg.refdef.vieworg, local); + + transformed[0] = DotProduct(local,right); + transformed[1] = DotProduct(local,up); + transformed[2] = DotProduct(local,fwd); + + /* Make sure Z is not negative. */ + if(transformed[2] < 0.01) + { + if ( clamp ) + { + transformed[2] = 0.01f; } - count = 0; - while (s && *s && count < len) { - if ( Q_IsColorString(s) ) { - s += 2; - continue; - } else { - glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build - if (max < glyph->height) { - max = glyph->height; - } - s++; - count++; - } - } - } - return max * useScale; -} - -void CG_Text_PaintChar(float x, float y, float width, float height, float scale, float s, float t, float s2, float t2, qhandle_t hShader) { - float w, h; - w = width * scale; - h = height * scale; - CG_AdjustFrom640( &x, &y, &w, &h ); - trap_R_DrawStretchPic( x, y, w, h, s, t, s2, t2, hShader ); -} - -void CG_Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style) { - int len, count; - vec4_t newColor; - glyphInfo_t *glyph; - float useScale; - fontInfo_t *font = &cgDC.Assets.textFont; - if (scale <= cg_smallFont.value) { - font = &cgDC.Assets.smallFont; - } else if (scale > cg_bigFont.value) { - font = &cgDC.Assets.bigFont; - } - useScale = scale * font->glyphScale; - if (text) { -// TTimo: FIXME -// const unsigned char *s = text; - const char *s = text; - trap_R_SetColor( color ); - memcpy(&newColor[0], &color[0], sizeof(vec4_t)); - len = strlen(text); - if (limit > 0 && len > limit) { - len = limit; + else + { + return qfalse; } - count = 0; - while (s && *s && count < len) { - glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build - //int yadj = Assets.textFont.glyphs[text[i]].bottom + Assets.textFont.glyphs[text[i]].top; - //float yadj = scale * (Assets.textFont.glyphs[text[i]].imageHeight - Assets.textFont.glyphs[text[i]].height); - if ( Q_IsColorString( s ) ) { - memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) ); - newColor[3] = color[3]; - trap_R_SetColor( newColor ); - s += 2; - continue; - } else { - float yadj = useScale * glyph->top; - if (style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE) { - int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2; - colorBlack[3] = newColor[3]; - trap_R_SetColor( colorBlack ); - CG_Text_PaintChar(x + ofs, y - yadj + ofs, - glyph->imageWidth, - glyph->imageHeight, - useScale, - glyph->s, - glyph->t, - glyph->s2, - glyph->t2, - glyph->glyph); - colorBlack[3] = 1.0; - trap_R_SetColor( newColor ); - } - CG_Text_PaintChar(x, y - yadj, - glyph->imageWidth, - glyph->imageHeight, - useScale, - glyph->s, - glyph->t, - glyph->s2, - glyph->t2, - glyph->glyph); - // CG_DrawPic(x, y - yadj, scale * cgDC.Assets.textFont.glyphs[text[i]].imageWidth, scale * cgDC.Assets.textFont.glyphs[text[i]].imageHeight, cgDC.Assets.textFont.glyphs[text[i]].glyph); - x += (glyph->xSkip * useScale) + adjust; - s++; - count++; - } - } - trap_R_SetColor( NULL ); - } + } + /* Simple convert to screen coords. */ + xzi = xcenter / transformed[2] * (96.0/cg.refdef.fov_x);/*90*/ /*95*/ + yzi = ycenter / transformed[2] * (102.0/cg.refdef.fov_y);/*90*/ /*105*/ + + *x = (float)(xcenter + xzi * transformed[0]); + *y = (float)(ycenter - yzi * transformed[1]); + + return qtrue; } -#endif +/************************************* +CG_FlareScreenTrans - TiM + +Used to return an alpha value +based on how far the xy value is +from two boundaries (Used mainly +for when the flare exits the screen +and fades out) + +The function works by drawing an imaginary +line from the minimum point to the maximum +point. If a point is above that line, +the Y value is used to calculate the alpha, +else, the X value does. +There is a slight bit +of jerkiness if the point crosses this line, +but much less worse than what was before. :) +*************************************/ + +static float CG_FlareScreenTrans(int x, int y, int xmin, int ymin, int xmax, int ymax ) +{ + /* + * Think about it, when the XY points are in separate quadrants of the screen, + * they're all the same values anyway, but just either negative or positive. + * Making them all positive, and working on just that set kills about 8 birds with a fricken' huge stone. >:) + */ + int lx = abs(x); + int ly = abs(y); + int lxmin = abs(xmin); + int lymin = abs(ymin); + int lxmax = abs(xmax); + int lymax = abs(ymax); + int xDif = lxmax - lxmin; + int yDif = lymax - lymin; + float grad = ( (float)lymax/(float)lxmax ); /* calc the grad as if (xmin, ymin) were the origin */ + + float alpha = 1.0; + + /* if xy is under minimums, just make it 1 :P */ + if (lx < lxmin && ly < lymin ) { + return alpha; + } + + if ( ly < (lx * grad) ) {/* point is running along the side bar */ + alpha = (float)( 1.0 - ( (float)lx - (float)lxmin ) / (float)xDif ); + /* CG_Printf("SIDE BAR!!!! alpha = %f, ly = %i, lymin = %i, yDif = %i\n", alpha, ly, lymin, yDif); */ + } + + if ( ly > ( lx * grad) ) {/* point is running along the top bar */ + alpha = (float)( 1.0 - ( (float)ly - (float)lymin ) / (float)yDif ); + /* CG_Printf("TOP BAR!!!! alpha = %f, lx = %i, lxmin = %i, xDif = %i, xEq = %f\n", alpha, lx, lxmin, xDif, ((float)lx * grad) ); */ + } + + /* if xy has exceeded maxes, just make it 0 :P */ + if ( lx >= lxmax || ly >= lymax ) + alpha = 0.0; + + /* Lock it just in case something weird happened. :S */ + if ( alpha > 1.0 ) + alpha = 1.0; + if ( alpha < 0.0 ) + alpha = 0.0; + + return alpha; + +} + + +/* +================ +CG_CorrelateMaxMinDist + +Calcuates an alpha value +between a min and a max point +so elements can fade in or out +depending on relative distance :) +================ +*/ +static float CG_CorrelateMaxMinDist( float len, int min, int max ) { + + float alpha = 1.0; + + if ( min == max && max == 0 ) /* This means it will always be off */ + return 0.0; + + if ( min <= 0 ) /* this means that the parameter wants it to always be on */ + return alpha; + + alpha = /*1.0 -*/ ( len - (float)min ) / ((float)max - (float)min); /* calculate the alpha */ + + if (alpha > 1.0 ) /* Clamp it.... again */ + alpha = 1.0; + if (alpha < 0.0 ) + alpha = 0.0; + + return alpha; + +} + +/* +================ +CG_FadeAlpha + +Modified version of +CG_FadeColor. Only +covers alpha values now, +and also has an option +to fade in as well as out +================ +*/ +float CG_FadeAlpha( int startMsec, int totalMsec, qboolean fade_in ) { + static float alpha; + int t; + + if ( startMsec == 0 ) { + return (fade_in ? 0.0 : 1.0); + } + + t = cg.time - startMsec; + + if ( t >= totalMsec ) { + return (fade_in ? 1.0 : 0.0); + } + + // fade out + if ( totalMsec - t < FADE_TIME ) { + if (!fade_in) + alpha = ( totalMsec - t ) * 1.0/FADE_TIME; + else + alpha = 1.0 - (( totalMsec - t ) * 1.0/FADE_TIME); + } else { + alpha = fade_in ? 0.0 : 1.0; + } + + return alpha; +} + +/* +================ +CG_FlareTraceTrans + +Performs a trace between player +and origin, and if anything gets in +the way, an alpha value is generated +to make the flare fade out +================ +*/ + +static float prevFrac = 0.0; +static int fadeTime, fadeInTime; + +static qboolean CG_FlareTraceTrans ( vec3_t origin, float* alpha ) +{ + trace_t trace; + + CG_Trace( &trace, origin, NULL, NULL, cg.refdef.vieworg, -1, CONTENTS_SOLID|CONTENTS_BODY ); //Do a trace // switched start and end + + if ( fadeTime > 0 && fadeInTime == 0 ) { + *alpha = CG_FadeAlpha( fadeTime, 199, qfalse ); + if (*alpha == 0.0) + fadeTime = 0.0f; + } + + if ( fadeInTime > 0 && fadeTime == 0 ) { + *alpha = CG_FadeAlpha( fadeInTime, 199, qtrue ); + if (*alpha == 1.0) + fadeInTime = 0.0f; + } + + //fade out the flare + if (trace.fraction < 1.0 && prevFrac == 1.0 ) { + fadeTime = cg.time; + prevFrac = trace.fraction; + } + + //fade in the flare + if (trace.fraction == 1.0 && prevFrac < 1.0 ) { + fadeInTime = cg.time; + prevFrac = trace.fraction; + } + + if (fadeTime > 0 && fadeInTime > 0) { //Whoa, how did this happen??? + fadeTime = 0; //reset them both and all is good :) + fadeInTime = 0; + } + + if ( (fadeTime == 0.0 && fadeInTime == 0.0 ) && ( *alpha > 0.0 && *alpha < 1.0 ) ) //Now THIS effect was weird O_o + *alpha = 1.0; + + if (trace.fraction < 1.0 && prevFrac < 1.0 && fadeTime == 0 && fadeInTime == 0) { + prevFrac = trace.fraction; + return qfalse; + } + + return qtrue; + +} + +/************************************************************* +CG_DrawLensFlare - RPG-X : TiM +OMFG LENSFLARES R COOL!!!!! ^_^!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +Yes, I know I'm over-doing it now, coding this uber-huge +processor-intensive, totally un-necessary lensflare engine ;P + +Parameters Key: + +vec3_t worldCoord : Position in world to draw the flare +int w1, h1 : Initial (Maximum) w + h of the flare core +vec3_t glowColor : Color of the flare's glow +float glowOffset : Multiplier how much bigger the glow is than the core +float hazeOffset : Multiplier how much bigger the surrounding haze is to the core +int minDist : Minimum distance before the flare loses all brightness (Set to 0 if always normal size) +int maxDist : Maximum distance for flare's brightness +vec3_t streakColor : Color of the flare's lens reflections (if 0,0,0, then a default blue is used) +int streakDistMin : Distance at where the flare is totally transparent (Set to 0 if always on) +int streakDistMax : Distance at where the flare is totally opaque (Set to same as above to turn it always off) +int streakW : Length of the anamorphic lens streak +int streakH : Height of the anamorphic lens streak +qboolean whiteStreaks : Adds white streaks to the center of normal streaks ;P +int reflecDistMin : Distance at where the reflections are totally transparent (Set to NULL if always on) +int reflecDistMax : Distance at where the reflections are totally opaque (Set to same value as above if wanted off) +qboolean reflecAnamorphic : Enables anamorphic lens reflections +qboolean defReflecs : Makes the Lens Reflections default colors +qboolean clamp : If qtrue, the lensflare will not resize as the distance changes +float maxAlpha : All alpha values of the elements in the flare will not exceed this number +int upTime : How long it takes for the flare to go from 0 intense to maximum intense +int holdTime : How long the flare stays at max intensity for +int downTime : How long it takes for the flare to go from max intensity to 0. + +**************************************************************/ + +void CG_DrawLensFlare( lensFlare_t *flare ) +{ + int w = flare->w1; + int h = flare->h1; + float x, y, streakX, streakY; + int xCart, yCart; + int i; + vec4_t color, reflecColor, strkColor; + int xMax, yMax; + vec3_t distDif, black = {0.0, 0.0, 0.0}; + int maxTime = flare->upTime + flare->holdTime + flare->downTime; + int tMaxTime = maxTime + flare->startTime; + int tUpTime = flare->upTime + flare->startTime; + int tHoldTime = flare->upTime + flare->holdTime + flare->startTime; + int tDownTime = flare->upTime + flare->holdTime + flare->downTime + flare->startTime; + float length; + + float reflecAlpha = 1.0; //alpha channel of reflections + float streakAlpha = 1.0; //alpha channel of streaks + float boundAlpha = 1.0; //alpha if flare leaves screen + float commonAlpha = 1.0; //alpha variables common too all elements + float hazeAlpha = 1.0; + + static float fadeAlpha; //This can't have a default value otherwise it screws up the flare fade transition + static float timeAlpha; //Alpha/w/h over the specified time + + //First thing's first.... I understand if you hate flares :'( + if (!cg_dynamiclensflares.value) + return; + + //if we can't get an XY value, screw it :P + if ( !CG_WorldCoordToScreenCoord( flare->worldCoord, &x, &y, qfalse) ) + return; + + //if we can't actually see the flare in line of sight, screw it again. :P + if( !CG_FlareTraceTrans( flare->worldCoord, &fadeAlpha) ) + return; + + if (maxTime > 0 && cg.time <= tMaxTime) { + + if ( cg.time <= tUpTime ) + timeAlpha = (float)(cg.time - flare->startTime) * (float)(1.0/(float)flare->upTime); + + if (cg.time <= tHoldTime && cg.time > tUpTime ) + timeAlpha = 1.0; + + if (cg.time <= tDownTime && cg.time > tHoldTime ) + timeAlpha = 1.0 - ( (float)(cg.time - flare->startTime) * (float)(1.0/(float)flare->downTime) ); + } + + if (maxTime == 0 ) + timeAlpha = 1.0; + + w = w * timeAlpha; + h = h * timeAlpha; + + //calc the distance between the player and the flare + VectorSubtract( flare->worldCoord, cg.refdef.vieworg, distDif ); + length = VectorNormalize( distDif ); + + //if the clamp boolean is false, resize the flare over player distance from it + if ( !flare->clamp ) { + w = w * CG_CorrelateMaxMinDist(length, flare->minDist, flare->maxDist ); //Change size/height in relation to distance + h = h * CG_CorrelateMaxMinDist(length, flare->minDist, flare->maxDist ); + } + + xCart = (int)(x - HALF_SCREEN_WIDTH ); //Re-orient the EF drawing engine so co-ord (0,0) is in the middle of the screen) + yCart = (int)(y - HALF_SCREEN_HEIGHT ); + + streakX = (xCart - (flare->streakW*0.5)) + HALF_SCREEN_WIDTH; //Calculate X value of lens streak based on flare position + streakY = (yCart - (flare->streakH*0.5)) + HALF_SCREEN_HEIGHT; //Calculate Y value of lens streak based on flare position + + xMax = (w*0.5) + HALF_SCREEN_WIDTH; //define the point the flare should fully fade out + yMax = (h*0.5) + HALF_SCREEN_HEIGHT; + + if ( boundAlpha > 0.0 ) { //Calculate the reflections' opacity in contrast to the edge of the screen + boundAlpha = CG_FlareScreenTrans( xCart, yCart, HALF_SCREEN_WIDTH, HALF_SCREEN_HEIGHT, xMax, yMax); + } + + //set up all of the elements with their various alphas :P + commonAlpha = commonAlpha * fadeAlpha * boundAlpha * flare->maxAlpha; + + if (commonAlpha * timeAlpha < 0.01 ) //no point in drawing if it's really really faint + return; + + reflecAlpha = reflecAlpha * commonAlpha * timeAlpha * CG_CorrelateMaxMinDist(length, flare->reflecDistMin, flare->reflecDistMax ); + streakAlpha = streakAlpha * commonAlpha * timeAlpha * CG_CorrelateMaxMinDist(length, flare->streakDistMin, flare->streakDistMax ); + hazeAlpha = hazeAlpha * commonAlpha; + + //Copy in the color the user wants, but we need control of the alpha. + VectorCopy( flare->glowColor, color ); + color[3] = hazeAlpha; + + if ( VectorCompare( flare->streakColor, black) ) { //If they specified no streakcolor, use this awesome default blue one :) + strkColor[0] = 0.31; + strkColor[1] = 0.45; + strkColor[2] = 1.0; + strkColor[3] = streakAlpha; + } + else { //else, use the color they wanted + VectorCopy( flare->streakColor, strkColor ); + strkColor[3] = streakAlpha; + } + + //Lens Reflections - those cool circly bits that go in the opposite direction of the flare + if ( reflecAlpha != 0.0 ) {//Sheez, only do this if we really WANT it O_o + for( i = 0; i < 10; i++ ) { + + //if they wanted the cool photoshoppy style reflections + if ( flare->defReflecs ) { + VectorCopy( lensReflec[i].color, reflecColor ); + reflecColor[3] = reflecAlpha; + } + else { //otherwise, just use the color they picked + VectorCopy( color, reflecColor ); + reflecColor[3] = reflecAlpha; + } + + trap_R_SetColor( reflecColor ); + + CG_DrawPic( + ( ( ( lensReflec[i].positive ? xCart : -xCart ) * lensReflec[i].offset ) + HALF_SCREEN_WIDTH ) - ( flare->reflecAnamorphic ? lensReflec[i].width : lensReflec[i].width*0.5 ), //X + ( ( ( lensReflec[i].positive ? yCart : -yCart ) * lensReflec[i].offset ) + HALF_SCREEN_HEIGHT ) - ( lensReflec[i].height*0.5 ), //Y + flare->reflecAnamorphic ? lensReflec[i].width * 2 : lensReflec[i].width, //W + lensReflec[i].height, //H + lensReflec[i].graphic //pic + ); + } + } + + //Colored Middle + Streaks + trap_R_SetColor( color ); + if ( color[3] > 0.0 ) { + x = ( xCart - ( (w*flare->hazeOffset) *0.5) + HALF_SCREEN_WIDTH ); + y = ( yCart - ( (h*flare->hazeOffset) *0.5) + HALF_SCREEN_HEIGHT ); + CG_DrawPic( x, y, w*flare->hazeOffset, h*flare->hazeOffset, cgs.media.flareHaze ); //Surrounding ambient haze + } + + trap_R_SetColor( strkColor ); + if ( strkColor[3] > 0.0f ) + CG_DrawPic( streakX , streakY , flare->streakW, flare->streakH, cgs.media.flareStreak ); //Colored portion of the anamorphic streaks + + trap_R_SetColor( color ); + if ( color[3] > 0.0f ) { + x = ( xCart - ( (w*flare->glowOffset) *0.5) + HALF_SCREEN_WIDTH ); + y = ( yCart - ( (h*flare->glowOffset) *0.5) + HALF_SCREEN_HEIGHT ); + CG_DrawPic( x, y, w*flare->glowOffset, h*flare->glowOffset, cgs.media.flareCore ); //Main colored glow bit of the main flare + } + + if ( flare->whiteStreaks ) { //if player wanted white streaks in their streaks + strkColor[0] = strkColor[1] = strkColor[2] = 1.0; + + trap_R_SetColor( strkColor ); //White + if ( strkColor[3] > 0.0 ) + CG_DrawPic( streakX + (flare->streakW*0.2), streakY + (flare->streakH*0.2), flare->streakW*0.6, flare->streakH*0.6, cgs.media.flareStreak ); //White Core of streak is ALWAYS 20% smaller. + } + + color[0] = color[1] = color [2] = 1.0f; + color[3] = hazeAlpha; + + trap_R_SetColor( color ); + if ( color[3] > 0.0 ) { + x = ( xCart - (w *0.5) + HALF_SCREEN_WIDTH ); + y = ( yCart - (h *0.5) + HALF_SCREEN_HEIGHT ); + CG_DrawPic( x, y, w, h, cgs.media.flareCore ); //Draw teh main fl4r3 :) + } + //CG_Printf("worldCoord = %f, colorAlpha = %f, streakAlpha = %f, streakColor = %f \n", flare->worldCoord[0], color[3], strkColor[3], strkColor[2]); +} /* ============== @@ -208,22 +631,26 @@ CG_DrawField Draws large numbers for status bar and powerups ============== */ -#ifndef MISSIONPACK -static void CG_DrawField (int x, int y, int width, int value) { +/* +static void CG_DrawField (int x, int y, int width, int value) +{ char num[16], *ptr; int l; int frame; - if ( width < 1 ) { + if ( width < 1 ) + { return; } // draw number string - if ( width > 5 ) { + if ( width > 5 ) + { width = 5; } - switch ( width ) { + switch ( width ) + { case 1: value = value > 9 ? 9 : value; value = value < 0 ? 0 : value; @@ -262,7 +689,7 @@ static void CG_DrawField (int x, int y, int width, int value) { l--; } } -#endif // MISSIONPACK +*/ /* ================ @@ -270,7 +697,7 @@ CG_Draw3DModel ================ */ -void CG_Draw3DModel( float x, float y, float w, float h, qhandle_t model, qhandle_t skin, vec3_t origin, vec3_t angles ) { +static void CG_Draw3DModel( float x, float y, float w, float h, qhandle_t model, qhandle_t skin, qhandle_t shader, vec3_t origin, vec3_t angles ) { refdef_t refdef; refEntity_t ent; @@ -287,6 +714,7 @@ void CG_Draw3DModel( float x, float y, float w, float h, qhandle_t model, qhandl VectorCopy( origin, ent.origin ); ent.hModel = model; ent.customSkin = skin; + ent.customShader = shader; ent.renderfx = RF_NOSHADOW; // no stencil shadows refdef.rdflags = RDF_NOWORLDMODEL; @@ -315,16 +743,27 @@ CG_DrawHead Used for both the status bar and the scoreboard ================ */ + +//extern qhandle_t CG_CurrentHeadSkin( centity_t* cent, clientInfo_t* ci ); + void CG_DrawHead( float x, float y, float w, float h, int clientNum, vec3_t headAngles ) { clipHandle_t cm; + centity_t *cent; clientInfo_t *ci; + playerState_t *ps; + float value; float len; vec3_t origin; vec3_t mins, maxs; + cent = &cg_entities[ clientNum ]; ci = &cgs.clientinfo[ clientNum ]; - if ( cg_draw3dIcons.integer ) { + ps = &cg.snap->ps; + + value = ps->stats[STAT_HEALTH]; + + if ( cg_draw3dIcons.integer && (ci->headOffset[0] != 404) ) { cm = ci->headModel; if ( !cm ) { return; @@ -344,15 +783,28 @@ void CG_DrawHead( float x, float y, float w, float h, int clientNum, vec3_t head // allow per-model tweaking VectorAdd( origin, ci->headOffset, origin ); - CG_Draw3DModel( x, y, w, h, ci->headModel, ci->headSkin, origin, headAngles ); + CG_Draw3DModel( x, y, w, h, ci->headModel, ci->headSkin, 0, origin, headAngles ); + + if ((value < 82.000000) && (value >= 65.000000)){ + CG_Draw3DModel( x, y, w, h, ci->headModel, ci->headSkin, 0, origin, headAngles ); + }else if(value >= 49.000000){ + CG_Draw3DModel( x, y, w, h, ci->headModel, ci->headSkin, 0, origin, headAngles ); + }else if(value >= 32.000000){ + CG_Draw3DModel( x, y, w, h, ci->headModel, ci->headSkin, 0, origin, headAngles ); + }else if(value >= 2.000000){ + CG_Draw3DModel( x, y, w, h, ci->headModel, ci->headSkin, 0, origin, headAngles ); + }else if(value <= 1.000000){ + CG_Draw3DModel( x, y, w, h, ci->headModel, ci->headSkin, 0, origin, headAngles ); + } } else if ( cg_drawIcons.integer ) { CG_DrawPic( x, y, w, h, ci->modelIcon ); } - - // if they are deferred, draw a cross out - if ( ci->deferred ) { - CG_DrawPic( x, y, w, h, cgs.media.deferShader ); - } + + //if ( cgs.clientinfo[clientNum].health <= 1 ) {//if eliminated, draw the cross-out + // CG_DrawPic( x, y, w, h, cgs.media.eliminatedShader ); + //} else if ( ci->deferred ) {// if they are deferred, draw a cross out +// CG_DrawPic( x, y, w, h, cgs.media.deferShader ); + //} } /* @@ -362,14 +814,13 @@ CG_DrawFlagModel Used for both the status bar and the scoreboard ================ */ -void CG_DrawFlagModel( float x, float y, float w, float h, int team, qboolean force2D ) { +void CG_DrawFlagModel( float x, float y, float w, float h, int team ) { qhandle_t cm; float len; vec3_t origin, angles; vec3_t mins, maxs; - qhandle_t handle; - if ( !force2D && cg_draw3dIcons.integer ) { + if ( cg_draw3dIcons.integer ) { VectorClear( angles ); @@ -388,43 +839,27 @@ void CG_DrawFlagModel( float x, float y, float w, float h, int team, qboolean fo angles[YAW] = 60 * sin( cg.time / 2000.0 );; - if( team == TEAM_RED ) { - handle = cgs.media.redFlagModel; - } else if( team == TEAM_BLUE ) { - handle = cgs.media.blueFlagModel; - } else if( team == TEAM_FREE ) { - handle = cgs.media.neutralFlagModel; - } else { - return; - } - CG_Draw3DModel( x, y, w, h, handle, 0, origin, angles ); + CG_Draw3DModel( x, y, w, h, + team == TEAM_RED ? cgs.media.redFlagModel : cgs.media.blueFlagModel, 0, + team == TEAM_RED ? cgs.media.redFlagShader[3] : cgs.media.blueFlagShader[3], origin, angles ); } else if ( cg_drawIcons.integer ) { - gitem_t *item; + //gitem_t *item = BG_FindItemForPowerup( team == TEAM_RED ? PW_REDFLAG : PW_BORG_ADAPT ); - if( team == TEAM_RED ) { - item = BG_FindItemForPowerup( PW_REDFLAG ); - } else if( team == TEAM_BLUE ) { - item = BG_FindItemForPowerup( PW_BLUEFLAG ); - } else if( team == TEAM_FREE ) { - item = BG_FindItemForPowerup( PW_NEUTRALFLAG ); - } else { - return; - } - if (item) { - CG_DrawPic( x, y, w, h, cg_items[ ITEM_INDEX(item) ].icon ); - } + /*if (item) + { + CG_DrawPic( x, y, w, h, cg_items[ ITEM_INDEX(item) ].icon ); + }*/ } } /* ================ CG_DrawStatusBarHead - +RPG-X | Phenix | 09/06/2005 +I dont know who commented this out but it's going back in ;) ================ */ -#ifndef MISSIONPACK - -static void CG_DrawStatusBarHead( float x ) { +static int CG_DrawStatusBarHead( float x ) { vec3_t angles; float size, stretch; float frac; @@ -461,6 +896,8 @@ static void CG_DrawStatusBarHead( float x ) { size = ICON_SIZE * 1.25; } + size = size * 3; + // if the server was frozen for a while we may have a bad head start time if ( cg.headStartTime > cg.time ) { cg.headStartTime = cg.time; @@ -471,22 +908,11 @@ static void CG_DrawStatusBarHead( float x ) { angles[YAW] = cg.headStartYaw + ( cg.headEndYaw - cg.headStartYaw ) * frac; angles[PITCH] = cg.headStartPitch + ( cg.headEndPitch - cg.headStartPitch ) * frac; - CG_DrawHead( x, 480 - size, size, size, + CG_DrawHead( x, 480 - (size + BIGCHAR_HEIGHT + 5), size, size, cg.snap->ps.clientNum, angles ); -} -#endif // MISSIONPACK -/* -================ -CG_DrawStatusBarFlag - -================ -*/ -#ifndef MISSIONPACK -static void CG_DrawStatusBarFlag( float x, int team ) { - CG_DrawFlagModel( x, 480 - ICON_SIZE, ICON_SIZE, ICON_SIZE, team, qfalse ); + return size; } -#endif // MISSIONPACK /* ================ @@ -494,161 +920,798 @@ CG_DrawTeamBackground ================ */ -void CG_DrawTeamBackground( int x, int y, int w, int h, float alpha, int team ) +void CG_DrawTeamBackground( int x, int y, int w, int h, float alpha, int team, qboolean scoreboard ) { vec4_t hcolor; hcolor[3] = alpha; - if ( team == TEAM_RED ) { + if ( team == TEAM_RED ) + { hcolor[0] = 1; hcolor[1] = 0; hcolor[2] = 0; - } else if ( team == TEAM_BLUE ) { + } + else if ( team == TEAM_BLUE ) + { hcolor[0] = 0; hcolor[1] = 0; hcolor[2] = 1; - } else { - return; + } + else + { + return; // no team } + trap_R_SetColor( hcolor ); CG_DrawPic( x, y, w, h, cgs.media.teamStatusBar ); trap_R_SetColor( NULL ); } +/* +================ +CG_DrawAmmo + +================ +*/ +static void CG_DrawAmmo(centity_t *cent) +{ + float value; +// float xLength; + playerState_t *ps; +// int max,brightColor_i,darkColor_i,numColor_i; + + ps = &cg.snap->ps; + + value = ps->ammo[cent->currentState.weapon]; + + return; +} + +//RPG-X: - RedTechie NO ARMOR! how many times do i have to say it! +/* +================ +CG_DrawArmor + +================ +*/ +/* +static void CG_DrawArmor(centity_t *cent) +{ + int max; + float value,xLength; + playerState_t *ps; + int lengthMax; + + ps = &cg.snap->ps; + + value = ps->stats[STAT_ARMOR]; + + interface_graphics[IG_ARMOR_COUNT].max = value; + + if (interface_graphics[IG_ARMOR_COUNT].max <= ps->stats[STAT_MAX_HEALTH]) + { + interface_graphics[IG_ARMOR_COUNT].color = CT_LTPURPLE1; // + interface_graphics[IG_ARMOR_SLIDERFULL].color = CT_LTPURPLE1; // + interface_graphics[IG_ARMOR_COUNT].style &= ~UI_PULSE; // Numbers + } + else + { + interface_graphics[IG_ARMOR_COUNT].color = CT_LTGREY; // Numbers + interface_graphics[IG_ARMOR_SLIDERFULL].color = CT_LTGREY; // + interface_graphics[IG_ARMOR_COUNT].style |= UI_PULSE; // Numbers + } + + + +// if (cg.oldarmor < value) +// { +// cg.oldArmorTime = cg.time + 100; +// } + +// cg.oldarmor = value; + +// if (cg.oldArmorTime < cg.time) +// { +// interface_graphics[IG_ARMOR_COUNT].color = CT_LTPURPLE1; // Numbers +// } +// else +// { +// interface_graphics[IG_ARMOR_COUNT].color = CT_YELLOW; // Numbers +// } + + + max = ps->stats[STAT_MAX_HEALTH]; + lengthMax = 73; + if (max > 0) + { + if (value > max) + { + xLength = lengthMax; + } + else + { + xLength = lengthMax * (value/max); + } + + } + else + { + max = 0; + xLength = 0; + } + + // Armor empty section + interface_graphics[IG_ARMOR_SLIDEREMPTY].x = 72 + xLength; + interface_graphics[IG_ARMOR_SLIDEREMPTY].width = lengthMax - xLength; + + // Armor full section + interface_graphics[IG_ARMOR_SLIDERFULL].width = xLength; + + CG_PrintInterfaceGraphics(IG_ARMOR_START + 1,IG_ARMOR_END); + +} +*/ + +//RPG-X: - RedTechie Close but no cigar we need 3 stage health not a bar +/* +================ +CG_DrawHealth + +================ +*/ + +/*static void CG_DrawHealth(centity_t *cent) +{ + int max; + float value,xLength; + playerState_t *ps; + int lengthMax; + + ps = &cg.snap->ps; + + value = ps->stats[STAT_HEALTH]; + + + // Changing colors on numbers +// if (cg.oldhealth < value) +// { +// cg.oldHealthTime = cg.time + 100; +// } +// cg.oldhealth = value; + + // Is health changing? +// if (cg.oldHealthTime < cg.time) +// { +// interface_graphics[IG_HEALTH_COUNT].color = CT_LTBROWN1; // Numbers +// } +// else +// { +// } + interface_graphics[IG_HEALTH_COUNT].max = value; + + if (interface_graphics[IG_HEALTH_COUNT].max <= ps->stats[STAT_MAX_HEALTH]) + { + interface_graphics[IG_HEALTH_COUNT].color = CT_LTBROWN1; // + interface_graphics[IG_HEALTH_SLIDERFULL].color = CT_LTBROWN1; // + interface_graphics[IG_HEALTH_SLIDEREMPTY].color = CT_DKBROWN1; // + interface_graphics[IG_HEALTH_COUNT].style &= ~UI_PULSE; // Numbers + } + else + { + interface_graphics[IG_HEALTH_COUNT].color = CT_LTGREY; // Numbers + interface_graphics[IG_HEALTH_SLIDERFULL].color = CT_LTGREY; // + interface_graphics[IG_HEALTH_COUNT].style |= UI_PULSE; // Numbers + } + + // Calculating size of health bar + max = ps->stats[STAT_MAX_HEALTH]; + lengthMax = 73; + if (max > 0) + { + if (value < max) + { + xLength = lengthMax * (value/max); + } + else // So the graphic doesn't extend past the cap + { + xLength = lengthMax; + } + } + else + { + max = 0; + xLength = 0; + } + + // Health empty section + interface_graphics[IG_HEALTH_SLIDEREMPTY].x = 72 + xLength; + interface_graphics[IG_HEALTH_SLIDEREMPTY].width = lengthMax - xLength; + + // Health full section + interface_graphics[IG_HEALTH_SLIDERFULL].width = xLength; + + // Print it + CG_PrintInterfaceGraphics(IG_HEALTH_START + 1,IG_HEALTH_END); +}*/ + +//RPG-X: - RedTechie This is more like it +/* +================ +CG_DrawHealth +New Draw health function by yours truly RedTechie +New version by TiM lol +================ +*/ + +//static int CG_DrawHealth( centity_t *cent ) +//{ +// float value; +// float offset; +// float yOffset; +// +// value = cg.snap->ps.stats[STAT_HEALTH]; +// +// //Draw static graphics first +// CG_FillRect( 8, 428, 89, 1, colorTable[CT_LTPURPLE1] ); +// CG_FillRect( 8, 429, 1, 44, colorTable[CT_LTPURPLE1] ); +// CG_FillRect( 8, 473, 89, 1, colorTable[CT_LTPURPLE1] ); +// CG_FillRect( 96, 429, 1, 44, colorTable[CT_LTPURPLE1] ); +// +// //Okay... we'll need to work out some funky math here later... +// //For now, let's just test +// offset = (( (float)(cg.time % 2000) / 2000.0f ) * (1.0f+(1.0f-(value/100.0f)) * 0.25f)); +// yOffset = (value / 100.0f ) * 21.0f ; +// //CG_Printf( "%f\n", offset ); +// +// trap_R_SetColor( NULL ); +// CG_DrawStretchPic( 9, 450 - yOffset, 87, yOffset * 2.0f, 0.0f + offset, 0.0f, (1.0f+(1.0f-(value/100.0f)) * 0.25f) + offset, 1.0f, cgs.media.healthSineWave ); +// //CG_DrawStretchPic( 16, 413, 123, 60, 1.0f, 1.0f, 2.0f, 2.0f, cgs.media.healthSineWave ); +// +// return 125; +//} + +static int CG_DrawHealth(centity_t *cent) +{ + float value; + playerState_t *ps; + char *health_str = NULL; + int health_barwidth; + vec_t *health_txtcolor = NULL; + int health_txteffect = 0; + int x, y; + + ps = &cg.snap->ps; + + value = ps->stats[STAT_HEALTH]; + + //RPG-X: RedTechie - The GROSS math part icky icky! + if(value >= 82.000000){ + health_str = ingame_text[IGT_SB_HEALTHSTATUS1]; //RPG-X and SFEF + health_txtcolor = colorTable[CT_DKPURPLE2]; + health_txteffect = UI_BIGFONT; + }else if(value >= 65.000000){ + health_str = ingame_text[IGT_SB_HEALTHSTATUS2]; //Scott Carter, after being locked in a room with rpg-x team for 20 minuts.. + health_txtcolor = colorTable[CT_DKPURPLE2]; + health_txteffect = UI_BIGFONT; + }else if(value >= 49.000000){ + health_str = ingame_text[IGT_SB_HEALTHSTATUS3]; //Results after 10 minutes + health_txtcolor = colorTable[CT_LTBLUE2]; + health_txteffect = UI_BIGFONT; + }else if(value >= 32.000000){ + health_str = ingame_text[IGT_SB_HEALTHSTATUS4]; //Results after 15 minutes + health_txtcolor = colorTable[CT_LTBLUE2]; + health_txteffect = UI_BIGFONT; + }else if(value >= 2.000000){ + health_str = ingame_text[IGT_SB_HEALTHSTATUS5]; //Results after 20 minutes + health_txtcolor = colorTable[CT_VDKBLUE2]; + health_txteffect = UI_BIGFONT; + }else if(value <= 1.000000){ + health_str = ingame_text[IGT_SB_HEALTHSTATUS6]; //Final result - post your comments here coders ;) - + //What do you mean final result - this is like after 30 seconds in a room with the rpg-x team :P (Phenix) + health_txtcolor = colorTable[CT_RED]; //More like 10 -TiM + health_txteffect = UI_BIGFONT; + } + //Get a accurate width + health_barwidth = UI_ProportionalStringWidth(health_str,UI_BIGFONT); + + //Doom Style Health! + if (doomHead.integer == 1) + { + health_barwidth = CG_DrawStatusBarHead( 2 ); + health_barwidth = ((health_barwidth / 2) + 2) - (UI_ProportionalStringWidth(health_str,UI_BIGFONT) / 2); + UI_DrawProportionalString(health_barwidth, 460 - BIGCHAR_HEIGHT, health_str, health_txteffect, health_txtcolor); + + return health_barwidth; + } else { + x = 3; + y = 435; + + //Draw the text + UI_DrawProportionalString(x + 46, y + 11, health_str, health_txteffect, health_txtcolor); + + //RPG-X: - RedTechie The Graphics :) + + trap_R_SetColor( colorTable[CT_DKBLUE1] ); + CG_DrawPic( x, y, 85, 22, cgs.media.healthbigcurve ); //RPG-X: Big Curve //x,y,w,h=32 + CG_DrawPic( x + 49 + health_barwidth, y, 8, 7, cgs.media.healthendcap ); //RPG-X: Top End Cap - 133 + CG_DrawPic( x + 49 + health_barwidth, y + 37, 8, 7, cgs.media.healthendcap ); //RPG-X: Bottum End Cap - 133 //CG_DrawPic( x + 49 + health_barwidth, y + 49, 16, 16, cgs.media.healthendcap ); + CG_FillRect( x, y + 15, 40, 20, colorTable[CT_DKBLUE1]); //Extra bit to fill in the gap under the curve graphic + + CG_FillRect( x, y + 37, 40, 7, colorTable[CT_DKGOLD1]); //RPG-X: Middle bar //15 + CG_FillRect( x + 42, y + 37, 5+health_barwidth, 7, colorTable[CT_DKBLUE1]); //RPG-X: Bottum Horizontal bar - CG_FillRect( 45, 469, 86+health_barwidth, 15, colorTable[CT_DKBLUE1]); + CG_FillRect( x + 47, y, health_barwidth, 7, colorTable[CT_DKBLUE1]); //RPG-X: Top Horizontal bar - CG_FillRect( 61, 420, 70+health_barwidth, 15, colorTable[CT_DKBLUE1]); + + //RPG-X: RedTechie - Some eye candy text + UI_DrawProportionalString( x +40-3, y + 23, ingame_text[IGT_SB_HEALTHBARLCARS], UI_TINYFONT|UI_RIGHT, colorTable[CT_BLACK]);//456 +//x + 12 + return health_barwidth + 82; + } +} + /* ================ CG_DrawStatusBar ================ */ -#ifndef MISSIONPACK -static void CG_DrawStatusBar( void ) { - int color; +static void CG_DrawStatusBar( void ) +{ centity_t *cent; playerState_t *ps; - int value; - vec4_t hcolor; vec3_t angles; - vec3_t origin; + int y=0; + vec4_t whiteA; + int x, z, i, h, yZ; + vec3_t tmpVec, eAngle, forward, dAngle; + //RPG-X: Redtechie - for the HACK code below + //int rpg_shakemycamera; + int healthBarWidth; + //float rpg_shakemycamera_intensity; + //const char *info; - static float colors[4][4] = { -// { 0.2, 1.0, 0.2, 1.0 } , { 1.0, 0.2, 0.2, 1.0 }, {0.5, 0.5, 0.5, 1} }; - { 1.0f, 0.69f, 0.0f, 1.0f }, // normal - { 1.0f, 0.2f, 0.2f, 1.0f }, // low health - { 0.5f, 0.5f, 0.5f, 1.0f }, // weapon firing - { 1.0f, 1.0f, 1.0f, 1.0f } }; // health > 100 + /*static float colors[4][4] = + { + { 1, 0.69, 0, 1.0 } , // normal + { 1.0, 0.2, 0.2, 1.0 }, // low health + {0.5, 0.5, 0.5, 1}, // weapon firing + { 1, 1, 1, 1 } }; // health > 100*/ + + whiteA[0] = whiteA[1] = whiteA[2] = 1.0f; whiteA[3] = 0.3f; + + cent = &cg_entities[cg.snap->ps.clientNum]; + + //RPG-X: RedTechie - HACK HACK HACK!!!! this needs to be called soon to check to shake the players cameras + /*info = CG_ConfigString( CS_SERVERINFO ); + rpg_shakemycamera = atoi( Info_ValueForKey( info, "rpg_servershakeallclients" ) ); + rpg_shakemycamera_intensity = atof( Info_ValueForKey( info, "rpg_servershakeallclientsintensity" ) ); + if(rpg_shakemycamera == 1){ + CG_CameraShake(rpg_shakemycamera_intensity,300); + }*/ if ( cg_drawStatus.integer == 0 ) { return; } // draw the team background - CG_DrawTeamBackground( 0, 420, 640, 60, 0.33f, cg.snap->ps.persistant[PERS_TEAM] ); + CG_DrawTeamBackground( 0, 420, 640, 60, 0.33, cg.snap->ps.persistant[PERS_TEAM], qfalse ); - cent = &cg_entities[cg.snap->ps.clientNum]; ps = &cg.snap->ps; VectorClear( angles ); // draw any 3D icons first, so the changes back to 2D are minimized - if ( cent->currentState.weapon && cg_weapons[ cent->currentState.weapon ].ammoModel ) { - origin[0] = 70; - origin[1] = 0; - origin[2] = 0; - angles[YAW] = 90 + 20 * sin( cg.time / 1000.0 ); - CG_Draw3DModel( CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE, - cg_weapons[ cent->currentState.weapon ].ammoModel, 0, origin, angles ); + y = (SCREEN_HEIGHT - (4*ICON_SIZE) - 20); + /*if (cg.predictedPlayerState.powerups[PW_REDFLAG]) + { //fixme: move to powerup renderer? make it pulse? + // CG_FillRect( 5, y, ICON_SIZE*2, ICON_SIZE*2, whiteA); + CG_DrawFlagModel( 5, y, ICON_SIZE*2, ICON_SIZE*2, TEAM_RED ); + }*/ + /*else if (cg.predictedPlayerState.powerups[PW_BORG_ADAPT]) + { + // CG_FillRect( 5, y, ICON_SIZE*2, ICON_SIZE*2, whiteA); + // CG_DrawFlagModel( 5, y, ICON_SIZE*2, ICON_SIZE*2, TEAM_BLUE ); + //RPG-X | GSIO01 | 08/05/2009: we have flag in rpg? haha + }*/ + + // Do start + if (!cg.interfaceStartupDone) + { + CG_InterfaceStartup(); } - CG_DrawStatusBarHead( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE ); - - if( cg.predictedPlayerState.powerups[PW_REDFLAG] ) { - CG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_RED ); - } else if( cg.predictedPlayerState.powerups[PW_BLUEFLAG] ) { - CG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_BLUE ); - } else if( cg.predictedPlayerState.powerups[PW_NEUTRALFLAG] ) { - CG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_FREE ); - } - - if ( ps->stats[ STAT_ARMOR ] ) { - origin[0] = 90; - origin[1] = 0; - origin[2] = -10; - angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0; - CG_Draw3DModel( 370 + CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE, - cgs.media.armorModel, 0, origin, angles ); - } // // ammo // - if ( cent->currentState.weapon ) { - value = ps->ammo[cent->currentState.weapon]; - if ( value > -1 ) { - if ( cg.predictedPlayerState.weaponstate == WEAPON_FIRING - && cg.predictedPlayerState.weaponTime > 100 ) { - // draw as dark grey when reloading - color = 2; // dark grey - } else { - if ( value >= 0 ) { - color = 0; // green - } else { - color = 1; // red - } - } - trap_R_SetColor( colors[color] ); - - CG_DrawField (0, 432, 3, value); - trap_R_SetColor( NULL ); - - // if we didn't draw a 3D icon, draw a 2D icon for ammo - if ( !cg_draw3dIcons.integer && cg_drawIcons.integer ) { - qhandle_t icon; - - icon = cg_weapons[ cg.predictedPlayerState.weapon ].ammoIcon; - if ( icon ) { - CG_DrawPic( CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE, icon ); - } - } - } + if ( cent->currentState.weapon ) + { + CG_DrawAmmo(cent); } + // // health // - value = ps->stats[STAT_HEALTH]; - if ( value > 100 ) { - trap_R_SetColor( colors[3] ); // white - } else if (value > 25) { - trap_R_SetColor( colors[0] ); // green - } else if (value > 0) { - color = (cg.time >> 8) & 1; // flash - trap_R_SetColor( colors[color] ); - } else { - trap_R_SetColor( colors[1] ); // red + //RPG-X | Phenix | 09/06/2005 + // Added return of the width for the cloak etc messages + healthBarWidth = CG_DrawHealth(cent); + + + // RPG-X + // Print RPG Flags + //By: RedTechie & Phenix + // + if(cg.predictedPlayerState.powerups[PW_EVOSUIT] || cg.predictedPlayerState.powerups[PW_FLIGHT] || cg.predictedPlayerState.powerups[PW_INVIS]){ + //RPG-X | Phenix | 08/06/2005 + yZ = 478 - SMALLCHAR_HEIGHT; + // UI_BIGFONT + //DEBUG + if(cg.predictedPlayerState.powerups[PW_EVOSUIT]) { + UI_DrawProportionalString(healthBarWidth, yZ, ingame_text[IGT_SB_EVOSUITSTATUS], UI_SMALLFONT, colorTable[CT_CYAN]); + yZ -= SMALLCHAR_HEIGHT + 2; + } + if(cg.predictedPlayerState.powerups[PW_INVIS]){ + UI_DrawProportionalString(healthBarWidth, yZ, ingame_text[IGT_SB_CLOAKSTATUS], UI_SMALLFONT, colorTable[CT_RED]); + yZ -= SMALLCHAR_HEIGHT + 2; + } + if(cg.predictedPlayerState.powerups[PW_FLIGHT]){ + UI_DrawProportionalString(healthBarWidth, yZ, ingame_text[IGT_SB_FLIGHTSTATUS], UI_SMALLFONT, colorTable[CT_RED]); + yZ -= SMALLCHAR_HEIGHT + 2; + } } - // stretch the health up when taking damage - CG_DrawField ( 185, 432, 3, value); - CG_ColorForHealth( hcolor ); - trap_R_SetColor( hcolor ); - - // // armor // - value = ps->stats[STAT_ARMOR]; - if (value > 0 ) { - trap_R_SetColor( colors[0] ); - CG_DrawField (370, 432, 3, value); - trap_R_SetColor( NULL ); - // if we didn't draw a 3D icon, draw a 2D icon for armor - if ( !cg_draw3dIcons.integer && cg_drawIcons.integer ) { - CG_DrawPic( 370 + CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE, cgs.media.armorIcon ); + //RPG-X: - Redtechie IT A FRICKEN RP NOOOO ARMOR! OMG! + //CG_DrawArmor(cent); + + // Radar + // By Sam "-=Jazz=-"Dickinson + // http://www.telefragged.com/jazz + if ( ( cg.snap->ps.weapon == WP_2 || cg.snap->ps.weapon == WP_6 ) && cg_drawradar.integer != 0 && !cg.zoomed ) + { + vec4_t radColor; + + CG_DrawPic(40, 100, 100, 100, cgs.media.radarShader); + for (i = 0; i < cg.snap->numEntities; i++) // Go through all entities in VIS range + { + if ( cg.snap->entities[i].eType == ET_PLAYER ) // If the Entity is a Player + { + // Calculate How Far Away They Are + x = (cg.snap->entities[i].pos.trBase[0] - cg.predictedPlayerState.origin[0]); + y = (cg.snap->entities[i].pos.trBase[1] - cg.predictedPlayerState.origin[1]); + z = (cg.snap->entities[i].pos.trBase[2] - cg.predictedPlayerState.origin[2]); + tmpVec[0] = x; + tmpVec[1] = y; + tmpVec[2] = 0.0; + + // Convert Vector to Angle + vectoangles(tmpVec, eAngle); + h = sqrt((x*x) + (y*y)); // Get Range + + // We only Want "YAW" value + dAngle[0] = 0.0; + dAngle[1] = AngleSubtract(eAngle[1] - 180, cg.predictedPlayerState.viewangles[1]) + 180; + dAngle[0] = 0.0; + + // Convert Angle back to Vector + AngleVectors(dAngle, forward, NULL, NULL); + VectorScale(forward, h/32, forward); +// if (h/32 < 100 && h/32 > 0) // Limit Radar Range +// { + // Draw up arrow if above, down if below, or an ordinary blip if level + // With tolerance of +- 5 units + //RPG-X: RedTechie - No teams in a RP + /*if ( cgs.gametype >= GT_TEAM ) + { + if ( cgs.clientinfo[cg.snap->entities[i].number].team == TEAM_BLUE ) + { + if (z > 64) + { + CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_blue_up); + } + else if (z < -64) + { + CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_blue_down); + } + else + { + CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_blue_level); + } + } + else if ( cgs.clientinfo[cg.snap->entities[i].number].team == TEAM_RED ) + { + if (z > 64) + { + CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_red_up); + } + else if (z < -64) + { + CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_red_down); + } + else + { + CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_red_level); + } + } + }*/ + //RPG-X: RedTechie - If Dead show them as a medical symbol + //.number + if (h/32 < 100 && h/32 > 0) { // Limit Radar Range + if ( cg_entities[cg.snap->entities[i].number].currentState.eFlags & EF_DEAD ) + { + if (z > 64) + { + CG_DrawStretchPic( 86 - forward[1], 146 - forward[0], 16, 8, 0, 0, 1, 0.5, cgs.media.rd_injured_level ); + //CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_injured_up); + } + else if (z < -64) + { + //CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_injured_down); + CG_DrawStretchPic( 86 - forward[1], 146 - forward[0], 16, 8, 0, 0.5, 1, 1, cgs.media.rd_injured_level ); + } + else + { + CG_DrawPic(86 - forward[1], 146 - forward[0], 16, 16, cgs.media.rd_injured_level); + } + } + else + { + //if ( cgs.clientinfo[cg.snap->entities[i].number].pClass == PC_COMMAND ) + //{ + // /*if (z > 64) + // { + // CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_red_up); + // } + // else if (z < -64) + // { + // CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_red_down); + // } + // else + // { + // CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_red_level); + // }*/ + // //trap_R_SetColor( colorTable[CT_RED] ); + // VectorCopy( colorTable[CT_RED], radColor ); + // radColor[3] = colorTable[CT_RED][3]; + //} + //else if ( cgs.clientinfo[cg.snap->entities[i].number].pClass == PC_SCIENCE ) + //{ + // /*if (z > 64) + // { + // CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_teal_up); + // } + // else if (z < -64) + // { + // CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_teal_down); + // } + // else + // { + // CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_teal_level); + // }*/ + // //trap_R_SetColor( colorTable[CT_TEAL] ); + // VectorCopy( colorTable[CT_TEAL], radColor ); + // radColor[3] = colorTable[CT_TEAL][3]; + //} + //else if ( cgs.clientinfo[cg.snap->entities[i].number].pClass == PC_SECURITY ) + //{ + // /*if (z > 64) + // { + // CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_blue_up); + // } + // else if (z < -64) + // { + // CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_blue_down); + // } + // else + // { + // CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_blue_level); + // }*/ + // //trap_R_SetColor( colorTable[CT_GOLD] ); + // VectorCopy( colorTable[CT_GOLD], radColor ); + // radColor[3] = colorTable[CT_GOLD][3]; + //} + //else if ( cgs.clientinfo[cg.snap->entities[i].number].pClass == PC_MEDICAL ) + //{ + // /*if (z > 64) + // { + // CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_white_up); + // } + // else if (z < -64) + // { + // CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_white_down); + // } + // else + // { + // CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_white_level); + // }*/ + // //trap_R_SetColor( colorTable[CT_TEAL] ); + // VectorCopy( colorTable[CT_TEAL], radColor ); + // radColor[3] = colorTable[CT_TEAL][3]; + //} + //else if ( cgs.clientinfo[cg.snap->entities[i].number].pClass == PC_ENGINEER ) + //{ + // /*if (z > 64) + // { + // CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_up); + // } + // else if (z < -64) + // { + // CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_down); + // } + // else + // { + // CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_level); + // }*/ + // //trap_R_SetColor( colorTable[CT_GOLD] ); + // VectorCopy( colorTable[CT_GOLD], radColor ); + // radColor[3] = colorTable[CT_GOLD][3]; + //} + //else if ( cgs.clientinfo[cg.snap->entities[i].number].pClass == PC_ALPHAOMEGA22 ) + //{ + // /*if (z > 64) + // { + // CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_teal_up); + // } + // else if (z < -64) + // { + // CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_teal_down); + // } + // else + // { + // CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_teal_level); + // }*/ + // //trap_R_SetColor( colorTable[CT_GREEN] ); + // VectorCopy( colorTable[CT_GREEN], radColor ); + // radColor[3] = colorTable[CT_GREEN][3]; + //} + //else if ( cgs.clientinfo[cg.snap->entities[i].number].pClass == PC_ADMIN && cg.snap->ps.persistant[PERS_CLASS] != PC_ADMIN ) + //{ + // //RPG-X: RedTechie - Dont show admins on radar unless you are a admin + //} + if ( cgs.clientinfo[cg.snap->entities[i].number].pClass >= 0 ) + { + radColor[0] = (float)cgs.classData[cgs.clientinfo[cg.snap->entities[i].number].pClass].radarColor[0] / 255.0f; + radColor[1] = (float)cgs.classData[cgs.clientinfo[cg.snap->entities[i].number].pClass].radarColor[1] / 255.0f; + radColor[2] = (float)cgs.classData[cgs.clientinfo[cg.snap->entities[i].number].pClass].radarColor[2] / 255.0f; + radColor[3] = 1.0f; + } + else + { + + /*if (z > 64) + { + CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_black_up); + } + else if (z < -64) + { + CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_black_down); + } + else + { + CG_DrawPic(86 - forward[1], 146 - forward[0], 7, 7, cgs.media.rd_black_level); + }*/ + //trap_R_SetColor( colorTable[CT_BLACK] ); + VectorCopy( colorTable[CT_BLACK], radColor ); + radColor[3] = colorTable[CT_BLACK][3]; + } + + if ( cgs.clientinfo[cg.snap->entities[i].number].isAdmin && !cgs.clientinfo[cg.snap->ps.clientNum].isAdmin ) + continue; + + if ( z > 64 ) + { + trap_R_SetColor( radColor ); + CG_DrawStretchPic( 86 - forward[1], 146 - forward[0], 8, 4, 0, 0, 1, 0.5, cgs.media.radarMain ); + } + else if ( z < -64 ) + { + trap_R_SetColor( radColor ); + CG_DrawStretchPic( 86 - forward[1], 146 - forward[0], 8, 4, 0, 0.5, 1, 1, cgs.media.radarMain ); + } + else + { + trap_R_SetColor( radColor ); + CG_DrawPic( 86 - forward[1], 146 - forward[0], 8, 8, cgs.media.radarMain ); + } + trap_R_SetColor( NULL ); + } + } + } + } + } + // End Radar +} + +/* +================ +CG_InterfaceStartup +================ +*/ +static void CG_InterfaceStartup() +{ + + // Turn on Health Graphics + if ((interface_graphics[IG_HEALTH_START].timer < cg.time) && (interface_graphics[IG_HEALTH_BEGINCAP].type == SG_OFF)) + { + trap_S_StartLocalSound( cgs.media.interfaceSnd1, CHAN_LOCAL_SOUND ); + + interface_graphics[IG_HEALTH_BEGINCAP].type = SG_GRAPHIC; + interface_graphics[IG_HEALTH_BOX1].type = SG_GRAPHIC; + interface_graphics[IG_HEALTH_ENDCAP].type = SG_GRAPHIC; + } + + // Turn on Armor Graphics + //RPG-X: - RedTechie how many times do i have to say NO ARMOR IN RP's! + /*if ((interface_graphics[IG_ARMOR_START].timer < cg.time) && (interface_graphics[IG_ARMOR_BEGINCAP].type == SG_OFF)) + { + if (interface_graphics[IG_ARMOR_BEGINCAP].type == SG_OFF) + { + trap_S_StartLocalSound( cgs.media.interfaceSnd1, CHAN_LOCAL_SOUND ); } + interface_graphics[IG_ARMOR_BEGINCAP].type = SG_GRAPHIC; + interface_graphics[IG_ARMOR_BOX1].type = SG_GRAPHIC; + interface_graphics[IG_ARMOR_ENDCAP].type = SG_GRAPHIC; + + }*/ + + // Turn on Ammo Graphics + if (interface_graphics[IG_AMMO_START].timer < cg.time) + { + if (interface_graphics[IG_AMMO_UPPER_BEGINCAP].type == SG_OFF) + { + trap_S_StartLocalSound( cgs.media.interfaceSnd1, CHAN_LOCAL_SOUND ); + interface_graphics[IG_GROW].type = SG_VAR; + interface_graphics[IG_GROW].timer = cg.time; + } + + interface_graphics[IG_AMMO_UPPER_BEGINCAP].type = SG_GRAPHIC; + interface_graphics[IG_AMMO_UPPER_ENDCAP].type = SG_GRAPHIC; + interface_graphics[IG_AMMO_LOWER_BEGINCAP].type = SG_GRAPHIC; + interface_graphics[IG_AMMO_LOWER_ENDCAP].type = SG_GRAPHIC; } + + if (interface_graphics[IG_GROW].type == SG_VAR) + { + interface_graphics[IG_HEALTH_ENDCAP].x += 2; + interface_graphics[IG_ARMOR_ENDCAP].x += 2; + interface_graphics[IG_AMMO_UPPER_ENDCAP].x -= 1; + interface_graphics[IG_AMMO_LOWER_ENDCAP].x -= 1; + + if (interface_graphics[IG_HEALTH_ENDCAP].x >= interface_graphics[IG_HEALTH_ENDCAP].max) + { + interface_graphics[IG_HEALTH_ENDCAP].x = interface_graphics[IG_HEALTH_ENDCAP].max; + interface_graphics[IG_ARMOR_ENDCAP].x = interface_graphics[IG_ARMOR_ENDCAP].max; + + interface_graphics[IG_AMMO_UPPER_ENDCAP].x = interface_graphics[IG_AMMO_UPPER_ENDCAP].max; + interface_graphics[IG_AMMO_LOWER_ENDCAP].x = interface_graphics[IG_AMMO_LOWER_ENDCAP].max; + interface_graphics[IG_GROW].type = SG_OFF; + + interface_graphics[IG_HEALTH_SLIDERFULL].type = SG_GRAPHIC; + interface_graphics[IG_HEALTH_SLIDEREMPTY].type = SG_GRAPHIC; + interface_graphics[IG_HEALTH_COUNT].type = SG_NUMBER; + + interface_graphics[IG_ARMOR_SLIDERFULL].type = SG_GRAPHIC; + interface_graphics[IG_ARMOR_SLIDEREMPTY].type = SG_GRAPHIC; + interface_graphics[IG_ARMOR_COUNT].type = SG_NUMBER; + + interface_graphics[IG_AMMO_SLIDERFULL].type = SG_GRAPHIC; + interface_graphics[IG_AMMO_SLIDEREMPTY].type = SG_GRAPHIC; + interface_graphics[IG_AMMO_COUNT].type = SG_NUMBER; + + trap_S_StartLocalSound( cgs.media.interfaceSnd1, CHAN_LOCAL_SOUND ); + cg.interfaceStartupDone = 1; // All done + } + + interface_graphics[IG_GROW].timer = cg.time + 10; + } + + cg.interfaceStartupTime = cg.time; + + // kef -- init struct for post game awards + InitPostGameMenuStruct(); } -#endif /* =========================================================================================== @@ -664,7 +1727,7 @@ CG_DrawAttacker ================ */ -static float CG_DrawAttacker( float y ) { +/*static float CG_DrawAttacker( float y ) { int t; float size; vec3_t angles; @@ -701,10 +1764,11 @@ static float CG_DrawAttacker( float y ) { info = CG_ConfigString( CS_PLAYERS + clientNum ); name = Info_ValueForKey( info, "n" ); y += size; - CG_DrawBigString( 640 - ( Q_PrintStrlen( name ) * BIGCHAR_WIDTH), y, name, 0.5 ); +// CG_DrawBigString( 640 - ( Q_PrintStrlen( name ) * BIGCHAR_WIDTH), y, name, 0.5 ); + UI_DrawProportionalString( 635, y, name, UI_RIGHT | UI_SMALLFONT, colorTable[CT_LTGOLD1] ); return y + BIGCHAR_HEIGHT + 2; -} +}*/ /* ================== @@ -715,13 +1779,21 @@ static float CG_DrawSnapshot( float y ) { char *s; int w; - s = va( "time:%i snap:%i cmd:%i", cg.snap->serverTime, + s = va( "time:%i frametime:%i snap:%i cmd:%i", cg.snap->serverTime, cg.frametime, cg.latestSnapshotNum, cgs.serverCommandSequence ); - w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; - CG_DrawBigString( 635 - w, y + 2, s, 1.0F); + //y = (BIGCHAR_HEIGHT * 2) + 20; + - return y + BIGCHAR_HEIGHT + 4; + w = UI_ProportionalStringWidth(s,UI_BIGFONT); + + if ( cg_lagometer.integer && ( y < (BIGCHAR_HEIGHT * 2) + 20) ) { + w = w + 52; + } + + UI_DrawProportionalString(635 - (w - 2), y + 2, s, UI_BIGFONT, colorTable[CT_LTGOLD1]); + + return y + BIGCHAR_HEIGHT + 10; } /* @@ -760,12 +1832,16 @@ static float CG_DrawFPS( float y ) { fps = 1000 * FPS_FRAMES / total; s = va( "%ifps", fps ); - w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; - - CG_DrawBigString( 635 - w, y + 2, s, 1.0F); + w = UI_ProportionalStringWidth(s,UI_BIGFONT); + //RPG-X | Phenix | 08/06/2005 + // Changed "- w" to "- (w + 50)" to account for lagometer + if ( !cg_lagometer.integer ) { + w = w - 52; + } + UI_DrawProportionalString(635 - (w + 52), y + 2, s, UI_BIGFONT, colorTable[CT_LTGOLD1]); } - return y + BIGCHAR_HEIGHT + 4; + return y + BIGCHAR_HEIGHT + 10; } /* @@ -788,13 +1864,18 @@ static float CG_DrawTimer( float y ) { seconds -= tens * 10; s = va( "%i:%i%i", mins, tens, seconds ); - w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; - CG_DrawBigString( 635 - w, y + 2, s, 1.0F); + w = UI_ProportionalStringWidth(s,UI_BIGFONT); + // RPG-X | Phenix | 08/06/2005 + // Changed "- w" to "- (w + 50)" to account for lagometer + if ( !cg_lagometer.integer ) { + w = w - 52; + } + UI_DrawProportionalString(635 - (w + 52), y + 2, s, UI_BIGFONT, colorTable[CT_LTGOLD1]); - return y + BIGCHAR_HEIGHT + 4; + return y + BIGCHAR_HEIGHT + 10; } - +#define TINYPAD 1.25 /* ================= @@ -802,6 +1883,9 @@ CG_DrawTeamOverlay ================= */ +#define TEAM_OVERLAY_MAXNAME_WIDTH 12 +#define TEAM_OVERLAY_MAXLOCATION_WIDTH 16 + static float CG_DrawTeamOverlay( float y, qboolean right, qboolean upper ) { int x, w, h, xx; int i, j, len; @@ -811,29 +1895,38 @@ static float CG_DrawTeamOverlay( float y, qboolean right, qboolean upper ) { int plyrs; char st[16]; clientInfo_t *ci; - gitem_t *item; - int ret_y, count; + int ret_y; - if ( !cg_drawTeamOverlay.integer ) { + if ( !cg_drawTeamOverlay.integer ) + { return y; } - if ( cg.snap->ps.persistant[PERS_TEAM] != TEAM_RED && cg.snap->ps.persistant[PERS_TEAM] != TEAM_BLUE ) { + if ( cg.snap->ps.persistant[PERS_TEAM] != TEAM_RED && cg.snap->ps.persistant[PERS_TEAM] != TEAM_BLUE ) + { return y; // Not on any team } + if ( cg.snap->ps.pm_type == PM_INTERMISSION ) + { + return y; + } + plyrs = 0; + w = 0; // max player name width pwidth = 0; - count = (numSortedTeamPlayers > 8) ? 8 : numSortedTeamPlayers; - for (i = 0; i < count; i++) { + for (i = 0; i < numSortedTeamPlayers; i++) { ci = cgs.clientinfo + sortedTeamPlayers[i]; if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) { plyrs++; len = CG_DrawStrlen(ci->name); + if (len > pwidth) pwidth = len; + if ( ci->pClass >= 0 /*PC_NOCLASS*/ )//if any one of them has a class, then we alloc space for the icon + w = 1; } } @@ -857,14 +1950,15 @@ static float CG_DrawTeamOverlay( float y, qboolean right, qboolean upper ) { if (lwidth > TEAM_OVERLAY_MAXLOCATION_WIDTH) lwidth = TEAM_OVERLAY_MAXLOCATION_WIDTH; - w = (pwidth + lwidth + 4 + 7) * TINYCHAR_WIDTH; + w += (pwidth + lwidth + 4); + w *= (TINYCHAR_WIDTH * TINYPAD); if ( right ) x = 640 - w; else x = 0; - h = plyrs * TINYCHAR_HEIGHT; + h = plyrs * (TINYCHAR_HEIGHT * TINYPAD); if ( upper ) { ret_y = y + h; @@ -874,46 +1968,66 @@ static float CG_DrawTeamOverlay( float y, qboolean right, qboolean upper ) { } if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) { - hcolor[0] = 1.0f; - hcolor[1] = 0.0f; - hcolor[2] = 0.0f; - hcolor[3] = 0.33f; + hcolor[0] = 1; + hcolor[1] = 0; + hcolor[2] = 0; + hcolor[3] = 0.33; } else { // if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) - hcolor[0] = 0.0f; - hcolor[1] = 0.0f; - hcolor[2] = 1.0f; - hcolor[3] = 0.33f; + hcolor[0] = 0; + hcolor[1] = 0; + hcolor[2] = 1; + hcolor[3] = 0.33; } trap_R_SetColor( hcolor ); CG_DrawPic( x, y, w, h, cgs.media.teamStatusBar ); trap_R_SetColor( NULL ); - for (i = 0; i < count; i++) { + for (i = 0; i < numSortedTeamPlayers; i++) { ci = cgs.clientinfo + sortedTeamPlayers[i]; if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) { - hcolor[0] = hcolor[1] = hcolor[2] = hcolor[3] = 1.0; - xx = x + TINYCHAR_WIDTH; +//Draw class icon if appropriate + if ( ci->pClass >= 0/*PC_NOCLASS*/ ) + { + //qhandle_t icon; - CG_DrawStringExt( xx, y, - ci->name, hcolor, qfalse, qfalse, - TINYCHAR_WIDTH, TINYCHAR_HEIGHT, TEAM_OVERLAY_MAXNAME_WIDTH); + //Special hack: if it's Borg who has regen going, must be Borg queen + /*if ( ci->pClass == PC_BORG && (ci->powerups&(1<pClass]; + } + CG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT, icon );*/ + + xx += (TINYCHAR_WIDTH * TINYPAD); + } +//draw name +// CG_DrawStringExt( xx, y, +// ci->name, hcolor, qfalse, qfalse, +// TINYCHAR_WIDTH, TINYCHAR_HEIGHT, TEAM_OVERLAY_MAXNAME_WIDTH); + hcolor[0] = hcolor[1] = hcolor[2] = hcolor[3] = 1.0; + UI_DrawProportionalString( xx, y, ci->name, UI_TINYFONT, hcolor); if (lwidth) { p = CG_ConfigString(CS_LOCATIONS + ci->location); if (!p || !*p) p = "unknown"; -// len = CG_DrawStrlen(p); -// if (len > lwidth) -// len = lwidth; + len = CG_DrawStrlen(p); + if (len > lwidth) + len = lwidth; // xx = x + TINYCHAR_WIDTH * 2 + TINYCHAR_WIDTH * pwidth + // ((lwidth/2 - len/2) * TINYCHAR_WIDTH); xx = x + TINYCHAR_WIDTH * 2 + TINYCHAR_WIDTH * pwidth; - CG_DrawStringExt( xx, y, - p, hcolor, qfalse, qfalse, TINYCHAR_WIDTH, TINYCHAR_HEIGHT, - TEAM_OVERLAY_MAXLOCATION_WIDTH); +// CG_DrawStringExt( xx, y, +// p, hcolor, qfalse, qfalse, TINYCHAR_WIDTH, TINYCHAR_HEIGHT, +// TEAM_OVERLAY_MAXLOCATION_WIDTH); + UI_DrawProportionalString( xx, y, p, UI_TINYFONT, hcolor); + } CG_GetColorForHealth( ci->health, ci->armor, hcolor ); @@ -923,12 +2037,13 @@ static float CG_DrawTeamOverlay( float y, qboolean right, qboolean upper ) { xx = x + TINYCHAR_WIDTH * 3 + TINYCHAR_WIDTH * pwidth + TINYCHAR_WIDTH * lwidth; - CG_DrawStringExt( xx, y, - st, hcolor, qfalse, qfalse, - TINYCHAR_WIDTH, TINYCHAR_HEIGHT, 0 ); +// CG_DrawStringExt( xx, y, +// st, hcolor, qfalse, qfalse, +// TINYCHAR_WIDTH, TINYCHAR_HEIGHT, 0 ); + UI_DrawProportionalString( xx, y, st, UI_TINYFONT, hcolor); // draw weapon icon - xx += TINYCHAR_WIDTH * 3; + xx += (TINYCHAR_WIDTH * TINYPAD) * 3; if ( cg_weapons[ci->curWeapon].weaponIcon ) { CG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT, @@ -944,29 +2059,28 @@ static float CG_DrawTeamOverlay( float y, qboolean right, qboolean upper ) { } else { xx = x + w - TINYCHAR_WIDTH; } - for (j = 0; j <= PW_NUM_POWERUPS; j++) { + for (j = 0; j < PW_NUM_POWERUPS; j++) { if (ci->powerups & (1 << j)) { + gitem_t *item = BG_FindItemForPowerup( j ); - item = BG_FindItemForPowerup( j ); - - if (item) { + if (item) + { CG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT, - trap_R_RegisterShader( item->icon ) ); - if (right) { - xx -= TINYCHAR_WIDTH; - } else { - xx += TINYCHAR_WIDTH; - } + trap_R_RegisterShader( item->icon ) ); + } + if (right) { + xx -= (TINYCHAR_WIDTH * TINYPAD); + } else { + xx += (TINYCHAR_WIDTH * TINYPAD); } } } - y += TINYCHAR_HEIGHT; + y += (TINYCHAR_HEIGHT * TINYPAD); } } return ret_y; -//#endif } @@ -976,28 +2090,36 @@ CG_DrawUpperRight ===================== */ -static void CG_DrawUpperRight(stereoFrame_t stereoFrame) -{ +static void CG_DrawUpperRight( void ) { float y; - y = 0; + //vec3_t origin = {960, -1214, 242 }; + //vec3_t color = { 0.6, 0.6, 1.0 }; - if ( cgs.gametype >= GT_TEAM && cg_drawTeamOverlay.integer == 1 ) { - y = CG_DrawTeamOverlay( y, qtrue, qtrue ); - } - if ( cg_drawSnapshot.integer ) { - y = CG_DrawSnapshot( y ); - } - if (cg_drawFPS.integer && (stereoFrame == STEREO_CENTER || stereoFrame == STEREO_RIGHT)) { + cgs.widescreen.state = WIDESCREEN_RIGHT; + + y = 0; + if ( cg_drawFPS.integer ) { y = CG_DrawFPS( y ); } if ( cg_drawTimer.integer ) { y = CG_DrawTimer( y ); } - if ( cg_drawAttacker.integer ) { - y = CG_DrawAttacker( y ); + + if ( cg_drawSnapshot.integer ) { + y = CG_DrawSnapshot( y ); } + if ( cgs.gametype >= GT_TEAM && cg_drawTeamOverlay.integer == 1 ) { + y = CG_DrawTeamOverlay( y, qtrue, qtrue ); + } + + cgs.widescreen.state = WIDESCREEN_NONE; + +/* if ( cg_drawAttacker.integer ) { //RPG-X - TiM: We don't really need this in an RP + y = CG_DrawAttacker( y ); + }*/ + } /* @@ -1008,6 +2130,8 @@ static void CG_DrawUpperRight(stereoFrame_t stereoFrame) =========================================================================================== */ + + /* ================= CG_DrawScores @@ -1015,160 +2139,30 @@ CG_DrawScores Draw the small two score display ================= */ -#ifndef MISSIONPACK -static float CG_DrawScores( float y ) { - const char *s; - int s1, s2, score; - int x, w; - int v; - vec4_t color; +static float CG_DrawScores( float y ) +{ +// const char *s; + int s1, s2; //, score; +// int x, w; +// int v; +// vec4_t color; float y1; - gitem_t *item; +// gitem_t *item; s1 = cgs.scores1; s2 = cgs.scores2; y -= BIGCHAR_HEIGHT + 8; - y1 = y; - // draw from the right side to left - if ( cgs.gametype >= GT_TEAM ) { - x = 640; - color[0] = 0.0f; - color[1] = 0.0f; - color[2] = 1.0f; - color[3] = 0.33f; - s = va( "%2i", s2 ); - w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8; - x -= w; - CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color ); - if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) { - CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader ); - } - CG_DrawBigString( x + 4, y, s, 1.0F); - - if ( cgs.gametype == GT_CTF ) { - // Display flag status - item = BG_FindItemForPowerup( PW_BLUEFLAG ); - - if (item) { - y1 = y - BIGCHAR_HEIGHT - 8; - if( cgs.blueflag >= 0 && cgs.blueflag <= 2 ) { - CG_DrawPic( x, y1-4, w, BIGCHAR_HEIGHT+8, cgs.media.blueFlagShader[cgs.blueflag] ); - } - } - } - color[0] = 1.0f; - color[1] = 0.0f; - color[2] = 0.0f; - color[3] = 0.33f; - s = va( "%2i", s1 ); - w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8; - x -= w; - CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color ); - if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) { - CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader ); - } - CG_DrawBigString( x + 4, y, s, 1.0F); - - if ( cgs.gametype == GT_CTF ) { - // Display flag status - item = BG_FindItemForPowerup( PW_REDFLAG ); - - if (item) { - y1 = y - BIGCHAR_HEIGHT - 8; - if( cgs.redflag >= 0 && cgs.redflag <= 2 ) { - CG_DrawPic( x, y1-4, w, BIGCHAR_HEIGHT+8, cgs.media.redFlagShader[cgs.redflag] ); - } - } - } - - if ( cgs.gametype >= GT_CTF ) { - v = cgs.capturelimit; - } else { - v = cgs.fraglimit; - } - if ( v ) { - s = va( "%2i", v ); - w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8; - x -= w; - CG_DrawBigString( x + 4, y, s, 1.0F); - } - - } else { - qboolean spectator; - - x = 640; - score = cg.snap->ps.persistant[PERS_SCORE]; - spectator = ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ); - - // always show your score in the second box if not in first place - if ( s1 != score ) { - s2 = score; - } - if ( s2 != SCORE_NOT_PRESENT ) { - s = va( "%2i", s2 ); - w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8; - x -= w; - if ( !spectator && score == s2 && score != s1 ) { - color[0] = 1.0f; - color[1] = 0.0f; - color[2] = 0.0f; - color[3] = 0.33f; - CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color ); - CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader ); - } else { - color[0] = 0.5f; - color[1] = 0.5f; - color[2] = 0.5f; - color[3] = 0.33f; - CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color ); - } - CG_DrawBigString( x + 4, y, s, 1.0F); - } - - // first place - if ( s1 != SCORE_NOT_PRESENT ) { - s = va( "%2i", s1 ); - w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8; - x -= w; - if ( !spectator && score == s1 ) { - color[0] = 0.0f; - color[1] = 0.0f; - color[2] = 1.0f; - color[3] = 0.33f; - CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color ); - CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader ); - } else { - color[0] = 0.5f; - color[1] = 0.5f; - color[2] = 0.5f; - color[3] = 0.33f; - CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color ); - } - CG_DrawBigString( x + 4, y, s, 1.0F); - } - - if ( cgs.fraglimit ) { - s = va( "%2i", cgs.fraglimit ); - w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8; - x -= w; - CG_DrawBigString( x + 4, y, s, 1.0F); - } - - } - return y1 - 8; } -#endif // MISSIONPACK /* ================ CG_DrawPowerups ================ */ -#ifndef MISSIONPACK static float CG_DrawPowerups( float y ) { int sorted[MAX_POWERUPS]; int sortedTime[MAX_POWERUPS]; @@ -1182,9 +2176,10 @@ static float CG_DrawPowerups( float y ) { float size; float f; static float colors[2][4] = { - { 0.2f, 1.0f, 0.2f, 1.0f } , - { 1.0f, 0.2f, 0.2f, 1.0f } - }; + { 0.2, 1.0, 0.2, 1.0 } , { 1.0, 0.2, 0.2, 1.0 } }; + int hasHoldable; + + hasHoldable = cg.snap->ps.stats[STAT_HOLDABLE_ITEM]; ps = &cg.snap->ps; @@ -1221,48 +2216,60 @@ static float CG_DrawPowerups( float y ) { } // draw the icons and timers - x = 640 - ICON_SIZE - CHAR_WIDTH * 2; + x = 648; for ( i = 0 ; i < active ; i++ ) { + + // Don't draw almost timed out powerups if we have more than 3 and a holdable item + if (!(hasHoldable && ipowerups[ sorted[i] ]; + if ( t - cg.time >= POWERUP_BLINKS * POWERUP_BLINK_TIME ) { + trap_R_SetColor( NULL ); + } else { + vec4_t modulate; - t = ps->powerups[ sorted[i] ]; - if ( t - cg.time >= POWERUP_BLINKS * POWERUP_BLINK_TIME ) { - trap_R_SetColor( NULL ); - } else { - vec4_t modulate; + f = (float)( t - cg.time ) / POWERUP_BLINK_TIME; + f -= (int)f; + modulate[0] = modulate[1] = modulate[2] = modulate[3] = f; + trap_R_SetColor( modulate ); + } - f = (float)( t - cg.time ) / POWERUP_BLINK_TIME; - f -= (int)f; - modulate[0] = modulate[1] = modulate[2] = modulate[3] = f; - trap_R_SetColor( modulate ); - } + if ( cg.powerupActive == sorted[i] && + cg.time - cg.powerupTime < PULSE_TIME ) { + f = 1.0 - ( ( (float)cg.time - cg.powerupTime ) / PULSE_TIME ); + size = ICON_SIZE * ( 1.0 + ( PULSE_SCALE - 1.0 ) * f ); + } else { + size = ICON_SIZE; + } - if ( cg.powerupActive == sorted[i] && - cg.time - cg.powerupTime < PULSE_TIME ) { - f = 1.0 - ( ( (float)cg.time - cg.powerupTime ) / PULSE_TIME ); - size = ICON_SIZE * ( 1.0 + ( PULSE_SCALE - 1.0 ) * f ); - } else { - size = ICON_SIZE; - } + //CG_DrawPic( 640 - size, y + ICON_SIZE / 2 - size / 2, + // size, size, trap_R_RegisterShader( item->icon ) ); + x -= size + 10; - CG_DrawPic( 640 - size, y + ICON_SIZE / 2 - size / 2, - size, size, trap_R_RegisterShader( item->icon ) ); - } + CG_DrawPic( x, 478 - size, + size, size, trap_R_RegisterShader( item->icon ) ); + } } trap_R_SetColor( NULL ); return y; + } -#endif // MISSIONPACK + /* ===================== @@ -1270,11 +2277,12 @@ CG_DrawLowerRight ===================== */ -#ifndef MISSIONPACK static void CG_DrawLowerRight( void ) { float y; - y = 480 - ICON_SIZE; + y = LOWEROVERLAY_Y; + + cgs.widescreen.state = WIDESCREEN_RIGHT; if ( cgs.gametype >= GT_TEAM && cg_drawTeamOverlay.integer == 2 ) { y = CG_DrawTeamOverlay( y, qtrue, qfalse ); @@ -1282,15 +2290,15 @@ static void CG_DrawLowerRight( void ) { y = CG_DrawScores( y ); y = CG_DrawPowerups( y ); + + cgs.widescreen.state = WIDESCREEN_NONE; } -#endif // MISSIONPACK /* =================== CG_DrawPickupItem =================== */ -#ifndef MISSIONPACK static int CG_DrawPickupItem( int y ) { int value; float *fadeColor; @@ -1308,14 +2316,15 @@ static int CG_DrawPickupItem( int y ) { CG_RegisterItemVisuals( value ); trap_R_SetColor( fadeColor ); CG_DrawPic( 8, y, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon ); - CG_DrawBigString( ICON_SIZE + 16, y + (ICON_SIZE/2 - BIGCHAR_HEIGHT/2), bg_itemlist[ value ].pickup_name, fadeColor[0] ); + UI_DrawProportionalString( ICON_SIZE + 16, y + (ICON_SIZE/2 - BIGCHAR_HEIGHT/2), bg_itemlist[ value ].pickup_name, UI_SMALLFONT, fadeColor); + +// CG_DrawBigString( ICON_SIZE + 16, y + (ICON_SIZE/2 - BIGCHAR_HEIGHT/2), bg_itemlist[ value ].pickup_name, fadeColor[0] ); trap_R_SetColor( NULL ); } } return y; } -#endif // MISSIONPACK /* ===================== @@ -1323,11 +2332,12 @@ CG_DrawLowerLeft ===================== */ -#ifndef MISSIONPACK static void CG_DrawLowerLeft( void ) { float y; - y = 480 - ICON_SIZE; + y = LOWEROVERLAY_Y; + + cgs.widescreen.state = WIDESCREEN_LEFT; if ( cgs.gametype >= GT_TEAM && cg_drawTeamOverlay.integer == 3 ) { y = CG_DrawTeamOverlay( y, qfalse, qfalse ); @@ -1335,8 +2345,10 @@ static void CG_DrawLowerLeft( void ) { y = CG_DrawPickupItem( y ); + + cgs.widescreen.state = WIDESCREEN_NONE; } -#endif // MISSIONPACK + //=========================================================================================== @@ -1346,10 +2358,9 @@ static void CG_DrawLowerLeft( void ) { CG_DrawTeamInfo ================= */ -#ifndef MISSIONPACK static void CG_DrawTeamInfo( void ) { - int h; - int i; + int w, h; + int i, len; vec4_t hcolor; int chatHeight; @@ -1370,76 +2381,96 @@ static void CG_DrawTeamInfo( void ) { h = (cgs.teamChatPos - cgs.teamLastChatPos) * TINYCHAR_HEIGHT; + w = 0; + + for (i = cgs.teamLastChatPos; i < cgs.teamChatPos; i++) { + len = CG_DrawStrlen(cgs.teamChatMsgs[i % chatHeight]); + if (len > w) + w = len; + } + w *= TINYCHAR_WIDTH; + w += TINYCHAR_WIDTH * 2; + if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) { - hcolor[0] = 1.0f; - hcolor[1] = 0.0f; - hcolor[2] = 0.0f; - hcolor[3] = 0.33f; + hcolor[0] = 1; + hcolor[1] = 0; + hcolor[2] = 0; + hcolor[3] = 0.33; } else if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) { - hcolor[0] = 0.0f; - hcolor[1] = 0.0f; - hcolor[2] = 1.0f; - hcolor[3] = 0.33f; + hcolor[0] = 0; + hcolor[1] = 0; + hcolor[2] = 1; + hcolor[3] = 0.33; } else { - hcolor[0] = 0.0f; - hcolor[1] = 1.0f; - hcolor[2] = 0.0f; - hcolor[3] = 0.33f; + hcolor[0] = 0; + hcolor[1] = 1; + hcolor[2] = 0; + hcolor[3] = 0.33; } trap_R_SetColor( hcolor ); CG_DrawPic( CHATLOC_X, CHATLOC_Y - h, 640, h, cgs.media.teamStatusBar ); trap_R_SetColor( NULL ); - hcolor[0] = hcolor[1] = hcolor[2] = 1.0f; - hcolor[3] = 1.0f; + hcolor[0] = hcolor[1] = hcolor[2] = 1.0; + hcolor[3] = 1.0; for (i = cgs.teamChatPos - 1; i >= cgs.teamLastChatPos; i--) { - CG_DrawStringExt( CHATLOC_X + TINYCHAR_WIDTH, +// CG_DrawStringExt( CHATLOC_X + TINYCHAR_WIDTH, +// CHATLOC_Y - (cgs.teamChatPos - i)*TINYCHAR_HEIGHT, +// cgs.teamChatMsgs[i % chatHeight], hcolor, qfalse, qfalse, +// TINYCHAR_WIDTH, TINYCHAR_HEIGHT, 0 ); + UI_DrawProportionalString( CHATLOC_X + TINYCHAR_WIDTH, CHATLOC_Y - (cgs.teamChatPos - i)*TINYCHAR_HEIGHT, - cgs.teamChatMsgs[i % chatHeight], hcolor, qfalse, qfalse, - TINYCHAR_WIDTH, TINYCHAR_HEIGHT, 0 ); + cgs.teamChatMsgs[i % chatHeight], UI_TINYFONT, hcolor); + } } } -#endif // MISSIONPACK /* =================== CG_DrawHoldableItem =================== */ -#ifndef MISSIONPACK static void CG_DrawHoldableItem( void ) { int value; value = cg.snap->ps.stats[STAT_HOLDABLE_ITEM]; - if ( value ) { + if ( value ) + { CG_RegisterItemVisuals( value ); - CG_DrawPic( 640-ICON_SIZE, (SCREEN_HEIGHT-ICON_SIZE)/2, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon ); + if ( cg.snap->ps.stats[STAT_USEABLE_PLACED] && cg.snap->ps.stats[STAT_USEABLE_PLACED] != 2 ) + {//draw detpack... Borg 2-part teleporter will just draw the same until done + CG_DrawPic( 640-ICON_SIZE, 480-ICON_SIZE, ICON_SIZE, ICON_SIZE, cgs.media.detpackPlacedIcon ); + } + else + { + CG_DrawPic( 640-ICON_SIZE, 480-ICON_SIZE, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon ); + } } + else + {//holding nothing... + if ( cg.snap->ps.stats[STAT_USEABLE_PLACED] > 0 ) + {//it's a timed countdown to getting a holdable, display the number in seconds + int sec; + char *s; + int w; -} -#endif // MISSIONPACK + sec = cg.snap->ps.stats[STAT_USEABLE_PLACED]; -#ifdef MISSIONPACK -/* -=================== -CG_DrawPersistantPowerup -=================== -*/ -#if 0 // sos001208 - DEAD -static void CG_DrawPersistantPowerup( void ) { - int value; + if ( sec < 0 ) + { + sec = 0; + } - value = cg.snap->ps.stats[STAT_PERSISTANT_POWERUP]; - if ( value ) { - CG_RegisterItemVisuals( value ); - CG_DrawPic( 640-ICON_SIZE, (SCREEN_HEIGHT-ICON_SIZE)/2 - ICON_SIZE, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon ); + s = va( "%i", sec ); + + w = UI_ProportionalStringWidth(s,UI_BIGFONT); + UI_DrawProportionalString(640-(ICON_SIZE/2)-(w/2), (SCREEN_HEIGHT-ICON_SIZE)/2+(BIGCHAR_HEIGHT/2), s, UI_BIGFONT, colorTable[CT_WHITE]); + } } } -#endif -#endif // MISSIONPACK /* @@ -1449,67 +2480,23 @@ CG_DrawReward */ static void CG_DrawReward( void ) { float *color; - int i, count; + int i; float x, y; - char buf[32]; if ( !cg_drawRewards.integer ) { return; } - color = CG_FadeColor( cg.rewardTime, REWARD_TIME ); if ( !color ) { - if (cg.rewardStack > 0) { - for(i = 0; i < cg.rewardStack; i++) { - cg.rewardSound[i] = cg.rewardSound[i+1]; - cg.rewardShader[i] = cg.rewardShader[i+1]; - cg.rewardCount[i] = cg.rewardCount[i+1]; - } - cg.rewardTime = cg.time; - cg.rewardStack--; - color = CG_FadeColor( cg.rewardTime, REWARD_TIME ); - trap_S_StartLocalSound(cg.rewardSound[0], CHAN_ANNOUNCER); - } else { - return; - } + return; } trap_R_SetColor( color ); - - /* - count = cg.rewardCount[0]/10; // number of big rewards to draw - - if (count) { - y = 4; - x = 320 - count * ICON_SIZE; - for ( i = 0 ; i < count ; i++ ) { - CG_DrawPic( x, y, (ICON_SIZE*2)-4, (ICON_SIZE*2)-4, cg.rewardShader[0] ); - x += (ICON_SIZE*2); - } - } - - count = cg.rewardCount[0] - count*10; // number of small rewards to draw - */ - - if ( cg.rewardCount[0] >= 10 ) { - y = 56; - x = 320 - ICON_SIZE/2; - CG_DrawPic( x, y, ICON_SIZE-4, ICON_SIZE-4, cg.rewardShader[0] ); - Com_sprintf(buf, sizeof(buf), "%d", cg.rewardCount[0]); - x = ( SCREEN_WIDTH - SMALLCHAR_WIDTH * CG_DrawStrlen( buf ) ) / 2; - CG_DrawStringExt( x, y+ICON_SIZE, buf, color, qfalse, qtrue, - SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, 0 ); - } - else { - - count = cg.rewardCount[0]; - - y = 56; - x = 320 - count * ICON_SIZE/2; - for ( i = 0 ; i < count ; i++ ) { - CG_DrawPic( x, y, ICON_SIZE-4, ICON_SIZE-4, cg.rewardShader[0] ); - x += ICON_SIZE; - } + y = 56; + x = 320 - cg.rewardCount * ICON_SIZE/2; + for ( i = 0 ; i < cg.rewardCount ; i++ ) { + CG_DrawPic( x, y, ICON_SIZE-4, ICON_SIZE-4, cg.rewardShader ); + x += ICON_SIZE; } trap_R_SetColor( NULL ); } @@ -1592,23 +2579,29 @@ static void CG_DrawDisconnect( void ) { // draw the phone jack if we are completely past our buffers cmdNum = trap_GetCurrentCmdNumber() - CMD_BACKUP + 1; trap_GetUserCmd( cmdNum, &cmd ); - if ( cmd.serverTime <= cg.snap->ps.commandTime - || cmd.serverTime > cg.time ) { // special check for map_restart + if ( cmd.serverTime <= cg.snap->ps.commandTime || + cmd.serverTime > cg.time /*|| // special check for map_restart + cmd.serverTime < cg.snap->ps.introTime*/) // special check for holointro + { return; } // also add text in center of screen - s = "Connection Interrupted"; - w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; - CG_DrawBigString( 320 - w/2, 100, s, 1.0F); + s = ingame_text[IGT_CONNECTIONINTERRUPTED]; +// w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; + w = UI_ProportionalStringWidth(s,UI_BIGFONT); +// CG_DrawBigString( 320 - w/2, 100, s, 1.0F); + // Used to be (Height) 100 + UI_DrawProportionalString(320 - w/2, 240, s, UI_BIGFONT, colorTable[CT_LTGOLD1]); // blink the icon if ( ( cg.time >> 9 ) & 1 ) { return; } - x = 640 - 48; - y = 480 - 48; + // RPG-X | Phenix | 08/06/2005 + x = 296; //640 - 50; + y = 182; CG_DrawPic( x, y, 48, 48, trap_R_RegisterShader("gfx/2d/net.tga" ) ); } @@ -1629,7 +2622,7 @@ static void CG_DrawLagometer( void ) { int color; float vscale; - if ( !cg_lagometer.integer || cgs.localServer ) { + if ( !cg_lagometer.integer /* || cgs.localServer */) { CG_DrawDisconnect(); return; } @@ -1637,13 +2630,9 @@ static void CG_DrawLagometer( void ) { // // draw the graph // -#ifdef MISSIONPACK - x = 640 - 48; - y = 480 - 144; -#else - x = 640 - 48; - y = 480 - 48; -#endif + // 640, 480 (-48) + x = 640 - 50; //move it left of the ammo numbers + y = 2; trap_R_SetColor( NULL ); CG_DrawPic( x, y, 48, 48, cgs.media.lagometerShader ); @@ -1723,7 +2712,8 @@ static void CG_DrawLagometer( void ) { trap_R_SetColor( NULL ); if ( cg_nopredict.integer || cg_synchronousClients.integer ) { - CG_DrawBigString( ax, ay, "snc", 1.0 ); +// CG_DrawBigString( ax, ay, "snc", 1.0 ); + UI_DrawProportionalString(ax, ay, "snc", UI_BIGFONT, colorTable[CT_LTGOLD1]); } CG_DrawDisconnect(); @@ -1777,9 +2767,6 @@ static void CG_DrawCenterString( void ) { char *start; int l; int x, y, w; -#ifdef MISSIONPACK - int h; -#endif float *color; if ( !cg.centerPrintTime ) { @@ -1800,7 +2787,7 @@ static void CG_DrawCenterString( void ) { while ( 1 ) { char linebuffer[1024]; - for ( l = 0; l < 50; l++ ) { + for ( l = 0; l < 60; l++ ) { if ( !start[l] || start[l] == '\n' ) { break; } @@ -1808,22 +2795,18 @@ static void CG_DrawCenterString( void ) { } linebuffer[l] = 0; -#ifdef MISSIONPACK - w = CG_Text_Width(linebuffer, 0.5, 0); - h = CG_Text_Height(linebuffer, 0.5, 0); - x = (SCREEN_WIDTH - w) / 2; - CG_Text_Paint(x, y + h, 0.5, color, linebuffer, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE); - y += h + 6; -#else - w = cg.centerPrintCharWidth * CG_DrawStrlen( linebuffer ); +// w = cg.centerPrintCharWidth * CG_DrawStrlen( linebuffer ); + w = UI_ProportionalStringWidth(linebuffer,UI_BIGFONT); x = ( SCREEN_WIDTH - w ) / 2; - CG_DrawStringExt( x, y, linebuffer, color, qfalse, qtrue, - cg.centerPrintCharWidth, (int)(cg.centerPrintCharWidth * 1.5), 0 ); +// CG_DrawStringExt( x, y, linebuffer, color, qfalse, qtrue, +// cg.centerPrintCharWidth, (int)(cg.centerPrintCharWidth * 1.5), 0 ); + + UI_DrawProportionalString( x, y, linebuffer, UI_BIGFONT|UI_DROPSHADOW, color); y += cg.centerPrintCharWidth * 1.5; -#endif + while ( *start && ( *start != '\n' ) ) { start++; } @@ -1846,32 +2829,229 @@ CROSSHAIR ================================================================================ */ +/*qboolean CG_WorldCoordToScreenCoordFloat(vec3_t worldCoord, float *x, float *y) +{ + float xcenter, ycenter; + vec3_t local, transformed; + vec3_t vfwd; + vec3_t vright; + vec3_t vup; + float xzi; + float yzi; + +// xcenter = cg.refdef.width / 2;//gives screen coords adjusted for resolution +// ycenter = cg.refdef.height / 2;//gives screen coords adjusted for resolution + + //NOTE: did it this way because most draw functions expect virtual 640x480 coords + // and adjust them for current resolution + xcenter = 640.0f / 2.0f;//gives screen coords in virtual 640x480, to be adjusted when drawn + ycenter = 480.0f / 2.0f;//gives screen coords in virtual 640x480, to be adjusted when drawn + + AngleVectors (cg.refdefViewAngles, vfwd, vright, vup); + + VectorSubtract (worldCoord, cg.refdef.vieworg, local); + + transformed[0] = DotProduct(local,vright); + transformed[1] = DotProduct(local,vup); + transformed[2] = DotProduct(local,vfwd); + + // Make sure Z is not negative. + if(transformed[2] < 0.01f) + { + return qfalse; + } + + xzi = xcenter / transformed[2] * (96.0f/cg.refdef.fov_x); + yzi = ycenter / transformed[2] * (102.0f/cg.refdef.fov_y); + + *x = xcenter + xzi * transformed[0]; + *y = ycenter - yzi * transformed[1]; + + return qtrue; +}*/ + +/*float cg_crosshairPrevPosX = 0; +float cg_crosshairPrevPosY = 0; +#define CRAZY_CROSSHAIR_MAX_ERROR_X (100.0f*640.0f/480.0f) +#define CRAZY_CROSSHAIR_MAX_ERROR_Y (100.0f) +void CG_LerpCrosshairPos( float *x, float *y ) +{ + if ( cg_crosshairPrevPosX ) + {//blend from old pos + float maxMove = 100.0f * ((float)cg.frametime/500.0f) * 640.0f/480.0f; //30 + float xDiff = (*x - cg_crosshairPrevPosX); + if ( fabs(xDiff) > CRAZY_CROSSHAIR_MAX_ERROR_X ) + { + maxMove = CRAZY_CROSSHAIR_MAX_ERROR_X; + } + if ( xDiff > maxMove ) + { + *x = cg_crosshairPrevPosX + maxMove; + } + else if ( xDiff < -maxMove ) + { + *x = cg_crosshairPrevPosX - maxMove; + } + } + cg_crosshairPrevPosX = *x; + + if ( cg_crosshairPrevPosY ) + {//blend from old pos + float maxMove = 100.0f * ((float)cg.frametime/500.0f); + float yDiff = (*y - cg_crosshairPrevPosY); + if ( fabs(yDiff) > CRAZY_CROSSHAIR_MAX_ERROR_Y ) + { + maxMove = CRAZY_CROSSHAIR_MAX_ERROR_X; + } + if ( yDiff > maxMove ) + { + *y = cg_crosshairPrevPosY + maxMove; + } + else if ( yDiff < -maxMove ) + { + *y = cg_crosshairPrevPosY - maxMove; + } + } + cg_crosshairPrevPosY = *y; +}*/ + +/* +================= +CG_CalcMuzzlePoint +**Blatently plagiarised from JKA** + +Um, I guess this calculates the approximate vector +of where your gun is at ingame. :P +=================*/ + + +//static qboolean CG_CalcMuzzlePoint( int entityNum, vec3_t muzzle ) { +// vec3_t forward, right; +// vec3_t gunpoint; +// centity_t *cent; +// int anim; +// +// if ( entityNum == cg.snap->ps.clientNum ) +// { //I'm not exactly sure why we'd be rendering someone else's crosshair, but hey. +// int weapontype = cg.snap->ps.weapon; +// vec3_t weaponMuzzle = {13, 6, -6}; +// centity_t *pEnt = &cg_entities[cg.predictedPlayerState.clientNum]; +// +// if (cg.renderingThirdPerson) +// { +// VectorCopy( pEnt->lerpOrigin, gunpoint ); //lerp +// AngleVectors( pEnt->lerpAngles, forward, right, NULL ); +// } +// /*else +// { +// VectorCopy( cg.refdef.vieworg, gunpoint ); +// AngleVectors( cg.refdefViewAngles, forward, right, NULL ); +// }*/ +// +// VectorCopy(gunpoint, muzzle); +// +// VectorMA(muzzle, weaponMuzzle[0], forward, muzzle); +// VectorMA(muzzle, weaponMuzzle[1], right, muzzle); +// +// if (cg.renderingThirdPerson) +// { +// muzzle[2] += cg.snap->ps.viewheight + weaponMuzzle[2]; +// } +// /*else +// { +// muzzle[2] += weaponMuzzle[2]; +// }*/ +// +// return qtrue; +// } +// +// cent = &cg_entities[entityNum]; +// if ( !cent->currentValid ) { +// return qfalse; +// } +// +// VectorCopy( cent->currentState.pos.trBase, muzzle ); +// +// AngleVectors( cent->currentState.apos.trBase, forward, NULL, NULL ); +// anim = cent->currentState.legsAnim; +// if ( anim == BOTH_CROUCH1IDLE || anim == BOTH_CROUCH1WALK ) { +// muzzle[2] += CROUCH_VIEWHEIGHT; +// } else { +// muzzle[2] += DEFAULT_VIEWHEIGHT; +// } +// +// VectorMA( muzzle, 14, forward, muzzle ); +// +// return qtrue; +// +// +//} + +//end dCross /* ================= CG_DrawCrosshair ================= */ -static void CG_DrawCrosshair(void) -{ +static void CG_DrawCrosshair(void) { float w, h; - qhandle_t hShader; + //qhandle_t hShader; float f; - float x, y; - int ca; + float x = 0; + float y = 0; //float + int weaponCrosshairNum; + + //dCross + trace_t trace; + vec3_t start, end; + int ignore; + vec3_t d_f; + vec3_t pitchConstraint; + vec3_t worldPoint; + + crosshairsData_t *cd; + + if( cg.zoomed ) { //RPG-X - TiM: We dun need crosshairs when zoomed anymore :P + return; + } if ( !cg_drawCrosshair.integer ) { return; } - if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR) { + if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR /*|| (cg.snap->ps.eFlags&EF_ELIMINATED)*/ ) { return; } - if ( cg.renderingThirdPerson ) { + //clamp crosshair num + if ( (weaponCrosshairNum = cg.predictedPlayerState.weapon - 1) < 0 ){ + weaponCrosshairNum = 0; + } + else if ( weaponCrosshairNum >= MAX_CROSSHAIRS ) { + weaponCrosshairNum = 14; + } + + cd = &cgs.crosshairsData[weaponCrosshairNum]; + + ignore = cg.predictedPlayerState.clientNum; + + //if noDraw was specified in the crosshair script + if ( cd->noDraw ) { return; } + //TiM: With the new crosshair rendering system, this should be no problem + /*if ( cg.snap->ps.weapon == WP_1 ) { //Teh hand has no crosshair + return; + }*/ + +// if ( cg.renderingThirdPerson ) { +// return; +// } + +//We don't need this anymore (RPG-X: J2J) +/* // set color based on health if ( cg_crosshairHealth.integer ) { vec4_t hcolor; @@ -1880,7 +3060,7 @@ static void CG_DrawCrosshair(void) trap_R_SetColor( hcolor ); } else { trap_R_SetColor( NULL ); - } +// }*/ w = h = cg_crosshairSize.value; @@ -1892,98 +3072,661 @@ static void CG_DrawCrosshair(void) h *= ( 1 + f ); } - x = cg_crosshairX.integer; - y = cg_crosshairY.integer; + //dCross + + if( cg_dynamicCrosshair.value == 1 && cg.renderingThirdPerson) { + + //if ( cg.renderingThirdPerson ) { + VectorCopy( cg.predictedPlayerState.viewangles, pitchConstraint); //cg.predictedPlayerState.viewangles //cg.refdefViewAngles //vieworg + //} + /*else + { + VectorCopy(cg.refdefViewAngles, pitchConstraint); + }*/ + + AngleVectors( pitchConstraint, d_f, NULL, NULL ); + + //CG_CalcMuzzlePoint(cg.snap->ps.clientNum, start); + //if ( cg.renderingThirdPerson ) { + VectorCopy( cg.predictedPlayerState.origin, start); + if ( !(cg.predictedPlayerState.eFlags & EF_FULL_ROTATE) && Q_fabs( cg.predictedPlayerState.viewangles[PITCH] ) > 89.9f ) + start[2] -= 20; + else + start[2] += (float)cg.predictedPlayerState.viewheight * cgs.clientinfo[cg.predictedPlayerState.clientNum].height; + //} + // else { + // VectorCopy( cg.refdef.vieworg, start); + // } + + VectorMA( start, 6000.0f, d_f, end ); //cg.distanceCull + + CG_Trace( &trace, start, vec3_origin, vec3_origin, end, ignore, CONTENTS_SOLID|CONTENTS_BODY ); + + //TiM - if we hit a cloaked admin, bypass them so the crosshair doesn't jump randomly + //NOTE: Possibly could cause errors + while ( cg_entities[trace.entityNum].currentState.powerups & ( 1 <ps.weapon) + { + default: + case WP_5: hShader = cgs.media.crosshair[0]; break; + case WP_6: hShader = cgs.media.crosshair[1]; break; + case WP_1: hShader = cgs.media.crosshair[4]; break; + case WP_4: hShader = cgs.media.crosshair[2]; break; + case WP_10: hShader = cgs.media.crosshair[3]; break; + case WP_8: hShader = cgs.media.crosshair[6]; break; + case WP_7: hShader = cgs.media.crosshair[5]; break; + case WP_9: hShader = cgs.media.crosshair[7]; break; + case WP_13: hShader = cgs.media.crosshair[8]; break; + case WP_12: hShader = cgs.media.crosshair[9]; break; + case WP_14: hShader = cgs.media.crosshair[11]; break; + case WP_11: hShader = cgs.media.crosshair[10]; break; + case WP_2: hShader = cgs.media.crosshair[14]; break; + case WP_3: hShader = cgs.media.crosshair[13]; break; + case WP_NEUTRINO_PROBE: hShader = cgs.media.crosshair[12]; break; + }*/ + + //If admins scan non-players + if ( cg.predictedPlayerState.weapon == WP_2 && cg.predictedPlayerState.eFlags & EF_FIRING ) { + if (/*cg.predictedPlayerState.persistant[PERS_CLASS] == PC_ADMIN*/cg_showEntityNums.integer && cgs.clientinfo[cg.snap->ps.clientNum].isAdmin && cg.crosshairClientNum < ENTITYNUM_WORLD ) { + vec4_t ccolor; + /*color[0] = colorTable[CT_YELLOW][0]; + color[1] = colorTable[CT_YELLOW][1]; + color[2] = colorTable[CT_YELLOW][2];*/ + /*color[0] = 0.9F;//R + color[1] = 0.7F;//G + color[2] = 0.0F;//B + color[3] = 0.8;*/ + ccolor[0] = 0.694f;//0.9F;//R + ccolor[1] = 0.816f;//0.7F;//G + ccolor[2] = 1.0f;//0.0F;//B + ccolor[3] = 0.8f; + + //TiM + cgs.widescreen.state = WIDESCREEN_CENTER; + + UI_DrawProportionalString(x + 320, + y + 270, + va("Entity: %i", cg.crosshairClientNum), + UI_CENTER|UI_SMALLFONT, + ccolor); //170 + + //CG_Printf( "x= %i, y = %i, w = %i, h = %i\n", cg.refdef.x, cg.refdef.y, cg.refdef.width, cg.refdef.height ); + } + /*if(cg_entities[cg.crosshairClientNum].currentState.modelindex == HI_SHIELD && cg_entities[cg.crosshairClientNum].currentState.apos.trBase[0] != 0) { + vec4_t ccolor; + ccolor[0] = 0.694f; + ccolor[1] = 0.816f; + ccolor[2] = 1.0f; + ccolor[3] = 0.8f; + UI_DrawProportionalString(x + 320, + y + 285, + va("Frequency: %f", cg_entities[cg.crosshairClientNum].currentState.apos.trBase[0]), + UI_CENTER|UI_SMALLFONT, + ccolor); + }*/ + } + + cgs.widescreen.state = WIDESCREEN_LEFT; CG_AdjustFrom640( &x, &y, &w, &h ); - ca = cg_drawCrosshair.integer; - if (ca < 0) { - ca = 0; - } - hShader = cgs.media.crosshairShader[ ca % NUM_CROSSHAIRS ]; + trap_R_SetColor( cd->color ); + + //TiM: Huh... we have a problem cap'n. + //Even though we have absolutely perfect alignment, the ingame drawing (regardless of mipmapping) + //appears to be blurring the icons to the point where they overlap, leaving little smudges at the corners + //of certain crosshairs ingame :'( + //So I'm attempting to fix this by creating a very very subtle offset to scale the scan region inwards a bit. + //Addendum: FRAK! Okay... offsetting will not work. It clips any of the hairs that are in their full boundary. Which looks crap :P + //Com_Printf("s1 = %f, t1 = %f, s2 = %f, t2 = %f\n", ((float)cd->s1/128.0f), ((float)cd->t1/128.0f), ((float)cd->s2/128.0f), ((float)cd->t2/128.0f)); - trap_R_DrawStretchPic( x + cg.refdef.x + 0.5 * (cg.refdef.width - w), - y + cg.refdef.y + 0.5 * (cg.refdef.height - h), - w, h, 0, 0, 1, 1, hShader ); + //Magic number! 0.0078125 = 1 pixel in a 128x128 bitmap - Edited out. 1 pixel = WAY TOO MUCH! + trap_R_DrawStretchPic( x + cg.refdef.x + 0.5 * (cg.refdef.width - w), //X + y + cg.refdef.y + 0.5 * (cg.refdef.height - h), //Y + w, h, //W+H + ((float)cd->s1/128.0f), ((float)cd->t1/128.0f), //s1 + t1 + ((float)cd->s2/128.0f), ((float)cd->t2/128.0f), //s2 + t2 + cgs.media.crosshairSheet ); + + trap_R_SetColor( NULL ); } /* ================= -CG_DrawCrosshair3D +CG_LabelCrosshairEntity ================= */ -static void CG_DrawCrosshair3D(void) -{ - float w; - qhandle_t hShader; - float f; - int ca; - trace_t trace; - vec3_t endpos; - float stereoSep, zProj, maxdist, xmax; - char rendererinfos[128]; - refEntity_t ent; +static void CG_LabelViewEntity( int clientNum, vec3_t origin, vec3_t entMins, vec3_t entMaxs, char *name, qboolean scanAll, vec4_t color, qboolean drawHealth, int health, char *pClass, char *rank, char *race, char* age, char *height, char *weight, char *weapon ) +{//ID teammates, ID enemies, ID objectives, etc. + centity_t *cent; + //clientInfo_t *ci; + vec3_t center, maxs, mins, top, bottom, topLeft, topRight, bottomLeft, bottomRight; + vec3_t worldEast = {1.0f, 0, 0}, worldNorth = {0, 1.0f, 0}, worldUp = {0, 0, 1.0f}; + //vec4_t hcolor; + float x = 0, y = 0; + float topLeftx, topLefty, topRightx, topRighty, bottomLeftx, bottomLefty, bottomRightx, bottomRighty; + int corner, topSize, bottomSize, leftSize, rightSize; + int charIndex, classCharIndex, rankCharIndex, ageCharIndex, raceCharIndex, htCharIndex, wtCharIndex, weapCharIndex, healthCharIndex; + float lineHorzLength = 8.0f, lineVertLength = 8.0f, lineWidth = 2.0f; + float fUpDot, fEastDot, fNorthDot, uNorthDot, uEastDot;//, hwidth;//, timedScale = 1.0f; + qboolean doTopLeft = qfalse; + qboolean doTopRight = qfalse; + qboolean doBottomLeft = qfalse; + qboolean doBottomRight = qfalse; + qboolean doSizes = qtrue; + float w; + char showName[1024]; + char showRank[1024]; + char showRace[1024]; + char showHt[1024]; + char showWt[1024]; + char showWeap[1024]; + char showHealth[1024]; + char showAge[1024]; + char showClass[1024]; + //char *health = "100"; - if ( !cg_drawCrosshair.integer ) { - return; + cent = &cg_entities[clientNum]; + + /*if ( clientNum < MAX_CLIENTS ) { + ci = &cgs.clientinfo[clientNum]; + }*/ + + infoStringCount += cg.frametime; + rankCharIndex = raceCharIndex = classCharIndex = ageCharIndex = htCharIndex = wtCharIndex = weapCharIndex = charIndex = healthCharIndex = floor(infoStringCount/33); + //TODO: have box scale in from corners of screen? Or out from center? + /* + if(infoStringCount < 1000) + { + timedScale = (float)infoStringCount/100.0f; + timedScale = 10.0f - timedScale; + if(timedScale < 1.0f) + { + timedScale = 1.0f; + } + } + */ + //IDEA: We COULD actually rotate a wire-mesh version of the crossEnt until it + // matches the crossEnt's angles then flash it and pop up this info... + // but that would be way too much work for something like this. + // Alternately, could rotate a scaled-down fully-skinned version + // next to it, but that, too, might be overkill... (plus, model would + // need back faces) + + //FIXME: can be optimized... + + //Draw frame around ent's bbox + //FIXME: make global, do once + fUpDot = 1.0f - fabs( DotProduct( vfwd_n, worldUp ) );//1.0 if looking up or down, so use mins and maxs more + fEastDot = fabs( DotProduct( vfwd_n, worldEast ) );//1.0 if looking east or west, so use mins[1] and maxs[1] more + fNorthDot = fabs( DotProduct( vfwd_n, worldNorth ) );//1.0 if looking north or south, so use mins[0] and maxs[0] more + uEastDot = fabs( DotProduct( vup_n, worldEast ) );//1.0 if looking up or down, head towards east or west, so use mins[0] and maxs[0] more + uNorthDot = fabs( DotProduct( vup_n, worldNorth ) );//1.0 if looking up or down, head towards north or south, so use mins[1] and maxs[1] more + + /*if ( crossEnt->s.solid == SOLID_BMODEL ) + {//brush model, no origin, so use the center + VectorAdd( crossEnt->absmin, crossEnt->absmax, center ); + VectorScale( center, 0.5, center ); + VectorSubtract( crossEnt->absmax, center, maxs ); + VectorSubtract( crossEnt->absmin, center, mins ); + } + else + {*/ + VectorCopy( origin, center ); //crossEnt->currentOrigin//cent->lerpOrigin + VectorCopy( entMaxs, maxs ); //crossEnt->maxs //playerMaxs + VectorCopy( entMins, mins ); //crossEnt->mins //playerMins + //} + + //NOTE: this presumes that mins[0] and maxs[0] are symmetrical and mins[1] and maxs[1] as well + topSize = (maxs[2]*fUpDot + maxs[1]*uNorthDot + maxs[0]*uEastDot);//* timedScale + bottomSize = (mins[2]*fUpDot + mins[1]*uNorthDot + mins[0]*uEastDot);//* timedScale + leftSize = (fUpDot*(mins[0]*fNorthDot + mins[1]*fEastDot) + mins[0]*uNorthDot + mins[1]*uEastDot);//* timedScale + rightSize = (fUpDot*(maxs[0]*fNorthDot + maxs[1]*fEastDot) + maxs[0]*uNorthDot + maxs[1]*uEastDot);//* timedScale + + //Find corners + //top + VectorMA( center, topSize, vup_n, top ); + //bottom + VectorMA( center, bottomSize, vup_n, bottom ); + //Top-left frame + VectorMA( top, leftSize, vright_n, topLeft ); + //Top-right frame + VectorMA( top, rightSize, vright_n, topRight ); + //bottom-left frame + VectorMA( bottom, leftSize, vright_n, bottomLeft ); + //bottom-right frame + VectorMA( bottom, rightSize, vright_n, bottomRight ); + + if ( CG_WorldCoordToScreenCoord( topLeft, &topLeftx, &topLefty, qfalse ) ) + { + doTopLeft = qtrue; + } + else + { + doSizes = qfalse; } - if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR) { - return; + if ( CG_WorldCoordToScreenCoord( topRight, &topRightx, &topRighty, qfalse ) ) + { + doTopRight = qtrue; + } + else + { + doSizes = qfalse; } - if ( cg.renderingThirdPerson ) { - return; + if ( CG_WorldCoordToScreenCoord( bottomLeft, &bottomLeftx, &bottomLefty, qfalse ) ) + { + doBottomLeft = qtrue; + } + else + { + doSizes = qfalse; } - w = cg_crosshairSize.value; - - // pulse the size of the crosshair when picking up items - f = cg.time - cg.itemPickupBlendTime; - if ( f > 0 && f < ITEM_BLOB_TIME ) { - f /= ITEM_BLOB_TIME; - w *= ( 1 + f ); + if ( CG_WorldCoordToScreenCoord( bottomRight, &bottomRightx, &bottomRighty, qfalse ) ) + { + doBottomRight = qtrue; + } + else + { + doSizes = qfalse; } - ca = cg_drawCrosshair.integer; - if (ca < 0) { - ca = 0; + //NOTE: maybe print color-coded "Primary/Secondary Objective" on top if an objective? + for ( corner = 0; corner < 13; corner++ ) //11 + {//FIXME: make sure line length of 8 isn't greater than width of object + switch ( corner ) + { + case 0://top-left + if ( doTopLeft ) + { + if ( doSizes ) + { + //Line lengths + lineVertLength = (bottomLefty-topLefty)*0.25f; + lineHorzLength = (topRightx-topLeftx)*0.25f; + } + CG_FillRect( topLeftx + 2, topLefty, lineHorzLength, lineWidth, color ); + CG_FillRect( topLeftx, topLefty, lineWidth, lineVertLength, color ); + } + break; + case 1://top-right + if ( doTopRight ) + { + if ( doSizes ) + { + //Line lengths + lineVertLength = (bottomRighty-topRighty)*0.25f; + lineHorzLength = (topRightx-topLeftx)*0.25f; + } + CG_FillRect( topRightx-lineHorzLength, topRighty, lineHorzLength, lineWidth, color ); + CG_FillRect( topRightx, topRighty, lineWidth, lineVertLength, color ); + } + break; + case 2://bottom-left + if ( doBottomLeft ) + { + if ( doSizes ) + { + //Line lengths + lineVertLength = (bottomLefty-topLefty)*0.25f; + lineHorzLength = (bottomRightx-bottomLeftx)*0.25f; + } + CG_FillRect( bottomLeftx, bottomLefty, lineHorzLength, lineWidth, color ); + CG_FillRect( bottomLeftx, bottomLefty-lineVertLength, lineWidth, lineVertLength, color ); + } + break; + case 3://bottom-right + if ( doBottomRight ) + { + if ( doSizes ) + { + //Line lengths + lineVertLength = (bottomRighty-topRighty)*0.25f; + lineHorzLength = (bottomRightx-bottomLeftx)*0.25f; + } + CG_FillRect( bottomRightx-lineHorzLength, bottomRighty, lineHorzLength, lineWidth, color ); + CG_FillRect( bottomRightx, bottomRighty-lineVertLength, lineWidth, lineVertLength + 2, color ); + } + break; + case 4://healthBar + if ( charIndex > 0 ) + { + /* + //tried to keep original functionality, but it would pop from top to bottom + //when you let go of the button and had no way to tell then (during the + //fade-out) whether it should be on top or bottom. So now it is always on top. + if ( !scanAll ) + { + if ( !CG_WorldCoordToScreenCoord( bottom, &x, &y, qfalse ) ) + {//Can't draw bottom + return; + } + } + else + */ + {//try to draw at top as to not obscure the tricorder + CG_WorldCoordToScreenCoord( top, &x, &y, qtrue ); + if ( y > 0.01 ) + { + y -= SMALLCHAR_HEIGHT; + if ( y > 0.01 ) + { + if ( charIndex > 0 && name ) + { + if ( y >= SMALLCHAR_HEIGHT ) + { + y -= SMALLCHAR_HEIGHT; + } + else + { + y = 0.01; + } + } + if ( y > 0.01 ) + { + if ( rankCharIndex > 0 && rank ) + { + if ( y >= SMALLCHAR_HEIGHT ) + { + y -= SMALLCHAR_HEIGHT; + } + } + if ( y > 0.01 ) + { + if ( ageCharIndex > 0 && age ) + { + if ( y >= SMALLCHAR_HEIGHT ) + { + y -= SMALLCHAR_HEIGHT; + } + } + if ( y > 0.01 ) + { + if ( classCharIndex > 0 && pClass ) + { + if ( y >= SMALLCHAR_HEIGHT ) + { + y -= SMALLCHAR_HEIGHT; + } + } + if ( y > 0.01 ) + { + if ( raceCharIndex > 0 && race ) + { + if ( y >= SMALLCHAR_HEIGHT ) + { + y -= SMALLCHAR_HEIGHT; + } + } + if ( y > 0.01 ) + { + if ( htCharIndex > 0 && height ) + { + if ( y >= SMALLCHAR_HEIGHT ) + { + y -= SMALLCHAR_HEIGHT; + } + } + if ( y > 0.01 ) + { + if ( wtCharIndex > 0 && weight ) + { + if ( y >= SMALLCHAR_HEIGHT ) + { + y -= SMALLCHAR_HEIGHT; + } + } + if ( y > 0.01 ) + { + if ( weapCharIndex > 0 && weapon ) + { + if ( y >= SMALLCHAR_HEIGHT ) + { + y -= SMALLCHAR_HEIGHT; + } + } + } + } + } + } + } + } + } + } + } + } + + if ( !color[0] && !color[1] && !color[2] ) + { + // We really don't want black, so set it to yellow + color[0] = 0.9F;//R + color[1] = 0.7F;//G + color[2] = 0.0F;//B + } + color[3] = 0.75; + + if ( !drawHealth || !health ) + { + continue; + } + + //health = ci->health; //health, max_health //ceil( (float)ci->health/(float)100.0f*100.0f ); + //CG_ColorForGivenHealth( hcolor, health ); + //hwidth = (float)health*0.5f; + + //y += lineWidth + 2; + + //CG_FillRect( x - hwidth/2, y + lineWidth, hwidth, lineWidth*2, hcolor ); + + //y += lineWidth*2; + + Com_sprintf( showHealth, sizeof( showHealth ), "%s: %i", "Health", health ); + + if ( healthCharIndex > 0 && showHealth[0] ) { + int len = strlen( showHealth ); + + if ( healthCharIndex > len+1 ) + { + healthCharIndex = len+1; + } + else + { + trap_S_StartSound( NULL, 0, CHAN_ITEM, cgs.media.tedTextSound ); + } + //Q_strncpyz( showHealth, showHealth, healthCharIndex ); + w = CG_DrawStrlen( showHealth ) * SMALLCHAR_WIDTH; + Q_strncpyz( showHealth, showHealth, healthCharIndex ); + CG_DrawSmallStringColor( x - w / 2, y + lineWidth, showHealth, color ); + y += SMALLCHAR_HEIGHT; + } + } + break; + case 5://infoString (name/description) + //Bright yellow + //VectorCopy( crossEnt->startRGBA, color ); + + /*if ( !color[0] && !color[1] && !color[2] ) + { + // We really don't want black, so set it to yellow + color[0] = 0.9F;//R + color[1] = 0.7F;//G + color[2] = 0.0F;//B + } + color[3] = 0.75;*/ + if ( charIndex > 0 && name ) + { + int len = strlen(name); + if ( charIndex > len+1 ) + { + charIndex = len+1; + } + else + { + trap_S_StartSound( NULL, 0, CHAN_ITEM, cgs.media.tedTextSound ); + } + Q_strncpyz( showName, name, charIndex ); + w = CG_DrawStrlen( name ) * SMALLCHAR_WIDTH; + CG_DrawSmallStringColor( x - w / 2, y + lineWidth, showName, color ); + y += SMALLCHAR_HEIGHT; + } + break; + case 6://class + if ( classCharIndex > 0 && pClass ) + { + int len = strlen(pClass); + if ( classCharIndex > len+1 ) + { + classCharIndex = len+1; + } + else + { + trap_S_StartSound( NULL, 0, CHAN_ITEM, cgs.media.tedTextSound ); + } + Q_strncpyz( showClass, pClass, classCharIndex ); + w = CG_DrawStrlen( pClass ) * SMALLCHAR_WIDTH; + CG_DrawSmallStringColor( x - w / 2, y + lineWidth, showClass, color ); + y += SMALLCHAR_HEIGHT; + } + break; + case 7://rank + if ( rankCharIndex > 0 && rank ) + { + int len = strlen(rank); + if ( rankCharIndex > len+1 ) + { + rankCharIndex = len+1; + } + else + { + trap_S_StartSound( NULL, 0, CHAN_ITEM, cgs.media.tedTextSound ); + } + Q_strncpyz( showRank, rank, rankCharIndex ); + w = CG_DrawStrlen( rank ) * SMALLCHAR_WIDTH; + CG_DrawSmallStringColor( x - w / 2, y + lineWidth, showRank, color ); + y += SMALLCHAR_HEIGHT; + } + break; + case 8://age + if ( ageCharIndex > 0 && age ) + { + int len = strlen(age); + if ( ageCharIndex > len+1 ) + { + ageCharIndex = len+1; + } + else + { + trap_S_StartSound( NULL, 0, CHAN_ITEM, cgs.media.tedTextSound ); + } + Q_strncpyz( showAge, age, ageCharIndex ); + w = CG_DrawStrlen( age ) * SMALLCHAR_WIDTH; + CG_DrawSmallStringColor( x - w / 2, y + lineWidth, showAge, color ); + y += SMALLCHAR_HEIGHT; + } + break; + case 9://race + if ( raceCharIndex > 0 && race ) + { + int len = strlen(race); + if ( raceCharIndex > len+1 ) + { + raceCharIndex = len+1; + } + else + { + trap_S_StartSound( NULL, 0, CHAN_ITEM, cgs.media.tedTextSound ); + } + Q_strncpyz( showRace, race, raceCharIndex ); + w = CG_DrawStrlen( race ) * SMALLCHAR_WIDTH; + CG_DrawSmallStringColor( x - w / 2, y + lineWidth, showRace, color ); + y += SMALLCHAR_HEIGHT; + } + break; + case 10://height + if ( htCharIndex > 0 && height ) + { + int len = strlen(height); + if ( htCharIndex > len+1 ) + { + htCharIndex = len+1; + } + else + { + trap_S_StartSound( NULL, 0, CHAN_ITEM, cgs.media.tedTextSound ); + } + Q_strncpyz( showHt, height, htCharIndex ); + w = CG_DrawStrlen( height ) * SMALLCHAR_WIDTH; + CG_DrawSmallStringColor( x - w / 2, y + lineWidth, showHt, color ); + y += SMALLCHAR_HEIGHT; + } + break; + case 11://weight + if ( wtCharIndex > 0 && weight ) + { + int len = strlen(weight); + if ( wtCharIndex > len+1 ) + { + wtCharIndex = len+1; + } + else + { + trap_S_StartSound( NULL, 0, CHAN_ITEM, cgs.media.tedTextSound ); + } + Q_strncpyz( showWt, weight, wtCharIndex ); + w = CG_DrawStrlen( weight ) * SMALLCHAR_WIDTH; + CG_DrawSmallStringColor( x - w / 2, y + lineWidth, showWt, color ); + y += SMALLCHAR_HEIGHT; + } + break; + case 12://weapon + if ( weapCharIndex > 0 && weapon ) + { + int len = strlen(weapon); + if ( weapCharIndex > len+1 ) + { + weapCharIndex = len+1; + } + else + { + trap_S_StartSound( NULL, 0, CHAN_ITEM, cgs.media.tedTextSound ); + } + Q_strncpyz( showWeap, weapon, weapCharIndex ); + w = CG_DrawStrlen( weapon ) * SMALLCHAR_WIDTH; + CG_DrawSmallStringColor( x - w / 2, y + lineWidth, showWeap, color ); + y += SMALLCHAR_HEIGHT; + } + break; + } } - hShader = cgs.media.crosshairShader[ ca % NUM_CROSSHAIRS ]; - - // Use a different method rendering the crosshair so players don't see two of them when - // focusing their eyes at distant objects with high stereo separation - // We are going to trace to the next shootable object and place the crosshair in front of it. - - // first get all the important renderer information - trap_Cvar_VariableStringBuffer("r_zProj", rendererinfos, sizeof(rendererinfos)); - zProj = atof(rendererinfos); - trap_Cvar_VariableStringBuffer("r_stereoSeparation", rendererinfos, sizeof(rendererinfos)); - stereoSep = zProj / atof(rendererinfos); - - xmax = zProj * tan(cg.refdef.fov_x * M_PI / 360.0f); - - // let the trace run through until a change in stereo separation of the crosshair becomes less than one pixel. - maxdist = cgs.glconfig.vidWidth * stereoSep * zProj / (2 * xmax); - VectorMA(cg.refdef.vieworg, maxdist, cg.refdef.viewaxis[0], endpos); - CG_Trace(&trace, cg.refdef.vieworg, NULL, NULL, endpos, 0, MASK_SHOT); - - memset(&ent, 0, sizeof(ent)); - ent.reType = RT_SPRITE; - ent.renderfx = RF_DEPTHHACK | RF_CROSSHAIR; - - VectorCopy(trace.endpos, ent.origin); - - // scale the crosshair so it appears the same size for all distances - ent.radius = w / 640 * xmax * trace.fraction * maxdist / zProj; - ent.customShader = hShader; - - trap_R_AddRefEntityToScene(&ent); } - - /* ================= CG_ScanForCrosshairEntity @@ -1993,30 +3736,64 @@ static void CG_ScanForCrosshairEntity( void ) { trace_t trace; vec3_t start, end; int content; + vec3_t pitchConstraint, df_f; - VectorCopy( cg.refdef.vieworg, start ); - VectorMA( start, 131072, cg.refdef.viewaxis[0], end ); + VectorCopy( cg.predictedPlayerState.origin, start ); //cg.refdef.vieworg + start[2] += (float)cg.predictedPlayerState.viewheight * cgs.clientinfo[cg.predictedPlayerState.clientNum].height; + //VectorCopy( cg.predictedPlayerState.origin, start); + //start[2] += cg.predictedPlayerState.viewheight; - CG_Trace( &trace, start, vec3_origin, vec3_origin, end, - cg.snap->ps.clientNum, CONTENTS_SOLID|CONTENTS_BODY ); - if ( trace.entityNum >= MAX_CLIENTS ) { - return; + VectorCopy( cg.predictedPlayerState.viewangles, pitchConstraint ); + AngleVectors( pitchConstraint, df_f, NULL, NULL ); + + VectorMA( start, 8912, df_f, end); + + //VectorMA( start, 8192, cg.refdef.viewaxis[0], end ); + + if ( cg.snap->ps.weapon == WP_7 && cg.zoomed ) { + CG_Trace( &trace, start, vec3_origin, vec3_origin, end, + cg.snap->ps.clientNum, CONTENTS_BODY ); + + // if the player is invisible, don't show it + if ( cg_entities[ trace.entityNum ].currentState.powerups & ( 1 << PW_INVIS ) && !cgs.clientinfo[cg.snap->ps.clientNum].isAdmin/*cg.snap->ps.persistant[PERS_CLASS] != PC_ADMIN*/ ) { + return; + } } + else { + CG_Trace( &trace, start, vec3_origin, vec3_origin, end, + cg.snap->ps.clientNum, MASK_SHOT ); //CONTENTS_SOLID|CONTENTS_BODY - // if the player is in fog, don't show it - content = CG_PointContents( trace.endpos, 0 ); - if ( content & CONTENTS_FOG ) { - return; - } + if ( cg.predictedPlayerState.weapon == WP_2 && cg.predictedPlayerState.eFlags & EF_FIRING + && (cg_entities[trace.entityNum].currentState.eType == ET_TRIC_STRING || cg_entities[trace.entityNum].currentState.eType == ET_MOVER_STR) ) + { + //Never mind if it's a valid useable ent + } //else, return + else if ( trace.entityNum >= MAX_CLIENTS && !cgs.clientinfo[cg.snap->ps.clientNum].isAdmin/*cg.predictedPlayerState.persistant[PERS_CLASS] != PC_ADMIN*/ ) { + return; + } + + // if the player is in fog, don't show it + content = trap_CM_PointContents( trace.endpos, 0 ); + if ( content & CONTENTS_FOG ) { + return; + } + + // if the player is invisible, don't show it + if ( cg_entities[ trace.entityNum ].currentState.powerups & ( 1 << PW_INVIS ) && !cgs.clientinfo[cg.snap->ps.clientNum].isAdmin/*cg.snap->ps.persistant[PERS_CLASS] != PC_ADMIN*/ ) { + return; + } + + if ( cg.crosshairClientNum != trace.entityNum) { + infoStringCount = 0; + } - // if the player is invisible, don't show it - if ( cg_entities[ trace.entityNum ].currentState.powerups & ( 1 << PW_INVIS ) ) { - return; } // update the fade timer cg.crosshairClientNum = trace.entityNum; cg.crosshairClientTime = cg.time; + + //CG_Printf( "Current ent num: %i\n", cg.crosshairClientNum ); } @@ -2025,44 +3802,346 @@ static void CG_ScanForCrosshairEntity( void ) { CG_DrawCrosshairNames ===================== */ + +extern qboolean PM_PlayerCrouching ( int legsAnim ); + +static vec3_t playerMins = {-12, -12, -24}; //RPG-X : TiM - {-15, -15, -24} +static vec3_t playerMaxs = {12, 12, 32}; // {15, 15, 32} static void CG_DrawCrosshairNames( void ) { float *color; - char *name; - float w; + char name[MAX_QPATH]; + int team; + centity_t *cent; + //vec4_t vecColor = { 0.0, 1.0, 0.0, 1.0 }; + int x, y; + qboolean tinyFont; + int drawFlags; - if ( !cg_drawCrosshair.integer ) { - return; - } - if ( !cg_drawCrosshairNames.integer ) { - return; - } - if ( cg.renderingThirdPerson ) { + if ( !cg_drawCrosshair.integer ) + { return; } + //if ( cg.renderingThirdPerson ) + //{ + // return; + //} + // scan the known entities to see if the crosshair is sighted on one CG_ScanForCrosshairEntity(); - + // draw the name of the player being looked at color = CG_FadeColor( cg.crosshairClientTime, 1000 ); - if ( !color ) { + if ( !color ) + { trap_R_SetColor( NULL ); + infoStringCount = 0; return; } - name = cgs.clientinfo[ cg.crosshairClientNum ].name; -#ifdef MISSIONPACK - color[3] *= 0.5f; - w = CG_Text_Width(name, 0.3f, 0); - CG_Text_Paint( 320 - w / 2, 190, 0.3f, color, name, 0, 0, ITEM_TEXTSTYLE_SHADOWED); -#else - w = CG_DrawStrlen( name ) * BIGCHAR_WIDTH; - CG_DrawBigString( 320 - w / 2, 170, name, color[3] * 0.5f ); -#endif - trap_R_SetColor( NULL ); + color[3] *= 0.9; + + //If they're actively firing the tricorder + if( ( (cg.snap->ps.eFlags & EF_FIRING) && !(cg.snap->ps.eFlags & EF_ALT_FIRING) ) + && cg.snap->ps.weapon == WP_2 ) { + if(cg.crosshairClientNum != cg.predictedPlayerState.clientNum && cg.crosshairClientNum < MAX_CLIENTS ) { //ENTITYNUM_WORLD + + drawCrosshairName = qfalse; + + cent = &cg_entities[cg.crosshairClientNum]; + + if ( cent ) { + char *name = NULL; + char *rank = NULL; + char *race = NULL; + char *age = NULL; + char *pClass = NULL; + //vec3_t size; + float ht = 0; + float wt = 0; + //int health = 0; + char *weap = NULL; + char namestr[128]; + char rankstr[128]; + char racestr[128]; + char htstr[128]; + char wtstr[128]; + char weapstr[128]; + char agestr[128]; + char classstr[128]; + int i, irank; + int score = 0; + clientInfo_t *ci; + + for ( i = 0; i < cgs.maxclients; i++ ) { + if ( cg.scores[i].client == cg.crosshairClientNum ) { + score = cg.scores[i].score; + break; + } + } + + irank = score;//Q_log2( score ); + + ci = &cgs.clientinfo[cg.crosshairClientNum]; + //over-ride the color, since we can't get teams in this case + //use that good old LCARS yellow + color[0] = 0.694f;//0.9F;//R + color[1] = 0.816f;//0.7F;//G + color[2] = 1.0f;//0.0F;//B + color[3] *= 0.5; + + //vec3_t maxs, mins; + + //VectorCopy( crossEnt->maxs, maxs ); + //VectorCopy( crossEnt->mins, mins ); + //if ( crossEnt->client && crossEnt->NPC ) + //{//only use the standing height of the NPCs because people can't understand the complex dynamics of height in weight in a ceiling-installed anti-gravitic plating environment + // maxs[2] = crossEnt->client->standheight; + //} + //VectorSubtract(maxs, mins, size); + //ht = (maxs[2] - mins[2]) * 3.46875;//magic number + ht = ci->height * (float)BASE_HEIGHT; + //wt = VectorLength(size)*1.4;//magic number + wt = ci->weight * ci->height * (float)BASE_WEIGHT; + //if ( crossEnt->client && crossEnt->NPC ) + //{ + //if ( strstr( crossEnt->client->renderInfo.legsModelName, "female" ) || + // strstr( crossEnt->client->renderInfo.legsModelName, "seven" ) ) + //{//crewfemale, hazardfemale or seven of nine + if ( ci->gender == GENDER_FEMALE ) { + wt *= (float)FEMALE_OFFSET;//magic number, women are lighter than men + } + + if ( ci->race && ci->race[0] ) { + race = ci->race; + Com_sprintf( racestr, sizeof( racestr ), "%s: %s", "Race", race ); + //Q_strncpyz( race, racestr, sizeof( racestr) ); + } + + if ( ci->age && ci->age[0] ) { + age = ci->age; + Com_sprintf( agestr, sizeof( agestr ), "%s: %s", "Age", age ); + //Q_strncpyz( race, racestr, sizeof( racestr) ); + } + + //Com_Printf( "%i\n", ci->pClass ); + pClass = cgs.classData[ci->pClass].formalName; + /*switch ( ci->pClass ) { + case PC_ADMIN: + pClass = "Admin"; + break; + case PC_SECURITY: + pClass = "Security"; + break; + case PC_ALIEN: + pClass = "Alien"; + break; + case PC_COMMAND: + pClass = "Command"; + break; + case PC_SCIENCE: + pClass = "Science"; + break; + case PC_ENGINEER: + pClass = "Engineer"; + break; + case PC_ALPHAOMEGA22: + pClass = "Marine"; + break; + case PC_N00B: + pClass = "n00b"; + break; + case PC_NOCLASS: + default: + pClass = "Unknown"; + break; + }*/ + + if ( pClass ) { + Com_sprintf( classstr, sizeof(classstr), "%s: %s", "Class", pClass ); + } + + if ( cgs.classData[ci->pClass].showRanks/*ci->pClass != PC_ALIEN && ci->pClass != PC_NOCLASS*/ ) { + //rank = "Awesome"; //RankForNumber func needed + if ( cgs.ranksData[irank].formalName[0] ) { + rank = cgs.ranksData[irank].formalName; + Com_sprintf( rankstr, sizeof( rankstr ), "%s: %s", "Rank", rank ); + } + //Q_strncpyz( rank, rankstr, sizeof( rankstr ) ); + } + + if ( ci->name && ci->name[0] ) { + name = ci->name; + } + else { + name = "Data Not Available";//crossEnt->targetname; + } + + Com_sprintf( namestr, sizeof( namestr), "%s: %s", "Name", name ); + + if ( cent->currentState.weapon != WP_1 /*&& cg_weapons[ cent->currentState.weapon ].item*/ ) + { + if ( cg_weapons[ cent->currentState.weapon ].item->pickup_name ) { + weap = cg_weapons[ cent->currentState.weapon ].item->pickup_name; + Com_sprintf( weapstr, sizeof( weapstr), "%s: %s", "Weapon", weap ); + } + } + + Com_sprintf( htstr, sizeof(htstr), "%s: %4.2f %s","Height", ht, HEIGHT_UNIT ); + Com_sprintf( wtstr, sizeof(wtstr), "%s: %4.2f %s","Weight", wt, WEIGHT_UNIT ); + + //Com_Printf("Name: %s, Rank: %s, Race: %s, Height: %s, Weight: %s, Weap: %s\n", namestr, rankstr, racestr, htstr, wtstr, weapstr ); + + CG_LabelViewEntity( cg.crosshairClientNum, cent->lerpOrigin, playerMins, playerMaxs, + name ? namestr : NULL, qfalse, color, + (cgs.clientinfo[cg.snap->ps.clientNum].isAdmin || cgs.classData[cg.snap->ps.persistant[PERS_CLASS]].isMedic) ? qtrue : qfalse, ci->health, + pClass ? classstr : NULL, + rank ? rankstr : NULL, + race ? racestr : NULL, + age ? agestr : NULL, + ht ? htstr : NULL, + wt ? wtstr : NULL, + weap ? weapstr : NULL); + } + else { + infoStringCount = 0; + } + } + else { + if ( (cg_entities[cg.crosshairClientNum].currentState.eType == ET_TRIC_STRING || cg_entities[cg.crosshairClientNum].currentState.eType == ET_MOVER_STR) && cgs.scannablePanels ) + { + entityState_t *eState; + vec3_t origin; + vec3_t mins, maxs; + char *renderString; + + eState = &cg_entities[cg.crosshairClientNum].currentState; + + color[0] = 0.694f;//0.9F;//R + color[1] = 0.816f;//0.7F;//G + color[2] = 1.0f;//0.0F;//B + color[3] *= 0.5; + + //TiM: Since dynamic brush ents seem to have no freaking origin in them, let's + // calc our own using the bounding box dimensions (At least we have those lol ) + VectorAverage( eState->origin2, eState->angles2, origin ); + //origin[2] = eState->origin2[2] - 24; + + //The algorithm needs the max and min dimensions to be symmetrical on either side + //of the origin. This set of random code does that. :) + VectorSubtract( origin, eState->origin2, mins ); + + VectorSet( maxs, Q_fabs( mins[0] ), Q_fabs( mins[1] ), Q_fabs( mins[2] ) ); + VectorScale( maxs, -1, mins ); + + if ( eState->time2 > 0 ) + renderString = (char *)CG_ConfigString( CS_TRIC_STRINGS + eState->time2 ); + else if ( eState->weapon > 0 && cgs.scannableStrings[eState->weapon-1][0] ) + renderString = cgs.scannableStrings[eState->weapon-1]; //subtracted since '0' is a valid cell value + else + renderString = ""; + + + CG_LabelViewEntity( cg.crosshairClientNum, origin, + mins, maxs, renderString, //cgs.tricStrings[eState->time2], + qfalse, color, + qfalse, 0, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL); + } + } + } + else + drawCrosshairName = qtrue; + + if ( !cg_drawCrosshairNames.integer || cg.crosshairClientNum > MAX_CLIENTS || !drawCrosshairName ) + { + return; + } + + //Now only draw team names + health if specifically wanted + Q_strncpyz (name, cgs.clientinfo[ cg.crosshairClientNum ].name, sizeof (name) ); + + // Draw in red if red team, blue if blue team + if (cgs.gametype >= GT_TEAM) + { + Q_CleanStr(name); + team = cgs.clientinfo[ cg.crosshairClientNum ].team; + if (team==TEAM_RED) + { + color[0] = colorRed[0]; + color[1] = colorRed[1]; + color[2] = colorRed[2]; + } + else + { + color[0] = colorBlue[0]; + color[1] = colorBlue[1]; + color[2] = colorBlue[2]; + } + } + else + { + color[0] = colorTable[CT_YELLOW][0]; + color[1] = colorTable[CT_YELLOW][1]; + color[2] = colorTable[CT_YELLOW][2]; + } + + if ( !cg_dynamicCrosshairNames.integer ) + { + x = 320; + y = 170; + + tinyFont = qfalse; + + drawFlags = UI_CENTER|UI_SMALLFONT; + } + else + { + vec3_t org; + centity_t *cent; + float x2, y2; + + cent = &cg_entities[ cg.crosshairClientNum ]; + + VectorCopy( cent->lerpOrigin, org ); + + if ( PM_PlayerCrouching( cent->currentState.legsAnim ) ) + org[2] += CROUCH_VIEWHEIGHT + 7; + else + org[2] += DEFAULT_VIEWHEIGHT + 7; + + CG_WorldCoordToScreenCoord( org, &x2, &y2, qfalse); + + x = (int)x2; + y = (int)y2; + + tinyFont = qtrue; + drawFlags = UI_CENTER|UI_BOTTOM|UI_TINYFONT; + } + + //FIXME: need health (&armor?) of teammates (if not TEAM_FREE) or everyone (if SPECTATOR) (or just crosshairEnt?) sent to me + if (cgs.clientinfo[ cg.snap->ps.clientNum ].team == TEAM_SPECTATOR + || cgs.classData[cgs.clientinfo[ cg.snap->ps.clientNum ].pClass].isMedic + || cgs.clientinfo[ cg.snap->ps.clientNum ].isAdmin ) /*|| cgs.clientinfo[ cg.snap->ps.clientNum ].pClass == PC_MEDIC*/ + {//if I'm a spectator, draw colored health of target under crosshair + CG_GetColorForHealth( cgs.clientinfo[ cg.crosshairClientNum ].health, cgs.clientinfo[ cg.crosshairClientNum ].armor, color ); + + y -= ( tinyFont ? TINYCHAR_HEIGHT : SMALLCHAR_HEIGHT ); + + UI_DrawProportionalString(x,y+(tinyFont ? TINYCHAR_HEIGHT+5 : SMALLCHAR_HEIGHT),va( "^7%i", cgs.clientinfo[ cg.crosshairClientNum ].health ), drawFlags,color); + } + + UI_DrawProportionalString(x,y, va("^7%s ^7(%i)", name, cg.crosshairClientNum), drawFlags, color); } + //============================================================================== /* @@ -2071,12 +4150,22 @@ CG_DrawSpectator ================= */ static void CG_DrawSpectator(void) { - CG_DrawBigString(320 - 9 * 8, 440, "SPECTATOR", 1.0F); - if ( cgs.gametype == GT_TOURNAMENT ) { - CG_DrawBigString(320 - 15 * 8, 460, "waiting to play", 1.0F); +// CG_DrawBigString(320 - 9 * 8, 440, ingame_text[IGT_SPECTATOR], 1.0F); + if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) + { + UI_DrawProportionalString(SCREEN_WIDTH/2, SCREEN_HEIGHT - ((BIGCHAR_HEIGHT * 1.50) * 2) , ingame_text[IGT_SPECTATOR], UI_BIGFONT|UI_CENTER, colorTable[CT_LTGOLD1]); } - else if ( cgs.gametype >= GT_TEAM ) { - CG_DrawBigString(320 - 39 * 8, 460, "press ESC and use the JOIN menu to play", 1.0F); + /*else if ( cg.snap->ps.eFlags&EF_ELIMINATED ) + { + UI_DrawProportionalString(SCREEN_WIDTH/2, SCREEN_HEIGHT - ((BIGCHAR_HEIGHT * 1.50) * 2) , ingame_text[IGT_TITLEELIMINATED], UI_BIGFONT|UI_CENTER, colorTable[CT_LTGOLD1]); + }*/ + if ( cgs.gametype == GT_TOURNAMENT ) { +// CG_DrawBigString(320 - 15 * 8, 460, ingame_text[IGT_WAITINGTOPLAY], 1.0F); + UI_DrawProportionalString(SCREEN_WIDTH/2, SCREEN_HEIGHT - (BIGCHAR_HEIGHT * 1.5), ingame_text[IGT_WAITINGTOPLAY], UI_BIGFONT|UI_CENTER, colorTable[CT_LTGOLD1]); + } + if ( cgs.gametype == GT_TEAM || cgs.gametype == GT_CTF ) { +// CG_DrawBigString(320 - 25 * 8, 460, ingame_text[IGT_USEDTEAMMENU], 1.0F); + UI_DrawProportionalString(SCREEN_WIDTH/2, SCREEN_HEIGHT - (BIGCHAR_HEIGHT * 1.5), ingame_text[IGT_USEDTEAMMENU], UI_BIGFONT|UI_CENTER, colorTable[CT_LTGOLD1]); } } @@ -2103,114 +4192,10 @@ static void CG_DrawVote(void) { if ( sec < 0 ) { sec = 0; } -#ifdef MISSIONPACK - s = va("VOTE(%i):%s yes:%i no:%i", sec, cgs.voteString, cgs.voteYes, cgs.voteNo); - CG_DrawSmallString( 0, 58, s, 1.0F ); - s = "or press ESC then click Vote"; - CG_DrawSmallString( 0, 58 + SMALLCHAR_HEIGHT + 2, s, 1.0F ); -#else - s = va("VOTE(%i):%s yes:%i no:%i", sec, cgs.voteString, cgs.voteYes, cgs.voteNo ); - CG_DrawSmallString( 0, 58, s, 1.0F ); -#endif -} - -/* -================= -CG_DrawTeamVote -================= -*/ -static void CG_DrawTeamVote(void) { - char *s; - int sec, cs_offset; - - if ( cgs.clientinfo[cg.clientNum].team == TEAM_RED ) - cs_offset = 0; - else if ( cgs.clientinfo[cg.clientNum].team == TEAM_BLUE ) - cs_offset = 1; - else - return; - - if ( !cgs.teamVoteTime[cs_offset] ) { - return; - } - - // play a talk beep whenever it is modified - if ( cgs.teamVoteModified[cs_offset] ) { - cgs.teamVoteModified[cs_offset] = qfalse; - trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND ); - } - - sec = ( VOTE_TIME - ( cg.time - cgs.teamVoteTime[cs_offset] ) ) / 1000; - if ( sec < 0 ) { - sec = 0; - } - s = va("TEAMVOTE(%i):%s yes:%i no:%i", sec, cgs.teamVoteString[cs_offset], - cgs.teamVoteYes[cs_offset], cgs.teamVoteNo[cs_offset] ); - CG_DrawSmallString( 0, 90, s, 1.0F ); -} - - -static qboolean CG_DrawScoreboard( void ) { -#ifdef MISSIONPACK - static qboolean firstTime = qtrue; - - if (menuScoreboard) { - menuScoreboard->window.flags &= ~WINDOW_FORCED; - } - if (cg_paused.integer) { - cg.deferredPlayerLoading = 0; - firstTime = qtrue; - return qfalse; - } - - // should never happen in Team Arena - if (cgs.gametype == GT_SINGLE_PLAYER && cg.predictedPlayerState.pm_type == PM_INTERMISSION ) { - cg.deferredPlayerLoading = 0; - firstTime = qtrue; - return qfalse; - } - - // don't draw scoreboard during death while warmup up - if ( cg.warmup && !cg.showScores ) { - return qfalse; - } - - if ( cg.showScores || cg.predictedPlayerState.pm_type == PM_DEAD || cg.predictedPlayerState.pm_type == PM_INTERMISSION ) { - } else { - if ( !CG_FadeColor( cg.scoreFadeTime, FADE_TIME ) ) { - // next time scoreboard comes up, don't print killer - cg.deferredPlayerLoading = 0; - cg.killerName[0] = 0; - firstTime = qtrue; - return qfalse; - } - } - - if (menuScoreboard == NULL) { - if ( cgs.gametype >= GT_TEAM ) { - menuScoreboard = Menus_FindByName("teamscore_menu"); - } else { - menuScoreboard = Menus_FindByName("score_menu"); - } - } - - if (menuScoreboard) { - if (firstTime) { - CG_SetScoreSelection(menuScoreboard); - firstTime = qfalse; - } - Menu_Paint(menuScoreboard, qtrue); - } - - // load any models that have been deferred - if ( ++cg.deferredPlayerLoading > 10 ) { - CG_LoadDeferredPlayers(); - } - - return qtrue; -#else - return CG_DrawOldScoreboard(); -#endif + s = va("%s(%i):%s %s(F1):%i %s(F2):%i", ingame_text[IGT_VOTE],sec, cgs.voteString,ingame_text[IGT_YES], cgs.voteYes,ingame_text[IGT_NO] ,cgs.voteNo); + +// CG_DrawSmallStringColor( 0, 58, s, colorTable[CT_YELLOW] ); + UI_DrawProportionalString( 0, 58, s, UI_SMALLFONT, colorTable[CT_YELLOW]); } /* @@ -2219,20 +4204,41 @@ CG_DrawIntermission ================= */ static void CG_DrawIntermission( void ) { -// int key; -#ifdef MISSIONPACK - //if (cg_singlePlayer.integer) { - // CG_DrawCenterString(); - // return; - //} -#else - if ( cgs.gametype == GT_SINGLE_PLAYER ) { + if (0)// cgs.gametype == GT_SINGLE_PLAYER ) + { CG_DrawCenterString(); return; } -#endif + cg.scoreFadeTime = cg.time; - cg.scoreBoardShowing = CG_DrawScoreboard(); + CG_DrawScoreboard(); +} + +/* +================= +CG_DrawAbridgedObjective +================= +*/ +static void CG_DrawAbridgedObjective(void) +{ + int i,pixelLen,x,y; + + for (i=0;ips.clientNum ].name; - x = 0.5 * ( 640 - GIANT_WIDTH * CG_DrawStrlen( name ) ); - - CG_DrawStringExt( x, 40, name, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 ); + y += (BIGCHAR_HEIGHT * 1.25); + UI_DrawProportionalString( (SCREEN_WIDTH/2), 40, name, UI_BIGFONT|UI_CENTER, color); return qtrue; } @@ -2271,85 +4277,49 @@ static qboolean CG_DrawFollow( void ) { ================= CG_DrawAmmoWarning ================= +RPG-X | Marcin | 30/12/2008 +Don't!!! */ -static void CG_DrawAmmoWarning( void ) { - const char *s; - int w; - - if ( cg_drawAmmoWarning.integer == 0 ) { - return; - } - - if ( !cg.lowAmmoWarning ) { - return; - } - - if ( cg.lowAmmoWarning == 2 ) { - s = "OUT OF AMMO"; - } else { - s = "LOW AMMO WARNING"; - } - w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; - CG_DrawBigString(320 - w / 2, 64, s, 1.0F); -} - - -#ifdef MISSIONPACK +static void CG_DrawAmmoWarning( void ) +{ + return; /* -================= -CG_DrawProxWarning -================= -*/ -static void CG_DrawProxWarning( void ) { - char s [32]; - int w; - static int proxTime; - static int proxCounter; - static int proxTick; + const char *s; - if( !(cg.snap->ps.eFlags & EF_TICKING ) ) { - proxTime = 0; + if ( cg_drawAmmoWarning.integer == 0 ) + { return; } - if (proxTime == 0) { - proxTime = cg.time + 5000; - proxCounter = 5; - proxTick = 0; - } + if ( !cg.lowAmmoWarning ) + { + return; + } - if (cg.time > proxTime) { - proxTick = proxCounter--; - proxTime = cg.time + 1000; - } + if ( cg.lowAmmoWarning >= 2 ) + { + s = ingame_text[IGT_OUTOFAMMO]; + } else + { + s = ingame_text[IGT_LOWAMMO]; + } - if (proxTick != 0) { - Com_sprintf(s, sizeof(s), "INTERNAL COMBUSTION IN: %i", proxTick); - } else { - Com_sprintf(s, sizeof(s), "YOU HAVE BEEN MINED"); - } + UI_DrawProportionalString(320, 64, s, UI_SMALLFONT | UI_CENTER, colorTable[CT_LTGOLD1]); */ - w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; - CG_DrawBigStringColor( 320 - w / 2, 64 + BIGCHAR_HEIGHT, s, g_color_table[ColorIndex(COLOR_RED)] ); } -#endif - /* ================= CG_DrawWarmup ================= */ +extern void CG_AddGameModNameToGameName( char *gamename ); static void CG_DrawWarmup( void ) { int w; int sec; int i; -#ifdef MISSIONPACK - float scale; -#else - int cw; -#endif clientInfo_t *ci1, *ci2; + int cw; const char *s; sec = cg.warmup; @@ -2358,9 +4328,12 @@ static void CG_DrawWarmup( void ) { } if ( sec < 0 ) { - s = "Waiting for players"; - w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; - CG_DrawBigString(320 - w / 2, 24, s, 1.0F); + s = ingame_text[IGT_WAITINGFORPLAYERS]; +// w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; + w = UI_ProportionalStringWidth(s,UI_BIGFONT); +// CG_DrawBigString(320 - w / 2, 40, s, 1.0F); + UI_DrawProportionalString(320 - w / 2, 40, s, UI_BIGFONT, colorTable[CT_LTGOLD1]); + cg.warmupCount = 0; return; } @@ -2381,59 +4354,52 @@ static void CG_DrawWarmup( void ) { if ( ci1 && ci2 ) { s = va( "%s vs %s", ci1->name, ci2->name ); -#ifdef MISSIONPACK - w = CG_Text_Width(s, 0.6f, 0); - CG_Text_Paint(320 - w / 2, 60, 0.6f, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE); -#else - w = CG_DrawStrlen( s ); - if ( w > 640 / GIANT_WIDTH ) { +// w = CG_DrawStrlen( s ); + w = UI_ProportionalStringWidth(s,UI_BIGFONT); + + if ( w > 640 / BIGCHAR_WIDTH ) { cw = 640 / w; } else { - cw = GIANT_WIDTH; + cw = BIGCHAR_WIDTH; } - CG_DrawStringExt( 320 - w * cw/2, 20,s, colorWhite, - qfalse, qtrue, cw, (int)(cw * 1.5f), 0 ); -#endif +// CG_DrawStringExt( 320 - w * cw/2, 20,s, colorWhite, +// qfalse, qtrue, cw, (int)(cw * 1.5), 0 ); + UI_DrawProportionalString( (SCREEN_WIDTH/2), 20,s, UI_BIGFONT|UI_CENTER, colorTable[CT_LTGOLD1]); + } } else { + char gamename[1024]; + if ( cgs.gametype == GT_FFA ) { - s = "Free For All"; + s = ingame_text[IGT_GAME_FREEFORALL]; } else if ( cgs.gametype == GT_TEAM ) { - s = "Team Deathmatch"; + s =ingame_text[IGT_GAME_TEAMHOLOMATCH]; } else if ( cgs.gametype == GT_CTF ) { - s = "Capture the Flag"; -#ifdef MISSIONPACK - } else if ( cgs.gametype == GT_1FCTF ) { - s = "One Flag CTF"; - } else if ( cgs.gametype == GT_OBELISK ) { - s = "Overload"; - } else if ( cgs.gametype == GT_HARVESTER ) { - s = "Harvester"; -#endif + s = ingame_text[IGT_GAME_CAPTUREFLAG]; } else { s = ""; } -#ifdef MISSIONPACK - w = CG_Text_Width(s, 0.6f, 0); - CG_Text_Paint(320 - w / 2, 90, 0.6f, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE); -#else - w = CG_DrawStrlen( s ); - if ( w > 640 / GIANT_WIDTH ) { + + Q_strncpyz( gamename, s, sizeof(gamename) ); + + CG_AddGameModNameToGameName( gamename ); + + w = UI_ProportionalStringWidth(s,UI_BIGFONT); + + if ( w > 640 / BIGCHAR_WIDTH ) { cw = 640 / w; } else { - cw = GIANT_WIDTH; + cw = BIGCHAR_WIDTH; } - CG_DrawStringExt( 320 - w * cw/2, 25,s, colorWhite, - qfalse, qtrue, cw, (int)(cw * 1.1f), 0 ); -#endif + + UI_DrawProportionalString((SCREEN_WIDTH/2) , 20,gamename, UI_BIGFONT|UI_CENTER, colorTable[CT_LTGOLD1]); } sec = ( sec - cg.time ) / 1000; if ( sec < 0 ) { - cg.warmup = 0; sec = 0; } - s = va( "Starts in: %i", sec + 1 ); + s = va( "%s: %i",ingame_text[IGT_STARTSIN], sec + 1 ); if ( sec != cg.warmupCount ) { cg.warmupCount = sec; switch ( sec ) { @@ -2450,26 +4416,6 @@ static void CG_DrawWarmup( void ) { break; } } - -#ifdef MISSIONPACK - switch ( cg.warmupCount ) { - case 0: - scale = 0.54f; - break; - case 1: - scale = 0.51f; - break; - case 2: - scale = 0.48f; - break; - default: - scale = 0.45f; - break; - } - - w = CG_Text_Width(s, scale, 0); - CG_Text_Paint(320 - w / 2, 125, scale, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE); -#else switch ( cg.warmupCount ) { case 0: cw = 28; @@ -2485,42 +4431,401 @@ static void CG_DrawWarmup( void ) { break; } - w = CG_DrawStrlen( s ); - CG_DrawStringExt( 320 - w * cw/2, 70, s, colorWhite, - qfalse, qtrue, cw, (int)(cw * 1.5), 0 ); -#endif +// w = CG_DrawStrlen( s ); +// CG_DrawStringExt( 320 - w * cw/2, 70, s, colorWhite, +// qfalse, qtrue, cw, (int)(cw * 1.5), 0 ); + + w = UI_ProportionalStringWidth(s,UI_BIGFONT); + UI_DrawProportionalString( (SCREEN_WIDTH/2), 70, s, UI_BIGFONT|UI_CENTER, colorTable[CT_LTGOLD1]); + } -//================================================================================== -#ifdef MISSIONPACK -/* -================= -CG_DrawTimedMenus -================= +/* +================ +CG_DrawZoomMask + +================ */ -void CG_DrawTimedMenus( void ) { - if (cg.voiceTime) { - int t = cg.time - cg.voiceTime; - if ( t > 2500 ) { - Menus_CloseByName("voiceMenu"); - trap_Cvar_Set("cl_conXOffset", "0"); - cg.voiceTime = 0; +static void CG_DrawZoomMask( void ) +{ + float amt = 1, size, /*val,*/ start_x, start_y; + int width, height, i; + vec4_t color1; + int x, y; + + /*if ( cg.snap->ps.persistant[PERS_CLASS] == PC_NOCLASS + || cg.snap->ps.persistant[PERS_CLASS] != PC_SECURITY + && cg.snap->ps.persistant[PERS_CLASS] != PC_ALPHAOMEGA22 + && cg.snap->ps.persistant[PERS_CLASS] != PC_ADMIN ) + {//in a class-based game, only the sniper can zoom + cg.zoomed = qfalse; + cg.zoomLocked = qfalse; + return; + }*/ + //TiM: New system. :) Base zoom on current active weapon. :) + if ( !(cg.snap->ps.weapon == WP_6 || cg.snap->ps.weapon == WP_7) ) + { + cg.zoomed = qfalse; + cg.zoomLocked = qfalse; + return; + } + + // Calc where to place the zoom mask...all calcs are based off of a virtual 640x480 screen + size = cg_viewsize.integer; + + width = 640 * size * 0.01; + width &= ~1; + + height = 480 * size * 0.01; + height &= ~1; + + start_x = ( 640 - width ) * 0.5; + start_y = ( 480 - height ) * 0.5; + + if ( cg.zoomed ) + { + // Smoothly fade in..Turn this off for now since the zoom is set to snap to 30% or so...fade looks a bit weird when it does that + if ( cg.time - cg.zoomTime <= ZOOM_OUT_TIME ) { + amt = ( cg.time - cg.zoomTime ) / ZOOM_OUT_TIME; + } + + // Fade mask in + for ( i = 0; i < 4; i++ ) { + color1[i] = amt; + } + + // Set fade color + trap_R_SetColor( color1 ); + + if ( cg.snap->ps.weapon == WP_7 ) { + static int TR116LoopTime = 0; + + //Loop the whirring sight sound + if ( TR116LoopTime < cg.time ) + { + trap_S_StartSound( cg.refdef.vieworg, ENTITYNUM_WORLD, CHAN_LOCAL, cgs.media.tr116Whir ); + TR116LoopTime = cg.time + 900; + } + + CG_DrawPic( start_x, start_y, width, height, cgs.media.zoomMask116Shader ); + + //if we're zoomed over a potential target, start flashing the red crosshair + if ( cg.crosshairClientNum != cg.snap->ps.clientNum + && cg.crosshairClientNum < MAX_CLIENTS ) + { + vec4_t alphaColor; + float amt; + + if ( cg.time > zoomFlashTime ) { + zoomFlashTime = cg.time + 800; + trap_S_StartLocalSound( cgs.media.tr116Chirp, CHAN_LOCAL_SOUND ); + } + + amt = ( ( zoomFlashTime % cg.time ) / 500.0f ); + amt = Com_Clamp( 0.0, 1.0, amt ); + + //Com_Printf( S_COLOR_RED "Ratio: %f\n", amt ); + + VectorSet( alphaColor, 1, 1, 1 ); + alphaColor[3] = amt; + + trap_R_SetColor( alphaColor ); + //======================================== + + CG_DrawPic( 256, 176, 128, 128, cgs.media.zoomGlow116Shader ); + trap_R_SetColor( color1 ); + } + else + { + zoomFlashTime = 0; + } + } + else { + CG_DrawPic( start_x, start_y, width, height, cgs.media.zoomMaskShader ); + } + + /* RPG-X - TiM : Since the rifle's view doesn't really account for these elements, toss 'em + start_x = 210; + start_y = 80; + + CG_DrawPic( 320 + start_x, 241, 35, -170, cgs.media.zoomBarShader); + CG_DrawPic( 320 - start_x, 241, -35, -170, cgs.media.zoomBarShader); + CG_DrawPic( 320 + start_x, 239, 35, 170, cgs.media.zoomBarShader); + CG_DrawPic( 320 - start_x, 239, -35, 170, cgs.media.zoomBarShader); + + // Calculate a percent and clamp it + val = 26 - ( cg_fov.value - cg_zoomFov.value ) / ( cg_fov.value - MAX_ZOOM_FOV ) * 26; + + if ( val > 17.0f ) + val = 17.0f; + else if ( val < 0.0f ) + val = 0.0f; + + // pink + color1[0] = 0.85f; + color1[1] = 0.55f; + color1[2] = 0.75f; + color1[3] = 1.0f; + + CG_DrawPic( 320 + start_x + 12, 245, 10, 108, cgs.media.zoomInsertShader ); + CG_DrawPic( 320 + start_x + 12, 235, 10, -108, cgs.media.zoomInsertShader ); + CG_DrawPic( 320 - start_x - 12, 245, -10, 108, cgs.media.zoomInsertShader ); + CG_DrawPic( 320 - start_x - 12, 235, -10, -108, cgs.media.zoomInsertShader ); + + trap_R_SetColor( color1 ); + i = ((int)val) * 6; + + CG_DrawPic( 320 + start_x + 10, 230 - i, 12, 5, cgs.media.ammoslider ); + CG_DrawPic( 320 + start_x + 10, 251 + i, 12, -5, cgs.media.ammoslider ); + CG_DrawPic( 320 - start_x - 10, 230 - i, -12, 5, cgs.media.ammoslider ); + CG_DrawPic( 320 - start_x - 10, 251 + i, -12, -5, cgs.media.ammoslider ); + */ + + //yellow + if ( cg.snap->ps.weapon == WP_7 ) { + color1[0] = 0.886f; + color1[1] = 0.749f; + color1[2] = 0.0f; + color1[3] = 0.60f; + } + else { // red + color1[0] = 1.0f; + color1[1] = 0.0f; + color1[2] = 0.0f; + color1[3] = 0.60f; + } + + // Convert zoom and view axis into some numbers to throw onto the screen + if ( cg.snap->ps.weapon == WP_7 ) { + x = 74; + y = 340; + } + else { + x = 468; + y = 300; + } + + trap_R_SetColor( color1 ); + CG_DrawNumField( x, y, 5, cg_zoomFov.value * 1000 + 9999, 18, 10 ,NUM_FONT_BIG ); //100 + CG_DrawNumField( x, y+20, 5, cg.refdef.viewaxis[0][0] * 9999 + 20000, 18, 10,NUM_FONT_BIG ); + CG_DrawNumField( x, y+40, 5, cg.refdef.viewaxis[0][1] * 9999 + 20000, 18, 10,NUM_FONT_BIG ); + CG_DrawNumField( x, y+60, 5, cg.refdef.viewaxis[0][2] * 9999 + 20000, 18, 10,NUM_FONT_BIG ); + + /* + // Is it time to draw the little max zoom arrows? + if ( val < 0.2f ) + { + amt = sin( cg.time * 0.03 ) * 0.5 + 0.5; + color1[0] = 0.592156f * amt; + color1[1] = 0.592156f * amt; + color1[2] = 0.850980f * amt; + color1[3] = 1.0f * amt; + + trap_R_SetColor( color1 ); + + CG_DrawPic( 320 + start_x, 240 - 6, 16, 12, cgs.media.zoomArrowShader ); + CG_DrawPic( 320 - start_x, 240 - 6, -16, 12, cgs.media.zoomArrowShader ); + }*/ + } + else + { + if ( cg.time - cg.zoomTime <= ZOOM_OUT_TIME ) + { + amt = 1.0f - ( cg.time - cg.zoomTime ) / ZOOM_OUT_TIME; + + // Fade mask away + for ( i = 0; i < 4; i++ ) { + color1[i] = amt; + } + + trap_R_SetColor( color1 ); + if ( cg.snap->ps.weapon == WP_7 ) { + CG_DrawPic( start_x, start_y, width, height, cgs.media.zoomMask116Shader ); + } + else { + CG_DrawPic( start_x, start_y, width, height, cgs.media.zoomMaskShader ); + } } } } -#endif + +//================================================================================== + +/*static char *AfterSpace( char *p ) +{ + while (*p && *p != ' ') { + ++p; + } + + return p; +}*/ + +/* +===================== +CG_Drawcg.adminMsg +RPG-X | Phenix | 08/06/2005 +RPG-X | Marcin | 30/12/2008 + +Now I'm going to kill you Phenix!!!! +===================== +*/ +static void CG_DrawAdminMsg( void ) { + float y; + int t; + int i, msgRow, msgCol; + int biggestW, w; + char message[35][45]; + char *thisMessage; + char *p, *currRow; + static vec4_t color; + static vec4_t Boxcolor; + + y = 460; + + //Nothing to display + if ( cg.adminMsgTime < cg.time ) + { + return; + } + + //No message! + if ( cg.adminMsgMsg[0] == '\0' ) + { + return; + } + + //Colour Fade. + t = cg.adminMsgTime - cg.time; + + // fade out + if (t < 500) { + color[3] = t * 1.0/500; + } else { + color[3] = 1.0; + } + color[0] = color[1] = color[2] = 1; + + Boxcolor[0] = 0.016; + Boxcolor[1] = 0.055; + Boxcolor[2] = 0.170; + /* + CT_VDK_PURPLE + (New values are halfed + Boxcolor[0] = 0.031; + Boxcolor[1] = 0.110; + Boxcolor[2] = 0.341; + */ + Boxcolor[3] = color[3]; + + /*if ( !color ) { + return; + }*/ + + trap_R_SetColor( color ); + + i = 0; + + msgRow = 0; + msgCol = 0; + p = cg.adminMsgMsg; + currRow = p; + + while ( qtrue ) { + if ( !*p ) { + break; + } + + if ( NextWordEndsHere( p ) - currRow > 43 ) { //we need to wrap... + message[msgRow][msgCol] = '\0'; + currRow = p++; + ++msgRow, msgCol = 0; + continue; + } + + message[msgRow][msgCol] = *p; + ++p, ++msgCol; + } + + message[msgRow][msgCol] = '\0'; + ++msgRow; + + /* Sorry but this code really didn't work Phenix ... memory errors. + for (msgRow = 0; msgRow < 35; msgRow++) + { + if (cg.adminMsgMsg[i] == '\0') + { + break; + } + + for (msgCol = 0; msgCol < 45; msgCol++) + { + if (cg.adminMsgMsg[i] == '\0') + { + break; + } + + if (cg.adminMsgMsg[i] == '\\') + { + i++; + break; + } + + if ((msgCol >= 30) && (cg.adminMsgMsg[i] == ' ')) + { + i++; + break; + } + + if (msgCol == 44) { + message[msgRow][msgCol] = '-'; + } else { + message[msgRow][msgCol] = cg.adminMsgMsg[i]; + i++; + } + } + } + */ + + biggestW = 0; + for (i = 0; i < msgRow; i++) + { + thisMessage = va("%s", message[i]); + w = UI_ProportionalStringWidth(thisMessage, UI_SMALLFONT); + + if (w > biggestW) + { + biggestW = w; + } + } + + CG_FillRect( 640 - (biggestW + 22), y - (((SMALLCHAR_HEIGHT + 2) * msgRow) + 2), biggestW + 4, ((SMALLCHAR_HEIGHT + 2) * msgRow) + 4, Boxcolor ); + + for (i = (msgRow - 1); i >= 0; i--) + { + y -= (SMALLCHAR_HEIGHT + 2); + + //memset(&thisMessage, 0, sizeof(thisMessage)); + thisMessage = va("%s", message[i]); + UI_DrawProportionalString(640 - (biggestW + 20), y, thisMessage, UI_SMALLFONT, color); + } + + + trap_R_SetColor( NULL ); + +} + /* ================= CG_Draw2D ================= */ -static void CG_Draw2D(stereoFrame_t stereoFrame) -{ -#ifdef MISSIONPACK - if (cgs.orderPending && cg.time > cgs.orderTime) { - CG_CheckOrderPending(); - } -#endif +static void CG_Draw2D( void ) { + int i; + + //TiM : Testing this API function... + //trap_R_SetColor( colorTable[ CT_RED ] ); + //trap_R_DrawStretchPic( 100, 100, 800, 600, 0, 0, 0.5, 0.5, cgs.media.charsetPropB ); + // if we are taking a levelshot for the menu, don't draw anything if ( cg.levelShot ) { return; @@ -2530,96 +4835,116 @@ static void CG_Draw2D(stereoFrame_t stereoFrame) return; } + if ( cg.snap->ps.pm_type == PM_CCAM ) { + return; + } + if ( cg.snap->ps.pm_type == PM_INTERMISSION ) { +#ifndef FINAL_BUILD + CG_DrawUpperRight(); +#endif CG_DrawIntermission(); return; } -/* - if (cg.cameraMode) { - return; + if ( !cg.renderingThirdPerson ) + { + CG_DrawZoomMask(); } -*/ - if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) { - CG_DrawSpectator(); + + //RPG-X: RedTechie - Keep Lagometer on the botum always - if(stereoFrame == STEREO_CENTER) - CG_DrawCrosshair(); + cgs.widescreen.state = WIDESCREEN_RIGHT; + CG_DrawLagometer(); + cgs.widescreen.state = WIDESCREEN_NONE; + if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR /*|| (cg.snap->ps.eFlags&EF_ELIMINATED)*/ ) { +// CG_DrawSpectator(); + CG_DrawCrosshair(); CG_DrawCrosshairNames(); } else { - // don't draw any status if dead or the scoreboard is being explicitly shown - if ( !cg.showScores && cg.snap->ps.stats[STAT_HEALTH] > 0 ) { - -#ifdef MISSIONPACK - if ( cg_drawStatus.integer ) { - Menu_PaintAll(); - CG_DrawTimedMenus(); - } -#else - CG_DrawStatusBar(); -#endif - - CG_DrawAmmoWarning(); - -#ifdef MISSIONPACK - CG_DrawProxWarning(); -#endif - if(stereoFrame == STEREO_CENTER) + cgs.widescreen.state = WIDESCREEN_LEFT; + CG_DrawStatusBar(); //RPG-X: RedTechie - We want health displayed when dead + // don't draw any status if dead + if ( cg.snap->ps.stats[STAT_HEALTH] > 1 ) { //RPG-X: RedTechie - No weapons at health 1 (you die at health 1 now) + //CG_DrawStatusBar(); + CG_DrawAmmoWarning(); + + cgs.widescreen.state = WIDESCREEN_NONE; CG_DrawCrosshair(); - CG_DrawCrosshairNames(); - CG_DrawWeaponSelect(); -#ifndef MISSIONPACK - CG_DrawHoldableItem(); -#else - //CG_DrawPersistantPowerup(); -#endif - CG_DrawReward(); - } - - if ( cgs.gametype >= GT_TEAM ) { -#ifndef MISSIONPACK - CG_DrawTeamInfo(); -#endif - } + cgs.widescreen.state = WIDESCREEN_CENTER; + CG_DrawCrosshairNames(); + + cgs.widescreen.state = WIDESCREEN_LEFT; + CG_DrawWeaponSelect(); + + cgs.widescreen.state = WIDESCREEN_RIGHT; + CG_DrawHoldableItem(); + CG_DrawReward(); + CG_DrawAbridgedObjective(); + + cgs.widescreen.state = WIDESCREEN_NONE; + } + if ( cgs.gametype >= GT_TEAM ) { + CG_DrawTeamInfo(); + } + cgs.widescreen.state = WIDESCREEN_NONE; + } + + if (cg.showObjectives) + { + CG_DrawObjectiveInformation(); } CG_DrawVote(); - CG_DrawTeamVote(); + + //RPG-X: RedTechie - Moved above others to keep on the bottum + //CG_DrawLagometer(); - CG_DrawLagometer(); + CG_DrawUpperRight(); -#ifdef MISSIONPACK - if (!cg_paused.integer) { - CG_DrawUpperRight(stereoFrame); - } -#else - CG_DrawUpperRight(stereoFrame); -#endif - -#ifndef MISSIONPACK CG_DrawLowerRight(); - CG_DrawLowerLeft(); -#endif - if ( !CG_DrawFollow() ) { - CG_DrawWarmup(); - } + CG_DrawLowerLeft(); + + //RPG-X | Phenix | 08/06/2005 + cgs.widescreen.state = WIDESCREEN_CENTER; + CG_DrawAdminMsg(); + cgs.widescreen.state = WIDESCREEN_NONE; + + cgs.widescreen.state = WIDESCREEN_CENTER; + if ( !CG_DrawFollow() ) { + CG_DrawWarmup(); + } + cgs.widescreen.state = WIDESCREEN_NONE; // don't draw center string if scoreboard is up - cg.scoreBoardShowing = CG_DrawScoreboard(); - if ( !cg.scoreBoardShowing) { - CG_DrawCenterString(); + cgs.widescreen.state = WIDESCREEN_CENTER; + if ( !CG_DrawScoreboard() ) { + CG_DrawCenterString(); + } + cgs.widescreen.state = WIDESCREEN_NONE; + + // kef -- need the "use TEAM menu to play" message to draw on top of the bottom bar of scoreboard + if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR /*|| (cg.snap->ps.eFlags&EF_ELIMINATED)*/ ) + { + cgs.widescreen.state = WIDESCREEN_CENTER; + CG_DrawSpectator(); + cgs.widescreen.state = WIDESCREEN_NONE; } -} + //TiM - Draw teh fl4r3s + + for (i = 0; i < MAX_LENS_FLARES; i++) { + if ( lensFlare[i].qfull ) + CG_DrawLensFlare( &lensFlare[i] ); + + if ( lensFlare[i].upTime + lensFlare[i].holdTime + lensFlare[i].downTime > 0 && + cg.time > lensFlare[i].startTime + lensFlare[i].upTime + lensFlare[i].holdTime + lensFlare[i].downTime ) + lensFlare[i].qfull = qfalse; + } -static void CG_DrawTourneyScoreboard( void ) { -#ifdef MISSIONPACK -#else - CG_DrawOldTourneyScoreboard(); -#endif } /* @@ -2630,31 +4955,65 @@ Perform all drawing needed to completely fill the screen ===================== */ void CG_DrawActive( stereoFrame_t stereoView ) { + float separation; + vec3_t baseOrg; + // optionally draw the info screen instead if ( !cg.snap ) { CG_DrawInformation(); return; } + //vectors needed for tricorder + AngleVectors (cg.refdefViewAngles, vfwd, vright, vup); + VectorCopy( vfwd, vfwd_n ); + VectorCopy( vright, vright_n ); + VectorCopy( vup, vup_n ); + VectorNormalize( vfwd_n ); + VectorNormalize( vright_n ); + VectorNormalize( vup_n ); + // optionally draw the tournement scoreboard instead - if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR && + if ( (cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR /*|| (cg.snap->ps.eFlags&EF_ELIMINATED)*/)&& ( cg.snap->ps.pm_flags & PMF_SCOREBOARD ) ) { CG_DrawTourneyScoreboard(); return; } + switch ( stereoView ) { + case STEREO_CENTER: + separation = 0; + break; + case STEREO_LEFT: + separation = -cg_stereoSeparation.value / 2; + break; + case STEREO_RIGHT: + separation = cg_stereoSeparation.value / 2; + break; + default: + separation = 0; + CG_Error( "CG_DrawActive: Undefined stereoView" ); + } + + // clear around the rendered view if sized down CG_TileClear(); - if(stereoView != STEREO_CENTER) - CG_DrawCrosshair3D(); + // offset vieworg appropriately if we're doing stereo separation + VectorCopy( cg.refdef.vieworg, baseOrg ); + if ( separation != 0 ) { + VectorMA( cg.refdef.vieworg, -separation, cg.refdef.viewaxis[1], cg.refdef.vieworg ); + } // draw 3D view trap_R_RenderScene( &cg.refdef ); + // restore original viewpoint if running stereo + if ( separation != 0 ) { + VectorCopy( baseOrg, cg.refdef.vieworg ); + } + // draw status bar and other floating elements - CG_Draw2D(stereoView); + CG_Draw2D(); } - - diff --git a/code/cgame/cg_drawtools.c b/code/cgame/cg_drawtools.c index c0ce1ef..4a9c460 100644 --- a/code/cgame/cg_drawtools.c +++ b/code/cgame/cg_drawtools.c @@ -1,28 +1,18 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // // cg_drawtools.c -- helper functions called by cg_draw, cg_scoreboard, cg_info, etc #include "cg_local.h" +#define CHARMAX 256 + +static qboolean CG_IsWidescreen( void ) +{ + if ( cg_handleWidescreen.integer && cgs.widescreen.ratio && cgs.widescreen.state != WIDESCREEN_NONE ) + return qtrue; + + return qfalse; +} + /* ================ CG_AdjustFrom640 @@ -31,6 +21,8 @@ Adjusted for resolution and screen aspect ratio ================ */ void CG_AdjustFrom640( float *x, float *y, float *w, float *h ) { +//TiM - huh.... looks like the were looking into widescreens. +//only offsetting the X value isn't good enough tho #if 0 // adjust for wide screens if ( cgs.glconfig.vidWidth * 480 > cgs.glconfig.vidHeight * 640 ) { @@ -42,6 +34,19 @@ void CG_AdjustFrom640( float *x, float *y, float *w, float *h ) { *y *= cgs.screenYScale; *w *= cgs.screenXScale; *h *= cgs.screenYScale; + + //TiM - handle widescreens + if ( CG_IsWidescreen() ) + { + *w *= cgs.widescreen.ratio; + + if ( cgs.widescreen.state == WIDESCREEN_RIGHT ) + *x = (*x * cgs.widescreen.ratio) + (cgs.widescreen.bias*2);//*x = (*x+*w) - (*w * cgs.widescreen.ratio); + else if ( cgs.widescreen.state == WIDESCREEN_CENTER ) + *x = (*x * cgs.widescreen.ratio) + (cgs.widescreen.bias); + else + *x *= cgs.widescreen.ratio; + } } /* @@ -60,42 +65,6 @@ void CG_FillRect( float x, float y, float width, float height, const float *colo trap_R_SetColor( NULL ); } -/* -================ -CG_DrawSides - -Coords are virtual 640x480 -================ -*/ -void CG_DrawSides(float x, float y, float w, float h, float size) { - CG_AdjustFrom640( &x, &y, &w, &h ); - size *= cgs.screenXScale; - trap_R_DrawStretchPic( x, y, size, h, 0, 0, 0, 0, cgs.media.whiteShader ); - trap_R_DrawStretchPic( x + w - size, y, size, h, 0, 0, 0, 0, cgs.media.whiteShader ); -} - -void CG_DrawTopBottom(float x, float y, float w, float h, float size) { - CG_AdjustFrom640( &x, &y, &w, &h ); - size *= cgs.screenYScale; - trap_R_DrawStretchPic( x, y, w, size, 0, 0, 0, 0, cgs.media.whiteShader ); - trap_R_DrawStretchPic( x, y + h - size, w, size, 0, 0, 0, 0, cgs.media.whiteShader ); -} -/* -================ -UI_DrawRect - -Coordinates are 640*480 virtual values -================= -*/ -void CG_DrawRect( float x, float y, float width, float height, float size, const float *color ) { - trap_R_SetColor( color ); - - CG_DrawTopBottom(x, y, width, height, size); - CG_DrawSides(x, y, width, height, size); - - trap_R_SetColor( NULL ); -} - /* @@ -110,7 +79,20 @@ void CG_DrawPic( float x, float y, float width, float height, qhandle_t hShader trap_R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader ); } +/* +================ +CG_DrawStretchPic +TiM: Made so we can use +s1 - t2 as parameters as well :) + +Coordinates are 640*480 virtual values +================= +*/ +void CG_DrawStretchPic( float x, float y, float width, float height, float s1, float t1, float s2, float t2, qhandle_t hShader ) { + CG_AdjustFrom640( &x, &y, &width, &height ); + trap_R_DrawStretchPic( x, y, width, height, s1, t1, s2, t2, hShader ); +} /* =============== @@ -122,7 +104,7 @@ Coordinates and size in 640*480 virtual screen size void CG_DrawChar( int x, int y, int width, int height, int ch ) { int row, col; float frow, fcol; - float size; + float size,size2; float ax, ay, aw, ah; ch &= 255; @@ -140,14 +122,17 @@ void CG_DrawChar( int x, int y, int width, int height, int ch ) { row = ch>>4; col = ch&15; + frow = row*0.0625; fcol = col*0.0625; - size = 0.0625; + size = 0.03125; + size2 = 0.0625; trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, - fcol + size, frow + size, + fcol + size, frow + size2, cgs.media.charsetShader ); + } @@ -162,7 +147,7 @@ Coordinates are at 640 by 480 virtual resolution ================== */ void CG_DrawStringExt( int x, int y, const char *string, const float *setColor, - qboolean forceColor, qboolean shadow, int charWidth, int charHeight, int maxChars ) { + qboolean forceColor, qboolean shadow, int charWidth, int charHeight, int maxChars ) { vec4_t color; const char *s; int xx; @@ -272,10 +257,10 @@ refresh window. static void CG_TileClearBox( int x, int y, int w, int h, qhandle_t hShader ) { float s1, t1, s2, t2; - s1 = x/64.0; - t1 = y/64.0; - s2 = (x+w)/64.0; - t2 = (y+h)/64.0; + s1 = x / 64; + t1 = y / 64; + s2 = (x+w) / 64; + t2 = (y+h) / 64; trap_R_DrawStretchPic( x, y, w, h, s1, t1, s2, t2, hShader ); } @@ -357,10 +342,10 @@ CG_TeamColor ================ */ float *CG_TeamColor( int team ) { - static vec4_t red = {1, 0.2f, 0.2f, 1}; - static vec4_t blue = {0.2f, 0.2f, 1, 1}; + static vec4_t red = {1, 0.2, 0.2, 1}; + static vec4_t blue = {0.2, 0.2, 1, 1}; static vec4_t other = {1, 1, 1, 1}; - static vec4_t spectator = {0.7f, 0.7f, 0.7f, 1}; + static vec4_t spectator = {0.7, 0.7, 0.7, 1}; switch ( team ) { case TEAM_RED: @@ -393,7 +378,8 @@ void CG_GetColorForHealth( int health, int armor, vec4_t hcolor ) { return; } count = armor; - max = health * ARMOR_PROTECTION / ( 1.0 - ARMOR_PROTECTION ); + // kef -- FIXME ...not sure what's happening here, but a divide-by-zero would be bad + max = health;// * ARMOR_PROTECTION / ( 1.0 - ARMOR_PROTECTION ); if ( max < count ) { count = max; } @@ -431,120 +417,9 @@ void CG_ColorForHealth( vec4_t hcolor ) { } -/* -================= -UI_DrawProportionalString2 -================= -*/ -static int propMap[128][3] = { -{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, -{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, - -{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, -{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, - -{0, 0, PROP_SPACE_WIDTH}, // SPACE -{11, 122, 7}, // ! -{154, 181, 14}, // " -{55, 122, 17}, // # -{79, 122, 18}, // $ -{101, 122, 23}, // % -{153, 122, 18}, // & -{9, 93, 7}, // ' -{207, 122, 8}, // ( -{230, 122, 9}, // ) -{177, 122, 18}, // * -{30, 152, 18}, // + -{85, 181, 7}, // , -{34, 93, 11}, // - -{110, 181, 6}, // . -{130, 152, 14}, // / - -{22, 64, 17}, // 0 -{41, 64, 12}, // 1 -{58, 64, 17}, // 2 -{78, 64, 18}, // 3 -{98, 64, 19}, // 4 -{120, 64, 18}, // 5 -{141, 64, 18}, // 6 -{204, 64, 16}, // 7 -{162, 64, 17}, // 8 -{182, 64, 18}, // 9 -{59, 181, 7}, // : -{35,181, 7}, // ; -{203, 152, 14}, // < -{56, 93, 14}, // = -{228, 152, 14}, // > -{177, 181, 18}, // ? - -{28, 122, 22}, // @ -{5, 4, 18}, // A -{27, 4, 18}, // B -{48, 4, 18}, // C -{69, 4, 17}, // D -{90, 4, 13}, // E -{106, 4, 13}, // F -{121, 4, 18}, // G -{143, 4, 17}, // H -{164, 4, 8}, // I -{175, 4, 16}, // J -{195, 4, 18}, // K -{216, 4, 12}, // L -{230, 4, 23}, // M -{6, 34, 18}, // N -{27, 34, 18}, // O - -{48, 34, 18}, // P -{68, 34, 18}, // Q -{90, 34, 17}, // R -{110, 34, 18}, // S -{130, 34, 14}, // T -{146, 34, 18}, // U -{166, 34, 19}, // V -{185, 34, 29}, // W -{215, 34, 18}, // X -{234, 34, 18}, // Y -{5, 64, 14}, // Z -{60, 152, 7}, // [ -{106, 151, 13}, // '\' -{83, 152, 7}, // ] -{128, 122, 17}, // ^ -{4, 152, 21}, // _ - -{134, 181, 5}, // ' -{5, 4, 18}, // A -{27, 4, 18}, // B -{48, 4, 18}, // C -{69, 4, 17}, // D -{90, 4, 13}, // E -{106, 4, 13}, // F -{121, 4, 18}, // G -{143, 4, 17}, // H -{164, 4, 8}, // I -{175, 4, 16}, // J -{195, 4, 18}, // K -{216, 4, 12}, // L -{230, 4, 23}, // M -{6, 34, 18}, // N -{27, 34, 18}, // O - -{48, 34, 18}, // P -{68, 34, 18}, // Q -{90, 34, 17}, // R -{110, 34, 18}, // S -{130, 34, 14}, // T -{146, 34, 18}, // U -{166, 34, 19}, // V -{185, 34, 29}, // W -{215, 34, 18}, // X -{234, 34, 18}, // Y -{5, 64, 14}, // Z -{153, 152, 13}, // { -{11, 181, 5}, // | -{180, 152, 13}, // } -{79, 93, 17}, // ~ -{0, 0, -1} // DEL -}; +static int propMapTiny[CHARMAX][3]; +static int propMap[CHARMAX][3]; +static int propMapBig[CHARMAX][3]; static int propMapB[26][3] = { {11, 12, 33}, @@ -582,6 +457,9 @@ static int propMapB[26][3] = { #define PROPB_SPACE_WIDTH 12 #define PROPB_HEIGHT 36 +#define TEXTSHEET_SIZE 512 //TiM +#define ORIG_SCALE TEXTSHEET_SIZE / 256 + /* ================= UI_DrawBannerString @@ -590,7 +468,7 @@ UI_DrawBannerString static void UI_DrawBannerString2( int x, int y, const char* str, vec4_t color ) { const char* s; - unsigned char ch; + char ch; float ax; float ay; float aw; @@ -603,24 +481,25 @@ static void UI_DrawBannerString2( int x, int y, const char* str, vec4_t color ) // draw the colored text trap_R_SetColor( color ); - ax = x * cgs.screenXScale + cgs.screenXBias; +// ax = x * cgs.screenXScale + cgs.screenXBias; + ax = x * cgs.screenXScale; ay = y * cgs.screenYScale; s = str; while ( *s ) { - ch = *s & 127; + ch = *s & 255; if ( ch == ' ' ) { ax += ((float)PROPB_SPACE_WIDTH + (float)PROPB_GAP_WIDTH)* cgs.screenXScale; } else if ( ch >= 'A' && ch <= 'Z' ) { ch -= 'A'; - fcol = (float)propMapB[ch][0] / 256.0f; - frow = (float)propMapB[ch][1] / 256.0f; - fwidth = (float)propMapB[ch][2] / 256.0f; - fheight = (float)PROPB_HEIGHT / 256.0f; - aw = (float)propMapB[ch][2] * cgs.screenXScale; - ah = (float)PROPB_HEIGHT * cgs.screenYScale; + fcol = (float)propMapB[(int)ch][0] / 256; + frow = (float)propMapB[(int)ch][1] / 256; + fwidth = (float)propMapB[(int)ch][2] / 256; + fheight = (float)PROPB_HEIGHT / 256; + aw = (float)(propMapB[(int)ch][2] * cgs.screenXScale); + ah = (float)(PROPB_HEIGHT * cgs.screenYScale); trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol+fwidth, frow+fheight, cgs.media.charsetPropB ); ax += (aw + (float)PROPB_GAP_WIDTH * cgs.screenXScale); } @@ -674,70 +553,391 @@ void UI_DrawBannerString( int x, int y, const char* str, int style, vec4_t color UI_DrawBannerString2( x, y, str, color ); } +#define MAX_STRINGWIDTH 2048 -int UI_ProportionalStringWidth( const char* str ) { +/* +================= +UI_ProportionalSizeScale +================= +*/ +int UI_ProportionalStringWidth( const char* str,int style ) +{ const char * s; int ch; int charWidth; int width; + char holdStr[2048]; - s = str; - width = 0; - while ( *s ) { - ch = *s & 127; - charWidth = propMap[ch][2]; - if ( charWidth != -1 ) { - width += charWidth; - width += PROP_GAP_WIDTH; + Q_strncpyz( holdStr, str, MAX_STRINGWIDTH ); + + Q_CleanStr(holdStr); + + if (style & UI_TINYFONT) + { + s = holdStr; + width = 0; + while ( *s ) + { + ch = *s & 255; + charWidth = propMapTiny[ch][2]; + if ( charWidth != -1 ) + { + width += charWidth; + width += PROP_GAP_TINY_WIDTH; + } + s++; } - s++; + + width -= PROP_GAP_TINY_WIDTH; + } + else if (style & UI_BIGFONT) + { + s = holdStr; + width = 0; + while ( *s ) + { + ch = *s & 255; + charWidth = propMapBig[ch][2]; + if ( charWidth != -1 ) + { + width += charWidth; + width += PROP_GAP_BIG_WIDTH; + } + s++; + } + + width -= PROP_GAP_BIG_WIDTH; + } + else + { + s = holdStr; + width = 0; + while ( *s ) + { + ch = *s & 255; + charWidth = propMap[ch][2]; + if ( charWidth != -1 ) + { + width += charWidth; + width += PROP_GAP_WIDTH; + } + s++; + } + + width -= PROP_GAP_WIDTH; } - width -= PROP_GAP_WIDTH; return width; } -static void UI_DrawProportionalString2( int x, int y, const char* str, vec4_t color, float sizeScale, qhandle_t charset ) +static int specialTinyPropChars[CHARMAX][2] = { +{0, 0}, +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 10 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 20 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 30 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 40 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 50 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 60 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 70 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 80 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 90 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 100 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 110 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 120 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 130 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 140 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 150 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{2,-3},{0, 0}, // 160 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 170 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 180 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 190 +{0,-1},{2,-3},{2,-3},{2,-3},{2,-3},{2,-3},{2,-3},{0, 0},{2, 0},{2,-3}, // 200 +{2,-3},{2,-3},{2,-3},{2,-3},{2,-3},{2,-3},{2,-3},{0,-1},{2,-3},{2,-3}, // 210 +{2,-3},{3,-3},{2,-3},{2,-3},{0, 0},{0,-1},{2,-3},{2,-3},{2,-3},{2,-3}, // 220 +{2,-3},{0,-1},{0,-1},{2,-3},{2,-3},{2,-3},{2,-3},{2,-3},{2,-3},{0, 0}, // 230 +{2, 0},{2,-3},{2,-3},{2,-3},{2,-3},{2,-3},{2,-3},{2,-3},{2,-3},{0, 0}, // 240 +{2,-3},{2,-3},{2,-3},{2,-3},{2,-3},{2,-3},{0, 0},{0,-1},{2,-3},{2,-3}, // 250 +{2,-3},{2,-3},{2,-3},{0,-1},{2,-3} // 255 +}; + + +static int specialPropChars[CHARMAX][2] = { +{0, 0}, +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 10 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 20 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 30 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 40 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 50 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 60 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 70 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 80 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 90 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 100 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 110 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 120 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 130 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 140 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 150 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 160 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 170 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 180 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 190 +{2,-2},{2,-2},{2,-2},{2,-2},{2,-2},{2,-2},{2,-2},{0, 0},{1, 1},{2,-2}, // 200 +{2,-2},{2,-2},{2,-2},{2,-2},{2,-2},{2,-2},{2,-2},{0, 0},{2,-2},{2,-2}, // 210 +{2,-2},{2,-2},{2,-2},{2,-2},{0, 0},{0, 0},{2,-2},{2,-2},{2,-2},{2,-2}, // 220 +{2,-2},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 230 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 240 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 250 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0} // 255 +}; + + +static int specialBigPropChars[CHARMAX][2] = { +{0, 0}, +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 10 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 20 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 30 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 40 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 50 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 60 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 70 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 80 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 90 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 100 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 110 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 120 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 130 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 140 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 150 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 160 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 170 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 180 +{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0}, // 190 +{3,-3},{3,-3},{3,-3},{3,-3},{3,-3},{3,-3},{3,-3},{0, 0},{3, 1},{3,-3}, // 200 +{3,-3},{3,-3},{3,-3},{3,-3},{3,-3},{3,-3},{3,-3},{0, 0},{3,-3},{3,-3}, // 210 +{3,-3},{3,-3},{3,-3},{3,-3},{0, 0},{0, 0},{3,-3},{3,-3},{3,-3},{3,-3}, // 220 +{3,-3},{0, 0},{0, 0},{3,-3},{3,-3},{3,-3},{3,-3},{3,-3},{3,-3},{0, 0}, // 230 +{3, 1},{3,-3},{3,-3},{3,-3},{3,-3},{3,-3},{3,-3},{3,-3},{3,-3},{0, 0}, // 240 +{3,-3},{3,-3},{3,-3},{3,-3},{3,-3},{3,-3},{0, 0},{0, 0},{3,-3},{3,-3}, // 250 +{3,-3},{3,-3},{3,-3},{0, 0},{3,-3} // 255 +}; + +/* +================= +UI_AdjustForWideScreen +================= +*/ +static void UI_AdjustForWidescreen( float *x, float *w ) +{ + if ( CG_IsWidescreen() ) + *w *= cgs.widescreen.ratio; +} + +/* +================= +UI_DrawProportionalString2 +================= +*/ +static void UI_DrawProportionalString2( int x, int y, const char* str, vec4_t color, float sizeScale,int style, qhandle_t charset,qboolean forceColor ) { const char* s; unsigned char ch; float ax; - float ay; - float aw; + float ay,holdY; + float aw = 0; // stop compiler complaining about uninitialised vars float ah; float frow; float fcol; float fwidth; float fheight; + vec4_t givenColor; + int colorI; + int special; + + givenColor[0] = color[0]; + givenColor[1] = color[1]; + givenColor[2] = color[2]; + givenColor[3] = color[3]; // draw the colored text trap_R_SetColor( color ); - ax = x * cgs.screenXScale + cgs.screenXBias; +// ax = x * cgs.screenXScale + cgs.screenXBias; + ax = x * cgs.screenXScale; ay = y * cgs.screenYScale; + holdY = ay; - s = str; - while ( *s ) + if ( CG_IsWidescreen() ) { - ch = *s & 127; - if ( ch == ' ' ) { - aw = (float)PROP_SPACE_WIDTH * cgs.screenXScale * sizeScale; - } else if ( propMap[ch][2] != -1 ) { - fcol = (float)propMap[ch][0] / 256.0f; - frow = (float)propMap[ch][1] / 256.0f; - fwidth = (float)propMap[ch][2] / 256.0f; - fheight = (float)PROP_HEIGHT / 256.0f; - aw = (float)propMap[ch][2] * cgs.screenXScale * sizeScale; - ah = (float)PROP_HEIGHT * cgs.screenYScale * sizeScale; - trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol+fwidth, frow+fheight, charset ); - } else { - aw = 0; - } + ax *= cgs.widescreen.ratio; - ax += (aw + (float)PROP_GAP_WIDTH * cgs.screenXScale * sizeScale); - s++; + if ( cgs.widescreen.state == WIDESCREEN_CENTER ) + ax += cgs.widescreen.bias; + else if ( cgs.widescreen.state == WIDESCREEN_RIGHT ) + ax += (cgs.widescreen.bias*2); } + if (style & UI_TINYFONT) + { + s = str; + while ( *s ) + { + // Is there a color character + if ( Q_IsColorString( s ) ) + { + if (!forceColor) + { + colorI = ColorIndex( *(s+1) ); + trap_R_SetColor( g_color_table[colorI] ); + } + s += 2; + continue; + } + + //CG_Printf("s = %s, ch = %s", s, ch); + + ch = *s & 255; + if ( ch == ' ' ) + { + aw = (float)PROP_SPACE_TINY_WIDTH; + } + else if ( propMapTiny[ch][2] != -1 ) + { + // Because some foreign characters were a little different + special = specialTinyPropChars[ch][0]; + ay = holdY + (specialTinyPropChars[ch][1] * cgs.screenYScale); + + fcol = (float ) propMapTiny[ch][0] / 256; + frow = (float)propMapTiny[ch][1] / 256; + fwidth = (float)propMapTiny[ch][2] / 256; + fheight = (float)(PROP_TINY_HEIGHT + special) / 256; + aw = (float)propMapTiny[ch][2] * cgs.screenXScale * sizeScale; + ah = (float)(PROP_TINY_HEIGHT + special) * cgs.screenYScale * sizeScale; + + //TiM - adjust for widescreen + UI_AdjustForWidescreen( &ax, &aw ); + + trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol + fwidth, frow + fheight, charset ); + + } + + ax += (aw + (float)PROP_GAP_TINY_WIDTH * cgs.screenXScale * sizeScale); + + if ( CG_IsWidescreen() ) + ax -= ((float)PROP_GAP_TINY_WIDTH * cgs.screenXScale * sizeScale)*(1.0f-cgs.widescreen.ratio); + + s++; + } + } + else if (style & UI_BIGFONT) + { + s = str; + while ( *s ) + { + // Is there a color character + if ( Q_IsColorString( s ) ) + { + if (!forceColor) + { + colorI = ColorIndex( *(s+1) ); + trap_R_SetColor( g_color_table[colorI] ); + } + s += 2; + continue; + } + + ch = *s & 255; + if ( ch == ' ' ) + { + aw = (float)PROP_SPACE_BIG_WIDTH* cgs.screenXScale * sizeScale; + } + else if ( propMap[ch][2] != -1 ) + { + // Because some foreign characters were a little different + special = specialBigPropChars[ch][0]; + ay = holdY + (specialBigPropChars[ch][1] * cgs.screenYScale); + + fcol = (float ) propMapBig[ch][0] / 256; //256.0f + frow = (float)propMapBig[ch][1] / 256; + fwidth = (float)propMapBig[ch][2] / 256; + fheight = (float)(PROP_BIG_HEIGHT+ special) / 256; + aw = (float)propMapBig[ch][2] * cgs.screenXScale * sizeScale; + ah = (float)(PROP_BIG_HEIGHT+ special) * cgs.screenYScale * sizeScale; + + //TiM - adjust for widescreen + UI_AdjustForWidescreen( &ax, &aw ); + + trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol + fwidth, frow + fheight, + charset ); + + } + else + { + aw = 0; + } + + ax += (aw + (float)PROP_GAP_BIG_WIDTH * cgs.screenXScale * sizeScale); + + if ( CG_IsWidescreen() ) + ax -= ((float)PROP_GAP_BIG_WIDTH * cgs.screenXScale * sizeScale)*(1.0f-cgs.widescreen.ratio); + + + s++; + } + } + else + { + s = str; + while ( *s ) + { + // Is there a color character + if ( Q_IsColorString( s ) ) + { + if (!forceColor) + { + colorI = ColorIndex( *(s+1) ); + trap_R_SetColor( g_color_table[colorI] ); + } + s += 2; + continue; + } + + ch = *s & 255; + if ( ch == ' ' ) + { + aw = (float)PROP_SPACE_WIDTH * cgs.screenXScale * sizeScale; + } + else if ( propMap[ch][2] != -1 ) + { + // Because some foreign characters were a little different + special = specialPropChars[ch][0]; + ay = holdY + (specialPropChars[ch][1] * cgs.screenYScale); + + fcol = (float)propMap[ch][0] / 256; + frow = (float)propMap[ch][1] / 256; + fwidth = (float)propMap[ch][2] / 256; + fheight = (float)(PROP_HEIGHT+ special) / 256; + aw = (float)(propMap[ch][2] * cgs.screenXScale * sizeScale); + ah = (float)((PROP_HEIGHT+ special) * cgs.screenYScale * sizeScale); + + //TiM - adjust for widescreen + UI_AdjustForWidescreen( &ax, &aw ); + + trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol+fwidth, frow+fheight, charset ); + } + else + { + aw = 0; + } + + ax += (aw + (float)PROP_GAP_WIDTH * cgs.screenXScale * sizeScale); + + if ( CG_IsWidescreen() ) + ax -= ((float)PROP_GAP_WIDTH * cgs.screenXScale * sizeScale)*(1.0f-cgs.widescreen.ratio); + + s++; + } + } trap_R_SetColor( NULL ); } @@ -746,9 +946,11 @@ static void UI_DrawProportionalString2( int x, int y, const char* str, vec4_t co UI_ProportionalSizeScale ================= */ -float UI_ProportionalSizeScale( int style ) { - if( style & UI_SMALLFONT ) { - return 0.75; +float UI_ProportionalSizeScale( int style ) +{ + if( style & UI_SMALLFONT ) + { + return 1; } return 1.00; @@ -760,21 +962,24 @@ float UI_ProportionalSizeScale( int style ) { UI_DrawProportionalString ================= */ -void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color ) { - vec4_t drawcolor; - int width; - float sizeScale; +void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color ) +{ + vec4_t drawcolor; + int width; + float sizeScale; + qhandle_t charset; sizeScale = UI_ProportionalSizeScale( style ); - switch( style & UI_FORMATMASK ) { + switch( style & UI_FORMATMASK ) + { case UI_CENTER: - width = UI_ProportionalStringWidth( str ) * sizeScale; + width = UI_ProportionalStringWidth( str, style ) * sizeScale; x -= width / 2; break; case UI_RIGHT: - width = UI_ProportionalStringWidth( str ) * sizeScale; + width = UI_ProportionalStringWidth( str,style ) * sizeScale; x -= width; break; @@ -783,35 +988,891 @@ void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t break; } - if ( style & UI_DROPSHADOW ) { - drawcolor[0] = drawcolor[1] = drawcolor[2] = 0; - drawcolor[3] = color[3]; - UI_DrawProportionalString2( x+2, y+2, str, drawcolor, sizeScale, cgs.media.charsetProp ); + //TiM - vertical align + if ( style & UI_BOTTOM ) + { + if (style & UI_TINYFONT) + y -= (PROP_TINY_HEIGHT+3); + else if (style & UI_BIGFONT) + y -= (PROP_BIG_HEIGHT+3); + else + y -= (PROP_HEIGHT+3); } - if ( style & UI_INVERSE ) { + if (style & UI_TINYFONT) + { + charset = cgs.media.charsetPropTiny; + } + else if (style & UI_BIGFONT) + { + charset = cgs.media.charsetPropBig; + sizeScale = 1; + } + else + { + charset = cgs.media.charsetProp; + sizeScale = 1; + } + + if ( style & UI_DROPSHADOW ) + { + drawcolor[0] = drawcolor[1] = drawcolor[2] = 0; + drawcolor[3] = color[3]; + + UI_DrawProportionalString2( x+2, y+2, str, drawcolor, sizeScale,style, charset,qtrue ); + } + + if ( style & UI_INVERSE ) + { drawcolor[0] = color[0] * 0.8; drawcolor[1] = color[1] * 0.8; drawcolor[2] = color[2] * 0.8; drawcolor[3] = color[3]; - UI_DrawProportionalString2( x, y, str, drawcolor, sizeScale, cgs.media.charsetProp ); + UI_DrawProportionalString2( x, y, str, drawcolor, sizeScale,style, charset,qtrue ); return; } - if ( style & UI_PULSE ) { + if ( style & UI_PULSE ) + { drawcolor[0] = color[0] * 0.8; drawcolor[1] = color[1] * 0.8; drawcolor[2] = color[2] * 0.8; drawcolor[3] = color[3]; - UI_DrawProportionalString2( x, y, str, color, sizeScale, cgs.media.charsetProp ); + UI_DrawProportionalString2( x, y, str, color, sizeScale,style, charset,qtrue ); drawcolor[0] = color[0]; drawcolor[1] = color[1]; drawcolor[2] = color[2]; drawcolor[3] = 0.5 + 0.5 * sin( cg.time / PULSE_DIVISOR ); - UI_DrawProportionalString2( x, y, str, drawcolor, sizeScale, cgs.media.charsetPropGlow ); + UI_DrawProportionalString2( x, y, str, drawcolor, sizeScale,style,charset,qtrue ); return; } - UI_DrawProportionalString2( x, y, str, color, sizeScale, cgs.media.charsetProp ); + if ( style & UI_FORCECOLOR ) + { + UI_DrawProportionalString2( x, y, str, color, sizeScale,style, charset,qtrue); + return; + } + + UI_DrawProportionalString2( x, y, str, color, sizeScale,style, charset,qfalse); +} + +/* +============== +CG_DrawNumField + +Take x,y positions as if 640 x 480 and scales them to the proper resolution + +============== +*/ +void CG_DrawNumField (int x, int y, int width, int value,int charWidth,int charHeight,int style) +{ + char num[16], *ptr; + int l; + int frame; + int xWidth; + + if (width < 1) { + return; + } + + // draw number string + if (width > 5) { + width = 5; + } + + switch ( width ) { + case 1: + value = value > 9 ? 9 : value; + value = value < 0 ? 0 : value; + break; + case 2: + value = value > 99 ? 99 : value; + value = value < -9 ? -9 : value; + break; + case 3: + value = value > 999 ? 999 : value; + value = value < -99 ? -99 : value; + break; + case 4: + value = value > 9999 ? 9999 : value; + value = value < -999 ? -999 : value; + break; + } + + Com_sprintf (num, sizeof(num), "%i", value); + l = strlen(num); + if (l > width) + l = width; + + if (style & NUM_FONT_SMALL) + { + xWidth = 4 + 2; + } + else + { + xWidth = (charWidth/2) + 3;//(charWidth/6); + } + + x += 2 + (xWidth)*(width - l); + + ptr = num; + while (*ptr && l) + { + if (*ptr == '-') + frame = STAT_MINUS; + else + frame = *ptr -'0'; + + if (style & NUM_FONT_SMALL) + { + CG_DrawPic( x,y, charWidth, charHeight, cgs.media.smallnumberShaders[frame] ); + } + else + { + CG_DrawPic( x,y, charWidth, charHeight, cgs.media.numberShaders[frame] ); + } + + x += (xWidth); + ptr++; + l--; + } + +} + +/* +================ +CG_PrintInterfaceGraphics +================ +*/ +void CG_PrintInterfaceGraphics(int min,int max) +{ + int i; + vec4_t drawcolor; + + // Printing graphics + for (i=min;ips.persistant[PERS_TEAM] == TEAM_RED ) + { + drawcolor[0] = 1; + } + else if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) + { + drawcolor[2] = 1; + } + + if (interface_graphics[i].type == SG_GRAPHIC) + { + trap_R_SetColor(drawcolor); + + CG_DrawPic( interface_graphics[i].x, + interface_graphics[i].y, + interface_graphics[i].width, + interface_graphics[i].height, + interface_graphics[i].graphic); + } + else if (interface_graphics[i].type == SG_NUMBER) + { + if (interface_graphics[i].style & UI_PULSE) + { + drawcolor[3] = 0.5+0.5*sin(cg.time/PULSE_DIVISOR); + } + trap_R_SetColor( drawcolor); + + CG_DrawNumField ( + interface_graphics[i].x, + interface_graphics[i].y, 3, + interface_graphics[i].max, + interface_graphics[i].width, + interface_graphics[i].height,interface_graphics[i].style); + } + } + + trap_R_SetColor(NULL); +} + +/* +================= +CG_ParseFontParms +================= +*/ +static char *CG_ParseFontParms(char *buffer,int propArray[CHARMAX][3]) +{ + char *token; + int i,i2; + + while ( buffer ) + { + token = COM_ParseExt( &buffer, qtrue ); + + // Start with open braket + if ( !Q_stricmp( token, "{" ) ) + { + for (i=0;i FONT_BUFF_LENGTH) + { + trap_Print( va( S_COLOR_RED "CG_LoadFonts : FONTS.DAT file bigger than %d!\n",FONT_BUFF_LENGTH)); + return; + } + + // initialise the data area + memset(buffer, 0, sizeof(buffer)); + + trap_FS_Read( buffer, len, f ); + + trap_FS_FCloseFile( f ); + + COM_BeginParseSession(); + + holdBuf = (char *) buffer; + holdBuf = CG_ParseFontParms( holdBuf,propMapTiny); + holdBuf = CG_ParseFontParms( holdBuf,propMap); + holdBuf = CG_ParseFontParms( holdBuf,propMapBig); + +} + +/* +================= +CG_ParseRankData + +Takes '{ x, y, w, h, file_route } and parses it. +================= +*/ + +#define MAX_RANK_WIDTH 67 +#define MAX_RANK_HEIGHT 15 + +qboolean CG_ParseRankData( char **data, rankMenuData_t* rankMenuData ) { + const char* token; + + token = COM_ParseExt( data, qtrue ); + if ( token[0] == 0 ) { + Com_Printf( S_COLOR_RED "Unexpected EOF! O_o\n" ); + return qtrue; + } + + if ( !Q_stricmp( token, "{" ) ) { + //parse w value + token = COM_ParseExt( data, qtrue ); + if ( token[0] == 0 ) { + Com_Printf( S_COLOR_RED "Unexpected EOF! O_o\n" ); + return qtrue; + } + rankMenuData->w = atoi( token ); + + if ( rankMenuData->w > MAX_RANK_WIDTH ) { + rankMenuData->w = MAX_RANK_WIDTH; + } + + //parse h value + token = COM_ParseExt( data, qtrue ); + if ( token[0] == 0 ) { + Com_Printf( S_COLOR_RED "Unexpected EOF! O_o\n" ); + return qtrue; + } + rankMenuData->h = atoi( token ); + + if ( rankMenuData->h > MAX_RANK_HEIGHT ) { + rankMenuData->h = MAX_RANK_HEIGHT; + } + + //parse s1 value + token = COM_ParseExt( data, qtrue ); + if ( token[0] == 0 ) { + Com_Printf( S_COLOR_RED "Unexpected EOF! O_o\n" ); + return qtrue; + } + rankMenuData->s1 = atoi( token ); + + if ( !rankMenuData->s1 ) { + Com_Printf( S_COLOR_RED "Invalid s1 value in rankset\n"); + return qtrue; + } + + //parse t1 value + token = COM_ParseExt( data, qtrue ); + if ( token[0] == 0 ) { + Com_Printf( S_COLOR_RED "Unexpected EOF! O_o\n" ); + return qtrue; + } + rankMenuData->t1 = atoi( token ); + + if ( !rankMenuData->t1 ) { + Com_Printf( S_COLOR_RED "Invalid t1 value in rankset\n"); + return qtrue; + } + + //parse s2 value + token = COM_ParseExt( data, qtrue ); + if ( token[0] == 0 ) { + Com_Printf( S_COLOR_RED "Unexpected EOF! O_o\n" ); + return qtrue; + } + rankMenuData->s2 = atoi( token ); + + if ( !rankMenuData->s2 ) { + Com_Printf( S_COLOR_RED "Invalid s2 value in rankset\n"); + return qtrue; + } + + //parse t2 value + token = COM_ParseExt( data, qtrue ); + if ( token[0] == 0 ) { + Com_Printf( S_COLOR_RED "Unexpected EOF! O_o\n" ); + return qtrue; + } + rankMenuData->t2 = atoi( token ); + + if ( !rankMenuData->t2 ) { + Com_Printf( S_COLOR_RED "Invalid t2 value in rankset\n"); + return qtrue; + } + + //parse gWidth value + token = COM_ParseExt( data, qtrue ); + if ( token[0] == 0 ) { + Com_Printf( S_COLOR_RED "Unexpected EOF! O_o\n" ); + return qtrue; + } + rankMenuData->gWidth = atoi( token ); + + if ( !rankMenuData->gWidth ) { + Com_Printf( S_COLOR_RED "Invalid graphic width value in rankset\n"); + return qtrue; + } + + //parse gHeight value + token = COM_ParseExt( data, qtrue ); + if ( token[0] == 0 ) { + Com_Printf( S_COLOR_RED "Unexpected EOF! O_o\n" ); + return qtrue; + } + rankMenuData->gHeight = atoi( token ); + + if ( !rankMenuData->gHeight ) { + Com_Printf( S_COLOR_RED "Invalid graphic height value in rankset\n"); + return qtrue; + } + + //parse graphics handle + token = COM_ParseExt( data, qtrue ); + if ( token[0] == 0 ) { + Com_Printf( S_COLOR_RED "Unexpected EOF! O_o\n" ); + return qtrue; + } + rankMenuData->graphic = trap_R_RegisterShaderNoMip( token ); + + if ( !rankMenuData->graphic ) { + Com_Printf( S_COLOR_RED "Unable to find shader in rankset: %s\n", token ); + return qtrue; + } + + //error checking - we should see a '}' now :P + token = COM_ParseExt( data, qtrue ); + if ( token[0] == 0 ) { + Com_Printf( S_COLOR_RED "Unexpected EOF! O_o\n" ); + return qtrue; + } + + //all good :) return the function good + if ( !Q_stricmp( token, "}" ) ) { + return qfalse; + } + else { + return qtrue; + } + } + else { + Com_Printf( S_COLOR_RED, "Could not find { in current rankset file.\n" ); + return qtrue; + } +} + +/* +================= +CG_LoadRanks +By TiM +================= +*/ +qboolean CG_LoadRanks( void ) { + fileHandle_t file; + int file_len; + char charText[32000]; + char *textPtr, *prevValue; + char fileName[MAX_QPATH]; + int i; + int rankCount=0; + char *token; + + qboolean DefaultRankLoaded = qfalse; + + if ( cgs.rankSet ) { + Com_sprintf( fileName, sizeof( fileName ), "ext_data/ranksets/%s.ranks", cgs.rankSet ); + } + else { + return qfalse; + } + + file_len = trap_FS_FOpenFile( fileName, &file, FS_READ ); + + if ( file_len <= 0 ) { + return qfalse; + } + + if ( file_len >= sizeof( charText ) - 1 ) { + Com_Printf( S_COLOR_RED "Size of rankset file %s is too large.\n", fileName ); + return qfalse; + } + + memset( &charText, 0, sizeof( charText ) ); + memset( &cgs.defaultRankData, 0, sizeof( cgs.defaultRankData ) ); + memset( &cgs.ranksData, 0, sizeof( cgs.ranksData ) ); + + trap_FS_Read( charText, file_len, file ); + + charText[file_len] = 0; + + trap_FS_FCloseFile( file ); + + COM_BeginParseSession(); + + textPtr = charText; + + token = COM_Parse( &textPtr ); + + if ( !token[0] ) { + Com_Printf( S_COLOR_RED "No data found in rankset: %s\n", fileName ); + return qfalse; + } + + if ( Q_stricmp( token, "{" ) ) { + Com_Printf( S_COLOR_RED "Missing starting { in rankset file: %s\n", fileName); + return qfalse; + } + + //Parse the first one only... the first one should be the DEFAULT RANK!!! + //DEFAULT I SAY! IT'S SPECIAL! + //WE NEED A DEFAULT FOR ERRORS! NO DEFAULT NO RANK FOR YOU! + while ( 1 ) { + prevValue = textPtr; + + token = COM_Parse( &textPtr ); + if ( !token[0] ) { + break; + } + + if ( !Q_stricmpn( token, "MenuTextureDef", 14 ) ) { + if ( CG_ParseRankData( &textPtr, &cgs.defaultRankData.rankMenuData ) ) { + continue; + } + + DefaultRankLoaded = qtrue; + continue; + } + else if ( !Q_stricmpn( token, "BoltModel", 9 ) ) { + if ( COM_ParseString( &textPtr, &token ) ) { + continue; + } + + Q_strncpyz( cgs.defaultRankData.rankModelData.boltModelPath, token, + sizeof( cgs.defaultRankData.rankModelData.boltModelPath ) ); + + /*if ( !cgs.defaultRankData.boltModel ) { + Com_Printf(S_COLOR_RED "Unable to load model file: %s\n", token ); + }*/ + + continue; + + } + else if ( !Q_stricmpn( token, "boltShader", 8 ) ) { + if ( COM_ParseString( &textPtr, &token ) ) { + continue; + } + + Q_strncpyz( cgs.defaultRankData.rankModelData.boltShaderPath, token, + sizeof( cgs.defaultRankData.rankModelData.boltShaderPath ) ); + + /*cgs.defaultRankData.boltShader = trap_R_RegisterSkin( token ); + if ( !cgs.defaultRankData.boltShader ) { + Com_Printf(S_COLOR_RED "Unable to load skin file: %s\n", token ); + }*/ + + continue; + } + else if ( !Q_stricmpn( token, "AdmiralRank", 11 ) ) { + if ( COM_ParseInt( &textPtr, &i ) ) { + continue; + } + + cgs.defaultRankData.rankModelData.admiralRank = i; + continue; + } + else if ( !Q_stricmp( token, "}" ) ) { + break; + } + + } + + //if we succeeded in loading a default value (^_^!), then begin parsing the main ranks + if ( !DefaultRankLoaded ) { + Com_Printf( S_COLOR_RED "No default rank located in %s\n", fileName ); + return qfalse; + } + else { + //Parse.Rank.Data? :) *sigh* if only rofl + while (1) { + prevValue = textPtr; + token = COM_Parse( &textPtr ); + if ( !token[0] ) { + break; + } + + if ( rankCount >= MAX_RANKS ) { + break; + } + + if ( !Q_stricmpn( token, "{", 1 ) ) { + + while ( 1 ) { + token = COM_Parse( &textPtr ); + if ( !token[0] ) { + break; + } + + if ( !Q_stricmpn( token, "ConsoleName", 11 ) ) { + if ( COM_ParseString( &textPtr, &token ) ) { + Com_Printf( S_COLOR_RED "Could not parse console rank name for rank number: %i\n", rankCount ); + return qfalse; + } + + Q_strncpyz( cgs.ranksData[rankCount].consoleName, token, sizeof( cgs.ranksData[rankCount].consoleName ) ); + continue; + } + + if ( !Q_stricmpn( token, "FormalName", 10 ) ) { + if ( COM_ParseString( &textPtr, &token ) ) { + Com_Printf( S_COLOR_RED "Could not parse formal rank name for rank number: %i\n", rankCount ); + return qfalse; + } + + Q_strncpyz( cgs.ranksData[rankCount].formalName, token, sizeof( cgs.ranksData[rankCount].formalName ) ); + continue; + } + + if ( !Q_stricmpn( token, "MenuTextureRed", 14 ) ) { + if ( CG_ParseRankData( &textPtr, &cgs.ranksData[rankCount].rankMenuData[CLR_RED] ) ) { + Com_Printf( S_COLOR_RED "Could not parse red rank color for rank number: %i\n", rankCount ); + return qfalse; + } + + continue; + } + else if ( !Q_stricmpn( token, "MenuTextureTeal", 15 ) ) { + if ( CG_ParseRankData( &textPtr, &cgs.ranksData[rankCount].rankMenuData[CLR_TEAL] ) ) { + Com_Printf( S_COLOR_RED "Could not parse teal rank color for rank number: %i\n", rankCount ); + return qfalse; + } + + continue; + } + else if ( !Q_stricmpn( token, "MenuTextureGold", 15 ) ) { + if ( CG_ParseRankData( &textPtr, &cgs.ranksData[rankCount].rankMenuData[CLR_GOLD] ) ) { + Com_Printf( S_COLOR_RED "Could not parse teal rank color for rank number: %i\n", rankCount ); + return qfalse; + } + + continue; + } + else if ( !Q_stricmpn( token, "MenuTextureGreen", 16 ) ) { + if ( CG_ParseRankData( &textPtr, &cgs.ranksData[rankCount].rankMenuData[CLR_GREEN] ) ) { + Com_Printf( S_COLOR_RED "Could not parse green rank color for rank number: %i\n", rankCount ); + return qfalse; + } + + continue; + } + else if ( !Q_stricmpn( token, "BoltModel", 9 ) ) { + if ( COM_ParseString( &textPtr, &token ) ) { + continue; + } + + //cgs.ranksData[rankCount].boltModel = trap_R_RegisterModel( token ); + + Q_strncpyz( cgs.ranksData[rankCount].rankModelData.boltModelPath, + token, + sizeof( cgs.ranksData[rankCount].rankModelData.boltModelPath) ); + + /*if ( !cgs.ranksData[rankCount].boltModel ) { + Com_Printf( S_COLOR_RED, "Could not load bolt model: %s\n", token ); + }*/ + continue; + } + else if ( !Q_stricmpn( token, "boltShader", 8 ) ) { + if ( COM_ParseString( &textPtr, &token ) ) { + continue; + } + + Q_strncpyz( cgs.ranksData[rankCount].rankModelData.boltShaderPath, + token, + sizeof( cgs.ranksData[rankCount].rankModelData.boltShaderPath) ); + + + /*if ( !cgs.ranksData[rankCount].boltShader ) { + Com_Printf( S_COLOR_RED, "Could not load bolt skin: %s\n", token ); + }*/ + continue; + } + else if ( !Q_stricmpn( token, "AdmiralRank", 11 ) ) { + if ( COM_ParseInt( &textPtr, &i ) ) { + continue; + } + + cgs.ranksData[rankCount].rankModelData.admiralRank = i; + + continue; + } + else if ( !Q_stricmpn( token, "}", 1 ) ) { + break; + } + } + rankCount++; + } + } + } + return qtrue; +} + +/* +================= +CG_LoadCrosshairs +By TiM + +Parsing script to load +and display multiple +crosshairs. +================= +*/ +qboolean CG_LoadCrosshairs(void) { + fileHandle_t f; + int file_len; + char charText[20000]; + char *token, *textPtr; + char *fileName = "ext_data/crosshairs.dat"; + int cHairCount = 0; + //int i; + + //load file and get file length + file_len = trap_FS_FOpenFile( fileName, &f, FS_READ ); + + memset( &charText, 0, sizeof( charText ) ); + memset( &cgs.crosshairsData, 0, sizeof( &cgs.crosshairsData ) ); + + //check to see if we got anything + if ( file_len <= 0 ) { + Com_Printf( S_COLOR_RED "Could not find file: %s\n", fileName ); + return qfalse; + } + + //check to see if we got too much + if ( file_len > sizeof( charText) - 1 ) { + Com_Printf( S_COLOR_RED "File %s waaaaay too big.\n", fileName ); + return qfalse; + } + + //read the data into the array + trap_FS_Read( charText, file_len, f ); + + //EOF? + charText[file_len] = 0; + + trap_FS_FCloseFile( f ); + + COM_BeginParseSession(); + + textPtr = charText; + + token = COM_Parse( &textPtr ); + + //wtf? Nothing here?? + if ( !token[0] ) { + Com_Printf( S_COLOR_RED "File: %s terminated rather unexpectantly\n", fileName ); + return qfalse; + } + + if ( Q_stricmp( token, "{" ) ) { + Com_Printf( S_COLOR_RED "File: %s had no starting {\n", fileName ); + return qfalse; + } + + //now for the natural hard-core loop parsing bit + while ( 1 ) { + + if ( cHairCount >= MAX_CROSSHAIRS ) { + break; + } + + if ( !Q_stricmpn( token, "{", 1 ) ) { + //Make color default to white + VectorCopy( colorTable[CT_WHITE], cgs.crosshairsData[cHairCount].color ); + cgs.crosshairsData[cHairCount].color[3] = 1.0f; + + while ( 1 ) + { + token = COM_Parse( &textPtr ); + if (!token[0]) { + break; + } + + if ( !Q_stricmpn( token, "noDraw", 6 ) ) { + cgs.crosshairsData[cHairCount].noDraw = qtrue; + break; + } + else if ( !Q_stricmpn( token, "CrosshairColor", 14 ) ) { + if ( COM_ParseVec4( &textPtr, cgs.crosshairsData[cHairCount].color ) ) { + Com_Printf( S_COLOR_RED "Invalid Color Value in %s\n", fileName ); + return qfalse; + } + + VectorScale( cgs.crosshairsData[cHairCount].color, 1.0f/255.0f, cgs.crosshairsData[cHairCount].color ); + cgs.crosshairsData[cHairCount].color[3] *= 1.0f/255.0f; + + continue; + } + else if ( !Q_stricmpn( token, "BitmapCoords", 12 ) ) { + if ( COM_ParseString( &textPtr, &token ) ) { + Com_Printf( S_COLOR_RED "No bitmap co-ords found in %s\n", fileName ); + return qfalse; + } + + if ( Q_stricmpn( token, "{", 1 ) ) { + Com_Printf( S_COLOR_RED "No { found in bitmap co-ords in %s\n", fileName ); + return qfalse; + } + + //parse s1 value + if ( COM_ParseString( &textPtr, &token ) ) { + Com_Printf( S_COLOR_RED "Bit co-ord value ended prematurely: %s\n", fileName ); + return qfalse; + } + + cgs.crosshairsData[cHairCount].s1 = atoi( token ); + + //parse t1 value + if ( COM_ParseString( &textPtr, &token ) ) { + Com_Printf( S_COLOR_RED "Bit co-ord value ended prematurely: %s\n", fileName ); + return qfalse; + } + + cgs.crosshairsData[cHairCount].t1 = atoi( token ); + + //parse s2 value + if ( COM_ParseString( &textPtr, &token ) ) { + Com_Printf( S_COLOR_RED "Bit co-ord value ended prematurely: %s\n", fileName ); + return qfalse; + } + + cgs.crosshairsData[cHairCount].s2 = atoi( token ); + + //parse t2 value + if ( COM_ParseString( &textPtr, &token ) ) { + Com_Printf( S_COLOR_RED "Bit co-ord value ended prematurely: %s\n", fileName ); + return qfalse; + } + + cgs.crosshairsData[cHairCount].t2 = atoi( token ); + + //make sure we have } at the end FFS + if ( COM_ParseString( &textPtr, &token ) ) { + Com_Printf( S_COLOR_RED "Bit co-ord value ended prematurely: %s\n", fileName ); + return qfalse; + } + + //This is needed or else we can't tell between this and the main closing } + if ( Q_stricmpn( token, "}", 1 ) ) { + Com_Printf( S_COLOR_RED "No terminating } in bitmap co-ord: %s\n", fileName ); + return qfalse; + } + } + else if ( !Q_stricmpn ( token, "}", 1 ) ) { + break; + } + } + cHairCount++; + } + + token = COM_Parse( &textPtr ); + if (!token[0]) { + break; + } + } + return qtrue; } diff --git a/code/cgame/cg_effects.c b/code/cgame/cg_effects.c index 99f6499..255a3c3 100644 --- a/code/cgame/cg_effects.c +++ b/code/cgame/cg_effects.c @@ -1,29 +1,10 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // // cg_effects.c -- these functions generate localentities, usually as a result // of event processing #include "cg_local.h" +#include "fx_local.h" /* @@ -39,10 +20,6 @@ void CG_BubbleTrail( vec3_t start, vec3_t end, float spacing ) { float len; int i; - if ( cg_noProjectileTrail.integer ) { - return; - } - VectorCopy (start, move); VectorSubtract (end, start, vec); len = VectorNormalize (vec); @@ -65,11 +42,12 @@ void CG_BubbleTrail( vec3_t start, vec3_t end, float spacing ) { le->lifeRate = 1.0 / ( le->endTime - le->startTime ); re = &le->refEntity; - re->shaderTime = cg.time / 1000.0f; + //re->shaderTime = cg.time / 1000.0f; + re->shaderTime = cg.time * 0.001f; re->reType = RT_SPRITE; - re->rotation = 0; - re->radius = 3; + re->data.sprite.rotation = 0; + re->data.sprite.radius = 3; re->customShader = cgs.media.waterBubbleShader; re->shaderRGBA[0] = 0xff; re->shaderRGBA[1] = 0xff; @@ -101,33 +79,26 @@ localEntity_t *CG_SmokePuff( const vec3_t p, const vec3_t vel, float r, float g, float b, float a, float duration, int startTime, - int fadeInTime, int leFlags, qhandle_t hShader ) { static int seed = 0x92; localEntity_t *le; refEntity_t *re; -// int fadeInTime = startTime + duration / 2; le = CG_AllocLocalEntity(); le->leFlags = leFlags; - le->radius = radius; + le->data.sprite.radius = radius; re = &le->refEntity; - re->rotation = Q_random( &seed ) * 360; - re->radius = radius; - re->shaderTime = startTime / 1000.0f; + re->data.sprite.rotation = Q_random( &seed ) * 360; + re->data.sprite.radius = radius; + //re->shaderTime = startTime / 1000.0f; + re->shaderTime = startTime * 0.001f; le->leType = LE_MOVE_SCALE_FADE; le->startTime = startTime; - le->fadeInTime = fadeInTime; le->endTime = startTime + duration; - if ( fadeInTime > startTime ) { - le->lifeRate = 1.0 / ( le->endTime - le->fadeInTime ); - } - else { - le->lifeRate = 1.0 / ( le->endTime - le->startTime ); - } + le->lifeRate = 1.0 / ( le->endTime - le->startTime ); le->color[0] = r; le->color[1] = g; le->color[2] = b; @@ -157,7 +128,7 @@ localEntity_t *CG_SmokePuff( const vec3_t p, const vec3_t vel, } re->reType = RT_SPRITE; - re->radius = le->radius; + re->data.sprite.radius = le->data.sprite.radius; return le; } @@ -167,12 +138,15 @@ localEntity_t *CG_SmokePuff( const vec3_t p, const vec3_t vel, CG_SpawnEffect Player teleporting in or out + +RPG-X: RedTechie Added refEntity_t *ent_legs, refEntity_t *ent_torso, refEntity_t *ent_head ================== */ -void CG_SpawnEffect( vec3_t org ) { +void CG_SpawnEffect( vec3_t org, refEntity_t *ent_legs, refEntity_t *ent_torso, refEntity_t *ent_head ) { localEntity_t *le; refEntity_t *re; + FX_Transporter(org); le = CG_AllocLocalEntity(); le->leFlags = 0; le->leType = LE_FADE_RGB; @@ -181,247 +155,64 @@ void CG_SpawnEffect( vec3_t org ) { le->lifeRate = 1.0 / ( le->endTime - le->startTime ); le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0; + + re = &le->refEntity; + //RPG-X: RedTechie - Added for better trans effect - dosnt work right now + //ent_legs->shaderTime = cg.time / 1000.0f; + //ent_head->shaderTime = cg.time / 1000.0f; + //ent_torso->shaderTime = cg.time / 1000.0f; + //ent_legs->customShader = cgs.media.teleportEffectShader; + //trap_R_AddRefEntityToScene( ent_legs ); + //ent_head->customShader = cgs.media.teleportEffectShader; + //trap_R_AddRefEntityToScene( ent_head ); + //ent_torso->customShader = cgs.media.teleportEffectShader; + //trap_R_AddRefEntityToScene( ent_torso ); + //RPG-X: RedTechie - Playing with transporter crap + //re->shaderTime = cg.time / 1000.0f; + re->shaderTime = cg.time * 0.001f; re = &le->refEntity; re->reType = RT_MODEL; - re->shaderTime = cg.time / 1000.0f; + //re->shaderTime = cg.time / 1000.0f; + re->shaderTime = cg.time * 0.001f; -#ifndef MISSIONPACK re->customShader = cgs.media.teleportEffectShader; -#endif re->hModel = cgs.media.teleportEffectModel; AxisClear( re->axis ); VectorCopy( org, re->origin ); -#ifdef MISSIONPACK - re->origin[2] += 16; -#else re->origin[2] -= 24; -#endif } - -#ifdef MISSIONPACK -/* -=============== -CG_LightningBoltBeam -=============== -*/ -void CG_LightningBoltBeam( vec3_t start, vec3_t end ) { +void CG_QFlashEvent( vec3_t org ) { localEntity_t *le; - refEntity_t *beam; + /*refEntity_t *re; le = CG_AllocLocalEntity(); - le->leFlags = 0; - le->leType = LE_SHOWREFENTITY; - le->startTime = cg.time; - le->endTime = cg.time + 50; - - beam = &le->refEntity; - - VectorCopy( start, beam->origin ); - // this is the end point - VectorCopy( end, beam->oldorigin ); - - beam->reType = RT_LIGHTNING; - beam->customShader = cgs.media.lightningShader; -} - -/* -================== -CG_KamikazeEffect -================== -*/ -void CG_KamikazeEffect( vec3_t org ) { - localEntity_t *le; - refEntity_t *re; - - le = CG_AllocLocalEntity(); - le->leFlags = 0; - le->leType = LE_KAMIKAZE; - le->startTime = cg.time; - le->endTime = cg.time + 3000;//2250; - le->lifeRate = 1.0 / ( le->endTime - le->startTime ); - - le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0; - - VectorClear(le->angles.trBase); - - re = &le->refEntity; - - re->reType = RT_MODEL; - re->shaderTime = cg.time / 1000.0f; - - re->hModel = cgs.media.kamikazeEffectModel; - - VectorCopy( org, re->origin ); - -} - -/* -================== -CG_ObeliskExplode -================== -*/ -void CG_ObeliskExplode( vec3_t org, int entityNum ) { - localEntity_t *le; - vec3_t origin; - - // create an explosion - VectorCopy( org, origin ); - origin[2] += 64; - le = CG_MakeExplosion( origin, vec3_origin, - cgs.media.dishFlashModel, - cgs.media.rocketExplosionShader, - 600, qtrue ); - le->light = 300; - le->lightColor[0] = 1; - le->lightColor[1] = 0.75; - le->lightColor[2] = 0.0; -} - -/* -================== -CG_ObeliskPain -================== -*/ -void CG_ObeliskPain( vec3_t org ) { - float r; - sfxHandle_t sfx; - - // hit sound - r = rand() & 3; - if ( r < 2 ) { - sfx = cgs.media.obeliskHitSound1; - } else if ( r == 2 ) { - sfx = cgs.media.obeliskHitSound2; - } else { - sfx = cgs.media.obeliskHitSound3; - } - trap_S_StartSound ( org, ENTITYNUM_NONE, CHAN_BODY, sfx ); -} - - -/* -================== -CG_InvulnerabilityImpact -================== -*/ -void CG_InvulnerabilityImpact( vec3_t org, vec3_t angles ) { - localEntity_t *le; - refEntity_t *re; - int r; - sfxHandle_t sfx; - - le = CG_AllocLocalEntity(); - le->leFlags = 0; - le->leType = LE_INVULIMPACT; - le->startTime = cg.time; - le->endTime = cg.time + 1000; - le->lifeRate = 1.0 / ( le->endTime - le->startTime ); - - le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0; - - re = &le->refEntity; - - re->reType = RT_MODEL; - re->shaderTime = cg.time / 1000.0f; - - re->hModel = cgs.media.invulnerabilityImpactModel; - - VectorCopy( org, re->origin ); - AnglesToAxis( angles, re->axis ); - - r = rand() & 3; - if ( r < 2 ) { - sfx = cgs.media.invulnerabilityImpactSound1; - } else if ( r == 2 ) { - sfx = cgs.media.invulnerabilityImpactSound2; - } else { - sfx = cgs.media.invulnerabilityImpactSound3; - } - trap_S_StartSound (org, ENTITYNUM_NONE, CHAN_BODY, sfx ); -} - -/* -================== -CG_InvulnerabilityJuiced -================== -*/ -void CG_InvulnerabilityJuiced( vec3_t org ) { - localEntity_t *le; - refEntity_t *re; - vec3_t angles; - - le = CG_AllocLocalEntity(); - le->leFlags = 0; - le->leType = LE_INVULJUICED; - le->startTime = cg.time; - le->endTime = cg.time + 10000; - le->lifeRate = 1.0 / ( le->endTime - le->startTime ); - - le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0; - - re = &le->refEntity; - - re->reType = RT_MODEL; - re->shaderTime = cg.time / 1000.0f; - - re->hModel = cgs.media.invulnerabilityJuicedModel; - - VectorCopy( org, re->origin ); - VectorClear(angles); - AnglesToAxis( angles, re->axis ); - - trap_S_StartSound (org, ENTITYNUM_NONE, CHAN_BODY, cgs.media.invulnerabilityJuicedSound ); -} - -#endif - -/* -================== -CG_ScorePlum -================== -*/ -void CG_ScorePlum( int client, vec3_t org, int score ) { - localEntity_t *le; - refEntity_t *re; - vec3_t angles; - static vec3_t lastPos; - - // only visualize for the client that scored - if (client != cg.predictedPlayerState.clientNum || cg_scorePlum.integer == 0) { - return; - } - - le = CG_AllocLocalEntity(); - le->leFlags = 0; - le->leType = LE_SCOREPLUM; - le->startTime = cg.time; - le->endTime = cg.time + 4000; - le->lifeRate = 1.0 / ( le->endTime - le->startTime ); - + le->leFlags = LEF_SINE_SCALE; + le->leType = LE_PARTICLE; - le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0; - le->radius = score; - - VectorCopy( org, le->pos.trBase ); - if (org[2] >= lastPos[2] - 20 && org[2] <= lastPos[2] + 20) { - le->pos.trBase[2] -= 20; - } + le->startTime = cg.time; + le->endTime = cg.time + 600; - //CG_Printf( "Plum origin %i %i %i -- %i\n", (int)org[0], (int)org[1], (int)org[2], (int)Distance(org, lastPos)); - VectorCopy(org, lastPos); + le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0f; + le->data.particle.radius = 30; + le->data.particle.dradius = 5; re = &le->refEntity; + re->customShader = cgs.media.qFlashSprite; - re->reType = RT_SPRITE; - re->radius = 16; + VectorCopy( org, re->origin ); + VectorCopy( org, re->oldorigin );*/ - VectorClear(angles); - AnglesToAxis( angles, re->axis ); + le = FX_AddParticle( org, vec3_origin, qfalse, 110.0f, 109.0f, + 1.0f, 1.0f, 0, 0, + 290, cgs.media.qFlashSprite, 0 ); + le->leFlags = LEF_SINE_SCALE | LEF_REVERSE_SCALE; + + le->refEntity.renderfx |= RF_DEPTHHACK; } @@ -432,7 +223,7 @@ CG_MakeExplosion */ localEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir, qhandle_t hModel, qhandle_t shader, - int msec, qboolean isSprite ) { + int msec, float scale, qboolean isSprite ) { float ang; localEntity_t *ex; int offset; @@ -450,7 +241,7 @@ localEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir, ex->leType = LE_SPRITE_EXPLOSION; // randomly rotate sprite orientation - ex->refEntity.rotation = rand() % 360; + ex->refEntity.data.sprite.rotation = rand() % 360; VectorScale( dir, 16, tmpVec ); VectorAdd( tmpVec, origin, newOrigin ); } else { @@ -471,7 +262,8 @@ localEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir, ex->endTime = ex->startTime + msec; // bias the time so all shader effects start correctly - ex->refEntity.shaderTime = ex->startTime / 1000.0f; + //ex->refEntity.shaderTime = ex->startTime / 1000.0f; + ex->refEntity.shaderTime = ex->startTime * 0.001f; ex->refEntity.hModel = hModel; ex->refEntity.customShader = shader; @@ -480,12 +272,91 @@ localEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir, VectorCopy( newOrigin, ex->refEntity.origin ); VectorCopy( newOrigin, ex->refEntity.oldorigin ); + //Scale the explosion + if (scale != 1) { + ex->refEntity.nonNormalizedAxes = qtrue; + + VectorScale( ex->refEntity.axis[0], scale, ex->refEntity.axis[0] ); + VectorScale( ex->refEntity.axis[1], scale, ex->refEntity.axis[1] ); + VectorScale( ex->refEntity.axis[2], scale, ex->refEntity.axis[2] ); + } + + ex->color[0] = ex->color[1] = ex->color[2] = 1.0; + + return ex; +} + + +localEntity_t *CG_MakeExplosion2( vec3_t origin, vec3_t dir, + qhandle_t hModel, int numFrames, qhandle_t shader, + int msec, qboolean isSprite, float scale, int flags) { + float ang; + localEntity_t *ex; + int offset; + vec3_t tmpVec, newOrigin; + + if ( msec <= 0 ) { + CG_Error( "CG_MakeExplosion: msec = %i", msec ); + } + + // skew the time a bit so they aren't all in sync + offset = rand() & 63; + + ex = CG_AllocLocalEntity(); + if ( isSprite ) { + ex->leType = LE_SPRITE_EXPLOSION; + + // randomly rotate sprite orientation + ex->refEntity.data.sprite.rotation = rand() % 360; + VectorScale( dir, 16, tmpVec ); + VectorAdd( tmpVec, origin, newOrigin ); + } else { + ex->leType = LE_EXPLOSION; + VectorCopy( origin, newOrigin ); + + // set axis with random rotate + if ( !dir ) { + AxisClear( ex->refEntity.axis ); + } else { + ang = rand() % 360; + VectorCopy( dir, ex->refEntity.axis[0] ); + RotateAroundDirection( ex->refEntity.axis, ang ); + } + } + + ex->startTime = cg.time - offset; + ex->endTime = ex->startTime + msec; + + // bias the time so all shader effects start correctly + //ex->refEntity.shaderTime = ex->startTime / 1000.0f; + ex->refEntity.shaderTime = ex->startTime * 0.001f; + + ex->refEntity.hModel = hModel; + ex->refEntity.customShader = shader; + ex->lifeRate = (float)numFrames / msec; + ex->leFlags = flags; + + //Scale the explosion + if (scale != 1) { + ex->refEntity.nonNormalizedAxes = qtrue; + + VectorScale( ex->refEntity.axis[0], scale, ex->refEntity.axis[0] ); + VectorScale( ex->refEntity.axis[1], scale, ex->refEntity.axis[1] ); + VectorScale( ex->refEntity.axis[2], scale, ex->refEntity.axis[2] ); + } + + // set origin + VectorCopy( newOrigin, ex->refEntity.origin ); + VectorCopy( newOrigin, ex->refEntity.oldorigin ); + ex->color[0] = ex->color[1] = ex->color[2] = 1.0; return ex; } + + /* ================= CG_Bleed @@ -493,7 +364,7 @@ CG_Bleed This is the spurt of blood when a character gets hit ================= */ -void CG_Bleed( vec3_t origin, int entityNum ) { +/*void CG_Bleed( vec3_t origin, int entityNum ) { localEntity_t *ex; if ( !cg_blood.integer ) { @@ -508,8 +379,8 @@ void CG_Bleed( vec3_t origin, int entityNum ) { VectorCopy ( origin, ex->refEntity.origin); ex->refEntity.reType = RT_SPRITE; - ex->refEntity.rotation = rand() % 360; - ex->refEntity.radius = 24; + ex->refEntity.data.sprite.rotation = rand() % 360; + ex->refEntity.data.sprite.radius = 16; ex->refEntity.customShader = cgs.media.bloodExplosionShader; @@ -517,202 +388,222 @@ void CG_Bleed( vec3_t origin, int entityNum ) { if ( entityNum == cg.snap->ps.clientNum ) { ex->refEntity.renderfx |= RF_THIRD_PERSON; } -} +}*/ /* -================== -CG_LaunchGib -================== +------------------------- +CG_ExplosionEffects + +Used to find the player and shake the camera if close enough +intensity ranges from 1 (minor tremble) to 16 (major quake) +------------------------- */ -void CG_LaunchGib( vec3_t origin, vec3_t velocity, qhandle_t hModel ) { - localEntity_t *le; - refEntity_t *re; - le = CG_AllocLocalEntity(); - re = &le->refEntity; +void CG_ExplosionEffects( vec3_t origin, int intensity, int radius) +{ + //FIXME: When exactly is the vieworg calculated in relation to the rest of the frame?s - le->leType = LE_FRAGMENT; - le->startTime = cg.time; - le->endTime = le->startTime + 5000 + random() * 3000; + vec3_t dir; + float dist, intensityScale; + float realIntensity; - VectorCopy( origin, re->origin ); - AxisCopy( axisDefault, re->axis ); - re->hModel = hModel; + VectorSubtract( cg.refdef.vieworg, origin, dir ); + dist = VectorNormalize( dir ); - le->pos.trType = TR_GRAVITY; - VectorCopy( origin, le->pos.trBase ); - VectorCopy( velocity, le->pos.trDelta ); - le->pos.trTime = cg.time; + //Use the dir to add kick to the explosion - le->bounceFactor = 0.6f; - - le->leBounceSoundType = LEBS_BLOOD; - le->leMarkType = LEMT_BLOOD; -} - -/* -=================== -CG_GibPlayer - -Generated a bunch of gibs launching out from the bodies location -=================== -*/ -#define GIB_VELOCITY 250 -#define GIB_JUMP 250 -void CG_GibPlayer( vec3_t playerOrigin ) { - vec3_t origin, velocity; - - if ( !cg_blood.integer ) { + if ( dist > radius ) return; + + intensityScale = 1 - ( dist / (float) radius ); + realIntensity = intensity * intensityScale; + + CG_CameraShake( realIntensity, 500, qfalse ); +} + + +/* +================= +CG_Seeker +================= +*/ +/*void CG_Seeker( centity_t *cent ) +{ + refEntity_t re; + + vec3_t seekerOrg, viewAng; + float angle; + + + angle = cg.time/100.0f; + seekerOrg[0] = cent->lerpOrigin[0] + 18 * cos(angle); + seekerOrg[1] = cent->lerpOrigin[1] + 18 * sin(angle); + seekerOrg[2] = cent->lerpOrigin[2] + cg.predictedPlayerState.viewheight + 8 + (3*cos(cg.time/150.0f)); + + memset( &re, 0, sizeof( re ) ); + + re.reType = RT_MODEL; + VectorCopy ( seekerOrg, re.origin); + re.hModel = cgs.media.seekerModel; + re.shaderTime = (cg.time / 1000.0f); + + VectorCopy (cent->lerpAngles , viewAng); // so the seeker faces the same direction the player is + viewAng[0] = -90; // but, we don't want the seeker facing up or down, always horizontal + AnglesToAxis( viewAng, re.axis ); + VectorScale(re.axis[0], 0.5, re.axis[0]); + VectorScale(re.axis[1], 0.5, re.axis[1]); + VectorScale(re.axis[2], 0.5, re.axis[2]); + re.nonNormalizedAxes=qtrue; + + trap_R_AddRefEntityToScene( &re ); + +}*/ + +/* +------------------------- +CG_Smoke +TiM: Ported from EF SP +------------------------- +*/ + +//void CG_Smoke( vec3_t origin, vec3_t dir, float radius, float speed, qhandle_t shader ) +//{ +// vec3_t velocity/*, accel*/; +// int i; + +// for ( i = 0; i < 3; i++ ) +// { +// velocity[i] = dir[i] + ( 0.2f * crandom()); +// } + +// VectorScale( velocity, speed, velocity ); + //VectorScale( velocity, -0.25f, accel ); + //accel[2] = random() * 12.0f + 6.0f; + +// FX_AddSprite( origin, +// velocity, +// qfalse, //accel +// radius + (crandom() * radius * 0.5f ), +// radius + (crandom() * radius), +// 0.9f + crandom(), +// 0.0f, +// 16.0f + random() * 45.0f, +// 0.5f, +// 2000, +// shader ); //flags +//} + +qboolean SmokeThink( localEntity_t *le ) +{ + vec3_t velocity/*, accel*/; + vec3_t origin; + vec3_t dir; + float speed; + int i; + + VectorCopy( le->data.spawner.dir, dir ); + //clamp the smoke vector + //Smoke should always go up + dir[2] = Com_Clamp( 0.85f, 1.0f, dir[2] ); + + for ( i = 0; i < 3; i++ ) + { + velocity[i] = dir[i] + ( 0.2f * crandom()); } - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; - if ( rand() & 1 ) { - CG_LaunchGib( origin, velocity, cgs.media.gibSkull ); - } else { - CG_LaunchGib( origin, velocity, cgs.media.gibBrain ); - } + VectorMA( le->refEntity.origin, 1, le->data.spawner.dir, origin); - // allow gibs to be turned off for speed - if ( !cg_gibs.integer ) { - return; - } + //slow down the smoke the smaller it gets + //else it scatters too much + speed = le->data.spawner.data1 * 2.4; - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; - CG_LaunchGib( origin, velocity, cgs.media.gibAbdomen ); + VectorScale( velocity, speed, velocity ); //speed + //VectorScale( velocity, -0.25f, accel ); + //accel[2] = random() * 12.0f + 6.0f; - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; - CG_LaunchGib( origin, velocity, cgs.media.gibArm ); + FX_AddSprite( origin, + velocity, + qfalse, //accel + le->data.spawner.data1 + (crandom() * le->data.spawner.data1 * 0.5f ), + le->data.spawner.data1 + (crandom() * le->data.spawner.data1), + 0.8 /*+ crandom()*/, + 0.0, + 16.0f + random() * 45.0f, + 0.5f, + 7000, + cgs.media.smokeShader ); //flags - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; - CG_LaunchGib( origin, velocity, cgs.media.gibChest ); - - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; - CG_LaunchGib( origin, velocity, cgs.media.gibFist ); - - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; - CG_LaunchGib( origin, velocity, cgs.media.gibFoot ); - - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; - CG_LaunchGib( origin, velocity, cgs.media.gibForearm ); - - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; - CG_LaunchGib( origin, velocity, cgs.media.gibIntestine ); - - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; - CG_LaunchGib( origin, velocity, cgs.media.gibLeg ); - - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; - CG_LaunchGib( origin, velocity, cgs.media.gibLeg ); + return qtrue; } /* -================== -CG_LaunchGib -================== +====================== +CG_Smoke + +Creates a smoke effect +====================== */ -void CG_LaunchExplode( vec3_t origin, vec3_t velocity, qhandle_t hModel ) { - localEntity_t *le; - refEntity_t *re; - le = CG_AllocLocalEntity(); - re = &le->refEntity; - - le->leType = LE_FRAGMENT; - le->startTime = cg.time; - le->endTime = le->startTime + 10000 + random() * 6000; - - VectorCopy( origin, re->origin ); - AxisCopy( axisDefault, re->axis ); - re->hModel = hModel; - - le->pos.trType = TR_GRAVITY; - VectorCopy( origin, le->pos.trBase ); - VectorCopy( velocity, le->pos.trDelta ); - le->pos.trTime = cg.time; - - le->bounceFactor = 0.1f; - - le->leBounceSoundType = LEBS_BRASS; - le->leMarkType = LEMT_NONE; +void CG_Smoke( vec3_t position, vec3_t dir, int killTime, int radius ) +{ + //CG_Printf( " %f %f %f\n", dir[0], dir[1], dir[2] ); + // give it a lifetime of 10 seconds because the refresh thinktime in g_fx.c is 10 seconds + FX_AddSpawner( position, dir, NULL, NULL, qfalse, 0, 0.15, killTime, SmokeThink, radius ); // } -#define EXP_VELOCITY 100 -#define EXP_JUMP 150 /* -=================== -CG_GibPlayer +====================== +FireThink -Generated a bunch of gibs launching out from the bodies location -=================== +Engage fire effect +RPG-X | Marcin | 24/12/2008 +====================== */ -void CG_BigExplode( vec3_t playerOrigin ) { - vec3_t origin, velocity; +qboolean FireThink( localEntity_t *le ) +{ + vec3_t direction; + vec3_t origin; - if ( !cg_blood.integer ) { - return; - } + VectorCopy( le->data.spawner.dir, direction ); + VectorMA( le->refEntity.origin, 1, direction, origin ); - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*EXP_VELOCITY; - velocity[1] = crandom()*EXP_VELOCITY; - velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY; - CG_LaunchExplode( origin, velocity, cgs.media.smoke2 ); + origin[2] += 60.0f / (80.0f / le->data.spawner.data1); // extra offset - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*EXP_VELOCITY; - velocity[1] = crandom()*EXP_VELOCITY; - velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY; - CG_LaunchExplode( origin, velocity, cgs.media.smoke2 ); + FX_AddSprite( origin, + 0, + qfalse, + le->data.spawner.data1, + 0, + 1.0f, + 0.0f, + 0, + 0.5f, + 600, + cgs.media.fireShader ); - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*EXP_VELOCITY*1.5; - velocity[1] = crandom()*EXP_VELOCITY*1.5; - velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY; - CG_LaunchExplode( origin, velocity, cgs.media.smoke2 ); - - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*EXP_VELOCITY*2.0; - velocity[1] = crandom()*EXP_VELOCITY*2.0; - velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY; - CG_LaunchExplode( origin, velocity, cgs.media.smoke2 ); - - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*EXP_VELOCITY*2.5; - velocity[1] = crandom()*EXP_VELOCITY*2.5; - velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY; - CG_LaunchExplode( origin, velocity, cgs.media.smoke2 ); + return qtrue; } +/* +====================== +CG_Fire + +Creates a fire effect +RPG-X | Marcin | 24/12/2008 +====================== +*/ + +void CG_Fire( vec3_t position, vec3_t direction, int killTime, int radius, int fxEnt ) +{ + if(fxEnt) + FX_AddSpawner( position, direction, NULL, NULL, qfalse, 500, 0, killTime + 1000, FireThink, radius ); + else + FX_AddSpawner( position, direction, NULL, NULL, qfalse, 500, 0, killTime, FireThink, radius ); +} + +//localEntity_t *FX_AddSprite(vec3_t origin, vec3_t velocity, qboolean gravity, float scale, float dscale, +// float startalpha, float endalpha, float roll, float elasticity, +// float killTime, qhandle_t shader) + diff --git a/code/cgame/cg_ents.c b/code/cgame/cg_ents.c index 83a5332..b5aba67 100644 --- a/code/cgame/cg_ents.c +++ b/code/cgame/cg_ents.c @@ -1,29 +1,12 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // // cg_ents.c -- present snapshot entities, happens every single frame #include "cg_local.h" +#include "fx_local.h" +static void CG_LaserSight( centity_t *cent ); // Laser +static void CG_Turbolift( centity_t *cent ); /* ====================== @@ -51,6 +34,7 @@ void CG_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent, // had to cast away the const to avoid compiler problems... MatrixMultiply( lerped.axis, ((refEntity_t *)parent)->axis, entity->axis ); entity->backlerp = parent->backlerp; + } @@ -127,39 +111,104 @@ static void CG_EntityEffects( centity_t *cent ) { CG_SetEntitySoundPosition( cent ); // add loop sound - if ( cent->currentState.loopSound ) { - if (cent->currentState.eType != ET_SPEAKER) { - trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, - cgs.gameSounds[ cent->currentState.loopSound ] ); - } else { - trap_S_AddRealLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, - cgs.gameSounds[ cent->currentState.loopSound ] ); - } + if ( cent->currentState.loopSound && cent->currentState.loopSound < 256 ) { + trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, + cgs.gameSounds[ cent->currentState.loopSound ] ); } // constant light glow - if(cent->currentState.constantLight) - { + if ( cent->currentState.constantLight ) { int cl; - float i, r, g, b; + int i, r, g, b; cl = cent->currentState.constantLight; - r = (float) (cl & 0xFF) / 255.0; - g = (float) ((cl >> 8) & 0xFF) / 255.0; - b = (float) ((cl >> 16) & 0xFF) / 255.0; - i = (float) ((cl >> 24) & 0xFF) * 4.0; - trap_R_AddLightToScene(cent->lerpOrigin, i, r, g, b); + r = cl & 255; + g = ( cl >> 8 ) & 255; + b = ( cl >> 16 ) & 255; + i = ( ( cl >> 24 ) & 255 ) * 4; + trap_R_AddLightToScene( cent->lerpOrigin, i, r, g, b ); } } +/* +================== +CG_Useable +================== +*/ +static void CG_Useable( centity_t *cent ) { + refEntity_t ent; + entityState_t *s1; + + s1 = ¢->currentState; + + // if set to invisible, skip + if (!s1->modelindex) { + return; + } + + if (s1->modelindex == HI_SHIELD) + { // The portable shield should go through a different rendering function. + FX_DrawPortableShield(cent); + return; + } + + + memset (&ent, 0, sizeof(ent)); + + // set frame + + if (s1->eFlags & EF_ANIM_ALLFAST) + { + //ent.frame = (cg.time / 100); + ent.frame = (cg.time * 0.01); + ent.renderfx|=RF_WRAP_FRAMES; + } + else + { + ent.frame = s1->frame; + } + ent.oldframe = ent.frame; + ent.backlerp = 0; + + VectorCopy( cent->lerpOrigin, ent.origin); + VectorCopy( cent->lerpOrigin, ent.oldorigin); + + ent.hModel = cg_items[s1->modelindex2].model;//cgs.useableModels[s1->modelindex]; + + // player model + if (s1->number == cg.snap->ps.clientNum) { + ent.renderfx |= RF_THIRD_PERSON; // only draw from mirrors + } + + // convert angles to axis +// AnglesToAxis( cent->lerpAngles, ent.axis ); + { + // hack to keep dropped detpacks from rotating + vec3_t vecs[3]; + AngleVectors(s1->angles, vecs[0], vecs[1], vecs[2]); + VectorNegate(vecs[1], vecs[1]); + if (s1->modelindex == HI_DETPACK) // as stated, HACK for detpack + { + VectorScale(vecs[0], .5, vecs[0]); + VectorScale(vecs[1], .5, vecs[1]); + VectorScale(vecs[2], .5, vecs[2]); + } + AxisCopy( vecs, ent.axis ); + } + + // add to refresh list + trap_R_AddRefEntityToScene (&ent); +} + /* ================== CG_General ================== */ +#define ITEM_SCALEUP_DIV 1.0/(float)ITEM_SCALEUP_TIME static void CG_General( centity_t *cent ) { refEntity_t ent; entityState_t *s1; @@ -175,7 +224,23 @@ static void CG_General( centity_t *cent ) { // set frame - ent.frame = s1->frame; + if ( s1->eFlags & EF_ANIM_ONCE ) + { + ent.frame = s1->frame; + ent.renderfx|=RF_CAP_FRAMES; + } + else if (s1->eFlags & EF_ANIM_ALLFAST) + { + //ent.frame = (cg.time / 100); + ent.frame = (cg.time * 0.01); + ent.renderfx|=RF_WRAP_FRAMES; + } + else + { + ent.frame = s1->frame; + ent.renderfx|=RF_CAP_FRAMES; + } + ent.oldframe = ent.frame; ent.backlerp = 0; @@ -193,9 +258,61 @@ static void CG_General( centity_t *cent ) { AnglesToAxis( cent->lerpAngles, ent.axis ); // add to refresh list - trap_R_AddRefEntityToScene (&ent); + if ( s1->eFlags & EF_ITEMPLACEHOLDER ) // object is "spawning" in + { + int msec; + + if ( !cent->miscTime ) + { + cent->miscTime = cg.time; + } + + msec = cg.time - cent->miscTime; + if ( msec < ITEM_SCALEUP_TIME ) + { + float alpha; + int a; + alpha = (float)msec * ITEM_SCALEUP_DIV; + if ( s1->eventParm == 255 ) + { + alpha = 1.0f-alpha; + } + a = alpha * 255.0; + if (a <= 0) + a=1; + ent.shaderRGBA[0] = + ent.shaderRGBA[1] = + ent.shaderRGBA[2] = 255; + ent.shaderRGBA[3] = a; + ent.renderfx |= RF_FORCE_ENT_ALPHA; + trap_R_AddRefEntityToScene(&ent); + ent.renderfx &= ~RF_FORCE_ENT_ALPHA; + + // Now draw the static shader over it. + // Alpha in over half the time, out over half. + alpha = sin(M_PI*alpha); + a = alpha * 255.0; + if (a <= 0) + a=1; + ent.customShader = cgs.media.rezOutShader; + ent.shaderRGBA[0] = + ent.shaderRGBA[1] = + ent.shaderRGBA[2] = a; + trap_R_AddRefEntityToScene( &ent ); + } + else + { + trap_R_AddRefEntityToScene (&ent); + } + } + else + { + cent->miscTime = 0; + trap_R_AddRefEntityToScene (&ent); + } } + /* ================== CG_Speaker @@ -225,13 +342,30 @@ CG_Item ================== */ static void CG_Item( centity_t *cent ) { - refEntity_t ent; - entityState_t *es; - gitem_t *item; - int msec; - float frac; - float scale; - weaponInfo_t *wi; + refEntity_t ent; + entityState_t *es; + gitem_t *item; + int msec; +// float scale; + // RPG-X: Marcin: Custom angles for each weapon so they lie on the ground correctly. - 06/12/2008 + const vec3_t weaponangles[WP_NUM_WEAPONS] = { + { 0, 0, 0 }, // WP_0 + { 0, 0, 0 }, // WP_1 + { 52, 280, 18 }, // WP_2 + { 48, 26, 33 }, // WP_3 + { 335, 210, 347 }, // WP_4 + { 15, 160, 65 }, // WP_5 + { 5, 10, 70 }, // WP_6 + { 5, 6, 70 }, // WP_7 + { 5, 17, 70 }, // WP_8 + { 350, 23, 70 }, // WP_9 + { 15, 187, 80 }, // WP_10 + { 0, 270, 86 }, // WP_11 + { 0, 247, 90 }, // WP_12 + { 36, 190, 40 }, // WP_13 + { 0, 0, 105 }, // WP_14 + { 0, 210, 90 } // WP_15 + }; es = ¢->currentState; if ( es->modelindex >= bg_numItems ) { @@ -248,36 +382,96 @@ static void CG_Item( centity_t *cent ) { memset( &ent, 0, sizeof( ent ) ); ent.reType = RT_SPRITE; VectorCopy( cent->lerpOrigin, ent.origin ); - ent.radius = 14; + ent.data.sprite.radius = 14; + ent.customShader = cg_items[es->modelindex].icon; ent.shaderRGBA[0] = 255; ent.shaderRGBA[1] = 255; ent.shaderRGBA[2] = 255; - ent.shaderRGBA[3] = 255; + + if ( es->eFlags & EF_ITEMPLACEHOLDER ) + { + ent.renderfx |= RF_FORCE_ENT_ALPHA; + ent.shaderRGBA[3] = 50 + sin(cg.time*0.01)*30; + } + else + { + ent.shaderRGBA[3] = 255; + } + trap_R_AddRefEntityToScene(&ent); + return; } // items bob up and down continuously - scale = 0.005 + cent->currentState.number * 0.00001; - cent->lerpOrigin[2] += 4 + cos( ( cg.time + 1000 ) * scale ) * 4; +// scale = 0.005 + cent->currentState.number * 0.00001; +// cent->lerpOrigin[2] += 4 + cos( ( cg.time + 1000 ) * scale ) * 4; memset (&ent, 0, sizeof(ent)); + // autorotate at one of two speeds - if ( item->giType == IT_HEALTH ) { + if ( item->giType == IT_HEALTH ) + { VectorCopy( cg.autoAnglesFast, cent->lerpAngles ); AxisCopy( cg.autoAxisFast, ent.axis ); - } else { - VectorCopy( cg.autoAngles, cent->lerpAngles ); - AxisCopy( cg.autoAxis, ent.axis ); + } + else if (item->giType != IT_TEAM) // RPG-X | Marcin | 05/12/2008 + { + //VectorCopy( cg.autoAngles, cent->lerpAngles ); + //AxisCopy( cg.autoAxis, ent.axis ); + VectorCopy( weaponangles[item->giTag], cent->lerpAngles ); + AnglesToAxis( weaponangles[item->giTag], ent.axis); + } + else + { // Flags don't rotate at all... + float frame; + vec3_t vecs[3]; + + + // ...but they do animate. + //frame = (cg.time / 100.0); + frame = (cg.time * 0.01); + ent.renderfx|=RF_WRAP_FRAMES; + + ent.oldframe = (int)frame; + ent.frame = (int)frame+1; + ent.backlerp = (float)(ent.frame) - frame; + + // and they are scaled too + if (1) + { + AngleVectors(es->angles, vecs[0], vecs[1], vecs[2]); + VectorScale( vecs[0], 1.6, vecs[0] ); + VectorScale( vecs[1], 1.6, vecs[1] ); + VectorScale( vecs[2], 1.6, vecs[2] ); + AxisCopy( vecs, ent.axis ); + } + else + { + AnglesToAxis(cent->lerpAngles, ent.axis); + VectorScale( ent.axis[0], 1.6, ent.axis[0] ); + VectorScale( ent.axis[1], 1.6, ent.axis[1] ); + VectorScale( ent.axis[2], 1.6, ent.axis[2] ); + ent.nonNormalizedAxes = qtrue; + } + if (item->giTag == PW_BORG_ADAPT) + { + //ent.customShader = cgs.media.blueFlagShader[3]; + } + else + { + ent.customShader = cgs.media.redFlagShader[3]; + } } - wi = NULL; // the weapons have their origin where they attatch to player // models, so we need to offset them or they will rotate // eccentricly if ( item->giType == IT_WEAPON ) { + weaponInfo_t *wi; + wi = &cg_weapons[item->giTag]; cent->lerpOrigin[0] -= wi->weaponMidpoint[0] * ent.axis[0][0] + @@ -292,113 +486,105 @@ static void CG_Item( centity_t *cent ) { wi->weaponMidpoint[1] * ent.axis[1][2] + wi->weaponMidpoint[2] * ent.axis[2][2]; - cent->lerpOrigin[2] += 8; // an extra height boost - } - - if( item->giType == IT_WEAPON && item->giTag == WP_RAILGUN ) { - clientInfo_t *ci = &cgs.clientinfo[cg.snap->ps.clientNum]; - Byte4Copy( ci->c1RGBA, ent.shaderRGBA ); + cent->lerpOrigin[2] -= 14; // an extra height boost + // RPG-X | Marcin | 03/12/2008 + // (Was += 8) } - ent.hModel = cg_items[es->modelindex].models[0]; + ent.hModel = cg_items[es->modelindex].model; VectorCopy( cent->lerpOrigin, ent.origin); VectorCopy( cent->lerpOrigin, ent.oldorigin); ent.nonNormalizedAxes = qfalse; - // if just respawned, slowly scale up - msec = cg.time - cent->miscTime; - if ( msec >= 0 && msec < ITEM_SCALEUP_TIME ) { - frac = (float)msec / ITEM_SCALEUP_TIME; - VectorScale( ent.axis[0], frac, ent.axis[0] ); - VectorScale( ent.axis[1], frac, ent.axis[1] ); - VectorScale( ent.axis[2], frac, ent.axis[2] ); - ent.nonNormalizedAxes = qtrue; - } else { - frac = 1.0; + if ( es->eFlags & EF_ITEMPLACEHOLDER ) // item has been picked up + { + if ( es->eFlags & EF_DEAD ) // if item had been droped, don't show at all + return; + + ent.customShader = cgs.media.weaponPlaceholderShader; } - // items without glow textures need to keep a minimum light value - // so they are always visible - if ( ( item->giType == IT_WEAPON ) || - ( item->giType == IT_ARMOR ) ) { - ent.renderfx |= RF_MINLIGHT; - } - - // increase the size of the weapons when they are presented as items - if ( item->giType == IT_WEAPON ) { + // RPG-X | Marcin | 06/12/2008 + // increase the size of the weapons when they are presented as items - DON'T! + /*if ( item->giType == IT_WEAPON ) { VectorScale( ent.axis[0], 1.5, ent.axis[0] ); VectorScale( ent.axis[1], 1.5, ent.axis[1] ); VectorScale( ent.axis[2], 1.5, ent.axis[2] ); ent.nonNormalizedAxes = qtrue; -#ifdef MISSIONPACK - trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, cgs.media.weaponHoverSound ); -#endif - } + }*/ -#ifdef MISSIONPACK - if ( item->giType == IT_HOLDABLE && item->giTag == HI_KAMIKAZE ) { - VectorScale( ent.axis[0], 2, ent.axis[0] ); - VectorScale( ent.axis[1], 2, ent.axis[1] ); - VectorScale( ent.axis[2], 2, ent.axis[2] ); - ent.nonNormalizedAxes = qtrue; - } -#endif + msec = cg.time - cent->miscTime; // Count from last respawn. + /*if (cg.predictedPlayerState.introTime > cg.time) + { // The stuff is "holodecking in". + int dtime; - // add to refresh list - trap_R_AddRefEntityToScene(&ent); - -#ifdef MISSIONPACK - if ( item->giType == IT_WEAPON && wi->barrelModel ) { - refEntity_t barrel; - - memset( &barrel, 0, sizeof( barrel ) ); - - barrel.hModel = wi->barrelModel; - - VectorCopy( ent.lightingOrigin, barrel.lightingOrigin ); - barrel.shadowPlane = ent.shadowPlane; - barrel.renderfx = ent.renderfx; - - CG_PositionRotatedEntityOnTag( &barrel, &ent, wi->weaponModel, "tag_barrel" ); - - AxisCopy( ent.axis, barrel.axis ); - barrel.nonNormalizedAxes = ent.nonNormalizedAxes; - - trap_R_AddRefEntityToScene( &barrel ); - } -#endif - - // accompanying rings / spheres for powerups - if ( !cg_simpleItems.integer ) - { - vec3_t spinAngles; - - VectorClear( spinAngles ); - - if ( item->giType == IT_HEALTH || item->giType == IT_POWERUP ) - { - if ( ( ent.hModel = cg_items[es->modelindex].models[1] ) != 0 ) - { - if ( item->giType == IT_POWERUP ) - { - ent.origin[2] += 12; - spinAngles[1] = ( cg.time & 1023 ) * 360 / -1024.0f; - } - AnglesToAxis( spinAngles, ent.axis ); - - // scale up if respawning - if ( frac != 1.0 ) { - VectorScale( ent.axis[0], frac, ent.axis[0] ); - VectorScale( ent.axis[1], frac, ent.axis[1] ); - VectorScale( ent.axis[2], frac, ent.axis[2] ); - ent.nonNormalizedAxes = qtrue; - } - trap_R_AddRefEntityToScene( &ent ); - } + dtime = cg.predictedPlayerState.introTime - cg.time; + if (dtime < TIME_FADE_DUR) + { // "rez" in. + float alpha; + int a; + + alpha = 1.0 - ((float)dtime / (float)TIME_FADE_DUR); + a = alpha * 255.0; + if (a <= 0) + a=1; + ent.shaderRGBA[3] = a; + ent.renderfx |= RF_FORCE_ENT_ALPHA; + trap_R_AddRefEntityToScene(&ent); + ent.renderfx &= ~RF_FORCE_ENT_ALPHA; + + // Now draw the static shader over it. + // Alpha in over half the time, out over half. + alpha = sin(M_PI*alpha); + a = alpha * 255.0; + if (a <= 0) + a=1; + ent.customShader = cgs.media.rezOutShader; + ent.shaderRGBA[0] = + ent.shaderRGBA[1] = + ent.shaderRGBA[2] = a; + trap_R_AddRefEntityToScene( &ent ); + ent.shaderRGBA[0] = + ent.shaderRGBA[1] = + ent.shaderRGBA[2] = 255; } } + else*/ if (item->giType != IT_TEAM && msec >= 0 && msec < ITEM_SCALEUP_TIME && !(es->eFlags & EF_ITEMPLACEHOLDER)) + { // if just respawned, fade in, but don't do this for flags. + float alpha; + int a; + + alpha = (float)msec * ITEM_SCALEUP_DIV; + a = alpha * 255.0; + if (a <= 0) + a=1; + ent.shaderRGBA[3] = a; + ent.renderfx |= RF_FORCE_ENT_ALPHA; + trap_R_AddRefEntityToScene(&ent); + ent.renderfx &= ~RF_FORCE_ENT_ALPHA; + + // Now draw the static shader over it. + // Alpha in over half the time, out over half. + alpha = sin(M_PI*alpha); + a = alpha * 255.0; + if (a <= 0) + a=1; + ent.customShader = cgs.media.rezOutShader; + ent.shaderRGBA[0] = + ent.shaderRGBA[1] = + ent.shaderRGBA[2] = a; + trap_R_AddRefEntityToScene( &ent ); + //what is the point of this next bit??? + ent.shaderRGBA[0] = + ent.shaderRGBA[1] = + ent.shaderRGBA[2] = 255; + } + else + { // add to refresh list -- normal item + trap_R_AddRefEntityToScene(&ent); + } } //============================================================================ @@ -408,14 +594,16 @@ static void CG_Item( centity_t *cent ) { CG_Missile =============== */ -static void CG_Missile( centity_t *cent ) { +static void CG_Missile( centity_t *cent, qboolean altfire ) { refEntity_t ent; entityState_t *s1; + qhandle_t missile = 0; const weaponInfo_t *weapon; -// int col; - + int rpg_tripmines; + const char *info; + s1 = ¢->currentState; - if ( s1->weapon >= WP_NUM_WEAPONS ) { + if ( s1->weapon > WP_NUM_WEAPONS ) { s1->weapon = 0; } weapon = &cg_weapons[s1->weapon]; @@ -423,41 +611,79 @@ static void CG_Missile( centity_t *cent ) { // calculate the axis VectorCopy( s1->angles, cent->lerpAngles); - // add trails - if ( weapon->missileTrailFunc ) +// if (cent->currentState.eFlags & EF_ALT_FIRING) + if (altfire) { - weapon->missileTrailFunc( cent, weapon ); - } -/* - if ( cent->currentState.modelindex == TEAM_RED ) { - col = 1; - } - else if ( cent->currentState.modelindex == TEAM_BLUE ) { - col = 2; - } - else { - col = 0; - } + // add trails + if ( weapon->alt_missileTrailFunc ) + { + weapon->alt_missileTrailFunc( cent, weapon ); + } - // add dynamic light - if ( weapon->missileDlight ) { - trap_R_AddLightToScene(cent->lerpOrigin, weapon->missileDlight, - weapon->missileDlightColor[col][0], weapon->missileDlightColor[col][1], weapon->missileDlightColor[col][2] ); + // add dynamic light + if ( weapon->alt_missileDlight ) { + trap_R_AddLightToScene(cent->lerpOrigin, weapon->alt_missileDlight, + weapon->missileDlightColor[0], weapon->missileDlightColor[1], weapon->missileDlightColor[2] ); + } + + // add missile sound + if ( weapon->alt_missileSound ) + { + vec3_t velocity; + + BG_EvaluateTrajectoryDelta( ¢->currentState.pos, cg.time, velocity ); + if (velocity[0] || velocity[1] || velocity[2]) + { + trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, velocity, weapon->alt_missileSound ); + } + } + //RPG-X: RedTechie - non-admin see no tripmines! But first by popular demand check CVAR + info = CG_ConfigString( CS_SERVERINFO ); + rpg_tripmines = atoi( Info_ValueForKey( info, "rpg_invisibletripmines" ) ); + if (!weapon->alt_missileModel || (!cgs.clientinfo[cg.snap->ps.clientNum].isAdmin/*cg.snap->ps.persistant[PERS_CLASS] != PC_ADMIN*/ && rpg_tripmines == 1)) { + //if there is no missile then we're done + return; + } + missile = weapon->alt_missileModel; } + else + { + if (cent->thinkFlag) + { // we already grabbed info that was stored on the game side, so use what's already in cent->rawAngles + //and cent->rawOrigin + } + else + { + // kef -- get out some info we stored in a very unfortunate manner on the game side + VectorCopy(cent->currentState.angles2,cent->rawAngles); + VectorCopy(cent->currentState.angles2,cent->rawOrigin); + cent->thinkFlag = 1; + } + // add trails + if ( weapon->missileTrailFunc ) + { + weapon->missileTrailFunc( cent, weapon ); + } + + // add dynamic light + if ( weapon->missileDlight ) { + trap_R_AddLightToScene(cent->lerpOrigin, weapon->missileDlight, + weapon->missileDlightColor[0], weapon->missileDlightColor[1], weapon->missileDlightColor[2] ); + } + + // add missile sound +/* if ( weapon->missileSound ) { + vec3_t velocity; + + BG_EvaluateTrajectoryDelta( ¢->currentState.pos, cg.time, velocity ); + + trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, velocity, weapon->missileSound ); + } */ - // add dynamic light - if ( weapon->missileDlight ) { - trap_R_AddLightToScene(cent->lerpOrigin, weapon->missileDlight, - weapon->missileDlightColor[0], weapon->missileDlightColor[1], weapon->missileDlightColor[2] ); - } - - // add missile sound - if ( weapon->missileSound ) { - vec3_t velocity; - - BG_EvaluateTrajectoryDelta( ¢->currentState.pos, cg.time, velocity ); - - trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, velocity, weapon->missileSound ); + if (!weapon->missileModel) { //if ther is no missile then we're done + return; + } + missile = weapon->missileModel; } // create the render entity @@ -465,99 +691,71 @@ static void CG_Missile( centity_t *cent ) { VectorCopy( cent->lerpOrigin, ent.origin); VectorCopy( cent->lerpOrigin, ent.oldorigin); - if ( cent->currentState.weapon == WP_PLASMAGUN ) { + if ( cent->currentState.weapon == WP_9 ) { ent.reType = RT_SPRITE; - ent.radius = 16; - ent.rotation = 0; - ent.customShader = cgs.media.plasmaBallShader; + ent.data.sprite.radius = 16; + ent.data.sprite.rotation = 0; trap_R_AddRefEntityToScene( &ent ); return; } // flicker between two skins ent.skinNum = cg.clientFrame & 1; - ent.hModel = weapon->missileModel; - ent.renderfx = weapon->missileRenderfx | RF_NOSHADOW; + ent.hModel = missile; + ent.renderfx = RF_NOSHADOW; -#ifdef MISSIONPACK - if ( cent->currentState.weapon == WP_PROX_LAUNCHER ) { - if (s1->generic1 == TEAM_BLUE) { - ent.hModel = cgs.media.blueProxMine; - } + if ( s1->pos.trType == TR_STATIONARY ) + { + AnglesToAxis( s1->angles, ent.axis ); } -#endif - - // convert direction of travel into axis - if ( VectorNormalize2( s1->pos.trDelta, ent.axis[0] ) == 0 ) { - ent.axis[0][2] = 1; - } - - // spin as it moves - if ( s1->pos.trType != TR_STATIONARY ) { - RotateAroundDirection( ent.axis, cg.time / 4 ); - } else { -#ifdef MISSIONPACK - if ( s1->weapon == WP_PROX_LAUNCHER ) { - AnglesToAxis( cent->lerpAngles, ent.axis ); + else + { + // convert direction of travel into axis + if ( VectorNormalize2( s1->pos.trDelta, ent.axis[0] ) == 0 ) { + ent.axis[0][2] = 1; } - else -#endif - { + + // spin as it moves + if ( s1->pos.trType != TR_STATIONARY && (cent->currentState.weapon != WP_10) ) { //RPG-X-TiM: Stop from spinning O_o I got dizzy + //RotateAroundDirection( ent.axis, cg.time / 4 ); + RotateAroundDirection( ent.axis, cg.time * 0.25); + } else { RotateAroundDirection( ent.axis, s1->time ); } } // add to refresh list, possibly with quad glow - CG_AddRefEntityWithPowerups( &ent, s1, TEAM_FREE ); -} + CG_AddRefEntityWithPowerups( &ent, s1->powerups, s1->eFlags, ¢->beamData, cent->cloakTime, cent->decloakTime, qfalse ); + if ( s1->eFlags & EF_FIRING ) + {//special code for adding the beam to the attached tripwire mine + trace_t trace; + vec3_t beamOrg, beamEnd, rgb; + float alpha; + qhandle_t flareShader; + + if ( s1->otherEntityNum2 == TEAM_BLUE ) + { + VectorSet( rgb, 0.0f, 0.3f, 1.0f ); + alpha = 1.0f - (random() * 0.2); + flareShader = cgs.media.blueParticleShader; + } + else + { + VectorSet( rgb, 1.0f, 0.0f, 0.0f ); + alpha = 1.0f - (random() * 0.5); + flareShader = cgs.media.borgEyeFlareShader; + } + VectorCopy( ent.origin, beamOrg ); + VectorMA( beamOrg, -2, ent.axis[0], beamOrg );//forward + VectorMA( beamOrg, -1022, ent.axis[0], beamEnd);//forward to end, have to reverse it because it actually faces other way -/* -=============== -CG_Grapple - -This is called when the grapple is sitting up against the wall -=============== -*/ -static void CG_Grapple( centity_t *cent ) { - refEntity_t ent; - entityState_t *s1; - const weaponInfo_t *weapon; - - s1 = ¢->currentState; - if ( s1->weapon >= WP_NUM_WEAPONS ) { - s1->weapon = 0; + trap_CM_BoxTrace( &trace, beamOrg, beamEnd, NULL, NULL, 0, MASK_SHOT ); + VectorCopy(trace.endpos, beamEnd); + FX_AddLine2( beamOrg, beamEnd, 1.0f, 0.35f + ( crandom() * 0.1 ), 0.0f, 0.35f + ( crandom() * 0.1 ), 0.0f, alpha, alpha, rgb, rgb,1.0f, cgs.media.whiteLaserShader ); + //FX_AddSprite( beamOrg, NULL, qfalse, 1.0f + (random() * 2.0f), 0.0f, 0.9f, 0.9f, 0.0f, 0.0f, 0.0f, flareShader ); + FX_AddQuad( beamOrg, ent.axis[0], 1.0f, 1.0f, 2.0f + (crandom() * 1.0f), 0.0f, 0.0f, 1.0f, flareShader ); + FX_AddQuad( beamEnd, trace.plane.normal, 1.0f, 1.0f, 2.0f + (crandom() * 1.0f), 0.0f, 0.0f, 1.0f, flareShader ); } - weapon = &cg_weapons[s1->weapon]; - - // calculate the axis - VectorCopy( s1->angles, cent->lerpAngles); - -#if 0 // FIXME add grapple pull sound here..? - // add missile sound - if ( weapon->missileSound ) { - trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->missileSound ); - } -#endif - - // Will draw cable if needed - CG_GrappleTrail ( cent, weapon ); - - // create the render entity - memset (&ent, 0, sizeof(ent)); - VectorCopy( cent->lerpOrigin, ent.origin); - VectorCopy( cent->lerpOrigin, ent.oldorigin); - - // flicker between two skins - ent.skinNum = cg.clientFrame & 1; - ent.hModel = weapon->missileModel; - ent.renderfx = weapon->missileRenderfx | RF_NOSHADOW; - - // convert direction of travel into axis - if ( VectorNormalize2( s1->pos.trDelta, ent.axis[0] ) == 0 ) { - ent.axis[0][2] = 1; - } - - trap_R_AddRefEntityToScene( &ent ); } /* @@ -629,6 +827,7 @@ void CG_Beam( centity_t *cent ) { /* +RPG-X: RedTechie - FIXME: STILL FRICKEN SWAYS its not a sailing ship its a fricken star ship! =============== CG_Portal =============== @@ -652,9 +851,10 @@ static void CG_Portal( centity_t *cent ) { CrossProduct( ent.axis[0], ent.axis[1], ent.axis[2] ); ent.reType = RT_PORTALSURFACE; - ent.oldframe = s1->powerups; - ent.frame = s1->frame; // rotation speed - ent.skinNum = s1->clientNum/256.0 * 360; // roll offset + + ent.frame = s1->frame; // rotation speed - s1->frame + ent.skinNum = s1->clientNum / 256 * 360; // roll offset //RPG-X: RedTechie - ent.skinNum = s1->clientNum/256.0 * 360; + //ent.oldframe = 0; // add to refresh list trap_R_AddRefEntityToScene(&ent); @@ -671,8 +871,7 @@ Also called by client movement prediction code void CG_AdjustPositionForMover( const vec3_t in, int moverNum, int fromTime, int toTime, vec3_t out ) { centity_t *cent; vec3_t oldOrigin, origin, deltaOrigin; - vec3_t oldAngles, angles; - //vec3_t deltaAngles; + vec3_t oldAngles, angles, deltaAngles; if ( moverNum <= 0 || moverNum >= ENTITYNUM_MAX_NORMAL ) { VectorCopy( in, out ); @@ -680,7 +879,7 @@ void CG_AdjustPositionForMover( const vec3_t in, int moverNum, int fromTime, int } cent = &cg_entities[ moverNum ]; - if ( cent->currentState.eType != ET_MOVER ) { + if ( cent->currentState.eType != ET_MOVER && cent->currentState.eType != ET_MOVER_STR ) { //RPG-X | GSIO01 | 13/05/2009 VectorCopy( in, out ); return; } @@ -692,7 +891,7 @@ void CG_AdjustPositionForMover( const vec3_t in, int moverNum, int fromTime, int BG_EvaluateTrajectory( ¢->currentState.apos, toTime, angles ); VectorSubtract( origin, oldOrigin, deltaOrigin ); - //VectorSubtract( angles, oldAngles, deltaAngles ); + VectorSubtract( angles, oldAngles, deltaAngles ); VectorAdd( in, deltaOrigin, out ); @@ -742,29 +941,11 @@ CG_CalcEntityLerpPositions =============== */ static void CG_CalcEntityLerpPositions( centity_t *cent ) { - - // if this player does not want to see extrapolated players - if ( !cg_smoothClients.integer ) { - // make sure the clients use TR_INTERPOLATE - if ( cent->currentState.number < MAX_CLIENTS ) { - cent->currentState.pos.trType = TR_INTERPOLATE; - cent->nextState.pos.trType = TR_INTERPOLATE; - } - } - if ( cent->interpolate && cent->currentState.pos.trType == TR_INTERPOLATE ) { CG_InterpolateEntityPosition( cent ); return; } - - // first see if we can interpolate between two snaps for - // linear extrapolated clients - if ( cent->interpolate && cent->currentState.pos.trType == TR_LINEAR_STOP && - cent->currentState.number < MAX_CLIENTS) { - CG_InterpolateEntityPosition( cent ); - return; - } - + // just use the current frame and evaluate as best we can BG_EvaluateTrajectory( ¢->currentState.pos, cg.time, cent->lerpOrigin ); BG_EvaluateTrajectory( ¢->currentState.apos, cg.time, cent->lerpAngles ); @@ -777,159 +958,6 @@ static void CG_CalcEntityLerpPositions( centity_t *cent ) { } } -/* -=============== -CG_TeamBase -=============== -*/ -static void CG_TeamBase( centity_t *cent ) { - refEntity_t model; -#ifdef MISSIONPACK - vec3_t angles; - int t, h; - float c; - - if ( cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF ) { -#else - if ( cgs.gametype == GT_CTF) { -#endif - // show the flag base - memset(&model, 0, sizeof(model)); - model.reType = RT_MODEL; - VectorCopy( cent->lerpOrigin, model.lightingOrigin ); - VectorCopy( cent->lerpOrigin, model.origin ); - AnglesToAxis( cent->currentState.angles, model.axis ); - if ( cent->currentState.modelindex == TEAM_RED ) { - model.hModel = cgs.media.redFlagBaseModel; - } - else if ( cent->currentState.modelindex == TEAM_BLUE ) { - model.hModel = cgs.media.blueFlagBaseModel; - } - else { - model.hModel = cgs.media.neutralFlagBaseModel; - } - trap_R_AddRefEntityToScene( &model ); - } -#ifdef MISSIONPACK - else if ( cgs.gametype == GT_OBELISK ) { - // show the obelisk - memset(&model, 0, sizeof(model)); - model.reType = RT_MODEL; - VectorCopy( cent->lerpOrigin, model.lightingOrigin ); - VectorCopy( cent->lerpOrigin, model.origin ); - AnglesToAxis( cent->currentState.angles, model.axis ); - - model.hModel = cgs.media.overloadBaseModel; - trap_R_AddRefEntityToScene( &model ); - // if hit - if ( cent->currentState.frame == 1) { - // show hit model - // modelindex2 is the health value of the obelisk - c = cent->currentState.modelindex2; - model.shaderRGBA[0] = 0xff; - model.shaderRGBA[1] = c; - model.shaderRGBA[2] = c; - model.shaderRGBA[3] = 0xff; - // - model.hModel = cgs.media.overloadEnergyModel; - trap_R_AddRefEntityToScene( &model ); - } - // if respawning - if ( cent->currentState.frame == 2) { - if ( !cent->miscTime ) { - cent->miscTime = cg.time; - } - t = cg.time - cent->miscTime; - h = (cg_obeliskRespawnDelay.integer - 5) * 1000; - // - if (t > h) { - c = (float) (t - h) / h; - if (c > 1) - c = 1; - } - else { - c = 0; - } - // show the lights - AnglesToAxis( cent->currentState.angles, model.axis ); - // - model.shaderRGBA[0] = c * 0xff; - model.shaderRGBA[1] = c * 0xff; - model.shaderRGBA[2] = c * 0xff; - model.shaderRGBA[3] = c * 0xff; - - model.hModel = cgs.media.overloadLightsModel; - trap_R_AddRefEntityToScene( &model ); - // show the target - if (t > h) { - if ( !cent->muzzleFlashTime ) { - trap_S_StartSound (cent->lerpOrigin, ENTITYNUM_NONE, CHAN_BODY, cgs.media.obeliskRespawnSound); - cent->muzzleFlashTime = 1; - } - VectorCopy(cent->currentState.angles, angles); - angles[YAW] += (float) 16 * acos(1-c) * 180 / M_PI; - AnglesToAxis( angles, model.axis ); - - VectorScale( model.axis[0], c, model.axis[0]); - VectorScale( model.axis[1], c, model.axis[1]); - VectorScale( model.axis[2], c, model.axis[2]); - - model.shaderRGBA[0] = 0xff; - model.shaderRGBA[1] = 0xff; - model.shaderRGBA[2] = 0xff; - model.shaderRGBA[3] = 0xff; - // - model.origin[2] += 56; - model.hModel = cgs.media.overloadTargetModel; - trap_R_AddRefEntityToScene( &model ); - } - else { - //FIXME: show animated smoke - } - } - else { - cent->miscTime = 0; - cent->muzzleFlashTime = 0; - // modelindex2 is the health value of the obelisk - c = cent->currentState.modelindex2; - model.shaderRGBA[0] = 0xff; - model.shaderRGBA[1] = c; - model.shaderRGBA[2] = c; - model.shaderRGBA[3] = 0xff; - // show the lights - model.hModel = cgs.media.overloadLightsModel; - trap_R_AddRefEntityToScene( &model ); - // show the target - model.origin[2] += 56; - model.hModel = cgs.media.overloadTargetModel; - trap_R_AddRefEntityToScene( &model ); - } - } - else if ( cgs.gametype == GT_HARVESTER ) { - // show harvester model - memset(&model, 0, sizeof(model)); - model.reType = RT_MODEL; - VectorCopy( cent->lerpOrigin, model.lightingOrigin ); - VectorCopy( cent->lerpOrigin, model.origin ); - AnglesToAxis( cent->currentState.angles, model.axis ); - - if ( cent->currentState.modelindex == TEAM_RED ) { - model.hModel = cgs.media.harvesterModel; - model.customSkin = cgs.media.harvesterRedSkin; - } - else if ( cent->currentState.modelindex == TEAM_BLUE ) { - model.hModel = cgs.media.harvesterModel; - model.customSkin = cgs.media.harvesterBlueSkin; - } - else { - model.hModel = cgs.media.harvesterNeutralModel; - model.customSkin = 0; - } - trap_R_AddRefEntityToScene( &model ); - } -#endif -} - /* =============== CG_AddCEntity @@ -952,10 +980,14 @@ static void CG_AddCEntity( centity_t *cent ) { default: CG_Error( "Bad entity type: %i\n", cent->currentState.eType ); break; + case ET_TRIC_STRING: case ET_INVISIBLE: case ET_PUSH_TRIGGER: case ET_TELEPORT_TRIGGER: break; + case ET_USEABLE: // e.g. detpacks + CG_Useable( cent ); + break; case ET_GENERAL: CG_General( cent ); break; @@ -965,10 +997,14 @@ static void CG_AddCEntity( centity_t *cent ) { case ET_ITEM: CG_Item( cent ); break; + case ET_ALT_MISSILE: + CG_Missile( cent, qtrue ); + break; case ET_MISSILE: - CG_Missile( cent ); + CG_Missile( cent, qfalse ); break; case ET_MOVER: + case ET_MOVER_STR: CG_Mover( cent ); break; case ET_BEAM: @@ -980,11 +1016,11 @@ static void CG_AddCEntity( centity_t *cent ) { case ET_SPEAKER: CG_Speaker( cent ); break; - case ET_GRAPPLE: - CG_Grapple( cent ); + case ET_LASER: + CG_LaserSight( cent ); break; - case ET_TEAM: - CG_TeamBase( cent ); + case ET_TURBOLIFT: + CG_Turbolift( cent ); break; } } @@ -1015,13 +1051,18 @@ void CG_AddPacketEntities( void ) { // no entities should be marked as interpolating } + // the auto-rotating items will all have the same axis - cg.autoAngles[0] = 0; - cg.autoAngles[1] = ( cg.time & 2047 ) * 360 / 2048.0; - cg.autoAngles[2] = 0; + + // RPG-X | Marcin | 03/12/2008 + // We don't want dropped weapons to rotate at all + // -- NOT USED ANY MORE THOUGH -- + cg.autoAngles[0] = 0; + cg.autoAngles[1] = 0; + cg.autoAngles[2] = 68; cg.autoAnglesFast[0] = 0; - cg.autoAnglesFast[1] = ( cg.time & 1023 ) * 360 / 1024.0f; + cg.autoAnglesFast[1] = ( cg.time & 1023 ) * 360 / 1024; cg.autoAnglesFast[2] = 0; AnglesToAxis( cg.autoAngles, cg.autoAxis ); @@ -1042,3 +1083,110 @@ void CG_AddPacketEntities( void ) { } } +/* +================== +CG_LaserSight + Creates the laser +================== +*/ + +static void CG_LaserSight( centity_t *cent ) { + refEntity_t ent; + + // create the render entity + memset (&ent, 0, sizeof(ent)); + VectorCopy( cent->lerpOrigin, ent.origin); + VectorCopy( cent->lerpOrigin, ent.oldorigin); + + if (cent->currentState.eventParm == 1) + { + ent.reType = RT_SPRITE; + //ent.radius = 2; + //ent.rotation = 0; + ent.data.sprite.radius = 2; + ent.customShader = cgs.media.laserShader; + trap_R_AddRefEntityToScene( &ent ); + } + else { + trap_R_AddLightToScene(ent.origin, 200, 1, 1, 1); + } + + +} + +/* +================== +CG_Turbolift +A client complement +to the turbolift ent, +this plays the sound +FX whilst it is in action +================== +*/ + +static void CG_Turbolift( centity_t* cent ) +{ + int i; + centity_t *player; + //TiM - find all of the cents inside the lift, and make it so they orient to their view angles. + //Otherwise, when they teleport, the entire body snaps around, looking weird and/or painful. + + if ( cent->currentState.time2 <= 0 ) + return; + + for ( i = 0; i < MAX_CLIENTS; i++ ) + { + player = &cg_entities[i]; + + if ( !player ) + continue; + + if ( ( player->lerpOrigin[0] > cent->currentState.angles2[0] && player->lerpOrigin[0] < cent->currentState.origin2[0] ) + && ( player->lerpOrigin[1] > cent->currentState.angles2[1] && player->lerpOrigin[1] < cent->currentState.origin2[1] ) + && ( player->lerpOrigin[2] > cent->currentState.angles2[2] && player->lerpOrigin[2] < cent->currentState.origin2[2] ) ) + { + //time2 = startTime+waittime + if ( cent->currentState.time2 > 0 ) + { + cg_liftEnts[player->currentState.clientNum] = cent->currentState.time2; + } + else + { + cg_liftEnts[player->currentState.clientNum] = 0; + } + } + } + + trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, //cent->lerpOrigin + cgs.gameSounds[ cent->currentState.loopSound ] ); +} + +/*static void CG_Turbolift( centity_t* cent ) +{ + if ( cent->currentState.eventParm <= 0 ) + { + cent->deathTime = 0; + cent->miscTime = 0; + return; + } + + //Init sound + if ( cent->miscTime == 0 ) + { + cent->miscTime = cg.time + cent->currentState.modelindex2; //set the end of the wait time + } + + if ( cg.time < cent->miscTime ) + { + trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, //cent->lerpOrigin + cgs.gameSounds[ cent->currentState.loopSound ] ); + + return; + } + + if ( cent->deathTime == 0 ) + { + trap_S_StartSound (NULL, cent->currentState.number, CHAN_ITEM, cgs.gameSounds[cent->currentState.otherEntityNum2] ); + cent->deathTime = 1; + } +}*/ diff --git a/code/cgame/cg_env.c b/code/cgame/cg_env.c new file mode 100644 index 0000000..8abb726 --- /dev/null +++ b/code/cgame/cg_env.c @@ -0,0 +1,2181 @@ +//This file contains environmental effects for the designers + +#include "cg_local.h" +#include "fx_local.h" + +// these flags should be synchronized with the spawnflags in g_fx.c for fx_bolt +#define BOLT_SPARKS (1<<0) +#define BOLT_BORG (1<<1) + + +qboolean SparkThink( localEntity_t *le ) +{ + vec3_t dir, direction, start, end; + vec3_t velocity; + float scale = 0, alpha = 0; + int numSparks = 0, i = 0, j = 0; + sfxHandle_t snd = cgs.media.envSparkSound1; + + switch(irandom(1, 3)) + { + case 1: + snd = cgs.media.envSparkSound1; + break; + case 2: + snd = cgs.media.envSparkSound2; + break; + case 3: + snd = cgs.media.envSparkSound3; + break; + } + trap_S_StartSound (le->refEntity.origin, ENTITYNUM_WORLD, CHAN_BODY, snd ); + + CG_InitLensFlare( le->refEntity.origin, + 40, 40, + colorTable[CT_YELLOW], 1.2, 2.0, 1600, 200, + colorTable[CT_YELLOW], 1600, 200, 600, 6, qtrue, + 0, 0, qfalse, qtrue, + qtrue, 0.7, cg.time, 90, 0, 300); + + + VectorCopy(le->data.spawner.dir, dir); + + //AngleVectors( dir, dir, NULL, NULL ); + for ( j = 0; j < 3; j ++ ) + direction[j] = dir[j] + (0.25f * crandom()); + + VectorNormalize( direction ); + + //trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgi_S_RegisterSound( va( "sound/world/ric%d.wav", (rand() & 2)+1) ) ); + + numSparks = 8 + (random() * 4.0f); + + scale = 0.2f + (random() *0.4); + VectorMA( le->refEntity.origin, 24.0f + (crandom() * 4.0f), dir, end ); + + //One long spark + FX_AddLine( le->refEntity.origin, + end, + 1.0f, + scale, + 0.0f, + 1.0f, + 0.25f, + 125.0f, + cgs.media.sparkShader ); + + for ( i = 0; i < numSparks; i++ ) + { + scale = 0.2f + (random() *0.4); + + for ( j = 0; j < 3; j ++ ) + direction[j] = dir[j] + (0.25f * crandom()); + + VectorNormalize(direction); + + VectorMA( le->refEntity.origin, 0.0f + ( random() * 2.0f ), direction, start ); + VectorMA( start, 2.0f + ( random() * 16.0f ), direction, end ); + + FX_AddLine( start, + end, + 1.0f, + scale, + 0.0f, + 1.0f, + 0.25f, + 125.0f, + cgs.media.sparkShader ); + } + + if ( rand() & 1 ) + { + numSparks = 1 + (random() * 2.0f); + for ( i = 0; i < numSparks; i++ ) + { + scale = 0.5f + (random() * 0.5f); + + VectorScale( direction, 250, velocity ); + + FX_AddTrail( start, + velocity, + qtrue, + 8.0f, + -32.0f, + scale, + -scale, + 1.0f, + 0.5f, + 0.25f, + 700.0f, + cgs.media.sparkShader); + + } + } + + VectorMA( le->refEntity.origin, 1, dir, direction ); + + scale = 6.0f + (random() * 8.0f); + alpha = 0.1 + (random() * 0.4f); + + VectorSet( velocity, 0, 0, 8 ); + + FX_AddSprite( direction, + velocity, + qfalse, + scale, + scale, + alpha, + 0.0f, + random()*45.0f, + 0.0f, + 1000.0f, + cgs.media.steamShader ); + + return qtrue; +} + +/* +====================== +CG_Spark + +Creates a spark effect +====================== +*/ + +void CG_Spark( vec3_t origin, vec3_t normal, int delay, int killTime ) +{ + // give it a lifetime of 10 seconds because the refresh thinktime in g_fx.c is 10 seconds + FX_AddSpawner( origin, normal, NULL, NULL, qfalse, delay, 1.5, killTime, SparkThink, 100 ); //10000 + +} + + + +qboolean SteamThink( localEntity_t *le ) +{ + float speed = 200; + vec3_t direction; + vec3_t velocity = { 0, 0, 128 }; + float scale, dscale; + vec3_t origin; + + //FIXME: Whole lotta randoms... + + VectorCopy( le->data.spawner.dir, direction ); + //AngleVectors( direction, direction, NULL, NULL ); + //VectorNormalize(direction); + + //TiM : Offset by 1. sometimes it can spawn in walls and the particles act weird then + VectorMA( le->refEntity.origin, 1, direction, origin ); + + direction[0] += (direction[0] * crandom() * le->data.spawner.variance); + direction[1] += (direction[0] * crandom() * le->data.spawner.variance); + direction[2] += (direction[0] * crandom() * le->data.spawner.variance); + + VectorScale( direction, speed, velocity ); + + scale = 4.0f + (random()); + dscale = scale * 4.0; + + FX_AddSprite( origin, + velocity, + qfalse, + scale, + dscale, + 1.0f, + 0.0f, + random() * 360, + 0.25f, + 300,//(len / speed) * 1000, + cgs.media.steamShader ); + + return qtrue; +} + +/* +====================== +CG_Steam + +Creates a steam effect +====================== +*/ + +void CG_Steam( vec3_t position, vec3_t dir, int killTime ) +{ + // give it a lifetime of 10 seconds because the refresh thinktime in g_fx.c is 10 seconds + FX_AddSpawner( position, dir, NULL, NULL, qfalse, 0, 0.15, killTime, SteamThink, 100 ); // +} + +/* +====================== +CG_Bolt + +Creates a electricity bolt effect +====================== +*/ +#define DATA_EFFECTS 0 +#define DATA_CHAOS 1 +#define DATA_RADIUS 2 + +//----------------------------- +void BoltSparkSpew( vec3_t origin, vec3_t normal ) +{ + float scale = 1.0f + ( random() * 1.0f ); + int num = 0, i = 0; + vec3_t vel; + + trap_R_AddLightToScene( origin, 75 + (rand()&31), 1.0, 0.8, 1.0 ); + + // Drop some sparks + num = (int)(random() * 2) + 2; + + for ( i = 0; i < num; i++ ) + { + scale = 0.6f + random(); + if ( rand() & 1 ) + FXE_Spray( normal, 70, 80, 0.9f, vel); + else + FXE_Spray( normal, 80, 200, 0.5f, vel); + + FX_AddTrail( origin, vel, qfalse, 8.0f + random() * 8, -48.0f, + scale, -scale, 1.0f, 0.8f, 0.4f, 600.0f, cgs.media.spark2Shader ); + } +} + + +qboolean BoltFireback( localEntity_t *le) +{ +//localEntity_t *FX_AddElectricity( vec3_t origin, vec3_t origin2, float stScale, float scale, float dscale, +// float startalpha, float endalpha, float killTime, qhandle_t shader, float deviation ); + float killTime = (0 == le->data.spawner.delay)?10000:200; + + FX_AddElectricity(le->refEntity.origin, le->data.spawner.dir, 0.2f, 15.0, -15.0, 1.0, 0.5, killTime, + cgs.media.bolt2Shader, le->data.spawner.variance ); + // is this spawner on a random delay? + if (le->data.spawner.data1) + { + le->data.spawner.delay = flrandom(0,5000); + } + return qtrue; +} + +//----------------------------- +qboolean BorgBoltFireback( localEntity_t *le) +{ + float killTime = (0 == le->data.spawner.delay)?10000:200; + + FX_AddElectricity(le->refEntity.origin, le->data.spawner.dir, 0.2f, 15.0, -5.0, 1.0, 0.5, killTime, + cgs.media.borgLightningShaders[1], le->data.spawner.variance ); + // is this spawner on a random delay? + if (le->data.spawner.data1) + { + le->data.spawner.delay = flrandom(0,5000); + } + return qtrue; +} + +//----------------------------- +qboolean BoltFirebackSparks( localEntity_t *le) +{ + vec3_t dir; + float killTime = (0 == le->data.spawner.delay)?10000:200; + + VectorSubtract(le->refEntity.origin, le->data.spawner.dir, dir); + VectorNormalize(dir); + FX_AddElectricity(le->refEntity.origin, le->data.spawner.dir, 0.2f, 15.0, -15.0, 1.0, 0.5, killTime, + cgs.media.bolt2Shader, le->data.spawner.variance ); + BoltSparkSpew(le->data.spawner.dir, dir); + // is this spawner on a random delay? + if (le->data.spawner.data1) + { + le->data.spawner.delay = flrandom(0,5000); + } + return qtrue; +} + +//----------------------------- +qboolean BorgBoltFirebackSparks( localEntity_t *le) +{ + vec3_t dir; + float killTime = (0 == le->data.spawner.delay)?10000:200; + + VectorSubtract(le->refEntity.origin, le->data.spawner.dir, dir); + VectorNormalize(dir); + FX_AddElectricity(le->refEntity.origin, le->data.spawner.dir, 0.2f, 15.0, -15.0, 1.0, 0.5, killTime, + cgs.media.borgLightningShaders[0], le->data.spawner.variance ); + BoltSparkSpew(le->data.spawner.dir, dir); + // is this spawner on a random delay? + if (le->data.spawner.data1) + { + le->data.spawner.delay = flrandom(0,5000); + } + return qtrue; +} + +//----------------------------- +void CG_Bolt( centity_t *cent ) +{ + localEntity_t *le = NULL; + qboolean bSparks = (qboolean)(cent->currentState.eventParm & BOLT_SPARKS); + qboolean bBorg = (qboolean)(cent->currentState.eventParm & BOLT_BORG); + float radius = cent->currentState.angles2[0], chaos = cent->currentState.angles2[1]; + float delay = cent->currentState.time2 * 1000; // the value given by the designer is in seconds + qboolean bRandom = qfalse; + + if (delay < 0) + { + // random + delay = flrandom(0.1, 5000.0); + bRandom = qtrue; + } + if (delay > 10000) + { + delay = 10000; + } + + if ( bBorg ) + { + if (bSparks) + { + le = FX_AddSpawner( cent->lerpOrigin, cent->currentState.origin2, NULL, NULL, qfalse, delay, + chaos, 10000, BorgBoltFirebackSparks, radius ); + } + else + { + le = FX_AddSpawner( cent->lerpOrigin, cent->currentState.origin2, NULL, NULL, qfalse, delay, + chaos, 10000, BorgBoltFireback, radius ); + } + } + else + { + if (bSparks) + { + le = FX_AddSpawner( cent->lerpOrigin, cent->currentState.origin2, NULL, NULL, qfalse, delay, + chaos, 10000, BoltFirebackSparks, radius ); + } + else + { + le = FX_AddSpawner( cent->lerpOrigin, cent->currentState.origin2, NULL, NULL, qfalse, delay, + chaos, 10000, BoltFireback, radius ); + } + } + if (bRandom) + { + le->data.spawner.data1 = 1; + } +} + +void CG_TransporterPad(vec3_t origin) +{ + FX_TransporterPad(origin); +} + +/* +=========================== +Drip + +Create timed drip effect +=========================== +*/ + +qboolean DripCallback( localEntity_t *le ) +{ + localEntity_t *trail = NULL; + qhandle_t shader = 0; + + switch (le->data.spawner.data1) + { + case 1: + shader = cgs.media.oilDropShader; + break; + case 2: + shader = cgs.media.greenDropShader; + break; + case 0: + default: + shader = cgs.media.waterDropShader; + break; + } + trail = FX_AddTrail(le->refEntity.origin, le->pos.trDelta, qfalse, 4, -2, 1, 0, 0.8, 0.4, 0.0, + 300, shader); + trail->leFlags |= LEF_ONE_FRAME; + + return qtrue; +} + +//------------------------------------------------------------------------------ +qboolean DripSplash( localEntity_t *le ) +{ + float scale = 1.0f + ( random() * 1.0f ); + int num = 0, i = 0; + vec3_t vel, normal, origin; + qhandle_t shader = 0; + + switch (le->data.spawner.data1) + { + case 1: + shader = cgs.media.oilDropShader; + break; + case 2: + shader = cgs.media.greenDropShader; + break; + case 0: + default: + shader = cgs.media.waterDropShader; + break; + } + + VectorCopy(le->data.spawner.dir, normal); + VectorCopy(le->refEntity.origin, origin); + + // splashing water droplets. which, I'm fairly certain, is an alternative band from Europe. + num = (int)(random() * 2) + 6; + + for ( i = 0; i < num; i++ ) + { + scale = 0.6f + random(); + if ( rand() & 1 ) + FXE_Spray( normal, 110, 80, 0.9f, vel); + else + FXE_Spray( normal, 150, 150, 0.5f, vel); + + FX_AddTrail( origin, vel, qtrue, 4.0f, 0.0f, + scale, -scale, 1.0f, 0.8f, 0.4f, 200.0f, shader ); + } + + switch( rand() & 3 ) + { + case 1: + trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_BODY, cgs.media.waterDropSound1 ); + break; + case 2: + trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_BODY, cgs.media.waterDropSound2 ); + break; + default: + trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_BODY, cgs.media.waterDropSound3 ); + break; + } + return qtrue; + +} + +qboolean JackTheDripper( localEntity_t *le ) +{ + trace_t trace; + vec3_t vel, down = {0,0,-1}, end, origin, new_origin; + float time, dis, diameter = 1.0; + qhandle_t shader = 0; + int maxDripsPerLifetime = 200; // given a 10 second lifetime + int desiredDrips = 1 + (int)(le->data.spawner.variance * (maxDripsPerLifetime-1)); // range of (1...max) + float percentLife = 1.0f - (le->endTime - cg.time)*le->lifeRate; + localEntity_t *splash = NULL; + + switch (le->data.spawner.data1) + { + case 1: + shader = cgs.media.oilDropShader; + break; + case 2: + shader = cgs.media.greenDropShader; + break; + case 0: + default: + shader = cgs.media.waterDropShader; + break; + } + + // do we need to add a drip to maintain our drips-per-second rate? + while ( (int)(flrandom(percentLife-0.05,percentLife+0.05)*desiredDrips) > le->data.spawner.data2) + { + VectorCopy(le->refEntity.origin, origin); + + // the more drips per second, spread them out from our origin point + fxRandCircumferencePos(origin, down, 10*le->data.spawner.variance, new_origin); + + // Ideally, zero should be used for vel...so just use something sufficiently close + VectorSet( vel, 0, 0, -0.00001 ); + + // Find out where it will hit + VectorMA( new_origin, 1024, down, end ); + CG_Trace( &trace, new_origin, NULL, NULL, end, 0, MASK_SHOT ); + if ( trace.fraction < 1.0 ) + { + VectorSubtract( trace.endpos, new_origin, end ); + dis = VectorNormalize( end ); + + time = sqrt( 2*dis / DEFAULT_GRAVITY ) * 1000; // Calculate how long the thing will take to travel that distance + + // Falling drop + splash = FX_AddParticle( new_origin, vel, qtrue, diameter, 0.0, 0.8, 0.8, 0.0, 0.0, time, shader, DripCallback ); + splash->data.spawner.data1 = le->data.spawner.data1; + + splash = FX_AddSpawner(trace.endpos, trace.plane.normal, vel, NULL, qfalse, time, 0, time + 200, DripSplash, 10); + splash->data.spawner.data1 = le->data.spawner.data1; + } + else + // Falling a long way so just send one that will fall for 2 secs, but don't spawn a splash + { + FX_AddParticle( new_origin, vel, qtrue, diameter, 0.0, 0.8, 0.8, 0.0, 0.0, 2000, shader, 0/*NULL*/ ); + } + //increase our number-of-drips counter + le->data.spawner.data2++; + } + return qtrue; +} + +//------------------------------------------------------------------------------ +void CG_Drip(centity_t *cent, int killTime ) +{ + vec3_t down = {0,0,-1}; + localEntity_t *le = NULL; + + // clamp variance to [0...1] + if (cent->currentState.angles2[0] < 0) + { + cent->currentState.angles2[0] = 0; + } + else if (cent->currentState.angles2[0] > 1) + { + cent->currentState.angles2[0] = 1; + } + // cent->currentState.angles2[0] is the degree of drippiness + // cent->currentState.time2 is the type of drip (water, oil, etc.) + le = FX_AddSpawner( cent->lerpOrigin, down, NULL, NULL, qfalse, 0, + cent->currentState.angles2[0], killTime, JackTheDripper, cent->currentState.time2 ); + //init our number-of-drips counter + le->data.spawner.data2 = 0; +} + +//------------------------------------------------------------------------------ +void CG_Chunks( vec3_t origin, vec3_t dir, float scale, material_type_t type ) +{ + int i, j, k; + int numChunks; + float baseScale = 1.0f, dist, radius; + vec3_t v; + sfxHandle_t snd = 0; + localEntity_t *le; + refEntity_t *re; + + if ( type == MT_NONE ) + return; + + if ( type >= NUM_CHUNK_TYPES ) + { + CG_Printf( "^6Chunk has invalid material %d!\n", type); + type = MT_METAL; //something legal please + } + + switch( type ) + { + case MT_GLASS: + case MT_GLASS_METAL: + snd = cgs.media.glassChunkSound; + break; + + case MT_METAL: + case MT_STONE: + case MT_WOOD: + default: + snd = cgs.media.metalChunkSound; + break; + } + + trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_BODY, snd ); + + numChunks = irandom( 8, 12 ); + + // LOD num chunks + VectorSubtract( cg.snap->ps.origin, origin, v ); + dist = VectorLength( v ); + + if ( dist > 512 ) + { + numChunks *= 512.0 / dist; // 1/2 at 1024, 1/4 at 2048, etc. + } + + // attempt to scale the size of the chunks based on the size of the brush + radius = baseScale + ( ( scale - 128 ) / 128 ); + + for ( i = 0; i < numChunks; i++ ) + { + le = CG_AllocLocalEntity(); + re = &le->refEntity; + + le->leType = LE_FRAGMENT; + le->endTime = cg.time + 2000; + + VectorCopy( origin, re->origin ); + + for ( j = 0; j < 3; j++ ) + { + re->origin[j] += crandom() * 12; + } + VectorCopy( re->origin, le->pos.trBase ); + + //Velocity + VectorSet( v, crandom(), crandom(), crandom() ); + VectorAdd( v, dir, v ); + VectorScale( v, flrandom( 100, 350 ), le->pos.trDelta ); + + //Angular Velocity + VectorSet( le->angles.trBase, crandom() * 360, crandom() * 360, crandom() * 360 ); + VectorSet( le->angles.trDelta, crandom() * 90, crandom() * 90, crandom() * 90 ); + + AxisCopy( axisDefault, re->axis ); + + le->data.fragment.radius = flrandom( radius * 0.7f, radius * 1.3f ); + + re->nonNormalizedAxes = qtrue; + + if ( type == MT_GLASS_METAL ) + { + if ( rand() & 1 ) + { + re->hModel = cgs.media.chunkModels[MT_METAL][irandom(0,5)]; + } + else + { + re->hModel = cgs.media.chunkModels[MT_GLASS][irandom(0,5)]; + } + } + else + { + re->hModel = cgs.media.chunkModels[type][irandom(0,5)]; + } + + le->pos.trType = TR_GRAVITY; + le->pos.trTime = cg.time; + le->angles.trType = TR_INTERPOLATE; + le->angles.trTime = cg.time; + le->bounceFactor = 0.2f + random() * 0.2f; + le->leFlags |= LEF_TUMBLE; + + re->shaderRGBA[0] = re->shaderRGBA[1] = re->shaderRGBA[2] = re->shaderRGBA[3] = 255; + + // Make sure that we have the desired start size set + for( k = 0; k < 3; k++) + { + VectorScale( le->refEntity.axis[k], le->data.fragment.radius, le->refEntity.axis[k] ); + } + } +} + +//TiM - org is where teh spray originates, and end is where the splash ends +//The fun part is corellating the height and direction to the bezier function... heh +void CG_FountainSpurt( vec3_t org, vec3_t end ) +{ + int /*i,*/ t; + vec3_t org1, org2, cpt1, cpt2; + vec3_t dir/*, dir2*/; + //vec3_t rgb = { 0.4f, 0.7f, 0.8f }; + //float distance; + //FXBezier *fxb; + localEntity_t *le; + + // offset table, could have used sin/cos, I suppose + //TiM - This was for the 4-way fountain. not needed no more + /*const float m[][2] = { + 1, 0, + 0, 1, + -1, 0, + 0, -1 };*/ + + // The origin shouldn't be in solid, otherwise the ent won't think. So, place the spawner above + // the solid object, then move the spout spawn points down to where they should be. + //org[2] -= 56; // magic number stuff + //TiM... uh O_o I think that was another thing with the 4 way fountain... won't work too well O_o + //Lessee what happens if we blatently disregard this lol + + // Create four spouts + //for ( i = 0; i < 4; i++ ) //TiM No! + //{ + //TiM - Set a direction we can use to figure out the end from the start.... >.< + //We'll need the literal direction between X + Y... Z is pretty easy to figure out + //VectorSubtract( end, org, dir ); + //distance = (dir[0] + dir[1]) * 0.5f; //so get the average + + // Move the spout out from the exact center + VectorCopy( org, org1 ); + + //TiM: No offset for now + //org1[0] += 35 * m[i][0]; + //org1[1] += 35 * m[i][1]; + + // Create our Bezier path control points + //TiM: judging from the hardcoded values, point 1 is positioned 45% units away from length, on same Z-axis + //VectorSet( cpt1, 50 * m[i][0], 50 * m[i][1], 0 ); + //VectorAdd( org1, cpt1, cpt1 ); + //VectorSet( cpt1, org1[0] + 100, org[1] + 100, 0 ); + + VectorSet( cpt1, org[0] + ( end[0] - org[0] ) * 0.65f, org[1] + ( end[1] - org[1] ) * 0.65f, org1[2] ); + //VectorAdd( org1, cpt1, cpt1 ); + + //Com_Printf("ORG = { %f, %f, %f }, CPT = { %f, %f, %f }\n", org1[0], org1[1], org1[2], cpt1[0], cpt1[1], cpt1[2] ); + + //point 2 is positioned + //TiM - point 2 I guess is the remaining 55% + //VectorSet( cpt2, 60 * m[i][0], 60 * m[i][1], -78 ); + //VectorAdd( org1, cpt2, cpt2 ); + + //VectorSet( cpt2, distance * 0.55, distance * 0.55, -Q_fabs(org1[2] - end[2]) ); + //VectorAdd( org1, cpt2, cpt2 ); + VectorCopy( end, cpt2 ); + + // Create the second endpoint--for now just try and use the last control point + VectorCopy( cpt2, org2 ); + + // Add the main spout + le = FX_AddBezier( org1, org2, cpt1, cpt2, NULL, NULL, NULL, NULL, 4, 90, + cgs.media.fountainShader); + + //if ( fxb ) + // fxb->SetSTScale( 0.7f ); + + // Add a hazy faint spout + le = FX_AddBezier( org1, org2, cpt1, cpt2, NULL, NULL, NULL, NULL, 10, 200, + cgs.media.fountainShader); + + //if ( fxb ) + // fxb->SetSTScale( 0.7f ); + + // Create misty bits at the impact point + VectorSet( dir, crandom(), crandom(), crandom() + 4 ); // always move mostly up + VectorScale( dir, random() * 3 + 2, dir ); + FX_AddSprite( org2, dir, qfalse, 20, -8, 0.3f, 0.0, 0, 0, 600, cgs.media.steamShader ); + + // ripple shader + VectorSet( dir, 0, 0, 1 ); // normal + //VectorSet( dir2, crandom() * 8, crandom() * 8, 0 ); // random drift + FX_AddQuad( org2, dir, 14.0f, 6.0f + random() * 16.0f, 0.2f, 0.0f, crandom() * 50, 800, cgs.media.rippleShader ); + + // Spray from nozzle + for ( t = 0; t < 2; t++ ) + { + //VectorSet( dir, 45 * m[i][0] + crandom() * 12, 45 * m[i][1] + crandom() * 12, crandom() * 16 ); + //VectorSet( dir2, -5 * m[i][0], -5 * m[i][1], -95 ); + VectorSet( dir, 0.4 * ( end[0] - org[0] ) + crandom() * 12, 0.4 * ( end[1] - org[1] ) + crandom() * 12, crandom() * 16 ); + //VectorSet( dir2, -0.04 * distance, -0.04 * distance, -95 ); + + FX_AddSprite( org1, dir, qtrue, 0.9f, 0.0f, 0.7f, 0.1f, 0.0f, 0.0f, 400.0f, cgs.media.waterDropShader ); + } + + // Impact splashes + for ( t = 0; t < 3; t++ ) + { + VectorCopy( org2, org1 ); + org1[0] += crandom() * 2; + org1[1] += crandom() * 2; + //VectorSet( dir, m[i][0] * 14 + crandom() * 16, m[i][1] * 14 + crandom() * 16, 50 + random() * 50 ); + VectorSet( dir, ( end[0] - org[0] ) * 0.127 + crandom() * 16, ( end[1] - org[1] ) * 0.127 + crandom() * 16, 50 + random() * 50 ); + //VectorSet( dir2, 0, 0, -250 ); + FX_AddSprite( org1, dir, qtrue, 1.1f, -0.4f, 0.7f, 0.1f, 0.0f, 0.0f, 400.0f, cgs.media.waterDropShader ); + } + //} + //Com_Printf( S_COLOR_RED "Rendering Fountain\n" ); +} + +/*================ +CG_ElectricalExplosion +=================*/ + +void smoke_puffs( vec3_t position, vec3_t dest, vec3_t dir, vec3_t user ) +{ + vec3_t direc; + + direc[0] = crandom() * 7; + direc[1] = crandom() * 7; + direc[2] = random() * 6 + 8; + + FX_AddSprite( position, direc, qfalse, 6.0f, 10.0f, 0.3f, 0.0f, 0.0f, 0.0f, 2200, cgs.media.steamShader ); +} + +//------------------------------------------------------------------------------ +void electric_spark( vec3_t pos, vec3_t normal, vec3_t dir, vec3_t user ) +{ + CG_Spark( pos, normal, 0, 10000 ); +} + +//------------------------------------------------------------------------------ +void CG_ElectricalExplosion( vec3_t start, vec3_t dir, float radius ) +{ + localEntity_t *le; + localEntity_t *particle; //FXTrail + vec3_t pos, temp/*, angles*/; + int i, numSparks; + float scale, dscale; + + // Spawn some delayed smoke + /*FX_AddSpawner( start, dir, NULL, NULL, 150, 40, qfalse, 9000, smoke_puffs ); + vectoangles( dir, angles ); + FX_AddSpawner( start, angles, NULL, NULL, 900, 800, 4000, FXF_DELAY_SPAWN, electric_spark );*/ + + // Create the sparks for the explosion + numSparks = 46 + (random() * 8.0f); + + for ( i = 0; i < numSparks; i++ ) + { + scale = 0.7f + random(); //0.2 + dscale = -scale*2; + + particle = FX_AddTrail( start, + NULL, + qfalse, + 8.0f + random() * 6, + -16.0f, + scale, + -scale, + 1.0f, + 0.0f, + 0.25f, + 700.0f, + cgs.media.spark2Shader ); + + /*if ( particle == NULL ) + return;*/ + + //FXE_Spray( dir, 200, 200, 0.3f, 500 + (rand() & 300), (FXPrimitive *) particle ); + } + + // Create some initial smoke puffs + for (i = 0; i < 12; i++) + { + VectorCopy( dir, temp ); + temp[0] += crandom() * 0.5f; + temp[1] += crandom() * 0.5f; + temp[2] += crandom() * 0.5f; + + VectorMA( start, random() * 16 + 8, temp, pos ); + VectorScale( temp, random() * 4 + 5, temp ); + + FX_AddSprite( pos, temp, qfalse, radius * 5.3f/*16.0*/, 3.0f, 1.0f, 0.0f, 0.0f, 0.0f, 2700 + random() * 600, cgs.media.steamShader ); + } + + // Now place a cool explosion model on top + VectorSubtract( cg.refdef.vieworg, start, dir ); + VectorNormalize( dir ); + + //le = CG_MakeExplosion( start, dir, cgs.media.explosionModel, 6, cgs.media.electricalExplosionSlowShader, 500, qfalse, radius * 0.01f + ( crandom() * 0.3f) ); + le = CG_MakeExplosion( start, dir, cgs.media.explosionModel, cgs.media.electricalExplosionSlowShader, 500, radius, qfalse ); + le->light = 150; + //le->refEntity. radius * 0.01f + ( crandom() * 0.3f) + + le->refEntity.renderfx |= RF_NOSHADOW; + + VectorSet( le->lightColor, 0.8f, 0.8f, 1.0f ); +} + +//RPG-X | GSIO01 | 09/05/2009: +void FX_PhaserFire2(vec3_t startpos, vec3_t endpos, vec3_t normal, qboolean impact, float scale) +{ + refEntity_t beam; + //float size; + //vec3_t velocity; + //int sparks; + vec3_t rgb = { 1,0.9,0.6}, rgb2={1,0.3,0}; + + // Draw beam first. + memset( &beam, 0, sizeof( beam ) ); + VectorCopy( startpos, beam.origin); + VectorCopy( endpos, beam.oldorigin ); + beam.reType = RT_LINE; + beam.customShader = cgs.media.phaserShader; + AxisClear( beam.axis ); + beam.shaderRGBA[0] = 0xff; + beam.shaderRGBA[1] = 0xff; + beam.shaderRGBA[2] = 0xff; + beam.shaderRGBA[3] = 0xff; + beam.data.line.width = scale + ( crandom() * 0.6f ); + beam.data.line.stscale = 5.0; + trap_R_AddRefEntityToScene( &beam ); + if (impact) + { + FX_AddQuad2( endpos, normal, (0.75f * scale) + random() * .75 + 1.0f, 0.0f, 0.5f, 0.0f, rgb, rgb2, rand() % 360, 300 + random() * 200, + cgs.media.sunnyFlareShader ); + } +} + +qboolean PhaserFX_Think(localEntity_t *le) { + vec3_t dir; + qboolean impact = qfalse; + le->data.spawner.nextthink = cg.time; + VectorSubtract(le->data.spawner.dir, le->refEntity.origin, dir); + VectorNormalize(dir); + if(le->data.spawner.data2 == 1) + impact = qtrue; + + FX_PhaserFire2(le->refEntity.origin, le->data.spawner.dir, dir, impact, le->data.spawner.data1); + + return qtrue; +} + +void CG_PhaserFX(centity_t *cent) { + localEntity_t *le; + le = FX_AddSpawner(cent->currentState.origin, cent->currentState.origin2, NULL, NULL, qfalse, 0, 0, cent->currentState.time2, PhaserFX_Think, 10); + le->data.spawner.data1 = cent->currentState.angles[0]; + le->data.spawner.data2 = cent->currentState.angles[2]; + le->data.spawner.nextthink = cg.time + (int)cent->currentState.angles[1]; +} + +qboolean TorpedoQFX_Think(localEntity_t *le) +{ + vec3_t line1end, line2end, axis[3], rgb, vel, dis; + float dist; + + VectorSubtract(le->refEntity.origin, le->addOrigin, dis); + dist = VectorLength(dis); + if(dist < 0) + dist *= -1; + if(dist < 10) + le->data.spawner.nextthink = le->endTime; + + AxisClear( axis ); + + // convert direction of travel into axis + if ( VectorNormalize2( le->data.spawner.dir, axis[0] ) == 0 ) { + axis[0][2] = 1; + } + + // spin as it moves + RotateAroundDirection( axis, cg.time * 0.3f );// * 1.25f ); + + VectorMA( le->refEntity.origin, -48.0f, axis[1], line1end ); // -24 is to high + VectorMA( le->refEntity.origin, 48.0f, axis[1], line2end ); // 24 is to high + FX_AddLine( line1end, line2end, 1.0f, random() * 18 + 2, 0.0f, 0.2 + random() * 0.2, 0.0f, 1, cgs.media.quantumGlow ); // replaced yellowParticleShader + + AxisClear( axis ); + + // convert direction of travel into axis + if ( VectorNormalize2( le->data.spawner.dir, axis[0] ) == 0 ) { + axis[0][2] = 1; + } + + // spin as it moves + RotateAroundDirection( axis, -cg.time * 0.1f );// * 1.25f ); + + VectorMA( le->refEntity.origin, 0.0f/*-128.0f*/, axis[2], line1end ); // -48 to high + VectorMA( le->refEntity.origin, 128.0f, axis[2], line2end ); // 48 to high + FX_AddLine( line1end, line2end, 1.0f, random() * 25 + 2, 0.0f, /*0.1 + random() * 0.2*/0.0f, 0.0f, 1, cgs.media.quantumGlow); + //FX_AddSprite(line1end, NULL, qfalse, random() * 90 + 30, 4, 1.0f, 0.0f, 0, 0.0f, 1.0f, cgs.media.photonStar); + + VectorSet( rgb, 1.0f, 0.45f, 0.15f ); // orange + + FX_AddSprite( le->refEntity.origin, NULL,qfalse,random() * 60 + 30, 4, 0.5f, 0.0f, 0, 0.0f, 1.0f, cgs.media.quantumRays); + //FX_AddSprite2(le->refEntity.origin, NULL,qfalse,random() * 10 + 60, 0.0f, 0.1f, 0.1f, rgb, rgb, 0.0f, 0.0f, 1, cgs.media.whiteRingShader); + FX_AddSprite( le->refEntity.origin, NULL,qfalse,random() * 40 + 8, 4, 0.5f, 0.0f, 0, 0.0f, 1.0f, cgs.media.quantumGlow ); + + VectorCopy(le->data.spawner.dir, vel); + VectorNormalize(vel); + VectorScale(vel, le->refEntity.oldorigin[0], vel); + VectorAdd(le->refEntity.origin, vel, le->refEntity.origin); + //le->data.spawner.nextthink = cg.time + 100; + + return qtrue; +} + +qboolean TorpedoPFX_Think(localEntity_t *le) +{ + vec3_t line1end, line2end, axis[3], rgb, vel, dis; + float dist; + + VectorSubtract(le->refEntity.origin, le->addOrigin, dis); + dist = VectorLength(dis); + if(dist < 0) + dist *= -1; + if(dist < 10) + le->data.spawner.nextthink = le->endTime; + + AxisClear( axis ); + + // convert direction of travel into axis + if ( VectorNormalize2( le->data.spawner.dir, axis[0] ) == 0 ) { + axis[0][2] = 1; + } + + // spin as it moves + RotateAroundDirection( axis, cg.time * 0.3f );// * 1.25f ); + + VectorMA( le->refEntity.origin, -48.0f, axis[1], line1end ); // -24 is to high + VectorMA( le->refEntity.origin, 48.0f, axis[1], line2end ); // 24 is to high + FX_AddLine( line1end, line2end, 1.0f, random() * 18 + 2, 0.0f, 0.2 + random() * 0.2, 0.0f, 1, cgs.media.photonGlow ); // replaced yellowParticleShader + + AxisClear( axis ); + + // convert direction of travel into axis + if ( VectorNormalize2( le->data.spawner.dir, axis[0] ) == 0 ) { + axis[0][2] = 1; + } + + // spin as it moves + RotateAroundDirection( axis, -cg.time * 0.1f );// * 1.25f ); + + VectorMA( le->refEntity.origin, 0.0f/*-128.0f*/, axis[2], line1end ); // -48 to high + VectorMA( le->refEntity.origin, 128.0f, axis[2], line2end ); // 48 to high + FX_AddLine( line1end, line2end, 1.0f, random() * 25 + 2, 0.0f, /*0.1 + random() * 0.2*/0.0f, 0.0f, 1, cgs.media.photonGlow); + //FX_AddSprite(line1end, NULL, qfalse, random() * 90 + 30, 4, 1.0f, 0.0f, 0, 0.0f, 1.0f, cgs.media.photonStar); + + VectorSet( rgb, 1.0f, 0.45f, 0.15f ); // orange + + FX_AddSprite( le->refEntity.origin, NULL,qfalse,random() * 60 + 30, 4, 0.5f, 0.0f, 0, 0.0f, 1.0f, cgs.media.photonRay); + //FX_AddSprite2(le->refEntity.origin, NULL,qfalse,random() * 10 + 60, 0.0f, 0.1f, 0.1f, rgb, rgb, 0.0f, 0.0f, 1, cgs.media.whiteRingShader); + FX_AddSprite( le->refEntity.origin, NULL,qfalse,random() * 40 + 8, 4, 0.5f, 0.0f, 0, 0.0f, 1.0f, cgs.media.photonGlow ); + + VectorCopy(le->data.spawner.dir, vel); + VectorNormalize(vel); + VectorScale(vel, le->refEntity.oldorigin[0], vel); + VectorAdd(le->refEntity.origin, vel, le->refEntity.origin); + //le->data.spawner.nextthink = cg.time + 100; + + return qtrue; +} + +void CG_TorpedoFX(centity_t *cent) { + localEntity_t *le; + if(cent->currentState.eventParm & 1) { // quantum fx + le = FX_AddSpawner(cent->currentState.origin, cent->currentState.angles, NULL, NULL, qfalse, 0, 0, 10000, TorpedoQFX_Think, 10); + } else { // photon fx + le = FX_AddSpawner(cent->currentState.origin, cent->currentState.angles, NULL, NULL, qfalse, 0, 0, 10000, TorpedoPFX_Think, 10); + } + le->refEntity.oldorigin[0] = cent->currentState.angles2[0]; + VectorCopy(cent->currentState.origin2, le->addOrigin); +} + +qboolean ParitcleFire_CreateParticles(localEntity_t *le) { + + return qtrue; +} + +qboolean ParticleFire_Think(localEntity_t *le) { + vec3_t velocity; + vec3_t origin; + vec3_t dir = { 0, 0 , 15 }; + float speed; + int i; + vec3_t startRGB = { 1, 0.2, 0 }; + vec3_t endRGB = { 1, 0.9, 0.7 }; + + dir[2] = Com_Clamp( 0.85f, 1.0f, dir[2] ); + + for ( i = 0; i < 3; i++ ) + { + velocity[i] = dir[i] + ( 0.2f * crandom()); + } + + VectorMA( le->refEntity.origin, 1, le->data.spawner.dir, origin); + + speed = le->data.spawner.data1 * 2.4; + + VectorScale( velocity, speed, velocity ); //speed + + FX_AddSprite2( origin, + velocity, + qfalse, //accel + le->data.spawner.data1 + (flrandom(0.4,2) * le->data.spawner.data1 ), + le->data.spawner.data1 + (crandom() * le->data.spawner.data1 * 0.5f), + 0.8, + 0.0, + startRGB, + endRGB, + 0.1f,//16.0f + random() * 45.0f, + 0.1f, + 3500, + cgs.media.fireParticle ); //flags + + le->data.spawner.nextthink = cg.time + 750; // don't generate to many or we will get low fps + + return qtrue; +} + +void CG_ParticleFire(vec3_t origin, int killtime, int size) { + localEntity_t *le; + le = FX_AddSpawner(origin, NULL, NULL, NULL, qfalse, 0, 0, killtime, ParticleFire_Think, 10); + //le->data.spawner.data1 = size; +} + +qboolean ShowTrigger_Think(localEntity_t *le) { + vec4_t RGBA = { 0, 1, 0, 0.75 }; + vec3_t a, b, c, d; + + VectorCopy(le->refEntity.lightingOrigin, a); + c[0] = b[0] = le->lightColor[0]; + c[2] = d[2] = le->lightColor[2]; + b[1] = c[1] = d[1] = a[1]; + d[0] = a[0]; + b[2] = a[2]; + + FX_AddLine2(a, b, 0.5, 0.5, 0, 0.5, 0, 1, 1, RGBA, RGBA, 10000, cgs.media.whiteShader); + FX_AddLine2(b, c, 0.5, 0.5, 0, 0.5, 0, 1, 1, RGBA, RGBA, 10000, cgs.media.whiteShader); + FX_AddLine2(c, d, 0.5, 0.5, 0, 0.5, 0, 1, 1, RGBA, RGBA, 10000, cgs.media.whiteShader); + FX_AddLine2(d, a, 0.5, 0.5, 0, 0.5, 0, 1, 1, RGBA, RGBA, 10000, cgs.media.whiteShader); + + return qtrue; +} + +qboolean ShowTrigger_Think2(localEntity_t *le) { + vec4_t RGBA = { 0, 1, 0, 0.75 }; + vec3_t e, f, g, h; + + VectorCopy(le->lightColor, g); + h[0] = f[0] = le->refEntity.lightingOrigin[0]; + f[2] = e[2] = le->refEntity.lightingOrigin[2]; + e[1] = f[1] = h[1] = g[1]; + e[0] = g[0]; + h[2] = g[2]; + + FX_AddLine2(f, e, 0.5, 0.5, 0, 0.5, 0, 1, 1, RGBA, RGBA, 10000, cgs.media.whiteShader); + FX_AddLine2(e, g, 0.5, 0.5, 0, 0.5, 0, 1, 1, RGBA, RGBA, 10000, cgs.media.whiteShader); + FX_AddLine2(g, h, 0.5, 0.5, 0, 0.5, 0, 1, 1, RGBA, RGBA, 10000, cgs.media.whiteShader); + FX_AddLine2(h, f, 0.5, 0.5, 0, 0.5, 0, 1, 1, RGBA, RGBA, 10000, cgs.media.whiteShader); + + return qtrue; +} + +qboolean ShowTrigger_Think3(localEntity_t *le) { + vec4_t RGBA = { 0, 1, 0, 0.75 }; + vec3_t a, b, c, d, e, f, g, h; + + VectorCopy(le->refEntity.lightingOrigin, a); + VectorCopy(le->lightColor, g); + d[0] = f[0] = h[0] = a[0]; + b[0] = c[0] = e[0] = g[0]; + e[1] = f[1] = h[1] = g[1]; + b[1] = c[1] = d[1] = a[1]; + b[2] = f[2] = e[2] = a[2]; + h[2] = d[2] = c[2] = g[2]; + + FX_AddLine2(a, f, 0.5, 0.5, 0, 0.5, 0, 1, 1, RGBA, RGBA, 10000, cgs.media.whiteShader); + FX_AddLine2(d, h, 0.5, 0.5, 0, 0.5, 0, 1, 1, RGBA, RGBA, 10000, cgs.media.whiteShader); + FX_AddLine2(b, e, 0.5, 0.5, 0, 0.5, 0, 1, 1, RGBA, RGBA, 10000, cgs.media.whiteShader); + FX_AddLine2(c, g, 0.5, 0.5, 0, 0.5, 0, 1, 1, RGBA, RGBA, 10000, cgs.media.whiteShader); + + return qtrue; +} + +void CG_ShowTrigger(centity_t *cent) { + localEntity_t *le; + if(cent->currentState.eventParm) { + le = FX_AddSpawner(cent->currentState.origin, NULL, NULL, NULL, qfalse, 0, 0, 10000, ShowTrigger_Think, 0); + VectorCopy(cent->currentState.apos.trBase, le->lightColor); + VectorCopy(cent->currentState.pos.trBase, le->refEntity.lightingOrigin); + le = FX_AddSpawner(cent->currentState.origin, NULL, NULL, NULL, qfalse, 0, 0, 10000, ShowTrigger_Think2, 0); + VectorCopy(cent->currentState.apos.trBase, le->lightColor); + VectorCopy(cent->currentState.pos.trBase, le->refEntity.lightingOrigin); + le = FX_AddSpawner(cent->currentState.origin, NULL, NULL, NULL, qfalse, 0, 0, 10000, ShowTrigger_Think3, 0); + VectorCopy(cent->currentState.apos.trBase, le->lightColor); + VectorCopy(cent->currentState.pos.trBase, le->refEntity.lightingOrigin); + } else { + le = FX_AddSpawner(cent->currentState.origin, NULL, NULL, NULL, qfalse, 0, 0, 10000, ShowTrigger_Think, 0); + VectorCopy(cent->currentState.origin2, le->lightColor); + VectorCopy(cent->currentState.angles2, le->refEntity.lightingOrigin); + le = FX_AddSpawner(cent->currentState.origin, NULL, NULL, NULL, qfalse, 0, 0, 10000, ShowTrigger_Think2, 0); + VectorCopy(cent->currentState.origin2, le->lightColor); + VectorCopy(cent->currentState.angles2, le->refEntity.lightingOrigin); + le = FX_AddSpawner(cent->currentState.origin, NULL, NULL, NULL, qfalse, 0, 0, 10000, ShowTrigger_Think3, 0); + VectorCopy(cent->currentState.origin2, le->lightColor); + VectorCopy(cent->currentState.angles2, le->refEntity.lightingOrigin); + } +} + +//RPG-X | Harry Young | 03.12.2011 +void FX_DisruptorFire2(vec3_t startpos, vec3_t endpos, vec3_t normal, qboolean impact, float scale) +{ + refEntity_t beam; + //float size; + //vec3_t velocity; + //int sparks; + vec3_t rgb = { 1,0.9,0.6}, rgb2={1,0.3,0}; + + // Draw beam first. + memset( &beam, 0, sizeof( beam ) ); + VectorCopy( startpos, beam.origin); + VectorCopy( endpos, beam.oldorigin ); + beam.reType = RT_LINE; + beam.customShader = cgs.media.disruptorBeam; + AxisClear( beam.axis ); + beam.shaderRGBA[0] = 0xff; + beam.shaderRGBA[1] = 0xff; + beam.shaderRGBA[2] = 0xff; + beam.shaderRGBA[3] = 0xff; + beam.data.line.width = scale + ( crandom() * 0.6f ); + beam.data.line.stscale = 5.0; + trap_R_AddRefEntityToScene( &beam ); + if (impact) + { + FX_AddQuad2( endpos, normal, (0.75f * scale) + random() * .75 + 1.0f, 0.0f, 0.5f, 0.0f, rgb, rgb2, rand() % 360, 300 + random() * 200, + cgs.media.disruptorStreak ); + } +} + +qboolean DisruptorFX_Think(localEntity_t *le) { + vec3_t dir; + qboolean impact = qfalse; + le->data.spawner.nextthink = cg.time; + VectorSubtract(le->data.spawner.dir, le->refEntity.origin, dir); + VectorNormalize(dir); + if(le->data.spawner.data2 == 1) + impact = qtrue; + + FX_DisruptorFire2(le->refEntity.origin, le->data.spawner.dir, dir, impact, le->data.spawner.data1); + + return qtrue; +} + +void CG_DisruptorFX(centity_t *cent) { + localEntity_t *le; + le = FX_AddSpawner(cent->currentState.origin, cent->currentState.origin2, NULL, NULL, qfalse, 0, 0, cent->currentState.time2, DisruptorFX_Think, 10); + le->data.spawner.data1 = cent->currentState.angles[0]; + le->data.spawner.data2 = cent->currentState.angles[2]; + le->data.spawner.nextthink = cg.time + (int)cent->currentState.angles[1]; +} + +// Additional ports from SP by Harry Young + +/* +=========================== +Laser + +Create directed laser shot +=========================== +*/ +void CG_SmallSpark( vec3_t origin, vec3_t normal ) +{ + vec3_t dir, direction, start, end, velocity; + float scale; + int numSparks; + + AngleVectors( normal, normal, NULL, NULL ); + + int j; + for ( j = 0; j < 3; j ++ ) + normal[j] = normal[j] + (0.1f * crandom()); + + VectorNormalize( normal ); + + numSparks = 6 + (random() * 4.0f ); + + int i; + for ( i = 0; i < numSparks; i++ ) + { + scale = 0.1f + (random() *0.2f ); + + for ( j = 0; j < 3; j ++ ) + dir[j] = normal[j] + (0.7f * crandom()); + + VectorMA( origin, 0.0f + ( random() * 0.5f ), dir, start ); + VectorMA( start, 1.0f + ( random() * 1.5f ), dir, end ); + + FX_AddLine( start, + end, + 1.0f, + scale, + 0.0f, + 1.0f, + 0.7f, + 4.0f, + cgs.media.sparkShader ); + } + + VectorMA( origin, 1, normal, direction ); + + scale = 2.0f + (random() * 3.0f ); + float alpha = 0.6f + (random() * 0.4f ); + + VectorSet( velocity, crandom() * 2, crandom() * 2, 8 + random() * 4 ); + VectorMA( velocity, 5, normal, velocity ); + + FX_AddSprite( direction, + velocity, + qfalse, + scale, + scale, + alpha, + 0.0f, + random() * 45.0f, + 0.0f, + 1000.0f, + cgs.media.steamShader ); +} + + +void CG_FireLaser( vec3_t start, vec3_t end, vec3_t normal, vec3_t laserRGB, float alpha ) +{ + vec3_t dir, right, up, angles, work, pos, + sRGB; + float scale = 1.0f; + int life = 0; + + // Orient the laser spray + VectorSubtract( end, start, dir ); + VectorNormalize( dir ); + + VectorMA( end, 0.5f, normal, pos ); + MakeNormalVectors( normal, right, up ); + + VectorSet( sRGB, 1.0f, 0.8f, 0.8f ); + + FX_AddSprite2( start, NULL, qfalse, + 1.75f, 1.0f, + alpha, 0.0f, + laserRGB, laserRGB, + 0.0f, + 0.0f, + 200, + cgs.media.waterDropShader ); + + FX_AddLine3( start, end, + 1.0f, + 3.0f, 5.0f, + alpha, 0.0f, + laserRGB, laserRGB, + 125, + cgs.media.whiteLaserShader ); + + FX_AddLine( start, end, + 1.0f, + 0.3f, 5.0f, + random() * 0.4 + 0.4, 0.1f, + 125, + cgs.media.whiteLaserShader ); + + // Doing all of this extra stuff would look weird if it hits a player ent. + //if ( !hit_ent ) + //{ + FX_AddQuad2( pos, normal, + 3.5f, 1.0f, + alpha, 0.0f, + laserRGB, laserRGB, + 0.0f, + 200, + cgs.media.waterDropShader ); + int t; + for ( t=0; t < 2; t ++ ) + { + VectorMA( pos, crandom() * 0.5f, right, work ); + VectorMA( work, crandom() * 0.5f, up, work ); + + scale = crandom() * 0.5f + 1.75f; + life = crandom() * 300 + 2100; + + VectorSet( sRGB, 1.0f, 0.7f, 0.2f ); + FX_AddQuad2( work, normal, + scale, -0.1f, + 1.0f, 0.0f, + sRGB, sRGB, + 0, + life, + cgs.media.waterDropShader ); + } + + FX_AddQuad( pos, normal, + scale * 2.5f, 0.0f, + 1.0f, 0.0f, + 0, + life * 2, + cgs.media.smokeShader ); + + vectoangles( normal, angles ); + CG_SmallSpark( end, angles ); + /*} + else + { + // However, do add a little smoke puff + FX_AddSprite2( pos, NULL, qfalse, + 2.0f, 1.0f, + alpha, 0.0f, + laserRGB, laserRGB, + 0.0f, + 0.0f, + 200, + cgs.media.waterDropShader ); + + VectorMA( end, 1, normal, dir ); + scale = 1.0f + (random() * 3.0f); + + CG_Smoke( dir, normal, scale, 12.0f ); + }*/ +} + +//------------------------------------------------------------------------------ +void CG_AimLaser( vec3_t start, vec3_t end, vec3_t normal ) +{ + vec3_t lRGB = {1.0,0.0,0.0}; + + // Beam + FX_AddLine3( start, end, + 1.0f, + 5.5f, 5.0f, + random() * 0.2 + 0.2, 0.1f, + lRGB, lRGB, + 150, + cgs.media.whiteLaserShader ); + + FX_AddLine( start, end, + 1.0f, + 0.3f, 5.0f, + random() * 0.4 + 0.4, 0.1f, + 125, + cgs.media.whiteLaserShader ); + + // Flare at the start point + FX_AddSprite( start, NULL, qfalse, + 1.5 + random() * 4, 0.0, + 0.1f,0.0, + 0.0, + 0.0, + 100, + cgs.media.borgEyeFlareShader ); + + // endpoint flare + FX_AddSprite( end, NULL, qfalse, + 2.5 + random() * 4, 0.0, + 0.1f,0.0, + 0.0, + 0.0, + 100, + cgs.media.borgEyeFlareShader ); + + // oriented impact flare + FX_AddQuad( end, normal, + 1.5 + random() * 2, 0.0, + 1.0, 0.0, + 0.0, + 120, + cgs.media.borgEyeFlareShader ); +} + +/* +====================== +CG_CookingSteam + +Creates a basic cooking steam effect +====================== +*/ +void CG_CookingSteam( vec3_t origin, float radius ) +{ + vec3_t dir; + + VectorSet( dir, crandom()*2, crandom()*2, crandom() + radius); // always move mostly up + VectorScale( dir, random() * 5 + 2, dir ); + + FX_AddSprite( origin, dir, qfalse, radius, radius * 2, 0.4F, 0.0, 0, 0, 1000, cgs.media.steamShader ); +} + +/* +====================== +CG_ElectricFire + +Creates an electric fire effect +====================== +*/ + +void CG_ElectricFire( vec3_t origin, vec3_t normal ) +{ + void *particle; + vec3_t dir, direction, start, end; + vec3_t velocity; + float scale, alpha; + int numSparks, i, j; + + AngleVectors( normal, normal, NULL, NULL); + + numSparks = 4 + (random() * 8.0f); + + for ( i = 0; i < numSparks; i++ ) + { + scale = 0.3f + (random() *0.4); + + for ( j = 0; j < 3; j ++ ) + dir[j] = normal[j] + (0.4f * crandom()); + + VectorNormalize(dir); + + VectorMA( origin, -1.0f + ( random() * 2.0f ), dir, start ); + VectorMA( start, 2.0f + ( random() * 12.0f ), dir, end ); + + FX_AddLine( start, + end, + 1.0f, + scale, + 0.0f, + 1.0f, + 0.0f, + 75.0f, + cgs.media.sparkShader ); + } + + scale = 0.5f + (random() * 0.5f); + + VectorScale( normal, 300, velocity ); + + particle = FX_AddTrail( start, + velocity, + qtrue, + 6.0f, + -24.0f, + scale, + -scale, + 1.0f, + 0.5f, + 0.0f, + 200.0f, + cgs.media.sparkShader); + + if ( particle == NULL ) + return; + + VectorMA( origin, 1, normal, direction ); + VectorSet( velocity, 0, 0, 8 ); + + FXE_Spray( dir, 200, 200, 0.2f, velocity); + + VectorMA( origin, 1, normal, direction ); + VectorSet( velocity, 0, 0, 8 ); + + for ( i = 0; i < 3; i++) + { + scale = 6.0f + (random() * 8.0f); + alpha = 0.1 + (random() * 0.4f); + + FX_AddSprite( direction, + velocity, + qfalse, + scale, + scale, + alpha, + 0.0, + random()*45.0f, + 0.0f, + 1000.0f, + cgs.media.steamShader ); + + VectorMA( velocity, 9.0, normal, velocity); + } +} + +/* +====================== +CG_ForgeBolt + +Creates an orange electricity bolt effect with a pulse that travels down the beam +====================== +*/ + +/*void ForgeBoltFireback( vec3_t start, vec3_t end, vec3_t velocity, vec3_t user ) +{ + FX_AddElectricity( start, end, 1.0, user[DATA_RADIUS], 5.0, 1.0, 0.0, 200, cgs.media.pjBoltShader, + (int)user[DATA_EFFECTS], user[DATA_CHAOS] ); +} + +//--------------------------------------------------- +bool ForgeBoltPulse( FXPrimitive *fx, centity_t *ent ) +{ + vec3_t origin, new_org; + trace_t trace; + qboolean remove = qfalse; + + VectorCopy( fx->m_origin, origin ); + fx->UpdateOrigin(); + VectorCopy( fx->m_origin, new_org ); + + CG_Trace( &trace, origin, NULL, NULL, new_org, -1, CONTENTS_SOLID ); + + if ( trace.fraction < 1.0f && !trace.startsolid && !trace.allsolid ) + { + // The effect hit something, presumably a barrier, so kill it + remove = qtrue; + return false; + } + + vec3_t normal, rgb1 ={ 1.0F, 0.5F, 0.4F}, rgb2 ={ 1.0F, 1.0F, 0.3F};//, org; + FXCylinder *fxc; + + // Convert the direction of travel in to a normal; + VectorCopy( fx->m_velocity, normal ); + VectorNormalize( normal ); + VectorScale( normal, -1, normal ); + + fxc = FX_AddCylinder( new_org, normal, 16, 0, 16 - random() * 8, 0, 32 + random() * 24, 0, 0.2F, 0.2F, rgb1, rgb1, 1, cgs.media.psychicShader, 0.6F ); + + if ( fxc == NULL ) + return false; + + fxc->SetFlags( FXF_WRAP ); + fxc->SetSTScale( Q_irand(1,3) ); + + fxc = FX_AddCylinder( new_org, normal, 8, 0, 12 - random() * 8, 0, 24 + random() * 24, 0, 0.2F, 0.2F, rgb2, rgb2, 1, cgs.media.psychicShader, 0.6F ); + + if ( fxc == NULL ) + return false; + + fxc->SetFlags( FXF_WRAP ); + fxc->SetSTScale( Q_irand(1,2) ); + + return true; +} + +//----------------------------- +/*void CG_ForgeBolt( centity_t *cent ) +{ + qboolean pulse; + int effects; + float chaos, radius; + + // Set up all of the parms + pulse = (cent->gent->spawnflags & 8) ? qtrue : qfalse; + effects = (cent->gent->spawnflags & 16) ? FXF_TAPER : 0; + effects = (cent->gent->spawnflags & 32) ? (FXF_WRAP | effects) : effects; + chaos = cent->gent->random; + radius = cent->gent->radius; + + // Delayed bolt that should "work" a while + if ( cent->gent->spawnflags & 2 ) + { + vec3_t data; + + // This sucks, but the spawn function needs some extra bits of info + data[DATA_EFFECTS] = effects; + data[DATA_CHAOS] = chaos; + data[DATA_RADIUS] = radius; + + FX_AddSpawner( cent->lerpOrigin, cent->currentState.origin2, NULL, data, 70, random() * 25, 450, (void *) ForgeBoltFireback ); + } + else + { + FX_AddElectricity( cent->lerpOrigin, cent->currentState.origin2, 1.0, radius, 5.0, 1.0, 0.0, 200, cgs.media.pjBoltShader, + effects, chaos ); + + if ( rand() & 1 ) + FX_AddElectricity( cent->currentState.origin2, cent->lerpOrigin, 1.0, radius * 2, 5.0, 1.0, 0.0, 200, cgs.media.pjBoltShader, + effects, chaos ); + + if ( cg.time > cent->gent->delay && pulse ) + { + vec3_t dir; + float amt; + + VectorSubtract( cent->currentState.origin2, cent->lerpOrigin, dir ); + VectorNormalize( dir ); + amt = 200 + random() * 100; + VectorScale( dir, amt, dir ); + + FX_AddParticle( cent, cent->lerpOrigin, dir, NULL, 16, 0.0, 1.0, 1.0, + 0.0, 0.0, 6000, cgs.media.ltblueParticleShader, FXF_NODRAW, ForgeBoltPulse ); + + cent->gent->delay = cg.time + 500; + } + } + + // Bolt that generates sparks at the impact point + if ( cent->gent->spawnflags & 4 ) + { + vec3_t dir; + + VectorSubtract( cent->lerpOrigin, cent->currentState.origin2, dir ); + VectorNormalize( dir ); + + BoltSparkSpew( cent->currentState.origin2, dir, cgs.media.dkorangeParticleShader ); + } +} + +/* +=========================== +Plasma + +Create directed and scaled plasma jet +=========================== +*/ + +void CG_Plasma( vec3_t start, vec3_t end, vec3_t sRGB, vec3_t eRGB, int startalpha, int endalpha ) +{ + vec3_t v, sp; + float detail, len, salpha = (startalpha / 255) , ealpha = (endalpha / 255); + + //detail = FX_DetailLevel( start, 16, 1200 ); + //if ( detail == 0 ) + // return; + + // Orient the plasma + VectorSubtract( end, start, v ); + len = VectorNormalize( v ); + VectorMA( start, 0.5f, v, sp ); + + // Stash a quad at the base to make the effect look a bit more solid + //FX_AddQuad( sp, v, NULL, NULL, len * 0.36f, 0.0f, salpha, salpha, sRGB, sRGB, 0.0f, 45.0f, 0.0f, 200, cgs.media.prifleImpactShader ); + + // Add a subtle, random flutter to the cone direction + v[0] += crandom() * 0.04; + v[1] += crandom() * 0.04; + v[2] += crandom() * 0.04; + + // Wanted the effect to be scalable based on the length of the jet. + FX_AddCylinder2( start, v, len * 0.05, len * 2.0f, len * 0.16f, len * 0.32f, len * 0.40f, len * 0.64f, + salpha, ealpha, sRGB, eRGB, 200, cgs.media.plasmaShader, 0.3f ); + FX_AddCylinder2( start, v, len * 0.05, len * 4.0f, len * 0.16f, len * 0.32f, len * 0.28f, len * 0.64f, + salpha, ealpha, sRGB, eRGB, 200, cgs.media.plasmaShader, 0.2f ); + FX_AddCylinder2( start, v, len * 0.25, len * 8.0f, len * 0.20f, len * 0.32f, len * 0.02f, len * 0.32f, + salpha, ealpha, sRGB, eRGB, 200, cgs.media.plasmaShader, 0.1f ); +} + +/* +====================== +CG_ParticleStream + +particle stream fx for STASIS level +====================== +*/ + +/*bool particle_stream_think( FXPrimitive *fx, centity_t *ent ) +{ + vec3_t old_org; + + // Make it flicker. . .always safe to do this + fx->m_scale = random() * 12 + 2; + fx->m_alpha = random() * 0.4 + 0.6; + + // If the ent was somehow removed, we don't want to continue any further. + if ( !ent ) + return false; + + // Stash the old position so that we can draw a trailer line + VectorCopy( fx->m_origin, old_org ); + + // Update the position of the particle. + fx->m_origin[0] = cos(cg.time * 0.01 + fx->m_velocity[0]) * fx->m_velocity[1] + ent->lerpOrigin[0]; + fx->m_origin[1] = sin(cg.time * 0.01 + fx->m_velocity[0]) * fx->m_velocity[1] + ent->lerpOrigin[1]; + fx->m_origin[2] += (fx->m_velocity[2] * cg.frametime * 0.001); + + FX_AddLine( fx->m_origin, old_org, 1.0f, 2.0f, -4.0f, 0.6f, 0.0, 500, cgs.media.IMOD2Shader ); + + return true; +} + +//------------------------------------------------------------------------------ +void CG_ParticleStream( centity_t *cent ) +{ + vec3_t vel, org, dir; + float len, time; + + // This effect will currently only travel directly up or down--never sideways + VectorSubtract( cent->currentState.origin2, cent->lerpOrigin, dir ); + len = VectorNormalize( dir ); + + // since the movement direction is limited, use the velocity var a bit more efficiently + vel[0] = random() * 360; // random position around the cylinder + vel[1] = random() > 0.9 ? 20 : 6; // random radius + vel[2] = dir[2] * 120 + dir[2] * random() * 50; // random velocity (up or down) + + // Set the particle position + org[0] = cos(cg.time * 0.01 + vel[0]) * vel[1] + cent->lerpOrigin[0]; + org[1] = sin(cg.time * 0.01 + vel[0]) * vel[1] + cent->lerpOrigin[1]; + org[2] = cent->lerpOrigin[2]; + + // Calculate how long the thing should live based on it's velocity and the distance it has to travel + time = len / vel[2] * 1000; + + // Use a couple of different kinds to break up the monotony + if ( rand() & 1 ) + { + FX_AddParticle( cent, org, vel, NULL, 16, 0.0, 1.0, 1.0, + 0.0, 0.0, time, cgs.media.ltblueParticleShader, 0, particle_stream_think ); + } + else + { + FX_AddParticle( cent, org, vel, NULL, 16, 0.0, 1.0, 1.0, + 0.0, 0.0, time, cgs.media.purpleParticleShader, 0, particle_stream_think ); + } +} + +/* +====================== +CG_TransporterStream + +particle stream fx for forge level +The particles will accelerate up to the half-way point of the cylinder, then deccelerate til they hit their target +====================== +*/ + +/*void CG_TransporterStream( centity_t *cent ) +{ + vec3_t vel, accel, dir, pos, right, up; + float len, time, acceleration, scale, dis, vf; + int t; + VectorSubtract( cent->currentState.origin2, cent->lerpOrigin, dir ); + len = VectorNormalize( dir ); + MakeNormalVectors( dir, right, up ); + + for ( t=0; t < 3; t++ ) + { + // Create start offset within a circular radius + VectorMA( cent->lerpOrigin, 8 * crandom(), right, pos ); + VectorMA( pos, 8 * crandom(), up, pos ); + + acceleration = 80 + random() * 50; + VectorScale( dir, acceleration, accel ); // acceleration vector + VectorScale( dir, 0.0001, vel ); // Ideally, vel would be zero, so just make it really small + + dis = ( len * 0.8f ); // the two segs will be overlapping to cover up the middle + + // This is derived from dis = (vi)(t) + (1/2)(a)(t)^2 where the inital velocity (vi) = zero + time = sqrt( 2 / acceleration * dis ); // Calculate how long the thing will take to travel that distance + + scale = 1.5f + random() * 4; + + // These will spawn at the base and accelerate towards the middle + if ( rand() & 1 ) + { + FX_AddSprite3( pos, vel, accel, + scale, 0.0f, + 1.0f, 0.0f, + 0.0f, + 0.0f, + time * 1000, + cgs.media.orangeParticleShader ); + } + else + { + FX_AddSprite3( pos, vel, accel, + scale, 0.0f, + 1.0f, 0.0f, + 0.0f, + 0.0f, + time * 1000, + cgs.media.dkorangeParticleShader ); + } + + // These will be spawned somewhere in the middle and deccelerate till they reach the end of their target + VectorMA( pos, len - dis, dir, pos ); + VectorScale( accel, -1, accel ); + + vf = sqrt( 2 * dis * acceleration ); // calculate the how fast it would be moving at the end of its path + VectorScale( dir, vf, vel ); // this will be the _initial_ velocity for those starting in the middle + + if ( rand() & 1 ) + { + FX_AddSprite3( pos, vel, accel, + scale, 0.0f, + 0.0f, 1.0f, + 0.0f, + 0.0f, + time * 1000, + cgs.media.orangeParticleShader ); + } + else + { + FX_AddSprite3( pos, vel, accel, + scale, 0.0f, + 0.0f, 1.0f, + 0.0f, + 0.0f, + time * 1000, + cgs.media.dkorangeParticleShader ); + } + } +} + +/* +------------------------- +CG_ExplosionTrail +------------------------- +*/ + +/*qboolean explosionTrailThink( localEntity_t *fx ) +{ + localEntity_t *le=0; + vec3_t direction, origin, new_org, angles, dir; + trace_t trace; + float scale; + int i; + qboolean remove = qfalse; + + VectorCopy( fx->m_origin, origin ); + fx->UpdateOrigin(); + VectorCopy( fx->m_origin, new_org ); + + CG_Trace( &trace, origin, NULL, NULL, new_org, -1, CONTENTS_SOLID ); + + if ( trace.fraction < 1.0f && !trace.startsolid && !trace.allsolid ) + { + // The effect hit something, presumably a barrier, so kill it + // When the effect gets killed like this, it dies quickly and looks a bit thin. + // Maybe something else should be done as well... + remove = qtrue; + //FIXME: FX_RemoveEffect( fx ); + return qfalse; + } + + scale = 80 * 0.03f; + + VectorSubtract( new_org, origin, dir ); + VectorNormalize( dir ); + vectoangles( dir, angles ); + + //Orient the explosions to face the camera + VectorSubtract( cg.refdef.vieworg, origin, direction ); + VectorNormalize( direction ); + + for ( i = 0; i < 3 + (int)remove * 6; i++) + { + angles[2] = crandom() * 360; + + AngleVectors( angles, NULL, dir, NULL ); + VectorMA( origin, random() * 50.0f, dir, new_org ); + + le = CG_MakeExplosion( new_org, direction, cgs.media.explosionModel, 6, cgs.media.surfaceExplosionShader, 400 + (int)remove * 800, qfalse, random() * 1.0 + 0.8 );//random() * 1.0 + 1.0 ); + } + + le->light = 150; + VectorSet( le->lightColor, 64, 192, 255 ); + + //Shake the camera and damage everything in an area + CG_ExplosionEffects( origin, 3.0f, 600 ); + G_RadiusDamage( origin, ent->gent, 150, 80, NULL, MOD_UNKNOWN ); + + return qtrue; +} + +//------------------------------------------------------------------------------ +void CG_ExplosionTrail( centity_t *cent ) +{ + vec3_t dir; + float len; + + VectorSubtract( cent->currentState.origin2, cent->currentState.origin, dir ); + len = VectorNormalize( dir ); + VectorScale( dir, 325, dir ); + + FX_AddParticle( cent->currentState.origin, dir, qfalse, 16, 0.0, 1.0, 1.0, + 0.0, 0.0, 6000, cgs.media.ltblueParticleShader, explosionTrailThink ); +} + +/* +---------------------- +CG_BorgEnergyBeam + +A scanning type beam +---------------------- +*/ + +/*void CG_BorgEnergyBeam( centity_t *cent ) +{ + vec3_t normal, angles, base, dir, dir2, rgb; + float len, alpha; + + VectorSubtract( cent->currentState.origin2, cent->lerpOrigin, normal ); + len = VectorNormalize( normal ); + vectoangles( normal, angles ); + alpha = Vector4to3( cent->gent->startRGBA, rgb ); + + // Code to make the thing "snap" when it's doing the beam slices + if ( abs( cent->gent->pos2[0] ) >= cent->gent->radius ) + { + // Snap back to start and move to the next slice + cent->gent->pos2[0] = cent->gent->radius; + cent->gent->pos2[1] -= ( cg.frametime * 0.0003 * cent->gent->speed ); + } + + // The slice has moved past the end so snap back to the first slice position + if ( abs( cent->gent->pos2[1] ) >= cent->gent->radius ) + { + cent->gent->pos2[1] = cent->gent->radius; + } + + // Always move across the slice + cent->gent->pos2[0] -= ( cg.frametime * 0.001 * cent->gent->speed ); + + + if ( cent->gent->spawnflags & 2 ) + { + // Trace a cone + angles[2] = cent->gent->angle; + } + + AngleVectors( angles, NULL, dir, dir2 ); + + if ( cent->gent->spawnflags & 2 ) + { + // Cone + VectorMA( cent->currentState.origin2, cent->gent->radius, dir, base ); + } + else + { + // Swinging pendulum + VectorMA( cent->currentState.origin2, cent->gent->radius * ( sin( cent->gent->angle * 0.03f )), dir, base ); + VectorMA( base, cent->gent->radius * ( cos( cent->gent->angle * 0.003f )), dir2, base ); + // Do "snapping" beam slices +// VectorMA( cent->currentState.origin2, cent->gent->pos2[0], dir, base ); +// VectorMA( base, cent->gent->pos2[1], dir2, base ); + } + + // Main trace laser + FX_AddLine( cent->lerpOrigin, base, 64, 0.8f, 5.0f, alpha, 0.0, rgb, rgb, 120, cgs.media.whiteLaserShader ); + // Faint trail at base. Is this really adding anything useful? + FX_AddLine( cent->gent->pos1, base, 1, 1.0, 2.0, alpha * 0.2, 0.0, rgb, rgb, 1000, cgs.media.whiteLaserShader ); + // Faint trace cone, adds a bit of meat to the effect + FX_AddTri( cent->lerpOrigin, cent->gent->pos1, base, alpha * 0.2, 0.0, rgb, rgb, 800, cgs.media.solidWhiteShader ); + // Laser impact point + FX_AddSprite( base, NULL, NULL, random() * 2, 0.0, alpha, 0.0, rgb, rgb, 0.0, 0.0, 100, cgs.media.waterDropShader ); + + VectorCopy( base, cent->gent->pos1 ); + cent->gent->angle += cent->gent->speed * 0.08f; +} + +/* +---------------------- +CG_ShimmeryThing + +Creates column or cone of shimmering lines +Kind of looks like a teleporter effect +---------------------- +*/ + +void CG_ShimmeryThing( vec3_t start, vec3_t end, vec3_t content ) +{ + vec3_t normal, angles, base, top, dir; + float len; + int i; + int taper = content[2]; + + VectorSubtract( end, start, normal ); + len = VectorNormalize( normal ); + vectoangles( normal, angles ); + + for ( i=0; i < 2; i++) + { + // Spawn the shards of light around a cylinder + angles[2] = crandom() * 360; + AngleVectors( angles, NULL, dir, NULL ); + + // See if the effect should be tapered at the top + if ( taper == 2 ) + { + VectorMA( start, content[1] * 0.25f, dir, top ); + } + else + { + VectorMA( start, content[1], dir, top ); + } + + VectorMA( end, content[1], dir, base ); + + // Use a couple of different kinds to break up the monotony.. + if ( rand() & 1 ) + { + FX_AddLine( top, base, 1.0f, len * 0.008f, len * 0.19f, 0.3f, 0.0f, random() * 200 + 600, cgs.media.ltblueParticleShader ); + } + else + { + FX_AddLine( top, base, 1.0f, len * 0.008f, len * 0.19f, 0.2f, 0.0f, random() * 200 + 600, cgs.media.spark2Shader ); + } + } +} + +/* +---------------------- +CG_Borg_Bolt + +Yellow bolts that spark when the endpoints get close together +---------------------- +*/ + +void CG_Borg_Bolt_static( centity_t *cent ) +{ + vec3_t diff; + float len; + + // Get the midpoint of the seg + VectorSubtract( cent->currentState.origin2, cent->currentState.origin, diff ); + len = VectorNormalize( diff ); + + // Use this to scale down the width of the bolts. Otherwise, they will look pretty fairly nasty when they + // get too short. + len = len / 32; + + FX_AddElectricity( cent->currentState.origin, cent->currentState.origin2, 1.0, len, 5.0, 1.0, 0.0, 200, cgs.media.phaserShader, 0 ); +} + +void CG_Borg_Bolt_dynamic( centity_t *cent ) +{ + vec3_t diff, neworg; + float len; + + + // Get the midpoint of the seg + VectorSubtract( cent->currentState.origin2, cent->currentState.origin, diff ); + len = VectorNormalize( diff ); + VectorMA( cent->currentState.origin, len * 0.5, diff, neworg ); + + // If the length is pretty short, then spawn a glow spark + if ( len > 0 && len < 12 ) + { + int ct, t; + vec3_t angles, dir, vel; + localEntity_t *particle; + + FX_AddSprite( neworg, NULL, qfalse, random() * (128 / len) + 12, 16.0, 0.6f, 0.0, 0.0, 0.0, 50, + cgs.media.yellowParticleShader ); + + vectoangles( dir, angles ); + + ct = 12 - len; + + // fun sparks + for ( t=0; t < ct; t++ ) + { + angles[1] = random() * 360; + AngleVectors( angles, dir, NULL, NULL ); + dir[2] = random() * 0.3f; + VectorScale( dir, 300, vel ); + + particle = FX_AddTrail( neworg, NULL, qfalse, 8.0f + random() * 6, -16.0f, 1, -1, + 1.0f, 0.0f, 0.25f, 50, cgs.media.yellowParticleShader ); + + if ( particle == NULL ) + return; + + FXE_Spray( dir, 100, 150, 0.5f, vel ); + } + + // If it's really short, spark and make a noise. Tried this without the if (len>0... and it was way + // too obnoxious + if ( len <= 5 ) + { + trap_S_StartSound( neworg, 0, 0, trap_S_RegisterSound( "sound/enemies/borg/borgtaser.wav") ); + } + } + + // Use this to scale down the width of the bolts. Otherwise, they will look pretty fairly nasty when they + // get too short. + len = len / 32; + + FX_AddElectricity( cent->currentState.origin, cent->currentState.origin2, 1.0, len, 5.0, 1.0, 0.0, 50, cgs.media.phaserShader, 0 ); +} + +/* +---------------------- +CG_StasisDoor + +Does Fade-Effect for func_stasis_door +---------------------- +*/ + +void CG_StasisDoor(centity_t *cent, qboolean close) { + localEntity_t *le; + + return; + + FX_AddQuad(cent->currentState.origin, NULL, 10, 100, 1, 1, 0, 1000, cgs.media.photonGlow); + + le = CG_AllocLocalEntity(); + le->leType = LE_STASISDOOR; + + VectorCopy(cent->lerpOrigin, le->refEntity.origin); + VectorCopy(cent->lerpOrigin, le->refEntity.oldorigin); + AnglesToAxis( cent->lerpAngles, le->refEntity.axis ); + + le->refEntity.renderfx = RF_NOSHADOW | RF_FORCE_ENT_ALPHA; + le->refEntity.skinNum = 0; + + le->refEntity.hModel = cgs.media.stasisDoorModel; + + trap_R_AddRefEntityToScene(&le->refEntity); +} diff --git a/code/cgame/cg_event.c b/code/cgame/cg_event.c index 5be5838..fdbdcf8 100644 --- a/code/cgame/cg_event.c +++ b/code/cgame/cg_event.c @@ -1,33 +1,12 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // // cg_event.c -- handle entity events at snapshot or playerstate transitions #include "cg_local.h" +#include "fx_local.h" +#include "cg_text.h" +#include "cg_screenfx.h" -// for the voice chats -#ifdef MISSIONPACK -#include "../../ui/menudef.h" -#endif //========================================================================== /* @@ -39,35 +18,56 @@ Also called by scoreboard drawing */ const char *CG_PlaceString( int rank ) { static char str[64]; + static char str2[64]; char *s, *t; if ( rank & RANK_TIED_FLAG ) { rank &= ~RANK_TIED_FLAG; - t = "Tied for "; + t = ingame_text[IGT_TIEDFOR]; } else { t = ""; } if ( rank == 1 ) { - s = S_COLOR_BLUE "1st" S_COLOR_WHITE; // draw in blue +// s = S_COLOR_BLUE "1st" S_COLOR_WHITE; // draw in blue + Com_sprintf( str2, sizeof( str2 ), "%s%s%s",S_COLOR_BLUE, ingame_text[IGT_1ST],S_COLOR_WHITE ); + s = str2; } else if ( rank == 2 ) { - s = S_COLOR_RED "2nd" S_COLOR_WHITE; // draw in red +// s = S_COLOR_RED "2nd" S_COLOR_WHITE; // draw in red + Com_sprintf( str2, sizeof( str2 ), "%s%s%s",S_COLOR_RED, ingame_text[IGT_2ND],S_COLOR_WHITE ); + s = str2; } else if ( rank == 3 ) { - s = S_COLOR_YELLOW "3rd" S_COLOR_WHITE; // draw in yellow +// s = S_COLOR_YELLOW "3rd" S_COLOR_WHITE; // draw in yellow + Com_sprintf( str2, sizeof( str2 ), "%s%s%s",S_COLOR_YELLOW, ingame_text[IGT_3RD],S_COLOR_WHITE ); + s = str2; } else if ( rank == 11 ) { - s = "11th"; +// s = "11th"; + Com_sprintf( str2, sizeof( str2 ), "%s",ingame_text[IGT_11TH]); + s = str2; } else if ( rank == 12 ) { - s = "12th"; +// s = "12th"; + Com_sprintf( str2, sizeof( str2 ), "%s",ingame_text[IGT_12TH]); + s = str2; } else if ( rank == 13 ) { - s = "13th"; +// s = "13th"; + Com_sprintf( str2, sizeof( str2 ), "%s",ingame_text[IGT_13TH]); + s = str2; } else if ( rank % 10 == 1 ) { - s = va("%ist", rank); +// s = va("%ist", rank); + Com_sprintf( str2, sizeof( str2 ), "%i%s",rank,ingame_text[IGT_NUM_ST]); + s = str2; } else if ( rank % 10 == 2 ) { - s = va("%ind", rank); +// s = va("%ind", rank); + Com_sprintf( str2, sizeof( str2 ), "%i%s",rank,ingame_text[IGT_NUM_ND]); + s = str2; } else if ( rank % 10 == 3 ) { - s = va("%ird", rank); +// s = va("%ird", rank); + Com_sprintf( str2, sizeof( str2 ), "%i%s",rank,ingame_text[IGT_NUM_RD]); + s = str2; } else { - s = va("%ith", rank); +// s = va("%ith", rank); + Com_sprintf( str2, sizeof( str2 ), "%i%s",rank,ingame_text[IGT_NUM_TH]); + s = str2; } Com_sprintf( str, sizeof( str ), "%s%s", t, s ); @@ -82,131 +82,167 @@ CG_Obituary static void CG_Obituary( entityState_t *ent ) { int mod; int target, attacker; - char *message; - char *message2; + char *method; const char *targetInfo; const char *attackerInfo; - char targetName[32]; - char attackerName[32]; - gender_t gender; - clientInfo_t *ci; + char targetName[64]; + char attackerName[64]; target = ent->otherEntityNum; attacker = ent->otherEntityNum2; mod = ent->eventParm; - if ( target < 0 || target >= MAX_CLIENTS ) { + if ( target < 0 || target >= MAX_CLIENTS ) + { CG_Error( "CG_Obituary: target out of range" ); } - ci = &cgs.clientinfo[target]; - if ( attacker < 0 || attacker >= MAX_CLIENTS ) { + if ( attacker < 0 || attacker >= MAX_CLIENTS ) + { attacker = ENTITYNUM_WORLD; attackerInfo = NULL; - } else { + } + else + { attackerInfo = CG_ConfigString( CS_PLAYERS + attacker ); } targetInfo = CG_ConfigString( CS_PLAYERS + target ); - if ( !targetInfo ) { + if ( !targetInfo ) + { return; } Q_strncpyz( targetName, Info_ValueForKey( targetInfo, "n" ), sizeof(targetName) - 2); - strcat( targetName, S_COLOR_WHITE ); +// strcat( targetName, S_COLOR_WHITE ); - message2 = ""; - - // check for single client messages - - switch( mod ) { - case MOD_SUICIDE: - message = "suicides"; - break; - case MOD_FALLING: - message = "cratered"; - break; - case MOD_CRUSH: - message = "was squished"; - break; + switch( mod ) + { case MOD_WATER: - message = "sank like a rock"; + method = ingame_text[IGT_DROWNING]; break; case MOD_SLIME: - message = "melted"; + method = ingame_text[IGT_CORROSION]; break; case MOD_LAVA: - message = "does a back flip into the lava"; + method = ingame_text[IGT_BOILING]; + break; + case MOD_CRUSH: + method = ingame_text[IGT_COMPRESSION]; + break; + case MOD_TELEFRAG: + method = ingame_text[IGT_TRANSPORTERACCIDENT]; + break; + case MOD_FALLING: + method = ingame_text[IGT_IMPACT]; + break; + case MOD_SUICIDE: + case MOD_RESPAWN: + method = ingame_text[IGT_SUICIDE]; break; case MOD_TARGET_LASER: - message = "saw the light"; + method = ingame_text[IGT_LASERBURNS]; break; case MOD_TRIGGER_HURT: - message = "was in the wrong place"; + method = ingame_text[IGT_MISADVENTURE]; + break; + case MOD_EXPLOSION: + method = ingame_text[IGT_DESTROYED]; + break; + case MOD_PHASER: + case MOD_PHASER_ALT: + method = ingame_text[IGT_PHASERBURNS]; + break; + case MOD_CRIFLE: + case MOD_CRIFLE_SPLASH: + case MOD_CRIFLE_ALT_SPLASH: + method = ingame_text[IGT_ENERGYSCARS]; + break; + case MOD_CRIFLE_ALT: + method = ingame_text[IGT_PHASERBURNS]; //RPG-X | GSIO01 | 08/05/2009: was IGT_SNIPED + break; + case MOD_IMOD: + case MOD_IMOD_ALT: + method = ingame_text[IGT_INFINITEMODULATION]; + break; + case MOD_SCAVENGER: + method = ingame_text[IGT_GUNNEDDOWN]; + break; + case MOD_SCAVENGER_ALT: + case MOD_SCAVENGER_ALT_SPLASH: + method = ingame_text[IGT_SCAVENGED]; + break; + case MOD_STASIS: + case MOD_STASIS_ALT: + method = ingame_text[IGT_PERMANENTSTASIS]; + break; + case MOD_GRENADE: + case MOD_GRENADE_SPLASH: + method = ingame_text[IGT_BLASTED]; + break; + case MOD_GRENADE_ALT: + case MOD_GRENADE_ALT_SPLASH: + method = ingame_text[IGT_MINED]; + break; + case MOD_TETRION: + method = ingame_text[IGT_PERFORATED]; + break; + case MOD_TETRION_ALT: + method = ingame_text[IGT_DISRUPTED]; + break; + case MOD_DREADNOUGHT: + method = ingame_text[IGT_WELDED]; + break; + case MOD_DREADNOUGHT_ALT: + method = ingame_text[IGT_DEGAUSSED]; + break; + case MOD_QUANTUM: + case MOD_QUANTUM_SPLASH: + method = ingame_text[IGT_DESTROYED]; + break; + case MOD_QUANTUM_ALT: + case MOD_QUANTUM_ALT_SPLASH: + method = ingame_text[IGT_ANNIHILATED]; + break; + case MOD_DETPACK: + method = ingame_text[IGT_VAPORIZED]; + break; + case MOD_KNOCKOUT: + method = ingame_text[IGT_KNOCKOUT]; + break; + case MOD_SEEKER: + method = ingame_text[IGT_AUTOGUNNED]; + break; + case MOD_ASSIMILATE: + method = ingame_text[IGT_ASSIMILATED]; + break; + case MOD_BORG: + case MOD_BORG_ALT: + method = ingame_text[IGT_ZAPPED]; + break; + case MOD_FORCEFIELD: + method =ingame_text[IGT_FORCEFIELDDEATH]; + break; + case MOD_FORCEDSUICIDE: + method =ingame_text[IGT_FORCEDSUICIDE]; break; default: - message = NULL; + method =ingame_text[IGT_UNKNOWN]; break; } - if (attacker == target) { - gender = ci->gender; - switch (mod) { -#ifdef MISSIONPACK - case MOD_KAMIKAZE: - message = "goes out with a bang"; - break; -#endif - case MOD_GRENADE_SPLASH: - if ( gender == GENDER_FEMALE ) - message = "tripped on her own grenade"; - else if ( gender == GENDER_NEUTER ) - message = "tripped on its own grenade"; - else - message = "tripped on his own grenade"; - break; - case MOD_ROCKET_SPLASH: - if ( gender == GENDER_FEMALE ) - message = "blew herself up"; - else if ( gender == GENDER_NEUTER ) - message = "blew itself up"; - else - message = "blew himself up"; - break; - case MOD_PLASMA_SPLASH: - if ( gender == GENDER_FEMALE ) - message = "melted herself"; - else if ( gender == GENDER_NEUTER ) - message = "melted itself"; - else - message = "melted himself"; - break; - case MOD_BFG_SPLASH: - message = "should have used a smaller gun"; - break; -#ifdef MISSIONPACK - case MOD_PROXIMITY_MINE: - if( gender == GENDER_FEMALE ) { - message = "found her prox mine"; - } else if ( gender == GENDER_NEUTER ) { - message = "found its prox mine"; - } else { - message = "found his prox mine"; - } - break; -#endif - default: - if ( gender == GENDER_FEMALE ) - message = "killed herself"; - else if ( gender == GENDER_NEUTER ) - message = "killed itself"; - else - message = "killed himself"; - break; - } + + if ( target == cg.snap->ps.clientNum ) + { + cg.mod = mod; } - if (message) { - CG_Printf( "%s %s.\n", targetName, message); + // If killed self, send "Casualty" message. + if (attacker == target || attacker == ENTITYNUM_WORLD || !attackerInfo) + { // Killed self + if ( cg_disablekillmsgs.integer == 0 ) + { + CG_Printf(S_COLOR_CYAN"%s: "S_COLOR_WHITE"%10s "S_COLOR_CYAN"%s: "S_COLOR_WHITE"%s\n", ingame_text[IGT_CASUALTY],targetName,ingame_text[IGT_METHOD], method); + } return; } @@ -214,124 +250,50 @@ static void CG_Obituary( entityState_t *ent ) { if ( attacker == cg.snap->ps.clientNum ) { char *s; - if ( cgs.gametype < GT_TEAM ) { - s = va("You fragged %s\n%s place with %i", targetName, - CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ), - cg.snap->ps.persistant[PERS_SCORE] ); - } else { - s = va("You fragged %s", targetName ); - } -#ifdef MISSIONPACK - if (!(cg_singlePlayerActive.integer && cg_cameraOrbit.integer)) { - CG_CenterPrint( s, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH ); + if ( cgs.gametype < GT_TEAM ) + { + s = va("%s %s", ingame_text[IGT_YOUELIMINATED],targetName); + /*s = va("%s %s\n%s %s %i", ingame_text[IGT_YOUELIMINATED],targetName, + CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ),ingame_text[IGT_PLACEWITH], + cg.snap->ps.persistant[PERS_SCORE] );*/ } -#else - CG_CenterPrint( s, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH ); -#endif - + else + { + //Assimilated message as well + if ( mod == MOD_ASSIMILATE ) + { + s = va("%s %s", ingame_text[IGT_YOUASSIMILATED],targetName ); + } + else + { + s = va("%s %s", ingame_text[IGT_YOUELIMINATED],targetName ); + } + } + CG_CenterPrint( s, SCREEN_HEIGHT * 0.25, BIGCHAR_WIDTH ); // print the text message as well } // check for double client messages - if ( !attackerInfo ) { + if ( !attackerInfo ) + { attacker = ENTITYNUM_WORLD; strcpy( attackerName, "noname" ); - } else { + } + else + { Q_strncpyz( attackerName, Info_ValueForKey( attackerInfo, "n" ), sizeof(attackerName) - 2); - strcat( attackerName, S_COLOR_WHITE ); +// strcat( attackerName, S_COLOR_WHITE ); // check for kill messages about the current clientNum if ( target == cg.snap->ps.clientNum ) { Q_strncpyz( cg.killerName, attackerName, sizeof( cg.killerName ) ); } } - if ( attacker != ENTITYNUM_WORLD ) { - switch (mod) { - case MOD_GRAPPLE: - message = "was caught by"; - break; - case MOD_GAUNTLET: - message = "was pummeled by"; - break; - case MOD_MACHINEGUN: - message = "was machinegunned by"; - break; - case MOD_SHOTGUN: - message = "was gunned down by"; - break; - case MOD_GRENADE: - message = "ate"; - message2 = "'s grenade"; - break; - case MOD_GRENADE_SPLASH: - message = "was shredded by"; - message2 = "'s shrapnel"; - break; - case MOD_ROCKET: - message = "ate"; - message2 = "'s rocket"; - break; - case MOD_ROCKET_SPLASH: - message = "almost dodged"; - message2 = "'s rocket"; - break; - case MOD_PLASMA: - message = "was melted by"; - message2 = "'s plasmagun"; - break; - case MOD_PLASMA_SPLASH: - message = "was melted by"; - message2 = "'s plasmagun"; - break; - case MOD_RAILGUN: - message = "was railed by"; - break; - case MOD_LIGHTNING: - message = "was electrocuted by"; - break; - case MOD_BFG: - case MOD_BFG_SPLASH: - message = "was blasted by"; - message2 = "'s BFG"; - break; -#ifdef MISSIONPACK - case MOD_NAIL: - message = "was nailed by"; - break; - case MOD_CHAINGUN: - message = "got lead poisoning from"; - message2 = "'s Chaingun"; - break; - case MOD_PROXIMITY_MINE: - message = "was too close to"; - message2 = "'s Prox Mine"; - break; - case MOD_KAMIKAZE: - message = "falls to"; - message2 = "'s Kamikaze blast"; - break; - case MOD_JUICED: - message = "was juiced by"; - break; -#endif - case MOD_TELEFRAG: - message = "tried to invade"; - message2 = "'s personal space"; - break; - default: - message = "was killed by"; - break; - } - - if (message) { - CG_Printf( "%s %s %s%s\n", - targetName, message, attackerName, message2); - return; - } + if ( cg_disablekillmsgs.integer == 0 ) + { + CG_Printf(S_COLOR_CYAN"%s: "S_COLOR_WHITE"%10s "S_COLOR_CYAN"%s: "S_COLOR_WHITE"%10s "S_COLOR_CYAN"%s: "S_COLOR_WHITE"%s\n", ingame_text[IGT_OBITELIMINATED],targetName,ingame_text[IGT_CREDIT],attackerName, ingame_text[IGT_METHOD], method); } - // we don't know what it was - CG_Printf( "%s died.\n", targetName ); } //========================================================================== @@ -342,9 +304,7 @@ CG_UseItem =============== */ static void CG_UseItem( centity_t *cent ) { - clientInfo_t *ci; - int itemNum, clientNum; - gitem_t *item; + int itemNum; entityState_t *es; es = ¢->currentState; @@ -353,45 +313,41 @@ static void CG_UseItem( centity_t *cent ) { if ( itemNum < 0 || itemNum > HI_NUM_HOLDABLE ) { itemNum = 0; } - // print a message if the local player - if ( es->number == cg.snap->ps.clientNum ) { +/* if ( es->number == cg.snap->ps.clientNum ) { if ( !itemNum ) { - CG_CenterPrint( "No item to use", SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH ); + CG_CenterPrint( "No item to use", SCREEN_HEIGHT * 0.25, BIGCHAR_WIDTH ); } else { + gitem_t *item; item = BG_FindItemForHoldable( itemNum ); - CG_CenterPrint( va("Use %s", item->pickup_name), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH ); + CG_CenterPrint( va("Use %s", item->pickup_name), SCREEN_HEIGHT * 0.25, BIGCHAR_WIDTH ); } } - +*/ switch ( itemNum ) { default: case HI_NONE: trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.useNothingSound ); break; - case HI_TELEPORTER: + case HI_TRANSPORTER: break; case HI_MEDKIT: - clientNum = cent->currentState.clientNum; - if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) { - ci = &cgs.clientinfo[ clientNum ]; - ci->medkitUsageTime = cg.time; - } trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.medkitSound ); break; -#ifdef MISSIONPACK - case HI_KAMIKAZE: + case HI_DETPACK: break; - case HI_PORTAL: + //--------------------------------------- TEMP DECOY + case HI_DECOY: + /* + if ( es->number == cg.snap->ps.clientNum ) { + CG_CenterPrint( "Decoy Placed\n",SCREEN_HEIGHT * 0.25, BIGCHAR_WIDTH ); + } + */ break; - case HI_INVULNERABILITY: - trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.useInvulnerabilitySound ); - break; -#endif } } @@ -408,62 +364,62 @@ static void CG_ItemPickup( int itemNum ) { cg.itemPickupTime = cg.time; cg.itemPickupBlendTime = cg.time; // see if it should be the grabbed weapon - if ( bg_itemlist[itemNum].giType == IT_WEAPON ) { - // select it immediately - if ( cg_autoswitch.integer && bg_itemlist[itemNum].giTag != WP_MACHINEGUN ) { - cg.weaponSelectTime = cg.time; - cg.weaponSelect = bg_itemlist[itemNum].giTag; - } - } -} + if (cg.snap->ps.stats[STAT_WEAPONS] & (1 << itemNum)) + return; -/* -================ -CG_WaterLevel + if ( bg_itemlist[itemNum].giType == IT_WEAPON ) + { + int nCurWpn = cg.predictedPlayerState.weapon; + int nNewWpn = bg_itemlist[itemNum].giTag; -Returns waterlevel for entity origin -================ -*/ -int CG_WaterLevel(centity_t *cent) { - vec3_t point; - int contents, sample1, sample2, anim, waterlevel; + // kef -- check cg_autoswitch... + // + // 0 == no switching + // 1 == automatically switch to best SAFE weapon + // 2 == automatically switch to best weapon, safe or otherwise + // + // NOTE: automatically switching to any weapon you pick up is stupid and annoying and we won't do it. + // - // get waterlevel, accounting for ducking - waterlevel = 0; - VectorCopy(cent->lerpOrigin, point); - point[2] += MINS_Z + 1; - anim = cent->currentState.legsAnim & ~ANIM_TOGGLEBIT; - - if (anim == LEGS_WALKCR || anim == LEGS_IDLECR) { - point[2] += CROUCH_VIEWHEIGHT; - } else { - point[2] += DEFAULT_VIEWHEIGHT; - } - - contents = CG_PointContents(point, -1); - - if (contents & MASK_WATER) { - sample2 = point[2] - MINS_Z; - sample1 = sample2 / 2; - waterlevel = 1; - point[2] = cent->lerpOrigin[2] + MINS_Z + sample1; - contents = CG_PointContents(point, -1); - - if (contents & MASK_WATER) { - waterlevel = 2; - point[2] = cent->lerpOrigin[2] + MINS_Z + sample2; - contents = CG_PointContents(point, -1); - - if (contents & MASK_WATER) { - waterlevel = 3; + switch(cg_autoswitch.integer) + { + case 1: + // safe switching + if ( (nNewWpn > nCurWpn) && + !(nNewWpn == WP_8) && + !(nNewWpn == WP_9) ) + { + // switch to new wpn + cg.weaponSelectTime = cg.time; + cg.weaponSelect = nNewWpn; } + break; + case 2: + // best, even if unsafe. + if (nNewWpn > nCurWpn) + { + // switch to new wpn + cg.weaponSelectTime = cg.time; + cg.weaponSelect = nNewWpn; + } + break; + case 3: + // Always switch + // switch to new wpn + cg.weaponSelectTime = cg.time; + cg.weaponSelect = nNewWpn; + break; + case 0: + default: + // Don't switch. + break; } - } - return waterlevel; + } } + /* ================ CG_PainEvent @@ -480,31 +436,22 @@ void CG_PainEvent( centity_t *cent, int health ) { } if ( health < 25 ) { - snd = "*pain25_1.wav"; + snd = "*pain25.wav"; } else if ( health < 50 ) { - snd = "*pain50_1.wav"; + snd = "*pain50.wav"; } else if ( health < 75 ) { - snd = "*pain75_1.wav"; + snd = "*pain75.wav"; } else { - snd = "*pain100_1.wav"; - } - // play a gurp sound instead of a normal pain sound - if (CG_WaterLevel(cent) >= 1) { - if (rand()&1) { - trap_S_StartSound(NULL, cent->currentState.number, CHAN_VOICE, CG_CustomSound(cent->currentState.number, "sound/player/gurp1.wav")); - } else { - trap_S_StartSound(NULL, cent->currentState.number, CHAN_VOICE, CG_CustomSound(cent->currentState.number, "sound/player/gurp2.wav")); - } - } else { - trap_S_StartSound(NULL, cent->currentState.number, CHAN_VOICE, CG_CustomSound(cent->currentState.number, snd)); + snd = "*pain100.wav"; } + trap_S_StartSound( NULL, cent->currentState.number, CHAN_VOICE, + CG_CustomSound( cent->currentState.number, snd ) ); + // save pain time for programitic twitch animation cent->pe.painTime = cg.time; cent->pe.painDirection ^= 1; } - - /* ============== CG_EntityEvent @@ -521,10 +468,18 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { const char *s; int clientNum; clientInfo_t *ci; + vec3_t normal = { 0, 0, 1 }; + int a, b; + + refEntity_t legs; + refEntity_t torso; + refEntity_t head; + //vec3_t forward, right, up; + //vec3_t spray_dir; //RPG-X: J2J - Trying to fix hypo, aim direction stored here as raw vector. es = ¢->currentState; event = es->event & ~EV_EVENT_BITS; - + if ( cg_debugEvents.integer ) { CG_Printf( "ent:%3i event:%3i ", es->number, event ); } @@ -546,20 +501,41 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { // case EV_FOOTSTEP: DEBUGNAME("EV_FOOTSTEP"); - if (cg_footsteps.integer) { - trap_S_StartSound (NULL, es->number, CHAN_BODY, - cgs.media.footsteps[ ci->footsteps ][rand()&3] ); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; + + if ( ci->animSndIndex == -1 ) { + if (cg_footsteps.integer ) { + if ( cent->beamData.beamTimeParam == 0 || + ( ( es->powerups & ( 1 << PW_BEAM_OUT ) ) && ( cg.time < cent->beamData.beamTimeParam + 2200 ) ) || + ( ( es->powerups & ( 1 << PW_QUAD ) ) && ( cg.time > cent->beamData.beamTimeParam + 1800 ) ) ) { + trap_S_StartSound (NULL, es->number, CHAN_BODY, + cgs.media.footsteps[ ci->footsteps ][rand()&3] ); + } + } } break; case EV_FOOTSTEP_METAL: DEBUGNAME("EV_FOOTSTEP_METAL"); - if (cg_footsteps.integer) { - trap_S_StartSound (NULL, es->number, CHAN_BODY, - cgs.media.footsteps[ FOOTSTEP_METAL ][rand()&3] ); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; + + if ( ci->animSndIndex == -1 ) { + if (cg_footsteps.integer) { + if ( cent->beamData.beamTimeParam == 0 || + ( ( es->powerups & ( 1 << PW_BEAM_OUT ) ) && ( cg.time < cent->beamData.beamTimeParam + 2200 ) ) || + ( ( es->powerups & ( 1 << PW_QUAD ) ) && ( cg.time > cent->beamData.beamTimeParam + 1800 ) ) ) { + trap_S_StartSound (NULL, es->number, CHAN_BODY, + cgs.media.footsteps[ FOOTSTEP_METAL ][rand()&3] ); + } + } } break; case EV_FOOTSPLASH: DEBUGNAME("EV_FOOTSPLASH"); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; + if (cg_footsteps.integer) { trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] ); @@ -567,6 +543,9 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { break; case EV_FOOTWADE: DEBUGNAME("EV_FOOTWADE"); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; + if (cg_footsteps.integer) { trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] ); @@ -574,6 +553,9 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { break; case EV_SWIM: DEBUGNAME("EV_SWIM"); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; + if (cg_footsteps.integer) { trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] ); @@ -583,7 +565,14 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { case EV_FALL_SHORT: DEBUGNAME("EV_FALL_SHORT"); - trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound ); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; + + if ( !( cent->currentState.eFlags & EF_DEAD ) ) + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound[LANDSOUND_NORMAL] ); + else + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.splatSound ); + if ( clientNum == cg.predictedPlayerState.clientNum ) { // smooth landing z changes cg.landChange = -8; @@ -592,8 +581,15 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { break; case EV_FALL_MEDIUM: DEBUGNAME("EV_FALL_MEDIUM"); - // use normal pain sound - trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*pain100_1.wav" ) ); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; + + if ( !( cent->currentState.eFlags & EF_DEAD ) ) + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound[LANDSOUND_NORMAL] ); + else + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.splatSound ); + + // use normal pain sound trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*pain100.wav" ) ); if ( clientNum == cg.predictedPlayerState.clientNum ) { // smooth landing z changes cg.landChange = -16; @@ -602,6 +598,15 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { break; case EV_FALL_FAR: DEBUGNAME("EV_FALL_FAR"); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; + + //if ( ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) != BOTH_FALLDEATH1INAIR && ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) != BOTH_FALLDEATH1LAND ) + if ( !( cent->currentState.eFlags & EF_DEAD ) ) + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound[LANDSOUND_NORMAL] ); + else + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.splatSound ); + trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*fall1.wav" ) ); cent->pe.painTime = cg.time; // don't play a pain sound right after this if ( clientNum == cg.predictedPlayerState.clientNum ) { @@ -611,11 +616,19 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { } break; + case EV_SPLAT: + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; + + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.splatSound ); + break; case EV_STEP_4: case EV_STEP_8: case EV_STEP_12: case EV_STEP_16: // smooth out step up transitions DEBUGNAME("EV_STEP"); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; { float oldStep; int delta; @@ -649,20 +662,8 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { case EV_JUMP_PAD: DEBUGNAME("EV_JUMP_PAD"); -// CG_Printf( "EV_JUMP_PAD w/effect #%i\n", es->eventParm ); - { - vec3_t up = {0, 0, 1}; - - - CG_SmokePuff( cent->lerpOrigin, up, - 32, - 1, 1, 1, 0.33f, - 1000, - cg.time, 0, - LEF_PUFF_DONT_SCALE, - cgs.media.smokePuffShader ); - } - + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; // boing sound at origin, jump sound on player trap_S_StartSound ( cent->lerpOrigin, -1, CHAN_VOICE, cgs.media.jumpPadSound ); trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.wav" ) ); @@ -670,52 +671,46 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { case EV_JUMP: DEBUGNAME("EV_JUMP"); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.wav" ) ); break; case EV_TAUNT: DEBUGNAME("EV_TAUNT"); - trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*taunt.wav" ) ); + /*if ( ci->numTaunts > 0 ) + { + if ( ci->pClass == PC_BORG ) + { + trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, CG_CustomSound( es->number, va("*taunt%d.wav", irandom(1, ci->numTaunts) ) ) ); + } + else + { + trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, va("*taunt%d.wav", irandom(1, ci->numTaunts) ) ) ); + } + }*/ break; -#ifdef MISSIONPACK - case EV_TAUNT_YES: - DEBUGNAME("EV_TAUNT_YES"); - CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_YES); - break; - case EV_TAUNT_NO: - DEBUGNAME("EV_TAUNT_NO"); - CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_NO); - break; - case EV_TAUNT_FOLLOWME: - DEBUGNAME("EV_TAUNT_FOLLOWME"); - CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_FOLLOWME); - break; - case EV_TAUNT_GETFLAG: - DEBUGNAME("EV_TAUNT_GETFLAG"); - CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONGETFLAG); - break; - case EV_TAUNT_GUARDBASE: - DEBUGNAME("EV_TAUNT_GUARDBASE"); - CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONDEFENSE); - break; - case EV_TAUNT_PATROL: - DEBUGNAME("EV_TAUNT_PATROL"); - CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONPATROL); - break; -#endif case EV_WATER_TOUCH: DEBUGNAME("EV_WATER_TOUCH"); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrInSound ); break; case EV_WATER_LEAVE: DEBUGNAME("EV_WATER_LEAVE"); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrOutSound ); break; case EV_WATER_UNDER: DEBUGNAME("EV_WATER_UNDER"); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrUnSound ); break; case EV_WATER_CLEAR: DEBUGNAME("EV_WATER_CLEAR"); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*gasp.wav" ) ); break; @@ -734,27 +729,13 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { // powerups and team items will have a separate global sound, this one // will be played at prediction time - if ( item->giType == IT_POWERUP || item->giType == IT_TEAM) { - trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.n_healthSound ); - } else if (item->giType == IT_PERSISTANT_POWERUP) { -#ifdef MISSIONPACK - switch (item->giTag ) { - case PW_SCOUT: - trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.scoutSound ); - break; - case PW_GUARD: - trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.guardSound ); - break; - case PW_DOUBLER: - trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.doublerSound ); - break; - case PW_AMMOREGEN: - trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.ammoregenSound ); - break; - } -#endif - } else { - trap_S_StartSound (NULL, es->number, CHAN_AUTO, trap_S_RegisterSound( item->pickup_sound, qfalse ) ); + if ( item->giType == IT_POWERUP) + { + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.defaultPickupSound ); + } + else if (item->pickup_sound && (item->giType != IT_TEAM)) + { + trap_S_StartSound (NULL, es->number, CHAN_AUTO, trap_S_RegisterSound( item->pickup_sound ) ); } // show icon and name on status bar @@ -776,9 +757,68 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { break; } item = &bg_itemlist[ index ]; - // powerup pickups are global - if( item->pickup_sound ) { - trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, trap_S_RegisterSound( item->pickup_sound, qfalse ) ); + + // if it's a IT_TEAM type, then its a CTF FLAG, and if so, we need to do different sounds for different people + // not nice to do as a specific sound type, but without rebuilding the item structure there is no choice. + /*if (item->giType == IT_TEAM) + { + // are we the same client as the one that fired this global sound call off in the first place? + // if so, we have already handled the sound call in EV_ITEM_PICKUP + if ( es->otherEntityNum != cg.snap->ps.clientNum ) + { + clientInfo_t *us; + + us = &cgs.clientinfo[ cg.snap->ps.clientNum ]; + + if (us->team != TEAM_SPECTATOR) + { + // red or blue? + if (item->giTag == PW_REDFLAG) + { + // red + if (us->team == TEAM_RED) + { // Your flag has been touched. + trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_ANNOUNCER, cgs.media.ctfTheyStealVoiceSound); + } + else + { + trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_ANNOUNCER, cgs.media.ctfYouStealVoiceSound); + } + } + else + { + // no, Blue! + if (us->team == TEAM_BLUE) + { // Your flag has been touched. + trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_ANNOUNCER, cgs.media.ctfTheyStealVoiceSound); + } + else + { + trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_ANNOUNCER, cgs.media.ctfYouStealVoiceSound); + } + } + } + else + { // Spectators should hear generic steal sound with no voice + trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_ANNOUNCER, cgs.media.ctfStealSound); + } + } + else + { + trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_ANNOUNCER, trap_S_RegisterSound( item->pickup_sound ) ); + } + + } + else*/ if (item->pickup_sound) + { // powerup pickups are NOT global anymore, they are in the world. + if (es->otherEntityNum==cg.snap->ps.clientNum) + { // YOU are the one who started this sound. + trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_ITEM, trap_S_RegisterSound( item->pickup_sound ) ); + } + else + { // Maybe it is too quiet for a pickup? + trap_S_StartSound (NULL, es->number, CHAN_AUTO, trap_S_RegisterSound( item->pickup_sound ) ); + } } // show icon and name on status bar @@ -795,76 +835,124 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { DEBUGNAME("EV_NOAMMO"); // trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.noAmmoSound ); if ( es->number == cg.snap->ps.clientNum ) { - CG_OutOfAmmoChange(); + //primary fire switches weapons + CG_OutOfAmmoChange(qfalse); + } + break; + case EV_NOAMMO_ALT: + DEBUGNAME("EV_NOAMMO_ALT"); +// trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.noAmmoSound ); + if ( es->number == cg.snap->ps.clientNum ) { + CG_OutOfAmmoChange(qtrue); +// cg.lowAmmoWarning = 1000;//flash out of ammo message for 1 whole second +// trap_S_StartLocalSound( cgs.media.noAmmoSound, CHAN_LOCAL_SOUND ); } break; case EV_CHANGE_WEAPON: DEBUGNAME("EV_CHANGE_WEAPON"); - trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.selectSound ); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; + //trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.selectSound ); break; case EV_FIRE_WEAPON: DEBUGNAME("EV_FIRE_WEAPON"); - CG_FireWeapon( cent ); + cent->pe.empty = qfalse; + CG_FireWeapon( cent, qfalse ); + break; + case EV_ALT_FIRE: + DEBUGNAME("EV_ALT_FIRE"); + cent->pe.empty = qfalse; + CG_FireWeapon( cent, qtrue ); + break; + + case EV_USE: + DEBUGNAME("EV_USE"); + //??? + break; + + case EV_FIRE_EMPTY_PHASER: + DEBUGNAME("EV_FIRE_EMPTY_PHASER"); + cent->pe.lightningFiring = qtrue; + cent->pe.empty = qtrue; + CG_FireWeapon( cent, qfalse ); + break; + + case EV_Q_FLASH: + DEBUGNAME("EV_Q_FLASH"); + CG_InitLensFlare( cent->lerpOrigin, + 160, 500, + colorTable[CT_WHITE], 1.2, 2.0, 700, 1, + colorTable[CT_WHITE], 0, 0, 0, 0, qfalse, + 0, 0, qfalse, qfalse, + qfalse, 1.0, cg.time, 120, 0, 120 ); + break; + +case EV_HYPO_PUFF: + DEBUGNAME("EV_HYPO_PUFF"); + //UnVectorShort(cent->currentState.angles); + //VectorCopy(cent->lerpOrigin, hypo_vec); + //hypo_vec[0] += cg.snap->ps.viewheight; + //AngleVectors (cg.snap->ps.viewangles, forward, right, up); + //CalcMuzzlePoint ( cent, forward, right, up, muzzle, projsize); + //dir + + //VectorSubtract(spray_dir, /*cent->lerpOrigin*/cg.refdefViewAngles, cent->currentState.origin); + /* + spray_dir[0] = cg.refdefViewAngles[0]; + spray_dir[1] = cg.refdefViewAngles[2]; + spray_dir[2] = cg.refdefViewAngles[1]; + + //RPG-X: J2J - Correct Angles now used :-) + spray_dir[0] = cg.snap->ps.viewangles[0]; + spray_dir[1] = cg.snap->ps.viewangles[2]; + spray_dir[2] = cg.snap->ps.viewangles[1]; + */ + + FX_HypoSpray( cent->lerpOrigin, /*spray_dircg.snap->ps.viewangles*/cent->currentState.angles2, qfalse ); + break; + +case EV_TR116_TRIS: + DEBUGNAME("EV_TR116_TRIS"); + /*if(tris_state == 1){ + tris_state = 0; + }else{ + tris_state = 1; + } + + //trap_Cvar_Set("r_showtris", va("%i",tris_state)); + trap_SendConsoleCommand( va("r_showtris %i",tris_state) ); + */ + break; + +//RPG-X: RedTechie - Tring to get fricken shake sound to work +case EV_SHAKE_SOUND: + DEBUGNAME("EV_SHAKE_SOUND"); + /*spray_dir[0] = cg.refdefViewAngles[0]; + spray_dir[1] = cg.refdefViewAngles[2]; + spray_dir[2] = cg.refdefViewAngles[1]; + + FX_HypoSpray( cent->lerpOrigin, spray_dir, qfalse );*/ + //trap_S_AddLoopingSound( es->number, NULL, NULL, cgs.media.phaserEmptySound ); + trap_S_StartLocalSound( cgs.media.ShakeSound, CHAN_LOCAL ); break; case EV_USE_ITEM0: - DEBUGNAME("EV_USE_ITEM0"); - CG_UseItem( cent ); - break; case EV_USE_ITEM1: - DEBUGNAME("EV_USE_ITEM1"); - CG_UseItem( cent ); - break; case EV_USE_ITEM2: - DEBUGNAME("EV_USE_ITEM2"); - CG_UseItem( cent ); - break; case EV_USE_ITEM3: - DEBUGNAME("EV_USE_ITEM3"); - CG_UseItem( cent ); - break; case EV_USE_ITEM4: - DEBUGNAME("EV_USE_ITEM4"); - CG_UseItem( cent ); - break; case EV_USE_ITEM5: - DEBUGNAME("EV_USE_ITEM5"); - CG_UseItem( cent ); - break; case EV_USE_ITEM6: - DEBUGNAME("EV_USE_ITEM6"); - CG_UseItem( cent ); - break; case EV_USE_ITEM7: - DEBUGNAME("EV_USE_ITEM7"); - CG_UseItem( cent ); - break; case EV_USE_ITEM8: - DEBUGNAME("EV_USE_ITEM8"); - CG_UseItem( cent ); - break; case EV_USE_ITEM9: - DEBUGNAME("EV_USE_ITEM9"); - CG_UseItem( cent ); - break; case EV_USE_ITEM10: - DEBUGNAME("EV_USE_ITEM10"); - CG_UseItem( cent ); - break; case EV_USE_ITEM11: - DEBUGNAME("EV_USE_ITEM11"); - CG_UseItem( cent ); - break; case EV_USE_ITEM12: - DEBUGNAME("EV_USE_ITEM12"); - CG_UseItem( cent ); - break; case EV_USE_ITEM13: - DEBUGNAME("EV_USE_ITEM13"); - CG_UseItem( cent ); - break; case EV_USE_ITEM14: - DEBUGNAME("EV_USE_ITEM14"); + case EV_USE_ITEM15: + DEBUGNAME("EV_USE_ITEMxx"); CG_UseItem( cent ); break; @@ -876,18 +964,38 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { case EV_PLAYER_TELEPORT_IN: DEBUGNAME("EV_PLAYER_TELEPORT_IN"); trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.teleInSound ); - CG_SpawnEffect( position); + CG_SpawnEffect( position, &legs, &torso, &head); + CG_AddFullScreenEffect(SCREENFX_TRANSPORTER, clientNum); break; case EV_PLAYER_TELEPORT_OUT: DEBUGNAME("EV_PLAYER_TELEPORT_OUT"); - trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.teleOutSound ); - CG_SpawnEffect( position); - break; + trap_S_StartSound ( NULL, es->number, CHAN_AUTO, cgs.media.qFlash ); + CG_QFlashEvent( position ); + //trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.teleOutSound ); + //CG_SpawnEffect( position, &legs, &torso, &head); + break; + //RPG-X: TiM -> + case EV_PLAYER_TRANSPORT_IN: + DEBUGNAME("EV_PLAYER_TRANSPORT_IN"); + trap_S_StartSound ( cent->lerpOrigin, es->number, CHAN_WEAPON, cgs.media.transportSound ); + //CG_AddFullScreenEffect( SCREENFX_SP_TRANSPORTER_IN, clientNum ); + break; + case EV_PLAYER_TRANSPORT_OUT: + DEBUGNAME("EV_PLAYER_TRANSPORT_OUT"); + trap_S_StartSound ( cent->lerpOrigin, es->number, CHAN_WEAPON, cgs.media.transportSound ); + //CG_AddFullScreenEffect( SCREENFX_SP_TRANSPORTER_OUT, clientNum ); + break; +/* case EV_BORG_TELEPORT: + DEBUGNAME("EV_BORG_TELEPORT"); + FX_BorgTeleport( position ); + // FIXME: Hmmm, sound? + break;*/ case EV_ITEM_POP: DEBUGNAME("EV_ITEM_POP"); trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.respawnSound ); +//bookmark break; case EV_ITEM_RESPAWN: DEBUGNAME("EV_ITEM_RESPAWN"); @@ -897,115 +1005,216 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { case EV_GRENADE_BOUNCE: DEBUGNAME("EV_GRENADE_BOUNCE"); - if ( rand() & 1 ) { - trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.hgrenb1aSound ); - } else { - trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.hgrenb2aSound ); - } - break; - -#ifdef MISSIONPACK - case EV_PROXIMITY_MINE_STICK: - DEBUGNAME("EV_PROXIMITY_MINE_STICK"); - if( es->eventParm & SURF_FLESH ) { - trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimplSound ); - } else if( es->eventParm & SURF_METALSTEPS ) { - trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimpmSound ); - } else { - trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimpdSound ); - } - break; - - case EV_PROXIMITY_MINE_TRIGGER: - DEBUGNAME("EV_PROXIMITY_MINE_TRIGGER"); - trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbactvSound ); - break; - case EV_KAMIKAZE: - DEBUGNAME("EV_KAMIKAZE"); - CG_KamikazeEffect( cent->lerpOrigin ); - break; - case EV_OBELISKEXPLODE: - DEBUGNAME("EV_OBELISKEXPLODE"); - CG_ObeliskExplode( cent->lerpOrigin, es->eventParm ); - break; - case EV_OBELISKPAIN: - DEBUGNAME("EV_OBELISKPAIN"); - CG_ObeliskPain( cent->lerpOrigin ); - break; - case EV_INVUL_IMPACT: - DEBUGNAME("EV_INVUL_IMPACT"); - CG_InvulnerabilityImpact( cent->lerpOrigin, cent->currentState.angles ); - break; - case EV_JUICED: - DEBUGNAME("EV_JUICED"); - CG_InvulnerabilityJuiced( cent->lerpOrigin ); - break; - case EV_LIGHTNINGBOLT: - DEBUGNAME("EV_LIGHTNINGBOLT"); - CG_LightningBoltBeam(es->origin2, es->pos.trBase); - break; -#endif - case EV_SCOREPLUM: - DEBUGNAME("EV_SCOREPLUM"); - CG_ScorePlum( cent->currentState.otherEntityNum, cent->lerpOrigin, cent->currentState.time ); + UnVectorShort(cent->currentState.angles2); + CG_BounceEffect( cent, es->weapon, position, cent->currentState.angles2 ); break; // // missile impacts // + case EV_MISSILE_STICK: + DEBUGNAME("EV_MISSILE_STICK"); + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.grenadeAltStickSound ); + break; + case EV_MISSILE_HIT: DEBUGNAME("EV_MISSILE_HIT"); ByteToDir( es->eventParm, dir ); - CG_MissileHitPlayer( es->weapon, position, dir, es->otherEntityNum ); + CG_MissileHitPlayer( cent, es->weapon, position, dir); break; case EV_MISSILE_MISS: DEBUGNAME("EV_MISSILE_MISS"); ByteToDir( es->eventParm, dir ); - CG_MissileHitWall( es->weapon, 0, position, dir, IMPACTSOUND_DEFAULT ); + CG_MissileHitWall( cent, es->weapon, position, dir ); break; - case EV_MISSILE_MISS_METAL: - DEBUGNAME("EV_MISSILE_MISS_METAL"); + case EV_COMPRESSION_RIFLE: + DEBUGNAME("EV_MISSILE_MISS"); + UnVectorShort(cent->currentState.origin2); + FX_CompressionShot( cent->lerpOrigin, cent->currentState.origin2 ); + break; + + case EV_COMPRESSION_RIFLE_ALT: + DEBUGNAME("EV_COMPRESSION_RIFLE_ALT"); + UnVectorShort(cent->currentState.origin2); + FX_CompressionAltShot( cent->lerpOrigin, cent->currentState.origin2 ); + break; + +/* case EV_IMOD: + DEBUGNAME("EV_IMOD"); + ByteToDir( es->eventParm, dir ); + FX_IMODShot( cent->lerpOrigin, cent->currentState.origin2, dir ); + break;*/ + +/* case EV_IMOD_ALTFIRE: + DEBUGNAME("EV_IMOD_ALTFIRE"); + ByteToDir( es->eventParm, dir ); + FX_AltIMODShot( cent->lerpOrigin, cent->currentState.origin2, dir ); + break;*/ + +/* case EV_IMOD_HIT: + DEBUGNAME("EV_IMOD_HIT"); ByteToDir( es->eventParm, dir ); - CG_MissileHitWall( es->weapon, 0, position, dir, IMPACTSOUND_METAL ); + FX_IMODExplosion( cent->lerpOrigin, dir ); + break;*/ + +/* case EV_IMOD_ALTFIRE_HIT: + DEBUGNAME("EV_IMOD_ALTFIRE_HIT"); + ByteToDir( es->eventParm, dir ); + FX_AltIMODExplosion( cent->lerpOrigin, dir ); + break;*/ + +/* case EV_STASIS: + DEBUGNAME("EV_STASIS"); + FX_StasisShot( cent, cent->lerpOrigin, cent->currentState.origin2 ); + break;*/ + +/* case EV_BORG_ALT_WEAPON: + DEBUGNAME("EV_BORG_ALT_WEAPON"); + FX_BorgTaser( cent->lerpOrigin, cent->currentState.origin2 ); + break;*/ + + case EV_GRENADE_EXPLODE: + DEBUGNAME("EV_GRENADE_EXPLODE"); + CG_MissileHitWall( cent, WP_8, position, normal ); break; - case EV_RAILTRAIL: - DEBUGNAME("EV_RAILTRAIL"); - cent->currentState.weapon = WP_RAILGUN; + case EV_GRENADE_SHRAPNEL_EXPLODE: + DEBUGNAME("EV_GRENADE_SHRAPNEL_EXPLODE"); + ByteToDir( es->eventParm, dir ); + FX_GrenadeShrapnelExplode( position, dir ); + break; + + case EV_GRENADE_SHRAPNEL: + DEBUGNAME("EV_GRENADE_SHRAPNEL"); + // just for beeping sound + FX_GrenadeShrapnelBits(cent->lerpOrigin); + break; + + case EV_DETPACK: + DEBUGNAME("EV_DETPACK"); + FX_Detpack(cent->lerpOrigin); + break; + +/* case EV_DREADNOUGHT_MISS: + DEBUGNAME("EV_DREADNOUGHT_MISS"); + ByteToDir( es->eventParm, dir ); + FX_DreadnoughtShotMiss( cent->lerpOrigin, dir ); + break;*/ + + case EV_TETRION: + DEBUGNAME("EV_TETRION"); + // lerpOrigin == muzzle + // angles2 == firing direction + UnVectorShort(cent->currentState.angles2); + FX_TetrionShot( cent->lerpOrigin, cent->currentState.angles2 ); + break; + + //RPG-X: RedTechie - Added for fx gun + case EV_EFFECTGUN_SHOOT: + DEBUGNAME("EV_EFFECTGUN_EXPLO"); + UnVectorShort(cent->currentState.origin2); + FX_fxfunc_Shot( cent->lerpOrigin, cent->currentState.origin2 ); + //FX_fxfunc_Explosion( cent->lerpOrigin, cent->currentState.origin2 ); + break; + + case EV_SHIELD_HIT: + DEBUGNAME("EV_SHIELD_HIT"); + ByteToDir(es->eventParm, dir); + CG_PlayerShieldHit(es->otherEntityNum, dir, es->time2); + break; + + //special effects + + case EV_FX_SPARK: + DEBUGNAME("EV_FX_SPARK"); + UnVectorShort(cent->currentState.angles2); - if(es->clientNum == cg.snap->ps.clientNum && !cg.renderingThirdPerson) + //CG_Printf( S_COLOR_RED "%f, %f, %f\n", cent->currentState.angles2[0], cent->currentState.angles2[1], cent->currentState.angles2[2] ); + CG_Spark( cent->lerpOrigin, cent->currentState.angles2, cent->currentState.time2, cent->currentState.time ); + break; + + case EV_FX_STEAM: + DEBUGNAME("EV_FX_STEAM"); + UnVectorShort(cent->currentState.angles2); + //CG_Printf( S_COLOR_RED "%f, %f, %f\n", cent->currentState.angles2[0], cent->currentState.angles2[1], cent->currentState.angles2[2] ); + CG_Steam( cent->lerpOrigin, cent->currentState.angles2, cent->currentState.time ); + break; + + case EV_FX_BOLT: + DEBUGNAME("EV_FX_BOLT"); + CG_Bolt( cent ); + break; + + case EV_FX_TRANSPORTER_PAD: + DEBUGNAME("EV_FX_TRANSPORTER_PAD"); + CG_TransporterPad(cent->lerpOrigin); + break; + + case EV_FX_DRIP: + DEBUGNAME("EV_FX_DRIP"); + CG_Drip(cent, cent->currentState.powerups ); + break; + + case EV_FX_CHUNKS: + DEBUGNAME("EV_FX_CHUNKS"); + UnVectorShort( cent->currentState.angles2 ); + CG_Chunks( cent->lerpOrigin, cent->currentState.angles2, cent->currentState.time2, cent->currentState.powerups ); + break; + + case EV_FX_GARDEN_FOUNTAIN_SPURT: + DEBUGNAME("EV_FX_GARDEN_FOUNTAIN_SPURT"); + CG_FountainSpurt( cent->lerpOrigin, cent->currentState.origin2 ); + break; + + case EV_FX_SURFACE_EXPLOSION: + DEBUGNAME("EV_FX_SURFACE_EXPLOSION"); + + // This is kind of cheap, but tom wanted a louder explosion...sigh. + // TiM - Jeez Tom... ;P + if ( cent->currentState.time2 & 2 ) { - if(cg_drawGun.integer == 2) - VectorMA(es->origin2, 8, cg.refdef.viewaxis[1], es->origin2); - else if(cg_drawGun.integer == 3) - VectorMA(es->origin2, 4, cg.refdef.viewaxis[1], es->origin2); + trap_S_StartSound(cent->lerpOrigin, es->number, CHAN_AUTO, cgs.media.bigSurfExpSound ); //CHAN_VOICE + } + else + { + trap_S_StartSound( cent->lerpOrigin, es->number, CHAN_AUTO, cgs.media.surfaceExpSound[irandom(0,2)] ); } - CG_RailTrail(ci, es->origin2, es->pos.trBase); - - // if the end was on a nomark surface, don't make an explosion - if ( es->eventParm != 255 ) { - ByteToDir( es->eventParm, dir ); - CG_MissileHitWall( es->weapon, es->clientNum, position, dir, IMPACTSOUND_DEFAULT ); - } + CG_SurfaceExplosion( cent->lerpOrigin, cent->currentState.origin2, cent->currentState.angles2[0], cent->currentState.angles2[1], + !(cent->currentState.time2 & 1) ); break; - case EV_BULLET_HIT_WALL: - DEBUGNAME("EV_BULLET_HIT_WALL"); - ByteToDir( es->eventParm, dir ); - CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qfalse, ENTITYNUM_WORLD ); + case EV_FX_SMOKE: + //VectorSubtract( cent->currentState.origin2, cent->lerpOrigin, dir ); + //VectorNormalize( dir ); + UnVectorShort(cent->currentState.angles2); + //CG_Smoke( cent->lerpOrigin, dir, cent->currentState.angles2[0], 24.0f, cgs.media.smokeShader/*, 8*/ ); + CG_Smoke( cent->lerpOrigin, cent->currentState.angles2, cent->currentState.time2, cent->currentState.time ); break; - case EV_BULLET_HIT_FLESH: - DEBUGNAME("EV_BULLET_HIT_FLESH"); - CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qtrue, es->eventParm ); + case EV_FX_ELECTRICAL_EXPLOSION: + DEBUGNAME("EV_FX_ELECTRICAL_EXPLOSION"); + trap_S_StartSound( cent->lerpOrigin, es->number, CHAN_AUTO, cgs.media.electricExpSound[irandom(0,2)] ); + CG_ElectricalExplosion( cent->lerpOrigin, cent->currentState.origin2, cent->currentState.angles2[0] ); break; - case EV_SHOTGUN: - DEBUGNAME("EV_SHOTGUN"); - CG_ShotgunFire( es ); + // RPG-X | Marcin | 24/12/2008 + case EV_FX_FIRE: + DEBUGNAME("EV_FX_FIRE"); + UnVectorShort(cent->currentState.angles2); + CG_Fire( cent->lerpOrigin, cent->currentState.angles2, cent->currentState.time2, cent->currentState.time, cent->currentState.eventParm ); + break; + // RPG-X | Marcin | 03/01/2009 + case EV_FX_SHAKE: + DEBUGNAME("EV_FX_SHAKE"); + CG_ExplosionEffects( cent->lerpOrigin, cent->currentState.time2, cent->currentState.time ); + break; + + case EV_SCREENFX_TRANSPORTER: + DEBUGNAME("EV_FULLSCREEN EFFECT"); + CG_AddFullScreenEffect(SCREENFX_TRANSPORTER, clientNum); break; case EV_GENERAL_SOUND: @@ -1028,121 +1237,77 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { } break; - case EV_GLOBAL_TEAM_SOUND: // play from the player's head so it never diminishes + /*case EV_TEAM_SOUND: // play from the player's head so it never diminishes + DEBUGNAME("EV_TEAM_SOUND"); { - DEBUGNAME("EV_GLOBAL_TEAM_SOUND"); - switch( es->eventParm ) { - case GTS_RED_CAPTURE: // CTF: red team captured the blue flag, 1FCTF: red team captured the neutral flag - if ( cgs.clientinfo[cg.clientNum].team == TEAM_RED ) - CG_AddBufferedSound( cgs.media.captureYourTeamSound ); - else - CG_AddBufferedSound( cgs.media.captureOpponentSound ); - break; - case GTS_BLUE_CAPTURE: // CTF: blue team captured the red flag, 1FCTF: blue team captured the neutral flag - if ( cgs.clientinfo[cg.clientNum].team == TEAM_BLUE ) - CG_AddBufferedSound( cgs.media.captureYourTeamSound ); - else - CG_AddBufferedSound( cgs.media.captureOpponentSound ); - break; - case GTS_RED_RETURN: // CTF: blue flag returned, 1FCTF: never used - if ( cgs.clientinfo[cg.clientNum].team == TEAM_RED ) - CG_AddBufferedSound( cgs.media.returnYourTeamSound ); - else - CG_AddBufferedSound( cgs.media.returnOpponentSound ); - // - CG_AddBufferedSound( cgs.media.blueFlagReturnedSound ); - break; - case GTS_BLUE_RETURN: // CTF red flag returned, 1FCTF: neutral flag returned - if ( cgs.clientinfo[cg.clientNum].team == TEAM_BLUE ) - CG_AddBufferedSound( cgs.media.returnYourTeamSound ); - else - CG_AddBufferedSound( cgs.media.returnOpponentSound ); - // - CG_AddBufferedSound( cgs.media.redFlagReturnedSound ); - break; + clientInfo_t *us = &cgs.clientinfo[ cg.snap->ps.clientNum ]; - case GTS_RED_TAKEN: // CTF: red team took blue flag, 1FCTF: blue team took the neutral flag - // if this player picked up the flag then a sound is played in CG_CheckLocalSounds - if (cg.snap->ps.powerups[PW_BLUEFLAG] || cg.snap->ps.powerups[PW_NEUTRALFLAG]) { + // which kind of team sound is coming through? + switch (es->eventParm) + { + case RETURN_FLAG_SOUND: + if (us->team != TEAM_SPECTATOR) + { + if (us->team == es->otherEntityNum) + { // Your flag has been returned! + trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_ANNOUNCER, cgs.media.ctfYouReturnVoiceSound); } - else { - if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) { -#ifdef MISSIONPACK - if (cgs.gametype == GT_1FCTF) - CG_AddBufferedSound( cgs.media.yourTeamTookTheFlagSound ); - else -#endif - CG_AddBufferedSound( cgs.media.enemyTookYourFlagSound ); - } - else if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) { -#ifdef MISSIONPACK - if (cgs.gametype == GT_1FCTF) - CG_AddBufferedSound( cgs.media.enemyTookTheFlagSound ); - else -#endif - CG_AddBufferedSound( cgs.media.yourTeamTookEnemyFlagSound ); - } + else + { + trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_ANNOUNCER, cgs.media.ctfTheyReturnVoiceSound); } - break; - case GTS_BLUE_TAKEN: // CTF: blue team took the red flag, 1FCTF red team took the neutral flag - // if this player picked up the flag then a sound is played in CG_CheckLocalSounds - if (cg.snap->ps.powerups[PW_REDFLAG] || cg.snap->ps.powerups[PW_NEUTRALFLAG]) { - } - else { - if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) { -#ifdef MISSIONPACK - if (cgs.gametype == GT_1FCTF) - CG_AddBufferedSound( cgs.media.yourTeamTookTheFlagSound ); - else -#endif - CG_AddBufferedSound( cgs.media.enemyTookYourFlagSound ); - } - else if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) { -#ifdef MISSIONPACK - if (cgs.gametype == GT_1FCTF) - CG_AddBufferedSound( cgs.media.enemyTookTheFlagSound ); - else -#endif - CG_AddBufferedSound( cgs.media.yourTeamTookEnemyFlagSound ); - } - } - break; - case GTS_REDOBELISK_ATTACKED: // Overload: red obelisk is being attacked - if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) { - CG_AddBufferedSound( cgs.media.yourBaseIsUnderAttackSound ); - } - break; - case GTS_BLUEOBELISK_ATTACKED: // Overload: blue obelisk is being attacked - if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) { - CG_AddBufferedSound( cgs.media.yourBaseIsUnderAttackSound ); - } - break; + } + else + { // Spectators should hear a generic return sound. + trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_ANNOUNCER, cgs.media.ctfReturnSound); + } + break; - case GTS_REDTEAM_SCORED: - CG_AddBufferedSound(cgs.media.redScoredSound); - break; - case GTS_BLUETEAM_SCORED: - CG_AddBufferedSound(cgs.media.blueScoredSound); - break; - case GTS_REDTEAM_TOOK_LEAD: - CG_AddBufferedSound(cgs.media.redLeadsSound); - break; - case GTS_BLUETEAM_TOOK_LEAD: - CG_AddBufferedSound(cgs.media.blueLeadsSound); - break; - case GTS_TEAMS_ARE_TIED: - CG_AddBufferedSound( cgs.media.teamsTiedSound ); - break; -#ifdef MISSIONPACK - case GTS_KAMIKAZE: - trap_S_StartLocalSound(cgs.media.kamikazeFarSound, CHAN_ANNOUNCER); - break; -#endif - default: - break; + case DROPPED_FLAG_SOUND: + if (us->team != TEAM_SPECTATOR) + { + if (us->team == es->otherEntityNum) + { // Your flag was dropped by the enemy. + trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_ANNOUNCER, cgs.media.ctfTheyDroppedVoiceSound); + } + else + { + trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_ANNOUNCER, cgs.media.ctfYouDroppedVoiceSound); + } + } // Spectators do not hear any sound when a flag is dropped. + break; + + case SCORED_FLAG_SOUND: + if (us->team != TEAM_SPECTATOR) + { + if (us->team == es->otherEntityNum) + { // Your flag has been touched, while you are holding the enemy flag. + trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_ANNOUNCER, cgs.media.ctfYouScoreVoiceSound); + } + else + { + trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_ANNOUNCER, cgs.media.ctfTheyScoreVoiceSound); + } + } + else + { // Spectators should hear a generic scored sound. + trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_ANNOUNCER, cgs.media.ctfScoreSound); + } + break; + + case SCORED_FLAG_NO_VOICE_SOUND: + if (us->team == es->otherEntityNum) + { + trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.media.ctfScoreSound); + } + else + { // Spectators also hear this sound, a generic score sound. + trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.media.ctfScoreSound); + } + break; } - break; } + break;*/ case EV_PAIN: // local player sounds are triggered in CG_CheckLocalSounds, @@ -1157,71 +1322,524 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { case EV_DEATH2: case EV_DEATH3: DEBUGNAME("EV_DEATHx"); - - if (CG_WaterLevel(cent) >= 1) { - trap_S_StartSound(NULL, es->number, CHAN_VOICE, CG_CustomSound(es->number, "*drown.wav")); - } else { - trap_S_StartSound(NULL, es->number, CHAN_VOICE, CG_CustomSound(es->number, va("*death%i.wav", event - EV_DEATH1 + 1))); - } - + trap_S_StartSound( NULL, es->number, CHAN_VOICE, + CG_CustomSound( es->number, va("*death%i.wav", event - EV_DEATH1 + 1) ) ); break; - case EV_OBITUARY: DEBUGNAME("EV_OBITUARY"); CG_Obituary( es ); break; + case EV_DISINTEGRATION: + DEBUGNAME("EV_DISINTEGRATION"); + cg_entities[es->number].deathTime = cg.time; + FX_Disruptor( cent->lerpOrigin, 1000 ); + if (irandom(0,1)) + { + trap_S_StartSound (NULL, es->number, CHAN_VOICE, cgs.media.disintegrateSound); + } + else + { + trap_S_StartSound (NULL, es->number, CHAN_VOICE, cgs.media.disintegrate2Sound); + } + break; + + case EV_DISINTEGRATION2: + DEBUGNAME("EV_DISINTEGRATION2"); + cg_entities[es->number].deathTime = cg.time; + FX_QuantumColumns( cent->lerpOrigin ); + FX_ExplodeBits( cent->lerpOrigin); + trap_S_StartSound (NULL, es->number, CHAN_VOICE, cgs.media.playerExplodeSound); + break; + + case EV_EXPLODESHELL: + DEBUGNAME("EV_EXPLODESHELL"); + cg_entities[es->number].deathTime = cg.time; + FX_ExplodeBits( cent->lerpOrigin); + trap_S_StartSound (NULL, es->number, CHAN_VOICE, cgs.media.playerExplodeSound); + break; + + case EV_ARCWELD_DISINT: + DEBUGNAME("EV_ARCWELD_DISINT"); + cg_entities[es->number].deathTime = cg.time; + VectorSubtract( cg.refdef.vieworg, cent->lerpOrigin, dir ); + VectorNormalize( dir ); + break; + // // powerup events // - case EV_POWERUP_QUAD: - DEBUGNAME("EV_POWERUP_QUAD"); - if ( es->number == cg.snap->ps.clientNum ) { - cg.powerupActive = PW_QUAD; - cg.powerupTime = cg.time; - } - trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.quadSound ); - break; - case EV_POWERUP_BATTLESUIT: +/* case EV_POWERUP_BATTLESUIT: DEBUGNAME("EV_POWERUP_BATTLESUIT"); if ( es->number == cg.snap->ps.clientNum ) { - cg.powerupActive = PW_BATTLESUIT; + cg.powerupActive = PW_BOLTON; cg.powerupTime = cg.time; } - trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.protectSound ); - break; - case EV_POWERUP_REGEN: + trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.invulnoProtectSound ); + break;*/ + /*case EV_POWERUP_REGEN: DEBUGNAME("EV_POWERUP_REGEN"); if ( es->number == cg.snap->ps.clientNum ) { - cg.powerupActive = PW_REGEN; + cg.powerupActive = PW_LASER; cg.powerupTime = cg.time; } trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.regenSound ); + break;*/ + case EV_POWERUP_SEEKER_FIRE: + DEBUGNAME("EV_POWERUP_SEEKER_FIRE"); + CG_FireSeeker( cent ); break; - - case EV_GIB_PLAYER: - DEBUGNAME("EV_GIB_PLAYER"); - // don't play gib sound when using the kamikaze because it interferes - // with the kamikaze sound, downside is that the gib sound will also - // not be played when someone is gibbed while just carrying the kamikaze - if ( !(es->eFlags & EF_KAMIKAZE) ) { - trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.gibSound ); - } - CG_GibPlayer( cent->lerpOrigin ); - break; - - case EV_STOPLOOPINGSOUND: - DEBUGNAME("EV_STOPLOOPINGSOUND"); - trap_S_StopLoopingSound( es->number ); - es->loopSound = 0; - break; - case EV_DEBUG_LINE: DEBUGNAME("EV_DEBUG_LINE"); - CG_Beam( cent ); + FX_AddLine(cent->lerpOrigin, cent->currentState.origin2, 1.0, 2.0, 0.0, 1.0, 0.0, 5000.0, (qhandle_t)0); break; + case EV_OBJECTIVE_COMPLETE: + if ( es->eventParm == 0 ) + {//Special code meaning clear all objectives + int i; + for ( i = 0; i < MAX_OBJECTIVES; i++ ) + { + cgs.objectives[i].complete = qfalse; + } + return; + } + if ( es->eventParm < 0 || es->eventParm > MAX_OBJECTIVES ) + {//FIXME: error message? + return; + } + cgs.objectives[es->eventParm-1].complete = qtrue; + break; + + case EV_ADAPT_SOUND: + trap_S_StartSound(NULL, es->number, CHAN_ITEM, cgs.media.invulnoProtectSound); + break; + + case EV_FX_PHASER: + s = CG_ConfigString(CS_SOUNDS + es->time); + trap_S_StartSound(NULL, es->number, CHAN_VOICE, CG_CustomSound(es->number, s)); + CG_PhaserFX(cent); + break; + + case EV_FX_DISRUPTOR: + s = CG_ConfigString(CS_SOUNDS + es->time); + trap_S_StartSound(NULL, es->number, CHAN_VOICE, CG_CustomSound(es->number, s)); + CG_DisruptorFX(cent); + break; + + case EV_SET_CLOAK: + ci->silentCloak = es->eventParm; + break; + + case EV_FX_TORPEDO: + s = CG_ConfigString( CS_SOUNDS + es->time ); + trap_S_StartSound(NULL, es->number, CHAN_VOICE, CG_CustomSound(es->number, s)); + CG_TorpedoFX(cent); + break; + + case EV_FOOTSTEP_GRASS: + DEBUGNAME("EV_FOOTSTEP_GRASS"); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; + + if ( ci->animSndIndex == -1 ) { + if (cg_footsteps.integer) { + if ( cent->beamData.beamTimeParam == 0 || + ( ( es->powerups & ( 1 << PW_BEAM_OUT ) ) && ( cg.time < cent->beamData.beamTimeParam + 2200 ) ) || + ( ( es->powerups & ( 1 << PW_QUAD ) ) && ( cg.time > cent->beamData.beamTimeParam + 1800 ) ) ) { + trap_S_StartSound (NULL, es->number, CHAN_BODY, + cgs.media.footsteps[ FOOTSTEP_GRASS ][rand()&3] ); + } + } + } + break; + + case EV_FOOTSTEP_GRAVEL: + DEBUGNAME("EV_FOOTSTEP_GRAVEL"); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; + + if ( ci->animSndIndex == -1 ) { + if (cg_footsteps.integer) { + if ( cent->beamData.beamTimeParam == 0 || + ( ( es->powerups & ( 1 << PW_BEAM_OUT ) ) && ( cg.time < cent->beamData.beamTimeParam + 2200 ) ) || + ( ( es->powerups & ( 1 << PW_QUAD ) ) && ( cg.time > cent->beamData.beamTimeParam + 1800 ) ) ) { + trap_S_StartSound (NULL, es->number, CHAN_BODY, + cgs.media.footsteps[ FOOTSTEP_GRAVEL ][rand()&3] ); + } + } + } + break; + + case EV_FOOTSTEP_SNOW: + DEBUGNAME("EV_FOOTSTEP_SNOW"); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; + + if ( ci->animSndIndex == -1 ) { + if (cg_footsteps.integer) { + if ( cent->beamData.beamTimeParam == 0 || + ( ( es->powerups & ( 1 << PW_BEAM_OUT ) ) && ( cg.time < cent->beamData.beamTimeParam + 2200 ) ) || + ( ( es->powerups & ( 1 << PW_QUAD ) ) && ( cg.time > cent->beamData.beamTimeParam + 1800 ) ) ) { + trap_S_StartSound (NULL, es->number, CHAN_BODY, + cgs.media.footsteps[ FOOTSTEP_SNOW ][rand()&3] ); + } + } + } + break; + + case EV_FOOTSTEP_WOOD: + DEBUGNAME("EV_FOOTSTEP_WOOD"); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; + + if ( ci->animSndIndex == -1 ) { + if (cg_footsteps.integer) { + if ( cent->beamData.beamTimeParam == 0 || + ( ( es->powerups & ( 1 << PW_BEAM_OUT ) ) && ( cg.time < cent->beamData.beamTimeParam + 2200 ) ) || + ( ( es->powerups & ( 1 << PW_QUAD ) ) && ( cg.time > cent->beamData.beamTimeParam + 1800 ) ) ) { + trap_S_StartSound (NULL, es->number, CHAN_BODY, + cgs.media.footsteps[ FOOTSTEP_WOOD ][rand()&3] ); + } + } + } + break; + + + case EV_FALL_SHORT_GRASS: + DEBUGNAME("EV_FALL_SHORT_GRASS"); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; + + if ( !( cent->currentState.eFlags & EF_DEAD ) ) + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound[LANDSOUND_GRASS] ); + else + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.splatSound ); + + if ( clientNum == cg.predictedPlayerState.clientNum ) { + // smooth landing z changes + cg.landChange = -8; + cg.landTime = cg.time; + } + break; + + case EV_FALL_SHORT_GRAVEL: + DEBUGNAME("EV_FALL_SHORT_GRAVEL"); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; + + if ( !( cent->currentState.eFlags & EF_DEAD ) ) + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound[LANDSOUND_GRAVEL] ); + else + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.splatSound ); + + if ( clientNum == cg.predictedPlayerState.clientNum ) { + // smooth landing z changes + cg.landChange = -8; + cg.landTime = cg.time; + } + break; + + case EV_FALL_SHORT_SNOW: + DEBUGNAME("EV_FALL_SHORT_SNOW"); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; + + if ( !( cent->currentState.eFlags & EF_DEAD ) ) + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound[LANDSOUND_SNOW] ); + else + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.splatSound ); + + if ( clientNum == cg.predictedPlayerState.clientNum ) { + // smooth landing z changes + cg.landChange = -8; + cg.landTime = cg.time; + } + break; + + case EV_FALL_SHORT_WOOD: + DEBUGNAME("EV_FALL_SHORT_WOOD"); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; + + if ( !( cent->currentState.eFlags & EF_DEAD ) ) + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound[LANDSOUND_WOOD] ); + else + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.splatSound ); + + if ( clientNum == cg.predictedPlayerState.clientNum ) { + // smooth landing z changes + cg.landChange = -8; + cg.landTime = cg.time; + } + break; + + case EV_FALL_MEDIUM_GRASS: + DEBUGNAME("EV_FALL_MEDIUM_GRASS"); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; + + if ( !( cent->currentState.eFlags & EF_DEAD ) ) + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound[LANDSOUND_GRASS] ); + else + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.splatSound ); + + // use normal pain sound trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*pain100.wav" ) ); + if ( clientNum == cg.predictedPlayerState.clientNum ) { + // smooth landing z changes + cg.landChange = -16; + cg.landTime = cg.time; + } + break; + + case EV_FALL_MEDIUM_GRAVEL: + DEBUGNAME("EV_FALL_MEDIUM_GRAVEL"); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; + + if ( !( cent->currentState.eFlags & EF_DEAD ) ) + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound[LANDSOUND_GRAVEL] ); + else + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.splatSound ); + + // use normal pain sound trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*pain100.wav" ) ); + if ( clientNum == cg.predictedPlayerState.clientNum ) { + // smooth landing z changes + cg.landChange = -16; + cg.landTime = cg.time; + } + break; + + case EV_FALL_MEDIUM_SNOW: + DEBUGNAME("EV_FALL_MEDIUM_SNOW"); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; + + if ( !( cent->currentState.eFlags & EF_DEAD ) ) + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound[LANDSOUND_SNOW] ); + else + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.splatSound ); + + // use normal pain sound trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*pain100.wav" ) ); + if ( clientNum == cg.predictedPlayerState.clientNum ) { + // smooth landing z changes + cg.landChange = -16; + cg.landTime = cg.time; + } + break; + + case EV_FALL_MEDIUM_WOOD: + DEBUGNAME("EV_FALL_MEDIUM_WOOD"); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; + + if ( !( cent->currentState.eFlags & EF_DEAD ) ) + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound[LANDSOUND_WOOD] ); + else + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.splatSound ); + + // use normal pain sound trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*pain100.wav" ) ); + if ( clientNum == cg.predictedPlayerState.clientNum ) { + // smooth landing z changes + cg.landChange = -16; + cg.landTime = cg.time; + } + break; + + case EV_FALL_FAR_GRASS: + DEBUGNAME("EV_FALL_FAR_GRASS"); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; + + //if ( ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) != BOTH_FALLDEATH1INAIR && ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) != BOTH_FALLDEATH1LAND ) + if ( !( cent->currentState.eFlags & EF_DEAD ) ) + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound[LANDSOUND_GRASS] ); + else + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.splatSound ); + + trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*fall1.wav" ) ); + cent->pe.painTime = cg.time; // don't play a pain sound right after this + if ( clientNum == cg.predictedPlayerState.clientNum ) { + // smooth landing z changes + cg.landChange = -24; + cg.landTime = cg.time; + } + break; + + case EV_FALL_FAR_GRAVEL: + DEBUGNAME("EV_FALL_FAR_GRAVEL"); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; + + //if ( ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) != BOTH_FALLDEATH1INAIR && ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) != BOTH_FALLDEATH1LAND ) + if ( !( cent->currentState.eFlags & EF_DEAD ) ) + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound[LANDSOUND_GRAVEL] ); + else + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.splatSound ); + + trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*fall1.wav" ) ); + cent->pe.painTime = cg.time; // don't play a pain sound right after this + if ( clientNum == cg.predictedPlayerState.clientNum ) { + // smooth landing z changes + cg.landChange = -24; + cg.landTime = cg.time; + } + break; + + case EV_FALL_FAR_SNOW: + DEBUGNAME("EV_FALL_FAR_SNOW"); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; + + //if ( ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) != BOTH_FALLDEATH1INAIR && ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) != BOTH_FALLDEATH1LAND ) + if ( !( cent->currentState.eFlags & EF_DEAD ) ) + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound[LANDSOUND_SNOW] ); + else + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.splatSound ); + + trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*fall1.wav" ) ); + cent->pe.painTime = cg.time; // don't play a pain sound right after this + if ( clientNum == cg.predictedPlayerState.clientNum ) { + // smooth landing z changes + cg.landChange = -24; + cg.landTime = cg.time; + } + break; + + case EV_FALL_FAR_WOOD: + DEBUGNAME("EV_FALL_FAR_WOOD"); + if ( es->powerups & ( 1 << PW_INVIS ) ) + break; + + //if ( ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) != BOTH_FALLDEATH1INAIR && ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) != BOTH_FALLDEATH1LAND ) + if ( !( cent->currentState.eFlags & EF_DEAD ) ) + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound[LANDSOUND_WOOD] ); + else + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.splatSound ); + + trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*fall1.wav" ) ); + cent->pe.painTime = cg.time; // don't play a pain sound right after this + if ( clientNum == cg.predictedPlayerState.clientNum ) { + // smooth landing z changes + cg.landChange = -24; + cg.landTime = cg.time; + } + break; + + case EV_FX_PARTICLEFIRE: + DEBUGNAME("EV_FX_PARTICLEFIRE"); + CG_ParticleFire(cent->currentState.origin, cent->currentState.time2, cent->currentState.eventParm); + break; + + case EV_SHOOTER_SOUND: + DEBUGNAME("EV_SHOOTER_SOUND"); + CG_PlayShooterSound(cent); + break; + + case EV_TRIGGER_SHOW: + DEBUGNAME("EV_TRIGGER_SHOW"); + CG_ShowTrigger(cent); + break; + + case EV_SCRIPT_SOUND: + DEBUGNAME("EV_SCRIPT_SOUND"); + b = es->eventParm >> 8; + a = es->eventParm - (b << 8); + if ( cgs.gameSounds[ a ] ) { + trap_S_StartSound (NULL, cent->currentState.number, b, cgs.gameSounds[ a ] ); + } else { + s = CG_ConfigString( CS_SOUNDS + a ); + trap_S_StartSound (NULL, cg.snap->ps.clientNum, b, CG_CustomSound( es->number, s ) ); + } + break; + + case EV_LASERTURRET_AIM: + DEBUGNAME("EV_LASERTURRET_AIM"); + CG_AimLaser( cent->currentState.origin, cent->currentState.origin2, cent->currentState.angles); + break; + + case EV_LASERTURRET_FIRE: + DEBUGNAME("EV_LASERTURRET_FIRE"); + //CG_FireLaser( cent->currentState.origin, cent->currentState.origin2, cent->currentState.angles, cent->currentState.angles2, cent->currentState.scale); + break; + + case EV_STASIS_DOOR_CLOSING: + DEBUGNAME("EV_STASIS_DOOR_CLOSING"); + CG_Printf("EV_STASIS_DOOR_CLOSING\n"); + // do alpha fade, play sound + CG_StasisDoor(cent, qtrue); + break; + + case EV_STASIS_DOOR_OPENING: + DEBUGNAME("EV_STASIS_DOOR_OPENING"); + CG_Printf("EV_STASIS_DOOR_OPENING\n"); + // do inverse alpha fade, play sound + CG_StasisDoor(cent, qfalse); + break; + +// Additional ports from SP by Harry Young + + case EV_FX_COOKING_STEAM: + DEBUGNAME("EV_FX_COOKING_STEAM"); + CG_CookingSteam( cent->currentState.origin, cent->currentState.angles[0] ); + break; + + case EV_FX_ELECFIRE: + DEBUGNAME("EV_FX_ELECFIRE"); + // Don't play this sound quite so much... + if ( rand() & 1 ) + { + //cgi_S_StartSound (NULL, es->number, CHAN_BODY, cgi_S_RegisterSound ( va("sound/ambience/spark%d.wav", Q_irand(1,6)) )); + } + CG_ElectricFire( cent->currentState.origin, cent->currentState.angles ); + break; + + case EV_FX_FORGE_BOLT: + DEBUGNAME("EV_FX_FORGE_BOLT"); + //CG_ForgeBolt( cent ); + break; + + case EV_FX_PLASMA: + DEBUGNAME("EV_FX_PLASMA"); + CG_Plasma( cent->currentState.origin, cent->currentState.origin2, cent->currentState.angles, cent->currentState.angles2, cent->currentState.weapon, cent->currentState.powerups ); + break; + + case EV_FX_STREAM: + DEBUGNAME("EV_FX_STREAM"); + //CG_ParticleStream( cent ); + break; + + case EV_FX_TRANSPORTER_STREAM: + DEBUGNAME("EV_FX_TRANSPORTER_STREAM"); + //CG_TransporterStream( cent ); + break; + + case EV_FX_EXPLOSION_TRAIL: + DEBUGNAME("EV_FX_EXPLOSION_TRAIL"); + //CG_ExplosionTrail( cent ); + break; + + case EV_FX_BORG_ENERGY_BEAM: + DEBUGNAME("EV_FX_BORG_ENERGY_BEAM"); + //CG_BorgEnergyBeam( cent ); + break; + + case EV_FX_SHIMMERY_THING: + DEBUGNAME("EV_FX_SHIMMERY_THING"); + CG_ShimmeryThing( cent->currentState.origin, cent->currentState.origin2, cent->currentState.angles ); // Radius and spawnflags + break; + + case EV_FX_BORG_BOLT: + DEBUGNAME("EV_FX_BORG_BOLT"); + if ( cent->currentState.eventParm != 2 ) //we don't want the extra stuff? + CG_Borg_Bolt_dynamic( cent ); + else + CG_Borg_Bolt_static( cent ); + break; + +// Default + default: DEBUGNAME("UNKNOWN"); CG_Error( "Unknown event: %i", event ); @@ -1243,11 +1861,6 @@ void CG_CheckEvents( centity_t *cent ) { if ( cent->previousEvent ) { return; // already fired } - // if this is a player event set the entity number of the client entity number - if ( cent->currentState.eFlags & EF_PLAYER_EVENT ) { - cent->currentState.number = cent->currentState.otherEntityNum; - } - cent->previousEvent = 1; cent->currentState.event = cent->currentState.eType - ET_EVENTS; @@ -1268,4 +1881,3 @@ void CG_CheckEvents( centity_t *cent ) { CG_EntityEvent( cent, cent->lerpOrigin ); } - diff --git a/code/cgame/cg_info.c b/code/cgame/cg_info.c index 1bf23ec..1ab7c78 100644 --- a/code/cgame/cg_info.c +++ b/code/cgame/cg_info.c @@ -1,37 +1,17 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // // cg_info.c -- display information while data is being loading #include "cg_local.h" +#include "cg_text.h" #define MAX_LOADING_PLAYER_ICONS 16 #define MAX_LOADING_ITEM_ICONS 26 -static int loadingPlayerIconCount; -static int loadingItemIconCount; -static qhandle_t loadingPlayerIcons[MAX_LOADING_PLAYER_ICONS]; -static qhandle_t loadingItemIcons[MAX_LOADING_ITEM_ICONS]; +static qhandle_t loadingPlayerIcon; +static qhandle_t loadingItemIcon; +void CG_LoadBar(void); /* =================== @@ -39,22 +19,23 @@ CG_DrawLoadingIcons =================== */ static void CG_DrawLoadingIcons( void ) { - int n; +// int n; int x, y; - for( n = 0; n < loadingPlayerIconCount; n++ ) { - x = 16 + n * 78; - y = 324-40; - CG_DrawPic( x, y, 64, 64, loadingPlayerIcons[n] ); - } + trap_R_SetColor( colorTable[CT_WHITE]); - for( n = 0; n < loadingItemIconCount; n++ ) { - y = 400-40; - if( n >= 13 ) { - y += 40; - } - x = 16 + n % 13 * 48; - CG_DrawPic( x, y, 32, 32, loadingItemIcons[n] ); + x= 500; + y = 342; + if (loadingPlayerIcon) + { + CG_DrawPic( x, y, 64, 64, loadingPlayerIcon ); + } + else if (loadingItemIcon) + { + trap_R_SetColor(colorTable[CT_LTPURPLE1]); + CG_DrawPic( x, y, 64, 64, cgs.media.weaponbox2 ); + trap_R_SetColor( NULL); + CG_DrawPic( x, y, 64, 64, loadingItemIcon ); } } @@ -80,9 +61,9 @@ void CG_LoadingItem( int itemNum ) { gitem_t *item; item = &bg_itemlist[itemNum]; - - if ( item->icon && loadingItemIconCount < MAX_LOADING_ITEM_ICONS ) { - loadingItemIcons[loadingItemIconCount++] = trap_R_RegisterShaderNoMip( item->icon ); + + if ( item->icon ) { + loadingItemIcon = trap_R_RegisterShaderNoMip( item->icon ); } CG_LoadingString( item->pickup_name ); @@ -102,39 +83,32 @@ void CG_LoadingClient( int clientNum ) { info = CG_ConfigString( CS_PLAYERS + clientNum ); - if ( loadingPlayerIconCount < MAX_LOADING_PLAYER_ICONS ) { - Q_strncpyz( model, Info_ValueForKey( info, "model" ), sizeof( model ) ); - skin = strrchr( model, '/' ); - if ( skin ) { - *skin++ = '\0'; - } else { - skin = "default"; - } - - Com_sprintf( iconName, MAX_QPATH, "models/players/%s/icon_%s.tga", model, skin ); - - loadingPlayerIcons[loadingPlayerIconCount] = trap_R_RegisterShaderNoMip( iconName ); - if ( !loadingPlayerIcons[loadingPlayerIconCount] ) { - Com_sprintf( iconName, MAX_QPATH, "models/players/characters/%s/icon_%s.tga", model, skin ); - loadingPlayerIcons[loadingPlayerIconCount] = trap_R_RegisterShaderNoMip( iconName ); - } - if ( !loadingPlayerIcons[loadingPlayerIconCount] ) { - Com_sprintf( iconName, MAX_QPATH, "models/players/%s/icon_%s.tga", DEFAULT_MODEL, "default" ); - loadingPlayerIcons[loadingPlayerIconCount] = trap_R_RegisterShaderNoMip( iconName ); - } - if ( loadingPlayerIcons[loadingPlayerIconCount] ) { - loadingPlayerIconCount++; - } + Q_strncpyz( model, Info_ValueForKey( info, "model" ), sizeof( model ) ); + skin = strchr( model, '/' ); + if ( skin ) { + //*skin++ = '\0'; + //} else { + // skin = "default"; + model[strlen(model) - strlen(skin)] = '\0'; } + //RPG-X: MODEL SYSTEM CHANGE + Com_sprintf( iconName, MAX_QPATH, "models/players_rpgx/%s/model_icon.jpg", model ); + + //Com_sprintf( iconName, MAX_QPATH, "models/players/%s/icon_%s.jpg", model, skin ); + + //CG_Printf( S_COLOR_RED "Loading %s\n", iconName ); + loadingPlayerIcon = trap_R_RegisterShaderNoMip( iconName ); //iconName; + Q_strncpyz( personality, Info_ValueForKey( info, "n" ), sizeof(personality) ); Q_CleanStr( personality ); if( cgs.gametype == GT_SINGLE_PLAYER ) { - trap_S_RegisterSound( va( "sound/player/announce/%s.wav", personality ), qtrue ); - } + trap_S_RegisterSound( va( "sound/voice/computer/misc/%s.wav", model ) ); //not exactly right since it'll miss subskins, but better than using personality + }//precache sound played in g_bot.c, PlayerIntroSound CG_LoadingString( personality ); + } @@ -143,17 +117,22 @@ void CG_LoadingClient( int clientNum ) { CG_DrawInformation Draw all the status / pacifier stuff during level loading +this overlays the ui version in ui_connect.c, UI_DrawConnectScreen ==================== */ +extern void CG_AddGameModNameToGameName( char *gamename ); void CG_DrawInformation( void ) { const char *s; const char *info; const char *sysInfo; - int y; - int value; + int y,x; +// int value; qhandle_t levelshot; - qhandle_t detail; +// qhandle_t detail; char buf[1024]; + int strlength,length; + + //trap_Cvar_Set ("rpg_playIntro", "1"); info = CG_ConfigString( CS_SERVERINFO ); sysInfo = CG_ConfigString( CS_SYSTEMINFO ); @@ -161,55 +140,94 @@ void CG_DrawInformation( void ) { s = Info_ValueForKey( info, "mapname" ); levelshot = trap_R_RegisterShaderNoMip( va( "levelshots/%s.tga", s ) ); if ( !levelshot ) { - levelshot = trap_R_RegisterShaderNoMip( "menu/art/unknownmap" ); + levelshot = trap_R_RegisterShaderNoMip( "levelshots/unknownmap" ); } + + cgs.widescreen.state = WIDESCREEN_NONE; + + trap_R_SetColor( colorTable[CT_BLACK] ); + CG_DrawPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, cgs.media.whiteShader ); + + cgs.widescreen.state = WIDESCREEN_CENTER; + + trap_R_SetColor( colorTable[CT_DKGREY] ); + CG_DrawPic( 11, 60, 260, 196, cgs.media.whiteShader ); + trap_R_SetColor( NULL ); - CG_DrawPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, levelshot ); + CG_DrawPic( 13, 62, 256, 192, levelshot ); //correct aspect + +// trap_R_SetColor( colorTable[CT_LTGREY] ); +// CG_DrawPic( 418, 82, 132, 132, cgs.media.whiteShader ); + +// trap_R_SetColor( NULL ); +// CG_DrawPic( 420, 84, 128, 128, levelshot ); // blend a detail texture over it - detail = trap_R_RegisterShader( "levelShotDetail" ); - trap_R_DrawStretchPic( 0, 0, cgs.glconfig.vidWidth, cgs.glconfig.vidHeight, 0, 0, 2.5, 2, detail ); +// detail = trap_R_RegisterShader( "levelShotDetail" ); +// trap_R_DrawStretchPic( 0, 0, cgs.glconfig.vidWidth, cgs.glconfig.vidHeight, 0, 0, 1, 1, detail ); - // draw the icons of things as they are loaded + UI_DrawProportionalString( 10, 10, ingame_text[IGT_HOLODECKSIMULATION], UI_BIGFONT, colorTable[CT_LTORANGE] ); + + + strlength = UI_ProportionalStringWidth(ingame_text[IGT_HOLODECKSIMULATION],UI_BIGFONT); + length = 582 - (strlength + 6); + + trap_R_SetColor( colorTable[CT_DKORANGE]); + CG_DrawPic( 10 + strlength + 6, 11, length, 22,cgs.media.whiteShader); +// CG_DrawPic( 224, 11, 368, 22,cgs.media.whiteShader); + CG_DrawPic( 595, 11, 32, 32,cgs.media.halfroundr_22); // Right End + + trap_R_SetColor( colorTable[CT_DKPURPLE1]); + + CG_DrawPic( 274+333, 232, -32, 32,cgs.media.corner_12_18); // LR + CG_DrawPic( 274+333, 84, -32, -32,cgs.media.corner_12_18); // UR + + CG_DrawPic( 274, 60, 314, 18,cgs.media.whiteShader); // Top + CG_DrawPic( 274, 238, 314, 18,cgs.media.whiteShader); //Bottom + CG_DrawPic( 274, 75, 10, 170,cgs.media.whiteShader); // Left + CG_DrawPic( 274+321, 78, 12, 162,cgs.media.whiteShader); // Right + + CG_LoadBar(); + + // draw the icons of thiings as they are loaded CG_DrawLoadingIcons(); // the first 150 rows are reserved for the client connection // screen to write into if ( cg.infoScreenText[0] ) { - UI_DrawProportionalString( 320, 128-32, va("Loading... %s", cg.infoScreenText), - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + UI_DrawProportionalString( 320, 442, va("%s ... %s", ingame_text[IGT_LOADING], cg.infoScreenText), + UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_LTGOLD1]); } else { - UI_DrawProportionalString( 320, 128-32, "Awaiting snapshot...", - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + UI_DrawProportionalString( 320, 442, va("%s...", ingame_text[IGT_SNAPSHOT]), + UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_LTGOLD1] ); } // draw info string information - y = 180-32; - + y = 107; + x = 288; // don't print server lines if playing a local game trap_Cvar_VariableStringBuffer( "sv_running", buf, sizeof( buf ) ); if ( !atoi( buf ) ) { // server hostname Q_strncpyz(buf, Info_ValueForKey( info, "sv_hostname" ), 1024); Q_CleanStr(buf); - UI_DrawProportionalString( 320, y, buf, - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + UI_DrawProportionalString( x, y, buf, UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_VLTGOLD1] ); y += PROP_HEIGHT; // pure server s = Info_ValueForKey( sysInfo, "sv_pure" ); if ( s[0] == '1' ) { - UI_DrawProportionalString( 320, y, "Pure Server", - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + UI_DrawProportionalString( x, y, ingame_text[IGT_PURESERVER], + UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_VLTGOLD1] ); y += PROP_HEIGHT; } // server-specific message of the day s = CG_ConfigString( CS_MOTD ); if ( s[0] ) { - UI_DrawProportionalString( 320, y, s, - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + UI_DrawProportionalString(320, y, s, + UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_VLTGOLD1] ); y += PROP_HEIGHT; } @@ -220,78 +238,631 @@ void CG_DrawInformation( void ) { // map-specific message (long map name) s = CG_ConfigString( CS_MESSAGE ); if ( s[0] ) { - UI_DrawProportionalString( 320, y, s, - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + UI_DrawProportionalString( x, y, s, + UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_VLTGOLD1] ); y += PROP_HEIGHT; } // cheats warning s = Info_ValueForKey( sysInfo, "sv_cheats" ); if ( s[0] == '1' ) { - UI_DrawProportionalString( 320, y, "CHEATS ARE ENABLED", - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + UI_DrawProportionalString( x, y, ingame_text[IGT_CHEATSAREENABLED], + UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_VLTGOLD1] ); + y += PROP_HEIGHT; + } + + // RPG-X | Marcin | 24/12/2008 + // privacy thing :p + // translate later + s = Info_ValueForKey( info, "rpg_respectPrivacy" ); + if ( atoi( s ) != 0 ) { + UI_DrawProportionalString( x, y, "PRIVACY MODE ^5ON", + UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_VLTGOLD1] ); + y += PROP_HEIGHT; + } else { + UI_DrawProportionalString( x, y, "PRIVACY MODE ^1OFF", + UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_VLTGOLD1] ); y += PROP_HEIGHT; } // game type - switch ( cgs.gametype ) { + switch ( cgs.gametype ) + { case GT_FFA: - s = "Free For All"; + s = ingame_text[IGT_GAME_FREEFORALL]; break; case GT_SINGLE_PLAYER: - s = "Single Player"; + s = ingame_text[IGT_GAME_SINGLEPLAYER]; break; case GT_TOURNAMENT: - s = "Tournament"; + s = ingame_text[IGT_GAME_TOURNAMENT]; break; case GT_TEAM: - s = "Team Deathmatch"; + s = ingame_text[IGT_GAME_TEAMHOLOMATCH]; break; case GT_CTF: - s = "Capture The Flag"; + s = ingame_text[IGT_GAME_CAPTUREFLAG]; break; -#ifdef MISSIONPACK - case GT_1FCTF: - s = "One Flag CTF"; - break; - case GT_OBELISK: - s = "Overload"; - break; - case GT_HARVESTER: - s = "Harvester"; - break; -#endif default: - s = "Unknown Gametype"; + s = ingame_text[IGT_GAME_UNKNOWN]; break; } - UI_DrawProportionalString( 320, y, s, - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + + { + char gamename[1024]; + + Q_strncpyz( gamename, s, sizeof(gamename) ); + + CG_AddGameModNameToGameName( gamename ); + + UI_DrawProportionalString( x, y, gamename, UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_VLTGOLD1] ); + } + y += PROP_HEIGHT; - value = atoi( Info_ValueForKey( info, "timelimit" ) ); +/* value = atoi( Info_ValueForKey( info, "timelimit" ) ); if ( value ) { - UI_DrawProportionalString( 320, y, va( "timelimit %i", value ), - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + UI_DrawProportionalString( x, y, va( "%s %i",ingame_text[IGT_TIME_LIMIT], value ), + UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_VLTGOLD1] ); y += PROP_HEIGHT; } - if (cgs.gametype < GT_CTF ) { + if (cgs.gametype != GT_CTF) { value = atoi( Info_ValueForKey( info, "fraglimit" ) ); if ( value ) { - UI_DrawProportionalString( 320, y, va( "fraglimit %i", value ), - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + UI_DrawProportionalString( x, y, va( "%s %i", ingame_text[IGT_POINT_LIMIT],value ), + UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_VLTGOLD1] ); y += PROP_HEIGHT; } } - if (cgs.gametype >= GT_CTF) { + if (cgs.gametype == GT_CTF) { value = atoi( Info_ValueForKey( info, "capturelimit" ) ); if ( value ) { - UI_DrawProportionalString( 320, y, va( "capturelimit %i", value ), - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + UI_DrawProportionalString( x, y, va( "%s %i",ingame_text[IGT_CAPTURE_LIMIT], value ), + UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_VLTGOLD1] ); y += PROP_HEIGHT; } + }*/ + + cgs.widescreen.state = WIDESCREEN_NONE; +} + +/* +==================== +CG_LoadBar +==================== +*/ +void CG_LoadBar(void) +{ + int x,y,pad; + + // Round LCARS buttons + y = 309; + x = 10; + pad = 22; + // First Bit (0987) + if (cg.loadLCARSStage < 1) + { + trap_R_SetColor( colorTable[CT_VDKBROWN1]); //PURPLE3]); + } + else + { + trap_R_SetColor( colorTable[CT_VLTGOLD1]); + CG_DrawPic( x + 222 - 20,y + 14, 16, 16,cgs.media.circle2); + UI_DrawProportionalString( x + 222, y + 14, ingame_text[IGT_REPLICATION_MATRIX],UI_SMALLFONT, colorTable[CT_VLTGOLD1]); + trap_R_SetColor( colorTable[CT_LTBROWN1]); //VLTPURPLE3]); + } + CG_DrawPic( x + 18, y +102, 128, 64,cgs.media.loading1); + + + if (cg.loadLCARSStage < 2) + { + trap_R_SetColor( colorTable[CT_VDKBLUE1]); + } + else + { + trap_R_SetColor( colorTable[CT_VLTGOLD1]); + CG_DrawPic( x + 222 - 20,y + 14, 16, 16,cgs.media.circle); + trap_R_SetColor( colorTable[CT_LTBLUE1]); + } + CG_DrawPic( x, y + 37, 64, 64,cgs.media.loading2); + + + if (cg.loadLCARSStage < 3) + { + trap_R_SetColor( colorTable[CT_DKGOLD1]); //VDKPURPLE1]); + } + else + { + trap_R_SetColor( colorTable[CT_VLTGOLD1]); + CG_DrawPic( x + 222 - 20,y + 14+pad, 16, 16,cgs.media.circle2); + UI_DrawProportionalString( x + 222, y + 14 + pad, ingame_text[IGT_HOLOGRAPHIC_PROJECTORS],UI_SMALLFONT, colorTable[CT_VLTGOLD1]); + trap_R_SetColor( colorTable[CT_LTGOLD1]); //LTPURPLE1]); + } + CG_DrawPic( x + 17, y, 128, 64,cgs.media.loading3); + + + if (cg.loadLCARSStage < 4) + { + trap_R_SetColor( colorTable[CT_VDKBLUE1]); //VDKPURPLE2]); + } + else + { + trap_R_SetColor( colorTable[CT_VLTGOLD1]); + CG_DrawPic( x + 222 - 20,y + 14+pad, 16, 16,cgs.media.circle); + trap_R_SetColor( colorTable[CT_LTBLUE1]); //PURPLE2]); + } + CG_DrawPic( x + 99, y, 128, 128,cgs.media.loading4); + + + if (cg.loadLCARSStage < 5) + { + trap_R_SetColor( colorTable[CT_VDKBROWN1]); //BLUE2]); + } + else + { + trap_R_SetColor( colorTable[CT_VLTGOLD1]); + CG_DrawPic( x + 222 - 20,y + 14+pad+pad, 16, 16,cgs.media.circle2); + UI_DrawProportionalString( x + 222, y + 14 + pad + pad, ingame_text[IGT_SIMULATION_DATA_BASE],UI_SMALLFONT, colorTable[CT_VLTGOLD1]); + trap_R_SetColor( colorTable[CT_LTBROWN1]); //VLTBLUE2]); + } + CG_DrawPic( x +137, y + 81, 64, 64,cgs.media.loading5); + + + if (cg.loadLCARSStage < 6) + { + trap_R_SetColor( colorTable[CT_VDKRED1]); //ORANGE]); + } + else + { + trap_R_SetColor( colorTable[CT_VLTGOLD1]); + CG_DrawPic( x + 222 - 20,y + 14+pad+pad, 16, 16,cgs.media.circle); + trap_R_SetColor( colorTable[CT_DKRED1]); //LTORANGE]); + } + CG_DrawPic( x + 45, y + 99, 128, 64,cgs.media.loading6); + + + if (cg.loadLCARSStage < 7) + { + trap_R_SetColor( colorTable[CT_VDKRED1]); //BLUE2]); + } + else + { + trap_R_SetColor( colorTable[CT_VLTGOLD1]); + CG_DrawPic( x + 222 - 20,y + 14+pad+pad+pad, 16, 16,cgs.media.circle2); + UI_DrawProportionalString( x + 222, y + 14 + pad + pad + pad, ingame_text[IGT_SAFETY_LOCKS],UI_SMALLFONT, colorTable[CT_VLTGOLD1]); + trap_R_SetColor( colorTable[CT_DKRED1]); //LTBLUE2]); + } + CG_DrawPic( x + 38, y + 24, 64, 128,cgs.media.loading7); + + if (cg.loadLCARSStage < 8) + { + trap_R_SetColor( colorTable[CT_VDKBROWN1]); //PURPLE1]); + } + else + { + trap_R_SetColor( colorTable[CT_VLTGOLD1]); + CG_DrawPic( x + 222 - 20,y + 14+pad+pad+pad, 16, 16,cgs.media.circle); + trap_R_SetColor( colorTable[CT_LTBROWN1]); //PURPLE1]); + } + CG_DrawPic( x + 78, y + 20, 128, 64,cgs.media.loading8); + + if (cg.loadLCARSStage < 9) + { + trap_R_SetColor( colorTable[CT_VDKBLUE2]); //VDKBROWN1]); + } + else + { + trap_R_SetColor( colorTable[CT_DKBLUE2]); //VLTBROWN1]); + } + CG_DrawPic( x +112, y + 66, 64, 128,cgs.media.loading9); + + + if (cg.loadLCARSStage < 9) + { + trap_R_SetColor( colorTable[CT_VDKORANGE]); //DKBLUE2]); + } + else + { + trap_R_SetColor( colorTable[CT_LTORANGE]); //LTBLUE2]); + } + CG_DrawPic( x + 62, y + 44, 128, 128,cgs.media.loadingcircle); // Center arrows + + cg.loadLCARScnt++; + if (cg.loadLCARScnt > 3) + { + cg.loadLCARScnt = 0; + } + + trap_R_SetColor( colorTable[CT_VDKBLUE1]); //DKPURPLE2]); + CG_DrawPic( x + 61, y + 43, 32, 32,cgs.media.loadingquarter); // Quad UL + CG_DrawPic( x + 135, y + 43, -32, 32,cgs.media.loadingquarter); // Quad UR + CG_DrawPic( x + 135, y +117, -32, -32,cgs.media.loadingquarter); // Quad LR + CG_DrawPic( x + 61, y +117, 32, -32,cgs.media.loadingquarter); // Quad LL + + trap_R_SetColor( colorTable[CT_LTBLUE1]); //LTPURPLE2]); + switch (cg.loadLCARScnt) + { + case 0 : + CG_DrawPic( x + 61, y + 43, 32, 32,cgs.media.loadingquarter); // Quad UL + break; + case 1 : + CG_DrawPic( x + 135, y + 43, -32, 32,cgs.media.loadingquarter); // Quad UR + break; + case 2 : + CG_DrawPic( x + 135, y +117, -32, -32,cgs.media.loadingquarter); // Quad LR + break; + case 3 : + CG_DrawPic( x + 61, y +117, 32, -32,cgs.media.loadingquarter); // Quad LL + break; + } + + UI_DrawProportionalString( x + 21, y + 150, "0987",UI_TINYFONT, colorTable[CT_BLACK]); + UI_DrawProportionalString( x + 3, y + 90, "18",UI_TINYFONT, colorTable[CT_BLACK]); + UI_DrawProportionalString( x + 24, y + 20, "7",UI_TINYFONT, colorTable[CT_BLACK]); + UI_DrawProportionalString( x + 93, y + 5, "51",UI_RIGHT|UI_TINYFONT, colorTable[CT_BLACK]); + UI_DrawProportionalString( x + 103, y + 5, "35",UI_TINYFONT, colorTable[CT_BLACK]); + UI_DrawProportionalString( x + 165, y + 83, "21",UI_TINYFONT, colorTable[CT_BLACK]); + UI_DrawProportionalString( x + 101, y + 149, "67",UI_TINYFONT, colorTable[CT_BLACK]); + UI_DrawProportionalString( x + 123, y + 36, "8",UI_TINYFONT, colorTable[CT_BLACK]); + + UI_DrawProportionalString( x + 90, y + 65, "1",UI_RIGHT|UI_TINYFONT, colorTable[CT_BLACK]); + UI_DrawProportionalString( x + 105, y + 65, "2",UI_TINYFONT, colorTable[CT_BLACK]); + UI_DrawProportionalString( x + 105, y + 87, "3",UI_TINYFONT, colorTable[CT_BLACK]); + UI_DrawProportionalString( x + 91, y + 87, "4",UI_RIGHT|UI_TINYFONT, colorTable[CT_BLACK]); + + trap_R_SetColor( colorTable[CT_DKGOLD1]); //DKBROWN1]); + y +=10; + CG_DrawPic( x + 130, y - 10 , 64, 16,cgs.media.loadingtrim); + CG_DrawPic( x + 130, y + 150, 64, -16,cgs.media.loadingtrim); + + CG_DrawPic( x + 150, y - 10, 432, 8, cgs.media.whiteShader); // Top line + CG_DrawPic( x + 150, y + 142, 432, 8, cgs.media.whiteShader); // Bottom line + CG_DrawPic( x + 583, y - 7, 16, 151, cgs.media.whiteShader); // Side line + + CG_DrawPic( x + 580, y + 1, 32, -16,cgs.media.loadingcorner); + CG_DrawPic( x + 580, y + 139, 32, 16,cgs.media.loadingcorner); + +} + +static int missionYcnt; +static int missionYpos; +static int missionInfoScreenY; + +#define OBJ_HORIZONTAL_BORDER_X 15 // Where graphic starts +#define OBJ_HORIZONTAL_BORDER_WIDTH 30 // Thickness of graphic +#define OBJ_TEXT_X_BORDER_LEFT 10 // Distance from right edge of graphic to circle graphic +#define OBJ_TEXT_X_BORDER_RIGHT 10 // Distance from right edge of text to right edge of screen +#define OBJ_CIRCLE_SIZE 16 // Size of circle graphic +#define OBJ_CIRCLE_TEXT_MARGIN 4 // Distance between circle and text +#define OBJ_TEXT_XPOS (OBJ_HORIZONTAL_BORDER_X + OBJ_HORIZONTAL_BORDER_WIDTH + OBJ_TEXT_X_BORDER_LEFT) +#define OBJ_SCREEN_HEIGHT 428 +#define OBJ_SCREEN_YMARGIN 8 +#define OBJ_SCREEN_Y2MARGIN 4 +#define OBJ_SCREEN_YBORDERTOP 20 +#define OBJ_SCREEN_YBORDERBOT 8 +#define OBJ_NORMAL_LINE_HEIGHT (PROP_HEIGHT * 1.15) +#define OBJ_ADDITIONAL_LINE_HEIGHT .20 + + + +/* +==================== +ObjectivePrint_Line +==================== +*/ +static void ObjectivePrint_Line(int strIndex,int color,centity_t *cent) +{ + char *str,*strBegin; + int y,pixelLen,charLen; + char holdText[1024], holdText2[2]; + char finalText[MAX_OBJ_LENGTH]; + int len,len_s,maxPixLength,charHeight; + + assert(cgs.objectives[strIndex].text); + + str = cgs.objectives[strIndex].text; + + len = strlen(str); + len++; + Q_strncpyz(finalText,str,len); + len_s = strlen(str); + + pixelLen = UI_ProportionalStringWidth(finalText,UI_SMALLFONT); + + str = finalText; + maxPixLength = SCREEN_WIDTH - (OBJ_TEXT_XPOS + OBJ_TEXT_X_BORDER_RIGHT + OBJ_CIRCLE_SIZE + OBJ_CIRCLE_TEXT_MARGIN); + charHeight = OBJ_NORMAL_LINE_HEIGHT; + + if (missionYcnt) // Not the very first objective to be printed? + { + missionYpos += (PROP_HEIGHT * OBJ_ADDITIONAL_LINE_HEIGHT); // Add a little space between objective lines + } + + y =missionYpos + (charHeight * (missionYcnt)); + trap_R_SetColor( colorTable[color]); + + if (cgs.objectives[strIndex].complete) + { + CG_DrawPic( OBJ_TEXT_XPOS,y, OBJ_CIRCLE_SIZE, OBJ_CIRCLE_SIZE,cgs.media.circle); + } + else + { + CG_DrawPic( OBJ_TEXT_XPOS,y, OBJ_CIRCLE_SIZE, OBJ_CIRCLE_SIZE,cgs.media.circle2); + } + + if (pixelLen < maxPixLength) // One shot - small enough to print entirely on one line + { + UI_DrawProportionalString(OBJ_TEXT_XPOS + OBJ_CIRCLE_SIZE + OBJ_CIRCLE_TEXT_MARGIN, y,str, UI_SMALLFONT, colorTable[color] ); + ++missionYcnt; + } + // Text is too long, break into lines. + else + { + pixelLen = 0; + charLen = 0; + holdText2[1] = '\0'; + strBegin = str; + + while( *str ) + { + holdText2[0] = *str; + pixelLen += UI_ProportionalStringWidth(holdText2,UI_SMALLFONT); + pixelLen += 2; // For kerning + ++charLen; + + if (pixelLen > maxPixLength ) + { //Reached max length of this line + //step back until we find a space + while ((charLen) && (*str != ' ' )) + { + --str; + --charLen; + } + + if (*str==' ') + { + ++str; // To get past space + } + + Q_strncpyz( holdText, strBegin, charLen); + holdText[charLen] = '\0'; + strBegin = str; + pixelLen = 0; + charLen = 1; + + y = missionYpos + (charHeight * missionYcnt); + + UI_DrawProportionalString(OBJ_TEXT_XPOS + OBJ_CIRCLE_SIZE + OBJ_CIRCLE_TEXT_MARGIN, y, holdText, UI_SMALLFONT, colorTable[color] ); + ++missionYcnt; + } + else if (*(str+1) == '\0') + { + ++charLen; + + y = missionYpos + (charHeight * missionYcnt); + Q_strncpyz( holdText, strBegin, charLen); + UI_DrawProportionalString(OBJ_TEXT_XPOS + OBJ_CIRCLE_SIZE + OBJ_CIRCLE_TEXT_MARGIN, y, holdText, UI_SMALLFONT, colorTable[color] ); + ++missionYcnt; + break; + } + ++str; + } + } +} + +static int Objective_LineCnt(int strIndex,centity_t *cent) +{ + char *str,*strBegin; + int pixelLen,charLen; + char holdText[1024], holdText2[2]; + char finalText[MAX_OBJ_LENGTH]; + int len,len_s,maxPixLength; + int lineCnt; + + assert(cgs.objectives[strIndex].text); + str = cgs.objectives[strIndex].text; + + len = strlen(str); + len++; + Q_strncpyz(finalText,str,len); + len_s = strlen(str); + + pixelLen = UI_ProportionalStringWidth(finalText,UI_SMALLFONT); + lineCnt = 0; + + maxPixLength = SCREEN_WIDTH - (OBJ_TEXT_XPOS + OBJ_TEXT_X_BORDER_RIGHT + OBJ_CIRCLE_SIZE + OBJ_CIRCLE_TEXT_MARGIN); + + str = finalText; + + if (pixelLen < maxPixLength) // One shot - small enough to print entirely on one line + { + lineCnt = 1; + } + // Text is too long, break into lines. + else + { + pixelLen = 0; + charLen = 0; + holdText2[1] = '\0'; + strBegin = str; + + while( *str ) + { + holdText2[0] = *str; + pixelLen += UI_ProportionalStringWidth(holdText2,UI_SMALLFONT); + pixelLen += 2; // For kerning + ++charLen; + + if (pixelLen > maxPixLength ) + { //Reached max length of this line + //step back until we find a space + while ((charLen) && (*str != ' ' )) + { + --str; + --charLen; + } + + if (*str==' ') + { + ++str; // To get past space + } + + Q_strncpyz( holdText, strBegin, charLen); + holdText[charLen] = '\0'; + strBegin = str; + pixelLen = 0; + charLen = 1; + + lineCnt++; + } + else if (*(str+1) == '\0') + { + ++charLen; + lineCnt++; + break; + } + ++str; + } + } + return (lineCnt); +} + + +/* +==================== +Objectives_Draw +==================== +*/ +static void Objectives_Draw( centity_t *cent ) +{ + int objCnt,i,lineCnt,maxLines; + int total,textYCnt,length,color; + vec4_t newColor; + + objCnt=0; + for (i=0;i maxLines) // Too many lines? + { + lineCnt = maxLines; + } + + if (lineCnt==0) // Show there are no objectives + { + Q_strncpyz(cgs.objectives[0].text,ingame_text[IGT_NONETEXT],sizeof(cgs.objectives[0].text)); + } + + textYCnt = lineCnt * OBJ_NORMAL_LINE_HEIGHT; + + // For the space between objectives + textYCnt += (objCnt-1) * (OBJ_ADDITIONAL_LINE_HEIGHT * PROP_HEIGHT); + + // Calc starting Y of text + total = OBJ_SCREEN_YMARGIN + OBJ_SCREEN_YMARGIN + OBJ_SCREEN_Y2MARGIN + OBJ_SCREEN_Y2MARGIN + + OBJ_SCREEN_YBORDERTOP + OBJ_SCREEN_YBORDERBOT + textYCnt; + + if (OBJ_SCREEN_HEIGHT < total) // This should never happen (but just in case) + { + total = OBJ_SCREEN_HEIGHT; + } + + missionInfoScreenY = ((OBJ_SCREEN_HEIGHT - total) /2) + (OBJ_SCREEN_YMARGIN + OBJ_SCREEN_YBORDERTOP); + + missionYcnt = 0; + missionYpos = missionInfoScreenY; + + // Print top of frame + trap_R_SetColor( colorTable[CT_DKPURPLE3]); + CG_DrawPic( OBJ_HORIZONTAL_BORDER_X + 10, missionInfoScreenY - (OBJ_SCREEN_YMARGIN + OBJ_SCREEN_YBORDERTOP) , + SCREEN_WIDTH - (OBJ_HORIZONTAL_BORDER_X + OBJ_TEXT_X_BORDER_RIGHT + 10), OBJ_SCREEN_YBORDERTOP, cgs.media.whiteShader); // Middle column + + // Print bottom of frame + CG_DrawPic( OBJ_HORIZONTAL_BORDER_X + 10, missionInfoScreenY - OBJ_SCREEN_YMARGIN + textYCnt + (2 * OBJ_SCREEN_YMARGIN), + SCREEN_WIDTH - (OBJ_HORIZONTAL_BORDER_X + OBJ_TEXT_X_BORDER_RIGHT + 10), OBJ_SCREEN_YBORDERBOT, cgs.media.whiteShader); // Middle column + + length = (missionInfoScreenY - OBJ_SCREEN_YMARGIN + textYCnt + (2 * OBJ_SCREEN_YMARGIN)) - (missionInfoScreenY - (OBJ_SCREEN_YMARGIN + OBJ_SCREEN_YBORDERTOP)) - 15; + + // Print left hand column of frame + CG_DrawPic( OBJ_HORIZONTAL_BORDER_X, (missionInfoScreenY - (OBJ_SCREEN_YMARGIN + OBJ_SCREEN_YBORDERTOP)) + 10, + OBJ_HORIZONTAL_BORDER_WIDTH, length, cgs.media.whiteShader); // Middle column + + // Top corner + trap_R_SetColor( colorTable[CT_DKPURPLE3]); + CG_DrawPic( OBJ_HORIZONTAL_BORDER_X, + missionInfoScreenY - (OBJ_SCREEN_YMARGIN + OBJ_SCREEN_YBORDERTOP), + 32, 32, cgs.media.corner_ul_20_30); // Top corner + + // Bottom corner + CG_DrawPic( OBJ_HORIZONTAL_BORDER_X, + (missionInfoScreenY - OBJ_SCREEN_YMARGIN + textYCnt + (2 * OBJ_SCREEN_YMARGIN))-5, + 32, 32, cgs.media.corner_ll_8_30); // Bottom corner + + UI_DrawProportionalString( OBJ_HORIZONTAL_BORDER_X + 30, missionInfoScreenY - (OBJ_SCREEN_YMARGIN + OBJ_SCREEN_YBORDERTOP) + 2, ingame_text[IGT_OBJECTIVES],UI_SMALLFONT, colorTable[CT_BLACK]); + + + // Print the background + newColor[0] = colorTable[CT_BLACK][0]; + newColor[1] = colorTable[CT_BLACK][1]; + newColor[2] = colorTable[CT_BLACK][2]; + newColor[3] = 0.5; + trap_R_SetColor(newColor); + CG_DrawPic( (OBJ_TEXT_XPOS - OBJ_TEXT_X_BORDER_LEFT), missionInfoScreenY - OBJ_SCREEN_YMARGIN, SCREEN_WIDTH - ((OBJ_TEXT_XPOS - OBJ_TEXT_X_BORDER_LEFT)+OBJ_TEXT_X_BORDER_RIGHT) , textYCnt + (2 * OBJ_SCREEN_YMARGIN), cgs.media.whiteShader); + + // Print the lines + for (i=0;ips.clientNum]; + + Objectives_Draw(cent); +} + diff --git a/code/cgame/cg_lensflares.c b/code/cgame/cg_lensflares.c new file mode 100644 index 0000000..96ee0bb --- /dev/null +++ b/code/cgame/cg_lensflares.c @@ -0,0 +1,25 @@ +/*************************************************** +Copyright TiM - UberGames, 2005 + +cg_lensflares.c - Stores all of the functions +required to draw a dynamic lensflare ingame + +The flare is broken up and drawn in separate passes: + +Ambient Glow - Colored hazy glow (controlled by a vec4_t) +that expands around the core + +Direct Glow - Much stronger glow that surrounds the +core directly + +White Core - The actual white, focussed part of the flare + +Anamorphic Streak - Horizontal line running through +the flare (Current rage in lensflare FX) + +Lens Reflections - Circular parts that go in the opposite dir +of the flare itself +***************************************************/ + +//#include "cg_local.h" +//#include "cg_text.h" diff --git a/code/cgame/cg_local.h b/code/cgame/cg_local.h index 6f0a52f..9ff47f5 100644 --- a/code/cgame/cg_local.h +++ b/code/cgame/cg_local.h @@ -1,42 +1,23 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // -#include "../qcommon/q_shared.h" -#include "../renderer/tr_types.h" + +#include "../game/q_shared.h" +#include "tr_types.h" #include "../game/bg_public.h" #include "cg_public.h" - // The entire cgame module is unloaded and reloaded on each level change, // so there is NO persistant data between levels on the client side. // If you absolutely need something stored, it can either be kept // by the server in the server stored userinfos, or stashed in a cvar. -#ifdef MISSIONPACK -#define CG_FONT_THRESHOLD 0.1 -#endif +//RPG-X | Phenix | 13/02/2005 +#define N00bSoundCount 12 #define POWERUP_BLINKS 5 +#define Q_FLASH_TIME 450 + #define POWERUP_BLINK_TIME 1000 #define FADE_TIME 200 #define PULSE_TIME 200 @@ -50,7 +31,14 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define PAIN_TWITCH_TIME 200 #define WEAPON_SELECT_TIME 1400 #define ITEM_SCALEUP_TIME 1000 + +// Zoom vars #define ZOOM_TIME 150 +#define MAX_ZOOM_FOV 5.0f +#define ZOOM_IN_TIME 1000.0f +#define ZOOM_OUT_TIME 100.0f +#define ZOOM_START_PERCENT 0.3f + #define ITEM_BLOB_TIME 200 #define MUZZLE_FLASH_TIME 20 #define SINK_TIME 1000 // time for fragments to sink into ground before going away @@ -78,42 +66,213 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define GIANT_WIDTH 32 #define GIANT_HEIGHT 48 -#define NUM_CROSSHAIRS 10 +#define NUM_FONT_BIG 1 +#define NUM_FONT_SMALL 2 -#define TEAM_OVERLAY_MAXNAME_WIDTH 12 -#define TEAM_OVERLAY_MAXLOCATION_WIDTH 16 +#define NUM_CROSSHAIRS 12 -#define DEFAULT_MODEL "sarge" -#ifdef MISSIONPACK -#define DEFAULT_TEAM_MODEL "james" -#define DEFAULT_TEAM_HEAD "*james" -#else -#define DEFAULT_TEAM_MODEL "sarge" -#define DEFAULT_TEAM_HEAD "sarge" -#endif +#define MAX_OBJECTIVES 16 +#define MAX_OBJ_LENGTH 1024 +#define MAX_OBJ_TEXT_LENGTH (MAX_OBJECTIVES*MAX_OBJ_LENGTH) -#define DEFAULT_REDTEAM_NAME "Stroggs" -#define DEFAULT_BLUETEAM_NAME "Pagans" +//beam defines used to calc player fading in beam sequence +#define PLAYER_BEAM_FADE 1500 //RPG-X: TiM - Time index for when player model fades in/out in a beam sequence +#define PLAYER_BEAM_FADETIME 1000 //Length of time the player will be fading out typedef enum { FOOTSTEP_NORMAL, - FOOTSTEP_BOOT, - FOOTSTEP_FLESH, - FOOTSTEP_MECH, - FOOTSTEP_ENERGY, + FOOTSTEP_BORG, + FOOTSTEP_REAVER, + FOOTSTEP_SPECIES, + FOOTSTEP_WARBOT, FOOTSTEP_METAL, FOOTSTEP_SPLASH, + FOOTSTEP_BOOT, + FOOTSTEP_GRASS, + FOOTSTEP_GRAVEL, + FOOTSTEP_SNOW, + FOOTSTEP_WOOD, FOOTSTEP_TOTAL } footstep_t; +//RPG-X | GSIO01 | 20/05/2009: typedef enum { - IMPACTSOUND_DEFAULT, - IMPACTSOUND_METAL, - IMPACTSOUND_FLESH -} impactSound_t; + LANDSOUND_NORMAL, + LANDSOUND_METAL, + LANDSOUND_GRASS, + LANDSOUND_GRAVEL, + LANDSOUND_SNOW, + LANDSOUND_WOOD, + + LANDSOUND_TOTAL +} landsound_t; + +// For the holodoor intro + +#define TIME_INIT 100 +#define TIME_DOOR_START 1000 +#define TIME_DOOR_DUR (TIME_FADE_START-TIME_DOOR_START) +#define TIME_FADE_START 3000 +#define TIME_FADE_DUR (TIME_INTRO-TIME_FADE_START) + +/*============================================== +TiM - Since the majority of the body models use the same anim config, +I'm going to adapt the same logic from JKA where common animations +are stored in a global array and then whenever a new model is called, +a check is done to see we already have the anims parsed, rather than +parse them allll over again. Might shave a few seconds off of loadtime +and put them towards more precious roleplaying. :) + +Hrm, they'll also need to be parsed CG and G for the emote system to fully +work. +*/ + +typedef struct animsList_s { + char animFileRoute[MAX_QPATH]; + + animation_t animations[MAX_ANIMATIONS]; +} animsList_t; + +//TiM: Borrowed from EF SP +//Data struct for necessary dynamic animation sound effects. +//Useful for proper footstep sync and emote-based sound FX. +#define MAX_ANIM_SOUNDS 64 +#define MAX_RANDOM_ANIMSOUNDS 8 +typedef struct animsounds_s +{ + int keyFrame; //Frame to play sound on + int soundIndex[MAX_RANDOM_ANIMSOUNDS]; //sound file to play - FIXME: should be an index, handle random some other way? + int numRandomAnimSounds; //string variable min for va("...%d.wav", Q_irand(lowestVa, highestVa)) + int probability; //chance sound will play, zero value will not run this test (0 = 100% basically) +} animsounds_t; + +typedef struct animsSndList_s { + char animSndFileRoute[MAX_QPATH]; + + animsounds_t upperAnimSounds[MAX_ANIM_SOUNDS]; + animsounds_t lowerAnimSounds[MAX_ANIM_SOUNDS]; +} animsSndList_t; + +//TiM : JKA had 32, but since each potential char could have a +//dif anim list in EF, I'll allocate enough space if need be. +//Hopefully, if I've done my job, we won't actually ever exceed 2. :) +extern animsSndList_t cg_animsSndList[MAX_CLIENTS]; +extern int cg_numSndAnims; + +extern animsList_t cg_animsList[MAX_CLIENTS]; +extern int cg_numAnims; + +//Unlike EF SP, the anim and sound configs here are kept separately. +//I plan to make the animsounds config into a parameter in the model +//script file. It won't use up more resources, and it'll give modders additional +//flexibilty if they wish + +//================================================ + +//Struct to hold tricorder info strings +//typedef char tricString_t[MAX_TOKEN_CHARS]; + +/*================================================= +TiM: Rank Structs +The data in these structs are necessary for each seperate +rank in order to be loaded and displayed in the client +base. +==================================================*/ + +//CLR_GREY, //Grey is only used if there is no real class or rank. So it's default +typedef enum { + CLR_RED, + CLR_GOLD, + CLR_TEAL, + CLR_GREEN, + + MAX_COLORS +} rankColor_t; + +//Data needed for each rank entry in the TAB menu +typedef struct { + float w; + float h; + + int s1; + int t1; + + int s2; + int t2; + + int gWidth; + int gHeight; + + qhandle_t graphic; +} rankMenuData_t; + +/*Data relating to the loadage +and displayage of rank pips +on player models. I've set it up +this way so models are cached AS THEY ARE USED. +The point being to limit the number of shaders +we'll actually need cached at any given point. +That MAX_SHADERS error ticks me off... T_T +*/ +typedef struct { + char boltModelPath[MAX_QPATH]; + qhandle_t boltModel; + + char boltShaderPath[MAX_QPATH]; + qhandle_t boltShader; + + qboolean triedToLoad; + + qboolean admiralRank; +} rankModelData_t; + +//POSSIBLE FIXME: A string value for each rank may be needed at some stage... not sure +//Yeah... we need the formal name for the tricorder scanner. +//And we'll also need the consoleName so we can list the possible choices if needed. +typedef struct { + char consoleName[MAX_QPATH]; + char formalName[MAX_QPATH]; + + rankMenuData_t rankMenuData[MAX_COLORS]; + + rankModelData_t rankModelData; +} ranksData_t; + +typedef struct { + rankMenuData_t rankMenuData; + + rankModelData_t rankModelData; +} defaultRankData_t; + +#define MAX_CROSSHAIRS 15 //================================================= +//TiM: Importable - Custom Crosshair Data +typedef struct { + qboolean noDraw; + + vec4_t color; + + int s1; + int t1; + + int s2; + int t2; + + //qhandle_t graphic; +} crosshairsData_t; + +//================================================= + +typedef struct { + char formalName[25]; + int radarColor[3]; + int iconColor; + qboolean showRanks; + qboolean isMedic; + qboolean isBorg; +} cg_classData_t; // player entities need to track more information // than any other type of entity. @@ -137,6 +296,11 @@ typedef struct { qboolean yawing; float pitchAngle; qboolean pitching; + + //TiM + float rollAngle; + qboolean rolling; + //eTiM int animationNumber; // may include ANIM_TOGGLEBIT animation_t *animation; @@ -145,13 +309,12 @@ typedef struct { typedef struct { - lerpFrame_t legs, torso, flag; + lerpFrame_t head, legs, torso; int painTime; int painDirection; // flip from 0 to 1 + qboolean empty; int lightningFiring; - int railFireTime; - // machinegun spinning float barrelAngle; int barrelTime; @@ -160,6 +323,24 @@ typedef struct { //================================================= +//TiM - struct containing all the necessary data required +//for the SP style transporter. Due to really whacky design on id's behalf, +//this data has to be global enough for players AND weapons +//to accept it. :P +typedef struct { + //RPG-X | TiM - Time when a transport powerup is detected. + //I originally only had one variable, but found trying to track two + //different powerups with one value was causing some undesired render effects. + //This method is far better in the fact it means much cleaner render effects, + //and also if there is a delay in the server-side teleport function, the visual FX + //on this side will still remain in sync. :) + //int beamTime; + qboolean beamInDetected; + float beamAlpha; //put in here so it's in scope for me to pass it to the weapons renderer + int beamTimeParam; +} beamData_t; + +//================================================= // centity_t have a direct corespondence with gentity_t in the game, but @@ -172,19 +353,27 @@ typedef struct centity_s { int muzzleFlashTime; // move to playerEntity? int previousEvent; - int teleportFlag; + int thinkFlag; int trailTime; // so missile trails can handle dropped initial packets - int dustTrailTime; int miscTime; - int snapShotTime; // last time this entity was found in a snapshot + vec3_t damageAngles; + int damageTime; + int deathTime; playerEntity_t pe; + beamData_t beamData; + + int cloakTime; //time index we started cloaking, for the Q-Flash + int decloakTime; + qboolean wasCloaked; + + // Unused int errorTime; // decay the error from this time - vec3_t errorOrigin; - vec3_t errorAngles; +// vec3_t errorOrigin; +// vec3_t errorAngles; qboolean extrapolated; // false if origin / angles is an interpolation vec3_t rawOrigin; @@ -195,8 +384,15 @@ typedef struct centity_s { // exact interpolated position of entity on this frame vec3_t lerpOrigin; vec3_t lerpAngles; + + int turboTime; + //qboolean unclampAngles; //TiM - Unstor player clamp angles + qboolean clampAngles; } centity_t; +//TiM - stores the time index of each client to be used when they enter a turbolift. +//it's been placed here to ensure no changes will be made to it, unlike the cent structs +extern int cg_liftEnts[MAX_CLIENTS]; //====================================================================== @@ -218,39 +414,44 @@ typedef enum { LE_MARK, LE_EXPLOSION, LE_SPRITE_EXPLOSION, - LE_FRAGMENT, LE_MOVE_SCALE_FADE, LE_FALL_SCALE_FADE, LE_FADE_RGB, LE_SCALE_FADE, - LE_SCOREPLUM, -#ifdef MISSIONPACK - LE_KAMIKAZE, - LE_INVULIMPACT, - LE_INVULJUICED, - LE_SHOWREFENTITY -#endif + LE_SCALE_FADE_SPRITE, + LE_SCALE_SINE, //RPG-X: TiM + LE_LINE, + LE_LINE2, + LE_OLINE, + LE_TRAIL, + LE_VIEWSPRITE, + LE_BEZIER, + LE_QUAD, + LE_CYLINDER, + LE_ELECTRICITY, + LE_PARTICLE, + LE_SPAWNER, + LE_FRAGMENT, + LE_STASISDOOR } leType_t; typedef enum { - LEF_PUFF_DONT_SCALE = 0x0001, // do not scale size over time - LEF_TUMBLE = 0x0002, // tumble over time, used for ejecting shells - LEF_SOUND1 = 0x0004, // sound 1 for kamikaze - LEF_SOUND2 = 0x0008 // sound 2 for kamikaze + LEF_NONE = 0x0000, // Use for "no flag" + LEF_PUFF_DONT_SCALE = 0x0001, // do not scale size over time + LEF_TUMBLE = 0x0002, // tumble over time, used for ejecting shells + LEF_MOVE = 0x0004, // Sprites and models and trails use this when they use velocity + LEF_USE_COLLISION = 0x0008, // Sprites, models and trails use this when they want to collide and bounce. + LEF_ONE_FRAME = 0x0010, // One frame only is to be shown of the entity. + LEF_ONE_FRAME_DONE = 0x0020, // This bit is set AFTER the one frame is shown. + LEF_FADE_RGB = 0x0040, // Force fading through color. + LEF_SINE_SCALE = 0x0080, // TiM-Used for non-linear ratio calcs + LEF_REVERSE_SCALE = 0x0100 // TiM-Make the scale decrease instead of increase } leFlag_t; typedef enum { LEMT_NONE, - LEMT_BURN, - LEMT_BLOOD } leMarkType_t; // fragment local entities can leave marks on walls -typedef enum { - LEBS_NONE, - LEBS_BLOOD, - LEBS_BRASS -} leBounceSoundType_t; // fragment local entities can make sounds on impacts - typedef struct localEntity_s { struct localEntity_s *prev, *next; leType_t leType; @@ -258,7 +459,6 @@ typedef struct localEntity_s { int startTime; int endTime; - int fadeInTime; float lifeRate; // 1.0 / (endTime - startTime) @@ -269,17 +469,125 @@ typedef struct localEntity_s { float color[4]; - float radius; + float frameRate; + int numFrames; + +// float radius; +// float dradius; + +// float length; +// float dlength; + + float alpha; + float dalpha; + + float shaderRate; + int numShaders; + qhandle_t *leShaders; float light; vec3_t lightColor; - leMarkType_t leMarkType; // mark to leave on fragment impact - leBounceSoundType_t leBounceSoundType; + leMarkType_t leMarkType; - refEntity_t refEntity; + union { + struct { + float radius; + float dradius; + vec3_t startRGB; + vec3_t dRGB; + } sprite; + struct { + float width; + float dwidth; + float length; + float dlength; + vec3_t startRGB; + vec3_t dRGB; + } trail; + struct { + float width; + float dwidth; + // Below are bezier specific. + vec3_t control1; // initial position of control points + vec3_t control2; + vec3_t control1_velocity; // initial velocity of control points + vec3_t control2_velocity; + vec3_t control1_acceleration; // constant acceleration of control points + vec3_t control2_acceleration; + } line; + struct { + float width; + float dwidth; + float width2; + float dwidth2; + vec3_t startRGB; + vec3_t dRGB; + } line2; + struct { + float width; + float dwidth; + float width2; + float dwidth2; + float height; + float dheight; + } cylinder; + struct { + float width; + float dwidth; + } electricity; + struct + { + // fight the power! open and close brackets in the same column! + float radius; + float dradius; + qboolean (*thinkFn)(struct localEntity_s *le); + vec3_t dir; // magnitude is 1, but this is oldpos - newpos right before the + //particle is sent to the renderer + // may want to add something like particle::localEntity_s *le (for the particle's think fn) + } particle; + struct + { + qboolean dontDie; + vec3_t dir; + float variance; + int delay; + int nextthink; + qboolean (*thinkFn)(struct localEntity_s *le); + int data1; + int data2; + } spawner; + struct + { + float radius; + } fragment; + } data; + + refEntity_t refEntity; + + vec3_t addOrigin; } localEntity_t; +// kef -- there may well be a cleaner way of doing this, but the think functions for particles +//will need access to these CG_AddXXXXXX functions, so... +void CG_AddMoveScaleFade( localEntity_t *le ); +void CG_AddScaleFade( localEntity_t *le ); +void CG_AddFallScaleFade( localEntity_t *le ); +void CG_AddExplosion( localEntity_t *ex ); +void CG_AddSpriteExplosion( localEntity_t *le ); +void CG_AddScaleFadeSprite( localEntity_t *le ); +void CG_AddQuad( localEntity_t *le ); +void CG_AddLine( localEntity_t *le ); +void CG_AddOLine( localEntity_t *le ); +void CG_AddLine2( localEntity_t *le ); +void CG_AddTrail( localEntity_t *le ); +void CG_AddViewSprite( localEntity_t *le ); +void CG_AddBezier( localEntity_t *le ); +void CG_AddCylinder( localEntity_t *le ); +void CG_AddElectricity( localEntity_t *le ); +// IMPORTANT!! Don't make CG_AddParticle or CG_AddSpawner available here to prevent unpalateable recursion possibilities +// + //====================================================================== @@ -289,38 +597,61 @@ typedef struct { int ping; int time; int scoreFlags; - int powerUps; - int accuracy; - int impressiveCount; - int excellentCount; - int guantletCount; - int defendCount; - int assistCount; - int captures; - qboolean perfect; - int team; +// int faveTarget; +// int faveTargetKills; // # of times you killed fave target + int worstEnemy; + int worstEnemyKills; // # of times worst Enemy Killed you + int faveWeapon; // your favorite weapon + int killedCnt; // # of times you were killed } score_t; +//********************************************************** +//RPG-X Player Model Additional Data +//This is the struct where all the data loaded from .model files +//is parsed to. From there, it can be plugged straight into +//the original model loading pipeline.... I think +//********************************************************** +#define MAX_BOLTONS 10 +#define MAX_TALK_SKINS 4 + +typedef enum { + BOLTON_HEAD = 0, + BOLTON_TORSO, + BOLTON_LEGS, + BOLTON_MAX +} boltonLoc_t; + +//min and max value for any timed events +typedef struct { + int nextTime; + + int minSeconds; + int maxSeconds; +} charSecs_t; + +typedef struct { + int modelBase; + char tagName[MAX_QPATH]; + qhandle_t tagModel; +} boltonTags_t; + + // each client has an associated clientInfo_t // that contains media references necessary to present the // client model and other color coded effects // this is regenerated each time a client's configstring changes, // usually as a result of a userinfo (name, model, etc) change #define MAX_CUSTOM_SOUNDS 32 - typedef struct { qboolean infoValid; char name[MAX_QPATH]; team_t team; + pclass_t pClass; int botSkill; // 0 = not bot, 1-5 = bot - vec3_t color1; - vec3_t color2; - - byte c1RGBA[4]; - byte c2RGBA[4]; + vec3_t color; int score; // updated by score servercmds int location; // location index for team mode @@ -331,35 +662,23 @@ typedef struct { int handicap; int wins, losses; // in tourney mode - int teamTask; // task in teamplay (offence/defence) - qboolean teamLeader; // true when this is a team leader - int powerups; // so can display quad/flag status + qboolean eliminated; // so can display quad/flag status - int medkitUsageTime; - int invulnerabilityStartTime; - int invulnerabilityStopTime; - - int breathPuffTime; + qboolean hasRanks; //displays ranks on model or not // when clientinfo is changed, the loading of models/skins/sounds // can be deferred until you are dead, to prevent hitches in // gameplay + char charName[MAX_QPATH]; char modelName[MAX_QPATH]; char skinName[MAX_QPATH]; - char headModelName[MAX_QPATH]; - char headSkinName[MAX_QPATH]; - char redTeam[MAX_TEAMNAME]; - char blueTeam[MAX_TEAMNAME]; qboolean deferred; - qboolean newAnims; // true if using the new mission pack animations - qboolean fixedlegs; // true if legs yaw is always the same as torso yaw - qboolean fixedtorso; // true if torso never changes yaw - vec3_t headOffset; // move head in icon views footstep_t footsteps; gender_t gender; // from model + char soundPath[MAX_QPATH]; //from model qhandle_t legsModel; qhandle_t legsSkin; @@ -370,11 +689,62 @@ typedef struct { qhandle_t headModel; qhandle_t headSkin; + //int numBoltOns; + boltonTags_t boltonTags[MAX_BOLTONS]; + + //TiM - Additional Parameters + qhandle_t headSkinBlink; + + //frowning + qhandle_t headSkinFrown; + qhandle_t headSkinFrownBlink; + + charSecs_t headBlinkTime; + //charSecs_t headFrownTime; + + //TiM + qhandle_t headSkinTalk[MAX_TALK_SKINS]; + int nextTalkTime; + int currentTalkSkin; + + int nextTalkAngle; //Time index until the new talk angles are calculated + int talkDifferential; //Length of time between changes, without cg.time added + vec3_t talkAngles; //decimal values to offset the head orientation + int headDebounceTime; //Time to spend checking for talking checks + + qhandle_t holsterModel; //RPG-X : TiM + //-- + + //char race[256]; + qhandle_t modelIcon; - animation_t animations[MAX_TOTALANIMATIONS]; + //TiM - Whoa... this thing is pretty huge now thanks to the 50+ anims I added :/ + //animation_t animations[MAX_ANIMATIONS]; + //animation_t *animations; + int animIndex; //index to the array cell with the anim data we want in it. :) + int animSndIndex; //index to the array cell where the sound data for certain anims is kept. sfxHandle_t sounds[MAX_CUSTOM_SOUNDS]; + int numTaunts; + + qboolean animsFlushed; + + //Player Model System Custom Parameters + //TiM + char age[MAX_NAME_LENGTH]; + float height; + float weight; + char race[MAX_NAME_LENGTH]; + //-- + + int modelOffset; + + qboolean isAdmin; //local store to determine if client is an admin or not (for both class and login) + + qboolean isHazardModel; //yeh lame lol + + int silentCloak; } clientInfo_t; @@ -386,35 +756,40 @@ typedef struct weaponInfo_s { gitem_t *item; qhandle_t handsModel; // the hands don't actually draw, they just position the weapon - qhandle_t weaponModel; - qhandle_t barrelModel; + qhandle_t weaponModel; // this is the pickup model + qhandle_t viewModel; // this is the in-view model used by the player + qhandle_t barrelModel[4]; // Trek weapons have lots of barrels qhandle_t flashModel; vec3_t weaponMidpoint; // so it will rotate centered instead of by tag - float flashDlight; vec3_t flashDlightColor; - sfxHandle_t flashSound[4]; // fast firing weapons randomly choose + + sfxHandle_t flashSound; // fast firing weapons randomly choose + sfxHandle_t altFlashSnd; + sfxHandle_t stopSound; + sfxHandle_t altStopSound; + sfxHandle_t firingSound; + sfxHandle_t altFiringSound; +// sfxHandle_t missileSound; + sfxHandle_t alt_missileSound; + sfxHandle_t mainHitSound; + sfxHandle_t altHitSound; qhandle_t weaponIcon; - qhandle_t ammoIcon; - qhandle_t ammoModel; +// qhandle_t ammoModel; qhandle_t missileModel; - sfxHandle_t missileSound; void (*missileTrailFunc)( centity_t *, const struct weaponInfo_s *wi ); float missileDlight; vec3_t missileDlightColor; - int missileRenderfx; - void (*ejectBrassFunc)( centity_t * ); + qhandle_t alt_missileModel; + void (*alt_missileTrailFunc)( centity_t *, const struct weaponInfo_s *wi ); + float alt_missileDlight; - float trailRadius; - float wiTrailTime; - - sfxHandle_t readySound; - sfxHandle_t firingSound; + qboolean isAnimSndBased; //TiM - play this sound, only if the player has no anim sound cfg. } weaponInfo_t; @@ -423,7 +798,7 @@ typedef struct weaponInfo_s { // item and its effects typedef struct { qboolean registered; - qhandle_t models[MAX_ITEM_MODELS]; + qhandle_t model; qhandle_t icon; } itemInfo_t; @@ -432,29 +807,26 @@ typedef struct { int itemNum; } powerupInfo_t; - -#define MAX_SKULLTRAIL 10 - typedef struct { - vec3_t positions[MAX_SKULLTRAIL]; - int numpositions; -} skulltrail_t; + char text[MAX_OBJ_LENGTH]; + char abridgedText[MAX_OBJ_LENGTH]; + qboolean complete; +} objective_t; - -#define MAX_REWARDSTACK 10 -#define MAX_SOUNDBUFFER 20 +//TiM - Data needed for FPS Body CVAR +typedef struct { + int anim; + int offset; + float sizeOffset; +} fpsBody_t; //====================================================================== // all cg.stepTime, cg.duckTime, cg.landTime, etc are set to cg.time when the action // occurs, and they will have visible effects for #define STEP_TIME or whatever msec after - -#define MAX_PREDICTED_EVENTS 16 typedef struct { int clientFrame; // incremented each frame - - int clientNum; qboolean demoPlayback; qboolean levelShot; // taking a level menu screenshot @@ -486,8 +858,6 @@ typedef struct { int timelimitWarnings; // 5 min, 1 min, overtime int fraglimitWarnings; - qboolean mapRestart; // set on a map restart to set back the weapon - qboolean renderingThirdPerson; // during deaths, chasecams, etc // prediction state @@ -498,9 +868,6 @@ typedef struct { int predictedErrorTime; vec3_t predictedError; - int eventSequence; - int predictableEvents[MAX_PREDICTED_EVENTS]; - float stepChange; // for stair up smoothing int stepTime; @@ -525,6 +892,7 @@ typedef struct { // zoom key qboolean zoomed; + qboolean zoomLocked; int zoomTime; float zoomSensitivity; @@ -534,26 +902,11 @@ typedef struct { // scoreboard int scoresRequestTime; int numScores; - int selectedScore; int teamScores[2]; score_t scores[MAX_CLIENTS]; qboolean showScores; - qboolean scoreBoardShowing; int scoreFadeTime; char killerName[MAX_NAME_LENGTH]; - char spectatorList[MAX_STRING_CHARS]; // list of names - int spectatorLen; // length of list - float spectatorWidth; // width in device units - int spectatorTime; // next time to offset - int spectatorPaintX; // current paint x - int spectatorPaintX2; // current paint x - int spectatorOffset; // current offset from start - int spectatorPaintLen; // current offset from start - -#ifdef MISSIONPACK - // skull trails - skulltrail_t skulltrails[MAX_CLIENTS]; -#endif // centerprinting int centerPrintTime; @@ -565,6 +918,9 @@ typedef struct { // low ammo warning state int lowAmmoWarning; // 1 = low, 2 = empty + // kill timers for carnage reward + int lastKillTime; + // crosshair client ID int crosshairClientNum; int crosshairClientTime; @@ -575,25 +931,11 @@ typedef struct { // attacking player int attackerTime; - int voiceTime; // reward medals - int rewardStack; int rewardTime; - int rewardCount[MAX_REWARDSTACK]; - qhandle_t rewardShader[MAX_REWARDSTACK]; - qhandle_t rewardSound[MAX_REWARDSTACK]; - - // sound buffer mainly for announcer sounds - int soundBufferIn; - int soundBufferOut; - int soundTime; - qhandle_t soundBuffer[MAX_SOUNDBUFFER]; - - // for voice chat buffer - int voiceChatTime; - int voiceChatBufferIn; - int voiceChatBufferOut; + int rewardCount; + qhandle_t rewardShader; // warmup countdown int warmup; @@ -611,9 +953,11 @@ typedef struct { // blend blobs float damageTime; - float damageX, damageY, damageValue; + float damageX, damageY, damageValue, damageShieldValue; // status bar head + //RPG-X | Phenix | 09/06/2005 + // Raven commented this out! float headYaw; float headEndPitch; float headEndYaw; @@ -622,319 +966,464 @@ typedef struct { float headStartYaw; int headStartTime; + int interfaceStartupTime; // Timer for menu graphics + int interfaceStartupDone; // True when menu is done starting up + // view movement float v_dmg_time; float v_dmg_pitch; float v_dmg_roll; + vec3_t kick_angles; // weapon kicks + vec3_t kick_origin; + // temp working variables for player view float bobfracsin; int bobcycle; float xyspeed; - int nextOrbitTime; - //qboolean cameraMode; // if rendering from a loaded camera + //Shake information + float shake_intensity; + int shake_duration; + int shake_start; + int shake_serverIndex; //end time for the server so client-side shakes don't stop it + //TiM : RPG-X Shake Info To try and make it look better + int shake_nextLerp, shake_lastLerp; //next cg.time value where a new random lerp value will be chosen (Updating per frame makes me motion sick due to its l33t jerkiness ) + vec3_t shake_LerpAngle, shake_LerpOrigin; //Relevant data to lerp to + vec3_t shake_LastAngle, shake_LastOrigin; // development tool refEntity_t testModelEntity; char testModelName[MAX_QPATH]; qboolean testGun; + int loadLCARSStage; + int loadLCARScnt; + qboolean showObjectives; + int mod;//method O' death + + //RPG-X | Phenix | 08/06/2005 + //RPG-X | TiM | 13/2/2006 - Moved here for standardisation + int adminMsgTime; + char adminMsgMsg[MAX_OBJ_LENGTH]; + + //TiM : ThirdPersonZoom Booleans + //These are inserted into the thirdperson camera func + qboolean zoomedForward; + qboolean zoomedBackward; + qboolean zoomedLeft; + qboolean zoomedRight; + qboolean zoomedUp; + qboolean zoomedDown; + + qboolean zoomAngleLeft; + qboolean zoomAngleRight; + + qboolean zoomPitchDown; + qboolean zoomPitchUp; + + //TiM - The body in FPS mode + fpsBody_t fpsBody; + + //TiM - A local boolean for the TPS view + qboolean thirdPersonNoLerp; + + // cinematics + int cinematicFade; } cg_t; +typedef enum +{ + MT_NONE = 0, + MT_METAL, + MT_GLASS, + MT_GLASS_METAL, + MT_WOOD, + MT_STONE, + + NUM_CHUNK_TYPES + +} material_type_t; + +#define NUM_CHUNKS 6 + // all of the model, shader, and sound references that are // loaded at gamestate time are stored in cgMedia_t // Other media that can be tied to clients, weapons, or items are // stored in the clientInfo_t, itemInfo_t, weaponInfo_t, and powerupInfo_t typedef struct { qhandle_t charsetShader; + qhandle_t charsetPropTiny; qhandle_t charsetProp; - qhandle_t charsetPropGlow; + qhandle_t charsetPropBig; +// qhandle_t charsetPropGlow; qhandle_t charsetPropB; qhandle_t whiteShader; + qhandle_t white2Shader; -#ifdef MISSIONPACK - qhandle_t redCubeModel; - qhandle_t blueCubeModel; - qhandle_t redCubeIcon; - qhandle_t blueCubeIcon; -#endif qhandle_t redFlagModel; qhandle_t blueFlagModel; - qhandle_t neutralFlagModel; - qhandle_t redFlagShader[3]; - qhandle_t blueFlagShader[3]; - qhandle_t flagShader[4]; - - qhandle_t flagPoleModel; - qhandle_t flagFlapModel; - - qhandle_t redFlagFlapSkin; - qhandle_t blueFlagFlapSkin; - qhandle_t neutralFlagFlapSkin; - - qhandle_t redFlagBaseModel; - qhandle_t blueFlagBaseModel; - qhandle_t neutralFlagBaseModel; - -#ifdef MISSIONPACK - qhandle_t overloadBaseModel; - qhandle_t overloadTargetModel; - qhandle_t overloadLightsModel; - qhandle_t overloadEnergyModel; - - qhandle_t harvesterModel; - qhandle_t harvesterRedSkin; - qhandle_t harvesterBlueSkin; - qhandle_t harvesterNeutralModel; -#endif - - qhandle_t armorModel; - qhandle_t armorIcon; + qhandle_t redFlagShader[4]; + qhandle_t blueFlagShader[4]; qhandle_t teamStatusBar; qhandle_t deferShader; + //qhandle_t eliminatedShader; - // gib explosions - qhandle_t gibAbdomen; - qhandle_t gibArm; - qhandle_t gibChest; - qhandle_t gibFist; - qhandle_t gibFoot; - qhandle_t gibForearm; - qhandle_t gibIntestine; - qhandle_t gibLeg; - qhandle_t gibSkull; - qhandle_t gibBrain; +// recently added Trek shaders - qhandle_t smoke2; + qhandle_t phaserShader; + qhandle_t phaserEmptyShader; + qhandle_t phaserAltShader; + qhandle_t phaserAltEmptyShader; + qhandle_t phaserMuzzleEmptyShader; - qhandle_t machinegunBrassModel; - qhandle_t shotgunBrassModel; + qhandle_t testDetpackShader3; + qhandle_t testDetpackRingShader1; + qhandle_t testDetpackRingShader2; + qhandle_t testDetpackRingShader3; + qhandle_t testDetpackRingShader4; + qhandle_t testDetpackRingShader5; + qhandle_t testDetpackRingShader6; - qhandle_t railRingsShader; - qhandle_t railCoreShader; + qhandle_t detpackPlacedIcon; - qhandle_t lightningShader; + //qhandle_t dnBoltShader; - qhandle_t friendShader; + //qhandle_t stasisRingShader; + //qhandle_t stasisAltShader; - qhandle_t balloonShader; + qhandle_t disruptorBolt; + qhandle_t disruptorStreak; + + qhandle_t whiteRingShader; + qhandle_t orangeRingShader; + qhandle_t quantumExplosionShader; + qhandle_t quantumFlashShader; + + //qhandle_t scavengerAltShader; + + /*qhandle_t imodExplosionShader; + qhandle_t IMODShader; + qhandle_t IMOD2Shader; + qhandle_t altIMODShader; + qhandle_t altIMOD2Shader;*/ + + qhandle_t prifleBeam; + qhandle_t prifleImpactShader; + qhandle_t compressionAltBeamShader; + qhandle_t compressionAltBlastShader; + qhandle_t prifleBolt; + qhandle_t flashlightModel; + + qhandle_t disruptorBeam; + //qhandle_t greenBurstShader; + //qhandle_t greenTrailShader; + //qhandle_t tetrionTrail2Shader; + //qhandle_t tetrionFlareShader; + qhandle_t borgFlareShader; + //qhandle_t bulletmarksShader; + qhandle_t borgLightningShaders[4]; + + //qhandle_t bigBoomShader; + //qhandle_t scavExplosionFastShader; + //qhandle_t scavExplosionSlowShader; + + qhandle_t sunnyFlareShader; + qhandle_t scavMarkShader; + qhandle_t sparkShader; + qhandle_t spark2Shader; + qhandle_t steamShader; + qhandle_t fireShader; //RPG-X | Marcin | 24/12/2008 + qhandle_t fire2Shader; //RPG-X | Marcin | 24/12/2008 + qhandle_t fire3Shader; //RPG-X | Marcin | 24/12/2008 + qhandle_t smokeShader; + //qhandle_t IMODMarkShader; + qhandle_t waterDropShader; + qhandle_t oilDropShader; + qhandle_t greenDropShader; + + //RPG-X | GSIO01 | 11/05/2009: + qhandle_t quantumGlow; + qhandle_t quantumRays; + qhandle_t photonGlow; + qhandle_t photonRay; + qhandle_t fireParticle; + + qhandle_t explosionModel; + qhandle_t nukeModel; + //qhandle_t electricalExplosionFastShader;// These are used to have a bit of variation in the explosions + qhandle_t electricalExplosionSlowShader; + qhandle_t surfaceExplosionShader; + //qhandle_t purpleParticleShader; + qhandle_t blueParticleShader; + qhandle_t ltblueParticleShader; + + qhandle_t yellowParticleShader; + qhandle_t orangeParticleShader; + qhandle_t dkorangeParticleShader; + qhandle_t orangeTrailShader; + qhandle_t compressionMarkShader; + + qhandle_t redFlareShader; + qhandle_t redRingShader; + qhandle_t redRing2Shader; + qhandle_t bigShockShader; + qhandle_t plasmaShader; + qhandle_t bolt2Shader; + qhandle_t quantumRingShader; + + //qhandle_t holoOuchShader; + qhandle_t painBlobShader; + qhandle_t painShieldBlobShader; + //qhandle_t shieldBlobShader; + //qhandle_t halfShieldShader; + //qhandle_t holoDecoyShader; + + qhandle_t trans1Shader; + qhandle_t trans2Shader; + + //TiM - SP Transporter FX shaders + qhandle_t transport1Shader; + qhandle_t transport2Shader; + + qhandle_t fountainShader; + qhandle_t rippleShader; +// end recently added Trek shaders + + //qhandle_t teamRedShader; + //qhandle_t teamBlueShader; + + //qhandle_t chatShader; qhandle_t connectionShader; - qhandle_t selectShader; - qhandle_t viewBloodShader; - qhandle_t tracerShader; - qhandle_t crosshairShader[NUM_CROSSHAIRS]; + //qhandle_t selectShader; + //qhandle_t crosshairShader[NUM_CROSSHAIRS]; + qhandle_t laserShader; // LASER + qhandle_t lagometerShader; qhandle_t backTileShader; - qhandle_t noammoShader; + //qhandle_t noammoShader; - qhandle_t smokePuffShader; qhandle_t smokePuffRageProShader; - qhandle_t shotgunSmokePuffShader; - qhandle_t plasmaBallShader; qhandle_t waterBubbleShader; - qhandle_t bloodTrailShader; -#ifdef MISSIONPACK - qhandle_t nailPuffShader; - qhandle_t blueProxMine; -#endif qhandle_t numberShaders[11]; + qhandle_t smallnumberShaders[11]; qhandle_t shadowMarkShader; - qhandle_t botSkillShaders[5]; + //qhandle_t botSkillShaders[5]; + + //TiM + //qhandle_t pClassShaders[NUM_PLAYER_CLASSES]; + //qhandle_t borgIconShader; + //qhandle_t borgQueenIconShader; + //qhandle_t heroSpriteShader; + //-TiM + + + // Zoom + qhandle_t zoomMaskShader; + qhandle_t zoomMask116Shader; + qhandle_t zoomGlow116Shader; + /*qhandle_t zoomBarShader; + qhandle_t zoomInsertShader; + qhandle_t zoomArrowShader; + qhandle_t ammoslider;*/ // wall mark shaders qhandle_t wakeMarkShader; - qhandle_t bloodMarkShader; - qhandle_t bulletMarkShader; - qhandle_t burnMarkShader; qhandle_t holeMarkShader; - qhandle_t energyMarkShader; + qhandle_t energyMarkShader; // powerup shaders - qhandle_t quadShader; - qhandle_t redQuadShader; - qhandle_t quadWeaponShader; - qhandle_t invisShader; - qhandle_t regenShader; - qhandle_t battleSuitShader; - qhandle_t battleWeaponShader; - qhandle_t hastePuffShader; - qhandle_t redKamikazeShader; - qhandle_t blueKamikazeShader; + //qhandle_t quadShader; + //qhandle_t redQuadShader; + //qhandle_t quadWeaponShader; + //qhandle_t invisShader; + //qhandle_t regenShader; + //qhandle_t battleSuitShader; + //qhandle_t battleWeaponShader; + //qhandle_t hastePuffShader; + //qhandle_t flightPuffShader; + //qhandle_t seekerModel; + qhandle_t disruptorShader; + qhandle_t explodeShellShader; + qhandle_t quantumDisruptorShader; + qhandle_t borgFullBodyShieldShader; + + qhandle_t transportShader; //RPG-X : TiM - SP Transport Shader + qhandle_t transportKlingon; + qhandle_t transportRomulan; + qhandle_t transportCardassian; + + qhandle_t weaponPlaceholderShader; + qhandle_t rezOutShader; + qhandle_t electricBodyShader; + + //eyebeam/tripwire shaders + qhandle_t whiteLaserShader; + qhandle_t borgEyeFlareShader; // weapon effect models - qhandle_t bulletFlashModel; - qhandle_t ringFlashModel; - qhandle_t dishFlashModel; - qhandle_t lightningExplosionModel; + //qhandle_t ringFlashModel; // weapon effect shaders - qhandle_t railExplosionShader; - qhandle_t plasmaExplosionShader; - qhandle_t bulletExplosionShader; - qhandle_t rocketExplosionShader; - qhandle_t grenadeExplosionShader; - qhandle_t bfgExplosionShader; - qhandle_t bloodExplosionShader; + //qhandle_t bloodExplosionShader; // special effects models qhandle_t teleportEffectModel; qhandle_t teleportEffectShader; -#ifdef MISSIONPACK - qhandle_t kamikazeEffectModel; - qhandle_t kamikazeShockWave; - qhandle_t kamikazeHeadModel; - qhandle_t kamikazeHeadTrail; - qhandle_t guardPowerupModel; - qhandle_t scoutPowerupModel; - qhandle_t doublerPowerupModel; - qhandle_t ammoRegenPowerupModel; - qhandle_t invulnerabilityImpactModel; - qhandle_t invulnerabilityJuicedModel; - qhandle_t medkitUsageModel; - qhandle_t dustPuffShader; - qhandle_t heartShader; -#endif - qhandle_t invulnerabilityPowerupModel; + qhandle_t shieldActivateShaderBlue; + //RPG-X START | GSIO01 | 09/05/2009 + qhandle_t shieldActivateShaderBorg; + qhandle_t shieldActivateShaderYellow; + //RPG-Y END + //qhandle_t shieldDamageShaderBlue; + qhandle_t shieldActivateShaderRed; + qhandle_t shieldDamageShaderRed; + + qhandle_t holoDoorModel; + qhandle_t chunkModels[NUM_CHUNK_TYPES][NUM_CHUNKS]; + + //RPG-X: RedTechie - Register Endcaps for scoreboard + qhandle_t scoreboardtopleft; + qhandle_t scoreboardtopright; + qhandle_t scoreboardbotleft; + qhandle_t scoreboardbotright; - // scoreboard headers - qhandle_t scoreboardName; - qhandle_t scoreboardPing; - qhandle_t scoreboardScore; - qhandle_t scoreboardTime; + //RPG-X: RedTechie - Register new healthbar + qhandle_t healthbigcurve; + qhandle_t healthendcap; + + //TiM + qhandle_t healthSineWave; + + //RPG-X: RedTechie - Registered Cloak Sprite + qhandle_t cloakspriteShader; + + qhandle_t scoreboardEndcap; + qhandle_t weaponbox; + qhandle_t weaponbox2; + qhandle_t corner_12_24; + qhandle_t corner_8_16_b; + + qhandle_t weaponcap1; + qhandle_t weaponcap2; // medals shown during gameplay - qhandle_t medalImpressive; + /*qhandle_t medalImpressive; qhandle_t medalExcellent; - qhandle_t medalGauntlet; - qhandle_t medalDefend; - qhandle_t medalAssist; - qhandle_t medalCapture; + qhandle_t medalFirstStrike; + qhandle_t medalAce; + qhandle_t medalExpert; + qhandle_t medalMaster; + qhandle_t medalChampion;*/ + + // Holodeck doors + //qhandle_t doorbox; + + //RPG-X Mod + //qhandle_t rpgxlogo; + qhandle_t greenParticleShader; + qhandle_t greenParticleStreakShader; + //qhandle_t blueParticleStreakShader; + + qhandle_t liteRedParticleStreakShader; + qhandle_t liteRedParticleShader; + + qhandle_t probeBeam; + qhandle_t probeDecal; + + qhandle_t regenDecal; + + //RPG-X : Weapon Holsters + qhandle_t phaserHolster; + qhandle_t phaserHolsterInner; + + qhandle_t tricorderHolster; + qhandle_t tricorderHolsterInner; + + //TR-116 Scope + qhandle_t tr116EyeScope; + + //SIMS module + qhandle_t simsModule; + + //EVA + qhandle_t evaInterior; + + qhandle_t medicalScanner; + + //hazard Helmet + qhandle_t hazardHelmet; + + // stasis door model + qhandle_t stasisDoorModel; // sounds - sfxHandle_t quadSound; - sfxHandle_t tracerSound; - sfxHandle_t selectSound; + //sfxHandle_t quadSound; + //sfxHandle_t selectSound; sfxHandle_t useNothingSound; - sfxHandle_t wearOffSound; + //sfxHandle_t wearOffSound; sfxHandle_t footsteps[FOOTSTEP_TOTAL][4]; - sfxHandle_t sfx_lghit1; - sfxHandle_t sfx_lghit2; - sfxHandle_t sfx_lghit3; - sfxHandle_t sfx_ric1; - sfxHandle_t sfx_ric2; - sfxHandle_t sfx_ric3; - //sfxHandle_t sfx_railg; - sfxHandle_t sfx_rockexp; - sfxHandle_t sfx_plasmaexp; -#ifdef MISSIONPACK - sfxHandle_t sfx_proxexp; - sfxHandle_t sfx_nghit; - sfxHandle_t sfx_nghitflesh; - sfxHandle_t sfx_nghitmetal; - sfxHandle_t sfx_chghit; - sfxHandle_t sfx_chghitflesh; - sfxHandle_t sfx_chghitmetal; - sfxHandle_t kamikazeExplodeSound; - sfxHandle_t kamikazeImplodeSound; - sfxHandle_t kamikazeFarSound; - sfxHandle_t useInvulnerabilitySound; - sfxHandle_t invulnerabilityImpactSound1; - sfxHandle_t invulnerabilityImpactSound2; - sfxHandle_t invulnerabilityImpactSound3; - sfxHandle_t invulnerabilityJuicedSound; - sfxHandle_t obeliskHitSound1; - sfxHandle_t obeliskHitSound2; - sfxHandle_t obeliskHitSound3; - sfxHandle_t obeliskRespawnSound; - sfxHandle_t winnerSound; - sfxHandle_t loserSound; -#endif - sfxHandle_t gibSound; - sfxHandle_t gibBounce1Sound; - sfxHandle_t gibBounce2Sound; - sfxHandle_t gibBounce3Sound; + sfxHandle_t holoOpenSound; sfxHandle_t teleInSound; - sfxHandle_t teleOutSound; - sfxHandle_t noAmmoSound; + //sfxHandle_t teleOutSound; + //RPG-X + sfxHandle_t transportSound; + //sfxHandle_t noAmmoSound; sfxHandle_t respawnSound; sfxHandle_t talkSound; - sfxHandle_t landSound; - sfxHandle_t fallSound; + //sfxHandle_t landSound; + sfxHandle_t landSound[LANDSOUND_TOTAL]; //RPG-X | GSIO01 | 20/05/2009 sfxHandle_t jumpPadSound; sfxHandle_t oneMinuteSound; sfxHandle_t fiveMinuteSound; sfxHandle_t suddenDeathSound; - sfxHandle_t threeFragSound; - sfxHandle_t twoFragSound; - sfxHandle_t oneFragSound; + //sfxHandle_t threeFragSound; + //sfxHandle_t twoFragSound; + //sfxHandle_t oneFragSound; - sfxHandle_t hitSound; - sfxHandle_t hitSoundHighArmor; - sfxHandle_t hitSoundLowArmor; - sfxHandle_t hitTeamSound; - sfxHandle_t impressiveSound; - sfxHandle_t excellentSound; - sfxHandle_t deniedSound; - sfxHandle_t humiliationSound; - sfxHandle_t assistSound; - sfxHandle_t defendSound; - sfxHandle_t firstImpressiveSound; - sfxHandle_t firstExcellentSound; - sfxHandle_t firstHumiliationSound; + //sfxHandle_t hitSound; + //sfxHandle_t shieldHitSound; + //sfxHandle_t shieldPierceSound; + //sfxHandle_t hitTeamSound; - sfxHandle_t takenLeadSound; - sfxHandle_t tiedLeadSound; - sfxHandle_t lostLeadSound; + //sfxHandle_t rewardImpressiveSound; + //sfxHandle_t rewardExcellentSound; + //sfxHandle_t rewardDeniedSound; + //sfxHandle_t rewardFirstStrikeSound; + //sfxHandle_t rewardAceSound; + //sfxHandle_t rewardExpertSound; + //sfxHandle_t rewardMasterSound; + //sfxHandle_t rewardChampionSound; - sfxHandle_t voteNow; - sfxHandle_t votePassed; - sfxHandle_t voteFailed; + //sfxHandle_t takenLeadSound; + //sfxHandle_t tiedLeadSound; + //sfxHandle_t lostLeadSound; sfxHandle_t watrInSound; sfxHandle_t watrOutSound; sfxHandle_t watrUnSound; - sfxHandle_t flightSound; + //sfxHandle_t flightSound; sfxHandle_t medkitSound; + sfxHandle_t borgBeamInSound; - sfxHandle_t weaponHoverSound; + // Interface sounds + sfxHandle_t interfaceSnd1; // teamplay sounds - sfxHandle_t captureAwardSound; - sfxHandle_t redScoredSound; - sfxHandle_t blueScoredSound; - sfxHandle_t redLeadsSound; - sfxHandle_t blueLeadsSound; - sfxHandle_t teamsTiedSound; - - sfxHandle_t captureYourTeamSound; - sfxHandle_t captureOpponentSound; - sfxHandle_t returnYourTeamSound; - sfxHandle_t returnOpponentSound; - sfxHandle_t takenYourTeamSound; - sfxHandle_t takenOpponentSound; - - sfxHandle_t redFlagReturnedSound; - sfxHandle_t blueFlagReturnedSound; - sfxHandle_t neutralFlagReturnedSound; - sfxHandle_t enemyTookYourFlagSound; - sfxHandle_t enemyTookTheFlagSound; - sfxHandle_t yourTeamTookEnemyFlagSound; - sfxHandle_t yourTeamTookTheFlagSound; - sfxHandle_t youHaveFlagSound; - sfxHandle_t yourBaseIsUnderAttackSound; - sfxHandle_t holyShitSound; + //sfxHandle_t redLeadsSound; + //sfxHandle_t blueLeadsSound; + //sfxHandle_t teamsTiedSound; // tournament sounds sfxHandle_t count3Sound; @@ -943,37 +1432,169 @@ typedef struct { sfxHandle_t countFightSound; sfxHandle_t countPrepareSound; -#ifdef MISSIONPACK - // new stuff - qhandle_t patrolShader; - qhandle_t assaultShader; - qhandle_t campShader; - qhandle_t followShader; - qhandle_t defendShader; - qhandle_t teamLeaderShader; - qhandle_t retrieveShader; - qhandle_t escortShader; - qhandle_t flagShaders[3]; - sfxHandle_t countPrepareTeamSound; + // CTF sounds + /*sfxHandle_t ctfStealSound; + sfxHandle_t ctfReturnSound; + sfxHandle_t ctfScoreSound; + sfxHandle_t ctfYouStealVoiceSound; + sfxHandle_t ctfYouDroppedVoiceSound; + sfxHandle_t ctfYouReturnVoiceSound; + sfxHandle_t ctfYouScoreVoiceSound; + sfxHandle_t ctfTheyStealVoiceSound; + sfxHandle_t ctfTheyDroppedVoiceSound; + sfxHandle_t ctfTheyReturnVoiceSound; + sfxHandle_t ctfTheyScoreVoiceSound; */ - sfxHandle_t ammoregenSound; - sfxHandle_t doublerSound; - sfxHandle_t guardSound; - sfxHandle_t scoutSound; -#endif - qhandle_t cursor; - qhandle_t selectCursor; - qhandle_t sizeCursor; + // + // trek sounds + // + sfxHandle_t envSparkSound1; + sfxHandle_t envSparkSound2; + sfxHandle_t envSparkSound3; + sfxHandle_t defaultPickupSound; + sfxHandle_t grenadeAltStickSound; + sfxHandle_t grenadeBounceSound1; + sfxHandle_t grenadeBounceSound2; + sfxHandle_t grenadeExplodeSound; + //sfxHandle_t tetrionRicochetSound1; + //sfxHandle_t tetrionRicochetSound2; + //sfxHandle_t tetrionRicochetSound3; + sfxHandle_t invulnoProtectSound; + //sfxHandle_t regenSound; + //sfxHandle_t poweruprespawnSound; + sfxHandle_t disintegrateSound; + sfxHandle_t disintegrate2Sound; + sfxHandle_t playerExplodeSound; + sfxHandle_t waterDropSound1; + sfxHandle_t waterDropSound2; + sfxHandle_t waterDropSound3; + sfxHandle_t holoInitSound; + sfxHandle_t holoDoorSound; + sfxHandle_t holoFadeSound; + sfxHandle_t phaserEmptySound; + sfxHandle_t quantumBoom; + //RPG-X: RedTechie - Better explo sounds for glauncher + sfxHandle_t grenadeAltExplodeSnd; + //RPG-X: RedTechie - Shake command sound + sfxHandle_t ShakeSound; + //RPG-X | Phenix | 13/02/2005 + sfxHandle_t N00bSound[N00bSoundCount]; + //RPG-X | Phenix | 08/06/2005 + sfxHandle_t AdminMsgSound; + //RPG-X | TiM + sfxHandle_t splatSound; + //RPG-X | TiM + sfxHandle_t tedTextSound; - sfxHandle_t regenSound; - sfxHandle_t protectSound; - sfxHandle_t n_healthSound; - sfxHandle_t hgrenb1aSound; - sfxHandle_t hgrenb2aSound; - sfxHandle_t wstbimplSound; - sfxHandle_t wstbimpmSound; - sfxHandle_t wstbimpdSound; - sfxHandle_t wstbactvSound; + // Zoom + sfxHandle_t zoomStart; + sfxHandle_t zoomStart116; + sfxHandle_t zoomLoop; + sfxHandle_t zoomEnd; + sfxHandle_t zoomEnd116; + sfxHandle_t tr116Chirp; + sfxHandle_t tr116Whir; + + // Chunk sounds + sfxHandle_t metalChunkSound; + sfxHandle_t glassChunkSound; + sfxHandle_t woodChunkSound; + sfxHandle_t stoneChunkSound; + + //TiM : Splosion sounds + sfxHandle_t surfaceExpSound[3]; + sfxHandle_t electricExpSound[3]; + sfxHandle_t bigSurfExpSound; + + //TiM - Q Flash sound + sfxHandle_t qFlash; + + qhandle_t loading1; + qhandle_t loading2; + qhandle_t loading3; + qhandle_t loading4; + qhandle_t loading5; + qhandle_t loading6; + qhandle_t loading7; + qhandle_t loading8; + qhandle_t loading9; + qhandle_t loadingcircle; + qhandle_t loadingquarter; + qhandle_t loadingcorner; + qhandle_t loadingtrim; + qhandle_t circle; + qhandle_t circle2; + qhandle_t corner_12_18; + qhandle_t halfroundr_22; + qhandle_t corner_ul_20_30; + qhandle_t corner_ll_8_30; + + //TiM - OPTIMIZATION: + //Used 2 API functions to cut down the + //shader usage on this thing significantly ^_^ + qhandle_t radarShader; + /*qhandle_t rd_up; + qhandle_t rd_down; + qhandle_t rd_level; + qhandle_t rd_red_up; + qhandle_t rd_red_down; + qhandle_t rd_red_level; + qhandle_t rd_blue_up; + qhandle_t rd_blue_down; + qhandle_t rd_blue_level; + qhandle_t rd_white_up; + qhandle_t rd_white_down; + qhandle_t rd_white_level; + qhandle_t rd_teal_up; + qhandle_t rd_teal_down; + qhandle_t rd_teal_level; + qhandle_t rd_black_up; + qhandle_t rd_black_down; + qhandle_t rd_black_level; + qhandle_t rd_injured_up; + qhandle_t rd_injured_down;*/ + qhandle_t rd_injured_level; + + qhandle_t radarMain; + + //RPG-X (J2J) Rank Images for Score Board (Arrays for each class type) + //TiM: *shudder* There was a better way! + /*qhandle_t ri_Civ; + qhandle_t ri_Crewman[4]; + qhandle_t ri_Cadet1[4]; + qhandle_t ri_Cadet2[4]; + qhandle_t ri_Cadet3[4]; + qhandle_t ri_Cadet4[4]; + qhandle_t ri_Ensign[4]; + qhandle_t ri_Ltjg[4]; + qhandle_t ri_Lt[4]; + qhandle_t ri_Ltcmdr[4]; + qhandle_t ri_Cmdr[4]; + qhandle_t ri_Capt[4]; + qhandle_t ri_Cmmdr[4]; + qhandle_t ri_Admr2[4]; + qhandle_t ri_Admr3[4]; + qhandle_t ri_Admr4[4]; + qhandle_t ri_Admr5[4];*/ + + //RPG-X: J2J - This is for sharky's crosshiar for each weapon. + //TiM: hrmmmm..... O_o + //qhandle_t crosshair[15]; + qhandle_t crosshairSheet; + + //TiM : LensFlare Parts + qhandle_t flareCore; + qhandle_t flareStreak; + qhandle_t flareChroma; + qhandle_t flareRadial; + qhandle_t flareStraight; + qhandle_t flareInverseRad; + qhandle_t flareHaze; + + qhandle_t orangeStarShader; + + //Q Flash sprite + qhandle_t qFlashSprite; } cgMedia_t; @@ -996,6 +1617,11 @@ typedef struct { // parsed from serverinfo gametype_t gametype; + qboolean pModAssimilation; + qboolean pModDisintegration; + qboolean pModActionHero; + qboolean pModSpecialties; + qboolean pModElimination; int dmflags; int teamflags; int fraglimit; @@ -1003,8 +1629,9 @@ typedef struct { int timelimit; int maxclients; char mapname[MAX_QPATH]; - char redTeam[MAX_QPATH]; - char blueTeam[MAX_QPATH]; + qboolean ForceClassColor; + char rankSet[MAX_QPATH]; + char classSet[MAX_QPATH]; int voteTime; int voteYes; @@ -1012,24 +1639,16 @@ typedef struct { qboolean voteModified; // beep whenever changed char voteString[MAX_STRING_TOKENS]; - int teamVoteTime[2]; - int teamVoteYes[2]; - int teamVoteNo[2]; - qboolean teamVoteModified[2]; // beep whenever changed - char teamVoteString[2][MAX_STRING_TOKENS]; - int levelStartTime; int scores1, scores2; // from configstrings int redflag, blueflag; // flag status from configstrings - int flagStatus; - - qboolean newHud; // // locally derived information from gamestate // qhandle_t gameModels[MAX_MODELS]; +// qhandle_t useableModels[HI_NUM_HOLDABLE]; sfxHandle_t gameSounds[MAX_SOUNDS]; int numInlineModels; @@ -1044,27 +1663,36 @@ typedef struct { int teamChatPos; int teamLastChatPos; - int cursorX; - int cursorY; - qboolean eventHandling; - qboolean mouseCaptured; - qboolean sizingHud; - void *capturedItem; - qhandle_t activeCursor; - - // orders - int currentOrder; - qboolean orderPending; - int orderTime; - int currentVoiceClient; - int acceptOrderTime; - int acceptTask; - int acceptLeader; - char acceptVoice[MAX_NAME_LENGTH]; - // media cgMedia_t media; + //TiM: ranks data + defaultRankData_t defaultRankData; + ranksData_t ranksData[MAX_RANKS]; + + //TiM: crosshair data + crosshairsData_t crosshairsData[MAX_CROSSHAIRS]; + + //decoy memory spaces + clientInfo_t decoyInfo[MAX_DECOYS]; + + //During game load, check to see if we have any locations + //so we may edit the scoreboard to account for them + qboolean locations; + + //TiM - static class data + cg_classData_t classData[MAX_CLASSES]; + + //objectives + objective_t objectives[MAX_OBJECTIVES]; + + //widescreen variables + widescreen_t widescreen; + + //scannable tricorder dynamic text + char scannableStrings[MAX_SCANNABLES][36]; + + qboolean scannablePanels; } cgs_t; //============================================================================== @@ -1093,6 +1721,7 @@ extern vmCvar_t cg_drawIcons; extern vmCvar_t cg_drawAmmoWarning; extern vmCvar_t cg_drawCrosshair; extern vmCvar_t cg_drawCrosshairNames; +extern vmCvar_t cg_dynamicCrosshairNames; extern vmCvar_t cg_drawRewards; extern vmCvar_t cg_drawTeamOverlay; extern vmCvar_t cg_teamOverlayUserinfo; @@ -1106,23 +1735,18 @@ extern vmCvar_t cg_animSpeed; extern vmCvar_t cg_debugAnim; extern vmCvar_t cg_debugPosition; extern vmCvar_t cg_debugEvents; -extern vmCvar_t cg_railTrailTime; extern vmCvar_t cg_errorDecay; extern vmCvar_t cg_nopredict; extern vmCvar_t cg_noPlayerAnims; extern vmCvar_t cg_showmiss; extern vmCvar_t cg_footsteps; extern vmCvar_t cg_addMarks; -extern vmCvar_t cg_brassTime; extern vmCvar_t cg_gun_frame; extern vmCvar_t cg_gun_x; extern vmCvar_t cg_gun_y; extern vmCvar_t cg_gun_z; extern vmCvar_t cg_drawGun; extern vmCvar_t cg_viewsize; -extern vmCvar_t cg_tracerChance; -extern vmCvar_t cg_tracerWidth; -extern vmCvar_t cg_tracerLength; extern vmCvar_t cg_autoswitch; extern vmCvar_t cg_ignore; extern vmCvar_t cg_simpleItems; @@ -1130,79 +1754,98 @@ extern vmCvar_t cg_fov; extern vmCvar_t cg_zoomFov; extern vmCvar_t cg_thirdPersonRange; extern vmCvar_t cg_thirdPersonAngle; +extern vmCvar_t cg_thirdPersonVertOffset; //RPG-X: TiM +extern vmCvar_t cg_thirdPersonHorzOffset; +extern vmCvar_t cg_thirdPersonAlpha; +extern vmCvar_t cg_thirdPersonCameraDamp; +extern vmCvar_t cg_thirdPersonTargetDamp; +extern vmCvar_t cg_thirdPersonPitchOffset; extern vmCvar_t cg_thirdPerson; +extern vmCvar_t cg_stereoSeparation; extern vmCvar_t cg_lagometer; extern vmCvar_t cg_drawAttacker; extern vmCvar_t cg_synchronousClients; extern vmCvar_t cg_teamChatTime; extern vmCvar_t cg_teamChatHeight; extern vmCvar_t cg_stats; +extern vmCvar_t cg_reportDamage; extern vmCvar_t cg_forceModel; extern vmCvar_t cg_buildScript; extern vmCvar_t cg_paused; extern vmCvar_t cg_blood; extern vmCvar_t cg_predictItems; extern vmCvar_t cg_deferPlayers; -extern vmCvar_t cg_drawFriend; -extern vmCvar_t cg_teamChatsOnly; -extern vmCvar_t cg_noVoiceChats; -extern vmCvar_t cg_noVoiceText; -extern vmCvar_t cg_scorePlum; -extern vmCvar_t cg_smoothClients; -extern vmCvar_t pmove_fixed; -extern vmCvar_t pmove_msec; -//extern vmCvar_t cg_pmove_fixed; -extern vmCvar_t cg_cameraOrbit; -extern vmCvar_t cg_cameraOrbitDelay; -extern vmCvar_t cg_timescaleFadeEnd; -extern vmCvar_t cg_timescaleFadeSpeed; -extern vmCvar_t cg_timescale; -extern vmCvar_t cg_cameraMode; -extern vmCvar_t cg_smallFont; -extern vmCvar_t cg_bigFont; -extern vmCvar_t cg_noTaunt; -extern vmCvar_t cg_noProjectileTrail; -extern vmCvar_t cg_oldRail; -extern vmCvar_t cg_oldRocket; -extern vmCvar_t cg_oldPlasma; -extern vmCvar_t cg_trueLightning; -#ifdef MISSIONPACK -extern vmCvar_t cg_redTeamName; -extern vmCvar_t cg_blueTeamName; -extern vmCvar_t cg_currentSelectedPlayer; -extern vmCvar_t cg_currentSelectedPlayerName; -extern vmCvar_t cg_singlePlayer; -extern vmCvar_t cg_enableDust; -extern vmCvar_t cg_enableBreath; -extern vmCvar_t cg_singlePlayerActive; -extern vmCvar_t cg_recordSPDemo; -extern vmCvar_t cg_recordSPDemoName; -extern vmCvar_t cg_obeliskRespawnDelay; +extern vmCvar_t cg_disablekillmsgs; +extern vmCvar_t cg_drawradar; +extern vmCvar_t cg_noclipSpectate; //RPG-X J2J: Option for client to go no-clip in spectator mode. +extern vmCvar_t rpg_ctribgrenade; //RPG-X: RedTechie - Nevermind :P +extern vmCvar_t cg_dynamicCrosshair; //RPG-X | Phenix | 09/06/2005 +extern vmCvar_t doomHead; //RPG-X | Phenix | 09/06/2005 +extern vmCvar_t cg_dynamiclensflares; //RPG-X | TiM | 29/6/2005 +extern vmCvar_t cg_noTalkingHeads; +extern vmCvar_t cg_noFrowningHeads; +extern vmCvar_t cg_noBlinkingHeads; +extern vmCvar_t cg_noDynamicRanks; +extern vmCvar_t noAdminChat; +extern vmCvar_t cg_firstPersonBody; +extern vmCvar_t cg_defaultModel; + +extern vmCvar_t cg_defaultChar; + +//RPG-X: TiM - Player Model System Parameters +extern vmCvar_t pms_age; +extern vmCvar_t pms_height; +extern vmCvar_t pms_weight; +extern vmCvar_t pms_race; + +extern vmCvar_t emote_Offset; + +extern vmCvar_t cg_thirdPersonZoomRate; +extern vmCvar_t cg_showEntityNums; + +//TiM - SecurityCode +extern vmCvar_t sv_securityHash; +extern vmCvar_t sv_securityCode; + +extern vmCvar_t cg_handleWidescreen; +extern vmCvar_t ui_handleWidescreen; + +//extern vmCvar_t cg_chatBGColor; + +extern vmCvar_t cg_chatColor; + +//RPG-X | GSIO01 | 11/05/2009 +extern vmCvar_t rpg_forceFieldSet; + +// grp cvars +extern vmCvar_t grp_berp; + +// lua +#ifdef CG_LUA +extern vmCvar_t cg_debugLua; +extern vmCvar_t cg_logLua; #endif + + + + +qboolean CG_Cvar_ClampInt( const char *name, vmCvar_t *vmCvar, int min, int max ); + // // cg_main.c // const char *CG_ConfigString( int index ); const char *CG_Argv( int arg ); -void QDECL CG_Printf( const char *msg, ... ) __attribute__ ((format (printf, 1, 2))); -void QDECL CG_Error( const char *msg, ... ) __attribute__ ((noreturn, format (printf, 1, 2))); - +void QDECL CG_Printf( const char *msg, ... ); +void QDECL CG_Error( const char *msg, ... ); void CG_StartMusic( void ); void CG_UpdateCvars( void ); int CG_CrosshairPlayer( void ); int CG_LastAttacker( void ); -void CG_LoadMenus(const char *menuFile); -void CG_KeyEvent(int key, qboolean down); -void CG_MouseEvent(int x, int y); -void CG_EventHandling(int type); -void CG_RankRunFrame( void ); -void CG_SetScoreSelection(void *menu); -score_t *CG_GetSelectedScore( void ); -void CG_BuildSpectatorString( void ); // @@ -1216,7 +1859,7 @@ void CG_TestModelNextSkin_f (void); void CG_TestModelPrevSkin_f (void); void CG_ZoomDown_f( void ); void CG_ZoomUp_f( void ); -void CG_AddBufferedSound( sfxHandle_t sfx); +void CG_CameraShake( float intensity, int duration, qboolean addRumbleSound ); void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback ); @@ -1224,11 +1867,16 @@ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demo // // cg_drawtools.c // +void CG_PrintInterfaceGraphics(int min,int max); void CG_AdjustFrom640( float *x, float *y, float *w, float *h ); void CG_FillRect( float x, float y, float width, float height, const float *color ); void CG_DrawPic( float x, float y, float width, float height, qhandle_t hShader ); +void CG_DrawStretchPic( float x, float y, float width, float height, float s1, + float t1, float s2, float t2, qhandle_t hShader ); void CG_DrawString( float x, float y, const char *string, float charWidth, float charHeight, const float *modulate ); +void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color ); +void CG_LoadFonts(void); void CG_DrawStringExt( int x, int y, const char *string, const float *setColor, @@ -1246,62 +1894,103 @@ void CG_TileClear( void ); void CG_ColorForHealth( vec4_t hcolor ); void CG_GetColorForHealth( int health, int armor, vec4_t hcolor ); -void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color ); -void CG_DrawRect( float x, float y, float width, float height, float size, const float *color ); -void CG_DrawSides(float x, float y, float w, float h, float size); -void CG_DrawTopBottom(float x, float y, float w, float h, float size); +int UI_ProportionalStringWidth( const char* str,int style ); + +qboolean CG_LoadRanks( void ); +qboolean CG_LoadCrosshairs( void ); +qboolean CG_LoadClasses( void ); +// +// cg_draw.c +// +typedef struct +{ + int type; // STRING or GRAPHIC + float timer; // When it changes + int x; // X position + int y; // Y positon + int width; // Graphic width + int height; // Graphic height + char *file; // File name of graphic/ text if STRING + qhandle_t graphic; // Handle of graphic if GRAPHIC + int min; + int max; + int color; // Normal color + int style; // Style of characters +// void *pointer; // To an address +} interfacegraphics_s; + +typedef enum +{ + IG_GROW, + + IG_HEALTH_START, + IG_HEALTH_BEGINCAP, + IG_HEALTH_BOX1, + IG_HEALTH_SLIDERFULL, + IG_HEALTH_SLIDEREMPTY, + IG_HEALTH_ENDCAP, + IG_HEALTH_COUNT, + IG_HEALTH_END, + + IG_ARMOR_START, + IG_ARMOR_BEGINCAP, + IG_ARMOR_BOX1, + IG_ARMOR_SLIDERFULL, + IG_ARMOR_SLIDEREMPTY, + IG_ARMOR_ENDCAP, + IG_ARMOR_COUNT, + IG_ARMOR_END, + + IG_AMMO_START, + IG_AMMO_UPPER_BEGINCAP, + IG_AMMO_UPPER_ENDCAP, + IG_AMMO_LOWER_BEGINCAP, + IG_AMMO_SLIDERFULL, + IG_AMMO_SLIDEREMPTY, + IG_AMMO_LOWER_ENDCAP, + IG_AMMO_COUNT, + IG_AMMO_END, + + IG_MAX +} interface_graphics_t; + + +extern interfacegraphics_s interface_graphics[IG_MAX]; + +#define SG_OFF 0 +#define SG_STRING 1 +#define SG_GRAPHIC 2 +#define SG_NUMBER 3 +#define SG_VAR 4 -// -// cg_draw.c, cg_newDraw.c -// extern int sortedTeamPlayers[TEAM_MAXOVERLAY]; extern int numSortedTeamPlayers; extern int drawTeamOverlayModificationCount; -extern char systemChat[256]; -extern char teamChat1[256]; -extern char teamChat2[256]; void CG_AddLagometerFrameInfo( void ); void CG_AddLagometerSnapshotInfo( snapshot_t *snap ); void CG_CenterPrint( const char *str, int y, int charWidth ); void CG_DrawHead( float x, float y, float w, float h, int clientNum, vec3_t headAngles ); void CG_DrawActive( stereoFrame_t stereoView ); -void CG_DrawFlagModel( float x, float y, float w, float h, int team, qboolean force2D ); -void CG_DrawTeamBackground( int x, int y, int w, int h, float alpha, int team ); -void CG_OwnerDraw(float x, float y, float w, float h, float text_x, float text_y, int ownerDraw, int ownerDrawFlags, int align, float special, float scale, vec4_t color, qhandle_t shader, int textStyle); -void CG_Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style); -int CG_Text_Width(const char *text, float scale, int limit); -int CG_Text_Height(const char *text, float scale, int limit); -void CG_SelectPrevPlayer( void ); -void CG_SelectNextPlayer( void ); -float CG_GetValue(int ownerDraw); -qboolean CG_OwnerDrawVisible(int flags); -void CG_RunMenuScript(char **args); -void CG_ShowResponseHead( void ); -void CG_SetPrintString(int type, const char *p); -void CG_InitTeamChat( void ); -void CG_GetTeamColor(vec4_t *color); -const char *CG_GetGameStatusText( void ); -const char *CG_GetKillerText( void ); -void CG_Draw3DModel(float x, float y, float w, float h, qhandle_t model, qhandle_t skin, vec3_t origin, vec3_t angles); -void CG_Text_PaintChar(float x, float y, float width, float height, float scale, float s, float t, float s2, float t2, qhandle_t hShader); -void CG_CheckOrderPending( void ); -const char *CG_GameTypeString( void ); -qboolean CG_YourTeamHasFlag( void ); -qboolean CG_OtherTeamHasFlag( void ); -qhandle_t CG_StatusHandle(int task); - +void CG_DrawFlagModel( float x, float y, float w, float h, int team ); +void CG_DrawTeamBackground( int x, int y, int w, int h, float alpha, int team, qboolean scoreboard ); +void CG_DrawNumField (int x, int y, int width, int value,int charWidth,int charHeight,int style); +void CG_DrawObjectiveInformation( void ); // // cg_player.c // +void CG_PlayerShieldHit(int entitynum, vec3_t angles, int amount); void CG_Player( centity_t *cent ); void CG_ResetPlayerEntity( centity_t *cent ); -void CG_AddRefEntityWithPowerups( refEntity_t *ent, entityState_t *state, int team ); +//void CG_AddRefEntityWithPowerups( refEntity_t *ent, int powerups, int eFlags, qboolean borg ); +//void CG_AddRefEntityWithPowerups( refEntity_t *ent, int powerups, int eFlags, beamData_t *beamData, qboolean borg ); +void CG_AddRefEntityWithPowerups( refEntity_t *ent, int powerups, int eFlags, beamData_t *beamData, int cloakTime, int decloakTime, qboolean borg ); void CG_NewClientInfo( int clientNum ); sfxHandle_t CG_CustomSound( int clientNum, const char *soundName ); +void CG_NewDecoyInfo( int decoyNum ); // // cg_predict.c @@ -1337,6 +2026,45 @@ void CG_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *pare qhandle_t parentModel, char *tagName ); +// +// cg_env.c +// +void CG_Spark( vec3_t origin, vec3_t dir, int delay, int killTime ); +void CG_Steam( vec3_t position, vec3_t dir, int killTime ); +void CG_Bolt( centity_t *cent ); +void CG_TransporterPad(vec3_t origin); +void CG_Drip(centity_t *cent, int killTime ); +void CG_Chunks( vec3_t origin, vec3_t dir, float size, material_type_t type ); +void CG_FireLaser( vec3_t start, vec3_t end, vec3_t normal, vec3_t laserRGB, float alpha ); +void CG_AimLaser( vec3_t start, vec3_t end, vec3_t normal ); +void CG_StasisDoor(centity_t *cent, qboolean close); + +//TiM +void CG_FountainSpurt( vec3_t org, vec3_t end ); +void CG_ElectricalExplosion( vec3_t start, vec3_t dir, float radius ); + +//RPG-X | GSIO01 | 09/05/2009 +void CG_PhaserFX(centity_t *cent); +void CG_DisruptorFX(centity_t *cent); //RPG-X | Harry Young | 03.12.2011 +void CG_TorpedoFX(centity_t *cent); +void CG_ParticleFire(vec3_t origin, int killtime, int size); +void CG_ShowTrigger(centity_t *cent); + +// Additional ports from SP by Harry Young +void CG_CookingSteam( vec3_t origin, float radius ); +void CG_ElectricFire( vec3_t origin, vec3_t normal ); +void ForgeBoltFireback( vec3_t start, vec3_t end, vec3_t velocity, vec3_t user ); +void CG_ForgeBolt( centity_t *cent ); +void CG_Plasma( vec3_t start, vec3_t end, vec3_t sRGB, vec3_t eRGB, int startalpha, int endalpha ); +void CG_ParticleStream( centity_t *cent ); +void CG_TransporterStream( centity_t *cent ); +void CG_ExplosionTrail( centity_t *cent ); +void CG_BorgEnergyBeam( centity_t *cent ); +void CG_ShimmeryThing( vec3_t start, vec3_t end, vec3_t content ); +void CG_Shimmer( vec3_t position, vec3_t dest, vec3_t dir, vec3_t other ); +void CG_ShimmeryThing_Spawner( vec3_t start, vec3_t end, float radius, qboolean taper, int duration ); +void CG_Borg_Bolt_static( centity_t *cent ); +void CG_Borg_Bolt_dynamic( centity_t *cent ); // // cg_weapons.c @@ -1348,19 +2076,23 @@ void CG_Weapon_f( void ); void CG_RegisterWeapon( int weaponNum ); void CG_RegisterItemVisuals( int itemNum ); -void CG_FireWeapon( centity_t *cent ); -void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, impactSound_t soundType ); -void CG_MissileHitPlayer( int weapon, vec3_t origin, vec3_t dir, int entityNum ); -void CG_ShotgunFire( entityState_t *es ); -void CG_Bullet( vec3_t origin, int sourceEntityNum, vec3_t normal, qboolean flesh, int fleshEntityNum ); +void CG_FireWeapon( centity_t *cent, qboolean alt_fire ); +void CG_FireSeeker( centity_t *cent ); +void CG_MissileHitWall( centity_t *cent, int weapon, vec3_t origin, vec3_t dir ); +void CG_MissileHitPlayer( centity_t *cent, int weapon, vec3_t origin, vec3_t dir); -void CG_RailTrail( clientInfo_t *ci, vec3_t start, vec3_t end ); -void CG_GrappleTrail( centity_t *ent, const weaponInfo_t *wi ); void CG_AddViewWeapon (playerState_t *ps); -void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent, int team ); +void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent ); void CG_DrawWeaponSelect( void ); +void CG_DrawWeaponIcon ( int x, int y, int weapon ); //RPG-X | Phenix | 08/06/2005 -void CG_OutOfAmmoChange( void ); // should this be in pmove? +void CG_OutOfAmmoChange( qboolean altfire ); // should this be in pmove? +void CG_BounceEffect( centity_t *cent, int weapon, vec3_t origin, vec3_t normal ); +//void CG_BorgEyebeam( centity_t *cent, const refEntity_t *parent ); + +void CG_PlayShooterSound(centity_t *cent); + +extern int tris_state; // // cg_marks.c @@ -1379,6 +2111,7 @@ void CG_ImpactMark( qhandle_t markShader, // void CG_InitLocalEntities( void ); localEntity_t *CG_AllocLocalEntity( void ); +localEntity_t CG_GetActiveList( void ); void CG_AddLocalEntities( void ); // @@ -1390,29 +2123,31 @@ localEntity_t *CG_SmokePuff( const vec3_t p, float r, float g, float b, float a, float duration, int startTime, - int fadeInTime, int leFlags, qhandle_t hShader ); void CG_BubbleTrail( vec3_t start, vec3_t end, float spacing ); -void CG_SpawnEffect( vec3_t org ); -#ifdef MISSIONPACK -void CG_KamikazeEffect( vec3_t org ); -void CG_ObeliskExplode( vec3_t org, int entityNum ); -void CG_ObeliskPain( vec3_t org ); -void CG_InvulnerabilityImpact( vec3_t org, vec3_t angles ); -void CG_InvulnerabilityJuiced( vec3_t org ); -void CG_LightningBoltBeam( vec3_t start, vec3_t end ); -#endif -void CG_ScorePlum( int client, vec3_t org, int score ); +void CG_SpawnEffect( vec3_t org, refEntity_t *ent_legs, refEntity_t *ent_torso, refEntity_t *ent_head); +void CG_QFlashEvent( vec3_t org ); -void CG_GibPlayer( vec3_t playerOrigin ); -void CG_BigExplode( vec3_t playerOrigin ); void CG_Bleed( vec3_t origin, int entityNum ); +void CG_Seeker( centity_t *cent ); + +//RPG-X: TiM : Smoke Ent +//void CG_Smoke( vec3_t origin, vec3_t dir, float radius, float speed, qhandle_t shader ); +void CG_Smoke( vec3_t position, vec3_t dir, int killTime, int radius ); +//RPG-X: Marcin: Fire +void CG_Fire( vec3_t position, vec3_t dir, int killTime, int radius, int fxEnt ); localEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir, - qhandle_t hModel, qhandle_t shader, int msec, + qhandle_t hModel, qhandle_t shader, int msec, float scale, qboolean isSprite ); +localEntity_t *CG_MakeExplosion2( vec3_t origin, vec3_t dir, + qhandle_t hModel, int numFrames, qhandle_t shader, + int msec, qboolean isSprite, float scale, int flags ); + +void CG_SurfaceExplosion( vec3_t origin, vec3_t normal, float radius, float shake_speed, qboolean smoke ); +void CG_ExplosionEffects( vec3_t origin, int intensity, int radius); // // cg_snapshot.c @@ -1430,8 +2165,68 @@ void CG_DrawInformation( void ); // // cg_scoreboard.c // -qboolean CG_DrawOldScoreboard( void ); -void CG_DrawOldTourneyScoreboard( void ); + +qboolean CG_DrawScoreboard( void ); +void CG_DrawTourneyScoreboard( void ); + +// +// these lists need to be sync'ed with stuff under g_log in g_local.h +// + +// awards +typedef enum { + AWARD_EFFICIENCY, // Accuracy + AWARD_SHARPSHOOTER, // Most compression rifle frags + AWARD_UNTOUCHABLE, // Perfect (no deaths) + AWARD_LOGISTICS, // Most pickups + AWARD_TACTICIAN, // Kills with all weapons + AWARD_DEMOLITIONIST, // Most explosive damage kills + AWARD_STREAK, // Ace/Expert/Master/Champion + AWARD_TEAM, // MVP/Defender/Warrior/Carrier/Interceptor/Bravery + AWARD_SECTION31, // All-around god + AWARD_MAX +} awardType_t; + +typedef enum +{ + TEAM_NONE = 0, // ha ha! you suck! + TEAM_MVP, // most overall points + TEAM_DEFENDER, // killed the most baddies near your flag + TEAM_WARRIOR, // most frags + TEAM_CARRIER, // infected the most people with plague + TEAM_INTERCEPTOR, // returned your own flag the most + TEAM_BRAVERY, // Red Shirt Award (tm). you died more than anybody. + TEAM_MAX +} teamAward_e; + +// +// above lists need to be sync'ed with stuff under g_log in g_local.h +// + +typedef enum +{ + AWARD_STREAK_NONE = 0, + AWARD_STREAK_ACE, + AWARD_STREAK_EXPERT, + AWARD_STREAK_MASTER, + AWARD_STREAK_CHAMPION, + AWARD_STREAK_MAX +} awardStreak_t; + + + + +extern char *cg_medalPicNames[]; +extern char *cg_medalSounds[]; + +extern char *cg_medalTeamPicNames[]; +extern char *cg_medalTeamSounds[]; + +extern char *cg_medalStreakPicNames[]; +extern char *cg_medalStreakSounds[]; + +void AW_SPPostgameMenu_f( void ); + // // cg_consolecmds.c @@ -1445,19 +2240,44 @@ void CG_InitConsoleCommands( void ); void CG_ExecuteNewServerCommands( int latestSequence ); void CG_ParseServerinfo( void ); void CG_SetConfigValues( void ); -void CG_LoadVoiceChats( void ); -void CG_ShaderStateChanged(void); -void CG_VoiceChatLocal( int mode, qboolean voiceOnly, int clientNum, int color, const char *cmd ); -void CG_PlayBufferedVoiceChats( void ); // // cg_playerstate.c // void CG_Respawn( void ); void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops ); -void CG_CheckChangedPredictableEvents( playerState_t *ps ); +// cg_players.c +void updateSkin(int clientNum, char *new_model); + +/* +RPG-X J2J: This struct is used to convientently store the data loaded from TiM's + data.cfg file. References what body to use, skins etc.. + + TiM: Haha thanks Jay +*/ + +//typedef struct +//{ +// char ID[80]; +// char Name[255]; +// char BodyModel[255]; +// char Gender; +// qboolean Alien; +// qboolean Humanoid; +// char DefaultRank[255]; +// char SoundSet[255]; +////Allowed Classes +// qboolean Engineer; +// qboolean Science; +// qboolean Command; +// qboolean Security; +// qboolean Medical; +// +//} +//X_ModelCfgData; + //=============================================== // @@ -1469,7 +2289,7 @@ void CG_CheckChangedPredictableEvents( playerState_t *ps ); void trap_Print( const char *fmt ); // abort the game -void trap_Error(const char *fmt) __attribute__((noreturn)); +void trap_Error( const char *fmt ); // milliseconds should only be used for performance tuning, never // for anything game related. Get time from the CG_DrawActiveFrame parameter @@ -1479,6 +2299,7 @@ int trap_Milliseconds( void ); void trap_Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags ); void trap_Cvar_Update( vmCvar_t *vmCvar ); void trap_Cvar_Set( const char *var_name, const char *value ); +void trap_Cvar_Set_No_Modify( const char *var_name, const char *value ); void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ); // ServerCommand and ConsoleCommand parameter access @@ -1492,7 +2313,6 @@ int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode ); void trap_FS_Read( void *buffer, int len, fileHandle_t f ); void trap_FS_Write( const void *buffer, int len, fileHandle_t f ); void trap_FS_FCloseFile( fileHandle_t f ); -int trap_FS_Seek( fileHandle_t f, long offset, int origin ); // fsOrigin_t // add commands to the local console as if they were typed in // for map changing, etc. The command is not executed immediately, @@ -1534,21 +2354,18 @@ int trap_CM_MarkFragments( int numPoints, const vec3_t *points, // normal sounds will have their volume dynamically changed as their entity // moves and the listener moves void trap_S_StartSound( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx ); -void trap_S_StopLoopingSound(int entnum); // a local sound is always played full volume void trap_S_StartLocalSound( sfxHandle_t sfx, int channelNum ); -void trap_S_ClearLoopingSounds( qboolean killall ); +void trap_S_ClearLoopingSounds( void ); void trap_S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ); -void trap_S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ); void trap_S_UpdateEntityPosition( int entityNum, const vec3_t origin ); -// respatialize recalculates the volumes of sound as they should be heard by the +// repatialize recalculates the volumes of sound as they should be heard by the // given entityNum and position void trap_S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater ); -sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed ); // returns buzz if not found +sfxHandle_t trap_S_RegisterSound( const char *sample ); // returns buzz if not found void trap_S_StartBackgroundTrack( const char *intro, const char *loop ); // empty name stops music -void trap_S_StopBackgroundTrack( void ); void trap_R_LoadWorldMap( const char *mapname ); @@ -1558,6 +2375,7 @@ void trap_R_LoadWorldMap( const char *mapname ); qhandle_t trap_R_RegisterModel( const char *name ); // returns rgb axis if not found qhandle_t trap_R_RegisterSkin( const char *name ); // returns all white if not found qhandle_t trap_R_RegisterShader( const char *name ); // returns all white if not found +qhandle_t trap_R_RegisterShader3D( const char *name ); // returns all white if not found qhandle_t trap_R_RegisterShaderNoMip( const char *name ); // returns all white if not found // a scene is built up by calls to R_ClearScene and the various R_Add functions. @@ -1568,17 +2386,14 @@ void trap_R_AddRefEntityToScene( const refEntity_t *re ); // polys are intended for simple wall marks, not really for doing // significant construction void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts ); -void trap_R_AddPolysToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int numPolys ); void trap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ); -int trap_R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ); void trap_R_RenderScene( const refdef_t *fd ); void trap_R_SetColor( const float *rgba ); // NULL = 1,1,1,1 void trap_R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader ); void trap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs ); -int trap_R_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame, +void trap_R_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame, float frac, const char *tagName ); -void trap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset ); // The glconfig_t will not change during the life of a cgame. // If it needs to change, the entire cgame will be restarted, because @@ -1620,46 +2435,65 @@ void testPrintInt( char *string, int i ); void testPrintFloat( char *string, float f ); int trap_MemoryRemaining( void ); -void trap_R_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font); -qboolean trap_Key_IsDown( int keynum ); -int trap_Key_GetCatcher( void ); -void trap_Key_SetCatcher( int catcher ); -int trap_Key_GetKey( const char *binding ); +#define MAX_LENS_FLARES 64 -typedef enum { - SYSTEM_PRINT, - CHAT_PRINT, - TEAMCHAT_PRINT -} q3print_t; +//RPG-X | TiM | 28/06/2005 +typedef struct { + int width; + int height; + float offset; + qboolean positive; + vec3_t color; + char* file; + qhandle_t graphic; +} lensReflec_s; +typedef struct { + vec3_t worldCoord; + int w1; + int h1; + vec3_t glowColor; + float glowOffset; + float hazeOffset; + int minDist; + int maxDist; + vec3_t streakColor; + int streakDistMin; + int streakDistMax; + int streakW; + int streakH; + qboolean whiteStreaks; + int reflecDistMin; + int reflecDistMax; + qboolean reflecAnamorphic; + qboolean defReflecs; + qboolean clamp; + float maxAlpha; + int startTime; + int upTime; + int holdTime; + int downTime; + qboolean qfull; +} lensFlare_t; -int trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits); -e_status trap_CIN_StopCinematic(int handle); -e_status trap_CIN_RunCinematic (int handle); -void trap_CIN_DrawCinematic (int handle); -void trap_CIN_SetExtents (int handle, int x, int y, int w, int h); +extern lensReflec_s lensReflec[10]; +//extern lensFlare_t lensFlare[MAX_LENS_FLARES]; -void trap_SnapVector( float *v ); +void CG_DrawLensFlare( lensFlare_t *flare ); +void CG_InitLensFlare( vec3_t worldCoord, + int w1, int h1, + vec3_t glowColor, float glowOffset, float hazeOffset, int minDist, int maxDist, + vec3_t streakColor, int streakDistMin, int streakDistMax, int streakW, int streakH, qboolean whiteStreaks, + int reflecDistMin, int reflecDistMax, qboolean reflecAnamorphic, qboolean defReflecs, + qboolean clamp, float maxAlpha, int startTime, int upTime, int holdTime, int downTime ); -qboolean trap_loadCamera(const char *name); -void trap_startCamera(int time); -qboolean trap_getCameraInfo(int time, vec3_t *origin, vec3_t *angles); +//void CG_ParseClassData( void ); -qboolean trap_GetEntityToken( char *buffer, int bufferSize ); - -void CG_ClearParticles (void); -void CG_AddParticles (void); -void CG_ParticleSnow (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum); -void CG_ParticleSmoke (qhandle_t pshader, centity_t *cent); -void CG_AddParticleShrapnel (localEntity_t *le); -void CG_ParticleSnowFlurry (qhandle_t pshader, centity_t *cent); -void CG_ParticleBulletDebris (vec3_t org, vec3_t vel, int duration); -void CG_ParticleSparks (vec3_t org, vec3_t vel, int duration, float x, float y, float speed); -void CG_ParticleDust (centity_t *cent, vec3_t origin, vec3_t dir); -void CG_ParticleMisc (qhandle_t pshader, vec3_t origin, int size, int duration, float alpha); -void CG_ParticleExplosion (char *animStr, vec3_t origin, vec3_t vel, int duration, int sizeStart, int sizeEnd); -extern qboolean initparticles; -int CG_NewParticleArea ( int num ); +//TiM - Allow parts of the lerp code to update the 3rd view if need be +void CG_ResetThirdPersonViewDamp ( void ); +/* GSIO - shader remapping */ +void trap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset ); +void CG_ShaderStateChanged(void); diff --git a/code/cgame/cg_localents.c b/code/cgame/cg_localents.c index 8a85621..fb724d4 100644 --- a/code/cgame/cg_localents.c +++ b/code/cgame/cg_localents.c @@ -1,24 +1,4 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // // cg_localents.c -- every frame, generate renderer commands for locally @@ -59,6 +39,7 @@ CG_FreeLocalEntity void CG_FreeLocalEntity( localEntity_t *le ) { if ( !le->prev ) { CG_Error( "CG_FreeLocalEntity: not active" ); + return; } // remove from the doubly linked active list @@ -99,6 +80,16 @@ localEntity_t *CG_AllocLocalEntity( void ) { return le; } +/* +================== +CG_GetActiveList +Accessor fn +================== +*/ +localEntity_t CG_GetActiveList( void ) +{ + return cg_activeLocalEntities; +} /* ==================================================================================== @@ -111,99 +102,6 @@ or generates more localentities along a trail. ==================================================================================== */ -/* -================ -CG_BloodTrail - -Leave expanding blood puffs behind gibs -================ -*/ -void CG_BloodTrail( localEntity_t *le ) { - int t; - int t2; - int step; - vec3_t newOrigin; - localEntity_t *blood; - - step = 150; - t = step * ( (cg.time - cg.frametime + step ) / step ); - t2 = step * ( cg.time / step ); - - for ( ; t <= t2; t += step ) { - BG_EvaluateTrajectory( &le->pos, t, newOrigin ); - - blood = CG_SmokePuff( newOrigin, vec3_origin, - 20, // radius - 1, 1, 1, 1, // color - 2000, // trailTime - t, // startTime - 0, // fadeInTime - 0, // flags - cgs.media.bloodTrailShader ); - // use the optimized version - blood->leType = LE_FALL_SCALE_FADE; - // drop a total of 40 units over its lifetime - blood->pos.trDelta[2] = 40; - } -} - - -/* -================ -CG_FragmentBounceMark -================ -*/ -void CG_FragmentBounceMark( localEntity_t *le, trace_t *trace ) { - int radius; - - if ( le->leMarkType == LEMT_BLOOD ) { - - radius = 16 + (rand()&31); - CG_ImpactMark( cgs.media.bloodMarkShader, trace->endpos, trace->plane.normal, random()*360, - 1,1,1,1, qtrue, radius, qfalse ); - } else if ( le->leMarkType == LEMT_BURN ) { - - radius = 8 + (rand()&15); - CG_ImpactMark( cgs.media.burnMarkShader, trace->endpos, trace->plane.normal, random()*360, - 1,1,1,1, qtrue, radius, qfalse ); - } - - - // don't allow a fragment to make multiple marks, or they - // pile up while settling - le->leMarkType = LEMT_NONE; -} - -/* -================ -CG_FragmentBounceSound -================ -*/ -void CG_FragmentBounceSound( localEntity_t *le, trace_t *trace ) { - if ( le->leBounceSoundType == LEBS_BLOOD ) { - // half the gibs will make splat sounds - if ( rand() & 1 ) { - int r = rand()&3; - sfxHandle_t s; - - if ( r == 0 ) { - s = cgs.media.gibBounce1Sound; - } else if ( r == 1 ) { - s = cgs.media.gibBounce2Sound; - } else { - s = cgs.media.gibBounce3Sound; - } - trap_S_StartSound( trace->endpos, ENTITYNUM_WORLD, CHAN_AUTO, s ); - } - } else if ( le->leBounceSoundType == LEBS_BRASS ) { - - } - - // don't allow a fragment to make multiple bounce sounds, - // or it gets too noisy as they settle - le->leBounceSoundType = LEBS_NONE; -} - /* ================ @@ -237,84 +135,6 @@ void CG_ReflectVelocity( localEntity_t *le, trace_t *trace ) { } } -/* -================ -CG_AddFragment -================ -*/ -void CG_AddFragment( localEntity_t *le ) { - vec3_t newOrigin; - trace_t trace; - - if ( le->pos.trType == TR_STATIONARY ) { - // sink into the ground if near the removal time - int t; - float oldZ; - - t = le->endTime - cg.time; - if ( t < SINK_TIME ) { - // we must use an explicit lighting origin, otherwise the - // lighting would be lost as soon as the origin went - // into the ground - VectorCopy( le->refEntity.origin, le->refEntity.lightingOrigin ); - le->refEntity.renderfx |= RF_LIGHTING_ORIGIN; - oldZ = le->refEntity.origin[2]; - le->refEntity.origin[2] -= 16 * ( 1.0 - (float)t / SINK_TIME ); - trap_R_AddRefEntityToScene( &le->refEntity ); - le->refEntity.origin[2] = oldZ; - } else { - trap_R_AddRefEntityToScene( &le->refEntity ); - } - - return; - } - - // calculate new position - BG_EvaluateTrajectory( &le->pos, cg.time, newOrigin ); - - // trace a line from previous position to new position - CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID ); - if ( trace.fraction == 1.0 ) { - // still in free fall - VectorCopy( newOrigin, le->refEntity.origin ); - - if ( le->leFlags & LEF_TUMBLE ) { - vec3_t angles; - - BG_EvaluateTrajectory( &le->angles, cg.time, angles ); - AnglesToAxis( angles, le->refEntity.axis ); - } - - trap_R_AddRefEntityToScene( &le->refEntity ); - - // add a blood trail - if ( le->leBounceSoundType == LEBS_BLOOD ) { - CG_BloodTrail( le ); - } - - return; - } - - // if it is in a nodrop zone, remove it - // this keeps gibs from waiting at the bottom of pits of death - // and floating levels - if ( CG_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) { - CG_FreeLocalEntity( le ); - return; - } - - // leave a mark - CG_FragmentBounceMark( le, &trace ); - - // do a bouncy sound - CG_FragmentBounceSound( le, &trace ); - - // reflect the velocity on the trace plane - CG_ReflectVelocity( le, &trace ); - - trap_R_AddRefEntityToScene( &le->refEntity ); -} - /* ===================================================================== @@ -351,7 +171,8 @@ void CG_AddFadeRGB( localEntity_t *le ) { CG_AddMoveScaleFade ================== */ -static void CG_AddMoveScaleFade( localEntity_t *le ) { +void CG_AddMoveScaleFade( localEntity_t *le ) +{ refEntity_t *re; float c; vec3_t delta; @@ -359,19 +180,13 @@ static void CG_AddMoveScaleFade( localEntity_t *le ) { re = &le->refEntity; - if ( le->fadeInTime > le->startTime && cg.time < le->fadeInTime ) { - // fade / grow time - c = 1.0 - (float) ( le->fadeInTime - cg.time ) / ( le->fadeInTime - le->startTime ); - } - else { - // fade / grow time - c = ( le->endTime - cg.time ) * le->lifeRate; - } + // fade / grow time + c = ( le->endTime - cg.time ) * le->lifeRate; re->shaderRGBA[3] = 0xff * c * le->color[3]; if ( !( le->leFlags & LEF_PUFF_DONT_SCALE ) ) { - re->radius = le->radius * ( 1.0 - c ) + 8; + re->data.sprite.radius = le->data.sprite.radius * ( 1.0 - c ) + 8; } BG_EvaluateTrajectory( &le->pos, cg.time, re->origin ); @@ -380,7 +195,7 @@ static void CG_AddMoveScaleFade( localEntity_t *le ) { // so it doesn't add too much overdraw VectorSubtract( re->origin, cg.refdef.vieworg, delta ); len = VectorLength( delta ); - if ( len < le->radius ) { + if ( len < le->data.sprite.radius ) { CG_FreeLocalEntity( le ); return; } @@ -398,7 +213,8 @@ removed if the view passes through them. There are often many of these, so it needs to be simple. =================== */ -static void CG_AddScaleFade( localEntity_t *le ) { +void CG_AddScaleFade( localEntity_t *le ) +{ refEntity_t *re; float c; vec3_t delta; @@ -410,13 +226,13 @@ static void CG_AddScaleFade( localEntity_t *le ) { c = ( le->endTime - cg.time ) * le->lifeRate; re->shaderRGBA[3] = 0xff * c * le->color[3]; - re->radius = le->radius * ( 1.0 - c ) + 8; + re->data.sprite.radius = le->data.sprite.radius * ( 1.0 - c ) + 8; // if the view would be "inside" the sprite, kill the sprite // so it doesn't add too much overdraw VectorSubtract( re->origin, cg.refdef.vieworg, delta ); len = VectorLength( delta ); - if ( len < le->radius ) { + if ( len < le->data.sprite.radius ) { CG_FreeLocalEntity( le ); return; } @@ -435,7 +251,8 @@ removed if the view passes through them. There are often 100+ of these, so it needs to be simple. ================= */ -static void CG_AddFallScaleFade( localEntity_t *le ) { +void CG_AddFallScaleFade( localEntity_t *le ) +{ refEntity_t *re; float c; vec3_t delta; @@ -450,13 +267,13 @@ static void CG_AddFallScaleFade( localEntity_t *le ) { re->origin[2] = le->pos.trBase[2] - ( 1.0 - c ) * le->pos.trDelta[2]; - re->radius = le->radius * ( 1.0 - c ) + 16; + re->data.sprite.radius = le->data.sprite.radius * ( 1.0 - c ) + 16; // if the view would be "inside" the sprite, kill the sprite // so it doesn't add too much overdraw VectorSubtract( re->origin, cg.refdef.vieworg, delta ); len = VectorLength( delta ); - if ( len < le->radius ) { + if ( len < le->data.sprite.radius ) { CG_FreeLocalEntity( le ); return; } @@ -471,11 +288,37 @@ static void CG_AddFallScaleFade( localEntity_t *le ) { CG_AddExplosion ================ */ -static void CG_AddExplosion( localEntity_t *ex ) { +void CG_AddExplosion( localEntity_t *ex ) +{ refEntity_t *ent; ent = &ex->refEntity; + // calculate model frame + if ( ex->lifeRate > 0 ) { + float frac = (cg.time - ex->startTime) * ex->lifeRate; + int f = floor(frac); + if ( f < 0 ) { + f = 0; + } + + ent->frame = f + 1; + ent->oldframe = f; + ent->backlerp = 1.0 - ( frac - f ); + ent->renderfx |= RF_CAP_FRAMES; + } + // Explosions with zero shaders (using model default shader) don't fade, so + // allow fading when this flag is set. + if ( ex->leFlags & LEF_FADE_RGB ) + { + float frac = (float)( cg.time - ex->startTime )/(float)( ex->endTime - ex->startTime ); + + ent->shaderRGBA[0] = + ent->shaderRGBA[1] = + ent->shaderRGBA[2] = frac * 255; + ent->shaderRGBA[3] = 255; + } + // add the entity trap_R_AddRefEntityToScene(ent); @@ -499,7 +342,8 @@ static void CG_AddExplosion( localEntity_t *ex ) { CG_AddSpriteExplosion ================ */ -static void CG_AddSpriteExplosion( localEntity_t *le ) { +void CG_AddSpriteExplosion( localEntity_t *le ) +{ refEntity_t re; float c; @@ -516,7 +360,7 @@ static void CG_AddSpriteExplosion( localEntity_t *le ) { re.shaderRGBA[3] = 0xff * c * 0.33; re.reType = RT_SPRITE; - re.radius = 42 * ( 1.0 - c ) + 30; + re.data.sprite.radius = 42 * ( 1.0 - c ) + 30; trap_R_AddRefEntityToScene( &re ); @@ -536,265 +380,804 @@ static void CG_AddSpriteExplosion( localEntity_t *le ) { } -#ifdef MISSIONPACK + + /* -==================== -CG_AddKamikaze -==================== +=================== +CG_AddScaleFadeSprite + +For trek, oriented sprites like blast rings and the like. +=================== */ -void CG_AddKamikaze( localEntity_t *le ) { +void CG_AddScaleFadeSprite( localEntity_t *le ) +{ refEntity_t *re; - refEntity_t shockwave; float c; - vec3_t test, axis[3]; - int t; + vec3_t delta; + float len; re = &le->refEntity; - t = cg.time - le->startTime; - VectorClear( test ); - AnglesToAxis( test, axis ); - - if (t > KAMI_SHOCKWAVE_STARTTIME && t < KAMI_SHOCKWAVE_ENDTIME) { - - if (!(le->leFlags & LEF_SOUND1)) { -// trap_S_StartSound (re->origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.kamikazeExplodeSound ); - trap_S_StartLocalSound(cgs.media.kamikazeExplodeSound, CHAN_AUTO); - le->leFlags |= LEF_SOUND1; - } - // 1st kamikaze shockwave - memset(&shockwave, 0, sizeof(shockwave)); - shockwave.hModel = cgs.media.kamikazeShockWave; - shockwave.reType = RT_MODEL; - shockwave.shaderTime = re->shaderTime; - VectorCopy(re->origin, shockwave.origin); - - c = (float)(t - KAMI_SHOCKWAVE_STARTTIME) / (float)(KAMI_SHOCKWAVE_ENDTIME - KAMI_SHOCKWAVE_STARTTIME); - VectorScale( axis[0], c * KAMI_SHOCKWAVE_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[0] ); - VectorScale( axis[1], c * KAMI_SHOCKWAVE_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[1] ); - VectorScale( axis[2], c * KAMI_SHOCKWAVE_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[2] ); - shockwave.nonNormalizedAxes = qtrue; - - if (t > KAMI_SHOCKWAVEFADE_STARTTIME) { - c = (float)(t - KAMI_SHOCKWAVEFADE_STARTTIME) / (float)(KAMI_SHOCKWAVE_ENDTIME - KAMI_SHOCKWAVEFADE_STARTTIME); - } - else { - c = 0; - } - c *= 0xff; - shockwave.shaderRGBA[0] = 0xff - c; - shockwave.shaderRGBA[1] = 0xff - c; - shockwave.shaderRGBA[2] = 0xff - c; - shockwave.shaderRGBA[3] = 0xff - c; - - trap_R_AddRefEntityToScene( &shockwave ); + c = ( le->endTime - cg.time ) / ( float ) ( le->endTime - le->startTime ); + if ( c > 1 ) { + c = 1.0; // can happen during connection problems } - if (t > KAMI_EXPLODE_STARTTIME && t < KAMI_IMPLODE_ENDTIME) { - // explosion and implosion - c = ( le->endTime - cg.time ) * le->lifeRate; - c *= 0xff; - re->shaderRGBA[0] = le->color[0] * c; - re->shaderRGBA[1] = le->color[1] * c; - re->shaderRGBA[2] = le->color[2] * c; - re->shaderRGBA[3] = le->color[3] * c; - - if( t < KAMI_IMPLODE_STARTTIME ) { - c = (float)(t - KAMI_EXPLODE_STARTTIME) / (float)(KAMI_IMPLODE_STARTTIME - KAMI_EXPLODE_STARTTIME); - } - else { - if (!(le->leFlags & LEF_SOUND2)) { -// trap_S_StartSound (re->origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.kamikazeImplodeSound ); - trap_S_StartLocalSound(cgs.media.kamikazeImplodeSound, CHAN_AUTO); - le->leFlags |= LEF_SOUND2; - } - c = (float)(KAMI_IMPLODE_ENDTIME - t) / (float) (KAMI_IMPLODE_ENDTIME - KAMI_IMPLODE_STARTTIME); - } - VectorScale( axis[0], c * KAMI_BOOMSPHERE_MAXRADIUS / KAMI_BOOMSPHEREMODEL_RADIUS, re->axis[0] ); - VectorScale( axis[1], c * KAMI_BOOMSPHERE_MAXRADIUS / KAMI_BOOMSPHEREMODEL_RADIUS, re->axis[1] ); - VectorScale( axis[2], c * KAMI_BOOMSPHERE_MAXRADIUS / KAMI_BOOMSPHEREMODEL_RADIUS, re->axis[2] ); - re->nonNormalizedAxes = qtrue; - - trap_R_AddRefEntityToScene( re ); - // add the dlight - trap_R_AddLightToScene( re->origin, c * 1000.0, 1.0, 1.0, c ); - } - - if (t > KAMI_SHOCKWAVE2_STARTTIME && t < KAMI_SHOCKWAVE2_ENDTIME) { - // 2nd kamikaze shockwave - if (le->angles.trBase[0] == 0 && - le->angles.trBase[1] == 0 && - le->angles.trBase[2] == 0) { - le->angles.trBase[0] = random() * 360; - le->angles.trBase[1] = random() * 360; - le->angles.trBase[2] = random() * 360; - } - memset(&shockwave, 0, sizeof(shockwave)); - shockwave.hModel = cgs.media.kamikazeShockWave; - shockwave.reType = RT_MODEL; - shockwave.shaderTime = re->shaderTime; - VectorCopy(re->origin, shockwave.origin); - - test[0] = le->angles.trBase[0]; - test[1] = le->angles.trBase[1]; - test[2] = le->angles.trBase[2]; - AnglesToAxis( test, axis ); - - c = (float)(t - KAMI_SHOCKWAVE2_STARTTIME) / (float)(KAMI_SHOCKWAVE2_ENDTIME - KAMI_SHOCKWAVE2_STARTTIME); - VectorScale( axis[0], c * KAMI_SHOCKWAVE2_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[0] ); - VectorScale( axis[1], c * KAMI_SHOCKWAVE2_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[1] ); - VectorScale( axis[2], c * KAMI_SHOCKWAVE2_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[2] ); - shockwave.nonNormalizedAxes = qtrue; - - if (t > KAMI_SHOCKWAVE2FADE_STARTTIME) { - c = (float)(t - KAMI_SHOCKWAVE2FADE_STARTTIME) / (float)(KAMI_SHOCKWAVE2_ENDTIME - KAMI_SHOCKWAVE2FADE_STARTTIME); - } - else { - c = 0; - } - c *= 0xff; - shockwave.shaderRGBA[0] = 0xff - c; - shockwave.shaderRGBA[1] = 0xff - c; - shockwave.shaderRGBA[2] = 0xff - c; - shockwave.shaderRGBA[3] = 0xff - c; - - trap_R_AddRefEntityToScene( &shockwave ); - } -} - -/* -=================== -CG_AddInvulnerabilityImpact -=================== -*/ -void CG_AddInvulnerabilityImpact( localEntity_t *le ) { - trap_R_AddRefEntityToScene( &le->refEntity ); -} - -/* -=================== -CG_AddInvulnerabilityJuiced -=================== -*/ -void CG_AddInvulnerabilityJuiced( localEntity_t *le ) { - int t; - - t = cg.time - le->startTime; - if ( t > 3000 ) { - le->refEntity.axis[0][0] = (float) 1.0 + 0.3 * (t - 3000) / 2000; - le->refEntity.axis[1][1] = (float) 1.0 + 0.3 * (t - 3000) / 2000; - le->refEntity.axis[2][2] = (float) 0.7 + 0.3 * (2000 - (t - 3000)) / 2000; - } - if ( t > 5000 ) { - le->endTime = 0; - CG_GibPlayer( le->refEntity.origin ); - } - else { - trap_R_AddRefEntityToScene( &le->refEntity ); - } -} - -/* -=================== -CG_AddRefEntity -=================== -*/ -void CG_AddRefEntity( localEntity_t *le ) { - if (le->endTime < cg.time) { + // Use the liferate to set the scale over time. + re->data.sprite.radius = le->data.sprite.radius + (le->lifeRate * (cg.time - le->startTime)); + if (re->data.sprite.radius <= 0) + { CG_FreeLocalEntity( le ); return; } - trap_R_AddRefEntityToScene( &le->refEntity ); -} - -#endif -/* -=================== -CG_AddScorePlum -=================== -*/ -#define NUMBER_SIZE 8 - -void CG_AddScorePlum( localEntity_t *le ) { - refEntity_t *re; - vec3_t origin, delta, dir, vec, up = {0, 0, 1}; - float c, len; - int i, score, digits[10], numdigits, negative; - - re = &le->refEntity; - - c = ( le->endTime - cg.time ) * le->lifeRate; - - score = le->radius; - if (score < 0) { - re->shaderRGBA[0] = 0xff; - re->shaderRGBA[1] = 0x11; - re->shaderRGBA[2] = 0x11; - } - else { - re->shaderRGBA[0] = 0xff; - re->shaderRGBA[1] = 0xff; - re->shaderRGBA[2] = 0xff; - if (score >= 50) { - re->shaderRGBA[1] = 0; - } else if (score >= 20) { - re->shaderRGBA[0] = re->shaderRGBA[1] = 0; - } else if (score >= 10) { - re->shaderRGBA[2] = 0; - } else if (score >= 2) { - re->shaderRGBA[0] = re->shaderRGBA[2] = 0; - } - - } - if (c < 0.25) - re->shaderRGBA[3] = 0xff * 4 * c; - else - re->shaderRGBA[3] = 0xff; - - re->radius = NUMBER_SIZE / 2; - - VectorCopy(le->pos.trBase, origin); - origin[2] += 110 - c * 100; - - VectorSubtract(cg.refdef.vieworg, origin, dir); - CrossProduct(dir, up, vec); - VectorNormalize(vec); - - VectorMA(origin, -10 + 20 * sin(c * 2 * M_PI), vec, origin); // if the view would be "inside" the sprite, kill the sprite // so it doesn't add too much overdraw - VectorSubtract( origin, cg.refdef.vieworg, delta ); + VectorSubtract( re->origin, cg.refdef.vieworg, delta ); len = VectorLength( delta ); - if ( len < 20 ) { + if ( len < le->data.sprite.radius ) { CG_FreeLocalEntity( le ); return; } - negative = qfalse; - if (score < 0) { - negative = qtrue; - score = -score; + // We will assume here that we want additive transparency effects. + re->shaderRGBA[0] = 0xff * c; + re->shaderRGBA[1] = 0xff * c; + re->shaderRGBA[2] = 0xff * c; + re->shaderRGBA[3] = 0xff * le->color[3]; + + re->reType = RT_ORIENTEDSPRITE; + + trap_R_AddRefEntityToScene( re ); +} + +/* +=================== +CG_AddQuad + +Of Trek, by Trek, and for Trek +=================== +*/ +void CG_AddQuad( localEntity_t *le ) +{ + refEntity_t *re; + float frac, alpha; + vec3_t delta; + float len; + vec3_t curRGB; + + re = &le->refEntity; + + frac = ( cg.time - le->startTime ) / ( float ) ( le->endTime - le->startTime ); + if ( frac > 1 ) + frac = 1.0; // can happen during connection problems + else if (frac < 0) + frac = 0.0; + + // Use the liferate to set the scale over time. + re->data.sprite.radius = le->data.sprite.radius + (le->data.sprite.dradius*frac); + if (re->data.sprite.radius <= 0) + { + CG_FreeLocalEntity( le ); + return; } - for (numdigits = 0; !(numdigits && !score); numdigits++) { - digits[numdigits] = score % 10; - score = score / 10; + // if the view would be "inside" the sprite, kill the sprite + // so it doesn't add too much overdraw + VectorSubtract( re->origin, cg.refdef.vieworg, delta ); + len = VectorLength( delta ); + if ( len < le->data.sprite.radius ) { + CG_FreeLocalEntity( le ); + return; } - if (negative) { - digits[numdigits] = 10; - numdigits++; + // Calculate the current alpha. + alpha = le->alpha + (le->dalpha * frac); + VectorMA(le->data.sprite.startRGB, frac, le->data.sprite.dRGB, curRGB); + re->shaderRGBA[0] = 0xff * alpha * curRGB[0]; + re->shaderRGBA[1] = 0xff * alpha * curRGB[1]; + re->shaderRGBA[2] = 0xff * alpha * curRGB[2]; + re->shaderRGBA[3] = 0xff; + + re->reType = RT_ORIENTEDSPRITE; + + trap_R_AddRefEntityToScene( re ); +} + + +/* +=================== +CG_AddLine + +For trek, for beams and the like. +=================== +*/ +void CG_AddLine( localEntity_t *le ) +{ + refEntity_t *re; + float frac, alpha; + + re = &le->refEntity; + + frac = (cg.time - le->startTime) / ( float ) ( le->endTime - le->startTime ); + if ( frac > 1 ) + frac = 1.0; // can happen during connection problems + else if (frac < 0) + frac = 0.0; + + // Use the liferate to set the scale over time. + re->data.line.width = le->data.line.width + (le->data.line.dwidth * frac); + if (re->data.line.width <= 0) + { + CG_FreeLocalEntity( le ); + return; } - for (i = 0; i < numdigits; i++) { - VectorMA(origin, (float) (((float) numdigits / 2) - i) * NUMBER_SIZE, vec, re->origin); - re->customShader = cgs.media.numberShaders[digits[numdigits-1-i]]; - trap_R_AddRefEntityToScene( re ); + // We will assume here that we want additive transparency effects. + alpha = le->alpha + (le->dalpha * frac); + re->shaderRGBA[0] = 0xff * alpha; + re->shaderRGBA[1] = 0xff * alpha; + re->shaderRGBA[2] = 0xff * alpha; + re->shaderRGBA[3] = 0xff * alpha; // Yes, we could apply c to this too, but fading the color is better for lines. + + re->reType = RT_LINE; + + trap_R_AddRefEntityToScene( re ); +} + + +/* +=================== +CG_AddOLine + +For trek, for rectangles. +=================== +*/ +void CG_AddOLine( localEntity_t *le ) +{ + refEntity_t *re; + float frac, alpha; + + re = &le->refEntity; + + frac = (cg.time - le->startTime) / ( float ) ( le->endTime - le->startTime ); + if ( frac > 1 ) + frac = 1.0; // can happen during connection problems + else if (frac < 0) + frac = 0.0; + + // Use the liferate to set the scale over time. + re->data.line.width = le->data.line.width + (le->data.line.dwidth * frac); + if (re->data.line.width <= 0) + { + CG_FreeLocalEntity( le ); + return; + } + + // We will assume here that we want additive transparency effects. + alpha = le->alpha + (le->dalpha * frac); + re->shaderRGBA[0] = 0xff * alpha; + re->shaderRGBA[1] = 0xff * alpha; + re->shaderRGBA[2] = 0xff * alpha; + re->shaderRGBA[3] = 0xff * alpha; // Yes, we could apply c to this too, but fading the color is better for lines. + + re->reType = RT_ORIENTEDLINE; + + trap_R_AddRefEntityToScene( re ); +} + +/* +=================== +CG_AddLine2 + +For trek, for beams and the like. +=================== +*/ +void CG_AddLine2( localEntity_t *le ) +{ + refEntity_t *re; + float frac, alpha; + vec3_t curRGB; + + re = &le->refEntity; + + frac = (cg.time - le->startTime) / ( float ) ( le->endTime - le->startTime ); + if ( frac > 1 ) + frac = 1.0; // can happen during connection problems + else if (frac < 0) + frac = 0.0; + + // Use the liferate to set the scale over time. + re->data.line.width = le->data.line2.width + (le->data.line2.dwidth * frac); + re->data.line.width2 = le->data.line2.width2 + (le->data.line2.dwidth2 * frac); + if (re->data.line.width <= 0) + { + CG_FreeLocalEntity( le ); + return; + } + + // We will assume here that we want additive transparency effects. + alpha = le->alpha + (le->dalpha * frac); + VectorMA(le->data.line2.startRGB, frac, le->data.line2.dRGB, curRGB); + re->shaderRGBA[0] = 0xff * alpha * curRGB[0]; + re->shaderRGBA[1] = 0xff * alpha * curRGB[1]; + re->shaderRGBA[2] = 0xff * alpha * curRGB[2]; + re->shaderRGBA[3] = 0xff * alpha; // Yes, we could apply c to this too, but fading the color is better for lines. + + re->reType = RT_LINE2; + + trap_R_AddRefEntityToScene( re ); +} + + + +/* +=================== +CG_AddTrail + +For trek, for sparks and the like. +=================== +*/ +void CG_AddTrail( localEntity_t *le ) +{ + refEntity_t *re; + float frac, length, alpha; + vec3_t dir; + trace_t trace; + vec3_t curRGB; + + re = &le->refEntity; + + frac = (cg.time - le->startTime) / ( float ) ( le->endTime - le->startTime ); + if ( frac > 1 ) + frac = 1.0; // can happen during connection problems + else if (frac < 0) + frac = 0.0; + + // Use the liferate to set the scale over time. + re->data.line.width = le->data.trail.width + (le->data.trail.dwidth * frac); + if (re->data.line.width <= 0) + { + CG_FreeLocalEntity( le ); + return; + } + + if (!(le->leFlags & LEF_MOVE)) + { + return; + } + + // kef -- do these two lines _before_ copying origin into oldorigin + VectorSubtract(re->oldorigin, re->origin, dir); + VectorNormalize(dir); + + VectorCopy(re->origin, re->oldorigin); + BG_EvaluateTrajectory( &le->pos, cg.time, re->origin ); + + if (le->leFlags & LEF_USE_COLLISION) + { + // trace a line from previous position to new position + CG_Trace( &trace, re->oldorigin, NULL, NULL, re->origin, -1, CONTENTS_SOLID ); + + if ( trace.fraction != 1.0 ) + { // Hit something. + // if it is in a nodrop zone, remove it + // this keeps gibs from waiting at the bottom of pits of death + // and floating levels + if ( trap_CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) { + CG_FreeLocalEntity( le ); + return; + } + + // reflect the velocity on the trace plane + CG_ReflectVelocity( le, &trace ); + } + VectorSubtract(re->oldorigin, re->origin, dir); + VectorNormalize(dir); + } + + // Set the length based on the velocity of the bit. + length = le->data.trail.length + (le->data.trail.dlength * frac); + if (length <= 0) + { + CG_FreeLocalEntity( le ); + return; + } + + VectorMA(re->origin, length, dir, re->oldorigin); + + // We will assume here that we want additive transparency effects. + alpha = le->alpha + (le->dalpha * frac); + VectorMA(le->data.trail.startRGB, frac, le->data.trail.dRGB, curRGB); + re->shaderRGBA[0] = 0xff * alpha * curRGB[0]; + re->shaderRGBA[1] = 0xff * alpha * curRGB[1]; + re->shaderRGBA[2] = 0xff * alpha * curRGB[2]; + re->shaderRGBA[3] = 0xff; // Yes, we could apply c to this too, but fading the color is better for lines. + + re->reType = RT_LINE; + + trap_R_AddRefEntityToScene( re ); +} + + + +/* +=================== +CG_AddViewSprite + +For trek, view sprites like smoke and the like. +=================== +*/ +void CG_AddViewSprite( localEntity_t *le ) +{ + refEntity_t *re; + float frac, alpha; + vec3_t delta; + float len; + trace_t trace; + vec3_t curRGB; + + re = &le->refEntity; + + frac = ( cg.time - le->startTime ) / ( float ) ( le->endTime - le->startTime ); + if ( frac > 1 ) + frac = 1.0; // can happen during connection problems + else if (frac < 0) + frac = 0.0; + + // Use the liferate to set the scale over time. + re->data.sprite.radius = le->data.sprite.radius + (le->data.sprite.dradius*frac); + if (re->data.sprite.radius <= 0) + { + CG_FreeLocalEntity( le ); + return; + } + + if (le->leFlags & LEF_MOVE) + { + VectorCopy(re->origin, re->oldorigin); + BG_EvaluateTrajectory( &le->pos, cg.time, re->origin ); + + if (le->leFlags & LEF_USE_COLLISION) + { + // trace a line from previous position to new position + CG_Trace( &trace, re->oldorigin, NULL, NULL, re->origin, -1, CONTENTS_SOLID ); + + if ( trace.fraction != 1.0 ) + { // Hit something. + // if it is in a nodrop zone, remove it + // this keeps gibs from waiting at the bottom of pits of death + // and floating levels + if ( trap_CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) { + CG_FreeLocalEntity( le ); + return; + } + + // reflect the velocity on the trace plane + CG_ReflectVelocity( le, &trace ); + } + } + } + + // if the view would be "inside" the sprite, kill the sprite + // so it doesn't add too much overdraw + VectorSubtract( re->origin, cg.refdef.vieworg, delta ); + len = VectorLength( delta ); + if ( len < le->data.sprite.radius ) { + CG_FreeLocalEntity( le ); + return; + } + + // Calculate the current alpha. + alpha = le->alpha + (le->dalpha * frac); + VectorMA(le->data.sprite.startRGB, frac, le->data.sprite.dRGB, curRGB); + re->shaderRGBA[0] = 0xff * alpha * curRGB[0]; + re->shaderRGBA[1] = 0xff * alpha * curRGB[1]; + re->shaderRGBA[2] = 0xff * alpha * curRGB[2]; + re->shaderRGBA[3] = 0xff; + + re->reType = RT_SPRITE; + + trap_R_AddRefEntityToScene( re ); +} + + +/* +=================== +CG_AddBezier + +For trek, for the imod and the...uh...imod. + +=================== +*/ +void CG_AddBezier( localEntity_t *le ) +{ + refEntity_t *re; + float frac, alpha; + float t = (cg.time - le->startTime)*0.001; // time elapsed since beginning of effect + vec3_t vTempPos; + + re = &le->refEntity; + + frac = (cg.time - le->startTime) / ( float ) ( le->endTime - le->startTime ); + if ( frac > 1 ) + frac = 1.0; // can happen during connection problems + else if (frac < 0) + frac = 0.0; + + // Use the liferate to set the scale over time. + re->data.bezier.width = le->data.line.width + (le->data.line.dwidth * frac); + if (re->data.bezier.width <= 0) + { + CG_FreeLocalEntity( le ); + return; + } + + // We will assume here that we want additive transparency effects. + alpha = le->alpha + (le->dalpha * frac); + re->shaderRGBA[0] = 0xff * alpha; + re->shaderRGBA[1] = 0xff * alpha; + re->shaderRGBA[2] = 0xff * alpha; + re->shaderRGBA[3] = 0xff; // Yes, we could apply c to this too, but fading the color is better for lines. + + re->reType = RT_BEZIER; + + // the refEntity only stores the two control points, so we need to update them here with + //the control_velocity and control_acceleration, then store the results in refEntity. + //use (cg.time - le->startTime) as a value for elapsed time t, plug it into the position formula: + // + // x = x0 + (v0 * t) + (0.5 * a * t * t) + // + //...where x is the position at time t, x0 is initial control point position, v0 is control point velocity, + //and a is control point acceleration + // + + // update control point 1 + VectorMA(le->data.line.control1, t, le->data.line.control1_velocity, vTempPos); + VectorMA(vTempPos, (0.5*t*t), le->data.line.control1_acceleration, re->data.bezier.control1); + + // update control point 2 + VectorMA(le->data.line.control2, t, le->data.line.control2_velocity, vTempPos); + VectorMA(vTempPos, (0.5*t*t), le->data.line.control2_acceleration, re->data.bezier.control2); + + trap_R_AddRefEntityToScene( re ); +} + + + +/* +=================== +CG_AddCylinder + +For trek, cylinder primitive. +=================== +*/ +void CG_AddCylinder( localEntity_t *le ) +{ + refEntity_t *re; + float frac, alpha; + + re = &le->refEntity; + + frac = ( cg.time - le->startTime ) / ( float ) ( le->endTime - le->startTime ); + if ( frac > 1 ) + frac = 1.0; // can happen during connection problems + else if (frac < 0) + frac = 0.0; + + // Use the liferate to set the scale over time. + re->data.cylinder.height = le->data.cylinder.height + (le->data.cylinder.dheight*frac); + if (re->data.cylinder.height <= 0) + { + CG_FreeLocalEntity( le ); + return; + } + re->data.cylinder.width = le->data.cylinder.width + (le->data.cylinder.dwidth*frac); + if (re->data.cylinder.width <= 0) + { + CG_FreeLocalEntity( le ); + return; + } + re->data.cylinder.width2 = le->data.cylinder.width2 + (le->data.cylinder.dwidth2*frac); + if (re->data.cylinder.width2 <= 0) + { + CG_FreeLocalEntity( le ); + return; + } + + // Calculate the current alpha. + alpha = le->alpha + (le->dalpha * frac); + re->shaderRGBA[0] = 0xff * alpha; + re->shaderRGBA[1] = 0xff * alpha; + re->shaderRGBA[2] = 0xff * alpha; + re->shaderRGBA[3] = 0xff; + + re->reType = RT_CYLINDER; + + trap_R_AddRefEntityToScene( re ); +} + + + +/* +=================== +CG_AddElectricity + +For trek, electricity primitive. +=================== +*/ + +#define DEFAULT_DEVIATION 0.5 + +void CG_AddElectricity( localEntity_t *le ) { + refEntity_t *re; + float frac, alpha; + + re = &le->refEntity; + + frac = ( cg.time - le->startTime ) / ( float ) ( le->endTime - le->startTime ); + if ( frac > 1 ) + frac = 1.0; // can happen during connection problems + else if (frac < 0) + frac = 0.0; + + re->data.electricity.width = le->data.electricity.width + (le->data.electricity.dwidth*frac); + + // Calculate the current alpha. + alpha = le->alpha + (le->dalpha * frac); + re->shaderRGBA[0] = 0xff * alpha; + re->shaderRGBA[1] = 0xff * alpha; + re->shaderRGBA[2] = 0xff * alpha; + re->shaderRGBA[3] = 0xff; + + re->reType = RT_ELECTRICITY; + + trap_R_AddRefEntityToScene( re ); +} + +/* +=================== +CG_AddParticle + +For trek, special explosion stuff sometimes wants these +=================== +*/ +static void CG_AddParticle( localEntity_t *le ) +{ + refEntity_t *re; + float frac, alpha; + vec3_t delta, dir; + float len; + trace_t trace; + + re = &le->refEntity; + + //safety check - since this renders over all, make sure we can't see this thru a wall + if ( re->renderfx & RF_DEPTHHACK ) { + CG_Trace( &trace, re->origin, NULL, NULL, cg.refdef.vieworg, cg.predictedPlayerState.clientNum, MASK_SOLID ); + + if ( trace.fraction != 1.0 ) + return; + + } + + frac = ( cg.time - le->startTime ) / ( float ) ( le->endTime - le->startTime ); + if ( le->leFlags & LEF_SINE_SCALE ) { + //frac = 1.0-(0.5f * sin( 4.0f * frac + 0.75f ) + 0.5f); //TiM: Sine calc //+ 1.5f + frac = 1.0-(0.65 * sin( 3.0 * frac +0.75 ) + 0.35); + } + + if ( frac > 1 ) + frac = 1.0; // can happen during connection problems + else if (frac < 0) + frac = 0.0; + + //CG_Printf( "%f\n", frac ); + + // Use the liferate to set the scale over time. + if ( !(le->leFlags & LEF_REVERSE_SCALE) ) + re->data.sprite.radius = le->data.particle.radius + (le->data.particle.dradius*frac); + else + re->data.sprite.radius = le->data.particle.radius - (le->data.particle.dradius*frac); + if (re->data.sprite.radius <= 0) + { + CG_FreeLocalEntity( le ); + return; + } + + if (le->leFlags & LEF_MOVE) + { + // kef -- do these two lines _before_ copying origin into oldorigin + VectorSubtract(re->oldorigin, re->origin, dir); + VectorNormalize(dir); + + VectorCopy(re->origin, re->oldorigin); + BG_EvaluateTrajectory( &le->pos, cg.time, re->origin ); + + if (le->leFlags & LEF_USE_COLLISION) + { + // trace a line from previous position to new position + CG_Trace( &trace, re->oldorigin, NULL, NULL, re->origin, -1, CONTENTS_SOLID ); + + if ( trace.fraction != 1.0 ) + { // Hit something. + // if it is in a nodrop zone, remove it + // this keeps gibs from waiting at the bottom of pits of death + // and floating levels + if ( trap_CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) { + CG_FreeLocalEntity( le ); + return; + } + + // reflect the velocity on the trace plane + CG_ReflectVelocity( le, &trace ); + } + VectorSubtract(re->oldorigin, re->origin, dir); + VectorNormalize(dir); + } + } + + // if the view would be "inside" the sprite, kill the sprite + // so it doesn't add too much overdraw + VectorSubtract( re->origin, cg.refdef.vieworg, delta ); + len = VectorLength( delta ); + if ( len < le->data.particle.radius ) { + CG_FreeLocalEntity( le ); + return; + } + + // kef -- here's where I, in my infinite wisdom, have decided to emulate the singleplayer + //particle think function + VectorNegate(dir, le->data.particle.dir); + if (le->data.particle.thinkFn) + { + le->data.particle.thinkFn(le); + } + + // Calculate the current alpha. + alpha = le->alpha + (le->dalpha * frac); + re->shaderRGBA[0] = 0xff * alpha; + re->shaderRGBA[1] = 0xff * alpha; + re->shaderRGBA[2] = 0xff * alpha; + re->shaderRGBA[3] = 0xff; + + re->reType = RT_SPRITE; + + trap_R_AddRefEntityToScene( re ); +} + +static void CG_AddSpawner( localEntity_t *le ) +{ + refEntity_t *re; + vec3_t dir; + trace_t trace; + + re = &le->refEntity; + if (le->leFlags & LEF_MOVE) + { + // kef -- do these two lines _before_ copying origin into oldorigin + VectorSubtract(re->oldorigin, re->origin, dir); + VectorNormalize(dir); + + VectorCopy(re->origin, re->oldorigin); + BG_EvaluateTrajectory( &le->pos, cg.time, re->origin ); + + if (le->leFlags & LEF_USE_COLLISION) + { + // trace a line from previous position to new position + CG_Trace( &trace, re->oldorigin, NULL, NULL, re->origin, -1, CONTENTS_SOLID ); + + if ( trace.fraction != 1.0 ) + { // Hit something. + // if it is in a nodrop zone, remove it + // this keeps gibs from waiting at the bottom of pits of death + // and floating levels + if ( trap_CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) { + CG_FreeLocalEntity( le ); + return; + } + + // reflect the velocity on the trace plane + CG_ReflectVelocity( le, &trace ); + } + VectorSubtract(re->oldorigin, re->origin, dir); + VectorNormalize(dir); + } + } + + // kef -- here's where I, in my infinite wisdom, have decided to emulate the singleplayer + //particle think function + if (cg.time < le->data.spawner.nextthink) + { + return; + } + le->data.spawner.nextthink = cg.time + (le->data.spawner.delay + + (le->data.spawner.delay*flrandom(-le->data.spawner.variance,le->data.spawner.variance))); + + if (le->data.spawner.thinkFn) + { + le->data.spawner.thinkFn(le); + } + if (le->data.spawner.dontDie) + { + le->endTime = le->endTime + 10000; } } +/* +================ +CG_AddFragment +================ +*/ +void CG_AddFragment( localEntity_t *le ) { + vec3_t newOrigin; + trace_t trace; + int k; + + if ( le->pos.trType == TR_STATIONARY ) { + // sink into the ground if near the removal time + int t; + float oldZ; + + t = le->endTime - cg.time; + if ( t < SINK_TIME ) { + // we must use an explicit lighting origin, otherwise the + // lighting would be lost as soon as the origin went + // into the ground + VectorCopy( le->refEntity.origin, le->refEntity.lightingOrigin ); + le->refEntity.renderfx |= RF_LIGHTING_ORIGIN; + oldZ = le->refEntity.origin[2]; + le->refEntity.origin[2] -= 16 * ( 1.0 - (float)t / SINK_TIME ); + trap_R_AddRefEntityToScene( &le->refEntity ); + le->refEntity.origin[2] = oldZ; + } else { + trap_R_AddRefEntityToScene( &le->refEntity ); + } + + return; + } + + // calculate new position + BG_EvaluateTrajectory( &le->pos, cg.time, newOrigin ); + + // trace a line from previous position to new position + CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, 0 /*le->ownerGentNum*/, CONTENTS_SOLID ); + if ( trace.fraction == 1.0 ) { + // still in free fall + VectorCopy( newOrigin, le->refEntity.origin ); + + if ( le->leFlags & LEF_TUMBLE ) { + vec3_t angles; + + BG_EvaluateTrajectory( &le->angles, cg.time, angles ); + AnglesToAxis( angles, le->refEntity.axis ); + for(k = 0; k < 3; k++) + { + VectorScale(le->refEntity.axis[k], le->data.fragment.radius, le->refEntity.axis[k]); + } + + } + + trap_R_AddRefEntityToScene( &le->refEntity ); + + return; + } + + // if it is in a nodrop zone, remove it + // this keeps gibs from waiting at the bottom of pits of death + // and floating levels + if ( trap_CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) { + CG_FreeLocalEntity( le ); + return; + } + + // reflect the velocity on the trace plane + CG_ReflectVelocity( le, &trace ); + //FIXME: if LEF_TUMBLE, change avelocity too? + + trap_R_AddRefEntityToScene( &le->refEntity ); +} //============================================================================== @@ -820,6 +1203,20 @@ void CG_AddLocalEntities( void ) { CG_FreeLocalEntity( le ); continue; } + + if (le->leFlags & LEF_ONE_FRAME) + { // If this flag is set, only render one single frame, no more. + if (le->leFlags & LEF_ONE_FRAME_DONE) + { + CG_FreeLocalEntity( le ); + continue; + } + else + { + le->leFlags |= LEF_ONE_FRAME_DONE; + } + } + switch ( le->leType ) { default: CG_Error( "Bad leType: %i", le->leType ); @@ -836,10 +1233,6 @@ void CG_AddLocalEntities( void ) { CG_AddExplosion( le ); break; - case LE_FRAGMENT: // gibs and brass - CG_AddFragment( le ); - break; - case LE_MOVE_SCALE_FADE: // water bubbles CG_AddMoveScaleFade( le ); break; @@ -856,24 +1249,66 @@ void CG_AddLocalEntities( void ) { CG_AddScaleFade( le ); break; - case LE_SCOREPLUM: - CG_AddScorePlum( le ); + case LE_SCALE_FADE_SPRITE: // Trek type for oriented poly sprites. + CG_AddScaleFadeSprite( le ); break; -#ifdef MISSIONPACK - case LE_KAMIKAZE: - CG_AddKamikaze( le ); + case LE_LINE: // Trek type for beams. + CG_AddLine( le ); break; - case LE_INVULIMPACT: - CG_AddInvulnerabilityImpact( le ); + + case LE_LINE2: // Trek type for beams, with taper support. + CG_AddLine2( le ); break; - case LE_INVULJUICED: - CG_AddInvulnerabilityJuiced( le ); + + case LE_OLINE: // Trek type for rectangles + CG_AddOLine( le ); break; - case LE_SHOWREFENTITY: - CG_AddRefEntity( le ); + + case LE_TRAIL: // Trek type for sparks. + CG_AddTrail( le ); + break; + + case LE_VIEWSPRITE: // Trek primitive for camera-facing sprites. + CG_AddViewSprite( le ); + break; + + case LE_BEZIER: + CG_AddBezier( le ); + break; + + case LE_QUAD: + CG_AddQuad( le ); + break; + + case LE_CYLINDER: + CG_AddCylinder(le); + break; + + case LE_ELECTRICITY: + CG_AddElectricity(le); + break; + + case LE_PARTICLE: + CG_AddParticle(le); + break; + + case LE_SPAWNER: + CG_AddSpawner(le); + break; + + case LE_FRAGMENT: + CG_AddFragment(le); + break; + + case LE_STASISDOOR: + if(le->refEntity.data.cylinder.wrap) { + le->refEntity.shaderRGBA[3] = (1 - (le->endTime - cg.time)/1000) * 255; + } else { + le->refEntity.shaderRGBA[3] = ((le->endTime - cg.time)/1000) * 255; + } + trap_R_AddRefEntityToScene(&le->refEntity); break; -#endif } } } diff --git a/code/cgame/cg_lua.c b/code/cgame/cg_lua.c new file mode 100644 index 0000000..1281e63 --- /dev/null +++ b/code/cgame/cg_lua.c @@ -0,0 +1,373 @@ +// g_lua.c + +#include "cg_lua.h" + +#ifdef CG_LUA + +lvm_t *lVM[NUM_VMS]; +fileHandle_t lualog; + +void QDECL LUA_DEBUG(const char *fmt, ...) +{ + va_list argptr; + char text[1024]; + + if(cg_debugLua.integer >= 1) + { + va_start(argptr, fmt); + Com_sprintf(text, sizeof(text), fmt, argptr); + va_end(argptr); + CG_Printf(S_COLOR_YELLOW "LUA DEBUG:" S_COLOR_WHITE " %s\n", text); + } +} + +void QDECL LUA_LOG(const char *fmt, ...) +{ + va_list argptr; + char buff[1024], string[1024]; + int min, tens, sec; + + va_start(argptr, fmt); + Com_sprintf(buff, sizeof(buff), fmt, argptr); + va_end(argptr); + + if(cg_logLua.integer) { + sec = cg.time / 1000; + min = sec / 60; + sec -= min * 60; + tens = sec / 10; + sec -= tens * 10; + + Com_sprintf(string, sizeof(string), "%i:%i%i %s", min, tens, sec, buff); + + trap_FS_Write(string, strlen(string), lualog); + } +} + +qboolean LoadLuaFile(char *path, int num_vm) +{ + int flen = 0; + char *code; + fileHandle_t f; + lvm_t *vm; + + flen = trap_FS_FOpenFile(path, &f, FS_READ); + if(flen < 0) + { + LUA_LOG("Lua: can not open file %s\n", path); + CG_Printf(S_COLOR_YELLOW "Lua: can not open file %s\n", path); + trap_FS_FCloseFile(f); + return qfalse; + } + else + { + code = (char *)malloc(flen + 1); + if(!code) return qfalse; + trap_FS_Read(code, flen, f); + *(code + flen) = '\0'; + trap_FS_FCloseFile(f); + + vm = (lvm_t *) malloc(sizeof(lvm_t)); + if(vm == NULL) + { + LUA_LOG("Lua: failed to allocate memory for lua VM\n"); + CG_Printf(S_COLOR_YELLOW "Lua: failed to allocate memory for lua VM\n"); + return qfalse; + } + memset(vm, 0, sizeof(lvm_t)); + vm->id = -1; + Q_strncpyz(vm->filename, path, sizeof(vm->filename)); + vm->code = code; + vm->code_size = flen; + vm->error = 0; + + if(CG_LuaStartVM(vm) == qfalse) + { + CG_LuaStopVM(vm); + vm = NULL; + return qfalse; + } + else + { + vm->id = num_vm; + lVM[num_vm] = vm; + return qtrue; + } + } + //return qfalse; +} + +qboolean CG_LuaInit() +{ + char fxfilename[MAX_QPATH]; + fileHandle_t fxfile; + + CG_Printf("------- CG_LuaInit -------\n"); + + // read map fx file + + + // open log file + if(cg_logLua.integer) { + trap_FS_FOpenFile("cg_lua.log", &lualog, FS_APPEND); + } + + CG_Printf("------- CG_LuaInit Finish -------\n"); + + return qtrue; +} + +qboolean CG_LuaResume(lvm_t *vm, lua_State *T, char *func, int nargs) { + int res = lua_resume(T, nargs); + + if(res == LUA_ERRRUN) { + LUA_LOG("Lua: %s error running lua script: %s\n", func, lua_tostring(T, -1)); + CG_Printf(S_COLOR_YELLOW "Lua: %s error running lua script: %s\n", func, lua_tostring(T, -1)); + lua_pop(T, 1); + vm->error++; + return qfalse; + } else if(res == LUA_ERRMEM) { + LUA_LOG("Lua: memory allocation error #2 ( %s )\n", vm->filename); + vm->error++; + return qfalse; + } else if(res == LUA_ERRERR) { + LUA_LOG("Lua: traceback error ( %s )\n", vm->filename); + CG_Printf(S_COLOR_YELLOW "Lua: traceback error ( %s )\n", vm->filename); + vm->error++; + return qfalse; + } + return qtrue; +} + +qboolean CG_LuaCall(lvm_t * vm, char *func, int nargs, int nresults) +{ + int res = lua_pcall(vm->L, nargs, nresults, 0); + + if(res == LUA_ERRRUN) + { + LUA_LOG("Lua: %s error running lua script: %s\n", func, lua_tostring(vm->L, -1)); + CG_Printf(S_COLOR_YELLOW "Lua: %s error running lua script: %s\n", func, lua_tostring(vm->L, -1)); + lua_pop(vm->L, 1); + vm->error++; + return qfalse; + } + else if(res == LUA_ERRMEM) + { + LUA_LOG("Lua: memory allocation error #2 ( %s )\n", vm->filename); + vm->error++; + return qfalse; + } + else if(res == LUA_ERRERR) + { + LUA_LOG("Lua: traceback error ( %s )\n", vm->filename); + CG_Printf(S_COLOR_YELLOW "Lua: traceback error ( %s )\n", vm->filename); + vm->error++; + return qfalse; + } + return qtrue; +} + +#define SAY_ALL 0 +#define SAY_TEAM 1 + +qboolean CG_LuaGetFunctionT(lua_State *T, char *name) +{ + if(T) + { + lua_getglobal(T, name); + if(lua_isfunction(T, -1)) + { + return qtrue; + } + else + { + lua_pop(T, 1); + return qfalse; + } + } + return qfalse; +} + +qboolean CG_LuaGetFunction(lvm_t * vm, char *name) +{ + if(vm->L) + { + lua_getglobal(vm->L, name); + if(lua_isfunction(vm->L, -1)) + { + return qtrue; + } + else + { + lua_pop(vm->L, 1); + return qfalse; + } + } + return qfalse; +} + +qboolean CG_LuaStartVM(lvm_t * vm) +{ + int res = 0; + char homepath[MAX_QPATH], gamepath[MAX_QPATH]; + + vm->L = luaL_newstate(); + if(!vm->L) + { + LUA_LOG("Lua: Lua failed to initialise.\n"); + return qfalse; + } + + luaL_openlibs(vm->L); + + trap_Cvar_VariableStringBuffer("fs_homepath", homepath, sizeof(homepath)); + trap_Cvar_VariableStringBuffer("fs_game", gamepath, sizeof(gamepath)); + + lua_getglobal(vm->L, LUA_LOADLIBNAME); + if(lua_istable(vm->L, -1)) + { + lua_pushstring(vm->L, va("%s%s%s%s?.lua;%s%s%s%slualib%slua%s?.lua", + homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, + homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, LUA_DIRSEP, LUA_DIRSEP)); + lua_setfield(vm->L, -2, "path"); + lua_pushstring(vm->L, va("%s%s%s%s?.%s;%s%s%s%slualib%sclibs%s?.%s", + homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, EXTENSION, + homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, LUA_DIRSEP, LUA_DIRSEP, EXTENSION)); + lua_setfield(vm->L, -2, "cpath"); + } + lua_pop(vm->L, 1); + + Lua_RegisterGlobal(vm->L, "LUA_PATH", va("%s%s%s%s?.lua;%s%s%s%slualib%slua%s?.lua", + homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, + homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, LUA_DIRSEP, LUA_DIRSEP)); + Lua_RegisterGlobal(vm->L, "LUA_CPATH", va("%s%s%s%s?.%s;%s%s%s%slualib%sclibs%s?.%s", + homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, EXTENSION, + homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, LUA_DIRSEP, LUA_DIRSEP, EXTENSION)); + Lua_RegisterGlobal(vm->L, "LUA_DIRSEP", LUA_DIRSEP); + + lua_newtable(vm->L); + Lua_RegConstInteger(vm->L, CS_PLAYERS); + Lua_RegConstInteger(vm->L, EXEC_NOW); + Lua_RegConstInteger(vm->L, EXEC_INSERT); + Lua_RegConstInteger(vm->L, EXEC_APPEND); + Lua_RegConstInteger(vm->L, FS_READ); + Lua_RegConstInteger(vm->L, FS_WRITE); + Lua_RegConstInteger(vm->L, FS_APPEND); + Lua_RegConstInteger(vm->L, FS_APPEND_SYNC); + Lua_RegConstInteger(vm->L, SAY_ALL); + Lua_RegConstInteger(vm->L, SAY_TEAM); + Lua_RegConstString(vm->L, HOSTARCH); + + luaopen_base(vm->L); + luaopen_string(vm->L); + luaopen_coroutine(vm->L); + Luaopen_Qmath(vm->L); + Luaopen_Vector(vm->L); + + res = luaL_loadbuffer(vm->L, vm->code, vm->code_size, vm->filename); + if(res == LUA_ERRSYNTAX) + { + LUA_LOG("Lua: syntax error during pre-compilation: %s\n", (char *)lua_tostring(vm->L, -1)); + CG_Printf(S_COLOR_YELLOW "Lua: syntax error: %s\n", (char *)lua_tostring(vm->L, -1)); + lua_pop(vm->L, 1); + vm->error++; + return qfalse; + } + else if(res == LUA_ERRMEM) + { + LUA_LOG("Lua: memory allocation error #1 ( %s )\n", vm->filename); + vm->error++; + return qfalse; + } + + if(!CG_LuaCall(vm, "CG_LuaStartVM", 0, 0)) + return qfalse; + + LUA_LOG("Lua: Loading %s\n", vm->filename); + return qtrue; +} + +void CG_LuaStopVM(lvm_t * vm) +{ + if(vm == NULL) + return; + if(vm->code != NULL) + { + free(vm->code); + vm->code = NULL; + } + if(vm->id >= 0) + { + if(lVM[vm->id] == vm) + lVM[vm->id] = NULL; + if(!vm->error) + { + LUA_LOG("Lua: Lua module [%s] unloaded.\n", vm->filename); + } + } + free(vm); +} + +void CG_LuaShutdown() +{ + int i; + lvm_t *vm; + + for(i = 0; i < NUM_VMS; i++) + { + vm = lVM[i]; + if(vm) + { + CG_LuaStopVM(vm); + } + } + + trap_FS_FCloseFile(lualog); +} + +void CG_LuaStatus(void) +{ + int i, cnt = 0; + + for(i = 0; i < NUM_VMS; i++) + if(lVM[i]) + cnt++; + + if(cnt == 0) + { + CG_Printf("Lua: no scripts loaded.\n"); + return; + } + else if(cnt == 1) + { + CG_Printf("Lua: showing lua information ( 1 module loaded )\n"); + } + else + { + CG_Printf("Lua: showing lua information ( %d modules loaded )\n", cnt); + } + CG_Printf("%-2s %-24s\n", "VM", "Filename"); + CG_Printf("-- ------------------------\n"); + for(i = 0; i < NUM_VMS; i++) + { + if(lVM[i]) + { + CG_Printf("%2d %-24s\n", lVM[i]->id, lVM[i]->filename); + } + } + CG_Printf("-- ------------------------\n"); + +} + +lvm_t *CG_LuaGetVM(lua_State * L) +{ + int i; + + for(i = 0; i < NUM_VMS; i++) + if(lVM[i] && lVM[i]->L == L) + return lVM[i]; + return NULL; +} + + +#endif diff --git a/code/cgame/cg_lua.h b/code/cgame/cg_lua.h new file mode 100644 index 0000000..ef9c944 --- /dev/null +++ b/code/cgame/cg_lua.h @@ -0,0 +1,99 @@ +#ifndef _G_LUA_H +#define _G_LUA_H + +#include "cg_local.h" + +#if (defined __linux__ || defined __WIN32__) // linux or mingw +#include "../game/lua.h" +#include "../game/lauxlib.h" +#include "../game/lualib.h" +#else +#include "../game/lua.h" +#include "../game/lauxlib.h" +#include "../game/lualib.h" +#endif + +#define NUM_VMS 1 + +#if defined __linux__ +#define HOSTARCH "UNIX" +#define EXTENSION "so" +#elif defined WIN32 +#define HOSTARCH "WIN32" +#define EXTENSION "dll" +#elif defined __APPLE__ +#define HOSTARCH "UNIX" +#define EXTENSION "dylib" +#endif + +#define Lua_RegisterGlobal(L, n, v) (lua_pushstring(L, v), lua_setglobal(L, n)) +#define Lua_RegConstInteger(L, n) (lua_pushstring(L, #n), lua_pushinteger(L, n), lua_settable(L, -3)) +#define Lua_RegConstString(L, n) (lua_pushstring(L, #n), lua_pushstring(L, n), lua_settable(L, -3)) + +typedef struct { + int id; + char filename[MAX_QPATH]; + char *code; + int code_size; + int error; + lua_State *L; +} lvm_t; + +extern lvm_t *lVM[NUM_VMS]; + +void QDECL LUA_DEBUG(const char *fmt, ...); +void QDECL LUA_LOG(const char *fmt, ...); +qboolean CG_LuaInit(void); +qboolean CG_LuaCall(lvm_t *vm, char *func, int nargs, int nresults); +qboolean CG_LuaResume(lvm_t *vm, lua_State *T, char *func, int nargs); +qboolean CG_LuaGetFunction(lvm_t *vm, char *name); +qboolean CG_LuaGetFunctionT(lua_State *T, char *name); +qboolean CG_LuaStartVM(lvm_t *vm); +void CG_LuaStopVM(lvm_t *vm); +void CG_LuaShutdown(void); +void CG_LuaStatus(void); +lvm_t *CG_LuaGetVM(lua_State *L); + +// lua_cgame.c +int Luaopen_CGame(lua_State *L); + +// lua_qmath.c +int Luaopen_Qmath(lua_State *L); + +// lua_vector.c +int Luaopen_Vector(lua_State *L); +void Lua_PushVector(lua_State *L, vec3_t v); +vec_t *Lua_GetVector(lua_State *L, int argNum); +int Lua_IsVector(lua_State *L, int index); +vec3_t *Lua_GetVectorMisc(lua_State *L, int *index); + +// lua_cfx.c +typedef struct { + char luaFunc[MAX_QPATH]; +} cfx_t; + +typedef struct { + cfx_t **cfx; + int cnt; +} cfxList_t; + +void Lua_CFX_LoadMapFxFile(void); + +// lua_cent.c +typedef struct { + centity_t *e; +} cent_t; + +int Luaopen_Cent(lua_State *L); +void Lua_PushCent(lua_State *L, centity_t *ent); +cent_t *Lua_GetCent(lua_State *L, int argNum); +// lua_refent.c +typedef struct { + refEntity_t *r; +} rent_t; + +int Luaopen_Rent(lua_State *L); +void Lua_PushRent(lua_State *L, refEntity_t *rent); +rent_t *Lua_GetRent(lua_State *L, int argNum); + +#endif diff --git a/code/cgame/cg_main.c b/code/cgame/cg_main.c index 6bed3da..2794963 100644 --- a/code/cgame/cg_main.c +++ b/code/cgame/cg_main.c @@ -1,39 +1,34 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // // cg_main.c -- initialization and primary entry point for cgame + +//TiM : 22/12/2005 - Commented out any assets that we no longer use. +//TiM : 24/12/2005 - Added a ranks parsing function. + #include "cg_local.h" +#include "cg_text.h" -#ifdef MISSIONPACK -#include "../ui/ui_shared.h" -// display context for new ui stuff -displayContextDef_t cgDC; -#endif - -int forceModelModificationCount = -1; - -void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum ); +void CG_Init( int serverMessageNum, int serverCommandSequence ); void CG_Shutdown( void ); +void CG_LoadIngameText(void); +void CG_LoadObjectivesForMap(void); +void BG_LoadItemNames(void); +qboolean CG_LoadUsablesStrings( void ); +//TiM - Placed the func @ the bottom of the page for easier access +//extern static qboolean CG_LoadRanks( void ); + +extern void FX_InitSinTable(void); + +//extern lensReflec_s lensReflec[10]; + +int cg_liftEnts[MAX_CLIENTS]; +int cg_numAnims; +int cg_numSndAnims; + +animsSndList_t cg_animsSndList[MAX_CLIENTS]; + +animsList_t cg_animsList[MAX_CLIENTS]; /* ================ @@ -43,11 +38,10 @@ This is the only way control passes into the module. This must be the very first function compiled into the .q3vm file ================ */ -Q_EXPORT intptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11 ) { - +int vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6 ) { switch ( command ) { case CG_INIT: - CG_Init( arg0, arg1, arg2 ); + CG_Init( arg0, arg1 ); return 0; case CG_SHUTDOWN: CG_Shutdown(); @@ -61,19 +55,6 @@ Q_EXPORT intptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3, i return CG_CrosshairPlayer(); case CG_LAST_ATTACKER: return CG_LastAttacker(); - case CG_KEY_EVENT: - CG_KeyEvent(arg0, arg1); - return 0; - case CG_MOUSE_EVENT: -#ifdef MISSIONPACK - cgDC.cursorx = cgs.cursorX; - cgDC.cursory = cgs.cursorY; -#endif - CG_MouseEvent(arg0, arg1); - return 0; - case CG_EVENT_HANDLING: - CG_EventHandling(arg0); - return 0; default: CG_Error( "vmMain: unknown command %i", command ); break; @@ -88,8 +69,6 @@ centity_t cg_entities[MAX_GENTITIES]; weaponInfo_t cg_weapons[MAX_WEAPONS]; itemInfo_t cg_items[MAX_ITEMS]; - -vmCvar_t cg_railTrailTime; vmCvar_t cg_centertime; vmCvar_t cg_runpitch; vmCvar_t cg_runroll; @@ -107,6 +86,7 @@ vmCvar_t cg_drawIcons; vmCvar_t cg_drawAmmoWarning; vmCvar_t cg_drawCrosshair; vmCvar_t cg_drawCrosshairNames; +vmCvar_t cg_dynamicCrosshairNames; vmCvar_t cg_drawRewards; vmCvar_t cg_crosshairSize; vmCvar_t cg_crosshairX; @@ -124,16 +104,12 @@ vmCvar_t cg_noPlayerAnims; vmCvar_t cg_showmiss; vmCvar_t cg_footsteps; vmCvar_t cg_addMarks; -vmCvar_t cg_brassTime; vmCvar_t cg_viewsize; vmCvar_t cg_drawGun; vmCvar_t cg_gun_frame; vmCvar_t cg_gun_x; vmCvar_t cg_gun_y; vmCvar_t cg_gun_z; -vmCvar_t cg_tracerChance; -vmCvar_t cg_tracerWidth; -vmCvar_t cg_tracerLength; vmCvar_t cg_autoswitch; vmCvar_t cg_ignore; vmCvar_t cg_simpleItems; @@ -142,60 +118,98 @@ vmCvar_t cg_zoomFov; vmCvar_t cg_thirdPerson; vmCvar_t cg_thirdPersonRange; vmCvar_t cg_thirdPersonAngle; +//RPG-X: TiM - Cool JKA CVARs +vmCvar_t cg_thirdPersonVertOffset; +vmCvar_t cg_thirdPersonHorzOffset; +vmCvar_t cg_thirdPersonAlpha; +vmCvar_t cg_thirdPersonCameraDamp; +vmCvar_t cg_thirdPersonTargetDamp; +vmCvar_t cg_thirdPersonPitchOffset; +vmCvar_t cg_stereoSeparation; vmCvar_t cg_lagometer; vmCvar_t cg_drawAttacker; vmCvar_t cg_synchronousClients; vmCvar_t cg_teamChatTime; vmCvar_t cg_teamChatHeight; vmCvar_t cg_stats; +vmCvar_t cg_reportDamage; vmCvar_t cg_buildScript; vmCvar_t cg_forceModel; vmCvar_t cg_paused; vmCvar_t cg_blood; + vmCvar_t cg_predictItems; vmCvar_t cg_deferPlayers; vmCvar_t cg_drawTeamOverlay; vmCvar_t cg_teamOverlayUserinfo; -vmCvar_t cg_drawFriend; -vmCvar_t cg_teamChatsOnly; -vmCvar_t cg_noVoiceChats; -vmCvar_t cg_noVoiceText; -vmCvar_t cg_hudFiles; -vmCvar_t cg_scorePlum; -vmCvar_t cg_smoothClients; -vmCvar_t pmove_fixed; -//vmCvar_t cg_pmove_fixed; -vmCvar_t pmove_msec; -vmCvar_t cg_pmove_msec; -vmCvar_t cg_cameraMode; -vmCvar_t cg_cameraOrbit; -vmCvar_t cg_cameraOrbitDelay; -vmCvar_t cg_timescaleFadeEnd; -vmCvar_t cg_timescaleFadeSpeed; -vmCvar_t cg_timescale; -vmCvar_t cg_smallFont; -vmCvar_t cg_bigFont; -vmCvar_t cg_noTaunt; -vmCvar_t cg_noProjectileTrail; -vmCvar_t cg_oldRail; -vmCvar_t cg_oldRocket; -vmCvar_t cg_oldPlasma; -vmCvar_t cg_trueLightning; +vmCvar_t ui_playerClass; +vmCvar_t ui_playerRank; +vmCvar_t cg_disablekillmsgs; +vmCvar_t cg_drawradar; +vmCvar_t rpg_ctribgrenade; //RPG-X: - RedTechie i think J2J added this to control invisible tripmines on clients end - TOFIX:THIS ALSO COULD BE HACKED! +vmCvar_t cg_dynamicCrosshair; //RPG-X | Phenix | 09/06/2005 +vmCvar_t doomHead; //RPG-X | Phenix | 09/06/2005 +vmCvar_t cg_dynamiclensflares; +vmCvar_t cg_noTalkingHeads; +vmCvar_t cg_noDynamicRanks; -#ifdef MISSIONPACK -vmCvar_t cg_redTeamName; -vmCvar_t cg_blueTeamName; -vmCvar_t cg_currentSelectedPlayer; -vmCvar_t cg_currentSelectedPlayerName; -vmCvar_t cg_singlePlayer; -vmCvar_t cg_enableDust; -vmCvar_t cg_enableBreath; -vmCvar_t cg_singlePlayerActive; -vmCvar_t cg_recordSPDemo; -vmCvar_t cg_recordSPDemoName; -vmCvar_t cg_obeliskRespawnDelay; +vmCvar_t noAdminChat; //TiM + +//RPG-X: TiM - Player Model Parameters +vmCvar_t pms_age; +vmCvar_t pms_height; +vmCvar_t pms_weight; +vmCvar_t pms_race; + +vmCvar_t cg_defaultChar; + +//RPG-X: TiM - Emote system model offset +vmCvar_t emote_Offset; + +vmCvar_t cg_thirdPersonZoomRate; +vmCvar_t cg_noFrowningHeads; +vmCvar_t cg_noBlinkingHeads; + +//RPG-X: TiM - First Person Body +vmCvar_t cg_firstPersonBody; + +vmCvar_t cg_defaultModel; + +vmCvar_t cg_showEntityNums; + +//TiM - SecurityCode +vmCvar_t sv_securityHash; +vmCvar_t sv_securityCode; + +//TiM - widescreen +vmCvar_t cg_handleWidescreen; +vmCvar_t ui_handleWidescreen; + +//vmCvar_t cg_chatBGColor; + +vmCvar_t cg_chatColor; + +//RPG-X | GSIO01 | 11/05/2009 +vmCvar_t rpg_forceFieldSet; + +// grp cvars +vmCvar_t grp_berp; + +// lua +#ifdef CG_LUA +vmCvar_t cg_debugLua; +vmCvar_t cg_logLua; #endif + +//RPG-X | Phenix | 05/02/2006 +//Ban System (and it's backup cvars) +//vmCvar_t cg_playerID; +//vmCvar_t s_mhz; //Part A + 562 +//vmCvar_t cg_fow; //Part B + 333 +//vmCvar_t cl_avgPacket; //Part C + 99 +//vmCvar_t cg_rewardsSize;//Part D + 120 + typedef struct { vmCvar_t *vmCvar; char *cvarName; @@ -203,15 +217,19 @@ typedef struct { int cvarFlags; } cvarTable_t; -static cvarTable_t cvarTable[] = { +static cvarTable_t cvarTable[] = { { &cg_ignore, "cg_ignore", "0", 0 }, // used for debugging + //{ &s_mhz, "s_mhz", "0", CVAR_ARCHIVE | CVAR_ROM | CVAR_NORESTART }, //RPG-X | Phenix | 05/02/2006 { &cg_autoswitch, "cg_autoswitch", "1", CVAR_ARCHIVE }, { &cg_drawGun, "cg_drawGun", "1", CVAR_ARCHIVE }, { &cg_zoomFov, "cg_zoomfov", "22.5", CVAR_ARCHIVE }, - { &cg_fov, "cg_fov", "90", CVAR_ARCHIVE }, + { &cg_fov, "cg_fov", "80", CVAR_ARCHIVE }, + //{ &cg_fow, "cg_fow", "0", CVAR_ARCHIVE | CVAR_ROM | CVAR_NORESTART }, //RPG-X | Phenix | 05/02/2006 { &cg_viewsize, "cg_viewsize", "100", CVAR_ARCHIVE }, + { &cg_stereoSeparation, "cg_stereoSeparation", "0.4", CVAR_ARCHIVE }, + //{ &s_mhz, "s_mhz", "0", CVAR_ARCHIVE | CVAR_ROM | CVAR_NORESTART }, //RPG-X | Phenix | 05/02/2006 { &cg_shadows, "cg_shadows", "1", CVAR_ARCHIVE }, - { &cg_gibs, "cg_gibs", "1", CVAR_ARCHIVE }, + { &cg_gibs, "cg_gibs", "0", CVAR_ARCHIVE }, //no gibs in trek { &cg_draw2D, "cg_draw2D", "1", CVAR_ARCHIVE }, { &cg_drawStatus, "cg_drawStatus", "1", CVAR_ARCHIVE }, { &cg_drawTimer, "cg_drawTimer", "0", CVAR_ARCHIVE }, @@ -220,29 +238,28 @@ static cvarTable_t cvarTable[] = { { &cg_draw3dIcons, "cg_draw3dIcons", "1", CVAR_ARCHIVE }, { &cg_drawIcons, "cg_drawIcons", "1", CVAR_ARCHIVE }, { &cg_drawAmmoWarning, "cg_drawAmmoWarning", "1", CVAR_ARCHIVE }, - { &cg_drawAttacker, "cg_drawAttacker", "1", CVAR_ARCHIVE }, - { &cg_drawCrosshair, "cg_drawCrosshair", "4", CVAR_ARCHIVE }, + { &cg_drawAttacker, "cg_drawAttacker", "0", CVAR_ARCHIVE }, //RPG-X TiM + { &cg_drawCrosshair, "cg_drawCrosshair", "1", CVAR_ARCHIVE }, { &cg_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE }, { &cg_drawRewards, "cg_drawRewards", "1", CVAR_ARCHIVE }, + //{ &cg_rewardsSize, "cg_rewardsSize", "0", CVAR_ARCHIVE | CVAR_ROM | CVAR_NORESTART }, //RPG-X | Phenix | 05/02/2006 { &cg_crosshairSize, "cg_crosshairSize", "24", CVAR_ARCHIVE }, { &cg_crosshairHealth, "cg_crosshairHealth", "1", CVAR_ARCHIVE }, { &cg_crosshairX, "cg_crosshairX", "0", CVAR_ARCHIVE }, { &cg_crosshairY, "cg_crosshairY", "0", CVAR_ARCHIVE }, - { &cg_brassTime, "cg_brassTime", "2500", CVAR_ARCHIVE }, { &cg_simpleItems, "cg_simpleItems", "0", CVAR_ARCHIVE }, { &cg_addMarks, "cg_marks", "1", CVAR_ARCHIVE }, - { &cg_lagometer, "cg_lagometer", "1", CVAR_ARCHIVE }, - { &cg_railTrailTime, "cg_railTrailTime", "400", CVAR_ARCHIVE }, + { &cg_lagometer, "cg_lagometer", "0", CVAR_ARCHIVE }, { &cg_gun_x, "cg_gunX", "0", CVAR_CHEAT }, { &cg_gun_y, "cg_gunY", "0", CVAR_CHEAT }, { &cg_gun_z, "cg_gunZ", "0", CVAR_CHEAT }, { &cg_centertime, "cg_centertime", "3", CVAR_CHEAT }, { &cg_runpitch, "cg_runpitch", "0.002", CVAR_ARCHIVE}, { &cg_runroll, "cg_runroll", "0.005", CVAR_ARCHIVE }, - { &cg_bobup , "cg_bobup", "0.005", CVAR_CHEAT }, + { &cg_bobup , "cg_bobup", "0.005", CVAR_ARCHIVE }, { &cg_bobpitch, "cg_bobpitch", "0.002", CVAR_ARCHIVE }, { &cg_bobroll, "cg_bobroll", "0.002", CVAR_ARCHIVE }, - { &cg_swingSpeed, "cg_swingSpeed", "0.3", CVAR_CHEAT }, + { &cg_swingSpeed, "cg_swingSpeed", "0.2", CVAR_CHEAT }, //0.3 //TiM - slowed for better realism { &cg_animSpeed, "cg_animspeed", "1", CVAR_CHEAT }, { &cg_debugAnim, "cg_debuganim", "0", CVAR_CHEAT }, { &cg_debugPosition, "cg_debugposition", "0", CVAR_CHEAT }, @@ -252,71 +269,96 @@ static cvarTable_t cvarTable[] = { { &cg_noPlayerAnims, "cg_noplayeranims", "0", CVAR_CHEAT }, { &cg_showmiss, "cg_showmiss", "0", 0 }, { &cg_footsteps, "cg_footsteps", "1", CVAR_CHEAT }, - { &cg_tracerChance, "cg_tracerchance", "0.4", CVAR_CHEAT }, - { &cg_tracerWidth, "cg_tracerwidth", "1", CVAR_CHEAT }, - { &cg_tracerLength, "cg_tracerlength", "100", CVAR_CHEAT }, - { &cg_thirdPersonRange, "cg_thirdPersonRange", "40", CVAR_CHEAT }, - { &cg_thirdPersonAngle, "cg_thirdPersonAngle", "0", CVAR_CHEAT }, - { &cg_thirdPerson, "cg_thirdPerson", "0", 0 }, + { &cg_thirdPersonRange, "cg_thirdPersonRange", "80", CVAR_ARCHIVE }, + { &cg_thirdPersonAngle, "cg_thirdPersonAngle", "0", CVAR_ARCHIVE }, + { &cg_thirdPerson, "cg_thirdPerson", "0", CVAR_ARCHIVE }, + { &cg_thirdPersonVertOffset, "cg_thirdPersonVertOffset", "16", CVAR_ARCHIVE }, //RPG-X: TiM + { &cg_thirdPersonHorzOffset, "cg_thirdPersonHorzOffset", "0", CVAR_ARCHIVE }, //RPG-X: TiM + { &cg_thirdPersonAlpha, "cg_thirdPersonAlpha", "1.0", CVAR_ARCHIVE },//RPG-X: TiM + { &cg_thirdPersonCameraDamp, "cg_thirdPersonCameraDamp", "0.3", CVAR_ARCHIVE },//RPG-X: TiM + { &cg_thirdPersonTargetDamp, "cg_thirdPersonTargetDamp", "0.5", CVAR_ARCHIVE },//RPG-X: TiM + { &cg_thirdPersonPitchOffset, "cg_thirdPersonPitchOffset", "0.0", CVAR_ARCHIVE},//RPG-X: TiM + { &cg_firstPersonBody, "cg_firstPersonBody", "0", CVAR_ARCHIVE}, { &cg_teamChatTime, "cg_teamChatTime", "3000", CVAR_ARCHIVE }, { &cg_teamChatHeight, "cg_teamChatHeight", "0", CVAR_ARCHIVE }, { &cg_forceModel, "cg_forceModel", "0", CVAR_ARCHIVE }, { &cg_predictItems, "cg_predictItems", "1", CVAR_ARCHIVE }, -#ifdef MISSIONPACK - { &cg_deferPlayers, "cg_deferPlayers", "0", CVAR_ARCHIVE }, -#else { &cg_deferPlayers, "cg_deferPlayers", "1", CVAR_ARCHIVE }, -#endif { &cg_drawTeamOverlay, "cg_drawTeamOverlay", "0", CVAR_ARCHIVE }, { &cg_teamOverlayUserinfo, "teamoverlay", "0", CVAR_ROM | CVAR_USERINFO }, { &cg_stats, "cg_stats", "0", 0 }, - { &cg_drawFriend, "cg_drawFriend", "1", CVAR_ARCHIVE }, - { &cg_teamChatsOnly, "cg_teamChatsOnly", "0", CVAR_ARCHIVE }, - { &cg_noVoiceChats, "cg_noVoiceChats", "0", CVAR_ARCHIVE }, - { &cg_noVoiceText, "cg_noVoiceText", "0", CVAR_ARCHIVE }, + { &cg_reportDamage, "cg_reportDamage", "0", 0}, + { &rpg_ctribgrenade, "rpg_ctribgrenade", "0", CVAR_ARCHIVE}, //RPG-X: - RedTechie i think J2J added this to control invisible tripmines on clients end - TOFIX:THIS ALSO COULD BE HACKED! + { &pms_age, "age", "Unknown", CVAR_ARCHIVE | CVAR_USERINFO }, + { &pms_height, "height", "1.0", CVAR_ARCHIVE | CVAR_USERINFO }, + { &pms_weight, "weight", "1.0", CVAR_ARCHIVE | CVAR_USERINFO }, + { &pms_race, "race", "Unknown", CVAR_ARCHIVE | CVAR_USERINFO }, + { &emote_Offset, "modelOffset", "0", CVAR_ARCHIVE | CVAR_USERINFO }, + + { &cg_defaultChar, "cg_defaultChar", DEFAULT_CHAR, CVAR_ARCHIVE }, + // the following variables are created in other parts of the system, // but we also reference them here + { &cg_buildScript, "com_buildScript", "0", 0 }, // force loading of all possible data amd error on failures { &cg_paused, "cl_paused", "0", CVAR_ROM }, - { &cg_blood, "com_blood", "1", CVAR_ARCHIVE }, - { &cg_synchronousClients, "g_synchronousClients", "0", CVAR_SYSTEMINFO }, -#ifdef MISSIONPACK - { &cg_redTeamName, "g_redteam", DEFAULT_REDTEAM_NAME, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO }, - { &cg_blueTeamName, "g_blueteam", DEFAULT_BLUETEAM_NAME, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO }, - { &cg_currentSelectedPlayer, "cg_currentSelectedPlayer", "0", CVAR_ARCHIVE}, - { &cg_currentSelectedPlayerName, "cg_currentSelectedPlayerName", "", CVAR_ARCHIVE}, - { &cg_singlePlayer, "ui_singlePlayerActive", "0", CVAR_USERINFO}, - { &cg_enableDust, "g_enableDust", "0", CVAR_SERVERINFO}, - { &cg_enableBreath, "g_enableBreath", "0", CVAR_SERVERINFO}, - { &cg_singlePlayerActive, "ui_singlePlayerActive", "0", CVAR_USERINFO}, - { &cg_recordSPDemo, "ui_recordSPDemo", "0", CVAR_ARCHIVE}, - { &cg_recordSPDemoName, "ui_recordSPDemoName", "", CVAR_ARCHIVE}, - { &cg_obeliskRespawnDelay, "g_obeliskRespawnDelay", "10", CVAR_SERVERINFO}, - { &cg_hudFiles, "cg_hudFiles", "ui/hud.txt", CVAR_ARCHIVE}, -#endif - { &cg_cameraOrbit, "cg_cameraOrbit", "0", CVAR_CHEAT}, - { &cg_cameraOrbitDelay, "cg_cameraOrbitDelay", "50", CVAR_ARCHIVE}, - { &cg_timescaleFadeEnd, "cg_timescaleFadeEnd", "1", 0}, - { &cg_timescaleFadeSpeed, "cg_timescaleFadeSpeed", "0", 0}, - { &cg_timescale, "timescale", "1", 0}, - { &cg_scorePlum, "cg_scorePlums", "1", CVAR_USERINFO | CVAR_ARCHIVE}, - { &cg_smoothClients, "cg_smoothClients", "0", CVAR_USERINFO | CVAR_ARCHIVE}, - { &cg_cameraMode, "com_cameraMode", "0", CVAR_CHEAT}, + { &cg_blood, "com_blood", "0", CVAR_ARCHIVE }, //no blood in trek + //{ &cl_avgPacket, "cl_avgPacket", "0", CVAR_ARCHIVE | CVAR_ROM | CVAR_NORESTART }, //RPG-X | Phenix | 05/02/2006 + { &cg_synchronousClients, "g_synchronousClients", "0", 0 }, // communicated by systeminfo + { &ui_playerClass, "ui_playerClass", "noclass", CVAR_ARCHIVE /*| CVAR_ROM | CVAR_USERINFO*/ }, + //{ &ui_playerclass, "ui_playerclass", "0", 0 }, // player class + { &ui_playerRank, "ui_playerRank", "crewman", CVAR_ARCHIVE /*| CVAR_ROM | CVAR_USERINFO*/ }, + + { &cg_disablekillmsgs, "cg_disablekillmsgs", "0", CVAR_ARCHIVE }, + { &cg_drawradar, "cg_drawradar", "1", CVAR_ARCHIVE }, + + { &cg_dynamicCrosshair, "cg_dynamicCrosshair", "1", CVAR_ARCHIVE }, //RPG-X | Phenix | 09/06/2005 + { &doomHead, "doomHead", "0", CVAR_ARCHIVE }, //RPG-X | Phenix | 09/06/2005 + { &cg_dynamiclensflares, "cg_dynamicLensFlares", "1", CVAR_ARCHIVE }, //RPG-X | TiM | 29/6/2005 + + { &cg_dynamicCrosshairNames, "cg_dynamicCrosshairNames", "1", CVAR_ARCHIVE }, + + { &noAdminChat, "noAdminChat", "0", CVAR_ARCHIVE | CVAR_USERINFO }, + + //RPG-X Memory optimization CVARs + { &cg_noTalkingHeads, "cg_noTalkingHeads", "0", CVAR_ARCHIVE }, + { &cg_noDynamicRanks, "cg_noDynamicRanks", "0", CVAR_ARCHIVE }, + { &cg_noFrowningHeads, "cg_noFrowningHeads", "1", CVAR_ARCHIVE }, //On by default since this isn't REALLY needed... :P + { &cg_noBlinkingHeads, "cg_noBlinkingHeads", "0", CVAR_ARCHIVE }, + + { &cg_thirdPersonZoomRate, "cg_thirdPersonZoomRate", "25", CVAR_ARCHIVE }, + { &cg_showEntityNums, "cg_showEntityNums", "1", CVAR_ARCHIVE }, + + //TiM - security cvars + { &sv_securityHash, "sv_securityHash", "4294967295", CVAR_ARCHIVE | CVAR_ROM | CVAR_NORESTART }, + { &sv_securityCode, "sv_securityCode", "4294967295", CVAR_ARCHIVE | CVAR_USERINFO | CVAR_ROM | CVAR_NORESTART }, + + { &cg_handleWidescreen, "cg_handleWidescreen", "1", CVAR_ARCHIVE }, + { &ui_handleWidescreen, "ui_handleWidescreen", "1", CVAR_ARCHIVE }, + + { &cg_chatColor, "cg_chatColor", "", CVAR_ARCHIVE }, + + //RPG-X | GSIO01 | 11/05/2009 + { &rpg_forceFieldSet, "rpg_forceFieldSet", "1", CVAR_ARCHIVE | CVAR_LATCH }, + + //{ &cg_chatBGColor, "cg_chatBGColor", "", CVAR_ARCHIVE } + + //{ &cg_defaultModel, "cg_defaultModel", DEFAULT_PLAYER, CVAR_ARCHIVE }, + + //{ &cg_playerID, "cg_playerID", "0", CVAR_ARCHIVE | CVAR_ROM | CVAR_NORESTART } + + // grp cvars + { &grp_berp, "grp_berp", "0", CVAR_ARCHIVE | CVAR_LATCH }, + + // lua +#ifdef CG_LUA + { &cg_debugLua, "cg_debuglua", "0", CVAR_ARCHIVE | CVAR_LATCH }, + { &cg_logLua, "cg_loglua", "0", CVAR_ARCHIVE } +#endif - { &pmove_fixed, "pmove_fixed", "0", CVAR_SYSTEMINFO}, - { &pmove_msec, "pmove_msec", "8", CVAR_SYSTEMINFO}, - { &cg_noTaunt, "cg_noTaunt", "0", CVAR_ARCHIVE}, - { &cg_noProjectileTrail, "cg_noProjectileTrail", "0", CVAR_ARCHIVE}, - { &cg_smallFont, "ui_smallFont", "0.25", CVAR_ARCHIVE}, - { &cg_bigFont, "ui_bigFont", "0.4", CVAR_ARCHIVE}, - { &cg_oldRail, "cg_oldRail", "1", CVAR_ARCHIVE}, - { &cg_oldRocket, "cg_oldRocket", "1", CVAR_ARCHIVE}, - { &cg_oldPlasma, "cg_oldPlasma", "1", CVAR_ARCHIVE}, - { &cg_trueLightning, "cg_trueLightning", "0.0", CVAR_ARCHIVE} -// { &cg_pmove_fixed, "cg_pmove_fixed", "0", CVAR_USERINFO | CVAR_ARCHIVE } }; -static int cvarTableSize = ARRAY_LEN( cvarTable ); +static int cvarTableSize = sizeof( cvarTable ) / sizeof( cvarTable[0] ); /* ================= @@ -336,33 +378,8 @@ void CG_RegisterCvars( void ) { // see if we are also running the server on this machine trap_Cvar_VariableStringBuffer( "sv_running", var, sizeof( var ) ); cgs.localServer = atoi( var ); - - forceModelModificationCount = cg_forceModel.modificationCount; - - trap_Cvar_Register(NULL, "model", DEFAULT_MODEL, CVAR_USERINFO | CVAR_ARCHIVE ); - trap_Cvar_Register(NULL, "headmodel", DEFAULT_MODEL, CVAR_USERINFO | CVAR_ARCHIVE ); - trap_Cvar_Register(NULL, "team_model", DEFAULT_TEAM_MODEL, CVAR_USERINFO | CVAR_ARCHIVE ); - trap_Cvar_Register(NULL, "team_headmodel", DEFAULT_TEAM_HEAD, CVAR_USERINFO | CVAR_ARCHIVE ); } -/* -=================== -CG_ForceModelChange -=================== -*/ -static void CG_ForceModelChange( void ) { - int i; - - for (i=0 ; ivmCvar ); } // check for modications here - // If team overlay is on, ask for updates from the server. If it's off, + // If team overlay is on, ask for updates from the server. If its off, // let the server know so we don't receive it if ( drawTeamOverlayModificationCount != cg_drawTeamOverlay.modificationCount ) { drawTeamOverlayModificationCount = cg_drawTeamOverlay.modificationCount; @@ -390,14 +408,9 @@ void CG_UpdateCvars( void ) { trap_Cvar_Set( "teamoverlay", "0" ); } } - - // if force model changed - if ( forceModelModificationCount != cg_forceModel.modificationCount ) { - forceModelModificationCount = cg_forceModel.modificationCount; - CG_ForceModelChange(); - } } + int CG_CrosshairPlayer( void ) { if ( cg.time > ( cg.crosshairClientTime + 1000 ) ) { return -1; @@ -405,6 +418,7 @@ int CG_CrosshairPlayer( void ) { return cg.crosshairClientNum; } + int CG_LastAttacker( void ) { if ( !cg.attackerTime ) { return -1; @@ -412,14 +426,68 @@ int CG_LastAttacker( void ) { return cg.snap->ps.persistant[PERS_ATTACKER]; } + void QDECL CG_Printf( const char *msg, ... ) { va_list argptr; char text[1024]; + char *msgPtr; va_start (argptr, msg); - Q_vsnprintf (text, sizeof(text), msg, argptr); + vsprintf (text, msg, argptr); va_end (argptr); + if ( cg_chatColor.integer > 0 && cg_chatColor.integer < 8 ) + { + msgPtr = text; + + while ( msgPtr && *msgPtr != '\0' ) + { + if ( *msgPtr == '^' ) + { + msgPtr++; + *msgPtr = 48 + cg_chatColor.integer; + } + + msgPtr++; + } + } + + //CVAR background + /*if ( cg_chatBGColor.string[0] ) + { + char *bgColor; + char *rimColor; + int rgb[3]; + int i; + + Q_strlwr( cg_chatBGColor.string ); + + bgColor = cg_chatBGColor.string; + + if ( *bgColor == '#' ) + { + bgColor[7]='\0'; + bgColor++; + + for ( i=0; i < 3; i++ ) + { + if ( *bgColor >= 'a' && *bgColor <='f' ) + rgb[i] = 16 * ( 10 + (int)(*bgColor - 'a')); + else + rgb[i] = 16 * atoi(bgColor[0]); + + bgColor++; + + if ( *bgColor >= 'a' && *bgColor <='f' ) + rgb[i] += ( 10 + (int)(*bgColor - 'a')); + else + rgb[i] += atoi(bgColor[0]); + } + + + } + }*/ + trap_Print( text ); } @@ -428,18 +496,21 @@ void QDECL CG_Error( const char *msg, ... ) { char text[1024]; va_start (argptr, msg); - Q_vsnprintf (text, sizeof(text), msg, argptr); + vsprintf (text, msg, argptr); va_end (argptr); trap_Error( text ); } +#ifndef CGAME_HARD_LINKED +// this is only here so the functions in q_shared.c and bg_*.c can link (FIXME) + void QDECL Com_Error( int level, const char *error, ... ) { va_list argptr; char text[1024]; va_start (argptr, error); - Q_vsnprintf (text, sizeof(text), error, argptr); + vsprintf (text, error, argptr); va_end (argptr); CG_Error( "%s", text); @@ -450,12 +521,16 @@ void QDECL Com_Printf( const char *msg, ... ) { char text[1024]; va_start (argptr, msg); - Q_vsnprintf (text, sizeof(text), msg, argptr); + vsprintf (text, msg, argptr); va_end (argptr); CG_Printf ("%s", text); } +#endif + + + /* ================ CG_Argv @@ -487,8 +562,9 @@ static void CG_RegisterItemSounds( int itemNum ) { item = &bg_itemlist[ itemNum ]; - if( item->pickup_sound ) { - trap_S_RegisterSound( item->pickup_sound, qfalse ); + if ( item->pickup_sound ) + { + trap_S_RegisterSound( item->pickup_sound ); } // parse the space seperated precache string for other media @@ -515,7 +591,7 @@ static void CG_RegisterItemSounds( int itemNum ) { } if ( !strcmp(data+len-3, "wav" )) { - trap_S_RegisterSound( data, qfalse ); + trap_S_RegisterSound( data ); } } } @@ -528,183 +604,189 @@ CG_RegisterSounds called during a precache command ================= */ -static void CG_RegisterSounds( void ) { +static void CG_RegisterSounds( void ) +{ int i; char items[MAX_ITEMS+1]; char name[MAX_QPATH]; const char *soundName; - // voice commands -#ifdef MISSIONPACK - CG_LoadVoiceChats(); -#endif + cg.loadLCARSStage = 1; // Loading bar stage 1 + CG_LoadingString( "sounds" ); - cgs.media.oneMinuteSound = trap_S_RegisterSound( "sound/feedback/1_minute.wav", qtrue ); - cgs.media.fiveMinuteSound = trap_S_RegisterSound( "sound/feedback/5_minute.wav", qtrue ); - cgs.media.suddenDeathSound = trap_S_RegisterSound( "sound/feedback/sudden_death.wav", qtrue ); - cgs.media.oneFragSound = trap_S_RegisterSound( "sound/feedback/1_frag.wav", qtrue ); - cgs.media.twoFragSound = trap_S_RegisterSound( "sound/feedback/2_frags.wav", qtrue ); - cgs.media.threeFragSound = trap_S_RegisterSound( "sound/feedback/3_frags.wav", qtrue ); - cgs.media.count3Sound = trap_S_RegisterSound( "sound/feedback/three.wav", qtrue ); - cgs.media.count2Sound = trap_S_RegisterSound( "sound/feedback/two.wav", qtrue ); - cgs.media.count1Sound = trap_S_RegisterSound( "sound/feedback/one.wav", qtrue ); - cgs.media.countFightSound = trap_S_RegisterSound( "sound/feedback/fight.wav", qtrue ); - cgs.media.countPrepareSound = trap_S_RegisterSound( "sound/feedback/prepare.wav", qtrue ); -#ifdef MISSIONPACK - cgs.media.countPrepareTeamSound = trap_S_RegisterSound( "sound/feedback/prepare_team.wav", qtrue ); -#endif + //TiM + /*if ( cgs.timelimit || cg_buildScript.integer ) { // should we always load this? + cgs.media.oneMinuteSound = trap_S_RegisterSound( "sound/voice/computer/misc/1_minute.wav" ); + cgs.media.fiveMinuteSound = trap_S_RegisterSound( "sound/voice/computer/misc/5_minute.wav" ); + cgs.media.suddenDeathSound = trap_S_RegisterSound( "sound/voice/computer/misc/sudden_death.wav" ); + }*/ - if ( cgs.gametype >= GT_TEAM || cg_buildScript.integer ) { + //TiM + /*if ( cgs.fraglimit || cg_buildScript.integer ) { + cgs.media.oneFragSound = trap_S_RegisterSound( "sound/voice/computer/misc/1_frag.wav" ); + cgs.media.twoFragSound = trap_S_RegisterSound( "sound/voice/computer/misc/2_frags.wav" ); + cgs.media.threeFragSound = trap_S_RegisterSound( "sound/voice/computer/misc/3_frags.wav" ); + }*/ - cgs.media.captureAwardSound = trap_S_RegisterSound( "sound/teamplay/flagcapture_yourteam.wav", qtrue ); - cgs.media.redLeadsSound = trap_S_RegisterSound( "sound/feedback/redleads.wav", qtrue ); - cgs.media.blueLeadsSound = trap_S_RegisterSound( "sound/feedback/blueleads.wav", qtrue ); - cgs.media.teamsTiedSound = trap_S_RegisterSound( "sound/feedback/teamstied.wav", qtrue ); - cgs.media.hitTeamSound = trap_S_RegisterSound( "sound/feedback/hit_teammate.wav", qtrue ); +// if ( cgs.gametype == GT_TOURNAMENT || cg_buildScript.integer ) { +// We always need this since a warmup can be enabled in any game mode +//TiM /*cgs.media.count3Sound = trap_S_RegisterSound( "sound/voice/computer/misc/three.wav" ); + cgs.media.count2Sound = trap_S_RegisterSound( "sound/voice/computer/misc/two.wav" ); + cgs.media.count1Sound = trap_S_RegisterSound( "sound/voice/computer/misc/one.wav" ); + cgs.media.countFightSound = trap_S_RegisterSound( "sound/voice/computer/misc/fight.wav" ); + cgs.media.countPrepareSound = trap_S_RegisterSound( "sound/voice/computer/misc/prepare.wav" ); +// } + //TiM +/* if ( cgs.gametype >= GT_TEAM || cg_buildScript.integer ) { + cgs.media.redLeadsSound = trap_S_RegisterSound( "sound/voice/computer/misc/redleads.wav" ); + cgs.media.blueLeadsSound = trap_S_RegisterSound( "sound/voice/computer/misc/blueleads.wav" ); + cgs.media.teamsTiedSound = trap_S_RegisterSound( "sound/voice/computer/misc/teamstied.wav" ); + cgs.media.hitTeamSound = trap_S_RegisterSound( "sound/feedback/hit_teammate.wav" ); + }*/ - cgs.media.redScoredSound = trap_S_RegisterSound( "sound/teamplay/voc_red_scores.wav", qtrue ); - cgs.media.blueScoredSound = trap_S_RegisterSound( "sound/teamplay/voc_blue_scores.wav", qtrue ); + //TiM + /*if (cgs.gametype == GT_CTF || cg_buildScript.integer) + { + cgs.media.ctfStealSound = trap_S_RegisterSound("sound/voice/computer/misc/flagtk_blu.wav"); + cgs.media.ctfReturnSound = trap_S_RegisterSound("sound/voice/computer/misc/flagret_blu.wav"); + cgs.media.ctfScoreSound = trap_S_RegisterSound("sound/voice/computer/misc/flagcap_blu.wav"); + cgs.media.ctfYouStealVoiceSound = trap_S_RegisterSound("sound/voice/computer/misc/stolen.wav"); + cgs.media.ctfYouDroppedVoiceSound = trap_S_RegisterSound("sound/voice/computer/misc/dropped_e.wav"); + cgs.media.ctfYouReturnVoiceSound = trap_S_RegisterSound("sound/voice/computer/misc/returned.wav"); + cgs.media.ctfYouScoreVoiceSound = trap_S_RegisterSound("sound/voice/computer/misc/scored.wav"); + cgs.media.ctfTheyStealVoiceSound = trap_S_RegisterSound("sound/voice/computer/misc/stolen_e.wav"); + cgs.media.ctfTheyDroppedVoiceSound = trap_S_RegisterSound("sound/voice/computer/misc/dropped.wav"); // Note the flip, because YOU dropped THEIR flag + cgs.media.ctfTheyReturnVoiceSound = trap_S_RegisterSound("sound/voice/computer/misc/returned_e.wav"); + cgs.media.ctfTheyScoreVoiceSound = trap_S_RegisterSound("sound/voice/computer/misc/scored_e.wav"); + }*/ - cgs.media.captureYourTeamSound = trap_S_RegisterSound( "sound/teamplay/flagcapture_yourteam.wav", qtrue ); - cgs.media.captureOpponentSound = trap_S_RegisterSound( "sound/teamplay/flagcapture_opponent.wav", qtrue ); + cgs.media.interfaceSnd1 = trap_S_RegisterSound( "sound/interface/button4.wav" ); - cgs.media.returnYourTeamSound = trap_S_RegisterSound( "sound/teamplay/flagreturn_yourteam.wav", qtrue ); - cgs.media.returnOpponentSound = trap_S_RegisterSound( "sound/teamplay/flagreturn_opponent.wav", qtrue ); + //cgs.media.selectSound = trap_S_RegisterSound( "sound/silence.wav" );//trap_S_RegisterSound( "sound/weapons/change.wav" ); + //cgs.media.wearOffSound = trap_S_RegisterSound( "sound/items/wearoff.wav" ); + cgs.media.useNothingSound = trap_S_RegisterSound( "sound/items/use_nothing.wav" ); - cgs.media.takenYourTeamSound = trap_S_RegisterSound( "sound/teamplay/flagtaken_yourteam.wav", qtrue ); - cgs.media.takenOpponentSound = trap_S_RegisterSound( "sound/teamplay/flagtaken_opponent.wav", qtrue ); + //TiM//cgs.media.holoOpenSound = trap_S_RegisterSound( "sound/movers/doors/holoopen.wav" ); + cgs.media.teleInSound = trap_S_RegisterSound( "sound/world/transin.wav" ); + //cgs.media.teleOutSound = trap_S_RegisterSound( "sound/world/transout.wav" ); + cgs.media.transportSound = trap_S_RegisterSound( "sound/world/transporter.wav" ); + cgs.media.respawnSound = trap_S_RegisterSound( "sound/items/respawn1.wav" ); - if ( cgs.gametype == GT_CTF || cg_buildScript.integer ) { - cgs.media.redFlagReturnedSound = trap_S_RegisterSound( "sound/teamplay/voc_red_returned.wav", qtrue ); - cgs.media.blueFlagReturnedSound = trap_S_RegisterSound( "sound/teamplay/voc_blue_returned.wav", qtrue ); - cgs.media.enemyTookYourFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_enemy_flag.wav", qtrue ); - cgs.media.yourTeamTookEnemyFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_team_flag.wav", qtrue ); - } + //cgs.media.noAmmoSound = trap_S_RegisterSound( "sound/weapons/noammo.wav" ); -#ifdef MISSIONPACK - if ( cgs.gametype == GT_1FCTF || cg_buildScript.integer ) { - // FIXME: get a replacement for this sound ? - cgs.media.neutralFlagReturnedSound = trap_S_RegisterSound( "sound/teamplay/flagreturn_opponent.wav", qtrue ); - cgs.media.yourTeamTookTheFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_team_1flag.wav", qtrue ); - cgs.media.enemyTookTheFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_enemy_1flag.wav", qtrue ); - } + cgs.media.talkSound = trap_S_RegisterSound( "sound/interface/communicator.wav" ); + + //cgs.media.landSound = trap_S_RegisterSound( "sound/player/land1.wav"); + //RPG-X | GSIO01 | 20/05/2009: + cgs.media.landSound[LANDSOUND_NORMAL] = trap_S_RegisterSound("sound/player/land1.wav"); + cgs.media.landSound[LANDSOUND_GRASS] = trap_S_RegisterSound("sound/player/footsteps/grass_jump.wav"); + cgs.media.landSound[LANDSOUND_GRAVEL] = trap_S_RegisterSound("sound/player/footsteps/gravel_jump.wav"); + cgs.media.landSound[LANDSOUND_SNOW] = trap_S_RegisterSound("sound/player/footsteps/snow_jump.wav"); + cgs.media.landSound[LANDSOUND_WOOD] = trap_S_RegisterSound("sound/player/footsteps/wood_jump.wav"); - if ( cgs.gametype == GT_1FCTF || cgs.gametype == GT_CTF || cg_buildScript.integer ) { - cgs.media.youHaveFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_you_flag.wav", qtrue ); - cgs.media.holyShitSound = trap_S_RegisterSound("sound/feedback/voc_holyshit.wav", qtrue); - } + cgs.media.splatSound = trap_S_RegisterSound( "sound/weapons/bodyfall.wav"); - if ( cgs.gametype == GT_OBELISK || cg_buildScript.integer ) { - cgs.media.yourBaseIsUnderAttackSound = trap_S_RegisterSound( "sound/teamplay/voc_base_attack.wav", qtrue ); - } -#else - cgs.media.youHaveFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_you_flag.wav", qtrue ); - cgs.media.holyShitSound = trap_S_RegisterSound("sound/feedback/voc_holyshit.wav", qtrue); - cgs.media.neutralFlagReturnedSound = trap_S_RegisterSound( "sound/teamplay/flagreturn_opponent.wav", qtrue ); - cgs.media.yourTeamTookTheFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_team_1flag.wav", qtrue ); - cgs.media.enemyTookTheFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_enemy_1flag.wav", qtrue ); -#endif + //cgs.media.hitSound = trap_S_RegisterSound( "sound/feedback/hit.wav" ); + //cgs.media.shieldHitSound = trap_S_RegisterSound( "sound/feedback/shieldHit.wav" ); + //cgs.media.shieldPierceSound = trap_S_RegisterSound( "sound/feedback/shieldPierce.wav" ); + + //TiM + /*cgs.media.rewardImpressiveSound = trap_S_RegisterSound( "sound/voice/computer/misc/impressive.wav" ); + cgs.media.rewardExcellentSound = trap_S_RegisterSound( "sound/voice/computer/misc/excellent.wav" ); + cgs.media.rewardDeniedSound = trap_S_RegisterSound( "sound/voice/computer/misc/denied.wav" ); + cgs.media.rewardFirstStrikeSound = trap_S_RegisterSound( "sound/voice/computer/misc/1ststrike.wav"); + cgs.media.rewardAceSound = trap_S_RegisterSound( "sound/voice/computer/misc/ace.wav"); + cgs.media.rewardExpertSound = trap_S_RegisterSound( "sound/voice/computer/misc/expert.wav"); + cgs.media.rewardMasterSound = trap_S_RegisterSound( "sound/voice/computer/misc/master.wav"); + cgs.media.rewardChampionSound = trap_S_RegisterSound( "sound/voice/computer/misc/champion.wav");*/ + + //TiM + /*cgs.media.takenLeadSound = trap_S_RegisterSound( "sound/voice/computer/misc/takenlead.wav"); + cgs.media.tiedLeadSound = trap_S_RegisterSound( "sound/voice/computer/misc/tiedlead.wav"); + cgs.media.lostLeadSound = trap_S_RegisterSound( "sound/voice/computer/misc/lostlead.wav");*/ + + cgs.media.watrInSound = trap_S_RegisterSound( "sound/player/watr_in.wav"); + cgs.media.watrOutSound = trap_S_RegisterSound( "sound/player/watr_out.wav"); + cgs.media.watrUnSound = trap_S_RegisterSound( "sound/player/watr_un.wav"); + + cgs.media.jumpPadSound = trap_S_RegisterSound ("sound/items/damage3.wav" ); + + //cgs.media.poweruprespawnSound = trap_S_RegisterSound ("sound/items/poweruprespawn.wav"); + cgs.media.disintegrateSound = trap_S_RegisterSound( "sound/weapons/prifle/disint.wav" ); + cgs.media.disintegrate2Sound = trap_S_RegisterSound( "sound/weapons/prifle/disint2.wav" ); + cgs.media.playerExplodeSound = trap_S_RegisterSound( "sound/weapons/explosions/fireball.wav" ); + + //TiM + /*cgs.media.holoInitSound = trap_S_RegisterSound("sound/voice/computer/misc/proginit.wav"); + cgs.media.holoDoorSound = trap_S_RegisterSound("sound/movers/doors/holoopen.wav"); + cgs.media.holoFadeSound = trap_S_RegisterSound("sound/movers/holodeckdecloak.wav");*/ + + cgs.media.phaserEmptySound = trap_S_RegisterSound("sound/weapons/phaser/phaserempty.wav"); + + //RPG-X: RedTechie - Load sound for shake cmd + cgs.media.ShakeSound = trap_S_RegisterSound("sound/shake.wav"); + + cgs.media.tedTextSound = trap_S_RegisterSound( "sound/interface/tedtext.wav" ); + + //RPG-X | Phenix | 13/02/2005 + for (i=0 ; i= GT_TEAM || cg_buildScript.integer ) { - cgs.media.friendShader = trap_R_RegisterShader( "sprites/foe" ); + //TiM + /*if ( cgs.gametype >= GT_TEAM || cg_buildScript.integer ) { + cgs.media.teamRedShader = trap_R_RegisterShader( "sprites/team_red" ); + cgs.media.teamBlueShader = trap_R_RegisterShader( "sprites/team_blue" ); cgs.media.redQuadShader = trap_R_RegisterShader("powerups/blueflag" ); cgs.media.teamStatusBar = trap_R_RegisterShader( "gfx/2d/colorbar.tga" ); -#ifdef MISSIONPACK - cgs.media.blueKamikazeShader = trap_R_RegisterShader( "models/weaphits/kamikblu" ); -#endif - } + }*/ - cgs.media.armorModel = trap_R_RegisterModel( "models/powerups/armor/armor_yel.md3" ); - cgs.media.armorIcon = trap_R_RegisterShaderNoMip( "icons/iconr_yellow" ); + //cgs.media.chatShader = trap_R_RegisterShader( "sprites/chat" ); - cgs.media.machinegunBrassModel = trap_R_RegisterModel( "models/weapons2/shells/m_shell.md3" ); - cgs.media.shotgunBrassModel = trap_R_RegisterModel( "models/weapons2/shells/s_shell.md3" ); + //cgs.media.bloodExplosionShader = trap_R_RegisterShader( "bloodExplosion" ); - cgs.media.gibAbdomen = trap_R_RegisterModel( "models/gibs/abdomen.md3" ); - cgs.media.gibArm = trap_R_RegisterModel( "models/gibs/arm.md3" ); - cgs.media.gibChest = trap_R_RegisterModel( "models/gibs/chest.md3" ); - cgs.media.gibFist = trap_R_RegisterModel( "models/gibs/fist.md3" ); - cgs.media.gibFoot = trap_R_RegisterModel( "models/gibs/foot.md3" ); - cgs.media.gibForearm = trap_R_RegisterModel( "models/gibs/forearm.md3" ); - cgs.media.gibIntestine = trap_R_RegisterModel( "models/gibs/intestine.md3" ); - cgs.media.gibLeg = trap_R_RegisterModel( "models/gibs/leg.md3" ); - cgs.media.gibSkull = trap_R_RegisterModel( "models/gibs/skull.md3" ); - cgs.media.gibBrain = trap_R_RegisterModel( "models/gibs/brain.md3" ); - - cgs.media.smoke2 = trap_R_RegisterModel( "models/weapons2/shells/s_shell.md3" ); - - cgs.media.balloonShader = trap_R_RegisterShader( "sprites/balloon3" ); - - cgs.media.bloodExplosionShader = trap_R_RegisterShader( "bloodExplosion" ); - - cgs.media.bulletFlashModel = trap_R_RegisterModel("models/weaphits/bullet.md3"); - cgs.media.ringFlashModel = trap_R_RegisterModel("models/weaphits/ring02.md3"); - cgs.media.dishFlashModel = trap_R_RegisterModel("models/weaphits/boom01.md3"); -#ifdef MISSIONPACK - cgs.media.teleportEffectModel = trap_R_RegisterModel( "models/powerups/pop.md3" ); -#else + //cgs.media.ringFlashModel = trap_R_RegisterModel("models/weaphits/ring02.md3"); cgs.media.teleportEffectModel = trap_R_RegisterModel( "models/misc/telep.md3" ); - cgs.media.teleportEffectShader = trap_R_RegisterShader( "teleportEffect" ); -#endif -#ifdef MISSIONPACK - cgs.media.kamikazeEffectModel = trap_R_RegisterModel( "models/weaphits/kamboom2.md3" ); - cgs.media.kamikazeShockWave = trap_R_RegisterModel( "models/weaphits/kamwave.md3" ); - cgs.media.kamikazeHeadModel = trap_R_RegisterModel( "models/powerups/kamikazi.md3" ); - cgs.media.kamikazeHeadTrail = trap_R_RegisterModel( "models/powerups/trailtest.md3" ); - cgs.media.guardPowerupModel = trap_R_RegisterModel( "models/powerups/guard_player.md3" ); - cgs.media.scoutPowerupModel = trap_R_RegisterModel( "models/powerups/scout_player.md3" ); - cgs.media.doublerPowerupModel = trap_R_RegisterModel( "models/powerups/doubler_player.md3" ); - cgs.media.ammoRegenPowerupModel = trap_R_RegisterModel( "models/powerups/ammo_player.md3" ); - cgs.media.invulnerabilityImpactModel = trap_R_RegisterModel( "models/powerups/shield/impact.md3" ); - cgs.media.invulnerabilityJuicedModel = trap_R_RegisterModel( "models/powerups/shield/juicer.md3" ); - cgs.media.medkitUsageModel = trap_R_RegisterModel( "models/powerups/regen.md3" ); - cgs.media.heartShader = trap_R_RegisterShaderNoMip( "ui/assets/statusbar/selectedhealth.tga" ); + cgs.media.teleportEffectShader = trap_R_RegisterShader( "playerTeleport" ); -#endif + //cgs.media.doorbox = trap_R_RegisterModel( "models/mapobjects/podium/hm_room.md3"); - cgs.media.invulnerabilityPowerupModel = trap_R_RegisterModel( "models/powerups/shield/shield.md3" ); - cgs.media.medalImpressive = trap_R_RegisterShaderNoMip( "medal_impressive" ); + //RPG-X TiM : the bolton assets + cgs.media.phaserHolster = trap_R_RegisterModel( "models/boltOns/phaser_holster.md3"); + cgs.media.phaserHolsterInner = trap_R_RegisterModel( "models/boltOns/phaser_holster_inner.md3"); + + cgs.media.tricorderHolster = trap_R_RegisterModel( "models/boltOns/tricorder_holster.md3"); + cgs.media.tricorderHolsterInner = trap_R_RegisterModel( "models/boltOns/tricorder_holster_inner.md3"); + + //TiM : TR116 Eyescope + cgs.media.tr116EyeScope = trap_R_RegisterModel( "models/boltOns/tr116_scope.md3"); + //TiM : Flashlight + cgs.media.simsModule = trap_R_RegisterModel( "models/boltOns/sims_beacon.md3" ); + //EVA FPS Helmet + cgs.media.evaInterior = trap_R_RegisterModel( "models/boltOns/eva_interior.md3" ); + //Medical Scanner + cgs.media.medicalScanner = trap_R_RegisterModel( "models/weapons2/tricorder/tricorder_scanner.md3" ); + cgs.media.hazardHelmet = trap_R_RegisterModel( "models/boltOns/helmet.md3" ); + + //Stasis Door + cgs.media.stasisDoorModel = trap_R_RegisterModel( "models/mapobjects/stasis/door.md3" ); + + //RPG-X START | GSIO01 | 09/05/2009 | START + switch(rpg_forceFieldSet.integer) { + case 2: + cgs.media.shieldActivateShaderBorg = trap_R_RegisterShader( "gfx/forcefielddarkgreen" ); + cgs.media.shieldActivateShaderYellow = trap_R_RegisterShader( "gfx/forcefielddarkyellow" ); + cgs.media.shieldActivateShaderRed = trap_R_RegisterShader( "gfx/forcefielddarkred" ); + cgs.media.shieldActivateShaderBlue = trap_R_RegisterShader( "gfx/forcefielddarkblue" ); + break; + case 1: + default: + cgs.media.shieldActivateShaderBorg = trap_R_RegisterShader( "gfx/ff_green" ); + cgs.media.shieldActivateShaderYellow = trap_R_RegisterShader( "gfx/ff_yellow" ); + cgs.media.shieldActivateShaderRed = trap_R_RegisterShader( "gfx/ff_red" ); + cgs.media.shieldActivateShaderBlue = trap_R_RegisterShader( "gfx/ff_blue" ); + break; + } + //RPG-X END + //cgs.media.shieldDamageShaderBlue = trap_R_RegisterShader( "gfx/misc/blue_dmgshield" ); + + + + //cgs.media.shieldActivateShaderRed = trap_R_RegisterShader( "gfx/misc/red_portashield" ); + //cgs.media.shieldDamageShaderRed = trap_R_RegisterShader( "gfx/misc/red_dmgshield" ); + + cgs.media.weaponPlaceholderShader = trap_R_RegisterShader("powerups/placeholder" ); + cgs.media.rezOutShader = trap_R_RegisterShader("powerups/rezout"); + cgs.media.electricBodyShader = trap_R_RegisterShader("gfx/misc/electric"); + + /*cgs.media.medalImpressive = trap_R_RegisterShaderNoMip( "medal_impressive" ); cgs.media.medalExcellent = trap_R_RegisterShaderNoMip( "medal_excellent" ); - cgs.media.medalGauntlet = trap_R_RegisterShaderNoMip( "medal_gauntlet" ); - cgs.media.medalDefend = trap_R_RegisterShaderNoMip( "medal_defend" ); - cgs.media.medalAssist = trap_R_RegisterShaderNoMip( "medal_assist" ); - cgs.media.medalCapture = trap_R_RegisterShaderNoMip( "medal_capture" ); + cgs.media.medalFirstStrike = trap_R_RegisterShaderNoMip( "medal_firststrike" ); + cgs.media.medalAce = trap_R_RegisterShaderNoMip( "medal_ace" ); + cgs.media.medalExpert = trap_R_RegisterShaderNoMip( "medal_expert" ); + cgs.media.medalMaster = trap_R_RegisterShaderNoMip( "medal_master" ); + cgs.media.medalChampion = trap_R_RegisterShaderNoMip( "medal_champion" );*/ + + //RPG-X: RedTechie - Scoreboard Endcaps + cgs.media.scoreboardtopleft = trap_R_RegisterShaderNoMip( "menu/common/rpgx_sb_topleft"); + cgs.media.scoreboardtopright = trap_R_RegisterShaderNoMip( "menu/common/rpgx_sb_topright"); + cgs.media.scoreboardbotleft = trap_R_RegisterShaderNoMip( "menu/common/rpgx_sb_bottomleft"); + cgs.media.scoreboardbotright = trap_R_RegisterShaderNoMip( "menu/common/rpgx_sb_bottomright"); + + //RPG-X: RedTechie - Healthbar Curves + cgs.media.healthendcap = trap_R_RegisterShaderNoMip("gfx/interface/rpgx_healthbar_endcap"); + cgs.media.healthbigcurve = trap_R_RegisterShaderNoMip("gfx/interface/rpgx_healthbar_leftcorner"); + //TiM: New Healthbar Graphics + //cgs.media.healthSineWave = trap_R_RegisterShaderNoMip( "menu/healthbar/sinewave" ); + //RPG-X: RedTechie - Cloak Sprite + //cgs.media.cloakspriteShader = trap_R_RegisterShader("sprites/cloak"); + + cgs.media.scoreboardEndcap = trap_R_RegisterShaderNoMip( "menu/common/halfround_r_24"); + cgs.media.corner_12_24 = trap_R_RegisterShaderNoMip( "menu/common/corner_ll_24_12"); + cgs.media.corner_8_16_b = trap_R_RegisterShaderNoMip( "menu/common/corner_lr_8_16_b"); + + cgs.media.weaponcap1 = trap_R_RegisterShaderNoMip("gfx/interface/cap4"); + cgs.media.weaponcap2 = trap_R_RegisterShaderNoMip("gfx/interface/cap5"); + + cgs.media.weaponbox = trap_R_RegisterShaderNoMip("gfx/interface/weapon_box"); + cgs.media.weaponbox2 = trap_R_RegisterShaderNoMip("gfx/interface/weapon_box2"); memset( cg_items, 0, sizeof( cg_items ) ); memset( cg_weapons, 0, sizeof( cg_weapons ) ); + cg.loadLCARSStage = 5; // Loading bar stage 5 + //don't need a CG_LoadingString because there will be one in the LoadingItem() + // only register the items that the server says we need - Q_strncpyz(items, CG_ConfigString(CS_ITEMS), sizeof(items)); + strcpy( items, CG_ConfigString( CS_ITEMS) ); for ( i = 1 ; i < bg_numItems ; i++ ) { if ( items[ i ] == '1' || cg_buildScript.integer ) { @@ -1018,13 +1237,39 @@ static void CG_RegisterGraphics( void ) { } // wall marks - cgs.media.bulletMarkShader = trap_R_RegisterShader( "gfx/damage/bullet_mrk" ); - cgs.media.burnMarkShader = trap_R_RegisterShader( "gfx/damage/burn_med_mrk" ); cgs.media.holeMarkShader = trap_R_RegisterShader( "gfx/damage/hole_lg_mrk" ); cgs.media.energyMarkShader = trap_R_RegisterShader( "gfx/damage/plasma_mrk" ); cgs.media.shadowMarkShader = trap_R_RegisterShader( "markShadow" ); cgs.media.wakeMarkShader = trap_R_RegisterShader( "wake" ); - cgs.media.bloodMarkShader = trap_R_RegisterShader( "bloodMark" ); + + // Radar + //TiM: OPTIMIZATION: + //It's possible to use one set of textures, and use Alpha channels to vary + //the color thru the code... wouldn't that be better? + cgs.media.radarShader = trap_R_RegisterShader( "gfx/radar/radar" ); + /*cgs.media.rd_up = trap_R_RegisterShader( "gfx/radar/rd_up" ); + cgs.media.rd_down = trap_R_RegisterShader( "gfx/radar/rd_down" ); + cgs.media.rd_level = trap_R_RegisterShader( "gfx/radar/rd_level" ); + cgs.media.rd_red_up = trap_R_RegisterShader( "gfx/radar/rd_red_up" ); + cgs.media.rd_red_down = trap_R_RegisterShader( "gfx/radar/rd_red_down" ); + cgs.media.rd_red_level = trap_R_RegisterShader( "gfx/radar/rd_red_level" ); + cgs.media.rd_blue_up = trap_R_RegisterShader( "gfx/radar/rd_blue_up" ); + cgs.media.rd_blue_down = trap_R_RegisterShader( "gfx/radar/rd_blue_down" ); + cgs.media.rd_blue_level = trap_R_RegisterShader( "gfx/radar/rd_blue_level" ); + cgs.media.rd_white_up = trap_R_RegisterShader( "gfx/radar/rd_white_up" ); + cgs.media.rd_white_down = trap_R_RegisterShader( "gfx/radar/rd_white_down" ); + cgs.media.rd_white_level = trap_R_RegisterShader( "gfx/radar/rd_white_level" ); + cgs.media.rd_teal_up = trap_R_RegisterShader( "gfx/radar/rd_teal_up" ); + cgs.media.rd_teal_down = trap_R_RegisterShader( "gfx/radar/rd_teal_down" ); + cgs.media.rd_teal_level = trap_R_RegisterShader( "gfx/radar/rd_teal_level" ); + cgs.media.rd_black_up = trap_R_RegisterShader( "gfx/radar/rd_black_up" ); + cgs.media.rd_black_down = trap_R_RegisterShader( "gfx/radar/rd_black_down" ); + cgs.media.rd_black_level = trap_R_RegisterShader( "gfx/radar/rd_black_level" ); + cgs.media.rd_injured_up = trap_R_RegisterShader( "gfx/radar/injured_up" ); + cgs.media.rd_injured_down = trap_R_RegisterShader( "gfx/radar/injured_down" );*/ + cgs.media.rd_injured_level = trap_R_RegisterShader( "gfx/radar/injured_level" ); + + cgs.media.radarMain = trap_R_RegisterShaderNoMip( "gfx/radar/radar_icon" ); // register the inline models cgs.numInlineModels = trap_CM_NumInlineModels(); @@ -1041,6 +1286,9 @@ static void CG_RegisterGraphics( void ) { } } + cg.loadLCARSStage = 6; // Loading bar stage 6 + CG_LoadingString( "Game Models" ); + // register all the server specified models for (i=1 ; i 0 ) { + cgs.locations = qtrue; + break; + } + } - trap_R_RegisterModel( "models/players/janet/lower.md3" ); - trap_R_RegisterModel( "models/players/janet/upper.md3" ); - trap_R_RegisterModel( "models/players/heads/janet/janet.md3" ); + //TiM: Do the same for all tricorder string names + /*or ( i = 1; i < MAX_TRIC_STRINGS; i++ ) { + const char *strName; -#endif - CG_ClearParticles (); -/* - for (i=1; i= MAX_MENUFILE ) { - trap_Print( va( S_COLOR_RED "menu file too large: %s is %i, max allowed is %i\n", filename, len, MAX_MENUFILE ) ); - trap_FS_FCloseFile( f ); - return NULL; - } - - trap_FS_Read( buf, len, f ); - buf[len] = 0; - trap_FS_FCloseFile( f ); - - return buf; -} - -// -// ============================== -// new hud stuff ( mission pack ) -// ============================== -// -qboolean CG_Asset_Parse(int handle) { - pc_token_t token; - const char *tempStr; - - if (!trap_PC_ReadToken(handle, &token)) - return qfalse; - if (Q_stricmp(token.string, "{") != 0) { - return qfalse; - } - - while ( 1 ) { - if (!trap_PC_ReadToken(handle, &token)) - return qfalse; - - if (Q_stricmp(token.string, "}") == 0) { - return qtrue; - } - - // font - if (Q_stricmp(token.string, "font") == 0) { - int pointSize; - if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle, &pointSize)) { - return qfalse; - } - cgDC.registerFont(tempStr, pointSize, &cgDC.Assets.textFont); - continue; - } - - // smallFont - if (Q_stricmp(token.string, "smallFont") == 0) { - int pointSize; - if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle, &pointSize)) { - return qfalse; - } - cgDC.registerFont(tempStr, pointSize, &cgDC.Assets.smallFont); - continue; - } - - // font - if (Q_stricmp(token.string, "bigfont") == 0) { - int pointSize; - if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle, &pointSize)) { - return qfalse; - } - cgDC.registerFont(tempStr, pointSize, &cgDC.Assets.bigFont); - continue; - } - - // gradientbar - if (Q_stricmp(token.string, "gradientbar") == 0) { - if (!PC_String_Parse(handle, &tempStr)) { - return qfalse; - } - cgDC.Assets.gradientBar = trap_R_RegisterShaderNoMip(tempStr); - continue; - } - - // enterMenuSound - if (Q_stricmp(token.string, "menuEnterSound") == 0) { - if (!PC_String_Parse(handle, &tempStr)) { - return qfalse; - } - cgDC.Assets.menuEnterSound = trap_S_RegisterSound( tempStr, qfalse ); - continue; - } - - // exitMenuSound - if (Q_stricmp(token.string, "menuExitSound") == 0) { - if (!PC_String_Parse(handle, &tempStr)) { - return qfalse; - } - cgDC.Assets.menuExitSound = trap_S_RegisterSound( tempStr, qfalse ); - continue; - } - - // itemFocusSound - if (Q_stricmp(token.string, "itemFocusSound") == 0) { - if (!PC_String_Parse(handle, &tempStr)) { - return qfalse; - } - cgDC.Assets.itemFocusSound = trap_S_RegisterSound( tempStr, qfalse ); - continue; - } - - // menuBuzzSound - if (Q_stricmp(token.string, "menuBuzzSound") == 0) { - if (!PC_String_Parse(handle, &tempStr)) { - return qfalse; - } - cgDC.Assets.menuBuzzSound = trap_S_RegisterSound( tempStr, qfalse ); - continue; - } - - if (Q_stricmp(token.string, "cursor") == 0) { - if (!PC_String_Parse(handle, &cgDC.Assets.cursorStr)) { - return qfalse; - } - cgDC.Assets.cursor = trap_R_RegisterShaderNoMip( cgDC.Assets.cursorStr); - continue; - } - - if (Q_stricmp(token.string, "fadeClamp") == 0) { - if (!PC_Float_Parse(handle, &cgDC.Assets.fadeClamp)) { - return qfalse; - } - continue; - } - - if (Q_stricmp(token.string, "fadeCycle") == 0) { - if (!PC_Int_Parse(handle, &cgDC.Assets.fadeCycle)) { - return qfalse; - } - continue; - } - - if (Q_stricmp(token.string, "fadeAmount") == 0) { - if (!PC_Float_Parse(handle, &cgDC.Assets.fadeAmount)) { - return qfalse; - } - continue; - } - - if (Q_stricmp(token.string, "shadowX") == 0) { - if (!PC_Float_Parse(handle, &cgDC.Assets.shadowX)) { - return qfalse; - } - continue; - } - - if (Q_stricmp(token.string, "shadowY") == 0) { - if (!PC_Float_Parse(handle, &cgDC.Assets.shadowY)) { - return qfalse; - } - continue; - } - - if (Q_stricmp(token.string, "shadowColor") == 0) { - if (!PC_Color_Parse(handle, &cgDC.Assets.shadowColor)) { - return qfalse; - } - cgDC.Assets.shadowFadeClamp = cgDC.Assets.shadowColor[3]; - continue; - } - } - return qfalse; -} - -void CG_ParseMenu(const char *menuFile) { - pc_token_t token; - int handle; - - handle = trap_PC_LoadSource(menuFile); - if (!handle) - handle = trap_PC_LoadSource("ui/testhud.menu"); - if (!handle) - return; - - while ( 1 ) { - if (!trap_PC_ReadToken( handle, &token )) { - break; - } - - //if ( Q_stricmp( token, "{" ) ) { - // Com_Printf( "Missing { in menu file\n" ); - // break; - //} - - //if ( menuCount == MAX_MENUS ) { - // Com_Printf( "Too many menus!\n" ); - // break; - //} - - if ( token.string[0] == '}' ) { - break; - } - - if (Q_stricmp(token.string, "assetGlobalDef") == 0) { - if (CG_Asset_Parse(handle)) { - continue; - } else { - break; - } - } - - - if (Q_stricmp(token.string, "menudef") == 0) { - // start a new menu - Menu_New(handle); - } - } - trap_PC_FreeSource(handle); -} - -qboolean CG_Load_Menu(char **p) { - char *token; - - token = COM_ParseExt(p, qtrue); - - if (token[0] != '{') { - return qfalse; - } - - while ( 1 ) { - - token = COM_ParseExt(p, qtrue); - - if (Q_stricmp(token, "}") == 0) { - return qtrue; - } - - if ( !token || token[0] == 0 ) { - return qfalse; - } - - CG_ParseMenu(token); - } - return qfalse; -} - - - -void CG_LoadMenus(const char *menuFile) { - char *token; - char *p; - int len, start; - fileHandle_t f; - static char buf[MAX_MENUDEFFILE]; - - start = trap_Milliseconds(); - - len = trap_FS_FOpenFile( menuFile, &f, FS_READ ); - if ( !f ) { - Com_Printf( S_COLOR_YELLOW "menu file not found: %s, using default\n", menuFile ); - len = trap_FS_FOpenFile( "ui/hud.txt", &f, FS_READ ); - if (!f) { - trap_Error( va( S_COLOR_RED "default menu file not found: ui/hud.txt, unable to continue!\n") ); - } - } - - if ( len >= MAX_MENUDEFFILE ) { - trap_Error( va( S_COLOR_RED "menu file too large: %s is %i, max allowed is %i\n", menuFile, len, MAX_MENUDEFFILE ) ); - trap_FS_FCloseFile( f ); - return; - } - - trap_FS_Read( buf, len, f ); - buf[len] = 0; - trap_FS_FCloseFile( f ); - - COM_Compress(buf); - - Menu_Reset(); - - p = buf; - - while ( 1 ) { - token = COM_ParseExt( &p, qtrue ); - if( !token || token[0] == 0 || token[0] == '}') { - break; - } - - //if ( Q_stricmp( token, "{" ) ) { - // Com_Printf( "Missing { in menu file\n" ); - // break; - //} - - //if ( menuCount == MAX_MENUS ) { - // Com_Printf( "Too many menus!\n" ); - // break; - //} - - if ( Q_stricmp( token, "}" ) == 0 ) { - break; - } - - if (Q_stricmp(token, "loadmenu") == 0) { - if (CG_Load_Menu(&p)) { - continue; - } else { - break; - } - } - } - - Com_Printf("UI menu load time = %d milli seconds\n", trap_Milliseconds() - start); - -} - - - -static qboolean CG_OwnerDrawHandleKey(int ownerDraw, int flags, float *special, int key) { - return qfalse; -} - - -static int CG_FeederCount(float feederID) { - int i, count; - count = 0; - if (feederID == FEEDER_REDTEAM_LIST) { - for (i = 0; i < cg.numScores; i++) { - if (cg.scores[i].team == TEAM_RED) { - count++; - } - } - } else if (feederID == FEEDER_BLUETEAM_LIST) { - for (i = 0; i < cg.numScores; i++) { - if (cg.scores[i].team == TEAM_BLUE) { - count++; - } - } - } else if (feederID == FEEDER_SCOREBOARD) { - return cg.numScores; - } - return count; -} - - -void CG_SetScoreSelection(void *p) { - menuDef_t *menu = (menuDef_t*)p; - playerState_t *ps = &cg.snap->ps; - int i, red, blue; - red = blue = 0; - for (i = 0; i < cg.numScores; i++) { - if (cg.scores[i].team == TEAM_RED) { - red++; - } else if (cg.scores[i].team == TEAM_BLUE) { - blue++; - } - if (ps->clientNum == cg.scores[i].client) { - cg.selectedScore = i; - } - } - - if (menu == NULL) { - // just interested in setting the selected score - return; - } - - if ( cgs.gametype >= GT_TEAM ) { - int feeder = FEEDER_REDTEAM_LIST; - i = red; - if (cg.scores[cg.selectedScore].team == TEAM_BLUE) { - feeder = FEEDER_BLUETEAM_LIST; - i = blue; - } - Menu_SetFeederSelection(menu, feeder, i, NULL); - } else { - Menu_SetFeederSelection(menu, FEEDER_SCOREBOARD, cg.selectedScore, NULL); + if ( cgs.pModSpecialties ) + {//tripwires use more ammo + altAmmoUsage[WP_8] = 3; } } -// FIXME: might need to cache this info -static clientInfo_t * CG_InfoFromScoreIndex(int index, int team, int *scoreIndex) { - int i, count; - if ( cgs.gametype >= GT_TEAM ) { - count = 0; - for (i = 0; i < cg.numScores; i++) { - if (cg.scores[i].team == team) { - if (count == index) { - *scoreIndex = i; - return &cgs.clientinfo[cg.scores[i].client]; - } - count++; - } - } - } - *scoreIndex = index; - return &cgs.clientinfo[ cg.scores[index].client ]; -} - -static const char *CG_FeederItemText(float feederID, int index, int column, qhandle_t *handle) { - gitem_t *item; - int scoreIndex = 0; - clientInfo_t *info = NULL; - int team = -1; - score_t *sp = NULL; - - *handle = -1; - - if (feederID == FEEDER_REDTEAM_LIST) { - team = TEAM_RED; - } else if (feederID == FEEDER_BLUETEAM_LIST) { - team = TEAM_BLUE; - } - - info = CG_InfoFromScoreIndex(index, team, &scoreIndex); - sp = &cg.scores[scoreIndex]; - - if (info && info->infoValid) { - switch (column) { - case 0: - if ( info->powerups & ( 1 << PW_NEUTRALFLAG ) ) { - item = BG_FindItemForPowerup( PW_NEUTRALFLAG ); - *handle = cg_items[ ITEM_INDEX(item) ].icon; - } else if ( info->powerups & ( 1 << PW_REDFLAG ) ) { - item = BG_FindItemForPowerup( PW_REDFLAG ); - *handle = cg_items[ ITEM_INDEX(item) ].icon; - } else if ( info->powerups & ( 1 << PW_BLUEFLAG ) ) { - item = BG_FindItemForPowerup( PW_BLUEFLAG ); - *handle = cg_items[ ITEM_INDEX(item) ].icon; - } else { - if ( info->botSkill > 0 && info->botSkill <= 5 ) { - *handle = cgs.media.botSkillShaders[ info->botSkill - 1 ]; - } else if ( info->handicap < 100 ) { - return va("%i", info->handicap ); - } - } - break; - case 1: - if (team == -1) { - return ""; - } else { - *handle = CG_StatusHandle(info->teamTask); - } - break; - case 2: - if ( cg.snap->ps.stats[ STAT_CLIENTS_READY ] & ( 1 << sp->client ) ) { - return "Ready"; - } - if (team == -1) { - if (cgs.gametype == GT_TOURNAMENT) { - return va("%i/%i", info->wins, info->losses); - } else if (info->infoValid && info->team == TEAM_SPECTATOR ) { - return "Spectator"; - } else { - return ""; - } - } else { - if (info->teamLeader) { - return "Leader"; - } - } - break; - case 3: - return info->name; - break; - case 4: - return va("%i", info->score); - break; - case 5: - return va("%4i", sp->time); - break; - case 6: - if ( sp->ping == -1 ) { - return "connecting"; - } - return va("%4i", sp->ping); - break; - } - } - - return ""; -} - -static qhandle_t CG_FeederItemImage(float feederID, int index) { - return 0; -} - -static void CG_FeederSelection(float feederID, int index) { - if ( cgs.gametype >= GT_TEAM ) { - int i, count; - int team = (feederID == FEEDER_REDTEAM_LIST) ? TEAM_RED : TEAM_BLUE; - count = 0; - for (i = 0; i < cg.numScores; i++) { - if (cg.scores[i].team == team) { - if (index == count) { - cg.selectedScore = i; - } - count++; - } - } - } else { - cg.selectedScore = index; - } -} -#endif - -#ifdef MISSIONPACK -static float CG_Cvar_Get(const char *cvar) { - char buff[128]; - memset(buff, 0, sizeof(buff)); - trap_Cvar_VariableStringBuffer(cvar, buff, sizeof(buff)); - return atof(buff); -} -#endif - -#ifdef MISSIONPACK -void CG_Text_PaintWithCursor(float x, float y, float scale, vec4_t color, const char *text, int cursorPos, char cursor, int limit, int style) { - CG_Text_Paint(x, y, scale, color, text, 0, limit, style); -} - -static int CG_OwnerDrawWidth(int ownerDraw, float scale) { - switch (ownerDraw) { - case CG_GAME_TYPE: - return CG_Text_Width(CG_GameTypeString(), scale, 0); - case CG_GAME_STATUS: - return CG_Text_Width(CG_GetGameStatusText(), scale, 0); - break; - case CG_KILLER: - return CG_Text_Width(CG_GetKillerText(), scale, 0); - break; - case CG_RED_NAME: - return CG_Text_Width(cg_redTeamName.string, scale, 0); - break; - case CG_BLUE_NAME: - return CG_Text_Width(cg_blueTeamName.string, scale, 0); - break; - - - } - return 0; -} - -static int CG_PlayCinematic(const char *name, float x, float y, float w, float h) { - return trap_CIN_PlayCinematic(name, x, y, w, h, CIN_loop); -} - -static void CG_StopCinematic(int handle) { - trap_CIN_StopCinematic(handle); -} - -static void CG_DrawCinematic(int handle, float x, float y, float w, float h) { - trap_CIN_SetExtents(handle, x, y, w, h); - trap_CIN_DrawCinematic(handle); -} - -static void CG_RunCinematicFrame(int handle) { - trap_CIN_RunCinematic(handle); -} - -/* -================= -CG_LoadHudMenu(); - -================= -*/ -void CG_LoadHudMenu( void ) { - char buff[1024]; - const char *hudSet; - - cgDC.registerShaderNoMip = &trap_R_RegisterShaderNoMip; - cgDC.setColor = &trap_R_SetColor; - cgDC.drawHandlePic = &CG_DrawPic; - cgDC.drawStretchPic = &trap_R_DrawStretchPic; - cgDC.drawText = &CG_Text_Paint; - cgDC.textWidth = &CG_Text_Width; - cgDC.textHeight = &CG_Text_Height; - cgDC.registerModel = &trap_R_RegisterModel; - cgDC.modelBounds = &trap_R_ModelBounds; - cgDC.fillRect = &CG_FillRect; - cgDC.drawRect = &CG_DrawRect; - cgDC.drawSides = &CG_DrawSides; - cgDC.drawTopBottom = &CG_DrawTopBottom; - cgDC.clearScene = &trap_R_ClearScene; - cgDC.addRefEntityToScene = &trap_R_AddRefEntityToScene; - cgDC.renderScene = &trap_R_RenderScene; - cgDC.registerFont = &trap_R_RegisterFont; - cgDC.ownerDrawItem = &CG_OwnerDraw; - cgDC.getValue = &CG_GetValue; - cgDC.ownerDrawVisible = &CG_OwnerDrawVisible; - cgDC.runScript = &CG_RunMenuScript; - cgDC.getTeamColor = &CG_GetTeamColor; - cgDC.setCVar = trap_Cvar_Set; - cgDC.getCVarString = trap_Cvar_VariableStringBuffer; - cgDC.getCVarValue = CG_Cvar_Get; - cgDC.drawTextWithCursor = &CG_Text_PaintWithCursor; - //cgDC.setOverstrikeMode = &trap_Key_SetOverstrikeMode; - //cgDC.getOverstrikeMode = &trap_Key_GetOverstrikeMode; - cgDC.startLocalSound = &trap_S_StartLocalSound; - cgDC.ownerDrawHandleKey = &CG_OwnerDrawHandleKey; - cgDC.feederCount = &CG_FeederCount; - cgDC.feederItemImage = &CG_FeederItemImage; - cgDC.feederItemText = &CG_FeederItemText; - cgDC.feederSelection = &CG_FeederSelection; - //cgDC.setBinding = &trap_Key_SetBinding; - //cgDC.getBindingBuf = &trap_Key_GetBindingBuf; - //cgDC.keynumToStringBuf = &trap_Key_KeynumToStringBuf; - //cgDC.executeText = &trap_Cmd_ExecuteText; - cgDC.Error = &Com_Error; - cgDC.Print = &Com_Printf; - cgDC.ownerDrawWidth = &CG_OwnerDrawWidth; - //cgDC.Pause = &CG_Pause; - cgDC.registerSound = &trap_S_RegisterSound; - cgDC.startBackgroundTrack = &trap_S_StartBackgroundTrack; - cgDC.stopBackgroundTrack = &trap_S_StopBackgroundTrack; - cgDC.playCinematic = &CG_PlayCinematic; - cgDC.stopCinematic = &CG_StopCinematic; - cgDC.drawCinematic = &CG_DrawCinematic; - cgDC.runCinematicFrame = &CG_RunCinematicFrame; - - Init_Display(&cgDC); - - Menu_Reset(); - - trap_Cvar_VariableStringBuffer("cg_hudFiles", buff, sizeof(buff)); - hudSet = buff; - if (hudSet[0] == '\0') { - hudSet = "ui/hud.txt"; - } - - CG_LoadMenus(hudSet); -} - -void CG_AssetCache( void ) { - //if (Assets.textFont == NULL) { - // trap_R_RegisterFont("fonts/arial.ttf", 72, &Assets.textFont); - //} - //Assets.background = trap_R_RegisterShaderNoMip( ASSET_BACKGROUND ); - //Com_Printf("Menu Size: %i bytes\n", sizeof(Menus)); - cgDC.Assets.gradientBar = trap_R_RegisterShaderNoMip( ASSET_GRADIENTBAR ); - cgDC.Assets.fxBasePic = trap_R_RegisterShaderNoMip( ART_FX_BASE ); - cgDC.Assets.fxPic[0] = trap_R_RegisterShaderNoMip( ART_FX_RED ); - cgDC.Assets.fxPic[1] = trap_R_RegisterShaderNoMip( ART_FX_YELLOW ); - cgDC.Assets.fxPic[2] = trap_R_RegisterShaderNoMip( ART_FX_GREEN ); - cgDC.Assets.fxPic[3] = trap_R_RegisterShaderNoMip( ART_FX_TEAL ); - cgDC.Assets.fxPic[4] = trap_R_RegisterShaderNoMip( ART_FX_BLUE ); - cgDC.Assets.fxPic[5] = trap_R_RegisterShaderNoMip( ART_FX_CYAN ); - cgDC.Assets.fxPic[6] = trap_R_RegisterShaderNoMip( ART_FX_WHITE ); - cgDC.Assets.scrollBar = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR ); - cgDC.Assets.scrollBarArrowDown = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWDOWN ); - cgDC.Assets.scrollBarArrowUp = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWUP ); - cgDC.Assets.scrollBarArrowLeft = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWLEFT ); - cgDC.Assets.scrollBarArrowRight = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWRIGHT ); - cgDC.Assets.scrollBarThumb = trap_R_RegisterShaderNoMip( ASSET_SCROLL_THUMB ); - cgDC.Assets.sliderBar = trap_R_RegisterShaderNoMip( ASSET_SLIDER_BAR ); - cgDC.Assets.sliderThumb = trap_R_RegisterShaderNoMip( ASSET_SLIDER_THUMB ); -} -#endif /* ================= CG_Init @@ -1843,8 +1660,9 @@ Called after every level change or subsystem restart Will perform callbacks to make the loading info screen update. ================= */ -void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum ) { +void CG_Init( int serverMessageNum, int serverCommandSequence ) { const char *s; + int i; // clear everything memset( &cgs, 0, sizeof( cgs ) ); @@ -1853,26 +1671,61 @@ void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum ) { memset( cg_weapons, 0, sizeof(cg_weapons) ); memset( cg_items, 0, sizeof(cg_items) ); - cg.clientNum = clientNum; + //Flush Sound Effects + memset( &cg_animsSndList, 0, sizeof( cg_animsSndList ) ); + + init_tonextint(qfalse); cgs.processedSnapshotNum = serverMessageNum; cgs.serverCommandSequence = serverCommandSequence; + CG_LoadIngameText(); + + CG_LoadFonts(); + + // Loading graphics + cgs.media.loading1 = trap_R_RegisterShaderNoMip( "menu/loading/smpiece1.tga" ); + cgs.media.loading2 = trap_R_RegisterShaderNoMip( "menu/loading/smpiece2.tga" ); + cgs.media.loading3 = trap_R_RegisterShaderNoMip( "menu/loading/smpiece3.tga" ); + cgs.media.loading4 = trap_R_RegisterShaderNoMip( "menu/loading/smpiece4.tga" ); + cgs.media.loading5 = trap_R_RegisterShaderNoMip( "menu/loading/smpiece5.tga" ); + cgs.media.loading6 = trap_R_RegisterShaderNoMip( "menu/loading/smpiece6.tga" ); + cgs.media.loading7 = trap_R_RegisterShaderNoMip( "menu/loading/smpiece7.tga" ); + cgs.media.loading8 = trap_R_RegisterShaderNoMip( "menu/loading/smpiece8.tga" ); + cgs.media.loading9 = trap_R_RegisterShaderNoMip( "menu/loading/smpiece9.tga" ); + cgs.media.loadingcircle = trap_R_RegisterShaderNoMip( "menu/loading/arrowpiece.tga" ); + cgs.media.loadingquarter= trap_R_RegisterShaderNoMip( "menu/loading/quarter.tga" ); + cgs.media.loadingcorner = trap_R_RegisterShaderNoMip( "menu/common/corner_lr_8_16.tga" ); + cgs.media.loadingtrim = trap_R_RegisterShaderNoMip( "menu/loading/trimupper.tga" ); + cgs.media.circle = trap_R_RegisterShaderNoMip( "menu/common/circle.tga" ); + cgs.media.circle2 = trap_R_RegisterShaderNoMip( "menu/objectives/circle_out.tga" ); + cgs.media.corner_12_18 = trap_R_RegisterShaderNoMip( "menu/common/corner_ll_12_18.tga" ); + cgs.media.halfroundr_22 = trap_R_RegisterShaderNoMip( "menu/common/halfroundr_22.tga" ); + + cgs.media.corner_ul_20_30= trap_R_RegisterShaderNoMip( "menu/common/corner_ul_20_30.tga" ); + cgs.media.corner_ll_8_30= trap_R_RegisterShaderNoMip( "menu/common/corner_ll_8_30.tga" ); + + cg.loadLCARSStage = 0; + cg.loadLCARScnt = 0; // load a few needed things before we do any screen updates - cgs.media.charsetShader = trap_R_RegisterShader( "gfx/2d/bigchars" ); + cgs.media.charsetShader = trap_R_RegisterShaderNoMip( "gfx/2d/charsgrid_med" ); cgs.media.whiteShader = trap_R_RegisterShader( "white" ); - cgs.media.charsetProp = trap_R_RegisterShaderNoMip( "menu/art/font1_prop.tga" ); - cgs.media.charsetPropGlow = trap_R_RegisterShaderNoMip( "menu/art/font1_prop_glo.tga" ); - cgs.media.charsetPropB = trap_R_RegisterShaderNoMip( "menu/art/font2_prop.tga" ); + cgs.media.white2Shader = trap_R_RegisterShader( "white2" ); + cgs.media.charsetPropTiny = trap_R_RegisterShaderNoMip("gfx/2d/chars_tiny"); + cgs.media.charsetProp = trap_R_RegisterShaderNoMip("gfx/2d/chars_medium"); + cgs.media.charsetPropBig = trap_R_RegisterShaderNoMip("gfx/2d/chars_big"); +// cgs.media.charsetPropGlow = trap_R_RegisterShaderNoMip( "menu/art/font1_prop_glo.tga" ); + cgs.media.charsetPropB = trap_R_RegisterShaderNoMip( "gfx/2d/chars_medium.tga" ); CG_RegisterCvars(); CG_InitConsoleCommands(); - cg.weaponSelect = WP_MACHINEGUN; + BG_LoadItemNames(); + + cg.weaponSelect = WP_1; cgs.redflag = cgs.blueflag = -1; // For compatibily, default to unset for - cgs.flagStatus = -1; // old servers // get the rendering configuration from the client system @@ -1880,6 +1733,18 @@ void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum ) { cgs.screenXScale = cgs.glconfig.vidWidth / 640.0; cgs.screenYScale = cgs.glconfig.vidHeight / 480.0; + //TiM - handle wide screens + if ( cgs.glconfig.vidWidth * 480 > cgs.glconfig.vidHeight * 640 ) + { + cgs.widescreen.ratio = 640.0f*cgs.screenYScale * (1.0f/cgs.glconfig.vidWidth); + cgs.widescreen.bias = 0.5 * ( cgs.glconfig.vidWidth - ( cgs.glconfig.vidHeight * (640.0/480.0) ) ); + } + else + { + cgs.widescreen.ratio = 0; + cgs.widescreen.bias = 0; + } + // get the gamestate from the client system trap_GetGameState( &cgs.gameState ); @@ -1899,29 +1764,16 @@ void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum ) { trap_CM_LoadMap( cgs.mapname ); -#ifdef MISSIONPACK - String_Init(); -#endif - cg.loading = qtrue; // force players to load instead of defer - CG_LoadingString( "sounds" ); + CG_LoadObjectivesForMap(); CG_RegisterSounds(); - CG_LoadingString( "graphics" ); - CG_RegisterGraphics(); - CG_LoadingString( "clients" ); - CG_RegisterClients(); // if low on memory, some clients will be deferred -#ifdef MISSIONPACK - CG_AssetCache(); - CG_LoadHudMenu(); // load new hud stuff -#endif - cg.loading = qfalse; // future players will be deferred CG_InitLocalEntities(); @@ -1938,13 +1790,47 @@ void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum ) { CG_LoadingString( "" ); -#ifdef MISSIONPACK - CG_InitTeamChat(); -#endif + //RPG-X | GSIO01 | 08/05/09: + //Make sure all weapons are registered to prevent + //missing models when someone get killed and weapons are dropped + for(i = 0; i < WP_NUM_WEAPONS; i++) { + CG_RegisterWeapon(i); + } + // To get the interface timing started + cg.interfaceStartupTime = 0; + cg.interfaceStartupDone = 0; + + CG_InitModRules(); + + if ( !CG_LoadCrosshairs() ) + { + CG_Error( "Couldn't load crosshairs script" ); + } + + if ( !CG_LoadRanks() ) + { + CG_Error( "Couldn't load rankset script: %s", cgs.rankSet ); + } + + if ( !CG_LoadClasses() ) + { + CG_Error( "Couldn't load classset script: %s", cgs.classSet ); + } + + //where possible, load in the usable strings locally + if ( cgs.scannablePanels ) + CG_LoadUsablesStrings(); + + //TiM Finally, init class data received from Server + //TiM2 - Separated this out so class data has to be locally accessed now + //CG_ParseClassData(); + + /* shader remapping */ CG_ShaderStateChanged(); - trap_S_ClearLoopingSounds( qtrue ); + if(grp_berp.integer) + CG_Printf(S_COLOR_YELLOW "GSIO01 and Ubergames greet Brave Explorers.\n"); } /* @@ -1957,28 +1843,509 @@ Called before every level change or subsystem restart void CG_Shutdown( void ) { // some mods may need to do cleanup work here, // like closing files or archiving session data + //trap_Cvar_Set ("rpg_playIntro", "0"); } +#define MAXINGAMETEXT 5000 +char ingameText[MAXINGAMETEXT]; + /* -================== -CG_EventHandling -================== - type 0 - no event handling - 1 - team menu - 2 - hud editor - +================= +CG_ParseIngameText +================= */ -#ifndef MISSIONPACK -void CG_EventHandling(int type) { +void CG_ParseIngameText(void) +{ + char *token; + char *buffer; + int i; + int len; + + COM_BeginParseSession(); + + buffer = ingameText; + i = 1; // Zero is null string + while ( buffer ) + { + token = COM_ParseExt( &buffer, qtrue ); + + len = strlen(token); + if (len) + { + ingame_text[i] = (buffer - (len + 1)); // The +1 is to get rid of the " at the beginning of the sting. + *(buffer - 1) = '\0'; // Place an string end where is belongs. + + ++i; + } + + if (i> IGT_MAX) + { + Com_Printf( S_COLOR_RED "CG_ParseIngameText : too many values!\n"); + return; + } + } + + if (i != IGT_MAX) + { + Com_Printf( S_COLOR_RED "CG_ParseIngameText : not enough lines! Read %d of %d!\n",i,IGT_MAX); + for(;i MAXINGAMETEXT) + { + Com_Printf( S_COLOR_RED "CG_LoadIngameText : mp_ingametext.dat file bigger than %d!\n",MAXINGAMETEXT); + return; + } + + // initialise the data area + memset(ingameText, 0, sizeof(ingameText)); + + trap_FS_Read( ingameText, len, f ); + + trap_FS_FCloseFile( f ); + + + CG_ParseIngameText(); + +} + +/* +================= +CG_LoadObjectivesForMap +================= +*/ +void CG_LoadObjectivesForMap(void) +{ + int len, objnum = 0; + char *token; + char *buf; + fileHandle_t f; + char fileName[MAX_QPATH]; + char fullFileName[MAX_QPATH]; + char objtext[MAX_OBJ_TEXT_LENGTH]; + + COM_StripExtension( cgs.mapname, fileName ); + CG_LanguageFilename( fileName, "efo", fullFileName); + + len = trap_FS_FOpenFile( fullFileName, &f, FS_READ ); + + if ( len > MAX_OBJ_TEXT_LENGTH ) + { + Com_Printf( S_COLOR_RED "CG_LoadObjectivesForMap : %s file bigger than %d!\n", fileName, MAX_OBJ_TEXT_LENGTH ); + return; + } + + trap_FS_Read( objtext, len, f ); + + trap_FS_FCloseFile( f ); + + buf = objtext; + //Now parse out each objective + while ( 1 ) + { + token = COM_ParseExt( &buf, qtrue ); + if ( !token[0] ) { + break; + } + + // Normal objective text + if ( !Q_strncmp( token, "obj", 3 ) ) + { + objnum = atoi( &token[3] ); + + if ( objnum < 1 || objnum == MAX_OBJECTIVES ) { + Com_Printf( "Invalid objective number (%d), valid range is 1 to %d\n", objnum, MAX_OBJECTIVES ); + break; + } + + //Now read the objective text into the current objective + token = COM_ParseExt( &buf, qfalse ); + Q_strncpyz( cgs.objectives[objnum-1].text, token, sizeof(cgs.objectives[objnum-1].text) ); + } + + else if ( !Q_strncmp( token, "abridged_obj", 12 ) ) + { + objnum = atoi( &token[12] ); + + if ( objnum < 1 || objnum == MAX_OBJECTIVES ) + { + Com_Printf( "Invalid objective number (%d), valid range is 1 to %d\n", objnum, MAX_OBJECTIVES ); + break; + } + + //Now read the objective text into the current objective + token = COM_ParseExt( &buf, qfalse ); + Q_strncpyz( cgs.objectives[objnum-1].abridgedText, token, sizeof(cgs.objectives[objnum-1].abridgedText) ); + } + } } +qboolean CG_LoadClasses( void ) +{ + fileHandle_t f; + int file_len; + char buffer[32000]; + char *token, *textPtr; + char filePath[MAX_QPATH]; + int numClasses=0; + int i; -void CG_KeyEvent(int key, qboolean down) { + Com_sprintf( filePath, sizeof( filePath ), "ext_data/classes/%s.classes", cgs.classSet ); + + memset( &cgs.classData, 0, sizeof( cg_classData_t ) ); + + file_len = trap_FS_FOpenFile( filePath, &f, FS_READ ); + + if ( !file_len ) + { + CG_Printf( S_COLOR_RED "Couldn't find class file: %s\n", filePath ); + return qfalse; + } + + if ( file_len > sizeof( buffer ) ) + { + CG_Printf( S_COLOR_RED "File %s was way too big to be loaded.\n", filePath ); + return qfalse; + } + + trap_FS_Read( buffer, file_len, f ); + trap_FS_FCloseFile( f ); + + buffer[file_len] = '\0'; + + COM_BeginParseSession(); + + textPtr = buffer; + + token = COM_Parse( &textPtr ); + + if ( !token[0] ) { + CG_Printf( S_COLOR_RED "ERROR: No data was found when going to parse the file!\n" ); + return qfalse; + } + + if ( Q_stricmpn( token, "{", 1 ) ) { + CG_Printf( S_COLOR_RED "ERROR: File did not start with a '{' symbol!\n" ); + return qfalse; + } + + while( 1 ) + { + if ( numClasses >= MAX_CLASSES ) + break; + + + if ( !Q_strncmp( token, "{", 1 ) ) + { + while ( 1 ) + { + token = COM_Parse( &textPtr ); + + if (!token[0]) { + break; + } + + if ( !Q_stricmpn( token, "formalName", 10 ) ) + { + if ( COM_ParseString( &textPtr, &token ) ) + { + CG_Printf( S_COLOR_RED "ERROR: Invalid class formal name in class index: %i.\n", numClasses ); + continue; + } + + Q_strncpyz( cgs.classData[numClasses].formalName, token, sizeof( cgs.classData[numClasses].formalName ) ); + continue; + } + + if ( !Q_stricmpn( token, "radarColor", 5 ) ) + { + vec3_t temp; + + if ( COM_ParseVec3( &textPtr, temp ) ) + { + CG_Printf( S_COLOR_RED "ERROR: Invalid color values in class index: %i.\n", numClasses ); + continue; + } + + for ( i = 0; i < 3; i++ ) + { + cgs.classData[numClasses].radarColor[i] = (int)Com_Clamp( 0, 255, (int)temp[i] ); + //G_Printf( S_COLOR_RED "g_classData[numClasses].color[%i] = %i\n", i, g_classData[numClasses].color[i] ); + } + + continue; + } + + if ( !Q_stricmpn( token, "iconColor", 9 ) ) + { + if ( COM_ParseString( &textPtr, &token ) ) + { + CG_Printf( S_COLOR_RED "ERROR: Invalid class icon color in class index: %i.\n", numClasses ); + continue; + } + + //Eh... there are enum values for these, + //but they're currently out of scope ;P + if ( !Q_stricmp( token, "red" ) ) + { + cgs.classData[numClasses].iconColor = 1; //CLR_RED + } + else if ( !Q_stricmp( token, "gold" ) ) + { + cgs.classData[numClasses].iconColor = 2; //CLR_GOLD + } + else if ( !Q_stricmp( token, "teal" ) ) + { + cgs.classData[numClasses].iconColor = 3; //CLR_TEAL + } + else if ( !Q_stricmp( token, "green" ) ) + { + cgs.classData[numClasses].iconColor = 4; //CLR_GREEN + } + else + { + cgs.classData[numClasses].iconColor = 0; //0 + } + + continue; + } + + if ( !Q_stricmpn( token, "medical", 7 ) ) + { + if ( COM_ParseInt( &textPtr, (int *)&cgs.classData[numClasses].isMedic ) ) + { + CG_Printf( S_COLOR_RED "ERROR: Class medic check for class %i was invalid.\n", numClasses ); + continue; + } + + continue; + } + + if( !Q_stricmpn( token, "isBorg", 6 ) ) + { + if( COM_ParseInt( &textPtr, (int *)&cgs.classData[numClasses].isBorg ) ) + { + CG_Printf( S_COLOR_RED "ERROR: Class borg check for class %i was invalid.\n", numClasses ); + continue; + } + continue; + } + + if ( !Q_stricmpn( token, "hasRanks", 8 ) ) + { + if ( COM_ParseInt( &textPtr, (int *)&cgs.classData[numClasses].showRanks ) ) + { + CG_Printf( S_COLOR_RED "ERROR: Class Ranks check for class %i was invalid.\n", numClasses ); + continue; + } + + continue; + } + + //I'm a n00b lol. I made a class called 'medical' and a parameter called 'medical'. + //I have to double check both parms or else it confuses the parser + //better check all of them. I'm still getting errors + if ( !Q_stricmpn( token, "consoleName", 10 ) + || !Q_stricmpn( token, "modelSkin", 9 ) + || !Q_stricmpn( token, "message", 7 ) + || !Q_stricmpn( token, "admin", 5 ) + || !Q_stricmpn( token, "marine", 6 ) + || !Q_stricmpn( token, "noShow", 6 ) + ) + { + SkipRestOfLine(&textPtr); + continue; + } + + //this one is a pain since it can potentially have multiple lines + if ( !Q_stricmpn( token, "weapons", 7 ) ) + { + SkipBracedSection( &textPtr ); + continue; + } + + if ( !Q_stricmpn( token, "}", 1 ) ) + { + numClasses++; + break; + } + } + } + + token = COM_Parse( &textPtr ); + + if (!token[0]) + { + break; + } + } + + if ( numClasses > 0 ) + return qtrue; + else + { + CG_Printf( S_COLOR_RED "ERROR: No classes were found in the class file!\n" ); + return qfalse; + } } -void CG_MouseEvent(int x, int y) { -} -#endif +qboolean CG_LoadUsablesStrings( void ) +{ + char fileRoute[MAX_QPATH]; + char mapRoute[MAX_QPATH]; + char buffer[20000]; + int file_len; + char *textPtr, *token; + fileHandle_t f; + int i; + int strLen; + + //setup the file route + Com_sprintf( mapRoute, sizeof( mapRoute ), "%s", cgs.mapname ); + + strLen = strlen( mapRoute ); + + //*sigh* remove the bsp bit + if ( strLen > 4 && !Q_stricmp( mapRoute + strLen-4, ".bsp" ) ) + mapRoute[strLen-4] = '\0'; + + //check for language + CG_LanguageFilename( mapRoute, "usables", fileRoute ); + + file_len = trap_FS_FOpenFile( fileRoute, &f, FS_READ ); + + //It's assumed most maps won't have this feature, so just exit 'gracefully' + if ( file_len<=1 ) + { + //CG_Printf( S_COLOR_YELLOW "WARNING: No file named %s was found. If the server \n", fileRoute ); + trap_FS_FCloseFile( f ); + return qfalse; + } + + //fill the buffer with the file data + memset( &buffer, 0, sizeof( buffer ) ); + trap_FS_Read( buffer, file_len, f ); + buffer[file_len] = '0'; + + trap_FS_FCloseFile( f ); + + if ( !buffer[0] ) + { + CG_Printf( S_COLOR_RED "ERROR: Attempted to load %s, but no data was inside!\n", fileRoute ); + return qfalse; + } + + COM_BeginParseSession(); + textPtr = buffer; + + i = 0; //used for the main arrays indices + + while( 1 ) + { + token = COM_Parse( &textPtr ); + if ( !token[0] ) + break; + + if ( !Q_strncmp( token, "UsableDescriptions", 18 ) ) + { + token = COM_Parse( &textPtr ); + if ( Q_strncmp( token, "{", 1 ) != 0 ) + { + CG_Printf( S_COLOR_RED "ERROR: UsableDescriptions had no opening brace ( { )!\n", fileRoute ); + continue; + } + + token = COM_Parse( &textPtr ); + + //expected format is 'id' 'string' + while ( Q_strncmp( token, "}", 1 ) ) + { + if ( !token[0] ) + break; + + if ( !Q_strncmp( token, "UsableEntities", 14 ) ) + { + SkipBracedSection( &textPtr ); + continue; + } + else + { + //parse past the ID num + token = COM_ParseExt( &textPtr, qfalse ); + + //copy the line of text + if( token[0] ) + { + Q_strncpyz( cgs.scannableStrings[i], token, sizeof( cgs.scannableStrings[i] ) ); + i++; + } + + token = COM_Parse( &textPtr ); + } + } + } + } + + return qtrue; +} diff --git a/code/cgame/cg_main.c.orig b/code/cgame/cg_main.c.orig new file mode 100644 index 0000000..d37f2b5 --- /dev/null +++ b/code/cgame/cg_main.c.orig @@ -0,0 +1,1792 @@ +// Copyright (C) 1999-2000 Id Software, Inc. +// +// cg_main.c -- initialization and primary entry point for cgame + +//TiM : 22/12/2005 - Commented out any assets that we no longer use. +//TiM : 24/12/2005 - Added a ranks parsing function. + +#include "cg_local.h" +#include "cg_text.h" + +void CG_Init( int serverMessageNum, int serverCommandSequence ); +void CG_Shutdown( void ); +void CG_LoadIngameText(void); +void CG_LoadObjectivesForMap(void); +void BG_LoadItemNames(void); + +//TiM - Placed the func @ the bottom of the page for easier access +//extern static qboolean CG_LoadRanks( void ); + +extern void FX_InitSinTable(void); + +//extern lensReflec_s lensReflec[10]; + +/* +================ +vmMain + +This is the only way control passes into the module. +This must be the very first function compiled into the .q3vm file +================ +*/ +int vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6 ) { + switch ( command ) { + case CG_INIT: + CG_Init( arg0, arg1 ); + return 0; + case CG_SHUTDOWN: + CG_Shutdown(); + return 0; + case CG_CONSOLE_COMMAND: + return CG_ConsoleCommand(); + case CG_DRAW_ACTIVE_FRAME: + CG_DrawActiveFrame( arg0, arg1, arg2 ); + return 0; + case CG_CROSSHAIR_PLAYER: + return CG_CrosshairPlayer(); + case CG_LAST_ATTACKER: + return CG_LastAttacker(); + default: + CG_Error( "vmMain: unknown command %i", command ); + break; + } + return -1; +} + + +cg_t cg; +cgs_t cgs; +centity_t cg_entities[MAX_GENTITIES]; +weaponInfo_t cg_weapons[MAX_WEAPONS]; +itemInfo_t cg_items[MAX_ITEMS]; + +vmCvar_t cg_centertime; +vmCvar_t cg_runpitch; +vmCvar_t cg_runroll; +vmCvar_t cg_bobup; +vmCvar_t cg_bobpitch; +vmCvar_t cg_bobroll; +vmCvar_t cg_swingSpeed; +vmCvar_t cg_shadows; +vmCvar_t cg_gibs; +vmCvar_t cg_drawTimer; +vmCvar_t cg_drawFPS; +vmCvar_t cg_drawSnapshot; +vmCvar_t cg_draw3dIcons; +vmCvar_t cg_drawIcons; +vmCvar_t cg_drawAmmoWarning; +vmCvar_t cg_drawCrosshair; +vmCvar_t cg_drawCrosshairNames; +vmCvar_t cg_drawRewards; +vmCvar_t cg_crosshairSize; +vmCvar_t cg_crosshairX; +vmCvar_t cg_crosshairY; +vmCvar_t cg_crosshairHealth; +vmCvar_t cg_draw2D; +vmCvar_t cg_drawStatus; +vmCvar_t cg_animSpeed; +vmCvar_t cg_debugAnim; +vmCvar_t cg_debugPosition; +vmCvar_t cg_debugEvents; +vmCvar_t cg_errorDecay; +vmCvar_t cg_nopredict; +vmCvar_t cg_noPlayerAnims; +vmCvar_t cg_showmiss; +vmCvar_t cg_footsteps; +vmCvar_t cg_addMarks; +vmCvar_t cg_viewsize; +vmCvar_t cg_drawGun; +vmCvar_t cg_gun_frame; +vmCvar_t cg_gun_x; +vmCvar_t cg_gun_y; +vmCvar_t cg_gun_z; +vmCvar_t cg_autoswitch; +vmCvar_t cg_ignore; +vmCvar_t cg_simpleItems; +vmCvar_t cg_fov; +vmCvar_t cg_zoomFov; +vmCvar_t cg_thirdPerson; +vmCvar_t cg_thirdPersonRange; +vmCvar_t cg_thirdPersonAngle; +//RPG-X: TiM - Cool JKA CVARs +vmCvar_t cg_thirdPersonVertOffset; +vmCvar_t cg_thirdPersonHorzOffset; +vmCvar_t cg_thirdPersonAlpha; +vmCvar_t cg_thirdPersonCameraDamp; +vmCvar_t cg_thirdPersonTargetDamp; +vmCvar_t cg_thirdPersonPitchOffset; +vmCvar_t cg_stereoSeparation; +vmCvar_t cg_lagometer; +vmCvar_t cg_drawAttacker; +vmCvar_t cg_synchronousClients; +vmCvar_t cg_teamChatTime; +vmCvar_t cg_teamChatHeight; +vmCvar_t cg_stats; +vmCvar_t cg_reportDamage; +vmCvar_t cg_buildScript; +vmCvar_t cg_forceModel; +vmCvar_t cg_paused; +vmCvar_t cg_blood; +vmCvar_t cg_predictItems; +vmCvar_t cg_deferPlayers; +vmCvar_t cg_drawTeamOverlay; +vmCvar_t cg_teamOverlayUserinfo; +vmCvar_t ui_playerclass; +vmCvar_t ui_playerrank; +vmCvar_t cg_disablekillmsgs; +vmCvar_t cg_drawradar; +vmCvar_t rpg_ctribgrenade; //RPG-X: - RedTechie i think J2J added this to control invisible tripmines on clients end - TOFIX:THIS ALSO COULD BE HACKED! +vmCvar_t cg_dynamicCrosshair; //RPG-X | Phenix | 09/06/2005 +vmCvar_t doomHead; //RPG-X | Phenix | 09/06/2005 +vmCvar_t cg_dynamiclensflares; +vmCvar_t cg_noTalkingHeads; +vmCvar_t cg_noDynamicRanks; + +vmCvar_t noAdminChat; //TiM + +//RPG-X: TiM - Player Model Parameters +vmCvar_t pms_age; +vmCvar_t pms_height; +vmCvar_t pms_weight; +vmCvar_t pms_race; + +//RPG-X: TiM - Emote system model offset +vmCvar_t emote_Offset; + +vmCvar_t cg_thirdPersonZoomRate; +vmCvar_t cg_noFrowningHeads; +vmCvar_t cg_noBlinkingHeads; + +//RPG-X | Phenix | 05/02/2006 +//Ban System (and it's backup cvars) +vmCvar_t cg_playerID; +vmCvar_t s_mhz; //Part A + 562 +vmCvar_t cg_fow; //Part B + 333 +vmCvar_t cl_avgPacket; //Part C + 99 +vmCvar_t cg_rewardsSize;//Part D + 120 + +typedef struct { + vmCvar_t *vmCvar; + char *cvarName; + char *defaultString; + int cvarFlags; +} cvarTable_t; + +static cvarTable_t cvarTable[] = { + { &cg_ignore, "cg_ignore", "0", 0 }, // used for debugging + { &s_mhz, "s_mhz", "0", CVAR_ARCHIVE | CVAR_ROM | CVAR_NORESTART }, //RPG-X | Phenix | 05/02/2006 + { &cg_autoswitch, "cg_autoswitch", "1", CVAR_ARCHIVE }, + { &cg_drawGun, "cg_drawGun", "1", CVAR_ARCHIVE }, + { &cg_zoomFov, "cg_zoomfov", "22.5", CVAR_ARCHIVE }, + { &cg_fov, "cg_fov", "80", CVAR_ARCHIVE }, + { &cg_fow, "cg_fow", "0", CVAR_ARCHIVE | CVAR_ROM | CVAR_NORESTART }, //RPG-X | Phenix | 05/02/2006 + { &cg_viewsize, "cg_viewsize", "100", CVAR_ARCHIVE }, + { &cg_stereoSeparation, "cg_stereoSeparation", "0.4", CVAR_ARCHIVE }, + { &s_mhz, "s_mhz", "0", CVAR_ARCHIVE | CVAR_ROM | CVAR_NORESTART }, //RPG-X | Phenix | 05/02/2006 + { &cg_shadows, "cg_shadows", "1", CVAR_ARCHIVE }, + { &cg_gibs, "cg_gibs", "0", CVAR_ARCHIVE }, //no gibs in trek + { &cg_draw2D, "cg_draw2D", "1", CVAR_ARCHIVE }, + { &cg_drawStatus, "cg_drawStatus", "1", CVAR_ARCHIVE }, + { &cg_drawTimer, "cg_drawTimer", "0", CVAR_ARCHIVE }, + { &cg_drawFPS, "cg_drawFPS", "0", CVAR_ARCHIVE }, + { &cg_drawSnapshot, "cg_drawSnapshot", "0", CVAR_ARCHIVE }, + { &cg_draw3dIcons, "cg_draw3dIcons", "1", CVAR_ARCHIVE }, + { &cg_drawIcons, "cg_drawIcons", "1", CVAR_ARCHIVE }, + { &cg_drawAmmoWarning, "cg_drawAmmoWarning", "1", CVAR_ARCHIVE }, + { &cg_drawAttacker, "cg_drawAttacker", "0", CVAR_ARCHIVE }, //RPG-X TiM + { &cg_drawCrosshair, "cg_drawCrosshair", "1", CVAR_ARCHIVE }, + { &cg_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE }, + { &cg_drawRewards, "cg_drawRewards", "1", CVAR_ARCHIVE }, + { &cg_rewardsSize, "cg_rewardsSize", "0", CVAR_ARCHIVE | CVAR_ROM | CVAR_NORESTART }, //RPG-X | Phenix | 05/02/2006 + { &cg_crosshairSize, "cg_crosshairSize", "24", CVAR_ARCHIVE }, + { &cg_crosshairHealth, "cg_crosshairHealth", "1", CVAR_ARCHIVE }, + { &cg_crosshairX, "cg_crosshairX", "0", CVAR_ARCHIVE }, + { &cg_crosshairY, "cg_crosshairY", "0", CVAR_ARCHIVE }, + { &cg_simpleItems, "cg_simpleItems", "0", CVAR_ARCHIVE }, + { &cg_addMarks, "cg_marks", "1", CVAR_ARCHIVE }, + { &cg_lagometer, "cg_lagometer", "0", CVAR_ARCHIVE }, + { &cg_gun_x, "cg_gunX", "0", CVAR_CHEAT }, + { &cg_gun_y, "cg_gunY", "0", CVAR_CHEAT }, + { &cg_gun_z, "cg_gunZ", "0", CVAR_CHEAT }, + { &cg_centertime, "cg_centertime", "3", CVAR_CHEAT }, + { &cg_runpitch, "cg_runpitch", "0.002", CVAR_ARCHIVE}, + { &cg_runroll, "cg_runroll", "0.005", CVAR_ARCHIVE }, + { &cg_bobup , "cg_bobup", "0.005", CVAR_ARCHIVE }, + { &cg_bobpitch, "cg_bobpitch", "0.002", CVAR_ARCHIVE }, + { &cg_bobroll, "cg_bobroll", "0.002", CVAR_ARCHIVE }, + { &cg_swingSpeed, "cg_swingSpeed", "0.3", CVAR_CHEAT }, + { &cg_animSpeed, "cg_animspeed", "1", CVAR_CHEAT }, + { &cg_debugAnim, "cg_debuganim", "0", CVAR_CHEAT }, + { &cg_debugPosition, "cg_debugposition", "0", CVAR_CHEAT }, + { &cg_debugEvents, "cg_debugevents", "0", CVAR_CHEAT }, + { &cg_errorDecay, "cg_errordecay", "100", 0 }, + { &cg_nopredict, "cg_nopredict", "0", 0 }, + { &cg_noPlayerAnims, "cg_noplayeranims", "0", CVAR_CHEAT }, + { &cg_showmiss, "cg_showmiss", "0", 0 }, + { &cg_footsteps, "cg_footsteps", "1", CVAR_CHEAT }, + { &cg_thirdPersonRange, "cg_thirdPersonRange", "80", CVAR_ARCHIVE }, + { &cg_thirdPersonAngle, "cg_thirdPersonAngle", "0", CVAR_ARCHIVE }, + { &cg_thirdPerson, "cg_thirdPerson", "0", CVAR_ARCHIVE }, + { &cg_thirdPersonVertOffset, "cg_thirdPersonVertOffset", "16", CVAR_ARCHIVE }, //RPG-X: TiM + { &cg_thirdPersonHorzOffset, "cg_thirdPersonHorzOffset", "0", CVAR_ARCHIVE }, //RPG-X: TiM + { &cg_thirdPersonAlpha, "cg_thirdPersonAlpha", "1.0", CVAR_ARCHIVE },//RPG-X: TiM + { &cg_thirdPersonCameraDamp, "cg_thirdPersonCameraDamp", "0.3", CVAR_ARCHIVE },//RPG-X: TiM + { &cg_thirdPersonTargetDamp, "cg_thirdPersonTargetDamp", "0.5", CVAR_ARCHIVE },//RPG-X: TiM + { &cg_thirdPersonPitchOffset, "cg_thirdPersonPitchOffset", "0.0", CVAR_ARCHIVE},//RPG-X: TiM + { &cg_teamChatTime, "cg_teamChatTime", "3000", CVAR_ARCHIVE }, + { &cg_teamChatHeight, "cg_teamChatHeight", "0", CVAR_ARCHIVE }, + { &cg_forceModel, "cg_forceModel", "0", CVAR_ARCHIVE }, + { &cg_predictItems, "cg_predictItems", "1", CVAR_ARCHIVE }, + { &cg_deferPlayers, "cg_deferPlayers", "1", CVAR_ARCHIVE }, + { &cg_drawTeamOverlay, "cg_drawTeamOverlay", "0", CVAR_ARCHIVE }, + { &cg_teamOverlayUserinfo, "teamoverlay", "0", CVAR_ROM | CVAR_USERINFO }, + { &cg_stats, "cg_stats", "0", 0 }, + { &cg_reportDamage, "cg_reportDamage", "0", 0}, + { &rpg_ctribgrenade, "rpg_ctribgrenade", "0", CVAR_ARCHIVE}, //RPG-X: - RedTechie i think J2J added this to control invisible tripmines on clients end - TOFIX:THIS ALSO COULD BE HACKED! + { &pms_age, "age", "Unknown", CVAR_ARCHIVE | CVAR_USERINFO }, + { &pms_height, "height", "1.0", CVAR_ARCHIVE | CVAR_USERINFO }, + { &pms_weight, "weight", "1.0", CVAR_ARCHIVE | CVAR_USERINFO }, + { &pms_race, "race", "Unknown", CVAR_ARCHIVE | CVAR_USERINFO }, + { &emote_Offset, "modelOffset", "0.0", CVAR_ARCHIVE | CVAR_USERINFO }, + + + // the following variables are created in other parts of the system, + // but we also reference them here + + { &cg_buildScript, "com_buildScript", "0", 0 }, // force loading of all possible data amd error on failures + { &cg_paused, "cl_paused", "0", CVAR_ROM }, + { &cg_blood, "com_blood", "0", CVAR_ARCHIVE }, //no blood in trek + { &cl_avgPacket, "cl_avgPacket", "0", CVAR_ARCHIVE | CVAR_ROM | CVAR_NORESTART }, //RPG-X | Phenix | 05/02/2006 + { &cg_synchronousClients, "g_synchronousClients", "0", 0 }, // communicated by systeminfo + { &ui_playerclass, "ui_playerclass", "noclass", CVAR_ARCHIVE | CVAR_ROM }, + //{ &ui_playerclass, "ui_playerclass", "0", 0 }, // player class + { &ui_playerrank, "ui_playerrank", "crewman", CVAR_ARCHIVE | CVAR_ROM }, + + { &cg_disablekillmsgs, "cg_disablekillmsgs", "0", CVAR_ARCHIVE }, + { &cg_drawradar, "cg_drawradar", "1", CVAR_ARCHIVE }, + + { &cg_dynamicCrosshair, "cg_dynamicCrosshair", "1", CVAR_ARCHIVE }, //RPG-X | Phenix | 09/06/2005 + { &doomHead, "doomHead", "0", CVAR_ARCHIVE }, //RPG-X | Phenix | 09/06/2005 + { &cg_dynamiclensflares, "cg_dynamicLensFlares", "1", CVAR_ARCHIVE }, //RPG-X | TiM | 29/6/2005 + + { &noAdminChat, "noAdminChat", "0", CVAR_ARCHIVE | CVAR_USERINFO }, + + //RPG-X Memory optimization CVARs + { &cg_noTalkingHeads, "cg_noTalkingHeads", "0", CVAR_ARCHIVE }, + { &cg_noDynamicRanks, "cg_noDynamicRanks", "0", CVAR_ARCHIVE }, + { &cg_noFrowningHeads, "cg_noFrowningHeads", "1", CVAR_ARCHIVE }, //On by default since this isn't REALLY needed... :P + { &cg_noBlinkingHeads, "cg_noBlinkingHeads", "0", CVAR_ARCHIVE }, + + { &cg_thirdPersonZoomRate, "cg_thirdPersonZoomRate", "25", CVAR_ARCHIVE }, + + { &cg_playerID, "cg_playerID", "0", CVAR_ARCHIVE | CVAR_ROM | CVAR_USERINFO | CVAR_NORESTART } //RPG-X | Phenix | 05/02/2006 +}; + +static int cvarTableSize = sizeof( cvarTable ) / sizeof( cvarTable[0] ); + +/* +================= +CG_RegisterCvars +================= +*/ +void CG_RegisterCvars( void ) { + int i; + cvarTable_t *cv; + char var[MAX_TOKEN_CHARS]; + + for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) { + trap_Cvar_Register( cv->vmCvar, cv->cvarName, + cv->defaultString, cv->cvarFlags ); + } + + // see if we are also running the server on this machine + trap_Cvar_VariableStringBuffer( "sv_running", var, sizeof( var ) ); + cgs.localServer = atoi( var ); +} + + +/* +================= +CG_UpdateCvars +================= +*/ +void CG_UpdateCvars( void ) { + int i; + cvarTable_t *cv; + + for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) + { + trap_Cvar_Update( cv->vmCvar ); + } + + // check for modications here + + // If team overlay is on, ask for updates from the server. If its off, + // let the server know so we don't receive it + if ( drawTeamOverlayModificationCount != cg_drawTeamOverlay.modificationCount ) { + drawTeamOverlayModificationCount = cg_drawTeamOverlay.modificationCount; + + if ( cg_drawTeamOverlay.integer > 0 ) { + trap_Cvar_Set( "teamoverlay", "1" ); + } else { + trap_Cvar_Set( "teamoverlay", "0" ); + } + } +} + + +int CG_CrosshairPlayer( void ) { + if ( cg.time > ( cg.crosshairClientTime + 1000 ) ) { + return -1; + } + return cg.crosshairClientNum; +} + + +int CG_LastAttacker( void ) { + if ( !cg.attackerTime ) { + return -1; + } + return cg.snap->ps.persistant[PERS_ATTACKER]; +} + + +void QDECL CG_Printf( const char *msg, ... ) { + va_list argptr; + char text[1024]; + + va_start (argptr, msg); + vsprintf (text, msg, argptr); + va_end (argptr); + + trap_Print( text ); +} + +void QDECL CG_Error( const char *msg, ... ) { + va_list argptr; + char text[1024]; + + va_start (argptr, msg); + vsprintf (text, msg, argptr); + va_end (argptr); + + trap_Error( text ); +} + +#ifndef CGAME_HARD_LINKED +// this is only here so the functions in q_shared.c and bg_*.c can link (FIXME) + +void QDECL Com_Error( int level, const char *error, ... ) { + va_list argptr; + char text[1024]; + + va_start (argptr, error); + vsprintf (text, error, argptr); + va_end (argptr); + + CG_Error( "%s", text); +} + +void QDECL Com_Printf( const char *msg, ... ) { + va_list argptr; + char text[1024]; + + va_start (argptr, msg); + vsprintf (text, msg, argptr); + va_end (argptr); + + CG_Printf ("%s", text); +} + +#endif + + + +/* +================ +CG_Argv +================ +*/ +const char *CG_Argv( int arg ) { + static char buffer[MAX_STRING_CHARS]; + + trap_Argv( arg, buffer, sizeof( buffer ) ); + + return buffer; +} + + +//======================================================================== + +/* +================= +CG_RegisterItemSounds + +The server says this item is used on this level +================= +*/ +static void CG_RegisterItemSounds( int itemNum ) { + gitem_t *item; + char data[MAX_QPATH]; + char *s, *start; + int len; + + item = &bg_itemlist[ itemNum ]; + + if ( item->pickup_sound ) + { + trap_S_RegisterSound( item->pickup_sound ); + } + + // parse the space seperated precache string for other media + s = item->sounds; + if (!s || !s[0]) + return; + + while (*s) { + start = s; + while (*s && *s != ' ') { + s++; + } + + len = s-start; + if (len >= MAX_QPATH || len < 5) { + CG_Error( "PrecacheItem: %s has bad precache string", + item->classname); + return; + } + memcpy (data, start, len); + data[len] = 0; + if ( *s ) { + s++; + } + + if ( !strcmp(data+len-3, "wav" )) { + trap_S_RegisterSound( data ); + } + } +} + + +/* +================= +CG_RegisterSounds + +called during a precache command +================= +*/ +static void CG_RegisterSounds( void ) +{ + int i; + char items[MAX_ITEMS+1]; + char name[MAX_QPATH]; + const char *soundName; + + cg.loadLCARSStage = 1; // Loading bar stage 1 + CG_LoadingString( "sounds" ); + + //TiM + /*if ( cgs.timelimit || cg_buildScript.integer ) { // should we always load this? + cgs.media.oneMinuteSound = trap_S_RegisterSound( "sound/voice/computer/misc/1_minute.wav" ); + cgs.media.fiveMinuteSound = trap_S_RegisterSound( "sound/voice/computer/misc/5_minute.wav" ); + cgs.media.suddenDeathSound = trap_S_RegisterSound( "sound/voice/computer/misc/sudden_death.wav" ); + }*/ + + //TiM + /*if ( cgs.fraglimit || cg_buildScript.integer ) { + cgs.media.oneFragSound = trap_S_RegisterSound( "sound/voice/computer/misc/1_frag.wav" ); + cgs.media.twoFragSound = trap_S_RegisterSound( "sound/voice/computer/misc/2_frags.wav" ); + cgs.media.threeFragSound = trap_S_RegisterSound( "sound/voice/computer/misc/3_frags.wav" ); + }*/ + +// if ( cgs.gametype == GT_TOURNAMENT || cg_buildScript.integer ) { +// We always need this since a warmup can be enabled in any game mode +//TiM /*cgs.media.count3Sound = trap_S_RegisterSound( "sound/voice/computer/misc/three.wav" ); + cgs.media.count2Sound = trap_S_RegisterSound( "sound/voice/computer/misc/two.wav" ); + cgs.media.count1Sound = trap_S_RegisterSound( "sound/voice/computer/misc/one.wav" ); + cgs.media.countFightSound = trap_S_RegisterSound( "sound/voice/computer/misc/fight.wav" ); + cgs.media.countPrepareSound = trap_S_RegisterSound( "sound/voice/computer/misc/prepare.wav" ); +// } + //TiM +/* if ( cgs.gametype >= GT_TEAM || cg_buildScript.integer ) { + cgs.media.redLeadsSound = trap_S_RegisterSound( "sound/voice/computer/misc/redleads.wav" ); + cgs.media.blueLeadsSound = trap_S_RegisterSound( "sound/voice/computer/misc/blueleads.wav" ); + cgs.media.teamsTiedSound = trap_S_RegisterSound( "sound/voice/computer/misc/teamstied.wav" ); + cgs.media.hitTeamSound = trap_S_RegisterSound( "sound/feedback/hit_teammate.wav" ); + }*/ + + //TiM + /*if (cgs.gametype == GT_CTF || cg_buildScript.integer) + { + cgs.media.ctfStealSound = trap_S_RegisterSound("sound/voice/computer/misc/flagtk_blu.wav"); + cgs.media.ctfReturnSound = trap_S_RegisterSound("sound/voice/computer/misc/flagret_blu.wav"); + cgs.media.ctfScoreSound = trap_S_RegisterSound("sound/voice/computer/misc/flagcap_blu.wav"); + cgs.media.ctfYouStealVoiceSound = trap_S_RegisterSound("sound/voice/computer/misc/stolen.wav"); + cgs.media.ctfYouDroppedVoiceSound = trap_S_RegisterSound("sound/voice/computer/misc/dropped_e.wav"); + cgs.media.ctfYouReturnVoiceSound = trap_S_RegisterSound("sound/voice/computer/misc/returned.wav"); + cgs.media.ctfYouScoreVoiceSound = trap_S_RegisterSound("sound/voice/computer/misc/scored.wav"); + cgs.media.ctfTheyStealVoiceSound = trap_S_RegisterSound("sound/voice/computer/misc/stolen_e.wav"); + cgs.media.ctfTheyDroppedVoiceSound = trap_S_RegisterSound("sound/voice/computer/misc/dropped.wav"); // Note the flip, because YOU dropped THEIR flag + cgs.media.ctfTheyReturnVoiceSound = trap_S_RegisterSound("sound/voice/computer/misc/returned_e.wav"); + cgs.media.ctfTheyScoreVoiceSound = trap_S_RegisterSound("sound/voice/computer/misc/scored_e.wav"); + }*/ + + cgs.media.interfaceSnd1 = trap_S_RegisterSound( "sound/interface/button4.wav" ); + + cgs.media.selectSound = trap_S_RegisterSound( "sound/weapons/change.wav" ); + cgs.media.wearOffSound = trap_S_RegisterSound( "sound/items/wearoff.wav" ); + cgs.media.useNothingSound = trap_S_RegisterSound( "sound/items/use_nothing.wav" ); + + //TiM//cgs.media.holoOpenSound = trap_S_RegisterSound( "sound/movers/doors/holoopen.wav" ); + cgs.media.teleInSound = trap_S_RegisterSound( "sound/world/transin.wav" ); + cgs.media.teleOutSound = trap_S_RegisterSound( "sound/world/transout.wav" ); + cgs.media.transportSound = trap_S_RegisterSound( "sound/world/transporter.wav" ); + cgs.media.respawnSound = trap_S_RegisterSound( "sound/items/respawn1.wav" ); + + cgs.media.noAmmoSound = trap_S_RegisterSound( "sound/weapons/noammo.wav" ); + + cgs.media.talkSound = trap_S_RegisterSound( "sound/interface/communicator.wav" ); + cgs.media.landSound = trap_S_RegisterSound( "sound/player/land1.wav"); + cgs.media.splatSound = trap_S_RegisterSound( "sound/weapons/bodyfall.wav"); + + cgs.media.hitSound = trap_S_RegisterSound( "sound/feedback/hit.wav" ); + cgs.media.shieldHitSound = trap_S_RegisterSound( "sound/feedback/shieldHit.wav" ); + cgs.media.shieldPierceSound = trap_S_RegisterSound( "sound/feedback/shieldPierce.wav" ); + + //TiM + /*cgs.media.rewardImpressiveSound = trap_S_RegisterSound( "sound/voice/computer/misc/impressive.wav" ); + cgs.media.rewardExcellentSound = trap_S_RegisterSound( "sound/voice/computer/misc/excellent.wav" ); + cgs.media.rewardDeniedSound = trap_S_RegisterSound( "sound/voice/computer/misc/denied.wav" ); + cgs.media.rewardFirstStrikeSound = trap_S_RegisterSound( "sound/voice/computer/misc/1ststrike.wav"); + cgs.media.rewardAceSound = trap_S_RegisterSound( "sound/voice/computer/misc/ace.wav"); + cgs.media.rewardExpertSound = trap_S_RegisterSound( "sound/voice/computer/misc/expert.wav"); + cgs.media.rewardMasterSound = trap_S_RegisterSound( "sound/voice/computer/misc/master.wav"); + cgs.media.rewardChampionSound = trap_S_RegisterSound( "sound/voice/computer/misc/champion.wav");*/ + + //TiM + /*cgs.media.takenLeadSound = trap_S_RegisterSound( "sound/voice/computer/misc/takenlead.wav"); + cgs.media.tiedLeadSound = trap_S_RegisterSound( "sound/voice/computer/misc/tiedlead.wav"); + cgs.media.lostLeadSound = trap_S_RegisterSound( "sound/voice/computer/misc/lostlead.wav");*/ + + cgs.media.watrInSound = trap_S_RegisterSound( "sound/player/watr_in.wav"); + cgs.media.watrOutSound = trap_S_RegisterSound( "sound/player/watr_out.wav"); + cgs.media.watrUnSound = trap_S_RegisterSound( "sound/player/watr_un.wav"); + + cgs.media.jumpPadSound = trap_S_RegisterSound ("sound/items/damage3.wav" ); + + cgs.media.poweruprespawnSound = trap_S_RegisterSound ("sound/items/poweruprespawn.wav"); + cgs.media.disintegrateSound = trap_S_RegisterSound( "sound/weapons/prifle/disint.wav" ); + cgs.media.disintegrate2Sound = trap_S_RegisterSound( "sound/weapons/prifle/disint2.wav" ); + cgs.media.playerExplodeSound = trap_S_RegisterSound( "sound/weapons/explosions/fireball.wav" ); + + //TiM + /*cgs.media.holoInitSound = trap_S_RegisterSound("sound/voice/computer/misc/proginit.wav"); + cgs.media.holoDoorSound = trap_S_RegisterSound("sound/movers/doors/holoopen.wav"); + cgs.media.holoFadeSound = trap_S_RegisterSound("sound/movers/holodeckdecloak.wav");*/ + + cgs.media.phaserEmptySound = trap_S_RegisterSound("sound/weapons/phaser/phaserempty.wav"); + + //RPG-X: RedTechie - Load sound for shake cmd + cgs.media.ShakeSound = trap_S_RegisterSound("sound/shake.wav"); + + cgs.media.tedTextSound = trap_S_RegisterSound( "sound/interface/tedtext.wav" ); + + //RPG-X | Phenix | 13/02/2005 + for (i=0 ; i= GT_TEAM || cg_buildScript.integer ) { + cgs.media.teamRedShader = trap_R_RegisterShader( "sprites/team_red" ); + cgs.media.teamBlueShader = trap_R_RegisterShader( "sprites/team_blue" ); + cgs.media.redQuadShader = trap_R_RegisterShader("powerups/blueflag" ); + cgs.media.teamStatusBar = trap_R_RegisterShader( "gfx/2d/colorbar.tga" ); + }*/ + + cgs.media.chatShader = trap_R_RegisterShader( "sprites/chat" ); + + //cgs.media.bloodExplosionShader = trap_R_RegisterShader( "bloodExplosion" ); + + cgs.media.ringFlashModel = trap_R_RegisterModel("models/weaphits/ring02.md3"); + cgs.media.teleportEffectModel = trap_R_RegisterModel( "models/misc/telep.md3" ); + cgs.media.teleportEffectShader = trap_R_RegisterShader( "playerTeleport" ); + + //cgs.media.doorbox = trap_R_RegisterModel( "models/mapobjects/podium/hm_room.md3"); + + //RPG-X TiM : the bolton assets + cgs.media.phaserHolster = trap_R_RegisterModel( "models/boltOns/phaser_holster.md3"); + cgs.media.phaserHolsterInner = trap_R_RegisterModel( "models/boltOns/phaser_holster_inner.md3"); + + cgs.media.tricorderHolster = trap_R_RegisterModel( "models/boltOns/tricorder_holster.md3"); + cgs.media.tricorderHolsterInner = trap_R_RegisterModel( "models/boltOns/tricorder_holster_inner.md3"); + + //TiM : TR116 Eyescope + cgs.media.tr116EyeScope = trap_R_RegisterModel( "models/boltOns/tr116_scope.md3"); + //TiM : Flashlight + cgs.media.simsModule = trap_R_RegisterModel( "models/boltOns/sims_beacon.md3" ); + //EVA FPS Helmet + cgs.media.evaInterior = trap_R_RegisterModel( "models/boltOns/eva_interior.md3" ); + + cgs.media.shieldActivateShaderBlue = trap_R_RegisterShader( "gfx/misc/forcefield" ); //blue_portashield + cgs.media.shieldDamageShaderBlue = trap_R_RegisterShader( "gfx/misc/blue_dmgshield" ); + cgs.media.shieldActivateShaderRed = trap_R_RegisterShader( "gfx/misc/red_portashield" ); + cgs.media.shieldDamageShaderRed = trap_R_RegisterShader( "gfx/misc/red_dmgshield" ); + + cgs.media.weaponPlaceholderShader = trap_R_RegisterShader("powerups/placeholder" ); + cgs.media.rezOutShader = trap_R_RegisterShader("powerups/rezout"); + cgs.media.electricBodyShader = trap_R_RegisterShader("gfx/misc/electric"); + + /*cgs.media.medalImpressive = trap_R_RegisterShaderNoMip( "medal_impressive" ); + cgs.media.medalExcellent = trap_R_RegisterShaderNoMip( "medal_excellent" ); + cgs.media.medalFirstStrike = trap_R_RegisterShaderNoMip( "medal_firststrike" ); + cgs.media.medalAce = trap_R_RegisterShaderNoMip( "medal_ace" ); + cgs.media.medalExpert = trap_R_RegisterShaderNoMip( "medal_expert" ); + cgs.media.medalMaster = trap_R_RegisterShaderNoMip( "medal_master" ); + cgs.media.medalChampion = trap_R_RegisterShaderNoMip( "medal_champion" );*/ + + //RPG-X: RedTechie - Scoreboard Endcaps + cgs.media.scoreboardtopleft = trap_R_RegisterShaderNoMip( "menu/common/rpgx_sb_topleft"); + cgs.media.scoreboardtopright = trap_R_RegisterShaderNoMip( "menu/common/rpgx_sb_topright"); + cgs.media.scoreboardbotleft = trap_R_RegisterShaderNoMip( "menu/common/rpgx_sb_bottomleft"); + cgs.media.scoreboardbotright = trap_R_RegisterShaderNoMip( "menu/common/rpgx_sb_bottomright"); + + //RPG-X: RedTechie - Healthbar Curves + cgs.media.healthendcap = trap_R_RegisterShaderNoMip("gfx/interface/rpgx_healthbar_endcap"); + cgs.media.healthbigcurve = trap_R_RegisterShaderNoMip("gfx/interface/rpgx_healthbar_leftcorner"); + + //RPG-X: RedTechie - Cloak Sprite + cgs.media.cloakspriteShader = trap_R_RegisterShader("sprites/cloak"); + + cgs.media.scoreboardEndcap = trap_R_RegisterShaderNoMip( "menu/common/halfround_r_24"); + cgs.media.corner_12_24 = trap_R_RegisterShaderNoMip( "menu/common/corner_ll_24_12"); + cgs.media.corner_8_16_b = trap_R_RegisterShaderNoMip( "menu/common/corner_lr_8_16_b"); + + cgs.media.weaponcap1 = trap_R_RegisterShaderNoMip("gfx/interface/cap4"); + cgs.media.weaponcap2 = trap_R_RegisterShaderNoMip("gfx/interface/cap5"); + + cgs.media.weaponbox = trap_R_RegisterShaderNoMip("gfx/interface/weapon_box"); + cgs.media.weaponbox2 = trap_R_RegisterShaderNoMip("gfx/interface/weapon_box2"); + + memset( cg_items, 0, sizeof( cg_items ) ); + memset( cg_weapons, 0, sizeof( cg_weapons ) ); + + cg.loadLCARSStage = 5; // Loading bar stage 5 + //don't need a CG_LoadingString because there will be one in the LoadingItem() + + // only register the items that the server says we need + strcpy( items, CG_ConfigString( CS_ITEMS) ); + + for ( i = 1 ; i < bg_numItems ; i++ ) { + if ( items[ i ] == '1' || cg_buildScript.integer ) { + CG_LoadingItem( i ); + CG_RegisterItemVisuals( i ); + } + } + + // wall marks + cgs.media.holeMarkShader = trap_R_RegisterShader( "gfx/damage/hole_lg_mrk" ); + cgs.media.energyMarkShader = trap_R_RegisterShader( "gfx/damage/plasma_mrk" ); + cgs.media.shadowMarkShader = trap_R_RegisterShader( "markShadow" ); + cgs.media.wakeMarkShader = trap_R_RegisterShader( "wake" ); + + // Radar + //TiM: OPTIMIZATION: + //It's possible to use one set of textures, and use Alpha channels to vary + //the color thru the code... wouldn't that be better? + cgs.media.radarShader = trap_R_RegisterShader( "gfx/radar/radar" ); + /*cgs.media.rd_up = trap_R_RegisterShader( "gfx/radar/rd_up" ); + cgs.media.rd_down = trap_R_RegisterShader( "gfx/radar/rd_down" ); + cgs.media.rd_level = trap_R_RegisterShader( "gfx/radar/rd_level" ); + cgs.media.rd_red_up = trap_R_RegisterShader( "gfx/radar/rd_red_up" ); + cgs.media.rd_red_down = trap_R_RegisterShader( "gfx/radar/rd_red_down" ); + cgs.media.rd_red_level = trap_R_RegisterShader( "gfx/radar/rd_red_level" ); + cgs.media.rd_blue_up = trap_R_RegisterShader( "gfx/radar/rd_blue_up" ); + cgs.media.rd_blue_down = trap_R_RegisterShader( "gfx/radar/rd_blue_down" ); + cgs.media.rd_blue_level = trap_R_RegisterShader( "gfx/radar/rd_blue_level" ); + cgs.media.rd_white_up = trap_R_RegisterShader( "gfx/radar/rd_white_up" ); + cgs.media.rd_white_down = trap_R_RegisterShader( "gfx/radar/rd_white_down" ); + cgs.media.rd_white_level = trap_R_RegisterShader( "gfx/radar/rd_white_level" ); + cgs.media.rd_teal_up = trap_R_RegisterShader( "gfx/radar/rd_teal_up" ); + cgs.media.rd_teal_down = trap_R_RegisterShader( "gfx/radar/rd_teal_down" ); + cgs.media.rd_teal_level = trap_R_RegisterShader( "gfx/radar/rd_teal_level" ); + cgs.media.rd_black_up = trap_R_RegisterShader( "gfx/radar/rd_black_up" ); + cgs.media.rd_black_down = trap_R_RegisterShader( "gfx/radar/rd_black_down" ); + cgs.media.rd_black_level = trap_R_RegisterShader( "gfx/radar/rd_black_level" ); + cgs.media.rd_injured_up = trap_R_RegisterShader( "gfx/radar/injured_up" ); + cgs.media.rd_injured_down = trap_R_RegisterShader( "gfx/radar/injured_down" );*/ + cgs.media.rd_injured_level = trap_R_RegisterShader( "gfx/radar/injured_level" ); + + cgs.media.radarMain = trap_R_RegisterShaderNoMip( "gfx/radar/radar_icon" ); + + // register the inline models + cgs.numInlineModels = trap_CM_NumInlineModels(); + for ( i = 1 ; i < cgs.numInlineModels ; i++ ) { + char name[10]; + vec3_t mins, maxs; + int j; + + Com_sprintf( name, sizeof(name), "*%i", i ); + cgs.inlineDrawModel[i] = trap_R_RegisterModel( name ); + trap_R_ModelBounds( cgs.inlineDrawModel[i], mins, maxs ); + for ( j = 0 ; j < 3 ; j++ ) { + cgs.inlineModelMidpoints[i][j] = mins[j] + 0.5 * ( maxs[j] - mins[j] ); + } + } + + cg.loadLCARSStage = 6; // Loading bar stage 6 + CG_LoadingString( "Game Models" ); + + // register all the server specified models + for (i=1 ; i 0 ) { + cgs.locations = qtrue; + break; + } + } + + //TiM: Do the same for all tricorder string names + /*or ( i = 1; i < MAX_TRIC_STRINGS; i++ ) { + const char *strName; + + strName = CG_ConfigString( CS_TRIC_STRINGS+i ); + if ( !strName[0] ) { + break; + } + + //Com_Printf( S_COLOR_RED "USABLE MESSAGE IN CG: %s\n", strName ); + + //Com_sprintf( cgs.tricStrings[i], MAX_TOKEN_CHARS, "%s", strName ); + + //cgs.tricStrings[i] = (char *)strName; + //Com_Printf( S_COLOR_RED "%s\n", cgs.tricStrings[i] ); + Q_strncpyz( cgs.tricStrings[i], strName, MAX_TOKEN_CHARS ); + }*/ + + cg.loadLCARSStage = 7; // Loading bar stage 7 + CG_LoadingString( "Interface" ); + + // Registering interface graphics + for (i=0;i= MAX_CONFIGSTRINGS ) { + CG_Error( "CG_ConfigString: bad index: %i", index ); + } + return cgs.gameState.stringData + cgs.gameState.stringOffsets[ index ]; +} + +//================================================================== + +/* +====================== +CG_StartMusic + +====================== +*/ +void CG_StartMusic( void ) { + char *s; + char parm1[MAX_QPATH], parm2[MAX_QPATH]; + + // start the background music + s = (char *)CG_ConfigString( CS_MUSIC ); + Q_strncpyz( parm1, COM_Parse( &s ), sizeof( parm1 ) ); + Q_strncpyz( parm2, COM_Parse( &s ), sizeof( parm2 ) ); + + trap_S_StartBackgroundTrack( parm1, parm2 ); +} + +extern int altAmmoUsage[]; +void CG_InitModRules( void ) +{ + if ( cgs.pModDisintegration ) + {//don't use up ammo in disintegration mode + altAmmoUsage[WP_COMPRESSION_RIFLE] = 0; + } + if ( cgs.pModSpecialties ) + {//tripwires use more ammo + altAmmoUsage[WP_GRENADE_LAUNCHER] = 3; + } +} + +/* +================= +CG_Init + +Called after every level change or subsystem restart +Will perform callbacks to make the loading info screen update. +================= +*/ +void CG_Init( int serverMessageNum, int serverCommandSequence ) { + const char *s; + + // clear everything + memset( &cgs, 0, sizeof( cgs ) ); + memset( &cg, 0, sizeof( cg ) ); + memset( cg_entities, 0, sizeof(cg_entities) ); + memset( cg_weapons, 0, sizeof(cg_weapons) ); + memset( cg_items, 0, sizeof(cg_items) ); + + //Flush Sound Effects + memset( &cg_animsSndList, 0, sizeof( cg_animsSndList ) ); + + cgs.processedSnapshotNum = serverMessageNum; + cgs.serverCommandSequence = serverCommandSequence; + + CG_LoadIngameText(); + + CG_LoadFonts(); + + // Loading graphics + cgs.media.loading1 = trap_R_RegisterShaderNoMip( "menu/loading/smpiece1.tga" ); + cgs.media.loading2 = trap_R_RegisterShaderNoMip( "menu/loading/smpiece2.tga" ); + cgs.media.loading3 = trap_R_RegisterShaderNoMip( "menu/loading/smpiece3.tga" ); + cgs.media.loading4 = trap_R_RegisterShaderNoMip( "menu/loading/smpiece4.tga" ); + cgs.media.loading5 = trap_R_RegisterShaderNoMip( "menu/loading/smpiece5.tga" ); + cgs.media.loading6 = trap_R_RegisterShaderNoMip( "menu/loading/smpiece6.tga" ); + cgs.media.loading7 = trap_R_RegisterShaderNoMip( "menu/loading/smpiece7.tga" ); + cgs.media.loading8 = trap_R_RegisterShaderNoMip( "menu/loading/smpiece8.tga" ); + cgs.media.loading9 = trap_R_RegisterShaderNoMip( "menu/loading/smpiece9.tga" ); + cgs.media.loadingcircle = trap_R_RegisterShaderNoMip( "menu/loading/arrowpiece.tga" ); + cgs.media.loadingquarter= trap_R_RegisterShaderNoMip( "menu/loading/quarter.tga" ); + cgs.media.loadingcorner = trap_R_RegisterShaderNoMip( "menu/common/corner_lr_8_16.tga" ); + cgs.media.loadingtrim = trap_R_RegisterShaderNoMip( "menu/loading/trimupper.tga" ); + cgs.media.circle = trap_R_RegisterShaderNoMip( "menu/common/circle.tga" ); + cgs.media.circle2 = trap_R_RegisterShaderNoMip( "menu/objectives/circle_out.tga" ); + cgs.media.corner_12_18 = trap_R_RegisterShaderNoMip( "menu/common/corner_ll_12_18.tga" ); + cgs.media.halfroundr_22 = trap_R_RegisterShaderNoMip( "menu/common/halfroundr_22.tga" ); + + cgs.media.corner_ul_20_30= trap_R_RegisterShaderNoMip( "menu/common/corner_ul_20_30.tga" ); + cgs.media.corner_ll_8_30= trap_R_RegisterShaderNoMip( "menu/common/corner_ll_8_30.tga" ); + + cg.loadLCARSStage = 0; + cg.loadLCARScnt = 0; + // load a few needed things before we do any screen updates + cgs.media.charsetShader = trap_R_RegisterShaderNoMip( "gfx/2d/charsgrid_med" ); + cgs.media.whiteShader = trap_R_RegisterShader( "white" ); + cgs.media.white2Shader = trap_R_RegisterShader( "white2" ); + cgs.media.charsetPropTiny = trap_R_RegisterShaderNoMip("gfx/2d/chars_tiny"); + cgs.media.charsetProp = trap_R_RegisterShaderNoMip("gfx/2d/chars_medium"); + cgs.media.charsetPropBig = trap_R_RegisterShaderNoMip("gfx/2d/chars_big"); +// cgs.media.charsetPropGlow = trap_R_RegisterShaderNoMip( "menu/art/font1_prop_glo.tga" ); + cgs.media.charsetPropB = trap_R_RegisterShaderNoMip( "gfx/2d/chars_medium.tga" ); + + CG_RegisterCvars(); + + CG_InitConsoleCommands(); + + BG_LoadItemNames(); + + cg.weaponSelect = WP_PHASER; + + cgs.redflag = cgs.blueflag = -1; // For compatibily, default to unset for + // old servers + + // get the rendering configuration from the client system + trap_GetGlconfig( &cgs.glconfig ); + cgs.screenXScale = cgs.glconfig.vidWidth / 640.0; + cgs.screenYScale = cgs.glconfig.vidHeight / 480.0; + + // get the gamestate from the client system + trap_GetGameState( &cgs.gameState ); + + // check version + s = CG_ConfigString( CS_GAME_VERSION ); + if ( strcmp( s, GAME_VERSION ) ) { + CG_Error( "Client/Server game mismatch: %s/%s", GAME_VERSION, s ); + } + + s = CG_ConfigString( CS_LEVEL_START_TIME ); + cgs.levelStartTime = atoi( s ); + + CG_ParseServerinfo(); + + // load the new map + CG_LoadingString( "collision map" ); + + trap_CM_LoadMap( cgs.mapname ); + + cg.loading = qtrue; // force players to load instead of defer + + CG_LoadObjectivesForMap(); + + CG_RegisterSounds(); + + CG_RegisterGraphics(); + + CG_RegisterClients(); // if low on memory, some clients will be deferred + + cg.loading = qfalse; // future players will be deferred + + CG_InitLocalEntities(); + + CG_InitMarkPolys(); + + // remove the last loading update + cg.infoScreenText[0] = 0; + + // Make sure we have update values (scores) + CG_SetConfigValues(); + + CG_StartMusic(); + + CG_LoadingString( "" ); + + // To get the interface timing started + cg.interfaceStartupTime = 0; + cg.interfaceStartupDone = 0; + + CG_InitModRules(); + + if ( !CG_LoadCrosshairs() ) { + CG_Error( "Couldn't load crosshairs script" ); + } + + if ( !CG_LoadRanks() ) { + CG_Error( "Couldn't load rankset script: %s", cgs.rankSet ); + } +} + +/* +================= +CG_Shutdown + +Called before every level change or subsystem restart +================= +*/ +void CG_Shutdown( void ) { + // some mods may need to do cleanup work here, + // like closing files or archiving session data + trap_Cvar_Set ("rpg_playIntro", "0"); +} + + +#define MAXINGAMETEXT 5000 +char ingameText[MAXINGAMETEXT]; + +/* +================= +CG_ParseIngameText +================= +*/ +void CG_ParseIngameText(void) +{ + char *token; + char *buffer; + int i; + int len; + + COM_BeginParseSession(); + + buffer = ingameText; + i = 1; // Zero is null string + while ( buffer ) + { + token = COM_ParseExt( &buffer, qtrue ); + + len = strlen(token); + if (len) + { + ingame_text[i] = (buffer - (len + 1)); // The +1 is to get rid of the " at the beginning of the sting. + *(buffer - 1) = '\0'; // Place an string end where is belongs. + + ++i; + } + + if (i> IGT_MAX) + { + Com_Printf( S_COLOR_RED "CG_ParseIngameText : too many values!\n"); + return; + } + } + + if (i != IGT_MAX) + { + Com_Printf( S_COLOR_RED "CG_ParseIngameText : not enough lines! Read %d of %d!\n",i,IGT_MAX); + for(;i MAXINGAMETEXT) + { + Com_Printf( S_COLOR_RED "CG_LoadIngameText : mp_ingametext.dat file bigger than %d!\n",MAXINGAMETEXT); + return; + } + + // initialise the data area + memset(ingameText, 0, sizeof(ingameText)); + + trap_FS_Read( ingameText, len, f ); + + trap_FS_FCloseFile( f ); + + + CG_ParseIngameText(); + +} + +/* +================= +CG_LoadObjectivesForMap +================= +*/ +void CG_LoadObjectivesForMap(void) +{ + int len, objnum = 0; + char *token; + char *buf; + fileHandle_t f; + char fileName[MAX_QPATH]; + char fullFileName[MAX_QPATH]; + char objtext[MAX_OBJ_TEXT_LENGTH]; + + COM_StripExtension( cgs.mapname, fileName ); + CG_LanguageFilename( fileName, "efo", fullFileName); + + len = trap_FS_FOpenFile( fullFileName, &f, FS_READ ); + + if ( len > MAX_OBJ_TEXT_LENGTH ) + { + Com_Printf( S_COLOR_RED "CG_LoadObjectivesForMap : %s file bigger than %d!\n", fileName, MAX_OBJ_TEXT_LENGTH ); + return; + } + + trap_FS_Read( objtext, len, f ); + + trap_FS_FCloseFile( f ); + + buf = objtext; + //Now parse out each objective + while ( 1 ) + { + token = COM_ParseExt( &buf, qtrue ); + if ( !token[0] ) { + break; + } + + // Normal objective text + if ( !Q_strncmp( token, "obj", 3 ) ) + { + objnum = atoi( &token[3] ); + + if ( objnum < 1 || objnum == MAX_OBJECTIVES ) { + Com_Printf( "Invalid objective number (%d), valid range is 1 to %d\n", objnum, MAX_OBJECTIVES ); + break; + } + + //Now read the objective text into the current objective + token = COM_ParseExt( &buf, qfalse ); + Q_strncpyz( cgs.objectives[objnum-1].text, token, sizeof(cgs.objectives[objnum-1].text) ); + } + + else if ( !Q_strncmp( token, "abridged_obj", 12 ) ) + { + objnum = atoi( &token[12] ); + + if ( objnum < 1 || objnum == MAX_OBJECTIVES ) + { + Com_Printf( "Invalid objective number (%d), valid range is 1 to %d\n", objnum, MAX_OBJECTIVES ); + break; + } + + //Now read the objective text into the current objective + token = COM_ParseExt( &buf, qfalse ); + Q_strncpyz( cgs.objectives[objnum-1].abridgedText, token, sizeof(cgs.objectives[objnum-1].abridgedText) ); + } + } +} + + diff --git a/code/cgame/cg_marks.c b/code/cgame/cg_marks.c index e29f4c9..0fd06ed 100644 --- a/code/cgame/cg_marks.c +++ b/code/cgame/cg_marks.c @@ -1,24 +1,4 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // // cg_marks.c -- wall marks @@ -36,7 +16,6 @@ MARK POLYS markPoly_t cg_activeMarkPolys; // double linked list markPoly_t *cg_freeMarkPolys; // single linked list markPoly_t cg_markPolys[MAX_MARK_POLYS]; -static int markTotal; /* =================== @@ -65,6 +44,8 @@ CG_FreeMarkPoly ================== */ void CG_FreeMarkPoly( markPoly_t *le ) { + if(!le) return; + if ( !le->prevMark ) { CG_Error( "CG_FreeLocalEntity: not active" ); } @@ -140,18 +121,22 @@ void CG_ImpactMark( qhandle_t markShader, const vec3_t origin, const vec3_t dir, vec3_t markPoints[MAX_MARK_POINTS]; vec3_t projection; +#ifdef _DEBUG + if (!markShader) + { + Com_Printf("CG_ImpactMark: NULL shader\n"); + } +#endif + if ( !cg_addMarks.integer ) { return; } if ( radius <= 0 ) { - CG_Error( "CG_ImpactMark called with <= 0 radius" ); + //CG_Error( "CG_ImpactMark called with <= 0 radius" ); + return; } - //if ( markTotal >= MAX_MARK_POLYS ) { - // return; - //} - // create the texture axis VectorNormalize2( dir, axis[0] ); PerpendicularVector( axis[1], axis[0] ); @@ -217,7 +202,6 @@ void CG_ImpactMark( qhandle_t markShader, const vec3_t origin, const vec3_t dir, mark->color[2] = blue; mark->color[3] = alpha; memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) ); - markTotal++; } } @@ -227,8 +211,9 @@ void CG_ImpactMark( qhandle_t markShader, const vec3_t origin, const vec3_t dir, CG_AddMarks =============== */ -#define MARK_TOTAL_TIME 10000 -#define MARK_FADE_TIME 1000 +#define MARK_TOTAL_TIME 500000 +#define MARK_FADE_TIME 50000 +#define MARK_DIV_3000 1.0/3000.0 void CG_AddMarks( void ) { int j; @@ -255,7 +240,7 @@ void CG_AddMarks( void ) { // fade out the energy bursts if ( mp->markShader == cgs.media.energyMarkShader ) { - fade = 450 - 450 * ( (cg.time - mp->time ) / 3000.0 ); + fade = 450 - 450 * ( (cg.time - mp->time ) * MARK_DIV_3000 ); if ( fade < 255 ) { if ( fade < 0 ) { fade = 0; @@ -291,3 +276,4 @@ void CG_AddMarks( void ) { trap_R_AddPolyToScene( mp->markShader, mp->poly.numVerts, mp->verts ); } } + diff --git a/code/cgame/cg_motionblur.c b/code/cgame/cg_motionblur.c new file mode 100644 index 0000000..40bcd4b --- /dev/null +++ b/code/cgame/cg_motionblur.c @@ -0,0 +1,84 @@ +#include "cg_local.h" + +#define MAX_MOTIONBLURDOTS 20 + +typedef struct motionblurDot_s { + qboolean active; + refEntity_t refEnt; + int startTime; + int lifeTime; +} motionblurDot_t; + +//static motionblurDot_t cg_motionblurDots[MAX_MOTIONBLURDOTS]; + + + +void CG_MotionBlur(void) { + //motionblurDot_t *dot; + //vec3_t pos, axis[3]; + //int i; + + + /*if ( !cg.snap->ps.powerups[PW_BOOST] && cg.snap->ps.timers[tmZanzoken] < 1 && !cg.snap->ps.timers[tmTransform]) { + cg.refdef.rdflags &= ~RDF_MOTIONBLUR; + + + //for ( i = 0; i < MAX_MOTIONBLURDOTS; i++ ) { + // cg_motionblurDots[i].active = qfalse; + //} + + + return; + }*/ + + + cg.refdef.rdflags |= RDF_MOTIONBLUR; + + /* + // Destroy dots over lifetime + for ( i = 0; i < MAX_MOTIONBLURDOTS; i++ ) { + dot = &cg_motionblurDots[i]; + + if ( dot->lifeTime + dot->startTime < cg.time ) { + dot->active = qfalse; + } + } + + // Create new dots + for ( i = 0; i < MAX_MOTIONBLURDOTS; i++ ) { + dot = &cg_motionblurDots[i]; + + if ( dot->active ) + continue; + + VectorCopy( cg.predictedPlayerEntity.lerpOrigin, pos ); + VectorNormalize2( cg.predictedPlayerState.velocity, axis[0] ); + VectorMA( pos, 300, axis[0], pos ); + RotateAroundDirection( axis, crandom() * 360 ); + VectorMA( pos, 120, axis[2], pos ); + + memset( &(dot->refEnt), 0, sizeof(refEntity_t)); + dot->refEnt.reType = RT_SPRITE; + dot->refEnt.radius = 2; + dot->refEnt.customShader = cgs.media.whiteShader; + dot->refEnt.shaderRGBA[0] = 255; + dot->refEnt.shaderRGBA[1] = 255; + dot->refEnt.shaderRGBA[2] = 255; + dot->refEnt.shaderRGBA[3] = 128; + VectorCopy( pos, dot->refEnt.origin ); + + dot->lifeTime = 250 + crandom() * 100; + dot->startTime = cg.time + crandom() * 150; + dot->active = qtrue; + } + + // Render dots + for ( i = 0; i < MAX_MOTIONBLURDOTS; i++ ) { + dot = &cg_motionblurDots[i]; + if ( dot->startTime > cg.time ) + continue; + + trap_R_AddRefEntityToScene( &(dot->refEnt)); + } + */ +} diff --git a/code/cgame/cg_newdraw.c b/code/cgame/cg_newdraw.c deleted file mode 100644 index d0028d6..0000000 --- a/code/cgame/cg_newdraw.c +++ /dev/null @@ -1,1837 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#ifndef MISSIONPACK -#error This file not be used for classic Q3A. -#endif - -#include "cg_local.h" -#include "../ui/ui_shared.h" - -extern displayContextDef_t cgDC; - - -// set in CG_ParseTeamInfo - -//static int sortedTeamPlayers[TEAM_MAXOVERLAY]; -//static int numSortedTeamPlayers; -int drawTeamOverlayModificationCount = -1; - -//static char systemChat[256]; -//static char teamChat1[256]; -//static char teamChat2[256]; - -void CG_InitTeamChat(void) { - memset(teamChat1, 0, sizeof(teamChat1)); - memset(teamChat2, 0, sizeof(teamChat2)); - memset(systemChat, 0, sizeof(systemChat)); -} - -void CG_SetPrintString(int type, const char *p) { - if (type == SYSTEM_PRINT) { - strcpy(systemChat, p); - } else { - strcpy(teamChat2, teamChat1); - strcpy(teamChat1, p); - } -} - -void CG_CheckOrderPending(void) { - if (cgs.gametype < GT_CTF) { - return; - } - if (cgs.orderPending) { - //clientInfo_t *ci = cgs.clientinfo + sortedTeamPlayers[cg_currentSelectedPlayer.integer]; - const char *p1, *p2, *b; - p1 = p2 = b = NULL; - switch (cgs.currentOrder) { - case TEAMTASK_OFFENSE: - p1 = VOICECHAT_ONOFFENSE; - p2 = VOICECHAT_OFFENSE; - b = "+button7; wait; -button7"; - break; - case TEAMTASK_DEFENSE: - p1 = VOICECHAT_ONDEFENSE; - p2 = VOICECHAT_DEFEND; - b = "+button8; wait; -button8"; - break; - case TEAMTASK_PATROL: - p1 = VOICECHAT_ONPATROL; - p2 = VOICECHAT_PATROL; - b = "+button9; wait; -button9"; - break; - case TEAMTASK_FOLLOW: - p1 = VOICECHAT_ONFOLLOW; - p2 = VOICECHAT_FOLLOWME; - b = "+button10; wait; -button10"; - break; - case TEAMTASK_CAMP: - p1 = VOICECHAT_ONCAMPING; - p2 = VOICECHAT_CAMP; - break; - case TEAMTASK_RETRIEVE: - p1 = VOICECHAT_ONGETFLAG; - p2 = VOICECHAT_RETURNFLAG; - break; - case TEAMTASK_ESCORT: - p1 = VOICECHAT_ONFOLLOWCARRIER; - p2 = VOICECHAT_FOLLOWFLAGCARRIER; - break; - } - - if (cg_currentSelectedPlayer.integer == numSortedTeamPlayers) { - // to everyone - trap_SendConsoleCommand(va("cmd vsay_team %s\n", p2)); - } else { - // for the player self - if (sortedTeamPlayers[cg_currentSelectedPlayer.integer] == cg.snap->ps.clientNum && p1) { - trap_SendConsoleCommand(va("teamtask %i\n", cgs.currentOrder)); - //trap_SendConsoleCommand(va("cmd say_team %s\n", p2)); - trap_SendConsoleCommand(va("cmd vsay_team %s\n", p1)); - } else if (p2) { - //trap_SendConsoleCommand(va("cmd say_team %s, %s\n", ci->name,p)); - trap_SendConsoleCommand(va("cmd vtell %d %s\n", sortedTeamPlayers[cg_currentSelectedPlayer.integer], p2)); - } - } - if (b) { - trap_SendConsoleCommand(b); - } - cgs.orderPending = qfalse; - } -} - -static void CG_SetSelectedPlayerName( void ) { - if (cg_currentSelectedPlayer.integer >= 0 && cg_currentSelectedPlayer.integer < numSortedTeamPlayers) { - clientInfo_t *ci = cgs.clientinfo + sortedTeamPlayers[cg_currentSelectedPlayer.integer]; - if (ci) { - trap_Cvar_Set("cg_selectedPlayerName", ci->name); - trap_Cvar_Set("cg_selectedPlayer", va("%d", sortedTeamPlayers[cg_currentSelectedPlayer.integer])); - cgs.currentOrder = ci->teamTask; - } - } else { - trap_Cvar_Set("cg_selectedPlayerName", "Everyone"); - } -} -int CG_GetSelectedPlayer( void ) { - if (cg_currentSelectedPlayer.integer < 0 || cg_currentSelectedPlayer.integer >= numSortedTeamPlayers) { - cg_currentSelectedPlayer.integer = 0; - } - return cg_currentSelectedPlayer.integer; -} - -void CG_SelectNextPlayer( void ) { - CG_CheckOrderPending(); - if (cg_currentSelectedPlayer.integer >= 0 && cg_currentSelectedPlayer.integer < numSortedTeamPlayers) { - cg_currentSelectedPlayer.integer++; - } else { - cg_currentSelectedPlayer.integer = 0; - } - CG_SetSelectedPlayerName(); -} - -void CG_SelectPrevPlayer( void ) { - CG_CheckOrderPending(); - if (cg_currentSelectedPlayer.integer > 0 && cg_currentSelectedPlayer.integer < numSortedTeamPlayers) { - cg_currentSelectedPlayer.integer--; - } else { - cg_currentSelectedPlayer.integer = numSortedTeamPlayers; - } - CG_SetSelectedPlayerName(); -} - - -static void CG_DrawPlayerArmorIcon( rectDef_t *rect, qboolean draw2D ) { - vec3_t angles; - vec3_t origin; - - if ( cg_drawStatus.integer == 0 ) { - return; - } - - if ( draw2D || ( !cg_draw3dIcons.integer && cg_drawIcons.integer) ) { - CG_DrawPic( rect->x, rect->y + rect->h/2 + 1, rect->w, rect->h, cgs.media.armorIcon ); - } else if (cg_draw3dIcons.integer) { - VectorClear( angles ); - origin[0] = 90; - origin[1] = 0; - origin[2] = -10; - angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0f; - CG_Draw3DModel( rect->x, rect->y, rect->w, rect->h, cgs.media.armorModel, 0, origin, angles ); - } -} - -static void CG_DrawPlayerArmorValue(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) { - char num[16]; - int value; - playerState_t *ps; - - ps = &cg.snap->ps; - - value = ps->stats[STAT_ARMOR]; - - if (shader) { - trap_R_SetColor( color ); - CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader); - trap_R_SetColor( NULL ); - } else { - Com_sprintf (num, sizeof(num), "%i", value); - value = CG_Text_Width(num, scale, 0); - CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle); - } -} - -#ifndef MISSIONPACK -static float healthColors[4][4] = { -// { 0.2, 1.0, 0.2, 1.0 } , { 1.0, 0.2, 0.2, 1.0 }, {0.5, 0.5, 0.5, 1} }; - { 1.0f, 0.69f, 0.0f, 1.0f } , // normal - { 1.0f, 0.2f, 0.2f, 1.0f }, // low health - { 0.5f, 0.5f, 0.5f, 1.0f}, // weapon firing - { 1.0f, 1.0f, 1.0f, 1.0f } }; // health > 100 -#endif - -static void CG_DrawPlayerAmmoIcon( rectDef_t *rect, qboolean draw2D ) { - centity_t *cent; - vec3_t angles; - vec3_t origin; - - cent = &cg_entities[cg.snap->ps.clientNum]; - - if ( draw2D || (!cg_draw3dIcons.integer && cg_drawIcons.integer) ) { - qhandle_t icon; - icon = cg_weapons[ cg.predictedPlayerState.weapon ].ammoIcon; - if ( icon ) { - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, icon ); - } - } else if (cg_draw3dIcons.integer) { - if ( cent->currentState.weapon && cg_weapons[ cent->currentState.weapon ].ammoModel ) { - VectorClear( angles ); - origin[0] = 70; - origin[1] = 0; - origin[2] = 0; - angles[YAW] = 90 + 20 * sin( cg.time / 1000.0 ); - CG_Draw3DModel( rect->x, rect->y, rect->w, rect->h, cg_weapons[ cent->currentState.weapon ].ammoModel, 0, origin, angles ); - } - } -} - -static void CG_DrawPlayerAmmoValue(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) { - char num[16]; - int value; - centity_t *cent; - playerState_t *ps; - - cent = &cg_entities[cg.snap->ps.clientNum]; - ps = &cg.snap->ps; - - if ( cent->currentState.weapon ) { - value = ps->ammo[cent->currentState.weapon]; - if ( value > -1 ) { - if (shader) { - trap_R_SetColor( color ); - CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader); - trap_R_SetColor( NULL ); - } else { - Com_sprintf (num, sizeof(num), "%i", value); - value = CG_Text_Width(num, scale, 0); - CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle); - } - } - } - -} - - - -static void CG_DrawPlayerHead(rectDef_t *rect, qboolean draw2D) { - vec3_t angles; - float size, stretch; - float frac; - float x = rect->x; - - VectorClear( angles ); - - if ( cg.damageTime && cg.time - cg.damageTime < DAMAGE_TIME ) { - frac = (float)(cg.time - cg.damageTime ) / DAMAGE_TIME; - size = rect->w * 1.25 * ( 1.5 - frac * 0.5 ); - - stretch = size - rect->w * 1.25; - // kick in the direction of damage - x -= stretch * 0.5 + cg.damageX * stretch * 0.5; - - cg.headStartYaw = 180 + cg.damageX * 45; - - cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI ); - cg.headEndPitch = 5 * cos( crandom()*M_PI ); - - cg.headStartTime = cg.time; - cg.headEndTime = cg.time + 100 + random() * 2000; - } else { - if ( cg.time >= cg.headEndTime ) { - // select a new head angle - cg.headStartYaw = cg.headEndYaw; - cg.headStartPitch = cg.headEndPitch; - cg.headStartTime = cg.headEndTime; - cg.headEndTime = cg.time + 100 + random() * 2000; - - cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI ); - cg.headEndPitch = 5 * cos( crandom()*M_PI ); - } - - size = rect->w * 1.25; - } - - // if the server was frozen for a while we may have a bad head start time - if ( cg.headStartTime > cg.time ) { - cg.headStartTime = cg.time; - } - - frac = ( cg.time - cg.headStartTime ) / (float)( cg.headEndTime - cg.headStartTime ); - frac = frac * frac * ( 3 - 2 * frac ); - angles[YAW] = cg.headStartYaw + ( cg.headEndYaw - cg.headStartYaw ) * frac; - angles[PITCH] = cg.headStartPitch + ( cg.headEndPitch - cg.headStartPitch ) * frac; - - CG_DrawHead( x, rect->y, rect->w, rect->h, cg.snap->ps.clientNum, angles ); -} - -static void CG_DrawSelectedPlayerHealth( rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) { - clientInfo_t *ci; - int value; - char num[16]; - - ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()]; - if (ci) { - if (shader) { - trap_R_SetColor( color ); - CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader); - trap_R_SetColor( NULL ); - } else { - Com_sprintf (num, sizeof(num), "%i", ci->health); - value = CG_Text_Width(num, scale, 0); - CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle); - } - } -} - -static void CG_DrawSelectedPlayerArmor( rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) { - clientInfo_t *ci; - int value; - char num[16]; - ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()]; - if (ci) { - if (ci->armor > 0) { - if (shader) { - trap_R_SetColor( color ); - CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader); - trap_R_SetColor( NULL ); - } else { - Com_sprintf (num, sizeof(num), "%i", ci->armor); - value = CG_Text_Width(num, scale, 0); - CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle); - } - } - } -} - -qhandle_t CG_StatusHandle(int task) { - qhandle_t h; - switch (task) { - case TEAMTASK_OFFENSE : - h = cgs.media.assaultShader; - break; - case TEAMTASK_DEFENSE : - h = cgs.media.defendShader; - break; - case TEAMTASK_PATROL : - h = cgs.media.patrolShader; - break; - case TEAMTASK_FOLLOW : - h = cgs.media.followShader; - break; - case TEAMTASK_CAMP : - h = cgs.media.campShader; - break; - case TEAMTASK_RETRIEVE : - h = cgs.media.retrieveShader; - break; - case TEAMTASK_ESCORT : - h = cgs.media.escortShader; - break; - default : - h = cgs.media.assaultShader; - break; - } - return h; -} - -static void CG_DrawSelectedPlayerStatus( rectDef_t *rect ) { - clientInfo_t *ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()]; - if (ci) { - qhandle_t h; - if (cgs.orderPending) { - // blink the icon - if ( cg.time > cgs.orderTime - 2500 && (cg.time >> 9 ) & 1 ) { - return; - } - h = CG_StatusHandle(cgs.currentOrder); - } else { - h = CG_StatusHandle(ci->teamTask); - } - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, h ); - } -} - - -static void CG_DrawPlayerStatus( rectDef_t *rect ) { - clientInfo_t *ci = &cgs.clientinfo[cg.snap->ps.clientNum]; - if (ci) { - qhandle_t h = CG_StatusHandle(ci->teamTask); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, h); - } -} - - -static void CG_DrawSelectedPlayerName( rectDef_t *rect, float scale, vec4_t color, qboolean voice, int textStyle) { - clientInfo_t *ci; - ci = cgs.clientinfo + ((voice) ? cgs.currentVoiceClient : sortedTeamPlayers[CG_GetSelectedPlayer()]); - if (ci) { - CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, ci->name, 0, 0, textStyle); - } -} - -static void CG_DrawSelectedPlayerLocation( rectDef_t *rect, float scale, vec4_t color, int textStyle ) { - clientInfo_t *ci; - ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()]; - if (ci) { - const char *p = CG_ConfigString(CS_LOCATIONS + ci->location); - if (!p || !*p) { - p = "unknown"; - } - CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, p, 0, 0, textStyle); - } -} - -static void CG_DrawPlayerLocation( rectDef_t *rect, float scale, vec4_t color, int textStyle ) { - clientInfo_t *ci = &cgs.clientinfo[cg.snap->ps.clientNum]; - if (ci) { - const char *p = CG_ConfigString(CS_LOCATIONS + ci->location); - if (!p || !*p) { - p = "unknown"; - } - CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, p, 0, 0, textStyle); - } -} - - - -static void CG_DrawSelectedPlayerWeapon( rectDef_t *rect ) { - clientInfo_t *ci; - - ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()]; - if (ci) { - if ( cg_weapons[ci->curWeapon].weaponIcon ) { - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cg_weapons[ci->curWeapon].weaponIcon ); - } else { - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.deferShader); - } - } -} - -static void CG_DrawPlayerScore( rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) { - char num[16]; - int value = cg.snap->ps.persistant[PERS_SCORE]; - - if (shader) { - trap_R_SetColor( color ); - CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader); - trap_R_SetColor( NULL ); - } else { - Com_sprintf (num, sizeof(num), "%i", value); - value = CG_Text_Width(num, scale, 0); - CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle); - } -} - -static void CG_DrawPlayerItem( rectDef_t *rect, float scale, qboolean draw2D) { - int value; - vec3_t origin, angles; - - value = cg.snap->ps.stats[STAT_HOLDABLE_ITEM]; - if ( value ) { - CG_RegisterItemVisuals( value ); - - if (qtrue) { - CG_RegisterItemVisuals( value ); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cg_items[ value ].icon ); - } else { - VectorClear( angles ); - origin[0] = 90; - origin[1] = 0; - origin[2] = -10; - angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0; - CG_Draw3DModel(rect->x, rect->y, rect->w, rect->h, cg_items[ value ].models[0], 0, origin, angles ); - } - } - -} - - -static void CG_DrawSelectedPlayerPowerup( rectDef_t *rect, qboolean draw2D ) { - clientInfo_t *ci; - int j; - float x, y; - - ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()]; - if (ci) { - x = rect->x; - y = rect->y; - - for (j = 0; j < PW_NUM_POWERUPS; j++) { - if (ci->powerups & (1 << j)) { - gitem_t *item; - item = BG_FindItemForPowerup( j ); - if (item) { - CG_DrawPic( x, y, rect->w, rect->h, trap_R_RegisterShader( item->icon ) ); - x += 3; - y += 3; - return; - } - } - } - - } -} - - -static void CG_DrawSelectedPlayerHead( rectDef_t *rect, qboolean draw2D, qboolean voice ) { - clipHandle_t cm; - clientInfo_t *ci; - float len; - vec3_t origin; - vec3_t mins, maxs, angles; - - - ci = cgs.clientinfo + ((voice) ? cgs.currentVoiceClient : sortedTeamPlayers[CG_GetSelectedPlayer()]); - - if (ci) { - if ( cg_draw3dIcons.integer ) { - cm = ci->headModel; - if ( !cm ) { - return; - } - - // offset the origin y and z to center the head - trap_R_ModelBounds( cm, mins, maxs ); - - origin[2] = -0.5 * ( mins[2] + maxs[2] ); - origin[1] = 0.5 * ( mins[1] + maxs[1] ); - - // calculate distance so the head nearly fills the box - // assume heads are taller than wide - len = 0.7 * ( maxs[2] - mins[2] ); - origin[0] = len / 0.268; // len / tan( fov/2 ) - - // allow per-model tweaking - VectorAdd( origin, ci->headOffset, origin ); - - angles[PITCH] = 0; - angles[YAW] = 180; - angles[ROLL] = 0; - - CG_Draw3DModel( rect->x, rect->y, rect->w, rect->h, ci->headModel, ci->headSkin, origin, angles ); - } else if ( cg_drawIcons.integer ) { - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, ci->modelIcon ); - } - - // if they are deferred, draw a cross out - if ( ci->deferred ) { - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.deferShader ); - } - } - -} - - -static void CG_DrawPlayerHealth(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) { - playerState_t *ps; - int value; - char num[16]; - - ps = &cg.snap->ps; - - value = ps->stats[STAT_HEALTH]; - - if (shader) { - trap_R_SetColor( color ); - CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader); - trap_R_SetColor( NULL ); - } else { - Com_sprintf (num, sizeof(num), "%i", value); - value = CG_Text_Width(num, scale, 0); - CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle); - } -} - - -static void CG_DrawRedScore(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) { - int value; - char num[16]; - if ( cgs.scores1 == SCORE_NOT_PRESENT ) { - Com_sprintf (num, sizeof(num), "-"); - } - else { - Com_sprintf (num, sizeof(num), "%i", cgs.scores1); - } - value = CG_Text_Width(num, scale, 0); - CG_Text_Paint(rect->x + rect->w - value, rect->y + rect->h, scale, color, num, 0, 0, textStyle); -} - -static void CG_DrawBlueScore(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) { - int value; - char num[16]; - - if ( cgs.scores2 == SCORE_NOT_PRESENT ) { - Com_sprintf (num, sizeof(num), "-"); - } - else { - Com_sprintf (num, sizeof(num), "%i", cgs.scores2); - } - value = CG_Text_Width(num, scale, 0); - CG_Text_Paint(rect->x + rect->w - value, rect->y + rect->h, scale, color, num, 0, 0, textStyle); -} - -// FIXME: team name support -static void CG_DrawRedName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) { - CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cg_redTeamName.string , 0, 0, textStyle); -} - -static void CG_DrawBlueName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) { - CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cg_blueTeamName.string, 0, 0, textStyle); -} - -static void CG_DrawBlueFlagName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) { - int i; - for ( i = 0 ; i < cgs.maxclients ; i++ ) { - if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_RED && cgs.clientinfo[i].powerups & ( 1<< PW_BLUEFLAG )) { - CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cgs.clientinfo[i].name, 0, 0, textStyle); - return; - } - } -} - -static void CG_DrawBlueFlagStatus(rectDef_t *rect, qhandle_t shader) { - if (cgs.gametype != GT_CTF && cgs.gametype != GT_1FCTF) { - if (cgs.gametype == GT_HARVESTER) { - vec4_t color = {0, 0, 1, 1}; - trap_R_SetColor(color); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.blueCubeIcon ); - trap_R_SetColor(NULL); - } - return; - } - if (shader) { - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader ); - } else { - gitem_t *item = BG_FindItemForPowerup( PW_BLUEFLAG ); - if (item) { - vec4_t color = {0, 0, 1, 1}; - trap_R_SetColor(color); - if( cgs.blueflag >= 0 && cgs.blueflag <= 2 ) { - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[cgs.blueflag] ); - } else { - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[0] ); - } - trap_R_SetColor(NULL); - } - } -} - -static void CG_DrawBlueFlagHead(rectDef_t *rect) { - int i; - for ( i = 0 ; i < cgs.maxclients ; i++ ) { - if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_RED && cgs.clientinfo[i].powerups & ( 1<< PW_BLUEFLAG )) { - vec3_t angles; - VectorClear( angles ); - angles[YAW] = 180 + 20 * sin( cg.time / 650.0 );; - CG_DrawHead( rect->x, rect->y, rect->w, rect->h, 0,angles ); - return; - } - } -} - -static void CG_DrawRedFlagName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) { - int i; - for ( i = 0 ; i < cgs.maxclients ; i++ ) { - if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_BLUE && cgs.clientinfo[i].powerups & ( 1<< PW_REDFLAG )) { - CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cgs.clientinfo[i].name, 0, 0, textStyle); - return; - } - } -} - -static void CG_DrawRedFlagStatus(rectDef_t *rect, qhandle_t shader) { - if (cgs.gametype != GT_CTF && cgs.gametype != GT_1FCTF) { - if (cgs.gametype == GT_HARVESTER) { - vec4_t color = {1, 0, 0, 1}; - trap_R_SetColor(color); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.redCubeIcon ); - trap_R_SetColor(NULL); - } - return; - } - if (shader) { - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader ); - } else { - gitem_t *item = BG_FindItemForPowerup( PW_REDFLAG ); - if (item) { - vec4_t color = {1, 0, 0, 1}; - trap_R_SetColor(color); - if( cgs.redflag >= 0 && cgs.redflag <= 2) { - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[cgs.redflag] ); - } else { - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[0] ); - } - trap_R_SetColor(NULL); - } - } -} - -static void CG_DrawRedFlagHead(rectDef_t *rect) { - int i; - for ( i = 0 ; i < cgs.maxclients ; i++ ) { - if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_BLUE && cgs.clientinfo[i].powerups & ( 1<< PW_REDFLAG )) { - vec3_t angles; - VectorClear( angles ); - angles[YAW] = 180 + 20 * sin( cg.time / 650.0 );; - CG_DrawHead( rect->x, rect->y, rect->w, rect->h, 0,angles ); - return; - } - } -} - -static void CG_HarvesterSkulls(rectDef_t *rect, float scale, vec4_t color, qboolean force2D, int textStyle ) { - char num[16]; - vec3_t origin, angles; - qhandle_t handle; - int value = cg.snap->ps.generic1; - - if (cgs.gametype != GT_HARVESTER) { - return; - } - - if( value > 99 ) { - value = 99; - } - - Com_sprintf (num, sizeof(num), "%i", value); - value = CG_Text_Width(num, scale, 0); - CG_Text_Paint(rect->x + (rect->w - value), rect->y + rect->h, scale, color, num, 0, 0, textStyle); - - if (cg_drawIcons.integer) { - if (!force2D && cg_draw3dIcons.integer) { - VectorClear(angles); - origin[0] = 90; - origin[1] = 0; - origin[2] = -10; - angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0; - if( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) { - handle = cgs.media.redCubeModel; - } else { - handle = cgs.media.blueCubeModel; - } - CG_Draw3DModel( rect->x, rect->y, 35, 35, handle, 0, origin, angles ); - } else { - if( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) { - handle = cgs.media.redCubeIcon; - } else { - handle = cgs.media.blueCubeIcon; - } - CG_DrawPic( rect->x + 3, rect->y + 16, 20, 20, handle ); - } - } -} - -static void CG_OneFlagStatus(rectDef_t *rect) { - if (cgs.gametype != GT_1FCTF) { - return; - } else { - gitem_t *item = BG_FindItemForPowerup( PW_NEUTRALFLAG ); - if (item) { - if( cgs.flagStatus >= 0 && cgs.flagStatus <= 4 ) { - vec4_t color = {1, 1, 1, 1}; - int index = 0; - if (cgs.flagStatus == FLAG_TAKEN_RED) { - color[1] = color[2] = 0; - index = 1; - } else if (cgs.flagStatus == FLAG_TAKEN_BLUE) { - color[0] = color[1] = 0; - index = 1; - } else if (cgs.flagStatus == FLAG_DROPPED) { - index = 2; - } - trap_R_SetColor(color); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[index] ); - } - } - } -} - - -static void CG_DrawCTFPowerUp(rectDef_t *rect) { - int value; - - if (cgs.gametype < GT_CTF) { - return; - } - value = cg.snap->ps.stats[STAT_PERSISTANT_POWERUP]; - if ( value ) { - CG_RegisterItemVisuals( value ); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cg_items[ value ].icon ); - } -} - - - -static void CG_DrawTeamColor(rectDef_t *rect, vec4_t color) { - CG_DrawTeamBackground(rect->x, rect->y, rect->w, rect->h, color[3], cg.snap->ps.persistant[PERS_TEAM]); -} - -static void CG_DrawAreaPowerUp(rectDef_t *rect, int align, float special, float scale, vec4_t color) { - char num[16]; - int sorted[MAX_POWERUPS]; - int sortedTime[MAX_POWERUPS]; - int i, j, k; - int active; - playerState_t *ps; - int t; - gitem_t *item; - float f; - rectDef_t r2; - float *inc; - r2.x = rect->x; - r2.y = rect->y; - r2.w = rect->w; - r2.h = rect->h; - - inc = (align == HUD_VERTICAL) ? &r2.y : &r2.x; - - ps = &cg.snap->ps; - - if ( ps->stats[STAT_HEALTH] <= 0 ) { - return; - } - - // sort the list by time remaining - active = 0; - for ( i = 0 ; i < MAX_POWERUPS ; i++ ) { - if ( !ps->powerups[ i ] ) { - continue; - } - t = ps->powerups[ i ] - cg.time; - // ZOID--don't draw if the power up has unlimited time (999 seconds) - // This is true of the CTF flags - if ( t <= 0 || t >= 999000) { - continue; - } - - // insert into the list - for ( j = 0 ; j < active ; j++ ) { - if ( sortedTime[j] >= t ) { - for ( k = active - 1 ; k >= j ; k-- ) { - sorted[k+1] = sorted[k]; - sortedTime[k+1] = sortedTime[k]; - } - break; - } - } - sorted[j] = i; - sortedTime[j] = t; - active++; - } - - // draw the icons and timers - for ( i = 0 ; i < active ; i++ ) { - item = BG_FindItemForPowerup( sorted[i] ); - - if (item) { - t = ps->powerups[ sorted[i] ]; - if ( t - cg.time >= POWERUP_BLINKS * POWERUP_BLINK_TIME ) { - trap_R_SetColor( NULL ); - } else { - vec4_t modulate; - - f = (float)( t - cg.time ) / POWERUP_BLINK_TIME; - f -= (int)f; - modulate[0] = modulate[1] = modulate[2] = modulate[3] = f; - trap_R_SetColor( modulate ); - } - - CG_DrawPic( r2.x, r2.y, r2.w * .75, r2.h, trap_R_RegisterShader( item->icon ) ); - - Com_sprintf (num, sizeof(num), "%i", sortedTime[i] / 1000); - CG_Text_Paint(r2.x + (r2.w * .75) + 3 , r2.y + r2.h, scale, color, num, 0, 0, 0); - *inc += r2.w + special; - } - - } - trap_R_SetColor( NULL ); - -} - -float CG_GetValue(int ownerDraw) { - centity_t *cent; - clientInfo_t *ci; - playerState_t *ps; - - cent = &cg_entities[cg.snap->ps.clientNum]; - ps = &cg.snap->ps; - - switch (ownerDraw) { - case CG_SELECTEDPLAYER_ARMOR: - ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()]; - return ci->armor; - break; - case CG_SELECTEDPLAYER_HEALTH: - ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()]; - return ci->health; - break; - case CG_PLAYER_ARMOR_VALUE: - return ps->stats[STAT_ARMOR]; - break; - case CG_PLAYER_AMMO_VALUE: - if ( cent->currentState.weapon ) { - return ps->ammo[cent->currentState.weapon]; - } - break; - case CG_PLAYER_SCORE: - return cg.snap->ps.persistant[PERS_SCORE]; - break; - case CG_PLAYER_HEALTH: - return ps->stats[STAT_HEALTH]; - break; - case CG_RED_SCORE: - return cgs.scores1; - break; - case CG_BLUE_SCORE: - return cgs.scores2; - break; - default: - break; - } - return -1; -} - -qboolean CG_OtherTeamHasFlag(void) { - if (cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF) { - int team = cg.snap->ps.persistant[PERS_TEAM]; - if (cgs.gametype == GT_1FCTF) { - if (team == TEAM_RED && cgs.flagStatus == FLAG_TAKEN_BLUE) { - return qtrue; - } else if (team == TEAM_BLUE && cgs.flagStatus == FLAG_TAKEN_RED) { - return qtrue; - } else { - return qfalse; - } - } else { - if (team == TEAM_RED && cgs.redflag == FLAG_TAKEN) { - return qtrue; - } else if (team == TEAM_BLUE && cgs.blueflag == FLAG_TAKEN) { - return qtrue; - } else { - return qfalse; - } - } - } - return qfalse; -} - -qboolean CG_YourTeamHasFlag(void) { - if (cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF) { - int team = cg.snap->ps.persistant[PERS_TEAM]; - if (cgs.gametype == GT_1FCTF) { - if (team == TEAM_RED && cgs.flagStatus == FLAG_TAKEN_RED) { - return qtrue; - } else if (team == TEAM_BLUE && cgs.flagStatus == FLAG_TAKEN_BLUE) { - return qtrue; - } else { - return qfalse; - } - } else { - if (team == TEAM_RED && cgs.blueflag == FLAG_TAKEN) { - return qtrue; - } else if (team == TEAM_BLUE && cgs.redflag == FLAG_TAKEN) { - return qtrue; - } else { - return qfalse; - } - } - } - return qfalse; -} - -// THINKABOUTME: should these be exclusive or inclusive.. -// -qboolean CG_OwnerDrawVisible(int flags) { - - if (flags & CG_SHOW_TEAMINFO) { - return (cg_currentSelectedPlayer.integer == numSortedTeamPlayers); - } - - if (flags & CG_SHOW_NOTEAMINFO) { - return !(cg_currentSelectedPlayer.integer == numSortedTeamPlayers); - } - - if (flags & CG_SHOW_OTHERTEAMHASFLAG) { - return CG_OtherTeamHasFlag(); - } - - if (flags & CG_SHOW_YOURTEAMHASENEMYFLAG) { - return CG_YourTeamHasFlag(); - } - - if (flags & (CG_SHOW_BLUE_TEAM_HAS_REDFLAG | CG_SHOW_RED_TEAM_HAS_BLUEFLAG)) { - if (flags & CG_SHOW_BLUE_TEAM_HAS_REDFLAG && (cgs.redflag == FLAG_TAKEN || cgs.flagStatus == FLAG_TAKEN_RED)) { - return qtrue; - } else if (flags & CG_SHOW_RED_TEAM_HAS_BLUEFLAG && (cgs.blueflag == FLAG_TAKEN || cgs.flagStatus == FLAG_TAKEN_BLUE)) { - return qtrue; - } - return qfalse; - } - - if (flags & CG_SHOW_ANYTEAMGAME) { - if( cgs.gametype >= GT_TEAM) { - return qtrue; - } - } - - if (flags & CG_SHOW_ANYNONTEAMGAME) { - if( cgs.gametype < GT_TEAM) { - return qtrue; - } - } - - if (flags & CG_SHOW_HARVESTER) { - if( cgs.gametype == GT_HARVESTER ) { - return qtrue; - } else { - return qfalse; - } - } - - if (flags & CG_SHOW_ONEFLAG) { - if( cgs.gametype == GT_1FCTF ) { - return qtrue; - } else { - return qfalse; - } - } - - if (flags & CG_SHOW_CTF) { - if( cgs.gametype == GT_CTF ) { - return qtrue; - } - } - - if (flags & CG_SHOW_OBELISK) { - if( cgs.gametype == GT_OBELISK ) { - return qtrue; - } else { - return qfalse; - } - } - - if (flags & CG_SHOW_HEALTHCRITICAL) { - if (cg.snap->ps.stats[STAT_HEALTH] < 25) { - return qtrue; - } - } - - if (flags & CG_SHOW_HEALTHOK) { - if (cg.snap->ps.stats[STAT_HEALTH] >= 25) { - return qtrue; - } - } - - if (flags & CG_SHOW_SINGLEPLAYER) { - if( cgs.gametype == GT_SINGLE_PLAYER ) { - return qtrue; - } - } - - if (flags & CG_SHOW_TOURNAMENT) { - if( cgs.gametype == GT_TOURNAMENT ) { - return qtrue; - } - } - - if (flags & CG_SHOW_DURINGINCOMINGVOICE) { - } - - if (flags & CG_SHOW_IF_PLAYER_HAS_FLAG) { - if (cg.snap->ps.powerups[PW_REDFLAG] || cg.snap->ps.powerups[PW_BLUEFLAG] || cg.snap->ps.powerups[PW_NEUTRALFLAG]) { - return qtrue; - } - } - return qfalse; -} - - - -static void CG_DrawPlayerHasFlag(rectDef_t *rect, qboolean force2D) { - int adj = (force2D) ? 0 : 2; - if( cg.predictedPlayerState.powerups[PW_REDFLAG] ) { - CG_DrawFlagModel( rect->x + adj, rect->y + adj, rect->w - adj, rect->h - adj, TEAM_RED, force2D); - } else if( cg.predictedPlayerState.powerups[PW_BLUEFLAG] ) { - CG_DrawFlagModel( rect->x + adj, rect->y + adj, rect->w - adj, rect->h - adj, TEAM_BLUE, force2D); - } else if( cg.predictedPlayerState.powerups[PW_NEUTRALFLAG] ) { - CG_DrawFlagModel( rect->x + adj, rect->y + adj, rect->w - adj, rect->h - adj, TEAM_FREE, force2D); - } -} - -static void CG_DrawAreaSystemChat(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) { - CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, systemChat, 0, 0, 0); -} - -static void CG_DrawAreaTeamChat(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) { - CG_Text_Paint(rect->x, rect->y + rect->h, scale, color,teamChat1, 0, 0, 0); -} - -static void CG_DrawAreaChat(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) { - CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, teamChat2, 0, 0, 0); -} - -const char *CG_GetKillerText(void) { - const char *s = ""; - if ( cg.killerName[0] ) { - s = va("Fragged by %s", cg.killerName ); - } - return s; -} - - -static void CG_DrawKiller(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) { - // fragged by ... line - if ( cg.killerName[0] ) { - int x = rect->x + rect->w / 2; - CG_Text_Paint(x - CG_Text_Width(CG_GetKillerText(), scale, 0) / 2, rect->y + rect->h, scale, color, CG_GetKillerText(), 0, 0, textStyle); - } - -} - - -static void CG_DrawCapFragLimit(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) { - int limit = (cgs.gametype >= GT_CTF) ? cgs.capturelimit : cgs.fraglimit; - CG_Text_Paint(rect->x, rect->y, scale, color, va("%2i", limit),0, 0, textStyle); -} - -static void CG_Draw1stPlace(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) { - if (cgs.scores1 != SCORE_NOT_PRESENT) { - CG_Text_Paint(rect->x, rect->y, scale, color, va("%2i", cgs.scores1),0, 0, textStyle); - } -} - -static void CG_Draw2ndPlace(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) { - if (cgs.scores2 != SCORE_NOT_PRESENT) { - CG_Text_Paint(rect->x, rect->y, scale, color, va("%2i", cgs.scores2),0, 0, textStyle); - } -} - -const char *CG_GetGameStatusText(void) { - const char *s = ""; - if ( cgs.gametype < GT_TEAM) { - if (cg.snap->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR ) { - s = va("%s place with %i",CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ),cg.snap->ps.persistant[PERS_SCORE] ); - } - } else { - if ( cg.teamScores[0] == cg.teamScores[1] ) { - s = va("Teams are tied at %i", cg.teamScores[0] ); - } else if ( cg.teamScores[0] >= cg.teamScores[1] ) { - s = va("Red leads Blue, %i to %i", cg.teamScores[0], cg.teamScores[1] ); - } else { - s = va("Blue leads Red, %i to %i", cg.teamScores[1], cg.teamScores[0] ); - } - } - return s; -} - -static void CG_DrawGameStatus(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) { - CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, CG_GetGameStatusText(), 0, 0, textStyle); -} - -const char *CG_GameTypeString(void) { - if ( cgs.gametype == GT_FFA ) { - return "Free For All"; - } else if ( cgs.gametype == GT_TEAM ) { - return "Team Deathmatch"; - } else if ( cgs.gametype == GT_CTF ) { - return "Capture the Flag"; - } else if ( cgs.gametype == GT_1FCTF ) { - return "One Flag CTF"; - } else if ( cgs.gametype == GT_OBELISK ) { - return "Overload"; - } else if ( cgs.gametype == GT_HARVESTER ) { - return "Harvester"; - } - return ""; -} -static void CG_DrawGameType(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) { - CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, CG_GameTypeString(), 0, 0, textStyle); -} - -static void CG_Text_Paint_Limit(float *maxX, float x, float y, float scale, vec4_t color, const char* text, float adjust, int limit) { - int len, count; - vec4_t newColor; - glyphInfo_t *glyph; - if (text) { - const char *s = text; - float max = *maxX; - float useScale; - fontInfo_t *font = &cgDC.Assets.textFont; - if (scale <= cg_smallFont.value) { - font = &cgDC.Assets.smallFont; - } else if (scale > cg_bigFont.value) { - font = &cgDC.Assets.bigFont; - } - useScale = scale * font->glyphScale; - trap_R_SetColor( color ); - len = strlen(text); - if (limit > 0 && len > limit) { - len = limit; - } - count = 0; - while (s && *s && count < len) { - glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build - if ( Q_IsColorString( s ) ) { - memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) ); - newColor[3] = color[3]; - trap_R_SetColor( newColor ); - s += 2; - continue; - } else { - float yadj = useScale * glyph->top; - if (CG_Text_Width(s, useScale, 1) + x > max) { - *maxX = 0; - break; - } - CG_Text_PaintChar(x, y - yadj, - glyph->imageWidth, - glyph->imageHeight, - useScale, - glyph->s, - glyph->t, - glyph->s2, - glyph->t2, - glyph->glyph); - x += (glyph->xSkip * useScale) + adjust; - *maxX = x; - count++; - s++; - } - } - trap_R_SetColor( NULL ); - } - -} - - - -#define PIC_WIDTH 12 - -void CG_DrawNewTeamInfo(rectDef_t *rect, float text_x, float text_y, float scale, vec4_t color, qhandle_t shader) { - int xx; - float y; - int i, j, len, count; - const char *p; - vec4_t hcolor; - float pwidth, lwidth, maxx, leftOver; - clientInfo_t *ci; - gitem_t *item; - qhandle_t h; - - // max player name width - pwidth = 0; - count = (numSortedTeamPlayers > 8) ? 8 : numSortedTeamPlayers; - for (i = 0; i < count; i++) { - ci = cgs.clientinfo + sortedTeamPlayers[i]; - if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) { - len = CG_Text_Width( ci->name, scale, 0); - if (len > pwidth) - pwidth = len; - } - } - - // max location name width - lwidth = 0; - for (i = 1; i < MAX_LOCATIONS; i++) { - p = CG_ConfigString(CS_LOCATIONS + i); - if (p && *p) { - len = CG_Text_Width(p, scale, 0); - if (len > lwidth) - lwidth = len; - } - } - - y = rect->y; - - for (i = 0; i < count; i++) { - ci = cgs.clientinfo + sortedTeamPlayers[i]; - if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) { - - xx = rect->x + 1; - for (j = 0; j <= PW_NUM_POWERUPS; j++) { - if (ci->powerups & (1 << j)) { - - item = BG_FindItemForPowerup( j ); - - if (item) { - CG_DrawPic( xx, y, PIC_WIDTH, PIC_WIDTH, trap_R_RegisterShader( item->icon ) ); - xx += PIC_WIDTH; - } - } - } - - // FIXME: max of 3 powerups shown properly - xx = rect->x + (PIC_WIDTH * 3) + 2; - - CG_GetColorForHealth( ci->health, ci->armor, hcolor ); - trap_R_SetColor(hcolor); - CG_DrawPic( xx, y + 1, PIC_WIDTH - 2, PIC_WIDTH - 2, cgs.media.heartShader ); - - //Com_sprintf (st, sizeof(st), "%3i %3i", ci->health, ci->armor); - //CG_Text_Paint(xx, y + text_y, scale, hcolor, st, 0, 0); - - // draw weapon icon - xx += PIC_WIDTH + 1; - -// weapon used is not that useful, use the space for task -#if 0 - if ( cg_weapons[ci->curWeapon].weaponIcon ) { - CG_DrawPic( xx, y, PIC_WIDTH, PIC_WIDTH, cg_weapons[ci->curWeapon].weaponIcon ); - } else { - CG_DrawPic( xx, y, PIC_WIDTH, PIC_WIDTH, cgs.media.deferShader ); - } -#endif - - trap_R_SetColor(NULL); - if (cgs.orderPending) { - // blink the icon - if ( cg.time > cgs.orderTime - 2500 && (cg.time >> 9 ) & 1 ) { - h = 0; - } else { - h = CG_StatusHandle(cgs.currentOrder); - } - } else { - h = CG_StatusHandle(ci->teamTask); - } - - if (h) { - CG_DrawPic( xx, y, PIC_WIDTH, PIC_WIDTH, h); - } - - xx += PIC_WIDTH + 1; - - leftOver = rect->w - xx; - maxx = xx + leftOver / 3; - - - - CG_Text_Paint_Limit(&maxx, xx, y + text_y, scale, color, ci->name, 0, 0); - - p = CG_ConfigString(CS_LOCATIONS + ci->location); - if (!p || !*p) { - p = "unknown"; - } - - xx += leftOver / 3 + 2; - maxx = rect->w - 4; - - CG_Text_Paint_Limit(&maxx, xx, y + text_y, scale, color, p, 0, 0); - y += text_y + 2; - if ( y + text_y + 2 > rect->y + rect->h ) { - break; - } - - } - } -} - - -void CG_DrawTeamSpectators(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) { - if (cg.spectatorLen) { - float maxX; - - if (cg.spectatorWidth == -1) { - cg.spectatorWidth = 0; - cg.spectatorPaintX = rect->x + 1; - cg.spectatorPaintX2 = -1; - } - - if (cg.spectatorOffset > cg.spectatorLen) { - cg.spectatorOffset = 0; - cg.spectatorPaintX = rect->x + 1; - cg.spectatorPaintX2 = -1; - } - - if (cg.time > cg.spectatorTime) { - cg.spectatorTime = cg.time + 10; - if (cg.spectatorPaintX <= rect->x + 2) { - if (cg.spectatorOffset < cg.spectatorLen) { - cg.spectatorPaintX += CG_Text_Width(&cg.spectatorList[cg.spectatorOffset], scale, 1) - 1; - cg.spectatorOffset++; - } else { - cg.spectatorOffset = 0; - if (cg.spectatorPaintX2 >= 0) { - cg.spectatorPaintX = cg.spectatorPaintX2; - } else { - cg.spectatorPaintX = rect->x + rect->w - 2; - } - cg.spectatorPaintX2 = -1; - } - } else { - cg.spectatorPaintX--; - if (cg.spectatorPaintX2 >= 0) { - cg.spectatorPaintX2--; - } - } - } - - maxX = rect->x + rect->w - 2; - CG_Text_Paint_Limit(&maxX, cg.spectatorPaintX, rect->y + rect->h - 3, scale, color, &cg.spectatorList[cg.spectatorOffset], 0, 0); - if (cg.spectatorPaintX2 >= 0) { - float maxX2 = rect->x + rect->w - 2; - CG_Text_Paint_Limit(&maxX2, cg.spectatorPaintX2, rect->y + rect->h - 3, scale, color, cg.spectatorList, 0, cg.spectatorOffset); - } - if (cg.spectatorOffset && maxX > 0) { - // if we have an offset ( we are skipping the first part of the string ) and we fit the string - if (cg.spectatorPaintX2 == -1) { - cg.spectatorPaintX2 = rect->x + rect->w - 2; - } - } else { - cg.spectatorPaintX2 = -1; - } - - } -} - - - -void CG_DrawMedal(int ownerDraw, rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) { - score_t *score = &cg.scores[cg.selectedScore]; - float value = 0; - char *text = NULL; - color[3] = 0.25; - - switch (ownerDraw) { - case CG_ACCURACY: - value = score->accuracy; - break; - case CG_ASSISTS: - value = score->assistCount; - break; - case CG_DEFEND: - value = score->defendCount; - break; - case CG_EXCELLENT: - value = score->excellentCount; - break; - case CG_IMPRESSIVE: - value = score->impressiveCount; - break; - case CG_PERFECT: - value = score->perfect; - break; - case CG_GAUNTLET: - value = score->guantletCount; - break; - case CG_CAPTURES: - value = score->captures; - break; - } - - if (value > 0) { - if (ownerDraw != CG_PERFECT) { - if (ownerDraw == CG_ACCURACY) { - text = va("%i%%", (int)value); - if (value > 50) { - color[3] = 1.0; - } - } else { - text = va("%i", (int)value); - color[3] = 1.0; - } - } else { - if (value) { - color[3] = 1.0; - } - text = "Wow"; - } - } - - trap_R_SetColor(color); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader ); - - if (text) { - color[3] = 1.0; - value = CG_Text_Width(text, scale, 0); - CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h + 10 , scale, color, text, 0, 0, 0); - } - trap_R_SetColor(NULL); - -} - - -// -void CG_OwnerDraw(float x, float y, float w, float h, float text_x, float text_y, int ownerDraw, int ownerDrawFlags, int align, float special, float scale, vec4_t color, qhandle_t shader, int textStyle) { - rectDef_t rect; - - if ( cg_drawStatus.integer == 0 ) { - return; - } - - //if (ownerDrawFlags != 0 && !CG_OwnerDrawVisible(ownerDrawFlags)) { - // return; - //} - - rect.x = x; - rect.y = y; - rect.w = w; - rect.h = h; - - switch (ownerDraw) { - case CG_PLAYER_ARMOR_ICON: - CG_DrawPlayerArmorIcon(&rect, ownerDrawFlags & CG_SHOW_2DONLY); - break; - case CG_PLAYER_ARMOR_ICON2D: - CG_DrawPlayerArmorIcon(&rect, qtrue); - break; - case CG_PLAYER_ARMOR_VALUE: - CG_DrawPlayerArmorValue(&rect, scale, color, shader, textStyle); - break; - case CG_PLAYER_AMMO_ICON: - CG_DrawPlayerAmmoIcon(&rect, ownerDrawFlags & CG_SHOW_2DONLY); - break; - case CG_PLAYER_AMMO_ICON2D: - CG_DrawPlayerAmmoIcon(&rect, qtrue); - break; - case CG_PLAYER_AMMO_VALUE: - CG_DrawPlayerAmmoValue(&rect, scale, color, shader, textStyle); - break; - case CG_SELECTEDPLAYER_HEAD: - CG_DrawSelectedPlayerHead(&rect, ownerDrawFlags & CG_SHOW_2DONLY, qfalse); - break; - case CG_VOICE_HEAD: - CG_DrawSelectedPlayerHead(&rect, ownerDrawFlags & CG_SHOW_2DONLY, qtrue); - break; - case CG_VOICE_NAME: - CG_DrawSelectedPlayerName(&rect, scale, color, qtrue, textStyle); - break; - case CG_SELECTEDPLAYER_STATUS: - CG_DrawSelectedPlayerStatus(&rect); - break; - case CG_SELECTEDPLAYER_ARMOR: - CG_DrawSelectedPlayerArmor(&rect, scale, color, shader, textStyle); - break; - case CG_SELECTEDPLAYER_HEALTH: - CG_DrawSelectedPlayerHealth(&rect, scale, color, shader, textStyle); - break; - case CG_SELECTEDPLAYER_NAME: - CG_DrawSelectedPlayerName(&rect, scale, color, qfalse, textStyle); - break; - case CG_SELECTEDPLAYER_LOCATION: - CG_DrawSelectedPlayerLocation(&rect, scale, color, textStyle); - break; - case CG_SELECTEDPLAYER_WEAPON: - CG_DrawSelectedPlayerWeapon(&rect); - break; - case CG_SELECTEDPLAYER_POWERUP: - CG_DrawSelectedPlayerPowerup(&rect, ownerDrawFlags & CG_SHOW_2DONLY); - break; - case CG_PLAYER_HEAD: - CG_DrawPlayerHead(&rect, ownerDrawFlags & CG_SHOW_2DONLY); - break; - case CG_PLAYER_ITEM: - CG_DrawPlayerItem(&rect, scale, ownerDrawFlags & CG_SHOW_2DONLY); - break; - case CG_PLAYER_SCORE: - CG_DrawPlayerScore(&rect, scale, color, shader, textStyle); - break; - case CG_PLAYER_HEALTH: - CG_DrawPlayerHealth(&rect, scale, color, shader, textStyle); - break; - case CG_RED_SCORE: - CG_DrawRedScore(&rect, scale, color, shader, textStyle); - break; - case CG_BLUE_SCORE: - CG_DrawBlueScore(&rect, scale, color, shader, textStyle); - break; - case CG_RED_NAME: - CG_DrawRedName(&rect, scale, color, textStyle); - break; - case CG_BLUE_NAME: - CG_DrawBlueName(&rect, scale, color, textStyle); - break; - case CG_BLUE_FLAGHEAD: - CG_DrawBlueFlagHead(&rect); - break; - case CG_BLUE_FLAGSTATUS: - CG_DrawBlueFlagStatus(&rect, shader); - break; - case CG_BLUE_FLAGNAME: - CG_DrawBlueFlagName(&rect, scale, color, textStyle); - break; - case CG_RED_FLAGHEAD: - CG_DrawRedFlagHead(&rect); - break; - case CG_RED_FLAGSTATUS: - CG_DrawRedFlagStatus(&rect, shader); - break; - case CG_RED_FLAGNAME: - CG_DrawRedFlagName(&rect, scale, color, textStyle); - break; - case CG_HARVESTER_SKULLS: - CG_HarvesterSkulls(&rect, scale, color, qfalse, textStyle); - break; - case CG_HARVESTER_SKULLS2D: - CG_HarvesterSkulls(&rect, scale, color, qtrue, textStyle); - break; - case CG_ONEFLAG_STATUS: - CG_OneFlagStatus(&rect); - break; - case CG_PLAYER_LOCATION: - CG_DrawPlayerLocation(&rect, scale, color, textStyle); - break; - case CG_TEAM_COLOR: - CG_DrawTeamColor(&rect, color); - break; - case CG_CTF_POWERUP: - CG_DrawCTFPowerUp(&rect); - break; - case CG_AREA_POWERUP: - CG_DrawAreaPowerUp(&rect, align, special, scale, color); - break; - case CG_PLAYER_STATUS: - CG_DrawPlayerStatus(&rect); - break; - case CG_PLAYER_HASFLAG: - CG_DrawPlayerHasFlag(&rect, qfalse); - break; - case CG_PLAYER_HASFLAG2D: - CG_DrawPlayerHasFlag(&rect, qtrue); - break; - case CG_AREA_SYSTEMCHAT: - CG_DrawAreaSystemChat(&rect, scale, color, shader); - break; - case CG_AREA_TEAMCHAT: - CG_DrawAreaTeamChat(&rect, scale, color, shader); - break; - case CG_AREA_CHAT: - CG_DrawAreaChat(&rect, scale, color, shader); - break; - case CG_GAME_TYPE: - CG_DrawGameType(&rect, scale, color, shader, textStyle); - break; - case CG_GAME_STATUS: - CG_DrawGameStatus(&rect, scale, color, shader, textStyle); - break; - case CG_KILLER: - CG_DrawKiller(&rect, scale, color, shader, textStyle); - break; - case CG_ACCURACY: - case CG_ASSISTS: - case CG_DEFEND: - case CG_EXCELLENT: - case CG_IMPRESSIVE: - case CG_PERFECT: - case CG_GAUNTLET: - case CG_CAPTURES: - CG_DrawMedal(ownerDraw, &rect, scale, color, shader); - break; - case CG_SPECTATORS: - CG_DrawTeamSpectators(&rect, scale, color, shader); - break; - case CG_TEAMINFO: - if (cg_currentSelectedPlayer.integer == numSortedTeamPlayers) { - CG_DrawNewTeamInfo(&rect, text_x, text_y, scale, color, shader); - } - break; - case CG_CAPFRAGLIMIT: - CG_DrawCapFragLimit(&rect, scale, color, shader, textStyle); - break; - case CG_1STPLACE: - CG_Draw1stPlace(&rect, scale, color, shader, textStyle); - break; - case CG_2NDPLACE: - CG_Draw2ndPlace(&rect, scale, color, shader, textStyle); - break; - default: - break; - } -} - -void CG_MouseEvent(int x, int y) { - int n; - - if ( (cg.predictedPlayerState.pm_type == PM_NORMAL || cg.predictedPlayerState.pm_type == PM_SPECTATOR) && cg.showScores == qfalse) { - trap_Key_SetCatcher(0); - return; - } - - cgs.cursorX+= x; - if (cgs.cursorX < 0) - cgs.cursorX = 0; - else if (cgs.cursorX > 640) - cgs.cursorX = 640; - - cgs.cursorY += y; - if (cgs.cursorY < 0) - cgs.cursorY = 0; - else if (cgs.cursorY > 480) - cgs.cursorY = 480; - - n = Display_CursorType(cgs.cursorX, cgs.cursorY); - cgs.activeCursor = 0; - if (n == CURSOR_ARROW) { - cgs.activeCursor = cgs.media.selectCursor; - } else if (n == CURSOR_SIZER) { - cgs.activeCursor = cgs.media.sizeCursor; - } - - if (cgs.capturedItem) { - Display_MouseMove(cgs.capturedItem, x, y); - } else { - Display_MouseMove(NULL, cgs.cursorX, cgs.cursorY); - } - -} - -/* -================== -CG_HideTeamMenus -================== - -*/ -void CG_HideTeamMenu( void ) { - Menus_CloseByName("teamMenu"); - Menus_CloseByName("getMenu"); -} - -/* -================== -CG_ShowTeamMenus -================== - -*/ -void CG_ShowTeamMenu( void ) { - Menus_OpenByName("teamMenu"); -} - - - - -/* -================== -CG_EventHandling -================== - type 0 - no event handling - 1 - team menu - 2 - hud editor - -*/ -void CG_EventHandling(int type) { - cgs.eventHandling = type; - if (type == CGAME_EVENT_NONE) { - CG_HideTeamMenu(); - } else if (type == CGAME_EVENT_TEAMMENU) { - //CG_ShowTeamMenu(); - } else if (type == CGAME_EVENT_SCOREBOARD) { - } - -} - - - -void CG_KeyEvent(int key, qboolean down) { - - if (!down) { - return; - } - - if ( cg.predictedPlayerState.pm_type == PM_NORMAL || (cg.predictedPlayerState.pm_type == PM_SPECTATOR && cg.showScores == qfalse)) { - CG_EventHandling(CGAME_EVENT_NONE); - trap_Key_SetCatcher(0); - return; - } - - //if (key == trap_Key_GetKey("teamMenu") || !Display_CaptureItem(cgs.cursorX, cgs.cursorY)) { - // if we see this then we should always be visible - // CG_EventHandling(CGAME_EVENT_NONE); - // trap_Key_SetCatcher(0); - //} - - - - Display_HandleKey(key, down, cgs.cursorX, cgs.cursorY); - - if (cgs.capturedItem) { - cgs.capturedItem = NULL; - } else { - if (key == K_MOUSE2 && down) { - cgs.capturedItem = Display_CaptureItem(cgs.cursorX, cgs.cursorY); - } - } -} - -int CG_ClientNumFromName(const char *p) { - int i; - for (i = 0; i < cgs.maxclients; i++) { - if (cgs.clientinfo[i].infoValid && Q_stricmp(cgs.clientinfo[i].name, p) == 0) { - return i; - } - } - return -1; -} - -void CG_ShowResponseHead(void) { - Menus_OpenByName("voiceMenu"); - trap_Cvar_Set("cl_conXOffset", "72"); - cg.voiceTime = cg.time; -} - -void CG_RunMenuScript(char **args) { -} - - -void CG_GetTeamColor(vec4_t *color) { - if (cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED) { - (*color)[0] = 1.0f; - (*color)[3] = 0.25f; - (*color)[1] = (*color)[2] = 0.0f; - } else if (cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE) { - (*color)[0] = (*color)[1] = 0.0f; - (*color)[2] = 1.0f; - (*color)[3] = 0.25f; - } else { - (*color)[0] = (*color)[2] = 0.0f; - (*color)[1] = 0.17f; - (*color)[3] = 0.25f; - } -} - diff --git a/code/cgame/cg_particles.c b/code/cgame/cg_particles.c deleted file mode 100644 index d421e3d..0000000 --- a/code/cgame/cg_particles.c +++ /dev/null @@ -1,2041 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// Rafael particles -// cg_particles.c - -#include "cg_local.h" - -//#define WOLF_PARTICLES - -#define BLOODRED 2 -#define EMISIVEFADE 3 -#define GREY75 4 - -typedef struct particle_s -{ - struct particle_s *next; - - float time; - float endtime; - - vec3_t org; - vec3_t vel; - vec3_t accel; - int color; - float colorvel; - float alpha; - float alphavel; - int type; - qhandle_t pshader; - - float height; - float width; - - float endheight; - float endwidth; - - float start; - float end; - - float startfade; - qboolean rotate; - int snum; - - qboolean link; - - // Ridah - int shaderAnim; - int roll; - - int accumroll; - -} cparticle_t; - -typedef enum -{ - P_NONE, - P_WEATHER, - P_FLAT, - P_SMOKE, - P_ROTATE, - P_WEATHER_TURBULENT, - P_ANIM, // Ridah - P_BAT, - P_BLEED, - P_FLAT_SCALEUP, - P_FLAT_SCALEUP_FADE, - P_WEATHER_FLURRY, - P_SMOKE_IMPACT, - P_BUBBLE, - P_BUBBLE_TURBULENT, - P_SPRITE -} particle_type_t; - -#define MAX_SHADER_ANIMS 32 -#define MAX_SHADER_ANIM_FRAMES 64 - -#ifndef WOLF_PARTICLES -static char *shaderAnimNames[MAX_SHADER_ANIMS] = { - "explode1", - NULL -}; -static qhandle_t shaderAnims[MAX_SHADER_ANIMS][MAX_SHADER_ANIM_FRAMES]; -static int shaderAnimCounts[MAX_SHADER_ANIMS] = { - 23 -}; -static float shaderAnimSTRatio[MAX_SHADER_ANIMS] = { - 1.0f -}; -static int numShaderAnims; -// done. -#else -static char *shaderAnimNames[MAX_SHADER_ANIMS] = { - "explode1", - "blacksmokeanim", - "twiltb2", - "expblue", - "blacksmokeanimb", // uses 'explode1' sequence - "blood", - NULL -}; -static qhandle_t shaderAnims[MAX_SHADER_ANIMS][MAX_SHADER_ANIM_FRAMES]; -static int shaderAnimCounts[MAX_SHADER_ANIMS] = { - 23, - 25, - 45, - 25, - 23, - 5, -}; -static float shaderAnimSTRatio[MAX_SHADER_ANIMS] = { - 1.405f, - 1.0f, - 1.0f, - 1.0f, - 1.0f, - 1.0f, -}; -#endif - -#define PARTICLE_GRAVITY 40 - -#ifdef WOLF_PARTICLES -#define MAX_PARTICLES 1024 * 8 -#else -#define MAX_PARTICLES 1024 -#endif - -cparticle_t *active_particles, *free_particles; -cparticle_t particles[MAX_PARTICLES]; -int cl_numparticles = MAX_PARTICLES; - -qboolean initparticles = qfalse; -vec3_t vforward, vright, vup; -vec3_t rforward, rright, rup; - -float oldtime; - -/* -=============== -CL_ClearParticles -=============== -*/ -void CG_ClearParticles (void) -{ - int i; - - memset( particles, 0, sizeof(particles) ); - - free_particles = &particles[0]; - active_particles = NULL; - - for (i=0 ;itype == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY - || p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT) - {// create a front facing polygon - - if (p->type != P_WEATHER_FLURRY) - { - if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT) - { - if (org[2] > p->end) - { - p->time = cg.time; - VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground - - p->org[2] = ( p->start + crandom () * 4 ); - - - if (p->type == P_BUBBLE_TURBULENT) - { - p->vel[0] = crandom() * 4; - p->vel[1] = crandom() * 4; - } - - } - } - else - { - if (org[2] < p->end) - { - p->time = cg.time; - VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground - - while (p->org[2] < p->end) - { - p->org[2] += (p->start - p->end); - } - - - if (p->type == P_WEATHER_TURBULENT) - { - p->vel[0] = crandom() * 16; - p->vel[1] = crandom() * 16; - } - - } - } - - - // Rafael snow pvs check - if (!p->link) - return; - - p->alpha = 1; - } - - // Ridah, had to do this or MAX_POLYS is being exceeded in village1.bsp - if (Distance( cg.snap->ps.origin, org ) > 1024) { - return; - } - // done. - - if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT) - { - VectorMA (org, -p->height, vup, point); - VectorMA (point, -p->width, vright, point); - VectorCopy (point, verts[0].xyz); - verts[0].st[0] = 0; - verts[0].st[1] = 0; - verts[0].modulate[0] = 255; - verts[0].modulate[1] = 255; - verts[0].modulate[2] = 255; - verts[0].modulate[3] = 255 * p->alpha; - - VectorMA (org, -p->height, vup, point); - VectorMA (point, p->width, vright, point); - VectorCopy (point, verts[1].xyz); - verts[1].st[0] = 0; - verts[1].st[1] = 1; - verts[1].modulate[0] = 255; - verts[1].modulate[1] = 255; - verts[1].modulate[2] = 255; - verts[1].modulate[3] = 255 * p->alpha; - - VectorMA (org, p->height, vup, point); - VectorMA (point, p->width, vright, point); - VectorCopy (point, verts[2].xyz); - verts[2].st[0] = 1; - verts[2].st[1] = 1; - verts[2].modulate[0] = 255; - verts[2].modulate[1] = 255; - verts[2].modulate[2] = 255; - verts[2].modulate[3] = 255 * p->alpha; - - VectorMA (org, p->height, vup, point); - VectorMA (point, -p->width, vright, point); - VectorCopy (point, verts[3].xyz); - verts[3].st[0] = 1; - verts[3].st[1] = 0; - verts[3].modulate[0] = 255; - verts[3].modulate[1] = 255; - verts[3].modulate[2] = 255; - verts[3].modulate[3] = 255 * p->alpha; - } - else - { - VectorMA (org, -p->height, vup, point); - VectorMA (point, -p->width, vright, point); - VectorCopy( point, TRIverts[0].xyz ); - TRIverts[0].st[0] = 1; - TRIverts[0].st[1] = 0; - TRIverts[0].modulate[0] = 255; - TRIverts[0].modulate[1] = 255; - TRIverts[0].modulate[2] = 255; - TRIverts[0].modulate[3] = 255 * p->alpha; - - VectorMA (org, p->height, vup, point); - VectorMA (point, -p->width, vright, point); - VectorCopy (point, TRIverts[1].xyz); - TRIverts[1].st[0] = 0; - TRIverts[1].st[1] = 0; - TRIverts[1].modulate[0] = 255; - TRIverts[1].modulate[1] = 255; - TRIverts[1].modulate[2] = 255; - TRIverts[1].modulate[3] = 255 * p->alpha; - - VectorMA (org, p->height, vup, point); - VectorMA (point, p->width, vright, point); - VectorCopy (point, TRIverts[2].xyz); - TRIverts[2].st[0] = 0; - TRIverts[2].st[1] = 1; - TRIverts[2].modulate[0] = 255; - TRIverts[2].modulate[1] = 255; - TRIverts[2].modulate[2] = 255; - TRIverts[2].modulate[3] = 255 * p->alpha; - } - - } - else if (p->type == P_SPRITE) - { - vec3_t rr, ru; - vec3_t rotate_ang; - -#ifdef WOLF_PARTICLES - VectorSet (color, 1.0, 1.0, 1.0); -#else - VectorSet (color, 1.0, 1.0, 0.5); -#endif - time = cg.time - p->time; - time2 = p->endtime - p->time; - ratio = time / time2; - - width = p->width + ( ratio * ( p->endwidth - p->width) ); - height = p->height + ( ratio * ( p->endheight - p->height) ); - - if (p->roll) { - vectoangles( cg.refdef.viewaxis[0], rotate_ang ); - rotate_ang[ROLL] += p->roll; - AngleVectors ( rotate_ang, NULL, rr, ru); - } - - if (p->roll) { - VectorMA (org, -height, ru, point); - VectorMA (point, -width, rr, point); - } else { - VectorMA (org, -height, vup, point); - VectorMA (point, -width, vright, point); - } - VectorCopy (point, verts[0].xyz); - verts[0].st[0] = 0; - verts[0].st[1] = 0; - verts[0].modulate[0] = 255; - verts[0].modulate[1] = 255; - verts[0].modulate[2] = 255; - verts[0].modulate[3] = 255; - - if (p->roll) { - VectorMA (point, 2*height, ru, point); - } else { - VectorMA (point, 2*height, vup, point); - } - VectorCopy (point, verts[1].xyz); - verts[1].st[0] = 0; - verts[1].st[1] = 1; - verts[1].modulate[0] = 255; - verts[1].modulate[1] = 255; - verts[1].modulate[2] = 255; - verts[1].modulate[3] = 255; - - if (p->roll) { - VectorMA (point, 2*width, rr, point); - } else { - VectorMA (point, 2*width, vright, point); - } - VectorCopy (point, verts[2].xyz); - verts[2].st[0] = 1; - verts[2].st[1] = 1; - verts[2].modulate[0] = 255; - verts[2].modulate[1] = 255; - verts[2].modulate[2] = 255; - verts[2].modulate[3] = 255; - - if (p->roll) { - VectorMA (point, -2*height, ru, point); - } else { - VectorMA (point, -2*height, vup, point); - } - VectorCopy (point, verts[3].xyz); - verts[3].st[0] = 1; - verts[3].st[1] = 0; - verts[3].modulate[0] = 255; - verts[3].modulate[1] = 255; - verts[3].modulate[2] = 255; - verts[3].modulate[3] = 255; - } - else if (p->type == P_SMOKE || p->type == P_SMOKE_IMPACT) - {// create a front rotating facing polygon - - if ( p->type == P_SMOKE_IMPACT && Distance( cg.snap->ps.origin, org ) > 1024) { - return; - } - - if (p->color == BLOODRED) - VectorSet (color, 0.22f, 0.0f, 0.0f); - else if (p->color == GREY75) - { - float len; - float greyit; - float val; - len = Distance (cg.snap->ps.origin, org); - if (!len) - len = 1; - - val = 4096/len; - greyit = 0.25 * val; - if (greyit > 0.5) - greyit = 0.5; - - VectorSet (color, greyit, greyit, greyit); - } - else - VectorSet (color, 1.0, 1.0, 1.0); - - time = cg.time - p->time; - time2 = p->endtime - p->time; - ratio = time / time2; - - if (cg.time > p->startfade) - { - invratio = 1 - ( (cg.time - p->startfade) / (p->endtime - p->startfade) ); - - if (p->color == EMISIVEFADE) - { - float fval; - fval = (invratio * invratio); - if (fval < 0) - fval = 0; - VectorSet (color, fval , fval , fval ); - } - invratio *= p->alpha; - } - else - invratio = 1 * p->alpha; - - if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) - invratio = 1; - - if (invratio > 1) - invratio = 1; - - width = p->width + ( ratio * ( p->endwidth - p->width) ); - height = p->height + ( ratio * ( p->endheight - p->height) ); - - if (p->type != P_SMOKE_IMPACT) - { - vec3_t temp; - - vectoangles (rforward, temp); - p->accumroll += p->roll; - temp[ROLL] += p->accumroll * 0.1; - AngleVectors ( temp, NULL, rright2, rup2); - } - else - { - VectorCopy (rright, rright2); - VectorCopy (rup, rup2); - } - - if (p->rotate) - { - VectorMA (org, -height, rup2, point); - VectorMA (point, -width, rright2, point); - } - else - { - VectorMA (org, -p->height, vup, point); - VectorMA (point, -p->width, vright, point); - } - VectorCopy (point, verts[0].xyz); - verts[0].st[0] = 0; - verts[0].st[1] = 0; - verts[0].modulate[0] = 255 * color[0]; - verts[0].modulate[1] = 255 * color[1]; - verts[0].modulate[2] = 255 * color[2]; - verts[0].modulate[3] = 255 * invratio; - - if (p->rotate) - { - VectorMA (org, -height, rup2, point); - VectorMA (point, width, rright2, point); - } - else - { - VectorMA (org, -p->height, vup, point); - VectorMA (point, p->width, vright, point); - } - VectorCopy (point, verts[1].xyz); - verts[1].st[0] = 0; - verts[1].st[1] = 1; - verts[1].modulate[0] = 255 * color[0]; - verts[1].modulate[1] = 255 * color[1]; - verts[1].modulate[2] = 255 * color[2]; - verts[1].modulate[3] = 255 * invratio; - - if (p->rotate) - { - VectorMA (org, height, rup2, point); - VectorMA (point, width, rright2, point); - } - else - { - VectorMA (org, p->height, vup, point); - VectorMA (point, p->width, vright, point); - } - VectorCopy (point, verts[2].xyz); - verts[2].st[0] = 1; - verts[2].st[1] = 1; - verts[2].modulate[0] = 255 * color[0]; - verts[2].modulate[1] = 255 * color[1]; - verts[2].modulate[2] = 255 * color[2]; - verts[2].modulate[3] = 255 * invratio; - - if (p->rotate) - { - VectorMA (org, height, rup2, point); - VectorMA (point, -width, rright2, point); - } - else - { - VectorMA (org, p->height, vup, point); - VectorMA (point, -p->width, vright, point); - } - VectorCopy (point, verts[3].xyz); - verts[3].st[0] = 1; - verts[3].st[1] = 0; - verts[3].modulate[0] = 255 * color[0]; - verts[3].modulate[1] = 255 * color[1]; - verts[3].modulate[2] = 255 * color[2]; - verts[3].modulate[3] = 255 * invratio; - - } - else if (p->type == P_BLEED) - { - vec3_t rr, ru; - vec3_t rotate_ang; - float alpha; - - alpha = p->alpha; - - if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) - alpha = 1; - - if (p->roll) - { - vectoangles( cg.refdef.viewaxis[0], rotate_ang ); - rotate_ang[ROLL] += p->roll; - AngleVectors ( rotate_ang, NULL, rr, ru); - } - else - { - VectorCopy (vup, ru); - VectorCopy (vright, rr); - } - - VectorMA (org, -p->height, ru, point); - VectorMA (point, -p->width, rr, point); - VectorCopy (point, verts[0].xyz); - verts[0].st[0] = 0; - verts[0].st[1] = 0; - verts[0].modulate[0] = 111; - verts[0].modulate[1] = 19; - verts[0].modulate[2] = 9; - verts[0].modulate[3] = 255 * alpha; - - VectorMA (org, -p->height, ru, point); - VectorMA (point, p->width, rr, point); - VectorCopy (point, verts[1].xyz); - verts[1].st[0] = 0; - verts[1].st[1] = 1; - verts[1].modulate[0] = 111; - verts[1].modulate[1] = 19; - verts[1].modulate[2] = 9; - verts[1].modulate[3] = 255 * alpha; - - VectorMA (org, p->height, ru, point); - VectorMA (point, p->width, rr, point); - VectorCopy (point, verts[2].xyz); - verts[2].st[0] = 1; - verts[2].st[1] = 1; - verts[2].modulate[0] = 111; - verts[2].modulate[1] = 19; - verts[2].modulate[2] = 9; - verts[2].modulate[3] = 255 * alpha; - - VectorMA (org, p->height, ru, point); - VectorMA (point, -p->width, rr, point); - VectorCopy (point, verts[3].xyz); - verts[3].st[0] = 1; - verts[3].st[1] = 0; - verts[3].modulate[0] = 111; - verts[3].modulate[1] = 19; - verts[3].modulate[2] = 9; - verts[3].modulate[3] = 255 * alpha; - - } - else if (p->type == P_FLAT_SCALEUP) - { - float width, height; - float sinR, cosR; - - if (p->color == BLOODRED) - VectorSet (color, 1, 1, 1); - else - VectorSet (color, 0.5, 0.5, 0.5); - - time = cg.time - p->time; - time2 = p->endtime - p->time; - ratio = time / time2; - - width = p->width + ( ratio * ( p->endwidth - p->width) ); - height = p->height + ( ratio * ( p->endheight - p->height) ); - - if (width > p->endwidth) - width = p->endwidth; - - if (height > p->endheight) - height = p->endheight; - - sinR = height * sin(DEG2RAD(p->roll)) * sqrt(2); - cosR = width * cos(DEG2RAD(p->roll)) * sqrt(2); - - VectorCopy (org, verts[0].xyz); - verts[0].xyz[0] -= sinR; - verts[0].xyz[1] -= cosR; - verts[0].st[0] = 0; - verts[0].st[1] = 0; - verts[0].modulate[0] = 255 * color[0]; - verts[0].modulate[1] = 255 * color[1]; - verts[0].modulate[2] = 255 * color[2]; - verts[0].modulate[3] = 255; - - VectorCopy (org, verts[1].xyz); - verts[1].xyz[0] -= cosR; - verts[1].xyz[1] += sinR; - verts[1].st[0] = 0; - verts[1].st[1] = 1; - verts[1].modulate[0] = 255 * color[0]; - verts[1].modulate[1] = 255 * color[1]; - verts[1].modulate[2] = 255 * color[2]; - verts[1].modulate[3] = 255; - - VectorCopy (org, verts[2].xyz); - verts[2].xyz[0] += sinR; - verts[2].xyz[1] += cosR; - verts[2].st[0] = 1; - verts[2].st[1] = 1; - verts[2].modulate[0] = 255 * color[0]; - verts[2].modulate[1] = 255 * color[1]; - verts[2].modulate[2] = 255 * color[2]; - verts[2].modulate[3] = 255; - - VectorCopy (org, verts[3].xyz); - verts[3].xyz[0] += cosR; - verts[3].xyz[1] -= sinR; - verts[3].st[0] = 1; - verts[3].st[1] = 0; - verts[3].modulate[0] = 255 * color[0]; - verts[3].modulate[1] = 255 * color[1]; - verts[3].modulate[2] = 255 * color[2]; - verts[3].modulate[3] = 255; - } - else if (p->type == P_FLAT) - { - - VectorCopy (org, verts[0].xyz); - verts[0].xyz[0] -= p->height; - verts[0].xyz[1] -= p->width; - verts[0].st[0] = 0; - verts[0].st[1] = 0; - verts[0].modulate[0] = 255; - verts[0].modulate[1] = 255; - verts[0].modulate[2] = 255; - verts[0].modulate[3] = 255; - - VectorCopy (org, verts[1].xyz); - verts[1].xyz[0] -= p->height; - verts[1].xyz[1] += p->width; - verts[1].st[0] = 0; - verts[1].st[1] = 1; - verts[1].modulate[0] = 255; - verts[1].modulate[1] = 255; - verts[1].modulate[2] = 255; - verts[1].modulate[3] = 255; - - VectorCopy (org, verts[2].xyz); - verts[2].xyz[0] += p->height; - verts[2].xyz[1] += p->width; - verts[2].st[0] = 1; - verts[2].st[1] = 1; - verts[2].modulate[0] = 255; - verts[2].modulate[1] = 255; - verts[2].modulate[2] = 255; - verts[2].modulate[3] = 255; - - VectorCopy (org, verts[3].xyz); - verts[3].xyz[0] += p->height; - verts[3].xyz[1] -= p->width; - verts[3].st[0] = 1; - verts[3].st[1] = 0; - verts[3].modulate[0] = 255; - verts[3].modulate[1] = 255; - verts[3].modulate[2] = 255; - verts[3].modulate[3] = 255; - - } - // Ridah - else if (p->type == P_ANIM) { - vec3_t rr, ru; - vec3_t rotate_ang; - int i, j; - - time = cg.time - p->time; - time2 = p->endtime - p->time; - ratio = time / time2; - if (ratio >= 1.0f) { - ratio = 0.9999f; - } - - width = p->width + ( ratio * ( p->endwidth - p->width) ); - height = p->height + ( ratio * ( p->endheight - p->height) ); - - // if we are "inside" this sprite, don't draw - if (Distance( cg.snap->ps.origin, org ) < width/1.5) { - return; - } - - i = p->shaderAnim; - j = (int)floor(ratio * shaderAnimCounts[p->shaderAnim]); - p->pshader = shaderAnims[i][j]; - - if (p->roll) { - vectoangles( cg.refdef.viewaxis[0], rotate_ang ); - rotate_ang[ROLL] += p->roll; - AngleVectors ( rotate_ang, NULL, rr, ru); - } - - if (p->roll) { - VectorMA (org, -height, ru, point); - VectorMA (point, -width, rr, point); - } else { - VectorMA (org, -height, vup, point); - VectorMA (point, -width, vright, point); - } - VectorCopy (point, verts[0].xyz); - verts[0].st[0] = 0; - verts[0].st[1] = 0; - verts[0].modulate[0] = 255; - verts[0].modulate[1] = 255; - verts[0].modulate[2] = 255; - verts[0].modulate[3] = 255; - - if (p->roll) { - VectorMA (point, 2*height, ru, point); - } else { - VectorMA (point, 2*height, vup, point); - } - VectorCopy (point, verts[1].xyz); - verts[1].st[0] = 0; - verts[1].st[1] = 1; - verts[1].modulate[0] = 255; - verts[1].modulate[1] = 255; - verts[1].modulate[2] = 255; - verts[1].modulate[3] = 255; - - if (p->roll) { - VectorMA (point, 2*width, rr, point); - } else { - VectorMA (point, 2*width, vright, point); - } - VectorCopy (point, verts[2].xyz); - verts[2].st[0] = 1; - verts[2].st[1] = 1; - verts[2].modulate[0] = 255; - verts[2].modulate[1] = 255; - verts[2].modulate[2] = 255; - verts[2].modulate[3] = 255; - - if (p->roll) { - VectorMA (point, -2*height, ru, point); - } else { - VectorMA (point, -2*height, vup, point); - } - VectorCopy (point, verts[3].xyz); - verts[3].st[0] = 1; - verts[3].st[1] = 0; - verts[3].modulate[0] = 255; - verts[3].modulate[1] = 255; - verts[3].modulate[2] = 255; - verts[3].modulate[3] = 255; - } - // done. - - if (!p->pshader) { -// (SA) temp commented out for DM -// CG_Printf ("CG_AddParticleToScene type %d p->pshader == ZERO\n", p->type); - return; - } - - if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY) - trap_R_AddPolyToScene( p->pshader, 3, TRIverts ); - else - trap_R_AddPolyToScene( p->pshader, 4, verts ); - -} - -// Ridah, made this static so it doesn't interfere with other files -static float roll = 0.0; - -/* -=============== -CG_AddParticles -=============== -*/ -void CG_AddParticles (void) -{ - cparticle_t *p, *next; - float alpha; - float time, time2; - vec3_t org; - cparticle_t *active, *tail; - vec3_t rotate_ang; - - if (!initparticles) - CG_ClearParticles (); - - VectorCopy( cg.refdef.viewaxis[0], vforward ); - VectorCopy( cg.refdef.viewaxis[1], vright ); - VectorCopy( cg.refdef.viewaxis[2], vup ); - - vectoangles( cg.refdef.viewaxis[0], rotate_ang ); - roll += ((cg.time - oldtime) * 0.1) ; - rotate_ang[ROLL] += (roll*0.9); - AngleVectors ( rotate_ang, rforward, rright, rup); - - oldtime = cg.time; - - active = NULL; - tail = NULL; - - for (p=active_particles ; p ; p=next) - { - - next = p->next; - - time = (cg.time - p->time)*0.001; - - alpha = p->alpha + time*p->alphavel; - if (alpha <= 0) - { // faded out - p->next = free_particles; - free_particles = p; - p->type = 0; - p->color = 0; - p->alpha = 0; - continue; - } - - if (p->type == P_SMOKE || p->type == P_ANIM || p->type == P_BLEED || p->type == P_SMOKE_IMPACT) - { - if (cg.time > p->endtime) - { - p->next = free_particles; - free_particles = p; - p->type = 0; - p->color = 0; - p->alpha = 0; - - continue; - } - - } - - if (p->type == P_WEATHER_FLURRY) - { - if (cg.time > p->endtime) - { - p->next = free_particles; - free_particles = p; - p->type = 0; - p->color = 0; - p->alpha = 0; - - continue; - } - } - - - if (p->type == P_FLAT_SCALEUP_FADE) - { - if (cg.time > p->endtime) - { - p->next = free_particles; - free_particles = p; - p->type = 0; - p->color = 0; - p->alpha = 0; - continue; - } - - } - - if ((p->type == P_BAT || p->type == P_SPRITE) && p->endtime < 0) { - // temporary sprite - CG_AddParticleToScene (p, p->org, alpha); - p->next = free_particles; - free_particles = p; - p->type = 0; - p->color = 0; - p->alpha = 0; - continue; - } - - p->next = NULL; - if (!tail) - active = tail = p; - else - { - tail->next = p; - tail = p; - } - - if (alpha > 1.0) - alpha = 1; - - time2 = time*time; - - org[0] = p->org[0] + p->vel[0]*time + p->accel[0]*time2; - org[1] = p->org[1] + p->vel[1]*time + p->accel[1]*time2; - org[2] = p->org[2] + p->vel[2]*time + p->accel[2]*time2; - - CG_AddParticleToScene (p, org, alpha); - } - - active_particles = active; -} - -/* -====================== -CG_AddParticles -====================== -*/ -void CG_ParticleSnowFlurry (qhandle_t pshader, centity_t *cent) -{ - cparticle_t *p; - qboolean turb = qtrue; - - if (!pshader) - CG_Printf ("CG_ParticleSnowFlurry pshader == ZERO!\n"); - - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - p->time = cg.time; - p->color = 0; - p->alpha = 0.90f; - p->alphavel = 0; - - p->start = cent->currentState.origin2[0]; - p->end = cent->currentState.origin2[1]; - - p->endtime = cg.time + cent->currentState.time; - p->startfade = cg.time + cent->currentState.time2; - - p->pshader = pshader; - - if (rand()%100 > 90) - { - p->height = 32; - p->width = 32; - p->alpha = 0.10f; - } - else - { - p->height = 1; - p->width = 1; - } - - p->vel[2] = -20; - - p->type = P_WEATHER_FLURRY; - - if (turb) - p->vel[2] = -10; - - VectorCopy(cent->currentState.origin, p->org); - - p->org[0] = p->org[0]; - p->org[1] = p->org[1]; - p->org[2] = p->org[2]; - - p->vel[0] = p->vel[1] = 0; - - p->accel[0] = p->accel[1] = p->accel[2] = 0; - - p->vel[0] += cent->currentState.angles[0] * 32 + (crandom() * 16); - p->vel[1] += cent->currentState.angles[1] * 32 + (crandom() * 16); - p->vel[2] += cent->currentState.angles[2]; - - if (turb) - { - p->accel[0] = crandom () * 16; - p->accel[1] = crandom () * 16; - } - -} - -void CG_ParticleSnow (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum) -{ - cparticle_t *p; - - if (!pshader) - CG_Printf ("CG_ParticleSnow pshader == ZERO!\n"); - - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - p->time = cg.time; - p->color = 0; - p->alpha = 0.40f; - p->alphavel = 0; - p->start = origin[2]; - p->end = origin2[2]; - p->pshader = pshader; - p->height = 1; - p->width = 1; - - p->vel[2] = -50; - - if (turb) - { - p->type = P_WEATHER_TURBULENT; - p->vel[2] = -50 * 1.3; - } - else - { - p->type = P_WEATHER; - } - - VectorCopy(origin, p->org); - - p->org[0] = p->org[0] + ( crandom() * range); - p->org[1] = p->org[1] + ( crandom() * range); - p->org[2] = p->org[2] + ( crandom() * (p->start - p->end)); - - p->vel[0] = p->vel[1] = 0; - - p->accel[0] = p->accel[1] = p->accel[2] = 0; - - if (turb) - { - p->vel[0] = crandom() * 16; - p->vel[1] = crandom() * 16; - } - - // Rafael snow pvs check - p->snum = snum; - p->link = qtrue; - -} - -void CG_ParticleBubble (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum) -{ - cparticle_t *p; - float randsize; - - if (!pshader) - CG_Printf ("CG_ParticleSnow pshader == ZERO!\n"); - - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - p->time = cg.time; - p->color = 0; - p->alpha = 0.40f; - p->alphavel = 0; - p->start = origin[2]; - p->end = origin2[2]; - p->pshader = pshader; - - randsize = 1 + (crandom() * 0.5); - - p->height = randsize; - p->width = randsize; - - p->vel[2] = 50 + ( crandom() * 10 ); - - if (turb) - { - p->type = P_BUBBLE_TURBULENT; - p->vel[2] = 50 * 1.3; - } - else - { - p->type = P_BUBBLE; - } - - VectorCopy(origin, p->org); - - p->org[0] = p->org[0] + ( crandom() * range); - p->org[1] = p->org[1] + ( crandom() * range); - p->org[2] = p->org[2] + ( crandom() * (p->start - p->end)); - - p->vel[0] = p->vel[1] = 0; - - p->accel[0] = p->accel[1] = p->accel[2] = 0; - - if (turb) - { - p->vel[0] = crandom() * 4; - p->vel[1] = crandom() * 4; - } - - // Rafael snow pvs check - p->snum = snum; - p->link = qtrue; - -} - -void CG_ParticleSmoke (qhandle_t pshader, centity_t *cent) -{ - - // using cent->density = enttime - // cent->frame = startfade - cparticle_t *p; - - if (!pshader) - CG_Printf ("CG_ParticleSmoke == ZERO!\n"); - - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - p->time = cg.time; - - p->endtime = cg.time + cent->currentState.time; - p->startfade = cg.time + cent->currentState.time2; - - p->color = 0; - p->alpha = 1.0; - p->alphavel = 0; - p->start = cent->currentState.origin[2]; - p->end = cent->currentState.origin2[2]; - p->pshader = pshader; - p->rotate = qfalse; - p->height = 8; - p->width = 8; - p->endheight = 32; - p->endwidth = 32; - p->type = P_SMOKE; - - VectorCopy(cent->currentState.origin, p->org); - - p->vel[0] = p->vel[1] = 0; - p->accel[0] = p->accel[1] = p->accel[2] = 0; - - p->vel[2] = 5; - - if (cent->currentState.frame == 1)// reverse gravity - p->vel[2] *= -1; - - p->roll = 8 + (crandom() * 4); -} - - -void CG_ParticleBulletDebris (vec3_t org, vec3_t vel, int duration) -{ - - cparticle_t *p; - - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - p->time = cg.time; - - p->endtime = cg.time + duration; - p->startfade = cg.time + duration/2; - - p->color = EMISIVEFADE; - p->alpha = 1.0; - p->alphavel = 0; - - p->height = 0.5; - p->width = 0.5; - p->endheight = 0.5; - p->endwidth = 0.5; - - p->pshader = cgs.media.tracerShader; - - p->type = P_SMOKE; - - VectorCopy(org, p->org); - - p->vel[0] = vel[0]; - p->vel[1] = vel[1]; - p->vel[2] = vel[2]; - p->accel[0] = p->accel[1] = p->accel[2] = 0; - - p->accel[2] = -60; - p->vel[2] += -20; - -} - -/* -====================== -CG_ParticleExplosion -====================== -*/ - -void CG_ParticleExplosion (char *animStr, vec3_t origin, vec3_t vel, int duration, int sizeStart, int sizeEnd) -{ - cparticle_t *p; - int anim; - - if (animStr < (char *)10) - CG_Error( "CG_ParticleExplosion: animStr is probably an index rather than a string" ); - - // find the animation string - for (anim=0; shaderAnimNames[anim]; anim++) { - if (!Q_stricmp( animStr, shaderAnimNames[anim] )) - break; - } - if (!shaderAnimNames[anim]) { - CG_Error("CG_ParticleExplosion: unknown animation string: %s\n", animStr); - return; - } - - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - p->time = cg.time; -#ifdef WOLF_PARTICLES - p->alpha = 1.0; -#else - p->alpha = 0.5; -#endif - p->alphavel = 0; - - if (duration < 0) { - duration *= -1; - p->roll = 0; - } else { - p->roll = crandom()*179; - } - - p->shaderAnim = anim; - - p->width = sizeStart; - p->height = sizeStart*shaderAnimSTRatio[anim]; // for sprites that are stretch in either direction - - p->endheight = sizeEnd; - p->endwidth = sizeEnd*shaderAnimSTRatio[anim]; - - p->endtime = cg.time + duration; - - p->type = P_ANIM; - - VectorCopy( origin, p->org ); - VectorCopy( vel, p->vel ); - VectorClear( p->accel ); - -} - -// Rafael Shrapnel -void CG_AddParticleShrapnel (localEntity_t *le) -{ - return; -} -// done. - -int CG_NewParticleArea (int num) -{ - // const char *str; - char *str; - char *token; - int type; - vec3_t origin, origin2; - int i; - float range = 0; - int turb; - int numparticles; - int snum; - - str = (char *) CG_ConfigString (num); - if (!str[0]) - return (0); - - // returns type 128 64 or 32 - token = COM_Parse (&str); - type = atoi (token); - - if (type == 1) - range = 128; - else if (type == 2) - range = 64; - else if (type == 3) - range = 32; - else if (type == 0) - range = 256; - else if (type == 4) - range = 8; - else if (type == 5) - range = 16; - else if (type == 6) - range = 32; - else if (type == 7) - range = 64; - - - for (i=0; i<3; i++) - { - token = COM_Parse (&str); - origin[i] = atof (token); - } - - for (i=0; i<3; i++) - { - token = COM_Parse (&str); - origin2[i] = atof (token); - } - - token = COM_Parse (&str); - numparticles = atoi (token); - - token = COM_Parse (&str); - turb = atoi (token); - - token = COM_Parse (&str); - snum = atoi (token); - - for (i=0; i= 4) - CG_ParticleBubble (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum); - else - CG_ParticleSnow (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum); - } - - return (1); -} - -void CG_SnowLink (centity_t *cent, qboolean particleOn) -{ - cparticle_t *p, *next; - int id; - - id = cent->currentState.frame; - - for (p=active_particles ; p ; p=next) - { - next = p->next; - - if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT) - { - if (p->snum == id) - { - if (particleOn) - p->link = qtrue; - else - p->link = qfalse; - } - } - - } -} - -void CG_ParticleImpactSmokePuff (qhandle_t pshader, vec3_t origin) -{ - cparticle_t *p; - - if (!pshader) - CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n"); - - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - p->time = cg.time; - p->alpha = 0.25; - p->alphavel = 0; - p->roll = crandom()*179; - - p->pshader = pshader; - - p->endtime = cg.time + 1000; - p->startfade = cg.time + 100; - - p->width = rand()%4 + 8; - p->height = rand()%4 + 8; - - p->endheight = p->height *2; - p->endwidth = p->width * 2; - - p->endtime = cg.time + 500; - - p->type = P_SMOKE_IMPACT; - - VectorCopy( origin, p->org ); - VectorSet(p->vel, 0, 0, 20); - VectorSet(p->accel, 0, 0, 20); - - p->rotate = qtrue; -} - -void CG_Particle_Bleed (qhandle_t pshader, vec3_t start, vec3_t dir, int fleshEntityNum, int duration) -{ - cparticle_t *p; - - if (!pshader) - CG_Printf ("CG_Particle_Bleed pshader == ZERO!\n"); - - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - p->time = cg.time; - p->alpha = 1.0; - p->alphavel = 0; - p->roll = 0; - - p->pshader = pshader; - - p->endtime = cg.time + duration; - - if (fleshEntityNum) - p->startfade = cg.time; - else - p->startfade = cg.time + 100; - - p->width = 4; - p->height = 4; - - p->endheight = 4+rand()%3; - p->endwidth = p->endheight; - - p->type = P_SMOKE; - - VectorCopy( start, p->org ); - p->vel[0] = 0; - p->vel[1] = 0; - p->vel[2] = -20; - VectorClear( p->accel ); - - p->rotate = qfalse; - - p->roll = rand()%179; - - p->color = BLOODRED; - p->alpha = 0.75; - -} - -void CG_Particle_OilParticle (qhandle_t pshader, centity_t *cent) -{ - cparticle_t *p; - - int time; - int time2; - float ratio; - - float duration = 1500; - - time = cg.time; - time2 = cg.time + cent->currentState.time; - - ratio =(float)1 - ((float)time / (float)time2); - - if (!pshader) - CG_Printf ("CG_Particle_OilParticle == ZERO!\n"); - - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - p->time = cg.time; - p->alpha = 1.0; - p->alphavel = 0; - p->roll = 0; - - p->pshader = pshader; - - p->endtime = cg.time + duration; - - p->startfade = p->endtime; - - p->width = 1; - p->height = 3; - - p->endheight = 3; - p->endwidth = 1; - - p->type = P_SMOKE; - - VectorCopy(cent->currentState.origin, p->org ); - - p->vel[0] = (cent->currentState.origin2[0] * (16 * ratio)); - p->vel[1] = (cent->currentState.origin2[1] * (16 * ratio)); - p->vel[2] = (cent->currentState.origin2[2]); - - p->snum = 1.0f; - - VectorClear( p->accel ); - - p->accel[2] = -20; - - p->rotate = qfalse; - - p->roll = rand()%179; - - p->alpha = 0.75; - -} - - -void CG_Particle_OilSlick (qhandle_t pshader, centity_t *cent) -{ - cparticle_t *p; - - if (!pshader) - CG_Printf ("CG_Particle_OilSlick == ZERO!\n"); - - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - p->time = cg.time; - - if (cent->currentState.angles2[2]) - p->endtime = cg.time + cent->currentState.angles2[2]; - else - p->endtime = cg.time + 60000; - - p->startfade = p->endtime; - - p->alpha = 1.0; - p->alphavel = 0; - p->roll = 0; - - p->pshader = pshader; - - if (cent->currentState.angles2[0] || cent->currentState.angles2[1]) - { - p->width = cent->currentState.angles2[0]; - p->height = cent->currentState.angles2[0]; - - p->endheight = cent->currentState.angles2[1]; - p->endwidth = cent->currentState.angles2[1]; - } - else - { - p->width = 8; - p->height = 8; - - p->endheight = 16; - p->endwidth = 16; - } - - p->type = P_FLAT_SCALEUP; - - p->snum = 1.0; - - VectorCopy(cent->currentState.origin, p->org ); - - p->org[2]+= 0.55 + (crandom() * 0.5); - - p->vel[0] = 0; - p->vel[1] = 0; - p->vel[2] = 0; - VectorClear( p->accel ); - - p->rotate = qfalse; - - p->roll = rand()%179; - - p->alpha = 0.75; - -} - -void CG_OilSlickRemove (centity_t *cent) -{ - cparticle_t *p, *next; - int id; - - id = 1.0f; - - if (!id) - CG_Printf ("CG_OilSlickRevove NULL id\n"); - - for (p=active_particles ; p ; p=next) - { - next = p->next; - - if (p->type == P_FLAT_SCALEUP) - { - if (p->snum == id) - { - p->endtime = cg.time + 100; - p->startfade = p->endtime; - p->type = P_FLAT_SCALEUP_FADE; - - } - } - - } -} - -qboolean ValidBloodPool (vec3_t start) -{ -#define EXTRUDE_DIST 0.5 - - vec3_t angles; - vec3_t right, up; - vec3_t this_pos, x_pos, center_pos, end_pos; - int x, y; - int fwidth, fheight; - trace_t trace; - vec3_t normal; - - fwidth = 16; - fheight = 16; - - VectorSet (normal, 0, 0, 1); - - vectoangles (normal, angles); - AngleVectors (angles, NULL, right, up); - - VectorMA (start, EXTRUDE_DIST, normal, center_pos); - - for (x= -fwidth/2; xendpos, start); - legit = ValidBloodPool (start); - - if (!legit) - return; - - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - p->time = cg.time; - - p->endtime = cg.time + 3000; - p->startfade = p->endtime; - - p->alpha = 1.0; - p->alphavel = 0; - p->roll = 0; - - p->pshader = pshader; - - rndSize = 0.4 + random()*0.6; - - p->width = 8*rndSize; - p->height = 8*rndSize; - - p->endheight = 16*rndSize; - p->endwidth = 16*rndSize; - - p->type = P_FLAT_SCALEUP; - - VectorCopy(start, p->org ); - - p->vel[0] = 0; - p->vel[1] = 0; - p->vel[2] = 0; - VectorClear( p->accel ); - - p->rotate = qfalse; - - p->roll = rand()%179; - - p->alpha = 0.75; - - p->color = BLOODRED; -} - -#define NORMALSIZE 16 -#define LARGESIZE 32 - -void CG_ParticleBloodCloud (centity_t *cent, vec3_t origin, vec3_t dir) -{ - float length; - float dist; - float crittersize; - vec3_t angles, forward; - vec3_t point; - cparticle_t *p; - int i; - - dist = 0; - - length = VectorLength (dir); - vectoangles (dir, angles); - AngleVectors (angles, forward, NULL, NULL); - - crittersize = LARGESIZE; - - if (length) - dist = length / crittersize; - - if (dist < 1) - dist = 1; - - VectorCopy (origin, point); - - for (i=0; inext; - p->next = active_particles; - active_particles = p; - - p->time = cg.time; - p->alpha = 1.0; - p->alphavel = 0; - p->roll = 0; - - p->pshader = cgs.media.smokePuffShader; - - p->endtime = cg.time + 350 + (crandom() * 100); - - p->startfade = cg.time; - - p->width = LARGESIZE; - p->height = LARGESIZE; - p->endheight = LARGESIZE; - p->endwidth = LARGESIZE; - - p->type = P_SMOKE; - - VectorCopy( origin, p->org ); - - p->vel[0] = 0; - p->vel[1] = 0; - p->vel[2] = -1; - - VectorClear( p->accel ); - - p->rotate = qfalse; - - p->roll = rand()%179; - - p->color = BLOODRED; - - p->alpha = 0.75; - - } - - -} - -void CG_ParticleSparks (vec3_t org, vec3_t vel, int duration, float x, float y, float speed) -{ - cparticle_t *p; - - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - p->time = cg.time; - - p->endtime = cg.time + duration; - p->startfade = cg.time + duration/2; - - p->color = EMISIVEFADE; - p->alpha = 0.4f; - p->alphavel = 0; - - p->height = 0.5; - p->width = 0.5; - p->endheight = 0.5; - p->endwidth = 0.5; - - p->pshader = cgs.media.tracerShader; - - p->type = P_SMOKE; - - VectorCopy(org, p->org); - - p->org[0] += (crandom() * x); - p->org[1] += (crandom() * y); - - p->vel[0] = vel[0]; - p->vel[1] = vel[1]; - p->vel[2] = vel[2]; - - p->accel[0] = p->accel[1] = p->accel[2] = 0; - - p->vel[0] += (crandom() * 4); - p->vel[1] += (crandom() * 4); - p->vel[2] += (20 + (crandom() * 10)) * speed; - - p->accel[0] = crandom () * 4; - p->accel[1] = crandom () * 4; - -} - -void CG_ParticleDust (centity_t *cent, vec3_t origin, vec3_t dir) -{ - float length; - float dist; - float crittersize; - vec3_t angles, forward; - vec3_t point; - cparticle_t *p; - int i; - - dist = 0; - - VectorNegate (dir, dir); - length = VectorLength (dir); - vectoangles (dir, angles); - AngleVectors (angles, forward, NULL, NULL); - - crittersize = LARGESIZE; - - if (length) - dist = length / crittersize; - - if (dist < 1) - dist = 1; - - VectorCopy (origin, point); - - for (i=0; inext; - p->next = active_particles; - active_particles = p; - - p->time = cg.time; - p->alpha = 5.0; - p->alphavel = 0; - p->roll = 0; - - p->pshader = cgs.media.smokePuffShader; - - // RF, stay around for long enough to expand and dissipate naturally - if (length) - p->endtime = cg.time + 4500 + (crandom() * 3500); - else - p->endtime = cg.time + 750 + (crandom() * 500); - - p->startfade = cg.time; - - p->width = LARGESIZE; - p->height = LARGESIZE; - - // RF, expand while falling - p->endheight = LARGESIZE*3.0; - p->endwidth = LARGESIZE*3.0; - - if (!length) - { - p->width *= 0.2f; - p->height *= 0.2f; - - p->endheight = NORMALSIZE; - p->endwidth = NORMALSIZE; - } - - p->type = P_SMOKE; - - VectorCopy( point, p->org ); - - p->vel[0] = crandom()*6; - p->vel[1] = crandom()*6; - p->vel[2] = random()*20; - - // RF, add some gravity/randomness - p->accel[0] = crandom()*3; - p->accel[1] = crandom()*3; - p->accel[2] = -PARTICLE_GRAVITY*0.4; - - VectorClear( p->accel ); - - p->rotate = qfalse; - - p->roll = rand()%179; - - p->alpha = 0.75; - - } - - -} - -void CG_ParticleMisc (qhandle_t pshader, vec3_t origin, int size, int duration, float alpha) -{ - cparticle_t *p; - - if (!pshader) - CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n"); - - if (!free_particles) - return; - - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - p->time = cg.time; - p->alpha = 1.0; - p->alphavel = 0; - p->roll = rand()%179; - - p->pshader = pshader; - - if (duration > 0) - p->endtime = cg.time + duration; - else - p->endtime = duration; - - p->startfade = cg.time; - - p->width = size; - p->height = size; - - p->endheight = size; - p->endwidth = size; - - p->type = P_SPRITE; - - VectorCopy( origin, p->org ); - - p->rotate = qfalse; -} diff --git a/code/cgame/cg_players.c b/code/cgame/cg_players.c index e5cf2f0..e880c82 100644 --- a/code/cgame/cg_players.c +++ b/code/cgame/cg_players.c @@ -1,44 +1,46 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ // // cg_players.c -- handle the media and animation for player entities -#include "cg_local.h" -char *cg_customSoundNames[MAX_CUSTOM_SOUNDS] = { +#define cg_players_c //RPG-X: J2J - Added to help solve LNK2005 errors (special case for cg_players.c) + +#include "cg_local.h" +#include "cg_screenfx.h" +#include "fx_local.h" +//#include "cg_anims.h" //RPG-X: J2J - Added for animation string table. + +const char *cg_customSoundNames[MAX_CUSTOM_SOUNDS] = { "*death1.wav", "*death2.wav", "*death3.wav", "*jump1.wav", - "*pain25_1.wav", - "*pain50_1.wav", - "*pain75_1.wav", - "*pain100_1.wav", + "*pain25.wav", + "*pain50.wav", + "*pain75.wav", + "*pain100.wav", "*falling1.wav", "*gasp.wav", "*drown.wav", "*fall1.wav", - "*taunt.wav" + "*taunt1.wav", + "*taunt2.wav", + "*taunt3.wav", + "*taunt4.wav", + "*taunt5.wav" }; +stringID_table_t BoltonTable[BOLTON_MAX + 1] = +{ + { ENUM2STRING(BOLTON_HEAD) }, + { ENUM2STRING(BOLTON_TORSO) }, + { ENUM2STRING(BOLTON_LEGS) }, + { NULL, -1 } +}; + +int timeParam; +//int beamTimeParam; //RPG-X : TiM - Beaming + +int entNum; +extern char* BG_RegisterRace( const char *name ); /* ================ @@ -51,7 +53,7 @@ sfxHandle_t CG_CustomSound( int clientNum, const char *soundName ) { int i; if ( soundName[0] != '*' ) { - return trap_S_RegisterSound( soundName, qfalse ); + return trap_S_RegisterSound( soundName ); } if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) { @@ -69,12 +71,336 @@ sfxHandle_t CG_CustomSound( int clientNum, const char *soundName ) { return 0; } +/* +============================================================================= +ANIM SOUND CONFIG LOADING AND PLAYING + +============================================================================= +*/ + +/* +void CG_PlayerAnimSounds( animsounds_t *animSounds, int frame, const vec3_t org, int entNum ) + +play any keyframed sounds - only when start a new frame +This func is called once for legs and once for torso +*/ +//void CG_PlayerAnimSounds( animsounds_t *animSounds, int frame, int entNum, qboolean metal ) +void CG_PlayerAnimSounds( animsounds_t *animSounds, int frame, int eNum, int surfType) +{ + int i; + int holdSnd = -1; + qboolean playSound = qfalse; + + /*if ( entNum == cg.predictedPlayerState.clientNum && !cg.renderingThirdPerson ) + {//player in first person view does not play any keyframed sounds + return; + }*/ + + // Check for anim sound + for (i=0;i irandom(0, 99) ) + { + playSound = qtrue; + } + break; + } + } + + // Play sound + if (holdSnd != -1 && playSound) + { + if (holdSnd != 0) // 0 = default sound, ie file was missing + { + trap_S_StartSound( NULL, eNum, CHAN_BODY, holdSnd ); //CHAN_AUTO + } + + } +} + +void ParseAnimationSndBlock(const char *filename, animsounds_t *animSounds, animation_t *animations, int *i,char **text_p) +{ + char *token; + char soundString[MAX_QPATH]; + int lowestVal, highestVal; + int animNum, num, n; + + // get past starting bracket + while(1) + { + token = COM_Parse( text_p ); + if ( !Q_stricmp( token, "{" ) ) + { + break; + } + } + + animSounds += *i; + + // read information for each frame + while ( 1 ) + { + // Get base frame of sequence + token = COM_Parse( text_p ); + if ( !token || !token[0]) + { + break; + } + + if ( !Q_stricmp( token, "}" ) ) // At end of block + { + break; + } + + //Compare to same table as animations used + // so we don't have to use actual numbers for animation first frames, + // just need offsets. + //This way when animation numbers change, this table won't have to be updated, + // at least not much. + animNum = GetIDForString(animTable, token); + if(animNum == -1) + {//Unrecognized ANIM ENUM name, or we're skipping this line, keep going till you get a good one + Com_Printf(S_COLOR_YELLOW"WARNING: Unknown token %s in animSound file %s\n", token, filename ); + continue; + } + + if ( animations[animNum].numFrames == 0 ) + {//we don't use this anim + Com_Printf(S_COLOR_YELLOW"WARNING: %s animsounds.cfg: anim %s not used by this model\n", filename, token); + + // Get offset to frame within sequence + token = COM_Parse( text_p ); + //get soundstring + token = COM_Parse( text_p ); + //get lowest value + token = COM_Parse( text_p ); + //get highest value + token = COM_Parse( text_p ); + //get probability + token = COM_Parse( text_p ); + + continue; + } + + animSounds->keyFrame = animations[animNum].firstFrame; + + // Get offset to frame within sequence + token = COM_Parse( text_p ); + if ( !token ) + { + break; + } + animSounds->keyFrame += atoi( token ); + + //get soundstring + token = COM_Parse( text_p ); + if ( !token ) + { + break; + } + strcpy(soundString, token); + + //get lowest value + token = COM_Parse( text_p ); + if ( !token ) + {//WARNING! BAD TABLE! + break; + } + lowestVal = atoi( token ); + + //get highest value + token = COM_Parse( text_p ); + if ( !token ) + {//WARNING! BAD TABLE! + break; + } + highestVal = atoi( token ); + + //Now precache all the sounds + //NOTE: If we can be assured sequential handles, we can store sound indices + // instead of strings, unfortunately, if these sounds were previously + // registered, we cannot be guaranteed sequential indices. Thus an array + if(lowestVal && highestVal) + { + for ( n = lowestVal, num = 0; n <= highestVal && num < MAX_RANDOM_ANIMSOUNDS; n++, num++ ) + { + animSounds->soundIndex[num] = trap_S_RegisterSound( va( soundString, n ) ); + } + animSounds->numRandomAnimSounds = num - 1; + } + else + { + animSounds->soundIndex[0] = trap_S_RegisterSound( va( soundString ) ); +#ifndef FINAL_BUILD + if ( !animSounds->soundIndex[0] ) + {//couldn't register it - file not found + Com_Printf( S_COLOR_RED "ParseAnimationSndBlock: sound %s does not exist (animsound.cfg %s)!\n", soundString, filename ); + } +#endif + animSounds->numRandomAnimSounds = 0; + } + + + //get probability + token = COM_Parse( text_p ); + if ( !token ) + {//WARNING! BAD TABLE! + break; + } + + animSounds->probability = atoi( token ); + ++animSounds; + ++*i; + } +} + + +/* +====================== +CG_ParseAnimationSndFile + +Read a configuration file containing animation sounds +models/players/munro/animsounds.cfg, etc + +This file's presence is not required + +====================== +*/ +static int CG_ParseAnimationSndFile( const char *filename, int animFileIndex ) +{ + char *text_p; + int len; + char *token; + char text[20000]; + fileHandle_t f; + int i, j, upper_i, lower_i; + animsounds_t *lowerAnimSounds; + animsounds_t *upperAnimSounds; + animation_t *animations; + + /*if ( knownAnimFileSets[animFileIndex].soundsCached ) + {//already cached this one + return; + }*/ + + for ( i = 0; i < cg_numSndAnims; i++ ) { + if ( !Q_stricmp( filename, cg_animsSndList[i].animSndFileRoute ) ) { + return i; + } + } + + //Mark this anim set so that we know we tried to load he sounds, don't care if the load failed + //knownAnimFileSets[animFileIndex].soundsCached = qtrue; + + animations = cg_animsList[animFileIndex].animations; + lowerAnimSounds = cg_animsSndList[cg_numSndAnims].lowerAnimSounds; + upperAnimSounds = cg_animsSndList[cg_numSndAnims].upperAnimSounds; + + //initialize anim sound array + for(i = 0; i < MAX_ANIM_SOUNDS; i++) + { + upperAnimSounds[i].numRandomAnimSounds = 0; + lowerAnimSounds[i].numRandomAnimSounds = 0; + for(j = 0; j < MAX_RANDOM_ANIMSOUNDS; j++) + { + upperAnimSounds[i].soundIndex[j] = -1; + lowerAnimSounds[i].soundIndex[j] = -1; + } + } + + // load the file + len = trap_FS_FOpenFile( filename, &f, FS_READ ); + if ( len <= 0 ) + {//no file + return -1; + } + if ( len >= sizeof( text ) - 1 ) + { + CG_Printf( "File %s too long\n", filename ); + return -1; + } + + trap_FS_Read( text, len, f ); + text[len] = 0; + trap_FS_FCloseFile( f ); + + // parse the text + text_p = text; + upper_i =0; + lower_i =0; + + // read information for batches of sounds (UPPER or LOWER) + while ( 1 ) + { + // Get base frame of sequence + token = COM_Parse( &text_p ); + if ( !token || !token[0] ) + { + break; + } + + if ( !Q_stricmp(token,"UPPERSOUNDS") ) // A batch of upper sounds + { + ParseAnimationSndBlock( filename, upperAnimSounds, animations, &upper_i, &text_p ); + } + + else if ( !Q_stricmp(token,"LOWERSOUNDS") ) // A batch of lower sounds + { + ParseAnimationSndBlock( filename, lowerAnimSounds, animations, &lower_i, &text_p ); + } + } + + i = cg_numSndAnims; + cg_numSndAnims++; + + return i; +} /* ============================================================================= -CLIENT INFO +MODEL SCRIPT LOADING ============================================================================= */ @@ -84,10 +410,20 @@ CLIENT INFO CG_ParseAnimationFile Read a configuration file containing animation coutns and rates -models/players/visor/animation.cfg, etc +models/players_rpgx/munro/animation.cfg, etc + +TiM: Small modification. Based on the nuber of animations parsed, +this will return an index to the cell in the global animation array +where the relevant animation data is kept. Based on both the JKA concept and the EF method +of caching assets, this is far more efficient since it means that if two people use models +with the same body models using the same animation data, the anim data will ony need be loaded once :) + +A lot more efficient considering how many freakin more animations we introduced with this model system lol. ====================== */ -static qboolean CG_ParseAnimationFile( const char *filename, clientInfo_t *ci ) { +// +//static qboolean CG_ParseAnimationFile( const char *filename, clientInfo_t *ci ) { +static int CG_ParseAnimationFile( const char* filename/*, clientInfo_t *ci*/ ) { char *text_p, *prev; int len; int i; @@ -98,31 +434,53 @@ static qboolean CG_ParseAnimationFile( const char *filename, clientInfo_t *ci ) fileHandle_t f; animation_t *animations; - animations = ci->animations; + //CG_Printf( "Anim is %s\n", filename ); + + if ( cg_numAnims > 0 ) { + for ( i = 0; i <= cg_numAnims; i++ ) { + if ( !Q_stricmpn( cg_animsList[i].animFileRoute, filename, (int)strlen( filename ) ) ) { //We found a matching anim set + //Com_Printf( S_COLOR_RED "Using index: %i\n", i ); + return i; + } + } + } // load the file len = trap_FS_FOpenFile( filename, &f, FS_READ ); if ( len <= 0 ) { - return qfalse; + CG_Printf( S_COLOR_RED "File %s not found\n", filename ); + return -1; //qfalse } if ( len >= sizeof( text ) - 1 ) { - CG_Printf( "File %s too long\n", filename ); - trap_FS_FCloseFile( f ); - return qfalse; + CG_Printf( S_COLOR_RED "File %s too long\n", filename ); + return -1; //qfalse } trap_FS_Read( text, len, f ); text[len] = 0; trap_FS_FCloseFile( f ); + + //animations = ci->animations; + animations = cg_animsList[cg_numAnims].animations; + + //copy the file name to the gloabl anims array. It doesn't matter + //if it returns false, since the same cell will be flushed on the next call then. + memset( cg_animsList[cg_numAnims].animFileRoute, 0, MAX_QPATH ); + Q_strncpyz( cg_animsList[cg_numAnims].animFileRoute, filename, MAX_QPATH ); + + //flush the anims + memset( animations, 0, sizeof( animations ) ); + // parse the text text_p = text; skip = 0; // quite the compiler warning + /* ci->footsteps = FOOTSTEP_NORMAL; VectorClear( ci->headOffset ); ci->gender = GENDER_MALE; - ci->fixedlegs = qfalse; - ci->fixedtorso = qfalse; + + Q_strncpyz(ci->soundPath, ci->modelName, sizeof(ci->soundPath));*/ // read optional parameters while ( 1 ) { @@ -131,21 +489,29 @@ static qboolean CG_ParseAnimationFile( const char *filename, clientInfo_t *ci ) if ( !token ) { break; } - if ( !Q_stricmp( token, "footsteps" ) ) { + /*if ( !Q_stricmp( token, "footsteps" ) ) { token = COM_Parse( &text_p ); if ( !token ) { break; } if ( !Q_stricmp( token, "default" ) || !Q_stricmp( token, "normal" ) ) { ci->footsteps = FOOTSTEP_NORMAL; - } else if ( !Q_stricmp( token, "boot" ) ) { + } else if ( !Q_stricmp( token, "borg" ) ) { + ci->footsteps = FOOTSTEP_BORG; + } else if ( !Q_stricmp( token, "reaver" ) ) { + ci->footsteps = FOOTSTEP_REAVER; + } else if ( !Q_stricmp( token, "species" ) ) { + ci->footsteps = FOOTSTEP_SPECIES; + } else if ( !Q_stricmp( token, "warbot" ) ) { + ci->footsteps = FOOTSTEP_WARBOT; + } else if ( !Q_stricmp( token, "boot" ) ) { ci->footsteps = FOOTSTEP_BOOT; - } else if ( !Q_stricmp( token, "flesh" ) ) { - ci->footsteps = FOOTSTEP_FLESH; - } else if ( !Q_stricmp( token, "mech" ) ) { - ci->footsteps = FOOTSTEP_MECH; - } else if ( !Q_stricmp( token, "energy" ) ) { - ci->footsteps = FOOTSTEP_ENERGY; + } else if ( !Q_stricmp( token, "flesh" ) ) { // Old Q3 defaults, for compatibility. -PJL + ci->footsteps = FOOTSTEP_SPECIES; + } else if ( !Q_stricmp( token, "mech" ) ) { // Ditto + ci->footsteps = FOOTSTEP_BORG; + } else if ( !Q_stricmp( token, "energy" ) ) { // Ditto + ci->footsteps = FOOTSTEP_BORG; } else { CG_Printf( "Bad footsteps parm in %s: %s\n", filename, token ); } @@ -172,13 +538,14 @@ static qboolean CG_ParseAnimationFile( const char *filename, clientInfo_t *ci ) ci->gender = GENDER_MALE; } continue; - } else if ( !Q_stricmp( token, "fixedlegs" ) ) { - ci->fixedlegs = qtrue; + } else if ( !Q_stricmp( token, "soundpath" ) ) { + token = COM_Parse( &text_p ); + if ( !token ) { + break; + } + Q_strncpyz(ci->soundPath,token,sizeof (ci->soundPath) ); continue; - } else if ( !Q_stricmp( token, "fixedtorso" ) ) { - ci->fixedtorso = qtrue; - continue; - } + } */ // if it is a number, start parsing animations if ( token[0] >= '0' && token[0] <= '9' ) { @@ -192,50 +559,32 @@ static qboolean CG_ParseAnimationFile( const char *filename, clientInfo_t *ci ) for ( i = 0 ; i < MAX_ANIMATIONS ; i++ ) { token = COM_Parse( &text_p ); - if ( !*token ) { - if( i >= TORSO_GETFLAG && i <= TORSO_NEGATIVE ) { - animations[i].firstFrame = animations[TORSO_GESTURE].firstFrame; - animations[i].frameLerp = animations[TORSO_GESTURE].frameLerp; - animations[i].initialLerp = animations[TORSO_GESTURE].initialLerp; - animations[i].loopFrames = animations[TORSO_GESTURE].loopFrames; - animations[i].numFrames = animations[TORSO_GESTURE].numFrames; - animations[i].reversed = qfalse; - animations[i].flipflop = qfalse; - continue; - } + if ( !token ) { break; } animations[i].firstFrame = atoi( token ); // leg only frames are adjusted to not count the upper body only frames - if ( i == LEGS_WALKCR ) { - skip = animations[LEGS_WALKCR].firstFrame - animations[TORSO_GESTURE].firstFrame; + if ( i == LEGS_KNEEL1 ) { //LEGS_WALKCR + skip = animations[LEGS_KNEEL1].firstFrame - animations[TORSO_ACTIVATEMEDKIT1].firstFrame; //TORSO_GESTURE } - if ( i >= LEGS_WALKCR && i= LEGS_KNEEL1 ) { animations[i].firstFrame -= skip; } token = COM_Parse( &text_p ); - if ( !*token ) { + if ( !token ) { break; } animations[i].numFrames = atoi( token ); - animations[i].reversed = qfalse; - animations[i].flipflop = qfalse; - // if numFrames is negative the animation is reversed - if (animations[i].numFrames < 0) { - animations[i].numFrames = -animations[i].numFrames; - animations[i].reversed = qtrue; - } - token = COM_Parse( &text_p ); - if ( !*token ) { + if ( !token ) { break; } animations[i].loopFrames = atoi( token ); token = COM_Parse( &text_p ); - if ( !*token ) { + if ( !token ) { break; } fps = atof( token ); @@ -247,304 +596,962 @@ static qboolean CG_ParseAnimationFile( const char *filename, clientInfo_t *ci ) } if ( i != MAX_ANIMATIONS ) { - CG_Printf( "Error parsing animation file: %s\n", filename ); + CG_Printf( S_COLOR_RED "Error parsing animation file: %s", filename ); + //return qfalse; + return -1; + } + + //CG_Printf( S_COLOR_RED "Cached File: %s\n", cgs.animsList[cgs.numAnims].animFileRoute ); + //return ++cg_numAnims; + + i = cg_numAnims; + if ( cg_numAnims < MAX_CLIENTS ) { + cg_numAnims++; //offset for the next time :) + } + + return i; + //return qtrue; +} + +/* +====================== +CG_InitModelData +by TiM + +Initialize default values +in case the crazy modder +left out some of the keys. + +In most cases, the fields +will just be left blank. +No point in using extra +resources if they weren't +specified. +====================== +*/ + +static void CG_InitModelData( clientInfo_t *ci ) { + + ci->holsterModel = 0; + ci->hasRanks = qfalse; + + //initialize all model + skin data as 0, so it can be told if they don't get + //values assigned in the script parser, in which case we exit. + ci->headModel = 0; + ci->torsoModel = 0; + ci->legsModel = 0; + + ci->headSkin = 0; + ci->headSkinBlink = 0; //doesn't matter if left 0; won't end the parser + ci->headSkinFrown = 0; + ci->headSkinFrownBlink = 0; + ci->torsoSkin = 0; + ci->legsSkin = 0; + + //doesn't matter if left 0 + ci->headBlinkTime.minSeconds = 0; + ci->headBlinkTime.maxSeconds = 0; + + ci->nextTalkTime = 0; + ci->currentTalkSkin = 0; + + ci->headSkinTalk[0] = 0; + ci->headSkinTalk[1] = 0; + ci->headSkinTalk[2] = 0; + ci->headSkinTalk[3] = 0; + + //animation.cfg former inits + ci->footsteps = FOOTSTEP_NORMAL; + VectorClear( ci->headOffset ); + ci->gender = GENDER_MALE; + Q_strncpyz(ci->soundPath, ci->charName, sizeof(ci->soundPath)); + + //set animIndex to -1. if still -1 at the end, we return false, coz we gotz no anims + ci->animIndex = -1; + ci->animSndIndex = -1; + + memset( &ci->boltonTags, 0, sizeof(ci->boltonTags)); + + ci->isHazardModel = qfalse; +} + +/* +===================== +CG_ParseSkinSetDataFile +by TiM + +Parses a separate.skinset +file to get the skin data +for this model. +====================== +*/ + +static qboolean CG_ParseSkinSetDataFile( clientInfo_t *ci, const char *skinSetFrame, const char *charName, const char *skinName ) +{ + char* skinStar; + char skinSetName[MAX_QPATH]; + char skinSetRoute[MAX_QPATH]; + char* token; + char* textPtr; + char buffer[5000]; + int len; + fileHandle_t f; + int n, i; + + if ( ( skinStar = strstr( skinSetFrame, "*" ) ) == NULL ) + { + CG_Printf( S_COLOR_RED "ERROR: No '*' specified in model skin set!\n" ); + return qfalse; + } + else + { + //star is at front + if ( skinStar == skinSetFrame ) + { + skinStar++; + Com_sprintf( skinSetName, sizeof( skinSetName ), "%s%s", skinName, skinStar ); + } + //star is at end + else if ((int)(skinStar - skinSetFrame)+1 == (int)strlen(skinSetFrame) ) + { + Q_strncpyz( skinSetName, skinSetFrame, strlen( skinSetFrame ) ); + Q_strcat( skinSetName, sizeof( skinSetName ), skinName ); + } + else + { + CG_Printf( "ERROR: The '*' in %s must be on either the start or end, not the middle.\n", skinSetFrame ); + return qfalse; + } + } + + //CG_Printf( S_COLOR_RED "DEBUG: skinSetName = %s \n", skinSetName ); + + Com_sprintf( skinSetRoute, sizeof( skinSetRoute ), "models/players_rpgx/%s/%s.skinset", charName, skinSetName ); + + len = trap_FS_FOpenFile( skinSetRoute, &f, FS_READ ); + + if ( len <= 0 ) + { + CG_Printf( S_COLOR_RED "ERROR: Could not open file: %s\n", skinSetRoute ); return qfalse; } - // crouch backward animation - memcpy(&animations[LEGS_BACKCR], &animations[LEGS_WALKCR], sizeof(animation_t)); - animations[LEGS_BACKCR].reversed = qtrue; - // walk backward animation - memcpy(&animations[LEGS_BACKWALK], &animations[LEGS_WALK], sizeof(animation_t)); - animations[LEGS_BACKWALK].reversed = qtrue; - // flag moving fast - animations[FLAG_RUN].firstFrame = 0; - animations[FLAG_RUN].numFrames = 16; - animations[FLAG_RUN].loopFrames = 16; - animations[FLAG_RUN].frameLerp = 1000 / 15; - animations[FLAG_RUN].initialLerp = 1000 / 15; - animations[FLAG_RUN].reversed = qfalse; - // flag not moving or moving slowly - animations[FLAG_STAND].firstFrame = 16; - animations[FLAG_STAND].numFrames = 5; - animations[FLAG_STAND].loopFrames = 0; - animations[FLAG_STAND].frameLerp = 1000 / 20; - animations[FLAG_STAND].initialLerp = 1000 / 20; - animations[FLAG_STAND].reversed = qfalse; - // flag speeding up - animations[FLAG_STAND2RUN].firstFrame = 16; - animations[FLAG_STAND2RUN].numFrames = 5; - animations[FLAG_STAND2RUN].loopFrames = 1; - animations[FLAG_STAND2RUN].frameLerp = 1000 / 15; - animations[FLAG_STAND2RUN].initialLerp = 1000 / 15; - animations[FLAG_STAND2RUN].reversed = qtrue; - // - // new anims changes - // -// animations[TORSO_GETFLAG].flipflop = qtrue; -// animations[TORSO_GUARDBASE].flipflop = qtrue; -// animations[TORSO_PATROL].flipflop = qtrue; -// animations[TORSO_AFFIRMATIVE].flipflop = qtrue; -// animations[TORSO_NEGATIVE].flipflop = qtrue; - // + if ( len > sizeof( buffer) - 1 ) + { + CG_Printf( S_COLOR_RED "ERROR: Imported file is too big for buffer: %s. Len is %i\n", skinSetRoute, len ); + return qfalse; + } + + trap_FS_Read( buffer, len, f ); + + trap_FS_FCloseFile( f ); + + if ( !buffer[0] ) + { + CG_Printf( S_COLOR_RED "ERROR: Could not import data from %s\n", skinSetRoute ); + return qfalse; + } + + buffer[len] = '\0'; + + textPtr = buffer; + + token = COM_Parse( &textPtr ); + + if ( Q_stricmp( token, "{" ) ) + { + CG_Printf( S_COLOR_RED "ERROR: Skinset %s did not start with a '{'\n", skinSetRoute ); + return qfalse; + } + else + { + while ( 1 ) + { //while we don't hit the closing brace + + token = COM_Parse( &textPtr ); //parse + if ( !token[0] ) { //error check + break; + } + + //head skin when blinking + //must be before headskin, or the damn thing will think the two are the same :P + if ( !Q_stricmp( token, "headSkinBlink" ) ) { + if ( COM_ParseString( &textPtr, &token ) ) { + continue; + } + + if ( !cg_noBlinkingHeads.integer ) { + ci->headSkinBlink = trap_R_RegisterSkin( token ); + + //We'll alert them, but not cancel the loop + if ( !ci->headSkinBlink ) + Com_Printf( S_COLOR_RED "WARNING: Couldn't load headSkinBlink: %s\n", token); + } + + continue; + } + + //head blink time + else if ( !Q_stricmpn( token, "headBlinkTime", 13 ) ) { + //Done this way so we know we got two valid args b4 proceeding + if ( COM_ParseInt( &textPtr, &n ) ) { //first arg + SkipRestOfLine( &textPtr ); + continue; + } + + if ( COM_ParseInt( &textPtr, &i ) ) { //2nd arg + SkipRestOfLine( &textPtr ); + continue; + } + + //Bug: if the stupid n00b of a modder made + //the minimum time larger than the max time >.< + if ( n > i ) + { + Com_Printf( S_COLOR_RED "ERROR: Minimum blink time was larger than maximum blink time.\n" ); + continue; + } + + if ( !cg_noBlinkingHeads.integer ) { + ci->headBlinkTime.minSeconds = n; + ci->headBlinkTime.maxSeconds = i; + } + continue; + } + + else if ( !Q_stricmpn( token, "headSkinFrownBlink", 18 ) ) { + if ( COM_ParseString( &textPtr, &token ) ) { + continue; + } + + if ( !cg_noFrowningHeads.integer ) { + ci->headSkinFrownBlink = trap_R_RegisterSkin( token ); + + if ( !ci->headSkinFrownBlink ) + Com_Printf( S_COLOR_RED "WARNING: Was unable to load frown blink skin: %s\n", token ); + } + + continue; + } + + else if ( !Q_stricmpn( token, "headSkinFrown", 13 ) ) { + if ( COM_ParseString( &textPtr, &token ) ) { + continue; + } + + //Only cache if we want to + if ( !cg_noFrowningHeads.integer ) { + ci->headSkinFrown = trap_R_RegisterSkin( token ); + } + + if ( !cg_noFrowningHeads.integer && !ci->headSkinFrown ) { + Com_Printf( S_COLOR_RED "WARNING: Couldn't load frowning skin: %s\n", token ); + } + continue; + } + + else if ( !Q_stricmpn( token, "torsoSkin", 9 ) ) { + if (COM_ParseString( &textPtr, &token ) ) { + continue; + } + + ci->torsoSkin = trap_R_RegisterSkin( token ); + if (!ci->torsoSkin ) { + Com_Printf( S_COLOR_RED "ERROR: Couldn't load torsoSkin: %s\n", token); + } + continue; + } + + else if ( !Q_stricmpn( token, "legsSkin", 8 ) ) { + if (COM_ParseString( &textPtr, &token ) ) { + continue; + } + + ci->legsSkin = trap_R_RegisterSkin( token ); + if (!ci->legsSkin ) { + Com_Printf( S_COLOR_RED "ERROR: Couldn't load legsSkin: %s\n", token); + } + continue; + } + + else if ( !Q_stricmpn( token, "headSkinTalk", 12 ) && !cg_noTalkingHeads.integer ) { + + token = COM_Parse( &textPtr ); //parse + if ( !token[0] ) { //error check + break; + } + + // if we found no {, then scrub the whole thing + if ( Q_stricmpn( token, "{", 1 ) ) { + continue; + } + else { + i = 0; + while ( 1 ) { + token = COM_Parse( &textPtr ); //parse + if ( !token[0] ) { //error check + break; + } + + ci->headSkinTalk[i] = trap_R_RegisterSkin( token ); + if ( !ci->headSkinTalk[i] ) { + Com_Printf( S_COLOR_RED "ERROR: Unable to parse headSkinTalk file: %s\n", token ); + break; + } + i++; + + //Com_Printf("Registered Skin: %i\n", i); + + if ( !Q_stricmpn( token, "}", 1) ) { + break; + } + + if ( i >= MAX_TALK_SKINS ) { + break; + } + } + } + continue; + } + //head skin + else if ( !Q_stricmpn( token, "headSkin", 8 ) ) { + if ( COM_ParseString( &textPtr, &token ) ) { + continue; + } + + ci->headSkin = trap_R_RegisterSkin( token ); + if ( !ci->headSkin ) { + Com_Printf( S_COLOR_RED "ERROR: Couldn't load headSkin: %s\n", token ); + return qfalse; + } + continue; + } + + if ( !Q_stricmpn( token, "}", 1) ) { + break; + } + } + } + + return qtrue; +} + + +/* +====================== +CG_ParseModelDataFile +by TiM + +Reads in the .model file +needed to put together +a character model. +====================== +*/ +static qboolean CG_ParseModelDataFile( clientInfo_t *ci, const char *charName, + const char *modelName, const char *skinName ) { + fileHandle_t file; + int file_len; + char charText[20000]; + char *textPtr, *prevValue; + char fileName[MAX_QPATH]; + //char animPath[MAX_QPATH]; + int i, n; + char *token; + char legsFileRoute[MAX_QPATH]; + char animSndFileRoute[MAX_QPATH]; + qboolean skinSetFound=qfalse; + //size_t strLen; + + //create the file route + Com_sprintf( fileName, sizeof(fileName), "models/players_rpgx/%s/%s.model", charName, modelName); + + //Okay... gotta get the hang of ANSI C text parsing >.< + //first... I guess load the file + file_len = trap_FS_FOpenFile( fileName, &file, FS_READ ); + //Error handle + //if length was 0, ie file not found or was empty + if (file_len <= 0 ) { + return qfalse; + } + //Another error... if text is WAY bigger than our available buffer O_O + if ( file_len >= sizeof( charText ) - 1 ) { + Com_Printf( S_COLOR_RED "Model Data File %s too long... WAY too long\n", fileName ); + return qfalse; + } + + //initialize the buffer + memset( charText, 0, sizeof( charText ) ); + + //read data into char array + //i guess we use a char array so we can actually specify size/width. + trap_FS_Read( charText, file_len, file ); + //I guess this is needed to mark the EOF. + charText[file_len] = 0; + //Free memory. Close Files + trap_FS_FCloseFile( file ); + + //default values if needed + CG_InitModelData( ci ); + + //Used to just clear any previous parse temp data + COM_BeginParseSession(); + + //transfer our data from a char array to a char ptr. + //needed for the parsing func methinks + textPtr = charText; + + token = COM_Parse( &textPtr ); //COM_Parse seems to work by splitting up each line of text by the spaces, + //and then removes that chunk from the original + //Okay, we should have the beginning variable first... which should be a '{' + + //from the looks of this, I think we have to do this after + //every parse call. O_O + if ( !token[0] ) { + Com_Printf( S_COLOR_RED "No data found in model data buffer!\n"); + return qfalse; + } + + if ( Q_stricmp(token, "{" ) ) { + Com_Printf(S_COLOR_RED "Missing { in %s\n", fileName); + return qfalse; + } + + while ( 1 ) { + prevValue = textPtr; //set a backup + token = COM_Parse( &textPtr ); + + if (!token[0] || !token ) { //we've hit the end of the file. w00t! exit! + break; + } + + //if we randomly find a brace in here (ie a sub-struct that may have no header) + //just skip it. :P + if ( !Q_stricmpn( token, "{", 1 ) ) { + SkipBracedSection ( &textPtr ); + } + + if ( !Q_stricmpn( token, "animsConfig", 11 ) ) { + if( COM_ParseString( &textPtr, &token ) ) { + continue; + } + + ci->animIndex = CG_ParseAnimationFile( token ); + + //no valid anim file found. Don't give up hope though. + //We have a backup resort at the end if need be. :) + if ( ci->animIndex == -1 ) { + Com_Printf( S_COLOR_RED "WARNING: Was unable to load file %s.\n", token ); + } + + continue; + } + + //anim sounds config file + else if ( !Q_stricmpn( token, "animSoundsConfig", 16 ) ) { + if ( COM_ParseString( &textPtr, &token ) ) { + continue; + } + + //check to see if we have a valid animlist we can sync these + //sounds to. if not, we'll put the file route asside, and + //try again at the end. + if ( ci->animIndex >= 0 ) { + ci->animSndIndex = CG_ParseAnimationSndFile( token, ci->animIndex ); + + if ( ci->animSndIndex == -1 ) { + Com_Printf( S_COLOR_RED "WARNING: Unable to load file: %s\n", token ); + } + } + else { + Q_strncpyz( animSndFileRoute, token, sizeof( animSndFileRoute ) ); + } + + continue; + } + + //character's legs model + else if ( !Q_stricmpn( token, "legsModel", 9 ) ) { + + if( COM_ParseString( &textPtr, &token ) ) { + continue; + } + + ci->legsModel = trap_R_RegisterModel( token ); + if (!ci->legsModel) { + Com_Printf( S_COLOR_RED "ERROR: Unable to load legs model: %s\n", token); + return qfalse; + } + + //if loaded no anims yet, copy the legs route to this variable, + //and we'll try again at the end of the function + //if ( ci->animIndex == -1 ) { + Q_strncpyz( legsFileRoute, token, sizeof( legsFileRoute ) ); + //} Actually. just copy it regardless. Just in case + + continue; + } + + //character's torso model + else if ( !Q_stricmpn( token, "torsoModel", 10 ) ) { + if( COM_ParseString( &textPtr, &token ) ) { + continue; + } + ci->torsoModel = trap_R_RegisterModel( token ); + //Com_Printf("Torsomodel passed as %s, %i\n", token, (int)ci->torsoModel); + + if (!ci->torsoModel) { + Com_Printf( S_COLOR_RED "ERROR: Unable to load torso model: %s\n", token); + return qfalse; + } + continue; + } + + //character's headmodel + else if ( !Q_stricmpn( token, "headModel", 9 ) ) { + + //return true = no extra text found on this line - bad! O_O! + if( COM_ParseString( &textPtr, &token ) ) { + continue; + } + + ci->headModel = trap_R_RegisterModel( token ); + if (!ci->headModel) { + Com_Printf( S_COLOR_RED "ERROR: Unable to load head model: %s\n", token); + return qfalse; + } + continue; + } + + //holster model (basically just a null md3 with 2 tags: one for phaser, other for tric) + else if ( !Q_stricmpn( token, "holsterModel", 12 ) ) { + + if( COM_ParseString( &textPtr, &token ) ) { + continue; + } + + ci->holsterModel = trap_R_RegisterModel( token ); + + //You'd hope like hell this will never happen. :P + if (!ci->holsterModel) { + Com_Printf( S_COLOR_RED "ERROR: Unable to load holster model: %s\n", token); + return qfalse; + } + continue; + } + + // Custom bolton models... oi O_o + else if ( !Q_stricmpn( token, "boltonModels", 12 ) ) { + //needed coz '{' could also be on next line + token = COM_Parse( &textPtr ); + if ( !token[0] ) { //if that was it + break; + } else { //else, if next character is '{' + if ( !Q_stricmpn( token, "{", 1 ) ) { + token = COM_Parse( &textPtr ); + if ( !token[0] ) { + break; + } + //loop till we hit the end of the brackets + i = 0; + + while ( Q_stricmp( token, "}" ) ) { + if ( !Q_stricmpn( token, "BOLTON_", 7 ) ) { + + ci->boltonTags[i].modelBase = GetIDForString( BoltonTable, token ); + + if( COM_ParseString( &textPtr, &token ) ) { + continue; + } + + if (!Q_stricmpn( token, "tag_", 4 ) ) { + Q_strncpyz(ci->boltonTags[i].tagName, token, sizeof (ci->boltonTags[i].tagName) ); + + if( COM_ParseString( &textPtr, &token ) ) { + continue; + } + ci->boltonTags[i].tagModel = trap_R_RegisterModel( token ); + + if (!ci->boltonTags[i].tagModel) { + Com_Printf( S_COLOR_RED "WARNING: Unable to load bolton model: %s\n", token); + } + + i++; + + if (i > MAX_BOLTONS -1) { + break; + } + } + } + + //Com_Printf("Index: %i, Name: %s, Handle: %i\n", ci->boltonTags[ci->numBoltOns].modelBase, ci->boltonTags[ci->numBoltOns].tagName, ci->boltonTags[ci->numBoltOns].tagModel ); + token = COM_Parse( &textPtr ); + if ( !token[0] ) { + break; + } + } + } + } + } + + //whether char is allowed to wear ranks + else if ( !Q_stricmpn( token, "hasRanks", 8 ) ) { + if (COM_ParseInt(&textPtr, &n ) ) { + continue; + } + if ( n > 0 ) + ci->hasRanks = qtrue; + else + ci->hasRanks = qfalse; + continue; + } + + //player footsteps. + //FIXME: Is it possible to make these things dynamic, so we can + //put in our own footstep sounds? + /*else if ( !Q_stricmp( token, "footsteps" ) ) { + token = COM_Parse( &textPtr ); + if ( !token ) { + break; + } + if ( !Q_stricmp( token, "default" ) || !Q_stricmp( token, "normal" ) ) { + ci->footsteps = FOOTSTEP_NORMAL; + } else if ( !Q_stricmp( token, "borg" ) ) { + ci->footsteps = FOOTSTEP_BORG; + } else if ( !Q_stricmp( token, "reaver" ) ) { + ci->footsteps = FOOTSTEP_REAVER; + } else if ( !Q_stricmp( token, "species" ) ) { + ci->footsteps = FOOTSTEP_SPECIES; + } else if ( !Q_stricmp( token, "warbot" ) ) { + ci->footsteps = FOOTSTEP_WARBOT; + } else if ( !Q_stricmp( token, "boot" ) ) { + ci->footsteps = FOOTSTEP_BOOT; + } else if ( !Q_stricmp( token, "flesh" ) ) { // Old Q3 defaults, for compatibility. -PJL + ci->footsteps = FOOTSTEP_SPECIES; + } else if ( !Q_stricmp( token, "mech" ) ) { // Ditto + ci->footsteps = FOOTSTEP_BORG; + } else if ( !Q_stricmp( token, "energy" ) ) { // Ditto + ci->footsteps = FOOTSTEP_BORG; + } else { + CG_Printf( "Bad footsteps parm in %s: %s\n", fileName, token ); + } + continue; + } */ + + //offset for player head in the scoreboard or whatever + else if ( !Q_stricmp( token, "headoffset" ) ) { + for ( i = 0 ; i < 3 ; i++ ) { + token = COM_Parse( &textPtr ); + if ( !token ) { + break; + } + ci->headOffset[i] = atof( token ); + } + continue; + } + + //what gender the character is + else if ( !Q_stricmpn( token, "sex", 3 ) ) { + if (COM_ParseString( &textPtr, &token ) ) { + continue; + } + if ( token[0] == 'f' || token[0] == 'F' ) { + ci->gender = GENDER_FEMALE; + } else if ( token[0] == 'n' || token[0] == 'N' ) { + ci->gender = GENDER_NEUTER; + } else { + ci->gender = GENDER_MALE; + } + continue; + } + + //file path to model sound files + else if ( !Q_stricmpn( token, "soundPath", 9 ) ) { + if (COM_ParseString( &textPtr, &token ) ){ + continue; + } + + Q_strncpyz( ci->soundPath, token, sizeof(ci->soundPath) ); + continue; + } + + //TiM - The skinset is defined + else if ( !Q_stricmpn( token, "skinSet", 7 ) ) { + if ( COM_ParseString( &textPtr, &token ) ) { + continue; + } + + if ( CG_ParseSkinSetDataFile( ci, token, charName, skinName ) ) + { + skinSetFound = qtrue; + } + + continue; + } + } + + //if any of the models or skins were left blank, then output false. Coz we need them. :P + if (!ci->headModel || !ci->torsoModel || !ci->legsModel ) { + Com_Printf( S_COLOR_RED "One or more necessary model files weren't loaded from %s\n", fileName ); + return qfalse; + } + + if ( !skinSetFound ) + { + if ( !CG_ParseSkinSetDataFile( ci, va("%s_*", modelName, skinName ), charName, skinName ) ) + { + CG_Printf( S_COLOR_RED "ERROR: Tried loading default skin set, however it failed.\n"); + } + } + + if (!ci->headSkin || !ci->torsoSkin || !ci->legsSkin ) { + + Com_Printf( S_COLOR_RED "One or more necessary skin files weren't loaded from %s\n", fileName ); + return qfalse; + } + + //if modder specified no animations file route, or they did, and it sucked (ie -1 ), + //Then try looking for one in the same directory as the lower.mdr file + + //k... the goal of this is to take a string like + //models/players_rpgx/crewman_male/lower.mdr + //and turn it into + //models/players_rpgx/crewman_male/animation.cfg + + if ( ci->animIndex == -1 && strlen( legsFileRoute ) > 0 ) { + //get length of file route + i = (int)strlen(legsFileRoute); + + while( 1 ) { + //if we looped all the way to the end.... ie BAD + if (i <= 0) { + //we obviously have no animation directory :( + Com_Printf(S_COLOR_RED "ERROR: Was unable to calculate location of animation.cfg for %s\n", fileName); + return qfalse; + } + + //if this is the first '/' we come across from going from the end to the start + if (legsFileRoute[i] == '/' ) { + //copy i bytes of data from token to animpath (effectively giving us the route, with no file) + Q_strncpyz(legsFileRoute, legsFileRoute, (i = i + 2 )); //+2 for the null char these things auto assign at the end... i think + break; //won't work without it anyway :P + } + i--; + } + + //add animation.cfg to the end of the string + Q_strcat(legsFileRoute, sizeof(legsFileRoute), "animation.cfg"); + + //Com_Printf( S_COLOR_RED "WARNING: Failed to load animation file specified in model config, attempting to load %s\n", legsFileRoute ); + + //parse it ^_^ + ci->animIndex = CG_ParseAnimationFile( legsFileRoute ); + + if ( ci->animIndex < 0 ) { + Com_Printf( "Tried loading anim data from location %s, however nothing was valid.\n", legsFileRoute ); + return qfalse; + } + } + else { + if ( !legsFileRoute[0] ) { + Com_Printf( S_COLOR_RED "Couldn't load/locate any player animation data for player: %s.\n", charName ); + return qfalse; + } + } + + //We'll check again if we can load a sound config file after everything else + if ( ci->animSndIndex == -1 && animSndFileRoute[0] ) + { + ci->animSndIndex = CG_ParseAnimationSndFile( animSndFileRoute, ci->animIndex ); + + if ( ci->animSndIndex == -1 ) { + Com_Printf( S_COLOR_RED "ERROR: Unable to load sound config file: %s.\n", animSndFileRoute ); + } + } + + ci->animsFlushed = qfalse; + + //TiM: Cheap hack - let us specifically check for hazard models + if ( !Q_stricmp( modelName, "hazard" ) ) + ci->isHazardModel = qtrue; + + //holy fudgenuggets. after all that checking, we actually made it to the end and have a valid freaking + //model! OWNED! return qtrue; } /* -========================== -CG_FileExists -========================== -*/ -static qboolean CG_FileExists(const char *filename) { - int len; +============================================================================= - len = trap_FS_FOpenFile( filename, NULL, FS_READ ); - if (len>0) { - return qtrue; - } - return qfalse; -} +CLIENT INFO + +============================================================================= +*/ /* -========================== -CG_FindClientModelFile -========================== -*/ -static qboolean CG_FindClientModelFile( char *filename, int length, clientInfo_t *ci, const char *teamName, const char *modelName, const char *skinName, const char *base, const char *ext ) { - char *team, *charactersFolder; - int i; +//This function has been rpg-x'ed®! (by J2J and fixed by RedTechie) +static qboolean CG_ParseAnimationFile( const char *filename, clientInfo_t *ci ) { + char *text_p; + int len; + int i; + char *token; +// char aniname[255]; + float fps; + int skip; + char text[20000]; +// char text2[20000]; + fileHandle_t f; + animation_t *animations; - if ( cgs.gametype >= GT_TEAM ) { - switch ( ci->team ) { - case TEAM_BLUE: { - team = "blue"; - break; - } - default: { - team = "red"; - break; - } - } + //Com_Printf(S_COLOR_RED"MAX_ANIMATIONS = %i\n", MAX_ANIMATIONS); //not needed + + animations = ci->animations; + + // load the file + len = trap_FS_FOpenFile( filename, &f, FS_READ ); + if ( len <= 0 ) { + return qfalse; } - else { - team = "default"; + if ( len >= sizeof( text ) - 1 ) { + CG_Printf( "File %s too long\n", filename ); + return qfalse; } - charactersFolder = ""; + trap_FS_Read( text, len, f ); + text[len] = 0; + trap_FS_FCloseFile( f ); + + // parse the text + text_p = text; + skip = 0; // quite the compiler warning + + //initialize anim array so that from 0 to MAX_ANIMATIONS, set default values of 0 1 0 100 + for(i = 0; i < MAX_ANIMATIONS; i++) + { + animations[i].firstFrame = 0; + animations[i].numFrames = 0; + animations[i].loopFrames = -1; + animations[i].frameLerp = 100; //Before redtechie change 0 + animations[i].initialLerp = 100;//Before redtechie change 0 + } + while(1) { - for ( i = 0; i < 2; i++ ) { - if ( i == 0 && teamName && *teamName ) { - // "models/players/characters/james/stroggs/lower_lily_red.skin" - Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s_%s.%s", charactersFolder, modelName, teamName, base, skinName, team, ext ); - } - else { - // "models/players/characters/james/lower_lily_red.skin" - Com_sprintf( filename, length, "models/players/%s%s/%s_%s_%s.%s", charactersFolder, modelName, base, skinName, team, ext ); - } - if ( CG_FileExists( filename ) ) { - return qtrue; - } - if ( cgs.gametype >= GT_TEAM ) { - if ( i == 0 && teamName && *teamName ) { - // "models/players/characters/james/stroggs/lower_red.skin" - Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", charactersFolder, modelName, teamName, base, team, ext ); - } - else { - // "models/players/characters/james/lower_red.skin" - Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", charactersFolder, modelName, base, team, ext ); - } - } - else { - if ( i == 0 && teamName && *teamName ) { - // "models/players/characters/james/stroggs/lower_lily.skin" - Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", charactersFolder, modelName, teamName, base, skinName, ext ); - } - else { - // "models/players/characters/james/lower_lily.skin" - Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", charactersFolder, modelName, base, skinName, ext ); - } - } - if ( CG_FileExists( filename ) ) { - return qtrue; - } - if ( !teamName || !*teamName ) { - break; - } - } - // if tried the heads folder first - if ( charactersFolder[0] ) { + + token = COM_Parse( &text_p ); + if ( !token || !token[0] ) { break; } - charactersFolder = "characters/"; - } + + i = GetIDForString(animTable, token); - return qfalse; + if(i == -1) + { + Com_Printf(S_COLOR_RED"WARNING: Unknown token %s in %s\n", token, filename); + continue; + } + + token = COM_Parse( &text_p ); + if ( !token ) { + break; + } + animations[i].firstFrame = atoi( token ); + + token = COM_Parse( &text_p ); + if ( !token ) { + break; + } + animations[i].numFrames = atoi( token ); + + token = COM_Parse( &text_p ); + if ( !token ) { + break; + } + + animations[i].loopFrames = atoi( token ); + + token = COM_Parse( &text_p ); + if ( !token ) { + break; + } + fps = atof( token ); + + //Com_Printf(S_COLOR_RED"INFO: fps = %s - %f\n", token, fps); //debug only + + if ( fps == 0 ) + { + fps = 1;//Don't allow divide by zero error + } + if ( fps < 0 ) + {//backwards + animations[i].frameLerp = floor(1000.0f / fps); + } + else + { + animations[i].frameLerp = ceil(1000.0f / fps); + } + + animations[i].initialLerp = ceil(1000.0f / fabs(fps)); + + } + return qtrue; } + +*/ /* ========================== -CG_FindClientHeadFile +\CG_RegisterClientSkin ========================== */ -static qboolean CG_FindClientHeadFile( char *filename, int length, clientInfo_t *ci, const char *teamName, const char *headModelName, const char *headSkinName, const char *base, const char *ext ) { - char *team, *headsFolder; - int i; - - if ( cgs.gametype >= GT_TEAM ) { - switch ( ci->team ) { - case TEAM_BLUE: { - team = "blue"; - break; - } - default: { - team = "red"; - break; - } - } - } - else { - team = "default"; - } - - if ( headModelName[0] == '*' ) { - headsFolder = "heads/"; - headModelName++; - } - else { - headsFolder = ""; - } - while(1) { - for ( i = 0; i < 2; i++ ) { - if ( i == 0 && teamName && *teamName ) { - Com_sprintf( filename, length, "models/players/%s%s/%s/%s%s_%s.%s", headsFolder, headModelName, headSkinName, teamName, base, team, ext ); - } - else { - Com_sprintf( filename, length, "models/players/%s%s/%s/%s_%s.%s", headsFolder, headModelName, headSkinName, base, team, ext ); - } - if ( CG_FileExists( filename ) ) { - return qtrue; - } - if ( cgs.gametype >= GT_TEAM ) { - if ( i == 0 && teamName && *teamName ) { - Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", headsFolder, headModelName, teamName, base, team, ext ); - } - else { - Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", headsFolder, headModelName, base, team, ext ); - } - } - else { - if ( i == 0 && teamName && *teamName ) { - Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", headsFolder, headModelName, teamName, base, headSkinName, ext ); - } - else { - Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", headsFolder, headModelName, base, headSkinName, ext ); - } - } - if ( CG_FileExists( filename ) ) { - return qtrue; - } - if ( !teamName || !*teamName ) { - break; - } - } - // if tried the heads folder first - if ( headsFolder[0] ) { - break; - } - headsFolder = "heads/"; - } - - return qfalse; -} - /* ========================== CG_RegisterClientSkin ========================== */ -static qboolean CG_RegisterClientSkin( clientInfo_t *ci, const char *teamName, const char *modelName, const char *skinName, const char *headModelName, const char *headSkinName ) { - char filename[MAX_QPATH]; +/*static qboolean CG_RegisterClientSkin( clientInfo_t *ci, const char *modelName, const char *skinName ) { + char filename[MAX_QPATH]; - /* - Com_sprintf( filename, sizeof( filename ), "models/players/%s/%slower_%s.skin", modelName, teamName, skinName ); + Com_sprintf( filename, sizeof( filename ), "models/players2/%s/lower_%s.skin", modelName, skinName ); ci->legsSkin = trap_R_RegisterSkin( filename ); - if (!ci->legsSkin) { - Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/%slower_%s.skin", modelName, teamName, skinName ); - ci->legsSkin = trap_R_RegisterSkin( filename ); - if (!ci->legsSkin) { - Com_Printf( "Leg skin load failure: %s\n", filename ); - } - } - - Com_sprintf( filename, sizeof( filename ), "models/players/%s/%supper_%s.skin", modelName, teamName, skinName ); + Com_sprintf( filename, sizeof( filename ), "models/players2/%s/upper_%s.skin", modelName, skinName ); ci->torsoSkin = trap_R_RegisterSkin( filename ); - if (!ci->torsoSkin) { - Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/%supper_%s.skin", modelName, teamName, skinName ); - ci->torsoSkin = trap_R_RegisterSkin( filename ); - if (!ci->torsoSkin) { - Com_Printf( "Torso skin load failure: %s\n", filename ); - } - } - */ - if ( CG_FindClientModelFile( filename, sizeof(filename), ci, teamName, modelName, skinName, "lower", "skin" ) ) { - ci->legsSkin = trap_R_RegisterSkin( filename ); - } - if (!ci->legsSkin) { - Com_Printf( "Leg skin load failure: %s\n", filename ); - } - if ( CG_FindClientModelFile( filename, sizeof(filename), ci, teamName, modelName, skinName, "upper", "skin" ) ) { - ci->torsoSkin = trap_R_RegisterSkin( filename ); - } - if (!ci->torsoSkin) { - Com_Printf( "Torso skin load failure: %s\n", filename ); - } + Com_sprintf( filename, sizeof( filename ), "models/players2/%s/head_%s.skin", modelName, skinName ); + ci->headSkin = trap_R_RegisterSkin( filename ); - if ( CG_FindClientHeadFile( filename, sizeof(filename), ci, teamName, headModelName, headSkinName, "head", "skin" ) ) { - ci->headSkin = trap_R_RegisterSkin( filename ); - } - if (!ci->headSkin) { - Com_Printf( "Head skin load failure: %s\n", filename ); - } + //Com_sprintf( filename, sizeof( filename ), "models/players2/%s/groups.cfg", modelName); + //strcpy(ci->race, BG_RegisterRace( filename )); - // if any skins failed to load if ( !ci->legsSkin || !ci->torsoSkin || !ci->headSkin ) { return qfalse; } + return qtrue; -} +}*/ /* ========================== CG_RegisterClientModelname ========================== */ -static qboolean CG_RegisterClientModelname( clientInfo_t *ci, const char *modelName, const char *skinName, const char *headModelName, const char *headSkinName, const char *teamName ) { - char filename[MAX_QPATH*2]; - const char *headName; - char newTeamName[MAX_QPATH*2]; +static qboolean CG_RegisterClientModelname( clientInfo_t *ci, const char *charName, const char *modelName, const char *skinName ) { + char filename[MAX_QPATH]; - if ( headModelName[0] == '\0' ) { - headName = modelName; - } - else { - headName = headModelName; - } - Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower.md3", modelName ); + // load cmodels before models so filecache works + + /*Com_sprintf( filename, sizeof( filename ), "models/players2/%s/lower.mdr", modelName ); ci->legsModel = trap_R_RegisterModel( filename ); if ( !ci->legsModel ) { - Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/lower.md3", modelName ); + Com_sprintf( filename, sizeof( filename ), "models/players2/%s/lower.md3", modelName ); ci->legsModel = trap_R_RegisterModel( filename ); if ( !ci->legsModel ) { - Com_Printf( "Failed to load model file %s\n", filename ); + Com_Printf( S_COLOR_RED"Failed to load model file %s\n", filename ); return qfalse; } } - - Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper.md3", modelName ); + Com_sprintf( filename, sizeof( filename ), "models/players2/%s/upper.mdr", modelName ); ci->torsoModel = trap_R_RegisterModel( filename ); if ( !ci->torsoModel ) { - Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/upper.md3", modelName ); + Com_sprintf( filename, sizeof( filename ), "models/players2/%s/upper.md3", modelName ); ci->torsoModel = trap_R_RegisterModel( filename ); if ( !ci->torsoModel ) { Com_Printf( "Failed to load model file %s\n", filename ); @@ -552,62 +1559,43 @@ static qboolean CG_RegisterClientModelname( clientInfo_t *ci, const char *modelN } } - if( headName[0] == '*' ) { - Com_sprintf( filename, sizeof( filename ), "models/players/heads/%s/%s.md3", &headModelName[1], &headModelName[1] ); - } - else { - Com_sprintf( filename, sizeof( filename ), "models/players/%s/head.md3", headName ); - } + Com_sprintf( filename, sizeof( filename ), "models/players2/%s/head.md3", modelName ); ci->headModel = trap_R_RegisterModel( filename ); - // if the head model could not be found and we didn't load from the heads folder try to load from there - if ( !ci->headModel && headName[0] != '*' ) { - Com_sprintf( filename, sizeof( filename ), "models/players/heads/%s/%s.md3", headModelName, headModelName ); - ci->headModel = trap_R_RegisterModel( filename ); - } if ( !ci->headModel ) { Com_Printf( "Failed to load model file %s\n", filename ); return qfalse; } // if any skins failed to load, return failure - if ( !CG_RegisterClientSkin( ci, teamName, modelName, skinName, headName, headSkinName ) ) { - if ( teamName && *teamName) { - Com_Printf( "Failed to load skin file: %s : %s : %s, %s : %s\n", teamName, modelName, skinName, headName, headSkinName ); - if( ci->team == TEAM_BLUE ) { - Com_sprintf(newTeamName, sizeof(newTeamName), "%s/", DEFAULT_BLUETEAM_NAME); - } - else { - Com_sprintf(newTeamName, sizeof(newTeamName), "%s/", DEFAULT_REDTEAM_NAME); - } - if ( !CG_RegisterClientSkin( ci, newTeamName, modelName, skinName, headName, headSkinName ) ) { - Com_Printf( "Failed to load skin file: %s : %s : %s, %s : %s\n", newTeamName, modelName, skinName, headName, headSkinName ); - return qfalse; - } - } else { - Com_Printf( "Failed to load skin file: %s : %s, %s : %s\n", modelName, skinName, headName, headSkinName ); - return qfalse; - } + if ( !CG_RegisterClientSkin( ci, modelName, skinName ) ) { + Com_Printf( "Failed to load skin file: %s : %s\n", modelName, skinName ); + return qfalse; } // load the animations - Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg", modelName ); - if ( !CG_ParseAnimationFile( filename, ci ) ) { - Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/animation.cfg", modelName ); - if ( !CG_ParseAnimationFile( filename, ci ) ) { - Com_Printf( "Failed to load animation file %s\n", filename ); - return qfalse; - } - } - - if ( CG_FindClientHeadFile( filename, sizeof(filename), ci, teamName, headName, headSkinName, "icon", "skin" ) ) { - ci->modelIcon = trap_R_RegisterShaderNoMip( filename ); - } - else if ( CG_FindClientHeadFile( filename, sizeof(filename), ci, teamName, headName, headSkinName, "icon", "tga" ) ) { - ci->modelIcon = trap_R_RegisterShaderNoMip( filename ); - } - - if ( !ci->modelIcon ) { + Com_sprintf( filename, sizeof( filename ), "models/players2/%s/animation.cfg", modelName ); + if ( !CG_ParseAnimationFile( filename, ci ) ) {\ + Com_Printf( "Failed to load animation file %s\n", filename ); return qfalse; + }*/ + + if ( !CG_ParseModelDataFile( ci, charName, modelName, skinName) ) { + //Com_Printf( S_COLOR_RED "ERROR: Failed to parse .model file for character: %s/%s/%s\n", charName, modelName, skinName ); + return qfalse; + } + + /*Com_sprintf( filename, sizeof( filename ), "models/players2/%s/icon_%s.jpg", modelName, skinName ); + ci->modelIcon = trap_R_RegisterShaderNoMip( filename ); + if ( !ci->modelIcon ) { + Com_Printf( "Failed to load icon file: %s\n", filename ); + return qfalse; + }*/ + + Com_sprintf( filename, sizeof( filename ), "models/players_rpgx/%s/model_icon.jpg", charName ); + ci->modelIcon = trap_R_RegisterShaderNoMip( filename ); + if ( !ci->modelIcon ) { + Com_Printf( S_COLOR_RED "ERROR: Failed to load icon file: %s\n", filename ); + //return qfalse; } return qtrue; @@ -618,7 +1606,7 @@ static qboolean CG_RegisterClientModelname( clientInfo_t *ci, const char *modelN CG_ColorFromString ==================== */ -static void CG_ColorFromString( const char *v, vec3_t color ) { +/*static void CG_ColorFromString( const char *v, vec3_t color ) { int val; VectorClear( color ); @@ -639,7 +1627,7 @@ static void CG_ColorFromString( const char *v, vec3_t color ) { if ( val & 4 ) { color[0] = 1.0f; } -} +}*/ /* =================== @@ -649,99 +1637,112 @@ Load it now, taking the disk hits. This will usually be deferred to a safe time =================== */ -static void CG_LoadClientInfo( int clientNum, clientInfo_t *ci ) { +static void CG_LoadClientInfo( clientInfo_t *ci , int clientNum) { const char *dir, *fallback; - int i, modelloaded; + int i; const char *s; - char teamname[MAX_QPATH]; + char temp_string[200]; - teamname[0] = 0; -#ifdef MISSIONPACK - if( cgs.gametype >= GT_TEAM) { - if( ci->team == TEAM_BLUE ) { - Q_strncpyz(teamname, cg_blueTeamName.string, sizeof(teamname) ); - } else { - Q_strncpyz(teamname, cg_redTeamName.string, sizeof(teamname) ); - } - } - if( teamname[0] ) { - strcat( teamname, "/" ); - } -#endif - modelloaded = qtrue; - if ( !CG_RegisterClientModelname( ci, ci->modelName, ci->skinName, ci->headModelName, ci->headSkinName, teamname ) ) { + //if ( !CG_RegisterClientModelname( ci, ci->modelName, ci->skinName ) ) { + + //Com_Printf("charName = %s, modelName = %s, skinName = %s\n", ci->charName, ci->modelName, ci->skinName); + if ( !CG_RegisterClientModelname( ci, ci->charName, ci->modelName, ci->skinName ) ) { if ( cg_buildScript.integer ) { - CG_Error( "CG_RegisterClientModelname( %s, %s, %s, %s %s ) failed", ci->modelName, ci->skinName, ci->headModelName, ci->headSkinName, teamname ); + CG_Error( "CG_RegisterClientModelname( %s/%s/%s ) failed", ci->charName, ci->modelName, ci->skinName ); } + + Com_Printf( S_COLOR_RED "ERROR: Failed to parse .model file for character: %s/%s/%s\n", ci->charName, ci->modelName, ci->skinName ); - // fall back to default team name - if( cgs.gametype >= GT_TEAM) { - // keep skin name - if( ci->team == TEAM_BLUE ) { - Q_strncpyz(teamname, DEFAULT_BLUETEAM_NAME, sizeof(teamname) ); - } else { - Q_strncpyz(teamname, DEFAULT_REDTEAM_NAME, sizeof(teamname) ); + if ( !CG_RegisterClientModelname( ci, ci->charName, DEFAULT_MODEL, ci->skinName ) ) + { + if ( !CG_RegisterClientModelname( ci, cg_defaultChar.string, DEFAULT_MODEL, ci->skinName ) ) + { + // fall back + if ( cgs.gametype >= GT_TEAM ) + { + // keep skin name + if ( !CG_RegisterClientModelname( ci, DEFAULT_CHAR, DEFAULT_MODEL, ci->skinName ) ) { + CG_Error( "DEFAULT_CHAR / model /skin ( %s/%s/%s ) failed to register", + DEFAULT_CHAR, DEFAULT_MODEL, ci->skinName ); + } + } + else + { + if ( !CG_RegisterClientModelname( ci, cg_defaultChar.string, DEFAULT_MODEL, DEFAULT_SKIN ) ) + { + if ( !CG_RegisterClientModelname( ci, DEFAULT_CHAR, DEFAULT_MODEL, DEFAULT_SKIN ) ) + { + CG_Error( "DEFAULT_CHAR (%s) failed to register", DEFAULT_CHAR ); + } + } + } } - if ( !CG_RegisterClientModelname( ci, DEFAULT_TEAM_MODEL, ci->skinName, DEFAULT_TEAM_HEAD, ci->skinName, teamname ) ) { - CG_Error( "DEFAULT_TEAM_MODEL / skin (%s/%s) failed to register", DEFAULT_TEAM_MODEL, ci->skinName ); - } - } else { - if ( !CG_RegisterClientModelname( ci, DEFAULT_MODEL, "default", DEFAULT_MODEL, "default", teamname ) ) { - CG_Error( "DEFAULT_MODEL (%s) failed to register", DEFAULT_MODEL ); - } - } - modelloaded = qfalse; - } - - ci->newAnims = qfalse; - if ( ci->torsoModel ) { - orientation_t tag; - // if the torso model has the "tag_flag" - if ( trap_R_LerpTag( &tag, ci->torsoModel, 0, 0, 1, "tag_flag" ) ) { - ci->newAnims = qtrue; } } // sounds - dir = ci->modelName; - fallback = (cgs.gametype >= GT_TEAM) ? DEFAULT_TEAM_MODEL : DEFAULT_MODEL; + dir = ci->soundPath; + fallback = (ci->gender==GENDER_FEMALE)?"hm_female":"hm_male"; for ( i = 0 ; i < MAX_CUSTOM_SOUNDS ; i++ ) { s = cg_customSoundNames[i]; if ( !s ) { break; } - ci->sounds[i] = 0; - // if the model didn't load use the sounds of the default model - if (modelloaded) { - ci->sounds[i] = trap_S_RegisterSound( va("sound/player/%s/%s", dir, s + 1), qfalse ); - } + ci->sounds[i] = trap_S_RegisterSound( va("sound/voice/%s/misc/%s", dir, s + 1) ); if ( !ci->sounds[i] ) { - ci->sounds[i] = trap_S_RegisterSound( va("sound/player/%s/%s", fallback, s + 1), qfalse ); + ci->sounds[i] = trap_S_RegisterSound( va("sound/player/%s/%s", fallback, s + 1) ); } } ci->deferred = qfalse; + Com_sprintf(temp_string, sizeof(temp_string), "%s/%s/%s", ci->charName, ci->modelName, ci->skinName); + updateSkin(clientNum, temp_string); + // reset any existing players and bodies, because they might be in bad // frames for this new model for ( i = 0 ; i < MAX_GENTITIES ; i++ ) { if ( cg_entities[i].currentState.clientNum == clientNum - && cg_entities[i].currentState.eType == ET_PLAYER ) { + && cg_entities[i].currentState.eType == ET_PLAYER ) + { CG_ResetPlayerEntity( &cg_entities[i] ); } } } + +// we need to check here to see if the clientinfo model variable is the same as the one that is in the +// clientinfo block. This is because it is possible for the server to change skins on us when we hit a CTF +// teamplay game where groups are defined. +// most of the time this will not hit + +void updateSkin(int clientNum, char *new_model) +{ + char model_string[200]; + + // create string to be checked against + trap_Cvar_VariableStringBuffer("model", model_string, sizeof(model_string) ); + + if (Q_stricmp(new_model, model_string) && cg.validPPS && (clientNum == cg.predictedPlayerState.clientNum)) + { + trap_Cvar_Set_No_Modify ("model",new_model); + } +} + + /* ====================== CG_CopyClientInfoModel ====================== */ static void CG_CopyClientInfoModel( clientInfo_t *from, clientInfo_t *to ) { + //int i; + VectorCopy( from->headOffset, to->headOffset ); to->footsteps = from->footsteps; to->gender = from->gender; + to->numTaunts = from->numTaunts; to->legsModel = from->legsModel; to->legsSkin = from->legsSkin; @@ -751,10 +1752,59 @@ static void CG_CopyClientInfoModel( clientInfo_t *from, clientInfo_t *to ) { to->headSkin = from->headSkin; to->modelIcon = from->modelIcon; - to->newAnims = from->newAnims; + to->animIndex = from->animIndex; + to->animSndIndex = from->animSndIndex; - memcpy( to->animations, from->animations, sizeof( to->animations ) ); + to->hasRanks = from->hasRanks; + + //Blinking + if ( from->headSkinBlink ) { + to->headSkinBlink = from->headSkinBlink; + + if ( from->headBlinkTime.maxSeconds > 0 ) { + //memcpy( to->headBlinkTime, from->headBlinkTime, sizeof( to->headBlinkTime ) ); + to->headBlinkTime = from->headBlinkTime; + } + } + + //Frowning/Blink Frowning + if ( from->headSkinFrown ) { + to->headSkinFrown = from->headSkinFrown; + + if ( from->headSkinFrownBlink ) + to->headSkinFrownBlink = from->headSkinFrownBlink; + } + + //Copy over bolton info + /*if ( from->boltonTags[0].tagModel && from->boltonTags[0].tagName ) { //if there actually is bolton data... + for (i = 0; i < MAX_BOLTONS; i++ ) { //loop thru all of them + if ( from->boltonTags[i].tagModel && from->boltonTags[i].tagName ) { //only work on ones that actually have data. + to->boltonTags[i].modelBase = from->boltonTags[i].modelBase; + to->boltonTags[i].tagModel = from->boltonTags[i].tagModel; + Q_strncpyz( to->boltonTags[i].tagName, from->boltonTags[i].tagName, sizeof (to->boltonTags[i].tagName) );*/ + memcpy( to->boltonTags, from->boltonTags, sizeof(to->boltonTags) ); +// } +// } +// } + + //Talking skin data + /*if ( from->headSkinTalk[0] ) { + for (i = 0; i < MAX_TALK_SKINS; i++ ) { + if ( from->headSkinTalk[i] ) {*/ + memcpy( to->headSkinTalk, from->headSkinTalk, sizeof( to->headSkinTalk ) ); + /* } + } + }*/ + + to->holsterModel = from->holsterModel; + + Q_strncpyz( to->soundPath, from->soundPath, sizeof (to->soundPath) ); + //memcpy( to->animations, from->animations, sizeof( to->animations ) ); + //TiM : New animation method :) + to->animIndex = from->animIndex; memcpy( to->sounds, from->sounds, sizeof( to->sounds ) ); + + to->isHazardModel = from->isHazardModel; } /* @@ -774,14 +1824,9 @@ static qboolean CG_ScanForExistingClientInfo( clientInfo_t *ci ) { if ( match->deferred ) { continue; } - if ( !Q_stricmp( ci->modelName, match->modelName ) - && !Q_stricmp( ci->skinName, match->skinName ) - && !Q_stricmp( ci->headModelName, match->headModelName ) - && !Q_stricmp( ci->headSkinName, match->headSkinName ) - && !Q_stricmp( ci->blueTeam, match->blueTeam ) - && !Q_stricmp( ci->redTeam, match->redTeam ) - && (cgs.gametype < GT_TEAM || ci->team == match->team) ) { - // this clientinfo is identical, so use its handles + if ( !Q_stricmp(ci->charName, match->charName) && !Q_stricmp( ci->modelName, match->modelName ) + && !Q_stricmp( ci->skinName, match->skinName ) ) { + // this clientinfo is identical, so use it's handles ci->deferred = qfalse; @@ -803,49 +1848,31 @@ We aren't going to load it now, so grab some other client's info to use until we have some spare time. ====================== */ -static void CG_SetDeferredClientInfo( int clientNum, clientInfo_t *ci ) { +static void CG_SetDeferredClientInfo( clientInfo_t *ci, int clientNum ) { int i; clientInfo_t *match; - // if someone else is already the same models and skins we - // can just load the client info - for ( i = 0 ; i < cgs.maxclients ; i++ ) { - match = &cgs.clientinfo[ i ]; - if ( !match->infoValid || match->deferred ) { - continue; - } - if ( Q_stricmp( ci->skinName, match->skinName ) || - Q_stricmp( ci->modelName, match->modelName ) || -// Q_stricmp( ci->headModelName, match->headModelName ) || -// Q_stricmp( ci->headSkinName, match->headSkinName ) || - (cgs.gametype >= GT_TEAM && ci->team != match->team) ) { - continue; - } - // just load the real info cause it uses the same models and skins - CG_LoadClientInfo( clientNum, ci ); - return; - } - // if we are in teamplay, only grab a model if the skin is correct if ( cgs.gametype >= GT_TEAM ) { + // this is ONLY for optimization - it's exactly the same effect as CG_LoadClientInfo for ( i = 0 ; i < cgs.maxclients ; i++ ) { match = &cgs.clientinfo[ i ]; - if ( !match->infoValid || match->deferred ) { + if ( !match->infoValid ) { continue; } - if ( Q_stricmp( ci->skinName, match->skinName ) || - (cgs.gametype >= GT_TEAM && ci->team != match->team) ) { + if ( Q_stricmp( ci->skinName, match->skinName ) ) { continue; } ci->deferred = qtrue; CG_CopyClientInfoModel( match, ci ); return; } + // load the full model, because we don't ever want to show // an improper team skin. This will cause a hitch for the first // player, when the second enters. Combat shouldn't be going on // yet, so it shouldn't matter - CG_LoadClientInfo( clientNum, ci ); + CG_LoadClientInfo( ci, clientNum ); return; } @@ -864,7 +1891,7 @@ static void CG_SetDeferredClientInfo( int clientNum, clientInfo_t *ci ) { // we should never get here... CG_Printf( "CG_SetDeferredClientInfo: no valid clients!\n" ); - CG_LoadClientInfo( clientNum, ci ); + CG_LoadClientInfo( ci ,clientNum); } @@ -878,7 +1905,10 @@ void CG_NewClientInfo( int clientNum ) { clientInfo_t newInfo; const char *configstring; const char *v; - char *slash; + char *model = NULL; + char *skin = NULL; + size_t len; + //int i; ci = &cgs.clientinfo[clientNum]; @@ -897,21 +1927,8 @@ void CG_NewClientInfo( int clientNum ) { Q_strncpyz( newInfo.name, v, sizeof( newInfo.name ) ); // colors - v = Info_ValueForKey( configstring, "c1" ); - CG_ColorFromString( v, newInfo.color1 ); - - newInfo.c1RGBA[0] = 255 * newInfo.color1[0]; - newInfo.c1RGBA[1] = 255 * newInfo.color1[1]; - newInfo.c1RGBA[2] = 255 * newInfo.color1[2]; - newInfo.c1RGBA[3] = 255; - - v = Info_ValueForKey( configstring, "c2" ); - CG_ColorFromString( v, newInfo.color2 ); - - newInfo.c2RGBA[0] = 255 * newInfo.color2[0]; - newInfo.c2RGBA[1] = 255 * newInfo.color2[1]; - newInfo.c2RGBA[2] = 255 * newInfo.color2[2]; - newInfo.c2RGBA[3] = 255; + //v = Info_ValueForKey( configstring, "c1" ); + //CG_ColorFromString( v, newInfo.color ); // bot skill v = Info_ValueForKey( configstring, "skill" ); @@ -933,126 +1950,178 @@ void CG_NewClientInfo( int clientNum ) { v = Info_ValueForKey( configstring, "t" ); newInfo.team = atoi( v ); - // team task - v = Info_ValueForKey( configstring, "tt" ); - newInfo.teamTask = atoi(v); - - // team leader - v = Info_ValueForKey( configstring, "tl" ); - newInfo.teamLeader = atoi(v); - - v = Info_ValueForKey( configstring, "g_redteam" ); - Q_strncpyz(newInfo.redTeam, v, MAX_TEAMNAME); - - v = Info_ValueForKey( configstring, "g_blueteam" ); - Q_strncpyz(newInfo.blueTeam, v, MAX_TEAMNAME); + // playerclass + v = Info_ValueForKey( configstring, "p" ); + newInfo.pClass = atoi( v ); // model v = Info_ValueForKey( configstring, "model" ); if ( cg_forceModel.integer ) { // forcemodel makes everyone use a single model // to prevent load hitches - char modelStr[MAX_QPATH]; + char charStr[MAX_QPATH]; + char *model; char *skin; + size_t len; - if( cgs.gametype >= GT_TEAM ) { - Q_strncpyz( newInfo.modelName, DEFAULT_TEAM_MODEL, sizeof( newInfo.modelName ) ); - Q_strncpyz( newInfo.skinName, "default", sizeof( newInfo.skinName ) ); + trap_Cvar_VariableStringBuffer( "model", charStr, sizeof( charStr ) ); + if ( ( model = strchr( charStr, '/' ) ) == NULL) { + model = "main"; + skin = "default"; } else { - trap_Cvar_VariableStringBuffer( "model", modelStr, sizeof( modelStr ) ); - if ( ( skin = strchr( modelStr, '/' ) ) == NULL) { - skin = "default"; - } else { - *skin++ = 0; + *model = 0; //*model++ = 0; + len = strlen(model); + + //if there was a slash, but no model afterwards + if ( !model || !model[1] ) { + model = "main"; } - Q_strncpyz( newInfo.skinName, skin, sizeof( newInfo.skinName ) ); - Q_strncpyz( newInfo.modelName, modelStr, sizeof( newInfo.modelName ) ); + if ( ( skin = strchr( model, '/' ) ) == NULL ) { + skin = "default"; + } else { + *skin = 0; //*skin++ = 0; + + if ( !skin || !skin[1] ) { + skin = "default"; + } + + Com_sprintf( model, len - strlen(skin), model); + } } + Q_strncpyz( newInfo.skinName, skin, sizeof( newInfo.skinName ) ); + Q_strncpyz( newInfo.modelName, model, sizeof( newInfo.modelName ) ); + Q_strncpyz( newInfo.charName, charStr, sizeof( newInfo.charName ) ); + +// Q_strncpyz( newInfo.modelName, DEFAULT_MODEL, sizeof( newInfo.modelName ) ); +// Q_strncpyz( newInfo.skinName, "default", sizeof( newInfo.skinName ) ); + if ( cgs.gametype >= GT_TEAM ) { // keep skin name - slash = strchr( v, '/' ); - if ( slash ) { - Q_strncpyz( newInfo.skinName, slash + 1, sizeof( newInfo.skinName ) ); + skin = strchr( v, '/' ); + if ( model ) { + Q_strncpyz( newInfo.skinName, skin + 1, sizeof( newInfo.skinName ) ); } } } else { - Q_strncpyz( newInfo.modelName, v, sizeof( newInfo.modelName ) ); + //Q_strncpyz( newInfo.modelName, v, sizeof( newInfo.modelName ) ); + //Okay! Here we go! We gotta take a string like kulhane/admiral/teal + //divide it, and put it into three different vars, accounting for user n00biness + //(ie mistakes and stuff) along the way. + + //step 1, take the first bit of the string and put it in the charName var. + if ( ( model = strchr( v, '/') ) == NULL ) { //if there's no slash + Q_strncpyz( newInfo.charName, v, sizeof( newInfo.charName ) ); //just set it + } else { //otherwise, isolate the first bit, and copy that + len = strlen( v ); + Q_strncpyz( newInfo.charName, v, ((int)len - (int)strlen(model)) + 1 ); + } - slash = strchr( newInfo.modelName, '/' ); - if ( !slash ) { + //Com_Printf("%s\n", newInfo.charName); + + //slash = strchr( newInfo.modelName, '/' ); + if ( !model || !model[1] ) { // modelName didn not include a skin name + //Q_strncpyz( newInfo.skinName, "default", sizeof( newInfo.skinName ) ); + Q_strncpyz( newInfo.modelName, "main", sizeof( newInfo.modelName ) ); Q_strncpyz( newInfo.skinName, "default", sizeof( newInfo.skinName ) ); - } else { - Q_strncpyz( newInfo.skinName, slash + 1, sizeof( newInfo.skinName ) ); - // truncate modelName - *slash = 0; - } - } - // head model - v = Info_ValueForKey( configstring, "hmodel" ); - if ( cg_forceModel.integer ) { - // forcemodel makes everyone use a single model - // to prevent load hitches - char modelStr[MAX_QPATH]; - char *skin; - - if( cgs.gametype >= GT_TEAM ) { - Q_strncpyz( newInfo.headModelName, DEFAULT_TEAM_HEAD, sizeof( newInfo.headModelName ) ); - Q_strncpyz( newInfo.headSkinName, "default", sizeof( newInfo.headSkinName ) ); + if ( model && !model[1] ) + {//if we had a slash, but nothing after, clear it + *model = 0; + } } else { - trap_Cvar_VariableStringBuffer( "headmodel", modelStr, sizeof( modelStr ) ); - if ( ( skin = strchr( modelStr, '/' ) ) == NULL) { - skin = "default"; + model++; //bypass the slash //QVMNOTE + len = strlen(model); + skin = strchr( model, '/' ); + + //if there was a model defined, but no skin + if ( !skin || !skin[1] ) { + //no skin, but I'm guessing we gotz a model at least + if ( !skin ) { + Q_strncpyz( newInfo.modelName, model, sizeof( newInfo.modelName ) ); + } + else { + if ( !skin[1] ) { + Q_strncpyz( newInfo.modelName, model, (int)strlen(model) ); + } + } + + Q_strncpyz( newInfo.skinName, "default", sizeof( newInfo.skinName ) ); + + if ( skin && !skin[1] ) { + *skin = 0; + } } else { - *skin++ = 0; + skin++; //QVMNOTE + Q_strncpyz( newInfo.modelName, model, ((int)len - (int)strlen(skin)) ); + Q_strncpyz( newInfo.skinName, skin, sizeof( newInfo.skinName ) ); } - Q_strncpyz( newInfo.headSkinName, skin, sizeof( newInfo.headSkinName ) ); - Q_strncpyz( newInfo.headModelName, modelStr, sizeof( newInfo.headModelName ) ); - } - - if ( cgs.gametype >= GT_TEAM ) { - // keep skin name - slash = strchr( v, '/' ); - if ( slash ) { - Q_strncpyz( newInfo.headSkinName, slash + 1, sizeof( newInfo.headSkinName ) ); - } - } - } else { - Q_strncpyz( newInfo.headModelName, v, sizeof( newInfo.headModelName ) ); - - slash = strchr( newInfo.headModelName, '/' ); - if ( !slash ) { - // modelName didn not include a skin name - Q_strncpyz( newInfo.headSkinName, "default", sizeof( newInfo.headSkinName ) ); - } else { - Q_strncpyz( newInfo.headSkinName, slash + 1, sizeof( newInfo.headSkinName ) ); + //Q_strncpyz( newInfo.skinName, slash + 1, sizeof( newInfo.skinName ) ); // truncate modelName - *slash = 0; + *model = 0; } + } + //TiM: PMS - age + v = Info_ValueForKey( configstring, "age" ); + Q_strncpyz( newInfo.age, v, sizeof(newInfo.age) ); + + //PMS - height + v = Info_ValueForKey( configstring, "height" ); + newInfo.height = atof( v ); + + //PMS - weight + v = Info_ValueForKey( configstring, "weight" ); + newInfo.weight = atof( v ); + + //PMS - race + v = Info_ValueForKey( configstring, "race" ); + Q_strncpyz( newInfo.race, v, sizeof(newInfo.race) ); + + //TiM : Offset for the emote system and solid chairs + v = Info_ValueForKey( configstring, "of" ); + newInfo.modelOffset = atoi( v ); + //CG_Printf( "Set modeloffset as: %f\n", newInfo.modelOffset ); + + v = Info_ValueForKey( configstring, "admin" ); + newInfo.isAdmin = atoi( v ); + + //ensure the health value is carried over + //it normally only gets updated when it itself is changed + //newInfo.health = ci->health; + //Actually... this might actually screw it up on server start time + // scan for an existing clientinfo that matches this modelname // so we can avoid loading checks if possible if ( !CG_ScanForExistingClientInfo( &newInfo ) ) { qboolean forceDefer; - forceDefer = trap_MemoryRemaining() < 4000000; + forceDefer = trap_MemoryRemaining() < 2000000; // if we are defering loads, just have it pick the first valid - if ( forceDefer || (cg_deferPlayers.integer && !cg_buildScript.integer && !cg.loading ) ) { + if ( forceDefer || + ( cg_deferPlayers.integer && !cg_buildScript.integer && !cg.loading && + ((clientNum != cg.predictedPlayerState.clientNum) && cg.validPPS) ) ) { // keep whatever they had if it won't violate team skins - CG_SetDeferredClientInfo( clientNum, &newInfo ); + if ( ci->infoValid && + ( cgs.gametype < GT_TEAM || !Q_stricmp( newInfo.skinName, ci->skinName ) ) ) { + CG_CopyClientInfoModel( ci, &newInfo ); + newInfo.deferred = qtrue; + } else { + // use whatever is available + CG_SetDeferredClientInfo( &newInfo, clientNum ); + } // if we are low on memory, leave them with this model if ( forceDefer ) { - CG_Printf( "Memory is low. Using deferred model.\n" ); + CG_Printf( "Memory is low. Using deferred model.\n" ); newInfo.deferred = qfalse; } } else { - CG_LoadClientInfo( clientNum, &newInfo ); + CG_LoadClientInfo( &newInfo, clientNum ); } } @@ -1062,7 +2131,6 @@ void CG_NewClientInfo( int clientNum ) { } - /* ====================== CG_LoadDeferredPlayers @@ -1081,16 +2149,173 @@ void CG_LoadDeferredPlayers( void ) { if ( ci->infoValid && ci->deferred ) { // if we are low on memory, leave it deferred if ( trap_MemoryRemaining() < 4000000 ) { - CG_Printf( "Memory is low. Using deferred model.\n" ); + CG_Printf( "Memory is low. Using deferred model.\n" ); ci->deferred = qfalse; continue; } - CG_LoadClientInfo( i, ci ); + CG_LoadClientInfo( ci, i ); // break; } } } +/* +====================== +CG_NewDecoyInfo + +TiM: A decoy was spawned, +so the relevant data will +be set up so it may be displayed +independantly of its spawner player. +====================== +*/ +void CG_NewDecoyInfo( int decoyNum ) { + clientInfo_t *ci; + char *userinfo; + int i; + char *v; + char *temp, *temp2; + //char charName[MAX_QPATH], modelName[MAX_QPATH], skinName[MAX_QPATH]; + int len; + qboolean noMemoryLeft=qfalse; + + ci = &cgs.decoyInfo[decoyNum]; + noMemoryLeft = ( trap_MemoryRemaining() < 4000000 ); + + //First, check if force player models is on. if so, copy all the data from us to the decoy. + //Or, if we're low on memory, let's do this anyway + if ( cg_forceModel.integer || noMemoryLeft ) { + *ci = cgs.clientinfo[cg.predictedPlayerState.clientNum]; + + if ( noMemoryLeft ) + CG_Printf( S_COLOR_RED "WARNING: Very little memory remains. Decoy data is being deferred to player's active data.\n" ); + + ci->infoValid = qtrue; + return; + } + + //CG_Printf( S_COLOR_RED "decoy ID: %i\n", decoyNum ); + + //Get the necessary decoy data + userinfo = (char *)CG_ConfigString( CS_DECOYS + decoyNum ); + + if ( !userinfo || !userinfo[0] ) { //No data, so flush and continue + memset( ci, 0, sizeof( clientInfo_t ) ); + return; + } + + //CG_Printf( S_COLOR_RED "%s\n", userinfo ); + + //Get model string + v = Info_ValueForKey( userinfo, "model" ); + + //First thing's first. We need to isolate these into three strings: model, char, skin + { + //step 1, take the first bit of the string and put it in the charName var. + if ( ( temp = strchr( v, '/') ) == NULL ) { //if there's no slash + Q_strncpyz( ci->charName, v, sizeof( ci->charName ) ); //just set it + } else { //otherwise, isolate the first bit, and copy that + len = strlen( v ); + Q_strncpyz( ci->charName, v, ((int)len - (int)strlen(temp)) + 1 ); + } + + //Com_Printf("%s\n", newInfo.charName); + + //slash = strchr( newInfo.modelName, '/' ); + if ( !temp || !temp[1] ) { + // modelName did not include a skin name + //Q_strncpyz( newInfo.skinName, "default", sizeof( newInfo.skinName ) ); + Q_strncpyz( ci->modelName, "main", sizeof( ci->modelName ) ); + Q_strncpyz( ci->skinName, "default", sizeof( ci->skinName ) ); + + if ( temp && !temp[1] ) + {//if we had a slash, but nothing after, clear it + *temp = 0; + } + } else { + temp++; //bypass the slash + len = strlen(temp); + temp2 = strchr( temp, '/' ); + + //if there was a model defined, but no skin + if ( !temp2 || !temp2[1] ) { + //no skin, but I'm guessing we gotz a model at least + if ( !temp2 ) { + Q_strncpyz( ci->modelName, temp, sizeof( ci->modelName ) ); + } + else { + if ( !temp2[1] ) { + Q_strncpyz( ci->modelName, temp, (int)strlen(temp) ); + } + } + + Q_strncpyz( ci->skinName, "default", sizeof( ci->skinName ) ); + + if ( temp2 && !temp2[1] ) { + *temp2 = 0; + } + } else { + temp2++; + Q_strncpyz( ci->modelName, temp, ((int)len - (int)strlen(temp2)) ); + Q_strncpyz( ci->skinName, temp2, sizeof( ci->skinName ) ); + } + } + } + + //k... get the additional parms from the config string n' put em here + v = Info_ValueForKey( userinfo, "weight" ); + ci->weight = atof( v ); + v = Info_ValueForKey( userinfo, "height" ); + ci->height = atof( v ); + v = Info_ValueForKey( userinfo, "moOf" ); + ci->modelOffset = atoi( v ); + v = Info_ValueForKey( userinfo, "c" ); + ci->pClass = atoi( v ); + + ci->animsFlushed = qtrue; + + //Okay... if another player actively has the skin we want, let's pilfer that rather than load it like a schmuck rofl. + { + clientInfo_t *match; + + for ( i = 0; i < cgs.maxclients; i++ ) { + match = &cgs.clientinfo[i]; + + //We found a match! ^_^ + if ( !Q_stricmp( match->charName, ci->charName ) && + !Q_stricmp( match->modelName, ci->modelName ) && + !Q_stricmp( match->skinName, ci->skinName ) ) + { + CG_CopyClientInfoModel( match, ci ); + ci->infoValid = qtrue; + return; + } + } + } + + + //*sigh... guess worse came to worse... we gotta fricken load it. :'( + if ( !CG_ParseModelDataFile( ci, ci->charName, ci->modelName, ci->skinName ) ) + { + CG_Printf( S_COLOR_RED "ERROR: Unable to load character for decoy: %s/%s/%s\n", ci->charName, ci->modelName, ci->skinName ); + + if ( !CG_ParseModelDataFile( ci, ci->charName, DEFAULT_MODEL, DEFAULT_SKIN ) ) + { + if (!CG_ParseModelDataFile( ci, cg_defaultChar.string, ci->modelName, ci->skinName ) ) + { + if ( !CG_ParseModelDataFile( ci, cg_defaultChar.string, DEFAULT_MODEL, DEFAULT_SKIN ) ) + { + //if we hit this.... oh so bad... O_o + if ( !CG_ParseModelDataFile( ci, DEFAULT_CHAR, DEFAULT_MODEL, DEFAULT_SKIN ) ) + CG_Error( "DEFAULT_CHAR / model / skin ( %s/%s/%s ) failed to register", DEFAULT_CHAR, DEFAULT_MODEL, DEFAULT_SKIN ); + } + } + } + } + + ci->infoValid = qtrue; +} + /* ============================================================================= @@ -1113,17 +2338,21 @@ static void CG_SetLerpFrameAnimation( clientInfo_t *ci, lerpFrame_t *lf, int new lf->animationNumber = newAnimation; newAnimation &= ~ANIM_TOGGLEBIT; - if ( newAnimation < 0 || newAnimation >= MAX_TOTALANIMATIONS ) { + if ( newAnimation < 0 || newAnimation >= MAX_ANIMATIONS ) { CG_Error( "Bad animation number: %i", newAnimation ); } - anim = &ci->animations[ newAnimation ]; + //CG_Printf("animIndex: %i\n", ci->animIndex ); + //anim = &ci->animations[ newAnimation ]; + anim = &cg_animsList[ ci->animIndex ].animations[ newAnimation ]; + //CG_Printf(S_COLOR_RED "%i\n", ci->animIndex ); lf->animation = anim; lf->animationTime = lf->frameTime + anim->initialLerp; if ( cg_debugAnim.integer ) { - CG_Printf( "Anim: %i\n", newAnimation ); + CG_Printf( "Anim: %s (%i)\n", GetStringForID(animTable, newAnimation), newAnimation ); + //CG_Printf( "Anim: %i\n", newAnimation ); } } @@ -1135,14 +2364,16 @@ Sets cg.snap, cg.oldFrame, and cg.backlerp cg.time should be between oldFrameTime and frameTime after exit =============== */ -static void CG_RunLerpFrame( clientInfo_t *ci, lerpFrame_t *lf, int newAnimation, float speedScale ) { - int f, numFrames; +static qboolean CG_RunLerpFrame( clientInfo_t *ci, lerpFrame_t *lf, int newAnimation, float speedScale ) { + int f; animation_t *anim; + qboolean newFrame = qfalse; + float frameLerp; // debugging tool to get no animations if ( cg_animSpeed.integer == 0 ) { lf->oldFrame = lf->frame = lf->backlerp = 0; - return; + return qfalse; } // see if the animation sequence is switching @@ -1158,48 +2389,51 @@ static void CG_RunLerpFrame( clientInfo_t *ci, lerpFrame_t *lf, int newAnimation // get the next frame based on the animation anim = lf->animation; - if ( !anim->frameLerp ) { - return; // shouldn't happen + if ( !anim || !anim->frameLerp ) { + return qfalse; // shouldn't happen } + //RPG-X Check. Anims with lengths < 0 are emote stubs. + //If we get one, hardcode to override to default standing. + //Otherwise, we'll get complicated glitches. + if ( anim->numFrames < 0 ) { + CG_SetLerpFrameAnimation( ci, lf, BOTH_STAND1 ); + } + + //TiM - Calc frame lerp scale here, else the frames + //just snap to each other + frameLerp = (float)anim->frameLerp + (anim->frameLerp*(1.0f - speedScale)); + if ( frameLerp < 1.0f ) + frameLerp = 1.0f; + + //CG_Printf( "Lerp: %f\n", frameLerp ); + if ( cg.time < lf->animationTime ) { lf->frameTime = lf->animationTime; // initial lerp } else { - lf->frameTime = lf->oldFrameTime + anim->frameLerp; + lf->frameTime = lf->oldFrameTime + frameLerp;//anim->frameLerp; } - f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp; - f *= speedScale; // adjust for haste, etc - - numFrames = anim->numFrames; - if (anim->flipflop) { - numFrames *= 2; - } - if ( f >= numFrames ) { - f -= numFrames; + f = ( lf->frameTime - lf->animationTime ) / frameLerp;//anim->frameLerp; + //f *= speedScale; // adjust for haste, etc + if ( f >= anim->numFrames ) { + f -= anim->numFrames; if ( anim->loopFrames ) { f %= anim->loopFrames; f += anim->numFrames - anim->loopFrames; } else { - f = numFrames - 1; + f = anim->numFrames - 1; // the animation is stuck at the end, so it // can immediately transition to another sequence lf->frameTime = cg.time; } } - if ( anim->reversed ) { - lf->frame = anim->firstFrame + anim->numFrames - 1 - f; - } - else if (anim->flipflop && f>=anim->numFrames) { - lf->frame = anim->firstFrame + anim->numFrames - 1 - (f%anim->numFrames); - } - else { - lf->frame = anim->firstFrame + f; - } + lf->frame = anim->firstFrame + f; if ( cg.time > lf->frameTime ) { lf->frameTime = cg.time; if ( cg_debugAnim.integer ) { CG_Printf( "Clamp lf->frameTime\n"); } } + newFrame = qtrue; } if ( lf->frameTime > cg.time + 200 ) { @@ -1215,6 +2449,8 @@ static void CG_RunLerpFrame( clientInfo_t *ci, lerpFrame_t *lf, int newAnimation } else { lf->backlerp = 1.0 - (float)( cg.time - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime ); } + + return newFrame; } @@ -1223,10 +2459,28 @@ static void CG_RunLerpFrame( clientInfo_t *ci, lerpFrame_t *lf, int newAnimation CG_ClearLerpFrame =============== */ -static void CG_ClearLerpFrame( clientInfo_t *ci, lerpFrame_t *lf, int animationNumber ) { - lf->frameTime = lf->oldFrameTime = cg.time; +//This function has been rpg-x'ed®! (by RedTechie) +void CG_ClearLerpFrame( clientInfo_t *ci, lerpFrame_t *lf, int animationNumber ) { //RPG-X: RedTechie - Changed type from static void to void + + if(!lf) return; + + lf->frameTime = lf->oldFrameTime = cg.time; + lf->animation = 0; CG_SetLerpFrameAnimation( ci, lf, animationNumber ); lf->oldFrame = lf->frame = lf->animation->firstFrame; + + //RPG-X: RedTechie - Added this block of code + /*if ( lf->animation->frameLerp < 0 ) + {//Plays backwards + lf->oldFrame = lf->frame = (lf->animation->firstFrame + lf->animation->numFrames); + } + else + { + lf->oldFrame = lf->frame = lf->animation->firstFrame; + }*/ + + //TiM - Put in, for now + } @@ -1235,11 +2489,19 @@ static void CG_ClearLerpFrame( clientInfo_t *ci, lerpFrame_t *lf, int animationN CG_PlayerAnimation =============== */ +extern qboolean PM_PlayerWalking( int anim ); +extern qboolean PM_PlayerRunning( int anim ); +extern qboolean PM_PlayerCrouchWalking( int anim ); + static void CG_PlayerAnimation( centity_t *cent, int *legsOld, int *legs, float *legsBackLerp, int *torsoOld, int *torso, float *torsoBackLerp ) { clientInfo_t *ci; int clientNum; - float speedScale; + float speedScale=1; + qboolean newLegsFrame = qfalse; + qboolean newTorsoFrame = qfalse; + //float speed; + qboolean isDecoy = cent->currentState.eFlags & EF_ITEMPLACEHOLDER; clientNum = cent->currentState.clientNum; @@ -1248,26 +2510,119 @@ static void CG_PlayerAnimation( centity_t *cent, int *legsOld, int *legs, float return; } - if ( cent->currentState.powerups & ( 1 << PW_HASTE ) ) { - speedScale = 1.5; - } else { - speedScale = 1; - } + //if ( cent->currentState.powerups & ( 1 << PW_HASTE ) ) { + // speedScale = 1.5; + //} else { + // speedScale = 1; + //} + //CG_Printf( "Vel: %f\n", VectorLength(cent->currentState.pos.trDelta)); + + //TiM + // 250 = default running speed + // 125 = default walking speed + // 90 = default crouchwalk speed + //if ( !isDecoy ) + //{ + // if ( clientNum == cg.snap->ps.clientNum ) + // speed = VectorLength( cg.predictedPlayerState.velocity ); + // else + // speed = VectorLength(cent->currentState.pos.trDelta); + // //if ( speed < 50.0f ) + // //speed = 50.0f; - ci = &cgs.clientinfo[ clientNum ]; + // if ( PM_PlayerWalking( cent->currentState.legsAnim ) ) + // { + // speedScale = speed / 125.0f; + // } + // else if ( PM_PlayerRunning( cent->currentState.legsAnim ) ) + // { + // speedScale = speed / 250.0f; + // } + // else if ( PM_PlayerCrouchWalking( cent->currentState.legsAnim ) ) + // { + // speedScale = speed / 90.0f; + // } + // else + // { + // speedScale = 1.0f; + // } + //} + + + if ( isDecoy ) + ci = &cgs.decoyInfo[ cent->currentState.eventParm ]; + else + ci = &cgs.clientinfo[ clientNum ]; // do the shuffle turn frames locally - if ( cent->pe.legs.yawing && ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) == LEGS_IDLE ) { - CG_RunLerpFrame( ci, ¢->pe.legs, LEGS_TURN, speedScale ); + if ( !cent->clampAngles && cent->pe.legs.yawing && ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) == BOTH_STAND1 ) { //TORSO_STAND + newLegsFrame = CG_RunLerpFrame( ci, ¢->pe.legs, LEGS_TURN1, speedScale ); } else { - CG_RunLerpFrame( ci, ¢->pe.legs, cent->currentState.legsAnim, speedScale ); + newLegsFrame = CG_RunLerpFrame( ci, ¢->pe.legs, cent->currentState.legsAnim, speedScale ); + } + + if( newLegsFrame && ci->animSndIndex >= 0 && !(cent->currentState.powerups & ( 1 << PW_INVIS ) ) ) + { + trace_t tr; + vec3_t endPoint; + //qboolean metal = qfalse; //Uberhack meant specifically for metal clank surfaces + vec3_t mins = { -16, -16, 0 }; + vec3_t maxs = { 16, 16, 0 }; + int surfType; + + //TiM: Lower based sounds are always to do with things like shoes clopping n' stuff. + //This portion of code makes sure the player is on a solid surface in order to play this sound + VectorCopy( cent->lerpOrigin, endPoint); + endPoint[2] -= 24.50f; + CG_Trace( &tr, cent->lerpOrigin, mins, maxs, endPoint, cent->currentState.clientNum, MASK_PLAYERSOLID | CONTENTS_LADDER ); + //trap_CM_BoxTrace( &tr, cent->lerpOrigin, endPoint, mins, maxs, 0, MASK_PLAYERSOLID ); + //metal = tr.surfaceFlags & SURF_METALSTEPS || (tr.contents & CONTENTS_LADDER); + if(tr.surfaceFlags & SURF_METALSTEPS || (tr.contents & CONTENTS_LADDER)) + surfType = 1; + else if(tr.surfaceFlags & SURF_GRASS) + surfType = 2; + else if(tr.surfaceFlags & SURF_GRAVEL) + surfType = 3; + else if(tr.surfaceFlags & SURF_SNOW) + surfType = 4; + else if(tr.surfaceFlags & SURF_WOOD) + surfType = 5; + else + surfType = 0; + + //if there's something below us, or we're free floating in something like water/lava/slime + if ( tr.fraction != 1.0f || (tr.contents & MASK_WATER ) || (tr.contents & CONTENTS_LADDER) ) { + CG_PlayerAnimSounds( cg_animsSndList[ci->animSndIndex].lowerAnimSounds, cent->pe.legs.frame, cent->currentState.clientNum, /*metal*/surfType ); + } } *legsOld = cent->pe.legs.oldFrame; *legs = cent->pe.legs.frame; *legsBackLerp = cent->pe.legs.backlerp; - CG_RunLerpFrame( ci, ¢->pe.torso, cent->currentState.torsoAnim, speedScale ); + //if ( PM_PlayerWalking( cent->currentState.torsoAnim ) ) + //{ + // speedScale *= speed / 125.0f; + //} + //else if ( PM_PlayerRunning( cent->currentState.torsoAnim ) ) + //{ + // speedScale *= speed / 250.0f; + //} + //else if ( PM_PlayerCrouchWalking( cent->currentState.torsoAnim ) ) + //{ + // speedScale *= speed / 90.0f; + //} + //else + //{ + // speedScale = 1.0f; + //} + + newTorsoFrame = CG_RunLerpFrame( ci, ¢->pe.torso, cent->currentState.torsoAnim, speedScale ); + + if( newTorsoFrame && ci->animSndIndex >= 0 ) + { + CG_PlayerAnimSounds( cg_animsSndList[ci->animSndIndex].upperAnimSounds, cent->pe.torso.frame, cent->currentState.clientNum, /*qfalse*/0 ); + } *torsoOld = cent->pe.torso.oldFrame; *torso = cent->pe.torso.frame; @@ -1288,23 +2643,48 @@ CG_SwingAngles ================== */ static void CG_SwingAngles( float destination, float swingTolerance, float clampTolerance, - float speed, float *angle, qboolean *swinging ) { + float speed, float *angle, qboolean *swinging, qboolean pitch ) { float swing; float move; float scale; - if ( !*swinging ) { - // see if a swing should be started - swing = AngleSubtract( *angle, destination ); - if ( swing > swingTolerance || swing < -swingTolerance ) { + swing = AngleSubtract( destination, *angle ); + + /*if ( canSwing ) { + if ( swing == 0 ) { + *swinging = qfalse; + } else if ( swing >= clampTolerance || swing <= -clampTolerance ) { + *swinging = qtrue; + } else { *swinging = qtrue; } - } + } + else {*/ + if ( !*swinging ) { + // see if a swing should be started + //swing = AngleSubtract( *angle, destination ); + + if ( swing == 0 ) { + *swinging = qfalse; + } + + else if ( !pitch && ( swing >= clampTolerance || swing <= -clampTolerance ) ) { + *swinging = qtrue; + } + + if ( pitch ) + *swinging = qtrue; + + /*else if ( swing > swingTolerance || swing < -swingTolerance ) { + *swinging = qtrue; + }*/ + } + //} if ( !*swinging ) { return; } - + // modify the speed depending on the delta // so it doesn't seem so linear swing = AngleSubtract( destination, *angle ); @@ -1336,10 +2716,13 @@ static void CG_SwingAngles( float destination, float swingTolerance, float clamp // clamp to no more than tolerance swing = AngleSubtract( destination, *angle ); - if ( swing > clampTolerance ) { - *angle = AngleMod( destination - (clampTolerance - 1) ); - } else if ( swing < -clampTolerance ) { - *angle = AngleMod( destination + (clampTolerance - 1) ); + if ( swing > clampTolerance ) + { + *angle = AngleMod( destination - (clampTolerance - 1) ); //clampTolerance + } + else if ( swing < -clampTolerance ) + { + *angle = AngleMod( destination + (clampTolerance - 1) ); //clampTolerance } } @@ -1381,30 +2764,144 @@ Handles seperate torso motion if < 45 degrees, also show in torso =============== */ + +//static float yawClamped; +//static float headClamp; + +#define YAW_DELTA 100 //max yaw a head can turn around without looking like an exorcist spoof ;P +#define PITCH_DELTA 35 //max pitch a head can tilt before looking like the player sepearated their neck O_o + +extern qboolean PM_PlayerIdling ( int torsoAnim, int legsAnim ); + static void CG_PlayerAngles( centity_t *cent, vec3_t legs[3], vec3_t torso[3], vec3_t head[3] ) { vec3_t legsAngles, torsoAngles, headAngles; float dest; - static int movementOffsets[8] = { 0, 22, 45, -22, 0, 22, -45, -22 }; + //float delta; + static int movementOffsets[8] = { 0, 22, 45, -22, 0, 22, -45, -22 }; //{ 0, 22, 45, -22, 0, 22, -45, -22 }; vec3_t velocity; float speed; - int dir, clientNum; - clientInfo_t *ci; + int dir; + qboolean offsetPitch; + clientInfo_t* ci; + int i; + qboolean LockBodyYaw=qfalse; //RPG-X:TiM + + if ( cent->currentState.eFlags & EF_ITEMPLACEHOLDER ) + ci = &cgs.decoyInfo[cent->currentState.eventParm]; + else + ci = &cgs.clientinfo[cent->currentState.clientNum]; + + if ( cent->currentState.eFlags & EF_CLAMP_ALL ) { + + VectorSet( headAngles, 0, cent->pe.legs.yawAngle, 0 ); + VectorSet( torsoAngles, 0, cent->pe.legs.yawAngle, 0 ); + VectorSet( legsAngles, 0, cent->pe.legs.yawAngle, 0 ); + + AnglesSubtract( headAngles, torsoAngles, headAngles ); + AnglesSubtract( torsoAngles, legsAngles, torsoAngles ); + AnglesToAxis( legsAngles, legs ); + AnglesToAxis( torsoAngles, torso ); + AnglesToAxis( headAngles, head ); + return; + } + + if( /*( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) != BOTH_LADDER_DWN1 + && ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) != BOTH_LADDER_UP1 + && ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) != BOTH_LADDER_IDLE + &&*/ !( cent->currentState.eFlags & EF_CLAMP_BODY ) ) + { + LockBodyYaw = qfalse; + } + else { + LockBodyYaw = qtrue; + + cent->pe.torso.pitchAngle = 0; + } + //} + VectorCopy( cent->lerpAngles, headAngles ); - headAngles[YAW] = AngleMod( headAngles[YAW] ); VectorClear( legsAngles ); - VectorClear( torsoAngles ); + VectorClear( torsoAngles ); + headAngles[YAW] = AngleMod( headAngles[YAW] ); + //headAngles[PITCH] = AngleMod( headAngles[PITCH] ); + + /*if ( LockBodyYaw && yawClamped == 0.0 ) + yawClamped = headAngles[YAW]; + else if ( !LockBodyYaw ) { + yawClamped = 0.0; + }*/ + + if ( LockBodyYaw ) { + float deltaYaw; + float turnRatio; + float finalPitch; + + //calc ratio of delta from origin yaw to current yaw + turnRatio = Q_fabs( AngleDelta( cent->pe.torso.yawAngle, headAngles[YAW] ) ) / 90.0f; + if ( turnRatio > 1.0f ) + turnRatio = 1.0f; + if ( turnRatio < 0.0f ) + turnRatio = 0.0f; + + finalPitch = (float)PITCH_DELTA - ( 10.0f * turnRatio ); + + //CG_Printf( "Pitch Before: %f\n", headAngles[PITCH] ); + + //handle head pitch + //if players are looking down, clamp it so the more yaw there is, the higher they'll be looking. + //reason being, most humans can't bury their face that far into their shoulders. + if ( headAngles[PITCH] > finalPitch && headAngles[PITCH] > 0 ) //Looking down. weirdly enough + { + headAngles[PITCH] = finalPitch; + } + else if ( headAngles[PITCH] < -PITCH_DELTA ) + { + //delta = headAngles[YAW] + AngleMod( cent->pe.legs.yawAngle + YAW_DELTA); + //headAngles[YAW] = AngleMod(cent->pe.legs.yawAngle - YAW_DELTA) + delta; + headAngles[PITCH] = -PITCH_DELTA; + } + + //if head yaw is about to rip off the exorcist + /*if ( ( headAngles[YAW] > AngleMod( cent->pe.legs.yawAngle + YAW_DELTA) ) + && ( headAngles[YAW] < AngleMod( cent->pe.legs.yawAngle + 180.0f) ) ) + { + //delta = Q_fabs(headAngles[YAW] - AngleMod( cent->pe.legs.yawAngle + YAW_DELTA)); + //headAngles[YAW] = AngleMod(cent->pe.legs.yawAngle + YAW_DELTA) - delta; + headAngles[YAW] = AngleMod(cent->pe.legs.yawAngle + YAW_DELTA); + } + else if ( headAngles[YAW] < AngleMod( cent->pe.legs.yawAngle - YAW_DELTA) + && ( headAngles[YAW] > AngleMod( cent->pe.legs.yawAngle + 180.0f) ) ) + { + //delta = headAngles[YAW] + AngleMod( cent->pe.legs.yawAngle + YAW_DELTA); + //headAngles[YAW] = AngleMod(cent->pe.legs.yawAngle - YAW_DELTA) + delta; + headAngles[YAW] = AngleMod(cent->pe.legs.yawAngle - YAW_DELTA); + }*/ + + if ( Q_fabs( deltaYaw = AngleDelta( headAngles[YAW], cent->pe.torso.yawAngle ) ) > YAW_DELTA ) { + if ( deltaYaw > 0 ) { + headAngles[YAW] = AngleNormalize360 ( cent->pe.torso.yawAngle + YAW_DELTA ); + } + else { + headAngles[YAW] = AngleNormalize360 ( cent->pe.torso.yawAngle - YAW_DELTA ); + } + } + //CG_Printf( "Pitch After: %f\n", headAngles[PITCH] ); + } // --------- yaw ------------- // allow yaw to drift a bit - if ( ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) != LEGS_IDLE - || ((cent->currentState.torsoAnim & ~ANIM_TOGGLEBIT) != TORSO_STAND - && (cent->currentState.torsoAnim & ~ANIM_TOGGLEBIT) != TORSO_STAND2)) { + if ( !PM_PlayerIdling( cent->currentState.torsoAnim, cent->currentState.legsAnim ) + || ( cg_liftEnts[cent->currentState.clientNum] > 0/*(cg.time - cgs.levelStartTime)*/ ) ) { // if not standing still, always point all in the same direction cent->pe.torso.yawing = qtrue; // always center cent->pe.torso.pitching = qtrue; // always center cent->pe.legs.yawing = qtrue; // always center + offsetPitch = qfalse; + } + else { + offsetPitch = qtrue; } // adjust legs for movement dir @@ -1417,39 +2914,143 @@ static void CG_PlayerAngles( centity_t *cent, vec3_t legs[3], vec3_t torso[3], v CG_Error( "Bad player movement angle" ); } } - legsAngles[YAW] = headAngles[YAW] + movementOffsets[ dir ]; - torsoAngles[YAW] = headAngles[YAW] + 0.25 * movementOffsets[ dir ]; - // torso - CG_SwingAngles( torsoAngles[YAW], 25, 90, cg_swingSpeed.value, ¢->pe.torso.yawAngle, ¢->pe.torso.yawing ); - CG_SwingAngles( legsAngles[YAW], 40, 90, cg_swingSpeed.value, ¢->pe.legs.yawAngle, ¢->pe.legs.yawing ); + //RPG-X Ladder disables character yawing coz it's like they're spinning on air + if( !LockBodyYaw ) + { + legsAngles[YAW] = headAngles[YAW] ; + torsoAngles[YAW] = headAngles[YAW] ; + + if ( !cg_liftEnts[cent->currentState.clientNum] ) + { + legsAngles[YAW] += movementOffsets[ dir ]; + torsoAngles[YAW] += 0.25 * movementOffsets[ dir ]; + } + + CG_SwingAngles( torsoAngles[YAW], 25, 90, cg_swingSpeed.value, ¢->pe.torso.yawAngle, ¢->pe.torso.yawing, qfalse ); + CG_SwingAngles( legsAngles[YAW], 40, 90, cg_swingSpeed.value, ¢->pe.legs.yawAngle, ¢->pe.legs.yawing, qfalse ); + } + + //TiM - if turbolifting, rotate us, but then don't lerp + if ( cg_liftEnts[cent->currentState.clientNum] > 0/*(cg.time - cgs.levelStartTime)*/ ) + { + if ( !cent->pe.legs.yawing ) + { + cent->clampAngles = qtrue; + } + } + + if ( cent->clampAngles ) { + //torsoAngles[YAW] = headAngles[YAW]; + //legsAngles[YAW] = headAngles[YAW]; + cent->pe.torso.yawAngle = headAngles[YAW]; + cent->pe.legs.yawAngle = headAngles[YAW]; + } torsoAngles[YAW] = cent->pe.torso.yawAngle; legsAngles[YAW] = cent->pe.legs.yawAngle; + if ( !cg_liftEnts[cent->currentState.clientNum] && cent->clampAngles > qfalse ) + cent->clampAngles = qfalse; // --------- pitch ------------- + //TiM : Add an offset so they don't lean as much when idling + //Make it default elsewise tho // only show a fraction of the pitch angle in the torso - if ( headAngles[PITCH] > 180 ) { - dest = (-360 + headAngles[PITCH]) * 0.75f; - } else { - dest = headAngles[PITCH] * 0.75f; - } - CG_SwingAngles( dest, 15, 30, 0.1f, ¢->pe.torso.pitchAngle, ¢->pe.torso.pitching ); - torsoAngles[PITCH] = cent->pe.torso.pitchAngle; - // - clientNum = cent->currentState.clientNum; - if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) { - ci = &cgs.clientinfo[ clientNum ]; - if ( ci->fixedtorso ) { - torsoAngles[PITCH] = 0.0f; + //Com_Printf( "headPitch: %f\n", headAngles[PITCH] ); + if ( headAngles[PITCH] > 180 ) { + dest = (-360 + headAngles[PITCH]) * (offsetPitch==qtrue ? 0.45 : 0.75); //(offsetPitch ? 0.95 : 0.75) + } else { + //if offsetPitch enabled (ie, we're in the ideal pose for the cool neck-only rotation) + //this will make the actual torso pitch delay a tad until it's passed a threshold + //of 30 degrees in either direction. The overall aim of this is to try and minimize + //the torso movement so it's more realistically subtle, instead of stupidly, physics defyingly + //obvious (like being able to bend on a 90 degree ange >_< ) + if ( offsetPitch ) { + if ( headAngles[PITCH] > 30 ) { + dest = (headAngles[PITCH] - 30 ) * 0.60; + } else if ( headAngles[PITCH] < -40 ) { + dest = ( headAngles[PITCH] + 40 ) * 0.45; + } else { + dest = 0; + } + } + else { + dest = headAngles[PITCH] * 0.75; } } - // --------- roll ------------- + //I had to lock down the pitch when dead. The player's head was going thru the floor O_o + if( !LockBodyYaw && !( cent->currentState.eFlags & EF_DEAD ) /*&& !( cent->currentState.number == cg.snap->ps.clientNum && !cg.renderingThirdPerson )*/ ) + { //(offsetPitch ? 10 : 30) + if (cent->currentState.eFlags & EF_FULL_ROTATE ) + { + //CG_Printf("Lerp Detected\n"); + legsAngles[PITCH] = headAngles[PITCH]; + CG_SwingAngles( legsAngles[PITCH], 15, 30, 0.1, ¢->pe.legs.pitchAngle, ¢->pe.legs.pitching, qtrue ); + legsAngles[PITCH] = cent->pe.legs.pitchAngle; + + torsoAngles[PITCH] = headAngles[PITCH]; + CG_SwingAngles( torsoAngles[PITCH], 15, 30, 0.1, ¢->pe.torso.pitchAngle, ¢->pe.torso.pitching, qtrue ); + torsoAngles[PITCH] = cent->pe.torso.pitchAngle; + } + else + { + CG_SwingAngles( dest, 15, 30, 0.1, ¢->pe.torso.pitchAngle, ¢->pe.torso.pitching, qtrue ); + torsoAngles[PITCH] = cent->pe.torso.pitchAngle; + } + } + + //Com_Printf("Bitwise operation >>: %i, Bitwise Operation &: %i\n", Q_log2(8192), 10 & 255 ); + //Com_Printf("Atof: %f\n", atof( "0.43284673 t" ) ); + + // --------- talking ---------- + // ------ head rotation ------- + if ( cent->currentState.eFlags & EF_TALKING ) { + ci->headDebounceTime = cg.time + 1000; + } + + if (ci->headDebounceTime > cg.time /*&& !LockBodyYaw*/ ) { + if ( cent->currentState.eFlags & EF_TALKING ) { + if ( cg.time > ci->nextTalkAngle || (!ci->talkAngles[PITCH] && !ci->talkAngles[YAW] && !ci->talkAngles[ROLL]) ) { + + for ( i = 0; i < 3; i++ ) { + ci->talkAngles[i] = flrandom( -4, 4 ); + } + + ci->talkDifferential = irandom( 200, 500 ); + ci->nextTalkAngle = cg.time + ci->talkDifferential; + } + + } + else { + if ( ci->talkAngles[0] != 1 && ci->talkAngles[1] != 1 && ci->talkAngles[2] != 1 ) { + //VectorCopy(ci->talkAngles, cent->lerpAngles); + ci->talkDifferential = 300; + VectorSet(ci->talkAngles, 0, 0, 0 ); + } + } + //Com_Printf("Yaw Offset: %f, Yaw: %f, LerpYaw: %f\n", ci->talkAngles[YAW], headAngles[YAW], cent->lerpAngles[YAW]); + + //if ( (cent->pe.head.pitchAngle != 0.0 && cent->pe.head.yawAngle != 0.0 && cent->pe.head.yawAngle != 0.0) + // && !VectorCompare( ci->talkAngles, vec3_origin) ) { + + CG_SwingAngles( ci->talkAngles[PITCH], 30, 30, ci->talkDifferential*0.00005, ¢->pe.head.pitchAngle, ¢->pe.head.pitching, qtrue ); + CG_SwingAngles( ci->talkAngles[YAW], 30, 30, ci->talkDifferential*0.00005, ¢->pe.head.yawAngle, ¢->pe.head.yawing, qtrue ); + CG_SwingAngles( ci->talkAngles[ROLL], 30, 30, ci->talkDifferential*0.00005, ¢->pe.head.rollAngle, ¢->pe.head.rolling, qtrue ); + + headAngles[PITCH] = AngleMod(headAngles[PITCH] + cent->pe.head.pitchAngle); + headAngles[YAW] = AngleMod(headAngles[YAW] + cent->pe.head.yawAngle); + headAngles[ROLL] = AngleMod(headAngles[ROLL] + cent->pe.head.rollAngle); + //} + } + + // --------- roll ------------- + //TiM - After I reintegrated velocity into + //the player state, this code randomly started working lol! // lean towards the direction of travel VectorCopy( cent->currentState.pos.trDelta, velocity ); @@ -1458,7 +3059,7 @@ static void CG_PlayerAngles( centity_t *cent, vec3_t legs[3], vec3_t torso[3], v vec3_t axis[3]; float side; - speed *= 0.05f; + speed *= 0.04; //0.05 - TiM AnglesToAxis( legsAngles, axis ); side = speed * DotProduct( velocity, axis[1] ); @@ -1468,17 +3069,6 @@ static void CG_PlayerAngles( centity_t *cent, vec3_t legs[3], vec3_t torso[3], v legsAngles[PITCH] += side; } - // - clientNum = cent->currentState.clientNum; - if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) { - ci = &cgs.clientinfo[ clientNum ]; - if ( ci->fixedlegs ) { - legsAngles[YAW] = torsoAngles[YAW]; - legsAngles[PITCH] = 0.0f; - legsAngles[ROLL] = 0.0f; - } - } - // pain twitch CG_AddPainTwitch( cent, torsoAngles ); @@ -1498,16 +3088,16 @@ static void CG_PlayerAngles( centity_t *cent, vec3_t legs[3], vec3_t torso[3], v CG_HasteTrail =============== */ -static void CG_HasteTrail( centity_t *cent ) { +/*static void CG_HasteTrail( centity_t *cent ) { localEntity_t *smoke; - vec3_t origin; + vec3_t origin, pos2; int anim; if ( cent->trailTime > cg.time ) { return; } anim = cent->pe.legs.animationNumber & ~ANIM_TOGGLEBIT; - if ( anim != LEGS_RUN && anim != LEGS_BACK ) { + if ( anim != BOTH_RUN1 && anim != BOTH_RUN1 ) { //LEGS_RUN return; } @@ -1517,327 +3107,100 @@ static void CG_HasteTrail( centity_t *cent ) { } VectorCopy( cent->lerpOrigin, origin ); - origin[2] -= 16; + origin[0] += flrandom(-5,5); + origin[1] += flrandom(-5,5); + origin[2] -= 15; - smoke = CG_SmokePuff( origin, vec3_origin, - 8, - 1, 1, 1, 1, - 500, - cg.time, - 0, - 0, - cgs.media.hastePuffShader ); + AngleVectors(cent->lerpAngles, pos2, NULL, NULL); + pos2[2]=0; + VectorMA(origin, -22.0, pos2, pos2); - // use the optimized local entity add - smoke->leType = LE_SCALE_FADE; -} - -#ifdef MISSIONPACK -/* -=============== -CG_BreathPuffs -=============== -*/ -static void CG_BreathPuffs( centity_t *cent, refEntity_t *head) { - clientInfo_t *ci; - vec3_t up, origin; - int contents; - - ci = &cgs.clientinfo[ cent->currentState.number ]; - - if (!cg_enableBreath.integer) { - return; - } - if ( cent->currentState.number == cg.snap->ps.clientNum && !cg.renderingThirdPerson) { - return; - } - if ( cent->currentState.eFlags & EF_DEAD ) { - return; - } - contents = CG_PointContents( head->origin, 0 ); - if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) { - return; - } - if ( ci->breathPuffTime > cg.time ) { - return; - } - - VectorSet( up, 0, 0, 8 ); - VectorMA(head->origin, 8, head->axis[0], origin); - VectorMA(origin, -4, head->axis[2], origin); - CG_SmokePuff( origin, up, 16, 1, 1, 1, 0.66f, 1500, cg.time, cg.time + 400, LEF_PUFF_DONT_SCALE, cgs.media.shotgunSmokePuffShader ); - ci->breathPuffTime = cg.time + 2000; -} + smoke = FX_AddLine(origin, pos2, 1.0, 20.0, -12.0, 0.7, 0.0, 500, cgs.media.hastePuffShader); +}*/ /* =============== -CG_DustTrail +CG_FlightTrail =============== */ -static void CG_DustTrail( centity_t *cent ) { - int anim; - vec3_t end, vel; - trace_t tr; +/*static void CG_FlightTrail( centity_t *cent ) { + localEntity_t *smoke; + vec3_t origin; + vec3_t vel; + vec3_t startrgb={0.5, 0.5, 0.5}; + vec3_t endrgb={0.0,0.0,0.0}; - if (!cg_enableDust.integer) - return; + VectorCopy( cent->lerpOrigin, origin ); + origin[2] -= flrandom(10,18); - if ( cent->dustTrailTime > cg.time ) { - return; - } + VectorSet(vel, flrandom(-10,10), flrandom(-10, 10), flrandom(-30,-50)); - anim = cent->pe.legs.animationNumber & ~ANIM_TOGGLEBIT; - if ( anim != LEGS_LANDB && anim != LEGS_LAND ) { - return; - } - - cent->dustTrailTime += 40; - if ( cent->dustTrailTime < cg.time ) { - cent->dustTrailTime = cg.time; - } - - VectorCopy(cent->currentState.pos.trBase, end); - end[2] -= 64; - CG_Trace( &tr, cent->currentState.pos.trBase, NULL, NULL, end, cent->currentState.number, MASK_PLAYERSOLID ); - - if ( !(tr.surfaceFlags & SURF_DUST) ) - return; - - VectorCopy( cent->currentState.pos.trBase, end ); - end[2] -= 16; - - VectorSet(vel, 0, 0, -30); - CG_SmokePuff( end, vel, - 24, - .8f, .8f, 0.7f, 0.33f, - 500, - cg.time, - 0, - 0, - cgs.media.dustPuffShader ); -} - -#endif + smoke = FX_AddSprite2(origin, vel, qfalse, 4.0, 4.0, 0.5, 0.0, startrgb, endrgb, flrandom(0,360), 0, 500, cgs.media.flightPuffShader); +}*/ /* =============== CG_TrailItem =============== */ -static void CG_TrailItem( centity_t *cent, qhandle_t hModel ) { +/*static void CG_TrailItem( centity_t *cent, qhandle_t hModel ) { refEntity_t ent; vec3_t angles; - vec3_t axis[3]; + float frame; + + if ( cent->currentState.number == cg.snap->ps.clientNum && !cg.renderingThirdPerson ) + { + return; + } + + memset( &ent, 0, sizeof( ent ) ); VectorCopy( cent->lerpAngles, angles ); angles[PITCH] = 0; angles[ROLL] = 0; - AnglesToAxis( angles, axis ); - - memset( &ent, 0, sizeof( ent ) ); - VectorMA( cent->lerpOrigin, -16, axis[0], ent.origin ); - ent.origin[2] += 16; - angles[YAW] += 90; + angles[YAW] += 180.0; // It's facing the wrong way. AnglesToAxis( angles, ent.axis ); + VectorMA( cent->lerpOrigin, 12, ent.axis[0], ent.origin ); + ent.origin[2] += 4; + + // Make it animate. + frame = (cg.time / 100.0); + ent.renderfx|=RF_WRAP_FRAMES; + + ent.oldframe = (int)frame; + ent.frame = (int)frame+1; + ent.backlerp = (float)(ent.frame) - frame; + + // if the player is looking at himself in 3rd person, don't show the flag solid, 'cause he can't see!!! + if (cent->currentState.number == cg.snap->ps.clientNum) + { + ent.shaderRGBA[3] = 128; + ent.renderfx |= RF_FORCE_ENT_ALPHA; + } + + VectorScale(ent.axis[0], 0.75, ent.axis[0]); + VectorScale(ent.axis[1], 0.9, ent.axis[1]); + VectorScale(ent.axis[2], 0.9, ent.axis[2]); + ent.nonNormalizedAxes = qtrue; + +#if 0 // This approach is used if you want the item to autorotate. Since this is the flag, we don't. + VectorScale( cg.autoAxis[0], 0.75, ent.axis[0] ); + VectorScale( cg.autoAxis[1], 0.75, ent.axis[1] ); + VectorScale( cg.autoAxis[2], 0.75, ent.axis[2] ); +#endif + ent.hModel = hModel; trap_R_AddRefEntityToScene( &ent ); -} - - -/* -=============== -CG_PlayerFlag -=============== -*/ -static void CG_PlayerFlag( centity_t *cent, qhandle_t hSkin, refEntity_t *torso ) { - clientInfo_t *ci; - refEntity_t pole; - refEntity_t flag; - vec3_t angles, dir; - int legsAnim, flagAnim, updateangles; - float angle, d; - - // show the flag pole model - memset( &pole, 0, sizeof(pole) ); - pole.hModel = cgs.media.flagPoleModel; - VectorCopy( torso->lightingOrigin, pole.lightingOrigin ); - pole.shadowPlane = torso->shadowPlane; - pole.renderfx = torso->renderfx; - CG_PositionEntityOnTag( &pole, torso, torso->hModel, "tag_flag" ); - trap_R_AddRefEntityToScene( &pole ); - - // show the flag model - memset( &flag, 0, sizeof(flag) ); - flag.hModel = cgs.media.flagFlapModel; - flag.customSkin = hSkin; - VectorCopy( torso->lightingOrigin, flag.lightingOrigin ); - flag.shadowPlane = torso->shadowPlane; - flag.renderfx = torso->renderfx; - - VectorClear(angles); - - updateangles = qfalse; - legsAnim = cent->currentState.legsAnim & ~ANIM_TOGGLEBIT; - if( legsAnim == LEGS_IDLE || legsAnim == LEGS_IDLECR ) { - flagAnim = FLAG_STAND; - } else if ( legsAnim == LEGS_WALK || legsAnim == LEGS_WALKCR ) { - flagAnim = FLAG_STAND; - updateangles = qtrue; - } else { - flagAnim = FLAG_RUN; - updateangles = qtrue; - } - - if ( updateangles ) { - - VectorCopy( cent->currentState.pos.trDelta, dir ); - // add gravity - dir[2] += 100; - VectorNormalize( dir ); - d = DotProduct(pole.axis[2], dir); - // if there is anough movement orthogonal to the flag pole - if (fabs(d) < 0.9) { - // - d = DotProduct(pole.axis[0], dir); - if (d > 1.0f) { - d = 1.0f; - } - else if (d < -1.0f) { - d = -1.0f; - } - angle = acos(d); - - d = DotProduct(pole.axis[1], dir); - if (d < 0) { - angles[YAW] = 360 - angle * 180 / M_PI; - } - else { - angles[YAW] = angle * 180 / M_PI; - } - if (angles[YAW] < 0) - angles[YAW] += 360; - if (angles[YAW] > 360) - angles[YAW] -= 360; - - //vectoangles( cent->currentState.pos.trDelta, tmpangles ); - //angles[YAW] = tmpangles[YAW] + 45 - cent->pe.torso.yawAngle; - // change the yaw angle - CG_SwingAngles( angles[YAW], 25, 90, 0.15f, ¢->pe.flag.yawAngle, ¢->pe.flag.yawing ); - } - - /* - d = DotProduct(pole.axis[2], dir); - angle = Q_acos(d); - - d = DotProduct(pole.axis[1], dir); - if (d < 0) { - angle = 360 - angle * 180 / M_PI; - } - else { - angle = angle * 180 / M_PI; - } - if (angle > 340 && angle < 20) { - flagAnim = FLAG_RUNUP; - } - if (angle > 160 && angle < 200) { - flagAnim = FLAG_RUNDOWN; - } - */ - } - - // set the yaw angle - angles[YAW] = cent->pe.flag.yawAngle; - // lerp the flag animation frames - ci = &cgs.clientinfo[ cent->currentState.clientNum ]; - CG_RunLerpFrame( ci, ¢->pe.flag, flagAnim, 1 ); - flag.oldframe = cent->pe.flag.oldFrame; - flag.frame = cent->pe.flag.frame; - flag.backlerp = cent->pe.flag.backlerp; - - AnglesToAxis( angles, flag.axis ); - CG_PositionRotatedEntityOnTag( &flag, &pole, pole.hModel, "tag_flag" ); - - trap_R_AddRefEntityToScene( &flag ); -} - - -#ifdef MISSIONPACK -/* -=============== -CG_PlayerTokens -=============== -*/ -static void CG_PlayerTokens( centity_t *cent, int renderfx ) { - int tokens, i, j; - float angle; - refEntity_t ent; - vec3_t dir, origin; - skulltrail_t *trail; - trail = &cg.skulltrails[cent->currentState.number]; - tokens = cent->currentState.generic1; - if ( !tokens ) { - trail->numpositions = 0; - return; - } - - if ( tokens > MAX_SKULLTRAIL ) { - tokens = MAX_SKULLTRAIL; - } - - // add skulls if there are more than last time - for (i = 0; i < tokens - trail->numpositions; i++) { - for (j = trail->numpositions; j > 0; j--) { - VectorCopy(trail->positions[j-1], trail->positions[j]); - } - VectorCopy(cent->lerpOrigin, trail->positions[0]); - } - trail->numpositions = tokens; - - // move all the skulls along the trail - VectorCopy(cent->lerpOrigin, origin); - for (i = 0; i < trail->numpositions; i++) { - VectorSubtract(trail->positions[i], origin, dir); - if (VectorNormalize(dir) > 30) { - VectorMA(origin, 30, dir, trail->positions[i]); - } - VectorCopy(trail->positions[i], origin); - } - - memset( &ent, 0, sizeof( ent ) ); - if( cgs.clientinfo[ cent->currentState.clientNum ].team == TEAM_BLUE ) { - ent.hModel = cgs.media.redCubeModel; - } else { - ent.hModel = cgs.media.blueCubeModel; - } - ent.renderfx = renderfx; - - VectorCopy(cent->lerpOrigin, origin); - for (i = 0; i < trail->numpositions; i++) { - VectorSubtract(origin, trail->positions[i], ent.axis[0]); - ent.axis[0][2] = 0; - VectorNormalize(ent.axis[0]); - VectorSet(ent.axis[2], 0, 0, 1); - CrossProduct(ent.axis[0], ent.axis[2], ent.axis[1]); - - VectorCopy(trail->positions[i], ent.origin); - angle = (((cg.time + 500 * MAX_SKULLTRAIL - 500 * i) / 16) & 255) * (M_PI * 2) / 255; - ent.origin[2] += sin(angle) * 10; - trap_R_AddRefEntityToScene( &ent ); - VectorCopy(trail->positions[i], origin); - } -} -#endif - +}*/ /* =============== CG_PlayerPowerups =============== */ -static void CG_PlayerPowerups( centity_t *cent, refEntity_t *torso ) { +static void CG_PlayerPowerups( centity_t *cent ) { int powerups; - clientInfo_t *ci; powerups = cent->currentState.powerups; if ( !powerups ) { @@ -1845,56 +3208,59 @@ static void CG_PlayerPowerups( centity_t *cent, refEntity_t *torso ) { } // quad gives a dlight - if ( powerups & ( 1 << PW_QUAD ) ) { - trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 0.2f, 0.2f, 1 ); - } +/* if ( powerups & ( 1 << PW_QUAD ) ) { + trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 0.2, 0.2, 1.0 ); + }*/ + + // invul gives a dlight +/* if ( powerups & ( 1 << PW_BOLTON ) ) { + trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 0.8, 0.8, 0.2 ); + }*/ + + // borg adapt gives a dlight + //RPG-X TiM + /*if ( powerups & ( 1 << PW_BEAMING ) ) { + trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 0.2, 1.0, 0.2 ); + }*/ // flight plays a looped sound - if ( powerups & ( 1 << PW_FLIGHT ) ) { - trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, cgs.media.flightSound ); - } +// if ( powerups & ( 1 << PW_FLIGHT ) ) { +// trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, cgs.media.flightSound ); +// } - ci = &cgs.clientinfo[ cent->currentState.clientNum ]; // redflag - if ( powerups & ( 1 << PW_REDFLAG ) ) { - if (ci->newAnims) { - CG_PlayerFlag( cent, cgs.media.redFlagFlapSkin, torso ); - } - else { - CG_TrailItem( cent, cgs.media.redFlagModel ); - } - trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 1.0, 0.2f, 0.2f ); - } + /*if ( powerups & ( 1 << PW_REDFLAG ) ) { + CG_TrailItem( cent, cgs.media.redFlagModel ); + trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 1, 0.2, 0.2 ); + }*/ - // blueflag - if ( powerups & ( 1 << PW_BLUEFLAG ) ) { - if (ci->newAnims){ - CG_PlayerFlag( cent, cgs.media.blueFlagFlapSkin, torso ); - } - else { - CG_TrailItem( cent, cgs.media.blueFlagModel ); - } - trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 0.2f, 0.2f, 1.0 ); - } - - // neutralflag - if ( powerups & ( 1 << PW_NEUTRALFLAG ) ) { - if (ci->newAnims) { - CG_PlayerFlag( cent, cgs.media.neutralFlagFlapSkin, torso ); - } - else { - CG_TrailItem( cent, cgs.media.neutralFlagModel ); - } - trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 1.0, 1.0, 1.0 ); + // blueflag | RGP-X | GSIO01 | 08/05/2009: no blueflag no more... now borgadapt + if ( powerups & ( 1 << PW_BORG_ADAPT ) ) { + //CG_TrailItem( cent, cgs.media.blueFlagModel ); + //trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 0.2, 0.2, 1 ); + trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 0.2, 1.0, 0.2 ); } // haste leaves smoke trails - if ( powerups & ( 1 << PW_HASTE ) ) { + /*if ( powerups & ( 1 << PW_HASTE ) && (cent->currentState.groundEntityNum==ENTITYNUM_WORLD)) { CG_HasteTrail( cent ); - } + }*/ + + // haste leaves smoke trails +// if ( powerups & ( 1 << PW_FLIGHT ) && (cent->currentState.groundEntityNum!=ENTITYNUM_WORLD)) { +// CG_FlightTrail( cent ); +// } + + // seeker coolness + /*if ( powerups & ( 1 << PW_FLASHLIGHT ) ) + { + CG_Seeker(cent); + }*/ } + + /* =============== CG_PlayerFloatSprite @@ -1905,6 +3271,7 @@ Float a sprite over the player's head static void CG_PlayerFloatSprite( centity_t *cent, qhandle_t shader ) { int rf; refEntity_t ent; + int team; if ( cent->currentState.number == cg.snap->ps.clientNum && !cg.renderingThirdPerson ) { rf = RF_THIRD_PERSON; // only show in mirrors @@ -1912,16 +3279,33 @@ static void CG_PlayerFloatSprite( centity_t *cent, qhandle_t shader ) { rf = 0; } + team = cgs.clientinfo[ cent->currentState.clientNum ].team; + memset( &ent, 0, sizeof( ent ) ); VectorCopy( cent->lerpOrigin, ent.origin ); ent.origin[2] += 48; ent.reType = RT_SPRITE; ent.customShader = shader; - ent.radius = 10; + ent.data.sprite.radius = 10; ent.renderfx = rf; - ent.shaderRGBA[0] = 255; - ent.shaderRGBA[1] = 255; - ent.shaderRGBA[2] = 255; + if (team==TEAM_RED) + { + ent.shaderRGBA[0] = 255; + ent.shaderRGBA[1] = 64; + ent.shaderRGBA[2] = 64; + } + else if (team==TEAM_BLUE) + { + ent.shaderRGBA[0] = 64; + ent.shaderRGBA[1] = 64; + ent.shaderRGBA[2] = 255; + } + else + { + ent.shaderRGBA[0] = 255; + ent.shaderRGBA[1] = 255; + ent.shaderRGBA[2] = 255; + } ent.shaderRGBA[3] = 255; trap_R_AddRefEntityToScene( &ent ); } @@ -1936,15 +3320,62 @@ Float sprites over the player's head =============== */ static void CG_PlayerSprites( centity_t *cent ) { - int team; +// int team; - if ( cent->currentState.eFlags & EF_CONNECTION ) { + if ( cent->currentState.eFlags & EF_CONNECTION ) + { CG_PlayerFloatSprite( cent, cgs.media.connectionShader ); return; } - if ( cent->currentState.eFlags & EF_TALK ) { - CG_PlayerFloatSprite( cent, cgs.media.balloonShader ); +/* + if ( cent->currentState.eFlags & EF_TALK ) + { + if ( cgs.clientinfo[cent->currentState.number].pClass == PC_ACTIONHERO ) + { + CG_PlayerFloatSprite( cent, cgs.media.heroSpriteShader ); + } + if ( cgs.clientinfo[cent->currentState.number].pClass == PC_BORG ) + { + if ( (cg_entities[cent->currentState.number].currentState.powerups&(1<currentState.number].pClass == PC_ACTIONHERO ) + { + CG_PlayerFloatSprite( cent, cgs.media.heroSpriteShader ); + return; + } + + //Special hack: if it's Borg who has regen going, must be Borg queen + if ( cgs.clientinfo[cent->currentState.number].pClass == PC_BORG ) + { + if ( (cg_entities[cent->currentState.number].currentState.powerups&(1<currentState.number].pClass == PC_BORG ) + { + CG_PlayerFloatSprite( cent, cgs.media.borgIconShader ); + return; + } + + if ( cent->currentState.eFlags & EF_AWARD_FIRSTSTRIKE ) { + CG_PlayerFloatSprite( cent, cgs.media.medalFirstStrike ); return; } @@ -1958,35 +3389,111 @@ static void CG_PlayerSprites( centity_t *cent ) { return; } - if ( cent->currentState.eFlags & EF_AWARD_GAUNTLET ) { - CG_PlayerFloatSprite( cent, cgs.media.medalGauntlet ); + if ( cent->currentState.eFlags & EF_AWARD_ACE ) { + CG_PlayerFloatSprite( cent, cgs.media.medalAce ); return; } - if ( cent->currentState.eFlags & EF_AWARD_DEFEND ) { - CG_PlayerFloatSprite( cent, cgs.media.medalDefend ); + if ( cent->currentState.eFlags & EF_AWARD_EXPERT ) { + CG_PlayerFloatSprite( cent, cgs.media.medalExpert ); return; } - if ( cent->currentState.eFlags & EF_AWARD_ASSIST ) { - CG_PlayerFloatSprite( cent, cgs.media.medalAssist ); + if ( cent->currentState.eFlags & EF_AWARD_MASTER ) { + CG_PlayerFloatSprite( cent, cgs.media.medalMaster ); return; } - if ( cent->currentState.eFlags & EF_AWARD_CAP ) { - CG_PlayerFloatSprite( cent, cgs.media.medalCapture ); + if ( cent->currentState.eFlags & EF_AWARD_CHAMPION ) { + CG_PlayerFloatSprite( cent, cgs.media.medalChampion ); return; } team = cgs.clientinfo[ cent->currentState.clientNum ].team; if ( !(cent->currentState.eFlags & EF_DEAD) && - cg.snap->ps.persistant[PERS_TEAM] == team && - cgs.gametype >= GT_TEAM) { - if (cg_drawFriend.integer) { - CG_PlayerFloatSprite( cent, cgs.media.friendShader ); + cg.snap->ps.persistant[PERS_TEAM] == team && + cgs.gametype >= GT_TEAM && + cent->currentState.number != cg.snap->ps.clientNum ) // Don't show a sprite above a player's own head in 3rd person. + { + if (team==TEAM_RED) + { + CG_PlayerFloatSprite( cent, cgs.media.teamRedShader ); } + else if (team==TEAM_BLUE) + { + CG_PlayerFloatSprite( cent, cgs.media.teamBlueShader ); + } + // else don't show an icon. There currently are no other team types. + return; + }*/ + + //RPG-X: RedTechie - Cloak sprite basiclly other admins will see this only to tell if that player is cloaked and a admin + //if( cent->currentState.powerups & ( 1 << PW_INVIS ) ){ + // CG_PlayerFloatSprite( cent, cgs.media.cloakspriteShader ); + // return; + //} +return; + +} + +/* +=============== +CG_CalcBeamAlpha +By TiM + +Calculates the current point +in a transport cycle so we +can use it as a fade percentage +Used in shadows, and on the player +model itself +=============== +*/ +#define PLAYER_BEAM_FADETIME_DIV 1.0/(float)PLAYER_BEAM_FADETIME + +void CG_CalcBeamAlpha( int powerups, beamData_t *beamData ) { + float beamAlpha = 1.0; + int bTime = 0; + + + if ( ( powerups & ( 1 << PW_BEAM_OUT ) ) || ( powerups & ( 1 << PW_QUAD ) ) ) { + //TiM - SP transporter FX, also base alpha off of phase in transport cycle + //bTime = cg.time - beamData->beamTimeParam; + + bTime = cg.time - beamData->beamTimeParam; + + if (bTime > PLAYER_BEAM_FADE ) { + if ( bTime < ( PLAYER_BEAM_FADE + PLAYER_BEAM_FADETIME) ) { + beamAlpha = (float)( bTime - PLAYER_BEAM_FADE ) * PLAYER_BEAM_FADETIME_DIV; + + //if we're beaming out, invert the alpha value (so we fade out, not in ) + if ( powerups & ( 1 << PW_BEAM_OUT ) ) { + beamAlpha = 1.0 - beamAlpha; + } + + //Com_Printf( "Alpha = %f\n", beamAlpha ); + } + else { + if ( powerups & ( 1 << PW_BEAM_OUT ) ) { + beamAlpha = 0.0; + } + else { + beamAlpha = 1.0; + } + } + } + else { + if ( powerups & ( 1 << PW_BEAM_OUT ) ) { + beamAlpha = 1.0; + } + else { + beamAlpha = 0.0; + } + } + //CG_Printf( "BeamTime: %i, Alpha: %f\n", bTime, beamAlpha ); } + + beamData->beamAlpha = beamAlpha; } /* @@ -1999,8 +3506,8 @@ Returns the Z component of the surface being shadowed =============== */ #define SHADOW_DISTANCE 128 -static qboolean CG_PlayerShadow( centity_t *cent, float *shadowPlane ) { - vec3_t end, mins = {-15, -15, 0}, maxs = {15, 15, 2}; +static qboolean CG_PlayerShadow( centity_t *cent, vec3_t origin, float *shadowPlane, float sizeOffset ) { + vec3_t end, mins = {-7, -7, 0}, maxs = {7, 7, 2}; trace_t trace; float alpha; @@ -2011,18 +3518,24 @@ static qboolean CG_PlayerShadow( centity_t *cent, float *shadowPlane ) { } // no shadows when invisible - if ( cent->currentState.powerups & ( 1 << PW_INVIS ) ) { + //TiM - handled in two phases. When invis powerup is active, and beyond flash time, or invis is inactvie, and before flashtime + if ( + ( ( cent->currentState.powerups & ( 1 << PW_INVIS ) && cent->cloakTime > 0 && cg.time > cent->cloakTime + Q_FLASH_TIME * 0.5 ) + || ( !(cent->currentState.powerups & ( 1 << PW_INVIS )) && cent->decloakTime > 0 && cg.time < cent->decloakTime + Q_FLASH_TIME * 0.5 ) ) ) + { return qfalse; } // send a trace down from the player to the ground - VectorCopy( cent->lerpOrigin, end ); + //VectorCopy( cent->lerpOrigin, end ); + VectorCopy( origin, end ); end[2] -= SHADOW_DISTANCE; - trap_CM_BoxTrace( &trace, cent->lerpOrigin, end, mins, maxs, 0, MASK_PLAYERSOLID ); + //trap_CM_BoxTrace( &trace, cent->lerpOrigin, end, mins, maxs, 0, MASK_PLAYERSOLID ); + trap_CM_BoxTrace( &trace, origin, end, mins, maxs, 0, MASK_PLAYERSOLID ); // no shadow if too high - if ( trace.fraction == 1.0 || trace.startsolid || trace.allsolid ) { + if ( trace.fraction == 1.0 ) { return qfalse; } @@ -2035,13 +3548,19 @@ static qboolean CG_PlayerShadow( centity_t *cent, float *shadowPlane ) { // fade the shadow out with height alpha = 1.0 - trace.fraction; - // hack / FPE - bogus planes? - //assert( DotProduct( trace.plane.normal, trace.plane.normal ) != 0.0f ) + //transporter FX - beam alpha + alpha *= cent->beamData.beamAlpha; + + if ( alpha == 0.0 ) { + return qfalse; + } + + // --TiM // add the mark as a temporary, so it goes directly to the renderer // without taking a spot in the cg_marks array CG_ImpactMark( cgs.media.shadowMarkShader, trace.endpos, trace.plane.normal, - cent->pe.legs.yawAngle, alpha,alpha,alpha,1, qfalse, 24, qtrue ); + cent->pe.legs.yawAngle, 1,1,1,alpha, qfalse, ( 16 * sizeOffset ), qtrue ); return qtrue; } @@ -2060,6 +3579,8 @@ static void CG_PlayerSplash( centity_t *cent ) { int contents; polyVert_t verts[4]; + float beamRatio = 1.0; + if ( !cg_shadows.integer ) { return; } @@ -2069,7 +3590,7 @@ static void CG_PlayerSplash( centity_t *cent ) { // if the feet aren't in liquid, don't make a mark // this won't handle moving water brushes, but they wouldn't draw right anyway... - contents = CG_PointContents( end, 0 ); + contents = trap_CM_PointContents( end, 0 ); if ( !( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) ) { return; } @@ -2078,7 +3599,7 @@ static void CG_PlayerSplash( centity_t *cent ) { start[2] += 32; // if the head isn't out of liquid, don't make a mark - contents = CG_PointContents( start, 0 ); + contents = trap_CM_PointContents( start, 0 ); if ( contents & ( CONTENTS_SOLID | CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) { return; } @@ -2090,10 +3611,30 @@ static void CG_PlayerSplash( centity_t *cent ) { return; } + if ( (cent->currentState.powerups & ( 1 << PW_BEAM_OUT ) ) && ( cg.time > ( cent->beamData.beamTimeParam + 2000 ) ) ) { + //beamRatio = 1.0f - (( (float)cg.time - ( (float)cent->beamData.beamTimeParam + 2000.0f ) ) / 2000.0f); + beamRatio = 1.0f - (( (float)cg.time - ( (float)cent->beamData.beamTimeParam + 2000.0f ) ) * 0.0005f); + //CG_Printf( "Beam Out: %f\n", beamRatio ); + } + + if ( cent->currentState.powerups & ( 1 << PW_QUAD ) ) { + //beamRatio = ( ( (float)cg.time - (float)cent->beamData.beamTimeParam ) / 2000.0f ); + beamRatio = ( ( (float)cg.time - (float)cent->beamData.beamTimeParam ) * 0.0005f ); + //CG_Printf( "Beam In: %f\n", beamRatio ); + } + + if ( beamRatio > 1.0 ) { + beamRatio = 1.0; + } + + if ( beamRatio < 0.0 ) { + beamRatio = 0.0; + } + // create a mark polygon VectorCopy( trace.endpos, verts[0].xyz ); - verts[0].xyz[0] -= 32; - verts[0].xyz[1] -= 32; + verts[0].xyz[0] -= 32 * beamRatio; + verts[0].xyz[1] -= 32 * beamRatio; verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 255; @@ -2102,8 +3643,8 @@ static void CG_PlayerSplash( centity_t *cent ) { verts[0].modulate[3] = 255; VectorCopy( trace.endpos, verts[1].xyz ); - verts[1].xyz[0] -= 32; - verts[1].xyz[1] += 32; + verts[1].xyz[0] -= 32 * beamRatio; + verts[1].xyz[1] += 32 * beamRatio; verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 255; @@ -2112,8 +3653,8 @@ static void CG_PlayerSplash( centity_t *cent ) { verts[1].modulate[3] = 255; VectorCopy( trace.endpos, verts[2].xyz ); - verts[2].xyz[0] += 32; - verts[2].xyz[1] += 32; + verts[2].xyz[0] += 32 * beamRatio; + verts[2].xyz[1] += 32 * beamRatio; verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 255; @@ -2122,8 +3663,8 @@ static void CG_PlayerSplash( centity_t *cent ) { verts[2].modulate[3] = 255; VectorCopy( trace.endpos, verts[3].xyz ); - verts[3].xyz[0] += 32; - verts[3].xyz[1] -= 32; + verts[3].xyz[0] += 32 * beamRatio; + verts[3].xyz[1] -= 32 * beamRatio; verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = 255; @@ -2133,8 +3674,7 @@ static void CG_PlayerSplash( centity_t *cent ) { trap_R_AddPolyToScene( cgs.media.wakeMarkShader, 4, verts ); } - - +static int timestamp; /* =============== @@ -2144,25 +3684,232 @@ Adds a piece with modifications or duplications for powerups Also called by CG_Missile for quad rockets, but nobody can tell... =============== */ -void CG_AddRefEntityWithPowerups( refEntity_t *ent, entityState_t *state, int team ) { +void CG_AddRefEntityWithPowerups( refEntity_t *ent, int powerups, int eFlags, beamData_t *beamData, int cloakTime, int decloakTime, qboolean borg ) +{ - if ( state->powerups & ( 1 << PW_INVIS ) ) { - ent->customShader = cgs.media.invisShader; + //TiM : No more flickering. Flickering Starfleet officers is bad + /*if ( eFlags & EF_ITEMPLACEHOLDER ) // Hologram Decoy + { + float f1, f2; + + // We used EF_ITEMPLACEHOLDER flag to indicate that this 'player' model + // is actually a holographic decoy. Now there is a chance that the + // decoy will flicker a bit because of ordering with alpha shaders... + + // The lowest the alpha goes is 4.0-2.5-1.0=0.5. + f1 = 4.0 + 2.5*sin(52.423 + cg.time/205.243); + f2 = sin(14.232 + cg.time/63.572); + + f1 = f1+f2; + if (f1 > 1.0) + { // Just draw him solid. + if ( cg.snap->ps.persistant[PERS_CLASS] == PC_TECH ) + {//technicians can see decoys as grids + ent->customShader = cgs.media.rezOutShader; + ent->shaderRGBA[0] = + ent->shaderRGBA[1] = + ent->shaderRGBA[2] = 128; + } + + trap_R_AddRefEntityToScene( ent ); + } + else + { // Draw him faded. + if (f1 > 0.8) + { // Don't have alphas over 0.8, it just looks bad. + f1=0.8; + } + else if (f1 < 0.1) + { + f1=0.1; + } + + ent->renderfx |= RF_FORCE_ENT_ALPHA; // Override the skin shader info and use this alpha value. + ent->shaderRGBA[3] = 255.0*f1; + trap_R_AddRefEntityToScene( ent ); + ent->renderfx &= ~RF_FORCE_ENT_ALPHA; + ent->shaderRGBA[3] = 255; + + // ...with a static shader. + ent->customShader = cgs.media.holoDecoyShader; + ent->shaderRGBA[0] = + ent->shaderRGBA[1] = + ent->shaderRGBA[2] = 255.0*(1.0-f1); // More solid as the player fades out... + trap_R_AddRefEntityToScene(ent); + } + + return; + }*/ + if ((eFlags & EF_DEAD) && (timestamp > cg.time)) + { // Dead. timestamp holds the time of death. + + float alpha; + int a; + + // First draw the entity itself. + //alpha = (timestamp - cg.time)/2500.0; + alpha = (timestamp - cg.time) * 0.0004; + ent->renderfx |= RF_FORCE_ENT_ALPHA; + a = alpha * 255.0; + if (a <= 0) + a=1; + ent->shaderRGBA[3] = a; trap_R_AddRefEntityToScene( ent ); - } else { - /* - if ( state->eFlags & EF_KAMIKAZE ) { - if (team == TEAM_BLUE) - ent->customShader = cgs.media.blueKamikazeShader; + ent->renderfx &= ~RF_FORCE_ENT_ALPHA; + ent->shaderRGBA[3] = 255; + + // Now draw the static shader over it. + // Alpha in over half the time, out over half. + alpha = sin(M_PI*alpha); + a = alpha * 255.0; + if (a <= 0) + a=1; + ent->customShader = cgs.media.rezOutShader; + ent->shaderRGBA[0] = + ent->shaderRGBA[1] = + ent->shaderRGBA[2] = a; + trap_R_AddRefEntityToScene( ent ); + ent->shaderRGBA[0] = + ent->shaderRGBA[1] = + ent->shaderRGBA[2] = 255; + } + else if( powerups & ( 1 << PW_BORG_ADAPT ) ) + { + ent->renderfx |= RF_FORCE_ENT_ALPHA; + ent->shaderRGBA[3] = 255; + trap_R_AddRefEntityToScene(ent); + ent->customShader = cgs.media.borgFullBodyShieldShader; + trap_R_AddRefEntityToScene(ent); + return; + } + else if ( powerups & ( 1 << PW_INVIS ) || ( !(powerups & ( 1 << PW_INVIS )) && decloakTime > 0 ) ) + { + if ( ( cloakTime <= 0 && decloakTime <= 0 ) || ( decloakTime > 0 && cg.time < ( decloakTime + Q_FLASH_TIME * 0.5 ) ) + || ( cloakTime > 0 && cg.time > ( cloakTime + Q_FLASH_TIME * 0.5 ) ) ) + { + if ( cgs.clientinfo[cg.snap->ps.clientNum].isAdmin/*cg.snap->ps.persistant[PERS_CLASS] == PC_ADMIN*/ ) + {//admins can see cloaked people + //RPG-X: RedTechie - Pretty Admin Stuff + //ent->customShader = cgs.media.teleportEffectShader; + ent->renderfx |= RF_FORCE_ENT_ALPHA; + ent->shaderRGBA[3] = (unsigned char)(0.4f * 255.0f); + trap_R_AddRefEntityToScene( ent ); + } else - ent->customShader = cgs.media.redKamikazeShader; + return; + //ent->customShader = cgs.media.invisShader; //TiM : No point since it's a 100% transparent shader. Use the EF_NODRAW flag instead + } + else + trap_R_AddRefEntityToScene( ent ); + } + else if (powerups & (1<renderfx |= RF_FORCE_ENT_ALPHA; + ent->shaderRGBA[3] = 255 - (dtime)*0.25; + trap_R_AddRefEntityToScene( ent ); + ent->renderfx &= ~RF_FORCE_ENT_ALPHA; + ent->shaderRGBA[3] = 255; + } + + if (dtime < 2000) + { + ent->customShader = cgs.media.disruptorShader; + //ent->shaderTime = timeParam / 1000.0f; + ent->shaderTime = timeParam * 0.001f; trap_R_AddRefEntityToScene( ent ); } - else {*/ - trap_R_AddRefEntityToScene( ent ); - //} + } + else if (powerups & (1<powerups & ( 1 << PW_QUAD ) ) + dtime = cg.time-timeParam; + + if (dtime < 300) + { + ent->renderfx |= RF_FORCE_ENT_ALPHA; + ent->shaderRGBA[3] = (int)(255.0 - (dtime / 300.0) * 254.0); + trap_R_AddRefEntityToScene( ent ); + ent->renderfx &= ~RF_FORCE_ENT_ALPHA; + ent->shaderRGBA[3] = 255; + } + + if (dtime < 500) + { + ent->customShader = cgs.media.explodeShellShader; + ent->renderfx |= RF_CAP_FRAMES; + //ent->shaderTime = timeParam / 1000.0f; + ent->shaderTime = timeParam * 0.001f; + trap_R_AddRefEntityToScene( ent ); + ent->renderfx &= ~RF_CAP_FRAMES; + } + } + else if (powerups & (1<renderfx |= RF_FORCE_ENT_ALPHA; + //ent->shaderRGBA[3] = 100 + 50*sin(cg.time/200.0); + ent->shaderRGBA[3] = 100 + 50*sin(cg.time * 0.005); + trap_R_AddRefEntityToScene( ent ); + ent->renderfx &= ~RF_FORCE_ENT_ALPHA; + ent->shaderRGBA[3] = 255; + } + //SP Transporter Effect + else if ( powerups & ( 1 << PW_BEAM_OUT ) || powerups & ( 1 << PW_QUAD ) ) + { + int btime; + btime = cg.time - beamData->beamTimeParam; + + if ( btime <= PLAYER_BEAM_FADE ) { + if ( powerups & ( 1 << PW_BEAM_OUT ) ) { + ent->shaderRGBA[3] = 255; + } + else { + ent->shaderRGBA[3] = 0; + } + } + else if ( btime >= ( PLAYER_BEAM_FADE + PLAYER_BEAM_FADETIME ) ) { + if ( powerups & ( 1 << PW_BEAM_OUT ) ) { + ent->shaderRGBA[3] = 0; + } + else { + ent->shaderRGBA[3] = 255; + } + } + + if (btime > PLAYER_BEAM_FADE && btime < (PLAYER_BEAM_FADE + PLAYER_BEAM_FADETIME) ) + { + ent->renderfx |= RF_FORCE_ENT_ALPHA; + ent->shaderRGBA[3] = (int)(255 * beamData->beamAlpha); + } + + if ( ent->shaderRGBA[3] > 0 ) { + trap_R_AddRefEntityToScene( ent ); + ent->renderfx &= ~RF_FORCE_ENT_ALPHA; + ent->shaderRGBA[3] = 255; + } + + if ( btime < 4100 ) { + ent->customShader = cgs.media.transportShader; + //ent->shaderTime = beamData->beamTimeParam / 1000.0f; + ent->shaderTime = beamData->beamTimeParam * 0.001f; + trap_R_AddRefEntityToScene( ent ); + } + } + else + { + trap_R_AddRefEntityToScene( ent ); + + //if we did have third person alpha + if ( ent->renderfx & RF_FORCE_ENT_ALPHA ) { + ent->renderfx &= ~RF_FORCE_ENT_ALPHA; + } + // Quad should JUST be on the weapon now, sparky. +/* if ( powerups & ( 1 << PW_QUAD ) ) { if (team == TEAM_RED) ent->customShader = cgs.media.redQuadShader; @@ -2170,71 +3917,366 @@ void CG_AddRefEntityWithPowerups( refEntity_t *ent, entityState_t *state, int te ent->customShader = cgs.media.quadShader; trap_R_AddRefEntityToScene( ent ); } - if ( state->powerups & ( 1 << PW_REGEN ) ) { +*/ + + /*if ( powerups & ( 1 << PW_LASER ) ) { if ( ( ( cg.time / 100 ) % 10 ) == 1 ) { ent->customShader = cgs.media.regenShader; trap_R_AddRefEntityToScene( ent ); } - } - if ( state->powerups & ( 1 << PW_BATTLESUIT ) ) { - ent->customShader = cgs.media.battleSuitShader; + }*/ + /*if ( powerups & ( 1 << PW_BEAMING )) + { + ent->customShader = cgs.media.borgFullBodyShieldShader; trap_R_AddRefEntityToScene( ent ); + return; + }*/ +/* if ( powerups & ( 1 << PW_BOLTON )) + { + ent->customShader = cgs.media.battleSuitShader; + trap_R_AddRefEntityToScene( ent ); + return; + }*/ + /*if (powerups & (1 << PW_OUCH)) + { + ent->customShader = cgs.media.holoOuchShader; + // set rgb to 1 of 16 values from 0 to 255. don't use random so that the three + //parts of the player model as well as the gun will all look the same + ent->shaderRGBA[0] = + ent->shaderRGBA[1] = + ent->shaderRGBA[2] = ((cg.time % 17)*0.0625)*255.0;//irandom(0,255); + trap_R_AddRefEntityToScene(ent); + }*/ + + if (powerups & (1<customShader = cgs.media.electricBodyShader; +// ent->shaderTime = timeParam / 1000.0f; + ent->shaderRGBA[0] = + ent->shaderRGBA[1] = + //ent->shaderRGBA[2] = (int)(1.0 + ((4000.0 - dtime) / 4000.0f * 254.0f )); + ent->shaderRGBA[2] = (int)(1.0 + ((4000.0 - dtime) * 0.00025f + 256.0f)); + ent->shaderRGBA[3] = 255; + trap_R_AddRefEntityToScene( ent ); + + if ( random() > 0.95f ) + { + // Play a zap sound to go it. + trap_S_StartSound (ent->origin, entNum, CHAN_AUTO, cg_weapons[WP_13].altHitSound); + } + } } } } -/* -================= -CG_LightVerts -================= -*/ -int CG_LightVerts( vec3_t normal, int numVerts, polyVert_t *verts ) +#define MAX_SHIELD_TIME 2500.0 +#define MIN_SHIELD_TIME 1750.0 + + +void CG_PlayerShieldHit(int entitynum, vec3_t dir, int amount) { - int i, j; - float incoming; - vec3_t ambientLight; - vec3_t lightDir; - vec3_t directedLight; + centity_t *cent; + int time; - trap_R_LightForPoint( verts[0].xyz, ambientLight, directedLight, lightDir ); - - for (i = 0; i < numVerts; i++) { - incoming = DotProduct (normal, lightDir); - if ( incoming <= 0 ) { - verts[i].modulate[0] = ambientLight[0]; - verts[i].modulate[1] = ambientLight[1]; - verts[i].modulate[2] = ambientLight[2]; - verts[i].modulate[3] = 255; - continue; - } - j = ( ambientLight[0] + incoming * directedLight[0] ); - if ( j > 255 ) { - j = 255; - } - verts[i].modulate[0] = j; - - j = ( ambientLight[1] + incoming * directedLight[1] ); - if ( j > 255 ) { - j = 255; - } - verts[i].modulate[1] = j; - - j = ( ambientLight[2] + incoming * directedLight[2] ); - if ( j > 255 ) { - j = 255; - } - verts[i].modulate[2] = j; - - verts[i].modulate[3] = 255; + if (entitynum<0 || entitynum >= MAX_CLIENTS) + { + return; + } + + cent = &cg_entities[entitynum]; + + if (amount > 100) + { + time = cg.time + MAX_SHIELD_TIME; // 2 sec. + } + else + { + time = cg.time + 500 + amount*20; + } + + if (time > cent->damageTime) + { + cent->damageTime = time; + VectorScale(dir, -1, dir); + vectoangles(dir, cent->damageAngles); } - return qtrue; } + +/*void CG_DrawPlayerShield(centity_t *cent, vec3_t origin) +{ + refEntity_t ent; + int alpha; + float scale; + + // Don't draw the shield when the player is dead. + if (cent->currentState.eFlags & EF_DEAD) + { + return; + } + + memset( &ent, 0, sizeof( ent ) ); + + VectorCopy( origin, ent.origin ); + ent.origin[2] += 10.0; + AnglesToAxis( cent->damageAngles, ent.axis ); + + alpha = 255.0 * ((cent->damageTime - cg.time) / MIN_SHIELD_TIME) + irandom(0, 16); + if (alpha>255) + alpha=255; + + // Make it bigger, but tighter if more solid + scale = 1.8 - ((float)alpha*(0.4/255.0)); // Range from 1.4 to 1.8 + VectorScale( ent.axis[0], scale, ent.axis[0] ); + VectorScale( ent.axis[1], scale, ent.axis[1] ); + VectorScale( ent.axis[2], scale, ent.axis[2] ); + + ent.hModel = cgs.media.explosionModel; + ent.customShader = cgs.media.halfShieldShader; + ent.shaderRGBA[0] = alpha; + ent.shaderRGBA[1] = alpha; + ent.shaderRGBA[2] = alpha; + ent.shaderRGBA[3] = 255; + trap_R_AddRefEntityToScene( &ent ); +}*/ + + +/*void CG_PlayerHitFX(centity_t *cent) +{ + centity_t *curent; + + // only do the below fx if the cent in question is...uh...me, and it's first person. + if (cent->currentState.clientNum != cg.predictedPlayerState.clientNum || cg.renderingThirdPerson) + { + // Get the NON-PREDICTED player entity, because the predicted one doesn't have the damage info on it. + curent = &cg_entities[cent->currentState.number]; + + if (curent->damageTime > cg.time) + { + CG_DrawPlayerShield(curent, cent->lerpOrigin); + } + + return; + } +}*/ + +//------------------------------------ +/*void CG_BorgEyebeam( centity_t *cent, const refEntity_t *parent ) +{ + qboolean large = qfalse; + vec3_t beamOrg, beamEnd; + trace_t trace; + refEntity_t temp; + + CG_PositionEntityOnTag( &temp, parent, parent->hModel, "tag_ear"); + + if ( VectorCompare( temp.origin, parent->origin )) + { + // Vectors must be the same so the tag_ear wasn't found + return; + } + //Note the above will also prevent the beam from being drawn in first person view if you don't have a tag_ear + + // well, we are in thirdperson or whatnot, so we should just render from a bolt-on ( tag_ear ) + if ( cent->currentState.clientNum != cg.predictedPlayerState.clientNum + || cg.renderingThirdPerson + || cg.snap->ps.pm_type == PM_INTERMISSION ) + { + VectorCopy( temp.origin, beamOrg ); + VectorMA( beamOrg, 1024, temp.axis[0], beamEnd );//forward to end + } + else + { + vec3_t axis[3]; + + // stupid offset hack + AnglesToAxis( cent->lerpAngles, axis ); + VectorMA( cent->lerpOrigin, 26, axis[2], beamOrg );//up + VectorMA( beamOrg, -26, axis[1], beamOrg );//right +// VectorMA( beamOrg, 0.2f, axis[0], beamOrg );//forward + VectorMA( beamOrg, 1024, axis[0], beamEnd );//forward to end + large = qtrue; // render a fatter line + } + + trap_CM_BoxTrace( &trace, beamOrg, beamEnd, NULL, NULL, 0, MASK_SHOT ); + VectorCopy( trace.endpos, beamEnd ); + VectorMA( beamOrg, 0.5, parent->axis[0], beamOrg );//forward + + FX_BorgEyeBeam( beamOrg, beamEnd, trace.plane.normal, large ); +}*/ + +//------------------------------------------------------------------------------ +//Equip mode features + +void CG_AttachHolsters ( centity_t *cent, refEntity_t *parent, int weapon ) +{ + refEntity_t holster; + refEntity_t holsterInner; + + //CG_FlushRefEnt( parent, &holster ); + //CG_FlushRefEnt( parent, &holsterInner ); + + memset( &holster, 0, sizeof( holster ) ); + VectorCopy( parent->lightingOrigin, holster.lightingOrigin ); + holster.shadowPlane = parent->shadowPlane; + holster.renderfx = parent->renderfx; + + memset( &holsterInner, 0, sizeof( holsterInner ) ); + VectorCopy( parent->lightingOrigin, holsterInner.lightingOrigin ); + holsterInner.shadowPlane = parent->shadowPlane; + holsterInner.renderfx = parent->renderfx; + + holster.hModel = (weapon == WP_5) ? cgs.media.phaserHolster : cgs.media.tricorderHolster; + holsterInner.hModel = (weapon == WP_5) ? cgs.media.phaserHolsterInner : cgs.media.tricorderHolsterInner; + + if ( !holster.hModel ) { + return; + } + + CG_PositionEntityOnTag( &holster, parent, parent->hModel, (weapon == WP_5) ? "tag_p_holster" : "tag_t_holster" ); + CG_PositionEntityOnTag( &holsterInner, &holster, holster.hModel, (weapon == WP_5) ? "tag_phaser" : "tag_tricorder" ); + + CG_AddRefEntityWithPowerups( &holster, cent->currentState.powerups, cent->currentState.eFlags, ¢->beamData, cent->cloakTime, cent->decloakTime, qfalse ); + + if ( cent->currentState.weapon != weapon ) { + CG_AddRefEntityWithPowerups( &holsterInner, cent->currentState.powerups, cent->currentState.eFlags, ¢->beamData, cent->cloakTime, cent->decloakTime, qfalse ); + } + +} + +void CG_AttachTools ( centity_t *cent, refEntity_t *parent, int weaponNum ) +{ + refEntity_t tool; + weaponInfo_t *weaponInfo; + + weaponInfo = &cg_weapons[weaponNum]; + + //CG_FlushRefEnt( parent, &holster ); + //CG_FlushRefEnt( parent, &holsterInner ); + + memset( &tool, 0, sizeof( tool ) ); + VectorCopy( parent->lightingOrigin, tool.lightingOrigin ); + tool.shadowPlane = parent->shadowPlane; + tool.renderfx = parent->renderfx; + + tool.hModel = weaponInfo->weaponModel; + + if ( !tool.hModel ) { + return; + } + + CG_PositionEntityOnTag( &tool, parent, parent->hModel, (weaponNum == WP_11) ? "tag_torso" : "tag_lhand" ); + + if ( cent->currentState.weapon != weaponNum ) { + CG_AddRefEntityWithPowerups( &tool, cent->currentState.powerups, cent->currentState.eFlags, ¢->beamData, cent->cloakTime, cent->decloakTime, qfalse ); + } + +} +//-------------------------------------------------------------- +//CG version of the flashlight+laser. + +extern qboolean CG_CalcMuzzlePoint( centity_t *cent, vec3_t muzzle, qboolean isDecoy ); + +void CG_AddBeamFX( centity_t *cent ) { + //refEntity_t ent; + trace_t tr; + vec3_t origin, forward, end; + qboolean isDecoy; + + if ( !( cent->currentState.powerups & ( 1 << PW_LASER ) ) && + !( cent->currentState.powerups & ( 1 << PW_FLASHLIGHT ) ) ) + { + return; + } + + isDecoy = (qboolean)(cent->currentState.eFlags & EF_ITEMPLACEHOLDER ); + + //Get origin to render effect + //============================== + //if it's us, we get special treatment, wielding uber-smooth feelings. :) + if ( cent->currentState.clientNum == cg.predictedPlayerState.clientNum && !isDecoy ) { + VectorCopy( cg.predictedPlayerState.origin, origin ); + origin[2] += (float)cg.predictedPlayerState.viewheight * cgs.clientinfo[cg.predictedPlayerState.clientNum].height; + + AngleVectors( cg.predictedPlayerState.viewangles, forward, NULL, NULL ); + } + else { //else, we'll employ a rather hacky (but Official Ravensoft made) way to guess the data we'll need here on CG + if ( CG_CalcMuzzlePoint( cent, origin, isDecoy ) ) + if ( !isDecoy ) + AngleVectors( cent->lerpAngles, forward, NULL, NULL ); + else + AngleVectors( cent->currentState.angles, forward, NULL, NULL ); + else + return; + } + + //perform the trace + VectorMA( origin, 8192, forward, end ); + CG_Trace( &tr, origin, NULL, NULL, end, cent->currentState.clientNum, CONTENTS_SOLID ); + + if (tr.surfaceFlags & SURF_NOIMPACT || tr.surfaceFlags & SURF_SKY ) { + return; + } + + //offset back in a little, so we can actually see the ent lol + VectorMA( tr.endpos, -0.5, forward, end ); + + //============================== + + if ( cent->currentState.powerups & ( 1 << PW_LASER ) && cent->beamData.beamTimeParam == 0 ) { + /*// create the render entity + memset (&ent, 0, sizeof(ent)); + VectorCopy( end, ent.origin); + + ent.reType = RT_SPRITE; + //ent.radius = 2; + //ent.rotation = 0; + ent.data.sprite.radius = 2; + ent.customShader = cgs.media.laserShader; + trap_R_AddRefEntityToScene( &ent );*/ + + //TiM: based on the shadow code instead. This is so the sprite + //is always aligned to the normal of the surface it hits, making it + //act more like a fricken laser. :) + CG_ImpactMark( cgs.media.laserShader, end, tr.plane.normal, + 0,1,1,1,1, qfalse, 2, qtrue ); + } + + if ( cent->currentState.powerups & ( 1 << PW_FLASHLIGHT ) && cent->beamData.beamTimeParam == 0 ) { + vec3_t delta; + float dist, intensity; + + //TiM - calc radius based on distance. + //So it'll simulate real flashlights getting bigger/smaller the closer u are + VectorSubtract( end, origin, delta ); + dist = VectorNormalize( delta ); + //intensity = ( dist / 256.0f ); + intensity = ( dist * 0.00390625f ); + + if ( intensity > 1.0f ) + intensity = 1.0f; + if ( intensity < 0.3f ) + intensity = 0.3f; + + trap_R_AddLightToScene( end, intensity * 200.0f, 1, 1, 1); //200 + } +} + +//-------------------------------------------------------------- + /* =============== CG_Player =============== */ +#define EYES_BLINK_TIME 250 void CG_Player( centity_t *cent ) { clientInfo_t *ci; refEntity_t legs; @@ -2242,16 +4284,14 @@ void CG_Player( centity_t *cent ) { refEntity_t head; int clientNum; int renderfx; - qboolean shadow; - float shadowPlane; -#ifdef MISSIONPACK - refEntity_t skull; - refEntity_t powerup; - int t; - float c; - float angle; - vec3_t dir, angles; -#endif + qboolean shadow, borg = qfalse; + float shadowPlane = 0; + //alpha value + float alpha = cg_thirdPersonAlpha.value; + int i = 0; + rankModelData_t* rankModelData = NULL; + qboolean rankDataValidated = qfalse; + qboolean isDecoy = qfalse; // the client number is stored in clientNum. It can't be derived // from the entity number, because a single client may have @@ -2260,7 +4300,14 @@ void CG_Player( centity_t *cent ) { if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) { CG_Error( "Bad clientNum on player entity"); } - ci = &cgs.clientinfo[ clientNum ]; + + isDecoy = cent->currentState.eFlags & EF_ITEMPLACEHOLDER; + + //if we're a decoy, use the decoy info instead + if ( isDecoy ) + ci = &cgs.decoyInfo[ cent->currentState.eventParm ]; + else + ci = &cgs.clientinfo[ clientNum ]; // it is possible to see corpses from disconnected players that may // not have valid clientinfo @@ -2268,48 +4315,142 @@ void CG_Player( centity_t *cent ) { return; } - // get the player model information - renderfx = 0; - if ( cent->currentState.number == cg.snap->ps.clientNum) { - if (!cg.renderingThirdPerson) { - renderfx = RF_THIRD_PERSON; // only draw in mirrors - } else { - if (cg_cameraMode.integer) { - return; - } + //borg = ( ci->pClass == PC_BORG ? qtrue : qfalse ); + borg = qfalse; + + // If I'm a borg and there is another borg teleporting, at least allow me to see a trail, then return + /*if ( cg.snap->ps.persistant[PERS_CLASS] == PC_BORG && borg && ( cent->currentState.eFlags & EF_NODRAW )) + { + FX_BorgTeleportTrails( cent->lerpOrigin ); + return; + }*/ + + // add the talk baloon or disconnect icon (not in intermission) + if ( !cg.intermissionStarted ) + { + //RPG-X: RedTechie - Make sure there a admin before printing sprites above there head + if(cgs.clientinfo[cg.snap->ps.clientNum].isAdmin/*cg.snap->ps.persistant[PERS_CLASS] == PC_ADMIN*/){ + CG_PlayerSprites( cent ); } } + //TiM Little hack for RGBA shader rendering + //if we're completely invisible... save us some processing power lol + if ( alpha <= 0.0 ) { + return; + } + + if (cent->currentState.eFlags & EF_NODRAW) + { // Don't draw anymore... + return; + } memset( &legs, 0, sizeof(legs) ); memset( &torso, 0, sizeof(torso) ); memset( &head, 0, sizeof(head) ); + //TiM : Manually refresh anims here to make sure it's updated around the board. + //Previously, new players would be loaded, but anim data wouldn't, resulting in really weird looking poses. + //Absolutely flushing all current animation data, forcing the code to reset is the only way I managed to get it working O_o + if ( !ci->animsFlushed ) { + lerpFrame_t *lf; + lerpFrame_t *tf; + + lf = ¢->pe.legs; + tf = ¢->pe.torso; + + lf->animation = tf->animation = NULL; + lf->animationNumber = tf->animationNumber = 0; + lf->animationTime = tf->animationTime = 0; + lf->backlerp = tf->backlerp = 0; + lf->frame = tf->frame = 0; + lf->frameTime = tf->frameTime = 0; + lf->oldFrame = tf->oldFrame = 0; + lf->oldFrameTime = tf->oldFrameTime = 0; + + //TiM : As much as I'd love to do this, it'll delete current angles too, + //which results in players abruptly turning sharply when changing models. + //And might possibly make corpses do the same... which would look creepy lol + + //memset( ¢->pe.legs, 0, sizeof ( cent->pe.legs ) ); + //memset( ¢->pe.torso, 0, sizeof ( cent->pe.torso ) ); + ci->animsFlushed = qtrue; + } + // get the rotation information CG_PlayerAngles( cent, legs.axis, torso.axis, head.axis ); - + // get the animation state (after rotation, to allow feet shuffle) CG_PlayerAnimation( cent, &legs.oldframe, &legs.frame, &legs.backlerp, &torso.oldframe, &torso.frame, &torso.backlerp ); - // add the talk baloon or disconnect icon - CG_PlayerSprites( cent ); + // add powerups floating behind the player + CG_PlayerPowerups( cent ); + + //backup catch for the lift entity + if ( cg_liftEnts[cent->currentState.clientNum] > 0 && cg_liftEnts[cent->currentState.clientNum] < (cg.time - cgs.levelStartTime) ) + cg_liftEnts[cent->currentState.clientNum] = 0; + + //========================================================== + + /*CG_CalcBeamAlpha( cent->currentState.powerups, ¢->beamData ); // add the shadow - shadow = CG_PlayerShadow( cent, &shadowPlane ); + if ( !(cent->currentState.eFlags & EF_ITEMPLACEHOLDER) ) + { + shadow = CG_PlayerShadow( cent, &shadowPlane, ci->height ); + } + else + { // - unless we are a hologram... + shadow=qfalse; + shadowPlane=0; + }*/ // add a water splash if partially in and out of water - CG_PlayerSplash( cent ); + //CG_PlayerSplash( cent ); - if ( cg_shadows.integer == 3 && shadow ) { + // get the player model information + renderfx = 0; + + if ( cent->currentState.number == cg.snap->ps.clientNum && !cg.renderingThirdPerson && !cg_firstPersonBody.integer && !isDecoy ) { + renderfx |= RF_THIRD_PERSON; // only draw in mirrors + } + + /*if ( cg_shadows.integer == 3 && shadow ) { renderfx |= RF_SHADOW_PLANE; - } + }*/ + renderfx |= RF_LIGHTING_ORIGIN; // use the same origin for all -#ifdef MISSIONPACK - if( cgs.gametype == GT_HARVESTER ) { - CG_PlayerTokens( cent, renderfx ); + + //append this flag if zooming thru the TR-116. + //It'll render players over everything else. Not quite as good as the TV 116, but it'll do the job. :) + if ( cg.snap->ps.weapon == WP_7 && cg.zoomed ) { + renderfx |= RF_DEPTHHACK; //This flag makes making haxx for EF SO EASY!!!! O_O!!!!! } -#endif + + // if we've been hit, display proper fullscreen fx + //CG_PlayerHitFX(cent); + + // If we are dead, set up the correct fx. + if (cent->currentState.eFlags & EF_DEAD) + { + if (cent->deathTime==0) + cent->deathTime = cg.time; // Set Death Time so you can see yourself + + if (cent->currentState.time > cg.time) + { // Fading out. + timestamp=cent->currentState.time; + shadow = qfalse; + shadowPlane = 0; + } + else + { + timestamp = 0; + } + } + else + cent->deathTime = 0; + // // add the legs // @@ -2318,12 +4459,51 @@ void CG_Player( centity_t *cent ) { VectorCopy( cent->lerpOrigin, legs.origin ); + //TiM - A cheap override for some things. + //If emoting, offset the player model. Good for solid chairs n stuff + //CG_Printf( "Offset = %f\n", ci->modelOffset ); + if ( ci->modelOffset != 0 ) { + if ( cent->currentState.eFlags & EF_CLAMP_BODY || cent->currentState.eFlags & EF_CLAMP_ALL || cent->currentState.eFlags & EF_ITEMPLACEHOLDER ) { + //TiM: A bit of a hacky override. We don't want this on ladder climbing, yet the emote code + //now forms the basis of the ladder clamp code + if ( (cent->currentState.legsAnim & ~ANIM_TOGGLEBIT) != BOTH_LADDER_DWN1 && + (cent->currentState.legsAnim & ~ANIM_TOGGLEBIT) != BOTH_LADDER_UP1 && + (cent->currentState.legsAnim & ~ANIM_TOGGLEBIT) != BOTH_LADDER_IDLE ) + { + vec3_t offset; + vec3_t legsYaw; + + VectorSet( legsYaw, 0, cent->pe.legs.yawAngle, 0 ); + + AngleVectors( legsYaw, offset, NULL, NULL ); + + VectorMA( legs.origin, ci->modelOffset, offset, legs.origin ); + } + } + } + VectorCopy( cent->lerpOrigin, legs.lightingOrigin ); - legs.shadowPlane = shadowPlane; + //legs.shadowPlane = shadowPlane; legs.renderfx = renderfx; + + legs.nonNormalizedAxes = qtrue; + VectorScale( legs.axis[0], ci->height, legs.axis[0]); + VectorScale( legs.axis[1], (ci->height * ci->weight), legs.axis[1]); //weight... i think + VectorScale( legs.axis[2], ci->height, legs.axis[2]); + legs.origin[2] = legs.origin[2] - (24.0f * (1.0f - ci->height)); + //Com_Printf( "weight = %f, race = %s\n", ci->weight, ci->race); + + if ( cg.predictedPlayerState.clientNum == cent->currentState.clientNum && cg.renderingThirdPerson && cg_thirdPersonAlpha.value != 1.0 && !isDecoy ) { + legs.renderfx |= RF_FORCE_ENT_ALPHA; + legs.shaderRGBA[3] = (unsigned char)(alpha * 255.0f); + } + VectorCopy (legs.origin, legs.oldorigin); // don't positionally lerp at all - CG_AddRefEntityWithPowerups( &legs, ¢->currentState, ci->team ); + // Setup the param, in case it is needed. + timeParam = cent->deathTime; + entNum = cent->currentState.number; + //CG_AddRefEntityWithPowerups( &legs, cent->currentState.powerups, cent->currentState.eFlags, ¢->beamData, borg ); // if the model failed, allow the default nullmodel to be displayed if (!legs.hModel) { @@ -2342,216 +4522,72 @@ void CG_Player( centity_t *cent ) { VectorCopy( cent->lerpOrigin, torso.lightingOrigin ); - CG_PositionRotatedEntityOnTag( &torso, &legs, ci->legsModel, "tag_torso"); + CG_PositionRotatedEntityOnTag( &torso, &legs, ci->legsModel, "tag_torso" ); + torso.nonNormalizedAxes = qtrue; torso.shadowPlane = shadowPlane; torso.renderfx = renderfx; - CG_AddRefEntityWithPowerups( &torso, ¢->currentState, ci->team ); + if ( cg.predictedPlayerState.clientNum == cent->currentState.clientNum && cg.renderingThirdPerson && cg_thirdPersonAlpha.value != 1.0 ) { + torso.renderfx |= RF_FORCE_ENT_ALPHA; + torso.shaderRGBA[3] = (unsigned char)(alpha * 255.0f); + } -#ifdef MISSIONPACK - if ( cent->currentState.eFlags & EF_KAMIKAZE ) { + //TiM - If first person rendering, offset the view vector + if ( !isDecoy && cent->currentState.clientNum == cg.snap->ps.clientNum && cg_firstPersonBody.integer && !cg.renderingThirdPerson /*&& + !( cent->currentState.eFlags & EF_CLAMP_BODY )*/ ) { + vec3_t legsYaw; + vec3_t offset; + + if ( cent->currentState.legsAnim != cg.fpsBody.anim ) { + refEntity_t ref; + vec3_t temp; - memset( &skull, 0, sizeof(skull) ); + CG_PositionEntityOnTag( &ref, &torso, torso.hModel, "tag_head"); + VectorSubtract( cg.refdef.vieworg, ref.origin, temp ); - VectorCopy( cent->lerpOrigin, skull.lightingOrigin ); - skull.shadowPlane = shadowPlane; - skull.renderfx = renderfx; + //make the body smaller if need be + //if ( cg.refdef.vieworg[2] < ref.origin[2] ) + //{ + // cg.fpsBody.sizeOffset = (cg.refdef.vieworg[2] - legs.origin[2]) / (ref.origin[2] - legs.origin[2]); + //} + //else + // cg.fpsBody.sizeOffset = 0.0f; - if ( cent->currentState.eFlags & EF_DEAD ) { - // one skull bobbing above the dead body - angle = ((cg.time / 7) & 255) * (M_PI * 2) / 255; - if (angle > M_PI * 2) - angle -= (float)M_PI * 2; - dir[0] = sin(angle) * 20; - dir[1] = cos(angle) * 20; - angle = ((cg.time / 4) & 255) * (M_PI * 2) / 255; - dir[2] = 15 + sin(angle) * 8; - VectorAdd(torso.origin, dir, skull.origin); + cg.fpsBody.sizeOffset = 0.9f; + + //normalize, but don't take Z-axis (vertical) into account + //cg.fpsBody.offset = 0 + (int)sqrt( (temp[0]*temp[0]) + (temp[1]*temp[1]) ); + cg.fpsBody.offset = 2; + + cg.fpsBody.anim = cent->currentState.legsAnim ; //+15 for good measure :P + } + + if ( cg.fpsBody.offset > 0.0f ) + { + VectorSet( legsYaw, 0, cent->pe.legs.yawAngle, 0 ); + AngleVectors( legsYaw, offset, NULL, NULL ); + VectorMA( legs.origin, -cg.fpsBody.offset, offset, legs.origin ); + VectorMA( torso.origin, -cg.fpsBody.offset, offset, torso.origin ); + } + + if ( cg.fpsBody.sizeOffset > 0.0f ) + { + VectorScale( legs.axis[0], cg.fpsBody.sizeOffset, legs.axis[0] ); + VectorScale( legs.axis[1], cg.fpsBody.sizeOffset, legs.axis[1] ); + VectorScale( legs.axis[2], cg.fpsBody.sizeOffset, legs.axis[2] ); + VectorScale( torso.axis[0], cg.fpsBody.sizeOffset, torso.axis[0] ); + VectorScale( torso.axis[1], cg.fpsBody.sizeOffset, torso.axis[1] ); + VectorScale( torso.axis[2], cg.fpsBody.sizeOffset, torso.axis[2] ); - dir[2] = 0; - VectorCopy(dir, skull.axis[1]); - VectorNormalize(skull.axis[1]); - VectorSet(skull.axis[2], 0, 0, 1); - CrossProduct(skull.axis[1], skull.axis[2], skull.axis[0]); - - skull.hModel = cgs.media.kamikazeHeadModel; - trap_R_AddRefEntityToScene( &skull ); - skull.hModel = cgs.media.kamikazeHeadTrail; - trap_R_AddRefEntityToScene( &skull ); + legs.origin[2] = legs.origin[2] - (24.0f * (1.0f - cg.fpsBody.sizeOffset)); + torso.origin[2] = torso.origin[2] - (24.0f * (1.0f - cg.fpsBody.sizeOffset)); } - else { - // three skulls spinning around the player - angle = ((cg.time / 4) & 255) * (M_PI * 2) / 255; - dir[0] = cos(angle) * 20; - dir[1] = sin(angle) * 20; - dir[2] = cos(angle) * 20; - VectorAdd(torso.origin, dir, skull.origin); - angles[0] = sin(angle) * 30; - angles[1] = (angle * 180 / M_PI) + 90; - if (angles[1] > 360) - angles[1] -= 360; - angles[2] = 0; - AnglesToAxis( angles, skull.axis ); - - /* - dir[2] = 0; - VectorInverse(dir); - VectorCopy(dir, skull.axis[1]); - VectorNormalize(skull.axis[1]); - VectorSet(skull.axis[2], 0, 0, 1); - CrossProduct(skull.axis[1], skull.axis[2], skull.axis[0]); - */ - - skull.hModel = cgs.media.kamikazeHeadModel; - trap_R_AddRefEntityToScene( &skull ); - // flip the trail because this skull is spinning in the other direction - VectorInverse(skull.axis[1]); - skull.hModel = cgs.media.kamikazeHeadTrail; - trap_R_AddRefEntityToScene( &skull ); - - angle = ((cg.time / 4) & 255) * (M_PI * 2) / 255 + M_PI; - if (angle > M_PI * 2) - angle -= (float)M_PI * 2; - dir[0] = sin(angle) * 20; - dir[1] = cos(angle) * 20; - dir[2] = cos(angle) * 20; - VectorAdd(torso.origin, dir, skull.origin); - - angles[0] = cos(angle - 0.5 * M_PI) * 30; - angles[1] = 360 - (angle * 180 / M_PI); - if (angles[1] > 360) - angles[1] -= 360; - angles[2] = 0; - AnglesToAxis( angles, skull.axis ); - - /* - dir[2] = 0; - VectorCopy(dir, skull.axis[1]); - VectorNormalize(skull.axis[1]); - VectorSet(skull.axis[2], 0, 0, 1); - CrossProduct(skull.axis[1], skull.axis[2], skull.axis[0]); - */ - - skull.hModel = cgs.media.kamikazeHeadModel; - trap_R_AddRefEntityToScene( &skull ); - skull.hModel = cgs.media.kamikazeHeadTrail; - trap_R_AddRefEntityToScene( &skull ); - - angle = ((cg.time / 3) & 255) * (M_PI * 2) / 255 + 0.5 * M_PI; - if (angle > M_PI * 2) - angle -= (float)M_PI * 2; - dir[0] = sin(angle) * 20; - dir[1] = cos(angle) * 20; - dir[2] = 0; - VectorAdd(torso.origin, dir, skull.origin); - - VectorCopy(dir, skull.axis[1]); - VectorNormalize(skull.axis[1]); - VectorSet(skull.axis[2], 0, 0, 1); - CrossProduct(skull.axis[1], skull.axis[2], skull.axis[0]); - - skull.hModel = cgs.media.kamikazeHeadModel; - trap_R_AddRefEntityToScene( &skull ); - skull.hModel = cgs.media.kamikazeHeadTrail; - trap_R_AddRefEntityToScene( &skull ); - } + //CG_Printf( "Anim: %i Offset: %i\n", cg.fpsBody.anim, cg.fpsBody.offset ); } - if ( cent->currentState.powerups & ( 1 << PW_GUARD ) ) { - memcpy(&powerup, &torso, sizeof(torso)); - powerup.hModel = cgs.media.guardPowerupModel; - powerup.frame = 0; - powerup.oldframe = 0; - powerup.customSkin = 0; - trap_R_AddRefEntityToScene( &powerup ); - } - if ( cent->currentState.powerups & ( 1 << PW_SCOUT ) ) { - memcpy(&powerup, &torso, sizeof(torso)); - powerup.hModel = cgs.media.scoutPowerupModel; - powerup.frame = 0; - powerup.oldframe = 0; - powerup.customSkin = 0; - trap_R_AddRefEntityToScene( &powerup ); - } - if ( cent->currentState.powerups & ( 1 << PW_DOUBLER ) ) { - memcpy(&powerup, &torso, sizeof(torso)); - powerup.hModel = cgs.media.doublerPowerupModel; - powerup.frame = 0; - powerup.oldframe = 0; - powerup.customSkin = 0; - trap_R_AddRefEntityToScene( &powerup ); - } - if ( cent->currentState.powerups & ( 1 << PW_AMMOREGEN ) ) { - memcpy(&powerup, &torso, sizeof(torso)); - powerup.hModel = cgs.media.ammoRegenPowerupModel; - powerup.frame = 0; - powerup.oldframe = 0; - powerup.customSkin = 0; - trap_R_AddRefEntityToScene( &powerup ); - } - if ( cent->currentState.powerups & ( 1 << PW_INVULNERABILITY ) ) { - if ( !ci->invulnerabilityStartTime ) { - ci->invulnerabilityStartTime = cg.time; - } - ci->invulnerabilityStopTime = cg.time; - } - else { - ci->invulnerabilityStartTime = 0; - } - if ( (cent->currentState.powerups & ( 1 << PW_INVULNERABILITY ) ) || - cg.time - ci->invulnerabilityStopTime < 250 ) { - - memcpy(&powerup, &torso, sizeof(torso)); - powerup.hModel = cgs.media.invulnerabilityPowerupModel; - powerup.customSkin = 0; - // always draw - powerup.renderfx &= ~RF_THIRD_PERSON; - VectorCopy(cent->lerpOrigin, powerup.origin); - - if ( cg.time - ci->invulnerabilityStartTime < 250 ) { - c = (float) (cg.time - ci->invulnerabilityStartTime) / 250; - } - else if (cg.time - ci->invulnerabilityStopTime < 250 ) { - c = (float) (250 - (cg.time - ci->invulnerabilityStopTime)) / 250; - } - else { - c = 1; - } - VectorSet( powerup.axis[0], c, 0, 0 ); - VectorSet( powerup.axis[1], 0, c, 0 ); - VectorSet( powerup.axis[2], 0, 0, c ); - trap_R_AddRefEntityToScene( &powerup ); - } - - t = cg.time - ci->medkitUsageTime; - if ( ci->medkitUsageTime && t < 500 ) { - memcpy(&powerup, &torso, sizeof(torso)); - powerup.hModel = cgs.media.medkitUsageModel; - powerup.customSkin = 0; - // always draw - powerup.renderfx &= ~RF_THIRD_PERSON; - VectorClear(angles); - AnglesToAxis(angles, powerup.axis); - VectorCopy(cent->lerpOrigin, powerup.origin); - powerup.origin[2] += -24 + (float) t * 80 / 500; - if ( t > 400 ) { - c = (float) (t - 1000) * 0xff / 100; - powerup.shaderRGBA[0] = 0xff - c; - powerup.shaderRGBA[1] = 0xff - c; - powerup.shaderRGBA[2] = 0xff - c; - powerup.shaderRGBA[3] = 0xff - c; - } - else { - powerup.shaderRGBA[0] = 0xff; - powerup.shaderRGBA[1] = 0xff; - powerup.shaderRGBA[2] = 0xff; - powerup.shaderRGBA[3] = 0xff; - } - trap_R_AddRefEntityToScene( &powerup ); - } -#endif // MISSIONPACK + //CG_AddRefEntityWithPowerups( &torso, cent->currentState.powerups, cent->currentState.eFlags, ¢->beamData, borg ); // // add the head @@ -2560,33 +4596,666 @@ void CG_Player( centity_t *cent ) { if (!head.hModel) { return; } + head.customSkin = ci->headSkin; + if ( !cg_noFrowningHeads.integer && cent->currentState.eFlags & EF_EYES_ANGRY && ci->headSkinFrown ) { + head.customSkin = ci->headSkinFrown; + } + + //BLINK CODE + //if we have a valid blink skin... + //Or we're frowning and we have a frown blink skin + if ( (!cg_noBlinkingHeads.integer && ci->headSkinBlink) + || + (( !cg_noFrowningHeads.integer && + ( cent->currentState.eFlags & EF_EYES_ANGRY ) + && ci->headSkinFrownBlink) ) + ) + { + + //if time exceeded blink time and length of time to allocate blink + //Validate that the blink time won't cause errors + if ( ( ci->headBlinkTime.minSeconds < ci->headBlinkTime.maxSeconds ) ) { + if ( cg.time > ci->headBlinkTime.nextTime ) { + //if blink time has been exceeded, assign a new one + ci->headBlinkTime.nextTime = ( irandom( ci->headBlinkTime.minSeconds, ci->headBlinkTime.maxSeconds ) * 1000 ) + cg.time; + } + } + + //if time has exceeded next blink time, and is still under 250 from then + //Or if we've kicked t3h bucket and we're stone dead right now + //or if we emoted our eyes shut + if ( ( ( cent->currentState.eFlags & EF_EYES_SHUT ) + || ( cent->currentState.eFlags & EF_DEAD ) + || ( cg.time < ci->headBlinkTime.nextTime && cg.time > ci->headBlinkTime.nextTime - EYES_BLINK_TIME ) ) + ) + { + if ( cent->currentState.eFlags & EF_EYES_ANGRY ) + { + if ( ci->headSkinFrownBlink ) + head.customSkin = ci->headSkinFrownBlink; + } + else + { + if ( ci->headSkinBlink ) + head.customSkin = ci->headSkinBlink; + } + } + //Com_Printf( "Max: %i, Min: %i, NextTime: %i, Time: %i\n", ci->headBlinkTime.maxSeconds, ci->headBlinkTime.minSeconds, ci->headBlinkTime.nextTime, cg.time ); + } + + //TALK CODE + if ( !cg_noTalkingHeads.integer && (cent->currentState.eFlags & EF_TALKING) && ci->headSkinTalk[0] ) { + if (cg.time > ci->nextTalkTime ) { + + while ( i == ci->currentTalkSkin ) { + i = irandom( 0, 3 ); + } + ci->currentTalkSkin = i; + ci->nextTalkTime = cg.time + irandom( 100, 150 ); + } + if ( ci->headSkinTalk[ci->currentTalkSkin] ) + head.customSkin = ci->headSkinTalk[ci->currentTalkSkin]; + } + VectorCopy( cent->lerpOrigin, head.lightingOrigin ); - CG_PositionRotatedEntityOnTag( &head, &torso, ci->torsoModel, "tag_head"); + CG_PositionRotatedEntityOnTag( &head, &torso, ci->torsoModel, "tag_head" ); + head.nonNormalizedAxes = qtrue; head.shadowPlane = shadowPlane; head.renderfx = renderfx; - CG_AddRefEntityWithPowerups( &head, ¢->currentState, ci->team ); + if ( cg.predictedPlayerState.clientNum == cent->currentState.clientNum && cg.renderingThirdPerson && cg_thirdPersonAlpha.value != 1.0 ) { + head.renderfx |= RF_FORCE_ENT_ALPHA; + head.shaderRGBA[3] = (unsigned char)(alpha * 255.0f); + } -#ifdef MISSIONPACK - CG_BreathPuffs(cent, &head); + if ( cent->currentState.number == cg.snap->ps.clientNum && !cg.renderingThirdPerson && cg_firstPersonBody.integer ) + head.renderfx |= RF_THIRD_PERSON; + //CG_AddRefEntityWithPowerups( &head, cent->currentState.powerups, cent->currentState.eFlags, ¢->beamData, borg ); - CG_DustTrail(cent); -#endif + /*if ( borg && cgs.pModAssimilation ) + { + CG_BorgEyebeam( cent, &head ); + }*/ + + //player must have just uncloaked. Do the reverse effect + if ( !(cent->currentState.powerups & ( 1 << PW_INVIS )) && cent->wasCloaked ) { + //play flash VFX + if ( cent->decloakTime > 0 ) { + if ( cg.time < cent->decloakTime + Q_FLASH_TIME ) { + //calc the middle waypoint for the model + vec3_t mins, maxs, headTop, avg; + + trap_R_ModelBounds( head.hModel, mins, maxs ); + VectorCopy( head.origin, headTop ); + headTop[2] += ( maxs[2] - mins[2] ); + + VectorCopy( cent->lerpOrigin, mins ); + mins[2] -= 12; + + VectorCopy( headTop, maxs ); + + VectorAverage( mins, maxs, avg ); + + if(!ci->silentCloak) { + //play the VFX + FX_qFlash( cent, avg, cent->decloakTime ); + } + } + else { + if ( cent->wasCloaked ) { + cent->wasCloaked = qfalse; + } + } + } + + if ( cent->decloakTime <= 0 ) { + cent->decloakTime = cg.time; + if(!ci->silentCloak) { + trap_S_StartSound ( NULL, cent->currentState.clientNum, CHAN_AUTO, cgs.media.qFlash ); + } + } + } + else { + if ( cent->decloakTime >= 0 ) { + cent->decloakTime = -1; + } + } + + //Get the index for when we cloaked. We'll use this to stay visible for a split second after we cloaked to enable to proper Q-Effect + //Player just cloaked + if ( cent->currentState.powerups & ( 1 << PW_INVIS ) ) { + if ( cent->cloakTime > 0 && cg.time < cent->cloakTime + Q_FLASH_TIME) { + //calc the middle waypoint for the model + vec3_t mins, maxs, headTop, avg; + + trap_R_ModelBounds( head.hModel, mins, maxs ); + VectorCopy( head.origin, headTop ); + headTop[2] += ( maxs[2] - mins[2] ); + + VectorCopy( cent->lerpOrigin, mins ); + mins[2] -= 12; + + VectorCopy( headTop, maxs ); + + VectorAverage( mins, maxs, avg ); + + if(!ci->silentCloak) { + //play the VFX + FX_qFlash( cent, avg, cent->cloakTime ); + } + + } + + if ( cent->cloakTime <= 0 ) { + cent->wasCloaked = qtrue; + cent->cloakTime = cg.time; + if(!ci->silentCloak) { + trap_S_StartSound ( NULL, cent->currentState.clientNum, CHAN_AUTO, cgs.media.qFlash ); + } + } + } + else { + if ( cent->cloakTime >= 0 ) + cent->cloakTime = -1; + } + + //Like EF_DEAD, but when we're beaming + //========================================================= + if ( cent->currentState.powerups & ( 1 << PW_BEAM_OUT ) /*&& !( cent->currentState.powerups & ( 1 << PW_INVIS ) )*/ ) { + vec3_t mins, maxs, headTop; + + if (cent->beamData.beamTimeParam == 0 && !cent->beamData.beamInDetected ) { + cent->beamData.beamTimeParam = cg.time; + CG_AddFullScreenEffect( SCREENFX_SP_TRANSPORTER_OUT, clientNum ); + } + + //Calculate the bounding region of head so beam flares will end there + trap_R_ModelBounds( head.hModel, mins, maxs ); + VectorCopy( head.origin, headTop ); + headTop[2] += ( maxs[2] - mins[2] ); + + if ( !(cent->currentState.powerups & ( 1 << PW_INVIS )) ) + FX_SPTransporterLensFlares( cent, headTop, cent->beamData.beamTimeParam ); + } + else { + if ( !cent->beamData.beamInDetected ) { + cent->beamData.beamTimeParam = 0; + } + } + + + if ( cent->currentState.powerups & ( 1 << PW_QUAD ) && !( cent->currentState.powerups & ( 1 << PW_INVIS ) ) ) { + vec3_t mins, maxs, headTop; + + if ( cent->beamData.beamInDetected == qfalse ) { + cent->beamData.beamTimeParam = cg.time; + cent->beamData.beamInDetected = qtrue; + CG_AddFullScreenEffect( SCREENFX_SP_TRANSPORTER_IN, clientNum ); + + //normally player ents reset themselves... but we don't to ourselves >.< + //so do that now + if ( cent->currentState.clientNum == cg.snap->ps.clientNum ) { + CG_ResetPlayerEntity( cent ); + } + } + + trap_R_ModelBounds( head.hModel, mins, maxs ); + VectorCopy( head.origin, headTop ); + headTop[2] += ( maxs[2] - mins[2] ); + + FX_SPTransporterLensFlares( cent, headTop, cent->beamData.beamTimeParam ); + } + else { + if ( cent->beamData.beamInDetected ) { + cent->beamData.beamTimeParam = 0; + cent->beamData.beamInDetected = qfalse; + } + } + //========================================================= + + CG_CalcBeamAlpha( cent->currentState.powerups, ¢->beamData ); + + // add the shadow + if ( /*!(cent->currentState.eFlags & EF_ITEMPLACEHOLDER)*/ qtrue ) + { + shadow = CG_PlayerShadow( cent, legs.origin, &shadowPlane, ci->height ); + } + else + { // - unless we are a hologram... + shadow=qfalse; + shadowPlane=0; + } + + if ( cg_shadows.integer == 3 && shadow ) { + legs.renderfx |= RF_SHADOW_PLANE; + torso.renderfx |= RF_SHADOW_PLANE; + head.renderfx |= RF_SHADOW_PLANE; + } + + //TiM : Shadow calc must appear after beam code, or else we get intermittent glitches on transitioning + legs.shadowPlane = shadowPlane; + torso.shadowPlane = shadowPlane; + head.shadowPlane = shadowPlane; + + //TiM - Added here so it's better in the hierarchy + CG_PlayerSplash( cent ); + + CG_AddRefEntityWithPowerups( &legs, cent->currentState.powerups, cent->currentState.eFlags, ¢->beamData, cent->cloakTime, cent->decloakTime, borg ); + CG_AddRefEntityWithPowerups( &torso, cent->currentState.powerups, cent->currentState.eFlags, ¢->beamData, cent->cloakTime, cent->decloakTime, borg ); + CG_AddRefEntityWithPowerups( &head, cent->currentState.powerups, cent->currentState.eFlags, ¢->beamData, cent->cloakTime, cent->decloakTime, borg ); + + //TiM: Add player based interpolated vfx such as flashlight and the fricken laser. :) + CG_AddBeamFX( cent ); // // add the gun / barrel / flash // - CG_AddPlayerWeapon( &torso, NULL, cent, ci->team ); + CG_AddPlayerWeapon( &torso, NULL, cent ); - // add powerups floating behind the player - CG_PlayerPowerups( cent, &torso ); + //============================================================================= + //TR-116 EyeScope!! :) + // + if ( cent->currentState.weapon == WP_7 ) + { + refEntity_t eyeScope; + + memset( &eyeScope, 0, sizeof( eyeScope ) ); + VectorCopy( cent->lerpOrigin, eyeScope.lightingOrigin ); + eyeScope.shadowPlane = shadowPlane; + eyeScope.renderfx = renderfx; + eyeScope.hModel = cgs.media.tr116EyeScope; + + if ( !isDecoy && cent->currentState.clientNum == cg.snap->ps.clientNum && !cg.renderingThirdPerson ) + eyeScope.renderfx |= RF_THIRD_PERSON; + + if ( eyeScope.hModel ) { + CG_PositionEntityOnTag( &eyeScope, &head, head.hModel, "tag_eyescope" ); + + if ( !VectorCompare( eyeScope.origin, head.origin ) ) { + CG_AddRefEntityWithPowerups( &eyeScope, cent->currentState.powerups, cent->currentState.eFlags, ¢->beamData, cent->cloakTime, cent->decloakTime, borg ); + } + } + + } + + //SIMS Module + if ( cent->currentState.powerups & ( 1 << PW_FLASHLIGHT ) ) + { + refEntity_t flashlight; + + memset( &flashlight, 0, sizeof( flashlight ) ); + VectorCopy( cent->lerpOrigin, flashlight.lightingOrigin ); + flashlight.shadowPlane = shadowPlane; + flashlight.renderfx = renderfx; + flashlight.hModel = cgs.media.simsModule; + + if ( !isDecoy && cent->currentState.clientNum == cg.snap->ps.clientNum && !cg.renderingThirdPerson ) + flashlight.renderfx |= RF_THIRD_PERSON; + + if ( flashlight.hModel ) { + CG_PositionEntityOnTag( &flashlight, &head, head.hModel, "tag_flashlight" ); + + if ( !VectorCompare( flashlight.origin, head.origin ) ) { + CG_AddRefEntityWithPowerups( &flashlight, cent->currentState.powerups, cent->currentState.eFlags, ¢->beamData, cent->cloakTime, cent->decloakTime, borg ); + } + } + } + + //medical scanner + if ( cgs.classData[ci->pClass].isMedic && cent->currentState.weapon == WP_2 ) + { + refEntity_t scanner; + + memset( &scanner, 0, sizeof( scanner ) ); + VectorCopy( cent->lerpOrigin, scanner.lightingOrigin ); + scanner.shadowPlane = shadowPlane; + scanner.renderfx = renderfx; + scanner.hModel = cgs.media.medicalScanner; + + if ( scanner.hModel ) { + CG_PositionEntityOnTag( &scanner, &torso, torso.hModel, "tag_lhand" ); + + if ( !VectorCompare( scanner.origin, torso.origin ) ) { + CG_AddRefEntityWithPowerups( &scanner, cent->currentState.powerups, cent->currentState.eFlags, ¢->beamData, cent->cloakTime, cent->decloakTime, borg ); + } + } + } + + // + + //============================================================================= + // + // attach teh holsters + // + if ( cent->currentState.powerups & ( 1 << PW_BOLTON ) ) + { + if ( ci->isHazardModel && !( !cg.renderingThirdPerson && cent->currentState.clientNum == cg.snap->ps.clientNum ) ) + { + refEntity_t hazardHelmet; + + memset( &hazardHelmet, 0, sizeof( hazardHelmet ) ); + VectorCopy( cent->lerpOrigin, hazardHelmet.lightingOrigin ); + hazardHelmet.shadowPlane = shadowPlane; + hazardHelmet.renderfx = renderfx; + hazardHelmet.hModel = cgs.media.hazardHelmet; + + if ( cgs.media.hazardHelmet ) + { + CG_PositionEntityOnTag( &hazardHelmet, &torso, torso.hModel, "tag_head" ); + + //derive new rotation axis from head model + //else the helmet doesn't rotate with the head, wielding funny results + AxisCopy( head.axis, hazardHelmet.axis ); + + if ( !VectorCompare( hazardHelmet.origin, vec3_origin ) ) + { + CG_AddRefEntityWithPowerups( &hazardHelmet, cent->currentState.powerups, cent->currentState.eFlags, ¢->beamData, cent->cloakTime, cent->decloakTime, borg ); + } + } + } + else if ( ci->holsterModel ) + { + refEntity_t holsterTags; + + memset( &holsterTags, 0, sizeof(holsterTags) ); + VectorCopy( cent->lerpOrigin, holsterTags.lightingOrigin ); + holsterTags.shadowPlane = shadowPlane; + holsterTags.renderfx = renderfx; + holsterTags.hModel = ci->holsterModel; + + if ( holsterTags.hModel ) { + + CG_PositionEntityOnTag( &holsterTags, &legs, legs.hModel, "tag_torso" ); + + trap_R_AddRefEntityToScene( &holsterTags ); + + //TiM - Added an extra bit of data to entitystate, so now, the game + //should transmit each player's weapon list here, so we can make it dynamic now + + //if player has the phaser, bolt it + if ( cent->currentState.time2 & 1 << WP_5 ) { + CG_AttachHolsters( cent, &holsterTags, WP_5 ); + } + + //if player has tricorder + if ( cent->currentState.time2 & 1 << WP_2 ) { + CG_AttachHolsters( cent, &holsterTags, WP_2 ); + } + + //if player has medkit + if ( cent->currentState.time2 & 1 << WP_11 ) { + CG_AttachTools( cent, &torso, WP_11 ); + } + + //if player has toolkit + if ( cent->currentState.time2 & 1 << WP_14 ) { + CG_AttachTools( cent, &torso, WP_14 ); + } + + /*switch ( ci->pClass ) { + case PC_COMMAND: + case PC_ENGINEER: + case PC_SECURITY: + case PC_SCIENCE: + case PC_ADMIN: + CG_AttachHolsters( cent, &holsterTags, WP_5 ); + break; + } + + switch ( ci->pClass ) { + case PC_ENGINEER: + case PC_SECURITY: + case PC_SCIENCE: + case PC_MEDICAL: + case PC_ADMIN: + CG_AttachHolsters( cent, &holsterTags, WP_2 ); + break; + } + + switch ( ci->pClass ) { + case PC_ENGINEER: + CG_AttachTools( cent, &torso, WP_14 ); + break; + } + + switch ( ci->pClass ) { + case PC_MEDICAL: + CG_AttachTools( cent, &torso, WP_11 ); + break; + }*/ + } + } + } + //============================================================================= + // + //Custom Boltons + + //Com_Printf("Index: %i, Name: %s, Handle: %i\n", ci->boltonTags[0].modelBase, ci->boltonTags[0].tagName, ci->boltonTags[0].tagModel); + + //If we have boltons... + if ( ci->boltonTags[0].tagModel ) { //We'll test by seeing if a model was cached into the first slot + refEntity_t boltOns[MAX_BOLTONS]; + refEntity_t* target = NULL; + qhandle_t targetModel; + + for (i = 0; ( ( i < MAX_BOLTONS ) || ( ci->boltonTags[i].tagModel || ci->boltonTags[i].tagName[0] ) ); i++ ) { + //if there's no data in there... no point to rendering it + //ROFL... uh, we can't use .modelBase since 0 is a valid entry for that one :P + if ( !ci->boltonTags[i].tagName[0] || !ci->boltonTags[i].tagModel ) { + break; + } + + memset( &boltOns[i], 0, sizeof(boltOns[i]) ); + VectorCopy( cent->lerpOrigin, boltOns[i].lightingOrigin ); + boltOns[i].renderfx = renderfx; + boltOns[i].shadowPlane = shadowPlane; + + boltOns[i].hModel = ci->boltonTags[i].tagModel; + + //Get the necessary data for which mesh to bolt to + switch ( ci->boltonTags[i].modelBase ){ + case BOLTON_HEAD: + target = &head; + targetModel = ci->headModel; + break; + case BOLTON_TORSO: + target = &torso; + targetModel = ci->torsoModel; + break; + case BOLTON_LEGS: + default: + target = &legs; + targetModel = ci->legsModel; + break; + } + CG_PositionEntityOnTag( &boltOns[i], target, targetModel, ci->boltonTags[i].tagName ); + + if ( VectorCompare( boltOns[i].origin, target->origin ) ) { + break; + } + CG_AddRefEntityWithPowerups( &boltOns[i], cent->currentState.powerups, cent->currentState.eFlags, ¢->beamData, cent->cloakTime, cent->decloakTime, borg ); + } + } + + //============================================================================= + // teh much talked about rank system :) + // + // + + //First, check class to determine whether we'll have default or actual rank models displayed + if ( !cgs.classData[ci->pClass].showRanks || !ci->hasRanks /*ci->pClass == PC_NOCLASS || ci->pClass == PC_ALIEN || ci->pClass == PC_N00B*/ ) { + if ( cgs.defaultRankData.rankModelData.boltModelPath[0] ) { + rankModelData = &cgs.defaultRankData.rankModelData; + rankDataValidated = qtrue; + } + } + else { //Q_log2 + if ( cgs.ranksData[cg.scores[clientNum].score].rankModelData.boltModelPath[0] ) { + + //Ah... found the error with the ranks displaying wrong. Turns out cg.scores[val] is sorted by score ranking, not clientNum + //Gotta manually find ourselves in the list. + for ( i = 0; i < MAX_CLIENTS; i++ ) { + if ( cg.scores[i].client == clientNum ) { + break; + } + } + + //rankModelData = &cgs.ranksData[Q_log2( cg.scores[clientNum].score )].rankModelData; + rankModelData = &cgs.ranksData[cg.scores[i].score].rankModelData; + if ( rankModelData ) + rankDataValidated = qtrue; + } + } + + if ( !rankDataValidated || cg_noDynamicRanks.integer != 0 ) { + return; + } + + //Now check to see if we actually got any data + //I've purposely created this deferred kind of rank loading + //system to try and minimize the amount of shader slots this thing will use at one time. :P + //No point in loading it until we use it + if ( rankModelData->boltModelPath[0] ) { + //if we didn't try to cache it, try now + if ( !rankModelData->boltModel && !rankModelData->triedToLoad ) { + rankModelData->boltModel = trap_R_RegisterModel( rankModelData->boltModelPath ); + + if ( !rankModelData->boltModel ) { + Com_Printf( S_COLOR_RED "Unable to load model file: %s\n", rankModelData->boltModelPath ); + } + + if ( rankModelData->boltShaderPath[0] ) { + //rankModelData->boltShader = trap_R_RegisterSkin( rankModelData->boltShaderPath ); + rankModelData->boltShader = trap_R_RegisterShader( rankModelData->boltShaderPath ); + + if ( !rankModelData->boltShader ) { + Com_Printf( S_COLOR_RED "Unable to load skin: %s\n", rankModelData->boltShaderPath ); + } + } + + rankModelData->triedToLoad = qtrue; + } + } + + //Now for the actual renderisation of the model + + if ( rankModelData->boltModel ) { + refEntity_t rankPip; + + memset( &rankPip, 0, sizeof( rankPip ) ); + VectorCopy( cent->lerpOrigin, rankPip.lightingOrigin ); + rankPip.shadowPlane = shadowPlane; + rankPip.renderfx = renderfx; + + rankPip.hModel = rankModelData->boltModel; + if ( rankModelData->boltShader ) { + //rankPip.customSkin = rankModelData->boltShader; + rankPip.customShader = rankModelData->boltShader; + } + + CG_PositionEntityOnTag( &rankPip, &head, head.hModel, "tag_pip" ); + + if ( VectorCompare( rankPip.origin, head.origin ) ) { + return; + } + + CG_AddRefEntityWithPowerups( &rankPip, cent->currentState.powerups, cent->currentState.eFlags, ¢->beamData, cent->cloakTime, cent->decloakTime, borg ); + + //for admiral ranks, save the data and re-use, but offset origin+angles + if ( rankModelData->admiralRank ) { + /*refEntity_t rankPip1; + + memset( &rankPip1, 0, sizeof( rankPip1 ) ); + VectorCopy( cent->lerpOrigin, rankPip1.lightingOrigin ); + rankPip.shadowPlane = shadowPlane; + rankPip.renderfx = renderfx; + + rankPip1.hModel = rankModelData->boltModel; + if ( rankModelData->boltShader ) { + rankPip1.customSkin = rankModelData->boltShader; + }*/ + + //CG_PositionEntityOnTag( &rankPip1, &head, head.hModel, "tag_pip1" ); + CG_PositionEntityOnTag( &rankPip, &head, head.hModel, "tag_pip1" ); + + if ( VectorCompare( rankPip.origin, head.origin ) ) { + return; + } + + CG_AddRefEntityWithPowerups( &rankPip, cent->currentState.powerups, cent->currentState.eFlags, ¢->beamData, cent->cloakTime, cent->decloakTime, borg ); + + } + } + + //TiM - try out the procedural rank quad maker + //*sob* no normals = doesn't work :'( + //{ + // refEntity_t pip; + // polyVert_t verts[4]; + + // //use this to quickly get the tag porsition + orientation + // CG_PositionEntityOnTag( &pip, &head, head.hModel, "tag_pip" ); + // + // if ( VectorCompare( pip.origin, vec3_origin ) || cent->beamData.beamAlpha < 0.5f ) + // return; + + // //lower left + // verts[0].modulate[0] = 0xff; + // verts[0].modulate[1] = 0xff; + // verts[0].modulate[2] = 0xff; + // verts[0].modulate[3] = 0xff; + // verts[0].st[0] = 0; + // verts[0].st[1] = 1; + // + // //upper left + // verts[1].modulate[0] = 0xff; + // verts[1].modulate[1] = 0xff; + // verts[1].modulate[2] = 0xff; + // verts[1].modulate[3] = 0xff; + // verts[1].st[0] = 0; + // verts[1].st[1] = 0; + + // //upper right + // verts[2].modulate[0] = 0xff; + // verts[2].modulate[1] = 0xff; + // verts[2].modulate[2] = 0xff; + // verts[2].modulate[3] = 0xff; + // verts[2].st[0] = 1; + // verts[2].st[1] = 0; + + // //lower right + // verts[3].modulate[0] = 0xff; + // verts[3].modulate[1] = 0xff; + // verts[3].modulate[2] = 0xff; + // verts[3].modulate[3] = 0xff; + // verts[3].st[0] = 1; + // verts[3].st[1] = 1; + + // //offset each vert per axis + // //lower left + // VectorMA( pip.origin, -10, pip.axis[1], verts[0].xyz ); //shift the vert right + // VectorMA( verts[0].xyz, -5, pip.axis[2], verts[0].xyz ); + + // //upper left + // VectorMA( pip.origin, -10, pip.axis[1], verts[1].xyz ); //shift the vert right + // VectorMA( verts[1].xyz, 5, pip.axis[2], verts[1].xyz ); + + // //upper right + // VectorMA( pip.origin, 10, pip.axis[1], verts[2].xyz ); //shift the vert right + // VectorMA( verts[2].xyz, 5, pip.axis[2], verts[2].xyz ); + + // //lower right + // VectorMA( pip.origin, 10, pip.axis[1], verts[3].xyz ); //shift the vert right + // VectorMA( verts[3].xyz, -5, pip.axis[2], verts[3].xyz ); + + // trap_R_AddPolyToScene( rankModelData->boltShader, 4, verts ); + //} } - //===================================================================== /* @@ -2597,11 +5266,21 @@ A player just came into view or teleported, so reset all animation info =============== */ void CG_ResetPlayerEntity( centity_t *cent ) { + qboolean isDecoy=qfalse; + + isDecoy = (cent->currentState.eFlags & EF_ITEMPLACEHOLDER); + cent->errorTime = -99999; // guarantee no error decay added cent->extrapolated = qfalse; - CG_ClearLerpFrame( &cgs.clientinfo[ cent->currentState.clientNum ], ¢->pe.legs, cent->currentState.legsAnim ); - CG_ClearLerpFrame( &cgs.clientinfo[ cent->currentState.clientNum ], ¢->pe.torso, cent->currentState.torsoAnim ); + if ( !isDecoy ) { + CG_ClearLerpFrame( &cgs.clientinfo[ cent->currentState.clientNum ], ¢->pe.legs, cent->currentState.legsAnim ); + CG_ClearLerpFrame( &cgs.clientinfo[ cent->currentState.clientNum ], ¢->pe.torso, cent->currentState.torsoAnim ); + } + else { + CG_ClearLerpFrame( &cgs.decoyInfo[ cent->currentState.eventParm ], ¢->pe.legs, cent->currentState.legsAnim ); + CG_ClearLerpFrame( &cgs.decoyInfo[ cent->currentState.eventParm ], ¢->pe.torso, cent->currentState.torsoAnim ); + } BG_EvaluateTrajectory( ¢->currentState.pos, cg.time, cent->lerpOrigin ); BG_EvaluateTrajectory( ¢->currentState.apos, cg.time, cent->lerpAngles ); @@ -2609,20 +5288,28 @@ void CG_ResetPlayerEntity( centity_t *cent ) { VectorCopy( cent->lerpOrigin, cent->rawOrigin ); VectorCopy( cent->lerpAngles, cent->rawAngles ); - memset( ¢->pe.legs, 0, sizeof( cent->pe.legs ) ); - cent->pe.legs.yawAngle = cent->rawAngles[YAW]; - cent->pe.legs.yawing = qfalse; - cent->pe.legs.pitchAngle = 0; - cent->pe.legs.pitching = qfalse; + //TiM - Only do this if not emoting. Otherwise, if we go away, then come back, clamped players face different directions O_O + //ignore this for decoys too. they're static, so this won't affect them anyway - memset( ¢->pe.torso, 0, sizeof( cent->pe.legs ) ); - cent->pe.torso.yawAngle = cent->rawAngles[YAW]; - cent->pe.torso.yawing = qfalse; - cent->pe.torso.pitchAngle = cent->rawAngles[PITCH]; - cent->pe.torso.pitching = qfalse; + if ( !isDecoy && ( ( cent->currentState.eFlags & EF_CLAMP_BODY) || ( cent->currentState.eFlags & EF_CLAMP_ALL) ) ) { + //blah + } + else { + memset( ¢->pe.legs, 0, sizeof( cent->pe.legs ) ); + cent->pe.legs.yawAngle = cent->rawAngles[YAW]; + cent->pe.legs.yawing = qfalse; + cent->pe.legs.pitchAngle = 0; + cent->pe.legs.pitching = qfalse; + + memset( ¢->pe.torso, 0, sizeof( cent->pe.legs ) ); + cent->pe.torso.yawAngle = cent->rawAngles[YAW]; + cent->pe.torso.yawing = qfalse; + cent->pe.torso.pitchAngle = cent->rawAngles[PITCH]; + cent->pe.torso.pitching = qfalse; + } if ( cg_debugPosition.integer ) { - CG_Printf("%i ResetPlayerEntity yaw=%f\n", cent->currentState.number, cent->pe.torso.yawAngle ); + CG_Printf("%i ResetPlayerEntity yaw=%i\n", cent->currentState.number, cent->pe.torso.yawAngle ); } } diff --git a/code/cgame/cg_playerstate.c b/code/cgame/cg_playerstate.c index 066e24a..9b18fc4 100644 --- a/code/cgame/cg_playerstate.c +++ b/code/cgame/cg_playerstate.c @@ -1,24 +1,4 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // // cg_playerstate.c -- this file acts on changes in a new playerState_t // With normal play, this will be done after local prediction, but when @@ -40,21 +20,33 @@ void CG_CheckAmmo( void ) { int previous; int weapons; + if ( cg.lowAmmoWarning > 2 ) + {//a timed message, draws for a specific amount of time + if ( cg.lowAmmoWarning > cg.frametime ) + { + cg.lowAmmoWarning -= cg.frametime; + } + else + { + cg.lowAmmoWarning = 0; + } + return; + } // see about how many seconds of ammo we have remaining weapons = cg.snap->ps.stats[ STAT_WEAPONS ]; total = 0; - for ( i = WP_MACHINEGUN ; i < WP_NUM_WEAPONS ; i++ ) { + + //TiM + //for ( i = WP_5 ; i < WP_NUM_WEAPONS ; i++ ) { + for ( i = WP_1 ; i < WP_NUM_WEAPONS ; i++ ) { if ( ! ( weapons & ( 1 << i ) ) ) { continue; } switch ( i ) { - case WP_ROCKET_LAUNCHER: - case WP_GRENADE_LAUNCHER: - case WP_RAILGUN: - case WP_SHOTGUN: -#ifdef MISSIONPACK - case WP_PROX_LAUNCHER: -#endif + case WP_10: + case WP_8: + case WP_1: + case WP_6: total += cg.snap->ps.ammo[i] * 1000; break; default: @@ -76,9 +68,10 @@ void CG_CheckAmmo( void ) { } // play a sound on transitions - if ( cg.lowAmmoWarning != previous ) { + // RPG-X | Phenix | 13/02/2005 + /*if ( cg.lowAmmoWarning != previous ) { trap_S_StartLocalSound( cgs.media.noAmmoSound, CHAN_LOCAL_SOUND ); - } + }*/ } /* @@ -86,7 +79,7 @@ void CG_CheckAmmo( void ) { CG_DamageFeedback ============== */ -void CG_DamageFeedback( int yawByte, int pitchByte, int damage ) { +void CG_DamageFeedback( int yawByte, int pitchByte, int damage, int shielddamage ) { float left, front, up; float kick; int health; @@ -106,7 +99,8 @@ void CG_DamageFeedback( int yawByte, int pitchByte, int damage ) { } else { scale = 40.0 / health; } - kick = damage * scale; + + kick = (damage + shielddamage*0.5) * scale; if (kick < 5) kick = 5; @@ -140,7 +134,7 @@ void CG_DamageFeedback( int yawByte, int pitchByte, int damage ) { dir[2] = 0; dist = VectorLength( dir ); if ( dist < 0.1 ) { - dist = 0.1f; + dist = 0.1; } cg.v_dmg_roll = kick * left; @@ -148,7 +142,7 @@ void CG_DamageFeedback( int yawByte, int pitchByte, int damage ) { cg.v_dmg_pitch = -kick * front; if ( front <= 0.1 ) { - front = 0.1f; + front = 0.1; } cg.damageX = -left / front; cg.damageY = up / dist; @@ -169,11 +163,25 @@ void CG_DamageFeedback( int yawByte, int pitchByte, int damage ) { cg.damageY = -1.0; } - // don't let the screen flashes vary as much - if ( kick > 10 ) { - kick = 10; + cg.damageValue = damage * scale; + if (cg.damageValue > 10) + { + cg.damageValue = 1.0; } - cg.damageValue = kick; + else + { + cg.damageValue *= 0.1; + } + cg.damageShieldValue = shielddamage; + if (cg.damageShieldValue > 10) + { + cg.damageShieldValue = 1.0; + } + else + { + cg.damageShieldValue *= 0.1; + } + cg.v_dmg_time = cg.time + DAMAGE_TIME; cg.damageTime = cg.snap->serverTime; } @@ -199,7 +207,6 @@ void CG_Respawn( void ) { cg.weaponSelect = cg.snap->ps.weapon; } -extern char *eventnames[]; /* ============== @@ -226,104 +233,56 @@ void CG_CheckPlayerstateEvents( playerState_t *ps, playerState_t *ops ) { // or the server told us to play another event instead of a predicted event we already issued // or something the server told us changed our prediction causing a different event || (i > ops->eventSequence - MAX_PS_EVENTS && ps->events[i & (MAX_PS_EVENTS-1)] != ops->events[i & (MAX_PS_EVENTS-1)]) ) { - + event = ps->events[ i & (MAX_PS_EVENTS-1) ]; cent->currentState.event = event; cent->currentState.eventParm = ps->eventParms[ i & (MAX_PS_EVENTS-1) ]; CG_EntityEvent( cent, cent->lerpOrigin ); - cg.predictableEvents[ i & (MAX_PREDICTED_EVENTS-1) ] = event; +// cg.predictableEvents[ i & (MAX_PREDICTED_EVENTS-1) ] = event; - cg.eventSequence++; +// cg.eventSequence++; } } } -/* -================== -CG_CheckChangedPredictableEvents -================== -*/ -void CG_CheckChangedPredictableEvents( playerState_t *ps ) { - int i; - int event; - centity_t *cent; - - cent = &cg.predictedPlayerEntity; - for ( i = ps->eventSequence - MAX_PS_EVENTS ; i < ps->eventSequence ; i++ ) { - // - if (i >= cg.eventSequence) { - continue; - } - // if this event is not further back in than the maximum predictable events we remember - if (i > cg.eventSequence - MAX_PREDICTED_EVENTS) { - // if the new playerstate event is different from a previously predicted one - if ( ps->events[i & (MAX_PS_EVENTS-1)] != cg.predictableEvents[i & (MAX_PREDICTED_EVENTS-1) ] ) { - - event = ps->events[ i & (MAX_PS_EVENTS-1) ]; - cent->currentState.event = event; - cent->currentState.eventParm = ps->eventParms[ i & (MAX_PS_EVENTS-1) ]; - CG_EntityEvent( cent, cent->lerpOrigin ); - - cg.predictableEvents[ i & (MAX_PREDICTED_EVENTS-1) ] = event; - - if ( cg_showmiss.integer ) { - CG_Printf("WARNING: changed predicted event\n"); - } - } - } - } -} - -/* -================== -pushReward -================== -*/ -static void pushReward(sfxHandle_t sfx, qhandle_t shader, int rewardCount) { - if (cg.rewardStack < (MAX_REWARDSTACK-1)) { - cg.rewardStack++; - cg.rewardSound[cg.rewardStack] = sfx; - cg.rewardShader[cg.rewardStack] = shader; - cg.rewardCount[cg.rewardStack] = rewardCount; - } -} - /* ================== CG_CheckLocalSounds ================== */ -void CG_CheckLocalSounds( playerState_t *ps, playerState_t *ops ) { - int highScore, reward; -#ifdef MISSIONPACK - int health, armor; -#endif - sfxHandle_t sfx; +void CG_CheckLocalSounds( playerState_t *ps, playerState_t *ops ) +{ +// int highScore; - // don't play the sounds if the player just changed teams - if ( ps->persistant[PERS_TEAM] != ops->persistant[PERS_TEAM] ) { - return; - } + // The most important thing to know is if you are doing damage. + //RPG-X - TiM + /*if ( ps->persistant[PERS_HITS] > ops->persistant[PERS_HITS] ) + { + int diffhit, diffshields; - // hit changes - if ( ps->persistant[PERS_HITS] > ops->persistant[PERS_HITS] ) { -#ifdef MISSIONPACK - armor = ps->persistant[PERS_ATTACKEE_ARMOR] & 0xff; - health = ps->persistant[PERS_ATTACKEE_ARMOR] >> 8; - if (armor > 50 ) { - trap_S_StartLocalSound( cgs.media.hitSoundHighArmor, CHAN_LOCAL_SOUND ); - } else if (armor || health > 100) { - trap_S_StartLocalSound( cgs.media.hitSoundLowArmor, CHAN_LOCAL_SOUND ); - } else { + diffhit = ps->persistant[PERS_HITS] - ops->persistant[PERS_HITS]; + diffshields = ps->persistant[PERS_SHIELDS] - ops->persistant[PERS_SHIELDS]; + if (diffshields > diffhit/2) + { // We also hit shields along the way, so consider them "pierced". + trap_S_StartLocalSound( cgs.media.shieldPierceSound, CHAN_LOCAL_SOUND ); + } + else + { // Shields didn't really stand in our way. trap_S_StartLocalSound( cgs.media.hitSound, CHAN_LOCAL_SOUND ); } -#else - trap_S_StartLocalSound( cgs.media.hitSound, CHAN_LOCAL_SOUND ); -#endif - } else if ( ps->persistant[PERS_HITS] < ops->persistant[PERS_HITS] ) { + } + // The second most important thing to worry about is whether you hurt a friend. + else if ( ps->persistant[PERS_HITS] < ops->persistant[PERS_HITS] ) + { trap_S_StartLocalSound( cgs.media.hitTeamSound, CHAN_LOCAL_SOUND ); } + // Finally if all this damage bounced off the shields, indicate this. + else if (ps->persistant[PERS_SHIELDS] > ops->persistant[PERS_SHIELDS]) + { + // hit shields and the damage didn't go through + trap_S_StartLocalSound( cgs.media.shieldHitSound, CHAN_LOCAL_SOUND ); + }*/ // health changes of more than -1 should make pain sounds if ( ps->stats[STAT_HEALTH] < ops->stats[STAT_HEALTH] - 1 ) { @@ -339,104 +298,79 @@ void CG_CheckLocalSounds( playerState_t *ps, playerState_t *ops ) { } // reward sounds - reward = qfalse; - if (ps->persistant[PERS_CAPTURES] != ops->persistant[PERS_CAPTURES]) { - pushReward(cgs.media.captureAwardSound, cgs.media.medalCapture, ps->persistant[PERS_CAPTURES]); - reward = qtrue; - //Com_Printf("capture\n"); - } - if (ps->persistant[PERS_IMPRESSIVE_COUNT] != ops->persistant[PERS_IMPRESSIVE_COUNT]) { -#ifdef MISSIONPACK - if (ps->persistant[PERS_IMPRESSIVE_COUNT] == 1) { - sfx = cgs.media.firstImpressiveSound; - } else { - sfx = cgs.media.impressiveSound; + //RPG-X: RedTechie - No reward or frag limit sounds + /*if ( ps->persistant[PERS_REWARD_COUNT] > ops->persistant[PERS_REWARD_COUNT] ) { + switch ( ps->persistant[PERS_REWARD] ) { + case REWARD_IMPRESSIVE: + trap_S_StartLocalSound( cgs.media.rewardImpressiveSound, CHAN_ANNOUNCER ); + cg.rewardTime = cg.time; + cg.rewardShader = cgs.media.medalImpressive; + cg.rewardCount = ps->persistant[PERS_IMPRESSIVE_COUNT]; + break; + case REWARD_EXCELLENT: + trap_S_StartLocalSound( cgs.media.rewardExcellentSound, CHAN_ANNOUNCER ); + cg.rewardTime = cg.time; + cg.rewardShader = cgs.media.medalExcellent; + cg.rewardCount = ps->persistant[PERS_EXCELLENT_COUNT]; + break; + case REWARD_DENIED: + trap_S_StartLocalSound( cgs.media.rewardDeniedSound, CHAN_ANNOUNCER ); + break; + case REWARD_FIRST_STRIKE: + trap_S_StartLocalSound( cgs.media.rewardFirstStrikeSound, CHAN_ANNOUNCER); + cg.rewardTime = cg.time; + cg.rewardShader = cgs.media.medalFirstStrike; + cg.rewardCount = 1; + break; + case REWARD_STREAK: + // Play a different sound depending on how long the streak is. + cg.rewardTime = cg.time; + cg.rewardCount = 1; + if (ps->persistant[PERS_STREAK_COUNT] >= STREAK_CHAMPION) + { + trap_S_StartLocalSound( cgs.media.rewardChampionSound, CHAN_ANNOUNCER); + cg.rewardShader = cgs.media.medalChampion; + } + else if (ps->persistant[PERS_STREAK_COUNT] >= STREAK_MASTER) + { + trap_S_StartLocalSound( cgs.media.rewardMasterSound, CHAN_ANNOUNCER); + cg.rewardShader = cgs.media.medalMaster; + } + else if (ps->persistant[PERS_STREAK_COUNT] >= STREAK_EXPERT) + { + trap_S_StartLocalSound( cgs.media.rewardExpertSound, CHAN_ANNOUNCER); + cg.rewardShader = cgs.media.medalExpert; + } + else if (ps->persistant[PERS_STREAK_COUNT] >= STREAK_ACE) + { + trap_S_StartLocalSound( cgs.media.rewardAceSound, CHAN_ANNOUNCER); + cg.rewardShader = cgs.media.medalAce; + } + break; + default: + CG_Error( "Bad reward_t" ); } -#else - sfx = cgs.media.impressiveSound; -#endif - pushReward(sfx, cgs.media.medalImpressive, ps->persistant[PERS_IMPRESSIVE_COUNT]); - reward = qtrue; - //Com_Printf("impressive\n"); - } - if (ps->persistant[PERS_EXCELLENT_COUNT] != ops->persistant[PERS_EXCELLENT_COUNT]) { -#ifdef MISSIONPACK - if (ps->persistant[PERS_EXCELLENT_COUNT] == 1) { - sfx = cgs.media.firstExcellentSound; - } else { - sfx = cgs.media.excellentSound; - } -#else - sfx = cgs.media.excellentSound; -#endif - pushReward(sfx, cgs.media.medalExcellent, ps->persistant[PERS_EXCELLENT_COUNT]); - reward = qtrue; - //Com_Printf("excellent\n"); - } - if (ps->persistant[PERS_GAUNTLET_FRAG_COUNT] != ops->persistant[PERS_GAUNTLET_FRAG_COUNT]) { -#ifdef MISSIONPACK - if (ops->persistant[PERS_GAUNTLET_FRAG_COUNT] == 1) { - sfx = cgs.media.firstHumiliationSound; - } else { - sfx = cgs.media.humiliationSound; - } -#else - sfx = cgs.media.humiliationSound; -#endif - pushReward(sfx, cgs.media.medalGauntlet, ps->persistant[PERS_GAUNTLET_FRAG_COUNT]); - reward = qtrue; - //Com_Printf("guantlet frag\n"); - } - if (ps->persistant[PERS_DEFEND_COUNT] != ops->persistant[PERS_DEFEND_COUNT]) { - pushReward(cgs.media.defendSound, cgs.media.medalDefend, ps->persistant[PERS_DEFEND_COUNT]); - reward = qtrue; - //Com_Printf("defend\n"); - } - if (ps->persistant[PERS_ASSIST_COUNT] != ops->persistant[PERS_ASSIST_COUNT]) { - pushReward(cgs.media.assistSound, cgs.media.medalAssist, ps->persistant[PERS_ASSIST_COUNT]); - reward = qtrue; - //Com_Printf("assist\n"); - } - // if any of the player event bits changed - if (ps->persistant[PERS_PLAYEREVENTS] != ops->persistant[PERS_PLAYEREVENTS]) { - if ((ps->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_DENIEDREWARD) != - (ops->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_DENIEDREWARD)) { - trap_S_StartLocalSound( cgs.media.deniedSound, CHAN_ANNOUNCER ); - } - else if ((ps->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_GAUNTLETREWARD) != - (ops->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_GAUNTLETREWARD)) { - trap_S_StartLocalSound( cgs.media.humiliationSound, CHAN_ANNOUNCER ); - } - else if ((ps->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_HOLYSHIT) != - (ops->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_HOLYSHIT)) { - trap_S_StartLocalSound( cgs.media.holyShitSound, CHAN_ANNOUNCER ); - } - reward = qtrue; - } - - // check for flag pickup - if ( cgs.gametype > GT_TEAM ) { - if ((ps->powerups[PW_REDFLAG] != ops->powerups[PW_REDFLAG] && ps->powerups[PW_REDFLAG]) || - (ps->powerups[PW_BLUEFLAG] != ops->powerups[PW_BLUEFLAG] && ps->powerups[PW_BLUEFLAG]) || - (ps->powerups[PW_NEUTRALFLAG] != ops->powerups[PW_NEUTRALFLAG] && ps->powerups[PW_NEUTRALFLAG]) ) + } else { + // lead changes (only if no reward) + if ( !cg.warmup && !(cg.predictedPlayerState.introTime > cg.time) ) { - trap_S_StartLocalSound( cgs.media.youHaveFlagSound, CHAN_ANNOUNCER ); - } - } - - // lead changes - if (!reward) { - // - if ( !cg.warmup ) { - // never play lead changes during warmup + // never play lead changes during warmup or holo doors if ( ps->persistant[PERS_RANK] != ops->persistant[PERS_RANK] ) { - if ( cgs.gametype < GT_TEAM) { + if ( cgs.gametype >= GT_TEAM ) { + if ( ps->persistant[PERS_RANK] == 2 ) { + trap_S_StartLocalSound( cgs.media.teamsTiedSound, CHAN_ANNOUNCER ); + } else if ( ps->persistant[PERS_RANK] == 0 ) { + trap_S_StartLocalSound( cgs.media.redLeadsSound, CHAN_ANNOUNCER ); + } else if ( ps->persistant[PERS_RANK] == 1 ) { + trap_S_StartLocalSound( cgs.media.blueLeadsSound, CHAN_ANNOUNCER ); + } + } else { if ( ps->persistant[PERS_RANK] == 0 ) { - CG_AddBufferedSound(cgs.media.takenLeadSound); + trap_S_StartLocalSound( cgs.media.takenLeadSound, CHAN_ANNOUNCER ); } else if ( ps->persistant[PERS_RANK] == RANK_TIED_FLAG ) { - CG_AddBufferedSound(cgs.media.tiedLeadSound); + trap_S_StartLocalSound( cgs.media.tiedLeadSound, CHAN_ANNOUNCER ); } else if ( ( ops->persistant[PERS_RANK] & ~RANK_TIED_FLAG ) == 0 ) { - CG_AddBufferedSound(cgs.media.lostLeadSound); + trap_S_StartLocalSound( cgs.media.lostLeadSound, CHAN_ANNOUNCER ); } } } @@ -448,43 +382,71 @@ void CG_CheckLocalSounds( playerState_t *ps, playerState_t *ops ) { int msec; msec = cg.time - cgs.levelStartTime; - if ( !( cg.timelimitWarnings & 4 ) && msec > ( cgs.timelimit * 60 + 2 ) * 1000 ) { - cg.timelimitWarnings |= 1 | 2 | 4; - trap_S_StartLocalSound( cgs.media.suddenDeathSound, CHAN_ANNOUNCER ); - } - else if ( !( cg.timelimitWarnings & 2 ) && msec > (cgs.timelimit - 1) * 60 * 1000 ) { - cg.timelimitWarnings |= 1 | 2; - trap_S_StartLocalSound( cgs.media.oneMinuteSound, CHAN_ANNOUNCER ); - } - else if ( cgs.timelimit > 5 && !( cg.timelimitWarnings & 1 ) && msec > (cgs.timelimit - 5) * 60 * 1000 ) { + + if ( cgs.timelimit > 5 && !( cg.timelimitWarnings & 1 ) && msec > (cgs.timelimit - 5) * 60 * 1000 ) { cg.timelimitWarnings |= 1; trap_S_StartLocalSound( cgs.media.fiveMinuteSound, CHAN_ANNOUNCER ); } + if ( !( cg.timelimitWarnings & 2 ) && msec > (cgs.timelimit - 1) * 60 * 1000 ) { + cg.timelimitWarnings |= 2; + trap_S_StartLocalSound( cgs.media.oneMinuteSound, CHAN_ANNOUNCER ); + } + if ( !( cg.timelimitWarnings & 4 ) && msec > ( cgs.timelimit * 60 + 2 ) * 1000 ) { + cg.timelimitWarnings |= 4; + trap_S_StartLocalSound( cgs.media.suddenDeathSound, CHAN_ANNOUNCER ); + } } // fraglimit warnings - if ( cgs.fraglimit > 0 && cgs.gametype < GT_CTF) { + if ( cgs.fraglimit > 0 && cgs.gametype != GT_CTF ) { highScore = cgs.scores1; - - if (cgs.gametype == GT_TEAM && cgs.scores2 > highScore) { - highScore = cgs.scores2; - } - - if ( !( cg.fraglimitWarnings & 4 ) && highScore == (cgs.fraglimit - 1) ) { - cg.fraglimitWarnings |= 1 | 2 | 4; - CG_AddBufferedSound(cgs.media.oneFragSound); - } - else if ( cgs.fraglimit > 2 && !( cg.fraglimitWarnings & 2 ) && highScore == (cgs.fraglimit - 2) ) { - cg.fraglimitWarnings |= 1 | 2; - CG_AddBufferedSound(cgs.media.twoFragSound); - } - else if ( cgs.fraglimit > 3 && !( cg.fraglimitWarnings & 1 ) && highScore == (cgs.fraglimit - 3) ) { + if ( cgs.fraglimit > 3 && !( cg.fraglimitWarnings & 1 ) && highScore == (cgs.fraglimit - 3) ) { cg.fraglimitWarnings |= 1; - CG_AddBufferedSound(cgs.media.threeFragSound); + trap_S_StartLocalSound( cgs.media.threeFragSound, CHAN_ANNOUNCER ); } - } + if ( cgs.fraglimit > 2 && !( cg.fraglimitWarnings & 2 ) && highScore == (cgs.fraglimit - 2) ) { + cg.fraglimitWarnings |= 2; + trap_S_StartLocalSound( cgs.media.twoFragSound, CHAN_ANNOUNCER ); + } + if ( !( cg.fraglimitWarnings & 4 ) && highScore == (cgs.fraglimit - 1) ) { + cg.fraglimitWarnings |= 4; + trap_S_StartLocalSound( cgs.media.oneFragSound, CHAN_ANNOUNCER ); + } + }*/ } + +void CG_CheckDamageDealt(playerState_t *ps, playerState_t *ops) +{ + static int damagetime; + static int damageamount; + + if (cg_reportDamage.integer) + { + if (ps->persistant[PERS_HITS] > ops->persistant[PERS_HITS]) + { // We did some damage this frame. + if (damagetime+1000 < cg.time) + { // Start a new tally. + damageamount = ps->persistant[PERS_HITS] - ops->persistant[PERS_HITS]; + damagetime = cg.time; + } + else + { // Add to a tally that's already here. + damageamount += ps->persistant[PERS_HITS] - ops->persistant[PERS_HITS]; + } + } + + // Report the sum of damage done this second. + if (damageamount > 0 && (damagetime+1000 <= cg.time)) + { + Com_Printf("Damage this second: %d\n", damageamount); + damageamount = 0; + } + } +} + + + /* =============== CG_TransitionPlayerState @@ -500,8 +462,8 @@ void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops ) { } // damage events (player is getting wounded) - if ( ps->damageEvent != ops->damageEvent && ps->damageCount ) { - CG_DamageFeedback( ps->damageYaw, ps->damagePitch, ps->damageCount ); + if ( ps->damageEvent != ops->damageEvent && (ps->damageCount || ps->damageShieldCount)) { + CG_DamageFeedback( ps->damageYaw, ps->damagePitch, ps->damageCount, ps->damageShieldCount); } // respawning @@ -509,13 +471,13 @@ void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops ) { CG_Respawn(); } - if ( cg.mapRestart ) { +/* if ( cg.mapRestart ) { //q3 update -not tested yet CG_Respawn(); cg.mapRestart = qfalse; } - +*/ if ( cg.snap->ps.pm_type != PM_INTERMISSION - && ps->persistant[PERS_TEAM] != TEAM_SPECTATOR ) { + && ps->persistant[PERS_TEAM] != TEAM_SPECTATOR /*&& !(ps->eFlags&EF_ELIMINATED)*/) { CG_CheckLocalSounds( ps, ops ); } @@ -530,5 +492,9 @@ void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops ) { cg.duckChange = ps->viewheight - ops->viewheight; cg.duckTime = cg.time; } + +#ifdef _DEBUG + CG_CheckDamageDealt(ps, ops); +#endif //_DEBUG } diff --git a/code/cgame/cg_predict.c b/code/cgame/cg_predict.c index b7a6953..46fbda9 100644 --- a/code/cgame/cg_predict.c +++ b/code/cgame/cg_predict.c @@ -1,24 +1,4 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // // cg_predict.c -- this file generates cg.predictedPlayerState by either // interpolating between snapshots from the server or locally predicting @@ -82,6 +62,8 @@ CG_ClipMoveToEntities ==================== */ +#define SHIELD_HALFTHICKNESS 4 // should correspond with the #define in g_active.c + static void CG_ClipMoveToEntities ( const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int skipNumber, int mask, trace_t *tr ) { int i, x, zd, zu; @@ -105,11 +87,71 @@ static void CG_ClipMoveToEntities ( const vec3_t start, const vec3_t mins, const cmodel = trap_CM_InlineModel( ent->modelindex ); VectorCopy( cent->lerpAngles, angles ); BG_EvaluateTrajectory( ¢->currentState.pos, cg.physicsTime, origin ); - } else { + } + else if (ent->eFlags & EF_SHIELD_BOX_X) + { // "specially" encoded bbox for x-axis aligned shield + + //CG_Printf( S_COLOR_RED "Mins[ %d %d %d ] Maxs[ %d %d %d ]\n", mins[0], mins[1], mins[2], maxs[0], maxs[1], maxs[2] ); + + //this is a bit of a hack. Only deny entry to elements + //that do not specifiy collision boundaries. + //This will mean things like players won't be affected + //(there'll be a slight jerk as the server boots them back) + //but any FX like phaser beams will be. + if ( !mins || !VectorCompare( mins, vec3_origin ) || !VectorCompare( maxs, vec3_origin ) ) + continue; + + /*x = (ent->solid & 255); // i on server side + zd = ((ent->solid>>8) & 255); // j on server side + zu = ((ent->solid>>16) & 255); // k on server side*/ + + x = (ent->time2 & 1023); // i on server side + zd = ((ent->time2>>10) & 1023); // j on server side + zu = ((ent->time2>>20) & 1023); // k on server side + + bmins[0] = -x; //-zd + bmaxs[0] = zd; //x + bmins[1] = -SHIELD_HALFTHICKNESS; + bmaxs[1] = SHIELD_HALFTHICKNESS; + bmins[2] = 0; + bmaxs[2] = zu; + + cmodel = trap_CM_TempBoxModel( bmins, bmaxs ); + VectorCopy( vec3_origin, angles ); + VectorCopy( cent->lerpOrigin, origin ); + + //CG_Printf( S_COLOR_RED "X Aligned! Bmins = [ %f %f %f ],\nBMaxs = [%f %f %f]\n", bmins[0], bmins[1], bmins[2], bmaxs[0],bmaxs[1],bmaxs[2] ); + } + else if (ent->eFlags & EF_SHIELD_BOX_Y) + { // "specially" encoded bbox for y-axis aligned shield + /*x = (ent->solid & 255); // i on server side + zd = ((ent->solid>>8) & 255); // j on server side + zu = ((ent->solid>>16) & 255); // k on server side*/ + + if ( !VectorCompare( mins, vec3_origin ) || !VectorCompare( maxs, vec3_origin ) ) + continue; + + x = (ent->time2 & 1023); // i on server side + zd = ((ent->time2>>10) & 1023); // j on server side + zu = ((ent->time2>>20) & 1023); // k on server side + + bmins[1] = -x; + bmaxs[1] = zd; + bmins[0] = -SHIELD_HALFTHICKNESS; + bmaxs[0] = SHIELD_HALFTHICKNESS; + bmins[2] = 0; + bmaxs[2] = zu; + + cmodel = trap_CM_TempBoxModel( bmins, bmaxs ); + VectorCopy( vec3_origin, angles ); + VectorCopy( cent->lerpOrigin, origin ); + } + else + { // encoded bbox - x = (ent->solid & 255); - zd = ((ent->solid>>8) & 255); - zu = ((ent->solid>>16) & 255) - 32; + x = (ent->solid & 255); // i on server side + zd = ((ent->solid>>8) & 255); // j on server side + zu = ((ent->solid>>16) & 255) - 32; // k on server side bmins[0] = bmins[1] = -x; bmaxs[0] = bmaxs[1] = x; @@ -186,7 +228,7 @@ int CG_PointContents( const vec3_t point, int passEntityNum ) { continue; } - contents |= trap_CM_TransformedPointContents( point, cmodel, cent->lerpOrigin, cent->lerpAngles ); + contents |= trap_CM_TransformedPointContents( point, cmodel, ent->origin, ent->angles ); } return contents; @@ -261,19 +303,27 @@ CG_TouchItem static void CG_TouchItem( centity_t *cent ) { gitem_t *item; + //RPG-X | Marcin | 03/12/2008 + //this can't be predicted because as don't know whether USE was pressed... + if (qtrue) { + return; + } + if ( !cg_predictItems.integer ) { return; } - if ( !BG_PlayerTouchesItem( &cg.predictedPlayerState, ¢->currentState, cg.time ) ) { - return; - } // never pick an item up twice in a prediction if ( cent->miscTime == cg.time ) { return; } + + if ( !BG_PlayerTouchesItem( &cg.predictedPlayerState, ¢->currentState, cg.time ) ) { + return; + } - if ( !BG_CanItemBeGrabbed( cgs.gametype, ¢->currentState, &cg.predictedPlayerState ) ) { + // RPG-X: Marcin: Can't predict this any more sorry - 30/12/2008 + if ( 0 ) /* ( !BG_CanItemBeGrabbed( ¢->currentState, &cg.predictedPlayerState ) ) */ { return; // can't hold it } @@ -281,38 +331,45 @@ static void CG_TouchItem( centity_t *cent ) { // Special case for flags. // We don't predict touching our own flag -#ifdef MISSIONPACK - if( cgs.gametype == GT_1FCTF ) { - if( item->giTag != PW_NEUTRALFLAG ) { + if (item->giType == IT_TEAM) + { // NOTE: This code used to JUST check giTag. The problem is that the giTag for PW_REDFLAG + // is the same as WP_9. The giTag should be a SUBCHECK after giType. + /*if (cg.predictedPlayerState.persistant[PERS_TEAM] == TEAM_RED && + item->giTag == PW_REDFLAG) + return;*/ + if (cg.predictedPlayerState.persistant[PERS_TEAM] == TEAM_BLUE && + item->giTag == PW_BORG_ADAPT) return; + } + + if (!(cent->currentState.eFlags & (EF_ITEMPLACEHOLDER | EF_NODRAW))) + { + // grab it + BG_AddPredictableEventToPlayerstate( EV_ITEM_PICKUP, cent->currentState.modelindex , &cg.predictedPlayerState); + + // Draw the techy-itemplaceholder for weapons and powerups, not ammo, etc. + if (item->giType == IT_WEAPON || item->giType == IT_POWERUP) + { // draw it "gridded out" + cent->currentState.eFlags |= EF_ITEMPLACEHOLDER; + } + else + { // remove it from the frame so it won't be drawn + cent->currentState.eFlags |= EF_NODRAW; + // kef -- special client-only flag to prevent double pickup sounds + //cent->currentState.eFlags |= EF_CLIENT_NODRAW; + } + // if its a weapon, give them some predicted ammo so the autoswitch will work + if ( item->giType == IT_WEAPON ) + { + cg.predictedPlayerState.stats[ STAT_WEAPONS ] |= 1 << item->giTag; + if ( !cg.predictedPlayerState.ammo[ item->giTag ] ) { + cg.predictedPlayerState.ammo[ item->giTag ] = 1; + } } } -#endif - if( cgs.gametype == GT_CTF ) { - if (cg.predictedPlayerState.persistant[PERS_TEAM] == TEAM_RED && - item->giTag == PW_REDFLAG) - return; - if (cg.predictedPlayerState.persistant[PERS_TEAM] == TEAM_BLUE && - item->giTag == PW_BLUEFLAG) - return; - } - - // grab it - BG_AddPredictableEventToPlayerstate( EV_ITEM_PICKUP, cent->currentState.modelindex , &cg.predictedPlayerState); - - // remove it from the frame so it won't be drawn - cent->currentState.eFlags |= EF_NODRAW; // don't touch it again this prediction cent->miscTime = cg.time; - - // if it's a weapon, give them some predicted ammo so the autoswitch will work - if ( item->giType == IT_WEAPON ) { - cg.predictedPlayerState.stats[ STAT_WEAPONS ] |= 1 << item->giTag; - if ( !cg.predictedPlayerState.ammo[ item->giTag ] ) { - cg.predictedPlayerState.ammo[ item->giTag ] = 1; - } - } } @@ -368,21 +425,35 @@ static void CG_TouchTriggerPrediction( void ) { } if ( ent->eType == ET_TELEPORT_TRIGGER ) { - cg.hyperspace = qtrue; - } else if ( ent->eType == ET_PUSH_TRIGGER ) { - BG_TouchJumpPad( &cg.predictedPlayerState, ent ); + //cg.hyperspace = qtrue; + continue; + } else { + float s; + vec3_t dir; + + // we hit this push trigger + if ( spectator ) { + continue; + } + + // flying characters don't hit bounce pads + if ( cg.predictedPlayerState.powerups[PW_FLIGHT] ) { + continue; + } + + // if we are already flying along the bounce direction, don't play sound again + VectorNormalize2( ent->origin2, dir ); + s = DotProduct( cg.predictedPlayerState.velocity, dir ); + if ( s < 500 ) { + // don't play the event sound again if we are in a fat trigger + BG_AddPredictableEventToPlayerstate( EV_JUMP_PAD, 0, &cg.predictedPlayerState ); + } + VectorCopy( ent->origin2, cg.predictedPlayerState.velocity ); } } - - // if we didn't touch a jump pad this pmove frame - if ( cg.predictedPlayerState.jumppad_frame != cg.predictedPlayerState.pmove_framecount ) { - cg.predictedPlayerState.jumppad_frame = 0; - cg.predictedPlayerState.jumppad_ent = 0; - } } - /* ================= CG_PredictPlayerState @@ -415,6 +486,7 @@ void CG_PredictPlayerState( void ) { qboolean moved; usercmd_t oldestCmd; usercmd_t latestCmd; + char temp_string[200]; cg.hyperspace = qfalse; // will be set if touching a trigger_teleport @@ -424,6 +496,11 @@ void CG_PredictPlayerState( void ) { if ( !cg.validPPS ) { cg.validPPS = qtrue; cg.predictedPlayerState = cg.snap->ps; + // if we need to, we should check our model cvar and update it with the right value from the userinfo strings + // since it may have been modified by the server + Com_sprintf(temp_string, sizeof(temp_string), "%s/%s/%s", cgs.clientinfo[cg.predictedPlayerState.clientNum].charName, cgs.clientinfo[cg.predictedPlayerState.clientNum].modelName, + cgs.clientinfo[cg.predictedPlayerState.clientNum].skinName); + updateSkin(cg.predictedPlayerState.clientNum, temp_string); } @@ -443,16 +520,22 @@ void CG_PredictPlayerState( void ) { cg_pmove.ps = &cg.predictedPlayerState; cg_pmove.trace = CG_Trace; cg_pmove.pointcontents = CG_PointContents; + + cg_pmove.admin = cgs.clientinfo[cg.snap->ps.clientNum].isAdmin; + cg_pmove.medic = cgs.classData[cgs.clientinfo[cg.snap->ps.clientNum].pClass].isMedic; + cg_pmove.borg = cgs.classData[cgs.clientinfo[cg.snap->ps.clientNum].pClass].isBorg; + if ( cg_pmove.ps->pm_type == PM_DEAD ) { cg_pmove.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY; } else { cg_pmove.tracemask = MASK_PLAYERSOLID; } - if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) { + if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR /*|| (cg.snap->ps.eFlags&EF_ELIMINATED)*/ ) { cg_pmove.tracemask &= ~CONTENTS_BODY; // spectators can fly through bodies } cg_pmove.noFootsteps = ( cgs.dmflags & DF_NO_FOOTSTEPS ) > 0; + cg_pmove.pModDisintegration = cgs.pModDisintegration > 0; // save the state before the pmove so we can detect transitions oldPlayerState = cg.predictedPlayerState; @@ -487,26 +570,12 @@ void CG_PredictPlayerState( void ) { cg.physicsTime = cg.snap->serverTime; } - if ( pmove_msec.integer < 8 ) { - trap_Cvar_Set("pmove_msec", "8"); - } - else if (pmove_msec.integer > 33) { - trap_Cvar_Set("pmove_msec", "33"); - } - - cg_pmove.pmove_fixed = pmove_fixed.integer;// | cg_pmove_fixed.integer; - cg_pmove.pmove_msec = pmove_msec.integer; - // run cmds moved = qfalse; for ( cmdNum = current - CMD_BACKUP + 1 ; cmdNum <= current ; cmdNum++ ) { // get the command trap_GetUserCmd( cmdNum, &cg_pmove.cmd ); - if ( cg_pmove.pmove_fixed ) { - PM_UpdateViewAngles( cg_pmove.ps, &cg_pmove.cmd ); - } - // don't do anything if the time is before the snapshot player time if ( cg_pmove.cmd.serverTime <= cg.predictedPlayerState.commandTime ) { continue; @@ -517,6 +586,14 @@ void CG_PredictPlayerState( void ) { continue; } + /*if (cg.predictedPlayerState.introTime > cg.time) //what's this for? TiM: I think it's for the holoIntro... + { + cg_pmove.cmd.buttons = 0; + cg_pmove.cmd.weapon = 0; +// cg_pmove.cmd.angles[0] = cg_pmove.cmd.angles[1] = cg_pmove.cmd.angles[2] = 0; + cg_pmove.cmd.forwardmove = cg_pmove.cmd.rightmove = cg_pmove.cmd.upmove = 0; + }*/ + // check for a prediction error from last frame // on a lan, this will often be the exact value // from the snapshot, but on a wan we will have @@ -571,23 +648,12 @@ void CG_PredictPlayerState( void ) { } } - // don't predict gauntlet firing, which is only supposed to happen - // when it actually inflicts damage - cg_pmove.gauntletHit = qfalse; - - if ( cg_pmove.pmove_fixed ) { - cg_pmove.cmd.serverTime = ((cg_pmove.cmd.serverTime + pmove_msec.integer-1) / pmove_msec.integer) * pmove_msec.integer; - } - Pmove (&cg_pmove); moved = qtrue; // add push trigger movement effects CG_TouchTriggerPrediction(); - - // check for predictable events that changed from previous predictions - //CG_CheckChangedPredictableEvents(&cg.predictedPlayerState); } if ( cg_showmiss.integer > 1 ) { @@ -615,12 +681,13 @@ void CG_PredictPlayerState( void ) { // fire events and other transition triggered things CG_TransitionPlayerState( &cg.predictedPlayerState, &oldPlayerState ); - if ( cg_showmiss.integer ) { +/* if ( cg_showmiss.integer ) { if (cg.eventSequence > cg.predictedPlayerState.eventSequence) { CG_Printf("WARNING: double event\n"); cg.eventSequence = cg.predictedPlayerState.eventSequence; } } +*/ } diff --git a/code/cgame/cg_public.h b/code/cgame/cg_public.h index 0dd3b9d..3477d64 100644 --- a/code/cgame/cg_public.h +++ b/code/cgame/cg_public.h @@ -1,27 +1,11 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -This file is part of Quake III Arena source code. -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ + +// Copyright (C) 1999-2000 Id Software, Inc. // - #define CMD_BACKUP 64 #define CMD_MASK (CMD_BACKUP - 1) // allow a lot of command backups for very fast systems @@ -53,13 +37,6 @@ typedef struct { int serverCommandSequence; // snapshot becomes current } snapshot_t; -enum { - CGAME_EVENT_NONE, - CGAME_EVENT_TEAMMENU, - CGAME_EVENT_SCOREBOARD, - CGAME_EVENT_EDITHUD -}; - /* ================================================================== @@ -69,8 +46,9 @@ functions imported from the main executable ================================================================== */ -#define CGAME_IMPORT_API_VERSION 4 +#define CGAME_IMPORT_API_VERSION 3 +//these must match up with cg_syscalls.asm typedef enum { CG_PRINT, CG_ERROR, @@ -133,7 +111,7 @@ typedef enum { CG_MEMORY_REMAINING, CG_R_REGISTERSHADER3D, //59 CG_CVAR_SET_NO_MODIFY, // 60 - CG_R_REMAP_SHADER, + CG_R_REMAP_SHADER, CG_MEMSET = 100, CG_MEMCPY, @@ -147,6 +125,8 @@ typedef enum { CG_TESTPRINTINT, CG_TESTPRINTFLOAT, } cgameImport_t; +//these must match up with cg_syscalls.asm + /* @@ -159,7 +139,7 @@ functions exported to the main executable typedef enum { CG_INIT, -// void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum ) +// void CG_Init( int serverMessageNum, int serverCommandSequence ) // called when the level loads or when the renderer is restarted // all media should be registered at this time // cgame will display loading status by calling SCR_Update, which @@ -186,7 +166,7 @@ typedef enum { CG_CROSSHAIR_PLAYER, // int (*CG_CrosshairPlayer)( void ); - CG_LAST_ATTACKER, + CG_LAST_ATTACKER // int (*CG_LastAttacker)( void ); } cgameExport_t; diff --git a/code/cgame/cg_scoreboard.c b/code/cgame/cg_scoreboard.c index 34935fe..a309b15 100644 --- a/code/cgame/cg_scoreboard.c +++ b/code/cgame/cg_scoreboard.c @@ -1,63 +1,65 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // // cg_scoreboard -- draw the scoreboard on top of the game screen #include "cg_local.h" +#include "cg_text.h" -#define SCOREBOARD_X (0) +#define SCOREBOARD_X (37) //Before RPG-X: (13) //(53) -#define SB_HEADER 86 +//Header info of scoreboard +#define SB_HEADER 40 //Before RPG-X: 105 //40 #define SB_TOP (SB_HEADER+32) +#define SB_HEADERTEXT (SB_HEADER + 8) +#define SB_TOPLINE_LENGTH 550 //Before RPG-X: 590 //530 // Where the status bar starts, so we don't overwrite it #define SB_STATUSBAR 420 -#define SB_NORMAL_HEIGHT 40 -#define SB_INTER_HEIGHT 16 // interleaved height +//Scoreboard height +#define SB_NORMAL_HEIGHT_BIG 14 //RPG-X: RedTechie - Spacing between names +#define SB_NORMAL_HEIGHT 22 +#define SB_INTER_HEIGHT 16 //interleaved height +#define SB_RPG_X_FIXHEIGHT 350 //RPG-X: RedTechie - Fixed background height 350 before new health bar +#define SB_MAXCLIENTS_BIG ((SB_STATUSBAR - SB_TOP) / SB_NORMAL_HEIGHT_BIG) #define SB_MAXCLIENTS_NORMAL ((SB_STATUSBAR - SB_TOP) / SB_NORMAL_HEIGHT) #define SB_MAXCLIENTS_INTER ((SB_STATUSBAR - SB_TOP) / SB_INTER_HEIGHT - 1) // Used when interleaved - - - #define SB_LEFT_BOTICON_X (SCOREBOARD_X+0) -#define SB_LEFT_HEAD_X (SCOREBOARD_X+32) +#define SB_LEFT_HEAD_X (SCOREBOARD_X+12) #define SB_RIGHT_BOTICON_X (SCOREBOARD_X+64) #define SB_RIGHT_HEAD_X (SCOREBOARD_X+96) + // Normal -#define SB_BOTICON_X (SCOREBOARD_X+32) -#define SB_HEAD_X (SCOREBOARD_X+64) +#define SB_BOTICON_X (SCOREBOARD_X+10) //Before RPG-X - This is for positioning of class icon: (SCOREBOARD_X+20) +#define SB_HEAD_X (SCOREBOARD_X+10) //Before RPG-X - This is for positioning of head icon: (SCOREBOARD_X+50) -#define SB_SCORELINE_X 112 +//Intermission text alignment +#define SB_SCORELINE_X (SCOREBOARD_X + 76) +#define SB_CHAR_WIDTH 8 +#define SB_NAME_X (SB_SCORELINE_X + 12) +#define SB_SCORE_X (SB_SCORELINE_X + 112) +#define SB_KILLEDCNT_X (SB_SCORELINE_X + 155) +#define SB_TIME_X (SB_SCORELINE_X + 212) +#define SB_PING_X (SB_SCORELINE_X + 251) +#define SB_WORSTENEMY_X (SB_SCORELINE_X + 294) +#define SB_FAVEWEAPON_X (SB_SCORELINE_X + 398) -#define SB_RATING_WIDTH (6 * BIGCHAR_WIDTH) // width 6 -#define SB_SCORE_X (SB_SCORELINE_X + BIGCHAR_WIDTH) // width 6 -#define SB_RATING_X (SB_SCORELINE_X + 6 * BIGCHAR_WIDTH) // width 6 -#define SB_PING_X (SB_SCORELINE_X + 12 * BIGCHAR_WIDTH + 8) // width 5 -#define SB_TIME_X (SB_SCORELINE_X + 17 * BIGCHAR_WIDTH + 8) // width 5 -#define SB_NAME_X (SB_SCORELINE_X + 22 * BIGCHAR_WIDTH) // width 15 +#define SB_FAVETARGET_X (SB_SCORELINE_X + 182) + +//Scoreboard text alignment +#define SB_SCORELINE_X_BIG ( SCOREBOARD_X /*+ 13*/ ) //Before RPG-X: - This is the first leading space in the score line (SCOREBOARD_X + 125) +#define SB_RANK_X_BIG ( SB_SCORELINE_X_BIG + 6 ) //Before RPG-X: (SB_SCORELINE_X_BIG + 6) = 43 +#define SB_RPGCLASS_X_BIG ( SB_RANK_X_BIG + 78 ) //70 = 121 +#define SB_NAME_X_BIG ( SB_RPGCLASS_X_BIG + 46 ) //132 = 167 +#define SB_LOC_X_BIG ( SB_NAME_X_BIG + 188 ) +#define SB_SCORE_X_BIG ( SB_LOC_X_BIG + 148 ) //405 = 464 //335 //332 +#define SB_TIME_X_BIG ( SB_SCORE_X_BIG + 44 ) // = 493 +#define SB_PING_X_BIG ( SB_TIME_X_BIG + 35 ) //491 = 528 + +#define AWARD_Y 50 // height of awards medals on screen // The new and improved score board // @@ -72,158 +74,887 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA static qboolean localClient; // true if local client has been displayed +static void CG_ClipString(char *buffer,char *name,int pixelCnt,int font) +{ + char str[2]; + int length; - /* -================= -CG_DrawScoreboard -================= + str[1] = '\0'; + + length = 0; + while (*name) + { + str[0] = *name; + length += UI_ProportionalStringWidth(str,font ); + + if (font == UI_TINYFONT) + { + length += PROP_GAP_TINY_WIDTH; + } + else + { + length += PROP_GAP_WIDTH; + } + + if (length > pixelCnt) + { + *buffer = '\0'; + return; + } + else + { + *buffer = *name; + } + name++; + buffer++; + } + *buffer = '\0'; +} + +/* +#define crewman 1 +#define cadet1 2 +#define cadet2 4 +#define cadet3 8 +#define cadet4 16 +#define ensign 32 +#define ltjg 64 +#define lt 128 +#define ltcmdr 256 +#define cmdr 512 +#define cpt 1024 +#define cmmdr 2048 +#define adm2 4096 +#define adm3 8192 +#define adm4 16384 +#define adm5 32768 */ -static void CG_DrawClientScore( int y, score_t *score, float *color, float fade, qboolean largeFormat ) { - char string[1024]; - vec3_t headAngles; - clientInfo_t *ci; - int iconx, headx; - if ( score->client < 0 || score->client >= cgs.maxclients ) { - Com_Printf( "Bad score->client: %i\n", score->client ); - return; +//Modified by TiM for the new rank system +static void CG_DrawRank(int x, int y, pclass_t pClass, int score) { + int classno; + int score_log; + rankMenuData_t* ScoreMenuData; + + //Q_log2 + if ( ( score_log = score ) < 0 ) { //The log function takes the score and turns it into a useful + score_log = 0; //array value: ie 1024 -> 10. :) Hoorah for logarithms! } + classno = cgs.classData[pClass].iconColor-1; + + /*if ( !Q_stricmp( cgs.classData[pClass].iconColor, "r" ) ) { + classno = CLR_RED; + } + else if ( !Q_stricmp( cgs.classData[pClass].iconColor, "y" ) ) { + classno = CLR_GOLD; + } + else if ( !Q_stricmp( cgs.classData[pClass].iconColor, "t" ) ) { + classno = CLR_TEAL; + } + else if ( !Q_stricmp( cgs.classData[pClass].iconColor, "g" ) ) { + classno = CLR_GREEN; + } + else + classno = -1;*/ + + //based on class, choose our right color. + /*switch(pClass) + { + //Redshirt... heh heh + case PC_COMMAND: + case PC_ADMIN: + classno = CLR_RED; + break; + + //Yellowshirt + case PC_SECURITY: + case PC_ENGINEER: + classno = CLR_GOLD; + break; + + //Blueshirt + case PC_MEDICAL: + case PC_SCIENCE: + classno = CLR_TEAL; + break; + + //Marine + case PC_ALPHAOMEGA22: + classno = CLR_GREEN; + break; + + //N/A + case PC_NOCLASS: + case PC_N00B: + case PC_ALIEN: + default: + { + classno = -1; + //CG_DrawPic(x, y, 65, 14, cgs.media.ri_Civ ); + //return; + } + } */ + + //CG_Printf( "%i\n", classno ); + + //if we have a valid class and/or color + if ( classno >= 0 && cgs.ranksData[score_log].rankMenuData[classno].graphic ) { + ScoreMenuData = &cgs.ranksData[score_log].rankMenuData[classno]; + } + else { //else use our default data + ScoreMenuData = &cgs.defaultRankData.rankMenuData; + } + + //Finally, render our rank using the carefully crafted trap_R_DrawStretchPic API function :) + CG_DrawStretchPic( x, y, ScoreMenuData->w, ScoreMenuData->h, + (float)ScoreMenuData->s1/(float)ScoreMenuData->gWidth, + (float)ScoreMenuData->t1/(float)ScoreMenuData->gHeight, + (float)ScoreMenuData->s2/(float)ScoreMenuData->gWidth, + (float)ScoreMenuData->t2/(float)ScoreMenuData->gHeight, + ScoreMenuData->graphic ); + + + /*switch(score) + { + default: + case crewman: CG_DrawPic(x, y, 65, 14, cgs.media.ri_Crewman[classno] ); break; + case cadet1: CG_DrawPic(x, y, 65, 14, cgs.media.ri_Cadet1[classno] ); break; + case cadet2: CG_DrawPic(x, y, 65, 14, cgs.media.ri_Cadet2[classno] ); break; + case cadet3: CG_DrawPic(x, y, 65, 14, cgs.media.ri_Cadet3[classno] ); break; + case cadet4: CG_DrawPic(x, y, 65, 14, cgs.media.ri_Cadet4[classno] ); break; + case ensign: CG_DrawPic(x, y, 65, 14, cgs.media.ri_Ensign[classno]); break; + case ltjg: CG_DrawPic(x, y, 65, 14, cgs.media.ri_Ltjg[classno]); break; + case lt: CG_DrawPic(x, y, 65, 14, cgs.media.ri_Lt[classno]); break; + case ltcmdr: CG_DrawPic(x, y, 65, 14, cgs.media.ri_Ltcmdr[classno]); break; + case cmdr: CG_DrawPic(x, y, 65, 14, cgs.media.ri_Cmdr[classno]); break; + case cpt: CG_DrawPic(x, y, 65, 14, cgs.media.ri_Capt[classno]); break; + case cmmdr: CG_DrawPic(x, y, 65, 14, cgs.media.ri_Cmmdr[classno]); break; + case adm2: CG_DrawPic(x, y, 65, 14, cgs.media.ri_Admr2[classno]); break; + case adm3: CG_DrawPic(x, y, 65, 14, cgs.media.ri_Admr3[classno]); break; + case adm4: CG_DrawPic(x, y, 65, 14, cgs.media.ri_Admr4[classno]); break; + case adm5: CG_DrawPic(x, y, 65, 14, cgs.media.ri_Admr5[classno]); break; + }*/ +} + +static qboolean AW_Draw( void ); +/* +======================= +CG_DrawClientScoreboard_Big +======================= +*/ +static void CG_DrawClientScore_Big( int y, score_t *score, float *color, float fade, qboolean largeFormat ) { + char string[1024]; + char string2[1024]; + //RPG-X: Not Needed without a head + //vec3_t headAngles; + clientInfo_t *ci; + int picSize; + float hcolor[4]; + char *rpg_class; + vec4_t rpg_color; + vec_t *ping_txtcolor = NULL; + int intClamp; + ci = &cgs.clientinfo[score->client]; - iconx = SB_BOTICON_X + (SB_RATING_WIDTH / 2); - headx = SB_HEAD_X + (SB_RATING_WIDTH / 2); + // Black background + /*if (cgs.gametype < GT_TEAM) + { + hcolor[0] = 0; + hcolor[1] = 0; + hcolor[2] = 0; + hcolor[3] = fade * 0.7; + + if (cg.numScores > SB_MAXCLIENTS_BIG) + { + //CG_FillRect( SCOREBOARD_X, y,SB_TOPLINE_LENGTH , SB_NORMAL_HEIGHT+20, hcolor ); + } + else + { + //CG_FillRect( SCOREBOARD_X, y,SB_TOPLINE_LENGTH , SB_NORMAL_HEIGHT_BIG+200, hcolor ); + } + }*/ + //RPG-X: RedTechie - Side Strips + CG_FillRect( SCOREBOARD_X-15, SB_HEADER+20, 15, SB_RPG_X_FIXHEIGHT-4, colorTable[CT_DKBLUE1] ); //RPG-X: RedTechie - Left Strip + CG_FillRect( SB_TOPLINE_LENGTH+53, SB_HEADER+20, 15, SB_RPG_X_FIXHEIGHT-4, colorTable[CT_DKBLUE1] ); //RPG-X: RedTechie - Right Strip + + picSize = (SB_NORMAL_HEIGHT_BIG * .75); // draw the handicap or bot skill marker (unless player has flag) - if ( ci->powerups & ( 1 << PW_NEUTRALFLAG ) ) { - if( largeFormat ) { - CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_FREE, qfalse ); - } - else { - CG_DrawFlagModel( iconx, y, 16, 16, TEAM_FREE, qfalse ); - } - } else if ( ci->powerups & ( 1 << PW_REDFLAG ) ) { - if( largeFormat ) { - CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_RED, qfalse ); - } - else { - CG_DrawFlagModel( iconx, y, 16, 16, TEAM_RED, qfalse ); - } - } else if ( ci->powerups & ( 1 << PW_BLUEFLAG ) ) { - if( largeFormat ) { - CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_BLUE, qfalse ); - } - else { - CG_DrawFlagModel( iconx, y, 16, 16, TEAM_BLUE, qfalse ); - } - } else { - if ( ci->botSkill > 0 && ci->botSkill <= 5 ) { - if ( cg_drawIcons.integer ) { - if( largeFormat ) { - CG_DrawPic( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, cgs.media.botSkillShaders[ ci->botSkill - 1 ] ); - } - else { - CG_DrawPic( iconx, y, 16, 16, cgs.media.botSkillShaders[ ci->botSkill - 1 ] ); + //RPG-X: RedTechie - Dont need this in RPG + /*if ( ci->powerups & ( 1 << PW_REDFLAG ) ) + { + CG_DrawFlagModel( SB_BOTICON_X, y, picSize, picSize, TEAM_RED ); + } + else if ( ci->powerups & ( 1 << PW_BORG_ADAPT ) ) + { + CG_DrawFlagModel( SB_BOTICON_X, y, picSize, picSize, TEAM_BLUE ); + } + else + { + if ( ci->pClass > PC_NOCLASS ) + { + qhandle_t icon; + //Special hack: if it's Borg who has regen going, must be Borg queen + if ( ci->pClass == PC_BORG && (ci->powerups&(1<pClass > PC_NOCLASS ) + //{ + //icon = cgs.media.pClassShaders[ci->pClass]; + //RPG-X: RedTechie - New class output + //VectorSet( rpg_color, 1.0, 1.0, 1.0 ); + + rpg_class = cgs.classData[ci->pClass].formalName; + rpg_color[0] = (float)cgs.classData[ci->pClass].radarColor[0] / 255.0f; + rpg_color[1] = (float)cgs.classData[ci->pClass].radarColor[1] / 255.0f; + rpg_color[2] = (float)cgs.classData[ci->pClass].radarColor[2] / 255.0f; + rpg_color[3] = 1.0f; + + /*switch(ci->pClass){ + case PC_COMMAND: + rpg_class = va("COMMAND"); + //VectorSet( rpg_color, 0.604, 0, 0 ); + rpg_color = colorTable[CT_RED]; + break; + case PC_SECURITY: + rpg_class = va("SECURITY"); + //VectorSet( rpg_color, 0.761, 0.537, 0.024 ); + rpg_color = colorTable[CT_YELLOW]; + break; + case PC_MEDICAL: + rpg_class = va("MEDICAL"); + //VectorSet( rpg_color, 0.082, 0.337, 0.357 ); + rpg_color = colorTable[CT_BLUE]; + break; + case PC_ADMIN: + rpg_class = va("ADMIN"); + rpg_color = colorTable[CT_LTORANGE]; + //VectorCopy( colorTable[CT_LTORANGE], rpg_color ); + break; + case PC_N00B: + rpg_class = va("N00b"); + rpg_color = colorTable[CT_LTORANGE]; + //VectorCopy( colorTable[CT_LTORANGE], rpg_color ); + break; + case PC_SCIENCE: + rpg_class = va("SCIENCE"); + rpg_color = colorTable[CT_BLUE]; + //VectorSet( rpg_color, 0.082, 0.337, 0.357 ); + break; + case PC_ENGINEER: + rpg_class = va("ENGINEER"); + rpg_color = colorTable[CT_YELLOW]; + //VectorSet( rpg_color, 0.761, 0.537, 0.024 ); + break; + case PC_ALIEN: + rpg_class = va("ALIEN"); + rpg_color = colorTable[CT_LTORANGE]; + //VectorCopy( colorTable[CT_LTORANGE], rpg_color ); + break; + case PC_ALPHAOMEGA22: + rpg_class = va("MARINE"); + rpg_color = colorTable[CT_GREEN]; + //VectorSet( rpg_color, 0.012, 0.443, 0.047 ); + break; + case PC_NOCLASS: + rpg_class = va(""); + rpg_color = colorTable[CT_WHITE]; + //VectorCopy( colorTable[CT_WHITE], rpg_color ); + break; + }*/ + //rpg_color[3] = 1.0f; //100% alpha + //} + + //} + //RPG-X: RedTechie - Dont need this in RPG + /*else if ( ci->botSkill > 0 && ci->botSkill <= 5 ) + { + if ( cg_drawIcons.integer ) + { + CG_DrawPic( SB_BOTICON_X, y, picSize, picSize, cgs.media.botSkillShaders[ ci->botSkill - 1 ] ); } - } else if ( ci->handicap < 100 ) { + } + else if ( ci->handicap < 100 ) + { Com_sprintf( string, sizeof( string ), "%i", ci->handicap ); if ( cgs.gametype == GT_TOURNAMENT ) - CG_DrawSmallStringColor( iconx, y - SMALLCHAR_HEIGHT/2, string, color ); + { +// CG_DrawSmallStringColor( iconx, y - SMALLCHAR_HEIGHT/2, string, color ); + UI_DrawProportionalString( SB_BOTICON_X, y - SMALLCHAR_HEIGHT/2, string, UI_SMALLFONT, color); + } else - CG_DrawSmallStringColor( iconx, y, string, color ); + { +// CG_DrawSmallStringColor( iconx, y, string, color ); + UI_DrawProportionalString( SB_BOTICON_X, y , string, UI_SMALLFONT, color); + } } // draw the wins / losses if ( cgs.gametype == GT_TOURNAMENT ) { Com_sprintf( string, sizeof( string ), "%i/%i", ci->wins, ci->losses ); - if( ci->handicap < 100 && !ci->botSkill ) { - CG_DrawSmallStringColor( iconx, y + SMALLCHAR_HEIGHT/2, string, color ); + if( ci->handicap < 100 && !ci->botSkill ) + { +// CG_DrawSmallStringColor( iconx, y + SMALLCHAR_HEIGHT/2, string, color ); + UI_DrawProportionalString( SB_BOTICON_X, y + SMALLCHAR_HEIGHT/2 , string, UI_SMALLFONT, color); } - else { - CG_DrawSmallStringColor( iconx, y, string, color ); + else + { +// CG_DrawSmallStringColor( iconx, y, string, color ); + UI_DrawProportionalString( SB_BOTICON_X, y , string, UI_SMALLFONT, color); } } - } - + }*/ + //RPG-X: No face needed in new scoreboard // draw the face - VectorClear( headAngles ); - headAngles[YAW] = 180; - if( largeFormat ) { - CG_DrawHead( headx, y - ( ICON_SIZE - BIGCHAR_HEIGHT ) / 2, ICON_SIZE, ICON_SIZE, - score->client, headAngles ); - } - else { - CG_DrawHead( headx, y, 16, 16, score->client, headAngles ); - } - -#ifdef MISSIONPACK - // draw the team task - if ( ci->teamTask != TEAMTASK_NONE ) { - if ( ci->teamTask == TEAMTASK_OFFENSE ) { - CG_DrawPic( headx + 48, y, 16, 16, cgs.media.assaultShader ); - } - else if ( ci->teamTask == TEAMTASK_DEFENSE ) { - CG_DrawPic( headx + 48, y, 16, 16, cgs.media.defendShader ); - } - } -#endif - // draw the score line - if ( score->ping == -1 ) { - Com_sprintf(string, sizeof(string), - " connecting %s", ci->name); - } else if ( ci->team == TEAM_SPECTATOR ) { - Com_sprintf(string, sizeof(string), - " SPECT %3i %4i %s", score->ping, score->time, ci->name); - } else { - Com_sprintf(string, sizeof(string), - "%5i %4i %4i %s", score->score, score->ping, score->time, ci->name); - } - + //VectorClear( headAngles ); + //headAngles[YAW] = 180; + //CG_DrawHead( SB_HEAD_X, y, picSize, picSize, score->client, headAngles ); + + // highlight your position - if ( score->client == cg.snap->ps.clientNum ) { - float hcolor[4]; + if ( score->client == cg.snap->ps.clientNum ) + { int rank; localClient = qtrue; if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR - || cgs.gametype >= GT_TEAM ) { + || cgs.gametype >= GT_TEAM ) + { rank = -1; - } else { + } + else + { rank = cg.snap->ps.persistant[PERS_RANK] & ~RANK_TIED_FLAG; } - if ( rank == 0 ) { + if ( rank == 0 ) + { hcolor[0] = 0; hcolor[1] = 0; - hcolor[2] = 0.7f; - } else if ( rank == 1 ) { - hcolor[0] = 0.7f; + hcolor[2] = 0.7; + } + else if ( rank == 1 ) + { + hcolor[0] = 0.7; hcolor[1] = 0; hcolor[2] = 0; - } else if ( rank == 2 ) { - hcolor[0] = 0.7f; - hcolor[1] = 0.7f; + } + else if ( rank == 2 ) + { + hcolor[0] = 0.7; + hcolor[1] = 0.7; hcolor[2] = 0; - } else { - hcolor[0] = 0.7f; - hcolor[1] = 0.7f; - hcolor[2] = 0.7f; + } + else + { + hcolor[0] = 0.7; + hcolor[1] = 0.7; + hcolor[2] = 0.7; } hcolor[3] = fade * 0.7; - CG_FillRect( SB_SCORELINE_X + BIGCHAR_WIDTH + (SB_RATING_WIDTH / 2), y, - 640 - SB_SCORELINE_X - BIGCHAR_WIDTH, BIGCHAR_HEIGHT+1, hcolor ); + //RPG-X: RedTechie No highlighting player info in rpg + /* CG_FillRect( SB_SCORELINE_X_BIG - SMALLCHAR_WIDTH, y, + SB_TOPLINE_LENGTH - ((SB_SCORELINE_X_BIG - SMALLCHAR_WIDTH) - SCOREBOARD_X), BIGCHAR_HEIGHT+1, hcolor ); + */ } - CG_DrawBigString( SB_SCORELINE_X + (SB_RATING_WIDTH / 2), y, string, fade ); - // add the "ready" marker for intermission exiting - if ( cg.snap->ps.stats[ STAT_CLIENTS_READY ] & ( 1 << score->client ) ) { - CG_DrawBigStringColor( iconx, y, "READY", color ); + // draw the score line + //RPG-X: Redtechie - Ping color + if(score->ping >= 501){ + ping_txtcolor = colorTable[CT_RED]; + }else if(score->ping >= 230){ + ping_txtcolor = colorTable[CT_DKRED1]; + }else if(score->ping >= 118){ + ping_txtcolor = colorTable[CT_YELLOW]; + }else if(score->ping <= 117){ + ping_txtcolor = colorTable[CT_WHITE]; } + + //TiM : Re-structured slightly for lesser redundancy. + //Player is connecting + if ( score->ping == -1 ) { + Com_sprintf(string,sizeof(string),"(%s)%s",ingame_text[IGT_CONNECTING],ci->name); + UI_DrawProportionalString( SB_NAME_X_BIG, y , string, UI_TINYFONT, colorTable[CT_WHITE]); + } + else { + int clipLength; + + //draw rank image + CG_DrawRank( SB_RANK_X_BIG, y-2,ci->pClass, score->score); + + //draw player class name + if(rpg_class){ + UI_DrawProportionalString( SB_RPGCLASS_X_BIG, y , rpg_class, UI_TINYFONT | UI_LEFT, rpg_color); //CT_VLTPURPLE1 CT_WHITE + } + + //if we have locations, change the cliplength of the name field + if ( cgs.locations ) { + clipLength = 185; + } + else { + clipLength = 327; + } + + //draw player name with varying instances + //If spect, concat a spect msg next to it + if ( ci->team == TEAM_SPECTATOR ) { + Com_sprintf(string,sizeof(string),"(%s)%s",ingame_text[IGT_SPECTABBREV],ci->name); + CG_ClipString(string2,string,clipLength,UI_TINYFONT); //RPG-X ADDED: RedTechie - 200 pixels in the name column use to be 184 + UI_DrawProportionalString( SB_NAME_X_BIG, y , string2, UI_TINYFONT | UI_LEFT, colorTable[CT_WHITE]); + } + //if lagged out, add a lagged out msg + else if ( score->ping >= 827 ) + { + Com_sprintf(string,sizeof(string),"(%s)%s",ingame_text[IGT_PINGEDOUT],ci->name); + CG_ClipString(string2,string,clipLength,UI_TINYFONT); //RPG-X ADDED: RedTechie - 200 pixels in the name column use to be 184 + UI_DrawProportionalString( SB_NAME_X_BIG, y , string2, UI_TINYFONT | UI_LEFT, colorTable[CT_WHITE]); + } + //else, draw the name normally + else + { + CG_ClipString(string,ci->name,clipLength,UI_TINYFONT); //RPG-X ADDED: RedTechie - 200 pixels in the name column use to be 184 + UI_DrawProportionalString( SB_NAME_X_BIG, y , string, UI_TINYFONT | UI_LEFT, colorTable[CT_WHITE]); + } + + //Player locations + if ( cgs.locations ) { + CG_ClipString(string, va("%s", CG_ConfigString( CS_LOCATIONS + ci->location ) ), 495, UI_TINYFONT); //RPG-X ADDED: RedTechie - 200 pixels in the name column use to be 184 + UI_DrawProportionalString( SB_LOC_X_BIG, y , string, UI_TINYFONT | UI_LEFT, colorTable[CT_WHITE]); + } + + //player client Num + //Com_sprintf(string,sizeof(string), "%i", intClamp); //RPG-X: J2J Switched Scoore to Client No. + intClamp = Com_Clamp( 0, 128, cg_entities[score->client].currentState.clientNum ); + UI_DrawProportionalString( SB_SCORE_X_BIG, y , va("%i", intClamp), UI_TINYFONT | UI_LEFT, colorTable[CT_WHITE]); + + //player time + //If someone actually hits this limit, they officially have no life. + //Com_sprintf(string,sizeof(string),"%i", intClamp); + intClamp = Com_Clamp( 0, 99999, score->time ); + UI_DrawProportionalString( SB_TIME_X_BIG, y , va("%i", intClamp), UI_TINYFONT | UI_LEFT, colorTable[CT_WHITE]); + + //player ping + //Com_sprintf(string,sizeof(string),"%i",score->ping); + intClamp = Com_Clamp( 0, 999, score->ping ); + UI_DrawProportionalString( SB_PING_X_BIG, y, va("%i", intClamp), UI_TINYFONT | UI_LEFT, ping_txtcolor); + + } + + /*//RPG-X: RedTechie - Connecting + if ( score->ping == -1 ) { + Com_sprintf(string,sizeof(string),"(%s)%s",ingame_text[IGT_CONNECTING],ci->name); + UI_DrawProportionalString( SB_NAME_X_BIG, y , string, UI_TINYFONT, colorTable[CT_WHITE]); + } + //J2J Book + //RPG-X: RedTechie - Spectator + + else if ( ci->team == TEAM_SPECTATOR ) + { + Com_sprintf(string,sizeof(string),"(%s)%s",ingame_text[IGT_SPECTABBREV],ci->name); + CG_NamePrep(string2,string,200,UI_TINYFONT); //RPG-X ADDED: RedTechie - 200 pixels in the name column use to be 184 + UI_DrawProportionalString( SB_NAME_X_BIG, y , string2, UI_TINYFONT, colorTable[CT_WHITE]); + if(rpg_class && rpg_color){ + UI_DrawProportionalString( SB_RPGCLASS_X_BIG, y , rpg_class, UI_TINYFONT, rpg_color); //CT_VLTPURPLE1 CT_WHITE + } + Com_sprintf(string,sizeof(string),"%5i",cg_entities[score->client].currentState.clientNum); //RPG-X: J2J Switched Scoore to Client No. + UI_DrawProportionalString( SB_SCORE_X_BIG, y , string, UI_TINYFONT, colorTable[CT_WHITE]); + + Com_sprintf(string,sizeof(string),"%5i",score->time); + UI_DrawProportionalString( SB_TIME_X_BIG, y , string, UI_TINYFONT, colorTable[CT_WHITE]); + + Com_sprintf(string,sizeof(string),"%5i",score->ping); + UI_DrawProportionalString( SB_PING_X_BIG, y, string, UI_TINYFONT, ping_txtcolor); + CG_DrawRank(SB_RANK_X_BIG, y-2,ci->pClass, score->score); + } + //RPG-X: RedTechie - Pinged out + else if ( score->ping >= 827 ) + { + Com_sprintf(string,sizeof(string),"(%s)%s",ingame_text[IGT_PINGEDOUT],ci->name); + CG_NamePrep(string2,string,200,UI_TINYFONT); //RPG-X ADDED: RedTechie - 200 pixels in the name column use to be 184 + UI_DrawProportionalString( SB_NAME_X_BIG, y , string2, UI_TINYFONT, colorTable[CT_WHITE]); + if(rpg_class && rpg_color){ + UI_DrawProportionalString( SB_RPGCLASS_X_BIG, y , rpg_class, UI_TINYFONT, rpg_color); //CT_VLTPURPLE1 CT_WHITE + } + Com_sprintf(string,sizeof(string),"%5i",cg_entities[score->client].currentState.clientNum); //RPG-X: J2J Switched Scoore to Client No. + UI_DrawProportionalString( SB_SCORE_X_BIG, y , string, UI_TINYFONT, colorTable[CT_WHITE]); + + Com_sprintf(string,sizeof(string),"%5i",score->time); + UI_DrawProportionalString( SB_TIME_X_BIG, y , string, UI_TINYFONT, colorTable[CT_WHITE]); + + Com_sprintf(string,sizeof(string),"%5i",score->ping); + UI_DrawProportionalString( SB_PING_X_BIG, y, string, UI_TINYFONT, ping_txtcolor); + CG_DrawRank(SB_RANK_X_BIG, y-2,ci->pClass, score->score); + } + //RPG-X: RedTechie - Regular + else + { + //draw rank image + CG_DrawRank( SB_RANK_X_BIG, y-2,ci->pClass, score->score); + + //draw player class name + if(rpg_class && rpg_color){ + UI_DrawProportionalString( SB_RPGCLASS_X_BIG, y , rpg_class, UI_TINYFONT, rpg_color); //CT_VLTPURPLE1 CT_WHITE + } + + //prep name and then render it + CG_NamePrep(string,ci->name,200,UI_TINYFONT); //RPG-X ADDED: RedTechie - 200 pixels in the name column use to be 184 + UI_DrawProportionalString( SB_NAME_X_BIG, y , string, UI_TINYFONT, colorTable[CT_WHITE]); + + //player client Num + Com_sprintf(string,sizeof(string),"%3i",cg_entities[score->client].currentState.clientNum); //RPG-X: J2J Switched Scoore to Client No. + UI_DrawProportionalString( SB_SCORE_X_BIG, y , string, UI_TINYFONT, colorTable[CT_WHITE]); + + //player time + Com_sprintf(string,sizeof(string),"%5i",score->time); + UI_DrawProportionalString( SB_TIME_X_BIG, y , string, UI_TINYFONT, colorTable[CT_WHITE]); + + //player ping + Com_sprintf(string,sizeof(string),"%3i",score->ping); + UI_DrawProportionalString( SB_PING_X_BIG, y, string, UI_TINYFONT, ping_txtcolor); + }*/ + + //RPG-X: RedTechie - Draw live divider after every client + CG_FillRect( SB_NAME_X_BIG, y+11, SB_TOPLINE_LENGTH-119, 1, colorTable[CT_VDKBLUE2] ); // y off - 10, thickness - 2 //150 + } +/* +======================= +CG_DrawClientScoreboard +======================= +*/ +static void CG_DrawClientScore( int y, score_t *score, float *color, float fade, qboolean largeFormat ) { + //char string[1024]; + //char string2[1024]; + //vec3_t headAngles; + clientInfo_t *ci; + //int picSize; + //char /**worstEnemy,*/*faveWeapon=0; + //float hcolor[4]; + //gitem_t * item; + int inIntermission/*,length*/; + + inIntermission = ( + (cg.snap->ps.pm_type==PM_INTERMISSION) + || (cg.intermissionStarted) + || (cg.predictedPlayerState.pm_type==PM_INTERMISSION) ); + + + if ( score->client < 0 || score->client >= cgs.maxclients ) + { + Com_Printf( "Bad score->client: %i\n", score->client ); + return; + } + + + ci = &cgs.clientinfo[score->client]; + if (!ci->infoValid) + { + Com_Printf( "Bad clientInfo: %i\n", score->client ); + return; + } + + /*trap_R_SetColor( colorTable[CT_DKBLUE1] ); + CG_DrawPic( SCOREBOARD_X-15, y-28, 25, 28, cgs.media.scoreboardtopleft ); //RPG-X: - RedTechie Top Left + CG_DrawPic( SB_TOPLINE_LENGTH+43, y-28, 25, 28, cgs.media.scoreboardtopright ); //RPG-X: - RedTechie Top Right + CG_DrawPic( SCOREBOARD_X-15, y+325, 36, 28, cgs.media.scoreboardbotleft ); //RPG-X: - RedTechie Bottom Left + CG_DrawPic( SB_TOPLINE_LENGTH+32, y+321, 36, 32, cgs.media.scoreboardbotright ); //RPG-X: - RedTechie Bottom Right + */ + //RPG-X: - RedTechie Fixed intermissions scoreboard + if ( !inIntermission ) + { + //RPG-X BOOKMARK + CG_DrawClientScore_Big(y, score, color, fade, largeFormat ); + return; + }else{ + CG_DrawClientScore_Big(y, score, color, fade, largeFormat ); + return; + } + //TiM : From the looks of this, nothing after this is acctually called O_o + //Save graphics then + + // Black background + /*if (cgs.gametype < GT_TEAM) + { + hcolor[0] = 0; + hcolor[1] = 0; + hcolor[2] = 0; + hcolor[3] = fade * 0.7; + CG_FillRect( SCOREBOARD_X, y,SB_TOPLINE_LENGTH , SB_NORMAL_HEIGHT, hcolor ); + }*/ + + // Left Side of scoreboard + //CG_FillRect( SCOREBOARD_X, y - 16 , 12, 48, colorTable[CT_DKORANGE]); + + +/* + picSize = 20; + // draw the handicap or bot skill marker (unless player has flag) + if ( ci->powerups & ( 1 << PW_REDFLAG ) ) + { + CG_DrawFlagModel( SB_BOTICON_X, y, picSize, picSize, TEAM_RED ); + } + else if ( ci->powerups & ( 1 << PW_BORG_ADAPT ) ) + { + CG_DrawFlagModel( SB_BOTICON_X, y, picSize, picSize, TEAM_BLUE ); + } + else + { + if ( ci->botSkill > 0 && ci->botSkill <= 5 ) + { + if ( cg_drawIcons.integer ) + { + CG_DrawPic( SB_BOTICON_X, y+2, picSize, picSize, cgs.media.botSkillShaders[ ci->botSkill - 1 ] ); + } + } + else if ( ci->handicap < 100 ) + { + Com_sprintf( string, sizeof( string ), "%i", ci->handicap ); + if ( cgs.gametype == GT_TOURNAMENT ) + { +// CG_DrawSmallStringColor( iconx, y - SMALLCHAR_HEIGHT/2, string, color ); + UI_DrawProportionalString( SB_BOTICON_X+2, y - SMALLCHAR_HEIGHT/2, string, UI_SMALLFONT, color); + } + else + { +// CG_DrawSmallStringColor( iconx, y, string, color ); + UI_DrawProportionalString( SB_BOTICON_X+2, y , string, UI_SMALLFONT, color); + } + } + + // draw the wins / losses + if ( cgs.gametype == GT_TOURNAMENT ) { + Com_sprintf( string, sizeof( string ), "%i/%i", ci->wins, ci->losses ); + if( ci->handicap < 100 && !ci->botSkill ) + { +// CG_DrawSmallStringColor( iconx, y + SMALLCHAR_HEIGHT/2, string, color ); + UI_DrawProportionalString( SB_BOTICON_X, y + SMALLCHAR_HEIGHT/2 , string, UI_SMALLFONT, color); + } + else + { +// CG_DrawSmallStringColor( iconx, y, string, color ); + UI_DrawProportionalString( SB_BOTICON_X, y , string, UI_SMALLFONT, color); + } + } + }*/ + + // draw the face + /*VectorClear( headAngles ); + headAngles[YAW] = 180; + CG_DrawHead( SB_HEAD_X+14, y, picSize, picSize, score->client, headAngles );//Before RPG-X: CG_DrawHead( SB_HEAD_X+14, y, picSize, picSize, score->client, headAngles ); + + // highlight your position + if ( score->client == cg.snap->ps.clientNum ) + { + int rank; + + localClient = qtrue; + + if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR + || cgs.gametype >= GT_TEAM ) + { + rank = -1; + } + else + { + rank = cg.snap->ps.persistant[PERS_RANK] & ~RANK_TIED_FLAG; + } + if ( rank == 0 ) + { + hcolor[0] = 0; + hcolor[1] = 0; + hcolor[2] = 0.7; + } + else if ( rank == 1 ) + { + hcolor[0] = 0.7; + hcolor[1] = 0; + hcolor[2] = 0; + } + else if ( rank == 2 ) + { + hcolor[0] = 0.7; + hcolor[1] = 0.7; + hcolor[2] = 0; + } + else + { + hcolor[0] = 0.7; + hcolor[1] = 0.7; + hcolor[2] = 0.7; + } + + hcolor[3] = fade * 0.7; + CG_FillRect( SB_SCORELINE_X - TINYCHAR_WIDTH, y, + SB_TOPLINE_LENGTH - ((SB_SCORELINE_X - TINYCHAR_WIDTH) - SCOREBOARD_X), BIGCHAR_HEIGHT+1, hcolor ); + } + + // draw the score line + if ( score->ping == -1 ) { + Com_sprintf(string, sizeof(string), + " connecting %s", ci->name); + UI_DrawProportionalString( SB_SCORELINE_X, y, string, UI_TINYFONT, colorTable[CT_LTGOLD1]); + } + else if ( ci->team == TEAM_SPECTATOR ) + { + CG_NamePrep(string,ci->name,100,UI_TINYFONT); //100 pixels in the name column + + Com_sprintf(string,sizeof(string),"%s (%s)", string, ingame_text[IGT_SPECTATOR]); + UI_DrawProportionalString( SB_NAME_X, y + (TINYCHAR_HEIGHT/2), string, UI_TINYFONT, colorTable[CT_LTGOLD1]); + + // Don't show other stats for Spectators +// Com_sprintf(string,sizeof(string),"%5i",score->score); +// UI_DrawProportionalString( SB_SCORE_X, y + (TINYCHAR_HEIGHT/2), string, UI_TINYFONT, colorTable[CT_YELLOW]); + +// Com_sprintf(string,sizeof(string),"%5i",score->time); +// UI_DrawProportionalString( SB_TIME_X, y + (TINYCHAR_HEIGHT/2), string, UI_TINYFONT, colorTable[CT_LTGOLD1]); + +// Com_sprintf(string,sizeof(string),"%5i",score->ping); +// UI_DrawProportionalString( SB_PING_X, y + (TINYCHAR_HEIGHT/2), string, UI_TINYFONT, colorTable[CT_LTGOLD1]); + +// Com_sprintf(string,sizeof(string),"%5i",score->killedCnt); +// UI_DrawProportionalString( SB_KILLEDCNT_X, y + (TINYCHAR_HEIGHT/2), string, UI_TINYFONT, colorTable[CT_RED]); + } + else + {*/ + /* + if (score->faveTarget >= 0) + { + faveTarget = cgs.clientinfo[score->faveTarget].name; + } + else + { + faveTarget = ingame_text[IGT_NONE]; + } + */ + /*if (score->worstEnemy >= 0) + { + worstEnemy = cgs.clientinfo[score->worstEnemy].name; + } + else + { + worstEnemy = ingame_text[IGT_NONE]; + } + + if (score->faveWeapon > 0) + { + faveWeapon = ingame_text[IGT_NONE]; + // Find weapon + for ( item = bg_itemlist + 1 ; item->classname ; item++ ) + { + if ( item->giType != IT_WEAPON ) { + continue; + } + if (item->giTag == score->faveWeapon) + { + faveWeapon = item->pickup_name; + break; + } + } + } + +// Com_sprintf(string, sizeof(string), +// "%-20s %5i %5i %-20s (%5i) %-20s (%5i)",ci->name, score->score, score->time, +// faveTarget, score->faveTargetKills, +// worstEnemy, score->worstEnemyKills); + + CG_NamePrep(string,ci->name,100,UI_TINYFONT); //100 pixels in the name column + + //RPG-X: J2J (NOTE TO CODERS)- Heading for score board -DO NOT EDIT- Text for these are in mp_ingametext.dat + Com_sprintf(string,sizeof(string),"%5i", score->client); + UI_DrawProportionalString( SB_NAME_X-20, y + (TINYCHAR_HEIGHT/2), string, UI_TINYFONT, colorTable[CT_WHITE]); + + UI_DrawProportionalString( SB_NAME_X, y + (TINYCHAR_HEIGHT/2), string, UI_TINYFONT, colorTable[CT_WHITE]); + Com_sprintf(string,sizeof(string),"%5i",score->score); + UI_DrawProportionalString( SB_SCORE_X, y + (TINYCHAR_HEIGHT/2), string, UI_TINYFONT, colorTable[CT_YELLOW]); + + Com_sprintf(string,sizeof(string),"%5i",score->time); + UI_DrawProportionalString( SB_TIME_X, y + (TINYCHAR_HEIGHT/2), string, UI_TINYFONT, colorTable[CT_LTGOLD1]); + + Com_sprintf(string,sizeof(string),"%5i",score->ping); + UI_DrawProportionalString( SB_PING_X, y + (TINYCHAR_HEIGHT/2), string, UI_TINYFONT, colorTable[CT_LTGOLD1]); + + Com_sprintf(string,sizeof(string),"%5i",score->killedCnt); + UI_DrawProportionalString( SB_KILLEDCNT_X, y + (TINYCHAR_HEIGHT/2), string, UI_TINYFONT, colorTable[CT_RED]); + + if (worstEnemy) + { + Com_sprintf(string2,sizeof(string2)," (%i)",score->worstEnemyKills); + length = UI_ProportionalStringWidth(string2,UI_TINYFONT ); + + CG_NamePrep(string,worstEnemy,(100-length),UI_TINYFONT); //100 pixels in the worst enemy column + + Com_sprintf(string,sizeof(string),"%s%s",string, string2); + UI_DrawProportionalString( SB_WORSTENEMY_X, y + (TINYCHAR_HEIGHT/2), string, UI_TINYFONT, colorTable[CT_RED]); + } + + if (faveWeapon) + { + UI_DrawProportionalString( SB_FAVEWEAPON_X, y + (TINYCHAR_HEIGHT/2), faveWeapon, UI_TINYFONT, colorTable[CT_LTGOLD1]); + } + } + + //CG_DrawSmallString( SB_SCORELINE_X, y, string, fade ); + + // add the "ready" marker for intermission exiting, if not a bot, and if a team type game + if ( inIntermission ) + { + qhandle_t h = trap_R_RegisterShader("icons/icon_ready_on"), + h2 = trap_R_RegisterShader("icons/icon_ready_off"); + if ( ci->botSkill > 0 && ci->botSkill <= 5 ) + { + // i'm a bot. i'm always ready. + trap_R_SetColor( colorTable[CT_VLTGOLD1]); + CG_DrawPic( SB_BOTICON_X+26,y+2, 16, 16,h); + } + else + { + if ( cg.snap->ps.stats[ STAT_CLIENTS_READY ] & ( 1 << score->client ) ) + { + //trap_R_SetColor( colorTable[CT_VLTGOLD1]); + //CG_DrawPic( SB_BOTICON_X+26,y+2, 16, 16,h); + } + else// if (score->client) + { + //trap_R_SetColor( colorTable[CT_VLTGOLD1]); + //CG_DrawPic( SB_BOTICON_X+26,y+2, 16, 16,h2); + } + } + }*/ +} + +/*static int CG_GetTeamCount(team_t team, int maxClients) +{ + int i = 0; + int count = 0; + score_t *score = NULL; + clientInfo_t *ci = NULL; + + for ( i = 0 ; i < cg.numScores && count < maxClients ; i++ ) + { + score = &cg.scores[i]; + ci = &cgs.clientinfo[ score->client ]; + + if ( team!=ci->team || !ci->infoValid ) + { + continue; + } + count++; + } + + return count; +}*/ + /* ================= CG_TeamScoreboard @@ -240,6 +971,7 @@ static int CG_TeamScoreboard( int y, team_t team, float fade, int maxClients, in color[3] = fade; count = 0; + for ( i = 0 ; i < cg.numScores && count < maxClients ; i++ ) { score = &cg.scores[i]; ci = &cgs.clientinfo[ score->client ]; @@ -248,14 +980,52 @@ static int CG_TeamScoreboard( int y, team_t team, float fade, int maxClients, in continue; } - CG_DrawClientScore( y + lineHeight * count, score, color, fade, lineHeight == SB_NORMAL_HEIGHT ); - - count++; + if (ci->infoValid) + { + //RPG-X BOOKMARK + //UI_DrawProportionalString(60,y + lineHeight * count,va("%i",cg_entities[i].currentState.clientNum), UI_TINYFONT, colorTable[CT_LTGOLD1]); + CG_DrawClientScore( y + lineHeight * count, score, color, fade, lineHeight == SB_NORMAL_HEIGHT ); + count++; + } } return count; } +void CG_AddGameModNameToGameName( char *gamename ) +{ + //Primary Mod + if ( cgs.pModElimination ) + { + strcat( gamename, ": " ); + strcat( gamename, ingame_text[IGT_GAME_ELIMINATION] ); + } + else if ( cgs.pModAssimilation ) + { + strcat( gamename, ": " ); + strcat( gamename, ingame_text[IGT_GAME_ASSIMILATION] ); + } + else if ( cgs.pModActionHero ) + { + strcat( gamename, ": " ); + strcat( gamename, ingame_text[IGT_GAME_ACTIONHERO] ); + } + + //Secondary Mod + if ( cgs.pModSpecialties ) + { + strcat( gamename, " (" ); + strcat( gamename, ingame_text[IGT_GAME_SPECIALTIES] ); + strcat( gamename, ")" ); + } + else if ( cgs.pModDisintegration ) + { + strcat( gamename, " (" ); + strcat( gamename, ingame_text[IGT_GAME_DISINTEGRATION] ); + strcat( gamename, ")" ); + } +} + /* ================= CG_DrawScoreboard @@ -263,39 +1033,62 @@ CG_DrawScoreboard Draw the normal in-game scoreboard ================= */ -qboolean CG_DrawOldScoreboard( void ) { - int x, y, w, i, n1, n2; +qboolean CG_DrawScoreboard( void ) +{ + int y, i, n1 = 0, n2 = 0; // n3 = 0; float fade; float *fadeColor; char *s; - int maxClients; - int lineHeight; - int topBorderSize, bottomBorderSize; + //RPG-X: RedTechie dont need buf with all the print team code commented out + //char buf[64]; + int maxClients; + int lineHeight; + int topBorderSize, bottomBorderSize; + int rankOfClient; + int tTeam/*, bTeam*/; + float hcolor[4]; + int inIntermission; + char gamename[1024]; + //int gOffset = 20; - // don't draw amuthing if the menu or console is up - if ( cg_paused.integer ) { - cg.deferredPlayerLoading = 0; + inIntermission = ( + (cg.snap->ps.pm_type==PM_INTERMISSION) + || (cg.intermissionStarted) + || (cg.predictedPlayerState.pm_type==PM_INTERMISSION) ); + + // DO NOT SHOW THE SCOREBOARD IF: + //////////////////////////////////////////////////////////////// + // 1) Menu or Console is Up + if ( cg_paused.integer ) + { cg.deferredPlayerLoading = 0; + return qfalse; } + // + // 2) Awards Ceremony is not finished during Intermisison + if (inIntermission && !AW_Draw()) + { return qfalse; } + // + // 3) If we are doing a warmup + if (cg.warmup && !cg.showScores) + return qfalse; + //RPG-X: RedTechie - Hacked so scoreboard dosnt show when players die + if(cg.predictedPlayerState.pm_type==PM_DEAD){ return qfalse; } - if ( cgs.gametype == GT_SINGLE_PLAYER && cg.predictedPlayerState.pm_type == PM_INTERMISSION ) { - cg.deferredPlayerLoading = 0; - return qfalse; - } - - // don't draw scoreboard during death while warmup up - if ( cg.warmup && !cg.showScores ) { - return qfalse; - } + tTeam = TEAM_RED; // Compiler needed initialization here for some reason... + // FADE SETUP... ?? if ( cg.showScores || cg.predictedPlayerState.pm_type == PM_DEAD || - cg.predictedPlayerState.pm_type == PM_INTERMISSION ) { + inIntermission ) + { fade = 1.0; fadeColor = colorWhite; - } else { + } else + { fadeColor = CG_FadeColor( cg.scoreFadeTime, FADE_TIME ); - if ( !fadeColor ) { + if ( !fadeColor ) + { // next time scoreboard comes up, don't print killer cg.deferredPlayerLoading = 0; cg.killerName[0] = 0; @@ -305,119 +1098,326 @@ qboolean CG_DrawOldScoreboard( void ) { } - // fragged by ... line - if ( cg.killerName[0] ) { - s = va("Fragged by %s", cg.killerName ); - w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; - x = ( SCREEN_WIDTH - w ) / 2; - y = 40; - CG_DrawBigString( x, y, s, fade ); - } + // IN GAME SCOREBOARD HEADER STUFF + //--------------------------------- + rankOfClient = cg.snap->ps.persistant[PERS_RANK]; - // current rank - if ( cgs.gametype < GT_TEAM) { - if (cg.snap->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR ) { - s = va("%s place with %i", - CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ), - cg.snap->ps.persistant[PERS_SCORE] ); - w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; - x = ( SCREEN_WIDTH - w ) / 2; - y = 60; - CG_DrawBigString( x, y, s, fade ); + if ( !inIntermission && cg.snap->ps.persistant[PERS_TEAM]!=TEAM_SPECTATOR) + { + // Display Your Rank / Your Team + //----------------------------------------------- + //RPG-X: RedTechie Dont need this for rpg This code prints out what team your on and if your winning when you call the scoreboard just takes up to much room (i'll probly muck it all up but here it goes + /*if (cgs.gametype<=GT_SINGLE_PLAYER) + { + if (rankOfClient & RANK_TIED_FLAG) + Com_sprintf( buf, sizeof(buf), "%s %i", ingame_text[IGT_TIED_FOR], (rankOfClient&~RANK_TIED_FLAG)+1); + else + Com_sprintf( buf, sizeof(buf), "%s %i", ingame_text[IGT_YOUR_RANK], (rankOfClient&~RANK_TIED_FLAG)+1); + UI_DrawProportionalString( 14, AWARD_Y, buf, UI_BIGFONT|UI_LEFT, colorTable[CT_LTGOLD1] ); } - } else { - if ( cg.teamScores[0] == cg.teamScores[1] ) { - s = va("Teams are tied at %i", cg.teamScores[0] ); - } else if ( cg.teamScores[0] >= cg.teamScores[1] ) { - s = va("Red leads %i to %i",cg.teamScores[0], cg.teamScores[1] ); - } else { - s = va("Blue leads %i to %i",cg.teamScores[1], cg.teamScores[0] ); + if (cgs.gametype>GT_SINGLE_PLAYER) + { + if ( cg.teamScores[0] == cg.teamScores[1] ) + s = va("%s %i", ingame_text[IGT_TEAMSARETIED],cg.teamScores[0] ); + else if ( cg.teamScores[0] >= cg.teamScores[1] ) + s = va("%s %i %s %i",ingame_text[IGT_REDTEAMLEADS],cg.teamScores[0],ingame_text[IGT_TO], cg.teamScores[1] ); + else + s = va("%s %i %s %i",ingame_text[IGT_BLUETEAMLEADS],cg.teamScores[1],ingame_text[IGT_TO], cg.teamScores[0] ); + + UI_DrawProportionalString(14, AWARD_Y, s, UI_BIGFONT|UI_LEFT, colorTable[CT_LTGOLD1]); + }*/ + // Display Who Killed You + //----------------------------------------------- + if ( cg.killerName[0] ) + { + if ( cg.mod == MOD_ASSIMILATE ) + { + s = va("%s %s",ingame_text[IGT_ASSIMILATEDBY], cg.killerName ); + } + else + { + s = va("%s %s",ingame_text[IGT_FRAGGEDBY], cg.killerName ); + } + UI_DrawProportionalString((SCREEN_WIDTH/2), 438, s, UI_BIGFONT|UI_CENTER, colorTable[CT_CYAN]);//RPG-X: - RedTechie Y axis use to be 75 } - - w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; - x = ( SCREEN_WIDTH - w ) / 2; - y = 60; - CG_DrawBigString( x, y, s, fade ); } - // scoreboard y = SB_HEADER; - CG_DrawPic( SB_SCORE_X + (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardScore ); - CG_DrawPic( SB_PING_X - (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardPing ); - CG_DrawPic( SB_TIME_X - (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardTime ); - CG_DrawPic( SB_NAME_X - (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardName ); + // Top of scoreboard + //trap_R_SetColor( colorTable[CT_DKORANGE] ); +// CG_DrawPic( SCOREBOARD_X, y + 27, 16, -32, cgs.media.corner_12_24 ); // Corner +// CG_DrawPic( SCOREBOARD_X, y, 16, 32, cgs.media.corner_12_24 ); // Corner + //RPG-X: Bookmark + //CG_FillRect( SCOREBOARD_X, y, SB_TOPLINE_LENGTH, 24, colorTable[CT_DKORANGE]); + + // Black background + //if (cgs.gametype < GT_TEAM) + //{ + hcolor[0] = 0; + hcolor[1] = 0; + hcolor[2] = 0; + hcolor[3] = fade * 0.7; + //CG_FillRect( SCOREBOARD_X, y + 20,SB_TOPLINE_LENGTH, 12, hcolor ); + //RPG-X: RedTechie - Fixed black background height + CG_FillRect( SCOREBOARD_X, y + 5,SB_TOPLINE_LENGTH + 26, SB_RPG_X_FIXHEIGHT+15, hcolor );//RPG-X: RedTechie - Before CG_FillRect( SCOREBOARD_X, y + 20,SB_TOPLINE_LENGTH, SB_RPG_X_FIXHEIGHT, hcolor ); + //} + + trap_R_SetColor( colorTable[CT_DKBLUE1] ); + CG_DrawPic( SCOREBOARD_X-15, SB_TOP-28, 25, 28, cgs.media.scoreboardtopleft ); //RPG-X: - RedTechie Top Left + CG_DrawPic( SB_TOPLINE_LENGTH+43, SB_TOP-28, 25, 28, cgs.media.scoreboardtopright ); //RPG-X: - RedTechie Top Right + CG_DrawPic( SCOREBOARD_X-15, SB_TOP+325, 36, 28, cgs.media.scoreboardbotleft ); //RPG-X: - RedTechie Bottom Left + CG_DrawPic( SB_TOPLINE_LENGTH+32, SB_TOP+321, 36, 32, cgs.media.scoreboardbotright ); //RPG-X: - RedTechie Bottom Right + +/*#define SB_RANK_X_BIG ( SB_SCORELINE_X_BIG + 6 ) //Before RPG-X: (SB_SCORELINE_X_BIG + 6) = 43 +#define SB_RPGCLASS_X_BIG ( SB_RANK_X_BIG + 78 ) //70 = 121 +#define SB_NAME_X_BIG ( SB_RPGCLASS_X_BIG + 46 ) //132 = 167 +#define SB_LOC_X_BIG ( SB_NAME_X_BIG + 187 ) +#define SB_SCORE_X_BIG ( SB_LOC_X_BIG + 148 ) //405 = 464 //335 //332 +#define SB_TIME_X_BIG ( SB_SCORE_X_BIG + 44 ) // = 493 +#define SB_PING_X_BIG ( SB_TIME_X_BIG + 35 ) //491 = 528*/ + + CG_FillRect( SCOREBOARD_X, y+5, ( SB_RPGCLASS_X_BIG - 5 ) - SCOREBOARD_X, 15, colorTable[CT_DKBLUE1]); //RPG-X: Rank Bar //75 //79 + CG_FillRect( SB_RPGCLASS_X_BIG - 3, y+5, ( SB_NAME_X_BIG - 5 ) - ( SB_RPGCLASS_X_BIG - 3 ), 15, colorTable[CT_DKBLUE1]); //RPG-X: Class Bar //46 - 60 + if ( cgs.locations ) { + CG_FillRect( SB_NAME_X_BIG - 3, y+5, ( SB_LOC_X_BIG - 5 ) - ( SB_NAME_X_BIG - 3 ), 15, colorTable[CT_DKBLUE1]); //RPG-X: Name Bar //269 + CG_FillRect( SB_LOC_X_BIG - 3, y+5, ( SB_SCORE_X_BIG - 5 ) - ( SB_LOC_X_BIG - 3 ), 15, colorTable[CT_DKBLUE1]); //RPG-X: Locations Bar //269 + } + else { + CG_FillRect( SB_NAME_X_BIG - 3, y+5, ( SB_SCORE_X_BIG - 5 ) - ( SB_NAME_X_BIG - 3 ), 15, colorTable[CT_DKBLUE1]); //RPG-X: Name Bar //269 + } + + CG_FillRect( SB_SCORE_X_BIG - 3, y+5, ( SB_TIME_X_BIG - 5 ) - ( SB_SCORE_X_BIG - 3 ), 15, colorTable[CT_DKBLUE1]); //RPG-X: Client ID Bar //47 + CG_FillRect( SB_TIME_X_BIG - 3, y+5, ( SB_PING_X_BIG - 5 ) - ( SB_TIME_X_BIG - 3 ), 15, colorTable[CT_DKBLUE1]); //RPG-X: Time Bar //34 + CG_FillRect( SB_PING_X_BIG - 3, y+5, 602 - ( SB_PING_X_BIG - 3 ), 15, colorTable[CT_DKBLUE1]); //RPG-X: Ping Bar //35 + + //if ( inIntermission ) +// { + // UI_DrawProportionalString( SB_BOTICON_X+26, SB_HEADERTEXT, ingame_text[IGT_READY],UI_TINYFONT, colorTable[CT_BLACK] ); + // UI_DrawProportionalString( SB_NAME_X, SB_HEADERTEXT, ingame_text[IGT_SB_NAME],UI_TINYFONT, colorTable[CT_BLACK] ); + // UI_DrawProportionalString( SB_SCORE_X, SB_HEADERTEXT, ingame_text[IGT_SB_SCORE],UI_TINYFONT, colorTable[CT_BLACK] ); + // UI_DrawProportionalString( SB_TIME_X, SB_HEADERTEXT, ingame_text[IGT_SB_TIME],UI_TINYFONT, colorTable[CT_BLACK] ); + // UI_DrawProportionalString( SB_PING_X, SB_HEADERTEXT, ingame_text[IGT_SB_PING],UI_TINYFONT, colorTable[CT_BLACK] ); + // UI_DrawProportionalString( SB_KILLEDCNT_X, SB_HEADERTEXT,ingame_text[IGT_TITLEELIMINATED],UI_TINYFONT, colorTable[CT_BLACK] ); + // UI_DrawProportionalString( SB_WORSTENEMY_X, SB_HEADERTEXT,ingame_text[IGT_WORSTENEMY],UI_TINYFONT, colorTable[CT_BLACK] ); + // UI_DrawProportionalString( SB_FAVEWEAPON_X, SB_HEADERTEXT,ingame_text[IGT_FAVORITEWEAPON],UI_TINYFONT, colorTable[CT_BLACK] ); + //} + //else + //{ + //RPG-X: RedTechie (Rank BookMark) + UI_DrawProportionalString( SB_RANK_X_BIG, SB_HEADERTEXT, ingame_text[IGT_SB_RANK], UI_TINYFONT | UI_LEFT, colorTable[CT_BLACK] ); + UI_DrawProportionalString( SB_RPGCLASS_X_BIG, SB_HEADERTEXT, ingame_text[IGT_SB_RPGCLASS],UI_TINYFONT | UI_LEFT, colorTable[CT_BLACK] ); + UI_DrawProportionalString( SB_NAME_X_BIG, SB_HEADERTEXT, ingame_text[IGT_SB_NAME], UI_TINYFONT | UI_LEFT, colorTable[CT_BLACK] ); + if ( cgs.locations ) { + UI_DrawProportionalString( SB_LOC_X_BIG, SB_HEADERTEXT, ingame_text[IGT_SB_LOC], UI_TINYFONT | UI_LEFT, colorTable[CT_BLACK] ); + } + UI_DrawProportionalString( SB_SCORE_X_BIG, SB_HEADERTEXT, ingame_text[IGT_SB_SCORE], UI_TINYFONT | UI_LEFT, colorTable[CT_BLACK] ); + UI_DrawProportionalString( SB_TIME_X_BIG, SB_HEADERTEXT, ingame_text[IGT_SB_TIME], UI_TINYFONT | UI_LEFT, colorTable[CT_BLACK] ); + UI_DrawProportionalString( SB_PING_X_BIG, SB_HEADERTEXT, ingame_text[IGT_SB_PING], UI_TINYFONT | UI_LEFT, colorTable[CT_BLACK] ); + //} + + //trap_R_SetColor( colorTable[CT_DKORANGE] ); + //CG_DrawPic( 605, y, 16, 32, cgs.media.scoreboardEndcap ); + + /*trap_R_SetColor( colorTable[CT_DKBLUE1] ); + CG_DrawPic( SCOREBOARD_X-15, y-28, 25, 28, cgs.media.scoreboardtopleft ); //RPG-X: - RedTechie Top Left + CG_DrawPic( SB_TOPLINE_LENGTH+43, y-28, 25, 28, cgs.media.scoreboardtopright ); //RPG-X: - RedTechie Top Right + CG_DrawPic( SCOREBOARD_X-15, y+325, 36, 28, cgs.media.scoreboardbotleft ); //RPG-X: - RedTechie Bottom Left + CG_DrawPic( SB_TOPLINE_LENGTH+32, y+321, 36, 32, cgs.media.scoreboardbotright ); //RPG-X: - RedTechie Bottom Right +*/ y = SB_TOP; - // If there are more than SB_MAXCLIENTS_NORMAL, use the interleaved scores - if ( cg.numScores > SB_MAXCLIENTS_NORMAL ) { - maxClients = SB_MAXCLIENTS_INTER; - lineHeight = SB_INTER_HEIGHT; - topBorderSize = 8; - bottomBorderSize = 16; - } else { + // SET UP SIZES + //-------------- + if ( (inIntermission) || + (cg.numScores>SB_MAXCLIENTS_BIG) ) + {// POSTGAME maxClients = SB_MAXCLIENTS_NORMAL; lineHeight = SB_NORMAL_HEIGHT; topBorderSize = 16; bottomBorderSize = 16; } + else + {// INGAME + maxClients = SB_MAXCLIENTS_BIG; + lineHeight = SB_NORMAL_HEIGHT_BIG; + topBorderSize = 16; + bottomBorderSize = 16; + } localClient = qfalse; - - if ( cgs.gametype >= GT_TEAM ) { - // - // teamplay scoreboard - // - y += lineHeight/2; - - if ( cg.teamScores[0] >= cg.teamScores[1] ) { - n1 = CG_TeamScoreboard( y, TEAM_RED, fade, maxClients, lineHeight ); - CG_DrawTeamBackground( 0, y - topBorderSize, 640, n1 * lineHeight + bottomBorderSize, 0.33f, TEAM_RED ); - y += (n1 * lineHeight) + BIGCHAR_HEIGHT; - maxClients -= n1; - n2 = CG_TeamScoreboard( y, TEAM_BLUE, fade, maxClients, lineHeight ); - CG_DrawTeamBackground( 0, y - topBorderSize, 640, n2 * lineHeight + bottomBorderSize, 0.33f, TEAM_BLUE ); - y += (n2 * lineHeight) + BIGCHAR_HEIGHT; - maxClients -= n2; - } else { - n1 = CG_TeamScoreboard( y, TEAM_BLUE, fade, maxClients, lineHeight ); - CG_DrawTeamBackground( 0, y - topBorderSize, 640, n1 * lineHeight + bottomBorderSize, 0.33f, TEAM_BLUE ); - y += (n1 * lineHeight) + BIGCHAR_HEIGHT; - maxClients -= n1; - n2 = CG_TeamScoreboard( y, TEAM_RED, fade, maxClients, lineHeight ); - CG_DrawTeamBackground( 0, y - topBorderSize, 640, n2 * lineHeight + bottomBorderSize, 0.33f, TEAM_RED ); - y += (n2 * lineHeight) + BIGCHAR_HEIGHT; - maxClients -= n2; + + //TiM + /*if ( cgs.gametype >= GT_TEAM ) + { + y-=6; + // TEAM PLAY + //---------- + if ( cg.teamScores[0] >= cg.teamScores[1] ) + { + tTeam = TEAM_RED; + bTeam = TEAM_BLUE; + } + else + { + tTeam = TEAM_BLUE; + bTeam = TEAM_RED; } - n1 = CG_TeamScoreboard( y, TEAM_SPECTATOR, fade, maxClients, lineHeight ); - y += (n1 * lineHeight) + BIGCHAR_HEIGHT; - } else { - // - // free for all scoreboard - // + // TOP TEAM + n1 = CG_GetTeamCount(tTeam, maxClients); + CG_DrawTeamBackground( SCOREBOARD_X+15, y, SB_TOPLINE_LENGTH - 14, n1*lineHeight, 0.33, tTeam, qtrue ); + CG_TeamScoreboard( y, tTeam, fade, maxClients, lineHeight ); + + if(tTeam==TEAM_BLUE) + CG_FillRect( SCOREBOARD_X+12, y, 2, (n1*lineHeight), colorTable[CT_BLUE]); + else + CG_FillRect( SCOREBOARD_X+12, y, 2, (n1*lineHeight), colorTable[CT_RED]); + y += (n1*lineHeight); + maxClients -= n1; + + // BOTTOM TEAM + n2 = CG_GetTeamCount(bTeam, maxClients); + CG_DrawTeamBackground( SCOREBOARD_X+15, y, SB_TOPLINE_LENGTH - 14, n2*lineHeight, 0.33, bTeam, qtrue ); + CG_TeamScoreboard( y, bTeam, fade, maxClients, lineHeight ); + + if(bTeam==TEAM_BLUE) + CG_FillRect( SCOREBOARD_X+12, y, 2, (n2*lineHeight), colorTable[CT_BLUE]); + else + CG_FillRect( SCOREBOARD_X+12, y, 2, (n2*lineHeight), colorTable[CT_RED]); + y += (n2*lineHeight); + maxClients -= n2; + + // SPECTATOR TEAM + n3 = CG_TeamScoreboard( y, TEAM_SPECTATOR, fade, maxClients, lineHeight ); + y += (n3 * lineHeight); + maxClients -= n3; + } + else + {*/ + // FREE FOR ALL + //------------- n1 = CG_TeamScoreboard( y, TEAM_FREE, fade, maxClients, lineHeight ); - y += (n1 * lineHeight) + BIGCHAR_HEIGHT; - n2 = CG_TeamScoreboard( y, TEAM_SPECTATOR, fade, maxClients - n1, lineHeight ); - y += (n2 * lineHeight) + BIGCHAR_HEIGHT; + y += (n1 * lineHeight); + maxClients -= n1; + + n2 = CG_TeamScoreboard( y, TEAM_SPECTATOR, fade, maxClients, lineHeight ); + y += (n2 * lineHeight); + maxClients -= n2; + //} + + //LOCAL CLIENT AT BOTTOM OF SCOREBOARD + //------------------------------------ + // + // If we didn't draw the local client in the scoreboard (because ranked lower than maxClients) + // Look for him and display him at the bottom + // + // BUT not for 'GT_SINGLE_PLAYER' (shouldn't happen anyway, right?) + // + if (cgs.gametype==GT_SINGLE_PLAYER) + localClient = qtrue; + + i=0; + while (!localClient && ips.clientNum ) // it's me!! + { + CG_DrawClientScore( y, &cg.scores[i], colorYellow, 0.0, lineHeight==SB_NORMAL_HEIGHT ); + y += lineHeight; + localClient = qtrue; + } + i++; } - if (!localClient) { - // draw local client at the bottom - for ( i = 0 ; i < cg.numScores ; i++ ) { - if ( cg.scores[i].client == cg.snap->ps.clientNum ) { - CG_DrawClientScore( y, &cg.scores[i], fadeColor, fade, lineHeight == SB_NORMAL_HEIGHT ); - break; + // Bottom of scoreboard + //trap_R_SetColor( colorTable[CT_DKORANGE] ); + //CG_DrawPic( 13, y-3, 16, 32, cgs.media.corner_12_24 ); // Corner + //RPG-X BookMark Bottum bar + CG_FillRect( SCOREBOARD_X, SB_RPG_X_FIXHEIGHT+60, SB_TOPLINE_LENGTH, 15, colorTable[CT_DKBLUE1]); + //trap_R_SetColor( colorTable[CT_DKORANGE] ); + //CG_DrawPic( 605, y, 16, 32, cgs.media.scoreboardEndcap ); + + //RPG-X: - RedTechie no PRESS FIRE TO CONTINUE! + /*if ( inIntermission ) + { + if ( cgs.gametype != GT_SINGLE_PLAYER) + { + static int flashTime = 0; + static int flashColor = CT_RED; + if ( cg.time - flashTime >= 500 ) + { + flashTime = cg.time; + if ( flashColor == CT_RED ) + { + flashColor = CT_BLACK; + } + else + { + flashColor = CT_RED; + } } + UI_DrawProportionalString( SB_TOPLINE_LENGTH, y+10+BIGCHAR_HEIGHT, ingame_text[IGT_CLICK_PLAY_AGAIN], UI_RIGHT, colorTable[flashColor] ); } + }*/ + + //if (cgs.gametype < GT_TEAM) + s = va("%s: %i", ingame_text[IGT_PLAYERS], cg.numScores); // Number of Players + //} + //RPG-X: - RedTechie Dont need extra crap + //TiM: Yeah.... crap suxx. ;P + /*else + { + n1=n2=n3=0; + + for (i=0; i 10 ) { + if ( inIntermission || (++cg.deferredPlayerLoading > 10) ) CG_LoadDeferredPlayers(); - } - + return qtrue; } @@ -437,9 +1437,12 @@ static void CG_CenterGiantLine( float y, const char *string ) { color[2] = 1; color[3] = 1; - x = 0.5 * ( 640 - GIANT_WIDTH * CG_DrawStrlen( string ) ); +// x = 0.5 * ( 640 - GIANT_WIDTH * CG_DrawStrlen( string ) ); +// CG_DrawStringExt( x, y, string, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 ); + + x = 0.5 * ( 640 - UI_ProportionalStringWidth(string,UI_BIGFONT) ); + UI_DrawProportionalString( x, y, string, UI_BIGFONT|UI_DROPSHADOW, color); - CG_DrawStringExt( x, y, string, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 ); } /* @@ -449,13 +1452,13 @@ CG_DrawTourneyScoreboard Draw the oversize scoreboard for tournements ================= */ -void CG_DrawOldTourneyScoreboard( void ) { +void CG_DrawTourneyScoreboard( void ) { const char *s; vec4_t color; int min, tens, ones; clientInfo_t *ci; int y; - int i; + int i,w; // request more scores regularly if ( cg.scoresRequestTime + 2000 < cg.time ) { @@ -463,16 +1466,16 @@ void CG_DrawOldTourneyScoreboard( void ) { trap_SendClientCommand( "score" ); } - // draw the dialog background - color[0] = color[1] = color[2] = 0; - color[3] = 1; - CG_FillRect( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, color ); - color[0] = 1; color[1] = 1; color[2] = 1; color[3] = 1; + // draw the dialog background + color[0] = color[1] = color[2] = 0; + color[3] = 1; + CG_FillRect( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, color ); + // print the mesage of the day s = CG_ConfigString( CS_MOTD ); if ( !s[0] ) { @@ -500,15 +1503,21 @@ void CG_DrawOldTourneyScoreboard( void ) { // // teamplay scoreboard // - CG_DrawStringExt( 8, y, "Red Team", color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 ); +// CG_DrawStringExt( 8, y, ingame_text[IGT_REDTEAM], color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 ); + UI_DrawProportionalString( 8, y, ingame_text[IGT_REDTEAM], UI_BIGFONT|UI_DROPSHADOW, color); s = va("%i", cg.teamScores[0] ); - CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 ); +// CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 ); + w = UI_ProportionalStringWidth(s,UI_BIGFONT); + UI_DrawProportionalString(632 - w, y, s, UI_BIGFONT|UI_DROPSHADOW, color); y += 64; - CG_DrawStringExt( 8, y, "Blue Team", color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 ); +// CG_DrawStringExt( 8, y, ingame_text[IGT_BLUETEAM], color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 ); + UI_DrawProportionalString(8, y, ingame_text[IGT_BLUETEAM], UI_BIGFONT|UI_DROPSHADOW, color); s = va("%i", cg.teamScores[1] ); - CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 ); +// CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 ); + w = UI_ProportionalStringWidth(s,UI_BIGFONT); + UI_DrawProportionalString(632 - w, y, s, UI_BIGFONT|UI_DROPSHADOW, color); } else { // // free for all scoreboard @@ -522,9 +1531,13 @@ void CG_DrawOldTourneyScoreboard( void ) { continue; } - CG_DrawStringExt( 8, y, ci->name, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 ); +// CG_DrawStringExt( 8, y, ci->name, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 ); + UI_DrawProportionalString( 8, y, ci->name, UI_BIGFONT|UI_DROPSHADOW, color); s = va("%i", ci->score ); - CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 ); +// CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 ); + w = UI_ProportionalStringWidth(s,UI_BIGFONT); + UI_DrawProportionalString(632 - w, y, s, UI_BIGFONT|UI_DROPSHADOW, color); + y += 64; } } @@ -532,3 +1545,1095 @@ void CG_DrawOldTourneyScoreboard( void ) { } + + + + + + + +/* +============================================================================= + +AWARDS PRESENTATION + + The following code was ripped from ui_sppostgame.c and has been modified + to show the awards presentation for all game types + +FROM ????Server???? + AW_SPPostgameMenu_f() + -Parse award information and store in struct + + +FROM DrawScoreboard() + AW_Draw() + -PHASE I + Play Sounds + + -PHASE II + AW_DrawAwardsPresentation(timer) + AW_DrawAwards(max) + + -PHASE III + AW_DrawAwards(ALL) + + -PHASE IV + Draw the New Scoreboard + + +============================================================================= +*/ +#define AWARD_PRESENTATION_TIME 2000 // time each medal is shown + +typedef struct { + + int phase; + int ignoreKeysTime; + int starttime; + int scoreboardtime; + int serverId; + + int playerGameRank; + qboolean playersTeamWon; + int playerTied; + + char placeNames[3][64]; + char winTeamText[64]; + char losTeamText[64]; + char winTeamMVPText[64]; + char nameOfMVP[64]; + int scoreOfMVP; + int totalCaptures; + int totalPoints; + int losCaptures; + int losPoints; + int secondPlaceTied; + + int level; + int numClients; + int won; + int numAwards; + int awardsEarned[9]; + int awardsLevels[9]; + qboolean playedSound[9]; + int lastTier; + sfxHandle_t winnerSound; + int winnerDelay; + sfxHandle_t youPlacedSound; + sfxHandle_t commendationsSound; + + vec3_t intermission_origin; + vec3_t intermission_angle; +} postgameMenuInfo_t; + +static postgameMenuInfo_t postgameMenuInfo; +static qboolean postGameMenuStructInited = qfalse; + +void InitPostGameMenuStruct() +{ + if (qfalse == postGameMenuStructInited) + { + memset( &postgameMenuInfo, 0, sizeof(postgameMenuInfo) ); + postGameMenuStructInited = qtrue; + } +} + +/* +char *cg_medalNames[AWARD_MAX] = +{ + "Efficiency", // AWARD_EFFICIENCY, Accuracy + "Sharpshooter", // AWARD_SHARPSHOOTER, Most compression rifle frags + "Untouchable", // AWARD_UNTOUCHABLE, Perfect (no deaths) + "Logistics", // AWARD_LOGISTICS, Most pickups + "Tactician", // AWARD_TACTICIAN, Kills with all weapons + "Demolitionist", // AWARD_DEMOLITIONIST, Most explosive damage kills + "Streak", // AWARD_STREAK, Ace/Expert/Master/Champion + "Role", // AWARD_TEAM, MVP/Defender/Warrior/Carrier/Interceptor/Bravery + "Section 31" // AWARD_SECTION31 All-around god +}; +*/ + +int cg_medalNames[AWARD_MAX] = +{ + IGT_EFFICIENCY, // AWARD_EFFICIENCY, Accuracy + IGT_SHARPSHOOTER, // AWARD_SHARPSHOOTER, Most compression rifle frags + IGT_UNTOUCHABLE, // AWARD_UNTOUCHABLE, Perfect (no deaths) + IGT_LOGISTICS, // AWARD_LOGISTICS, Most pickups + IGT_TACTICIAN, // AWARD_TACTICIAN, Kills with all weapons + IGT_DEMOLITIONIST, // AWARD_DEMOLITIONIST, Most explosive damage kills + IGT_ROLE, // AWARD_STREAK, Ace/Expert/Master/Champion + IGT_STREAK, // AWARD_TEAM, MVP/Defender/Warrior/Carrier/Interceptor/Bravery + IGT_SECTION31 // AWARD_SECTION31 All-around god +}; + + +char *cg_medalPicNames[AWARD_MAX] = { + "menu/medals/medal_efficiency", // AWARD_EFFICIENCY, + "menu/medals/medal_sharpshooter", // AWARD_SHARPSHOOTER, + "menu/medals/medal_untouchable", // AWARD_UNTOUCHABLE, + "menu/medals/medal_logistics", // AWARD_LOGISTICS, + "menu/medals/medal_tactician", // AWARD_TACTICIAN, + "menu/medals/medal_demolitionist", // AWARD_DEMOLITIONIST, + "menu/medals/medal_ace", // AWARD_STREAK, + "menu/medals/medal_teammvp", // AWARD_TEAM, + "menu/medals/medal_section31" // AWARD_SECTION31 +}; + +char *cg_medalSounds[AWARD_MAX] = { + "sound/voice/computer/misc/effic.wav", // AWARD_EFFICIENCY, + "sound/voice/computer/misc/sharp.wav", // AWARD_SHARPSHOOTER, + "sound/voice/computer/misc/untouch.wav", // AWARD_UNTOUCHABLE, + "sound/voice/computer/misc/log.wav", // AWARD_LOGISTICS, + "sound/voice/computer/misc/tact.wav", // AWARD_TACTICIAN, + "sound/voice/computer/misc/demo.wav", // AWARD_DEMOLITIONIST, + "sound/voice/computer/misc/ace.wav", // AWARD_STREAK, + "",/*shouldn't use. use cg_medalTeamSounds instead*/ // AWARD_TEAM, + "sound/voice/computer/misc/sec31.wav" // AWARD_SECTION31 +}; + +char *cg_medalTeamPicNames[TEAM_MAX] = { + "", // TEAM_NONE + "menu/medals/medal_teammvp", // TEAM_MVP, + "menu/medals/medal_teamdefender", // TEAM_DEFENDER, + "menu/medals/medal_teamwarrior", // TEAM_WARRIOR, + "menu/medals/medal_teamcarrier", // TEAM_CARRIER, + "menu/medals/medal_teaminterceptor",// TEAM_INTERCEPTOR, + "menu/medals/medal_teambravery" // TEAM_BRAVERY, +}; + +char *cg_medalTeamSounds[TEAM_MAX] = { + "", // TEAM_NONE + "sound/voice/computer/misc/mvp.wav", // TEAM_MVP, + "sound/voice/computer/misc/defender.wav", // TEAM_DEFENDER, + "sound/voice/computer/misc/warrior.wav", // TEAM_WARRIOR, + "sound/voice/computer/misc/carrier.wav", // TEAM_CARRIER, + "sound/voice/computer/misc/intercept.wav", // TEAM_INTERCEPTOR, + "sound/voice/computer/misc/bravery.wav" // TEAM_BRAVERY, +}; + + +char *cg_medalStreakPicNames[AWARD_STREAK_MAX] = { + "", // AWARD_NONE + "menu/medals/medal_ace", // AWARD_STREAK_ACE, + "menu/medals/medal_expert", // AWARD_STREAK_EXPERT, + "menu/medals/medal_master", // AWARD_STREAK_MASTER, + "menu/medals/medal_champion" // AWARD_STREAK_CHAMPION, +}; + +char *cg_medalStreakSounds[AWARD_STREAK_MAX] = { + "", // AWARD_NONE + "sound/voice/computer/misc/ace.wav", // AWARD_STREAK_ACE, + "sound/voice/computer/misc/expert.wav", // AWARD_STREAK_EXPERT, + "sound/voice/computer/misc/master.wav", // AWARD_STREAK_MASTER, + "sound/voice/computer/misc/champion.wav" // AWARD_STREAK_CHAMPION, +}; +/* +char *cg_medalStreakNames[AWARD_STREAK_MAX] = { + "", // AWARD_NONE + "Ace", // AWARD_STREAK_ACE, + "Expert", // AWARD_STREAK_EXPERT, + "Master", // AWARD_STREAK_MASTER, + "Champion" // AWARD_STREAK_CHAMPION, +}; +*/ + +int cg_medalStreakNames[AWARD_STREAK_MAX] = { + IGT_NONE, // AWARD_NONE + IGT_ACE, // AWARD_STREAK_ACE, + IGT_EXPERT, // AWARD_STREAK_EXPERT, + IGT_MASTER, // AWARD_STREAK_MASTER, + IGT_CHAMPION // AWARD_STREAK_CHAMPION, +}; + +int cg_medalTeamNames[TEAM_MAX] = { + IGT_NONE, // AWARD_NONE + IGT_MVP, // TEAM_MVP, + IGT_DEFENDER, // TEAM_DEFENDER, + IGT_WARRIOR, // TEAM_WARRIOR, + IGT_CARRIER, // TEAM_CARRIER, + IGT_INTERCEPTOR, // TEAM_INTERCEPTOR + IGT_BRAVERY // TEAM_BRAVERY +}; + + +// spaced by 70 pixels apart +//static int medalLocations[6] = {570, 500, 430, 360, 290}; + +/*static void AW_DrawMedal( int medal, int amount, int x, int y ) +{ + char buf[20]; + qhandle_t hShader; + vec4_t yellow; + + // RED GREEN BLUE ALPHA + //----------------------------------------------------------------------- + yellow[0]=1.0f; yellow[1]=1.0f; yellow[2]=0.5f; yellow[3]=1.0f; + + if (medal == AWARD_STREAK) { + hShader = trap_R_RegisterShaderNoMip( cg_medalStreakPicNames[amount/5] ); + } + else if (medal == AWARD_TEAM) { + hShader = trap_R_RegisterShaderNoMip( cg_medalTeamPicNames[amount] ); + } + else { + hShader = trap_R_RegisterShaderNoMip( cg_medalPicNames[medal] ); + } + CG_DrawPic( x, y, 48, 48, hShader); + + if (postgameMenuInfo.phase<4) + { + //--------------------------------------------------------------- NAME OF THE AWARD + Com_sprintf( buf, sizeof(buf), "%s", ingame_text[cg_medalNames[medal]]); + if (medal== AWARD_STREAK) + Com_sprintf( buf, sizeof(buf), "%s", ingame_text[cg_medalStreakNames[amount/5]]); + if (medal== AWARD_TEAM) + Com_sprintf( buf, sizeof(buf), "%s", ingame_text[cg_medalTeamNames[amount]]); + +// Q_CleanStr( buf ); + + UI_DrawProportionalString( x+24, y+50, buf, UI_TINYFONT|UI_CENTER, yellow ); + //--------------------------------------------------------------- NAME OF THE AWARD + } +}*/ + +//======================== +// DrawTheMedals(int max) +// +// This function cycles from 0 to max and calls some functions to Draw the Picture and +// the text below for efficency. +// +//======================== +//RPG-X: RedTechie - No awards +/*static int presentedTeamAward[TEAM_MAX]; +static void AW_DrawTheMedals( int max ) { + int n, i; + int medal; + int amount; + int x, y; + int extraAwardOffset = 0; + + for( n = 0; n < max; n++ ) { + x = medalLocations[n] - extraAwardOffset; + y = AWARD_Y; + medal = postgameMenuInfo.awardsEarned[n]; + amount = postgameMenuInfo.awardsLevels[n]; + + if (medal == AWARD_TEAM) + {//amount is going to be a bitflag field... + for( i = TEAM_MVP; i < TEAM_MAX; i++ ) + { + if ( amount & (1<= postgameMenuInfo.numAwards ) + { + awardNum = (postgameMenuInfo.numAwards-1); + } + + medal = postgameMenuInfo.awardsEarned[awardNum]; + amount = postgameMenuInfo.awardsLevels[awardNum]; + + if ( medal == AWARD_TEAM ) + {//amount is going to be a bitflag field... + if ( !allTeamAwardsAnnounced ) + { + for( i = TEAM_MVP; i < TEAM_MAX; i++ ) + { + if ( amount & (1< cg.time ) + {//already announced this award + AW_PresentMedal( AWARD_TEAM, i, timer, awardNum ); + } + teamAward++; + } + } + } + } + else + { + AW_PresentMedal( medal, amount, timer, awardNum ); + } + + AW_DrawTheMedals( awardNum + 1 ); // Draw the awards + + if ( !awardNextDebounceTime ) + { + awardNextDebounceTime = cg.time + AWARD_PRESENTATION_TIME; + } + else if ( awardNextDebounceTime <= cg.time ) + { + awardNextDebounceTime = cg.time + AWARD_PRESENTATION_TIME; + if ( i == TEAM_MAX ) + { + //finished loop? Then we announced all these + allTeamAwardsAnnounced = qtrue; + } + if ( !extraAwardTime || allTeamAwardsAnnounced ) + { + awardNum++; + } + else + { + nextTeamAward++; + } + } +} +*/ + +/* +================= +AW_Draw +================= +*/ +static qboolean AW_Draw( void ) +{ + char buf[64]; + int timer; + int y=0, yfrom=0; + int len; + vec4_t white, red, blue, yellow, blueA; // new colors + + // RED GREEN BLUE ALPHA + //----------------------------------------------------------------------- + white[0] = white[1] = white[2] = 1.0f; white[3] = 1.0f; + red[0] = 1.0f; red[1] = 0.5f; red[2] = 0.5f; red[3] = 1.0f; + blue[0] = 0.5f; blue[1] = 0.5f; blue[2] = 1.0f; blue[3] = 1.0f; + yellow[0]= 1.0f; yellow[1]= 1.0f; yellow[2]= 0.5f; yellow[3]= 1.0f; + blueA[0] = 0.367f; blueA[1] = 0.261f;blueA[2] = 0.722f; blueA[3] = 0.5f; + + // REASONS NOT TO SHOW THE AWARDS CEREMONY: + //-------------------------------------------- + // if scoreboardtime is not set, we set it to current time plus five seconds slop time + if (postgameMenuInfo.scoreboardtime == 0) + { + postgameMenuInfo.scoreboardtime = cg.time+5000; + return qfalse; + } + + // if scoreboardtime is greater than current time, we don't draw anything (including no scoreboard) + // This should only happen if the scoreboard time had not been set properly to current time by + // the setup function below + if (postgameMenuInfo.scoreboardtime > cg.time+10) + return qfalse; + + // OK, so we've given the slop time and a chance for the information to be set properly in + // case of network lag. if .starttime is still not set properly, we have no right to show + // anything in the awards ceremony and go straight to the spiffy scoreboard... + if (postgameMenuInfo.starttime==0) + return qtrue; + + + + + + //RPG-X: RedTechie Dont need this aswell this also prints out what team your on and if your winning just takes up to much room + // ALL PHASES + // Display Your Rank / Your Team Wins + //----------------------------------------------- + /*if (cg.snap->ps.persistant[PERS_TEAM]!=TEAM_SPECTATOR) + { + if (cgs.gametype <= GT_SINGLE_PLAYER ) + { + if (postgameMenuInfo.playerTied) + Com_sprintf( buf, sizeof(buf), "%s %i", ingame_text[IGT_TIED_FOR], postgameMenuInfo.playerTied); + else + Com_sprintf( buf, sizeof(buf), "%s %i", ingame_text[IGT_YOUR_RANK], postgameMenuInfo.playerGameRank+1); + UI_DrawProportionalString( 14, AWARD_Y, buf, UI_BIGFONT|UI_LEFT, white ); + } + else + { + char *teamName = NULL; + + switch ( cg.snap->ps.persistant[PERS_TEAM] ) + { + case TEAM_RED: + teamName = (char *)CG_ConfigString( CS_RED_GROUP ); + break; + case TEAM_BLUE: + teamName = (char *)CG_ConfigString( CS_BLUE_GROUP ); + break; + } + if ( teamName == NULL || teamName[0] == 0 ) + { + teamName = ingame_text[IGT_YOUR_TEAM]; + } + + if (postgameMenuInfo.playersTeamWon) + Com_sprintf( buf, sizeof(buf), "%s %s", teamName, ingame_text[IGT_WON]); + else + Com_sprintf( buf, sizeof(buf), "%s %s", teamName, ingame_text[IGT_LOST]); + if (postgameMenuInfo.playerGameRank == 2) + Com_sprintf( buf, sizeof(buf), "%s", ingame_text[IGT_TEAMS_TIED]); + UI_DrawProportionalString( 14, AWARD_Y, buf, UI_BIGFONT|UI_LEFT, white ); + + } + }*/ + + // PHASES I & II & III + // Draw Character / Team names by podiums + //----------------------------------------------- + if (postgameMenuInfo.phase < 4) + { + if (cgs.gametype <= GT_SINGLE_PLAYER ) + { + // NON TEAM GAMES + // We want the top three player's names and their ranks below the podium + if ( postgameMenuInfo.numClients > 2 ) + { + UI_DrawProportionalString( 510, 480 - 64 - PROP_HEIGHT, postgameMenuInfo.placeNames[2], UI_CENTER, white ); + if (postgameMenuInfo.secondPlaceTied) + UI_DrawProportionalString( 510, 480 - 38 - PROP_HEIGHT, ingame_text[IGT_2ND], UI_CENTER, yellow ); + else + UI_DrawProportionalString( 510, 480 - 38 - PROP_HEIGHT, ingame_text[IGT_3RD], UI_CENTER, yellow ); + } + if ( postgameMenuInfo.numClients > 1) + { + UI_DrawProportionalString( 130, 480 - 64 - PROP_HEIGHT, postgameMenuInfo.placeNames[1], UI_CENTER, white ); + UI_DrawProportionalString( 130, 480 - 38 - PROP_HEIGHT, ingame_text[IGT_2ND], UI_CENTER, yellow ); + } + + UI_DrawProportionalString( 320, 480 - 64 - 2 * PROP_HEIGHT, postgameMenuInfo.placeNames[0], UI_CENTER, white ); + UI_DrawProportionalString( 320, 480 - 38 - 2 * PROP_HEIGHT, ingame_text[IGT_1ST], UI_CENTER, yellow ); + } + else //if (cg.snap->ps.persistant[PERS_TEAM]!=TEAM_SPECTATOR) + { + // TEAM + // We want the winning team character's name, a line explaining "Klingon MVP" + UI_DrawProportionalString( 320, 480 - 64 - 2 * PROP_HEIGHT, postgameMenuInfo.nameOfMVP, UI_CENTER, white ); + UI_DrawProportionalString( 320, 480 - 34 - 2 * PROP_HEIGHT, postgameMenuInfo.winTeamMVPText, UI_CENTER, yellow ); + Com_sprintf( buf, sizeof(buf), "%s %i", ingame_text[IGT_POINTS], postgameMenuInfo.scoreOfMVP); + UI_DrawProportionalString( 320, 480 - 14 - 2 * PROP_HEIGHT, buf, UI_CENTER, yellow ); + + + + // SPECIAL TEAM STATS BAR ON RIGHT SIDE OF SCREEN + //----------------------------------------------- + // + // THE TOP BAR + y=130; + if (cgs.gametype == GT_CTF) + Com_sprintf( buf, sizeof(buf), ingame_text[IGT_GAME_CAPTUREFLAG] ); + else + Com_sprintf( buf, sizeof(buf), ingame_text[IGT_GAME_TEAMHOLOMATCH] ); + len = UI_ProportionalStringWidth( buf, UI_SMALLFONT ); + + trap_R_SetColor( colorTable[CT_DKORANGE] ); + CG_DrawPic( 640-32, y+20, 16, -32, cgs.media.corner_8_16_b ); + CG_FillRect(640-80, y+1, 48, 15, colorTable[CT_DKORANGE]); + UI_DrawProportionalString( 640-82, y, buf, UI_RIGHT, colorTable[CT_DKORANGE] ); + trap_R_SetColor( colorTable[CT_DKORANGE] ); + CG_DrawPic( 640-80-len-5, y+1, -14, 20, cgs.media.scoreboardEndcap ); + yfrom = y+20; + y+=20; + + Com_sprintf( buf, sizeof(buf), "%s", postgameMenuInfo.winTeamText); + UI_DrawProportionalString( 640-34, y, buf, UI_BIGFONT|UI_RIGHT, yellow ); + y+=35; + + if (cgs.gametype == GT_CTF) + { + // HOW MANY CAPUTRES??? + Com_sprintf( buf, sizeof(buf), "%s %i", ingame_text[IGT_CAPTURES], postgameMenuInfo.totalCaptures); + UI_DrawProportionalString( 640-34, y, buf, UI_RIGHT, white ); + y+=20; + } + + // AND THE POINTS??? + Com_sprintf( buf, sizeof(buf), "%s %i", ingame_text[IGT_POINTS], postgameMenuInfo.totalPoints); + UI_DrawProportionalString( 640-34, y, buf, UI_RIGHT, white ); + y+=30; + + // THE SIDE BAR + CG_FillRect( 640-16-12, yfrom, 8, y-yfrom, colorTable[CT_DKORANGE]); + + + // THE MIDDLE BARS + CG_FillRect( 640-115, y, 95, 20, colorTable[CT_DKORANGE]); + y+=3; + if (postgameMenuInfo.playerGameRank==2) + Com_sprintf( buf, sizeof(buf), "%s", ingame_text[IGT_TEAMS_TIED]); + else + Com_sprintf( buf, sizeof(buf), "%s", ingame_text[IGT_VICTOR]); + + UI_DrawProportionalString( 640-34, y, buf, UI_RIGHT, colorTable[CT_BLACK] ); + y+=20; + + y+=30; + + yfrom=y; + CG_FillRect( 640-115, y, 95, 20, colorTable[CT_DKORANGE]); + y+=3; + if (postgameMenuInfo.playerGameRank==2) + Com_sprintf( buf, sizeof(buf), "%s", ingame_text[IGT_TEAMS_TIED]); + else + Com_sprintf( buf, sizeof(buf), "%s", ingame_text[IGT_DEFEATED]); + + UI_DrawProportionalString( 640-34, y, buf, UI_RIGHT, colorTable[CT_BLACK] ); + y+=25; + + // LOSING TEAM NAME + Com_sprintf( buf, sizeof(buf), "%s", postgameMenuInfo.losTeamText); + UI_DrawProportionalString( 640-34, y, buf, UI_BIGFONT|UI_RIGHT, yellow ); + y+=35; + + if (cgs.gametype == GT_CTF) + { + // HOW MANY CAPUTRES??? + Com_sprintf( buf, sizeof(buf), "%s %i", ingame_text[IGT_CAPTURES], postgameMenuInfo.losCaptures); + UI_DrawProportionalString( 640-34, y, buf, UI_RIGHT, white ); + y+=20; + } + + // AND THE POINTS??? + Com_sprintf( buf, sizeof(buf), "%s %i", ingame_text[IGT_POINTS], postgameMenuInfo.losPoints); + UI_DrawProportionalString( 640-34, y, buf, UI_RIGHT, white ); + y+=20; + + // THE SIDE BAR + CG_FillRect( 640-16-12, yfrom, 8, y-yfrom, colorTable[CT_DKORANGE]); + + // THE BOTTOM BAR + trap_R_SetColor( colorTable[CT_DKORANGE] ); + CG_DrawPic( 640-32, y, 16, 32, cgs.media.corner_8_16_b ); + CG_FillRect(640-100, y+4, 68, 15, colorTable[CT_DKORANGE]); + trap_R_SetColor( colorTable[CT_DKORANGE] ); + CG_DrawPic( 640-100-2, y+4, -14, 20, cgs.media.scoreboardEndcap ); + yfrom = y+20; + y+=20; + } + } + + + // if we are arriving as a spectator, there are no awards for you (not even sure that spectators + // will get the awards string that sets the whole thing up...) +// if (cg.snap->ps.persistant[PERS_TEAM]==TEAM_SPECTATOR) +// return qtrue; + + + // PHASE I + // Play Winner sound + //----------------------------------------------- + if( postgameMenuInfo.phase == 1 ) + { + timer = cg.time - postgameMenuInfo.starttime; // set up the timer + + //RPG-X: RedTechie - No winner + /*if( postgameMenuInfo.winnerSound ) // if havn't played yet + { + trap_S_StartLocalSound( postgameMenuInfo.winnerSound, CHAN_ANNOUNCER ); // play the sound + postgameMenuInfo.winnerSound = 0; // don't play again + // force another wait since we played a sound here + postgameMenuInfo.starttime = cg.time + postgameMenuInfo.winnerDelay; + timer = 0; + }*/ + + if( timer < 2000 ) + { + return qfalse; + } + + //RPG-X: RedTechie - No ranking sound + /*if (cg.snap->ps.persistant[PERS_TEAM]!=TEAM_SPECTATOR) + { + if (postgameMenuInfo.youPlacedSound) + { + trap_S_StartLocalSound( postgameMenuInfo.youPlacedSound, CHAN_ANNOUNCER ); + postgameMenuInfo.youPlacedSound = 0; + // force another wait since we played a sound here + postgameMenuInfo.starttime = cg.time; + timer = 0; + } + }*/ + + // if we didn't play a youPlaced sound, this won't slow us up at all + if( timer < 2000 ) + { + return qfalse; + } + + // play "commendations" sound + //RPG-X: RedTechie - No commendations + /*if (postgameMenuInfo.commendationsSound) + { + trap_S_StartLocalSound( postgameMenuInfo.commendationsSound, CHAN_ANNOUNCER ); + postgameMenuInfo.commendationsSound = 0; + // force another wait since we played a sound here + postgameMenuInfo.starttime = cg.time; + }*/ + + if( timer < 2500 ) + { + return qfalse; + } + // After 7 seconds, go on to phase II + postgameMenuInfo.phase = 2; // Setup PHASE II + postgameMenuInfo.starttime = cg.time; // +// memset( presentedTeamAward, 0, sizeof( presentedTeamAward ) ); +// extraAwardTime = 0; +// allTeamAwardsAnnounced = qfalse; +// awardNextDebounceTime = 0; +// awardNum = 0; +// nextTeamAward = 0; + + return qfalse; + } + + // PHASE II + // Introduce each medal on a timer + //----------------------------------------------- + //RPG-X: RedTechie - No awards + if( postgameMenuInfo.phase == 2 ) + { + + timer = cg.time - postgameMenuInfo.starttime;// - extraAwardTime; // Setup Timer + if( timer >= ( postgameMenuInfo.numAwards * AWARD_PRESENTATION_TIME ) ) + { + postgameMenuInfo.phase = 3; + //AW_DrawTheMedals( postgameMenuInfo.numAwards ); // Draw All Medals for this frame + } + else + { + //AW_DrawAwardsPresentation( timer ); // Draw Some Medals + } + + return qfalse; + } + + // PHASE III + // Just draw all the awards medals + //----------------------------------------------- + //RPG-X: RedTechie - No awards + if( postgameMenuInfo.phase == 3 ) + { + //AW_DrawTheMedals( postgameMenuInfo.numAwards ); + timer = cg.time - postgameMenuInfo.starttime; // Setup Timer + if (timer >= 5000) + postgameMenuInfo.phase = 4; // Got To Phase IV after 5 seconds + + return qfalse; + } + + + // PHASE IV + // Draw Medals & Draw the scoreboard + //----------------------------------------------- + //RPG-X: RedTechie - No awards + + postgameMenuInfo.phase = 4; + //AW_DrawTheMedals( postgameMenuInfo.numAwards ); + return qtrue; + +} + + +/* +================= +AW_SPPostgameMenu_Cache +================= + +void AW_SPPostgameMenu_Cache( void ) { + int n; + qboolean buildscript; + + buildscript = trap_Cvar_VariableValue("com_buildscript"); + + for( n = 0; n < AWARD_MAX; n++ ) + { + trap_R_RegisterShaderNoMip( ui_medalPicNames[n] ); + trap_S_RegisterSound( ui_medalSounds[n] ); + } + + if( buildscript ) { + trap_Cmd_ExecuteText( EXEC_APPEND, "music music/win\n" ); + trap_Cmd_ExecuteText( EXEC_APPEND, "music music/loss\n" ); + trap_S_RegisterSound( "sound/player/announce/youwin.wav" ); + } +} +*/ + + +/* +================= +AW_SPPostgameMenu_Cache + + This function writes the winning the winning team name if + we are in a team game. +================= +*/ +static void AW_Prepname( int index) +{ +// int len; + char name[64]; // The winning team's name.. Red/Blue/ Klingon... + char MVPname[64]; + char otherName[64]; + const char *redPtr = NULL; + const char *bluePtr = NULL; + char *red_team; + char *blue_team; + + red_team = ingame_text[IGT_REDTEAM]; + blue_team = ingame_text[IGT_BLUETEAM]; + + + redPtr = CG_ConfigString( CS_RED_GROUP ); + bluePtr= CG_ConfigString( CS_BLUE_GROUP); + if (!Q_stricmp(redPtr, "")) + redPtr = red_team; + + if (!Q_stricmp(bluePtr, "")) + bluePtr = blue_team; + + if (postgameMenuInfo.playerGameRank == 1) // Blue Team Won + { + Com_sprintf(name, sizeof(name), "%s", bluePtr); //Winners + Com_sprintf(otherName, sizeof(otherName), "%s", redPtr); //Losers + Com_sprintf(MVPname, sizeof(name), "%s %s", bluePtr, ingame_text[IGT_MVP]); + } + else if (postgameMenuInfo.playerGameRank == 0) // Red Team Won + { + Com_sprintf(name, sizeof(name), "%s", redPtr); //Winners + Com_sprintf(otherName, sizeof(otherName), "%s", bluePtr); //Losers + Com_sprintf(MVPname, sizeof(name), "%s %s", redPtr, ingame_text[IGT_MVP]); + } + else // Teams Tied + { + Com_sprintf(name, sizeof(name), "%s", ingame_text[IGT_TEAMS_TIED]); + Com_sprintf(otherName, sizeof(otherName), "%s", ingame_text[IGT_TEAMS_TIED]); + Com_sprintf(MVPname, sizeof(name), "%s %s", ingame_text[IGT_OVERALL], ingame_text[IGT_MVP]); + } + + Q_strncpyz( postgameMenuInfo.winTeamText, name, sizeof(postgameMenuInfo.winTeamText) ); + Q_strncpyz( postgameMenuInfo.losTeamText, otherName, sizeof(postgameMenuInfo.losTeamText) ); + Q_strncpyz( postgameMenuInfo.winTeamMVPText, MVPname, sizeof(postgameMenuInfo.winTeamMVPText) ); +} + + +/* +================= +AW_SPPostgameMenu_f + + This function essentially initializes the SPPostgameMenu_t structure + + Is called by the server command "awards ..." +================= +*/ + +void AW_SPPostgameMenu_f( void ) { + int playerGameRank; + int playerClientNum; + int playerTeam; + int n, clNum[3] = {0,0,0}; + int awardFlags; + int numNames; + char temp_string[200]; + + memset( &postgameMenuInfo, 0, sizeof(postgameMenuInfo) ); + + + // IMPORT AWARDS INFORMATION FROM SERVER AND CMD STRING + //___________________________________________________________________________________________ + // + playerClientNum = (cg.snap->ps.clientNum); + playerGameRank = (cg.snap->ps.persistant[PERS_RANK]&~RANK_TIED_FLAG); + //playerTeam = (cg.snap->ps.persistant[PERS_TEAM]); + playerTeam = (cgs.clientinfo[playerClientNum].team);//this should be more accurate + + postgameMenuInfo.starttime = cg.time; // Initialize Timers + postgameMenuInfo.scoreboardtime = cg.time; + postgameMenuInfo.numAwards = 0; // Initialize Awards Count + postgameMenuInfo.playerGameRank = playerGameRank; // Store Player Rank + postgameMenuInfo.numClients = atoi( CG_Argv( 1 ) ); // Store Number Of Clients + postgameMenuInfo.playerTied = (cg.snap->ps.persistant[PERS_RANK] & RANK_TIED_FLAG); + + if (playerTeam == playerGameRank+1 || playerGameRank==2) + postgameMenuInfo.playersTeamWon = qtrue; + else + postgameMenuInfo.playersTeamWon = qfalse; + + + for (n=0; (n>1; + } + + Q_strncpyz( postgameMenuInfo.nameOfMVP, (CG_Argv(numNames + postgameMenuInfo.numAwards + 3)), sizeof(postgameMenuInfo.nameOfMVP) ); + postgameMenuInfo.scoreOfMVP = atoi( CG_Argv(numNames + postgameMenuInfo.numAwards + 4)); + postgameMenuInfo.totalCaptures = atoi( CG_Argv(numNames + postgameMenuInfo.numAwards + 5)); + postgameMenuInfo.totalPoints = atoi( CG_Argv(numNames + postgameMenuInfo.numAwards + 6)); + if (cgs.gametype <= GT_SINGLE_PLAYER) + { + postgameMenuInfo.playerGameRank = atoi( CG_Argv(numNames + postgameMenuInfo.numAwards + 7)); + playerGameRank = postgameMenuInfo.playerGameRank; + } + postgameMenuInfo.playerTied = atoi( CG_Argv(numNames + postgameMenuInfo.numAwards + 8)); + postgameMenuInfo.losCaptures = atoi( CG_Argv(numNames + postgameMenuInfo.numAwards + 9)); + postgameMenuInfo.losPoints = atoi( CG_Argv(numNames + postgameMenuInfo.numAwards + 10)); + postgameMenuInfo.secondPlaceTied = atoi( CG_Argv(numNames + postgameMenuInfo.numAwards + 11)); + VectorSet(postgameMenuInfo.intermission_origin, + atoi( CG_Argv(numNames + postgameMenuInfo.numAwards + 12)), + atoi( CG_Argv(numNames + postgameMenuInfo.numAwards + 13)), + atoi( CG_Argv(numNames + postgameMenuInfo.numAwards + 14))); + VectorSet(postgameMenuInfo.intermission_angle, + atoi( CG_Argv(numNames + postgameMenuInfo.numAwards + 15)), + atoi( CG_Argv(numNames + postgameMenuInfo.numAwards + 16)), + atoi( CG_Argv(numNames + postgameMenuInfo.numAwards + 17))); + + cg.predictedPlayerState.pm_type = PM_INTERMISSION; + VectorCopy(postgameMenuInfo.intermission_origin, cg.predictedPlayerState.origin); + VectorCopy(postgameMenuInfo.intermission_angle, cg.predictedPlayerState.viewangles); + + + // SOUNDS + //___________________________________________________________________________________________ + // + if (postgameMenuInfo.numAwards) + { + postgameMenuInfo.commendationsSound = trap_S_RegisterSound("sound/voice/computer/misc/commendations.wav"); + } + else + { + postgameMenuInfo.commendationsSound = 0; + } + if (cgs.gametype <= GT_SINGLE_PLAYER) // for FFA, TOURNAMENT, and SINGLE_PLAYER TOURNAMENT: + { + if ( playerGameRank != 0 ) + { // Someone else wins + char *skin; + + skin = cgs.clientinfo[clNum[0]].skinName; + + if( Q_stricmp( skin, "default" ) == 0 ) { + skin = cgs.clientinfo[clNum[0]].modelName; + } + if( Q_stricmp( skin, "red" ) == 0 ) { + skin = cgs.clientinfo[clNum[0]].modelName; + } + if( Q_stricmp( skin, "blue" ) == 0 ) { + skin = cgs.clientinfo[clNum[0]].modelName; + } + + postgameMenuInfo.winnerSound = trap_S_RegisterSound( va( "sound/voice/computer/misc/%s_wins.wav", skin ) ); + if (0 == postgameMenuInfo.winnerSound) + { + postgameMenuInfo.winnerSound = trap_S_RegisterSound( va( "sound/voice/computer/misc/progcomp.wav", skin ) ); + } + postgameMenuInfo.winnerDelay = 2500; + if (1 == playerGameRank || postgameMenuInfo.playerTied==2) + { + postgameMenuInfo.youPlacedSound = trap_S_RegisterSound("sound/voice/computer/misc/2nd.wav"); + } + else if (2 == playerGameRank || postgameMenuInfo.playerTied==3) + { + postgameMenuInfo.youPlacedSound = trap_S_RegisterSound("sound/voice/computer/misc/3rd.wav"); + } + else + { + postgameMenuInfo.youPlacedSound = trap_S_RegisterSound("sound/voice/computer/misc/notPlace.wav"); + } + + // You lost, you get to listen to loser music. + // This might be a bit of a downer in FFA, since far more often than not you are not the winner... + // However, in this case the track is NOT a funeral march with an opera singer bellowing "LOSER, LOSER, LOSER, HA HA". + // SOOOOOO for consistency's sake, you will always hear the "loss" track when you don't win. --Pat + trap_S_StartBackgroundTrack( "music/loss", "music/loss" ); + } + else + { // You win + postgameMenuInfo.winnerSound = trap_S_RegisterSound( "sound/voice/computer/misc/youwin.wav" ); + postgameMenuInfo.youPlacedSound = 0; + postgameMenuInfo.winnerDelay = 500; + + // You won, you get to listen to the winner music. + trap_S_StartBackgroundTrack( "music/win", "music/win" ); + } + } + else // for TEAM, and CAPTURE THE FLAG: + { + qboolean bRaceSound = qfalse; + + AW_Prepname( 0); // Set Up "xxxx Team Wins" text + + // THE VOICE + //__________________________________________________ + if (playerGameRank == 1) + { + Com_sprintf(temp_string, sizeof(temp_string), "sound/voice/computer/misc/%s_wins.wav" , CG_ConfigString( CS_BLUE_GROUP )); + + postgameMenuInfo.winnerSound = trap_S_RegisterSound(temp_string); + if (!postgameMenuInfo.winnerSound) + { + postgameMenuInfo.winnerSound = trap_S_RegisterSound( "sound/voice/computer/misc/blueteam_wins.wav" ); + } + else + { + bRaceSound = qtrue; + } + } + else if (playerGameRank == 0) + { + Com_sprintf(temp_string, sizeof(temp_string), "sound/voice/computer/misc/%s_wins.wav" , CG_ConfigString( CS_RED_GROUP )); + + postgameMenuInfo.winnerSound = trap_S_RegisterSound(temp_string); + if (!postgameMenuInfo.winnerSound) + { + postgameMenuInfo.winnerSound = trap_S_RegisterSound( "sound/voice/computer/misc/redteam_wins.wav" ); + } + else + { + bRaceSound = qtrue; + } + } + else if (playerGameRank == 2) + { + postgameMenuInfo.winnerSound = trap_S_RegisterSound( "sound/voice/computer/misc/teamstied.wav" ); + } + if (!bRaceSound && (playerTeam == playerGameRank+1) ) + { + postgameMenuInfo.winnerSound = trap_S_RegisterSound( "sound/voice/computer/misc/yourteam_wins.wav" ); + } + + if (bRaceSound) + { + postgameMenuInfo.winnerDelay = 4000; + } + else + { + postgameMenuInfo.winnerDelay = 1000; + } + + // THE MUSIC + //__________________________________________________ + if (postgameMenuInfo.playersTeamWon) { + trap_S_StartBackgroundTrack( "music/win", "music/win" ); + } else { + trap_S_StartBackgroundTrack( "music/loss", "music/loss" ); + } + } + + //Set To Phase I + postgameMenuInfo.phase = 1; + +} diff --git a/code/cgame/cg_screenfx.c b/code/cgame/cg_screenfx.c new file mode 100644 index 0000000..67be991 --- /dev/null +++ b/code/cgame/cg_screenfx.c @@ -0,0 +1,434 @@ +#include "cg_local.h" +#include "cg_screenfx.h" + +// this is the list of currently drawing fx and their start times and end times +screenFX_t theScreenFX; + +int CG_GetScreenEffectEndTime(int event) +{ + switch (event) + { + case SCREENFX_TRANSPORTER: + return cg.time + 1000; + case SCREENFX_SP_TRANSPORTER_IN: + return cg.time + 4000; + case SCREENFX_SP_TRANSPORTER_OUT: + return cg.time + 8000; + default: + return 0; + } +} + +// maybe play a sound or something? +void CG_BeginScreenEffect(int event) +{ + switch (event) + { + case SCREENFX_TRANSPORTER: + break; + default: + break; + } +} + + +// when adding a new effect, we'll either take an empty slot in theScreenFX or +//overwrite the oldest effect +void CG_AddFullScreenEffect(int screenfx, int clientNum) +{ + int i = 0, oldestTime = cg.time, oldestEffect = 0; + + if (clientNum != cg.predictedPlayerState.clientNum) + { // only add screen effects for our client + return; + } + for (i = 0; i < MAX_SCREENFX; i++) + { + // if we already have one of these effects going, just add to the duration of + //the existing one...don't create a new instance of the same effect + if (theScreenFX.events[i] == screenfx) + { + theScreenFX.cgStartTimes[i] = cg.time; + theScreenFX.cgEndTimes[i] = CG_GetScreenEffectEndTime(screenfx); + return; + } + else if (theScreenFX.cgStartTimes[i]) + { + if (theScreenFX.cgStartTimes[i] < oldestTime) + { + oldestTime = theScreenFX.cgStartTimes[i]; + oldestEffect = i; + } + } + //Hack-didily-ack - TiM: If were already one powerup, switch to the next + else if ( screenfx == SCREENFX_SP_TRANSPORTER_OUT ) { + if ( theScreenFX.events[i] == SCREENFX_SP_TRANSPORTER_IN ) { + theScreenFX.events[i] = 0; + theScreenFX.cgStartTimes[i] = 0; + theScreenFX.cgEndTimes[i] = 0; + } + } + else if ( screenfx == SCREENFX_SP_TRANSPORTER_IN ) { + if ( theScreenFX.events[i] == SCREENFX_SP_TRANSPORTER_OUT ) { + theScreenFX.events[i] = 0; + theScreenFX.cgStartTimes[i] = 0; + theScreenFX.cgEndTimes[i] = 0; + } + } + else + { + oldestTime = theScreenFX.cgStartTimes[i]; + oldestEffect = i; + } + } + theScreenFX.events[oldestEffect] = screenfx; + theScreenFX.cgStartTimes[oldestEffect] = cg.time; + theScreenFX.cgEndTimes[oldestEffect] = CG_GetScreenEffectEndTime(screenfx); + CG_BeginScreenEffect(screenfx); +} + + + +/* +=============== +CG_DrawScreenQuad + +=============== +*/ + + +static void CG_DrawScreenQuad(float alpha, qhandle_t screenshader) +{ + refEntity_t ent; + float radius; + + // ragePro systems can't fade blends, so don't obscure the screen + if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) { + return; + } + + if (cg.refdef.fov_x > 120) + { + return; // Too wide to show this. + } + else if (cg.refdef.fov_x > 80) + { + radius = 8.0 + (cg.refdef.fov_x - 80)*0.2; + } + else + { + radius = 8.0; + } + + memset( &ent, 0, sizeof( ent ) ); + ent.reType = RT_SPRITE; + ent.renderfx = RF_FIRST_PERSON; + + VectorMA( cg.refdef.vieworg, 8, cg.refdef.viewaxis[0], ent.origin ); + + ent.data.sprite.radius = radius; + ent.customShader = screenshader; + ent.shaderRGBA[0] = alpha * 255; + ent.shaderRGBA[1] = alpha * 255; + ent.shaderRGBA[2] = alpha * 255; + ent.shaderRGBA[3] = 255; + trap_R_AddRefEntityToScene( &ent ); +} + +/* +static void CG_DrawDirectionalScreenQuad(float alpha, qhandle_t screenshader) +{ + refEntity_t ent; + vec3_t screencenter; + byte topleft, topright, lowleft, lowright, top, low, left, right; + float val; + + // ragePro systems can't fade blends, so don't obscure the screen + if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) { + return; + } + + // Set up all the basic info about this refentity + VectorMA( cg.refdef.vieworg, 8, cg.refdef.viewaxis[0], screencenter); + + memset( &ent, 0, sizeof( ent ) ); + ent.reType = RT_ALPHAVERTPOLY; + ent.renderfx = RF_FIRST_PERSON; + + ent.data.sprite.radius = 4; + ent.customShader = screenshader; + * (unsigned int *) ent.shaderRGBA = 0xffffffff; + * (unsigned int *) ent.data.sprite.vertRGBA[0] = 0xffffffff; + * (unsigned int *) ent.data.sprite.vertRGBA[1] = 0xffffffff; + * (unsigned int *) ent.data.sprite.vertRGBA[2] = 0xffffffff; + * (unsigned int *) ent.data.sprite.vertRGBA[3] = 0xffffffff; + + // left + val = alpha*(0.5 + 0.5*(cg.damageX - fabs(cg.damageY))); + if (val<0) + left=0; + else if (val>1.0) + left=255; + else + left=255.0*val; + + // upper left + val = alpha*(0.5*(cg.damageX + cg.damageY)); + if (val<0) + topleft=0; + else if (val>1.0) + topleft=255; + else + topleft=255.0*val; + + // top + val = alpha*(0.5 + 0.5*(-fabs(cg.damageX) + cg.damageY)); + if (val<0) + top=0; + else if (val>1.0) + top=255; + else + top=255.0*val; + + // upper right + val = alpha*(0.5*(-cg.damageX + cg.damageY)); + if (val<0) + topright=0; + else if (val>1.0) + topright=255; + else + topright=255.0*val; + + // right + val = alpha*(0.5 + 0.5*(-cg.damageX - fabs(cg.damageY))); + if (val<0) + right=0; + else if (val>1.0) + right=255; + else + right=255.0*val; + + // lower right + val = alpha*(0.5*(-cg.damageX - cg.damageY)); + if (val<0) + lowright=0; + else if (val>1.0) + lowright=255; + else + lowright=255.0*val; + + // bottom + val = alpha*(0.5 + 0.5*(-fabs(cg.damageX) - cg.damageY)); + if (val<0) + low=0; + else if (val>1.0) + low=255; + else + low=255.0*val; + + // lower left + val = alpha*(0.5*(cg.damageX - cg.damageY)); + if (val<0) + lowleft=0; + else if (val>1.0) + lowleft=255; + else + lowleft=255.0*val; + + + // Draw the upper left corner + VectorMA(screencenter, 4, cg.refdef.viewaxis[1], ent.origin); + VectorMA(ent.origin, 4, cg.refdef.viewaxis[2], ent.origin); + ent.data.sprite.vertRGBA[0][3] = topleft; + ent.data.sprite.vertRGBA[1][3] = top; + ent.data.sprite.vertRGBA[2][3] = 0; + ent.data.sprite.vertRGBA[3][3] = left; + trap_R_AddRefEntityToScene( &ent ); + + + // Draw topper right corner + VectorMA(screencenter, -4, cg.refdef.viewaxis[1], ent.origin); + VectorMA(ent.origin, 4, cg.refdef.viewaxis[2], ent.origin); + ent.data.sprite.vertRGBA[0][3] = top; + ent.data.sprite.vertRGBA[1][3] = topright; + ent.data.sprite.vertRGBA[2][3] = right; + ent.data.sprite.vertRGBA[3][3] = 0; + trap_R_AddRefEntityToScene( &ent ); + + + // Draw lower right corner + VectorMA(screencenter, -4, cg.refdef.viewaxis[1], ent.origin); + VectorMA(ent.origin, -4, cg.refdef.viewaxis[2], ent.origin); + ent.data.sprite.vertRGBA[0][3] = 0; + ent.data.sprite.vertRGBA[1][3] = right; + ent.data.sprite.vertRGBA[2][3] = lowright; + ent.data.sprite.vertRGBA[3][3] = low; + trap_R_AddRefEntityToScene( &ent ); + + + // Draw lower left corner + VectorMA(screencenter, 4, cg.refdef.viewaxis[1], ent.origin); + VectorMA(ent.origin, -4, cg.refdef.viewaxis[2], ent.origin); + ent.data.sprite.vertRGBA[0][3] = left; + ent.data.sprite.vertRGBA[1][3] = 0; + ent.data.sprite.vertRGBA[2][3] = low; + ent.data.sprite.vertRGBA[3][3] = lowleft; + trap_R_AddRefEntityToScene( &ent ); + +} +*/ + +static void CG_DrawScreenBlob(float redalpha, float greenalpha) +{ + refEntity_t ent; + float alphascale; + float bluealpha = 0; + + // ragePro systems can't fade blends, so don't obscure the screen + if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) { + return; + } + + memset( &ent, 0, sizeof( ent ) ); + ent.reType = RT_SPRITE; + ent.renderfx = RF_FIRST_PERSON; + + // Available input: + // cg.damageValue: Range from 0 to 1, indicating the amount of damage. + // cg.damageX and cg_damageY: Range from -1 to 1, indicating the location of the damage. + + VectorMA( cg.refdef.vieworg, 8, cg.refdef.viewaxis[0], ent.origin ); + VectorMA( ent.origin, cg.damageX * -8, cg.refdef.viewaxis[1], ent.origin ); + VectorMA( ent.origin, cg.damageY * 8, cg.refdef.viewaxis[2], ent.origin ); + + // Here's the scoop: The closer we are to the center, the more transparent this blob is. + alphascale = (2*fabs(cg.damageX)+fabs(cg.damageY))/3.0; + redalpha *= alphascale; + greenalpha *= alphascale; + + if (redalpha > greenalpha) + { + ent.data.sprite.radius = cg.damageValue * 15 * redalpha; + } + else + { + ent.data.sprite.radius = cg.damageShieldValue * 15 * greenalpha; + } + +/* if (redalpha < 0.01) + { // Just shield damage + ent.customShader = cgs.media.shieldBlobShader; + // Set all colors to the same as green, since the shader is green + redalpha = bluealpha = greenalpha; + } + else*/ if (greenalpha < 0.01) + { // Just pain damage + ent.customShader = cgs.media.painBlobShader; + // Set all colors to the same as red, since the shader is red + greenalpha = bluealpha = redalpha; + } + else + { // Both + ent.customShader = cgs.media.painShieldBlobShader; + } + + ent.shaderRGBA[0] = 0xff * redalpha; + ent.shaderRGBA[1] = 0xff * greenalpha; + ent.shaderRGBA[2] = 0xff * bluealpha; + ent.shaderRGBA[3] = 0xff; + trap_R_AddRefEntityToScene( &ent ); +} + + + +void CG_DrawFullScreenEffect(int screenfx, int start, int end) +{ + float alpha, alpha2 = 0.0; //TiM - second alpha + int end2, start2; + + alpha = (float)(end-cg.time)/(float)(end-start); + + switch (screenfx) + { + case SCREENFX_TRANSPORTER: + CG_DrawScreenQuad(alpha, cgs.media.teleportEffectShader); + break; + case SCREENFX_SP_TRANSPORTER_IN: + end2=end - 2500; + + CG_DrawScreenQuad( alpha, cgs.media.teleportEffectShader); + //Fade in a white quad a little later + if (cg.time <= end2 ) { + alpha2 = (float)(end2-cg.time)/(float)(end2-start); + CG_DrawScreenQuad( alpha2, cgs.media.white2Shader); + } + break; + case SCREENFX_SP_TRANSPORTER_OUT: + start2=start+2500; + end2=end - 4000; + + alpha = (float)(end2-cg.time)/(float)(end2-start); + CG_DrawScreenQuad(( 1.0f - alpha), cgs.media.teleportEffectShader); + if ( cg.time >= start2 ) { + alpha2 = (float)(end2-cg.time)/(float)(end2-start2); + if ( cg.time >= end2 ) + alpha2=0.0f; + + CG_DrawScreenQuad( ( 1.0f - alpha2), cgs.media.white2Shader); + } + break; + default: + break; + } +} + + +void CG_DrawFullScreenFX( void ) +{ + int i = 0, t; + float alpha, redalpha, greenalpha; + + if ( (cg.snap->ps.clientNum != cg.predictedPlayerState.clientNum) || cg.renderingThirdPerson ) + { + return; + } + + t = cg.time - cg.damageTime; + if ( t > 0 && t < DAMAGE_TIME) + { // Draw the blobs. + alpha = 1.0 - ((float)t / (float)DAMAGE_TIME); + + redalpha = alpha*cg.damageValue*1.5; + if (redalpha > 1.0) + { + redalpha = 1.0; + } + + greenalpha = alpha*cg.damageShieldValue*1.5; + if (greenalpha > 1.0) + { + greenalpha = 1.0; + } + + CG_DrawScreenBlob(redalpha, greenalpha); + } + + for (i = 0; i < MAX_SCREENFX; i++) + { + if (theScreenFX.cgEndTimes[i]) + { + if (theScreenFX.cgEndTimes[i] <= cg.time) + { + // remove this effect + theScreenFX.events[i] = 0; + theScreenFX.cgStartTimes[i] = 0; + theScreenFX.cgEndTimes[i] = 0; + } + else + { + // still drawing this effect + CG_DrawFullScreenEffect(theScreenFX.events[i],theScreenFX.cgStartTimes[i],theScreenFX.cgEndTimes[i]); + } + } + } +} diff --git a/code/cgame/cg_screenfx.h b/code/cgame/cg_screenfx.h new file mode 100644 index 0000000..fc43a60 --- /dev/null +++ b/code/cgame/cg_screenfx.h @@ -0,0 +1,28 @@ +// +// full-screen effects like beaming in/out, static from being hit, etc. +// + +enum screenfx_e +{ + SCREENFX_HIT, + SCREENFX_HALFSHIELDHIT, + SCREENFX_FULLSHIELDHIT, + SCREENFX_TRANSPORTER, + SCREENFX_SP_TRANSPORTER_IN, + SCREENFX_SP_TRANSPORTER_OUT, + MAX_SCREENFX +}; + +typedef struct screenFX_s +{ + int events[MAX_SCREENFX]; + int cgStartTimes[MAX_SCREENFX]; + int cgEndTimes[MAX_SCREENFX]; +} screenFX_t; + +extern screenFX_t theScreenFX; + +void CG_AddFullScreenEffect(int screenfx, int clientNum); + +void CG_DrawFullScreenFX(); + diff --git a/code/cgame/cg_servercmds.c b/code/cgame/cg_servercmds.c index 28147c6..bacbe53 100644 --- a/code/cgame/cg_servercmds.c +++ b/code/cgame/cg_servercmds.c @@ -1,62 +1,13 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // // cg_servercmds.c -- reliably sequenced text commands sent by the server // these are processed at snapshot transition time, so there will definately // be a valid snapshot this frame #include "cg_local.h" -#include "../../ui/menudef.h" -typedef struct { - const char *order; - int taskNum; -} orderTask_t; - -static const orderTask_t validOrders[] = { - { VOICECHAT_GETFLAG, TEAMTASK_OFFENSE }, - { VOICECHAT_OFFENSE, TEAMTASK_OFFENSE }, - { VOICECHAT_DEFEND, TEAMTASK_DEFENSE }, - { VOICECHAT_DEFENDFLAG, TEAMTASK_DEFENSE }, - { VOICECHAT_PATROL, TEAMTASK_PATROL }, - { VOICECHAT_CAMP, TEAMTASK_CAMP }, - { VOICECHAT_FOLLOWME, TEAMTASK_FOLLOW }, - { VOICECHAT_RETURNFLAG, TEAMTASK_RETRIEVE }, - { VOICECHAT_FOLLOWFLAGCARRIER, TEAMTASK_ESCORT } -}; - -static const int numValidOrders = ARRAY_LEN(validOrders); - -#ifdef MISSIONPACK -static int CG_ValidOrder(const char *p) { - int i; - for (i = 0; i < numValidOrders; i++) { - if (Q_stricmp(p, validOrders[i].order) == 0) { - return validOrders[i].taskNum; - } - } - return -1; -} -#endif +#define MAX_LOCAL_ENTITIES 512 +extern localEntity_t cg_localEntities[MAX_LOCAL_ENTITIES]; /* ================= @@ -65,7 +16,7 @@ CG_ParseScores ================= */ static void CG_ParseScores( void ) { - int i, powerups; + int i, powerups, eliminated; cg.numScores = atoi( CG_Argv( 1 ) ); if ( cg.numScores > MAX_CLIENTS ) { @@ -77,33 +28,27 @@ static void CG_ParseScores( void ) { memset( cg.scores, 0, sizeof( cg.scores ) ); for ( i = 0 ; i < cg.numScores ; i++ ) { - // - cg.scores[i].client = atoi( CG_Argv( i * 14 + 4 ) ); - cg.scores[i].score = atoi( CG_Argv( i * 14 + 5 ) ); - cg.scores[i].ping = atoi( CG_Argv( i * 14 + 6 ) ); - cg.scores[i].time = atoi( CG_Argv( i * 14 + 7 ) ); - cg.scores[i].scoreFlags = atoi( CG_Argv( i * 14 + 8 ) ); - powerups = atoi( CG_Argv( i * 14 + 9 ) ); - cg.scores[i].accuracy = atoi(CG_Argv(i * 14 + 10)); - cg.scores[i].impressiveCount = atoi(CG_Argv(i * 14 + 11)); - cg.scores[i].excellentCount = atoi(CG_Argv(i * 14 + 12)); - cg.scores[i].guantletCount = atoi(CG_Argv(i * 14 + 13)); - cg.scores[i].defendCount = atoi(CG_Argv(i * 14 + 14)); - cg.scores[i].assistCount = atoi(CG_Argv(i * 14 + 15)); - cg.scores[i].perfect = atoi(CG_Argv(i * 14 + 16)); - cg.scores[i].captures = atoi(CG_Argv(i * 14 + 17)); + cg.scores[i].client = atoi( CG_Argv( i * 11+ 4 ) ); + cg.scores[i].score = atoi( CG_Argv( i * 11+ 5 ) ); + cg.scores[i].ping = atoi( CG_Argv( i * 11+ 6 ) ); + cg.scores[i].time = atoi( CG_Argv( i * 11+ 7 ) ); + cg.scores[i].scoreFlags = atoi( CG_Argv( i * 11+ 8 ) ); + powerups = atoi( CG_Argv( i * 11+ 9 ) ); +// cg.scores[i].faveTarget = atoi( CG_Argv( i * 12+ 10) ); +// cg.scores[i].faveTargetKills = atoi( CG_Argv( i * 12+ 11) ); + cg.scores[i].worstEnemy = atoi( CG_Argv( i * 11+ 10) ); + cg.scores[i].worstEnemyKills= atoi( CG_Argv( i * 11+ 11) ); + cg.scores[i].faveWeapon = atoi( CG_Argv( i * 11+ 12) ); + cg.scores[i].killedCnt = atoi( CG_Argv( i * 11+ 13) ); + eliminated = atoi( CG_Argv( i * 11+ 14) ); if ( cg.scores[i].client < 0 || cg.scores[i].client >= MAX_CLIENTS ) { cg.scores[i].client = 0; } cgs.clientinfo[ cg.scores[i].client ].score = cg.scores[i].score; cgs.clientinfo[ cg.scores[i].client ].powerups = powerups; - - cg.scores[i].team = cgs.clientinfo[cg.scores[i].client].team; + cgs.clientinfo[ cg.scores[i].client ].eliminated = eliminated; } -#ifdef MISSIONPACK - CG_SetScoreSelection(NULL); -#endif } @@ -118,32 +63,39 @@ static void CG_ParseTeamInfo( void ) { int client; numSortedTeamPlayers = atoi( CG_Argv( 1 ) ); - if( numSortedTeamPlayers < 0 || numSortedTeamPlayers > TEAM_MAXOVERLAY ) - { - CG_Error( "CG_ParseTeamInfo: numSortedTeamPlayers out of range (%d)", - numSortedTeamPlayers ); - return; - } for ( i = 0 ; i < numSortedTeamPlayers ; i++ ) { - client = atoi( CG_Argv( i * 6 + 2 ) ); - if( client < 0 || client >= MAX_CLIENTS ) - { - CG_Error( "CG_ParseTeamInfo: bad client number: %d", client ); - return; - } + client = atoi( CG_Argv( i * 2 + 2 ) ); //6 sortedTeamPlayers[i] = client; - cgs.clientinfo[ client ].location = atoi( CG_Argv( i * 6 + 3 ) ); - cgs.clientinfo[ client ].health = atoi( CG_Argv( i * 6 + 4 ) ); + cgs.clientinfo[ client ].location = atoi( CG_Argv( i * 2 + 3 ) ); //6 + + /*cgs.clientinfo[ client ].health = atoi( CG_Argv( i * 6 + 4 ) ); cgs.clientinfo[ client ].armor = atoi( CG_Argv( i * 6 + 5 ) ); cgs.clientinfo[ client ].curWeapon = atoi( CG_Argv( i * 6 + 6 ) ); - cgs.clientinfo[ client ].powerups = atoi( CG_Argv( i * 6 + 7 ) ); + cgs.clientinfo[ client ].powerups = atoi( CG_Argv( i * 6 + 7 ) );*/ } } +/* +================= +CG_ParseHealthInfo +================= +*/ +static void CG_ParseHealthInfo( void ) { + int i; + int client; + int numHealthInfoClients = 0; + + numHealthInfoClients = atoi( CG_Argv( 1 ) ); + + for ( i = 0 ; i < numHealthInfoClients ; i++ ) { + client = atoi( CG_Argv( i * 2 + 2 ) ); + + cgs.clientinfo[ client ].health = atoi( CG_Argv( i * 2 + 3 ) ); + } +} /* ================ CG_ParseServerinfo @@ -158,19 +110,28 @@ void CG_ParseServerinfo( void ) { info = CG_ConfigString( CS_SERVERINFO ); cgs.gametype = atoi( Info_ValueForKey( info, "g_gametype" ) ); - trap_Cvar_Set("g_gametype", va("%i", cgs.gametype)); + cgs.pModAssimilation = atoi( Info_ValueForKey( info, "g_pModAssimilation" ) ); + cgs.pModDisintegration = atoi( Info_ValueForKey( info, "g_pModDisintegration" ) ); + cgs.pModActionHero = atoi( Info_ValueForKey( info, "g_pModActionHero" ) ); + cgs.pModSpecialties = atoi( Info_ValueForKey( info, "g_pModSpecialties" ) ); + cgs.pModElimination = atoi( Info_ValueForKey( info, "g_pModElimination" ) ); cgs.dmflags = atoi( Info_ValueForKey( info, "dmflags" ) ); cgs.teamflags = atoi( Info_ValueForKey( info, "teamflags" ) ); cgs.fraglimit = atoi( Info_ValueForKey( info, "fraglimit" ) ); cgs.capturelimit = atoi( Info_ValueForKey( info, "capturelimit" ) ); cgs.timelimit = atoi( Info_ValueForKey( info, "timelimit" ) ); cgs.maxclients = atoi( Info_ValueForKey( info, "sv_maxclients" ) ); + cgs.ForceClassColor = atoi( Info_ValueForKey( info, "rpg_forceClassColor" ) ); mapname = Info_ValueForKey( info, "mapname" ); Com_sprintf( cgs.mapname, sizeof( cgs.mapname ), "maps/%s.bsp", mapname ); - Q_strncpyz( cgs.redTeam, Info_ValueForKey( info, "g_redTeam" ), sizeof(cgs.redTeam) ); - trap_Cvar_Set("g_redTeam", cgs.redTeam); - Q_strncpyz( cgs.blueTeam, Info_ValueForKey( info, "g_blueTeam" ), sizeof(cgs.blueTeam) ); - trap_Cvar_Set("g_blueTeam", cgs.blueTeam); + + //RPG-X: TiM - new Rankset + Q_strncpyz( cgs.rankSet, Info_ValueForKey( info, "rpg_rankSet"), sizeof(cgs.rankSet) ); + //RPG-X: TiM - new Class set + Q_strncpyz( cgs.classSet, Info_ValueForKey( info, "rpg_classSet" ), sizeof( cgs.classSet ) ); + + //scannable panels + cgs.scannablePanels = atoi( Info_ValueForKey( info, "rpg_scannablePanels" ) ); } /* @@ -190,14 +151,7 @@ static void CG_ParseWarmup( void ) { if ( warmup == 0 && cg.warmup ) { } else if ( warmup > 0 && cg.warmup <= 0 ) { -#ifdef MISSIONPACK - if (cgs.gametype >= GT_CTF && cgs.gametype <= GT_HARVESTER) { - trap_S_StartLocalSound( cgs.media.countPrepareTeamSound, CHAN_ANNOUNCER ); - } else -#endif - { - trap_S_StartLocalSound( cgs.media.countPrepareSound, CHAN_ANNOUNCER ); - } + trap_S_StartLocalSound( cgs.media.countPrepareSound, CHAN_ANNOUNCER ); } cg.warmup = warmup; @@ -216,60 +170,112 @@ void CG_SetConfigValues( void ) { cgs.scores1 = atoi( CG_ConfigString( CS_SCORES1 ) ); cgs.scores2 = atoi( CG_ConfigString( CS_SCORES2 ) ); cgs.levelStartTime = atoi( CG_ConfigString( CS_LEVEL_START_TIME ) ); - if( cgs.gametype == GT_CTF ) { - s = CG_ConfigString( CS_FLAGSTATUS ); - cgs.redflag = s[0] - '0'; - cgs.blueflag = s[1] - '0'; - } -#ifdef MISSIONPACK - else if( cgs.gametype == GT_1FCTF ) { - s = CG_ConfigString( CS_FLAGSTATUS ); - cgs.flagStatus = s[0] - '0'; - } -#endif + s = CG_ConfigString( CS_FLAGSTATUS ); + cgs.redflag = s[0] - '0'; + cgs.blueflag = s[1] - '0'; cg.warmup = atoi( CG_ConfigString( CS_WARMUP ) ); } /* ===================== -CG_ShaderStateChanged +CG_ClientShakeCamera + +TiM: Parses the cam shake +config string, and inputs the useful +data. ===================== */ -void CG_ShaderStateChanged(void) { - char originalShader[MAX_QPATH]; - char newShader[MAX_QPATH]; - char timeOffset[16]; - const char *o; - char *n,*t; +void CG_ClientShakeCamera ( void ) { + float intensity; + int duration; + char *str; - o = CG_ConfigString( CS_SHADERSTATE ); - while (o && *o) { - n = strstr(o, "="); - if (n && *n) { - strncpy(originalShader, o, n-o); - originalShader[n-o] = 0; - n++; - t = strstr(n, ":"); - if (t && *t) { - strncpy(newShader, n, t-n); - newShader[t-n] = 0; - } else { - break; - } - t++; - o = strstr(t, "@"); - if (o) { - strncpy(timeOffset, t, o-t); - timeOffset[o-t] = 0; - o++; - trap_R_RemapShader( originalShader, newShader, timeOffset ); - } - } else { - break; - } - } + str = (char *)CG_ConfigString( CS_CAMERA_SHAKE ); + intensity = (float)atoi( COM_Parse( &str ) )/10.0f; + duration = atoi( COM_Parse( &str ) ); //This is an offset so if a player somehow received + //the string halfway thru the cycle (ie just connected etc) + //This way, it'll only do it as much as is left for the rest of the players + cg.shake_serverIndex = duration; //Back up the index for later + duration -= ( cg.time - cgs.levelStartTime ); //This is the actual duration, based off of length, and the time the command was received + + CG_CameraShake( intensity, duration, qtrue ); } +/* +================== +CG_ParseClassData +================== +*/ +/*void CG_ParseClassData( void ) +{ + char *str; + int i; + char *val; + char *lineChar; + char *lineCharEnd; + int colorBits; + int classBits; + + str = (char *)CG_ConfigString( CS_CLASS_DATA ); + + if ( !str[0] ) + return; + + memset( &cgs.classData, 0, sizeof( cgs.classData ) ); + + for ( i = 0; i < MAX_CLASSES; i++ ) { + val = Info_ValueForKey( str, va( "c%i", i ) ); + + if (!val[0]) + break; + + //First slash = consoleName, so skip that + lineChar = strstr( val, "|"); + lineChar++; + + //next line should be formal name + lineCharEnd = strstr( lineChar, "|" ); + lineCharEnd--; + + val = lineChar; + val[ strlen(lineChar) - strlen(lineCharEnd) + 1] = '\0'; + + Q_strncpyz( cgs.classData[i].formalName, val, sizeof( cgs.classData[i].formalName ) ); + + //CG_Printf( S_COLOR_RED "%s\n", cgs.classData[i].formalName ); + + //--Next is color + + lineChar = lineChar + (strlen(lineChar) - strlen(lineCharEnd))+2; + + lineCharEnd = strstr( lineChar, "|" ); + lineCharEnd--; + + val = lineChar; + val[ strlen(lineChar) - strlen(lineCharEnd)+1] = '\0'; + + colorBits=atoi( val ); + cgs.classData[i].radarColor[0] = colorBits & 255; + cgs.classData[i].radarColor[1] = (colorBits >> 8) & 255; + cgs.classData[i].radarColor[2] = (colorBits >> 16) & 255; + + //CG_Printf( S_COLOR_RED "%i\n", colorBits ); + + //cgs.classData[i].showRanks = (colorBits >> 25) & 1; + + //--Next is Rank Icon Color + lineChar = lineCharEnd+2; + + classBits = atoi( lineChar ); + + cgs.classData[i].isMedic = ( classBits >> 1 ) & 1; + cgs.classData[i].showRanks = ( classBits >> 2 ) & 1; + cgs.classData[i].iconColor = ( classBits >> 4 ) & 15; + + //CG_Printf( S_COLOR_RED "%i\n", classBits ); + } +}*/ + /* ================ CG_ConfigStringModified @@ -292,6 +298,8 @@ static void CG_ConfigStringModified( void ) { // do something with it if necessary if ( num == CS_MUSIC ) { CG_StartMusic(); + } else if ( num == CS_CAMERA_SHAKE ) { //RPG-X : TiM - Camera Shake + CG_ClientShakeCamera(); } else if ( num == CS_SERVERINFO ) { CG_ParseServerinfo(); } else if ( num == CS_WARMUP ) { @@ -300,6 +308,8 @@ static void CG_ConfigStringModified( void ) { cgs.scores1 = atoi( str ); } else if ( num == CS_SCORES2 ) { cgs.scores2 = atoi( str ); + } else if ( num == CS_WARMUP ) { + CG_ParseWarmup(); } else if ( num == CS_LEVEL_START_TIME ) { cgs.levelStartTime = atoi( str ); } else if ( num == CS_VOTE_TIME ) { @@ -313,47 +323,24 @@ static void CG_ConfigStringModified( void ) { cgs.voteModified = qtrue; } else if ( num == CS_VOTE_STRING ) { Q_strncpyz( cgs.voteString, str, sizeof( cgs.voteString ) ); -#ifdef MISSIONPACK - trap_S_StartLocalSound( cgs.media.voteNow, CHAN_ANNOUNCER ); -#endif //MISSIONPACK - } else if ( num >= CS_TEAMVOTE_TIME && num <= CS_TEAMVOTE_TIME + 1) { - cgs.teamVoteTime[num-CS_TEAMVOTE_TIME] = atoi( str ); - cgs.teamVoteModified[num-CS_TEAMVOTE_TIME] = qtrue; - } else if ( num >= CS_TEAMVOTE_YES && num <= CS_TEAMVOTE_YES + 1) { - cgs.teamVoteYes[num-CS_TEAMVOTE_YES] = atoi( str ); - cgs.teamVoteModified[num-CS_TEAMVOTE_YES] = qtrue; - } else if ( num >= CS_TEAMVOTE_NO && num <= CS_TEAMVOTE_NO + 1) { - cgs.teamVoteNo[num-CS_TEAMVOTE_NO] = atoi( str ); - cgs.teamVoteModified[num-CS_TEAMVOTE_NO] = qtrue; - } else if ( num >= CS_TEAMVOTE_STRING && num <= CS_TEAMVOTE_STRING + 1) { - Q_strncpyz( cgs.teamVoteString[num-CS_TEAMVOTE_STRING], str, sizeof( cgs.teamVoteString ) ); -#ifdef MISSIONPACK - trap_S_StartLocalSound( cgs.media.voteNow, CHAN_ANNOUNCER ); -#endif } else if ( num == CS_INTERMISSION ) { cg.intermissionStarted = atoi( str ); } else if ( num >= CS_MODELS && num < CS_MODELS+MAX_MODELS ) { cgs.gameModels[ num-CS_MODELS ] = trap_R_RegisterModel( str ); } else if ( num >= CS_SOUNDS && num < CS_SOUNDS+MAX_SOUNDS ) { if ( str[0] != '*' ) { // player specific sounds don't register here - cgs.gameSounds[ num-CS_SOUNDS] = trap_S_RegisterSound( str, qfalse ); + cgs.gameSounds[ num-CS_SOUNDS] = trap_S_RegisterSound( str ); } } else if ( num >= CS_PLAYERS && num < CS_PLAYERS+MAX_CLIENTS ) { CG_NewClientInfo( num - CS_PLAYERS ); - CG_BuildSpectatorString(); + } else if ( num >= CS_DECOYS && num < CS_DECOYS+MAX_DECOYS ) { + CG_NewDecoyInfo( num - CS_DECOYS ); } else if ( num == CS_FLAGSTATUS ) { - if( cgs.gametype == GT_CTF ) { - // format is rb where its red/blue, 0 is at base, 1 is taken, 2 is dropped - cgs.redflag = str[0] - '0'; - cgs.blueflag = str[1] - '0'; - } -#ifdef MISSIONPACK - else if( cgs.gametype == GT_1FCTF ) { - cgs.flagStatus = str[0] - '0'; - } -#endif + // format is rb where its red/blue, 0 is at base, 1 is taken, 2 is dropped + cgs.redflag = str[0] - '0'; + cgs.blueflag = str[1] - '0'; } - else if ( num == CS_SHADERSTATE ) { + else if(num == CS_SHADERSTATE) { CG_ShaderStateChanged(); } @@ -433,6 +420,8 @@ static void CG_AddToTeamChat( const char *str ) { cgs.teamLastChatPos = cgs.teamChatPos - chatHeight; } + + /* =============== CG_MapRestart @@ -451,7 +440,6 @@ static void CG_MapRestart( void ) { CG_InitLocalEntities(); CG_InitMarkPolys(); - CG_ClearParticles (); // make sure the "3 frags left" warnings play again cg.fraglimitWarnings = 0; @@ -459,526 +447,219 @@ static void CG_MapRestart( void ) { cg.timelimitWarnings = 0; cg.intermissionStarted = qfalse; - cg.levelShot = qfalse; cgs.voteTime = 0; - cg.mapRestart = qtrue; - CG_StartMusic(); - trap_S_ClearLoopingSounds(qtrue); - // we really should clear more parts of cg here and stop sounds // play the "fight" sound if this is a restart without warmup - if ( cg.warmup == 0 /* && cgs.gametype == GT_TOURNAMENT */) { + if ( cg.warmup == 0 /* && cgs.gametype == GT_TOURNAMENT */) + { trap_S_StartLocalSound( cgs.media.countFightSound, CHAN_ANNOUNCER ); - CG_CenterPrint( "FIGHT!", 120, GIANTCHAR_WIDTH*2 ); } -#ifdef MISSIONPACK - if (cg_singlePlayerActive.integer) { - trap_Cvar_Set("ui_matchStartTime", va("%i", cg.time)); - if (cg_recordSPDemo.integer && cg_recordSPDemoName.string && *cg_recordSPDemoName.string) { - trap_SendConsoleCommand(va("set g_synchronousclients 1 ; record %s \n", cg_recordSPDemoName.string)); - } - } -#endif - trap_Cvar_Set("cg_thirdPerson", "0"); } -#define MAX_VOICEFILESIZE 16384 -#define MAX_VOICEFILES 8 -#define MAX_VOICECHATS 64 -#define MAX_VOICESOUNDS 64 -#define MAX_CHATSIZE 64 -#define MAX_HEADMODELS 64 +/*********************** +CG_EncodeIDFile -typedef struct voiceChat_s +The server detected that +we have a pure copy of +the ID, so it's sent us +the IP it received so we +can byte encrypt it into +an ID and save it to file +***********************/ + +static void CG_EncodeIDFile( void ) { - char id[64]; - int numSounds; - sfxHandle_t sounds[MAX_VOICESOUNDS]; - char chats[MAX_VOICESOUNDS][MAX_CHATSIZE]; -} voiceChat_t; + unsigned int playerID; + char *IP; + char strSubnet[3]; + int intSubnet[4]; + int i, j; + + memset(strSubnet, 0, sizeof(strSubnet)); -typedef struct voiceChatList_s -{ - char name[64]; - int gender; - int numVoiceChats; - voiceChat_t voiceChats[MAX_VOICECHATS]; -} voiceChatList_t; + IP = (char *)CG_Argv( 1 ); + //IP = "143.163.12.2"; -typedef struct headModelVoiceChat_s -{ - char headmodel[64]; - int voiceChatNum; -} headModelVoiceChat_t; - -voiceChatList_t voiceChatLists[MAX_VOICEFILES]; -headModelVoiceChat_t headModelVoiceChat[MAX_HEADMODELS]; - -/* -================= -CG_ParseVoiceChats -================= -*/ -int CG_ParseVoiceChats( const char *filename, voiceChatList_t *voiceChatList, int maxVoiceChats ) { - int len, i; - fileHandle_t f; - char buf[MAX_VOICEFILESIZE]; - char **p, *ptr; - char *token; - voiceChat_t *voiceChats; - qboolean compress; - sfxHandle_t sound; - - compress = qtrue; - if (cg_buildScript.integer) { - compress = qfalse; - } - - len = trap_FS_FOpenFile( filename, &f, FS_READ ); - if ( !f ) { - trap_Print( va( S_COLOR_RED "voice chat file not found: %s\n", filename ) ); - return qfalse; - } - if ( len >= MAX_VOICEFILESIZE ) { - trap_Print( va( S_COLOR_RED "voice chat file too large: %s is %i, max allowed is %i\n", filename, len, MAX_VOICEFILESIZE ) ); - trap_FS_FCloseFile( f ); - return qfalse; - } - - trap_FS_Read( buf, len, f ); - buf[len] = 0; - trap_FS_FCloseFile( f ); - - ptr = buf; - p = &ptr; - - Com_sprintf(voiceChatList->name, sizeof(voiceChatList->name), "%s", filename); - voiceChats = voiceChatList->voiceChats; - for ( i = 0; i < maxVoiceChats; i++ ) { - voiceChats[i].id[0] = 0; - } - token = COM_ParseExt(p, qtrue); - if (!token || token[0] == 0) { - return qtrue; - } - if (!Q_stricmp(token, "female")) { - voiceChatList->gender = GENDER_FEMALE; - } - else if (!Q_stricmp(token, "male")) { - voiceChatList->gender = GENDER_MALE; - } - else if (!Q_stricmp(token, "neuter")) { - voiceChatList->gender = GENDER_NEUTER; - } - else { - trap_Print( va( S_COLOR_RED "expected gender not found in voice chat file: %s\n", filename ) ); - return qfalse; - } - - voiceChatList->numVoiceChats = 0; - while ( 1 ) { - token = COM_ParseExt(p, qtrue); - if (!token || token[0] == 0) { - return qtrue; - } - Com_sprintf(voiceChats[voiceChatList->numVoiceChats].id, sizeof( voiceChats[voiceChatList->numVoiceChats].id ), "%s", token); - token = COM_ParseExt(p, qtrue); - if (Q_stricmp(token, "{")) { - trap_Print( va( S_COLOR_RED "expected { found %s in voice chat file: %s\n", token, filename ) ); - return qfalse; - } - voiceChats[voiceChatList->numVoiceChats].numSounds = 0; - while(1) { - token = COM_ParseExt(p, qtrue); - if (!token || token[0] == 0) { - return qtrue; - } - if (!Q_stricmp(token, "}")) - break; - sound = trap_S_RegisterSound( token, compress ); - voiceChats[voiceChatList->numVoiceChats].sounds[voiceChats[voiceChatList->numVoiceChats].numSounds] = sound; - token = COM_ParseExt(p, qtrue); - if (!token || token[0] == 0) { - return qtrue; - } - Com_sprintf(voiceChats[voiceChatList->numVoiceChats].chats[ - voiceChats[voiceChatList->numVoiceChats].numSounds], MAX_CHATSIZE, "%s", token); - if (sound) - voiceChats[voiceChatList->numVoiceChats].numSounds++; - if (voiceChats[voiceChatList->numVoiceChats].numSounds >= MAX_VOICESOUNDS) - break; - } - voiceChatList->numVoiceChats++; - if (voiceChatList->numVoiceChats >= maxVoiceChats) - return qtrue; - } - return qtrue; -} - -/* -================= -CG_LoadVoiceChats -================= -*/ -void CG_LoadVoiceChats( void ) { - int size; - - size = trap_MemoryRemaining(); - CG_ParseVoiceChats( "scripts/female1.voice", &voiceChatLists[0], MAX_VOICECHATS ); - CG_ParseVoiceChats( "scripts/female2.voice", &voiceChatLists[1], MAX_VOICECHATS ); - CG_ParseVoiceChats( "scripts/female3.voice", &voiceChatLists[2], MAX_VOICECHATS ); - CG_ParseVoiceChats( "scripts/male1.voice", &voiceChatLists[3], MAX_VOICECHATS ); - CG_ParseVoiceChats( "scripts/male2.voice", &voiceChatLists[4], MAX_VOICECHATS ); - CG_ParseVoiceChats( "scripts/male3.voice", &voiceChatLists[5], MAX_VOICECHATS ); - CG_ParseVoiceChats( "scripts/male4.voice", &voiceChatLists[6], MAX_VOICECHATS ); - CG_ParseVoiceChats( "scripts/male5.voice", &voiceChatLists[7], MAX_VOICECHATS ); - CG_Printf("voice chat memory size = %d\n", size - trap_MemoryRemaining()); -} - -/* -================= -CG_HeadModelVoiceChats -================= -*/ -int CG_HeadModelVoiceChats( char *filename ) { - int len, i; - fileHandle_t f; - char buf[MAX_VOICEFILESIZE]; - char **p, *ptr; - char *token; - - len = trap_FS_FOpenFile( filename, &f, FS_READ ); - if ( !f ) { - //trap_Print( va( "voice chat file not found: %s\n", filename ) ); - return -1; - } - if ( len >= MAX_VOICEFILESIZE ) { - trap_Print( va( S_COLOR_RED "voice chat file too large: %s is %i, max allowed is %i\n", filename, len, MAX_VOICEFILESIZE ) ); - trap_FS_FCloseFile( f ); - return -1; - } - - trap_FS_Read( buf, len, f ); - buf[len] = 0; - trap_FS_FCloseFile( f ); - - ptr = buf; - p = &ptr; - - token = COM_ParseExt(p, qtrue); - if (!token || token[0] == 0) { - return -1; - } - - for ( i = 0; i < MAX_VOICEFILES; i++ ) { - if ( !Q_stricmp(token, voiceChatLists[i].name) ) { - return i; - } - } - - //FIXME: maybe try to load the .voice file which name is stored in token? - - return -1; -} - - -/* -================= -CG_GetVoiceChat -================= -*/ -int CG_GetVoiceChat( voiceChatList_t *voiceChatList, const char *id, sfxHandle_t *snd, char **chat) { - int i, rnd; - - for ( i = 0; i < voiceChatList->numVoiceChats; i++ ) { - if ( !Q_stricmp( id, voiceChatList->voiceChats[i].id ) ) { - rnd = random() * voiceChatList->voiceChats[i].numSounds; - *snd = voiceChatList->voiceChats[i].sounds[rnd]; - *chat = voiceChatList->voiceChats[i].chats[rnd]; - return qtrue; - } - } - return qfalse; -} - -/* -================= -CG_VoiceChatListForClient -================= -*/ -voiceChatList_t *CG_VoiceChatListForClient( int clientNum ) { - clientInfo_t *ci; - int voiceChatNum, i, j, k, gender; - char filename[MAX_QPATH], headModelName[MAX_QPATH]; - - if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) { - clientNum = 0; - } - ci = &cgs.clientinfo[ clientNum ]; - - for ( k = 0; k < 2; k++ ) { - if ( k == 0 ) { - if (ci->headModelName[0] == '*') { - Com_sprintf( headModelName, sizeof(headModelName), "%s/%s", ci->headModelName+1, ci->headSkinName ); - } - else { - Com_sprintf( headModelName, sizeof(headModelName), "%s/%s", ci->headModelName, ci->headSkinName ); - } - } - else { - if (ci->headModelName[0] == '*') { - Com_sprintf( headModelName, sizeof(headModelName), "%s", ci->headModelName+1 ); - } - else { - Com_sprintf( headModelName, sizeof(headModelName), "%s", ci->headModelName ); - } - } - // find the voice file for the head model the client uses - for ( i = 0; i < MAX_HEADMODELS; i++ ) { - if (!Q_stricmp(headModelVoiceChat[i].headmodel, headModelName)) { - break; - } - } - if (i < MAX_HEADMODELS) { - return &voiceChatLists[headModelVoiceChat[i].voiceChatNum]; - } - // find a .vc file - for ( i = 0; i < MAX_HEADMODELS; i++ ) { - if (!strlen(headModelVoiceChat[i].headmodel)) { - Com_sprintf(filename, sizeof(filename), "scripts/%s.vc", headModelName); - voiceChatNum = CG_HeadModelVoiceChats(filename); - if (voiceChatNum == -1) - break; - Com_sprintf(headModelVoiceChat[i].headmodel, sizeof ( headModelVoiceChat[i].headmodel ), - "%s", headModelName); - headModelVoiceChat[i].voiceChatNum = voiceChatNum; - return &voiceChatLists[headModelVoiceChat[i].voiceChatNum]; - } - } - } - gender = ci->gender; - for (k = 0; k < 2; k++) { - // just pick the first with the right gender - for ( i = 0; i < MAX_VOICEFILES; i++ ) { - if (strlen(voiceChatLists[i].name)) { - if (voiceChatLists[i].gender == gender) { - // store this head model with voice chat for future reference - for ( j = 0; j < MAX_HEADMODELS; j++ ) { - if (!strlen(headModelVoiceChat[j].headmodel)) { - Com_sprintf(headModelVoiceChat[j].headmodel, sizeof ( headModelVoiceChat[j].headmodel ), - "%s", headModelName); - headModelVoiceChat[j].voiceChatNum = i; - break; - } - } - return &voiceChatLists[i]; - } - } - } - // fall back to male gender because we don't have neuter in the mission pack - if (gender == GENDER_MALE) - break; - gender = GENDER_MALE; - } - // store this head model with voice chat for future reference - for ( j = 0; j < MAX_HEADMODELS; j++ ) { - if (!strlen(headModelVoiceChat[j].headmodel)) { - Com_sprintf(headModelVoiceChat[j].headmodel, sizeof ( headModelVoiceChat[j].headmodel ), - "%s", headModelName); - headModelVoiceChat[j].voiceChatNum = 0; - break; - } - } - // just return the first voice chat list - return &voiceChatLists[0]; -} - -#define MAX_VOICECHATBUFFER 32 - -typedef struct bufferedVoiceChat_s -{ - int clientNum; - sfxHandle_t snd; - int voiceOnly; - char cmd[MAX_SAY_TEXT]; - char message[MAX_SAY_TEXT]; -} bufferedVoiceChat_t; - -bufferedVoiceChat_t voiceChatBuffer[MAX_VOICECHATBUFFER]; - -/* -================= -CG_PlayVoiceChat -================= -*/ -void CG_PlayVoiceChat( bufferedVoiceChat_t *vchat ) { -#ifdef MISSIONPACK - // if we are going into the intermission, don't start any voices - if ( cg.intermissionStarted ) { + //TiM - Scooter's IP List + //Double-check we're not spawning an ID off of these + if( Q_stricmp( IP, "localhost" ) //localhost + && Q_strncmp( IP, "10.", 3 ) //class A + && Q_strncmp( IP, "172.16.", 7 ) //class B + && Q_strncmp( IP, "192.168.", 8 ) //class C + && Q_strncmp( IP, "127.", 4 ) //loopback + && Q_strncmp( IP, "169.254.", 8 ) //link-local + ) + { return; } - if ( !cg_noVoiceChats.integer ) { - trap_S_StartLocalSound( vchat->snd, CHAN_VOICE); - if (vchat->clientNum != cg.snap->ps.clientNum) { - int orderTask = CG_ValidOrder(vchat->cmd); - if (orderTask > 0) { - cgs.acceptOrderTime = cg.time + 5000; - Q_strncpyz(cgs.acceptVoice, vchat->cmd, sizeof(cgs.acceptVoice)); - cgs.acceptTask = orderTask; - cgs.acceptLeader = vchat->clientNum; - } - // see if this was an order - CG_ShowResponseHead(); - } - } - if (!vchat->voiceOnly && !cg_noVoiceText.integer) { - CG_AddToTeamChat( vchat->message ); - CG_Printf( "%s\n", vchat->message ); - } - voiceChatBuffer[cg.voiceChatBufferOut].snd = 0; -#endif -} - -/* -===================== -CG_PlayBufferedVoieChats -===================== -*/ -void CG_PlayBufferedVoiceChats( void ) { -#ifdef MISSIONPACK - if ( cg.voiceChatTime < cg.time ) { - if (cg.voiceChatBufferOut != cg.voiceChatBufferIn && voiceChatBuffer[cg.voiceChatBufferOut].snd) { - // - CG_PlayVoiceChat(&voiceChatBuffer[cg.voiceChatBufferOut]); - // - cg.voiceChatBufferOut = (cg.voiceChatBufferOut + 1) % MAX_VOICECHATBUFFER; - cg.voiceChatTime = cg.time + 1000; - } - } -#endif -} - -/* -===================== -CG_AddBufferedVoiceChat -===================== -*/ -void CG_AddBufferedVoiceChat( bufferedVoiceChat_t *vchat ) { -#ifdef MISSIONPACK - // if we are going into the intermission, don't start any voices - if ( cg.intermissionStarted ) { + //check we don't already have an ID + if ( (unsigned)atoul( sv_securityCode.string ) != SECURITY_PID ) return; - } - memcpy(&voiceChatBuffer[cg.voiceChatBufferIn], vchat, sizeof(bufferedVoiceChat_t)); - cg.voiceChatBufferIn = (cg.voiceChatBufferIn + 1) % MAX_VOICECHATBUFFER; - if (cg.voiceChatBufferIn == cg.voiceChatBufferOut) { - CG_PlayVoiceChat( &voiceChatBuffer[cg.voiceChatBufferOut] ); - cg.voiceChatBufferOut++; - } -#endif -} - -/* -================= -CG_VoiceChatLocal -================= -*/ -void CG_VoiceChatLocal( int mode, qboolean voiceOnly, int clientNum, int color, const char *cmd ) { -#ifdef MISSIONPACK - char *chat; - voiceChatList_t *voiceChatList; - clientInfo_t *ci; - sfxHandle_t snd; - bufferedVoiceChat_t vchat; - - // if we are going into the intermission, don't start any voices - if ( cg.intermissionStarted ) { - return; - } - - if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) { - clientNum = 0; - } - ci = &cgs.clientinfo[ clientNum ]; - - cgs.currentVoiceClient = clientNum; - - voiceChatList = CG_VoiceChatListForClient( clientNum ); - - if ( CG_GetVoiceChat( voiceChatList, cmd, &snd, &chat ) ) { - // - if ( mode == SAY_TEAM || !cg_teamChatsOnly.integer ) { - vchat.clientNum = clientNum; - vchat.snd = snd; - vchat.voiceOnly = voiceOnly; - Q_strncpyz(vchat.cmd, cmd, sizeof(vchat.cmd)); - if ( mode == SAY_TELL ) { - Com_sprintf(vchat.message, sizeof(vchat.message), "[%s]: %c%c%s", ci->name, Q_COLOR_ESCAPE, color, chat); - } - else if ( mode == SAY_TEAM ) { - Com_sprintf(vchat.message, sizeof(vchat.message), "(%s): %c%c%s", ci->name, Q_COLOR_ESCAPE, color, chat); - } - else { - Com_sprintf(vchat.message, sizeof(vchat.message), "%s: %c%c%s", ci->name, Q_COLOR_ESCAPE, color, chat); - } - CG_AddBufferedVoiceChat(&vchat); + i = 0; + j = 0; + while ( *IP ) + { + if( *IP != '.' ) + { + if ( i < 3 ) + strSubnet[i++] = *IP; } + else + { + if ( j < 4 ) + intSubnet[j++] = atoi( strSubnet ); + + i=0; + memset( strSubnet, 0, 3 ); + } + + IP++; } -#endif -} + + //the final cell + intSubnet[j++] = atoi( strSubnet ); -/* -================= -CG_VoiceChat -================= -*/ -void CG_VoiceChat( int mode ) { -#ifdef MISSIONPACK - const char *cmd; - int clientNum, color; - qboolean voiceOnly; + //calculate the key + playerID = ( intSubnet[3] << 24 ) | ( intSubnet[2] << 16 ) | ( intSubnet[1] << 8 ) | intSubnet[0]; - voiceOnly = atoi(CG_Argv(1)); - clientNum = atoi(CG_Argv(2)); - color = atoi(CG_Argv(3)); - cmd = CG_Argv(4); + //CG_Printf( "%i %i %i %i - %u\n", intSubnet[0], intSubnet[1], intSubnet[2], intSubnet[3], playerID ); + + //encode the information into the id key file + { + fileHandle_t f; + //unsigned char buffer[SECURITY_SIZE]; + int fileLen; + rpgxSecurityFile_t sF; - if (cg_noTaunt.integer != 0) { - if (!strcmp(cmd, VOICECHAT_KILLINSULT) || !strcmp(cmd, VOICECHAT_TAUNT) || \ - !strcmp(cmd, VOICECHAT_DEATHINSULT) || !strcmp(cmd, VOICECHAT_KILLGAUNTLET) || \ - !strcmp(cmd, VOICECHAT_PRAISE)) { + fileLen = trap_FS_FOpenFile( SECURITY_FILE, &f, FS_READ ); + + if ( !f || fileLen != SECURITY_SIZE ) + { + CG_Error( "ERROR: Could not validate %s file.\n", SECURITY_FILE ); return; } + + trap_FS_Read( &sF, SECURITY_SIZE, f ); + + trap_FS_FCloseFile( f ); + + if ( !sF.ID || sF.ID != SECURITY_ID ) + { + CG_Error( "ERROR: %s was loaded, but it wasn't valid.\n", SECURITY_FILE ); + return; + } + + //ensure the hash is valid + if ( sF.hash != atoul( sv_securityHash.string ) ) + { + CG_Error( "ERROR: %s was loaded, but the hash wasn't valid.\n", SECURITY_FILE ); + return; + } + + //okay, reopen the file for writing, and input the new ID + f = 0; + + fileLen = trap_FS_FOpenFile( SECURITY_FILE, &f, FS_WRITE ); + if ( !f ) + { + CG_Error( "ERROR: Could not validate %s file for writing.\n", SECURITY_FILE ); + return; + } + + //copy over the new key + sF.playerID = playerID; + + trap_FS_Write( &sF, SECURITY_SIZE, f ); + trap_FS_FCloseFile( f ); } - CG_VoiceChatLocal( mode, voiceOnly, clientNum, color, cmd ); -#endif + trap_Cvar_Set( "sv_SecurityCode", va( "%u", playerID ) ); +} + + +/* +================== +ConcatArgs +================== +*/ +char *ConcatArgs2( int start ) { + int i, c, tlen; + static char line[MAX_STRING_CHARS]; + int len; + char arg[MAX_STRING_CHARS]; + + len = 0; + c = trap_Argc(); + for ( i = start ; i < c ; i++ ) { + trap_Argv( i, arg, sizeof( arg ) ); + tlen = strlen( arg ); + if ( len + tlen >= MAX_STRING_CHARS - 1 ) { + break; + } + memcpy( line + len, arg, tlen ); + len += tlen; + if ( i != c - 1 ) { + line[len] = ' '; + len++; + } + } + + line[len] = 0; + + return line; } /* -================= -CG_RemoveChatEscapeChar -================= +===================== +CG_ShaderStateChanged +===================== */ -static void CG_RemoveChatEscapeChar( char *text ) { - int i, l; +void CG_ShaderStateChanged(void) { + char originalShader[MAX_QPATH]; + char newShader[MAX_QPATH]; + char timeOffset[16]; + const char *o; + char *n,*t; - l = 0; - for ( i = 0; text[i]; i++ ) { - if (text[i] == '\x19') - continue; - text[l++] = text[i]; + o = CG_ConfigString( CS_SHADERSTATE ); + + if(!o) return; + + while (o && *o) { + n = strstr(o, "="); + if (n && *n) { + strncpy(originalShader, o, n-o); + originalShader[n-o] = 0; + n++; + t = strstr(n, ":"); + if (t && *t) { + strncpy(newShader, n, t-n); + newShader[t-n] = 0; + } else { + break; + } + t++; + o = strstr(t, "@"); + if (o) { + strncpy(timeOffset, t, o-t); + timeOffset[o-t] = 0; + o++; + trap_R_RemapShader( originalShader, newShader, timeOffset ); + } + } else { + break; + } } - text[l] = '\0'; } + /* ================= CG_ServerCommand @@ -989,7 +670,6 @@ Cmd_Argc() / Cmd_Argv() */ static void CG_ServerCommand( void ) { const char *cmd; - char text[MAX_SAY_TEXT]; cmd = CG_Argv(0); @@ -998,8 +678,33 @@ static void CG_ServerCommand( void ) { return; } + //RPG-X | Phenix | 13/02/2005 + // Play a insult to the n00b when moved into n00b class + if ( !strcmp( cmd, "playN00bInsult") ) { + trap_S_StartLocalSound( cgs.media.N00bSound[(rand()%N00bSoundCount)], CHAN_LOCAL_SOUND ); + CG_CenterPrint( "Welcome to the n00b Class", SCREEN_HEIGHT * 0.25, BIGCHAR_WIDTH ); + return; + } + + // RPG-X | Phenix | 08/06/05 + if ( !strcmp( cmd, "servermsg") ) { + trap_S_StartLocalSound( cgs.media.AdminMsgSound, CHAN_LOCAL_SOUND ); + cg.adminMsgTime = cg.time + 10000; + Q_strncpyz( cg.adminMsgMsg, ConcatArgs2(1), sizeof( cg.adminMsgMsg ) ); + //CG_CenterPrint( cg.adminMsgMsg, SCREEN_HEIGHT * 0.25, BIGCHAR_WIDTH ); + return; + } + + if( !strcmp( cmd, "servercprint") ) { + trap_S_StartLocalSound( cgs.media.AdminMsgSound, CHAN_LOCAL_SOUND ); + //cg.adminMsgTime = cg.time + 10000; + Q_strncpyz( cg.adminMsgMsg, ConcatArgs2(1), sizeof( cg.adminMsgMsg ) ); + CG_CenterPrint( cg.adminMsgMsg, SCREEN_HEIGHT * 0.25, BIGCHAR_WIDTH ); + return; + } + if ( !strcmp( cmd, "cp" ) ) { - CG_CenterPrint( CG_Argv(1), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH ); + CG_CenterPrint( CG_Argv(1), SCREEN_HEIGHT * 0.25, BIGCHAR_WIDTH ); return; } @@ -1010,48 +715,43 @@ static void CG_ServerCommand( void ) { if ( !strcmp( cmd, "print" ) ) { CG_Printf( "%s", CG_Argv(1) ); -#ifdef MISSIONPACK - cmd = CG_Argv(1); // yes, this is obviously a hack, but so is the way we hear about - // votes passing or failing - if ( !Q_stricmpn( cmd, "vote failed", 11 ) || !Q_stricmpn( cmd, "team vote failed", 16 )) { - trap_S_StartLocalSound( cgs.media.voteFailed, CHAN_ANNOUNCER ); - } else if ( !Q_stricmpn( cmd, "vote passed", 11 ) || !Q_stricmpn( cmd, "team vote passed", 16 ) ) { - trap_S_StartLocalSound( cgs.media.votePassed, CHAN_ANNOUNCER ); - } -#endif return; } if ( !strcmp( cmd, "chat" ) ) { - if ( !cg_teamChatsOnly.integer ) { - trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND ); - Q_strncpyz( text, CG_Argv(1), MAX_SAY_TEXT ); - CG_RemoveChatEscapeChar( text ); - CG_Printf( "%s\n", text ); - } + trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND ); + CG_Printf( "%s\n", CG_Argv(1) ); return; } + if ( !strcmp( cmd, "pc" ) ) { + trap_Cvar_Set("ui_playerClass", CG_Argv(1)); + return; + } + + if ( !strcmp( cmd, "prank" ) ) { + trap_Cvar_Set("ui_playerRank", CG_Argv(1)); + return; + } + + /*if ( !strcmp( cmd, "cr" ) ) { + trap_Cvar_VariableStringBuffer( "ui_playerclass", pClass, sizeof(pClass) ); + trap_Cvar_VariableStringBuffer( "ui_playerrank", pRank, sizeof(pRank) ); + + if ( !strcmp( pClass, "maker" ) || !strcmp( pClass, "alphaomega22" ) ) { + trap_SendClientCommand( "class command" ); + trap_SendClientCommand( va( "rank %s", pRank) ); + } + + trap_SendClientCommand( va( "class %s", pClass) ); + trap_SendClientCommand( va( "rank %s", pRank) ); + return; + }*/ + if ( !strcmp( cmd, "tchat" ) ) { trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND ); - Q_strncpyz( text, CG_Argv(1), MAX_SAY_TEXT ); - CG_RemoveChatEscapeChar( text ); - CG_AddToTeamChat( text ); - CG_Printf( "%s\n", text ); - return; - } - if ( !strcmp( cmd, "vchat" ) ) { - CG_VoiceChat( SAY_ALL ); - return; - } - - if ( !strcmp( cmd, "vtchat" ) ) { - CG_VoiceChat( SAY_TEAM ); - return; - } - - if ( !strcmp( cmd, "vtell" ) ) { - CG_VoiceChat( SAY_TELL ); + CG_AddToTeamChat( CG_Argv(1) ); + CG_Printf( "%s\n", CG_Argv(1) ); return; } @@ -1060,16 +760,108 @@ static void CG_ServerCommand( void ) { return; } + if ( !strcmp( cmd, "awards" ) ) { + AW_SPPostgameMenu_f(); + return; + } + if ( !strcmp( cmd, "tinfo" ) ) { CG_ParseTeamInfo(); return; } + if ( !strcmp( cmd, "hinfo" ) ) { + CG_ParseHealthInfo(); + return; + } + if ( !strcmp( cmd, "map_restart" ) ) { CG_MapRestart(); return; } + //TiM: Purge all active effects + if ( !strcmp( cmd, "cg_flushFX" ) ) { + int i; + + for ( i = 0; i < MAX_LOCAL_ENTITIES; i ++ ) { + cg_localEntities[i].endTime = cg.time; + } + return; + } + + /*if ( !strcmp( cmd, "cg_flushAngles" ) ) { + //CG_ResetPlayerEntity( &cg.predictedPlayerEntity ); //&cg_entities[ cg.predictedPlayerState.clientNum ] + cg_entities[cg.predictedPlayerState.clientNum].pe.torso.yawAngle = cg_entities[cg.predictedPlayerState.clientNum].lerpAngles[YAW]; + cg_entities[cg.predictedPlayerState.clientNum].pe.legs.yawAngle = cg_entities[cg.predictedPlayerState.clientNum].lerpAngles[YAW]; + return; + }*/ + + // loaddeferred can be both a servercmd and a consolecmd + if ( !strcmp( cmd, "loaddeferred" ) ) { // FIXME: spelled wrong, but not changing for demo + CG_LoadDeferredPlayers(); + return; + } + + // clientLevelShot is sent before taking a special screenshot for + // the menu system during development + if ( !strcmp( cmd, "clientLevelShot" ) ) { + cg.levelShot = qtrue; + return; + } + + //TiM - client received a command from a turbolift ent + //Show the decks UI + if ( !strcmp( cmd, "lift" ) ) { + trap_SendConsoleCommand( va( "ui_turbolift %i", CG_Argv( 1 ) ) ); + return; + } + + //The server motd thingzor + //RPG-X | Marcin | 15/12/2008 + if ( !strcmp( cmd, "motd" ) ) { + trap_SendConsoleCommand( "ui_motd_reset\n" ); + trap_SendConsoleCommand( "ui_motd\n" ); + return; + } + + //RPG-X | Marcin | 15/12/2008 + if ( !strcmp( cmd, "motd_line" ) ) { + trap_SendConsoleCommand( va( "ui_motd_line \"%s\"\n", CG_Argv( 1 ) ) ); + return; + } + + if ( !strcmp( cmd, "configID" ) ) + { + CG_EncodeIDFile(); + return; + } + + if ( !strcmp( cmd, "changeClientInfo" ) ) + { + //create local copy of the args + //due to the way CG_Argv works + char arg1[64]; + char arg2[64]; + + Q_strncpyz( arg1, CG_Argv(1), sizeof(arg1) ); + Q_strncpyz( arg2, CG_Argv(2), sizeof(arg2) ); + + trap_Cvar_Set( arg1, arg2 ); + return; + } + + if ( !strcmp( cmd, "playSnd" ) ) + { + trap_SendConsoleCommand( va( "play %s", CG_Argv(1) ) ); + return; + } + + if ( !strcmp( cmd, "cg_connect" ) ) { + trap_SendConsoleCommand( va( "connect %s", CG_Argv(1) ) ); + return; + } + if ( Q_stricmp (cmd, "remapShader") == 0 ) { if (trap_Argc() == 4) @@ -1088,16 +880,29 @@ static void CG_ServerCommand( void ) { return; } - // loaddeferred can be both a servercmd and a consolecmd - if ( !strcmp( cmd, "loaddefered" ) ) { // FIXME: spelled wrong, but not changing for demo - CG_LoadDeferredPlayers(); + if(!strcmp(cmd, "ui_transporter")) { + trap_SendConsoleCommand(va("ui_transporter %s", CG_Argv(1))); return; } - // clientLevelShot is sent before taking a special screenshot for - // the menu system during development - if ( !strcmp( cmd, "clientLevelShot" ) ) { - cg.levelShot = qtrue; + if(!strcmp(cmd, "ui_trdata")) { + trap_SendConsoleCommand(va("ui_trdata \"%s\"", CG_Argv(1))); + return; + } + + if(!strcmp(cmd, "holo_data")) { + trap_SendConsoleCommand(va("holo_data \"%s\"", CG_Argv(1))); + return; + } + + if(!strcmp(cmd, "ui_holodeck")) { + trap_SendClientCommand(va("ui_holodeck %i", CG_Argv(1))); + return; + } + + /* TODO remove me? */ + if(!strcmp(cmd, "sqlkey")) { + trap_SendClientCommand(va("sqlkey %i", CG_Argv(1))); return; } diff --git a/code/cgame/cg_snapshot.c b/code/cgame/cg_snapshot.c index 1bf8970..c752e5d 100644 --- a/code/cgame/cg_snapshot.c +++ b/code/cgame/cg_snapshot.c @@ -1,24 +1,4 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // // cg_snapshot.c -- things that happen on snapshot transition, // not necessarily every single rendered frame @@ -33,13 +13,12 @@ CG_ResetEntity ================== */ static void CG_ResetEntity( centity_t *cent ) { - // if the previous snapshot this entity was updated in is at least - // an event window back in time then we can reset the previous event - if ( cent->snapShotTime < cg.time - EVENT_VALID_MSEC ) { - cent->previousEvent = 0; - } + // if an event is set, assume it is new enough to use + // if the event had timed out, it would have been cleared + cent->previousEvent = 0; cent->trailTime = cg.snap->serverTime; + cent->thinkFlag = 0; VectorCopy (cent->currentState.origin, cent->lerpOrigin); VectorCopy (cent->currentState.angles, cent->lerpAngles); @@ -55,8 +34,24 @@ CG_TransitionEntity cent->nextState is moved to cent->currentState and events are fired =============== */ -static void CG_TransitionEntity( centity_t *cent ) { +static void CG_TransitionEntity( centity_t *cent ) +{ +/* qboolean bNoDrawFlag = (cent->currentState.eFlags & EF_CLIENT_NODRAW); + if (cent->nextState.eFlags & EF_NODRAW) + { + // kef -- remove our special client-only flag because the game now believes we should have EF_NODRAW + bNoDrawFlag = qfalse; + } +*/ + // kef -- this will automatically remove EF_CLIENT_NODRAW because the game never sets it cent->currentState = cent->nextState; + +/* if (bNoDrawFlag) + { + cent->currentState.eFlags |= EF_NODRAW; + cent->currentState.eFlags |= EF_CLIENT_NODRAW; + } +*/ cent->currentValid = qtrue; // reset if the entity wasn't in the last frame or was teleported @@ -105,8 +100,7 @@ void CG_SetInitialSnapshot( snapshot_t *snap ) { state = &cg.snap->entities[ i ]; cent = &cg_entities[ state->number ]; - memcpy(¢->currentState, state, sizeof(entityState_t)); - //cent->currentState = *state; + cent->currentState = *state; cent->interpolate = qfalse; cent->currentValid = qtrue; @@ -132,9 +126,11 @@ static void CG_TransitionSnapshot( void ) { if ( !cg.snap ) { CG_Error( "CG_TransitionSnapshot: NULL cg.snap" ); + return; } if ( !cg.nextSnap ) { CG_Error( "CG_TransitionSnapshot: NULL cg.nextSnap" ); + return; } // execute any server string commands before transitioning entities @@ -160,9 +156,6 @@ static void CG_TransitionSnapshot( void ) { for ( i = 0 ; i < cg.snap->numEntities ; i++ ) { cent = &cg_entities[ cg.snap->entities[ i ].number ]; CG_TransitionEntity( cent ); - - // remember time of snapshot this entity was last updated in - cent->snapShotTime = cg.snap->serverTime; } cg.nextSnap = NULL; @@ -176,6 +169,11 @@ static void CG_TransitionSnapshot( void ) { // teleporting checks are irrespective of prediction if ( ( ps->eFlags ^ ops->eFlags ) & EF_TELEPORT_BIT ) { cg.thisFrameTeleport = qtrue; // will be cleared by prediction code + + //TiM - since the cg_view.c file seems to be out of scope here, + //manually reset the 3rd view + CG_ResetThirdPersonViewDamp(); + cg.thirdPersonNoLerp = qtrue; } // if we are not doing client side movement prediction for any @@ -184,6 +182,7 @@ static void CG_TransitionSnapshot( void ) { || cg_nopredict.integer || cg_synchronousClients.integer ) { CG_TransitionPlayerState( ps, ops ); } + } } @@ -211,8 +210,7 @@ static void CG_SetNextSnap( snapshot_t *snap ) { es = &snap->entities[num]; cent = &cg_entities[ es->number ]; - memcpy(¢->nextState, es, sizeof(entityState_t)); - //cent->nextState = *es; + cent->nextState = *es; // if this frame is a teleport, or the entity wasn't in the // previous frame, don't interpolate @@ -261,7 +259,7 @@ static snapshot_t *CG_ReadNextSnapshot( void ) { snapshot_t *dest; if ( cg.latestSnapshotNum > cgs.processedSnapshotNum + 1000 ) { - CG_Printf( "WARNING: CG_ReadNextSnapshot: way out of range, %i > %i\n", + CG_Printf( "WARNING: CG_ReadNextSnapshot: way out of range, %i > %i", cg.latestSnapshotNum, cgs.processedSnapshotNum ); } @@ -277,11 +275,6 @@ static snapshot_t *CG_ReadNextSnapshot( void ) { cgs.processedSnapshotNum++; r = trap_GetSnapshot( cgs.processedSnapshotNum, dest ); - // FIXME: why would trap_GetSnapshot return a snapshot with the same server time - if ( cg.snap && r && dest->serverTime == cg.snap->serverTime ) { - //continue; - } - // if it succeeded, return if ( r ) { CG_AddLagometerSnapshotInfo( dest ); @@ -371,10 +364,10 @@ void CG_ProcessSnapshots( void ) { CG_SetNextSnap( snap ); - // if time went backwards, we have a level restart if ( cg.nextSnap->serverTime < cg.snap->serverTime ) { CG_Error( "CG_ProcessSnapshots: Server time went backwards" ); + return; } } @@ -390,6 +383,7 @@ void CG_ProcessSnapshots( void ) { // assert our valid conditions upon exiting if ( cg.snap == NULL ) { CG_Error( "CG_ProcessSnapshots: cg.snap == NULL" ); + return; } if ( cg.time < cg.snap->serverTime ) { // this can happen right after a vid_restart diff --git a/code/cgame/cg_syscalls.asm b/code/cgame/cg_syscalls.asm index 0874b47..79166d0 100644 --- a/code/cgame/cg_syscalls.asm +++ b/code/cgame/cg_syscalls.asm @@ -1,95 +1,66 @@ code -equ trap_Print -1 -equ trap_Error -2 -equ trap_Milliseconds -3 -equ trap_Cvar_Register -4 -equ trap_Cvar_Update -5 -equ trap_Cvar_Set -6 -equ trap_Cvar_VariableStringBuffer -7 -equ trap_Argc -8 -equ trap_Argv -9 -equ trap_Args -10 -equ trap_FS_FOpenFile -11 -equ trap_FS_Read -12 -equ trap_FS_Write -13 -equ trap_FS_FCloseFile -14 -equ trap_SendConsoleCommand -15 -equ trap_AddCommand -16 -equ trap_SendClientCommand -17 -equ trap_UpdateScreen -18 -equ trap_CM_LoadMap -19 -equ trap_CM_NumInlineModels -20 -equ trap_CM_InlineModel -21 -equ trap_CM_LoadModel -22 -equ trap_CM_TempBoxModel -23 -equ trap_CM_PointContents -24 +equ trap_Print -1 +equ trap_Error -2 +equ trap_Milliseconds -3 +equ trap_Cvar_Register -4 +equ trap_Cvar_Update -5 +equ trap_Cvar_Set -6 +equ trap_Cvar_VariableStringBuffer -7 +equ trap_Argc -8 +equ trap_Argv -9 +equ trap_Args -10 +equ trap_FS_FOpenFile -11 +equ trap_FS_Read -12 +equ trap_FS_Write -13 +equ trap_FS_FCloseFile -14 +equ trap_SendConsoleCommand -15 +equ trap_AddCommand -16 +equ trap_SendClientCommand -17 +equ trap_UpdateScreen -18 +equ trap_CM_LoadMap -19 +equ trap_CM_NumInlineModels -20 +equ trap_CM_InlineModel -21 +equ trap_CM_LoadModel -22 +equ trap_CM_TempBoxModel -23 +equ trap_CM_PointContents -24 equ trap_CM_TransformedPointContents -25 -equ trap_CM_BoxTrace -26 -equ trap_CM_TransformedBoxTrace -27 -equ trap_CM_MarkFragments -28 -equ trap_S_StartSound -29 -equ trap_S_StartLocalSound -30 -equ trap_S_ClearLoopingSounds -31 -equ trap_S_AddLoopingSound -32 -equ trap_S_UpdateEntityPosition -33 -equ trap_S_Respatialize -34 -equ trap_S_RegisterSound -35 -equ trap_S_StartBackgroundTrack -36 -equ trap_R_LoadWorldMap -37 -equ trap_R_RegisterModel -38 -equ trap_R_RegisterSkin -39 -equ trap_R_RegisterShader -40 -equ trap_R_ClearScene -41 -equ trap_R_AddRefEntityToScene -42 -equ trap_R_AddPolyToScene -43 -equ trap_R_AddLightToScene -44 -equ trap_R_RenderScene -45 -equ trap_R_SetColor -46 -equ trap_R_DrawStretchPic -47 -equ trap_R_ModelBounds -48 -equ trap_R_LerpTag -49 -equ trap_GetGlconfig -50 -equ trap_GetGameState -51 -equ trap_GetCurrentSnapshotNumber -52 -equ trap_GetSnapshot -53 -equ trap_GetServerCommand -54 -equ trap_GetCurrentCmdNumber -55 -equ trap_GetUserCmd -56 -equ trap_SetUserCmdValue -57 -equ trap_R_RegisterShaderNoMip -58 -equ trap_MemoryRemaining -59 -equ trap_R_RegisterFont -60 -equ trap_Key_IsDown -61 -equ trap_Key_GetCatcher -62 -equ trap_Key_SetCatcher -63 -equ trap_Key_GetKey -64 -equ trap_PC_AddGlobalDefine -65 -equ trap_PC_LoadSource -66 -equ trap_PC_FreeSource -67 -equ trap_PC_ReadToken -68 -equ trap_PC_SourceFileAndLine -69 -equ trap_S_StopBackgroundTrack -70 -equ trap_RealTime -71 -equ trap_SnapVector -72 -equ trap_RemoveCommand -73 -equ trap_R_LightForPoint -74 -equ trap_CIN_PlayCinematic -75 -equ trap_CIN_StopCinematic -76 -equ trap_CIN_RunCinematic -77 -equ trap_CIN_DrawCinematic -78 -equ trap_CIN_SetExtents -79 -equ trap_R_RemapShader -80 -equ trap_S_AddRealLoopingSound -81 -equ trap_S_StopLoopingSound -82 -equ trap_CM_TempCapsuleModel -83 -equ trap_CM_CapsuleTrace -84 -equ trap_CM_TransformedCapsuleTrace -85 -equ trap_R_AddAdditiveLightToScene -86 -equ trap_GetEntityToken -87 -equ trap_R_AddPolysToScene -88 -equ trap_R_inPVS -89 -equ trap_FS_Seek -90 +equ trap_CM_BoxTrace -26 +equ trap_CM_TransformedBoxTrace -27 +equ trap_CM_MarkFragments -28 +equ trap_S_StartSound -29 +equ trap_S_StartLocalSound -30 +equ trap_S_ClearLoopingSounds -31 +equ trap_S_AddLoopingSound -32 +equ trap_S_UpdateEntityPosition -33 +equ trap_S_Respatialize -34 +equ trap_S_RegisterSound -35 +equ trap_S_StartBackgroundTrack -36 +equ trap_R_LoadWorldMap -37 +equ trap_R_RegisterModel -38 +equ trap_R_RegisterSkin -39 +equ trap_R_RegisterShader -40 +equ trap_R_ClearScene -41 +equ trap_R_AddRefEntityToScene -42 +equ trap_R_AddPolyToScene -43 +equ trap_R_AddLightToScene -44 +equ trap_R_RenderScene -45 +equ trap_R_SetColor -46 +equ trap_R_DrawStretchPic -47 +equ trap_R_ModelBounds -48 +equ trap_R_LerpTag -49 +equ trap_GetGlconfig -50 +equ trap_GetGameState -51 +equ trap_GetCurrentSnapshotNumber -52 +equ trap_GetSnapshot -53 +equ trap_GetServerCommand -54 +equ trap_GetCurrentCmdNumber -55 +equ trap_GetUserCmd -56 +equ trap_SetUserCmdValue -57 +equ trap_R_RegisterShaderNoMip -58 +equ trap_MemoryRemaining -59 +equ trap_R_RegisterShader3D -60 +equ trap_Cvar_Set_No_Modify -61 equ memset -101 equ memcpy -102 @@ -102,5 +73,6 @@ equ floor -108 equ ceil -109 equ testPrintInt -110 equ testPrintFloat -111 -equ acos -112 +equ trap_R_RemapShader -201 +equ trap_R_AddPolysToScene -202 diff --git a/code/cgame/cg_syscalls.c b/code/cgame/cg_syscalls.c index 010be94..72c028c 100644 --- a/code/cgame/cg_syscalls.c +++ b/code/cgame/cg_syscalls.c @@ -1,56 +1,39 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // // cg_syscalls.c -- this file is only included when building a dll // cg_syscalls.asm is included instead when building a qvm -#ifdef Q3_VM -#error "Do not use in VM build" -#endif - #include "cg_local.h" +//TiM | Hack coz VC 6 can't understand Thilo's defnitions :S +//typedef int intptr_t; + static intptr_t (QDECL *syscall)( intptr_t arg, ... ) = (intptr_t (QDECL *)( intptr_t, ...))-1; -Q_EXPORT void dllEntry( intptr_t (QDECL *syscallptr)( intptr_t arg,... ) ) { +void dllEntry( intptr_t (QDECL *syscallptr)( intptr_t arg,... ) ) { syscall = syscallptr; } +/*static int (QDECL *syscall)( int arg, ... ) = (int (QDECL *)( int, ...))-1; + + +void dllEntry( int (QDECL *syscallptr)( int arg,... ) ) { + syscall = syscallptr; +}*/ + int PASSFLOAT( float x ) { - floatint_t fi; - fi.f = x; - return fi.i; + float floatTemp; + floatTemp = x; + return *(int *)&floatTemp; } void trap_Print( const char *fmt ) { syscall( CG_PRINT, fmt ); } -void trap_Error(const char *fmt) -{ - syscall(CG_ERROR, fmt); - // shut up GCC warning about returning functions, because we know better - exit(1); +void trap_Error( const char *fmt ) { + syscall( CG_ERROR, fmt ); } int trap_Milliseconds( void ) { @@ -69,6 +52,10 @@ void trap_Cvar_Set( const char *var_name, const char *value ) { syscall( CG_CVAR_SET, var_name, value ); } +void trap_Cvar_Set_No_Modify( const char *var_name, const char *value ) { + syscall( CG_CVAR_SET_NO_MODIFY, var_name, value ); +} + void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ) { syscall( CG_CVAR_VARIABLESTRINGBUFFER, var_name, buffer, bufsize ); } @@ -101,10 +88,6 @@ void trap_FS_FCloseFile( fileHandle_t f ) { syscall( CG_FS_FCLOSEFILE, f ); } -int trap_FS_Seek( fileHandle_t f, long offset, int origin ) { - return syscall( CG_FS_SEEK, f, offset, origin ); -} - void trap_SendConsoleCommand( const char *text ) { syscall( CG_SENDCONSOLECOMMAND, text ); } @@ -113,10 +96,6 @@ void trap_AddCommand( const char *cmdName ) { syscall( CG_ADDCOMMAND, cmdName ); } -void trap_RemoveCommand( const char *cmdName ) { - syscall( CG_REMOVECOMMAND, cmdName ); -} - void trap_SendClientCommand( const char *s ) { syscall( CG_SENDCLIENTCOMMAND, s ); } @@ -141,10 +120,6 @@ clipHandle_t trap_CM_TempBoxModel( const vec3_t mins, const vec3_t maxs ) { return syscall( CG_CM_TEMPBOXMODEL, mins, maxs ); } -clipHandle_t trap_CM_TempCapsuleModel( const vec3_t mins, const vec3_t maxs ) { - return syscall( CG_CM_TEMPCAPSULEMODEL, mins, maxs ); -} - int trap_CM_PointContents( const vec3_t p, clipHandle_t model ) { return syscall( CG_CM_POINTCONTENTS, p, model ); } @@ -159,12 +134,6 @@ void trap_CM_BoxTrace( trace_t *results, const vec3_t start, const vec3_t end, syscall( CG_CM_BOXTRACE, results, start, end, mins, maxs, model, brushmask ); } -void trap_CM_CapsuleTrace( trace_t *results, const vec3_t start, const vec3_t end, - const vec3_t mins, const vec3_t maxs, - clipHandle_t model, int brushmask ) { - syscall( CG_CM_CAPSULETRACE, results, start, end, mins, maxs, model, brushmask ); -} - void trap_CM_TransformedBoxTrace( trace_t *results, const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, clipHandle_t model, int brushmask, @@ -172,13 +141,6 @@ void trap_CM_TransformedBoxTrace( trace_t *results, const vec3_t start, const ve syscall( CG_CM_TRANSFORMEDBOXTRACE, results, start, end, mins, maxs, model, brushmask, origin, angles ); } -void trap_CM_TransformedCapsuleTrace( trace_t *results, const vec3_t start, const vec3_t end, - const vec3_t mins, const vec3_t maxs, - clipHandle_t model, int brushmask, - const vec3_t origin, const vec3_t angles ) { - syscall( CG_CM_TRANSFORMEDCAPSULETRACE, results, start, end, mins, maxs, model, brushmask, origin, angles ); -} - int trap_CM_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection, int maxPoints, vec3_t pointBuffer, @@ -194,22 +156,14 @@ void trap_S_StartLocalSound( sfxHandle_t sfx, int channelNum ) { syscall( CG_S_STARTLOCALSOUND, sfx, channelNum ); } -void trap_S_ClearLoopingSounds( qboolean killall ) { - syscall( CG_S_CLEARLOOPINGSOUNDS, killall ); +void trap_S_ClearLoopingSounds( void ) { + syscall( CG_S_CLEARLOOPINGSOUNDS ); } void trap_S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ) { syscall( CG_S_ADDLOOPINGSOUND, entityNum, origin, velocity, sfx ); } -void trap_S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ) { - syscall( CG_S_ADDREALLOOPINGSOUND, entityNum, origin, velocity, sfx ); -} - -void trap_S_StopLoopingSound( int entityNum ) { - syscall( CG_S_STOPLOOPINGSOUND, entityNum ); -} - void trap_S_UpdateEntityPosition( int entityNum, const vec3_t origin ) { syscall( CG_S_UPDATEENTITYPOSITION, entityNum, origin ); } @@ -218,8 +172,8 @@ void trap_S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], in syscall( CG_S_RESPATIALIZE, entityNum, origin, axis, inwater ); } -sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed ) { - return syscall( CG_S_REGISTERSOUND, sample, compressed ); +sfxHandle_t trap_S_RegisterSound( const char *sample ) { + return syscall( CG_S_REGISTERSOUND, sample ); } void trap_S_StartBackgroundTrack( const char *intro, const char *loop ) { @@ -242,12 +196,12 @@ qhandle_t trap_R_RegisterShader( const char *name ) { return syscall( CG_R_REGISTERSHADER, name ); } -qhandle_t trap_R_RegisterShaderNoMip( const char *name ) { - return syscall( CG_R_REGISTERSHADERNOMIP, name ); +qhandle_t trap_R_RegisterShader3D( const char *name ) { + return syscall( CG_R_REGISTERSHADER3D, name ); } -void trap_R_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font) { - syscall(CG_R_REGISTERFONT, fontName, pointSize, font ); +qhandle_t trap_R_RegisterShaderNoMip( const char *name ) { + return syscall( CG_R_REGISTERSHADERNOMIP, name ); } void trap_R_ClearScene( void ) { @@ -262,22 +216,10 @@ void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t * syscall( CG_R_ADDPOLYTOSCENE, hShader, numVerts, verts ); } -void trap_R_AddPolysToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num ) { - syscall( CG_R_ADDPOLYSTOSCENE, hShader, numVerts, verts, num ); -} - -int trap_R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ) { - return syscall( CG_R_LIGHTFORPOINT, point, ambientLight, directedLight, lightDir ); -} - void trap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) { syscall( CG_R_ADDLIGHTTOSCENE, org, PASSFLOAT(intensity), PASSFLOAT(r), PASSFLOAT(g), PASSFLOAT(b) ); } -void trap_R_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ) { - syscall( CG_R_ADDADDITIVELIGHTTOSCENE, org, PASSFLOAT(intensity), PASSFLOAT(r), PASSFLOAT(g), PASSFLOAT(b) ); -} - void trap_R_RenderScene( const refdef_t *fd ) { syscall( CG_R_RENDERSCENE, fd ); } @@ -295,13 +237,9 @@ void trap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs ) { syscall( CG_R_MODELBOUNDS, model, mins, maxs ); } -int trap_R_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame, +void trap_R_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame, float frac, const char *tagName ) { - return syscall( CG_R_LERPTAG, tag, mod, startFrame, endFrame, PASSFLOAT(frac), tagName ); -} - -void trap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset ) { - syscall( CG_R_REMAP_SHADER, oldShader, newShader, timeOffset ); + syscall( CG_R_LERPTAG, tag, mod, startFrame, endFrame, PASSFLOAT(frac), tagName ); } void trap_GetGlconfig( glconfig_t *glconfig ) { @@ -348,101 +286,6 @@ int trap_MemoryRemaining( void ) { return syscall( CG_MEMORY_REMAINING ); } -qboolean trap_Key_IsDown( int keynum ) { - return syscall( CG_KEY_ISDOWN, keynum ); -} - -int trap_Key_GetCatcher( void ) { - return syscall( CG_KEY_GETCATCHER ); -} - -void trap_Key_SetCatcher( int catcher ) { - syscall( CG_KEY_SETCATCHER, catcher ); -} - -int trap_Key_GetKey( const char *binding ) { - return syscall( CG_KEY_GETKEY, binding ); -} - -int trap_PC_AddGlobalDefine( char *define ) { - return syscall( CG_PC_ADD_GLOBAL_DEFINE, define ); -} - -int trap_PC_LoadSource( const char *filename ) { - return syscall( CG_PC_LOAD_SOURCE, filename ); -} - -int trap_PC_FreeSource( int handle ) { - return syscall( CG_PC_FREE_SOURCE, handle ); -} - -int trap_PC_ReadToken( int handle, pc_token_t *pc_token ) { - return syscall( CG_PC_READ_TOKEN, handle, pc_token ); -} - -int trap_PC_SourceFileAndLine( int handle, char *filename, int *line ) { - return syscall( CG_PC_SOURCE_FILE_AND_LINE, handle, filename, line ); -} - -void trap_S_StopBackgroundTrack( void ) { - syscall( CG_S_STOPBACKGROUNDTRACK ); -} - -int trap_RealTime(qtime_t *qtime) { - return syscall( CG_REAL_TIME, qtime ); -} - -void trap_SnapVector( float *v ) { - syscall( CG_SNAPVECTOR, v ); -} - -// this returns a handle. arg0 is the name in the format "idlogo.roq", set arg1 to NULL, alteredstates to qfalse (do not alter gamestate) -int trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits) { - return syscall(CG_CIN_PLAYCINEMATIC, arg0, xpos, ypos, width, height, bits); -} - -// stops playing the cinematic and ends it. should always return FMV_EOF -// cinematics must be stopped in reverse order of when they are started -e_status trap_CIN_StopCinematic(int handle) { - return syscall(CG_CIN_STOPCINEMATIC, handle); -} - - -// will run a frame of the cinematic but will not draw it. Will return FMV_EOF if the end of the cinematic has been reached. -e_status trap_CIN_RunCinematic (int handle) { - return syscall(CG_CIN_RUNCINEMATIC, handle); -} - - -// draws the current frame -void trap_CIN_DrawCinematic (int handle) { - syscall(CG_CIN_DRAWCINEMATIC, handle); -} - - -// allows you to resize the animation dynamically -void trap_CIN_SetExtents (int handle, int x, int y, int w, int h) { - syscall(CG_CIN_SETEXTENTS, handle, x, y, w, h); -} - -/* -qboolean trap_loadCamera( const char *name ) { - return syscall( CG_LOADCAMERA, name ); -} - -void trap_startCamera(int time) { - syscall(CG_STARTCAMERA, time); -} - -qboolean trap_getCameraInfo( int time, vec3_t *origin, vec3_t *angles) { - return syscall( CG_GETCAMERAINFO, time, origin, angles ); -} -*/ - -qboolean trap_GetEntityToken( char *buffer, int bufferSize ) { - return syscall( CG_GET_ENTITY_TOKEN, buffer, bufferSize ); -} - -qboolean trap_R_inPVS( const vec3_t p1, const vec3_t p2 ) { - return syscall( CG_R_INPVS, p1, p2 ); +void trap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset ) { + syscall( CG_R_REMAP_SHADER, oldShader, newShader, timeOffset ); } diff --git a/code/cgame/cg_text.h b/code/cgame/cg_text.h new file mode 100644 index 0000000..a7022af --- /dev/null +++ b/code/cgame/cg_text.h @@ -0,0 +1,246 @@ +#ifndef __CG_TEXT_H__ +#define __CG_TEXT_H__ + +// Ingame Text enum +typedef enum +{ + IGT_NONE, + IGT_OUTOFAMMO, + IGT_LOWAMMO, + // Scoreboard + IGT_FRAGGEDBY, + IGT_ASSIMILATEDBY, + IGT_PLACEDWITH, + + IGT_SPECTATOR, + IGT_WAITINGTOPLAY, + IGT_USETEAMMENU, + IGT_FOLLOWING, + IGT_LOADING, + IGT_AWAITINGSNAPSHOT, + IGT_PURESERVER, + IGT_CHEATSAREENABLED, + IGT_TIMELIMIT, + IGT_FRAGLIMIT, + IGT_CAPTURELIMIT, + IGT_READY, + IGT_SB_SCORE, + IGT_SB_LOC, + IGT_SB_PING, + IGT_SB_TIME, + IGT_SB_NAME, + IGT_REDTEAM, + IGT_BLUETEAM, + IGT_SAY, + IGT_SAY_TEAM, + IGT_SAY_CLASS, + + IGT_POINT_LIMIT, + IGT_TIME_LIMIT, + IGT_CAPTURE_LIMIT, + + IGT_GAME_FREEFORALL, + IGT_GAME_SINGLEPLAYER, + IGT_GAME_TOURNAMENT, + IGT_GAME_TEAMHOLOMATCH, + IGT_GAME_CAPTUREFLAG, + IGT_GAME_UNKNOWN, + + IGT_YOUELIMINATED, + IGT_YOUASSIMILATED, + IGT_PLACEWITH, + + IGT_SUICIDES, + IGT_CRATERED, + IGT_WASSQUISHED, + IGT_SANK, + IGT_MELTED, + IGT_INTOLAVA, + IGT_SAWLIGHT, + IGT_WRONGPLACE, + + IGT_TRIPPEDHERGRENADE, + IGT_TRIPPEDITSGRENADE, + IGT_TRIPPEDHISGRENADE, + IGT_BLEWHERSELFUP, + IGT_BLEWITSELFUP, + IGT_BLEWHIMSELFUP, + IGT_MELTEDHERSELF, + IGT_MELTEDITSELF, + IGT_MELTEDHIMSELF, + IGT_SMALLERGUN, + IGT_DESTROYEDHERSELF, + IGT_DESTROYEDITSELF, + IGT_DESTROYEDHIMSELF, + + IGT_TIEDFOR, + + IGT_REDTEAMLEADS, + IGT_BLUETEAMLEADS, + IGT_TO , + IGT_TEAMSARETIED, + + IGT_ATE, + IGT_GRENADE, + + IGT_WITHINBLASTRADIUS, + + IGT_ALMOSTEVADED, + IGT_PHOTONBURST, + IGT_DISPATCHEDBY, + IGT_SCAVENGERWEAPON, + + IGT_NEARLYAVOIDED, + IGT_RAILEDBY, + IGT_ELECTROCUTEDBY, + IGT_DESTROYEDBY, + IGT_TETRYONPULSE, + + IGT_BLASTEDBY, + IGT_STASISWEAPON, + IGT_WASWITHIN, + IGT_TRANSPORTERBEAM, + IGT_WASELIMINATEDBY, + IGT_WASELIMINATED, + + IGT_SNAPSHOT, + + IGT_REPLICATION_MATRIX, + IGT_HOLOGRAPHIC_PROJECTORS, + IGT_SIMULATION_DATA_BASE, + IGT_SAFETY_LOCKS, + IGT_HOLODECKSIMULATION, + IGT_USEDTEAMMENU, + IGT_CONNECTIONINTERRUPTED, + IGT_VOTE, + IGT_YES, + IGT_NO, + IGT_WAITINGFORPLAYERS, + IGT_STARTSIN, + IGT_NONETEXT, + + IGT_EFFICIENCY, + IGT_SHARPSHOOTER, + IGT_UNTOUCHABLE, + IGT_LOGISTICS, + IGT_TACTICIAN, + IGT_DEMOLITIONIST, + IGT_STREAK, + IGT_ROLE, + IGT_SECTION31, + + IGT_ACE, + IGT_EXPERT, + IGT_MASTER, + IGT_CHAMPION, + + IGT_MVP, + IGT_DEFENDER, + IGT_WARRIOR, + IGT_CARRIER, + IGT_INTERCEPTOR, + IGT_BRAVERY, + + IGT_TIED_FOR, + IGT_YOUR_RANK, + + IGT_YOUR_TEAM, + IGT_WON, + IGT_LOST, + IGT_TEAMS_TIED, + + IGT_1ST, + IGT_2ND, + IGT_3RD, + + IGT_WINNER, + IGT_CAPTURES, + IGT_POINTS, + IGT_OVERALL, + + IGT_CLICK_PLAY_AGAIN, + IGT_TITLEELIMINATED, + IGT_WORSTENEMY, + IGT_FAVORITEWEAPON, + IGT_CONNECTING, + IGT_SPECTABBREV, + + IGT_VICTOR, + IGT_DEFEATED, + + IGT_DROWNING, + IGT_CORROSION, + IGT_BOILING, + IGT_COMPRESSION, + IGT_TRANSPORTERACCIDENT, + IGT_IMPACT, + IGT_SUICIDE, + IGT_LASERBURNS, + IGT_MISADVENTURE, + IGT_PHASERBURNS, + IGT_ENERGYSCARS, + IGT_SNIPED, + IGT_INFINITEMODULATION, + IGT_GUNNEDDOWN, + IGT_SCAVENGED, + IGT_PERMANENTSTASIS, + IGT_BLASTED, + IGT_MINED, + IGT_PERFORATED, + IGT_DISRUPTED, + IGT_WELDED, + IGT_DEGAUSSED, + IGT_DESTROYED, + IGT_ANNIHILATED, + IGT_VAPORIZED, + IGT_AUTOGUNNED, + IGT_KNOCKOUT, + IGT_ASSIMILATED, + IGT_ZAPPED, + IGT_UNKNOWN, + IGT_CASUALTY, + IGT_METHOD, + IGT_OBITELIMINATED, + IGT_CREDIT, + IGT_PLEASE, + + IGT_11TH, + IGT_12TH, + IGT_13TH, + IGT_NUM_ST, + IGT_NUM_ND, + IGT_NUM_RD, + IGT_NUM_TH, + + IGT_PLAYERS, + IGT_OBJECTIVES, + + IGT_GAME_ELIMINATION, + IGT_GAME_ASSIMILATION, + IGT_GAME_ACTIONHERO, + IGT_GAME_SPECIALTIES, + IGT_GAME_DISINTEGRATION, + //RPG-X: RedTechie Added new text definitions + IGT_SB_RANK, + IGT_SB_RPGCLASS, + IGT_SB_HEALTHBARLCARS, + IGT_SB_HEALTHSTATUS1, + IGT_SB_HEALTHSTATUS2, + IGT_SB_HEALTHSTATUS3, + IGT_SB_HEALTHSTATUS4, + IGT_SB_HEALTHSTATUS5, + IGT_SB_HEALTHSTATUS6, + IGT_SB_FLIGHTSTATUS, + IGT_SB_CLOAKSTATUS, + IGT_SB_EVOSUITSTATUS, + IGT_PINGEDOUT, + IGT_FORCEFIELDDEATH, + IGT_FORCEDSUICIDE, + + IGT_MAX +} ingameTextType_t; + + +extern char *ingame_text[IGT_MAX]; + +#endif //__CG_TEXT_H__ diff --git a/code/cgame/cg_view.c b/code/cgame/cg_view.c index 10cc097..76fc859 100644 --- a/code/cgame/cg_view.c +++ b/code/cgame/cg_view.c @@ -1,29 +1,13 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // // cg_view.c -- setup all the parameters (position, angle, etc) // for a 3D rendering #include "cg_local.h" +#include "cg_screenfx.h" +#define MAX_SHAKE_INTENSITY 16.0f + +#define FRAMES_DOOR 16 /* ============================================================================= @@ -109,7 +93,7 @@ Replaces the current view weapon with the given model void CG_TestGun_f (void) { CG_TestModel_f(); cg.testGun = qtrue; - cg.testModelEntity.renderfx = RF_MINLIGHT | RF_DEPTHHACK | RF_FIRST_PERSON; + cg.testModelEntity.renderfx = RF_DEPTHHACK | RF_FIRST_PERSON; } @@ -167,11 +151,8 @@ static void CG_AddTestModel (void) { trap_R_AddRefEntityToScene( &cg.testModelEntity ); } - - //============================================================================ - /* ================= CG_CalcVrect @@ -198,84 +179,563 @@ static void CG_CalcVrect (void) { } } - cg.refdef.width = cgs.glconfig.vidWidth*size/100; + cg.refdef.width = cgs.glconfig.vidWidth*size * 0.01; cg.refdef.width &= ~1; - cg.refdef.height = cgs.glconfig.vidHeight*size/100; + cg.refdef.height = cgs.glconfig.vidHeight*size * 0.01; cg.refdef.height &= ~1; - cg.refdef.x = (cgs.glconfig.vidWidth - cg.refdef.width)/2; - cg.refdef.y = (cgs.glconfig.vidHeight - cg.refdef.height)/2; + cg.refdef.x = (cgs.glconfig.vidWidth - cg.refdef.width) * 0.5; + cg.refdef.y = (cgs.glconfig.vidHeight - cg.refdef.height) * 0.5; } //============================================================================== +/*============================================================================== +New Third Person Camera Code +TiM: Based off of the logic of the camera code in Raven's Jedi Knight series, +however written by me, and tuned down since EF may not be that fast to handle +all of it. + +Although I consider copying someone else's logic to be somewhat lame, my programming +skills are not yet at the point I could do this by myself. I understand the concept behind +how the camera is offset and how the relevant angles are calculated, but am unsure how this +is coupled with a non-linear interpolation algorithm. +I am hoping that being able to trace how the JK code works will enlighten me to some +furthur graphical programming methodology + +Meanings of CG variables from JKA: + +Notes on the camera viewpoint in and out... + +cg.refdef.vieworg +--at the start of the function holds the player actor's origin (center of player model). +--it is set to the final view location of the camera at the end of the camera code. +cg.refdef.viewangles +--at the start holds the client's view angles +--it is set to the final view angle of the camera at the end of the camera code. +*/ + +//TiM: Static Global Variables +#define CAMERA_DAMP_INTERVAL 50 +#define CAMERA_SIZE 4 +#define MASK_CAMERACLIP (MASK_SOLID|CONTENTS_PLAYERCLIP) + +//Bounding Boxes for volume traces +static vec3_t cameraMins = { -CAMERA_SIZE, -CAMERA_SIZE, -CAMERA_SIZE }; +static vec3_t cameraMaxs = { CAMERA_SIZE, CAMERA_SIZE, CAMERA_SIZE }; + +//Directional Vectors +vec3_t cameraForward, cameraUp, cameraRight; + +vec3_t cameraFocusAngles, cameraFocusLoc; //location and view angles of the player's head +vec3_t cameraIdealTarget, cameraIdealLoc; //location and view angles of where the camera should be +vec3_t cameraCurTarget={0,0,0}, cameraCurLoc={0,0,0}; //Current view and location of camera +vec3_t CameraOldLoc={0,0,0}, cameraNewLoc={0,0,0}; //Backup data for the lerp func + +int cameraLastFrame=0; + +float cameraLastYaw=0; +float cameraStiffFactor=0.0f; + +qboolean freeRotate; + +/* +=============== +CG_CalcIdealThirdPersonViewTarget +TiM: +First Function : Calculate the point we should be looking at +as long as nothing is in the way +=============== +*/ +static void CG_CalcIdealThirdPersonViewTarget ( void ) { + //ATM, vieworg is the base of the feet + VectorCopy ( cg.refdef.vieworg, cameraFocusLoc ); + + //offset the Z value so it lines up with the eyeheight of the player + if ( freeRotate ) + VectorMA( cameraFocusLoc, (float)cg.predictedPlayerState.viewheight * cgs.clientinfo[cg.predictedPlayerState.clientNum].height, cameraUp, cameraFocusLoc ); + else + cameraFocusLoc[2] += (float)cg.predictedPlayerState.viewheight * cgs.clientinfo[cg.predictedPlayerState.clientNum].height; //cg.snap->ps.viewheight + + // emote based model offset + if ( cg.predictedPlayerState.stats[EMOTES] & EMOTE_LOWER ) + { + vec3_t yawForward, forward; + VectorSet( yawForward, 0, cg.predictedPlayerEntity.pe.legs.yawAngle, 0 ); + AngleVectors( yawForward, forward, NULL, NULL ); + + VectorMA( cameraFocusLoc, cgs.clientinfo[cg.predictedPlayerState.clientNum].modelOffset, forward, cameraFocusLoc ); + } + + //Transfer FocusLoc to CamTarget and use that from there + VectorCopy( cameraFocusLoc, cameraIdealTarget ); + + //Add in Horz offset + if ( cg.zoomedLeft ) { + float ratio = cg_thirdPersonRange.value * 0.02f; + if ( ratio > 1.0f ) ratio = 1.0f; + + cg_thirdPersonHorzOffset.value += ( cg_thirdPersonZoomRate.value * ratio * 0.075 ); + } + if ( cg.zoomedRight ) { + float ratio = cg_thirdPersonRange.value * 0.02f; + if ( ratio > 1.0f ) ratio = 1.0f; + + cg_thirdPersonHorzOffset.value -= ( cg_thirdPersonZoomRate.value * ratio * 0.075 ); + } + + if ( cg_thirdPersonHorzOffset.value ) { + VectorMA( cameraIdealTarget, -cg_thirdPersonHorzOffset.value, cameraRight, cameraIdealTarget ); + } + + //Add in the vertOffset + if ( cg.zoomedUp ) { + float ratio = cg_thirdPersonRange.value * 0.02f; + if ( ratio > 1.0f ) ratio = 1.0f; + + cg_thirdPersonVertOffset.value += ( cg_thirdPersonZoomRate.value * ratio * 0.075 ); + } + if ( cg.zoomedDown ) { + float ratio = cg_thirdPersonRange.value * 0.02f; + if ( ratio > 1.0f ) ratio = 1.0f; + + cg_thirdPersonVertOffset.value -= ( cg_thirdPersonZoomRate.value * ratio * 0.075 ); + } + if ( cg_thirdPersonVertOffset.value ) { + if ( freeRotate ) + VectorMA( cameraFocusLoc, cg_thirdPersonVertOffset.value, cameraUp, cameraFocusLoc ); + else + cameraIdealTarget[2] += cg_thirdPersonVertOffset.value; + } +} + +/* +=============== +CG_CalcIdealThirdPersonViewLocation +TiM: +Second Function : Calculate the point we should be looking out +from given all is good :) +=============== +*/ +static void CG_CalcIdealThirdPersonViewLocation ( void ) { + //float offset; + + if ( cg.zoomedForward ) { + cg_thirdPersonRange.value -= ( cg_thirdPersonZoomRate.value * 0.1 ); + } + else if ( cg.zoomedBackward ) { + cg_thirdPersonRange.value += ( cg_thirdPersonZoomRate.value * 0.1 ); + } + + VectorMA( cameraIdealTarget, -cg_thirdPersonRange.value, cameraForward, cameraIdealLoc ); +} + +/* +=============== +CG_ResetThirdPersonViewDamp +TiM: +Third Function : Reset all of the lerp and +set it back to normal +=============== +*/ + +void CG_ResetThirdPersonViewDamp ( void ) { + trace_t tr; + + //Clamp the pitch, so it won't cause bugs + if ( !freeRotate ) + cameraFocusAngles[PITCH] = Com_Clamp( -89.0f, 89.0f, cameraFocusAngles[PITCH] ); + + //Take our look directions and calculate vector angles + AngleVectors( cameraFocusAngles, cameraForward, cameraRight, cameraUp ); + + //Calc ideal cam target now + CG_CalcIdealThirdPersonViewTarget(); + + //Calc ideal cam view loaction now + CG_CalcIdealThirdPersonViewLocation(); + + //Take our ideal locations, and then set them to our active variables + VectorCopy( cameraIdealLoc, cameraCurLoc ); + VectorCopy( cameraIdealTarget, cameraCurTarget ); + + //Do a trace from the player's head out to the main location, in case something may be in the way + //This is mainly for stopping things like the camera going thru ceilings n stuff + CG_Trace( &tr, cameraFocusLoc, cameraMins, cameraMaxs, cameraCurTarget, cg.snap->ps.clientNum, MASK_CAMERACLIP ); + VectorCopy( tr.endpos, cameraCurTarget ); + + //Do a trace from the target to our current location to see if there's anything potentially + //blocking our view + CG_Trace( &tr, cameraCurTarget, cameraMins, cameraMaxs, cameraCurLoc, cg.snap->ps.clientNum, MASK_CAMERACLIP ); + VectorCopy( tr.endpos, cameraCurLoc ); + + //Initialise the lerp data + cameraLastFrame = cg.time; + cameraLastYaw = cameraFocusAngles[YAW]; + cameraStiffFactor = 0.0f; +} + +/* +====================== +CG_UpdateThirdPersonTargetDamp + +TiM: From the looks of this, target damp lags +the position of the camera behind a certain amount +when the player moves. The end result being a more +fluid movement. :) +Still trying to figure out how lerp actually works. +====================== +*/ +static void CG_UpdateThirdPersonTargetDamp ( void ) { + trace_t tr; + vec3_t targetDiff; //difference between our aimed target and current target + float dampFactor, dampTime, dampRatio; + + //Just to be on the safe side, let's set the current ideal data again + CG_CalcIdealThirdPersonViewTarget(); + + //if the CVAR says no delay, or if we're currently teleporting, don't do the lerp (Or we could make the player sick lol) + if ( cg_thirdPersonTargetDamp.value >= 1.0 || cg.thisFrameTeleport || cg.nextFrameTeleport || freeRotate || cg.thirdPersonNoLerp ) { + VectorCopy( cameraIdealTarget, cameraCurTarget ); + } + else if ( cg_thirdPersonTargetDamp.value >= 0.0 ) { //Okay, all's good, so let's get lerping lol + //First, let's get the difference between where we're at, and where we should be + VectorSubtract( cameraIdealTarget, cameraCurTarget, targetDiff ); + + //Ugh.... maaaaath >.< + //The JKA code says the equation is "(Damp)^(time)", so I'm guessing it's inverse exponential to + //get that cool slowy down effect :) + if ( !freeRotate ) + dampFactor = 1.0 - cg_thirdPersonTargetDamp.value; //yeh, I guess this is the inverse exponential bit. + else + dampFactor = 1.0 - Q_fabs( cameraFocusAngles[PITCH] ) / 90.0f; + + dampTime = (float)(cg.time - cameraLastFrame) * (1.0f/(float)CAMERA_DAMP_INTERVAL); //chikushou! I don't know how this time factor is caluclated O_o + + //Square this number for each unit of dampTime + dampRatio = Q_powf( dampFactor, dampTime); + + //Okay, so our current position is calulated as the difference * -ratio + ideal... O_o + VectorMA( cameraIdealTarget, -dampRatio, targetDiff, cameraCurTarget ); + } + + //Now, let's make sure we didn't lerp our way into a wall or summin + CG_Trace( &tr, cameraFocusLoc, cameraMins, cameraMaxs, cameraCurTarget, cg.snap->ps.clientNum, MASK_CAMERACLIP ); + if ( tr.fraction < 1.0 ) { + VectorCopy( tr.endpos, cameraCurTarget ); + } +} + +/* +=============== +CG_UpdateThirdPersonCameraDamp + +TiM: Okay, since the above function lagged +the camera's position, logic stands to reason +this one lags the camera's actual angles. +With the dynamic crosshair enabled, this should look pretty damn sweet. :) +Looks somewhat similar to Target Damp +================ +*/ +static void CG_UpdateThirdPersonCameraDamp ( void ) { + trace_t tr; + vec3_t locationDiff; + float dampFactor=0.0, dampTime, dampRatio; + + //Initialise our goal angle + CG_CalcIdealThirdPersonViewLocation(); + + //If we need to do any damping at all + if ( cg_thirdPersonCameraDamp.value != 0.0 ) { + float pitch; + + //get pitch, and make it all positive. Direction don't matter here + pitch = Q_fabs( cameraFocusAngles[PITCH] ); + + //If we're floating and rotate all around, perform this so the damping isn't so extreme + /*if ( pitch > 89.0f ) { + pitch = 90.0f - ( pitch - 90.0f ); + }*/ + + //The JKA code says these statments are to get it to damp less the more u look up. + //Makes sense. Still looking how tho lol + pitch /= 115.0; //magic number I guess lol. + dampFactor = (1.0-cg_thirdPersonCameraDamp.value) * ( pitch * pitch ); + + dampFactor += cg_thirdPersonCameraDamp.value; + + //the stiff factor is based off speed, so faster yaw changes seem stiffer + if ( cameraStiffFactor > 0.0f ) { + dampFactor += ( 1.0 - dampFactor) * cameraStiffFactor; + } + } + + //if our result meant no damping, or we're actively teleporting + //sigh I guess we'll need to disable dampin upon rotation. it causes absolute hell at the model's polar angles + if ( dampFactor >= 1.0 || cg.thisFrameTeleport || cg.nextFrameTeleport || freeRotate || cg.thirdPersonNoLerp ) { + VectorCopy( cameraIdealLoc, cameraCurLoc ); + } + else if ( dampFactor >= 0.0 ) { + //First, let's get the difference between where we're at, and where we should be + VectorSubtract( cameraIdealLoc, cameraCurLoc, locationDiff ); + + //Ugh.... maaaaath >.< + //The JKA code says the equation is "(Damp)^(time)", so I'm guessing it's inverse exponential to + //get that cool slowy down effect :) + dampFactor = 1.0 - dampFactor; //yeh, I guess this is the inverse exponential bit. + dampTime = (float)(cg.time - cameraLastFrame) * (1.0/(float)CAMERA_DAMP_INTERVAL); //chikushou! I don't know how this time factor is caluclated O_o + + //Square this number for each unit of dampTime + dampRatio = Q_powf( dampFactor, dampTime); + + //Okay, so our current position is calulated as the difference * -ratio + ideal... O_o + VectorMA( cameraIdealLoc, -dampRatio, locationDiff, cameraCurLoc ); + } + + //Now do a trace to see if we're all good for this loc + CG_Trace( &tr, cameraCurTarget, cameraMins, cameraMaxs, cameraCurLoc, cg.snap->ps.clientNum, MASK_CAMERACLIP ); + + //Now Raven added a huge hacky code tidbit at this stage regarding being on moving entities + //I'll see if I can get away without instituting it... + if ( tr.fraction < 1.0 ) { + VectorCopy( tr.endpos, cameraCurLoc ); + } +} /* =============== CG_OffsetThirdPersonView +TiM: The end is nigh! +So, all of the funky code above is +finally consolidated into this main function. + +Let's see if I can understand this in any way lol =============== */ -#define FOCUS_DISTANCE 512 static void CG_OffsetThirdPersonView( void ) { + vec3_t diff; + float deltaYaw; + qboolean neg=qfalse; + + cameraStiffFactor = 0.0f; + + //TiM: change the math a tad if we're in free rotate mode + if ( cg.predictedPlayerEntity.currentState.eFlags & EF_FULL_ROTATE ) + freeRotate = qtrue; + else + freeRotate = qfalse; + + //copy in our raw data values + VectorCopy( cg.refdefViewAngles, cameraFocusAngles ); + + //Add a rotation offset for viewAngle + if ( cg.zoomAngleRight ) { + cg_thirdPersonAngle.value -= ( cg_thirdPersonZoomRate.value * 0.1 ); + } + if ( cg.zoomAngleLeft ) { + cg_thirdPersonAngle.value += ( cg_thirdPersonZoomRate.value * 0.1 ); + } + cameraFocusAngles[YAW] -= cg_thirdPersonAngle.value; //TiM - offset so it swings the right way lol + + //Add in pitch + if ( cg.zoomPitchUp ) { + cg_thirdPersonPitchOffset.value += ( cg_thirdPersonZoomRate.value * 0.075 ); + cg_thirdPersonPitchOffset.value = Com_Clamp( -89.0f, 89.0f, cg_thirdPersonPitchOffset.value ); + } + if ( cg.zoomPitchDown ) { + cg_thirdPersonPitchOffset.value -= ( cg_thirdPersonZoomRate.value * 0.075 ); + cg_thirdPersonPitchOffset.value = Com_Clamp( -89.0f, 89.0f, cg_thirdPersonPitchOffset.value ); + } + cameraFocusAngles[PITCH] += cg_thirdPersonPitchOffset.value; + + //if something messed up, or we're just starting, initiliaze sample + if ( cameraLastFrame == 0 || cameraLastFrame > cg.time ) { + CG_ResetThirdPersonViewDamp(); + } + else { + //Cap the final angles :) + if ( !freeRotate ) { + cameraFocusAngles[PITCH] = Com_Clamp( -80.0, 89.0, cameraFocusAngles[PITCH] ); + } + + AngleVectors( cameraFocusAngles, cameraForward, cameraRight, cameraUp ); + + deltaYaw = fabs( cameraFocusAngles[YAW] - cameraLastYaw ); + //if we exceeded our norms, stick it back + if (deltaYaw > 180.0f ) { + deltaYaw = fabs( deltaYaw - 360.0f ); + } + + cameraStiffFactor = deltaYaw / (float)(cg.time-cameraLastFrame); + if ( cameraStiffFactor < 1.0 ) { + cameraStiffFactor = 0.0; + } + else if ( cameraStiffFactor > 2.5 ) { + cameraStiffFactor = 0.75; + } + else { + cameraStiffFactor = (cameraStiffFactor-1.0f)*0.5f; + } + cameraLastYaw = cameraFocusAngles[YAW]; + + CG_UpdateThirdPersonTargetDamp(); + CG_UpdateThirdPersonCameraDamp(); + } + + VectorSubtract( cameraCurTarget, cameraCurLoc, diff ); + + //if we're hitting something, use cameraForward to calc new angles + if ( VectorNormalize(diff) == 0 || diff[0] == 0 || diff[1] == 0 ) { + VectorCopy( cameraForward, diff ); + } + + //Hack-a-dood-do. vectoangles cannot comprehend if a player is upside-down. + //It assumes it's just an opposite direction vector, so everything is rendered the right way up. >.< + //To fix this, I'll hackily copy the viewangle pitch data, and then reset the angles afterwards + + if ( freeRotate && Q_fabs( cg.refdefViewAngles[PITCH] ) > 90.0f ) + neg = qtrue; + + vectoangles( diff, cg.refdefViewAngles ); + + //Also if rotating, provide an offset when players turn fully upside down + if ( freeRotate && neg ) { + cg.refdefViewAngles[ROLL] -= 180; //AngleNormalize360( cg.refdefViewAngles[YAW] - 180); + } + + /*if ( cg_thirdPersonHorzOffset.value != 0.0f ) { + AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis ); + VectorMA( cameraCurLoc, cg_thirdPersonHorzOffset.value, cg.refdef.viewaxis[1], cameraCurLoc ); + }*/ + + //And update our origin lol + VectorCopy( cameraCurLoc, cg.refdef.vieworg ); + + cameraLastFrame = cg.time; +} + +#define FOCUS_DISTANCE 512 //512 +/*static void CG_OffsetThirdPersonView( void ) { vec3_t forward, right, up; vec3_t view; vec3_t focusAngles; trace_t trace; - static vec3_t mins = { -4, -4, -4 }; - static vec3_t maxs = { 4, 4, 4 }; + static vec3_t mins = { -4, -4, -4 }; + static vec3_t maxs = { 4, 4, 4 }; vec3_t focusPoint; float focusDist; float forwardScale, sideScale; - - cg.refdef.vieworg[2] += cg.predictedPlayerState.viewheight; + char medicrevive[32]; + int medicrevive_int; + vec3_t camPlayerPos; //TiM + + //cg.refdef.vieworg[2] += cg.predictedPlayerState.viewheight; + cg.refdef.vieworg[2] += cg.predictedPlayerState.viewheight * cgs.clientinfo[cg.predictedPlayerState.clientNum].height; VectorCopy( cg.refdefViewAngles, focusAngles ); + VectorCopy( cg.refdef.vieworg, camPlayerPos); //Copy the values b4 we offset; + //RPG-X: TiM - Incorporated offsets so third person can be more dynamic + //Woo! I figured out how AngleVectors and VectorMA work!! ^_^ + AngleVectors( cg.refdefViewAngles, NULL, right, NULL); + VectorMA( cg.refdef.vieworg, cg_thirdPersonHorzOffset.value, right, cg.refdef.vieworg ); + //cg.refdef.vieworg[0] += cg_thirdPersonHorzOffset.value; + cg.refdef.vieworg[2] += cg_thirdPersonVertOffset.value; + + // if dead, look at killer - if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) { - focusAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW]; - cg.refdefViewAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW]; + //RPG-X: Fix camera movment when play dies with medics revive turned on + trap_Cvar_VariableStringBuffer( "rpg_medicsrevive", medicrevive, 32 ); + medicrevive_int = atoi(medicrevive); + + //TiM: Meh, you don't spin around to look at your killer in real life. O_o + //Plus, this screws up the model system :( + if(medicrevive_int == 1){ + if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 1 ) { + + focusAngles[YAW] = cg_entities[cg.predictedPlayerState.clientNum].pe.legs.yawAngle; + cg.refdefViewAngles[YAW] = cg_entities[cg.predictedPlayerState.clientNum].pe.legs.yawAngle; + //focusAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW]; + //cg.refdefViewAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW]; + } + }else{ + if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) { + + focusAngles[YAW] = cg_entities[cg.predictedPlayerState.clientNum].pe.legs.yawAngle; + cg.refdefViewAngles[YAW] = cg_entities[cg.predictedPlayerState.clientNum].pe.legs.yawAngle; + //focusAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW]; + //cg.refdefViewAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW]; + } } - if ( focusAngles[PITCH] > 45 ) { - focusAngles[PITCH] = 45; // don't go too far overhead + if ( focusAngles[PITCH] > 89.9 ) + { + focusAngles[PITCH] = 89.9f; // don't go too far overhead - has to be under 90 or bad things happen } + else if ( focusAngles[PITCH] < -89.9 ) //89 - Stop from going through legs + { + focusAngles[PITCH] = -89.9f; + } + + if ( cg.refdefViewAngles[PITCH] > 89.9 ) + { + cg.refdefViewAngles[PITCH] = 89.9f; // don't go too far overhead - has to be under 90 or bad things happen + } + else if ( cg.refdefViewAngles[PITCH] < -79.9 ) //89 - Stop from going through legs + { + cg.refdefViewAngles[PITCH] = -79.9f; + } + AngleVectors( focusAngles, forward, NULL, NULL ); VectorMA( cg.refdef.vieworg, FOCUS_DISTANCE, forward, focusPoint ); VectorCopy( cg.refdef.vieworg, view ); - view[2] += 8; + view[2] += 16; - cg.refdefViewAngles[PITCH] *= 0.5; + //cg.refdefViewAngles[PITCH] *= 0.5; AngleVectors( cg.refdefViewAngles, forward, right, up ); - forwardScale = cos( cg_thirdPersonAngle.value / 180 * M_PI ); - sideScale = sin( cg_thirdPersonAngle.value / 180 * M_PI ); + //VectorScale( forward, cg_thirdPersonAngle.value, normalize ); + forwardScale = VectorNormalize( forward ); //cos( cg_thirdPersonAngle.value / 180 * M_PI ); + + ///VectorScale( right, cg_thirdPersonAngle.value, normalize ); + sideScale = VectorNormalize( right );//sin( cg_thirdPersonAngle.value / 180 * M_PI ); VectorMA( view, -cg_thirdPersonRange.value * forwardScale, forward, view ); VectorMA( view, -cg_thirdPersonRange.value * sideScale, right, view ); // trace a ray from the origin to the viewpoint to make sure the view isn't // in a solid block. Use an 8 by 8 block to prevent the view from near clipping anything - if (!cg_cameraMode.integer) { - CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID ); + //TiM : Sometimes if the value of these variables is set to extreme numbers, they'll go thru walls. O_o + //This trace function is to fix that. + //If player is using these CVARs... + if ( cg_thirdPersonVertOffset.value != 0 || cg_thirdPersonHorzOffset.value != 0) { + //Do a trace from playermodel's head to our view location + CG_Trace( &trace, camPlayerPos, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID ); + //Okay, the trace hit something... O_o if ( trace.fraction != 1.0 ) { - VectorCopy( trace.endpos, view ); - view[2] += (1.0 - trace.fraction) * 32; - // try another trace to this position, because a tunnel may have the ceiling - // close enogh that this is poking out - - CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID ); - VectorCopy( trace.endpos, view ); + //copy where it hit to our view origin. :) + VectorCopy( trace.endpos, cg.refdef.vieworg ); } } + CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID ); + + if ( trace.fraction != 1.0 ) { + VectorCopy( trace.endpos, view ); + view[2] += (1.0 - trace.fraction) * 32; + // try another trace to this position, because a tunnel may have the ceiling + // close enogh that this is poking out + + CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID ); + VectorCopy( trace.endpos, view ); + } VectorCopy( view, cg.refdef.vieworg ); @@ -285,10 +745,9 @@ static void CG_OffsetThirdPersonView( void ) { if ( focusDist < 1 ) { focusDist = 1; // should never happen } - cg.refdefViewAngles[PITCH] = -180 / M_PI * atan2( focusPoint[2], focusDist ); + //cg.refdefViewAngles[PITCH] = -180 / M_PI * atan2( focusPoint[2], focusDist ); cg.refdefViewAngles[YAW] -= cg_thirdPersonAngle.value; -} - +}*/ // this causes a compiler bug on mac MrC compiler static void CG_StepOffset( void ) { @@ -318,6 +777,8 @@ static void CG_OffsetFirstPersonView( void ) { float f; vec3_t predictedVelocity; int timeDelta; + char medicrevive[32]; + int medicrevive_int; if ( cg.snap->ps.pm_type == PM_INTERMISSION ) { return; @@ -326,14 +787,44 @@ static void CG_OffsetFirstPersonView( void ) { origin = cg.refdef.vieworg; angles = cg.refdefViewAngles; + // emote based model offset + if ( cg.predictedPlayerState.stats[EMOTES] & EMOTE_LOWER ) + { + vec3_t yawForward, forward; + VectorSet( yawForward, 0, cg.predictedPlayerEntity.pe.legs.yawAngle, 0 ); + AngleVectors( yawForward, forward, NULL, NULL ); + + VectorMA( origin, cgs.clientinfo[cg.predictedPlayerState.clientNum].modelOffset, forward, origin ); + + //CG_Printf(S_COLOR_RED "%i\n", cgs.clientinfo[cg.predictedPlayerState.clientNum].modelOffset ); + } + // if dead, fix the angle and don't add any kick - if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) { + //RPG-X: Fix camera movment when play dies with medics revive turned on + trap_Cvar_VariableStringBuffer( "rpg_medicsrevive", medicrevive, 32 ); + medicrevive_int = atoi(medicrevive); + if(medicrevive_int == 1){ + if ( cg.snap->ps.stats[STAT_HEALTH] <= 1 ) { angles[ROLL] = 40; angles[PITCH] = -15; - angles[YAW] = cg.snap->ps.stats[STAT_DEAD_YAW]; + //angles[YAW] = cg.snap->ps.stats[STAT_DEAD_YAW]; + angles[YAW] = cg_entities[cg.predictedPlayerState.clientNum].pe.legs.yawAngle; origin[2] += cg.predictedPlayerState.viewheight; return; } + }else{ + if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) { + angles[ROLL] = 40; + angles[PITCH] = -15; + //angles[YAW] = cg.snap->ps.stats[STAT_DEAD_YAW]; + angles[YAW] = cg_entities[cg.predictedPlayerState.clientNum].pe.legs.yawAngle; + origin[2] += cg.predictedPlayerState.viewheight; + return; + } + } + + // add angles based on weapon kick + VectorAdd (angles, cg.kick_angles, angles); // add angles based on damage kick if ( cg.damageTime ) { @@ -387,7 +878,9 @@ static void CG_OffsetFirstPersonView( void ) { //=================================== // add view height - origin[2] += cg.predictedPlayerState.viewheight; + //origin[2] += cg.predictedPlayerState.viewheight; + origin[2] += (float)cg.predictedPlayerState.viewheight * cgs.clientinfo[cg.predictedPlayerState.clientNum].height; + //TiM: Model system enhancements // smooth out duck height changes timeDelta = cg.time - cg.duckTime; @@ -419,10 +912,18 @@ static void CG_OffsetFirstPersonView( void ) { // add step offset CG_StepOffset(); + // add kick offset + + VectorAdd (origin, cg.kick_origin, origin); + + //TiM : For rotated players + //if ( (cg.predictedPlayerEntity.currentState.eFlags & EF_FULL_ROTATE) && Q_fabs( angles[PITCH] ) > 89 ) + //angles[ROLL] += 180; + // pivot the eye based on a neck length -#if 0 +//#if 0 { -#define NECK_LENGTH 8 +#define NECK_LENGTH 8//8 vec3_t forward, up; cg.refdef.vieworg[2] -= NECK_LENGTH; @@ -430,28 +931,236 @@ static void CG_OffsetFirstPersonView( void ) { VectorMA( cg.refdef.vieworg, 3, forward, cg.refdef.vieworg ); VectorMA( cg.refdef.vieworg, NECK_LENGTH, up, cg.refdef.vieworg ); } -#endif +//#endif } +/* +------------------------- +CGCam_Shake +------------------------- +*/ + +void CG_CameraShake( float intensity, int duration, qboolean addRumbleSound ) +{ + if ( intensity > MAX_SHAKE_INTENSITY ) + intensity = MAX_SHAKE_INTENSITY; + + cg.shake_intensity = intensity; + cg.shake_duration = duration; + cg.shake_start = cg.time; +} + + + + +/* +------------------------- +CG_UpdateShake + +This doesn't actually affect the camera's info, but passed information instead +------------------------- +*/ + +extern void CG_ClientShakeCamera( void ); + +void CG_UpdateCameraShake( vec3_t origin, vec3_t angles ) +{ + vec3_t curOrigin, curAngle; //moveDir, + //vec3_t zero = {0, 0, 0}; + float intensity_scale, intensity; + //float ranIntensity; + float ratio; + int i; + + //TiM - restart a server loop shake + if ( cg.shake_duration <= 0 && cg.shake_serverIndex > (cg.time - cgs.levelStartTime ) ) { + CG_ClientShakeCamera(); + } + + if ( cg.shake_duration <= 0 ) { + //VectorSet( cg.shake_LastOrigin, 0, 0, 0 ); + //VectorSet( cg.shake_LastAngle, 0, 0, 0 ); + + //VectorSet( cg.shake_LerpOrigin, 0, 0, 0 ); + //VectorSet( cg.shake_LerpAngle, 0, 0, 0 ); + + memset( &cg.shake_LastOrigin, 0, sizeof( cg.shake_LastOrigin ) ); + memset( &cg.shake_LastAngle, 0, sizeof( cg.shake_LastAngle ) ); + + memset( &cg.shake_LerpOrigin, 0, sizeof( cg.shake_LerpOrigin ) ); + memset( &cg.shake_LerpAngle, 0, sizeof( cg.shake_LerpAngle ) ); + + return; + } + + //This is designed to try and make it lerp back to normal at the end + if ( cg.time > ( cg.shake_start + cg.shake_duration ) ) + { + cg.shake_intensity = 0; + cg.shake_duration = 0; + cg.shake_start = 0; + + return; + } + + //intensity_scale now also takes into account FOV with 90.0 as normal + intensity_scale = 1.0f - ( (float) ( cg.time - cg.shake_start ) / (float) cg.shake_duration ) * (cg.refdef.fov_x/90.0f); + + intensity = cg.shake_intensity * intensity_scale; + + //LerpCode + if ( cg.time > cg.shake_nextLerp ) { + + VectorCopy( cg.shake_LerpOrigin, cg.shake_LastOrigin ); + VectorCopy( cg.shake_LerpAngle, cg.shake_LastAngle ); + + //ranIntensity = flrandom( ( 10000.0f * ( 1.0f - Q_fabs( intensity ) ) ), ( 30000.0f * ( 1.0f - Q_fabs( intensity ) )) ); + + cg.shake_lastLerp = cg.shake_nextLerp; + //cg.shake_nextLerp = cg.time + (int)ranIntensity; + cg.shake_nextLerp = cg.time + irandom( 30, 40 ); + + if( cg.shake_nextLerp > ( cg.shake_start + cg.shake_duration ) ) { + cg.shake_nextLerp = (cg.shake_start + cg.shake_duration); + VectorSet( cg.shake_LerpOrigin, 0, 0, 0 ); + VectorSet( cg.shake_LerpAngle, 0, 0, 0 ); + } + else { + for (i=0; i < 3; i++ ) { + cg.shake_LerpOrigin[i] = ( crandom() * intensity ); + cg.shake_LerpAngle[i] = ( crandom() * intensity ); + } + + //If we're moving out of our boundary, away from the player... >.< + //clamp it bak in by inverting it + for ( i = 0; i < 3; i++ ) { + if ( ( cg.shake_LerpOrigin[i] + cg.shake_LastOrigin[i] ) > ( origin[i] * intensity ) ) { + cg.shake_LerpOrigin[i] = -(cg.shake_LerpOrigin[i]); + } + + if ( ( cg.shake_LerpAngle[i] + cg.shake_LastAngle[i] ) > ( angles[i] * intensity ) ) { + cg.shake_LerpAngle[i] = -(cg.shake_LerpAngle[i]); + } + } + + /*i = 0; + while ( 1 ) { + if ( ( cg.shake_LerpOrigin[i] + cg.shake_LastOrigin[i] ) > ( origin[i] * intensity ) || ( cg.shake_LerpAngle[i] + cg.shake_LastAngle[i] ) > ( angles[i] * intensity ) ) { + cg.shake_LerpOrigin[i] = crandom() * intensity; + cg.shake_LerpAngle[i] = crandom() * intensity; + } + else { + if ( i == 2 ) { + break; + } + } + i++; + if ( i == 3 ) { + i= 0; + } + }*/ + } + } + + //Com_Printf( S_COLOR_RED "NextLerp: %i, origin = { %f, %f, %f }\n", cg.shake_nextLerp, origin[0], origin[1], origin[2] ); + + //FIXME: Lerp + //TiM : Doing that + + ratio = ((float)( cg.time - cg.shake_lastLerp ) / (float)( cg.shake_nextLerp - cg.shake_lastLerp ) ); + if (ratio < 0 ) + ratio = 0.0f; + else if (ratio > 1 ) + ratio = 1.0f; + + for ( i = 0; i < 3; i++ ) { + curOrigin[i] = ratio * (float)( (origin[i] + cg.shake_LerpOrigin[i] ) - ( origin[i] + cg.shake_LastOrigin[i] ) ); //origin + } + + //Move the camera + //VectorAdd( origin, curOrigin, origin ); + VectorAdd( origin, cg.shake_LastOrigin, origin ); + VectorAdd( origin, curOrigin, origin ); + + /*for ( i=0; i < 3; i++ ) + moveDir[i] = ( crandom() * intensity );*/ + for ( i =0; i < 3; i++ ) { + curAngle[i] = ratio * (float)( ( angles[i] + cg.shake_LerpAngle[i] ) - ( angles[i] + cg.shake_LastAngle[i] ) ); //angles + } + + //FIXME: Lerp + + //Move the angles + //VectorAdd( angles, curAngle, angles ); + VectorAdd( angles, cg.shake_LastAngle, angles ); + VectorAdd( angles, curAngle, angles ); + + //Com_Printf( S_COLOR_RED "ratio: %f, origin = { %f, %f, %f }\n", ratio, origin[0], origin[1], origin[2] ); +} + + //====================================================================== -void CG_ZoomDown_f( void ) { +void CG_ZoomDown_f( void ) +{ + //if we're not holding a rifle or TR-116, don't draw + if ( !( cg.snap->ps.weapon == WP_6 || cg.snap->ps.weapon == WP_7 ) ) { + cg.zoomed = qfalse; + cg.zoomLocked = qfalse; + return; + } + + /*if ( cg.snap->ps.persistant[PERS_CLASS] == PC_NOCLASS + || cg.snap->ps.persistant[PERS_CLASS] != PC_SECURITY + && cg.snap->ps.persistant[PERS_CLASS] != PC_ALPHAOMEGA22 + && cg.snap->ps.persistant[PERS_CLASS] != PC_ADMIN ) + {//in a class-based game, only these can zoom + cg.zoomed = qfalse; + cg.zoomLocked = qfalse; + return; + }*/ + + // The zoom hasn't been started yet, so do it now + if ( !cg.zoomed ) + { + cg.zoomLocked = qfalse; + cg.zoomed = qtrue; + cg_zoomFov.value = cg_fov.value; + cg.zoomTime = cg.time; + if ( cg.snap->ps.weapon == WP_7 ) { + trap_S_StartSound( cg.refdef.vieworg, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.zoomStart116 ); + } + else { + trap_S_StartSound( cg.refdef.vieworg, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.zoomStart ); + } + return; + } + + // Can only snap out of the zoom mode if it has already been locked (CG_ZoomUp_f has been called) + if ( cg.zoomLocked ) + { + // Snap out of zoom mode + cg.zoomed = qfalse; + cg.zoomTime = cg.time; + + if ( cg.snap->ps.weapon == WP_7 ) { + trap_S_StartSound( cg.refdef.vieworg, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.zoomEnd116 ); + } + else { + trap_S_StartSound( cg.refdef.vieworg, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.zoomEnd ); + } + } +} + +void CG_ZoomUp_f( void ) +{ + if ( cg.zoomed ) { - return; + // Freeze the zoom mode + cg.zoomLocked = qtrue; } - cg.zoomed = qtrue; - cg.zoomTime = cg.time; } -void CG_ZoomUp_f( void ) { - if ( !cg.zoomed ) { - return; - } - cg.zoomed = qfalse; - cg.zoomTime = cg.time; -} - - /* ==================== CG_CalcFov @@ -462,6 +1171,8 @@ Fixed fov at intermissions, otherwise account for fov variable and zooms. #define WAVE_AMPLITUDE 1 #define WAVE_FREQUENCY 0.4 +#define FOV_MAX 120 + static int CG_CalcFov( void ) { float x; float phase; @@ -471,6 +1182,7 @@ static int CG_CalcFov( void ) { float zoomFov; float f; int inwater; + qboolean warpEffect=qfalse; if ( cg.predictedPlayerState.pm_type == PM_INTERMISSION ) { // if in intermission, use a fixed value @@ -479,13 +1191,13 @@ static int CG_CalcFov( void ) { // user selectable if ( cgs.dmflags & DF_FIXED_FOV ) { // dmflag to prevent wide fov for all clients - fov_x = 90; + fov_x = 80; } else { fov_x = cg_fov.value; if ( fov_x < 1 ) { fov_x = 1; - } else if ( fov_x > 160 ) { - fov_x = 160; + } else if ( fov_x > FOV_MAX ) { + fov_x = FOV_MAX; } } @@ -493,33 +1205,70 @@ static int CG_CalcFov( void ) { zoomFov = cg_zoomFov.value; if ( zoomFov < 1 ) { zoomFov = 1; - } else if ( zoomFov > 160 ) { - zoomFov = 160; + } else if ( zoomFov > FOV_MAX) { + zoomFov = FOV_MAX; } - if ( cg.zoomed ) { - f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME; - if ( f > 1.0 ) { - fov_x = zoomFov; - } else { - fov_x = fov_x + f * ( zoomFov - fov_x ); + // Disable zooming when in third person + if ( cg.zoomed && !cg.renderingThirdPerson ) + { + if ( !cg.zoomLocked ) + { + // Interpolate current zoom level + cg_zoomFov.value = cg_fov.value - ((float)( cg.time - cg.zoomTime ) / ZOOM_IN_TIME + ZOOM_START_PERCENT) + * ( cg_fov.value - MAX_ZOOM_FOV ); + + // Clamp zoomFov + if ( cg_zoomFov.value < MAX_ZOOM_FOV ) + { + cg_zoomFov.value = MAX_ZOOM_FOV; + } + else if ( cg_zoomFov.value > cg_fov.value ) + { + cg_zoomFov.value = cg_fov.value; + } + else + {//still zooming + static int zoomSoundTime = 0; + + if ( zoomSoundTime < cg.time ) + { + trap_S_StartSound( cg.refdef.vieworg, ENTITYNUM_WORLD, CHAN_LOCAL, cgs.media.zoomLoop ); + zoomSoundTime = cg.time + 300; + } + } } + + fov_x = cg_zoomFov.value; } else { - f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME; - if ( f <= 1.0 ) { + f = ( cg.time - cg.zoomTime ) / (float)ZOOM_OUT_TIME; + if ( f > 1.0 ) { + fov_x = fov_x; + } else { fov_x = zoomFov + f * ( fov_x - zoomFov ); } } } + /*if (cg.predictedPlayerState.introTime > cg.time) + { // The stuff is "holodecking in". + fov_x = 80; + }*/ + + x = cg.refdef.width / tan( fov_x / 360 * M_PI ); fov_y = atan2( cg.refdef.height, x ); fov_y = fov_y * 360 / M_PI; - // warp if underwater + // warp if underwater //TiM Also do it if we're critically injured contents = CG_PointContents( cg.refdef.vieworg, -1 ); - if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ){ - phase = cg.time / 1000.0 * WAVE_FREQUENCY * M_PI * 2; + + warpEffect = ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) + || ( !cg.renderingThirdPerson && cg.predictedPlayerState.stats[STAT_HEALTH] <= INJURED_MODE_HEALTH && cg.predictedPlayerState.stats[STAT_HEALTH] > 1 ); + + if ( warpEffect ){ + //phase = cg.time / 1000.0 * WAVE_FREQUENCY * M_PI * 2; + phase = cg.time * 0.001 * WAVE_FREQUENCY * M_PI * 2; v = WAVE_AMPLITUDE * sin( phase ); fov_x += v; fov_y -= v; @@ -545,58 +1294,6 @@ static int CG_CalcFov( void ) { -/* -=============== -CG_DamageBlendBlob - -=============== -*/ -static void CG_DamageBlendBlob( void ) { - int t; - int maxTime; - refEntity_t ent; - - if (!cg_blood.integer) { - return; - } - - if ( !cg.damageValue ) { - return; - } - - //if (cg.cameraMode) { - // return; - //} - - // ragePro systems can't fade blends, so don't obscure the screen - if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) { - return; - } - - maxTime = DAMAGE_TIME; - t = cg.time - cg.damageTime; - if ( t <= 0 || t >= maxTime ) { - return; - } - - - memset( &ent, 0, sizeof( ent ) ); - ent.reType = RT_SPRITE; - ent.renderfx = RF_FIRST_PERSON; - - VectorMA( cg.refdef.vieworg, 8, cg.refdef.viewaxis[0], ent.origin ); - VectorMA( ent.origin, cg.damageX * -8, cg.refdef.viewaxis[1], ent.origin ); - VectorMA( ent.origin, cg.damageY * 8, cg.refdef.viewaxis[2], ent.origin ); - - ent.radius = cg.damageValue * 3; - ent.customShader = cgs.media.viewBloodShader; - ent.shaderRGBA[0] = 255; - ent.shaderRGBA[1] = 255; - ent.shaderRGBA[2] = 255; - ent.shaderRGBA[3] = 200 * ( 1.0 - ((float)t / maxTime) ); - trap_R_AddRefEntityToScene( &ent ); -} - /* =============== @@ -618,20 +1315,7 @@ static int CG_CalcViewValues( void ) { CG_CalcVrect(); ps = &cg.predictedPlayerState; -/* - if (cg.cameraMode) { - vec3_t origin, angles; - if (trap_getCameraInfo(cg.time, &origin, &angles)) { - VectorCopy(origin, cg.refdef.vieworg); - angles[ROLL] = 0; - VectorCopy(angles, cg.refdefViewAngles); - AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis ); - return CG_CalcFov(); - } else { - cg.cameraMode = qfalse; - } - } -*/ + // intermission view if ( ps->pm_type == PM_INTERMISSION ) { VectorCopy( ps->origin, cg.refdef.vieworg ); @@ -649,12 +1333,6 @@ static int CG_CalcViewValues( void ) { VectorCopy( ps->origin, cg.refdef.vieworg ); VectorCopy( ps->viewangles, cg.refdefViewAngles ); - if (cg_cameraOrbit.integer) { - if (cg.time > cg.nextOrbitTime) { - cg.nextOrbitTime = cg.time + cg_cameraOrbitDelay.integer; - cg_thirdPersonAngle.value += cg_cameraOrbit.value; - } - } // add error decay if ( cg_errorDecay.value > 0 ) { int t; @@ -669,7 +1347,7 @@ static int CG_CalcViewValues( void ) { } } - if ( cg.renderingThirdPerson ) { + if ( cg.renderingThirdPerson && ps->pm_type != PM_CCAM ) { // back away from character CG_OffsetThirdPersonView(); } else { @@ -677,12 +1355,17 @@ static int CG_CalcViewValues( void ) { CG_OffsetFirstPersonView(); } + // shake the camera if necessary + CG_UpdateCameraShake( cg.refdef.vieworg, cg.refdefViewAngles ); // position eye reletive to origin AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis ); - if ( cg.hyperspace ) { + //TiM - As far as I can see, all this does is cause flashy + //effects on-screen when a player teleports the hide the delay. + //This probably doesn't really apply to us now... + /*if ( cg.hyperspace ) { cg.refdef.rdflags |= RDF_NOWORLDMODEL | RDF_HYPERSPACE; - } + }*/ // field of view return CG_CalcFov(); @@ -694,13 +1377,19 @@ static int CG_CalcViewValues( void ) { CG_PowerupTimerSounds ===================== */ -static void CG_PowerupTimerSounds( void ) { +/*static void CG_PowerupTimerSounds( void ) { int i; int t; // powerup timers going away for ( i = 0 ; i < MAX_POWERUPS ; i++ ) { t = cg.snap->ps.powerups[i]; + + // kef -- hack hack hack. additionally, hack. + if ( (PW_OUCH == i) || (PW_GHOST == i) ) + { + continue; + } if ( t <= cg.time ) { continue; } @@ -708,42 +1397,160 @@ static void CG_PowerupTimerSounds( void ) { continue; } if ( ( t - cg.time ) / POWERUP_BLINK_TIME != ( t - cg.oldTime ) / POWERUP_BLINK_TIME ) { - trap_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_ITEM, cgs.media.wearOffSound ); + //trap_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_ITEM, cgs.media.wearOffSound ); } } -} +}*/ + + + +//========================================================================= /* -===================== -CG_AddBufferedSound -===================== +============= +CG_IntroModel + +This is when the player is starting the level. +============= */ -void CG_AddBufferedSound( sfxHandle_t sfx ) { - if ( !sfx ) +/*void CG_AddIntroModel(playerState_t *ps, int time) +{ + static int soundpoint=0, lasttime=999999; + refEntity_t doorbox; + float alpha; + byte a; + //char pClass[MAX_QPATH]; + //char pRank[MAX_QPATH]; + + if (lasttime > time) + { // Restart everything. + soundpoint=0; + } + + lasttime=time; + + // add the model + memset( &doorbox, 0, sizeof( doorbox ) ); + VectorCopy( cg.refdef.vieworg, doorbox.lightingOrigin ); + + doorbox.shaderRGBA[0] = 255; + doorbox.shaderRGBA[1] = 255; + doorbox.shaderRGBA[2] = 255; + doorbox.shaderRGBA[3] = 255; + + doorbox.hModel = cgs.media.doorbox; + if (!doorbox.hModel) { return; - cg.soundBuffer[cg.soundBufferIn] = sfx; - cg.soundBufferIn = (cg.soundBufferIn + 1) % MAX_SOUNDBUFFER; - if (cg.soundBufferIn == cg.soundBufferOut) { - cg.soundBufferOut++; } -} -/* -===================== -CG_PlayBufferedSounds -===================== -*/ -static void CG_PlayBufferedSounds( void ) { - if ( cg.soundTime < cg.time ) { - if (cg.soundBufferOut != cg.soundBufferIn && cg.soundBuffer[cg.soundBufferOut]) { - trap_S_StartLocalSound(cg.soundBuffer[cg.soundBufferOut], CHAN_ANNOUNCER); - cg.soundBuffer[cg.soundBufferOut] = 0; - cg.soundBufferOut = (cg.soundBufferOut + 1) % MAX_SOUNDBUFFER; - cg.soundTime = cg.time + 750; + VectorMA(cg.refdef.vieworg, 25, cg.refdef.viewaxis[0], doorbox.origin); + VectorMA(doorbox.origin, -35, cg.refdef.viewaxis[2], doorbox.origin); + AnglesToAxis(cg.refdefViewAngles, doorbox.axis); + + VectorScale(doorbox.axis[0], -1.0, doorbox.axis[0]); + VectorScale(doorbox.axis[1], -1.0, doorbox.axis[1]); + + if (soundpoint <= 0) + { // First part... "Prepare to compete." + if (time >= TIME_INIT) + { + soundpoint = 1; + trap_S_StartSound( cg.refdef.vieworg, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.holoInitSound ); + } + doorbox.frame = 0; + } + else if (soundpoint == 1) + { // Second part... Open door after "prepare". + if (time >= TIME_DOOR_START) + { + soundpoint = 2; + trap_S_StartSound( cg.refdef.vieworg, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.holoDoorSound ); + } + doorbox.frame = 0; + } + else if (soundpoint == 2) + { // Third part... Fade in after opening door. + if (time >= TIME_FADE_START) + { + soundpoint = 3; + trap_S_StartSound( cg.refdef.vieworg, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.holoFadeSound ); + doorbox.frame = FRAMES_DOOR-1; + } + else + { + doorbox.frame = ((float)(time - TIME_DOOR_START) / 100.0) + 1; + if (doorbox.frame >= FRAMES_DOOR) + { + doorbox.frame=FRAMES_DOOR-1; + } + else + { + doorbox.oldframe = doorbox.frame-1; + doorbox.backlerp = (float)(doorbox.frame) - ((float)(time - TIME_DOOR_START) / 100.0); + } } } + else + { // Final part... Fade out the model. + + alpha = 1.0 - ((float)(time - TIME_FADE_START) / (float)TIME_FADE_DUR); + + if (alpha<0.0) + { + alpha=0.0; + } + + a=255.0*alpha; + if (a<=0) + { // An alpha of zero defaults to opaque... Makes sense, why even send something that is 100% transparent? + a=1; + } + + doorbox.shaderRGBA[0] = 255; + doorbox.shaderRGBA[1] = 255; + doorbox.shaderRGBA[2] = 255; + doorbox.shaderRGBA[3] = a; + doorbox.frame = FRAMES_DOOR-1; + } + + doorbox.renderfx |= (RF_DEPTHHACK|RF_FORCE_ENT_ALPHA|RF_FULLBRIGHT); + + trap_R_AddRefEntityToScene(&doorbox); +}*/ + +void CG_DrawEVAHelmet ( playerState_t *ps ) +{ + refEntity_t helmet; + + if ( !ps->powerups[PW_EVOSUIT] && !( cgs.clientinfo[ps->clientNum].isHazardModel && ps->powerups[PW_BOLTON] ) ) { + return; + } + + memset( &helmet, 0, sizeof(helmet) ); + VectorCopy( ps->origin, helmet.lightingOrigin ); + helmet.renderfx = RF_LIGHTING_ORIGIN | RF_DEPTHHACK | RF_FIRST_PERSON; + helmet.hModel = cgs.media.evaInterior; + + if ( !helmet.hModel ) { + CG_Printf("EVA Helmet Model not found\n"); + return; + } + + VectorCopy( cg.refdef.vieworg, helmet.origin ); + AxisCopy( cg.refdef.viewaxis, helmet.axis ); + VectorMA( helmet.origin, 6, cg.refdef.viewaxis[0], helmet.origin ); + + CG_AddRefEntityWithPowerups( &helmet, + cg.predictedPlayerEntity.currentState.powerups, + cg.predictedPlayerEntity.currentState.eFlags, + &cg.predictedPlayerEntity.beamData, + cg.predictedPlayerEntity.cloakTime, + cg.predictedPlayerEntity.decloakTime, + qfalse ); + } + //========================================================================= /* @@ -755,10 +1562,49 @@ Generates and draws a game scene and status information at the given time. */ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback ) { int inwater; + char cvarYaw[16]; //an uber long floating point value lol + float yaw; cg.time = serverTime; cg.demoPlayback = demoPlayback; + //RPG-X: TiM - Set up for giant uber rant. + //GARRRRRGGGGGGGGGGGGGGGGGGGGGGGGGHHHHHHHHHHHHHH!!!!!!!!!!!!!!!!!!!!!!!!! ->O_O<- + //Here's me looking at the BFP mod, wondering how the gravynuggets they managed + //to flip the yaw value when the players rotated beyond the normal view axis. + //I developed a totally l33tzor rotational offset algorithm that came oh so close + //to working, but after noticing a little inconsistancy in their rotation ingame, I realised + //all they did was change the player's mouse yaw CVAR to invert!!!! O_O + //Ohhhhh I just lost several years of my life and the use of my wrists..... + //Probably just as well we disabled the RPG-X online webcam... that wasn't pretty. O_o + + //load our yaw value + trap_Cvar_VariableStringBuffer( "m_yaw", cvarYaw, sizeof( cvarYaw ) ); + yaw = atof ( cvarYaw ); + + if ( cg.predictedPlayerEntity.currentState.eFlags & EF_FULL_ROTATE + && Q_fabs( cg.predictedPlayerEntity.lerpAngles[PITCH] ) > 89.0f ) + { + if ( yaw > 0.0f ) + { + //yaw = -yaw; + //trap_Cvar_Set( "m_yaw", va( "%f", yaw ) ); + trap_Cvar_Set( "m_yaw", va( "-%s", cvarYaw ) ); + + //CG_Printf( S_COLOR_RED "%f\n", yaw ); + } + } + else { //ugh... I hope no one plays with their yaws inverted. >.< This MAY need to be CVAR controlled + if ( yaw < 0.0f ) + { + char *tmp = cvarYaw; + if ( tmp[0] == '-') tmp++; //erase the neg sign + + //trap_Cvar_Set( "m_yaw", va( "%f", Q_fabs( yaw ) ) ); + trap_Cvar_Set( "m_yaw", va( "%s", tmp ) ); + } + } + // update cvars CG_UpdateCvars(); @@ -771,7 +1617,7 @@ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demo // any looped sounds will be respecified as entities // are added to the render list - trap_S_ClearLoopingSounds(qfalse); + trap_S_ClearLoopingSounds(); // clear all the render lists trap_R_ClearScene(); @@ -796,31 +1642,33 @@ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demo CG_PredictPlayerState(); // decide on third person view - cg.renderingThirdPerson = cg_thirdPerson.integer || (cg.snap->ps.stats[STAT_HEALTH] <= 0); + cg.renderingThirdPerson = ( cg_thirdPerson.integer && !cg.zoomed && cg.predictedPlayerState.pm_type != PM_SPECTATOR ) || (cg.snap->ps.stats[STAT_HEALTH] <= 1 ) ; //TiM - So we'll always be first person in zooming //0 // build cg.refdef inwater = CG_CalcViewValues(); // first person blend blobs, done after AnglesToAxis - if ( !cg.renderingThirdPerson ) { - CG_DamageBlendBlob(); + if ( !cg.renderingThirdPerson ) + { + CG_DrawFullScreenFX(); + CG_DrawEVAHelmet( &cg.predictedPlayerState ); } + // build the render lists if ( !cg.hyperspace ) { CG_AddPacketEntities(); // adter calcViewValues, so predicted player state is correct CG_AddMarks(); - CG_AddParticles (); CG_AddLocalEntities(); } + + /*if (cg.predictedPlayerState.introTime > cg.time) + { // Render the holodeck doors + CG_AddIntroModel(&cg.predictedPlayerState, TIME_INTRO - (cg.predictedPlayerState.introTime - cg.time)); + }*/ + CG_AddViewWeapon( &cg.predictedPlayerState ); - // add buffered sounds - CG_PlayBufferedSounds(); - - // play buffered voice chats - CG_PlayBufferedVoiceChats(); - // finish up the rest of the refdef if ( cg.testModelEntity.hModel ) { CG_AddTestModel(); @@ -828,12 +1676,13 @@ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demo cg.refdef.time = cg.time; memcpy( cg.refdef.areamask, cg.snap->areamask, sizeof( cg.refdef.areamask ) ); - // warning sounds when powerup is wearing off - CG_PowerupTimerSounds(); - // update audio positions trap_S_Respatialize( cg.snap->ps.clientNum, cg.refdef.vieworg, cg.refdef.viewaxis, inwater ); + // warning sounds when powerup is wearing off + //TiM - Not really needed :P + //CG_PowerupTimerSounds(); + // make sure the lagometerSample and frame timing isn't done twice when in stereo if ( stereoView != STEREO_RIGHT ) { cg.frametime = cg.time - cg.oldTime; @@ -843,21 +1692,6 @@ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demo cg.oldTime = cg.time; CG_AddLagometerFrameInfo(); } - if (cg_timescale.value != cg_timescaleFadeEnd.value) { - if (cg_timescale.value < cg_timescaleFadeEnd.value) { - cg_timescale.value += cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000; - if (cg_timescale.value > cg_timescaleFadeEnd.value) - cg_timescale.value = cg_timescaleFadeEnd.value; - } - else { - cg_timescale.value -= cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000; - if (cg_timescale.value < cg_timescaleFadeEnd.value) - cg_timescale.value = cg_timescaleFadeEnd.value; - } - if (cg_timescaleFadeSpeed.value) { - trap_Cvar_Set("timescale", va("%f", cg_timescale.value)); - } - } // actually issue the rendering calls CG_DrawActive( stereoView ); @@ -866,6 +1700,8 @@ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demo CG_Printf( "cg.clientFrame:%i\n", cg.clientFrame ); } - + //TiM - Reset the lerp code at the end of this frame. + if ( cg.thirdPersonNoLerp ) + cg.thirdPersonNoLerp = qfalse; } diff --git a/code/cgame/cg_weapons.c b/code/cgame/cg_weapons.c index f48dcb7..d793c28 100644 --- a/code/cgame/cg_weapons.c +++ b/code/cgame/cg_weapons.c @@ -1,600 +1,30 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // // cg_weapons.c -- events and effects dealing with weapons #include "cg_local.h" - -/* -========================== -CG_MachineGunEjectBrass -========================== -*/ -static void CG_MachineGunEjectBrass( centity_t *cent ) { - localEntity_t *le; - refEntity_t *re; - vec3_t velocity, xvelocity; - vec3_t offset, xoffset; - float waterScale = 1.0f; - vec3_t v[3]; - - if ( cg_brassTime.integer <= 0 ) { - return; - } - - le = CG_AllocLocalEntity(); - re = &le->refEntity; - - velocity[0] = 0; - velocity[1] = -50 + 40 * crandom(); - velocity[2] = 100 + 50 * crandom(); - - le->leType = LE_FRAGMENT; - le->startTime = cg.time; - le->endTime = le->startTime + cg_brassTime.integer + ( cg_brassTime.integer / 4 ) * random(); - - le->pos.trType = TR_GRAVITY; - le->pos.trTime = cg.time - (rand()&15); - - AnglesToAxis( cent->lerpAngles, v ); - - offset[0] = 8; - offset[1] = -4; - offset[2] = 24; - - xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0]; - xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1]; - xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2]; - VectorAdd( cent->lerpOrigin, xoffset, re->origin ); - - VectorCopy( re->origin, le->pos.trBase ); - - if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) { - waterScale = 0.10f; - } - - xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0]; - xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1]; - xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2]; - VectorScale( xvelocity, waterScale, le->pos.trDelta ); - - AxisCopy( axisDefault, re->axis ); - re->hModel = cgs.media.machinegunBrassModel; - - le->bounceFactor = 0.4 * waterScale; - - le->angles.trType = TR_LINEAR; - le->angles.trTime = cg.time; - le->angles.trBase[0] = rand()&31; - le->angles.trBase[1] = rand()&31; - le->angles.trBase[2] = rand()&31; - le->angles.trDelta[0] = 2; - le->angles.trDelta[1] = 1; - le->angles.trDelta[2] = 0; - - le->leFlags = LEF_TUMBLE; - le->leBounceSoundType = LEBS_BRASS; - le->leMarkType = LEMT_NONE; -} - -/* -========================== -CG_ShotgunEjectBrass -========================== -*/ -static void CG_ShotgunEjectBrass( centity_t *cent ) { - localEntity_t *le; - refEntity_t *re; - vec3_t velocity, xvelocity; - vec3_t offset, xoffset; - vec3_t v[3]; - int i; - - if ( cg_brassTime.integer <= 0 ) { - return; - } - - for ( i = 0; i < 2; i++ ) { - float waterScale = 1.0f; - - le = CG_AllocLocalEntity(); - re = &le->refEntity; - - velocity[0] = 60 + 60 * crandom(); - if ( i == 0 ) { - velocity[1] = 40 + 10 * crandom(); - } else { - velocity[1] = -40 + 10 * crandom(); - } - velocity[2] = 100 + 50 * crandom(); - - le->leType = LE_FRAGMENT; - le->startTime = cg.time; - le->endTime = le->startTime + cg_brassTime.integer*3 + cg_brassTime.integer * random(); - - le->pos.trType = TR_GRAVITY; - le->pos.trTime = cg.time; - - AnglesToAxis( cent->lerpAngles, v ); - - offset[0] = 8; - offset[1] = 0; - offset[2] = 24; - - xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0]; - xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1]; - xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2]; - VectorAdd( cent->lerpOrigin, xoffset, re->origin ); - VectorCopy( re->origin, le->pos.trBase ); - if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) { - waterScale = 0.10f; - } - - xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0]; - xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1]; - xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2]; - VectorScale( xvelocity, waterScale, le->pos.trDelta ); - - AxisCopy( axisDefault, re->axis ); - re->hModel = cgs.media.shotgunBrassModel; - le->bounceFactor = 0.3f; - - le->angles.trType = TR_LINEAR; - le->angles.trTime = cg.time; - le->angles.trBase[0] = rand()&31; - le->angles.trBase[1] = rand()&31; - le->angles.trBase[2] = rand()&31; - le->angles.trDelta[0] = 1; - le->angles.trDelta[1] = 0.5; - le->angles.trDelta[2] = 0; - - le->leFlags = LEF_TUMBLE; - le->leBounceSoundType = LEBS_BRASS; - le->leMarkType = LEMT_NONE; - } -} - - -#ifdef MISSIONPACK -/* -========================== -CG_NailgunEjectBrass -========================== -*/ -static void CG_NailgunEjectBrass( centity_t *cent ) { - localEntity_t *smoke; - vec3_t origin; - vec3_t v[3]; - vec3_t offset; - vec3_t xoffset; - vec3_t up; - - AnglesToAxis( cent->lerpAngles, v ); - - offset[0] = 0; - offset[1] = -12; - offset[2] = 24; - - xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0]; - xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1]; - xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2]; - VectorAdd( cent->lerpOrigin, xoffset, origin ); - - VectorSet( up, 0, 0, 64 ); - - smoke = CG_SmokePuff( origin, up, 32, 1, 1, 1, 0.33f, 700, cg.time, 0, 0, cgs.media.smokePuffShader ); - // use the optimized local entity add - smoke->leType = LE_SCALE_FADE; -} -#endif - - -/* -========================== -CG_RailTrail -========================== -*/ -void CG_RailTrail (clientInfo_t *ci, vec3_t start, vec3_t end) { - vec3_t axis[36], move, move2, vec, temp; - float len; - int i, j, skip; - - localEntity_t *le; - refEntity_t *re; - -#define RADIUS 4 -#define ROTATION 1 -#define SPACING 5 - - start[2] -= 4; - - le = CG_AllocLocalEntity(); - re = &le->refEntity; - - le->leType = LE_FADE_RGB; - le->startTime = cg.time; - le->endTime = cg.time + cg_railTrailTime.value; - le->lifeRate = 1.0 / (le->endTime - le->startTime); - - re->shaderTime = cg.time / 1000.0f; - re->reType = RT_RAIL_CORE; - re->customShader = cgs.media.railCoreShader; - - VectorCopy(start, re->origin); - VectorCopy(end, re->oldorigin); - - re->shaderRGBA[0] = ci->color1[0] * 255; - re->shaderRGBA[1] = ci->color1[1] * 255; - re->shaderRGBA[2] = ci->color1[2] * 255; - re->shaderRGBA[3] = 255; - - le->color[0] = ci->color1[0] * 0.75; - le->color[1] = ci->color1[1] * 0.75; - le->color[2] = ci->color1[2] * 0.75; - le->color[3] = 1.0f; - - AxisClear( re->axis ); - - if (cg_oldRail.integer) - { - // nudge down a bit so it isn't exactly in center - re->origin[2] -= 8; - re->oldorigin[2] -= 8; - return; - } - - VectorCopy (start, move); - VectorSubtract (end, start, vec); - len = VectorNormalize (vec); - PerpendicularVector(temp, vec); - for (i = 0 ; i < 36; i++) - { - RotatePointAroundVector(axis[i], vec, temp, i * 10);//banshee 2.4 was 10 - } - - VectorMA(move, 20, vec, move); - VectorScale (vec, SPACING, vec); - - skip = -1; - - j = 18; - for (i = 0; i < len; i += SPACING) - { - if (i != skip) - { - skip = i + SPACING; - le = CG_AllocLocalEntity(); - re = &le->refEntity; - le->leFlags = LEF_PUFF_DONT_SCALE; - le->leType = LE_MOVE_SCALE_FADE; - le->startTime = cg.time; - le->endTime = cg.time + (i>>1) + 600; - le->lifeRate = 1.0 / (le->endTime - le->startTime); - - re->shaderTime = cg.time / 1000.0f; - re->reType = RT_SPRITE; - re->radius = 1.1f; - re->customShader = cgs.media.railRingsShader; - - re->shaderRGBA[0] = ci->color2[0] * 255; - re->shaderRGBA[1] = ci->color2[1] * 255; - re->shaderRGBA[2] = ci->color2[2] * 255; - re->shaderRGBA[3] = 255; - - le->color[0] = ci->color2[0] * 0.75; - le->color[1] = ci->color2[1] * 0.75; - le->color[2] = ci->color2[2] * 0.75; - le->color[3] = 1.0f; - - le->pos.trType = TR_LINEAR; - le->pos.trTime = cg.time; - - VectorCopy( move, move2); - VectorMA(move2, RADIUS , axis[j], move2); - VectorCopy(move2, le->pos.trBase); - - le->pos.trDelta[0] = axis[j][0]*6; - le->pos.trDelta[1] = axis[j][1]*6; - le->pos.trDelta[2] = axis[j][2]*6; - } - - VectorAdd (move, vec, move); - - j = (j + ROTATION) % 36; - } -} - -/* -========================== -CG_RocketTrail -========================== -*/ -static void CG_RocketTrail( centity_t *ent, const weaponInfo_t *wi ) { - int step; - vec3_t origin, lastPos; - int t; - int startTime, contents; - int lastContents; - entityState_t *es; - vec3_t up; - localEntity_t *smoke; - - if ( cg_noProjectileTrail.integer ) { - return; - } - - up[0] = 0; - up[1] = 0; - up[2] = 0; - - step = 50; - - es = &ent->currentState; - startTime = ent->trailTime; - t = step * ( (startTime + step) / step ); - - BG_EvaluateTrajectory( &es->pos, cg.time, origin ); - contents = CG_PointContents( origin, -1 ); - - // if object (e.g. grenade) is stationary, don't toss up smoke - if ( es->pos.trType == TR_STATIONARY ) { - ent->trailTime = cg.time; - return; - } - - BG_EvaluateTrajectory( &es->pos, ent->trailTime, lastPos ); - lastContents = CG_PointContents( lastPos, -1 ); - - ent->trailTime = cg.time; - - if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) { - if ( contents & lastContents & CONTENTS_WATER ) { - CG_BubbleTrail( lastPos, origin, 8 ); - } - return; - } - - for ( ; t <= ent->trailTime ; t += step ) { - BG_EvaluateTrajectory( &es->pos, t, lastPos ); - - smoke = CG_SmokePuff( lastPos, up, - wi->trailRadius, - 1, 1, 1, 0.33f, - wi->wiTrailTime, - t, - 0, - 0, - cgs.media.smokePuffShader ); - // use the optimized local entity add - smoke->leType = LE_SCALE_FADE; - } - -} - -#ifdef MISSIONPACK -/* -========================== -CG_NailTrail -========================== -*/ -static void CG_NailTrail( centity_t *ent, const weaponInfo_t *wi ) { - int step; - vec3_t origin, lastPos; - int t; - int startTime, contents; - int lastContents; - entityState_t *es; - vec3_t up; - localEntity_t *smoke; - - if ( cg_noProjectileTrail.integer ) { - return; - } - - up[0] = 0; - up[1] = 0; - up[2] = 0; - - step = 50; - - es = &ent->currentState; - startTime = ent->trailTime; - t = step * ( (startTime + step) / step ); - - BG_EvaluateTrajectory( &es->pos, cg.time, origin ); - contents = CG_PointContents( origin, -1 ); - - // if object (e.g. grenade) is stationary, don't toss up smoke - if ( es->pos.trType == TR_STATIONARY ) { - ent->trailTime = cg.time; - return; - } - - BG_EvaluateTrajectory( &es->pos, ent->trailTime, lastPos ); - lastContents = CG_PointContents( lastPos, -1 ); - - ent->trailTime = cg.time; - - if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) { - if ( contents & lastContents & CONTENTS_WATER ) { - CG_BubbleTrail( lastPos, origin, 8 ); - } - return; - } - - for ( ; t <= ent->trailTime ; t += step ) { - BG_EvaluateTrajectory( &es->pos, t, lastPos ); - - smoke = CG_SmokePuff( lastPos, up, - wi->trailRadius, - 1, 1, 1, 0.33f, - wi->wiTrailTime, - t, - 0, - 0, - cgs.media.nailPuffShader ); - // use the optimized local entity add - smoke->leType = LE_SCALE_FADE; - } - -} -#endif - -/* -========================== -CG_NailTrail -========================== -*/ -static void CG_PlasmaTrail( centity_t *cent, const weaponInfo_t *wi ) { - localEntity_t *le; - refEntity_t *re; - entityState_t *es; - vec3_t velocity, xvelocity, origin; - vec3_t offset, xoffset; - vec3_t v[3]; - - float waterScale = 1.0f; - - if ( cg_noProjectileTrail.integer || cg_oldPlasma.integer ) { - return; - } - - es = ¢->currentState; - - BG_EvaluateTrajectory( &es->pos, cg.time, origin ); - - le = CG_AllocLocalEntity(); - re = &le->refEntity; - - velocity[0] = 60 - 120 * crandom(); - velocity[1] = 40 - 80 * crandom(); - velocity[2] = 100 - 200 * crandom(); - - le->leType = LE_MOVE_SCALE_FADE; - le->leFlags = LEF_TUMBLE; - le->leBounceSoundType = LEBS_NONE; - le->leMarkType = LEMT_NONE; - - le->startTime = cg.time; - le->endTime = le->startTime + 600; - - le->pos.trType = TR_GRAVITY; - le->pos.trTime = cg.time; - - AnglesToAxis( cent->lerpAngles, v ); - - offset[0] = 2; - offset[1] = 2; - offset[2] = 2; - - xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0]; - xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1]; - xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2]; - - VectorAdd( origin, xoffset, re->origin ); - VectorCopy( re->origin, le->pos.trBase ); - - if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) { - waterScale = 0.10f; - } - - xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0]; - xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1]; - xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2]; - VectorScale( xvelocity, waterScale, le->pos.trDelta ); - - AxisCopy( axisDefault, re->axis ); - re->shaderTime = cg.time / 1000.0f; - re->reType = RT_SPRITE; - re->radius = 0.25f; - re->customShader = cgs.media.railRingsShader; - le->bounceFactor = 0.3f; - - re->shaderRGBA[0] = wi->flashDlightColor[0] * 63; - re->shaderRGBA[1] = wi->flashDlightColor[1] * 63; - re->shaderRGBA[2] = wi->flashDlightColor[2] * 63; - re->shaderRGBA[3] = 63; - - le->color[0] = wi->flashDlightColor[0] * 0.2; - le->color[1] = wi->flashDlightColor[1] * 0.2; - le->color[2] = wi->flashDlightColor[2] * 0.2; - le->color[3] = 0.25f; - - le->angles.trType = TR_LINEAR; - le->angles.trTime = cg.time; - le->angles.trBase[0] = rand()&31; - le->angles.trBase[1] = rand()&31; - le->angles.trBase[2] = rand()&31; - le->angles.trDelta[0] = 1; - le->angles.trDelta[1] = 0.5; - le->angles.trDelta[2] = 0; - -} -/* -========================== -CG_GrappleTrail -========================== -*/ -void CG_GrappleTrail( centity_t *ent, const weaponInfo_t *wi ) { - vec3_t origin; - entityState_t *es; - vec3_t forward, up; - refEntity_t beam; - - es = &ent->currentState; - - BG_EvaluateTrajectory( &es->pos, cg.time, origin ); - ent->trailTime = cg.time; - - memset( &beam, 0, sizeof( beam ) ); - //FIXME adjust for muzzle position - VectorCopy ( cg_entities[ ent->currentState.otherEntityNum ].lerpOrigin, beam.origin ); - beam.origin[2] += 26; - AngleVectors( cg_entities[ ent->currentState.otherEntityNum ].lerpAngles, forward, NULL, up ); - VectorMA( beam.origin, -6, up, beam.origin ); - VectorCopy( origin, beam.oldorigin ); - - if (Distance( beam.origin, beam.oldorigin ) < 64 ) - return; // Don't draw if close - - beam.reType = RT_LIGHTNING; - beam.customShader = cgs.media.lightningShader; - - AxisClear( beam.axis ); - beam.shaderRGBA[0] = 0xff; - beam.shaderRGBA[1] = 0xff; - beam.shaderRGBA[2] = 0xff; - beam.shaderRGBA[3] = 0xff; - trap_R_AddRefEntityToScene( &beam ); -} - -/* -========================== -CG_GrenadeTrail -========================== -*/ -static void CG_GrenadeTrail( centity_t *ent, const weaponInfo_t *wi ) { - CG_RocketTrail( ent, wi ); -} - +#include "fx_local.h" + +//RPG-X : TiM - Weapons Arrays +static int RAweapons[8] = { WP_3, + WP_2, + WP_6, + WP_7, + WP_12, + WP_13, + WP_11, + WP_4 + }; + +static char *RAweapFileName[8] = { "padd", + "tricorder", + "prifle", + "tr116", + "hypospray", + "dermal_regen", + "medkit", + "coffeecup" + }; + /* ================= @@ -603,12 +33,74 @@ CG_RegisterWeapon The server says this item is used on this level ================= */ + +// kef -- sad? yep. +typedef struct wpnBarrelInfo_s +{ + weapon_t giTag; + int numBarrels; + int flashTime; +} wpnBarrelInfo_t; + +wpnBarrelInfo_t wpnBarrelData[] = +{ + {WP_1, 0, 0}, + + {WP_2, 0, 0}, + {WP_3, 0, 0}, + {WP_4, 0, 0}, + + {WP_5, 0, 0}, + {WP_6, 0, 120}, + {WP_7, 1, 60}, + + {WP_8, 2, 150}, + {WP_9, 1, 200}, + {WP_10, 1, 130}, + + {WP_11, 0, 0}, + {WP_12, 0, 0}, + {WP_13, 0, 0}, + + {WP_14, 0, 0}, + {WP_15, 0, 0}, + + // make sure this is the last entry in this array, please + {WP_0, 0, 0}, +}; + +//wpnBarrelInfo_t wpnBarrelData[] = +//{ +// {WP_5, 0, 0}, +// {WP_6, 0, 100}, +// {WP_1, 0, 0}, +// {WP_4, 0, 0}, +// {WP_10, 1, 80}, +// {WP_8, 2, 140}, +// {WP_7, 1, 120}, +// {WP_9, 1, 200}, +// {WP_13, 0, 0}, +// {WP_12, 0, 0}, +// {WP_14, 0, 0}, +// {WP_11, 0, 0}, +// {WP_2, 0, 0}, +// {WP_3, 0, 0}, +// {WP_NEUTRINO_PROBE, 0, 0}, +// {WP_7, 0, 90}, +// +// // make sure this is the last entry in this array, please +// {WP_0, 0}, +//}; + void CG_RegisterWeapon( int weaponNum ) { weaponInfo_t *weaponInfo; gitem_t *item, *ammo; char path[MAX_QPATH]; vec3_t mins, maxs; int i; + int numBarrels = 0; + wpnBarrelInfo_t *barrelInfo = NULL; + weaponInfo = &cg_weapons[weaponNum]; @@ -625,6 +117,9 @@ void CG_RegisterWeapon( int weaponNum ) { for ( item = bg_itemlist + 1 ; item->classname ; item++ ) { if ( item->giType == IT_WEAPON && item->giTag == weaponNum ) { + /*if ( weaponNum == WP_10 ) { + Com_Printf( S_COLOR_RED "Registering %s with pickup name of %s\n", bg_itemlist[10].classname, bg_itemlist[10].pickup_name ); + }*/ weaponInfo->item = item; break; } @@ -634,8 +129,10 @@ void CG_RegisterWeapon( int weaponNum ) { } CG_RegisterItemVisuals( item - bg_itemlist ); - // load cmodel before model so filecache works - weaponInfo->weaponModel = trap_R_RegisterModel( item->world_model[0] ); + weaponInfo->weaponModel = trap_R_RegisterModel( item->world_model ); + + // kef -- load in-view model + weaponInfo->viewModel = trap_R_RegisterModel(item->view_model); // calc midpoint for rotation trap_R_ModelBounds( weaponInfo->weaponModel, mins, maxs ); @@ -644,178 +141,307 @@ void CG_RegisterWeapon( int weaponNum ) { } weaponInfo->weaponIcon = trap_R_RegisterShader( item->icon ); - weaponInfo->ammoIcon = trap_R_RegisterShader( item->icon ); for ( ammo = bg_itemlist + 1 ; ammo->classname ; ammo++ ) { if ( ammo->giType == IT_AMMO && ammo->giTag == weaponNum ) { break; } } - if ( ammo->classname && ammo->world_model[0] ) { - weaponInfo->ammoModel = trap_R_RegisterModel( ammo->world_model[0] ); - } +// if ( ammo->classname && ammo->world_model ) { +// weaponInfo->ammoModel = trap_R_RegisterModel( ammo->world_model ); +// } - strcpy( path, item->world_model[0] ); - COM_StripExtension(path, path, sizeof(path)); + strcpy( path, item->view_model ); + COM_StripExtension( path, path ); strcat( path, "_flash.md3" ); weaponInfo->flashModel = trap_R_RegisterModel( path ); - strcpy( path, item->world_model[0] ); - COM_StripExtension(path, path, sizeof(path)); - strcat( path, "_barrel.md3" ); - weaponInfo->barrelModel = trap_R_RegisterModel( path ); + for (barrelInfo = wpnBarrelData; barrelInfo->giTag != WP_0; barrelInfo++) + { + if (barrelInfo->giTag == weaponNum) + { + numBarrels = barrelInfo->numBarrels; + break; + } + } + for (i=0; i< numBarrels; i++) { + Q_strncpyz( path, item->view_model, MAX_QPATH ); + COM_StripExtension( path, path ); + if (i) + { + strcat( path, va("_barrel%d.md3", i+1)); + } + else + strcat( path, "_barrel.md3" ); + weaponInfo->barrelModel[i] = trap_R_RegisterModel( path ); + } - strcpy( path, item->world_model[0] ); - COM_StripExtension(path, path, sizeof(path)); + strcpy( path, item->view_model ); + COM_StripExtension( path, path ); strcat( path, "_hand.md3" ); weaponInfo->handsModel = trap_R_RegisterModel( path ); if ( !weaponInfo->handsModel ) { - weaponInfo->handsModel = trap_R_RegisterModel( "models/weapons2/shotgun/shotgun_hand.md3" ); + weaponInfo->handsModel = trap_R_RegisterModel( "models/weapons2/prifle/prifle_hand.md3" ); } switch ( weaponNum ) { - case WP_GAUNTLET: - MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f ); - weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/melee/fstrun.wav", qfalse ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/melee/fstatck.wav", qfalse ); - break; + case WP_5: + MAKERGB( weaponInfo->flashDlightColor, 0, 0, 0 ); - case WP_LIGHTNING: - MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f ); - weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/melee/fsthum.wav", qfalse ); - weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/lightning/lg_hum.wav", qfalse ); + weaponInfo->firingSound = trap_S_RegisterSound( SOUND_DIR "phaser/phaserfiring.wav" ); + weaponInfo->altFiringSound = trap_S_RegisterSound( SOUND_DIR "phaser/altphaserfiring.wav" ); + weaponInfo->flashSound = trap_S_RegisterSound( SOUND_DIR "phaser/phaserstart.wav" ); + weaponInfo->altFlashSnd = trap_S_RegisterSound( SOUND_DIR "phaser/altphaserstart.wav" ); + weaponInfo->stopSound = trap_S_RegisterSound(SOUND_DIR "phaser/phaserstop.wav"); + weaponInfo->altStopSound = trap_S_RegisterSound(SOUND_DIR "phaser/altphaserstop.wav"); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/lightning/lg_fire.wav", qfalse ); - cgs.media.lightningShader = trap_R_RegisterShader( "lightningBoltNew"); - cgs.media.lightningExplosionModel = trap_R_RegisterModel( "models/weaphits/crackle.md3" ); - cgs.media.sfx_lghit1 = trap_S_RegisterSound( "sound/weapons/lightning/lg_hit.wav", qfalse ); - cgs.media.sfx_lghit2 = trap_S_RegisterSound( "sound/weapons/lightning/lg_hit2.wav", qfalse ); - cgs.media.sfx_lghit3 = trap_S_RegisterSound( "sound/weapons/lightning/lg_hit3.wav", qfalse ); + cgs.media.phaserShader = trap_R_RegisterShader( "gfx/misc/phaser_stx" ); + cgs.media.phaserEmptyShader = trap_R_RegisterShader( "gfx/misc/phaserempty" ); + + cgs.media.phaserAltShader = trap_R_RegisterShader("gfx/effects/whitelaser"); // "gfx/misc/phaser_alt" ); + + cgs.media.phaserAltEmptyShader = trap_R_RegisterShader( "gfx/misc/phaser_altempty" ); + cgs.media.phaserMuzzleEmptyShader= trap_R_RegisterShader( "models/weapons2/phaser/muzzle_empty" ); break; - case WP_GRAPPLING_HOOK: - MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f ); - weaponInfo->missileModel = trap_R_RegisterModel( "models/ammo/rocket/rocket.md3" ); - weaponInfo->missileTrailFunc = CG_GrappleTrail; - weaponInfo->missileDlight = 200; - MAKERGB( weaponInfo->missileDlightColor, 1, 0.75f, 0 ); - weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/melee/fsthum.wav", qfalse ); - weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/melee/fstrun.wav", qfalse ); - cgs.media.lightningShader = trap_R_RegisterShader( "lightningBoltNew"); + case WP_13: + weaponInfo->firingSound = trap_S_RegisterSound( SOUND_DIR "dermal_regen/dm_1.wav" ); + weaponInfo->altFiringSound = trap_S_RegisterSound( SOUND_DIR "dermal_regen/dm_2.wav" ); break; -#ifdef MISSIONPACK - case WP_CHAINGUN: - weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/vulcan/wvulfire.wav", qfalse ); - MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf1b.wav", qfalse ); - weaponInfo->flashSound[1] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf2b.wav", qfalse ); - weaponInfo->flashSound[2] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf3b.wav", qfalse ); - weaponInfo->flashSound[3] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf4b.wav", qfalse ); - weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass; - cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" ); - break; -#endif + case WP_10: + //weaponInfo->missileTrailFunc = FX_StasisProjectileThink; + weaponInfo->missileModel = trap_R_RegisterModel( "models/weapons2/alien_disruptor/disruptor_bolt.md3" ); + weaponInfo->missileDlight = 70; + MAKERGB( weaponInfo->missileDlightColor, 0.0, 1.0, 0.0 ); + MAKERGB( weaponInfo->flashDlightColor, 0.0, 1.0, 0.0 ); + + weaponInfo->altFlashSnd = trap_S_RegisterSound( SOUND_DIR "alien_disruptor/fire.wav" ); + weaponInfo->mainHitSound = trap_S_RegisterSound(SOUND_DIR "stasis/hit_wall.wav"); + + weaponInfo->flashSound = trap_S_RegisterSound( SOUND_DIR "alien_disruptor/disruptorstart.wav" ); + weaponInfo->stopSound = trap_S_RegisterSound(SOUND_DIR "alien_disruptor/disruptorstop.wav"); + weaponInfo->firingSound = trap_S_RegisterSound( SOUND_DIR "alien_disruptor/disruptorfiring.wav" ); + + cgs.media.disruptorBolt = trap_R_RegisterShader( "gfx/misc/disruptor_bolt" ); + cgs.media.disruptorStreak = trap_R_RegisterShader( "gfx/misc/disruptor_streak" ); + //cgs.media.altIMOD2Shader = trap_R_RegisterShader( "gfx/misc/IMOD2alt" ); + //cgs.media.dnBoltShader = trap_R_RegisterShader( "gfx/misc/dnBolt" ); + + cgs.media.greenParticleShader = trap_R_RegisterShader( "gfx/misc/greenparticle" ); + cgs.media.greenParticleStreakShader = trap_R_RegisterShader( "gfx/misc/greenparticle_anamorphic" ); + + cgs.media.disruptorBeam = trap_R_RegisterShader( "gfx/misc/disruptor" ); - case WP_MACHINEGUN: - MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf1b.wav", qfalse ); - weaponInfo->flashSound[1] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf2b.wav", qfalse ); - weaponInfo->flashSound[2] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf3b.wav", qfalse ); - weaponInfo->flashSound[3] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf4b.wav", qfalse ); - weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass; - cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" ); break; - case WP_SHOTGUN: - MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/shotgun/sshotf1b.wav", qfalse ); - weaponInfo->ejectBrassFunc = CG_ShotgunEjectBrass; - break; + case WP_8: + weaponInfo->missileModel = trap_R_RegisterModel( "models/weapons2/launcher/projectile.md3" ); + if(rpg_ctribgrenade.integer == 1)//RPG-X: - RedTechie Possible Hack! FIX | TiM: Heh, you're a possible hack :) + { + weaponInfo->alt_missileModel = trap_R_RegisterModel( "models/weapons2/launcher/projectile2a.md3" ); + weaponInfo->altFlashSnd = trap_S_RegisterSound( SOUND_DIR "glauncher/alt_fire.wav" ); + weaponInfo->altHitSound = trap_S_RegisterSound( "sound/weapons/glauncher/beepa.wav" ); + cgs.media.grenadeAltStickSound = trap_S_RegisterSound(SOUND_DIR "glauncher/alt_stick.wav"); + + } + else + { + weaponInfo->alt_missileModel = trap_R_RegisterModel( "models/weapons2/launcher/projectile2.md3" ); + weaponInfo->altFlashSnd = trap_S_RegisterSound( SOUND_DIR "glauncher/alt_fire.wav" ); + weaponInfo->altHitSound = trap_S_RegisterSound( SOUND_DIR "glauncher/beep.wav" ); + cgs.media.grenadeAltStickSound = trap_S_RegisterSound(SOUND_DIR "glauncher/alt_stick.wav"); + } - case WP_ROCKET_LAUNCHER: - weaponInfo->missileModel = trap_R_RegisterModel( "models/ammo/rocket/rocket.md3" ); - weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/rocket/rockfly.wav", qfalse ); - weaponInfo->missileTrailFunc = CG_RocketTrail; - weaponInfo->missileDlight = 200; - weaponInfo->wiTrailTime = 2000; - weaponInfo->trailRadius = 64; + weaponInfo->missileTrailFunc = FX_GrenadeThink; + //TiM : No flash anymore + MAKERGB( weaponInfo->flashDlightColor, 0.0, 0.0, 0.0 ); + //MAKERGB( weaponInfo->flashDlightColor, 0.6, 0.6, 1 ); + + weaponInfo->flashSound = trap_S_RegisterSound( SOUND_DIR "glauncher/fire.wav" ); + cgs.media.grenadeBounceSound1 = trap_S_RegisterSound(SOUND_DIR "glauncher/bounce1.wav"); + cgs.media.grenadeBounceSound2 = trap_S_RegisterSound(SOUND_DIR "glauncher/bounce2.wav"); + cgs.media.grenadeExplodeSound = trap_S_RegisterSound(SOUND_DIR "glauncher/explode.wav"); + cgs.media.grenadeAltExplodeSnd = trap_S_RegisterSound(SOUND_DIR "glauncher/alt_explode.wav" ); - MAKERGB( weaponInfo->missileDlightColor, 1, 0.75f, 0 ); - MAKERGB( weaponInfo->flashDlightColor, 1, 0.75f, 0 ); - - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/rocket/rocklf1a.wav", qfalse ); - cgs.media.rocketExplosionShader = trap_R_RegisterShader( "rocketExplosion" ); + cgs.media.orangeTrailShader = trap_R_RegisterShader( "gfx/misc/orangetrail" ); + cgs.media.compressionMarkShader = trap_R_RegisterShader( "gfx/damage/burnmark1" ); + cgs.media.whiteLaserShader = trap_R_RegisterShader( "gfx/effects/whitelaser" ); + cgs.media.borgEyeFlareShader = trap_R_RegisterShader( "gfx/misc/borgeyeflare" ); break; -#ifdef MISSIONPACK - case WP_PROX_LAUNCHER: - weaponInfo->missileModel = trap_R_RegisterModel( "models/weaphits/proxmine.md3" ); - weaponInfo->missileTrailFunc = CG_GrenadeTrail; - weaponInfo->wiTrailTime = 700; - weaponInfo->trailRadius = 32; - MAKERGB( weaponInfo->flashDlightColor, 1, 0.70f, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/proxmine/wstbfire.wav", qfalse ); - cgs.media.grenadeExplosionShader = trap_R_RegisterShader( "grenadeExplosion" ); - break; -#endif + case WP_4: + //MAKERGB( weaponInfo->flashDlightColor, 1, 0.6, 0.6 ); - case WP_GRENADE_LAUNCHER: - weaponInfo->missileModel = trap_R_RegisterModel( "models/ammo/grenade1.md3" ); - weaponInfo->missileTrailFunc = CG_GrenadeTrail; - weaponInfo->wiTrailTime = 700; - weaponInfo->trailRadius = 32; - MAKERGB( weaponInfo->flashDlightColor, 1, 0.70f, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/grenade/grenlf1a.wav", qfalse ); - cgs.media.grenadeExplosionShader = trap_R_RegisterShader( "grenadeExplosion" ); + /*weaponInfo->flashSound = trap_S_RegisterSound( SOUND_DIR "scavenger/fire.wav" ); + weaponInfo->altFlashSnd = trap_S_RegisterSound( SOUND_DIR "scavenger/alt_fire.wav" ); + weaponInfo->mainHitSound = trap_S_RegisterSound(SOUND_DIR "scavenger/hit_wall.wav"); + weaponInfo->altHitSound = trap_S_RegisterSound(SOUND_DIR "scavenger/alt_explode.wav"); + weaponInfo->missileTrailFunc = FX_ScavengerProjectileThink; + weaponInfo->alt_missileTrailFunc = FX_ScavengerAltFireThink; +// weaponInfo->wiTrailTime = 100; +// weaponInfo->trailRadius = 8; + cgs.media.tetrionFlareShader = trap_R_RegisterShader( "gfx/misc/tet1" ); + cgs.media.tetrionTrail2Shader = trap_R_RegisterShader( "gfx/misc/trail2" ); + cgs.media.redFlareShader = trap_R_RegisterShader( "gfx/misc/red_flare" ); + + cgs.media.scavengerAltShader = trap_R_RegisterShader( "gfx/misc/scavaltfire" ); + cgs.media.scavExplosionFastShader = trap_R_RegisterShader( "scavExplosionFast" ); + cgs.media.scavExplosionSlowShader = trap_R_RegisterShader( "scavExplosionSlow" ); + cgs.media.compressionMarkShader = trap_R_RegisterShader( "gfx/damage/burnmark1" );*/ break; -#ifdef MISSIONPACK - case WP_NAILGUN: - weaponInfo->ejectBrassFunc = CG_NailgunEjectBrass; - weaponInfo->missileTrailFunc = CG_NailTrail; -// weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/nailgun/wnalflit.wav", qfalse ); - weaponInfo->trailRadius = 16; - weaponInfo->wiTrailTime = 250; - weaponInfo->missileModel = trap_R_RegisterModel( "models/weaphits/nail.md3" ); - MAKERGB( weaponInfo->flashDlightColor, 1, 0.75f, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/nailgun/wnalfire.wav", qfalse ); - break; -#endif + case WP_9: + MAKERGB( weaponInfo->flashDlightColor, 0.6, 0.6, 1 ); //Bluish - case WP_PLASMAGUN: -// weaponInfo->missileModel = cgs.media.invulnerabilityPowerupModel; - weaponInfo->missileTrailFunc = CG_PlasmaTrail; - weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/plasma/lasfly.wav", qfalse ); - MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/plasma/hyprbf1a.wav", qfalse ); - cgs.media.plasmaExplosionShader = trap_R_RegisterShader( "plasmaExplosion" ); - cgs.media.railRingsShader = trap_R_RegisterShader( "railDisc" ); + weaponInfo->missileTrailFunc = FX_QuantumThink; + weaponInfo->alt_missileTrailFunc = FX_QuantumAltThink; + + weaponInfo->missileDlight = 75; + weaponInfo->alt_missileDlight = 100; + MAKERGB( weaponInfo->missileDlightColor, 1.0, 1.0, 0.5); //yellowish + + weaponInfo->flashSound = trap_S_RegisterSound( SOUND_DIR "quantum/fire.wav" ); + weaponInfo->altFlashSnd = trap_S_RegisterSound( SOUND_DIR "quantum/alt_fire.wav" ); + + weaponInfo->mainHitSound = trap_S_RegisterSound( SOUND_DIR "quantum/hit_wall.wav" );; + weaponInfo->altHitSound = trap_S_RegisterSound( SOUND_DIR "quantum/alt_hit_wall.wav" );; + + cgs.media.whiteRingShader = trap_R_RegisterShader( "gfx/misc/whitering" ); + cgs.media.orangeRingShader = trap_R_RegisterShader( "gfx/misc/orangering" ); + cgs.media.quantumExplosionShader = trap_R_RegisterShader( "quantumExplosion" ); + cgs.media.quantumFlashShader = trap_R_RegisterShader( "yellowflash" ); + //cgs.media.bigBoomShader = trap_R_RegisterShader( "gfx/misc/bigboom" ); + cgs.media.orangeTrailShader = trap_R_RegisterShader( "gfx/misc/orangetrail" ); + cgs.media.compressionMarkShader = trap_R_RegisterShader( "gfx/damage/burnmark1" ); + cgs.media.orangeTrailShader = trap_R_RegisterShader( "gfx/misc/orangetrail" ); + cgs.media.quantumRingShader = trap_R_RegisterShader( "gfx/misc/detpack3" ); + cgs.media.quantumBoom = trap_S_RegisterSound ( SOUND_DIR "explosions/explode5.wav" ); break; - case WP_RAILGUN: - weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/railgun/rg_hum.wav", qfalse ); - MAKERGB( weaponInfo->flashDlightColor, 1, 0.5f, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/railgun/railgf1a.wav", qfalse ); - cgs.media.railExplosionShader = trap_R_RegisterShader( "railExplosion" ); - cgs.media.railRingsShader = trap_R_RegisterShader( "railDisc" ); - cgs.media.railCoreShader = trap_R_RegisterShader( "railCore" ); + case WP_1: + /*MAKERGB( weaponInfo->flashDlightColor, 0.6, 0.6, 1 ); + + weaponInfo->flashSound = trap_S_RegisterSound( SOUND_DIR "IMOD/fire.wav" ); + weaponInfo->altFlashSnd = trap_S_RegisterSound( SOUND_DIR "IMOD/alt_fire.wav" ); + + cgs.media.IMODShader = trap_R_RegisterShader( "gfx/misc/IMOD" ); + cgs.media.IMOD2Shader = trap_R_RegisterShader( "gfx/misc/IMOD2" ); + cgs.media.altIMODShader = trap_R_RegisterShader( "gfx/misc/IMODalt" ); + cgs.media.altIMOD2Shader = trap_R_RegisterShader( "gfx/misc/IMOD2alt" ); + cgs.media.imodExplosionShader = trap_R_RegisterShader( "imodExplosion" );*/ break; - case WP_BFG: - weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/bfg/bfg_hum.wav", qfalse ); - MAKERGB( weaponInfo->flashDlightColor, 1, 0.7f, 1 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/bfg/bfg_fire.wav", qfalse ); - cgs.media.bfgExplosionShader = trap_R_RegisterShader( "bfgExplosion" ); - weaponInfo->missileModel = trap_R_RegisterModel( "models/weaphits/bfg.md3" ); - weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/rocket/rockfly.wav", qfalse ); + case WP_6: + if(!grp_berp.integer) { + MAKERGB( weaponInfo->flashDlightColor, 0.59, 0.24, 0.25 ); + MAKERGB( weaponInfo->missileDlightColor, 0.59, 0.24, 0.25 ); + } else { + MAKERGB( weaponInfo->flashDlightColor, 0.16, 0.32, 0.5 ); + MAKERGB( weaponInfo->missileDlightColor, 0.16, 0.32, 0.5 ); + } + + weaponInfo->missileModel = trap_R_RegisterModel( "models/weapons2/prifle/prifle_bolt.md3" ); + weaponInfo->missileDlight = 90; + + weaponInfo->flashSound = trap_S_RegisterSound( SOUND_DIR "prifle/fire.wav" ); + + weaponInfo->altFlashSnd = trap_S_RegisterSound( SOUND_DIR "prifle/phaserriflestart.wav" ); + weaponInfo->altStopSound = trap_S_RegisterSound(SOUND_DIR "prifle/phaserriflestop.wav"); + weaponInfo->altFiringSound = trap_S_RegisterSound( SOUND_DIR "prifle/phaserriflefiring.wav" ); + + weaponInfo->mainHitSound = trap_S_RegisterSound( SOUND_DIR "prifle/impact.wav" );; + + cgs.media.prifleImpactShader = trap_R_RegisterShader( "gfx/effects/prifle_hit" ); + cgs.media.compressionAltBeamShader = trap_R_RegisterShader( "gfx/effects/prifle_altbeam" ); + cgs.media.compressionAltBlastShader = trap_R_RegisterShader( "gfx/effects/prifle_altblast" ); + cgs.media.compressionMarkShader = trap_R_RegisterShader( "gfx/damage/burnmark1" ); + cgs.media.prifleBolt = trap_R_RegisterShader( "gfx/misc/priflebolt" ); + + cgs.media.liteRedParticleStreakShader = trap_R_RegisterShader( "gfx/misc/literedparticle_anamorphic" ); + cgs.media.liteRedParticleShader = trap_R_RegisterShader( "gfx/misc/literedparticle" ); + + cgs.media.flashlightModel = trap_R_RegisterModel( "models/weapons2/prifle/prifle_flashlight.md3" ); //RPG-X : TiM - flashlight model + + cgs.media.prifleBeam = trap_R_RegisterShader( "gfx/misc/phaser_rifle" ); + + break; + +/* case WP_7: + MAKERGB( weaponInfo->flashDlightColor, 0.16, 0.16, 1 ); + weaponInfo->flashSound = trap_S_RegisterSound( "sound/weapons/hitonhead.wav" ); + weaponInfo->altFlashSnd = trap_S_RegisterSound( "sound/weapons/guncharge.wav" ); + cgs.media.tetrionTrail2Shader = trap_R_RegisterShader( "gfx/misc/trail2" ); + cgs.media.compressionMarkShader = trap_R_RegisterShader( "gfx/damage/burnmark1" ); + weaponInfo->mainHitSound = trap_S_RegisterSound( SOUND_DIR "prifle/impact.wav" ); + break;*/ + /* + case WP_7: //OLD CODE (replaced for TR116) + MAKERGB( weaponInfo->flashDlightColor, 0.6, 0.6, 1 ); + + weaponInfo->flashSound = trap_S_RegisterSound( SOUND_DIR "tetrion/fire.wav" ); + weaponInfo->altFlashSnd = trap_S_RegisterSound( SOUND_DIR "tetrion/alt_fire.wav" ); + cgs.media.tetrionRicochetSound1 = trap_S_RegisterSound(SOUND_DIR "tetrion/ricochet1.wav"); + cgs.media.tetrionRicochetSound2 = trap_S_RegisterSound(SOUND_DIR "tetrion/ricochet2.wav"); + cgs.media.tetrionRicochetSound3 = trap_S_RegisterSound(SOUND_DIR "tetrion/ricochet3.wav"); + + weaponInfo->missileTrailFunc = FX_TetrionProjectileThink; + weaponInfo->alt_missileTrailFunc = FX_TetrionProjectileThink; + + cgs.media.greenBurstShader = trap_R_RegisterShader( "gfx/misc/greenburst" ); + cgs.media.greenTrailShader = trap_R_RegisterShader( "gfx/misc/greentrail" ); + cgs.media.tetrionTrail2Shader = trap_R_RegisterShader( "gfx/misc/trail2" ); + cgs.media.tetrionFlareShader = trap_R_RegisterShader( "gfx/misc/tet1" ); + cgs.media.borgFlareShader = trap_R_RegisterShader( "gfx/misc/borgflare" ); + cgs.media.bulletmarksShader = trap_R_RegisterShader( "textures/decals/bulletmark4" ); + break; +*/ + case WP_12: + weaponInfo->flashSound = weaponInfo->altFlashSnd = trap_S_RegisterSound( "sound/items/jetpuffmed.wav" ); + break; + + case WP_2: + weaponInfo->firingSound= trap_S_RegisterSound( "sound/items/tricorderscan.wav" ); //altFlashSnd + weaponInfo->altFiringSound = trap_S_RegisterSound( "sound/ambience/voyager/medictricorder.wav" ); //flashSound + + //weaponInfo->isAnimSndBased = qtrue; + break; + + case WP_3: + weaponInfo->firingSound = trap_S_RegisterSound( SOUND_DIR "padd/padd_1.wav" ); //flashSound + weaponInfo->altFiringSound = trap_S_RegisterSound( SOUND_DIR "padd/padd_2.wav" ); //altFlashSnd + + weaponInfo->isAnimSndBased = qtrue; + break; + + case WP_15: + weaponInfo->firingSound = trap_S_RegisterSound( SOUND_DIR "hyperspanner/spanner_1.wav" ); + weaponInfo->altFiringSound = trap_S_RegisterSound( SOUND_DIR "hyperspanner/spanner_2.wav" ); + break; + + case WP_7: + weaponInfo->flashSound = trap_S_RegisterSound( SOUND_DIR "hitonhead.wav" ); + weaponInfo->altFlashSnd = weaponInfo->flashSound; + //weaponInfo->altFlashSnd = trap_S_RegisterSound( "sound/weapons/guncharge.wav" ); + break; + +//Toolkit + case WP_14: + weaponInfo->flashSound = trap_S_RegisterSound( SOUND_DIR "toolkit/toolkit_1.wav" ); + weaponInfo->altFlashSnd = trap_S_RegisterSound( SOUND_DIR "toolkit/toolkit_2.wav" ); + break; + +//Medkit + case WP_11: + weaponInfo->flashSound = trap_S_RegisterSound( SOUND_DIR "medkit/medkit_1.wav" ); + weaponInfo->altFlashSnd = trap_S_RegisterSound( SOUND_DIR "medkit/medkit_2.wav" ); break; default: MAKERGB( weaponInfo->flashDlightColor, 1, 1, 1 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/rocket/rocklf1a.wav", qfalse ); + weaponInfo->flashSound = trap_S_RegisterSound( SOUND_DIR "prifle/fire.wav" ); break; } } @@ -831,10 +457,6 @@ void CG_RegisterItemVisuals( int itemNum ) { itemInfo_t *itemInfo; gitem_t *item; - if ( itemNum < 0 || itemNum >= bg_numItems ) { - CG_Error( "CG_RegisterItemVisuals: itemNum %d out of range [0-%d]", itemNum, bg_numItems-1 ); - } - itemInfo = &cg_items[ itemNum ]; if ( itemInfo->registered ) { return; @@ -845,7 +467,7 @@ void CG_RegisterItemVisuals( int itemNum ) { memset( itemInfo, 0, sizeof( &itemInfo ) ); itemInfo->registered = qtrue; - itemInfo->models[0] = trap_R_RegisterModel( item->world_model[0] ); + itemInfo->model = trap_R_RegisterModel( item->world_model ); itemInfo->icon = trap_R_RegisterShader( item->icon ); @@ -853,15 +475,29 @@ void CG_RegisterItemVisuals( int itemNum ) { CG_RegisterWeapon( item->giTag ); } - // - // powerups have an accompanying ring or sphere - // - if ( item->giType == IT_POWERUP || item->giType == IT_HEALTH || - item->giType == IT_ARMOR || item->giType == IT_HOLDABLE ) { - if ( item->world_model[1] ) { - itemInfo->models[1] = trap_R_RegisterModel( item->world_model[1] ); + // since the seeker uses the scavenger rifes sounds, we must precache the scavenger rifle stuff if we hit the item seeker +/* if ( item->giTag == PW_FLASHLIGHT) + { + CG_RegisterWeapon( WP_4 ); + }*/ + + // hang onto the handles for holdable items in case they're useable (e.g. detpack) +/* if (IT_HOLDABLE == item->giType) + { + // sanity check + if ( (item->giTag < HI_NUM_HOLDABLE) && (item->giTag > 0) ) // use "> 0" cuz first slot should be empty + { + if (item->world_model[1]) + { + cgs.useableModels[item->giTag] = trap_R_RegisterModel( item->useablemodel ); + } + else + { + cgs.useableModels[item->giTag] = itemInfo->model]; + } } } +*/ } @@ -880,34 +516,60 @@ CG_MapTorsoToWeaponFrame ================= */ static int CG_MapTorsoToWeaponFrame( clientInfo_t *ci, int frame ) { + animation_t *anim; // change weapon - if ( frame >= ci->animations[TORSO_DROP].firstFrame - && frame < ci->animations[TORSO_DROP].firstFrame + 9 ) { - return frame - ci->animations[TORSO_DROP].firstFrame + 6; + anim = &cg_animsList[ci->animIndex].animations[TORSO_DROPWEAP1]; + if ( frame >= anim->firstFrame + && frame < anim->firstFrame + 9 ) { + return frame - anim->firstFrame + 6; } // stand attack - if ( frame >= ci->animations[TORSO_ATTACK].firstFrame - && frame < ci->animations[TORSO_ATTACK].firstFrame + 6 ) { - return 1 + frame - ci->animations[TORSO_ATTACK].firstFrame; + anim = &cg_animsList[ci->animIndex].animations[BOTH_ATTACK3]; + if ( frame >= anim->firstFrame && frame < anim->firstFrame + 6 ) { + return 1 + frame - anim->firstFrame; } // stand attack 2 - if ( frame >= ci->animations[TORSO_ATTACK2].firstFrame - && frame < ci->animations[TORSO_ATTACK2].firstFrame + 6 ) { - return 1 + frame - ci->animations[TORSO_ATTACK2].firstFrame; + anim = &cg_animsList[ci->animIndex].animations[BOTH_ATTACK2]; + if ( frame >= anim->firstFrame && frame < anim->firstFrame + 6 ) { + return 1 + frame - anim->firstFrame; } + + anim = &cg_animsList[ci->animIndex].animations[TORSO_WEAPONREADY1]; + if ( frame >= anim->firstFrame && frame < anim->firstFrame + 6 ) { + return 1 + frame - anim->firstFrame; + } + + // change weapon + //USED TO BE TORSO_RAISE +/* if ( frame >= ci->animations[TORSO_DROPWEAP1].firstFrame + && frame < ci->animations[TORSO_DROPWEAP1].firstFrame + 9 ) { + return frame - ci->animations[TORSO_DROPWEAP1].firstFrame + 6; + } + + // stand attack + if ( frame >= ci->animations[BOTH_ATTACK3].firstFrame + && frame < ci->animations[BOTH_ATTACK3].firstFrame + 6 ) { + return 1 + frame - ci->animations[BOTH_ATTACK3].firstFrame; + } + + // stand attack 2 + if ( frame >= ci->animations[BOTH_ATTACK2].firstFrame + && frame < ci->animations[BOTH_ATTACK2].firstFrame + 6 ) { + return 1 + frame - ci->animations[BOTH_ATTACK2].firstFrame; + }*/ return 0; } - /* ============== CG_CalculateWeaponPosition ============== */ +//BOOKMARK static void CG_CalculateWeaponPosition( vec3_t origin, vec3_t angles ) { float scale; int delta; @@ -967,162 +629,153 @@ so the endpoint will reflect the simulated strike (lagging the predicted angle) =============== */ -static void CG_LightningBolt( centity_t *cent, vec3_t origin ) { - trace_t trace; - refEntity_t beam; - vec3_t forward; - vec3_t muzzlePoint, endPoint; - int anim; - if (cent->currentState.weapon != WP_LIGHTNING) { - return; - } +#define RANGE_BEAM (2048.0) +#define BEAM_VARIATION 6 - memset( &beam, 0, sizeof( beam ) ); - - // CPMA "true" lightning - if ((cent->currentState.number == cg.predictedPlayerState.clientNum) && (cg_trueLightning.value != 0)) { - vec3_t angle; - int i; - - for (i = 0; i < 3; i++) { - float a = cent->lerpAngles[i] - cg.refdefViewAngles[i]; - if (a > 180) { - a -= 360; - } - if (a < -180) { - a += 360; - } - - angle[i] = cg.refdefViewAngles[i] + a * (1.0 - cg_trueLightning.value); - if (angle[i] < 0) { - angle[i] += 360; - } - if (angle[i] > 360) { - angle[i] -= 360; - } - } - - AngleVectors(angle, forward, NULL, NULL ); - VectorCopy(cent->lerpOrigin, muzzlePoint ); -// VectorCopy(cg.refdef.vieworg, muzzlePoint ); - } else { - // !CPMA - AngleVectors( cent->lerpAngles, forward, NULL, NULL ); - VectorCopy(cent->lerpOrigin, muzzlePoint ); - } - - anim = cent->currentState.legsAnim & ~ANIM_TOGGLEBIT; - if ( anim == LEGS_WALKCR || anim == LEGS_IDLECR ) { - muzzlePoint[2] += CROUCH_VIEWHEIGHT; - } else { - muzzlePoint[2] += DEFAULT_VIEWHEIGHT; - } - - VectorMA( muzzlePoint, 14, forward, muzzlePoint ); - - // project forward by the lightning range - VectorMA( muzzlePoint, LIGHTNING_RANGE, forward, endPoint ); - - // see if it hit a wall - CG_Trace( &trace, muzzlePoint, vec3_origin, vec3_origin, endPoint, - cent->currentState.number, MASK_SHOT ); - - // this is the endpoint - VectorCopy( trace.endpos, beam.oldorigin ); - - // use the provided origin, even though it may be slightly - // different than the muzzle origin - VectorCopy( origin, beam.origin ); - - beam.reType = RT_LIGHTNING; - beam.customShader = cgs.media.lightningShader; - trap_R_AddRefEntityToScene( &beam ); - - // add the impact flare if it hit something - if ( trace.fraction < 1.0 ) { - vec3_t angles; - vec3_t dir; - - VectorSubtract( beam.oldorigin, beam.origin, dir ); - VectorNormalize( dir ); - - memset( &beam, 0, sizeof( beam ) ); - beam.hModel = cgs.media.lightningExplosionModel; - - VectorMA( trace.endpos, -16, dir, beam.origin ); - - // make a random orientation - angles[0] = rand() % 360; - angles[1] = rand() % 360; - angles[2] = rand() % 360; - AnglesToAxis( angles, beam.axis ); - trap_R_AddRefEntityToScene( &beam ); - } -} -/* - -static void CG_LightningBolt( centity_t *cent, vec3_t origin ) { +void CG_LightningBolt( centity_t *cent, vec3_t origin ) +{ trace_t trace; - refEntity_t beam; - vec3_t forward; - vec3_t muzzlePoint, endPoint; +// gentity_t *traceEnt; + vec3_t startpos, endpos, forward; + qboolean spark = qfalse, impact = qtrue; - if ( cent->currentState.weapon != WP_LIGHTNING ) { - return; + if ( cg.snap->ps.pm_type == PM_INTERMISSION ) + { + return; // Don't draw a phaser during an intermission you crezzy mon! } - memset( &beam, 0, sizeof( beam ) ); + //Must be a durational weapon + if ( cent->currentState.clientNum == cg.snap->ps.clientNum && !cg.renderingThirdPerson && !(cent->currentState.eFlags & EF_ITEMPLACEHOLDER ) ) //fuck decoys + { + // different checks for first person view + if ( cg.snap->ps.weapon == WP_15 || + cg.snap->ps.weapon == WP_5 || + cg.snap->ps.weapon == WP_13 || + (cg.snap->ps.eFlags & EF_ALT_FIRING && cg.snap->ps.weapon == WP_6 ) + || (!(cg.snap->ps.eFlags & EF_ALT_FIRING) && cg.snap->ps.weapon == WP_10 ) + ) + { /*continue*/ } + else + return; + } else { + if ( cent->currentState.weapon == WP_15 || + cent->currentState.weapon == WP_5 || + cent->currentState.weapon == WP_13 || + (cent->currentState.eFlags & EF_ALT_FIRING && (cent->currentState.weapon == WP_6) ) || + (!(cent->currentState.eFlags & EF_ALT_FIRING) && cent->currentState.weapon == WP_10) + ) + { /*continue*/ } + else + return; + } - // find muzzle point for this frame - VectorCopy( cent->lerpOrigin, muzzlePoint ); - AngleVectors( cent->lerpAngles, forward, NULL, NULL ); + // Find the impact point of the beam + if ( cent->currentState.clientNum == cg.snap->ps.clientNum + && !cg.renderingThirdPerson ) { + // take origin from view +/* + VectorCopy( cg.refdef.vieworg, origin ); + VectorMA( origin, -8, cg.refdef.viewaxis[2], origin ); + VectorMA( origin, 8, cg.refdef.viewaxis[0], origin ); + VectorMA( origin, -2, cg.refdef.viewaxis[1], origin ); +*/ + VectorCopy( cg.refdef.viewaxis[0], forward ); + VectorCopy( cg.refdef.vieworg, startpos); + } + else + { + // take origin from entity + if ( cent->currentState.clientNum == cg.snap->ps.clientNum ) + AngleVectors( cg.predictedPlayerState.viewangles, forward, NULL, NULL ); + else + AngleVectors( cent->lerpAngles, forward, NULL, NULL ); + VectorCopy( origin, startpos); - // FIXME: crouch - muzzlePoint[2] += DEFAULT_VIEWHEIGHT; + // Check first from the center to the muzzle. + CG_Trace(&trace, cent->lerpOrigin, vec3_origin, vec3_origin, origin, cent->currentState.number, MASK_SHOT); + if (trace.fraction < 1.0) + { // We hit something here... Stomp the muzzle back to the eye... + VectorCopy(cent->lerpOrigin, startpos); + if ( cg.snap->ps.eFlags & EF_FULL_ROTATE && Q_fabs( cg.snap->ps.viewangles[PITCH] ) > 89.0f ) + startpos[2] -= 20; + else + startpos[2] += cg.snap->ps.viewheight; + } + } - VectorMA( muzzlePoint, 14, forward, muzzlePoint ); + VectorMA( startpos, RANGE_BEAM, forward, endpos ); - // project forward by the lightning range - VectorMA( muzzlePoint, LIGHTNING_RANGE, forward, endPoint ); + // Add a subtle variation to the beam weapon's endpoint + /*for (i = 0; i < 3; i ++ ) + { + endpos[i] += crandom() * BEAM_VARIATION; + }*/ - // see if it hit a wall - CG_Trace( &trace, muzzlePoint, vec3_origin, vec3_origin, endPoint, - cent->currentState.number, MASK_SHOT ); + CG_Trace( &trace, startpos, vec3_origin, vec3_origin, endpos, cent->currentState.number, MASK_SHOT ); - // this is the endpoint - VectorCopy( trace.endpos, beam.oldorigin ); +// traceEnt = &g_entities[ trace.entityNum ]; - // use the provided origin, even though it may be slightly - // different than the muzzle origin - VectorCopy( origin, beam.origin ); + // Make sparking be a bit less frame-rate dependent..also never add sparking when we hit a surface with a NOIMPACT flag + if (!(trace.surfaceFlags & SURF_NOIMPACT)) + { + spark = qtrue; + } - beam.reType = RT_LIGHTNING; - beam.customShader = cgs.media.lightningShader; - trap_R_AddRefEntityToScene( &beam ); + // Don't draw certain kinds of impacts when it hits a player and such..or when we hit a surface with a NOIMPACT flag + if ( cg_entities[trace.entityNum].currentState.eType == ET_PLAYER || (trace.surfaceFlags & SURF_NOIMPACT) ) + { + impact = qfalse; + } + + // Add in the effect + switch ( cent->currentState.weapon ) + { + case WP_5: + if (cg.snap->ps.rechargeTime == 0) + { + if ( cent->currentState.eFlags & EF_ALT_FIRING ) + FX_PhaserAltFire( origin, trace.endpos, trace.plane.normal, spark, impact, cent->pe.empty ); + else + FX_PhaserFire( origin, trace.endpos, trace.plane.normal, spark, impact, cent->pe.empty ); + } + break; + case WP_6: + if ( cent->currentState.eFlags & EF_ALT_FIRING ) + { + FX_PrifleBeamFire( origin, trace.endpos, trace.plane.normal, spark, impact, cent->pe.empty ); + } + break; + case WP_15: + if ( cent->currentState.eFlags & EF_ALT_FIRING ) + FX_ProbeBeam( origin, forward, cent->currentState.clientNum, qtrue ); + else + FX_ProbeBeam( origin, forward, cent->currentState.clientNum, qfalse ); + break; - // add the impact flare if it hit something - if ( trace.fraction < 1.0 ) { - vec3_t angles; - vec3_t dir; + case WP_13: + if ( cent->currentState.eFlags & EF_ALT_FIRING ) + FX_RegenBeam( origin, forward, cent->currentState.clientNum, qtrue ); + else + FX_RegenBeam( origin, forward, cent->currentState.clientNum, qfalse ); + break; - VectorSubtract( beam.oldorigin, beam.origin, dir ); - VectorNormalize( dir ); + case WP_10: + if ( cent->currentState.eFlags & EF_FIRING && !(cent->currentState.eFlags & EF_ALT_FIRING) ) + FX_DisruptorBeamFire( origin, trace.endpos, trace.plane.normal, spark, impact, cent->pe.empty ); - memset( &beam, 0, sizeof( beam ) ); - beam.hModel = cgs.media.lightningExplosionModel; +/* case WP_13: + if (!(cent->currentState.eFlags & EF_ALT_FIRING)) + { + vec3_t org; - VectorMA( trace.endpos, -16, dir, beam.origin ); - - // make a random orientation - angles[0] = rand() % 360; - angles[1] = rand() % 360; - angles[2] = rand() % 360; - AnglesToAxis( angles, beam.axis ); - trap_R_AddRefEntityToScene( &beam ); + // Move the beam back a bit to help cover up the poly edges on the fire beam + VectorMA( origin, -4, forward, org ); + FX_DreadnoughtFire( org, trace.endpos, trace.plane.normal, spark, impact ); + } + break;*/ } } -*/ /* @@ -1153,11 +806,6 @@ static float CG_MachinegunSpinAngle( centity_t *cent ) { cent->pe.barrelTime = cg.time; cent->pe.barrelAngle = AngleMod( angle ); cent->pe.barrelSpinning = !!(cent->currentState.eFlags & EF_FIRING); -#ifdef MISSIONPACK - if ( cent->currentState.weapon == WP_CHAINGUN && !cent->pe.barrelSpinning ) { - trap_S_StartSound( NULL, cent->currentState.number, CHAN_WEAPON, trap_S_RegisterSound( "sound/weapons/vulcan/wvulwind.wav", qfalse ) ); - } -#endif } return angle; @@ -1169,25 +817,247 @@ static float CG_MachinegunSpinAngle( centity_t *cent ) { CG_AddWeaponWithPowerups ======================== */ -static void CG_AddWeaponWithPowerups( refEntity_t *gun, int powerups ) { + +static void CG_AddWeaponWithPowerups( refEntity_t *gun, int powerups, beamData_t* beamData, int cloakTime, int decloakTime ) // +{ // add powerup effects - if ( powerups & ( 1 << PW_INVIS ) ) { - gun->customShader = cgs.media.invisShader; - trap_R_AddRefEntityToScene( gun ); - } else { + if ( powerups & ( 1 << PW_INVIS ) || ( !(powerups & ( 1 << PW_INVIS )) && decloakTime > 0 ) ) { + + //TiM - modified so it persists during the first bit of cloaking / last of decloaking + if ( ( cloakTime <= 0 && decloakTime <= 0 ) || ( decloakTime > 0 && cg.time < ( decloakTime + Q_FLASH_TIME * 0.5 ) ) + || ( cloakTime > 0 && cg.time > ( cloakTime + Q_FLASH_TIME * 0.5 ) ) ) + { + if ( /*cg.snap->ps.persistant[PERS_CLASS] == PC_ADMIN*/ cgs.clientinfo[cg.snap->ps.clientNum].isAdmin ) + {//admins can see cloaked people + //gun->customShader = cgs.media.teleportEffectShader; + //TiM - Make it look cooler - Half invis + gun->renderfx |= RF_FORCE_ENT_ALPHA; + gun->shaderRGBA[3] = (unsigned char)(0.4f * 255.0f); + trap_R_AddRefEntityToScene( gun ); + } + } + else + trap_R_AddRefEntityToScene( gun ); + + //gun->customShader = cgs.media.invisShader; + //trap_R_AddRefEntityToScene( gun ); + } + else if ( powerups & ( 1 << PW_BEAM_OUT ) || powerups & ( 1 << PW_QUAD ) ) + { + int btime; + btime = cg.time - beamData->beamTimeParam; + + if ( btime <= PLAYER_BEAM_FADE ) { + if ( powerups & ( 1 << PW_BEAM_OUT ) ) { + gun->shaderRGBA[3] = 255; + } + else { + gun->shaderRGBA[3] = 0; + } + } + else if ( btime >= ( PLAYER_BEAM_FADE + PLAYER_BEAM_FADETIME ) ) { + if ( powerups & ( 1 << PW_BEAM_OUT ) ) { + gun->shaderRGBA[3] = 0; + } + else { + gun->shaderRGBA[3] = 255; + } + } + + if (btime > PLAYER_BEAM_FADE && btime < (PLAYER_BEAM_FADE + PLAYER_BEAM_FADETIME) ) + { + gun->renderfx |= RF_FORCE_ENT_ALPHA; + gun->shaderRGBA[3] = (int)(255 * beamData->beamAlpha); + } + + if ( gun->shaderRGBA[3] > 0 ) { + trap_R_AddRefEntityToScene( gun ); + gun->renderfx &= ~RF_FORCE_ENT_ALPHA; + gun->shaderRGBA[3] = 255; + } + + //Just a precaution. Loop it once, then the player should be invisible + if ( btime < 4100 ) { + gun->customShader = cgs.media.transportShader; + gun->shaderTime = beamData->beamTimeParam * 0.001; + trap_R_AddRefEntityToScene( gun ); + } + } else if(powerups & (1 << PW_BORG_ADAPT)) { + gun->renderfx |= RF_FORCE_ENT_ALPHA; + gun->shaderRGBA[3] = 255; + trap_R_AddRefEntityToScene(gun); + gun->customShader = cgs.media.borgFullBodyShieldShader; + trap_R_AddRefEntityToScene(gun); + return; + } + else { trap_R_AddRefEntityToScene( gun ); - if ( powerups & ( 1 << PW_BATTLESUIT ) ) { + if(gun->renderfx & RF_FORCE_ENT_ALPHA) { + gun->renderfx &= ~RF_FORCE_ENT_ALPHA; + } + +/* if ( powerups & ( 1 << PW_BOLTON ) ) { gun->customShader = cgs.media.battleWeaponShader; trap_R_AddRefEntityToScene( gun ); - } - if ( powerups & ( 1 << PW_QUAD ) ) { + }*/ + +/* if ( powerups & ( 1 << PW_QUAD ) ) { gun->customShader = cgs.media.quadWeaponShader; trap_R_AddRefEntityToScene( gun ); - } + }*/ + /*if (powerups & (1 << PW_OUCH)) + { + gun->customShader = cgs.media.holoOuchShader; + // set rgb to 1 of 16 values from 0 to 255. don't use random so that the three + //parts of the player model as well as the gun will all look the same + gun->shaderRGBA[0] = + gun->shaderRGBA[1] = + gun->shaderRGBA[2] = ((cg.time % 17)*0.0625)*255;//irandom(0,255); + trap_R_AddRefEntityToScene(gun); + }*/ } } +/*void CG_CoffeeSteamFirstPerson ( refEntity_t* parent, weaponInfo_t *weapon ) { + refEntity_t steam; + vec3_t angle = { 0.0, 0.0, 6.0 }; + + CG_PositionEntityOnTag( &steam, parent, weapon->viewModel, "tag_steam1" ); + + if ( VectorCompare( steam.origin, parent->origin ) ) {//whelp, for some whacky reason, there's no tag O_o + return; + } + + //CG_Steam( steam.origin, angle); + //Disables the OpenGL Hack where the viewmodel is drawn over EVERYTHING ELSE INCLUDING THE STEAM + parent->renderfx &= ~RF_DEPTHHACK; + + if (cg.time % 10 == 0 ) { + FX_AddSprite( steam.origin, + angle, qfalse, + ( random() * 3 + 1), (10), //random() * 4 + 2 //12 + 0.6 + random() * 0.4, 0.0, + random() * 120, //180 + 0.0, + 1300, //300 //random() * 200 + 1200, //300 // + cgs.media.steamShader ); + } + localEntity_t *FX_AddSprite(vec3_t origin, vec3_t velocity, qboolean gravity, float scale, float dscale, + float startalpha, float endalpha, float roll, float elasticity, + float killTime, qhandle_t shader)*/ + + //if ( +/*} + +void CG_CoffeeSteamThirdPerson ( refEntity_t* parent, weaponInfo_t *weapon) { + refEntity_t steam; + localEntity_t *le = NULL; + + vec3_t angle = { 0.0, 0.0, 6.0 }; + + CG_PositionEntityOnTag( &steam, parent, weapon->weaponModel, "tag_steam"); + + if ( VectorCompare( steam.origin, parent->origin ) ) {//whelp, for some whacky reason, there's no tag O_o + return; + } + + if (cg.time % 10 == 0 ) { + le = FX_AddSprite( steam.origin, + angle, qfalse, + ( random() * 1.2 + 0.5), ( 5 ), //random() * 4 + 2 //12 + 0.6 + random() * 0.4, 0.0, + random() * 120, //180 + 0.0, + 1300, //300 //random() * 200 + 1200, //300 // + cgs.media.steamShader ); + } + localEntity_t *FX_AddSprite(vec3_t origin, vec3_t velocity, qboolean gravity, float scale, float dscale, + float startalpha, float endalpha, float roll, float elasticity, + float killTime, qhandle_t shader)*/ + + //if ( +//}*/ + +void CG_CoffeeSteam( refEntity_t* parent, weaponInfo_t *weapon, qboolean thirdperson ) { + refEntity_t steam; + localEntity_t *le; + + vec3_t angle = { 0.0, 0.0, 10.0 }; + + //FIXME: I probably should name the tag the same thing in both models... O_o + if ( !thirdperson ) { + CG_PositionEntityOnTag( &steam, parent, weapon->viewModel, "tag_steam1" ); + } + else { + CG_PositionEntityOnTag( &steam, parent, weapon->weaponModel, "tag_steam"); + } + + if ( VectorCompare( steam.origin, parent->origin ) ) {//whelp, for some whacky reason, there's no tag O_o + return; + } + + //CG_Steam( steam.origin, angle); + //Disables the OpenGL Hack where the viewmodel is drawn over EVERYTHING ELSE INCLUDING THE STEAM + parent->renderfx &= ~RF_DEPTHHACK; + + if (cg.time % 10 == 0 ) { //release a sprite every .01 of a second + le = FX_AddSprite( steam.origin, + angle, qfalse, + ( thirdperson ? random() * 1.2 + 0.5 : random() * 1 + 1), ( thirdperson ? 7 : 10), //random() * 4 + 2 //12 + 0.05 + random() * 0.1, 0.0, + random() * 120, //180 + 0.0, + 1500, //300 //random() * 200 + 1200, //300 // + cgs.media.steamShader ); + } + /*localEntity_t *FX_AddSprite(vec3_t origin, vec3_t velocity, qboolean gravity, float scale, float dscale, + float startalpha, float endalpha, float roll, float elasticity, + float killTime, qhandle_t shader)*/ + //Without this, the steam gets drawn behind the cup... which looks weird + //le->refEntity.renderfx |= RF_DEPTHHACK; +} + +/* +============= +getClassColor + +RPG-X : TiM - used to determine what color skins the weapons should have applied to them +My way of having to not have to enter in so many conditionals over and over +============= +*/ + +//char *getClassColor ( void ) +//{ +// /*if (( cg.snap->ps.persistant[PERS_CLASS] == PC_SECURITY ) +// || ( cg.snap->ps.persistant[PERS_CLASS] == PC_ENGINEER)) +// { +// return "default"; +// } +// +// if (( cg.snap->ps.persistant[PERS_CLASS] == PC_SCIENCE ) +// || ( cg.snap->ps.persistant[PERS_CLASS] == PC_MEDICAL ) +// || ( cg.snap->ps.persistant[PERS_CLASS] == PC_ALPHAOMEGA22 )) +// { +// return "teal"; +// } +// +// if ((cg.snap->ps.persistant[PERS_CLASS] == PC_COMMAND) +// || (cg.snap->ps.persistant[PERS_CLASS] == PC_ADMIN)) +// { +// return "red"; +// } +// if ( cg.snap->ps.persistant[PERS_CLASS] == PC_NOCLASS ) { +// return "NULL"; +// }*/ +// +// //lolz... this time, let's base it off of current model +// //rather than class +// cgs.clientinfo[0]. +// +// return "default"; +//} + /* ============= @@ -1198,7 +1068,7 @@ The main player will have this called for BOTH cases, so effects like light and sound should only be done on the world model case. ============= */ -void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent, int team ) { +void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent ) { refEntity_t gun; refEntity_t barrel; refEntity_t flash; @@ -1206,7 +1076,11 @@ void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent weapon_t weaponNum; weaponInfo_t *weapon; centity_t *nonPredictedCent; - orientation_t lerped; + int i = 0, numBarrels = 0; + wpnBarrelInfo_t *barrelInfo = NULL; + + char filename[MAX_QPATH]; + char* skinColor; weaponNum = cent->currentState.weapon; @@ -1220,72 +1094,181 @@ void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent gun.renderfx = parent->renderfx; // set custom shading for railgun refire rate - if( weaponNum == WP_RAILGUN ) { - clientInfo_t *ci = &cgs.clientinfo[cent->currentState.clientNum]; - if( cent->pe.railFireTime + 1500 > cg.time ) { - int scale = 255 * ( cg.time - cent->pe.railFireTime ) / 1500; - gun.shaderRGBA[0] = ( ci->c1RGBA[0] * scale ) >> 8; - gun.shaderRGBA[1] = ( ci->c1RGBA[1] * scale ) >> 8; - gun.shaderRGBA[2] = ( ci->c1RGBA[2] * scale ) >> 8; + /*if ( ps ) { + if ( cg.predictedPlayerState.weapon == WP_1 + && cg.predictedPlayerState.weaponstate == WEAPON_FIRING ) { + float f; + + f = (float)cg.predictedPlayerState.weaponTime / 1500; + gun.shaderRGBA[1] = 0; + gun.shaderRGBA[0] = + gun.shaderRGBA[2] = 255 * ( 1.0 - f ); + } else { + gun.shaderRGBA[0] = 255; + gun.shaderRGBA[1] = 255; + gun.shaderRGBA[2] = 255; gun.shaderRGBA[3] = 255; } - else { - Byte4Copy( ci->c1RGBA, gun.shaderRGBA ); + }*/ + + if (ps) + { + qhandle_t skin; + + gun.hModel = weapon->viewModel; + + skinColor = cgs.clientinfo[cg.snap->ps.clientNum].skinName; + + //if ( skinColor != "NULL" ) { //RPG-X : TiM - Will change the color of the band on the viewmodel's arm, depending what class + if(!Q_stricmpn(skinColor, "NULL", 4)) { + for ( i = 0; i < 8; i++ ) { + if ( cg.predictedPlayerState.weapon == (RAweapons[i]) ) { + Com_sprintf( filename, sizeof( filename ),"models/weapons2/%s/model_%s.skin", RAweapFileName[i], skinColor ); //Formulate the skin route + + skin = trap_R_RegisterSkin ( filename ); + + if ( !skin ) + break; + + gun.customSkin = skin; //and 'plonk' it on the model :) + break; + } + } } + + } + else + { + gun.hModel = weapon->weaponModel; } - gun.hModel = weapon->weaponModel; if (!gun.hModel) { return; } if ( !ps ) { - // add weapon ready sound + // add weapon stop sound + if ( !( cent->currentState.eFlags & EF_FIRING ) && !( cent->currentState.eFlags & EF_ALT_FIRING ) && cent->pe.lightningFiring && + cg.predictedPlayerState.ammo[cg.predictedPlayerState.weapon] ) + { + if (weapon->stopSound) + { + trap_S_StartSound( cent->lerpOrigin, cent->currentState.number, CHAN_WEAPON, weapon->stopSound ); + } + else if (weapon->altStopSound ) + { + trap_S_StartSound( cent->lerpOrigin, cent->currentState.number, CHAN_WEAPON, weapon->altStopSound ); + } + } cent->pe.lightningFiring = qfalse; - if ( ( cent->currentState.eFlags & EF_FIRING ) && weapon->firingSound ) { - // lightning gun and guantlet make a different sound when fire is held down - trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->firingSound ); - cent->pe.lightningFiring = qtrue; - } else if ( weapon->readySound ) { - trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->readySound ); + if ( cent->currentState.eFlags & EF_ALT_FIRING ) + { + // hark, I smell hackery afoot + if ((weaponNum == WP_5) && !(cg.predictedPlayerState.ammo[WP_5])) + { + trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, cgs.media.phaserEmptySound ); + cent->pe.lightningFiring = qtrue; + } + else if ( weapon->altFiringSound && !weapon->isAnimSndBased ) + { + trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->altFiringSound ); + cent->pe.lightningFiring = qtrue; + } + + if ( weaponNum == WP_14 || weaponNum == WP_11 ) { + cent->pe.lightningFiring = qtrue; + } + } + else if ( cent->currentState.eFlags & EF_FIRING ) + { + if ((weaponNum == WP_5) && !(cg.predictedPlayerState.ammo[WP_5])) + { + trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, cgs.media.phaserEmptySound ); + cent->pe.lightningFiring = qtrue; + } + else if ( weapon->firingSound && !weapon->isAnimSndBased ) + { + trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->firingSound ); + cent->pe.lightningFiring = qtrue; + } + + //TiM: Haxxor. I want the medkit + toolkit sounds to play only once when u hold them down + if ( weaponNum == WP_14 || weaponNum == WP_11 ) { + cent->pe.lightningFiring = qtrue; + } } } - trap_R_LerpTag(&lerped, parent->hModel, parent->oldframe, parent->frame, - 1.0 - parent->backlerp, "tag_weapon"); - VectorCopy(parent->origin, gun.origin); - VectorMA(gun.origin, lerped.origin[0], parent->axis[0], gun.origin); + CG_PositionEntityOnTag( &gun, parent, parent->hModel, "tag_weapon"); + //RPG-X : TiM - A little variety here :) Toolkit gets attached to player model's left hand, medkit on waist :) + //Hack: I dunno why, but unless I specified thirdperson (ie (!ps) ), the viewmodel went crazy. :P + if (!ps) { + if (( weaponNum == WP_14 ) ) { //Toolkit //cg.predictedPlayerState.weapon + CG_PositionEntityOnTag( &gun, parent, parent->hModel, "tag_lhand"); + } + else if (( weaponNum == WP_11 ) ) { //Medkit + CG_PositionEntityOnTag( &gun, parent, parent->hModel, "tag_torso"); + } + /*else { + CG_PositionEntityOnTag( &gun, parent, parent->hModel, "tag_weapon"); + }*/ + //TiM: also in the hopes of keeping the weapon scale constant in contrast to the player model + gun.nonNormalizedAxes = qfalse; + } + + if ( weaponNum == WP_4 ) { + if ( !ps ) { + if ( !(!cg.renderingThirdPerson && cent->currentState.clientNum == cg.predictedPlayerState.clientNum) ) + CG_CoffeeSteam( &gun, weapon, qtrue ); + } + //else { + // CG_CoffeeSteam( &gun, weapon, qfalse ); + //} + } - // Make weapon appear left-handed for 2 and centered for 3 - if(ps && cg_drawGun.integer == 2) - VectorMA(gun.origin, -lerped.origin[1], parent->axis[1], gun.origin); - else if(!ps || cg_drawGun.integer != 3) - VectorMA(gun.origin, lerped.origin[1], parent->axis[1], gun.origin); - - VectorMA(gun.origin, lerped.origin[2], parent->axis[2], gun.origin); - - MatrixMultiply(lerped.axis, ((refEntity_t *)parent)->axis, gun.axis); - gun.backlerp = parent->backlerp; - - CG_AddWeaponWithPowerups( &gun, cent->currentState.powerups ); + CG_AddWeaponWithPowerups( &gun, cent->currentState.powerups, ¢->beamData, cent->cloakTime, cent->decloakTime ); // add the spinning barrel - if ( weapon->barrelModel ) { - memset( &barrel, 0, sizeof( barrel ) ); - VectorCopy( parent->lightingOrigin, barrel.lightingOrigin ); - barrel.shadowPlane = parent->shadowPlane; - barrel.renderfx = parent->renderfx; + // + // + for (barrelInfo = wpnBarrelData; barrelInfo->giTag != WP_0; barrelInfo++) + { + if (barrelInfo->giTag == weaponNum) + { + numBarrels = barrelInfo->numBarrels; + break; + } + } - barrel.hModel = weapon->barrelModel; - angles[YAW] = 0; - angles[PITCH] = 0; - angles[ROLL] = CG_MachinegunSpinAngle( cent ); - AnglesToAxis( angles, barrel.axis ); + // don't add barrels to world model...only viewmodels + if (ps) + { + for (i = 0; i < numBarrels; i++) + { + memset( &barrel, 0, sizeof( barrel ) ); + VectorCopy( parent->lightingOrigin, barrel.lightingOrigin ); + barrel.shadowPlane = parent->shadowPlane; + barrel.renderfx = parent->renderfx; - CG_PositionRotatedEntityOnTag( &barrel, &gun, weapon->weaponModel, "tag_barrel" ); + barrel.hModel = weapon->barrelModel[i]; + angles[YAW] = 0; + angles[PITCH] = 0; + if ( weaponNum == WP_7) { + angles[ROLL] = CG_MachinegunSpinAngle( cent ); + } else { + angles[ROLL] = 0;//CG_MachinegunSpinAngle( cent ); + } + AnglesToAxis( angles, barrel.axis ); - CG_AddWeaponWithPowerups( &barrel, cent->currentState.powerups ); + if (!i) { + CG_PositionRotatedEntityOnTag( &barrel, parent, weapon->handsModel, "tag_barrel" ); + } else { + CG_PositionRotatedEntityOnTag( &barrel, parent, weapon->handsModel, va("tag_barrel%d",i+1) ); + } + + CG_AddWeaponWithPowerups( &barrel, cent->currentState.powerups, ¢->beamData, cent->cloakTime, cent->decloakTime ); + } } // make sure we aren't looking at cg.predictedPlayerEntity for LG @@ -1298,14 +1281,59 @@ void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent nonPredictedCent = cent; } + //Com_Printf("eType: %i, eventParm: %i, weaponNum: %i\n", cent->currentState.eType, cent->currentState.eventParm, weaponNum); + if ( weaponNum == WP_6 + && + cent->currentState.powerups & ( 1 << PW_FLASHLIGHT ) + && + cent->beamData.beamTimeParam == 0 + && + ( !(cent->currentState.powerups & ( 1 << PW_INVIS )) + || cent->currentState.clientNum == cg.predictedPlayerState.clientNum ) + ) + { //FIXME: TiM - need to know if flashlight is on or off at the time :S + refEntity_t flashlight; + + memset( &flashlight, 0, sizeof( flashlight ) ); + VectorCopy( parent->lightingOrigin, flashlight.lightingOrigin ); + flashlight.shadowPlane = parent->shadowPlane; + flashlight.renderfx = parent->renderfx; + + flashlight.hModel = cgs.media.flashlightModel; + if (!flashlight.hModel) { + return; + } + + angles[YAW] = 0; + angles[PITCH] = 0; + angles[ROLL] = 0; + + AnglesToAxis( angles, flashlight.axis ); + + if (ps) + { // Rendering inside the head... + CG_PositionRotatedEntityOnTag( &flashlight, &gun, weapon->viewModel, "tag_flashlight"); + } + else + { // Rendering outside the head... + CG_PositionRotatedEntityOnTag( &flashlight, &gun, weapon->weaponModel, "tag_flashlight"); + } + trap_R_AddRefEntityToScene( &flashlight ); + } + // add the flash - if ( ( weaponNum == WP_LIGHTNING || weaponNum == WP_GAUNTLET || weaponNum == WP_GRAPPLING_HOOK ) + if ( ( weaponNum == WP_5 || + weaponNum == WP_13) && ( nonPredictedCent->currentState.eFlags & EF_FIRING ) ) { // continuous flash - } else { + } + else + { // impulse flash - if ( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME ) { + //if ( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME) { + if ( cg.time - cent->muzzleFlashTime > wpnBarrelData[weaponNum-1].flashTime ) + { return; } } @@ -1319,31 +1347,84 @@ void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent if (!flash.hModel) { return; } + angles[YAW] = 0; angles[PITCH] = 0; - angles[ROLL] = crandom() * 10; + angles[ROLL] = 0; //angles[ROLL] = crandom() * 10; //RPG-X - TiM: This stops the lensflare on the muzzle from jiggling around + AnglesToAxis( angles, flash.axis ); - // colorize the railgun blast - if ( weaponNum == WP_RAILGUN ) { - clientInfo_t *ci; + //TiM - Instead of briefly showing the flash, show it scaling down + if (weaponNum != WP_5 && + weaponNum != WP_15 && + weaponNum != WP_13 && + !(weaponNum == WP_6 && (cent->currentState.eFlags & EF_ALT_FIRING) ) && + !(weaponNum == WP_10 && !(cent->currentState.eFlags & EF_ALT_FIRING) ) + ) + { + float scale; + scale = (1.0f - ( (float)(cg.time - cent->muzzleFlashTime) / (float)wpnBarrelData[weaponNum-1].flashTime )) * 2.0f; - ci = &cgs.clientinfo[ cent->currentState.clientNum ]; - flash.shaderRGBA[0] = 255 * ci->color1[0]; - flash.shaderRGBA[1] = 255 * ci->color1[1]; - flash.shaderRGBA[2] = 255 * ci->color1[2]; + flash.nonNormalizedAxes = qtrue; + VectorScale( flash.axis[0], scale, flash.axis[0] ); + VectorScale( flash.axis[1], scale, flash.axis[1] ); + VectorScale( flash.axis[2], scale, flash.axis[2] ); } - CG_PositionRotatedEntityOnTag( &flash, &gun, weapon->weaponModel, "tag_flash"); - trap_R_AddRefEntityToScene( &flash ); + //TiM - quick hack + //jiggle the scale of the phaser rifle on alt fire around + if ( (weaponNum == WP_6 && (cent->currentState.eFlags & EF_ALT_FIRING)) + || + ( weaponNum == WP_10 && !(cent->currentState.eFlags & EF_ALT_FIRING)) ) + { + float min, max; - if ( ps || cg.renderingThirdPerson || - cent->currentState.number != cg.predictedPlayerState.clientNum ) { - // add lightning bolt + if ( weaponNum == WP_6 ) + { + min = 1.3f; + max = 1.6f; + } + else + { + min = 0.8f; + max = 0.9f; + } + + VectorScale( flash.axis[0], flrandom(min, max), flash.axis[0] ); + VectorScale( flash.axis[1], flrandom(min, max), flash.axis[1] ); + VectorScale( flash.axis[2], flrandom(min, max), flash.axis[2] ); + } + + if (cent->pe.empty) + { // Make muzzle flash wussy when empty. + flash.customShader = cgs.media.phaserMuzzleEmptyShader; + } + + if (ps) + { // Rendering inside the head... + CG_PositionRotatedEntityOnTag( &flash, &gun, weapon->viewModel, "tag_flash" ); + } + else + { // Rendering outside the head... + CG_PositionRotatedEntityOnTag( &flash, &gun, weapon->weaponModel, "tag_flash" ); + } + + if ( !(cent->currentState.powerups & ( 1 << PW_INVIS )) + || cent->currentState.clientNum == cg.predictedPlayerState.clientNum ) + { + trap_R_AddRefEntityToScene( &flash ); + } + + if ( ps || cg.renderingThirdPerson || cent->currentState.number != cg.predictedPlayerState.clientNum || cg_firstPersonBody.integer ) + { + // add phaser/dreadnought + // grrr nonPredictedCent doesn't have the proper empty setting + nonPredictedCent->pe.empty = cent->pe.empty; CG_LightningBolt( nonPredictedCent, flash.origin ); - if ( weapon->flashDlightColor[0] || weapon->flashDlightColor[1] || weapon->flashDlightColor[2] ) { - trap_R_AddLightToScene( flash.origin, 300 + (rand()&31), weapon->flashDlightColor[0], + // make a dlight for the flash + if ( (weapon->flashDlightColor[0] || weapon->flashDlightColor[1] || weapon->flashDlightColor[2]) && !(cent->currentState.powerups & ( 1 << PW_INVIS ) ) ) { + trap_R_AddLightToScene( flash.origin, 200 + (rand()&31), weapon->flashDlightColor[0], weapon->flashDlightColor[1], weapon->flashDlightColor[2] ); } } @@ -1364,7 +1445,7 @@ void CG_AddViewWeapon( playerState_t *ps ) { vec3_t angles; weaponInfo_t *weapon; - if ( ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) { + if ( ps->persistant[PERS_TEAM] == TEAM_SPECTATOR /*|| (ps->eFlags&EF_ELIMINATED)*/ ) { return; } @@ -1372,19 +1453,19 @@ void CG_AddViewWeapon( playerState_t *ps ) { return; } - // no gun if in third person view or a camera is active - //if ( cg.renderingThirdPerson || cg.cameraMode) { - if ( cg.renderingThirdPerson ) { + // no gun if in third person view + if ( cg.renderingThirdPerson || cg_firstPersonBody.integer ) { return; } - // allow the gun to be completely removed - if ( !cg_drawGun.integer ) { + //TiM: Added alt fire for alt-fire beam weapons + if ( !cg_drawGun.integer || cg.zoomed ) { vec3_t origin; - if ( cg.predictedPlayerState.eFlags & EF_FIRING ) { - // special hack for lightning gun... + if ( cg.predictedPlayerState.eFlags & EF_FIRING || cg.predictedPlayerState.eFlags & EF_ALT_FIRING ) + { + // special hack for phaser/dreadnought... VectorCopy( cg.refdef.vieworg, origin ); VectorMA( origin, -8, cg.refdef.viewaxis[2], origin ); CG_LightningBolt( &cg_entities[ps->clientNum], origin ); @@ -1392,14 +1473,18 @@ void CG_AddViewWeapon( playerState_t *ps ) { return; } + if ( (cg.zoomed) && (ps->weapon == WP_6) ) { //RPG-X : TiM - People were saying that being able to see the gunsight on the rifle thru the gunsight in zoom mode was weird :P + return; + } + // don't draw if testing a gun model if ( cg.testGun ) { return; } // drop gun lower at higher fov - if ( cg_fov.integer > 90 ) { - fovOffset = -0.2 * ( cg_fov.integer - 90 ); + if ( cg_fov.integer > 80 ) { + fovOffset = -0.2 * ( cg_fov.integer - 80 ); } else { fovOffset = 0; } @@ -1433,10 +1518,10 @@ void CG_AddViewWeapon( playerState_t *ps ) { } hand.hModel = weapon->handsModel; - hand.renderfx = RF_DEPTHHACK | RF_FIRST_PERSON | RF_MINLIGHT; + hand.renderfx = RF_DEPTHHACK | RF_FIRST_PERSON; // add everything onto the hand - CG_AddPlayerWeapon( &hand, ps, &cg.predictedPlayerEntity, ps->persistant[PERS_TEAM] ); + CG_AddPlayerWeapon( &hand, ps, &cg.predictedPlayerEntity ); } /* @@ -1447,21 +1532,100 @@ WEAPON SELECTION ============================================================================== */ +void static CG_RegisterWeaponIcon( int weaponNum ) { + weaponInfo_t *weaponInfo; + gitem_t *item; + + weaponInfo = &cg_weapons[weaponNum]; + + if ( weaponNum == 0 ) { + return; + } + + if ( weaponInfo->registered ) { + return; + } + + for ( item = bg_itemlist + 1 ; item->classname ; item++ ) { + if ( item->giType == IT_WEAPON && item->giTag == weaponNum ) { + weaponInfo->item = item; + break; + } + } + if ( !item->classname ) { + CG_Error( "Couldn't find weapon %i", weaponNum ); + } + + weaponInfo->weaponIcon = trap_R_RegisterShader( item->icon ); +} + +/* +================== +CG_DrawWeaponIcon +RPG-X | Phenix | 08/06/2005 +RPG-X | TiM | 5/1/2006 +=========================== +*/ +void CG_DrawWeaponIcon ( int x, int y, int weapon ) +{ + /*vec4_t color; + + color[3] = alpha; + if ( !color[3] ) { + return; + }*/ + + CG_RegisterWeaponIcon( weapon ); //short version + + // draw selection marker + + if ( weapon == cg.weaponSelect ) + { + trap_R_SetColor( colorTable[CT_LTPURPLE1] ); + } + else + { + trap_R_SetColor(colorTable[CT_DKPURPLE1]); + } + + CG_DrawPic( x-4,y-4,38, 38, cgs.media.weaponbox); + + // draw weapon icon + trap_R_SetColor(colorTable[CT_WHITE]); + CG_DrawPic( x, y, 32, 32, cg_weapons[weapon].weaponIcon ); + + // draw selection marker + /*if ( weapon == cg.weaponSelect ) { + CG_DrawPic( x-4, y-4, 40, 40, cgs.media.selectShader );*/ + //} + trap_R_SetColor( NULL ); +} + /* =================== CG_DrawWeaponSelect =================== */ + +static int weaponRows[6][3] = { { WP_1, 0, 0 }, + { WP_2, WP_3, WP_4 }, + { WP_5, WP_6, WP_7 }, + { WP_8, WP_9, WP_10 }, + { WP_11, WP_12, WP_13 }, + { WP_14, WP_15, 0 } }; + void CG_DrawWeaponSelect( void ) { - int i; + int i, rowCount, cellCount; int bits; - int count; - int x, y, w; + //int count; + int x, y, w, defaultX, defaultY; char *name; float *color; + qboolean WeapOnThisRow = qfalse; + //vec4_t color; // don't display if dead - if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) { + if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 1 || cg.predictedPlayerState.eFlags & EF_DEAD ) { //RPG-X: RedTechie - No weapons at health 1 (you die at health 1 now) return; } @@ -1469,53 +1633,70 @@ void CG_DrawWeaponSelect( void ) { if ( !color ) { return; } - trap_R_SetColor( color ); // showing weapon select clears pickup item display, but not the blend blob cg.itemPickupTime = 0; // count the number of weapons owned bits = cg.snap->ps.stats[ STAT_WEAPONS ]; - count = 0; - for ( i = 1 ; i < MAX_WEAPONS ; i++ ) { - if ( bits & ( 1 << i ) ) { - count++; + + //NEW HUD FOR RPG-X + defaultX = 18; + defaultY = 52; + x = defaultX; + + y = (BIGCHAR_HEIGHT * 2) + 20; + + for ( i = 0, rowCount = 0, cellCount = 0; i < MAX_WEAPONS; i++, cellCount++ ) { + if ( cellCount == 3 ) { //we've hit the end of the row + rowCount++; //go to the next row + cellCount = 0; //reset cell clock + + if ( WeapOnThisRow ) { + //**** Draw the end caps ***** + //VectorCopy( colorTable[CT_LTPURPLE2], color ); + trap_R_SetColor(colorTable[CT_LTPURPLE2]); + // Left end cap + CG_DrawPic( 2, y - 5, 16, 50, cgs.media.weaponcap1); //6 + // Right End Cap + CG_DrawPic( x - 20 + 16, y - 5, 16, 50, cgs.media.weaponcap2); //2 - 6, 16 - 18 + trap_R_SetColor(NULL); + + y += defaultY; + x = defaultX; + + WeapOnThisRow = qfalse; + } + + if ( rowCount >= 6 ) { //if we exceed our rows, that's bad O_o + break; + } } - } - x = 320 - count * 20; - y = 380; - - for ( i = 1 ; i < MAX_WEAPONS ; i++ ) { - if ( !( bits & ( 1 << i ) ) ) { + if ( weaponRows[rowCount][cellCount] == 0 ) { + i--; continue; } - CG_RegisterWeapon( i ); + if (bits & ( 1 << weaponRows[rowCount][cellCount] ) ) { + CG_DrawWeaponIcon( x, y, weaponRows[rowCount][cellCount] ); + x += 40; - // draw weapon icon - CG_DrawPic( x, y, 32, 32, cg_weapons[i].weaponIcon ); - - // draw selection marker - if ( i == cg.weaponSelect ) { - CG_DrawPic( x-4, y-4, 40, 40, cgs.media.selectShader ); + if ( !WeapOnThisRow ) { + WeapOnThisRow = qtrue; + } } - - // no ammo cross on top - if ( !cg.snap->ps.ammo[ i ] ) { - CG_DrawPic( x, y, 32, 32, cgs.media.noammoShader ); - } - - x += 40; } - // draw the selected name + // END HUD + + // draw the selected names if ( cg_weapons[ cg.weaponSelect ].item ) { name = cg_weapons[ cg.weaponSelect ].item->pickup_name; if ( name ) { - w = CG_DrawStrlen( name ) * BIGCHAR_WIDTH; - x = ( SCREEN_WIDTH - w ) / 2; - CG_DrawBigStringColor(x, y - 22, name, color); + w= UI_ProportionalStringWidth(name,UI_SMALLFONT); + UI_DrawProportionalString(x, y, name, UI_SMALLFONT,color); + } } @@ -1539,14 +1720,53 @@ static qboolean CG_WeaponSelectable( int i ) { return qtrue; } +extern int altAmmoUsage[]; +/* +{ + 0, //WP_0, + 2, //WP_5, + 10, //WP_6, + 3, //WP_1, + 5, //WP_4, + 1, //WP_10, + 1, //WP_8, + 2, //WP_7, + 2, //WP_9, + 5 //WP_13, + 20, //WP_12, + ##, //WP_14, + ##, //WP_11, + +}; +*/ + +/* +=============== +CG_WeaponAltSelectable +=============== +*/ +static qboolean CG_WeaponAltSelectable( int i ) { + if ( cg.snap->ps.ammo[i] < altAmmoUsage[cg.snap->ps.weapon]) { + return qfalse; + } + if ( ! (cg.snap->ps.stats[ STAT_WEAPONS ] & ( 1 << i ) ) ) { + return qfalse; + } + + return qtrue; +} + + /* =============== CG_NextWeapon_f =============== */ void CG_NextWeapon_f( void ) { - int i; + int i; //, topWeapon int original; +// int newWeapons[16]; +// int bits; if ( !cg.snap ) { return; @@ -1558,21 +1778,27 @@ void CG_NextWeapon_f( void ) { cg.weaponSelectTime = cg.time; original = cg.weaponSelect; - for ( i = 0 ; i < MAX_WEAPONS ; i++ ) { + + //RPG-X | Phenix | 08/06/2005 + //Removed to be replaced to scroll through our list + //TiM | 4/1/2006 + //Put back in since I optimized the way weapons are handled + for ( i = 0 ; i < 16 ; i++ ) { cg.weaponSelect++; - if ( cg.weaponSelect == MAX_WEAPONS ) { + if ( cg.weaponSelect == 16 ) { cg.weaponSelect = 0; } - if ( cg.weaponSelect == WP_GAUNTLET ) { - continue; // never cycle to gauntlet - } if ( CG_WeaponSelectable( cg.weaponSelect ) ) { break; } } - if ( i == MAX_WEAPONS ) { + if ( i == 16 ) { cg.weaponSelect = original; } + + //TiM: Just for the record. Phenix. Enumerated value lists. Look them up. Use them! + //Reading this code was really tricky when it didn't have to be >.< + //ie 1 = WP_5 etc } /* @@ -1581,8 +1807,10 @@ CG_PrevWeapon_f =============== */ void CG_PrevWeapon_f( void ) { - int i; + int i; //, topWeapon int original; +// int newWeapons[16]; +// int bits; if ( !cg.snap ) { return; @@ -1593,20 +1821,21 @@ void CG_PrevWeapon_f( void ) { cg.weaponSelectTime = cg.time; original = cg.weaponSelect; - - for ( i = 0 ; i < MAX_WEAPONS ; i++ ) { + + //RPG-X | Phenix | 08/06/2005 + //Removed to be replaced to scroll through our list + //TiM | 4/1/2006 + //Put back in since I optimized the way weapons are handled + for ( i = 0 ; i < 16 ; i++ ) { cg.weaponSelect--; if ( cg.weaponSelect == -1 ) { - cg.weaponSelect = MAX_WEAPONS - 1; - } - if ( cg.weaponSelect == WP_GAUNTLET ) { - continue; // never cycle to gauntlet + cg.weaponSelect = 15; } if ( CG_WeaponSelectable( cg.weaponSelect ) ) { break; } } - if ( i == MAX_WEAPONS ) { + if ( i == 16 ) { cg.weaponSelect = original; } } @@ -1616,8 +1845,25 @@ void CG_PrevWeapon_f( void ) { CG_Weapon_f =============== */ +/*TiM : Here for reference +static int weaponRows[6][3] = { WP_1, 0, 0, + WP_2, WP_3, WP_4, + WP_5, WP_6, WP_7, + WP_8, WP_9, WP_10, + WP_11, WP_12, WP_13, + WP_14, WP_NEUTRINO_PROBE, 0 };*/ + void CG_Weapon_f( void ) { int num; + //int newWeapons[16]; + int i; + int bits; + int weaponsOnRow; + int weaponGot[6]; + int onRow; + int onCol; + int rowsUsed; + int currentWeaponCol; if ( !cg.snap ) { return; @@ -1627,18 +1873,110 @@ void CG_Weapon_f( void ) { } num = atoi( CG_Argv( 1 ) ); + bits = cg.snap->ps.stats[ STAT_WEAPONS ]; - if ( num < 1 || num > MAX_WEAPONS-1 ) { + //TiM - 0 = Null hand weapon now + //if ( num < 1 || num > 15 ) { + if ( num < 0 || num > 15 ) { return; } cg.weaponSelectTime = cg.time; - if ( ! ( cg.snap->ps.stats[STAT_WEAPONS] & ( 1 << num ) ) ) { - return; // don't have the weapon + //Hacky Override: 0 = Null hand no matter what. + if (num == 0 ) { + if ( bits & ( 1 << WP_1 ) ) { + cg.weaponSelect = WP_1; + } + return; } - cg.weaponSelect = num; + //TiM : The code below went into an infinite loop if a high number was + //set as an arg to this command. + //Lemme just insert a check to make sure the code NEVER accepts args higher + //than the size of our weapons array. I'll put it underneath the weaponSelectTime + //statement, so the user will still see a response to their input. + else if ( num > 5 ) { + return; + } + + /* RPG-X | Phenix | 02/02/2006 + * + * Code to group weapons together by keyboard */ + + //Init weaponGot values + /*for (i = 0; i < 6; i++) + weaponGot[i] = -1;*/ + memset( weaponGot, -1, sizeof( weaponGot ) ); + + onCol = 0; + weaponsOnRow = 0; + rowsUsed = 0; + currentWeaponCol = -1; + + //Loop though every weapon in weaponRows (starting on row 2 - WHY TIM WHY!) + //TiM: ... because :) + for ( i = 0, onRow = 1; i < 15; i++ ) + { + if (onCol == 3) + { + onCol = 0; + weaponsOnRow = 0; + onRow++; + + if (onRow > 5) //Something has gone wrong! + break; + } + + if ( weaponRows[onRow][onCol] > 0) + { //Double check this is a weapon + if (( bits & ( 1 << weaponRows[onRow][onCol] ) ) && (weaponsOnRow == 0)) + { //If we have this weapon And it is the first weapon on this row we have + weaponGot[rowsUsed] = onRow; + weaponsOnRow++; + rowsUsed++; + } + + if ((cg.predictedPlayerState.weapon == weaponRows[onRow][onCol]) && (rowsUsed == num)) + { //If this is the selected weapon record what column it is on + currentWeaponCol = onCol; + } + } + + onCol++; + } + + //If they selected a row that doesn't exist + if (weaponGot[num - 1] == -1) + return; //(dont need to worry about num being zero because of tims hack ^^) + + do + { //Loop though this row until we come accross a weapon which the player has got and is not "null" (0) + currentWeaponCol++; + + if (currentWeaponCol == 3) + { + currentWeaponCol = 0; + } + } while ((weaponRows[ weaponGot[num - 1] ][currentWeaponCol] == 0) || !( bits & ( 1 << weaponRows[weaponGot[num - 1]][currentWeaponCol] ))); + + cg.weaponSelect = weaponRows[weaponGot[num - 1]][currentWeaponCol]; + + //TiM - based on the number we pressed, and whichever + //weapons we have in sequential order, select the one that corresponds. + + //Start at number 2, skipping null hand. He owns us all + /*for ( i = WP_2, weaponCount = 0; i < MAX_WEAPONS; i++ ) { + //if we have that weapon + if ( bits & ( 1 << i ) ) { + weaponCount++; + + if ( weaponCount == num ) { + cg.weaponSelect = i; + return; + } + } + }*/ } /* @@ -1648,15 +1986,28 @@ CG_OutOfAmmoChange The current weapon has just run out of ammo =================== */ -void CG_OutOfAmmoChange( void ) { +void CG_OutOfAmmoChange( qboolean altfire ) { int i; cg.weaponSelectTime = cg.time; - for ( i = MAX_WEAPONS-1 ; i > 0 ; i-- ) { - if ( CG_WeaponSelectable( i ) ) { - cg.weaponSelect = i; - break; + for ( i = 15 ; i > 0 ; i-- ) + { + if (altfire) + { + if ( CG_WeaponAltSelectable( i ) ) + { + cg.weaponSelect = i; + break; + } + } + else + { + if ( CG_WeaponSelectable( i ) ) + { + cg.weaponSelect = i; + break; + } } } } @@ -1678,13 +2029,17 @@ CG_FireWeapon Caused by an EV_FIRE_WEAPON event ================ */ -void CG_FireWeapon( centity_t *cent ) { +int tris_state = 0; +void CG_FireWeapon( centity_t *cent, qboolean alt_fire ) { entityState_t *ent; - int c; weaponInfo_t *weap; + int rpg_effectsgun; + int rpg_tripmines; + const char *info; + //const char *info2; ent = ¢->currentState; - if ( ent->weapon == WP_NONE ) { + if ( ent->weapon == WP_0 || ent->weapon == WP_1 ) { return; } if ( ent->weapon >= WP_NUM_WEAPONS ) { @@ -1698,41 +2053,93 @@ void CG_FireWeapon( centity_t *cent ) { cent->muzzleFlashTime = cg.time; // lightning gun only does this this on initial press - if ( ent->weapon == WP_LIGHTNING ) { + if ( ent->weapon == WP_5 /*|| + ent->weapon == WP_13*/ + || ent->weapon == WP_14 + || ent->weapon == WP_11 + || (!(cent->currentState.eFlags & EF_ALT_FIRING) && ent->weapon == WP_10 ) + || (cent->currentState.eFlags & EF_ALT_FIRING && ent->weapon == WP_6 ) + ) + { if ( cent->pe.lightningFiring ) { return; } } - if( ent->weapon == WP_RAILGUN ) { - cent->pe.railFireTime = cg.time; - } - // play quad sound if needed - if ( cent->currentState.powerups & ( 1 << PW_QUAD ) ) { +/* if ( cent->currentState.powerups & ( 1 << PW_QUAD ) ) { trap_S_StartSound (NULL, cent->currentState.number, CHAN_ITEM, cgs.media.quadSound ); - } + }*/ // play a sound - for ( c = 0 ; c < 4 ; c++ ) { - if ( !weap->flashSound[c] ) { - break; - } - } - if ( c > 0 ) { - c = rand() % c; - if ( weap->flashSound[c] ) + info = CG_ConfigString( CS_SERVERINFO ); + rpg_tripmines = atoi( Info_ValueForKey( info, "rpg_invisibletripmines" ) ); + rpg_effectsgun = atoi( Info_ValueForKey( info, "rpg_effectsgun" ) ); + if (alt_fire) + { + //RPG-X: RedTechie - Wrong place for show tris + /*if( ent->weapon == WP_7 ) { - trap_S_StartSound( NULL, ent->number, CHAN_WEAPON, weap->flashSound[c] ); + if(tris_state == 1) + tris_state = 0; + else + tris_state = 1; + + trap_Cvar_Set("r_showtris", va("%i",tris_state)); + }*/ + if ( weap->altFlashSnd ) + { + //TiM : Hark, I smell hackery again + //admin alt hypos no fire coz it grinds my teeth + if ( cgs.clientinfo[cg.snap->ps.clientNum].isAdmin/*cgs.clientinfo[cent->currentState.clientNum].pClass == PC_ADMIN*/ + && + cent->currentState.weapon == WP_12 ) { + return; + } + + if(ent->weapon == WP_8){ + if(rpg_tripmines != 1){ + trap_S_StartSound( NULL, ent->number, CHAN_WEAPON, weap->altFlashSnd ); + } + }else{ + trap_S_StartSound( NULL, ent->number, CHAN_WEAPON, weap->altFlashSnd ); + } } } - - // do brass ejection - if ( weap->ejectBrassFunc && cg_brassTime.integer > 0 ) { - weap->ejectBrassFunc( cent ); + else + { + if ( weap->flashSound ) + { + if(ent->weapon == WP_8){ + if((rpg_effectsgun == 1) || (rpg_tripmines == 1)){ + return; + }else{ + trap_S_StartSound( NULL, ent->number, CHAN_WEAPON, weap->flashSound ); + } + }else{ + trap_S_StartSound( NULL, ent->number, CHAN_WEAPON, weap->flashSound ); + } + } } } +/* +================ +CG_FireSeeker + +Caused by an EV_FIRE_WEAPON event +================ +*/ +void CG_FireSeeker( centity_t *cent ) +{ + entityState_t *ent; + weaponInfo_t *weap; + + ent = ¢->currentState; + weap = &cg_weapons[ WP_4 ]; + + trap_S_StartSound( NULL, ent->number, CHAN_WEAPON, weap->flashSound ); +} /* ================= @@ -1741,7 +2148,8 @@ CG_MissileHitWall Caused by an EV_MISSILE_MISS event, or directly by local bullet tracing ================= */ -void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, impactSound_t soundType ) { +void CG_MissileHitWall( centity_t *cent, int weapon, vec3_t origin, vec3_t dir ) +{ qhandle_t mod; qhandle_t mark; qhandle_t shader; @@ -1750,12 +2158,10 @@ void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, im float light; vec3_t lightColor; localEntity_t *le; - int r; - qboolean alphaFade; qboolean isSprite; int duration; - vec3_t sprOrg; - vec3_t sprVel; + qboolean alphaFade; +// weaponInfo_t *weaponInfo = &cg_weapons[weapon]; mark = 0; radius = 32; @@ -1773,134 +2179,71 @@ void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, im switch ( weapon ) { default: -#ifdef MISSIONPACK - case WP_NAILGUN: - if( soundType == IMPACTSOUND_FLESH ) { - sfx = cgs.media.sfx_nghitflesh; - } else if( soundType == IMPACTSOUND_METAL ) { - sfx = cgs.media.sfx_nghitmetal; - } else { - sfx = cgs.media.sfx_nghit; - } - mark = cgs.media.holeMarkShader; - radius = 12; - break; -#endif - case WP_LIGHTNING: + case WP_5: + // no explosion at LG impact, it is added with the beam + mark = cgs.media.holeMarkShader; + radius = 12; + break; + case WP_13: // no explosion at LG impact, it is added with the beam - r = rand() & 3; - if ( r < 2 ) { - sfx = cgs.media.sfx_lghit2; - } else if ( r == 2 ) { - sfx = cgs.media.sfx_lghit1; - } else { - sfx = cgs.media.sfx_lghit3; - } mark = cgs.media.holeMarkShader; radius = 12; break; -#ifdef MISSIONPACK - case WP_PROX_LAUNCHER: - mod = cgs.media.dishFlashModel; - shader = cgs.media.grenadeExplosionShader; - sfx = cgs.media.sfx_proxexp; - mark = cgs.media.burnMarkShader; - radius = 64; - light = 300; - isSprite = qtrue; + case WP_8: + FX_GrenadeExplode( origin, dir ); + return; break; -#endif - case WP_GRENADE_LAUNCHER: - mod = cgs.media.dishFlashModel; - shader = cgs.media.grenadeExplosionShader; - sfx = cgs.media.sfx_rockexp; - mark = cgs.media.burnMarkShader; - radius = 64; - light = 300; - isSprite = qtrue; + case WP_10: + FX_DisruptorWeaponHitWall( origin, dir, 2 ); //cent->currentState.time2 + return; break; - case WP_ROCKET_LAUNCHER: - mod = cgs.media.dishFlashModel; - shader = cgs.media.rocketExplosionShader; - sfx = cgs.media.sfx_rockexp; - mark = cgs.media.burnMarkShader; - radius = 64; - light = 300; - isSprite = qtrue; - duration = 1000; - lightColor[0] = 1; - lightColor[1] = 0.75; - lightColor[2] = 0.0; - if (cg_oldRocket.integer == 0) { - // explosion sprite animation - VectorMA( origin, 24, dir, sprOrg ); - VectorScale( dir, 64, sprVel ); - - CG_ParticleExplosion( "explode1", sprOrg, sprVel, 1400, 20, 30 ); - } - break; - case WP_RAILGUN: - mod = cgs.media.ringFlashModel; - shader = cgs.media.railExplosionShader; - //sfx = cgs.media.sfx_railg; - sfx = cgs.media.sfx_plasmaexp; + case WP_1: + /*mod = cgs.media.ringFlashModel; + shader = cgs.media.imodExplosionShader; mark = cgs.media.energyMarkShader; - radius = 24; + radius = 24;*/ break; - case WP_PLASMAGUN: - mod = cgs.media.ringFlashModel; - shader = cgs.media.plasmaExplosionShader; - sfx = cgs.media.sfx_plasmaexp; - mark = cgs.media.energyMarkShader; - radius = 16; + case WP_6: + //mod = cgs.media.ringFlashModel; + //shader = cgs.media.imodExplosionShader; + //mark = cgs.media.energyMarkShader; + //radius = 24; + FX_CompressionExplosion( cent->lerpOrigin, origin, dir, qfalse ); + return; break; - case WP_BFG: - mod = cgs.media.dishFlashModel; - shader = cgs.media.bfgExplosionShader; - sfx = cgs.media.sfx_rockexp; - mark = cgs.media.burnMarkShader; - radius = 32; - isSprite = qtrue; + case WP_7: + //FX_TetrionAltHitWall( origin, dir ); + return; break; - case WP_SHOTGUN: - mod = cgs.media.bulletFlashModel; - shader = cgs.media.bulletExplosionShader; - mark = cgs.media.bulletMarkShader; - sfx = 0; - radius = 4; - break; - -#ifdef MISSIONPACK - case WP_CHAINGUN: - mod = cgs.media.bulletFlashModel; - if( soundType == IMPACTSOUND_FLESH ) { - sfx = cgs.media.sfx_chghitflesh; - } else if( soundType == IMPACTSOUND_METAL ) { - sfx = cgs.media.sfx_chghitmetal; - } else { - sfx = cgs.media.sfx_chghit; +/* case WP_4: + if (cent->currentState.eFlags & EF_ALT_FIRING) + { + FX_ScavengerAltExplode( origin, dir ); } - mark = cgs.media.bulletMarkShader; - - radius = 8; - break; -#endif - - case WP_MACHINEGUN: - mod = cgs.media.bulletFlashModel; - shader = cgs.media.bulletExplosionShader; - mark = cgs.media.bulletMarkShader; - - r = rand() & 3; - if ( r == 0 ) { - sfx = cgs.media.sfx_ric1; - } else if ( r == 1 ) { - sfx = cgs.media.sfx_ric2; - } else { - sfx = cgs.media.sfx_ric3; + else + { + FX_ScavengerWeaponHitWall( origin, dir, qfalse ); } + return; + break;*/ +/* case WP_11: + if ( !( cent->currentState.eFlags & EF_ALT_FIRING )) + { + FX_BorgWeaponHitWall( origin, dir ); + } + return; + break;*/ - radius = 8; + case WP_9: + if ( cent->currentState.eFlags & EF_ALT_FIRING ) + { + FX_QuantumAltHitWall( origin, dir ); + } + else + { + FX_QuantumHitWall( origin, dir ); + } + return; break; } @@ -1914,32 +2257,16 @@ void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, im if ( mod ) { le = CG_MakeExplosion( origin, dir, mod, shader, - duration, isSprite ); + duration, 1, isSprite ); le->light = light; VectorCopy( lightColor, le->lightColor ); - if ( weapon == WP_RAILGUN ) { - // colorize with client color - VectorCopy( cgs.clientinfo[clientNum].color1, le->color ); - le->refEntity.shaderRGBA[0] = le->color[0] * 0xff; - le->refEntity.shaderRGBA[1] = le->color[1] * 0xff; - le->refEntity.shaderRGBA[2] = le->color[2] * 0xff; - le->refEntity.shaderRGBA[3] = 0xff; - } } // // impact mark // alphaFade = (mark == cgs.media.energyMarkShader); // plasma fades alpha, all others fade color - if ( weapon == WP_RAILGUN ) { - float *color; - - // colorize with client color - color = cgs.clientinfo[clientNum].color1; - CG_ImpactMark( mark, origin, dir, random()*360, color[0],color[1], color[2],1, alphaFade, radius, qfalse ); - } else { - CG_ImpactMark( mark, origin, dir, random()*360, 1,1,1,1, alphaFade, radius, qfalse ); - } + CG_ImpactMark( mark, origin, dir, random()*360, 1,1,1,1, alphaFade, radius, qfalse ); } @@ -1948,145 +2275,63 @@ void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, im CG_MissileHitPlayer ================= */ -void CG_MissileHitPlayer( int weapon, vec3_t origin, vec3_t dir, int entityNum ) { - CG_Bleed( origin, entityNum ); +void CG_MissileHitPlayer( centity_t *cent, int weapon, vec3_t origin, vec3_t dir) +{ + if (cent) + { // Showing blood is a no-no. - // some weapons will make an explosion with the blood, while - // others will just make the blood - switch ( weapon ) { - case WP_GRENADE_LAUNCHER: - case WP_ROCKET_LAUNCHER: - case WP_PLASMAGUN: - case WP_BFG: -#ifdef MISSIONPACK - case WP_NAILGUN: - case WP_CHAINGUN: - case WP_PROX_LAUNCHER: -#endif - CG_MissileHitWall( weapon, 0, origin, dir, IMPACTSOUND_FLESH ); +// CG_Bleed( origin, cent->currentState.otherEntityNum ); + } + + CG_MissileHitWall( cent, weapon, origin, dir ); +} + + +/* +================= +CG_BounceEffect + +Caused by an EV_BOUNCE | EV_BOUNCE_HALF event +================= +*/ + +// big fixme. none of these sounds should be registered at runtime +void CG_BounceEffect( centity_t *cent, int weapon, vec3_t origin, vec3_t normal ) +{ + int rpg_tripmines; + const char *info; + + switch( weapon ) + { + case WP_8: + info = CG_ConfigString( CS_SERVERINFO ); + rpg_tripmines = atoi( Info_ValueForKey( info, "rpg_invisibletripmines" ) ); + if(rpg_tripmines != 1){ + if ( rand() & 1 ) { + trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, trap_S_RegisterSound(SOUND_DIR "glauncher/bounce1.wav") ); + } else { + trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, trap_S_RegisterSound(SOUND_DIR "glauncher/bounce2.wav") ); + } + } break; + + case WP_7: + //trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, trap_S_RegisterSound ( va(SOUND_DIR "tetrion/ricochet%d.wav", irandom(1, 3)) ) ); + //FX_TetrionRicochet( origin, normal ); + break; + default: + if ( rand() & 1 ) { + trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, trap_S_RegisterSound(SOUND_DIR "glauncher/bounce1.wav") ); + } else { + trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, trap_S_RegisterSound(SOUND_DIR "glauncher/bounce2.wav") ); + } break; } } -/* -============================================================================ - -SHOTGUN TRACING - -============================================================================ -*/ - -/* -================ -CG_ShotgunPellet -================ -*/ -static void CG_ShotgunPellet( vec3_t start, vec3_t end, int skipNum ) { - trace_t tr; - int sourceContentType, destContentType; - - CG_Trace( &tr, start, NULL, NULL, end, skipNum, MASK_SHOT ); - - sourceContentType = CG_PointContents( start, 0 ); - destContentType = CG_PointContents( tr.endpos, 0 ); - - // FIXME: should probably move this cruft into CG_BubbleTrail - if ( sourceContentType == destContentType ) { - if ( sourceContentType & CONTENTS_WATER ) { - CG_BubbleTrail( start, tr.endpos, 32 ); - } - } else if ( sourceContentType & CONTENTS_WATER ) { - trace_t trace; - - trap_CM_BoxTrace( &trace, end, start, NULL, NULL, 0, CONTENTS_WATER ); - CG_BubbleTrail( start, trace.endpos, 32 ); - } else if ( destContentType & CONTENTS_WATER ) { - trace_t trace; - - trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, CONTENTS_WATER ); - CG_BubbleTrail( tr.endpos, trace.endpos, 32 ); - } - - if ( tr.surfaceFlags & SURF_NOIMPACT ) { - return; - } - - if ( cg_entities[tr.entityNum].currentState.eType == ET_PLAYER ) { - CG_MissileHitPlayer( WP_SHOTGUN, tr.endpos, tr.plane.normal, tr.entityNum ); - } else { - if ( tr.surfaceFlags & SURF_NOIMPACT ) { - // SURF_NOIMPACT will not make a flame puff or a mark - return; - } - if ( tr.surfaceFlags & SURF_METALSTEPS ) { - CG_MissileHitWall( WP_SHOTGUN, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_METAL ); - } else { - CG_MissileHitWall( WP_SHOTGUN, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_DEFAULT ); - } - } -} - -/* -================ -CG_ShotgunPattern - -Perform the same traces the server did to locate the -hit splashes -================ -*/ -static void CG_ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, int otherEntNum ) { - int i; - float r, u; - vec3_t end; - vec3_t forward, right, up; - - // derive the right and up vectors from the forward vector, because - // the client won't have any other information - VectorNormalize2( origin2, forward ); - PerpendicularVector( right, forward ); - CrossProduct( forward, right, up ); - - // generate the "random" spread pattern - for ( i = 0 ; i < DEFAULT_SHOTGUN_COUNT ; i++ ) { - r = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16; - u = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16; - VectorMA( origin, 8192 * 16, forward, end); - VectorMA (end, r, right, end); - VectorMA (end, u, up, end); - - CG_ShotgunPellet( origin, end, otherEntNum ); - } -} - -/* -============== -CG_ShotgunFire -============== -*/ -void CG_ShotgunFire( entityState_t *es ) { - vec3_t v; - int contents; - - VectorSubtract( es->origin2, es->pos.trBase, v ); - VectorNormalize( v ); - VectorScale( v, 32, v ); - VectorAdd( es->pos.trBase, v, v ); - if ( cgs.glconfig.hardwareType != GLHW_RAGEPRO ) { - // ragepro can't alpha fade, so don't even bother with smoke - vec3_t up; - - contents = CG_PointContents( es->pos.trBase, 0 ); - if ( !( contents & CONTENTS_WATER ) ) { - VectorSet( up, 0, 0, 8 ); - CG_SmokePuff( v, up, 32, 1, 1, 1, 0.33f, 900, cg.time, 0, LEF_PUFF_DONT_SCALE, cgs.media.shotgunSmokePuffShader ); - } - } - CG_ShotgunPattern( es->pos.trBase, es->origin2, es->eventParm, es->otherEntityNum ); -} /* ============================================================================ @@ -2097,114 +2342,41 @@ BULLETS */ -/* -=============== -CG_Tracer -=============== -*/ -void CG_Tracer( vec3_t source, vec3_t dest ) { - vec3_t forward, right; - polyVert_t verts[4]; - vec3_t line; - float len, begin, end; - vec3_t start, finish; - vec3_t midpoint; - - // tracer - VectorSubtract( dest, source, forward ); - len = VectorNormalize( forward ); - - // start at least a little ways from the muzzle - if ( len < 100 ) { - return; - } - begin = 50 + random() * (len - 60); - end = begin + cg_tracerLength.value; - if ( end > len ) { - end = len; - } - VectorMA( source, begin, forward, start ); - VectorMA( source, end, forward, finish ); - - line[0] = DotProduct( forward, cg.refdef.viewaxis[1] ); - line[1] = DotProduct( forward, cg.refdef.viewaxis[2] ); - - VectorScale( cg.refdef.viewaxis[1], line[1], right ); - VectorMA( right, -line[0], cg.refdef.viewaxis[2], right ); - VectorNormalize( right ); - - VectorMA( finish, cg_tracerWidth.value, right, verts[0].xyz ); - verts[0].st[0] = 0; - verts[0].st[1] = 1; - verts[0].modulate[0] = 255; - verts[0].modulate[1] = 255; - verts[0].modulate[2] = 255; - verts[0].modulate[3] = 255; - - VectorMA( finish, -cg_tracerWidth.value, right, verts[1].xyz ); - verts[1].st[0] = 1; - verts[1].st[1] = 0; - verts[1].modulate[0] = 255; - verts[1].modulate[1] = 255; - verts[1].modulate[2] = 255; - verts[1].modulate[3] = 255; - - VectorMA( start, -cg_tracerWidth.value, right, verts[2].xyz ); - verts[2].st[0] = 1; - verts[2].st[1] = 1; - verts[2].modulate[0] = 255; - verts[2].modulate[1] = 255; - verts[2].modulate[2] = 255; - verts[2].modulate[3] = 255; - - VectorMA( start, cg_tracerWidth.value, right, verts[3].xyz ); - verts[3].st[0] = 0; - verts[3].st[1] = 0; - verts[3].modulate[0] = 255; - verts[3].modulate[1] = 255; - verts[3].modulate[2] = 255; - verts[3].modulate[3] = 255; - - trap_R_AddPolyToScene( cgs.media.tracerShader, 4, verts ); - - midpoint[0] = ( start[0] + finish[0] ) * 0.5; - midpoint[1] = ( start[1] + finish[1] ) * 0.5; - midpoint[2] = ( start[2] + finish[2] ) * 0.5; - - // add the tracer sound - trap_S_StartSound( midpoint, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.tracerSound ); - -} - /* ====================== CG_CalcMuzzlePoint ====================== */ -static qboolean CG_CalcMuzzlePoint( int entityNum, vec3_t muzzle ) { + +extern qboolean PM_PlayerCrouching ( int legsAnim ); + +qboolean CG_CalcMuzzlePoint( centity_t *cent, vec3_t muzzle, qboolean isDecoy ) { vec3_t forward; - centity_t *cent; + //centity_t *cent; int anim; - if ( entityNum == cg.snap->ps.clientNum ) { + /*if ( entityNum == cg.snap->ps.clientNum && !isDecoy ) { VectorCopy( cg.snap->ps.origin, muzzle ); muzzle[2] += cg.snap->ps.viewheight; AngleVectors( cg.snap->ps.viewangles, forward, NULL, NULL ); VectorMA( muzzle, 14, forward, muzzle ); return qtrue; - } + }*/ - cent = &cg_entities[entityNum]; + //cent = &cg_entities[entityNum]; if ( !cent->currentValid ) { return qfalse; } - VectorCopy( cent->currentState.pos.trBase, muzzle ); + //if ( !isDecoy ) + VectorCopy( cent->currentState.pos.trBase, muzzle ); + //else + // VectorCopy( cent->currentState.origin, muzzle ); AngleVectors( cent->currentState.apos.trBase, forward, NULL, NULL ); anim = cent->currentState.legsAnim & ~ANIM_TOGGLEBIT; - if ( anim == LEGS_WALKCR || anim == LEGS_IDLECR ) { + if ( PM_PlayerCrouching( cent->currentState.legsAnim ) ) { muzzle[2] += CROUCH_VIEWHEIGHT; } else { muzzle[2] += DEFAULT_VIEWHEIGHT; @@ -2216,52 +2388,116 @@ static qboolean CG_CalcMuzzlePoint( int entityNum, vec3_t muzzle ) { } + /* -====================== -CG_Bullet +================ +CG_SurfaceExplosion -Renders bullet effects. -====================== +Adds an explosion to a surface +================ */ -void CG_Bullet( vec3_t end, int sourceEntityNum, vec3_t normal, qboolean flesh, int fleshEntityNum ) { - trace_t trace; - int sourceContentType, destContentType; - vec3_t start; - // if the shooter is currently valid, calc a source point and possibly - // do trail effects - if ( sourceEntityNum >= 0 && cg_tracerChance.value > 0 ) { - if ( CG_CalcMuzzlePoint( sourceEntityNum, start ) ) { - sourceContentType = CG_PointContents( start, 0 ); - destContentType = CG_PointContents( end, 0 ); +#define NUM_SPARKS 12 +#define NUM_PUFFS 1 +#define NUM_EXPLOSIONS 4 - // do a complete bubble trail if necessary - if ( ( sourceContentType == destContentType ) && ( sourceContentType & CONTENTS_WATER ) ) { - CG_BubbleTrail( start, end, 32 ); - } - // bubble trail from water into air - else if ( ( sourceContentType & CONTENTS_WATER ) ) { - trap_CM_BoxTrace( &trace, end, start, NULL, NULL, 0, CONTENTS_WATER ); - CG_BubbleTrail( start, trace.endpos, 32 ); - } - // bubble trail from air into water - else if ( ( destContentType & CONTENTS_WATER ) ) { - trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, CONTENTS_WATER ); - CG_BubbleTrail( trace.endpos, end, 32 ); - } +void CG_SurfaceExplosion( vec3_t origin, vec3_t normal, float radius, float shake_speed, qboolean smoke ) +{ + localEntity_t *le; + vec3_t direction, new_org; + vec3_t sprayvel, velocity = { 0, 0, 0 }; + vec3_t temp_org, temp_vel; + float scale, dscale; + int i, numSparks; - // draw a tracer - if ( random() < cg_tracerChance.value ) { - CG_Tracer( start, end ); - } - } + //Sparks + + numSparks = 32 + (random() * 16.0f); + + //VectorSet( normal, 0, 0, 1 ); + + for ( i = 0; i < numSparks; i++ ) + { + scale = 0.25f + (random() * 2.0f); + dscale = -scale*0.5; + + FXE_Spray( normal, 500, 150, 1.0f, sprayvel); + + FX_AddTrail( origin, + sprayvel, + qtrue, + 32.0f, + -64.0f, + scale, + -scale, + 1.0f, + 0.0f, + 0.25f, + 4000.0f, + cgs.media.sparkShader); } - // impact splash and mark - if ( flesh ) { - CG_Bleed( end, fleshEntityNum ); - } else { - CG_MissileHitWall( WP_MACHINEGUN, 0, end, normal, IMPACTSOUND_DEFAULT ); + //Smoke + + //Move this out a little from the impact surface + VectorMA( origin, 4, normal, new_org ); + VectorSet( velocity, 0.0f, 0.0f, 16.0f ); + + for ( i = 0; i < 4; i++ ) + { + VectorSet( temp_org, new_org[0] + (crandom() * 16.0f), new_org[1] + (crandom() * 16.0f), new_org[2] + (random() * 4.0f) ); + VectorSet( temp_vel, velocity[0] + (crandom() * 8.0f), velocity[1] + (crandom() * 8.0f), velocity[2] + (crandom() * 8.0f) ); + + FX_AddSprite( temp_org, + temp_vel, + qfalse, + radius /**96.0f*/ + (random() * 12.0f), + 16.0f, + 1.0f, + 0.0f, + 20.0f + (crandom() * 90.0f), + 0.5f, + 2000.0f, + cgs.media.smokeShader); } + //Core of the explosion + + //Orient the explosions to face the camera + VectorSubtract( cg.refdef.vieworg, origin, direction ); + VectorNormalize( direction ); + + //Tag the last one with a light + le = CG_MakeExplosion2( origin, direction, cgs.media.explosionModel, 5, cgs.media.surfaceExplosionShader, + 500, qfalse, radius * 0.02f + (random() * 0.3f), LEF_NONE); + le->light = 150; + VectorSet( le->lightColor, 0.9f, 0.8f, 0.5f ); + + for ( i = 0; i < NUM_EXPLOSIONS-1; i ++) + { + VectorSet( new_org, (origin[0] + (32 + (crandom() * 8))*crandom()), (origin[1] + (32 + (crandom() * 8))*crandom()), (origin[2] + (32 + (crandom() * 8))*crandom()) ); + le = CG_MakeExplosion2( new_org, direction, cgs.media.explosionModel, 5, cgs.media.surfaceExplosionShader, + 300 + (rand() & 99), qfalse, radius * 0.05f + (crandom() *0.3f), LEF_NONE); + } + + //Shake the camera + CG_ExplosionEffects( origin, shake_speed, 350 ); + +} + +void CG_PlayShooterSound(centity_t *cent) { + weaponInfo_t *weap; + + weap = &cg_weapons[cent->currentState.eventParm]; + + switch(cent->currentState.eventParm) { + case WP_6: + case WP_8: + case WP_9: + trap_S_StartSound(cent->currentState.origin, cent->currentState.number, CHAN_VOICE, weap->flashSound); + break; + case WP_10: + trap_S_StartSound(cent->currentState.origin, cent->currentState.number, CHAN_VOICE, weap->altFlashSnd); + break; + } } diff --git a/code/cgame/cgame.def b/code/cgame/cgame.def new file mode 100644 index 0000000..2ee748e --- /dev/null +++ b/code/cgame/cgame.def @@ -0,0 +1,3 @@ +EXPORTS + vmMain + dllEntry diff --git a/code/cgame/cgame.dsp b/code/cgame/cgame.dsp new file mode 100644 index 0000000..4799da7 --- /dev/null +++ b/code/cgame/cgame.dsp @@ -0,0 +1,337 @@ +# Microsoft Developer Studio Project File - Name="cgame" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=cgame - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "cgame.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "cgame.mak" CFG="cgame - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "cgame - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "cgame - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/StarTrek/Code-DM/cgame", VFJBAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "cgame - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /G6 /W4 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FR /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 /nologo /base:"0x30000000" /subsystem:windows /dll /map /machine:I386 /out:"../Release/cgamex86.dll" +# SUBTRACT LINK32 /incremental:yes /debug + +!ELSEIF "$(CFG)" == "cgame - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /G5 /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /base:"0x30000000" /subsystem:windows /dll /map /debug /machine:I386 /out:"../debug/cgamex86.dll" +# SUBTRACT LINK32 /profile /incremental:no /nodefaultlib + +!ENDIF + +# Begin Target + +# Name "cgame - Win32 Release" +# Name "cgame - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "c" +# Begin Source File + +SOURCE=..\game\bg_lib.c +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\game\bg_misc.c +# End Source File +# Begin Source File + +SOURCE=..\game\bg_oums.c +# End Source File +# Begin Source File + +SOURCE=..\game\bg_pmove.c +# End Source File +# Begin Source File + +SOURCE=..\game\bg_slidemove.c +# End Source File +# Begin Source File + +SOURCE=.\cg_consolecmds.c +# End Source File +# Begin Source File + +SOURCE=.\cg_draw.c +# End Source File +# Begin Source File + +SOURCE=.\cg_drawtools.c +# End Source File +# Begin Source File + +SOURCE=.\cg_effects.c +# End Source File +# Begin Source File + +SOURCE=.\cg_ents.c +# End Source File +# Begin Source File + +SOURCE=.\cg_env.c +# End Source File +# Begin Source File + +SOURCE=.\cg_event.c +# End Source File +# Begin Source File + +SOURCE=.\cg_info.c +# End Source File +# Begin Source File + +SOURCE=.\cg_localents.c +# End Source File +# Begin Source File + +SOURCE=.\cg_main.c +# End Source File +# Begin Source File + +SOURCE=.\cg_marks.c +# End Source File +# Begin Source File + +SOURCE=.\cg_players.c +# End Source File +# Begin Source File + +SOURCE=.\cg_playerstate.c +# End Source File +# Begin Source File + +SOURCE=.\cg_predict.c +# End Source File +# Begin Source File + +SOURCE=.\cg_scoreboard.c +# End Source File +# Begin Source File + +SOURCE=.\cg_screenfx.c +# End Source File +# Begin Source File + +SOURCE=.\cg_servercmds.c +# End Source File +# Begin Source File + +SOURCE=.\cg_snapshot.c +# End Source File +# Begin Source File + +SOURCE=.\cg_syscalls.c +# End Source File +# Begin Source File + +SOURCE=.\cg_view.c +# End Source File +# Begin Source File + +SOURCE=.\cg_weapons.c +# End Source File +# Begin Source File + +SOURCE=.\fx_borg.c +# End Source File +# Begin Source File + +SOURCE=.\fx_compression.c +# End Source File +# Begin Source File + +SOURCE=.\fx_dreadnought.c +# End Source File +# Begin Source File + +SOURCE=.\fx_grenade.c +# End Source File +# Begin Source File + +SOURCE=.\fx_imod.c +# End Source File +# Begin Source File + +SOURCE=.\fx_item.c +# End Source File +# Begin Source File + +SOURCE=.\fx_lib.c +# End Source File +# Begin Source File + +SOURCE=.\fx_misc.c +# End Source File +# Begin Source File + +SOURCE=.\fx_phaser.c +# End Source File +# Begin Source File + +SOURCE=.\fx_quantum.c +# End Source File +# Begin Source File + +SOURCE=.\fx_scavenger.c +# End Source File +# Begin Source File + +SOURCE=.\fx_stasis.c +# End Source File +# Begin Source File + +SOURCE=.\fx_tetrion.c +# End Source File +# Begin Source File + +SOURCE=.\fx_transporter.c +# End Source File +# Begin Source File + +SOURCE=..\game\q_math.c +# End Source File +# Begin Source File + +SOURCE=..\game\q_shared.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h" +# Begin Source File + +SOURCE=..\game\bg_local.h +# End Source File +# Begin Source File + +SOURCE=..\game\bg_oums.h +# End Source File +# Begin Source File + +SOURCE=..\game\bg_public.h +# End Source File +# Begin Source File + +SOURCE=.\cg_anims.h +# End Source File +# Begin Source File + +SOURCE=.\cg_local.h +# End Source File +# Begin Source File + +SOURCE=.\cg_public.h +# End Source File +# Begin Source File + +SOURCE=.\cg_screenfx.h +# End Source File +# Begin Source File + +SOURCE=.\cg_text.h +# End Source File +# Begin Source File + +SOURCE=.\cgame.def +# End Source File +# Begin Source File + +SOURCE=.\fx_local.h +# End Source File +# Begin Source File + +SOURCE=..\game\q_shared.h +# End Source File +# Begin Source File + +SOURCE=..\game\surfaceflags.h +# End Source File +# Begin Source File + +SOURCE=.\tr_types.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\cg_syscalls.asm +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\cgame.bat +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\cgame.q3asm +# PROP Exclude_From_Build 1 +# End Source File +# End Target +# End Project diff --git a/code/cgame/cgame.dsw b/code/cgame/cgame.dsw new file mode 100644 index 0000000..dc9ecc5 --- /dev/null +++ b/code/cgame/cgame.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "cgame"=".\cgame.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/code/cgame/cgame.opt b/code/cgame/cgame.opt new file mode 100644 index 0000000000000000000000000000000000000000..2f05cfaced6c46020ef5349f28eb2c12dd2508ad GIT binary patch literal 48640 zcmeHQTX!5s5nkD`k(CR%H~|7A9UHKnNSoNsg*c8uTCMGMq?ORFEgQ@cy)(VLgJ!3P zxo9PP{A2h7oWna$Jn#yKUjVOp;s*fctL~Y-Y1UrZ=WxPFja}N^neMLY>gww5nyT)< z{^gaw|LzZO{-ZQ;T`L_g{pZoC(#etgbNEhRu9r)A{^${X&p+uqZt?Yh#DRZEyMSQ*l_$B}%PY z0=@_MKHx3D+W<;e!{-^mS-=kfKLq>;a1L-DZ~^cxfYL7Fa|uueybt&Qa1n3`a2fC+ zfYN=8&rbk927C&*0{9GY74SLW8i3OM6ran06+i{B3aA3E18x9r0w^897x=ygSO?Sr z8-Pu~&j4G127uDt#^)WtHsCJc9^mJIUjXg{ehHv-UzKaCr138)3Di8mXH+@>g|lC8 zKw|Q`9D71Gaphlsd+w7z&r$vJq}#wAm3B*UDJ;p7Q&OO$0Xif=<%u5iDN4tTjFRjU z9gj&mcx31#Va2rq?7GwkeuZyGzg{jKo1?x%dU00#FA$mxf3@V6Jk*uA@HE#;z)$^^ zaMLwQ8E;Uc4F4S3k7z&PbYxGxRk?CMPWJS{{V41#?cX;y?ccH+hm`% zI9;j}*oap3bxc3bdTkLWXpbJ+wk&RH-xV$}h(_0I6KgVNlowi2e{q|*qll8Avq-fy zEuPW166t=dHi2(KoCYMg3iO$3jB_t5U>Q8y11TG65~j&Es-pX*DA$WaUmln?vkyhz zJS{J{te4`-Gr4uWJ@iF%gO=}3)_x`Re0K{hz{j%hn|ep~r=S|3FB>Th zBmHX#InaXa@&ZKe@r|qXZcj$Lmah}s%$`l~(lChlIm!gll`%wWPesy)1_;oPsXw4c z`nG-dyx2pX%`@S}LhVUEg;2O@ z(1&t^(Aa8ULT7`@5@%cz%g-;KF$e~aFONU|;LNyg%X&u5Xwh{Qq=xej#5W=72~;0^ z2vX?k7^=rn<03(-7>SIErH0Scva4bz@>Z=>ujq=TFR5jo0p~h4*+0!Yi zi)@Z|l@*#^3f1Q5UI?MFZ1JE;QkNJ-d2FAJbA_GB7U{EM;ey&k+bEHcwn9q{6)%Vw zsN>`y1cE}nXmyTZ%BYgC%vdsnw~Shv7&FHBx|K2SFmH!!B|T&6V4AT5dWPM3LVcNb zpQ61+yMon$nFhICZj?zgS7abvIV{_uK1-}!_h?Af(8=3g+!bpcL>2ATleYPXm#I1O5})@qIQ?T!AP0V25t&%017Z(?|G0UaX+{pG=Vvj zAB@Ub8|UcJ8_$1u>7xtc)5{+(ZPyw%A0xY~p7eF+Fo#`pe?)$#3roi4h8>)Bfc}Ot z%@k>842HZ+grF%?Gr$q=VrVWX*MR0Ps9!=IJ1!b#uOrPNVWOMD(rL$=C&+;rf40(~ zsVioBWD1N@J5qqrok;emA&9bU0%cX(jN{HUrEl;Uy`LA2*&F(@j5;c@l#6MkgDEBx zrfW$AL7=&d88@N1K&nLj+h#VHK#m}JnN}!^3Qe_4Rx{%;50OFbD-57knWCO348n+c zjNwf~C3SRojHPzk@zBc6vXxdhl6?|TVvm&?QN@fyW0IIpIFK#W5mY=BzQ$03nH@wM z>Br`JSsx(1(#5ofbd;IdEc=+~)Y{{Ty*M~WqtN1^v}P(t(-I6785{3q6CYF}!caj| z-gfGPXe)=rymq8}R%hldZpCq}R{ui0zj}LpQ(PtWc&%K$TeYgKSVd-xyP=!fG;j|U zwoPJqoiU1vvihXBl;PaIrJ%e5Vg}k!n&F=~WYEyv2dmmiX^cekM9IUl$SXT6LZLrA zA#)Y|$kLN%H*`aVI6BPrJO&`6_;D9~BJ6sOo%BSqLkiXm0B)p1qy0q_<1Xc;cJ?3v zwxw*7R+7la@NNVI@`JGg;x;)mvV&+13kAc-u|d?s-4P`;HTOu59?Nh0@kj~N)ff%R zREMFWqO}M5jJ;u40{OHZAP&v&XqAPpp#8ykV%nlz9UX^*-u`YJUxIwp!D5zVRxPzOmTkS9SQ&=UI(CKFhB8HtE|wmKFf@eGdZu&ai_2`1 zo&Tf-3}mhc;=sl%L*miOlxRJ)3>}|T*$!zKY?c>>`-u+GnXK|f~dUP5D&4Cqm|0YeetfqgJHhq z`s&Wp=B?&=#lvwrc9z%H&X3}+RQDYf()cqC{p?u=SSia0=9TJ=T79Rov37gCzO%l( zd4B%_dK378W~f(IcJfDO&+dyWBE%BRbA(Mk!VgpWunh31A7 zgP?$r>fL6w-XJ;}_2o^pTYY1-TB~2*D5PkR+9n>P9iwcJXtKx&5~rq{M(g$3TC=)U zNLco0j1GHm0_jK@1>9I~+$b!b?q_8mAHLBc>mJ+x*#5`%KeqqD9LV-Rw*S#<8MgoB z<_Nna++zD5+y9JtitT@F|C_WGvi;A#telM(#K5&vytzfV=jsrinl`X{bd zH@2>g{(aE|f?Ky|72798_vWu7vSe7q+uIZpYl0HanG()j5f{nbooq?x;|rrGW=s3L zCB%dZj^>^up5wnc{+l9CIR0B97?0z>IsO}FYmWam!QIAi%kkeF|4qSzd3ZR-f7?h% zj{oNP?~%QoIR2aCzd8P!m2|6*wFI=Q~XHm_M}Mt@8Z9I^`&+E ze9aoxmS|J1%a?@lN;qZi*^M9POO;J)w<}8d`graw%&KKh;$le1)i8cy?Sf=g`0La z$S0+gjc|3~qFz{-ZXIT41O-JKS6%>JJvJ9o1G zXPDdnicha0e@?dlVY6rQCFAp7`23gglZ^QMmuZLl@cA!%{)^!AU$A*5j`891U+54J zKL4dq4mkds{C9r-^P@+`|E}W4*L}C)>y`})CXYLF@H6}WvHg$Ff1WtAnC*XT|HBc0eEu_^ z|4gyfy#FKKlJWV^bbzTjr<(VF`TS=b(Oi5KH}C(*`#)kl z;r$9 zWcxp^VwXt=_-W_Ipp;-A#G_r<|8Z^}Sxx|E-T$#kC^G!?^;xf@?mzjg_$Ko|3;qS1 z|6{M5d(YwL$!(c9-HZ8`OZk_}`IirK8Yqf8?Qr~e;sqV!B|3J1kkeJpu4w7~@ScERrT@f-=+Nf@18trwJuQle07ySPSLe z87-Y8x<`8#k&=>Oh&7d@||Z*f*Dpa6|ReUNHEnu$0n~ z=z%yq%Q7Th55I_3jdCK;hy(9>21(g?agMLZ`224^|9f?(GTcM5z*v|2c+$Z=?EiT< zs{QZ=lLbs1cyzM=XRW?7gZ=lUIrjUHu;Q`(@76Z&|H$?~jroSLj`IGGKJWj?_CHs} zPUN+eOY`)rZ2x2XAMgKYU$gQ4k8J;A`ybo?*#0L2fersX|3FCB6?-!BWDEQ9v;7Z4 uCA}(Q`ybo?*#5Us&un;`8?}1#kTdI;fsgHf)va+3Sy#^qzC5%4=YIi08vTO+ literal 0 HcmV?d00001 diff --git a/code/cgame/cgame.plg b/code/cgame/cgame.plg new file mode 100644 index 0000000..cd75540 --- /dev/null +++ b/code/cgame/cgame.plg @@ -0,0 +1,147 @@ + + +
+

Build Log

+

+--------------------Configuration: cgame - Win32 Debug-------------------- +

+

Command Lines

+Creating temporary file "C:\DOCUME~1\marcin\LOCALS~1\Temp\RSP194.tmp" with contents +[ +/nologo /G5 /MLd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR"Release/" /Fp"Release/cgame.pch" /YX /Fo"Release/" /Fd"Release/" /FD /c +"C:\stvoy\code-dm\game\bg_misc.c" +"C:\stvoy\code-dm\game\bg_pmove.c" +"C:\stvoy\code-dm\game\bg_slidemove.c" +"C:\stvoy\code-dm\cgame\cg_consolecmds.c" +"C:\stvoy\code-dm\cgame\cg_draw.c" +"C:\stvoy\code-dm\cgame\cg_drawtools.c" +"C:\stvoy\code-dm\cgame\cg_effects.c" +"C:\stvoy\code-dm\cgame\cg_ents.c" +"C:\stvoy\code-dm\cgame\cg_env.c" +"C:\stvoy\code-dm\cgame\cg_event.c" +"C:\stvoy\code-dm\cgame\cg_info.c" +"C:\stvoy\code-dm\cgame\cg_localents.c" +"C:\stvoy\code-dm\cgame\cg_main.c" +"C:\stvoy\code-dm\cgame\cg_marks.c" +"C:\stvoy\code-dm\cgame\cg_players.c" +"C:\stvoy\code-dm\cgame\cg_playerstate.c" +"C:\stvoy\code-dm\cgame\cg_predict.c" +"C:\stvoy\code-dm\cgame\cg_scoreboard.c" +"C:\stvoy\code-dm\cgame\cg_screenfx.c" +"C:\stvoy\code-dm\cgame\cg_servercmds.c" +"C:\stvoy\code-dm\cgame\cg_snapshot.c" +"C:\stvoy\code-dm\cgame\cg_syscalls.c" +"C:\stvoy\code-dm\cgame\cg_view.c" +"C:\stvoy\code-dm\cgame\cg_weapons.c" +"C:\stvoy\code-dm\cgame\fx_borg.c" +"C:\stvoy\code-dm\cgame\fx_compression.c" +"C:\stvoy\code-dm\cgame\fx_dreadnought.c" +"C:\stvoy\code-dm\cgame\fx_grenade.c" +"C:\stvoy\code-dm\cgame\fx_imod.c" +"C:\stvoy\code-dm\cgame\fx_item.c" +"C:\stvoy\code-dm\cgame\fx_lib.c" +"C:\stvoy\code-dm\cgame\fx_misc.c" +"C:\stvoy\code-dm\cgame\fx_phaser.c" +"C:\stvoy\code-dm\cgame\fx_quantum.c" +"C:\stvoy\code-dm\cgame\fx_scavenger.c" +"C:\stvoy\code-dm\cgame\fx_stasis.c" +"C:\stvoy\code-dm\cgame\fx_tetrion.c" +"C:\stvoy\code-dm\cgame\fx_transporter.c" +] +Creating command line "cl.exe @C:\DOCUME~1\marcin\LOCALS~1\Temp\RSP194.tmp" +Creating temporary file "C:\DOCUME~1\marcin\LOCALS~1\Temp\RSP195.tmp" with contents +[ +/nologo /base:"0x30000000" /subsystem:windows /dll /incremental:yes /pdb:"Release/cgamex86.pdb" /map:"Release/cgamex86.map" /debug /machine:I386 /def:".\cgame.def" /out:"../debug/cgamex86.dll" /implib:"Release/cgamex86.lib" +".\Release\bg_misc.obj" +".\Release\bg_oums.obj" +".\Release\bg_pmove.obj" +".\Release\bg_slidemove.obj" +".\Release\cg_consolecmds.obj" +".\Release\cg_draw.obj" +".\Release\cg_drawtools.obj" +".\Release\cg_effects.obj" +".\Release\cg_ents.obj" +".\Release\cg_env.obj" +".\Release\cg_event.obj" +".\Release\cg_info.obj" +".\Release\cg_localents.obj" +".\Release\cg_main.obj" +".\Release\cg_marks.obj" +".\Release\cg_players.obj" +".\Release\cg_playerstate.obj" +".\Release\cg_predict.obj" +".\Release\cg_scoreboard.obj" +".\Release\cg_screenfx.obj" +".\Release\cg_servercmds.obj" +".\Release\cg_snapshot.obj" +".\Release\cg_syscalls.obj" +".\Release\cg_view.obj" +".\Release\cg_weapons.obj" +".\Release\fx_borg.obj" +".\Release\fx_compression.obj" +".\Release\fx_dreadnought.obj" +".\Release\fx_grenade.obj" +".\Release\fx_imod.obj" +".\Release\fx_item.obj" +".\Release\fx_lib.obj" +".\Release\fx_misc.obj" +".\Release\fx_phaser.obj" +".\Release\fx_quantum.obj" +".\Release\fx_scavenger.obj" +".\Release\fx_stasis.obj" +".\Release\fx_tetrion.obj" +".\Release\fx_transporter.obj" +".\Release\q_math.obj" +".\Release\q_shared.obj" +] +Creating command line "link.exe @C:\DOCUME~1\marcin\LOCALS~1\Temp\RSP195.tmp" +

Output Window

+Compiling... +bg_misc.c +bg_pmove.c +bg_slidemove.c +cg_consolecmds.c +cg_draw.c +cg_drawtools.c +cg_effects.c +cg_ents.c +cg_env.c +cg_event.c +cg_info.c +cg_localents.c +cg_main.c +cg_marks.c +cg_players.c +cg_playerstate.c +cg_predict.c +cg_scoreboard.c +cg_screenfx.c +cg_servercmds.c +cg_snapshot.c +cg_syscalls.c +cg_view.c +cg_weapons.c +fx_borg.c +fx_compression.c +fx_dreadnought.c +fx_grenade.c +fx_imod.c +fx_item.c +fx_lib.c +fx_misc.c +fx_phaser.c +fx_quantum.c +fx_scavenger.c +fx_stasis.c +fx_tetrion.c +fx_transporter.c +Linking... + Creating library Release/cgamex86.lib and object Release/cgamex86.exp + + + +

Results

+cgamex86.dll - 0 error(s), 0 warning(s) +
+ + diff --git a/code/cgame/cgame.q3asm b/code/cgame/cgame.q3asm new file mode 100644 index 0000000..3d09044 --- /dev/null +++ b/code/cgame/cgame.q3asm @@ -0,0 +1,42 @@ +-o "C:\stvoy\code-DM\vm\cgame" +cg_main +..\cg_syscalls +cg_consolecmds +cg_draw +cg_drawtools +cg_effects +cg_ents +cg_env +cg_event +cg_info +cg_localents +cg_marks +cg_players +cg_playerstate +cg_predict +cg_scoreboard +cg_screenfx +cg_servercmds +cg_snapshot +cg_view +cg_weapons +bg_slidemove +bg_pmove +bg_lib +bg_misc +q_math +q_shared +fx_compression +fx_imod +fx_misc +fx_lib +fx_phaser +fx_scavenger +fx_tetrion +fx_transporter +fx_grenade +fx_quantum +fx_stasis +fx_item +fx_dreadnought +fx_borg \ No newline at end of file diff --git a/code/cgame/cgame.vcproj b/code/cgame/cgame.vcproj new file mode 100644 index 0000000..8ed940d --- /dev/null +++ b/code/cgame/cgame.vcproj @@ -0,0 +1,1354 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/cgame/cgame.vcxproj b/code/cgame/cgame.vcxproj new file mode 100644 index 0000000..757edf8 --- /dev/null +++ b/code/cgame/cgame.vcxproj @@ -0,0 +1,499 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {EBB0D9E9-00FC-4DBA-AF4A-4052FE9B17B1} + cgame + + + + DynamicLibrary + false + + + DynamicLibrary + false + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\Debug\ + ..\Debug\ + false + ..\Release\ + ..\Release\ + false + AllRules.ruleset + + + AllRules.ruleset + + + C:\MinGW\include;$(IncludePath) + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Release/cgame.tlb + + + + + MaxSpeed + true + Speed + true + lua\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;XTRA;G_LUA;%(PreprocessorDefinitions) + MultiThreadedDebug + false + + + .\Release/cgame.pch + .\Release/ + .\Release/ + .\Release/ + true + Level4 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + odbc32.lib;odbccp32.lib;lua52.lib;%(AdditionalDependencies) + C:\Program Files\Raven\Star Trek Voyager Elite Force\RPG-X2\cgamex86.dll + true + .\cgame.def + true + .\Release/cgamex86.pdb + true + .\Release/cgamex86.map + Windows + UseLinkTimeCodeGeneration + 0x30000000 + false + + + .\Release/cgamex86.lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Release/cgame.tlb + + + + + /analyze %(AdditionalOptions) + MaxSpeed + OnlyExplicitInline + WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + MultiThreaded + 4Bytes + true + + + .\Release/cgame.pch + .\Release/ + .\Release/ + .\Release/ + + + Level4 + true + CompileAsC + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + ../Release/cgamex86.dll + true + .\cgame.def + .\Release/cgamex86.pdb + true + .\Release/cgamex86.map + Windows + 0x30000000 + false + + + .\Release/cgamex86.lib + MachineX86 + + + + + true + Disabled + WIN32;_DEBUG;_WINDOWS + true + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + Disabled + WIN32;_DEBUG;_WINDOWS + true + MaxSpeed + WIN32;NDEBUG;_WINDOWS + true + + + + + + + + + + + + + + + + + + + + + + + Document + true + true + + + Document + true + true + + + Document + true + true + + + + + + \ No newline at end of file diff --git a/code/cgame/cgame.vcxproj.filters b/code/cgame/cgame.vcxproj.filters new file mode 100644 index 0000000..4f23b58 --- /dev/null +++ b/code/cgame/cgame.vcxproj.filters @@ -0,0 +1,195 @@ + + + + + {90a720d9-41f5-4abf-91d4-5c109cd2d702} + c + + + {76164a83-7a3a-4473-b6db-f151d30a82d7} + h + + + {cc31ca7a-00a9-49ce-9830-b91beeffb091} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files\lua + + + Source Files\lua + + + Source Files\lua + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Header Files + + + + + + + + \ No newline at end of file diff --git a/code/cgame/cgame.vcxproj.user b/code/cgame/cgame.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/code/cgame/cgame.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/code/cgame/fx_compression.c b/code/cgame/fx_compression.c new file mode 100644 index 0000000..e607083 --- /dev/null +++ b/code/cgame/fx_compression.c @@ -0,0 +1,434 @@ +//Compression rifle weapon effects + +#include "cg_local.h" +#include "fx_local.h" + +qboolean AltCompressionAftereffect(localEntity_t *le) +{ + localEntity_t *cyl = NULL; + qhandle_t shader = cgs.media.compressionAltBlastShader; + float percentLife = 1.0 - (le->endTime - cg.time)*le->lifeRate; + float alpha = 0.6 - (0.6*percentLife); + float length = 20; + vec3_t vec2, dir2; + + cyl = FX_AddCylinder( le->refEntity.origin, + le->data.spawner.dir, + length,// height, + 0,// dheight, + 10,//10+(30*(1-percentLife)),// scale, + 210,// dscale, + 10+(30*percentLife),// scale2, + 210,// dscale2, + alpha,// startalpha, + 0.0,// endalpha, + 500,// killTime, + shader, + 15);// bias ); + cyl->leFlags |= LEF_ONE_FRAME; + + VectorMA(le->refEntity.origin, length*2.0, le->data.spawner.dir, vec2); + VectorScale(le->data.spawner.dir, -1.0, dir2); + cyl = FX_AddCylinder( vec2, + dir2, + length,// height, + 0,// dheight, + 10,//10+(30*(1-percentLife)),// scale, + 210,// dscale, + 10+(30*percentLife),// scale2, + 210,// dscale2, + alpha,// startalpha, + 0.0,// endalpha, + 500,// killTime, + shader, + 15);// bias ); + cyl->leFlags |= LEF_ONE_FRAME; + + return qtrue; +} + +/* +------------------------- +FX_CompressionShot +------------------------- +*/ +#define MAXRANGE_CRIFLE 8192 +void FX_CompressionShot( vec3_t start, vec3_t dir ) +{ + localEntity_t *le; + vec3_t end; + trace_t trace; + qboolean render_impact = qtrue; + centity_t *traceEnt = NULL; + int clientNum = -1; + + VectorMA(start, MAXRANGE_CRIFLE, dir, end); + CG_Trace( &trace, start, NULL, NULL, end, 0, MASK_SHOT ); + + // draw the beam + le = FX_AddLine(start, trace.endpos, 1.0, 2.0, 0.0, 1.0, 1.0, 100.0, cgs.media.prifleBolt); + le->leFlags |= LEF_ONE_FRAME; + + // draw an impact at the endpoint of the trace + // If the beam hits a skybox, etc. it would look foolish to add in an explosion + if ( trace.surfaceFlags & SURF_NOIMPACT ) + { + render_impact = qfalse; + } + if ( render_impact ) + { + traceEnt = &cg_entities[trace.entityNum]; + clientNum = traceEnt->currentState.clientNum; + if ( (trace.entityNum != ENTITYNUM_WORLD) && (clientNum >= 0 || clientNum < MAX_CLIENTS) ) + { + FX_CompressionHit(trace.endpos); + } + else + { + FX_CompressionExplosion(start, trace.endpos, trace.plane.normal, qfalse); + } + } +} +/* +------------------------- +FX_CompressionShot +------------------------- +*/ +void FX_CompressionAltShot( vec3_t start, vec3_t dir ) +{ + vec3_t end, vel = {0,0,0}; + trace_t trace; + qboolean render_impact = qtrue; + centity_t *traceEnt = NULL; + int clientNum = -1; + + VectorMA(start, MAXRANGE_CRIFLE, dir, end); + CG_Trace( &trace, start, NULL, NULL, end, cg_entities[cg.predictedPlayerState.clientNum].currentState.number, MASK_SHOT ); + + // draw the beam + FX_AddLine( start, trace.endpos, 1.0f, 3.0f, 0.0f, 1.0f, 0.0f, 350/*125.0f*/, cgs.media.sparkShader ); + FX_AddLine( start, trace.endpos, 1.0f, 6.0f, 20.0f, 0.6f, 0.0f, 800/*175.0f*/, cgs.media.phaserShader);//compressionAltBeamShader ); + + FX_AddSpawner( start, dir, vel, NULL, qfalse, 0, + 0, 500, AltCompressionAftereffect, 10 ); + + // draw an impact at the endpoint of the trace + // If the beam hits a skybox, etc. it would look foolish to add in an explosion + if ( trace.surfaceFlags & SURF_NOIMPACT ) + { + render_impact = qfalse; + } + if ( render_impact ) + { + traceEnt = &cg_entities[trace.entityNum]; + clientNum = traceEnt->currentState.clientNum; + if ( (trace.entityNum != ENTITYNUM_WORLD) && (clientNum >= 0 || clientNum < MAX_CLIENTS) ) + { + FX_CompressionHit(trace.endpos); + } + else + { + FX_CompressionExplosion(start, trace.endpos, trace.plane.normal, qtrue); + } + } +} + +/* +------------------------- +FX_CompressionExplosion +------------------------- +*/ + +void FX_CompressionExplosion( vec3_t start, vec3_t origin, vec3_t normal, qboolean altfire ) +{ + localEntity_t *le; + vec3_t dir; + vec3_t velocity; //, shot_dir; + vec3_t hitpos; + float scale, dscale; + int i, j, numSparks; + weaponInfo_t *weaponInfo = &cg_weapons[WP_6]; + float distance; + + vec3_t color = {0.7, 0.43, 0.44}; + + int size = 2; + + //FX_CompressionHit( origin ); //TiM: let's test if the rifle doesn't make stuff explode when its shot :) + //return; + + //Sparks + //TiM: Calc spark count off proximity to effect + VectorSubtract ( cg.refdef.vieworg, origin, dir ); + distance = VectorNormalize( dir ); + distance = 50 * ( 1.0f - (distance / 128) ) ; + distance = Com_Clamp( 25, 50, distance ); + + numSparks = distance + (random() * 4.0f); //4 + + if (altfire) + { + numSparks *= 1.5f; + } + for ( i = 0; i < numSparks; i++ ) + { + scale = 10.0f + (random() * 1.0f); //.25 + dscale = -scale; + + //Randomize the direction + for (j = 0; j < 3; j ++ ) + { + //if ( j !=5 ) + //dir[j] = normal[j] + (0.75 * crandom()); + //else + dir[j] = normal[j] + (-1 * crandom()); //0.75 + } + + VectorNormalize(dir); + + //set the speed + VectorScale( dir, 200 + (50 * crandom()), velocity); //200 + + le = FX_AddTrail( origin, + velocity, + qtrue, //qtrue + 12.0f,//4 + -12.0f,//4 + scale, + -scale, + 1.0f, + 1.0f, + 0.5f, + 1000.0f, //1000 + cgs.media.orangeStarShader); + +// FXE_Spray( normal, 200, 50, 0.4f, le); + } + + VectorMA( origin, 8, normal, dir ); + VectorSet(velocity, 0, 0, 8); +/* + FX_AddSprite( dir, + velocity, + qfalse, + (altfire?50.0f:32.0f), + 16.0f, + 1.0f, + 0.0f, + random()*45.0f, + 0.0f, + (altfire?1300.0f:1000.0f), + cgs.media.steamShader ); +*/ + //Orient the explosions to face the camera + VectorSubtract( cg.refdef.vieworg, origin, dir ); + VectorNormalize( dir ); + + if (!altfire) + { + CG_InitLensFlare( origin, + 350, 350, + color, 1.2, 2.0, 1600, 200, + color, 1600, 200, 800, 20, qtrue, + 0, 0, qfalse, qtrue, + qfalse, 1.0, cg.time, 0, 0, 210); + + + VectorMA(origin, size, normal, hitpos); + + FX_AddSprite( hitpos, NULL, qfalse, size * size * 15.0f, -150.0f, + 1.0f, 0.0f, 360*random(), 0, 400, cgs.media.liteRedParticleShader ); + + FX_AddSprite( hitpos, NULL, qfalse, size * size * 25.0f, -150.0f, + 1.0f, 0.0f, 0.0f, 0, 400, cgs.media.liteRedParticleStreakShader ); + + + le = CG_MakeExplosion2( origin, dir, cgs.media.explosionModel, 5, cgs.media.electricalExplosionSlowShader, + 475, qfalse, 1.2f + ( crandom() * 0.3f), LEF_NONE); + le->light = 150; + le->refEntity.renderfx |= RF_NOSHADOW; + VectorSet( le->lightColor, 0.8f, 0.8f, 1.0f ); + + CG_ImpactMark( cgs.media.compressionMarkShader, origin, normal, random()*360, 1,1,1,1, qfalse, 12, qfalse ); + + //Shake the camera + CG_ExplosionEffects( origin, 1, 200 ); + } + else + { + le = CG_MakeExplosion2( origin, dir, cgs.media.explosionModel, 5, cgs.media.electricalExplosionSlowShader, + 500, qfalse, 2.2f + ( crandom() * 0.4f), LEF_NONE); + le->light = 200; + le->refEntity.renderfx |= RF_NOSHADOW; + VectorSet( le->lightColor, 0.8f, 0.8f, 1.0f ); + + CG_ImpactMark( cgs.media.compressionMarkShader, origin, normal, random()*360, 1,1,1,1, qfalse, 28, qfalse ); + + //Shake the camera + CG_ExplosionEffects( origin, 2, 240 ); + } + + // nice explosion sound at the point of impact + trap_S_StartSound(origin, ENTITYNUM_WORLD, CHAN_AUTO, weaponInfo->mainHitSound); +} + +/* +------------------------- +FX_CompressionHit +------------------------- +*/ + +void FX_CompressionHit( vec3_t origin ) +{ + FX_AddSprite( origin, + NULL, + qfalse, + 32.0f, + -32.0f, + 1.0f, + 1.0f, + random()*360, + 0.0f, + 250.0f, + cgs.media.prifleImpactShader ); + + //FIXME: Play an impact sound with a body +// trap_S_StartSound (origin, NULL, 0, cgi_S_RegisterSound ("sound/weapons/prifle/fire.wav") ); +} + +void FX_PrifleBeamFire( vec3_t startpos, vec3_t endpos, vec3_t normal, qboolean spark, qboolean impact, qboolean empty ) +{ + refEntity_t beam; + sfxHandle_t sfx; + float size; + vec3_t velocity; + int sparks; + vec3_t rgb = { 1,0.9,0.6}, rgb2={1,0.3,0}; + + //vec3_t rgb3 = { 1.0, 1.0, 1.0 }; + + sfx = 0; + + // Draw beam first. + memset( &beam, 0, sizeof( beam ) ); + + VectorCopy( startpos, beam.origin); + VectorCopy( endpos, beam.oldorigin ); + beam.reType = RT_LINE; + if (empty) + { + beam.customShader = cgs.media.phaserEmptyShader; + } + else + { + beam.customShader = cgs.media.prifleBeam; + } + AxisClear( beam.axis ); + beam.shaderRGBA[0] = 0xff; + beam.shaderRGBA[1] = 0xff; + beam.shaderRGBA[2] = 0xff; + beam.shaderRGBA[3] = 0xff; + if (empty) + { + beam.data.line.width = 1.0f + ( crandom() * 0.6f ); + } + else + { + beam.data.line.width = 2.5f + ( crandom() * 0.6f ); + } + beam.data.line.stscale = 5.0; + trap_R_AddRefEntityToScene( &beam ); + + // Now draw the hit graphic + + // no explosion at LG impact, it is added with the beam + + if ( sfx ) + { + Com_Printf("playing %s\n", "phaser sound"); + trap_S_StartSound( endpos, ENTITYNUM_WORLD, CHAN_AUTO, sfx ); + } + + // + // impact mark + // + if (impact) + { + if (!empty) + { // normal. + CG_ImpactMark( cgs.media.scavMarkShader, endpos, normal, random()*360, 1,1,1,0.2, qfalse, + random() + 1, qfalse ); + + //VectorCopy( endpos, phaserFlare.worldCoord ); + + /*CG_InitLensFlare( endpos, + 80, + 80, + rgb, + 1.2, + 1.5, + 1600, + 200, + colorTable[CT_BLACK], + 1600, + 200, + 80, + 5, + qfalse, + 5, + 40, + qfalse, + qfalse, + qfalse, + 1.0, + 1.0, + 200.0, + 200.0, + 200.0 );*/ + + //CG_InitLensFlare( endpos, + // 30, 30, + // rgb, 1.2, 2.0, 1600, 200, + // colorTable[CT_BLACK], 1600, 200, 410, 15, qfalse, + // 0, 0, qfalse, qtrue, + // qfalse, 1.0, cg.time, 0, 0, 50); + + //TiM : Add your basic cheesy 'seen-way-too-much-in-movies-these-days' anamorphic lens streak :) + //CG_DrawLensFlare( &phaserFlare ); + //FX_AddSprite( endpos, NULL, qfalse, random() * 1.25 + 5.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 50.0, cgs.media.blueParticleStreakShader ); //1.5f + + //FX_AddQuad2( endpos, normal, random() * 1.25 + 8.0f, 0.0f, 1.0f, 1.0f, rgb3, rgb3, 270, 50.0, cgs.media.blueParticleStreakShader ); + //eh... looked bad :P + + FX_AddQuad2( endpos, normal, random() * 1.25 + 1.5f, 0.0f, 1.0f, 0.0f, rgb, rgb2, rand() % 360, 500 + random() * 200, + cgs.media.sunnyFlareShader ); + } + else + { // Wuss hit when empty. + FX_AddQuad2( endpos, normal, random() * .75 + 1.0f, 0.0f, 0.5f, 0.0f, rgb, rgb2, rand() % 360, 300 + random() * 200, + cgs.media.sunnyFlareShader ); + } + } + + // "Fun" sparks... Not when empty. + if ( spark && !empty) + { + sparks = (rand() & 1) + 1; + for(;sparks>0;sparks--) + { + size = 0.2f + (random() * 0.4); + FXE_Spray( normal, 200, 75, 0.8f, velocity); + if (rand() & LEF_USE_COLLISION) + { // This spark bounces. + FX_AddTrail( endpos, velocity, qtrue, 5.0f, -15.0f, + size, -size, 1.0f, 0.5f, 0.4f, 500.0f, cgs.media.sparkShader); + } + else + { + FX_AddTrail( endpos, velocity, qtrue, 5.0f, -15.0f, + size, -size, 1.0f, 0.5f, 0.0, 500.0f, cgs.media.sparkShader); + } + } + } +} + diff --git a/code/cgame/fx_disruptor.c b/code/cgame/fx_disruptor.c new file mode 100644 index 0000000..3d640fe --- /dev/null +++ b/code/cgame/fx_disruptor.c @@ -0,0 +1,296 @@ +#include "cg_local.h" +#include "fx_local.h" + +/* +------------------------- +FX_OrientedBolt + +Creates new bolts for a while +------------------------- +*/ + +void FX_OrientedBolt( vec3_t start, vec3_t end, vec3_t dir ) +{ + vec3_t mid; + + VectorSubtract( end, start, mid ); + VectorScale( mid, 0.1f + (random() * 0.8), mid ); + VectorAdd( start, mid, mid ); + VectorMA(mid, 3.0f + (random() * 10.0f), dir, mid ); + + //FX_AddElectricity( mid, start, 0.5, 0.75 + random() * 0.75, 0.0, 1.0, 0.5, 300.0f + random() * 300, cgs.media.bolt2Shader, DEFAULT_DEVIATION); + //FX_AddElectricity( mid, end, 0.5, 0.75 + random() * 0.75, 1.0, 1.0, 0.5, 300.0f + random() * 300, cgs.media.bolt2Shader, DEFAULT_DEVIATION); + + FX_AddElectricity( mid, start, 0.5, 0.75 + random() * 0.75, 0.0, 1.0, 0.5, 300.0f + random() * 300, cgs.media.borgLightningShaders[2], DEFAULT_DEVIATION); + FX_AddElectricity( mid, end, 0.5, 0.75 + random() * 0.75, 1.0, 1.0, 0.5, 300.0f + random() * 300, cgs.media.borgLightningShaders[3], DEFAULT_DEVIATION); +} + +/* +------------------------- +FX_DisruptorDischarge + +Fun "crawling" electricity ( credit goes to Josh for this one ) +------------------------- +*/ + +void FX_DisruptorDischarge( vec3_t origin, vec3_t normal, int count, float dist_out, float dist_side ) +{ + trace_t trace; + vec3_t org, dir, dest; + vec3_t vr; + int i; + int discharge = dist_side; + + vectoangles( normal, dir ); + dir[ROLL] += random() * 360; + + for (i = 0; i < count; i++) + { + //Move out a set distance + VectorMA( origin, dist_out, normal, org ); + + //Even out the hits + dir[ROLL] += (360 / count) + (rand() & 31); + AngleVectors( dir, NULL, vr, NULL ); + + //Move to the side in a random direction + discharge += (int)( crandom() * 8.0f ); + VectorMA( org, discharge, vr, org ); + + //Trace back to find a surface + VectorMA( org, -dist_out * 3, normal, dest ); + + CG_Trace( &trace, org, NULL, NULL, dest, 0, MASK_SHOT ); + + //No surface found, start over + if (trace.fraction == 1) + continue; + + //Connect the two points with bolts + FX_OrientedBolt( origin, trace.endpos, normal ); + + //TiM : Aww screw it. Add a lens flare. ^_^ + CG_InitLensFlare( trace.endpos, + 10, 10, + colorTable[CT_GREEN], 1.2, 2.0, 1600, 500, + colorTable[CT_GREEN], 1600, 500, 100, 5, qtrue, + 0, 0, qfalse, qtrue, + qfalse, 1.0, cg.time, 0, 0, 300.0f + random() * 300); + } +} + +/* +------------------------- +FX_DisruptorWeaponHitWall + +Main fire impact +------------------------- +*/ + +#define NUM_DISCHARGES 6 +#define DISCHARGE_DIST 8 +#define DISCHARGE_SIDE_DIST 24 + +void FX_DisruptorWeaponHitWall( vec3_t origin, vec3_t dir, int size ) +{ + vec3_t vel, /*accel,*/ hitpos, direction, org; + //int i, t; + weaponInfo_t *weaponInfo = &cg_weapons[WP_10]; + + CG_InitLensFlare( origin, + 375, 375, + colorTable[CT_GREEN], 1.2, 2.0, 1600, 200, + colorTable[CT_GREEN], 1600, 200, 800, 20, qtrue, + 0, 0, qfalse, qtrue, + qfalse, 1.0, cg.time, 0, 0, 200); + + // Generate "crawling" electricity // eh, don't it doesn't look that great. + FX_DisruptorDischarge( origin, dir, NUM_DISCHARGES, DISCHARGE_DIST, DISCHARGE_SIDE_DIST ); + + VectorMA(origin, size, dir, hitpos); + + // Set an oriented residual glow effect + FX_AddQuad( hitpos, dir, size * size * 15.0f, -150.0f, + 1.0f, 0.0f, 0, 300, cgs.media.greenParticleShader ); + + CG_ImpactMark( cgs.media.scavMarkShader, origin, dir, random()*360, 1,1,1,0.6, qfalse, + size * 12 + 1, qfalse ); + + FX_AddSprite( hitpos, NULL, qfalse, size * size * 15.0f, -150.0f, + 1.0f, 0.0f, 360*random(), 0, 400, cgs.media.greenParticleShader ); + +/* FX_AddSprite( hitpos, NULL, qfalse, size * size * 15.0f, -150.0f, + 1.0f, 0.0f, 360*random(), 0, 400, cgs.media.greenParticleStreakShader ); */ + + FX_AddSprite( hitpos, NULL, qfalse, size * size * 25.0f, -150.0f, + 1.0f, 0.0f, 0.0f, 0, 400, cgs.media.greenParticleStreakShader ); + + VectorSubtract( cg.refdef.vieworg, origin, direction ); + VectorNormalize( direction ); + + VectorMA( origin, 12, direction, org ); + VectorMA( org, 8, dir, direction ); + VectorSet(vel, 0, 0, 32 ); //8 + + FX_AddSprite( origin, + vel, qfalse, + random() * 4 + 2, 12, + 0.6 + random() * 0.4, 0.0, + random() * 180, + 0.0, + random() * 200 + 1200, //300 + cgs.media.steamShader ); + + //FX_AddSprite( + + // Only play the impact sound and throw off the purple particles when it's the main projectile +/* if ( size < 3 ) + return; + + for ( i = 0; i < 4; i++ ) + { + for ( t = 0; t < 3; t++ ) + vel[t] = ( dir[t] + crandom() * 0.9 ) * ( random() * 100 + 250 ); + + VectorScale( vel, -2.2, accel ); + FX_AddSprite( hitpos, vel, qfalse, random() * 8 + 8, 0, 1.0, 0.0, 0.0, 0.0, 200, cgs.media.purpleParticleShader ); + + }*/ + trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, weaponInfo->mainHitSound ); +} + +void FX_DisruptorBeamFire( vec3_t startpos, vec3_t endpos, vec3_t normal, qboolean spark, qboolean impact, qboolean empty ) +{ + refEntity_t beam; + sfxHandle_t sfx; + float size; + vec3_t velocity; + int sparks; + vec3_t rgb = { 1,0.9,0.6}, rgb2={1,0.3,0}; + + //vec3_t rgb3 = { 1.0, 1.0, 1.0 }; + + sfx = 0; + + // Draw beam first. + memset( &beam, 0, sizeof( beam ) ); + + VectorCopy( startpos, beam.origin); + VectorCopy( endpos, beam.oldorigin ); + beam.reType = RT_LINE; + if (empty) + { + beam.customShader = cgs.media.phaserEmptyShader; + } + else + { + beam.customShader = cgs.media.disruptorBeam; + } + AxisClear( beam.axis ); + beam.shaderRGBA[0] = 0xff; + beam.shaderRGBA[1] = 0xff; + beam.shaderRGBA[2] = 0xff; + beam.shaderRGBA[3] = 0xff; + if (empty) + { + beam.data.line.width = 1.0f + ( crandom() * 0.6f ); + } + else + { + beam.data.line.width = 1.5f + ( crandom() * 0.6f ); + } + beam.data.line.stscale = 5.0; + trap_R_AddRefEntityToScene( &beam ); + + // Now draw the hit graphic + + // no explosion at LG impact, it is added with the beam + + if ( sfx ) + { + Com_Printf("playing %s\n", "phaser sound"); + trap_S_StartSound( endpos, ENTITYNUM_WORLD, CHAN_AUTO, sfx ); + } + + // + // impact mark + // + if (impact) + { + if (!empty) + { // normal. + CG_ImpactMark( cgs.media.scavMarkShader, endpos, normal, random()*360, 1,1,1,0.2, qfalse, + random() + 1, qfalse ); + + //VectorCopy( endpos, phaserFlare.worldCoord ); + + /*CG_InitLensFlare( endpos, + 80, + 80, + rgb, + 1.2, + 1.5, + 1600, + 200, + colorTable[CT_BLACK], + 1600, + 200, + 80, + 5, + qfalse, + 5, + 40, + qfalse, + qfalse, + qfalse, + 1.0, + 1.0, + 200.0, + 200.0, + 200.0 );*/ + + //CG_InitLensFlare( endpos, + // 30, 30, + // rgb, 1.2, 2.0, 1600, 200, + // colorTable[CT_BLACK], 1600, 200, 410, 15, qfalse, + // 0, 0, qfalse, qtrue, + // qfalse, 1.0, cg.time, 0, 0, 50); + + //TiM : Add your basic cheesy 'seen-way-too-much-in-movies-these-days' anamorphic lens streak :) + //CG_DrawLensFlare( &phaserFlare ); + //FX_AddSprite( endpos, NULL, qfalse, random() * 1.25 + 5.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 50.0, cgs.media.blueParticleStreakShader ); //1.5f + + //FX_AddQuad2( endpos, normal, random() * 1.25 + 8.0f, 0.0f, 1.0f, 1.0f, rgb3, rgb3, 270, 50.0, cgs.media.blueParticleStreakShader ); + //eh... looked bad :P + + FX_AddQuad2( endpos, normal, random() * 1.25 + 1.5f, 0.0f, 1.0f, 0.0f, rgb, rgb2, rand() % 360, 500 + random() * 200, + cgs.media.sunnyFlareShader ); + } + else + { // Wuss hit when empty. + FX_AddQuad2( endpos, normal, random() * .75 + 1.0f, 0.0f, 0.5f, 0.0f, rgb, rgb2, rand() % 360, 300 + random() * 200, + cgs.media.sunnyFlareShader ); + } + } + + // "Fun" sparks... Not when empty. + if ( spark && !empty) + { + sparks = (rand() & 1) + 1; + for(;sparks>0;sparks--) + { + size = 0.2f + (random() * 0.4); + FXE_Spray( normal, 200, 75, 0.8f, velocity); + if (rand() & LEF_USE_COLLISION) + { // This spark bounces. + FX_AddTrail( endpos, velocity, qtrue, 5.0f, -15.0f, + size, -size, 1.0f, 0.5f, 0.4f, 500.0f, cgs.media.sparkShader); + } + else + { + FX_AddTrail( endpos, velocity, qtrue, 5.0f, -15.0f, + size, -size, 1.0f, 0.5f, 0.0, 500.0f, cgs.media.sparkShader); + } + } + } +} diff --git a/code/cgame/fx_grenade.c b/code/cgame/fx_grenade.c new file mode 100644 index 0000000..023b5eb --- /dev/null +++ b/code/cgame/fx_grenade.c @@ -0,0 +1,350 @@ +#include "cg_local.h" +#include "fx_local.h" + + +/* +------------------------- +FX_GrenadeThink +------------------------- +*/ + +void FX_GrenadeThink( centity_t *cent, const struct weaponInfo_s *weapon ) +{ + FX_AddSprite( cent->lerpOrigin, NULL, qfalse, 8.0f + random() * 32.0f, 0.0f, 0.75f, 0.75f, 0, 0.0f, 1, cgs.media.dkorangeParticleShader ); + if ( rand() & 1 ) + FX_AddSprite( cent->lerpOrigin, NULL, qfalse, 16.0f + random() * 32.0f, 0.0f, 0.6f, 0.6f, 0, 0.0f, 1, cgs.media.yellowParticleShader ); +} + +/* +------------------------- +FX_GrenadeHitWall +------------------------- +*/ + +void FX_GrenadeHitWall( vec3_t origin, vec3_t normal ) +{ + trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.grenadeExplodeSound ); + CG_SurfaceExplosion( origin, normal, 8, 1, qfalse ); +} + +/* +------------------------- +FX_GrenadeHitPlayer +------------------------- +*/ + +void FX_GrenadeHitPlayer( vec3_t origin, vec3_t normal ) +{ + trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.grenadeExplodeSound ); + CG_SurfaceExplosion( origin, normal, 8, 1, qfalse ); +} + +/* +------------------------- +FX_GrenadeExplode +------------------------- +*/ + +void FX_GrenadeExplode( vec3_t origin, vec3_t normal ) +{ + localEntity_t *le; + qhandle_t null = 0; + vec3_t direction, org, vel; + int i; + + VectorSet( direction, 0,0,1 ); + + // Add an explosion and tag a light to it + le = CG_MakeExplosion2( origin, direction, cgs.media.nukeModel, 5, null, 250, qfalse, 25.0f, LEF_FADE_RGB); + le->light = 150; + le->refEntity.renderfx |= RF_NOSHADOW; + + VectorSet( le->lightColor, 1.0f, 0.6f, 0.2f ); + + // Ground ring + FX_AddQuad( origin, normal, 5, 100, 1.0, 0.0, random() * 360, 300, cgs.media.bigShockShader ); + // Flare + VectorMA( origin, 12, direction, org ); + FX_AddSprite( org, NULL, qfalse, 160.0, -160.0, 1.0, 0.0, 0.0, 0.0, 200, cgs.media.sunnyFlareShader );//, FXF_NON_LINEAR_FADE ); + + for (i = 0; i < 12; i++) + { + float width, length; + FXE_Spray( normal, 470, 325, 0.5f, vel); + length = 24.0 + random() * 12; + width = 0.5 + random() * 2; + FX_AddTrail( origin, vel, qtrue, length, -length, width, -width, + 1.0f, 1.0f, 0.5f, 1000.0f, cgs.media.orangeTrailShader); + } + + trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.grenadeExplodeSound ); + + // Smoke and impact +// FX_AddSpawner( origin, normal, NULL, NULL, 100, 25.0f, 2000.0f, (void *) CG_SmokeSpawn, NULL, 1024 ); + CG_ImpactMark( cgs.media.compressionMarkShader, origin, normal, random()*360, 1,1,1,1.0, qfalse, + random() * 16 + 48, qfalse ); +} + + +/*void FX_GrenadeShrapnelExplode( vec3_t origin, vec3_t norm ) +{ + localEntity_t *le; + vec3_t direction, org, vel; + int i; + + VectorCopy( norm, direction); + + // Add an explosion and tag a light to it + le = CG_MakeExplosion2( origin, direction, cgs.media.nukeModel, 5, (qhandle_t)NULL, 250, qfalse, 25.0f, LEF_FADE_RGB); + le->light = 150; + le->refEntity.renderfx |= RF_NOSHADOW; + + VectorSet( le->lightColor, 1.0f, 0.6f, 0.2f ); + + // Ground ring + FX_AddQuad( origin, norm, 5, 100, 1.0, 0.0, random() * 360, 300, cgs.media.bigShockShader ); + // Flare + VectorMA( origin, 12, direction, org ); + FX_AddSprite( org, NULL, qfalse, 160.0, -160.0, 1.0, 0.0, 0.0, 0.0, 200, cgs.media.sunnyFlareShader );//, FXF_NON_LINEAR_FADE ); + + for (i = 0; i < 12; i++) + { + float width, length; + FXE_Spray( norm, 470, 325, 0.5f, vel); + length = 24.0 + random() * 12; + width = 0.5 + random() * 2; + FX_AddTrail( origin, vel, qtrue, length, -length, width, -width, + 1.0f, 1.0f, 0.5f, 1000.0f, cgs.media.orangeTrailShader); + } + + trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.grenadeExnull + // Smoke and impact + CG_ImpactMark( cgs.media.compressionMarkShader, origin, norm, random()*360, 1,1,1,1.0, qfalse, + random() * 16 + 48, qfalse ); +}*/ + +//----------------------------------- +//By: RedTechie - Imported/Modifyed from SP +//----------------------------------- +void FX_GrenadeShrapnelExplode( vec3_t origin, vec3_t norm ) +{ + localEntity_t *le; + //FXTrail *fx; + vec3_t direction, org, vel; + int i; + + CG_InitLensFlare( origin, + 350, 350, + colorTable[CT_DKRED1], 1.2, 2.0, 1600, 200, + colorTable[CT_DKRED1], 1600, 200, 800, 20, qtrue, + 0, 0, qfalse, qtrue, + qfalse, 1.0, cg.time, 90, 0, 300); + + //Orient the explosions to face the camera + VectorSubtract( cg.refdef.vieworg, origin, direction ); + VectorNormalize( direction ); + + VectorMA( origin, 12, direction, org ); + // Add an explosion and tag a light to it + le = CG_MakeExplosion2( org, direction, cgs.media.explosionModel, 6, cgs.media.surfaceExplosionShader, 700, qfalse, 1.2f + (random()*0.5f),LEF_FADE_RGB ); //RPG-X: RedTechie - Scale use to be 1.2f + (random()*0.3f) + le->light = 150; + le->refEntity.renderfx |= RF_NOSHADOW; + VectorSet( le->lightColor, 1.0f, 0.6f, 0.6f ); + + VectorMA( org, 8, norm, direction ); + VectorSet(vel, 0, 0, 8); + //Some smoke + FX_AddSprite( direction, + vel, + qfalse, + 20.0f + random()*50.0f,//1.2f + (random()*0.5f),//60.0f - random()*60.0f + 16.0f, + 100.0f,//1.0f + 100.0f,//0.0f + random()*45.0f, + -12.0f, + 8000.0f, + cgs.media.steamShader ); + + + for ( i = 0; i < 6; i++) + { + float width, length; + FXE_Spray( norm, 500, 175, 0.8f, vel);//, (FXPrimitive *) fx + length = 24.0 + random() * 12; + width = 0.5 + random() * 2; + FX_AddTrail( origin, vel, qtrue, length, -length, width, -width, + 1.0f, 1.0f, 0.5f, 2500.0f, cgs.media.orangeTrailShader);//RPG-X: RedTechie - Killtime use to be 1000.0f + + /*FX_AddTrail( origin, NULL, NULL, 16.0f, -15.0f, + 1.5, -1.5, 1.0f, 1.0f, 0.2f, 1000.0f, cgs.media.orangeTrailShader, rand() & FXF_BOUNCE ); +*/ + /*if ( fx == NULL ) + return;*/ + + + } + + trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.grenadeAltExplodeSnd ); + + CG_ImpactMark( cgs.media.compressionMarkShader, origin, norm, random()*360, 1,1,1,1.0, qfalse, + random() * 16 + 48, qfalse ); + + CG_ExplosionEffects( origin, 2.0, 350 ); +} + +qboolean GrenadeBeep(localEntity_t *le) +{ + weaponInfo_t *weaponInfo = &cg_weapons[WP_8]; + + trap_S_StartSound(le->refEntity.origin, ENTITYNUM_WORLD, CHAN_AUTO, weaponInfo->altHitSound); + return qtrue; +} + +/* +------------------------- +FX_GrenadeShrapnelBits +By: RedTechie - From SP +------------------------- +*/ + +/*void FX_BlowBits( vec3_t start, vec3_t end, vec3_t dir, vec3_t user ) +{ + vec3_t diff, org; + float len; +// FXLine *fx; + + VectorSubtract( end, start, diff ); + len = VectorNormalize( diff ) * ( 0.2 + random() * 0.3 ); + VectorMA( start, len, diff, org ); + + //fx = + FX_AddLine( end, start, (int)(random() * 3.2f), 2.0f + random() * 2, 0, 0.5f, 0.1f, 150 + random() * 150, cgs.media.orangeTrailShader ); + + //if ( fx == NULL ) + // return; + + //fx->SetFlags( FXF_SHRINK ); + + FX_AddQuad( end, dir, NULL, NULL, 1.0f, 64.0f, 1.0, 0.0, random() * 360.0f, 0.0f, 0.0, 200, cgs.media.orangeRingShader ); + // FX_AddQuad( end, dir, NULL, NULL, 20.0, -15.0, 0.6, 0.4, 0.0,0.0,0.0,450, cgs.media.borgEyeFlareShader ); +} +*/ +#define FX_GRENADE_ALT_STICK_TIME 2500 +void FX_GrenadeShrapnelBits( vec3_t start ) +{ + vec3_t zero = {0, 0, 0}; + // check G_MissileStick() to make sure this killtime coincides with that nextthink + FX_AddSpawner( start, zero, NULL, NULL, qfalse, 300, + 0, FX_GRENADE_ALT_STICK_TIME, GrenadeBeep, 10 ); +} + + +/* +------------------------- +FX_fxfunc_Explosion +------------------------- +*/ +void FX_fxfunc_Explosion( vec3_t start, vec3_t origin, vec3_t normal ) +{ + localEntity_t *le; + vec3_t dir; + vec3_t velocity; +// vec3_t end; +// trace_t trace; + float scale, dscale; + int i, j, numSparks; + //weaponInfo_t *weaponInfo = &cg_weapons[WP_6]; + //float scale, dscale; +// int s; +// vec3_t new_org; + + //Sparks + numSparks = 20 + (random() * 4.0f);//4 + + for ( i = 0; i < numSparks; i++ ) + { + scale = 0.25f + (random() * 1.0f); + dscale = -scale; + + //Randomize the direction + for (j = 0; j < 3; j ++ ) + { + dir[j] = normal[j] + (0.75 * crandom()); + } + + VectorNormalize(dir); + + //set the speed + VectorScale( dir, 200 + (50 * crandom()), velocity); + + le = FX_AddTrail( origin, + velocity, + qtrue, + 4.0f, + -4.0f, + scale, + -scale, + 1.0f, + 1.0f, + 0.5f, + 1000.0f, + cgs.media.sparkShader); + + } + + VectorMA( origin, 8, normal, dir ); + VectorSet(velocity, 0, 0, 8); + + // Smoke puffs + FX_AddSprite( dir, + velocity, + qfalse, + 20.0f + random()*60.0f,//2.2f + ( crandom() * 0.9f),//60.0f - random()*60.0f + 16.0f, + 100.0f,//1.0f + 100.0f,//0.0f + random()*45.0f, + -12.0f, + 8000.0f, + cgs.media.steamShader ); + + //Orient the explosions to face the camera + VectorSubtract( cg.refdef.vieworg, origin, dir ); + VectorNormalize( dir ); + + le = CG_MakeExplosion2( origin, dir, cgs.media.explosionModel, 5, cgs.media.electricalExplosionSlowShader, 475, qfalse, 2.2f + ( crandom() * 0.9f), LEF_NONE);//RPG-X: RedTechie - Scale use to be - 1.2f + ( crandom() * 0.3f) + le->light = 150; + le->refEntity.renderfx |= RF_NOSHADOW; + VectorSet( le->lightColor, 0.8f, 0.8f, 1.0f ); + + CG_ImpactMark( cgs.media.compressionMarkShader, origin, normal, random()*360, 1,1,1,1.0, qfalse, + random() * 16 + 48, qfalse ); + //CG_ImpactMark( cgs.media.compressionMarkShader, origin, normal, random()*360, 1,1,1,1, qfalse, 12, qfalse ); + + //Shake the camera + CG_ExplosionEffects( origin, 2, 400 ); + + // nice explosion sound at the point of impact + trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.grenadeAltExplodeSnd ); + //trap_S_StartSound(origin, ENTITYNUM_WORLD, CHAN_AUTO, weaponInfo->mainHitSound); +} + + +/* +------------------------- +FX_fxfunc_Shot +------------------------- +*/ +#define MAXRANGE_CRIFLE 8192 +void FX_fxfunc_Shot( vec3_t start, vec3_t dir ) +{ + vec3_t end; + trace_t trace; + + VectorMA(start, MAXRANGE_CRIFLE, dir, end); + CG_Trace( &trace, start, NULL, NULL, end, 0, MASK_SHOT ); + + //FX_CompressionExplosion(start, trace.endpos, trace.plane.normal, qfalse ); + FX_fxfunc_Explosion(start, trace.endpos, trace.plane.normal); +} diff --git a/code/cgame/fx_hypospray.c b/code/cgame/fx_hypospray.c new file mode 100644 index 0000000..3de557d --- /dev/null +++ b/code/cgame/fx_hypospray.c @@ -0,0 +1,59 @@ +#include "cg_local.h" +#include "fx_local.h" + + +/* +------------------------- +FX_HypoSpray +Redtechie: RPG-X Added +FIXME! FIXME! FIXME! FIXME! Im not spraying in the direction some one shoots me! +TiM: Fixed! An improperly formatted directional vector was being sent. it's all good now :) +------------------------- +*/ + +#define NUM_HYPO_PUFFS 20 + +void FX_HypoSpray( vec3_t origin, vec3_t dir, qboolean red ) // When not red, it'll be blue +{ + vec3_t color, vel, accel, angles, work; + float scale, dscale; + int i; + localEntity_t *le; + + vectoangles( dir, angles ); + + for ( i = 0; i < NUM_HYPO_PUFFS; i++ ) + { + if ( red ) + { + VectorSet( color, 1.0f, random() * 0.4f, random() * 0.4f ); // mostly red + } + else + { + VectorSet( color, random() * 0.5f, random() * 0.5f + 0.5f, 1.0f ); // mostly blue + } + + VectorCopy( angles, work ); + + work[0] += crandom() * 12.0f; + work[1] += crandom() * 12.0f; + + AngleVectors( work, vel, NULL, NULL ); + + scale = random() * 256.0f + 128.0f; + + VectorScale( vel, scale, vel ); + VectorScale( vel, random() * -0.3f, accel ); + + scale = random() * 4.0f + 2.0f; + dscale = random() * 64.0f + 24.0f; + + //localEntity_t *FX_AddSprite(vec3_t origin, vec3_t velocity, qboolean gravity, float scale, float dscale, + // float startalpha, float endalpha, float roll, float elasticity, + // float killTime, qhandle_t shader); + + le = FX_AddSprite( origin, vel, qfalse, scale, dscale, 0.8f + random() * 0.2f, 0.0f, crandom() * 50, /*crandom() * 5*/0, 1000, cgs.media.steamShader ); + VectorSet(le->data.sprite.startRGB, random() * 0.5f, random() * 0.5f + 0.5f, 1.0f );// mostly blue + } +} + diff --git a/code/cgame/fx_item.c b/code/cgame/fx_item.c new file mode 100644 index 0000000..56f3adf --- /dev/null +++ b/code/cgame/fx_item.c @@ -0,0 +1,306 @@ +#include "cg_local.h" +#include "fx_local.h" + + + +// +// detpack +// + +#define NUM_RING_SHADERS 6 + +qboolean DetpackAftereffect(localEntity_t *le) +{ + localEntity_t *cyl = NULL; + qhandle_t shader = cgs.media.phaserShader; + qhandle_t slowRingShaders[NUM_RING_SHADERS]; + float percentLife = 1.0 - (le->endTime - cg.time)*le->lifeRate; + float alpha = 0.6 - (0.6*percentLife*percentLife); + // data for shell + float shellLife = percentLife + .2; + float height1 = 20 + (percentLife * 150); + float height2 =(50*percentLife); + float scale1 = 40 + (percentLife * 1500); + float scale2 = 20 + (percentLife * 1200); + // data for flat energy rings + float ringLife = percentLife + .5; + float scale3 = 200 + (percentLife * 3400); + float scale4 = 100 + (percentLife * 3000); + float scale5 = 20 + (percentLife * 1000); + float scale6 = 10 + (percentLife * 200); + float ringAlpha = 0.6 - (0.6*ringLife*ringLife); + vec3_t up = {0,0,1},origin1; + + + slowRingShaders[0] = cgs.media.testDetpackRingShader1; + slowRingShaders[1] = cgs.media.testDetpackRingShader2; + slowRingShaders[2] = cgs.media.testDetpackRingShader3; + slowRingShaders[3] = cgs.media.testDetpackRingShader4; + slowRingShaders[4] = cgs.media.testDetpackRingShader5; + slowRingShaders[5] = cgs.media.testDetpackRingShader6; + + // slower, inner ring + VectorCopy(le->refEntity.origin, origin1); + if (NUM_RING_SHADERS == le->data.spawner.data1) + { + le->data.spawner.data1 = 0; + } + else if (le->data.spawner.data1 < 0) + { + le->data.spawner.data1 = 0; + } + shader = slowRingShaders[le->data.spawner.data1++]; + // fast, outer ring + cyl = FX_AddCylinder( origin1, + up, + 0.1,// height, + 0,// dheight, + scale5,// scale, + 0,// dscale, + scale6,// scale2, + 0,// dscale2, + ringAlpha,// startalpha, + 0.0,// endalpha, + 500,// killTime, + shader, + 15);// bias ); + cyl->leFlags |= LEF_ONE_FRAME; + + if (shellLife <= 1.0f) + { + origin1[2] += height2; + shader = cgs.media.phaserShader; + cyl = FX_AddCylinder( origin1, + up, + height1,// height, + 0,// dheight, + scale1,// scale, + 0,// dscale, + scale2,// scale2, + 0,// dscale2, + alpha,// startalpha, + 0.0,// endalpha, + 500,// killTime, + shader, + 15);// bias ); + cyl->leFlags |= LEF_ONE_FRAME; + + cyl = FX_AddCylinder( le->refEntity.origin, + up, + height2, // height, + 0, // dheight, + scale1, // scale, + 0, // dscale, + scale1, // scale2, + 0, // dscale2, + alpha, // startalpha, + 0.0, // endalpha, + 500, // killTime, + shader, + 15); // bias ); + cyl->leFlags |= LEF_ONE_FRAME; + } + // flat energy wave thingy + if (ringLife <= 1.0f) + { + shader = cgs.media.testDetpackShader3; + VectorCopy(le->refEntity.origin, origin1); + // fast, outer ring + + cyl = FX_AddCylinder( origin1, + up, + 0.1,// height, + 0,// dheight, + scale3,// scale, + 0,// dscale, + scale4,// scale2, + 0,// dscale2, + ringAlpha,// startalpha, + 0.0,// endalpha, + 500,// killTime, + shader, + 15);// bias ); + cyl->leFlags |= LEF_ONE_FRAME; + } + return qtrue; +} + + +void FX_Detpack(vec3_t origin) +{ + localEntity_t *le; + qhandle_t null = 0; + vec3_t direction, org, vel, norm = {0,0,1}; + int i; + + VectorCopy( norm, direction); + + // Add an explosion and tag a light to it + le = CG_MakeExplosion2( origin, direction, cgs.media.nukeModel, 5, null, 250, qfalse, 100.0f, LEF_FADE_RGB); + le->light = 300; + le->refEntity.renderfx |= RF_NOSHADOW; + + VectorSet( le->lightColor, 1.0f, 0.6f, 0.2f ); + + // Ground ring +// FX_AddQuad( origin, norm, 5, 150, 1.0, 0.0, random() * 360, 600, cgs.media.bigShockShader ); + // Flare + VectorMA( origin, 12, direction, org ); + FX_AddSprite( org, NULL, qfalse, 160.0, -160.0, 1.0, 0.0, 0.0, 0.0, 500, cgs.media.sunnyFlareShader );//, FXF_NON_LINEAR_FADE ); + + for (i = 0; i < 12; i++) + { + float width, length; + FXE_Spray( norm, 470, 325, 0.5f, vel); + length = 50.0 + random() * 12; + width = 1.5 + random() * 2; + FX_AddTrail( origin, vel, qtrue, length, -length, width, -width, + 1.0f, 1.0f, 0.5f, 1000.0f, cgs.media.orangeTrailShader); + } + +// trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.detpackExplodeSound ); + + // Smoke and impact + CG_ImpactMark( cgs.media.compressionMarkShader, origin, norm, random()*360, 1,1,1,1.0, qfalse, + random() * 16 + 48, qfalse ); + + // mondo explosion shock wave cloud thing + le = FX_AddSpawner( origin, norm, NULL, NULL, qfalse, 0, + 0, 1500, DetpackAftereffect, 10 ); + le->data.spawner.data1 = 0; + + // shake absolutely _everyone_ + CG_ExplosionEffects(origin, 5.0f, 8092); +} + + +// +// portable shield +// + +//RPG-X ToDo: Modify force field Code Here +void FX_DrawPortableShield(centity_t *cent) +{ + int xaxis, height, posWidth, negWidth, team; // light; + vec3_t start, end, normal; + //vec4_t RGBA; + float halfHeight; + localEntity_t *le; + qhandle_t shader; + + if (cent->currentState.eFlags & EF_NODRAW) + { + return; + } + + // decode the data stored in time2 + //pos = ((cent->currentState.time2 >> 32) & 1); + //vert = ((cent->currentState.time2 >> 31) & 1); + xaxis = ((cent->currentState.time2 >> 30) & 1); //24 + height = ((cent->currentState.time2 >> 20) & 1023); //16 + posWidth = ((cent->currentState.time2 >> 10) & 1023); //8 + negWidth = (cent->currentState.time2 & 1023); + + team = (cent->currentState.otherEntityNum2); + halfHeight = (float)height * .5; + + /*if ( !vert ) + {*/ + VectorCopy(cent->lerpOrigin, start); + VectorCopy(cent->lerpOrigin, end); + start[2] += halfHeight; + end[2] += halfHeight; + + VectorClear(normal); + if (xaxis) // drawing along x-axis + { + start[0] -= negWidth; + end[0] += posWidth; + normal[1] = 1; + } + else + { + start[1] -= negWidth; + end[1] += posWidth; + normal[0] = 1; + } + //} + //else + //{ + // VectorCopy(cent->lerpOrigin, start); + // VectorCopy(cent->lerpOrigin, end); + // if ( xaxis ) { + // start[1] += halfHeight; + // end[1] += halfHeight; + // } + // else + // { + // start[0] += halfHeight; + // end[0] += halfHeight; + // } + + // VectorClear(normal); + // if (xaxis) // drawing along x-axis + // { + // start[0] -= negWidth; + // end[0] += posWidth; + // normal[2] = 1; + // } + // else + // { + // start[1] -= negWidth; + // end[1] += posWidth; + // normal[2] = 1; + // } + //} + // draw a rectangle o' shieldness +/* + if (team == TEAM_RED) + { + if (cent->currentState.eFlags & EF_ITEMPLACEHOLDER) + { // Damaged. + shader = cgs.media.shieldDamageShaderRed; + } + else + { + shader = cgs.media.shieldActivateShaderRed; + } + } + else + {*/ + + //TiM - Show the forcefield when the place flag is active only + //This way, we canhave it flare on events, and invisible the rest of the time + + //tho make sure admins can see it + if((int)cent->currentState.origin2[0] == 1) { + shader = cgs.media.shieldActivateShaderBorg; + } + else if((int)cent->currentState.origin2[0] == 2) { + shader = cgs.media.shieldActivateShaderYellow; + } + else if((int)cent->currentState.origin2[0] == 3) { + shader = cgs.media.shieldActivateShaderRed; + } + else { + shader = cgs.media.shieldActivateShaderBlue; + } + if ( cent->currentState.eFlags & EF_ITEMPLACEHOLDER || cgs.clientinfo[cg.snap->ps.clientNum].isAdmin/*cg.snap->ps.persistant[PERS_CLASS] == PC_ADMIN*/ ) + le = FX_AddOrientedLine(start, end, normal, 1.0f, height, 0.0f, 1.0f, 1.0f, 50.0, shader); + //TiM + //if (cent->currentState.eFlags & EF_ITEMPLACEHOLDER) + //{ // Damaged. + // shader = cgs.media.shieldDamageShaderBlue; + //} + //else + //{ + // shader = cgs.media.shieldActivateShaderBlue; + //} + //- +// } + + //le = FX_AddOrientedLine(start, end, normal, 1.0f, height, 0.0f, 1.0f, 1.0f, 50.0, shader); +// le->leFlags |= LEF_ONE_FRAME; +} + + diff --git a/code/cgame/fx_lib.c b/code/cgame/fx_lib.c new file mode 100644 index 0000000..d2d5a41 --- /dev/null +++ b/code/cgame/fx_lib.c @@ -0,0 +1,1170 @@ +// FX Library + +#include "cg_local.h" + +void FXE_Spray (vec3_t direction, float speed, float variation, float cone, vec3_t velocity) +{ + vec3_t dir; + int i; + + //Randomize the direction + for (i = 0; i < 3; i ++ ) + { + dir[i] = direction[i] + (cone * crandom()); + } + + VectorNormalize(dir); + + //set the speed + VectorScale( dir, speed + (variation * crandom()), velocity); +} + + + +localEntity_t *FX_AddLine(vec3_t start, vec3_t end, float stScale, float scale, float dscale, float startalpha, float endalpha, float killTime, qhandle_t shader) +{ + localEntity_t *le; + +#ifdef _DEBUG + if (!shader) + { + Com_Printf("FX_AddLine: NULL shader\n"); + } +#endif + + le = CG_AllocLocalEntity(); + le->leType = LE_LINE; + + le->startTime = cg.time; + le->endTime = le->startTime + killTime; + le->data.line.width = scale; + le->data.line.dwidth = dscale; + + le->alpha = startalpha; + le->dalpha = endalpha - startalpha; + + le->refEntity.data.line.stscale = stScale; + le->refEntity.data.line.width = scale; + + le->refEntity.customShader = shader; + + // set origin + VectorCopy ( start, le->refEntity.origin); + VectorCopy ( end, le->refEntity.oldorigin ); + + AxisClear(le->refEntity.axis); + le->refEntity.shaderRGBA[0] = 0xff; + le->refEntity.shaderRGBA[1] = 0xff; + le->refEntity.shaderRGBA[2] = 0xff; + le->refEntity.shaderRGBA[3] = 0xff; + + le->color[0] = 1.0; + le->color[1] = 1.0; + le->color[2] = 1.0; + le->color[3] = 1.0; + le->lifeRate = 1.0 / ( le->endTime - le->startTime ); + + return(le); +} + + + +localEntity_t *FX_AddLine2(vec3_t start, vec3_t end, float stScale, float width1, float dwidth1, float width2, float dwidth2, + float startalpha, float endalpha, vec3_t startRGB, vec3_t endRGB, float killTime, qhandle_t shader) +{ + localEntity_t *le; + +#ifdef _DEBUG + if (!shader) + { + Com_Printf("FX_AddLine2: NULL shader\n"); + } +#endif + + le = CG_AllocLocalEntity(); + le->leType = LE_LINE2; + + le->startTime = cg.time; + le->endTime = le->startTime + killTime; + le->data.line2.width = width1; + le->data.line2.dwidth = dwidth1; + le->data.line2.width2 = width2; + le->data.line2.dwidth2 = dwidth2; + + le->alpha = startalpha; + le->dalpha = endalpha - startalpha; + VectorCopy(startRGB, le->data.line2.startRGB); + VectorSubtract(endRGB, startRGB, le->data.line2.dRGB); + + le->refEntity.data.line.stscale = stScale; + le->refEntity.data.line.width = width1; + le->refEntity.data.line.width2 = width2; + + le->refEntity.customShader = shader; + + // set origin + VectorCopy ( start, le->refEntity.origin); + VectorCopy ( end, le->refEntity.oldorigin ); + + AxisClear(le->refEntity.axis); + le->refEntity.shaderRGBA[0] = 0xff; + le->refEntity.shaderRGBA[1] = 0xff; + le->refEntity.shaderRGBA[2] = 0xff; + le->refEntity.shaderRGBA[3] = 0xff; + + le->color[0] = startRGB[0]; + le->color[1] = startRGB[1]; + le->color[2] = startRGB[2]; + le->color[3] = startalpha; + le->lifeRate = 1.0 / ( le->endTime - le->startTime ); + + return(le); +} + + + +localEntity_t *FX_AddLine3(vec3_t start, vec3_t end, float stScale, float scale, float dscale, + float startalpha, float endalpha, vec3_t startRGB, vec3_t endRGB, float killTime, qhandle_t shader) +{ + localEntity_t *le; + +#ifdef _DEBUG + if (!shader) + { + Com_Printf("FX_AddLine2: NULL shader\n"); + } +#endif + + le = CG_AllocLocalEntity(); + le->leType = LE_LINE2; + + le->startTime = cg.time; + le->endTime = le->startTime + killTime; + le->data.line.width = scale; + le->data.line.dwidth = dscale; + + le->alpha = startalpha; + le->dalpha = endalpha - startalpha; + VectorCopy(startRGB, le->data.line2.startRGB); + VectorSubtract(endRGB, startRGB, le->data.line2.dRGB); + + le->refEntity.data.line.stscale = stScale; + le->refEntity.data.line.width = scale; + + le->refEntity.customShader = shader; + + // set origin + VectorCopy ( start, le->refEntity.origin); + VectorCopy ( end, le->refEntity.oldorigin ); + + AxisClear(le->refEntity.axis); + le->refEntity.shaderRGBA[0] = 0xff; + le->refEntity.shaderRGBA[1] = 0xff; + le->refEntity.shaderRGBA[2] = 0xff; + le->refEntity.shaderRGBA[3] = 0xff; + + le->color[0] = startRGB[0]; + le->color[1] = startRGB[1]; + le->color[2] = startRGB[2]; + le->color[3] = startalpha; + le->lifeRate = 1.0 / ( le->endTime - le->startTime ); + + return(le); +} + +localEntity_t *FX_AddOrientedLine(vec3_t start, vec3_t end, vec3_t normal, float stScale, float scale, + float dscale, float startalpha, float endalpha, float killTime, qhandle_t shader) +{ + localEntity_t *le; + +#ifdef _DEBUG + if (!shader) + { + Com_Printf("FX_AddLine: NULL shader\n"); + } +#endif + + le = CG_AllocLocalEntity(); + le->leType = LE_OLINE; + + le->startTime = cg.time; + le->endTime = le->startTime + killTime; + le->data.line.width = scale; + le->data.line.dwidth = dscale; + + le->alpha = startalpha; + le->dalpha = endalpha - startalpha; + + le->refEntity.data.line.stscale = stScale; + le->refEntity.data.line.width = scale; + + le->refEntity.customShader = shader; + + // set origin + VectorCopy ( start, le->refEntity.origin); + VectorCopy ( end, le->refEntity.oldorigin ); + + AxisClear(le->refEntity.axis); + VectorCopy( normal, le->refEntity.axis[0] ); + RotateAroundDirection( le->refEntity.axis, 0); // le->refEntity.data.sprite.rotation ); This is roll in quad land + + le->refEntity.shaderRGBA[0] = 0xff; + le->refEntity.shaderRGBA[1] = 0xff; + le->refEntity.shaderRGBA[2] = 0xff; + le->refEntity.shaderRGBA[3] = 0xff; + + le->color[0] = 1.0; + le->color[1] = 1.0; + le->color[2] = 1.0; + le->color[3] = 1.0; + le->lifeRate = 1.0 / ( le->endTime - le->startTime ); + + return(le); +} + +localEntity_t *FX_AddTrail( vec3_t origin, vec3_t velocity, qboolean gravity, float length, float dlength, + float scale, float dscale, float startalpha, float endalpha, + float elasticity, float killTime, qhandle_t shader) +{ + localEntity_t *le; + +#ifdef _DEBUG + if (!shader) + { + Com_Printf("FX_AddTrail: NULL shader\n"); + } +#endif + + le = CG_AllocLocalEntity(); + le->leType = LE_TRAIL; + + le->startTime = cg.time; + le->endTime = le->startTime + killTime; + + le->data.trail.width = scale; + le->data.trail.dwidth = dscale; + le->data.trail.length = length; + le->data.trail.dlength = dlength; + + le->alpha = startalpha; + le->dalpha = endalpha - startalpha; + VectorSet(le->data.trail.startRGB, 1, 1, 1); + VectorSet(le->data.trail.dRGB, 0, 0, 0); + + le->refEntity.data.line.stscale = 1.0; + le->refEntity.data.line.width = scale; + + le->refEntity.customShader = shader; + + // set origin + VectorCopy ( origin, le->refEntity.origin); + // kef -- extrapolate oldorigin based on length of trail and origin? + if (velocity) + { + vec3_t vel; + VectorNormalize2(velocity, vel); + VectorMA(origin, -length, vel, le->refEntity.oldorigin); + } + else + { + VectorCopy ( origin, le->refEntity.oldorigin ); + } + + AxisClear(le->refEntity.axis); + le->refEntity.shaderRGBA[0] = 0xff; + le->refEntity.shaderRGBA[1] = 0xff; + le->refEntity.shaderRGBA[2] = 0xff; + le->refEntity.shaderRGBA[3] = 0xff*startalpha; + + le->color[0] = 1.0; + le->color[1] = 1.0; + le->color[2] = 1.0; + le->color[3] = 1.0; + le->lifeRate = 1.0 / ( le->endTime - le->startTime ); + + if (velocity) + { + le->leFlags |= LEF_MOVE; + VectorCopy (origin, le->pos.trBase); + VectorCopy (velocity, le->pos.trDelta); + if (gravity) + le->pos.trType = TR_GRAVITY; + else + le->pos.trType = TR_LINEAR; + le->pos.trTime = cg.time; + le->pos.trDuration = killTime; + + if (elasticity > 0) + { + le->leFlags |= LEF_USE_COLLISION; + le->bounceFactor = elasticity; + } + } + + return(le); +} + + + +localEntity_t *FX_AddTrail2( vec3_t origin, vec3_t velocity, qboolean gravity, float length, float dlength, + float scale, float dscale, float startalpha, float endalpha, vec3_t startRGB, vec3_t endRGB, + float elasticity, float killTime, qhandle_t shader) +{ + localEntity_t *le; + +#ifdef _DEBUG + if (!shader) + { + Com_Printf("FX_AddTrail: NULL shader\n"); + } +#endif + + le = CG_AllocLocalEntity(); + le->leType = LE_TRAIL; + + le->startTime = cg.time; + le->endTime = le->startTime + killTime; + + le->data.trail.width = scale; + le->data.trail.dwidth = dscale; + le->data.trail.length = length; + le->data.trail.dlength = dlength; + + le->alpha = startalpha; + le->dalpha = endalpha - startalpha; + VectorCopy(startRGB, le->data.trail.startRGB); + VectorSubtract(endRGB, startRGB, le->data.trail.dRGB); + + le->refEntity.data.line.stscale = 1.0; + le->refEntity.data.line.width = scale; + + le->refEntity.customShader = shader; + + // set origin + VectorCopy ( origin, le->refEntity.origin); + // kef -- extrapolate oldorigin based on length of trail and origin? + if (velocity) + { + vec3_t vel; + VectorNormalize2(velocity, vel); + VectorMA(origin, -length, vel, le->refEntity.oldorigin); + } + else + { + VectorCopy ( origin, le->refEntity.oldorigin ); + } + + AxisClear(le->refEntity.axis); + le->refEntity.shaderRGBA[0] = 0xff*startRGB[0]; + le->refEntity.shaderRGBA[1] = 0xff*startRGB[1]; + le->refEntity.shaderRGBA[2] = 0xff*startRGB[2]; + le->refEntity.shaderRGBA[3] = 0xff*startalpha; + + le->color[0] = 1.0; + le->color[1] = 1.0; + le->color[2] = 1.0; + le->color[3] = 1.0; + le->lifeRate = 1.0 / ( le->endTime - le->startTime ); + + if (velocity) + { + le->leFlags |= LEF_MOVE; + VectorCopy (origin, le->pos.trBase); + VectorCopy (velocity, le->pos.trDelta); + if (gravity) + le->pos.trType = TR_GRAVITY; + else + le->pos.trType = TR_LINEAR; + le->pos.trTime = cg.time; + le->pos.trDuration = killTime; + + if (elasticity > 0) + { + le->leFlags |= LEF_USE_COLLISION; + le->bounceFactor = elasticity; + } + } + + return(le); +} + + +/* +=============== +FX_AddSprite + +Adds a view oriented sprite to the FX wrapper render list +=============== +*/ + +localEntity_t *FX_AddSprite(vec3_t origin, vec3_t velocity, qboolean gravity, float scale, float dscale, + float startalpha, float endalpha, float roll, float elasticity, + float killTime, qhandle_t shader) +{ + localEntity_t *le; + +#ifdef _DEBUG + if (!shader) + { + Com_Printf("FX_AddSprite: NULL shader\n"); + } +#endif + + // Glow mark + + le = CG_AllocLocalEntity(); + le->leType = LE_VIEWSPRITE; + le->refEntity.data.sprite.rotation = roll; + + le->startTime = cg.time; + le->endTime = le->startTime + killTime; + + le->data.sprite.radius = scale; + le->data.sprite.dradius = dscale; + + le->alpha = startalpha; + le->dalpha = endalpha - startalpha; + VectorSet(le->data.sprite.startRGB, 1, 1, 1); + VectorSet(le->data.sprite.dRGB, 0, 0, 0); + +// le->refEntity.hModel = 0; + le->refEntity.customShader = shader; + + // set origin + VectorCopy ( origin, le->refEntity.origin); + VectorCopy ( origin, le->refEntity.oldorigin ); + + le->color[0] = 1.0; + le->color[1] = 1.0; + le->color[2] = 1.0; + le->color[3] = startalpha; + le->lifeRate = 1.0 / ( le->endTime - le->startTime ); + + if (velocity) + { + le->leFlags |= LEF_MOVE; + VectorCopy (origin, le->pos.trBase); + VectorCopy (velocity, le->pos.trDelta); + if (gravity) + le->pos.trType = TR_GRAVITY; + else + le->pos.trType = TR_LINEAR; + le->pos.trTime = cg.time; + le->pos.trDuration = killTime; + + if (elasticity > 0) + { + le->leFlags |= LEF_USE_COLLISION; + le->bounceFactor = elasticity; + } + } + + return(le); +} + + +/* +=============== +FX_AddSprite2 + +Adds a view oriented sprite to the FX wrapper render list +=============== +*/ + +localEntity_t *FX_AddSprite2(vec3_t origin, vec3_t velocity, qboolean gravity, float scale, float dscale, + float startalpha, float endalpha, vec3_t startRGB, vec3_t endRGB, float roll, float elasticity, + float killTime, qhandle_t shader) +{ + localEntity_t *le; + +#ifdef _DEBUG + if (!shader) + { + Com_Printf("FX_AddSprite: NULL shader\n"); + } +#endif + + // Glow mark + + le = CG_AllocLocalEntity(); + le->leType = LE_VIEWSPRITE; + le->refEntity.data.sprite.rotation = roll; + + le->startTime = cg.time; + le->endTime = le->startTime + killTime; + + le->data.sprite.radius = scale; + le->data.sprite.dradius = dscale; + + le->alpha = startalpha; + le->dalpha = endalpha - startalpha; + VectorCopy(startRGB, le->data.sprite.startRGB); + VectorSubtract(endRGB, startRGB, le->data.sprite.dRGB); + +// le->refEntity.hModel = 0; + le->refEntity.customShader = shader; + + // set origin + VectorCopy ( origin, le->refEntity.origin); + VectorCopy ( origin, le->refEntity.oldorigin ); + + le->color[0] = startRGB[0]; + le->color[1] = startRGB[1]; + le->color[2] = startRGB[2]; + le->color[3] = startalpha; + le->lifeRate = 1.0 / ( le->endTime - le->startTime ); + + if (velocity) + { + le->leFlags |= LEF_MOVE; + VectorCopy (origin, le->pos.trBase); + VectorCopy (velocity, le->pos.trDelta); + if (gravity) + le->pos.trType = TR_GRAVITY; + else + le->pos.trType = TR_LINEAR; + le->pos.trTime = cg.time; + le->pos.trDuration = killTime; + + if (elasticity > 0) + { + le->leFlags |= LEF_USE_COLLISION; + le->bounceFactor = elasticity; + } + } + + return(le); +} + + +/* +=============== +FX_AddSprite3 + +Adds a view oriented sprite to the FX wrapper render list +=============== +*/ + +localEntity_t *FX_AddSprite3(vec3_t origin, vec3_t velocity, vec3_t acceleration, float scale, float dscale, + float startalpha, float endalpha, float roll, float elasticity, + float killTime, qhandle_t shader) +{ + localEntity_t *le; + +#ifdef _DEBUG + if (!shader) + { + Com_Printf("FX_AddSprite: NULL shader\n"); + } +#endif + + // Glow mark + + le = CG_AllocLocalEntity(); + le->leType = LE_VIEWSPRITE; + le->refEntity.data.sprite.rotation = roll; + + le->startTime = cg.time; + le->endTime = le->startTime + killTime; + + le->data.sprite.radius = scale; + le->data.sprite.dradius = dscale; + + le->alpha = startalpha; + le->dalpha = endalpha - startalpha; + VectorSet(le->data.sprite.startRGB, 1, 1, 1); + VectorSet(le->data.sprite.dRGB, 0, 0, 0); + +// le->refEntity.hModel = 0; + le->refEntity.customShader = shader; + + // set origin + VectorCopy ( origin, le->refEntity.origin); + VectorCopy ( origin, le->refEntity.oldorigin ); + + le->color[0] = 1.0; + le->color[1] = 1.0; + le->color[2] = 1.0; + le->color[3] = startalpha; + le->lifeRate = 1.0 / ( le->endTime - le->startTime ); + + if (velocity) + { + le->leFlags |= LEF_MOVE; + VectorCopy (origin, le->pos.trBase); + VectorCopy (velocity, le->pos.trDelta); + if (acceleration) //how do i make this accellerate in the given direction?... lol, bee-fountain on forge3 now ^^ + le->pos.trType = TR_GRAVITY; + else + le->pos.trType = TR_LINEAR; + le->pos.trTime = cg.time; + le->pos.trDuration = killTime; + + if (elasticity > 0) + { + le->leFlags |= LEF_USE_COLLISION; + le->bounceFactor = elasticity; + } + } + + return(le); +} + +/* +=============== +FX_AddBezier + +Adds a Bezier curve to the FX wrapper render list +=============== +*/ + +localEntity_t *FX_AddBezier(vec3_t start, vec3_t end, vec3_t cpoint1, vec3_t cpoint2, vec3_t cpointvel1, vec3_t cpointvel2, + vec3_t cpointacc1, vec3_t cpointacc2, float width, float killTime, qhandle_t shader) +{ + localEntity_t *le = CG_AllocLocalEntity(); + +#ifdef _DEBUG + if (!shader) + { + Com_Printf("FX_AddBezier: NULL shader\n"); + } +#endif + + // just testing beziers + le->leType = LE_BEZIER; + + le->startTime = cg.time; + le->endTime = le->startTime + killTime; + le->data.line.width = width; + + le->alpha = 1.0; + le->dalpha = -1.0; + + le->refEntity.customShader = shader; + + // set origin + VectorCopy ( start, le->refEntity.origin); + VectorCopy ( end, le->refEntity.oldorigin ); + + AxisClear(le->refEntity.axis); + le->refEntity.shaderRGBA[0] = 0xff; + le->refEntity.shaderRGBA[1] = 0xff; + le->refEntity.shaderRGBA[2] = 0xff; + le->refEntity.shaderRGBA[3] = 0xff; + + le->color[0] = 1.0; + le->color[1] = 1.0; + le->color[2] = 1.0; + le->color[3] = 1.0; + le->lifeRate = 1.0 / ( le->endTime - le->startTime ); + + if (cpoint1) + { + VectorCopy(cpoint1, le->data.line.control1); + } + if (cpoint2) + { + VectorCopy(cpoint2, le->data.line.control2); + } + if (cpointvel1) + { + VectorCopy(cpointvel1, le->data.line.control1_velocity); + } + if (cpointvel2) + { + VectorCopy(cpointvel2, le->data.line.control2_velocity); + } + if (cpointacc1) + { + VectorCopy(cpointacc1, le->data.line.control1_acceleration); + } + if (cpointacc2) + { + VectorCopy(cpointacc2, le->data.line.control2_acceleration); + } + + return le; +} + +/* +=============== +FX_AddQuad + +Adds a quad to the FX wrapper render list +=============== +*/ + +localEntity_t *FX_AddQuad( vec3_t origin, vec3_t normal, float scale, float dscale, + float startalpha, float endalpha, float roll, float killTime, qhandle_t shader ) +{ + localEntity_t *le = CG_AllocLocalEntity(); + +#ifdef _DEBUG + if (!shader) + { + Com_Printf("FX_AddQuad: NULL shader\n"); + } +#endif + + le->leType = LE_QUAD; + le->refEntity.data.sprite.rotation = roll; + + le->startTime = cg.time; + le->endTime = le->startTime + killTime; + + le->data.sprite.radius = scale; + le->data.sprite.dradius = dscale; + + le->alpha = startalpha; + le->dalpha = endalpha - startalpha; + VectorSet(le->data.sprite.startRGB, 1, 1, 1); + VectorSet(le->data.sprite.dRGB, 0, 0, 0); + +// le->refEntity.hModel = 0; + le->refEntity.customShader = shader; + + // set origin + VectorCopy ( origin, le->refEntity.origin); + VectorCopy ( origin, le->refEntity.oldorigin ); + + VectorCopy( normal, le->refEntity.axis[0] ); + RotateAroundDirection( le->refEntity.axis, le->refEntity.data.sprite.rotation ); + + le->color[0] = 1.0; + le->color[1] = 1.0; + le->color[2] = 1.0; + le->color[3] = startalpha; + le->lifeRate = 1.0 / ( le->endTime - le->startTime ); + + return(le); +} + + + +/* +=============== +FX_AddQuad2 + +Adds a quad to the FX wrapper render list +=============== +*/ + +localEntity_t *FX_AddQuad2( vec3_t origin, vec3_t normal, float scale, float dscale, float startalpha, float endalpha, + vec3_t startRGB, vec3_t endRGB, float roll, float killTime, qhandle_t shader ) +{ + localEntity_t *le = CG_AllocLocalEntity(); + +#ifdef _DEBUG + if (!shader) + { + Com_Printf("FX_AddQuad: NULL shader\n"); + } +#endif + + le->leType = LE_QUAD; + le->refEntity.data.sprite.rotation = roll; + + le->startTime = cg.time; + le->endTime = le->startTime + killTime; + + le->data.sprite.radius = scale; + le->data.sprite.dradius = dscale; + VectorCopy(startRGB, le->data.sprite.startRGB); + VectorSubtract(endRGB, startRGB, le->data.sprite.dRGB); + + le->alpha = startalpha; + le->dalpha = endalpha - startalpha; + +// le->refEntity.hModel = 0; + le->refEntity.customShader = shader; + + // set origin + VectorCopy ( origin, le->refEntity.origin); + VectorCopy ( origin, le->refEntity.oldorigin ); + + VectorCopy( normal, le->refEntity.axis[0] ); + RotateAroundDirection( le->refEntity.axis, le->refEntity.data.sprite.rotation ); + + le->color[0] = startRGB[0]; + le->color[1] = startRGB[1]; + le->color[2] = startRGB[2]; + le->color[3] = startalpha; + le->lifeRate = 1.0 / ( le->endTime - le->startTime ); + + return(le); +} + + + +/* +=============== +FX_AddCylinder + +Adds a cylinder to the FX wrapper render list +=============== +*/ + +//NOTENOTE: The reigning king of parameters! +#define DEFAULT_ST_SCALE 1.0f + +localEntity_t *FX_AddCylinder( vec3_t start, + vec3_t normal, + float height, + float dheight, + float scale, + float dscale, + float scale2, + float dscale2, + float startalpha, + float endalpha, + float killTime, + qhandle_t shader, + float bias ) +{ + localEntity_t *le = CG_AllocLocalEntity(); + +#ifdef _DEBUG + if (!shader) + { + Com_Printf("FX_AddCylinder: NULL shader\n"); + } +#endif + + le->leType = LE_CYLINDER; + le->refEntity.data.cylinder.height = height; + le->refEntity.data.cylinder.width = scale; + le->refEntity.data.cylinder.width2 = scale2; + + le->startTime = cg.time; + le->endTime = le->startTime + killTime; + + le->data.cylinder.height = height; + le->data.cylinder.dheight = dheight; + le->data.cylinder.width = scale; + le->data.cylinder.dwidth = dscale; + le->data.cylinder.width2 = scale2; + le->data.cylinder.dwidth2 = dscale2; + + le->alpha = startalpha; + le->dalpha = endalpha - startalpha; + + le->refEntity.customShader = shader; + + le->refEntity.data.cylinder.bias = bias; + le->refEntity.data.cylinder.stscale = 1.0; + le->refEntity.data.cylinder.wrap = qtrue; + + // set origin + VectorCopy ( start, le->refEntity.origin); + VectorCopy ( start, le->refEntity.oldorigin ); + + VectorCopy( normal, le->refEntity.axis[0] ); + RotateAroundDirection( le->refEntity.axis, 0); + + le->color[0] = 1.0; + le->color[1] = 1.0; + le->color[2] = 1.0; + le->color[3] = startalpha; + le->lifeRate = 1.0 / ( le->endTime - le->startTime ); + + return(le); +} +/* +=============== +FX_AddCylinder2 + +Adds a cylinder to the FX wrapper render list +Overloaded for RGB +=============== +*/ + +//NOTENOTE: The reigning king of parameters! +#define DEFAULT_ST_SCALE 1.0f + +localEntity_t *FX_AddCylinder2( vec3_t start, + vec3_t normal, + float height, + float dheight, + float scale, + float dscale, + float scale2, + float dscale2, + float startalpha, + float endalpha, + vec3_t startRGB, + vec3_t endRGB, + float killTime, + qhandle_t shader, + float bias ) +{ + localEntity_t *le = CG_AllocLocalEntity(); + +#ifdef _DEBUG + if (!shader) + { + Com_Printf("FX_AddCylinder: NULL shader\n"); + } +#endif + + le->leType = LE_CYLINDER; + le->refEntity.data.cylinder.height = height; + le->refEntity.data.cylinder.width = scale; + le->refEntity.data.cylinder.width2 = scale2; + + le->startTime = cg.time; + le->endTime = le->startTime + killTime; + + le->data.cylinder.height = height; + le->data.cylinder.dheight = dheight; + le->data.cylinder.width = scale; + le->data.cylinder.dwidth = dscale; + le->data.cylinder.width2 = scale2; + le->data.cylinder.dwidth2 = dscale2; + + le->alpha = startalpha; + le->dalpha = endalpha - startalpha; + + le->refEntity.customShader = shader; + + le->refEntity.data.cylinder.bias = bias; + le->refEntity.data.cylinder.stscale = 1.0; + le->refEntity.data.cylinder.wrap = qtrue; + + // set origin + VectorCopy ( start, le->refEntity.origin); + VectorCopy ( start, le->refEntity.oldorigin ); + + VectorCopy( normal, le->refEntity.axis[0] ); + RotateAroundDirection( le->refEntity.axis, 0); + + le->color[0] = startRGB[0]; + le->color[1] = startRGB[1]; + le->color[2] = startRGB[2]; + le->color[3] = startalpha; + le->lifeRate = 1.0 / ( le->endTime - le->startTime ); + + return(le); +} + + + +/* +=============== +FX_AddElectricity + +Adds a electricity bolt to the scene +=============== +*/ + +localEntity_t *FX_AddElectricity( vec3_t origin, vec3_t origin2, float stScale, float scale, float dscale, + float startalpha, float endalpha, float killTime, qhandle_t shader, float deviation ) +{ + localEntity_t *le; + +#ifdef _DEBUG + if (!shader) + { + Com_Printf("FX_AddElectricity: NULL shader\n"); + } +#endif + + le = CG_AllocLocalEntity(); + le->leType = LE_ELECTRICITY; + + // set origin + VectorCopy (origin, le->refEntity.origin); + VectorCopy (origin2, le->refEntity.oldorigin ); + + le->refEntity.data.electricity.stscale = stScale; + le->refEntity.data.electricity.deviation = deviation; + le->data.electricity.width = scale; + le->data.electricity.dwidth = dscale; + + le->alpha = startalpha; + le->dalpha = endalpha - startalpha; + + le->startTime = cg.time; + le->endTime = le->startTime + killTime; + + le->refEntity.customShader = shader; + + le->color[0] = 1.0; + le->color[1] = 1.0; + le->color[2] = 1.0; + le->color[3] = startalpha; + + return(le); +} +/* +=============== +FX_AddParticle + +Adds a particle (basically, a sprite with an optional think function) to the FX wrapper render list +=============== +*/ + +localEntity_t *FX_AddParticle( vec3_t origin, vec3_t velocity, qboolean gravity, float scale, float dscale, + float startalpha, float endalpha, float roll, float elasticity, + float killTime, qhandle_t shader, qboolean (*thinkFn)(localEntity_t *le) ) +{ + localEntity_t *le; + +#ifdef _DEBUG + if (!shader) + { + Com_Printf("FX_AddParticle: NULL shader\n"); + } +#endif + + // Glow mark + + le = CG_AllocLocalEntity(); + le->leType = LE_PARTICLE; + le->refEntity.data.sprite.rotation = roll; + + le->startTime = cg.time; + le->endTime = le->startTime + killTime; + + le->data.particle.radius = scale; + le->data.particle.dradius = dscale; + + le->alpha = startalpha; + le->dalpha = endalpha - startalpha; + +// le->refEntity.hModel = 0; + le->refEntity.customShader = shader; + + // set origin + VectorCopy ( origin, le->refEntity.origin); + VectorCopy ( origin, le->refEntity.oldorigin ); + + le->color[0] = 1.0; + le->color[1] = 1.0; + le->color[2] = 1.0; + le->color[3] = startalpha; + le->lifeRate = 1.0 / ( le->endTime - le->startTime ); + + // wacky think function stuff + le->data.particle.thinkFn = thinkFn; + + if (velocity) + { + le->leFlags |= LEF_MOVE; + VectorCopy (origin, le->pos.trBase); + VectorCopy (velocity, le->pos.trDelta); + if (gravity) + le->pos.trType = TR_GRAVITY; + else + le->pos.trType = TR_LINEAR; + le->pos.trTime = cg.time; + le->pos.trDuration = killTime; + + if (elasticity > 0) + { + le->leFlags |= LEF_USE_COLLISION; + le->bounceFactor = elasticity; + } + } + + return(le); +} + +/* +=============== +FX_AddSpawner + +Adds a spawner -- basically, a local entity with a think function. Spawners don't have any rendered entities +associated with them inherently, but the spawner's think fn probably generates them. +=============== +*/ +localEntity_t *FX_AddSpawner( vec3_t origin, vec3_t dir, vec3_t velocity, vec3_t user, qboolean gravity, int delay, + float variance, float killTime, qboolean (*thinkFn)(localEntity_t *le), int radius ) +{ + localEntity_t *le = NULL; + + if (NULL == thinkFn) + { + // a spawner with no think fn is silly. and useless. + return NULL; + } + le = CG_AllocLocalEntity(); + + le->leType = LE_SPAWNER; + + le->data.spawner.data1 = radius; + le->data.spawner.delay = delay; + le->data.spawner.nextthink = cg.time + delay; + le->startTime = cg.time; + // if we want the spawner to hang around forever, we use a killtime of 0 and the think fn keeps adjusting it. + //thing is, we still need it to not get culled right here, so give it an arbitrary endTime somewhere in the future. + if (0 == killTime) + { + le->endTime = le->startTime + 10000; + le->data.spawner.dontDie = qtrue; + } + else + { + le->endTime = le->startTime + killTime; + } + + le->data.spawner.variance = variance; + if(dir) + VectorCopy(dir, le->data.spawner.dir); + // set origin + VectorCopy ( origin, le->refEntity.origin); + VectorCopy ( origin, le->refEntity.oldorigin ); + + // maybe employ the user variable here, like in singleplayer? or in the think fn? + le->color[0] = 1.0; + le->color[1] = 1.0; + le->color[2] = 1.0; + le->color[3] = 1.0; + le->lifeRate = 1.0 / ( le->endTime - le->startTime ); + + // wacky think function stuff + le->data.spawner.thinkFn = thinkFn; + + if (velocity) + { + le->leFlags |= LEF_MOVE; + VectorCopy (origin, le->pos.trBase); + if(velocity) + VectorCopy (velocity, le->pos.trDelta); + if (gravity) + le->pos.trType = TR_GRAVITY; + else + le->pos.trType = TR_LINEAR; + le->pos.trTime = cg.time; + // we better not ever have a spawner with a velocity that we expect to last forever, so just plain + //assigning killTime here _should_ be ok + le->pos.trDuration = killTime; + +// if (elasticity > 0) +// { +// le->leFlags |= LEF_USE_COLLISION; +// le->bounceFactor = elasticity; +// } + } + + return (le); +} + +// provide the center of the circle, a normal out from it (normalized, please), and the radius. +//out will then become a random position on the radius of the circle. +void fxRandCircumferencePos(vec3_t center, vec3_t normal, float radius, vec3_t out) +{ + float rnd = flrandom(0, 2*M_PI); + float s = sin(rnd); + float c = cos(rnd); + vec3_t vTemp, radialX, radialY; + + vTemp[0]=0.57735; + vTemp[1]=0.57735; + vTemp[2]=0.57735; + CrossProduct(normal, vTemp, radialX); + CrossProduct(normal, radialX, radialY); + VectorScale(radialX, radius, radialX); + VectorScale(radialY, radius, radialY); + VectorMA(center, s, radialX, out); + VectorMA(out, c, radialY, out); +} diff --git a/code/cgame/fx_local.h b/code/cgame/fx_local.h new file mode 100644 index 0000000..75ba83d --- /dev/null +++ b/code/cgame/fx_local.h @@ -0,0 +1,180 @@ + +#define DEFAULT_DEVIATION 0.5 + +/* + * fx_*.c + */ + +void FXE_Spray (vec3_t direction, float speed, float variation, float cone, vec3_t velocity); +localEntity_t *FX_AddLine(vec3_t start, vec3_t end, float stScale, float scale, float dscale, + float startalpha, float endalpha, float killTime, qhandle_t shader); +localEntity_t *FX_AddLine2(vec3_t start, vec3_t end, float stScale, float width1, float dwidth1, float width2, float dwidth2, + float startalpha, float endalpha, vec3_t startRGB, vec3_t endRGB, float killTime, qhandle_t shader); +localEntity_t *FX_AddLine3(vec3_t start, vec3_t end, float stScale, float scale, float dscale, + float startalpha, float endalpha, vec3_t startRGB, vec3_t endRGB, float killTime, qhandle_t shader); +localEntity_t *FX_AddOrientedLine(vec3_t start, vec3_t end, vec3_t normal, float stScale, float scale, + float dscale, float startalpha, float endalpha, float killTime, qhandle_t shader); +localEntity_t *FX_AddTrail( vec3_t origin, vec3_t velocity, qboolean gravity, float length, float dlength, + float scale, float dscale, float startalpha, float endalpha, + float elasticity, float killTime, qhandle_t shader); +localEntity_t *FX_AddTrail2( vec3_t origin, vec3_t velocity, qboolean gravity, float length, float dlength, + float scale, float dscale, float startalpha, float endalpha, vec3_t startRGB, vec3_t endRGB, + float elasticity, float killTime, qhandle_t shader); +localEntity_t *FX_AddSprite(vec3_t origin, vec3_t velocity, qboolean gravity, float scale, float dscale, + float startalpha, float endalpha, float roll, float elasticity, + float killTime, qhandle_t shader); +localEntity_t *FX_AddSprite2(vec3_t origin, vec3_t velocity, qboolean gravity, float scale, float dscale, + float startalpha, float endalpha, vec3_t startRGB, vec3_t endRGB, float roll, float elasticity, + float killTime, qhandle_t shader); +localEntity_t *FX_AddSprite3(vec3_t origin, vec3_t velocity, vec3_t acceleration, float scale, float dscale, + float startalpha, float endalpha, float roll, float elasticity, + float killTime, qhandle_t shader); +localEntity_t *FX_AddBezier(vec3_t start, vec3_t end, vec3_t cpoint1, vec3_t cpoint2, vec3_t cpointvel1, + vec3_t cpointvel2,vec3_t cpointacc1, vec3_t cpointacc2, float width, + float killTime, qhandle_t shader); +localEntity_t *FX_AddQuad( vec3_t origin, vec3_t normal, float scale, float dscale, + float startalpha, float endalpha, float roll, float killTime, qhandle_t shader ); +localEntity_t *FX_AddQuad2( vec3_t origin, vec3_t normal, float scale, float dscale, float startalpha, float endalpha, + vec3_t startRGB, vec3_t endRGB, float roll, float killTime, qhandle_t shader ); +localEntity_t *FX_AddCylinder( vec3_t start, + vec3_t normal, + float height, + float dheight, + float scale, + float dscale, + float scale2, + float dscale2, + float startalpha, + float endalpha, + float killTime, + qhandle_t shader, + float bias ); +localEntity_t *FX_AddCylinder2( vec3_t start, + vec3_t normal, + float height, + float dheight, + float scale, + float dscale, + float scale2, + float dscale2, + float startalpha, + float endalpha, + vec3_t startRGB, + vec3_t endRGB, + float killTime, + qhandle_t shader, + float bias ); +localEntity_t *FX_AddCylinder( vec3_t start, + vec3_t normal, + float height, + float dheight, + float scale, + float dscale, + float scale2, + float dscale2, + float startalpha, + float endalpha, + float killTime, + qhandle_t shader, + float bias ); +localEntity_t *FX_AddElectricity( vec3_t origin, vec3_t origin2, float stScale, float scale, float dscale, + float startalpha, float endalpha, float killTime, qhandle_t shader, float deviation ); +localEntity_t *FX_AddParticle( vec3_t origin, vec3_t velocity, qboolean gravity, float scale, float dscale, + float startalpha, float endalpha, float roll, float elasticity, + float killTime, qhandle_t shader, qboolean (*thinkFn)(localEntity_t *le)); + +localEntity_t *FX_AddSpawner( vec3_t origin, vec3_t dir, vec3_t velocity, vec3_t user, qboolean gravity, int delay, + float variance, float killTime, qboolean (*thinkFn)(localEntity_t *le), int radius ); + +/* + * phaser + */ +void FX_PhaserFire( vec3_t start, vec3_t end, vec3_t normal, qboolean spark, qboolean impact, qboolean empty ); +void FX_PhaserAltFire( vec3_t start, vec3_t end, vec3_t normal, qboolean spark, qboolean impact, qboolean empty ); + + +/* + * compression rifle + */ +void FX_CompressionShot( vec3_t start, vec3_t end ); +void FX_CompressionAltShot( vec3_t start, vec3_t end ); +void FX_CompressionExplosion( vec3_t start, vec3_t origin, vec3_t normal, qboolean altfire ); +void FX_CompressionHit( vec3_t origin ); +void FX_PrifleBeamFire( vec3_t startpos, vec3_t endpos, vec3_t normal, qboolean spark, qboolean impact, qboolean empty ); + +void FX_ProbeBeam( vec3_t origin, vec3_t dir, int clientNum, qboolean alt_fire ); +void FX_RegenBeam( vec3_t origin, vec3_t dir, int clientNum, qboolean alt_fire ); + +/* + * tetrion disruptor + */ +void FX_TetrionShot( vec3_t start, vec3_t forward ); + +/* + * Scavenger Rifle + */ +void FX_HypoSpray( vec3_t origin, vec3_t dir, qboolean red ); + +/* + * Grenade launcher + */ +void FX_GrenadeThink( centity_t *cent, const struct weaponInfo_s *weapon ); +void FX_GrenadeHitWall( vec3_t origin, vec3_t normal ); +void FX_GrenadeHitPlayer( vec3_t origin, vec3_t normal ); +void FX_GrenadeExplode( vec3_t origin, vec3_t normal ); +void FX_GrenadeShrapnelExplode( vec3_t origin, vec3_t norm ); +void FX_GrenadeShrapnelBits( vec3_t start); +void FX_fxfunc_Explosion( vec3_t start, vec3_t origin, vec3_t normal ); +void FX_fxfunc_Shot( vec3_t start, vec3_t dir ); + +/* + * detpack + */ +void FX_Detpack(vec3_t origin); + + +/* + * Disruptor Weapon + */ +void FX_DisruptorBeamFire( vec3_t startpos, vec3_t endpos, vec3_t normal, qboolean spark, qboolean impact, qboolean empty ); +void FX_DisruptorWeaponHitWall( vec3_t origin, vec3_t dir, int size ); + +/* + * Quantum Burst + */ +void FX_QuantumThink( centity_t *cent, const struct weaponInfo_s *weapon ); +void FX_QuantumAltThink( centity_t *cent, const struct weaponInfo_s *weapon ); +void FX_QuantumHitWall( vec3_t origin, vec3_t normal ); +void FX_QuantumAltHitWall( vec3_t origin, vec3_t normal ); +void FX_QuantumColumns( vec3_t origin ); + +/* + * transporter + */ +void FX_Transporter(vec3_t origin); +void FX_TransporterPad( vec3_t origin ); +void FX_SPTransporterLensFlares( centity_t* cent, vec3_t headVector, int startTime ); + + +/* Holdable, portable shield item */ +void FX_DrawPortableShield(centity_t *cent); + + + +/* Shield */ +void FX_PlayerShieldHit( centity_t *cent ); + + +/* + * Miscellaneous FX + */ +void FX_Disruptor( vec3_t org, float length ); +void FX_ExplodeBits( vec3_t org); + +void FX_qFlash( centity_t* cent, vec3_t org, int timeIndex ); + +/* + * sin table + */ +void fxRandCircumferencePos(vec3_t center, vec3_t normal, float radius, vec3_t out); + diff --git a/code/cgame/fx_misc.c b/code/cgame/fx_misc.c new file mode 100644 index 0000000..6b26afc --- /dev/null +++ b/code/cgame/fx_misc.c @@ -0,0 +1,286 @@ +#include "cg_local.h" +#include "fx_local.h" + + +/* +------------------------- +FX_Disruptor +------------------------- +*/ +void DisruptorShards(vec3_t org) +{ + vec3_t normal, end; + + // Pick a random endpoint + VectorSet( normal, crandom(), crandom(), crandom() ); + VectorNormalize( normal ); + + end[0] = org[0] + ( normal[0] * ( 48 + crandom() * 16 )); + end[1] = org[1] + ( normal[1] * ( 48 + crandom() * 16 )); + end[2] = org[2] + ( normal[2] * ( 64 + crandom() * 24 )); + + // Draw a light shard, use a couple of different kinds so it doesn't look too homogeneous + if( rand() & 1 ) + { + FX_AddLine( org, end, 1.0, random() * 0.5 + 0.5, 12.0, random() * 0.1 + 0.1, 0.0, 200 + random() * 350, cgs.media.orangeParticleShader ); + } + else + { + FX_AddLine( org, end, 1.0, random() * 0.5 + 0.5, 12.0, random() * 0.1 + 0.1, 0.0, 200 + random() * 350, cgs.media.yellowParticleShader ); + } +} + +qboolean MakeDisruptorShard( localEntity_t *le ) +{ + DisruptorShards(le->refEntity.origin); + return(qtrue); +} + +// Effect used when scav beams in--this wouldn't work well for a scav on the ground if they were to beam out +void FX_Disruptor( vec3_t org, float length ) +{//FIXME: make it move with owner? + vec3_t org1, org2, normal={0,0,1}; + int t; + + VectorMA( org, 48, normal, org1 ); + VectorMA( org, -48, normal, org2 ); + + // This is the core + FX_AddLine( org1, org2, 1.0, 0.1, 48.0, 1.0, 0.0, length, cgs.media.dkorangeParticleShader ); + + // Spawn a bunch to get the effect going + for (t=0; t < 12; t++ ) + { + DisruptorShards( org); + } + + // Keep spawning the light shards for a while. + FX_AddSpawner( org, normal, NULL, NULL, qfalse, 20, 10, length*0.75, MakeDisruptorShard, 0); +} + + + + +void FX_EnergyGibs(vec3_t origin ) +{ + localEntity_t *le; + refEntity_t *re; + vec3_t dir; + int i, j, k; + int chunkModel=0; + float baseScale = 0.7f, dist; + int numChunks; + + numChunks = irandom( 10, 15 ); + + VectorSubtract(cg.snap->ps.origin, origin, dir); + dist = VectorLength(dir); + if (dist > 512) + { + numChunks *= 512.0/dist; // 1/2 at 1024, 1/4 at 2048, etc. + } + + for ( i = 0; i < numChunks; i++ ) + { + chunkModel = cgs.media.chunkModels[MT_METAL][irandom(0,5)]; + + le = CG_AllocLocalEntity(); + re = &le->refEntity; + + le->leType = LE_FRAGMENT; + le->endTime = cg.time + 2000; + + VectorCopy( origin, re->origin ); + + for ( j = 0; j < 3; j++ ) + { + re->origin[j] += crandom() * 12; + } + VectorCopy( re->origin, le->pos.trBase ); + + //Velocity + VectorSet( dir, crandom(), crandom(), crandom() ); + VectorScale( dir, flrandom( 300, 500 ), le->pos.trDelta ); + + //Angular Velocity + VectorSet( le->angles.trBase, crandom() * 360, crandom() * 360, crandom() * 360 ); + VectorSet( le->angles.trDelta, crandom() * 90, crandom() * 90, crandom() * 90 ); + + AxisCopy( axisDefault, re->axis ); + + le->data.fragment.radius = flrandom(baseScale * 0.4f, baseScale * 0.8f ); + + re->nonNormalizedAxes = qtrue; + re->hModel = chunkModel; + re->renderfx |= RF_CAP_FRAMES; + re->customShader = cgs.media.quantumDisruptorShader; + re->shaderTime = cg.time/1000.0f; + + le->pos.trType = TR_GRAVITY; + le->pos.trTime = cg.time; + le->angles.trType = TR_INTERPOLATE; + le->angles.trTime = cg.time; + le->bounceFactor = 0.2f + random() * 0.2f; + le->leFlags |= LEF_TUMBLE; + + re->shaderRGBA[0] = re->shaderRGBA[1] = re->shaderRGBA[2] = re->shaderRGBA[3] = 255; + + // Make sure that we have the desired start size set + for( k = 0; k < 3; k++) + { + VectorScale(le->refEntity.axis[k], le->data.fragment.radius, le->refEntity.axis[k]); + } + } +} + + + +void FX_ExplodeBits( vec3_t org) +{ + float width, length; + vec3_t vel, pos; + int i; + + FX_EnergyGibs(org); + + for (i = 0; i < 32; i++) + { + VectorSet(vel, flrandom(-320,320), flrandom(-320,320), flrandom(-100,320)); + VectorCopy(org, pos); + pos[2] += flrandom(-8, 8); + length = flrandom(10,20); + width = flrandom(2.0,4.0); + FX_AddTrail( pos, vel, qtrue, length, -length, width, -width, + 1.0f, 1.0f, 0.5f, 1000.0f, cgs.media.orangeTrailShader); + } +} + +#define Q_FLASH_SIZE 110 + +void FX_qFlash( centity_t* cent, vec3_t org, int timeIndex ) { + trace_t tr; + refEntity_t flare; + float frac; + + if ( cg.predictedPlayerState.clientNum != cent->currentState.clientNum ) { + CG_Trace( &tr, cg.refdef.vieworg, NULL, NULL, + cent->lerpOrigin, cg.predictedPlayerState.clientNum, CONTENTS_SOLID ); + if ( tr.fraction != 1 ) { + return; + } + } + + memset( &flare, 0, sizeof( flare ) ); + + flare.reType = RT_SPRITE; + flare.shaderRGBA[0] = 0xff; + flare.shaderRGBA[1] = 0xff; + flare.shaderRGBA[2] = 0xff; + flare.shaderRGBA[3] = 0xff; + + flare.data.sprite.rotation = 0; + flare.nonNormalizedAxes = qtrue; //needed for effective scaling + + flare.customShader = cgs.media.qFlashSprite; + + flare.renderfx |= RF_DEPTHHACK; + + VectorCopy( org, flare.origin ); + + //find the basic ratio + frac = (float)(cg.time - timeIndex) / (float)( Q_FLASH_TIME ); + //apply a sine function to it to make it less linear + //calculated using the fine graph prog @ http://math.umn.edu/~garrett/a08/Graph.html + frac = ( 0.65f * sin( 4.5f * frac - 0.6f ) + 0.35f ); + + frac = Com_Clamp( 0.0f, 1.0f, frac ); + + //CG_Printf( "%f\n", frac ); + + flare.data.sprite.radius = (float)Q_FLASH_SIZE * frac; + + trap_R_AddRefEntityToScene( &flare ); +} + +#define PROBE_BEAM_LENGTH 32 +//TiM - Beam FX for the Neutrino Probe weapon +void FX_ProbeBeam( vec3_t origin, vec3_t dir, int clientNum, qboolean alt_fire ) +{ + trace_t tr; + refEntity_t beam; + vec3_t end; + float scale; + + memset( &beam, 0, sizeof( beam ) ); + + if ( alt_fire ) + scale = flrandom(7.0f, 12.0f); + else + scale = Q_fabs( 12.0f * sin( cg.time * 0.1f ) ); + + VectorMA( origin, PROBE_BEAM_LENGTH, dir, end ); + + CG_Trace( &tr, origin, NULL, NULL, end, clientNum, CONTENTS_SOLID ); + + trap_R_AddLightToScene( origin, 20, 114.0f / 255, 164.0f / 255, 1.0f ); + + VectorCopy( origin, beam.origin); + VectorCopy( tr.endpos, beam.oldorigin ); + beam.reType = RT_LINE; + beam.customShader = cgs.media.probeBeam; + beam.shaderRGBA[0] = 0xff; + beam.shaderRGBA[1] = 0xff; + beam.shaderRGBA[2] = 0xff; + beam.shaderRGBA[3] = 0xff; + AxisClear( beam.axis ); + + beam.data.line.width = scale*0.1; + beam.data.line.width2 = scale; + beam.data.line.stscale = 1.0; + trap_R_AddRefEntityToScene( &beam ); + + if ( tr.fraction != 1.0f ) + { + float radius; + + if ( alt_fire ) + radius = flrandom(1.5f, 3.0f) * (1.0 - (tr.fraction*0.3)); + else + radius = flrandom(0.5f, 1.5f) * (1.0 - (tr.fraction*0.3)); + + if ( !radius ) + return; + + CG_ImpactMark( cgs.media.probeDecal, tr.endpos, tr.plane.normal, 0, 1, 1, 1, 0.2*(1.0-tr.fraction), qfalse, radius, qtrue ); + trap_R_AddLightToScene( origin, radius*5, 114.0f / 255, 164.0f / 255, 1.0f ); + } +} + +#define REGEN_BEAM_LENGTH 64 +void FX_RegenBeam( vec3_t origin, vec3_t dir, int clientNum, qboolean alt_fire ) +{ + trace_t tr; + vec3_t end; + + VectorMA( origin, REGEN_BEAM_LENGTH, dir, end ); + + CG_Trace( &tr, origin, NULL, NULL, end, clientNum, CONTENTS_SOLID ); + + trap_R_AddLightToScene( origin, 30, 235.0f / 255, 74.0f / 255, 102.0f / 255 ); + + if ( tr.fraction != 1.0f ) + { + float radius; + + if ( alt_fire ) + radius = flrandom(1.5f, 3.0f) * (1.0 - (tr.fraction*0.3)); + else + radius = flrandom(0.5f, 1.5f) * (1.0 - (tr.fraction*0.3)); + + if ( !radius ) + return; + + CG_ImpactMark( cgs.media.regenDecal, tr.endpos, tr.plane.normal, 0, 1, 1, 1, 0.2*(1.0-tr.fraction), qfalse, radius, qtrue ); + trap_R_AddLightToScene( origin, radius*5, 235.0f / 255, 74.0f / 255, 102.0f / 255 ); + } +} diff --git a/code/cgame/fx_phaser.c b/code/cgame/fx_phaser.c new file mode 100644 index 0000000..4d41e4d --- /dev/null +++ b/code/cgame/fx_phaser.c @@ -0,0 +1,357 @@ +//Phaser + +#include "cg_local.h" +#include "fx_local.h" + +/* +------------------------- +FX_PhaserFire +------------------------- +*/ + +lensFlare_t phaserFlare = { {0.0,0.0,0.0}, + 20, + 20, + {1.0, 0.7, 0.13}, + 1.2, + 1.5, + 20, + 300, + {0.0, 0.0, 0.0}, + 20, + 300, + 80, + 5, + qfalse, + 5, + 40, + qfalse, + qfalse, + qtrue, + 1.0, + 1.0, + 1.0, + 1.0, + 1.0, + qtrue }; + +void FX_PhaserFire( vec3_t startpos, vec3_t endpos, vec3_t normal, qboolean spark, qboolean impact, qboolean empty ) +{ + refEntity_t beam; + sfxHandle_t sfx; + float size; + vec3_t velocity; + int sparks; + vec3_t rgb = { 1,0.9,0.6}, rgb2={1,0.3,0}; + + //vec3_t rgb3 = { 1.0, 1.0, 1.0 }; + + sfx = 0; + + // Draw beam first. + memset( &beam, 0, sizeof( beam ) ); + + VectorCopy( startpos, beam.origin); + VectorCopy( endpos, beam.oldorigin ); + beam.reType = RT_LINE; + if (empty) + { + beam.customShader = cgs.media.phaserEmptyShader; + } + else + { + beam.customShader = cgs.media.phaserShader; + } + AxisClear( beam.axis ); + beam.shaderRGBA[0] = 0xff; + beam.shaderRGBA[1] = 0xff; + beam.shaderRGBA[2] = 0xff; + beam.shaderRGBA[3] = 0xff; + if (empty) + { + beam.data.line.width = 1.0f + ( crandom() * 0.6f ); + } + else + { + beam.data.line.width = 2.0f + ( crandom() * 0.6f ); + } + beam.data.line.stscale = 5.0; + trap_R_AddRefEntityToScene( &beam ); + + // Now draw the hit graphic + + // no explosion at LG impact, it is added with the beam + + if ( sfx ) + { + Com_Printf("playing %s\n", "phaser sound"); + trap_S_StartSound( endpos, ENTITYNUM_WORLD, CHAN_AUTO, sfx ); + } + + // + // impact mark + // + if (impact) + { + if (!empty) + { // normal. + CG_ImpactMark( cgs.media.scavMarkShader, endpos, normal, random()*360, 1,1,1,0.2, qfalse, + random() + 1, qfalse ); + + //VectorCopy( endpos, phaserFlare.worldCoord ); + + /*CG_InitLensFlare( endpos, + 80, + 80, + rgb, + 1.2, + 1.5, + 1600, + 200, + colorTable[CT_BLACK], + 1600, + 200, + 80, + 5, + qfalse, + 5, + 40, + qfalse, + qfalse, + qfalse, + 1.0, + 1.0, + 200.0, + 200.0, + 200.0 );*/ + + //CG_InitLensFlare( endpos, + // 30, 30, + // rgb, 1.2, 2.0, 1600, 200, + // colorTable[CT_BLACK], 1600, 200, 410, 15, qfalse, + // 0, 0, qfalse, qtrue, + // qfalse, 1.0, cg.time, 0, 0, 50); + + //TiM : Add your basic cheesy 'seen-way-too-much-in-movies-these-days' anamorphic lens streak :) + //CG_DrawLensFlare( &phaserFlare ); + //FX_AddSprite( endpos, NULL, qfalse, random() * 1.25 + 5.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 50.0, cgs.media.blueParticleStreakShader ); //1.5f + + //FX_AddQuad2( endpos, normal, random() * 1.25 + 8.0f, 0.0f, 1.0f, 1.0f, rgb3, rgb3, 270, 50.0, cgs.media.blueParticleStreakShader ); + //eh... looked bad :P + + FX_AddQuad2( endpos, normal, random() * 1.25 + 1.5f, 0.0f, 1.0f, 0.0f, rgb, rgb2, rand() % 360, 500 + random() * 200, + cgs.media.sunnyFlareShader ); + } + else + { // Wuss hit when empty. + FX_AddQuad2( endpos, normal, random() * .75 + 1.0f, 0.0f, 0.5f, 0.0f, rgb, rgb2, rand() % 360, 300 + random() * 200, + cgs.media.sunnyFlareShader ); + } + } + + // "Fun" sparks... Not when empty. + if ( spark && !empty) + { + sparks = (rand() & 1) + 1; + for(;sparks>0;sparks--) + { + size = 0.2f + (random() * 0.4); + FXE_Spray( normal, 200, 75, 0.8f, velocity); + if (rand() & LEF_USE_COLLISION) + { // This spark bounces. + FX_AddTrail( endpos, velocity, qtrue, 5.0f, -15.0f, + size, -size, 1.0f, 0.5f, 0.4f, 500.0f, cgs.media.sparkShader); + } + else + { + FX_AddTrail( endpos, velocity, qtrue, 5.0f, -15.0f, + size, -size, 1.0f, 0.5f, 0.0, 500.0f, cgs.media.sparkShader); + } + } + } +} + +/* +------------------------- +FX_PhaserAltFire +------------------------- +*/ + +#define PHASER_ALT_CONE_LEN 256 + +void FX_PhaserAltFire( vec3_t start, vec3_t end, vec3_t normal, qboolean spark, qboolean impact, qboolean empty ) +{ + float scale = flrandom(13.0f, 17.0f), scale2 = flrandom(2.0f, 6.0f); + vec3_t vel, diff, end2; + int i = 0, sparks = 0; + refEntity_t beam; + vec3_t rgb = { 1,0.6,0.5}, rgb2={1,0.3,0}; + float len; + int color; + + VectorSubtract(end, start, diff); + len = VectorNormalize(diff); + + color = 0xff * flrandom(0.75, 1.0); + + if (empty) + { // More faint and shaky line. + scale *= flrandom(0.25,0.75); + } + + if (len > PHASER_ALT_CONE_LEN) + { // Draw beam in two parts... + + // Draw main beam first. + VectorMA(start, PHASER_ALT_CONE_LEN, diff, end2); + + // Draw starting cone + memset( &beam, 0, sizeof( beam ) ); + VectorCopy( start, beam.origin); + VectorCopy( end2, beam.oldorigin ); + beam.reType = RT_LINE2; + if (empty) + { + beam.customShader = cgs.media.phaserAltEmptyShader; + } + else + { + beam.customShader = cgs.media.phaserAltShader; + } + AxisClear( beam.axis ); + beam.shaderRGBA[0] = 0xff; + beam.shaderRGBA[1] = 0xff*0.3; + beam.shaderRGBA[2] = 0; + beam.shaderRGBA[3] = 0xff; + beam.data.line.width = scale*0.1; + beam.data.line.width2 = scale; + beam.data.line.stscale = 1.0; + trap_R_AddRefEntityToScene( &beam ); + + // Draw big thick normal beam for the rest. + memset( &beam, 0, sizeof( beam ) ); + VectorCopy( end2, beam.oldorigin); + VectorCopy( end, beam.origin ); + beam.reType = RT_LINE; + if (empty) + { + beam.customShader = cgs.media.phaserAltEmptyShader; + } + else + { + beam.customShader = cgs.media.phaserAltShader; + } + AxisClear( beam.axis ); + beam.shaderRGBA[0] = 0xff; + beam.shaderRGBA[1] = 0xff*0.3; + beam.shaderRGBA[2] = 0; + beam.shaderRGBA[3] = 0xff; + beam.data.line.width = scale; + beam.data.line.stscale = 1.0; + trap_R_AddRefEntityToScene( &beam ); + + // Draw beam core, all one bit. + memset( &beam, 0, sizeof( beam ) ); + VectorCopy( start, beam.origin); + VectorCopy( end, beam.oldorigin ); + beam.reType = RT_LINE2; + beam.customShader = cgs.media.phaserShader; + AxisClear( beam.axis ); + beam.shaderRGBA[0] = color*0.75f; + beam.shaderRGBA[1] = 0xff*0.5f; + beam.shaderRGBA[2] = 0xff*0.5f; + beam.shaderRGBA[3] = 0xff; + beam.data.line.width = scale2*0.2; + beam.data.line.width2 = scale2; + beam.data.line.stscale = 1.0; + trap_R_AddRefEntityToScene( &beam ); + } + else + { // Draw beam in two parts... + // Draw beam first. + memset( &beam, 0, sizeof( beam ) ); + VectorCopy( start, beam.origin); + VectorCopy( end, beam.oldorigin ); + beam.reType = RT_LINE2; + beam.customShader = cgs.media.phaserAltShader; + AxisClear( beam.axis ); + beam.shaderRGBA[0] = 0xff; + beam.shaderRGBA[1] = 0xff*0.3; + beam.shaderRGBA[2] = 0; + beam.shaderRGBA[3] = 0xff; + beam.data.line.width = scale*0.1; + beam.data.line.width2 = scale; + beam.data.line.stscale = 1.0; + trap_R_AddRefEntityToScene( &beam ); + + // just one beam is never enough + memset( &beam, 0, sizeof( beam ) ); + VectorCopy( start, beam.origin); + VectorCopy( end, beam.oldorigin ); + beam.reType = RT_LINE2; + beam.customShader = cgs.media.phaserShader; + AxisClear( beam.axis ); + beam.shaderRGBA[0] = color*0.75f; + beam.shaderRGBA[1] = 0xff*0.5f; + beam.shaderRGBA[2] = 0xff*0.5f; + beam.shaderRGBA[3] = 0xff; + beam.data.line.width = scale2*0.2; + beam.data.line.width2 = scale2; + beam.data.line.stscale = 1.0; + trap_R_AddRefEntityToScene( &beam ); + } + + + // Phaser beam +// FX_AddLine( start, end, 1.0f, scale, 0.0f, 0.9f, 0.9f, 2, cgs.media.phaserShader ); +// FX_AddLine( start, end, 1.0f, scale * 0.5f, 0.0f, 0.8f, 0.8f, 2, cgs.media.phaserShader ); + + // Per frame impact mark + FX_AddQuad( end, normal, random() * 1.5 + 1.75f, 0.0f, 1.0f, 0.0f, 0.0f, 1, cgs.media.sparkShader ); + FX_AddQuad( end, normal, random() * 5 + 2.75f, 0.0f, 1.0f, 0.0f, 0.0f, 1, cgs.media.yellowParticleShader ); + + // Multi frame impacts--never do this when it hits a player because it will just look stupid + if ( impact ) + { + FX_AddQuad2( end, normal, random() * 2.0 + 5.0f, 2.5f, 0.6f, 0.0f, rgb, rgb2, 0.0f, 500 + random() * 200, + cgs.media.sunnyFlareShader ); + + CG_ImpactMark( cgs.media.scavMarkShader, end, normal, random()*360, 1,1,1,0.1, qfalse, + random() + 6.0, qfalse ); + } + + // "Fun" sparks + if ( spark ) + { + // kef -- fixme. dunno what the deal is with this velocity vector + VectorClear(vel); + sparks = (rand() & 3) + 1; + + // Set random starting pos... + end2[0] = flrandom(-1.0, 1.0) + end[0]; + end2[1] = flrandom(-1.0, 1.0) + end[1]; + end2[2] = flrandom(-1.0, 1.0) + end[2]; + for( i = 0; i < sparks; i++ ) + { + scale = 0.5f + (random() * 0.5); + FXE_Spray( normal, 200, 75, 0.8f, /*1024*/vel); + FX_AddTrail2( end2, vel, qfalse, + 8.0f, -8.0f, + scale, -scale, 0.5f, 0.0f, rgb, rgb2, 0.4f, 500.0f, cgs.media.sparkShader ); + } + + VectorMA(end, -8, diff, end2); + // Add a hit sprite over everything... + memset( &beam, 0, sizeof( beam ) ); + VectorCopy( end2, beam.origin); + beam.reType = RT_SPRITE; + beam.customShader = cgs.media.sunnyFlareShader; + AxisClear( beam.axis ); + beam.shaderRGBA[0] = 0xff*1.0f; + beam.shaderRGBA[1] = 0xff*0.9f; + beam.shaderRGBA[2] = 0xff*0.8f; + beam.shaderRGBA[3] = 0xff; + beam.data.sprite.radius = random()*2.0 + 9.0; + trap_R_AddRefEntityToScene( &beam ); + } +} diff --git a/code/cgame/fx_quantum.c b/code/cgame/fx_quantum.c new file mode 100644 index 0000000..601ff7c --- /dev/null +++ b/code/cgame/fx_quantum.c @@ -0,0 +1,356 @@ +#include "cg_local.h" +#include "fx_local.h" + +void FX_QuantumThink( centity_t *cent, const struct weaponInfo_s *weapon ) +{ + vec3_t line1end, line2end, axis[3], rgb; + + AxisClear( axis ); + + // convert direction of travel into axis + if ( VectorNormalize2( cent->currentState.pos.trDelta, axis[0] ) == 0 ) { + axis[0][2] = 1; + } + + // spin as it moves + RotateAroundDirection( axis, cg.time * 0.3f );// * 1.25f ); + + VectorMA( cent->lerpOrigin, -24.0f, axis[1], line1end ); + VectorMA( cent->lerpOrigin, 24.0f, axis[1], line2end ); + FX_AddLine( line1end, line2end, 1.0f, random() * 6 + 2, 0.0f, 0.2 + random() * 0.2, 0.0f, 1, cgs.media.yellowParticleShader ); + + AxisClear( axis ); + + // convert direction of travel into axis + if ( VectorNormalize2( cent->currentState.pos.trDelta, axis[0] ) == 0 ) { + axis[0][2] = 1; + } + + // spin as it moves + RotateAroundDirection( axis, -cg.time * 0.3f );// * 1.25f ); + + VectorMA( cent->lerpOrigin, -48.0f, axis[2], line1end ); + VectorMA( cent->lerpOrigin, 48.0f, axis[2], line2end ); + FX_AddLine( line1end, line2end, 1.0f, random() * 5 + 2, 0.0f, 0.1 + random() * 0.2, 0.0f, 1, cgs.media.yellowParticleShader ); + + VectorSet( rgb, 1.0f, 0.45f, 0.15f ); // orange + + FX_AddSprite( cent->lerpOrigin, NULL,qfalse,random() * 60 + 30, 4, 0.5f, 0.0f, 0, 0.0f, 1.0f, cgs.media.orangeParticleShader ); + FX_AddSprite2(cent->lerpOrigin, NULL,qfalse,random() * 10 + 60, 0.0f, 0.1f, 0.1f, rgb, rgb, 0.0f, 0.0f, 1, cgs.media.whiteRingShader ); + FX_AddSprite( cent->lerpOrigin, NULL,qfalse,random() * 16 + 8, 4, 0.5f, 0.0f, 0, 0.0f, 1.0f, cgs.media.yellowParticleShader ); + + /* + VectorCopy( cent->lerpOrigin, quantumFlare.worldCoord ); + VectorCopy( colorTable[CT_CYAN], quantumFlare.glowColor ); + VectorCopy( colorTable[CT_CYAN], quantumFlare.streakColor ); + + CG_DrawLensFlare( quantumFlare );*/ +} + +/* +------------------------- +FX_QuantumAltThink +------------------------- +*/ +void FX_QuantumAltThink( centity_t *cent, const struct weaponInfo_s *weapon ) +{ + vec3_t line1end, line2end, axis[3], vel, rgb; + float scale; + + AxisClear( axis ); + + // convert direction of travel into axis + if ( VectorNormalize2( cent->currentState.pos.trDelta, axis[0] ) == 0 ) { + axis[0][2] = 1; + } + + // spin as it moves + RotateAroundDirection( axis, cg.time * 0.3f );// * 1.25f ); + + VectorMA( cent->lerpOrigin, -48.0f, axis[1], line1end ); + VectorMA( cent->lerpOrigin, 48.0f, axis[1], line2end ); + FX_AddLine( line1end, line2end, 1.0f, random() * 6 + 2, 0.0f, 0.2 + random() * 0.2, 0.0f, 1, cgs.media.yellowParticleShader ); + + VectorMA( cent->lerpOrigin, -48.0f, axis[2], line1end ); + VectorMA( cent->lerpOrigin, 48.0f, axis[2], line2end ); + FX_AddLine( line1end, line2end, 1.0f, random() * 5 + 2, 0.0f, 0.2 + random() * 0.2, 0.0f, 1, cgs.media.yellowParticleShader ); + + VectorSet( rgb, 1.0f, 0.45f, 0.15f ); // orange + + FX_AddSprite( cent->lerpOrigin, NULL,qfalse,random() * 60 + 30, 4, 0.5f, 0.0f, 0, 0.0f, 1.0f, cgs.media.orangeParticleShader ); + FX_AddSprite2(cent->lerpOrigin, NULL,qfalse,random() * 10 + 60, 0.0f, 0.1f, 0.1f, rgb, rgb, 0.0f, 0.0f, 1, cgs.media.whiteRingShader ); + FX_AddSprite( cent->lerpOrigin, NULL,qfalse,random() * 16 + 8, 4, 0.5f, 0.0f, 0, 0.0f, 1.0f, cgs.media.yellowParticleShader ); + + scale = ( 2.0f + cos( cg.time * ( M_PI * 0.001f * 4 ))) * 0.5f; + + // Unlike the main fire, I'm leaving around this center core for a moment as a trail... + VectorScale( cent->currentState.pos.trDelta, 0.25f, vel ); + FX_AddSprite( cent->lerpOrigin, NULL,qfalse,scale * 8 + 2, scale * -5.0f, 0.8f, 0.0f, 0, 0, 300.0f, cgs.media.sunnyFlareShader); + + // Tack on a sprite trail so we can see the cool tracking at work. + VectorSet( vel, flrandom(-12, 12), flrandom(-12, 12), flrandom(-12, 12)); + VectorMA( vel, 0.25f, cent->currentState.pos.trDelta, vel); + + if ( rand() & 1 ) + FX_AddSprite( cent->lerpOrigin, vel,qfalse,random() * 12.0f + scale * 14, -10, 0.2f + random() * 0.2f, 0.0, random()*360, 0, 800 + random() * 200.0f, + cgs.media.orangeRingShader ); + else + FX_AddSprite2(cent->lerpOrigin, vel,qfalse,random() * 12.0f + scale * 14, -10, 0.5, 0.0, rgb, rgb, random()*360, 0, 800 + random() * 200.0f, + cgs.media.whiteRingShader ); +} + +/* +------------------------- +FX_QuantumHitWall +------------------------- +*/ +void FX_QuantumHitWall( vec3_t origin, vec3_t normal ) +{ + localEntity_t *le = NULL; + vec3_t dir, org; + vec3_t vel; + float scale; + int i; + weaponInfo_t *weaponInfo = &cg_weapons[WP_9]; + + CG_InitLensFlare( origin, + 400, 400, + colorTable[CT_YELLOW], 1.2, 2.0, 1600, 200, + colorTable[CT_YELLOW], 1600, 200, 800, 35, qtrue, + 0, 0, qfalse, qtrue, + qfalse, 1.0, cg.time, 0, 0, 200); + + for ( i = 0; i < 12; i++ ) + { + VectorSet( dir, normal[0] + crandom() * 2, normal[1] + crandom() * 2, normal[2] + crandom() ); + VectorNormalize( dir ); + scale = random() * 300 + 300; + VectorScale( dir, scale, vel ); + vel[2] += 300; + if ( rand() & 1 ) + { + // FX_AddParticle( origin, vel, qfalse, random() * 14 + 2, -2.0, 0.9, 0.1, 0.0, 0.0, 300 + random() * 100, cgs.media.yellowParticleShader, explosionTailThink ); + scale = random()*14+2; + // Instead of the particle code, which seems redundant and doesn't fade real well, try adding the projectile... + le=FX_AddSprite(origin, vel, qfalse, scale, -scale, 0.9, 0.5, 0.0, 0.0, 200 + random() * 100, cgs.media.yellowParticleShader); + // ...with a trail that overlaps it exactly. + FX_AddTrail(origin, vel, qfalse, 80, -40, scale, -scale, 0.8, 0.4, 0.0, 300, cgs.media.orangeTrailShader); + } + else + { + // FX_AddParticle( origin, vel, qfalse, random() * 14 + 2, -2.0, 0.9, 0.1, 0.0, 0.0, 450 + random() * 200, cgs.media.sunnyFlareShader, explosionTailThink ); + scale = random()*14+6; + // Instead of the particle code, which seems redundant and doesn't fade real well, try adding the projectile... + le=FX_AddSprite(origin, vel, qfalse, scale, -scale, 0.9, 0.5, 0.0, 0.0, 350 + random() * 150, cgs.media.sunnyFlareShader); + // ...with a trail that overlaps it exactly. + FX_AddTrail(origin, vel, qfalse, 80, -40, scale, -scale, 0.8, 0.4, 0.0, 500, cgs.media.orangeTrailShader); + } + } + // Always face the camera + VectorSubtract( cg.refdef.vieworg, origin, dir ); + VectorNormalize( dir ); + + // Main explosion, tag with light + + le = CG_MakeExplosion2( origin, normal, (qhandle_t)0, 1, cgs.media.quantumExplosionShader, 600, qtrue, 3 + crandom(), 0 ); + le->light = 150; + le->refEntity.renderfx |= RF_NOSHADOW; + VectorSet( le->lightColor, 1.0f, 1.0f, 0.6f ); + + // Create sphere + CG_MakeExplosion2( origin, dir, cgs.media.explosionModel, 5, cgs.media.quantumFlashShader, 150, qfalse, 4.6f + ( crandom() * 0.3f), 0 ); + + // Make an offset explosion + for ( i = 0; i < 3; i++ ) { + org[i] = origin[i] + crandom() * 4; + } + + CG_MakeExplosion( org, dir, 0, cgs.media.quantumExplosionShader, 700, 1, qtrue ); + CG_ImpactMark( cgs.media.compressionMarkShader, origin, normal, random()*360, 1,1,1,1.0, qfalse, + random() * 16 + 48, qfalse ); + + CG_ExplosionEffects( origin, 3.0f, 256 ); + + // One big bright quick flash + FX_AddSprite( origin, NULL, qfalse, 100, -100, 1.0, 1.0, 0, 0, 300, cgs.media.sunnyFlareShader); + + + trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, weaponInfo->mainHitSound ); +} + +/* +------------------------- +FX_QuantumAltHitWall +------------------------- +*/ +void FX_QuantumAltHitWall( vec3_t origin, vec3_t normal ) +{ + localEntity_t *le = NULL; + vec3_t dir, org; + vec3_t vel; + float scale; + int i; + vec3_t RGB={1.0, 0.6, 0.3}, RGB2={1.0, 0.3, 0.0}; + weaponInfo_t *weaponInfo = &cg_weapons[WP_9]; + + CG_InitLensFlare( origin, + 500, 500, + colorTable[CT_YELLOW], 1.2, 2.0, 1600, 200, + colorTable[CT_YELLOW], 1600, 200, 800, 35, qtrue, + 1600, 200, qfalse, qfalse, + qfalse, 1.0, cg.time, 0, 0, 350); + + for ( i = 0; i < 12; i++ ) + { + VectorSet( dir, normal[0] + crandom() * 2, normal[1] + crandom() * 2, normal[2] + crandom() ); + VectorNormalize( dir ); + scale = random() * 500 + 500; + VectorScale( dir, scale, vel ); + vel[2] += 300; + if ( rand() & 1 ) + { + // FX_AddParticle( origin, vel, qfalse, random() * 14 + 2, -2.0, 0.9, 0.1, 0.0, 0.0, 300 + random() * 100, cgs.media.yellowParticleShader, explosionTailThink ); + scale = random()*14+2; + // Instead of the particle code, which seems redundant and doesn't fade real well, try adding the projectile... + le=FX_AddSprite2(origin, vel, qfalse, scale, -scale, 0.9, 0.5, RGB, RGB2, 0.0, 0.0, 200 + random() * 100, cgs.media.yellowParticleShader); + // ...with a trail that overlaps it exactly. + FX_AddTrail2(origin, vel, qfalse, 80, -40, scale, -scale, 0.8, 0.4, RGB, RGB2, 0.0, 300, cgs.media.orangeTrailShader); + } + else + { + // FX_AddParticle( origin, vel, qfalse, random() * 14 + 2, -2.0, 0.9, 0.1, 0.0, 0.0, 450 + random() * 200, cgs.media.sunnyFlareShader, explosionTailThink ); + scale = random()*14+6; + // Instead of the particle code, which seems redundant and doesn't fade real well, try adding the projectile... + le=FX_AddSprite2(origin, vel, qfalse, scale, -scale, 0.9, 0.5, RGB, RGB2, 0.0, 0.0, 350 + random() * 150, cgs.media.sunnyFlareShader); + // ...with a trail that overlaps it exactly. + FX_AddTrail2(origin, vel, qfalse, 80, -40, scale, -scale, 0.8, 0.4, RGB, RGB2, 0.0, 500, cgs.media.orangeTrailShader); + } + } + // Always face the camera + VectorSubtract( cg.refdef.vieworg, origin, dir ); + VectorNormalize( dir ); + + // Main explosion, tag with light + + le = CG_MakeExplosion2( origin, normal, (qhandle_t)0, 1, cgs.media.quantumExplosionShader, 600, qtrue, 3 + crandom(), 0 ); + le->light = 150; + le->refEntity.renderfx |= RF_NOSHADOW; + VectorSet( le->lightColor, 1.0f, 1.0f, 0.6f ); + + // Create sphere + CG_MakeExplosion2( origin, dir, cgs.media.explosionModel, 5, cgs.media.quantumFlashShader, 150, qfalse, 5.4f + ( crandom() * 0.3f), 0 ); + + // Make an offset explosion + for ( i = 0; i < 3; i++ ) { + org[i] = origin[i] + crandom() * 4; + } + + CG_MakeExplosion( org, dir, 0, cgs.media.quantumExplosionShader, 700, 1, qtrue ); + CG_ImpactMark( cgs.media.compressionMarkShader, origin, normal, random()*360, 1,1,1,1.0, qfalse, + random() * 16 + 48, qfalse ); + + CG_ExplosionEffects( origin, 3.0f, 256 ); + + // One big bright quick flash + FX_AddSprite( origin, NULL, qfalse, 200, -200, 1.0, 1.0, 0, 0, 400, cgs.media.sunnyFlareShader); + + trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, weaponInfo->altHitSound ); +} + +qboolean FX_QuantumSparkle( localEntity_t *le) +{ + int t, i; + vec3_t org, v; + + for ( i = 0; i < 4; i ++ ) + { + VectorCopy( le->refEntity.origin, org ); + + for ( t = 0; t < 3; t++ ) + { + org[t] = le->refEntity.origin[t] + crandom() * 12; + v[t] = crandom() * 18.0f; + } + + FX_AddSprite( org, v, qfalse, random() * 1 + 1, -4, 0.5f, 1.0f, 0.0f, 0.0f, 125 + random() * 100, cgs.media.yellowParticleShader); + } + return qtrue; +} + +void FX_QuantumFizzles( vec3_t origin ) +{ + float v; + vec3_t dir, vel, org; + int i; + + for ( i = 0; i < 32; i++ ) + { + v = random() * 6.0f + 6.0f; + + VectorSet( dir, crandom(), crandom(), crandom() ); + VectorNormalize( dir ); + VectorScale( dir, v, vel ); + + org[0] = origin[0] + dir[0] * 48; + org[1] = origin[1] + dir[1] * 48; + org[2] = origin[2] + dir[2] * 64; + + FX_AddSpawner( org, dir, vel, NULL, qfalse, 125, 10 + random() * 30, 200 + random() * 400, FX_QuantumSparkle, 1024 ); + } +} + +void FX_QuantumColumns( vec3_t origin ) +{ + vec3_t dir, bottom, top; + vec3_t sizeMin = {-4, -4, -1}; + vec3_t sizeMax = {-4, -4, 1}; + trace_t trace; + localEntity_t *le; + + //Orient the explosions to face the camera + VectorSubtract( cg.refdef.vieworg, origin, dir ); + VectorNormalize( dir ); + + //=== Sound === + trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.quantumBoom ); + + //=== columns === + VectorCopy( origin, bottom ); + bottom[2] -= 256; + + trap_CM_BoxTrace( &trace, origin, bottom, sizeMin, sizeMax, 0, MASK_OPAQUE ); + VectorCopy( trace.endpos, bottom ); + + VectorCopy( origin, top ); + top[2] += 256; + + trap_CM_BoxTrace( &trace, origin, top, sizeMin, sizeMax, 0, MASK_OPAQUE ); + VectorCopy( trace.endpos, top ); + + //found floor and ceiling, now do columns and ring explosions: + //ceiling + VectorSet( dir, 0, 0, -1 ); + + le = FX_AddCylinder( top, dir, top[2] - origin[2], (origin[2] - top[2]), 40, 100, 20, 50, 1.0, 0.0, 1000, cgs.media.quantumRingShader, 1.5 ); + + le->refEntity.data.cylinder.wrap = qtrue; + le->refEntity.data.cylinder.stscale = 6; + + //floor + VectorSet( dir, 0, 0, 1 ); + + le = FX_AddCylinder( bottom, dir, origin[2] - bottom[2], (bottom[2] - origin[2]), 40, 100, 20, 50, 1.0, 0.0, 1000, cgs.media.quantumRingShader, 1.5 ); + le->refEntity.data.cylinder.wrap = qtrue; + le->refEntity.data.cylinder.stscale = 6; + + FX_QuantumFizzles( origin ); + + // Main explosion, tag with light + + le = CG_MakeExplosion2( origin, dir, (qhandle_t)0, 1, cgs.media.quantumExplosionShader, 600, qtrue, 3 + crandom(), 0 ); + le->light = 150; + le->refEntity.renderfx |= RF_NOSHADOW; + VectorSet( le->lightColor, 1.0f, 1.0f, 0.6f ); + + +} diff --git a/code/cgame/fx_tetrion.c b/code/cgame/fx_tetrion.c new file mode 100644 index 0000000..6394533 --- /dev/null +++ b/code/cgame/fx_tetrion.c @@ -0,0 +1,56 @@ +#include "cg_local.h" +#include "fx_local.h" + +/* +------------------------- +FX_TetrionShot +------------------------- +*/ +#define MAXRANGE_TETRION 5000000 //RPG-X: J2J OLD: 8192 +void FX_TetrionShot( vec3_t start, vec3_t forward ) // TODO check whether I'm needed +{ + trace_t trace; + vec3_t end, dir, new_start, new_end, radial, start2, spreadFwd; + float off, len, i, numBullets = 3; + float firingRadius = 6, minDeviation = 0.95, maxDeviation = 1.1; + qboolean render_impact = qtrue; + + for (i = 0; i < numBullets; i++) + { + render_impact = qtrue; + // determine new firing position + fxRandCircumferencePos(start, forward, firingRadius, new_start); + VectorSubtract(new_start, start, radial); + VectorMA(start, 10, forward, start2); + VectorMA(start2, flrandom(minDeviation, maxDeviation), radial, start2); + VectorSubtract(start2, new_start, spreadFwd); + VectorNormalize(spreadFwd); + // determine new end position for this bullet. give the endpoint some spread, too. + VectorMA(new_start, MAXRANGE_TETRION, spreadFwd, end); + CG_Trace( &trace, new_start, NULL, NULL, end, cg_entities[cg.predictedPlayerState.clientNum].currentState.number, MASK_SHOT ); + // Get the length of the whole shot + VectorSubtract( trace.endpos, new_start, dir ); + len = VectorNormalize( dir ); + // Don't do tracers when it gets really short + if ( len >= 64 ) + { + // Move the end_point in a bit so the tracer doesn't always trace the full line length--this isn't strictly necessary, but it does + // add a bit of variance + off = flrandom(0.7, 1.0); + VectorMA( new_start, len * off, dir, new_end ); + + // Draw the tracer + FX_AddLine( new_end, new_start, 1.0f, 1.5f + random(), 0.0f, flrandom(0.3,0.6), 0.0, + flrandom(300,500), cgs.media.borgFlareShader ); + } + // put the impact effect where this tracer hits + if (len >= 32) + { + // Rendering things like impacts when hitting a sky box would look bad, but you still want to see the tracer + if ( trace.surfaceFlags & SURF_NOIMPACT ) + { + render_impact = qfalse; + } + } + } +} diff --git a/code/cgame/fx_transporter.c b/code/cgame/fx_transporter.c new file mode 100644 index 0000000..9a83d2a --- /dev/null +++ b/code/cgame/fx_transporter.c @@ -0,0 +1,293 @@ + +#include "cg_local.h" +#include "fx_local.h" + +/* +------------------------- +SPTransporterLensFlares + +TiM: Judging from the title, +you just KNOW it's mine ;) + +Anyway, the point of this +function is to render 4 +sprites and then scale + move +them in a way reminisicant +of ST: Voyager's transporter FX. + +I wrote this instead of using the +already made FX spawning functions +because they don't let u track an origin. +To stop the particle +from rendering within the character, I'm going to +use the DEPTHHACK renderflag, the flag +originally used for the weapon models +in first-person mode. :) + +Planned timing: + +0 - 500 : Flare spawns, and scales up to it's main size (width parameter) +500 - 1500 : Flare moves up the height/2 of model (height parameter) +1500 - 2000 : Flare scales down and disappears ( width * 1.0 - (timeScale) ) +------------------------- +*/ + +void FX_SPTransporterLensFlares( centity_t* cent, vec3_t headVector, int startTime ) { + refEntity_t flare; + trace_t tr; + int i; + int direction = 1; + int timeOffset = 0; //250 - time between first and second flares appearing; + float ratio; + float dlightRatio; + + vec3_t origin, tempOrigin; + int width; + int height; + + //Hrmm... we have a glitch lol. Since DEPTHHACK is on, the flare will be drawn + //from ANYWHERE IN THE LEVEL! O_o + //So.... uh, we'll do a trace between ourselves and the entity this is attached + //to, and if they can't see each other, screw it. :P + if ( cg.predictedPlayerState.clientNum != cent->currentState.clientNum ) { + CG_Trace( &tr, cg.refdef.vieworg, NULL, NULL, + cent->lerpOrigin, cg.predictedPlayerState.clientNum, CONTENTS_SOLID ); + if ( tr.fraction != 1 ) { + return; + } + } + /*else { + Com_Printf( "Origin: { %f, %f, %f }\n", cent->lerpOrigin[0], cent->lerpOrigin[1], cent->lerpOrigin[2] ); + Com_Printf( "HeadVector: { %f, %f, %f }\n", headVector[0], headVector[1], headVector[2] ); + return; + }*/ + + //calculate the necessary data we need to place the origin in the direct center of the model + + memset( &flare, 0, sizeof( flare ) ); + + //Bah. I thought lerpOrigin was at the base of the feet. Turns out it's at the knees O_o + //This little hack should help that + VectorCopy( cent->lerpOrigin, tempOrigin ); + tempOrigin[2] -= 24; + + //If the distance means we're not lying down + if ( ( headVector[2] - tempOrigin[2] ) > 8 ) { + //find the average between our lerp origin and headVector to find the center + //VectorAdd( headVector, tempOrigin, origin ); + //VectorScale( origin, 0.5, origin ); + VectorAverage( headVector, tempOrigin, origin ); + + width = 30; + height = (headVector[2] - tempOrigin[2]) / 2; + } + else { + width = 30; + height = 4; + + VectorCopy( cent->lerpOrigin, origin); + } + + flare.reType = RT_SPRITE; + flare.shaderRGBA[0] = 0xff; + flare.shaderRGBA[1] = 0xff; + flare.shaderRGBA[2] = 0xff; + flare.shaderRGBA[3] = 0xff; + + flare.data.sprite.rotation = 0; + flare.nonNormalizedAxes = qtrue; //needed for effective scaling + + flare.renderfx |= RF_DEPTHHACK; //DEPTHHACK renders the element over everything else. Useful in this lens flare simulation case :) + + //loop 4 times = 4 flares. :) + for (i = 0; i < 4; i++ ) { + VectorClear( flare.origin ); + VectorCopy( origin, flare.origin); + + //the first two flares are the main ones + if ( i < 2 ) { + flare.customShader = cgs.media.transport1Shader; //1 + timeOffset = startTime; + } + else { // the second two spawn a little later + flare.customShader = cgs.media.transport2Shader; + timeOffset = startTime + 650; //750 + } + + //the second flare each round goes down instead of up + if ( i % 2 == 0) + direction = 1; + else + direction = -1; + + //=========================== + + if ( cg.time > timeOffset + 2000 ) { + continue; + } + + //Phase 1: flares get bigger + if ( cg.time < timeOffset + 500 ) { + ratio = ((float)(cg.time - timeOffset) * 0.002); + if (ratio < 0 ) + ratio = 0.0f; + else if (ratio > 1 ) + ratio = 1.0f; + + flare.data.sprite.radius = (float)width * ratio; + /*if ( i ==0 ) + Com_Printf( "Phase 1 Radius: %f\n", flare.data.sprite.radius );*/ + } + //Phase 2: flares move up/down character + if ( ( cg.time < timeOffset + 1500 ) && ( cg.time >= timeOffset + 500 ) ) { + ratio = ( (float)(cg.time - (timeOffset + 500) ) * 0.001 ); + if (ratio < 0 ) + ratio = 0.0f; + else if (ratio > 1 ) + ratio = 1.0f; + + flare.data.sprite.radius = (float)width; + flare.origin[2] += (float)direction * (float)height * ratio; + /*if (i == 0 ) + Com_Printf( "Phase 2 Location: %f\n", flare.origin[2] );*/ + } + //Phase 3: flares get smaller + if ( ( cg.time < timeOffset + 2000 ) && ( cg.time >= timeOffset + 1500 ) ) { + ratio = 1.0f - (float)(cg.time - ( timeOffset + 1500 ) ) * 0,002; + if (ratio < 0 ) + ratio = 0.0f; + else if (ratio > 1 ) + ratio = 1.0f; + + flare.origin[2] += ((float)height * (float)direction); + flare.data.sprite.radius = (float)width * ratio; + /*if ( i == 0 ) + Com_Printf( "Phase 3 Radius: %f\n", flare.data.sprite.radius );*/ + } + + trap_R_AddRefEntityToScene( &flare ); + } + + //dynamic light calculation + if ( cg.time < ( startTime + 2000 ) ) { + dlightRatio = (float)( cg.time - startTime ) * 0,0005; + } + else { + dlightRatio = 1.0f - (float)( cg.time - ( startTime + 2000 ) ) * 0,0005; + } + + //dynamic light FX + trap_R_AddLightToScene( origin, 80.0f * dlightRatio, 0.345, 0.624, 0.835 ); +} + +/* +------------------------- +TransporterParticle +------------------------- +*/ + +qboolean TransporterParticle( localEntity_t *le) +{ + vec3_t org, velocity = { 0, 0, 68 }; + vec3_t accel = { 0, 0, -12 }; + float scale, dscale; + qhandle_t shader; + + VectorCopy( le->refEntity.origin, org ); + org[2] += 0;//38; + + shader = ( le->data.spawner.dir[0] == 0 ) ? cgs.media.trans1Shader : cgs.media.trans2Shader; + scale = ( le->data.spawner.dir[0] == 0 ) ? 2.0 : 4.0; + dscale = ( le->data.spawner.dir[0] == 0 ) ? 4.0 : 24.0; + + le->data.spawner.dir[0]++; + + FX_AddSprite( org, + velocity, + qfalse, + scale, + dscale, + 1.0f, + 0.0f, + 0, + 0.0f, + 450.0f, + shader ); + + VectorScale( velocity, -1, velocity ); + VectorScale( accel, -1, accel ); + + FX_AddSprite( org, + velocity, + qfalse, + scale, + dscale, + 1.0f, + 0.0f, + 0, + 0.0f, + 450.0f, + shader ); + + return qtrue; +} + +/* +------------------------- +TransporterPad +------------------------- +*/ + +qboolean TransporterPad( localEntity_t *le) +{ + vec3_t org; + vec3_t up = {0,0,1}; + float scale, dscale; + qhandle_t shader; + + VectorCopy( le->refEntity.origin, org ); + org[2] -= 3; + + shader = cgs.media.trans1Shader; + scale = 20.0; + dscale = 2.0; + + FX_AddQuad( org, + up, + scale, + dscale, + 1.0f, + 0.0f, + 0, + 950.0f, + shader ); + return qtrue; +} + +/* +------------------------- +FX_Transporter +------------------------- +*/ + +void FX_Transporter( vec3_t origin ) +{ + vec3_t up = {0,0,1}; + + FX_AddSpawner( origin, up, NULL, NULL, qfalse, 0, 0, 200, TransporterParticle, 0 ); +// trap_S_StartSound( origin, NULL, CHAN_AUTO, cgs.media.teleInSound ); +} + +/* +------------------------- +FX_TransporterPad +------------------------- +*/ + +void FX_TransporterPad( vec3_t origin ) +{ + vec3_t up = {0,0,1}; + + FX_AddSpawner( origin, up, NULL, NULL, qfalse, 1000, 0, 0, TransporterPad, 0 ); +} + diff --git a/code/cgame/lua_cent.c b/code/cgame/lua_cent.c new file mode 100644 index 0000000..77f4e1f --- /dev/null +++ b/code/cgame/lua_cent.c @@ -0,0 +1,75 @@ +#include "cg_lua.h" + +#ifdef CG_LUA +static int Cent_GC(lua_State * L) +{ + + return 0; +} + +static int Cent_ToString(lua_State * L) +{ + cent_t *cent; + centity_t *ent; + char buf[MAX_STRING_CHARS]; + + cent = Lua_GetCent(L, 1); + ent = cent->e; + Com_sprintf(buf, sizeof(buf), "centity: id=%d pointer=%p\n", ent - cg_entities, ent); + lua_pushstring(L, buf); + + return 1; +} + +static const luaL_Reg Centity_ctor[] = { + {NULL, NULL} +}; + +static const luaL_Reg Centity_meta[] = { + {"__gc", Cent_GC}, + {"__tostring", Cent_ToString}, + + {NULL, NULL} +}; + +/*void dummy(gentity_t *ent) { + ent->timestamp; +}*/ + +int Luaopen_Cent(lua_State * L) +{ + luaL_newmetatable(L, "cgame.centity"); + + lua_pushstring(L, "__index"); + lua_pushvalue(L, -2); + lua_settable(L, -3); + + luaL_register(L, NULL, Centity_meta); + luaL_register(L, "centity", Centity_ctor); + + return 1; +} + +void Lua_PushCent(lua_State * L, centity_t * ent) +{ + cent_t *cent; + + if(!ent) + lua_pushnil(L); + else { + cent = (cent_t *)lua_newuserdata(L, sizeof(cent_t)); + luaL_getmetatable(L, "cgame.centity"); + lua_setmetatable(L, -2); + cent->e = ent; + } +} + +cent_t *Lua_GetCent(lua_State * L, int argNum) +{ + void *ud; + + ud = luaL_checkudata(L, argNum, "cgame.centity"); + luaL_argcheck(L, ud != NULL, argNum, "\'centity\' expected"); + return (cent_t *) ud; +} +#endif diff --git a/code/cgame/lua_cfx.c b/code/cgame/lua_cfx.c new file mode 100644 index 0000000..bb269a6 --- /dev/null +++ b/code/cgame/lua_cfx.c @@ -0,0 +1,19 @@ +#include "cg_lua.h" + +#ifdef CG_LUA + +void Lua_CFX_ParseMapFxFile(fileHandle_t *f) { + // TODO +} + +void Lua_CFX_LoadMapFxFile(void) { + char filename[MAX_QPATH]; + fileHandle_t file; + + sprintf(filename, "maps/%s.fx", cgs.mapname); + trap_FS_FOpenFile(filename, &file, FS_READ); + if(!file) return; + + Lua_CFX_ParseMapFxFile(&file); +} +#endif diff --git a/code/cgame/lua_refent.c b/code/cgame/lua_refent.c new file mode 100644 index 0000000..e3cdb61 --- /dev/null +++ b/code/cgame/lua_refent.c @@ -0,0 +1,475 @@ +#include "cg_lua.h" + +#ifdef CG_LUA +#include "cg_lua.h" + +#ifdef CG_LUA +static int Refent_GC(lua_State * L) +{ + + return 0; +} + +static int Refent_ToString(lua_State * L) +{ + rent_t *rent; + refEntity_t *ent; + char buf[MAX_STRING_CHARS]; + + rent = Lua_GetRent(L, 1); + ent = rent->r; + Com_sprintf(buf, sizeof(buf), "centity: pointer=%p\n", ent); + lua_pushstring(L, buf); + + return 1; +} + +static int Refent_GetRenderfx(lua_State *L) { + rent_t *rent; + + rent = Lua_GetRent(L, 1); + lua_pushinteger(L, rent->r->renderfx); + + return 1; +} + +static int Refent_SetRenderfx(lua_State *L) { + rent_t *rent; + int renderfx; + + rent = Lua_GetRent(L, 1); + renderfx = (int)luaL_checknumber(L, 2); + + rent->r->renderfx = renderfx; + + return 1; +} + +static int Refent_GetType(lua_State *L) { + rent_t *rent; + + rent = Lua_GetRent(L, 1); + lua_pushinteger(L, rent->r->reType); + + return 1; +} + +static int Refent_SetType(lua_State *L) { + rent_t *rent; + refEntityType_t type; + + rent = Lua_GetRent(L, 1); + type = (refEntityType_t)((int)luaL_checknumber(L, 2)); + + if(type < 0 || type >= RT_MAX_REF_ENTITY_TYPE) + return 1; + + return 1; +} + +static int Refent_GetHmodel(lua_State *L) { + rent_t *rent; + + rent = Lua_GetRent(L, 1); + lua_pushinteger(L, rent->r->hModel); + + return 1; +} + +static int Refent_SetHmodel(lua_State *L) { + rent_t *rent; + int hmodel; + + rent = Lua_GetRent(L, 1); + hmodel = (int)luaL_checknumber(L, 2); + + rent->r->hModel = hmodel; + + return 1; +} + +static int Refent_GetLightingOrigin(lua_State *L) { + rent_t *rent; + + rent = Lua_GetRent(L, 1); + Lua_PushVector(L, rent->r->lightingOrigin); + + return 1; +} + +static int Refent_SetLightingOrigin(lua_State *L) { + rent_t *rent; + vec_t *origin; + + rent = Lua_GetRent(L, 1); + origin = Lua_GetVector(L, 2); + + VectorCopy(origin, rent->r->lightingOrigin); + + return 1; +} + +static int Refent_GetShadowPlane(lua_State *L) { + rent_t *rent; + + rent = Lua_GetRent(L, 1); + lua_pushnumber(L, rent->r->shadowPlane); + + return 1; +} + +static int Refent_SetShadowPlane(lua_State *L) { + rent_t *rent; + float sp; + + rent = Lua_GetRent(L, 1); + sp = (float)luaL_checknumber(L, 2); + + rent->r->shadowPlane = sp; + + return 1; +} + +static int Refent_GetAxis0(lua_State *L) { + rent_t *rent; + + rent = Lua_GetRent(L, 1); + Lua_PushVector(L, rent->r->axis[0]); + + return 1; +} + +static int Refent_SetAxis0(lua_State *L) { + rent_t *rent; + vec_t *axis; + + rent = Lua_GetRent(L, 1); + axis = Lua_GetVector(L, 2); + + VectorCopy(axis, rent->r->axis[0]); + + return 1; +} + +static int Refent_GetAxis1(lua_State *L) { + rent_t *rent; + + rent = Lua_GetRent(L, 1); + Lua_PushVector(L, rent->r->axis[1]); + + return 1; +} + +static int Refent_SetAxis1(lua_State *L) { + rent_t *rent; + vec_t *axis; + + rent = Lua_GetRent(L, 1); + axis = Lua_GetVector(L, 2); + + VectorCopy(axis, rent->r->axis[1]); + + return 1; +} + +static int Refent_GetAxis2(lua_State *L) { + rent_t *rent; + + rent = Lua_GetRent(L, 1); + Lua_PushVector(L, rent->r->axis[2]); + + return 1; +} + +static int Refent_SetAxis2(lua_State *L) { + rent_t *rent; + vec_t *axis; + + rent = Lua_GetRent(L, 1); + axis = Lua_GetVector(L, 2); + + VectorCopy(axis, rent->r->axis[2]); + + return 1; +} + +static int Refent_UseNormAxis(lua_State *L) { + rent_t *rent; + + rent = Lua_GetRent(L, 1); + lua_pushboolean(L, (int)(!(rent->r->nonNormalizedAxes))); + + return 1; +} + +static int Refent_SetUseNormAxis(lua_State *L) { + rent_t *rent; + qboolean b; + + rent = Lua_GetRent(L, 1); + b = (qboolean)lua_toboolean(L, 2); + + rent->r->nonNormalizedAxes = (qboolean)(!b); + + return 1; +} + +static int Refent_GetOrigin(lua_State *L) { + rent_t *rent; + + rent = Lua_GetRent(L, 1); + Lua_PushVector(L, rent->r->origin); + + return 1; +} + +static int Refent_SetOrigin(lua_State *L) { + rent_t *rent; + vec_t *origin; + + rent = Lua_GetRent(L, 1); + origin = Lua_GetVector(L, 1); + + VectorCopy(origin, rent->r->origin); + + return 1; +} + +static int Refent_GetFrame(lua_State *L) { + rent_t *rent; + + rent = Lua_GetRent(L, 1); + lua_pushinteger(L, rent->r->frame); + + return 1; +} + +static int Refent_SetFrame(lua_State *L) { + rent_t *rent; + int frame; + + rent = Lua_GetRent(L, 1); + frame = (int)luaL_checknumber(L, 2); + + rent->r->frame = frame; + + return 1; +} + +static int Refent_GetOldOrigin(lua_State *L) { + rent_t *rent; + + rent = Lua_GetRent(L, 1); + Lua_PushVector(L, rent->r->oldorigin); + + return 1; +} + +static int Refent_SetOldOrigin(lua_State *L) { + rent_t *rent; + vec_t *vec; + + rent = Lua_GetRent(L, 1); + vec = Lua_GetVector(L, 2); + + VectorCopy(vec, rent->r->oldorigin); + + return 1; +} + +static int Refent_GetOldFrame(lua_State *L) { + rent_t *rent; + + rent = Lua_GetRent(L, 1); + lua_pushinteger(L, rent->r->oldframe); + + return 1; +} + +static int Refent_SetOldFrame(lua_State *L) { + rent_t *rent; + int of; + + rent = Lua_GetRent(L, 1); + of = (int)luaL_checknumber(L, 2); + + rent->r->oldframe = of; + + return 1; +} + +static int Refent_GetBacklerp(lua_State *L) { + rent_t *rent; + + rent = Lua_GetRent(L, 1); + lua_pushnumber(L, rent->r->backlerp); + + return 1; +} + +static int Refent_SetBacklerp(lua_State *L) { + rent_t *rent; + float bl; + + rent = Lua_GetRent(L, 1); + bl = (float)luaL_checknumber(L, 2); + + rent->r->backlerp = bl; + + return 1; +} + +static int Refent_GetSkinNum(lua_State *L) { + rent_t *rent; + + rent = Lua_GetRent(L, 1); + lua_pushinteger(L, rent->r->skinNum); + + return 1; +} + +static int Refent_SetSkinNum(lua_State *L) { + rent_t *rent; + int sn; + + rent = Lua_GetRent(L, 1); + sn = (int)luaL_checknumber(L, 2); + + rent->r->skinNum = sn; + + return 1; +} + +static int Refent_GetCustomSkin(lua_State *L) { + rent_t *rent; + + rent = Lua_GetRent(L, 1); + lua_pushinteger(L, rent->r->customSkin); + + return 1; +} + +static int Refent_SetCustomSkin(lua_State *L) { + rent_t *rent; + int cs; + + rent = Lua_GetRent(L, 1); + cs = (int)luaL_checknumber(L, 2); + + rent->r->customSkin = cs; + + return 1; +} + +static int Refent_GetCustomShader(lua_State *L) { + rent_t *rent; + + rent = Lua_GetRent(L, 1); + lua_pushinteger(L, rent->r->customShader); + + return 1; +} + +static int Refent_SetCustomShader(lua_State *L) { + rent_t *rent; + int cs; + + rent = Lua_GetRent(L, 1); + cs = (int)luaL_checknumber(L, 2); + + rent->r->customShader = cs; + + return 1; +} + + +static const luaL_Reg Refentity_ctor[] = { + {NULL, NULL} +}; + +static const luaL_Reg Refentity_meta[] = { + {"__gc", Refent_GC}, + {"__tostring", Refent_ToString}, + {"GetType", Refent_GetType}, + {"SetType", Refent_SetType}, + {"GetRenderfx", Refent_GetRenderfx}, + {"SetRenderfx", Refent_SetRenderfx}, + {"GetHmodel", Refent_GetHmodel}, + {"SetHmodel", Refent_SetHmodel}, + {"GetLightingOrigin", Refent_GetLightingOrigin}, + {"SetLightingOrigin", Refent_SetLightingOrigin}, + {"GetShadowPlane", Refent_GetShadowPlane}, + {"SetShadowPlane", Refent_SetShadowPlane}, + {"GetAxis0", Refent_GetAxis0}, + {"SetAxis0", Refent_SetAxis0}, + {"GetAxis1", Refent_GetAxis1}, + {"SetAxis1", Refent_SetAxis1}, + {"GetAxis2", Refent_GetAxis2}, + {"SetAxis2", Refent_SetAxis2}, + {"UseNormalizedAxis", Refent_UseNormAxis}, + {"SetUseNormalizedAxis", Refent_SetUseNormAxis}, + {"GetOrigin", Refent_GetOrigin}, + {"GetBeamFrom", Refent_GetOrigin}, + {"SetOrigin", Refent_SetOrigin}, + {"SetBeamFrom", Refent_SetOrigin}, + {"GetFrame", Refent_GetFrame}, + {"GetModelBeamDiameter", Refent_GetFrame}, + {"SetFrame", Refent_SetFrame}, + {"SetModelBeamDiameter", Refent_SetFrame}, + {"GetOldOrigin", Refent_GetOldOrigin}, + {"GetModelBeamTo", Refent_GetOldOrigin}, + {"SetOldOrigin", Refent_SetOldOrigin}, + {"SetModelBeamTo", Refent_SetOldOrigin}, + {"GetOldFrame", Refent_GetOldFrame}, + {"SetOldFrame", Refent_SetOldFrame}, + {"GetBacklerp", Refent_GetBacklerp}, + {"SetBacklerp", Refent_SetBacklerp}, + {"GetSkinNum", Refent_GetSkinNum}, + {"SetSkinNum", Refent_SetSkinNum}, + {"GetCustomSkin", Refent_GetCustomSkin}, + {"SetCustomSkin", Refent_SetCustomSkin}, + {"GetCustomShader", Refent_GetCustomShader}, + {"SetCustomShader", Refent_SetCustomShader}, + + {NULL, NULL} +}; + +int Luaopen_Rent(lua_State * L) +{ + luaL_newmetatable(L, "cgame.refentity"); + + lua_pushstring(L, "__index"); + lua_pushvalue(L, -2); + lua_settable(L, -3); + + luaL_register(L, NULL, Refentity_meta); + luaL_register(L, "refentity", Refentity_ctor); + + return 1; +} + +void Lua_PushRent(lua_State * L, refEntity_t * rent) +{ + rent_t *refent; + + if(!rent) + lua_pushnil(L); + else { + refent = (rent_t *)lua_newuserdata(L, sizeof(cent_t)); + luaL_getmetatable(L, "cgame.refentity"); + lua_setmetatable(L, -2); + refent->r = rent; + } +} + +rent_t *Lua_GetRent(lua_State * L, int argNum) +{ + void *ud; + + ud = luaL_checkudata(L, argNum, "cgame.refentity"); + luaL_argcheck(L, ud != NULL, argNum, "\'refentity\' expected"); + return (rent_t *) ud; +} +#endif + +#endif diff --git a/code/cgame/tr_types.h b/code/cgame/tr_types.h new file mode 100644 index 0000000..212dd48 --- /dev/null +++ b/code/cgame/tr_types.h @@ -0,0 +1,252 @@ +// Copyright (C) 1999-2000 Id Software, Inc. +// +#ifndef __TR_TYPES_H +#define __TR_TYPES_H + + +#define MAX_DLIGHTS 32 // can't be increased, because bit flags are used on surfaces + +#define ENTITYNUM_BITS 11 // can't be increased without changing drawsurf bit packing +#define MAX_ENTITIES ((1<lightingOrigin instead of refEntity->origin + // for lighting. This allows entities to sink into the floor + // with their origin going solid, and allows all parts of a + // player to get the same lighting +#define RF_SHADOW_PLANE 0x0100 // use refEntity->shadowPlane +#define RF_WRAP_FRAMES 0x0200 // mod the model frames by the maxframes to allow continuous + // animation without needing to know the frame count +#define RF_CAP_FRAMES 0x0400 // cap the model frames by the maxframes for one shot anims +#define RF_FORCE_ENT_ALPHA 0x0800 // Models should use ent alpha regardless of what the shader says. + + +// refdef flags +#define RDF_NOWORLDMODEL 1 // used for player configuration screen +#define RDF_HYPERSPACE 4 // teleportation effect + +typedef struct { + vec3_t xyz; + float st[2]; + byte modulate[4]; +} polyVert_t; + +typedef struct poly_s { + qhandle_t hShader; + int numVerts; + polyVert_t *verts; +} poly_t; + +typedef enum { + RT_MODEL, + RT_SPRITE, + RT_ORIENTEDSPRITE, // Replaces RT_POLY, which wasn't used. --Pat + RT_ALPHAVERTPOLY, // Individual alpha levels on each vertex + RT_BEAM, + RT_RAIL_CORE, + RT_RAIL_RINGS, + RT_LIGHTNING, + RT_PORTALSURFACE, // doesn't draw anything, just info for portals + RT_LINE, // New type for Trek MP --Pat + RT_ORIENTEDLINE, + RT_LINE2, // New line type for Trek MP, with taper support --Pat + RT_BEZIER, // what he said --keith + RT_CYLINDER, // Yet another Trek primitive! + RT_ELECTRICITY, // Yet another Trek primitive! + + RT_MAX_REF_ENTITY_TYPE +} refEntityType_t; + + +typedef struct { + refEntityType_t reType; + int renderfx; + + qhandle_t hModel; // opaque type outside refresh + + // most recent data + vec3_t lightingOrigin; // so multi-part models can be lit identically (RF_LIGHTING_ORIGIN) + float shadowPlane; // projection shadows go here, stencils go slightly lower + + vec3_t axis[3]; // rotation vectors + qboolean nonNormalizedAxes; // axis are not normalized, i.e. they have scale + float origin[3]; // also used as MODEL_BEAM's "from" + int frame; // also used as MODEL_BEAM's diameter + + // previous data for frame interpolation + float oldorigin[3]; // also used as MODEL_BEAM's "to" + int oldframe; + float backlerp; // 0.0 = current, 1.0 = old + + // texturing + int skinNum; // inline skin index + qhandle_t customSkin; // NULL for default skin + qhandle_t customShader; // use one image for the entire thing + + // misc + byte shaderRGBA[4]; // colors used by rgbgen entity shaders + float shaderTexCoord[2]; // texture coordinates used by tcMod entity modifiers + float shaderTime; // subtracted from refdef time to control effect start times + + // extra sprite information + union { + struct + { + float rotation; + float radius; + byte vertRGBA[4][4]; + } sprite; + struct + { + float width; + float width2; + float stscale; + } line; + struct // that whole put-the-opening-brace-on-the-same-line-as-the-beginning-of-the-definition coding style is fecal + // TiM: You're a fecal. I prefer that style :D + // TiM: (c)2008 You're a you're a fecal. ;P I've grown to like the other one now.... it's way easier to read XD + { + float width; + vec3_t control1; + vec3_t control2; + } bezier; + struct + { + float width; + float width2; + float stscale; + float height; + float bias; + qboolean wrap; + } cylinder; + struct + { + float width; + float deviation; + float stscale; + qboolean wrap; + qboolean taper; + } electricity; + } data; +} refEntity_t; + + +#define MAX_RENDER_STRINGS 8 +#define MAX_RENDER_STRING_LENGTH 32 + +typedef struct { + int x, y, width, height; + float fov_x, fov_y; + vec3_t vieworg; + vec3_t viewaxis[3]; // transformation matrix + + // time in milliseconds for shader effects and other time dependent rendering issues + int time; + + int rdflags; // RDF_NOWORLDMODEL, etc + + // 1 bits will prevent the associated area from rendering at all + byte areamask[MAX_MAP_AREA_BYTES]; + + // text messages for deform text shaders +// char text[MAX_RENDER_STRINGS][MAX_RENDER_STRING_LENGTH]; +} refdef_t; + + +typedef enum { + STEREO_CENTER, + STEREO_LEFT, + STEREO_RIGHT +} stereoFrame_t; + + +/* +** glconfig_t +** +** Contains variables specific to the OpenGL configuration +** being run right now. These are constant once the OpenGL +** subsystem is initialized. +*/ +typedef enum { + TC_NONE, + TC_S3TC, + TC_S3TC_DXT +} textureCompression_t; + +typedef enum { + GLDRV_ICD, // driver is integrated with window system + // WARNING: there are tests that check for + // > GLDRV_ICD for minidriverness, so this + // should always be the lowest value in this + // enum set + GLDRV_STANDALONE, // driver is a non-3Dfx standalone driver + GLDRV_VOODOO // driver is a 3Dfx standalone driver +} glDriverType_t; + +typedef enum { + GLHW_GENERIC, // where everthing works the way it should + GLHW_3DFX_2D3D, // Voodoo Banshee or Voodoo3, relevant since if this is + // the hardware type then there can NOT exist a secondary + // display adapter + GLHW_RIVA128, // where you can't interpolate alpha + GLHW_RAGEPRO, // where you can't modulate alpha on alpha textures + GLHW_PERMEDIA2 // where you don't have src*dst +} glHardwareType_t; + +typedef struct { + char renderer_string[MAX_STRING_CHARS]; + char vendor_string[MAX_STRING_CHARS]; + char version_string[MAX_STRING_CHARS]; + char extensions_string[2*MAX_STRING_CHARS]; + + int maxTextureSize; // queried from GL + int maxActiveTextures; // multitexture ability + + int colorBits, depthBits, stencilBits; + + glDriverType_t driverType; + glHardwareType_t hardwareType; + + qboolean deviceSupportsGamma; + textureCompression_t textureCompression; + qboolean textureEnvAddAvailable; + qboolean textureFilterAnisotropicAvailable; + + int vidWidth, vidHeight; + // aspect is the screen's physical width / height, which may be different + // than scrWidth / scrHeight if the pixels are non-square + // normal screens should be 4/3, but wide aspect monitors may be 16/9 + float windowAspect; + + int displayFrequency; + + // synonymous with "does rendering consume the entire screen?", therefore + // a Voodoo or Voodoo2 will have this set to TRUE, as will a Win32 ICD that + // used CDS. + qboolean isFullscreen; + qboolean stereoEnabled; + qboolean smpActive; // dual processor +} glconfig_t; + + +#if !defined _WIN32 + +#define _3DFX_DRIVER_NAME "libMesaVoodooGL.so" +#define OPENGL_DRIVER_NAME "libGL.so" + +#else + +#define _3DFX_DRIVER_NAME "3dfxvgl" +#define OPENGL_DRIVER_NAME "opengl32" + +#endif // !defined _WIN32 + + +#endif // __TR_TYPES_H diff --git a/code/game/Makefile b/code/game/Makefile new file mode 100644 index 0000000..93df927 --- /dev/null +++ b/code/game/Makefile @@ -0,0 +1,281 @@ +default: so +so: build_so + +# determine arch and platform +ARCH=$(shell uname -m | sed -e s/i.86/i386/) +PLATFORM=$(shell uname|sed -e s/_.*//|tr '[:upper:]' '[:lower:]') + +# compiler to use for building shared objects +CC = gcc + +# cross compiling +ifneq ($(PLATFORM), mingw32) +ifeq ($(TARGET), win32) + PLATFORM=mingw32 + ARCH=x86 + CC=i686-w64-mingw32-gcc + CFLAGS+=-m32 +endif +ifeq ($(TARGET), win64) + PLATFORM=mingw32 + ARCH=x64 + CC=x86_64-w64-mingw32-gcc + CFLAGS+=-m64 +endif +else +#we are compiling on windows +ARCH=x86 +endif + +# cflags for the compiler +ifeq ($(PLATFORM), mingw32) +SOCFLAGS = $(CFLAGS) +else +SOCFLAGS = $(CFLAGS) -fPIC +endif + +# set extension +ifeq ($(PLATFORM), mingw32) +EXT=dll +else +EXT=so +endif + +# warning level +ifeq ($(DEBUG), 1) +WL=-Wall +else +WL=-Wall -Wno-unused-but-set-variable +endif + +#defines +DEFINES= + +ifeq ($(SQL), 1) +DEFINES+=-DSQL +endif + +# game objects +OBJ = \ + g_ui.o \ + g_lua.o \ + q_shared.o \ + q_math.o \ + g_weapon.o \ + g_utils.o \ + g_usable.o \ + g_turrets.o \ + g_trigger.o \ + g_team.o \ + g_target.o \ + g_svcmds.o \ + g_spawn.o \ + g_session.o \ + g_mover.o \ + g_missile.o \ + g_misc.o \ + g_mem.o \ + g_main.o \ + g_log.o \ + g_items.o \ + g_fx.o \ + g_combat.o \ + g_sql.o \ + g_cmds.o \ + g_client.o \ + g_breakable.o \ + g_bot.o \ + g_arenas.o \ + g_active.o \ + g_cinematic.o \ + bg_slidemove.o \ + bg_pmove.o \ + bg_oums.o \ + bg_misc.o \ + ai_team.o \ + ai_main.o \ + ai_dmq3.o \ + ai_dmnet.o \ + ai_cmd.o \ + ai_chat.o \ + lua_game.o \ + lua_entity.o \ + lua_vector.o \ + lua_mover.o \ + lua_qmath.o \ + lua_cinematic.o \ + lua_sound.o \ + lua_weapons.o \ + lua_trace.o \ + lua_cvar.o \ + sqlite3.o \ + md5.o \ + list.o + +# game object for syscalls to the engine +SOOBJ = \ + g_syscalls.o + +# objects for lua +LUAOBJ = \ + lapi.o \ + lauxlib.o \ + lbaselib.o \ + lbitlib.o \ + lcode.o \ + lcorolib.o \ + lctype.o \ + ldblib.o \ + ldebug.o \ + ldo.o \ + ldump.o \ + lfunc.o \ + lgc.o \ + linit.o \ + liolib.o \ + llex.o \ + lmathlib.o \ + lmem.o \ + loadlib.o \ + lobject.o \ + lopcodes.o \ + loslib.o \ + lparser.o \ + lstate.o \ + lstring.o \ + lstrlib.o \ + ltable.o \ + ltablib.o \ + ltm.o \ + lua.o \ + luac.o \ + lundump.o \ + lvm.o \ + lzio.o + +# sqlite +SQLITE= \ + sqlite3.o + +# do cc for shared library +ifeq ($(DEBUG), 1) +DO_SOCC = $(CC) $(SOCFLAGS) $(WL) -g3 $(DEFINES) -o $@ -c $< +else +DO_SOCC = $(CC) $(SOCFLAGS) $(WL) $(DEFINES) -o $@ -c $< +endif +# do cc for lua +ifeq ($(DEBUF), 1) +DO_LUACC = $(CC) -O2 -Wall -g3 $(SOCFLAGS) -DLUA_COMPAT_ALL -o $@ -c $< +else +DO_LUACC = $(CC) -O2 -Wall $(SOCFLAGS) -DLUA_COMPAT_ALL -o $@ -c $< +endif + +build_so: DO_CC=$(DO_SOCC) + +# game +ai_chat.o : ai_chat.c; $(DO_CC) +ai_cmd.o : ai_cmd.c; $(DO_CC) +ai_dmnet.o : ai_dmnet.c; $(DO_CC) +ai_dmq3.o : ai_dmq3.c; $(DO_CC) +ai_main.o : ai_main.c; $(DO_CC) +ai_team.o : ai_team.c; $(DO_CC) +bg_misc.o : bg_misc.c; $(DO_CC) +bg_pmove.o : bg_pmove.c; $(DO_CC) +bg_slidemove.o : bg_slidemove.c; $(DO_CC) +g_active.o : g_active.c; $(DO_CC) +g_arenas.o : g_arenas.c; $(DO_CC) +g_bot.o : g_bot.c; $(DO_CC) +g_breakable.o : g_breakable.c; $(DO_CC) +g_client.o : g_client.c; $(DO_CC) +g_cmds.o : g_cmds.c; $(DO_CC) +g_combat.o : g_combat.c; $(DO_CC) +g_fx.o : g_fx.c; $(DO_CC) +g_items.o : g_items.c; $(DO_CC) +g_log.o : g_log.c; $(DO_CC) +g_main.o : g_main.c; $(DO_CC) +g_mem.o : g_mem.c; $(DO_CC) +g_misc.o : g_misc.c; $(DO_CC) +g_missile.o : g_missile.c; $(DO_CC) +g_mover.o : g_mover.c; $(DO_CC) +g_session.o : g_session.c; $(DO_CC) +g_spawn.o : g_spawn.c; $(DO_CC) +g_svcmds.o : g_svcmds.c; $(DO_CC) +g_target.o : g_target.c; $(DO_CC) +g_team.o : g_team.c; $(DO_CC) +g_trigger.o : g_trigger.c; $(DO_CC) +g_turrets.o : g_turrets.c; $(DO_CC) +g_usable.o : g_usable.c; $(DO_CC) +g_utils.o : g_utils.c; $(DO_CC) +g_weapon.o : g_weapon.c; $(DO_CC) +q_math.o : q_math.c; $(DO_CC) +q_shared.o : q_shared.c; $(DO_CC) +g_lua.o: g_lua.c; $(DO_CC) +g_ui.o: g_ui.c; $(DO_CC) +g_sql.o: g_sql.c; $(DO_CC) +g_cinematic.o: g_cinematic.c; $(DO_CC) +bg_oums.o : bg_oums.c; $(DO_CC) +lua_game.o: lua_game.c; $(DO_CC) +lua_entity.o: lua_entity.c; $(DO_CC) +lua_mover.o: lua_mover.c; $(DO_CC) +lua_qmath.o: lua_qmath.c; $(DO_CC) +lua_vector.o: lua_vector.c; $(DO_CC) +lua_cinematic.o: lua_cinematic.c; $(DO_CC) +lua_sound.o: lua_sound.c; $(DO_CC) +lua_weapons.o: lua_weapons.c; $(DO_CC) +lua_trace.o: lua_trace.c; $(DO_CC) +lua_cvar.o: lua_cvar.c; $(DO_CC) +sqlite3.o: sqlite3.c; $(DO_CC) +md5.o: md5.c; $(DO_CC) +list.o: list.c; $(DO_CC) + +# game syscalls +g_syscalls.o : g_syscalls.c; $(DO_CC) + +# bg_lib +bg_lib.o : bg_lib.c; $(DO_CC) + +# lua +lapi.o: lapi.c; $(DO_LUACC) +lauxlib.o: lauxlib.c; $(DO_LUACC) +lbaselib.o: lbaselib.c; $(DO_LUACC) +lbitlib.o: lbitlib.c; $(DO_LUACC) +lcode.o: lcode.c; $(DO_LUACC) +lcorolib.o: lcorolib.c; $(DO_LUACC) +lctype.o: lctype.c; $(DO_LUACC) +ldblib.o: ldblib.c; $(DO_LUACC) +ldebug.o: ldebug.c; $(DO_LUACC) +ldo.o: ldo.c; $(DO_LUACC) +ldump.o: ldump.c; $(DO_LUACC) +lfunc.o: lfunc.c; $(DO_LUACC) +lgc.o: lgc.c; $(DO_LUACC) +linit.o: linit.c; $(DO_LUACC) +liolib.o: liolib.c; $(DO_LUACC) +llex.o: llex.c; $(DO_LUACC) +lmathlib.o: lmathlib.c; $(DO_LUACC) +lmem.o: lmem.c; $(DO_LUACC) +loadlib.o: loadlib.c; $(DO_LUACC) +lobject.o: lobject.c; $(DO_LUACC) +lopcodes.o: lopcodes.c; $(DO_LUACC) +loslib.o: loslib.c; $(DO_LUACC) +lparser.o: lparser.c; $(DO_LUACC) +lstate.o: lstate.c; $(DO_LUACC) +lstring.o: lstring.c; $(DO_LUACC) +lstrlib.o: lstrlib.c; $(DO_LUACC) +ltable.o: ltable.c; $(DO_LUACC) +ltablib.o: ltablib.c; $(DO_LUACC) +ltm.o: ltm.c; $(DO_LUACC) +lua.o: lua.c; $(DO_LUACC) +luac.o: luac.c; $(DO_LUACC) +lundump.o: lundump.c; $(DO_LUACC) +lvm.o: lvm.c; $(DO_LUACC) +lzio.o: lzio.c; $(DO_LUACC) + +build_so: $(OBJ) $(SOOBJ) $(LUAOBJ) +ifeq ($(PLATFORM), mingw32) + $(CC) -shared -Wl,--export-all-symbols,-soname,qqgame$(ARCH).$(EXT) -o qagame$(ARCH).$(EXT) $(OBJ) $(SOOBJ) $(LUAOBJ) -lm +else + $(CC) -shared -Wl,--export-dynamic,-soname,qagame$(ARCH).$(EXT) -o qagame$(ARCH).$(EXT) $(OBJ) $(SOOBJ) $(LUAOBJ) -lm -lpthread +endif + +clean: + rm -f *.o *.$(EXT) diff --git a/code/game/ToDo.txt b/code/game/ToDo.txt new file mode 100644 index 0000000..0dcf21d --- /dev/null +++ b/code/game/ToDo.txt @@ -0,0 +1,4 @@ +- Debug +- Static code analysis? +- throw out unused things +- Holodeck Entity ... \ No newline at end of file diff --git a/code/game/ai_chat.c b/code/game/ai_chat.c index 3a5928b..3ea3160 100644 --- a/code/game/ai_chat.c +++ b/code/game/ai_chat.c @@ -1,24 +1,4 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // /***************************************************************************** @@ -26,20 +6,24 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * desc: Quake3 bot AI * - * $Archive: /MissionPack/code/game/ai_chat.c $ + * $Archive: /StarTrek/Code-DM/game/ai_chat.c $ + * $Author: Mgummelt $ + * $Revision: 7 $ + * $Modtime: 3/09/01 11:52a $ + * $Date: 3/09/01 12:02p $ * *****************************************************************************/ #include "g_local.h" -#include "../botlib/botlib.h" -#include "../botlib/be_aas.h" -#include "../botlib/be_ea.h" -#include "../botlib/be_ai_char.h" -#include "../botlib/be_ai_chat.h" -#include "../botlib/be_ai_gen.h" -#include "../botlib/be_ai_goal.h" -#include "../botlib/be_ai_move.h" -#include "../botlib/be_ai_weap.h" +#include "botlib.h" +#include "be_aas.h" +#include "be_ea.h" +#include "be_ai_char.h" +#include "be_ai_chat.h" +#include "be_ai_gen.h" +#include "be_ai_goal.h" +#include "be_ai_move.h" +#include "be_ai_weap.h" // #include "ai_main.h" #include "ai_dmq3.h" @@ -52,13 +36,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "syn.h" //synonyms #include "match.h" //string matching types and vars -// for the voice chats -#ifdef MISSIONPACK -#include "../../ui/menudef.h" -#endif - -#define TIME_BETWEENCHATTING 25 - /* ================== @@ -68,13 +45,13 @@ BotNumActivePlayers int BotNumActivePlayers(void) { int i, num; char buf[MAX_INFO_STRING]; - static int maxclients; + static int maxclis; - if (!maxclients) - maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); + if (!maxclis) + maxclis = trap_Cvar_VariableIntegerValue("sv_maxclients"); num = 0; - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { + for (i = 0; i < maxclis && i < MAX_CLIENTS; i++) { trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf)); //if no config string or no name if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue; @@ -94,14 +71,14 @@ BotIsFirstInRankings int BotIsFirstInRankings(bot_state_t *bs) { int i, score; char buf[MAX_INFO_STRING]; - static int maxclients; + static int maxclis; playerState_t ps; - if (!maxclients) - maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); + if (!maxclis) + maxclis = trap_Cvar_VariableIntegerValue("sv_maxclients"); score = bs->cur_ps.persistant[PERS_SCORE]; - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { + for (i = 0; i < maxclis && i < MAX_CLIENTS; i++) { trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf)); //if no config string or no name if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue; @@ -122,14 +99,14 @@ BotIsLastInRankings int BotIsLastInRankings(bot_state_t *bs) { int i, score; char buf[MAX_INFO_STRING]; - static int maxclients; + static int maxclis; playerState_t ps; - if (!maxclients) - maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); + if (!maxclis) + maxclis = trap_Cvar_VariableIntegerValue("sv_maxclients"); score = bs->cur_ps.persistant[PERS_SCORE]; - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { + for (i = 0; i < maxclis && i < MAX_CLIENTS; i++) { trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf)); //if no config string or no name if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue; @@ -151,15 +128,15 @@ char *BotFirstClientInRankings(void) { int i, bestscore, bestclient; char buf[MAX_INFO_STRING]; static char name[32]; - static int maxclients; + static int maxclis; playerState_t ps; - if (!maxclients) - maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); + if (!maxclis) + maxclis = trap_Cvar_VariableIntegerValue("sv_maxclients"); bestscore = -999999; bestclient = 0; - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { + for (i = 0; i < maxclis && i < MAX_CLIENTS; i++) { trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf)); //if no config string or no name if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue; @@ -185,15 +162,15 @@ char *BotLastClientInRankings(void) { int i, worstscore, bestclient; char buf[MAX_INFO_STRING]; static char name[32]; - static int maxclients; + static int maxclis; playerState_t ps; - if (!maxclients) - maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); + if (!maxclis) + maxclis = trap_Cvar_VariableIntegerValue("sv_maxclients"); worstscore = 999999; bestclient = 0; - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { + for (i = 0; i < maxclis && i < MAX_CLIENTS; i++) { trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf)); //if no config string or no name if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue; @@ -219,15 +196,15 @@ char *BotRandomOpponentName(bot_state_t *bs) { int i, count; char buf[MAX_INFO_STRING]; int opponents[MAX_CLIENTS], numopponents; - static int maxclients; + static int maxclis; static char name[32]; - if (!maxclients) - maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); + if (!maxclis) + maxclis = trap_Cvar_VariableIntegerValue("sv_maxclients"); numopponents = 0; opponents[0] = 0; - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { + for (i = 0; i < maxclis && i < MAX_CLIENTS; i++) { if (i == bs->client) continue; // trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf)); @@ -280,27 +257,32 @@ BotWeaponNameForMeansOfDeath char *BotWeaponNameForMeansOfDeath(int mod) { switch(mod) { - case MOD_SHOTGUN: return "Shotgun"; - case MOD_GAUNTLET: return "Gauntlet"; - case MOD_MACHINEGUN: return "Machinegun"; + case MOD_PHASER: + case MOD_PHASER_ALT: return "Phaser"; + case MOD_CRIFLE: + case MOD_CRIFLE_SPLASH: + case MOD_CRIFLE_ALT: + case MOD_CRIFLE_ALT_SPLASH: return "Compression Rifle"; + case MOD_IMOD: + case MOD_IMOD_ALT: return "Infinity Modulator"; + case MOD_SCAVENGER: + case MOD_SCAVENGER_ALT: + case MOD_SCAVENGER_ALT_SPLASH: return "Scavenger Rifle"; + case MOD_STASIS: + case MOD_STASIS_ALT: return "Stasis Weapon"; case MOD_GRENADE: - case MOD_GRENADE_SPLASH: return "Grenade Launcher"; - case MOD_ROCKET: - case MOD_ROCKET_SPLASH: return "Rocket Launcher"; - case MOD_PLASMA: - case MOD_PLASMA_SPLASH: return "Plasmagun"; - case MOD_RAILGUN: return "Railgun"; - case MOD_LIGHTNING: return "Lightning Gun"; - case MOD_BFG: - case MOD_BFG_SPLASH: return "BFG10K"; -#ifdef MISSIONPACK - case MOD_NAIL: return "Nailgun"; - case MOD_CHAINGUN: return "Chaingun"; - case MOD_PROXIMITY_MINE: return "Proximity Launcher"; - case MOD_KAMIKAZE: return "Kamikaze"; - case MOD_JUICED: return "Prox mine"; -#endif - case MOD_GRAPPLE: return "Grapple"; + case MOD_GRENADE_SPLASH: + case MOD_GRENADE_ALT_SPLASH: return "Grenade Launcher"; + case MOD_TETRION: + case MOD_TETRION_ALT: return "Tetryon Disruptor"; + case MOD_DREADNOUGHT: + case MOD_DREADNOUGHT_ALT: return "Arc Welder"; + case MOD_QUANTUM: + case MOD_QUANTUM_SPLASH: + case MOD_QUANTUM_ALT: + case MOD_QUANTUM_ALT_SPLASH: return "Photon Burst Cannon"; + case MOD_KNOCKOUT: return "Hypo"; + default: return "[unknown weapon]"; } } @@ -313,26 +295,17 @@ BotRandomWeaponName char *BotRandomWeaponName(void) { int rnd; -#ifdef MISSIONPACK - rnd = random() * 11.9; -#else rnd = random() * 8.9; -#endif switch(rnd) { - case 0: return "Gauntlet"; - case 1: return "Shotgun"; - case 2: return "Machinegun"; - case 3: return "Grenade Launcher"; - case 4: return "Rocket Launcher"; - case 5: return "Plasmagun"; - case 6: return "Railgun"; - case 7: return "Lightning Gun"; -#ifdef MISSIONPACK - case 8: return "Nailgun"; - case 9: return "Chaingun"; - case 10: return "Proximity Launcher"; -#endif - default: return "BFG10K"; + case 0: return "Phaser"; + case 1: return "Compression Rifle"; + case 2: return "Infinity Modulator"; + case 3: return "Scavenger Rifle"; + case 4: return "Stasis Weapon"; + case 5: return "Grenade Launcher"; + case 6: return "Tetryon Disruptor"; + case 7: return "Dermal Regenerator"; + default: return "Photon Burst Cannon"; } } @@ -342,8 +315,9 @@ BotVisibleEnemies ================== */ int BotVisibleEnemies(bot_state_t *bs) { - float vis; + float vis, dist; int i; + vec3_t dir; aas_entityinfo_t entinfo; for (i = 0; i < MAX_CLIENTS; i++) { @@ -359,6 +333,9 @@ int BotVisibleEnemies(bot_state_t *bs) { if (EntityIsInvisible(&entinfo) && !EntityIsShooting(&entinfo)) { continue; } + //calculate the distance towards the enemy + VectorSubtract(entinfo.origin, bs->origin, dir); + dist = VectorLength(dir); //if on the same team if (BotSameTeam(bs, i)) continue; //check if the enemy is visible @@ -381,7 +358,6 @@ int BotValidChatPosition(bot_state_t *bs) { if (BotIsDead(bs)) return qtrue; //never start chatting with a powerup if (bs->inventory[INVENTORY_QUAD] || - bs->inventory[INVENTORY_ENVIRONMENTSUIT] || bs->inventory[INVENTORY_HASTE] || bs->inventory[INVENTORY_INVISIBILITY] || bs->inventory[INVENTORY_REGEN] || @@ -418,12 +394,10 @@ int BotChat_EnterGame(bot_state_t *bs) { float rnd; if (bot_nochat.integer) return qfalse; - if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; + if (bs->lastchat_time > trap_AAS_Time() - 3) return qfalse; //don't chat in teamplay if (TeamPlayIsOn()) return qfalse; - // don't chat in tournament mode - if (gametype == GT_TOURNAMENT) return qfalse; - rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_ENTEREXITGAME, 0, 1); + rnd = 0; if (!bot_fastchat.integer) { if (random() > rnd) return qfalse; } @@ -436,7 +410,7 @@ int BotChat_EnterGame(bot_state_t *bs) { "[invalid var]", // 3 BotMapTitle(), // 4 NULL); - bs->lastchat_time = FloatTime(); + bs->lastchat_time = trap_AAS_Time(); bs->chatto = CHAT_ALL; return qtrue; } @@ -451,12 +425,10 @@ int BotChat_ExitGame(bot_state_t *bs) { float rnd; if (bot_nochat.integer) return qfalse; - if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; + if (bs->lastchat_time > trap_AAS_Time() - 3) return qfalse; //don't chat in teamplay if (TeamPlayIsOn()) return qfalse; - // don't chat in tournament mode - if (gametype == GT_TOURNAMENT) return qfalse; - rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_ENTEREXITGAME, 0, 1); + rnd = 0; if (!bot_fastchat.integer) { if (random() > rnd) return qfalse; } @@ -469,7 +441,7 @@ int BotChat_ExitGame(bot_state_t *bs) { "[invalid var]", // 3 BotMapTitle(), // 4 NULL); - bs->lastchat_time = FloatTime(); + bs->lastchat_time = trap_AAS_Time(); bs->chatto = CHAT_ALL; return qtrue; } @@ -485,15 +457,10 @@ int BotChat_StartLevel(bot_state_t *bs) { if (bot_nochat.integer) return qfalse; if (BotIsObserver(bs)) return qfalse; - if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; + if (bs->lastchat_time > trap_AAS_Time() - 3) return qfalse; //don't chat in teamplay - if (TeamPlayIsOn()) { - trap_EA_Command(bs->client, "vtaunt"); - return qfalse; - } - // don't chat in tournament mode - if (gametype == GT_TOURNAMENT) return qfalse; - rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_STARTENDLEVEL, 0, 1); + if (TeamPlayIsOn()) return qfalse; + rnd = 0; if (!bot_fastchat.integer) { if (random() > rnd) return qfalse; } @@ -501,7 +468,7 @@ int BotChat_StartLevel(bot_state_t *bs) { BotAI_BotInitialChat(bs, "level_start", EasyClientName(bs->client, name, 32), // 0 NULL); - bs->lastchat_time = FloatTime(); + bs->lastchat_time = trap_AAS_Time(); bs->chatto = CHAT_ALL; return qtrue; } @@ -517,18 +484,10 @@ int BotChat_EndLevel(bot_state_t *bs) { if (bot_nochat.integer) return qfalse; if (BotIsObserver(bs)) return qfalse; - if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; - // teamplay - if (TeamPlayIsOn()) - { - if (BotIsFirstInRankings(bs)) { - trap_EA_Command(bs->client, "vtaunt"); - } - return qtrue; - } - // don't chat in tournament mode - if (gametype == GT_TOURNAMENT) return qfalse; - rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_STARTENDLEVEL, 0, 1); + if (bs->lastchat_time > trap_AAS_Time() - 3) return qfalse; + //don't chat in teamplay + if (TeamPlayIsOn()) return qfalse; + rnd = 0; if (!bot_fastchat.integer) { if (random() > rnd) return qfalse; } @@ -561,7 +520,7 @@ int BotChat_EndLevel(bot_state_t *bs) { BotMapTitle(), // 4 NULL); } - bs->lastchat_time = FloatTime(); + bs->lastchat_time = trap_AAS_Time(); bs->chatto = CHAT_ALL; return qtrue; } @@ -576,10 +535,8 @@ int BotChat_Death(bot_state_t *bs) { float rnd; if (bot_nochat.integer) return qfalse; - if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; - rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_DEATH, 0, 1); - // don't chat in tournament mode - if (gametype == GT_TOURNAMENT) return qfalse; + if (bs->lastchat_time > trap_AAS_Time() - 3) return qfalse; + rnd = 0; //if fast chatting is off if (!bot_fastchat.integer) { if (random() > rnd) return qfalse; @@ -598,11 +555,8 @@ int BotChat_Death(bot_state_t *bs) { } else { - //teamplay - if (TeamPlayIsOn()) { - trap_EA_Command(bs->client, "vtaunt"); - return qtrue; - } + //don't chat in teamplay + if (TeamPlayIsOn()) return qfalse; // if (bs->botdeathtype == MOD_WATER) BotAI_BotInitialChat(bs, "death_drown", BotRandomOpponentName(bs), NULL); @@ -615,17 +569,16 @@ int BotChat_Death(bot_state_t *bs) { else if (bs->botsuicide || //all other suicides by own weapon bs->botdeathtype == MOD_CRUSH || bs->botdeathtype == MOD_SUICIDE || + bs->botdeathtype == MOD_RESPAWN || bs->botdeathtype == MOD_TARGET_LASER || bs->botdeathtype == MOD_TRIGGER_HURT || - bs->botdeathtype == MOD_UNKNOWN) + bs->botdeathtype == MOD_UNKNOWN || + bs->botdeathtype == MOD_EXPLOSION) BotAI_BotInitialChat(bs, "death_suicide", BotRandomOpponentName(bs), NULL); else if (bs->botdeathtype == MOD_TELEFRAG) BotAI_BotInitialChat(bs, "death_telefrag", name, NULL); -#ifdef MISSIONPACK - else if (bs->botdeathtype == MOD_KAMIKAZE && trap_BotNumInitialChats(bs->cs, "death_kamikaze")) - BotAI_BotInitialChat(bs, "death_kamikaze", name, NULL); -#endif else { +#if 0 if ((bs->botdeathtype == MOD_GAUNTLET || bs->botdeathtype == MOD_RAILGUN || bs->botdeathtype == MOD_BFG || @@ -648,7 +601,10 @@ int BotChat_Death(bot_state_t *bs) { NULL); } //choose between insult and praise - else if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_INSULT, 0, 1)) { + else +#endif //0 + + if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_INSULT, 0, 1)) { BotAI_BotInitialChat(bs, "death_insult", name, // 0 BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1 @@ -663,7 +619,7 @@ int BotChat_Death(bot_state_t *bs) { } bs->chatto = CHAT_ALL; } - bs->lastchat_time = FloatTime(); + bs->lastchat_time = trap_AAS_Time(); return qtrue; } @@ -677,10 +633,8 @@ int BotChat_Kill(bot_state_t *bs) { float rnd; if (bot_nochat.integer) return qfalse; - if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; - rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_KILL, 0, 1); - // don't chat in tournament mode - if (gametype == GT_TOURNAMENT) return qfalse; + if (bs->lastchat_time > trap_AAS_Time() - 3) return qfalse; + rnd = 0; //if fast chat is off if (!bot_fastchat.integer) { if (random() > rnd) return qfalse; @@ -701,24 +655,20 @@ int BotChat_Kill(bot_state_t *bs) { else { //don't chat in teamplay - if (TeamPlayIsOn()) { - trap_EA_Command(bs->client, "vtaunt"); - return qfalse; // don't wait - } + if (TeamPlayIsOn()) return qfalse; // +#if 0 if (bs->enemydeathtype == MOD_GAUNTLET) { BotAI_BotInitialChat(bs, "kill_gauntlet", name, NULL); } else if (bs->enemydeathtype == MOD_RAILGUN) { BotAI_BotInitialChat(bs, "kill_rail", name, NULL); } +#endif // 0 + else if (bs->enemydeathtype == MOD_TELEFRAG) { BotAI_BotInitialChat(bs, "kill_telefrag", name, NULL); } -#ifdef MISSIONPACK - else if (bs->botdeathtype == MOD_KAMIKAZE && trap_BotNumInitialChats(bs->cs, "kill_kamikaze")) - BotAI_BotInitialChat(bs, "kill_kamikaze", name, NULL); -#endif //choose between insult and praise else if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_INSULT, 0, 1)) { BotAI_BotInitialChat(bs, "kill_insult", name, NULL); @@ -727,7 +677,7 @@ int BotChat_Kill(bot_state_t *bs) { BotAI_BotInitialChat(bs, "kill_praise", name, NULL); } } - bs->lastchat_time = FloatTime(); + bs->lastchat_time = trap_AAS_Time(); return qtrue; } @@ -741,14 +691,12 @@ int BotChat_EnemySuicide(bot_state_t *bs) { float rnd; if (bot_nochat.integer) return qfalse; - if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; + if (bs->lastchat_time > trap_AAS_Time() - 3) return qfalse; if (BotNumActivePlayers() <= 1) return qfalse; // - rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_ENEMYSUICIDE, 0, 1); + rnd = 0; //don't chat in teamplay if (TeamPlayIsOn()) return qfalse; - // don't chat in tournament mode - if (gametype == GT_TOURNAMENT) return qfalse; //if fast chat is off if (!bot_fastchat.integer) { if (random() > rnd) return qfalse; @@ -760,7 +708,7 @@ int BotChat_EnemySuicide(bot_state_t *bs) { if (bs->enemy >= 0) EasyClientName(bs->enemy, name, 32); else strcpy(name, ""); BotAI_BotInitialChat(bs, "enemy_suicide", name, NULL); - bs->lastchat_time = FloatTime(); + bs->lastchat_time = trap_AAS_Time(); bs->chatto = CHAT_ALL; return qtrue; } @@ -776,7 +724,7 @@ int BotChat_HitTalking(bot_state_t *bs) { float rnd; if (bot_nochat.integer) return qfalse; - if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; + if (bs->lastchat_time > trap_AAS_Time() - 3) return qfalse; if (BotNumActivePlayers() <= 1) return qfalse; lasthurt_client = g_entities[bs->client].client->lasthurt_client; if (!lasthurt_client) return qfalse; @@ -784,11 +732,9 @@ int BotChat_HitTalking(bot_state_t *bs) { // if (lasthurt_client < 0 || lasthurt_client >= MAX_CLIENTS) return qfalse; // - rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITTALKING, 0, 1); + rnd = 0; //don't chat in teamplay if (TeamPlayIsOn()) return qfalse; - // don't chat in tournament mode - if (gametype == GT_TOURNAMENT) return qfalse; //if fast chat is off if (!bot_fastchat.integer) { if (random() > rnd * 0.5) return qfalse; @@ -796,10 +742,10 @@ int BotChat_HitTalking(bot_state_t *bs) { if (!BotValidChatPosition(bs)) return qfalse; // ClientName(g_entities[bs->client].client->lasthurt_client, name, sizeof(name)); - weap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_mod); + weap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_client); // BotAI_BotInitialChat(bs, "hit_talking", name, weap, NULL); - bs->lastchat_time = FloatTime(); + bs->lastchat_time = trap_AAS_Time(); bs->chatto = CHAT_ALL; return qtrue; } @@ -822,13 +768,11 @@ int BotChat_HitNoDeath(bot_state_t *bs) { if (lasthurt_client < 0 || lasthurt_client >= MAX_CLIENTS) return qfalse; // if (bot_nochat.integer) return qfalse; - if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; + if (bs->lastchat_time > trap_AAS_Time() - 3) return qfalse; if (BotNumActivePlayers() <= 1) return qfalse; - rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITNODEATH, 0, 1); + rnd = 0; //don't chat in teamplay if (TeamPlayIsOn()) return qfalse; - // don't chat in tournament mode - if (gametype == GT_TOURNAMENT) return qfalse; //if fast chat is off if (!bot_fastchat.integer) { if (random() > rnd * 0.5) return qfalse; @@ -844,7 +788,7 @@ int BotChat_HitNoDeath(bot_state_t *bs) { weap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_mod); // BotAI_BotInitialChat(bs, "hit_nodeath", name, weap, NULL); - bs->lastchat_time = FloatTime(); + bs->lastchat_time = trap_AAS_Time(); bs->chatto = CHAT_ALL; return qtrue; } @@ -860,13 +804,11 @@ int BotChat_HitNoKill(bot_state_t *bs) { aas_entityinfo_t entinfo; if (bot_nochat.integer) return qfalse; - if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; + if (bs->lastchat_time > trap_AAS_Time() - 3) return qfalse; if (BotNumActivePlayers() <= 1) return qfalse; - rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITNOKILL, 0, 1); + rnd = 0; //don't chat in teamplay if (TeamPlayIsOn()) return qfalse; - // don't chat in tournament mode - if (gametype == GT_TOURNAMENT) return qfalse; //if fast chat is off if (!bot_fastchat.integer) { if (random() > rnd * 0.5) return qfalse; @@ -882,7 +824,7 @@ int BotChat_HitNoKill(bot_state_t *bs) { weap = BotWeaponNameForMeansOfDeath(g_entities[bs->enemy].client->lasthurt_mod); // BotAI_BotInitialChat(bs, "hit_nokill", name, weap, NULL); - bs->lastchat_time = FloatTime(); + bs->lastchat_time = trap_AAS_Time(); bs->chatto = CHAT_ALL; return qtrue; } @@ -898,36 +840,29 @@ int BotChat_Random(bot_state_t *bs) { if (bot_nochat.integer) return qfalse; if (BotIsObserver(bs)) return qfalse; - if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; - // don't chat in tournament mode - if (gametype == GT_TOURNAMENT) return qfalse; + if (bs->lastchat_time > trap_AAS_Time() - 3) return qfalse; + //don't chat in teamplay + if (TeamPlayIsOn()) return qfalse; //don't chat when doing something important :) if (bs->ltgtype == LTG_TEAMHELP || bs->ltgtype == LTG_TEAMACCOMPANY || bs->ltgtype == LTG_RUSHBASE) return qfalse; // - rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_RANDOM, 0, 1); + rnd = 0; if (random() > bs->thinktime * 0.1) return qfalse; if (!bot_fastchat.integer) { if (random() > rnd) return qfalse; if (random() > 0.25) return qfalse; } if (BotNumActivePlayers() <= 1) return qfalse; - // if (!BotValidChatPosition(bs)) return qfalse; // - if (BotVisibleEnemies(bs)) return qfalse; - // if (bs->lastkilledplayer == bs->client) { strcpy(name, BotRandomOpponentName(bs)); } else { EasyClientName(bs->lastkilledplayer, name, sizeof(name)); } - if (TeamPlayIsOn()) { - trap_EA_Command(bs->client, "vtaunt"); - return qfalse; // don't wait - } // if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_MISC, 0, 1)) { BotAI_BotInitialChat(bs, "random_misc", @@ -949,7 +884,7 @@ int BotChat_Random(bot_state_t *bs) { BotRandomWeaponName(), // 5 NULL); } - bs->lastchat_time = FloatTime(); + bs->lastchat_time = trap_AAS_Time(); bs->chatto = CHAT_ALL; return qtrue; } @@ -960,11 +895,10 @@ BotChatTime ================== */ float BotChatTime(bot_state_t *bs) { - //int cpm; + int cpm; - //cpm = trap_Characteristic_BInteger(bs->character, CHARACTERISTIC_CHAT_CPM, 1, 4000); - - return 2.0; //(float) trap_BotChatLength(bs->cs) * 30 / cpm; + cpm = 4000; + return 4000; } /* @@ -988,7 +922,7 @@ void BotChatTest(bot_state_t *bs) { "[invalid var]", // 3 BotMapTitle(), // 4 NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } num = trap_BotNumInitialChats(bs->cs, "game_exit"); for (i = 0; i < num; i++) @@ -1000,7 +934,7 @@ void BotChatTest(bot_state_t *bs) { "[invalid var]", // 3 BotMapTitle(), // 4 NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } num = trap_BotNumInitialChats(bs->cs, "level_start"); for (i = 0; i < num; i++) @@ -1008,7 +942,7 @@ void BotChatTest(bot_state_t *bs) { BotAI_BotInitialChat(bs, "level_start", EasyClientName(bs->client, name, 32), // 0 NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } num = trap_BotNumInitialChats(bs->cs, "level_end_victory"); for (i = 0; i < num; i++) @@ -1020,7 +954,7 @@ void BotChatTest(bot_state_t *bs) { BotLastClientInRankings(), // 3 BotMapTitle(), // 4 NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } num = trap_BotNumInitialChats(bs->cs, "level_end_lose"); for (i = 0; i < num; i++) @@ -1032,7 +966,7 @@ void BotChatTest(bot_state_t *bs) { BotLastClientInRankings(), // 3 BotMapTitle(), // 4 NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } num = trap_BotNumInitialChats(bs->cs, "level_end"); for (i = 0; i < num; i++) @@ -1044,7 +978,7 @@ void BotChatTest(bot_state_t *bs) { BotLastClientInRankings(), // 3 BotMapTitle(), // 4 NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } EasyClientName(bs->lastkilledby, name, sizeof(name)); num = trap_BotNumInitialChats(bs->cs, "death_drown"); @@ -1052,37 +986,37 @@ void BotChatTest(bot_state_t *bs) { { // BotAI_BotInitialChat(bs, "death_drown", name, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } num = trap_BotNumInitialChats(bs->cs, "death_slime"); for (i = 0; i < num; i++) { BotAI_BotInitialChat(bs, "death_slime", name, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } num = trap_BotNumInitialChats(bs->cs, "death_lava"); for (i = 0; i < num; i++) { BotAI_BotInitialChat(bs, "death_lava", name, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } num = trap_BotNumInitialChats(bs->cs, "death_cratered"); for (i = 0; i < num; i++) { BotAI_BotInitialChat(bs, "death_cratered", name, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } num = trap_BotNumInitialChats(bs->cs, "death_suicide"); for (i = 0; i < num; i++) { BotAI_BotInitialChat(bs, "death_suicide", name, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } num = trap_BotNumInitialChats(bs->cs, "death_telefrag"); for (i = 0; i < num; i++) { BotAI_BotInitialChat(bs, "death_telefrag", name, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } num = trap_BotNumInitialChats(bs->cs, "death_gauntlet"); for (i = 0; i < num; i++) @@ -1091,7 +1025,7 @@ void BotChatTest(bot_state_t *bs) { name, // 0 BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1 NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } num = trap_BotNumInitialChats(bs->cs, "death_rail"); for (i = 0; i < num; i++) @@ -1100,7 +1034,7 @@ void BotChatTest(bot_state_t *bs) { name, // 0 BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1 NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } num = trap_BotNumInitialChats(bs->cs, "death_bfg"); for (i = 0; i < num; i++) @@ -1109,7 +1043,7 @@ void BotChatTest(bot_state_t *bs) { name, // 0 BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1 NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } num = trap_BotNumInitialChats(bs->cs, "death_insult"); for (i = 0; i < num; i++) @@ -1118,7 +1052,7 @@ void BotChatTest(bot_state_t *bs) { name, // 0 BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1 NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } num = trap_BotNumInitialChats(bs->cs, "death_praise"); for (i = 0; i < num; i++) @@ -1127,7 +1061,7 @@ void BotChatTest(bot_state_t *bs) { name, // 0 BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1 NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } // EasyClientName(bs->lastkilledplayer, name, 32); @@ -1137,37 +1071,37 @@ void BotChatTest(bot_state_t *bs) { { // BotAI_BotInitialChat(bs, "kill_gauntlet", name, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } num = trap_BotNumInitialChats(bs->cs, "kill_rail"); for (i = 0; i < num; i++) { BotAI_BotInitialChat(bs, "kill_rail", name, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } num = trap_BotNumInitialChats(bs->cs, "kill_telefrag"); for (i = 0; i < num; i++) { BotAI_BotInitialChat(bs, "kill_telefrag", name, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } num = trap_BotNumInitialChats(bs->cs, "kill_insult"); for (i = 0; i < num; i++) { BotAI_BotInitialChat(bs, "kill_insult", name, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } num = trap_BotNumInitialChats(bs->cs, "kill_praise"); for (i = 0; i < num; i++) { BotAI_BotInitialChat(bs, "kill_praise", name, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } num = trap_BotNumInitialChats(bs->cs, "enemy_suicide"); for (i = 0; i < num; i++) { BotAI_BotInitialChat(bs, "enemy_suicide", name, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } ClientName(g_entities[bs->client].client->lasthurt_client, name, sizeof(name)); weap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_client); @@ -1175,19 +1109,19 @@ void BotChatTest(bot_state_t *bs) { for (i = 0; i < num; i++) { BotAI_BotInitialChat(bs, "hit_talking", name, weap, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } num = trap_BotNumInitialChats(bs->cs, "hit_nodeath"); for (i = 0; i < num; i++) { BotAI_BotInitialChat(bs, "hit_nodeath", name, weap, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } num = trap_BotNumInitialChats(bs->cs, "hit_nokill"); for (i = 0; i < num; i++) { BotAI_BotInitialChat(bs, "hit_nokill", name, weap, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } // if (bs->lastkilledplayer == bs->client) { @@ -1209,7 +1143,7 @@ void BotChatTest(bot_state_t *bs) { BotMapTitle(), // 4 BotRandomWeaponName(), // 5 NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } num = trap_BotNumInitialChats(bs->cs, "random_insult"); for (i = 0; i < num; i++) @@ -1222,6 +1156,6 @@ void BotChatTest(bot_state_t *bs) { BotMapTitle(), // 4 BotRandomWeaponName(), // 5 NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_ALL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } } diff --git a/code/game/ai_chat.h b/code/game/ai_chat.h index e458554..b94fb77 100644 --- a/code/game/ai_chat.h +++ b/code/game/ai_chat.h @@ -1,24 +1,4 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // /***************************************************************************** @@ -26,7 +6,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * desc: Quake3 bot AI * - * $Archive: /source/code/botai/ai_chat.c $ + * $Archive: /StarTrek/Code-DM/game/ai_chat.h $ + * $Author: Jmonroe $ + * $Revision: 1 $ + * $Modtime: 1/21/00 10:12p $ + * $Date: 1/25/00 6:26p $ * *****************************************************************************/ @@ -52,10 +36,10 @@ int BotChat_Kill(bot_state_t *bs); int BotChat_EnemySuicide(bot_state_t *bs); // int BotChat_Random(bot_state_t *bs); -// time the selected chat takes to type in +//! time the selected chat takes to type in float BotChatTime(bot_state_t *bs); -// returns true if the bot can chat at the current position +//! returns true if the bot can chat at the current position int BotValidChatPosition(bot_state_t *bs); -// test the initial bot chats +//! test the initial bot chats void BotChatTest(bot_state_t *bs); diff --git a/code/game/ai_cmd.c b/code/game/ai_cmd.c index db95485..1a5a021 100644 --- a/code/game/ai_cmd.c +++ b/code/game/ai_cmd.c @@ -1,24 +1,4 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // /***************************************************************************** @@ -26,20 +6,24 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * desc: Quake3 bot AI * - * $Archive: /MissionPack/code/game/ai_cmd.c $ + * $Archive: /StarTrek/Code-DM/game/ai_cmd.c $ + * $Author: Dkramer $ + * $Revision: 3 $ + * $Modtime: 5/09/00 4:04p $ + * $Date: 5/09/00 4:14p $ * *****************************************************************************/ #include "g_local.h" -#include "../botlib/botlib.h" -#include "../botlib/be_aas.h" -#include "../botlib/be_ea.h" -#include "../botlib/be_ai_char.h" -#include "../botlib/be_ai_chat.h" -#include "../botlib/be_ai_gen.h" -#include "../botlib/be_ai_goal.h" -#include "../botlib/be_ai_move.h" -#include "../botlib/be_ai_weap.h" +#include "botlib.h" +#include "be_aas.h" +#include "be_ea.h" +#include "be_ai_char.h" +#include "be_ai_chat.h" +#include "be_ai_gen.h" +#include "be_ai_goal.h" +#include "be_ai_move.h" +#include "be_ai_weap.h" // #include "ai_main.h" #include "ai_dmq3.h" @@ -53,10 +37,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "syn.h" //synonyms #include "match.h" //string matching types and vars -// for the voice chats -#include "../../ui/menudef.h" - -int notleader[MAX_CLIENTS]; #ifdef DEBUG /* @@ -69,7 +49,7 @@ void BotPrintTeamGoal(bot_state_t *bs) { float t; ClientName(bs->client, netname, sizeof(netname)); - t = bs->teamgoal_time - FloatTime(); + t = bs->teamgoal_time - trap_AAS_Time(); switch(bs->ltgtype) { case LTG_TEAMHELP: { @@ -96,18 +76,6 @@ void BotPrintTeamGoal(bot_state_t *bs) { BotAI_Print(PRT_MESSAGE, "%s: I'm gonna try to return the flag for %1.0f secs\n", netname, t); break; } -#ifdef MISSIONPACK - case LTG_ATTACKENEMYBASE: - { - BotAI_Print(PRT_MESSAGE, "%s: I'm gonna attack the enemy base for %1.0f secs\n", netname, t); - break; - } - case LTG_HARVEST: - { - BotAI_Print(PRT_MESSAGE, "%s: I'm gonna harvest for %1.0f secs\n", netname, t); - break; - } -#endif case LTG_DEFENDKEYAREA: { BotAI_Print(PRT_MESSAGE, "%s: I'm gonna defend a key area for %1.0f secs\n", netname, t); @@ -136,8 +104,8 @@ void BotPrintTeamGoal(bot_state_t *bs) { } default: { - if (bs->ctfroam_time > FloatTime()) { - t = bs->ctfroam_time - FloatTime(); + if (bs->ctfroam_time > trap_AAS_Time()) { + t = bs->ctfroam_time - trap_AAS_Time(); BotAI_Print(PRT_MESSAGE, "%s: I'm gonna roam for %1.0f secs\n", netname, t); } else { @@ -208,13 +176,7 @@ float BotGetTime(bot_match_t *match) { //match it to find out if the time is in seconds or minutes if (trap_BotFindMatch(timestring, &timematch, MTCONTEXT_TIME)) { if (timematch.type == MSG_FOREVER) { - t = 99999999.0f; - } - else if (timematch.type == MSG_FORAWHILE) { - t = 10 * 60; // 10 minutes - } - else if (timematch.type == MSG_FORALONGTIME) { - t = 30 * 60; // 30 minutes + t = 99999999; } else { trap_BotMatchVariable(&timematch, TIME, timestring, MAX_MESSAGE_SIZE); @@ -223,7 +185,7 @@ float BotGetTime(bot_match_t *match) { else t = 0; } //if there's a valid time - if (t > 0) return FloatTime() + t; + if (t > 0) return trap_AAS_Time() + t; } } return 0; @@ -237,15 +199,15 @@ FindClientByName int FindClientByName(char *name) { int i; char buf[MAX_INFO_STRING]; - static int maxclients; + static int maxclis; - if (!maxclients) - maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { + if (!maxclis) + maxclis = trap_Cvar_VariableIntegerValue("sv_maxclients"); + for (i = 0; i < maxclis && i < MAX_CLIENTS; i++) { ClientName(i, buf, sizeof(buf)); if (!Q_stricmp(buf, name)) return i; } - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { + for (i = 0; i < maxclis && i < MAX_CLIENTS; i++) { ClientName(i, buf, sizeof(buf)); if (stristr(buf, name)) return i; } @@ -260,16 +222,16 @@ FindEnemyByName int FindEnemyByName(bot_state_t *bs, char *name) { int i; char buf[MAX_INFO_STRING]; - static int maxclients; + static int maxclis; - if (!maxclients) - maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { + if (!maxclis) + maxclis = trap_Cvar_VariableIntegerValue("sv_maxclients"); + for (i = 0; i < maxclis && i < MAX_CLIENTS; i++) { if (BotSameTeam(bs, i)) continue; ClientName(i, buf, sizeof(buf)); if (!Q_stricmp(buf, name)) return i; } - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { + for (i = 0; i < maxclis && i < MAX_CLIENTS; i++) { if (BotSameTeam(bs, i)) continue; ClientName(i, buf, sizeof(buf)); if (stristr(buf, name)) return i; @@ -285,13 +247,13 @@ NumPlayersOnSameTeam int NumPlayersOnSameTeam(bot_state_t *bs) { int i, num; char buf[MAX_INFO_STRING]; - static int maxclients; + static int maxclis; - if (!maxclients) - maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); + if (!maxclis) + maxclis = trap_Cvar_VariableIntegerValue("sv_maxclients"); num = 0; - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { + for (i = 0; i < maxclis && i < MAX_CLIENTS; i++) { trap_GetConfigstring(CS_PLAYERS+i, buf, MAX_INFO_STRING); if (strlen(buf)) { if (BotSameTeam(bs, i+1)) num++; @@ -327,15 +289,13 @@ int BotGetPatrolWaypoints(bot_state_t *bs, bot_match_t *match) { trap_BotMatchVariable(&keyareamatch, KEYAREA, keyarea, MAX_MESSAGE_SIZE); if (!BotGetMessageTeamGoal(bs, keyarea, &goal)) { //BotAI_BotInitialChat(bs, "cannotfind", keyarea, NULL); - //trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); + //trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); BotFreeWaypoints(newpatrolpoints); bs->patrolpoints = NULL; return qfalse; } //create a new waypoint newwp = BotCreateWayPoint(keyarea, goal.origin, goal.areanum); - if (!newwp) - break; //add the waypoint to the patrol points newwp->next = NULL; for (wp = newpatrolpoints; wp && wp->next; wp = wp->next); @@ -394,8 +354,9 @@ int BotAddressedToBot(bot_state_t *bs, bot_match_t *match) { bot_match_t addresseematch; trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - client = ClientOnSameTeamFromName(bs, netname); + client = ClientFromName(netname); if (client < 0) return qfalse; + if (!BotSameTeam(bs, client)) return qfalse; //if the message is addressed to someone if (match->subtype & ST_ADDRESSED) { trap_BotMatchVariable(match, ADDRESSEE, addressedto, sizeof(addressedto)); @@ -428,15 +389,8 @@ int BotAddressedToBot(bot_state_t *bs, bot_match_t *match) { return qfalse; } else { - bot_match_t tellmatch; - - tellmatch.type = 0; - //if this message wasn't directed solely to this bot - if (!trap_BotFindMatch(match->string, &tellmatch, MTCONTEXT_REPLYCHAT) || - tellmatch.type != MSG_CHATTELL) { - //make sure not everyone reacts to this message - if (random() > (float ) 1.0 / (NumPlayersOnSameTeam(bs)-1)) return qfalse; - } + //make sure not everyone reacts to this message + if (random() > (float ) 1.0 / (NumPlayersOnSameTeam(bs)-1)) return qfalse; } return qtrue; } @@ -483,8 +437,7 @@ BotMatch_HelpAccompany */ void BotMatch_HelpAccompany(bot_state_t *bs, bot_match_t *match) { int client, other, areanum; - char teammate[MAX_MESSAGE_SIZE]; - char netname[MAX_MESSAGE_SIZE]; + char teammate[MAX_MESSAGE_SIZE], netname[MAX_MESSAGE_SIZE]; char itemname[MAX_MESSAGE_SIZE]; bot_match_t teammatematch; aas_entityinfo_t entinfo; @@ -522,8 +475,7 @@ void BotMatch_HelpAccompany(bot_state_t *bs, bot_match_t *match) { if (client < 0) { if (other) BotAI_BotInitialChat(bs, "whois", teammate, NULL); else BotAI_BotInitialChat(bs, "whois", netname, NULL); - client = ClientFromName(netname); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); return; } //don't help or accompany yourself @@ -536,7 +488,7 @@ void BotMatch_HelpAccompany(bot_state_t *bs, bot_match_t *match) { //if info is valid (in PVS) if (entinfo.valid) { areanum = BotPointAreaNum(entinfo.origin); - if (areanum) {// && trap_AAS_AreaReachability(areanum)) { + if (areanum && trap_AAS_AreaReachability(areanum)) { bs->teamgoal.entitynum = client; bs->teamgoal.areanum = areanum; VectorCopy(entinfo.origin, bs->teamgoal.origin); @@ -562,40 +514,27 @@ void BotMatch_HelpAccompany(bot_state_t *bs, bot_match_t *match) { if (bs->teamgoal.entitynum < 0) { if (other) BotAI_BotInitialChat(bs, "whereis", teammate, NULL); else BotAI_BotInitialChat(bs, "whereareyou", netname, NULL); - client = ClientFromName(netname); - trap_BotEnterChat(bs->cs, client, CHAT_TEAM); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); return; } //the team mate bs->teammate = client; - // - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - // - client = ClientFromName(netname); - //the team mate who ordered - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); //last time the team mate was assumed visible - bs->teammatevisible_time = FloatTime(); + bs->teammatevisible_time = trap_AAS_Time(); //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); + bs->teammessage_time = trap_AAS_Time() + 2 * random(); //get the team goal time bs->teamgoal_time = BotGetTime(match); //set the ltg type if (match->type == MSG_HELP) { bs->ltgtype = LTG_TEAMHELP; - if (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_HELP_TIME; + if (!bs->teamgoal_time) bs->teamgoal_time = trap_AAS_Time() + TEAM_HELP_TIME; } else { bs->ltgtype = LTG_TEAMACCOMPANY; - if (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME; + if (!bs->teamgoal_time) bs->teamgoal_time = trap_AAS_Time() + TEAM_ACCOMPANY_TIME; bs->formation_dist = 3.5 * 32; //3.5 meter bs->arrive_time = 0; - // - BotSetTeamStatus(bs); - // remember last ordered task - BotRememberLastOrderedTask(bs); } #ifdef DEBUG BotPrintTeamGoal(bs); @@ -609,8 +548,6 @@ BotMatch_DefendKeyArea */ void BotMatch_DefendKeyArea(bot_state_t *bs, bot_match_t *match) { char itemname[MAX_MESSAGE_SIZE]; - char netname[MAX_MESSAGE_SIZE]; - int client; if (!TeamPlayIsOn()) return; //if not addressed to this bot @@ -623,28 +560,16 @@ void BotMatch_DefendKeyArea(bot_state_t *bs, bot_match_t *match) { //trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); return; } - // - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - // - client = ClientFromName(netname); - //the team mate who ordered - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); + bs->teammessage_time = trap_AAS_Time() + 2 * random(); //set the ltg type bs->ltgtype = LTG_DEFENDKEYAREA; //get the team goal time bs->teamgoal_time = BotGetTime(match); //set the team goal time - if (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME; + if (!bs->teamgoal_time) bs->teamgoal_time = trap_AAS_Time() + TEAM_DEFENDKEYAREA_TIME; //away from defending bs->defendaway_time = 0; - // - BotSetTeamStatus(bs); - // remember last ordered task - BotRememberLastOrderedTask(bs); #ifdef DEBUG BotPrintTeamGoal(bs); #endif //DEBUG @@ -657,8 +582,6 @@ BotMatch_GetItem */ void BotMatch_GetItem(bot_state_t *bs, bot_match_t *match) { char itemname[MAX_MESSAGE_SIZE]; - char netname[MAX_MESSAGE_SIZE]; - int client; if (!TeamPlayIsOn()) return; //if not addressed to this bot @@ -671,20 +594,12 @@ void BotMatch_GetItem(bot_state_t *bs, bot_match_t *match) { //trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); return; } - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - client = ClientOnSameTeamFromName(bs, netname); - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); + bs->teammessage_time = trap_AAS_Time() + 2 * random(); //set the ltg type bs->ltgtype = LTG_GETITEM; //set the team goal time - bs->teamgoal_time = FloatTime() + TEAM_GETITEM_TIME; - // - BotSetTeamStatus(bs); + bs->teamgoal_time = trap_AAS_Time() + TEAM_GETITEM_TIME; #ifdef DEBUG BotPrintTeamGoal(bs); #endif //DEBUG @@ -734,8 +649,8 @@ void BotMatch_Camp(bot_state_t *bs, bot_match_t *match) { //if info is valid (in PVS) if (entinfo.valid) { areanum = BotPointAreaNum(entinfo.origin); - if (areanum) {// && trap_AAS_AreaReachability(areanum)) { - //NOTE: just assume the bot knows where the person is + if (areanum && trap_AAS_AreaReachability(areanum)) { + //NOTE: just cheat and assume the bot knows where the person is //if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, client)) { bs->teamgoal.entitynum = client; bs->teamgoal.areanum = areanum; @@ -748,35 +663,28 @@ void BotMatch_Camp(bot_state_t *bs, bot_match_t *match) { //if the other is not visible if (bs->teamgoal.entitynum < 0) { BotAI_BotInitialChat(bs, "whereareyou", netname, NULL); - client = ClientFromName(netname); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); return; } } else if (!BotGetMessageTeamGoal(bs, itemname, &bs->teamgoal)) { //BotAI_BotInitialChat(bs, "cannotfind", itemname, NULL); - //client = ClientFromName(netname); - //trap_BotEnterChat(bs->cs, client, CHAT_TELL); + //trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); return; } - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); + bs->teammessage_time = trap_AAS_Time() + 2 * random(); //set the ltg type bs->ltgtype = LTG_CAMPORDER; //get the team goal time bs->teamgoal_time = BotGetTime(match); //set the team goal time - if (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_CAMP_TIME; + if (!bs->teamgoal_time) bs->teamgoal_time = trap_AAS_Time() + TEAM_CAMP_TIME; + //the teammate that requested the camping + bs->teammate = client; //not arrived yet bs->arrive_time = 0; // - BotSetTeamStatus(bs); - // remember last ordered task - BotRememberLastOrderedTask(bs); #ifdef DEBUG BotPrintTeamGoal(bs); #endif //DEBUG @@ -788,34 +696,20 @@ BotMatch_Patrol ================== */ void BotMatch_Patrol(bot_state_t *bs, bot_match_t *match) { - char netname[MAX_MESSAGE_SIZE]; - int client; - if (!TeamPlayIsOn()) return; //if not addressed to this bot if (!BotAddressedToBot(bs, match)) return; //get the patrol waypoints if (!BotGetPatrolWaypoints(bs, match)) return; - // - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - // - client = FindClientByName(netname); - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); + bs->teammessage_time = trap_AAS_Time() + 2 * random(); //set the ltg type bs->ltgtype = LTG_PATROL; //get the team goal time bs->teamgoal_time = BotGetTime(match); //set the team goal time if not set already - if (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_PATROL_TIME; + if (!bs->teamgoal_time) bs->teamgoal_time = trap_AAS_Time() + TEAM_PATROL_TIME; // - BotSetTeamStatus(bs); - // remember last ordered task - BotRememberLastOrderedTask(bs); #ifdef DEBUG BotPrintTeamGoal(bs); #endif //DEBUG @@ -827,184 +721,38 @@ BotMatch_GetFlag ================== */ void BotMatch_GetFlag(bot_state_t *bs, bot_match_t *match) { - char netname[MAX_MESSAGE_SIZE]; - int client; - - if (gametype == GT_CTF) { - if (!ctf_redflag.areanum || !ctf_blueflag.areanum) - return; - } -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF) { - if (!ctf_neutralflag.areanum || !ctf_redflag.areanum || !ctf_blueflag.areanum) - return; - } -#endif - else { - return; - } + //if not in CTF mode + if (gametype != GT_CTF || !ctf_redflag.areanum || !ctf_blueflag.areanum) return; //if not addressed to this bot if (!BotAddressedToBot(bs, match)) return; - // - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - // - client = FindClientByName(netname); - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); + bs->teammessage_time = trap_AAS_Time() + 2 * random(); //set the ltg type bs->ltgtype = LTG_GETFLAG; //set the team goal time - bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME; - // get an alternate route in ctf - if (gametype == GT_CTF) { - //get an alternative route goal towards the enemy base - BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs)); - } - // - BotSetTeamStatus(bs); - // remember last ordered task - BotRememberLastOrderedTask(bs); + bs->teamgoal_time = trap_AAS_Time() + CTF_GETFLAG_TIME; #ifdef DEBUG BotPrintTeamGoal(bs); #endif //DEBUG } -/* -================== -BotMatch_AttackEnemyBase -================== -*/ -void BotMatch_AttackEnemyBase(bot_state_t *bs, bot_match_t *match) { - char netname[MAX_MESSAGE_SIZE]; - int client; - - if (gametype == GT_CTF) { - BotMatch_GetFlag(bs, match); - } -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF || gametype == GT_OBELISK || gametype == GT_HARVESTER) { - if (!redobelisk.areanum || !blueobelisk.areanum) - return; - } -#endif - else { - return; - } - //if not addressed to this bot - if (!BotAddressedToBot(bs, match)) return; - // - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - // - client = FindClientByName(netname); - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - //set the ltg type - bs->ltgtype = LTG_ATTACKENEMYBASE; - //set the team goal time - bs->teamgoal_time = FloatTime() + TEAM_ATTACKENEMYBASE_TIME; - bs->attackaway_time = 0; - // - BotSetTeamStatus(bs); - // remember last ordered task - BotRememberLastOrderedTask(bs); -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -#ifdef MISSIONPACK -/* -================== -BotMatch_Harvest -================== -*/ -void BotMatch_Harvest(bot_state_t *bs, bot_match_t *match) { - char netname[MAX_MESSAGE_SIZE]; - int client; - - if (gametype == GT_HARVESTER) { - if (!neutralobelisk.areanum || !redobelisk.areanum || !blueobelisk.areanum) - return; - } - else { - return; - } - //if not addressed to this bot - if (!BotAddressedToBot(bs, match)) return; - // - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - // - client = FindClientByName(netname); - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - //set the ltg type - bs->ltgtype = LTG_HARVEST; - //set the team goal time - bs->teamgoal_time = FloatTime() + TEAM_HARVEST_TIME; - bs->harvestaway_time = 0; - // - BotSetTeamStatus(bs); - // remember last ordered task - BotRememberLastOrderedTask(bs); -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} -#endif - /* ================== BotMatch_RushBase ================== */ void BotMatch_RushBase(bot_state_t *bs, bot_match_t *match) { - char netname[MAX_MESSAGE_SIZE]; - int client; - - if (gametype == GT_CTF) { - if (!ctf_redflag.areanum || !ctf_blueflag.areanum) - return; - } -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF || gametype == GT_HARVESTER) { - if (!redobelisk.areanum || !blueobelisk.areanum) - return; - } -#endif - else { - return; - } + //if not in CTF mode + if (gametype != GT_CTF || !ctf_redflag.areanum || !ctf_blueflag.areanum) return; //if not addressed to this bot if (!BotAddressedToBot(bs, match)) return; - // - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - // - client = FindClientByName(netname); - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); + bs->teammessage_time = trap_AAS_Time() + 2 * random(); //set the ltg type bs->ltgtype = LTG_RUSHBASE; //set the team goal time - bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME; + bs->teamgoal_time = trap_AAS_Time() + CTF_RUSHBASE_TIME; bs->rushbaseaway_time = 0; - // - BotSetTeamStatus(bs); #ifdef DEBUG BotPrintTeamGoal(bs); #endif //DEBUG @@ -1027,34 +775,32 @@ void BotMatch_TaskPreference(bot_state_t *bs, bot_match_t *match) { teammate = ClientFromName(teammatename); if (teammate < 0) return; - preference = BotGetTeamMateTaskPreference(bs, teammate); + preference = BotGetTeamMateCTFPreference(bs, teammate); switch(match->subtype) { case ST_DEFENDER: { - preference &= ~TEAMTP_ATTACKER; - preference |= TEAMTP_DEFENDER; + preference &= ~CTFTP_ATTACKER; + preference |= CTFTP_DEFENDER; break; } case ST_ATTACKER: { - preference &= ~TEAMTP_DEFENDER; - preference |= TEAMTP_ATTACKER; + preference &= ~CTFTP_DEFENDER; + preference |= CTFTP_ATTACKER; break; } case ST_ROAMER: { - preference &= ~(TEAMTP_ATTACKER|TEAMTP_DEFENDER); + preference &= ~(CTFTP_ATTACKER|CTFTP_DEFENDER); break; } } - BotSetTeamMateTaskPreference(bs, teammate, preference); + BotSetTeamMateCTFPreference(bs, teammate, preference); // EasyClientName(teammate, teammatename, sizeof(teammatename)); BotAI_BotInitialChat(bs, "keepinmind", teammatename, NULL); - trap_BotEnterChat(bs->cs, teammate, CHAT_TELL); - BotVoiceChatOnly(bs, teammate, VOICECHAT_YES); - trap_EA_Action(bs->client, ACTION_AFFIRMATIVE); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); } /* @@ -1063,37 +809,17 @@ BotMatch_ReturnFlag ================== */ void BotMatch_ReturnFlag(bot_state_t *bs, bot_match_t *match) { - char netname[MAX_MESSAGE_SIZE]; - int client; - //if not in CTF mode - if ( - gametype != GT_CTF -#ifdef MISSIONPACK - && gametype != GT_1FCTF -#endif - ) - return; + if (gametype != GT_CTF) return; //if not addressed to this bot - if (!BotAddressedToBot(bs, match)) - return; - // - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - // - client = FindClientByName(netname); - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); + if (!BotAddressedToBot(bs, match)) return; //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); + bs->teammessage_time = trap_AAS_Time() + 2 * random(); //set the ltg type bs->ltgtype = LTG_RETURNFLAG; //set the team goal time - bs->teamgoal_time = FloatTime() + CTF_RETURNFLAG_TIME; + bs->teamgoal_time = trap_AAS_Time() + CTF_RETURNFLAG_TIME; bs->rushbaseaway_time = 0; - // - BotSetTeamStatus(bs); #ifdef DEBUG BotPrintTeamGoal(bs); #endif //DEBUG @@ -1106,22 +832,18 @@ BotMatch_JoinSubteam */ void BotMatch_JoinSubteam(bot_state_t *bs, bot_match_t *match) { char teammate[MAX_MESSAGE_SIZE]; - char netname[MAX_MESSAGE_SIZE]; - int client; if (!TeamPlayIsOn()) return; //if not addressed to this bot if (!BotAddressedToBot(bs, match)) return; //get the sub team name - trap_BotMatchVariable(match, TEAMNAME, teammate, sizeof(teammate)); + trap_BotMatchVariable(match, TEAMNAME, teammate, MAX_MESSAGE_SIZE); //set the sub team name strncpy(bs->subteam, teammate, 32); bs->subteam[31] = '\0'; // - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); BotAI_BotInitialChat(bs, "joinedteam", teammate, NULL); - client = ClientFromName(netname); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); } /* @@ -1130,9 +852,6 @@ BotMatch_LeaveSubteam ================== */ void BotMatch_LeaveSubteam(bot_state_t *bs, bot_match_t *match) { - char netname[MAX_MESSAGE_SIZE]; - int client; - if (!TeamPlayIsOn()) return; //if not addressed to this bot if (!BotAddressedToBot(bs, match)) return; @@ -1140,10 +859,8 @@ void BotMatch_LeaveSubteam(bot_state_t *bs, bot_match_t *match) { if (strlen(bs->subteam)) { BotAI_BotInitialChat(bs, "leftteam", bs->subteam, NULL); - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - client = ClientFromName(netname); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); } //end if + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); strcpy(bs->subteam, ""); } @@ -1172,27 +889,24 @@ BotMatch_CheckPoint ================== */ void BotMatch_CheckPoint(bot_state_t *bs, bot_match_t *match) { - int areanum, client; + int areanum; char buf[MAX_MESSAGE_SIZE]; - char netname[MAX_MESSAGE_SIZE]; vec3_t position; bot_waypoint_t *cp; + int i; if (!TeamPlayIsOn()) return; // trap_BotMatchVariable(match, POSITION, buf, MAX_MESSAGE_SIZE); VectorClear(position); - // - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - client = ClientFromName(netname); //BotGPSToPosition(buf, position); - sscanf(buf, "%f %f %f", &position[0], &position[1], &position[2]); + i = sscanf(buf, "%f %f %f", &position[0], &position[1], &position[2]); position[2] += 0.5; areanum = BotPointAreaNum(position); if (!areanum) { if (BotAddressedToBot(bs, match)) { BotAI_BotInitialChat(bs, "checkpoint_invalid", NULL); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); } return; } @@ -1219,7 +933,7 @@ void BotMatch_CheckPoint(bot_state_t *bs, bot_match_t *match) { cp->goal.origin[2]); BotAI_BotInitialChat(bs, "checkpoint_confirm", cp->name, buf, NULL); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); } } @@ -1252,45 +966,15 @@ BotMatch_Dismiss ================== */ void BotMatch_Dismiss(bot_state_t *bs, bot_match_t *match) { - char netname[MAX_MESSAGE_SIZE]; - int client; - if (!TeamPlayIsOn()) return; //if not addressed to this bot if (!BotAddressedToBot(bs, match)) return; - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - client = ClientFromName(netname); - // - bs->decisionmaker = client; // bs->ltgtype = 0; bs->lead_time = 0; - bs->lastgoal_ltgtype = 0; // BotAI_BotInitialChat(bs, "dismissed", NULL); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); -} - -/* -================== -BotMatch_Suicide -================== -*/ -void BotMatch_Suicide(bot_state_t *bs, bot_match_t *match) { - char netname[MAX_MESSAGE_SIZE]; - int client; - - if (!TeamPlayIsOn()) return; - //if not addressed to this bot - if (!BotAddressedToBot(bs, match)) return; - // - trap_EA_Command(bs->client, "kill"); - // - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - client = ClientFromName(netname); - // - BotVoiceChat(bs, client, VOICECHAT_TAUNT); - trap_EA_Action(bs->client, ACTION_AFFIRMATIVE); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); } /* @@ -1344,7 +1028,6 @@ void BotMatch_StopTeamLeaderShip(bot_state_t *bs, bot_match_t *match) { if (client >= 0) { if (!Q_stricmp(bs->teamleader, ClientName(client, netname, sizeof(netname)))) { bs->teamleader[0] = '\0'; - notleader[client] = qtrue; } } } @@ -1374,7 +1057,6 @@ BotMatch_WhatAreYouDoing void BotMatch_WhatAreYouDoing(bot_state_t *bs, bot_match_t *match) { char netname[MAX_MESSAGE_SIZE]; char goalname[MAX_MESSAGE_SIZE]; - int client; //if not addressed to this bot if (!BotAddressedToBot(bs, match)) return; @@ -1436,18 +1118,6 @@ void BotMatch_WhatAreYouDoing(bot_state_t *bs, bot_match_t *match) { BotAI_BotInitialChat(bs, "returningflag", NULL); break; } -#ifdef MISSIONPACK - case LTG_ATTACKENEMYBASE: - { - BotAI_BotInitialChat(bs, "attackingenemybase", NULL); - break; - } - case LTG_HARVEST: - { - BotAI_BotInitialChat(bs, "harvesting", NULL); - break; - } -#endif default: { BotAI_BotInitialChat(bs, "roaming", NULL); @@ -1455,9 +1125,7 @@ void BotMatch_WhatAreYouDoing(bot_state_t *bs, bot_match_t *match) { } } //chat what the bot is doing - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - client = ClientFromName(netname); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); } /* @@ -1491,8 +1159,7 @@ float BotNearestVisibleItem(bot_state_t *bs, char *itemname, bot_goal_t *goal) { do { i = trap_BotGetLevelItemGoal(i, itemname, &tmpgoal); trap_BotGoalName(tmpgoal.number, name, sizeof(name)); - if (Q_stricmp(itemname, name) != 0) - continue; + if (Q_stricmp(itemname, name) != 0) continue; VectorSubtract(tmpgoal.origin, bs->origin, dir); dist = VectorLength(dir); if (dist < bestdist) { @@ -1514,48 +1181,33 @@ BotMatch_WhereAreYou */ void BotMatch_WhereAreYou(bot_state_t *bs, bot_match_t *match) { float dist, bestdist; - int i, bestitem, redtt, bluett, client; + int i, bestitem, redflagtt, blueflagtt, redtobluett; bot_goal_t goal; - char netname[MAX_MESSAGE_SIZE]; char *nearbyitems[] = { - "Shotgun", - "Grenade Launcher", - "Rocket Launcher", - "Plasmagun", - "Railgun", - "Lightning Gun", - "BFG10K", - "Quad Damage", - "Regeneration", - "Battle Suit", - "Speed", - "Invisibility", - "Flight", - "Armor", - "Heavy Armor", + "Phaser Compression Rifle", + "I-MOD", + "Scavenger Weapon", + "Stasis Weapon", + "Compound Grenade Launcher", + "Tetryon Pulse Disruptor", + "Dermal Regenerator", + "Photon Burst", + "Quantum Weapon Enhancer",//fixme! + "Nano-Regenerative Protoplasmer", + "Metaphasic Shielding", + "Temporal Accelerator", + "Personal Cloaking Device", + "Anti-Gravity Pack", + "Personal Deflector Screen", + "Isokinetic Deflector Screen", "Red Flag", "Blue Flag", -#ifdef MISSIONPACK - "Nailgun", - "Prox Launcher", - "Chaingun", - "Scout", - "Guard", - "Doubler", - "Ammo Regen", - "Neutral Flag", - "Red Obelisk", - "Blue Obelisk", - "Neutral Obelisk", -#endif NULL }; // - if (!TeamPlayIsOn()) - return; + if (!TeamPlayIsOn()) return; //if not addressed to this bot - if (!BotAddressedToBot(bs, match)) - return; + if (!BotAddressedToBot(bs, match)) return; bestitem = -1; bestdist = 999999; @@ -1567,44 +1219,24 @@ void BotMatch_WhereAreYou(bot_state_t *bs, bot_match_t *match) { } } if (bestitem != -1) { - if (gametype == GT_CTF -#ifdef MISSIONPACK - || gametype == GT_1FCTF -#endif - ) { - redtt = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, ctf_redflag.areanum, TFL_DEFAULT); - bluett = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, ctf_blueflag.areanum, TFL_DEFAULT); - if (redtt < (redtt + bluett) * 0.4) { - BotAI_BotInitialChat(bs, "teamlocation", nearbyitems[bestitem], "red", NULL); + if (gametype == GT_CTF) { + redflagtt = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, ctf_redflag.areanum, TFL_DEFAULT); + blueflagtt = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, ctf_blueflag.areanum, TFL_DEFAULT); + redtobluett = trap_AAS_AreaTravelTimeToGoalArea(ctf_redflag.areanum, ctf_redflag.origin, ctf_blueflag.areanum, TFL_DEFAULT); + if (redflagtt < (redflagtt + blueflagtt) * 0.4) { + BotAI_BotInitialChat(bs, "ctflocation", nearbyitems[bestitem], "red", NULL); } - else if (bluett < (redtt + bluett) * 0.4) { - BotAI_BotInitialChat(bs, "teamlocation", nearbyitems[bestitem], "blue", NULL); + else if (blueflagtt < (redflagtt + blueflagtt) * 0.4) { + BotAI_BotInitialChat(bs, "ctflocation", nearbyitems[bestitem], "blue", NULL); } else { BotAI_BotInitialChat(bs, "location", nearbyitems[bestitem], NULL); } } -#ifdef MISSIONPACK - else if (gametype == GT_OBELISK || gametype == GT_HARVESTER) { - redtt = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, redobelisk.areanum, TFL_DEFAULT); - bluett = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, blueobelisk.areanum, TFL_DEFAULT); - if (redtt < (redtt + bluett) * 0.4) { - BotAI_BotInitialChat(bs, "teamlocation", nearbyitems[bestitem], "red", NULL); - } - else if (bluett < (redtt + bluett) * 0.4) { - BotAI_BotInitialChat(bs, "teamlocation", nearbyitems[bestitem], "blue", NULL); - } - else { - BotAI_BotInitialChat(bs, "location", nearbyitems[bestitem], NULL); - } - } -#endif else { BotAI_BotInitialChat(bs, "location", nearbyitems[bestitem], NULL); } - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - client = ClientFromName(netname); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); } } @@ -1656,7 +1288,7 @@ void BotMatch_LeadTheWay(bot_state_t *bs, bot_match_t *match) { //if info is valid (in PVS) if (entinfo.valid) { areanum = BotPointAreaNum(entinfo.origin); - if (areanum) { // && trap_AAS_AreaReachability(areanum)) { + if (areanum && trap_AAS_AreaReachability(areanum)) { bs->lead_teamgoal.entitynum = client; bs->lead_teamgoal.areanum = areanum; VectorCopy(entinfo.origin, bs->lead_teamgoal.origin); @@ -1672,9 +1304,9 @@ void BotMatch_LeadTheWay(bot_state_t *bs, bot_match_t *match) { return; } bs->lead_teammate = client; - bs->lead_time = FloatTime() + TEAM_LEAD_TIME; + bs->lead_time = trap_AAS_Time() + TEAM_LEAD_TIME; bs->leadvisible_time = 0; - bs->leadmessage_time = -(FloatTime() + 2 * random()); + bs->leadmessage_time = -(trap_AAS_Time() + 2 * random()); } /* @@ -1684,7 +1316,6 @@ BotMatch_Kill */ void BotMatch_Kill(bot_state_t *bs, bot_match_t *match) { char enemy[MAX_MESSAGE_SIZE]; - char netname[MAX_MESSAGE_SIZE]; int client; if (!TeamPlayIsOn()) return; @@ -1696,20 +1327,16 @@ void BotMatch_Kill(bot_state_t *bs, bot_match_t *match) { client = FindEnemyByName(bs, enemy); if (client < 0) { BotAI_BotInitialChat(bs, "whois", enemy, NULL); - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - client = ClientFromName(netname); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); return; } bs->teamgoal.entitynum = client; //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); + bs->teammessage_time = trap_AAS_Time() + 2 * random(); //set the ltg type bs->ltgtype = LTG_KILL; //set the team goal time - bs->teamgoal_time = FloatTime() + TEAM_KILL_SOMEONE; - // - BotSetTeamStatus(bs); + bs->teamgoal_time = trap_AAS_Time() + TEAM_KILL_SOMEONE; #ifdef DEBUG BotPrintTeamGoal(bs); #endif //DEBUG @@ -1724,71 +1351,36 @@ void BotMatch_CTF(bot_state_t *bs, bot_match_t *match) { char flag[128], netname[MAX_NETNAME]; - if (gametype == GT_CTF) { - trap_BotMatchVariable(match, FLAG, flag, sizeof(flag)); - if (match->subtype & ST_GOTFLAG) { - if (!Q_stricmp(flag, "red")) { - bs->redflagstatus = 1; - if (BotTeam(bs) == TEAM_BLUE) { - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - bs->flagcarrier = ClientFromName(netname); - } + trap_BotMatchVariable(match, FLAG, flag, sizeof(flag)); + if (match->subtype & ST_GOTFLAG) { + if (!Q_stricmp(flag, "red")) { + bs->redflagstatus = 1; + if (BotCTFTeam(bs) == CTF_TEAM_BLUE) { + trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); + bs->flagcarrier = ClientFromName(netname); } - else { - bs->blueflagstatus = 1; - if (BotTeam(bs) == TEAM_RED) { - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - bs->flagcarrier = ClientFromName(netname); - } + } + else { + bs->blueflagstatus = 1; + if (BotCTFTeam(bs) == CTF_TEAM_RED) { + trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); + bs->flagcarrier = ClientFromName(netname); } - bs->flagstatuschanged = 1; - bs->lastflagcapture_time = FloatTime(); - } - else if (match->subtype & ST_CAPTUREDFLAG) { - bs->redflagstatus = 0; - bs->blueflagstatus = 0; - bs->flagcarrier = 0; - bs->flagstatuschanged = 1; - } - else if (match->subtype & ST_RETURNEDFLAG) { - if (!Q_stricmp(flag, "red")) bs->redflagstatus = 0; - else bs->blueflagstatus = 0; - bs->flagstatuschanged = 1; } + bs->flagstatuschanged = 1; + bs->lastflagcapture_time = trap_AAS_Time(); } -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF) { - if (match->subtype & ST_1FCTFGOTFLAG) { - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - bs->flagcarrier = ClientFromName(netname); - } + else if (match->subtype & ST_CAPTUREDFLAG) { + bs->redflagstatus = 0; + bs->blueflagstatus = 0; + bs->flagcarrier = 0; + bs->flagstatuschanged = 1; } -#endif -} - -void BotMatch_EnterGame(bot_state_t *bs, bot_match_t *match) { - int client; - char netname[MAX_NETNAME]; - - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - client = FindClientByName(netname); - if (client >= 0) { - notleader[client] = qfalse; + else if (match->subtype & ST_RETURNEDFLAG) { + if (!Q_stricmp(flag, "red")) bs->redflagstatus = 0; + else bs->blueflagstatus = 0; + bs->flagstatuschanged = 1; } - //NOTE: eliza chats will catch this - //Com_sprintf(buf, sizeof(buf), "heya %s", netname); - //EA_Say(bs->client, buf); -} - -void BotMatch_NewLeader(bot_state_t *bs, bot_match_t *match) { - int client; - char netname[MAX_NETNAME]; - - trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); - client = FindClientByName(netname); - if (!BotSameTeam(bs, client)) - return; - Q_strncpyz(bs->teamleader, netname, sizeof(bs->teamleader)); } /* @@ -1801,7 +1393,7 @@ int BotMatchMessage(bot_state_t *bs, char *message) { match.type = 0; //if it is an unknown message - if (!trap_BotFindMatch(message, &match, MTCONTEXT_MISC + if (!trap_BotFindMatch(message, &match, MTCONTEXT_ENTERGAME |MTCONTEXT_INITIALTEAMCHAT |MTCONTEXT_CTF)) { return qfalse; @@ -1830,50 +1422,33 @@ int BotMatchMessage(bot_state_t *bs, char *message) { BotMatch_Patrol(bs, &match); break; } - //CTF & 1FCTF +#ifdef CTF case MSG_GETFLAG: //ctf get the enemy flag { BotMatch_GetFlag(bs, &match); break; } -#ifdef MISSIONPACK - //CTF & 1FCTF & Obelisk & Harvester - case MSG_ATTACKENEMYBASE: - { - BotMatch_AttackEnemyBase(bs, &match); - break; - } - //Harvester - case MSG_HARVEST: - { - BotMatch_Harvest(bs, &match); - break; - } -#endif - //CTF & 1FCTF & Harvester case MSG_RUSHBASE: //ctf rush to the base { BotMatch_RushBase(bs, &match); break; } - //CTF & 1FCTF case MSG_RETURNFLAG: { BotMatch_ReturnFlag(bs, &match); break; } - //CTF & 1FCTF & Obelisk & Harvester - case MSG_TASKPREFERENCE: + case MSG_CTFTASKPREFERENCE: { BotMatch_TaskPreference(bs, &match); break; } - //CTF & 1FCTF case MSG_CTF: { BotMatch_CTF(bs, &match); break; } +#endif //CTF case MSG_GETITEM: { BotMatch_GetItem(bs, &match); @@ -1965,23 +1540,16 @@ int BotMatchMessage(bot_state_t *bs, char *message) { } case MSG_ENTERGAME: //someone entered the game { - BotMatch_EnterGame(bs, &match); - break; - } - case MSG_NEWLEADER: - { - BotMatch_NewLeader(bs, &match); + //NOTE: eliza chats will catch this + //BotMatchVariable(&match, NETNAME, netname); + //Com_sprintf(buf, sizeof(buf), "heya %s", netname); + //EA_Say(bs->client, buf); break; } case MSG_WAIT: { break; } - case MSG_SUICIDE: - { - BotMatch_Suicide(bs, &match); - break; - } default: { BotAI_Print(PRT_MESSAGE, "unknown match type\n"); diff --git a/code/game/ai_cmd.h b/code/game/ai_cmd.h index dd10bc1..a4866be 100644 --- a/code/game/ai_cmd.h +++ b/code/game/ai_cmd.h @@ -1,24 +1,4 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // /***************************************************************************** @@ -26,12 +6,14 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * desc: Quake3 bot AI * - * $Archive: /source/code/botai/ai_chat.c $ + * $Archive: /StarTrek/Code-DM/game/ai_cmd.h $ + * $Author: Jmonroe $ + * $Revision: 1 $ + * $Modtime: 1/21/00 10:12p $ + * $Date: 1/25/00 6:26p $ * *****************************************************************************/ -extern int notleader[MAX_CLIENTS]; - int BotMatchMessage(bot_state_t *bs, char *message); void BotPrintTeamGoal(bot_state_t *bs); diff --git a/code/game/ai_dmnet.c b/code/game/ai_dmnet.c index e8f461d..5d3f91e 100644 --- a/code/game/ai_dmnet.c +++ b/code/game/ai_dmnet.c @@ -1,24 +1,4 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // /***************************************************************************** @@ -26,43 +6,43 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * desc: Quake3 bot AI * - * $Archive: /MissionPack/code/game/ai_dmnet.c $ + * $Archive: /StarTrek/Code-DM/game/ai_dmnet.c $ + * $Author: Mgummelt $ + * $Revision: 7 $ + * $Modtime: 3/28/01 11:12a $ + * $Date: 3/28/01 11:15a $ * *****************************************************************************/ #include "g_local.h" -#include "../botlib/botlib.h" -#include "../botlib/be_aas.h" -#include "../botlib/be_ea.h" -#include "../botlib/be_ai_char.h" -#include "../botlib/be_ai_chat.h" -#include "../botlib/be_ai_gen.h" -#include "../botlib/be_ai_goal.h" -#include "../botlib/be_ai_move.h" -#include "../botlib/be_ai_weap.h" +#include "botlib.h" +#include "be_aas.h" +#include "be_ea.h" +#include "be_ai_char.h" +#include "be_ai_chat.h" +#include "be_ai_gen.h" +#include "be_ai_goal.h" +#include "be_ai_move.h" +#include "be_ai_weap.h" // #include "ai_main.h" #include "ai_dmq3.h" #include "ai_chat.h" #include "ai_cmd.h" #include "ai_dmnet.h" -#include "ai_team.h" //data file headers #include "chars.h" //characteristics #include "inv.h" //indexes into the inventory #include "syn.h" //synonyms #include "match.h" //string matching types and vars -// for the voice chats -#include "../../ui/menudef.h" - -//goal flag, see ../botlib/be_ai_goal.h for the other GFL_* +//goal flag, see be_ai_goal.h for the other GFL_* #define GFL_AIR 128 int numnodeswitches; char nodeswitch[MAX_NODESWITCHES+1][144]; -#define LOOKAHEAD_DISTANCE 300 +#define LOOKAHEAD_DISTANCE 300 /* ================== @@ -83,9 +63,9 @@ void BotDumpNodeSwitches(bot_state_t *bs) { char netname[MAX_NETNAME]; ClientName(bs->client, netname, sizeof(netname)); - BotAI_Print(PRT_MESSAGE, "%s at %1.1f switched more than %d AI nodes\n", netname, FloatTime(), MAX_NODESWITCHES); + BotAI_Print(PRT_MESSAGE, "%s at %1.1f switched more than %d AI nodes\n", netname, trap_AAS_Time(), MAX_NODESWITCHES); for (i = 0; i < numnodeswitches; i++) { - BotAI_Print(PRT_MESSAGE, "%s", nodeswitch[i]); + BotAI_Print(PRT_MESSAGE, nodeswitch[i]); } BotAI_Print(PRT_FATAL, ""); } @@ -95,14 +75,14 @@ void BotDumpNodeSwitches(bot_state_t *bs) { BotRecordNodeSwitch ================== */ -void BotRecordNodeSwitch(bot_state_t *bs, char *node, char *str, char *s) { +void BotRecordNodeSwitch(bot_state_t *bs, char *node, char *str) { char netname[MAX_NETNAME]; ClientName(bs->client, netname, sizeof(netname)); - Com_sprintf(nodeswitch[numnodeswitches], 144, "%s at %2.1f entered %s: %s from %s\n", netname, FloatTime(), node, str, s); + Com_sprintf(nodeswitch[numnodeswitches], 144, "%s at %2.1f entered %s: %s\n", netname, trap_AAS_Time(), node, str); #ifdef DEBUG if (0) { - BotAI_Print(PRT_MESSAGE, "%s", nodeswitch[numnodeswitches]); + BotAI_Print(PRT_MESSAGE, nodeswitch[numnodeswitches]); } #endif //DEBUG numnodeswitches++; @@ -157,7 +137,7 @@ int BotGoForAir(bot_state_t *bs, int tfl, bot_goal_t *ltg, float range) { bot_goal_t goal; //if the bot needs air - if (bs->lastair_time < FloatTime() - 6) { + if (bs->lastair_time < trap_AAS_Time() - 6) { // #ifdef DEBUG //BotAI_Print(PRT_MESSAGE, "going for air\n"); @@ -168,8 +148,13 @@ int BotGoForAir(bot_state_t *bs, int tfl, bot_goal_t *ltg, float range) { return qtrue; } else { + qboolean botRoamsOnly = qtrue; + /*if ( bs->cur_ps.persistant[PERS_CLASS]!=PC_NOCLASS && bs->cur_ps.persistant[PERS_CLASS]!=PC_ACTIONHERO ) + { + botRoamsOnly = qtrue; + }*/ //get a nearby goal outside the water - while(trap_BotChooseNBGItem(bs->gs, bs->origin, bs->inventory, tfl, ltg, range)) { + while( trap_BotChooseNBGItem( bs->gs, bs->origin, bs->inventory, tfl, ltg, range, botRoamsOnly ) ) { trap_BotGetTopGoal(bs->gs, &goal); //if the goal is not in water if (!(trap_AAS_PointContents(goal.origin) & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA))) { @@ -190,15 +175,12 @@ BotNearbyGoal */ int BotNearbyGoal(bot_state_t *bs, int tfl, bot_goal_t *ltg, float range) { int ret; + qboolean botRoamsOnly = qtrue; //check if the bot should go for air if (BotGoForAir(bs, tfl, ltg, range)) return qtrue; - // if the bot is carrying a flag or cubes - if (BotCTFCarryingFlag(bs) -#ifdef MISSIONPACK - || Bot1FCTFCarryingFlag(bs) || BotHarvesterCarryingCubes(bs) -#endif - ) { + //if the bot is carrying the enemy flag + if (BotCTFCarryingFlag(bs)) { //if the bot is just a few secs away from the base if (trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, bs->teamgoal.areanum, TFL_DEFAULT) < 300) { @@ -207,7 +189,11 @@ int BotNearbyGoal(bot_state_t *bs, int tfl, bot_goal_t *ltg, float range) { } } // - ret = trap_BotChooseNBGItem(bs->gs, bs->origin, bs->inventory, tfl, ltg, range); + /*if ( bs->cur_ps.persistant[PERS_CLASS]!=PC_NOCLASS && bs->cur_ps.persistant[PERS_CLASS]!=PC_ACTIONHERO ) + { + botRoamsOnly = qtrue; + }*/ + ret = trap_BotChooseNBGItem(bs->gs, bs->origin, bs->inventory, tfl, ltg, range, botRoamsOnly ); /* if (ret) { @@ -215,9 +201,9 @@ int BotNearbyGoal(bot_state_t *bs, int tfl, bot_goal_t *ltg, float range) { //get the goal at the top of the stack trap_BotGetTopGoal(bs->gs, &goal); trap_BotGoalName(goal.number, buf, sizeof(buf)); - BotAI_Print(PRT_MESSAGE, "%1.1f: new nearby goal %s\n", FloatTime(), buf); + BotAI_Print(PRT_MESSAGE, "%1.1f: new nearby goal %s\n", trap_AAS_Time(), buf); } - */ + //*/ return ret; } @@ -229,27 +215,9 @@ BotReachedGoal int BotReachedGoal(bot_state_t *bs, bot_goal_t *goal) { if (goal->flags & GFL_ITEM) { //if touching the goal - if (trap_BotTouchingGoal(bs->origin, goal)) { - if (!(goal->flags & GFL_DROPPED)) { - trap_BotSetAvoidGoalTime(bs->gs, goal->number, -1); - } - return qtrue; - } + if (trap_BotTouchingGoal(bs->origin, goal)) return qtrue; //if the goal isn't there - if (trap_BotItemGoalInVisButNotVisible(bs->entitynum, bs->eye, bs->viewangles, goal)) { - /* - float avoidtime; - int t; - - avoidtime = trap_BotAvoidGoalTime(bs->gs, goal->number); - if (avoidtime > 0) { - t = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, goal->areanum, bs->tfl); - if ((float) t * 0.009 < avoidtime) - return qtrue; - } - */ - return qtrue; - } + if (trap_BotItemGoalInVisButNotVisible(bs->entitynum, bs->eye, bs->viewangles, goal)) return qtrue; //if in the goal area and below or above the goal and not swimming if (bs->areanum == goal->areanum) { if (bs->origin[0] > goal->origin[0] + goal->mins[0] && bs->origin[0] < goal->origin[0] + goal->maxs[0]) { @@ -265,7 +233,7 @@ int BotReachedGoal(bot_state_t *bs, bot_goal_t *goal) { //if touching the goal if (trap_BotTouchingGoal(bs->origin, goal)) return qtrue; //if the bot got air - if (bs->lastair_time > FloatTime() - 1) return qtrue; + if (bs->lastair_time > trap_AAS_Time() - 1) return qtrue; } else { //if touching the goal @@ -280,6 +248,7 @@ BotGetItemLongTermGoal ================== */ int BotGetItemLongTermGoal(bot_state_t *bs, int tfl, bot_goal_t *goal) { + qboolean botRoamsOnly = qtrue; //if the bot has no goal if (!trap_BotGetTopGoal(bs->gs, goal)) { //BotAI_Print(PRT_MESSAGE, "no ltg on stack\n"); @@ -291,28 +260,32 @@ int BotGetItemLongTermGoal(bot_state_t *bs, int tfl, bot_goal_t *goal) { bs->ltg_time = 0; } //if it is time to find a new long term goal - if (bs->ltg_time < FloatTime()) { + if (bs->ltg_time < trap_AAS_Time()) { //pop the current goal from the stack trap_BotPopGoal(bs->gs); //BotAI_Print(PRT_MESSAGE, "%s: choosing new ltg\n", ClientName(bs->client, netname, sizeof(netname))); //choose a new goal - //BotAI_Print(PRT_MESSAGE, "%6.1f client %d: BotChooseLTGItem\n", FloatTime(), bs->client); - if (trap_BotChooseLTGItem(bs->gs, bs->origin, bs->inventory, tfl)) { + //BotAI_Print(PRT_MESSAGE, "%6.1f client %d: BotChooseLTGItem\n", trap_AAS_Time(), bs->client); + /*if ( bs->cur_ps.persistant[PERS_CLASS]!=PC_NOCLASS && bs->cur_ps.persistant[PERS_CLASS]!=PC_ACTIONHERO ) + { + botRoamsOnly = qtrue; + }*/ + if (trap_BotChooseLTGItem(bs->gs, bs->origin, bs->inventory, tfl, botRoamsOnly)) { /* char buf[128]; //get the goal at the top of the stack trap_BotGetTopGoal(bs->gs, goal); trap_BotGoalName(goal->number, buf, sizeof(buf)); - BotAI_Print(PRT_MESSAGE, "%1.1f: new long term goal %s\n", FloatTime(), buf); - */ - bs->ltg_time = FloatTime() + 20; + BotAI_Print(PRT_MESSAGE, "%1.1f: new long term goal %s\n", trap_AAS_Time(), buf); + //*/ + bs->ltg_time = trap_AAS_Time() + 20; } else {//the bot gets sorta stuck with all the avoid timings, shouldn't happen though // #ifdef DEBUG - char netname[128]; + //char netname[128]; - BotAI_Print(PRT_MESSAGE, "%s: no valid ltg (probably stuck)\n", ClientName(bs->client, netname, sizeof(netname))); + //BotAI_Print(PRT_MESSAGE, "%s: no valid ltg (probably stuck)\n", ClientName(bs->client, netname, sizeof(netname))); #endif //trap_BotDumpAvoidGoals(bs->gs); //reset the avoid goals and the avoid reach @@ -334,42 +307,40 @@ however this saves us a lot of code ================== */ int BotGetLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) { - vec3_t target, dir, dir2; + vec3_t target, dir; char netname[MAX_NETNAME]; char buf[MAX_MESSAGE_SIZE]; int areanum; float croucher; - aas_entityinfo_t entinfo, botinfo; + aas_entityinfo_t entinfo; bot_waypoint_t *wp; if (bs->ltgtype == LTG_TEAMHELP && !retreat) { //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { + if (bs->teammessage_time && bs->teammessage_time < trap_AAS_Time()) { BotAI_BotInitialChat(bs, "help_start", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL); - trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL); - BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES); - trap_EA_Action(bs->client, ACTION_AFFIRMATIVE); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); bs->teammessage_time = 0; } //if trying to help the team mate for more than a minute - if (bs->teamgoal_time < FloatTime()) + if (bs->teamgoal_time < trap_AAS_Time()) bs->ltgtype = 0; //if the team mate IS visible for quite some time - if (bs->teammatevisible_time < FloatTime() - 10) bs->ltgtype = 0; + if (bs->teammatevisible_time < trap_AAS_Time() - 10) bs->ltgtype = 0; //get entity information of the companion BotEntityInfo(bs->teammate, &entinfo); //if the team mate is visible if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->teammate)) { //if close just stand still there VectorSubtract(entinfo.origin, bs->origin, dir); - if (VectorLengthSquared(dir) < Square(100)) { + if (VectorLength(dir) < 100) { trap_BotResetAvoidReach(bs->ms); return qfalse; } } else { //last time the bot was NOT visible - bs->teammatevisible_time = FloatTime(); + bs->teammatevisible_time = trap_AAS_Time(); } //if the entity information is valid (entity in PVS) if (entinfo.valid) { @@ -389,17 +360,15 @@ int BotGetLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) //if the bot accompanies someone if (bs->ltgtype == LTG_TEAMACCOMPANY && !retreat) { //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { + if (bs->teammessage_time && bs->teammessage_time < trap_AAS_Time()) { BotAI_BotInitialChat(bs, "accompany_start", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL); - trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL); - BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES); - trap_EA_Action(bs->client, ACTION_AFFIRMATIVE); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); bs->teammessage_time = 0; } //if accompanying the companion for 3 minutes - if (bs->teamgoal_time < FloatTime()) { + if (bs->teamgoal_time < trap_AAS_Time()) { BotAI_BotInitialChat(bs, "accompany_stop", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL); - trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); bs->ltgtype = 0; } //get entity information of the companion @@ -407,69 +376,40 @@ int BotGetLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) //if the companion is visible if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->teammate)) { //update visible time - bs->teammatevisible_time = FloatTime(); + bs->teammatevisible_time = trap_AAS_Time(); VectorSubtract(entinfo.origin, bs->origin, dir); - if (VectorLengthSquared(dir) < Square(bs->formation_dist)) { - // - // if the client being followed bumps into this bot then - // the bot should back up - BotEntityInfo(bs->entitynum, &botinfo); - // if the followed client is not standing ontop of the bot - if (botinfo.origin[2] + botinfo.maxs[2] > entinfo.origin[2] + entinfo.mins[2]) { - // if the bounding boxes touch each other - if (botinfo.origin[0] + botinfo.maxs[0] > entinfo.origin[0] + entinfo.mins[0] - 4&& - botinfo.origin[0] + botinfo.mins[0] < entinfo.origin[0] + entinfo.maxs[0] + 4) { - if (botinfo.origin[1] + botinfo.maxs[1] > entinfo.origin[1] + entinfo.mins[1] - 4 && - botinfo.origin[1] + botinfo.mins[1] < entinfo.origin[1] + entinfo.maxs[1] + 4) { - if (botinfo.origin[2] + botinfo.maxs[2] > entinfo.origin[2] + entinfo.mins[2] - 4 && - botinfo.origin[2] + botinfo.mins[2] < entinfo.origin[2] + entinfo.maxs[2] + 4) { - // if the followed client looks in the direction of this bot - AngleVectors(entinfo.angles, dir, NULL, NULL); - dir[2] = 0; - VectorNormalize(dir); - //VectorSubtract(entinfo.origin, entinfo.lastvisorigin, dir); - VectorSubtract(bs->origin, entinfo.origin, dir2); - VectorNormalize(dir2); - if (DotProduct(dir, dir2) > 0.7) { - // back up - BotSetupForMovement(bs); - trap_BotMoveInDirection(bs->ms, dir2, 400, MOVE_WALK); - } - } - } - } - } + if (VectorLength(dir) < bs->formation_dist) { //check if the bot wants to crouch //don't crouch if crouched less than 5 seconds ago - if (bs->attackcrouch_time < FloatTime() - 5) { - croucher = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CROUCHER, 0, 1); + if (bs->attackcrouch_time < trap_AAS_Time() - 5) { + croucher = 1; if (random() < bs->thinktime * croucher) { - bs->attackcrouch_time = FloatTime() + 5 + croucher * 15; + bs->attackcrouch_time = trap_AAS_Time() + 5 + croucher * 15; } } //don't crouch when swimming - if (trap_AAS_Swimming(bs->origin)) bs->attackcrouch_time = FloatTime() - 1; + if (trap_AAS_Swimming(bs->origin)) bs->attackcrouch_time = trap_AAS_Time() - 1; //if not arrived yet or arived some time ago - if (bs->arrive_time < FloatTime() - 2) { + if (bs->arrive_time < trap_AAS_Time() - 2) { //if not arrived yet if (!bs->arrive_time) { trap_EA_Gesture(bs->client); BotAI_BotInitialChat(bs, "accompany_arrive", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL); - trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL); - bs->arrive_time = FloatTime(); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); + bs->arrive_time = trap_AAS_Time(); } //if the bot wants to crouch - else if (bs->attackcrouch_time > FloatTime()) { + else if (bs->attackcrouch_time > trap_AAS_Time()) { trap_EA_Crouch(bs->client); } //else do some model taunts - else if (random() < bs->thinktime * 0.05) { + else if (random() < bs->thinktime * 0.3) { //do a gesture :) trap_EA_Gesture(bs->client); } } //if just arrived look at the companion - if (bs->arrive_time > FloatTime() - 2) { + if (bs->arrive_time > trap_AAS_Time() - 2) { VectorSubtract(entinfo.origin, bs->origin, dir); vectoangles(dir, bs->ideal_viewangles); bs->ideal_viewangles[2] *= 0.5; @@ -489,8 +429,8 @@ int BotGetLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) //trap_BotGoalName(tmpgoal.number, buf, 144); //BotAI_Print(PRT_MESSAGE, "new nearby goal %s\n", buf); //time the bot gets to pick up the nearby goal item - bs->nbg_time = FloatTime() + 8; - AIEnter_Seek_NBG(bs, "BotLongTermGoal: go for air"); + bs->nbg_time = trap_AAS_Time() + 8; + AIEnter_Seek_NBG(bs); return qfalse; } // @@ -502,7 +442,7 @@ int BotGetLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) if (entinfo.valid) { areanum = BotPointAreaNum(entinfo.origin); if (areanum && trap_AAS_AreaReachability(areanum)) { - //update team goal + //update team goal so bot will accompany bs->teamgoal.entitynum = bs->teammate; bs->teamgoal.areanum = areanum; VectorCopy(entinfo.origin, bs->teamgoal.origin); @@ -513,12 +453,10 @@ int BotGetLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) //the goal the bot should go for memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t)); //if the companion is NOT visible for too long - if (bs->teammatevisible_time < FloatTime() - 60) { + if (bs->teammatevisible_time < trap_AAS_Time() - 60) { BotAI_BotInitialChat(bs, "accompany_cannotfind", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL); - trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); bs->ltgtype = 0; - // just to make sure the bot won't spam this message - bs->teammatevisible_time = FloatTime(); } return qtrue; } @@ -531,57 +469,51 @@ int BotGetLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) } //if defending a key area if (bs->ltgtype == LTG_DEFENDKEYAREA && !retreat && - bs->defendaway_time < FloatTime()) { + bs->defendaway_time < trap_AAS_Time()) { //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { + if (bs->teammessage_time && bs->teammessage_time < trap_AAS_Time()) { trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf)); BotAI_BotInitialChat(bs, "defend_start", buf, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - BotVoiceChatOnly(bs, -1, VOICECHAT_ONDEFENSE); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); bs->teammessage_time = 0; } //set the bot goal memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t)); //stop after 2 minutes - if (bs->teamgoal_time < FloatTime()) { + if (bs->teamgoal_time < trap_AAS_Time()) { trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf)); BotAI_BotInitialChat(bs, "defend_stop", buf, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); bs->ltgtype = 0; } //if very close... go away for some time VectorSubtract(goal->origin, bs->origin, dir); - if (VectorLengthSquared(dir) < Square(70)) { + if (VectorLength(dir) < 70) { trap_BotResetAvoidReach(bs->ms); - bs->defendaway_time = FloatTime() + 3 + 3 * random(); - if (BotHasPersistantPowerupAndWeapon(bs)) { - bs->defendaway_range = 100; - } - else { - bs->defendaway_range = 350; - } + bs->defendaway_time = trap_AAS_Time() + 2 + 5 * random(); + bs->defendaway_range = 250; } return qtrue; } //going to kill someone if (bs->ltgtype == LTG_KILL && !retreat) { //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { + if (bs->teammessage_time && bs->teammessage_time < trap_AAS_Time()) { EasyClientName(bs->teamgoal.entitynum, buf, sizeof(buf)); BotAI_BotInitialChat(bs, "kill_start", buf, NULL); - trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); bs->teammessage_time = 0; } // if (bs->lastkilledplayer == bs->teamgoal.entitynum) { EasyClientName(bs->teamgoal.entitynum, buf, sizeof(buf)); BotAI_BotInitialChat(bs, "kill_done", buf, NULL); - trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); bs->lastkilledplayer = -1; bs->ltgtype = 0; } // - if (bs->teamgoal_time < FloatTime()) { + if (bs->teamgoal_time < trap_AAS_Time()) { bs->ltgtype = 0; } //just roam around @@ -590,31 +522,29 @@ int BotGetLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) //get an item if (bs->ltgtype == LTG_GETITEM && !retreat) { //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { + if (bs->teammessage_time && bs->teammessage_time < trap_AAS_Time()) { trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf)); BotAI_BotInitialChat(bs, "getitem_start", buf, NULL); - trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL); - BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES); - trap_EA_Action(bs->client, ACTION_AFFIRMATIVE); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); bs->teammessage_time = 0; } //set the bot goal memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t)); //stop after some time - if (bs->teamgoal_time < FloatTime()) { + if (bs->teamgoal_time < trap_AAS_Time()) { bs->ltgtype = 0; } // if (trap_BotItemGoalInVisButNotVisible(bs->entitynum, bs->eye, bs->viewangles, goal)) { trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf)); BotAI_BotInitialChat(bs, "getitem_notthere", buf, NULL); - trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); bs->ltgtype = 0; } else if (BotReachedGoal(bs, goal)) { trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf)); BotAI_BotInitialChat(bs, "getitem_gotit", buf, NULL); - trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); bs->ltgtype = 0; } return qtrue; @@ -622,37 +552,34 @@ int BotGetLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) //if camping somewhere if ((bs->ltgtype == LTG_CAMP || bs->ltgtype == LTG_CAMPORDER) && !retreat) { //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { + if (bs->teammessage_time && bs->teammessage_time < trap_AAS_Time()) { if (bs->ltgtype == LTG_CAMPORDER) { BotAI_BotInitialChat(bs, "camp_start", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL); - trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL); - BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES); - trap_EA_Action(bs->client, ACTION_AFFIRMATIVE); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); } bs->teammessage_time = 0; } //set the bot goal memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t)); // - if (bs->teamgoal_time < FloatTime()) { + if (bs->teamgoal_time < trap_AAS_Time()) { if (bs->ltgtype == LTG_CAMPORDER) { BotAI_BotInitialChat(bs, "camp_stop", NULL); - trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); } bs->ltgtype = 0; } //if really near the camp spot VectorSubtract(goal->origin, bs->origin, dir); - if (VectorLengthSquared(dir) < Square(60)) + if (VectorLength(dir) < 60) { //if not arrived yet if (!bs->arrive_time) { if (bs->ltgtype == LTG_CAMPORDER) { BotAI_BotInitialChat(bs, "camp_arrive", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL); - trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL); - BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_INPOSITION); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); } - bs->arrive_time = FloatTime(); + bs->arrive_time = trap_AAS_Time(); } //look strategically around for enemies if (random() < bs->thinktime * 0.8) { @@ -663,32 +590,30 @@ int BotGetLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) } //check if the bot wants to crouch //don't crouch if crouched less than 5 seconds ago - if (bs->attackcrouch_time < FloatTime() - 5) { - croucher = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CROUCHER, 0, 1); + if (bs->attackcrouch_time < trap_AAS_Time() - 5) { + croucher = 1; if (random() < bs->thinktime * croucher) { - bs->attackcrouch_time = FloatTime() + 5 + croucher * 15; + bs->attackcrouch_time = trap_AAS_Time() + 5 + croucher * 15; } } //if the bot wants to crouch - if (bs->attackcrouch_time > FloatTime()) { + if (bs->attackcrouch_time > trap_AAS_Time()) { trap_EA_Crouch(bs->client); } //don't crouch when swimming - if (trap_AAS_Swimming(bs->origin)) bs->attackcrouch_time = FloatTime() - 1; + if (trap_AAS_Swimming(bs->origin)) bs->attackcrouch_time = trap_AAS_Time() - 1; //make sure the bot is not gonna drown if (trap_PointContents(bs->eye,bs->entitynum) & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA)) { if (bs->ltgtype == LTG_CAMPORDER) { BotAI_BotInitialChat(bs, "camp_stop", NULL); - trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL); - // - if (bs->lastgoal_ltgtype == LTG_CAMPORDER) { - bs->lastgoal_ltgtype = 0; - } + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); } bs->ltgtype = 0; } // - //FIXME: move around a bit + if (bs->camp_range > 0) { + //FIXME: move around a bit + } // trap_BotResetAvoidReach(bs->ms); return qfalse; @@ -698,16 +623,14 @@ int BotGetLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) //patrolling along several waypoints if (bs->ltgtype == LTG_PATROL && !retreat) { //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { + if (bs->teammessage_time && bs->teammessage_time < trap_AAS_Time()) { strcpy(buf, ""); for (wp = bs->patrolpoints; wp; wp = wp->next) { strcat(buf, wp->name); if (wp->next) strcat(buf, " to "); } BotAI_BotInitialChat(bs, "patrol_start", buf, NULL); - trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL); - BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES); - trap_EA_Action(bs->client, ACTION_AFFIRMATIVE); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); bs->teammessage_time = 0; } // @@ -737,9 +660,9 @@ int BotGetLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) } } //stop after 5 minutes - if (bs->teamgoal_time < FloatTime()) { + if (bs->teamgoal_time < trap_AAS_Time()) { BotAI_BotInitialChat(bs, "patrol_stop", NULL); - trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); bs->ltgtype = 0; } if (!bs->curpatrolpoint) { @@ -750,288 +673,80 @@ int BotGetLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) return qtrue; } #ifdef CTF - if (gametype == GT_CTF) { - //if going for enemy flag - if (bs->ltgtype == LTG_GETFLAG) { - //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { - BotAI_BotInitialChat(bs, "captureflag_start", NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - BotVoiceChatOnly(bs, -1, VOICECHAT_ONGETFLAG); - bs->teammessage_time = 0; + //if going for enemy flag + if (bs->ltgtype == LTG_GETFLAG) { + //check for bot typing status message + if (bs->teammessage_time && bs->teammessage_time < trap_AAS_Time()) { + BotAI_BotInitialChat(bs, "captureflag_start", NULL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); + bs->teammessage_time = 0; + } + // + switch(BotCTFTeam(bs)) { + case CTF_TEAM_RED: *goal = ctf_blueflag; break; + case CTF_TEAM_BLUE: *goal = ctf_redflag; break; + default: bs->ltgtype = 0; return qfalse; + } + //if touching the flag + if (trap_BotTouchingGoal(bs->origin, goal)) bs->ltgtype = 0; + //stop after 3 minutes + if (bs->teamgoal_time < trap_AAS_Time()) { +#ifdef DEBUG + BotAI_Print(PRT_MESSAGE, "%s: I quit getting the flag\n", ClientName(bs->client, netname, sizeof(netname))); +#endif //DEBUG + bs->ltgtype = 0; + } + return qtrue; + } + //if rushing to the base + if (bs->ltgtype == LTG_RUSHBASE && bs->rushbaseaway_time < trap_AAS_Time()) { + switch(BotCTFTeam(bs)) { + case CTF_TEAM_RED: *goal = ctf_redflag; break; + case CTF_TEAM_BLUE: *goal = ctf_blueflag; break; + default: bs->ltgtype = 0; return qfalse; + } + //if not carrying the flag anymore + if (!BotCTFCarryingFlag(bs)) bs->ltgtype = 0; + //quit rushing after 2 minutes + if (bs->teamgoal_time < trap_AAS_Time()) bs->ltgtype = 0; + //if touching the base flag the bot should loose the enemy flag + if (trap_BotTouchingGoal(bs->origin, goal)) { + //if the bot is still carrying the enemy flag then the + //base flag is gone, now just walk near the base a bit + if (BotCTFCarryingFlag(bs)) { + trap_BotResetAvoidReach(bs->ms); + bs->rushbaseaway_time = trap_AAS_Time() + 5 + 10 * random(); + //FIXME: add chat to tell the others to get back the flag + //FIXME: Make them camp? Get health? Preserve themselves? } - // - switch(BotTeam(bs)) { - case TEAM_RED: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break; - case TEAM_BLUE: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break; - default: bs->ltgtype = 0; return qfalse; - } - //if touching the flag - if (trap_BotTouchingGoal(bs->origin, goal)) { - // make sure the bot knows the flag isn't there anymore - switch(BotTeam(bs)) { - case TEAM_RED: bs->blueflagstatus = 1; break; - case TEAM_BLUE: bs->redflagstatus = 1; break; - } + else { bs->ltgtype = 0; } - //stop after 3 minutes - if (bs->teamgoal_time < FloatTime()) { - bs->ltgtype = 0; - } - BotAlternateRoute(bs, goal); - return qtrue; } - //if rushing to the base - if (bs->ltgtype == LTG_RUSHBASE && bs->rushbaseaway_time < FloatTime()) { - switch(BotTeam(bs)) { - case TEAM_RED: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break; - case TEAM_BLUE: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break; - default: bs->ltgtype = 0; return qfalse; - } - //if not carrying the flag anymore - if (!BotCTFCarryingFlag(bs)) bs->ltgtype = 0; - //quit rushing after 2 minutes - if (bs->teamgoal_time < FloatTime()) bs->ltgtype = 0; - //if touching the base flag the bot should loose the enemy flag - if (trap_BotTouchingGoal(bs->origin, goal)) { - //if the bot is still carrying the enemy flag then the - //base flag is gone, now just walk near the base a bit - if (BotCTFCarryingFlag(bs)) { - trap_BotResetAvoidReach(bs->ms); - bs->rushbaseaway_time = FloatTime() + 5 + 10 * random(); - //FIXME: add chat to tell the others to get back the flag - } - else { - bs->ltgtype = 0; - } - } - BotAlternateRoute(bs, goal); - return qtrue; + return qtrue; + } + //returning flag + if (bs->ltgtype == LTG_RETURNFLAG) { + //check for bot typing status message + if (bs->teammessage_time && bs->teammessage_time < trap_AAS_Time()) { + EasyClientName(bs->teamgoal.entitynum, buf, sizeof(buf)); + BotAI_BotInitialChat(bs, "returnflag_start", buf, NULL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); + bs->teammessage_time = 0; } - //returning flag - if (bs->ltgtype == LTG_RETURNFLAG) { - //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { - BotAI_BotInitialChat(bs, "returnflag_start", NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - BotVoiceChatOnly(bs, -1, VOICECHAT_ONRETURNFLAG); - bs->teammessage_time = 0; - } - // - switch(BotTeam(bs)) { - case TEAM_RED: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break; - case TEAM_BLUE: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break; - default: bs->ltgtype = 0; return qfalse; - } - //if touching the flag - if (trap_BotTouchingGoal(bs->origin, goal)) bs->ltgtype = 0; - //stop after 3 minutes - if (bs->teamgoal_time < FloatTime()) { - bs->ltgtype = 0; - } - BotAlternateRoute(bs, goal); - return qtrue; + // + if (bs->teamgoal_time < trap_AAS_Time()) { + bs->ltgtype = 0; } + //FIXME: Uh.... we're trying to retrieve our flag, shouldn't + // we set that as our goal somewhere? + //ALSO: Can't we also easily implement the ability to pick up + // the enemy flag if it's dropped in the field by a teammate? + + //just roam around + return BotGetItemLongTermGoal(bs, tfl, goal); } #endif //CTF -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF) { - if (bs->ltgtype == LTG_GETFLAG) { - //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { - BotAI_BotInitialChat(bs, "captureflag_start", NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - BotVoiceChatOnly(bs, -1, VOICECHAT_ONGETFLAG); - bs->teammessage_time = 0; - } - memcpy(goal, &ctf_neutralflag, sizeof(bot_goal_t)); - //if touching the flag - if (trap_BotTouchingGoal(bs->origin, goal)) { - bs->ltgtype = 0; - } - //stop after 3 minutes - if (bs->teamgoal_time < FloatTime()) { - bs->ltgtype = 0; - } - return qtrue; - } - //if rushing to the base - if (bs->ltgtype == LTG_RUSHBASE) { - switch(BotTeam(bs)) { - case TEAM_RED: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break; - case TEAM_BLUE: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break; - default: bs->ltgtype = 0; return qfalse; - } - //if not carrying the flag anymore - if (!Bot1FCTFCarryingFlag(bs)) { - bs->ltgtype = 0; - } - //quit rushing after 2 minutes - if (bs->teamgoal_time < FloatTime()) { - bs->ltgtype = 0; - } - //if touching the base flag the bot should loose the enemy flag - if (trap_BotTouchingGoal(bs->origin, goal)) { - bs->ltgtype = 0; - } - BotAlternateRoute(bs, goal); - return qtrue; - } - //attack the enemy base - if (bs->ltgtype == LTG_ATTACKENEMYBASE && - bs->attackaway_time < FloatTime()) { - //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { - BotAI_BotInitialChat(bs, "attackenemybase_start", NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - BotVoiceChatOnly(bs, -1, VOICECHAT_ONOFFENSE); - bs->teammessage_time = 0; - } - switch(BotTeam(bs)) { - case TEAM_RED: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break; - case TEAM_BLUE: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break; - default: bs->ltgtype = 0; return qfalse; - } - //quit rushing after 2 minutes - if (bs->teamgoal_time < FloatTime()) { - bs->ltgtype = 0; - } - //if touching the base flag the bot should loose the enemy flag - if (trap_BotTouchingGoal(bs->origin, goal)) { - bs->attackaway_time = FloatTime() + 2 + 5 * random(); - } - return qtrue; - } - //returning flag - if (bs->ltgtype == LTG_RETURNFLAG) { - //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { - BotAI_BotInitialChat(bs, "returnflag_start", NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - BotVoiceChatOnly(bs, -1, VOICECHAT_ONRETURNFLAG); - bs->teammessage_time = 0; - } - // - if (bs->teamgoal_time < FloatTime()) { - bs->ltgtype = 0; - } - //just roam around - return BotGetItemLongTermGoal(bs, tfl, goal); - } - } - else if (gametype == GT_OBELISK) { - if (bs->ltgtype == LTG_ATTACKENEMYBASE && - bs->attackaway_time < FloatTime()) { - - //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { - BotAI_BotInitialChat(bs, "attackenemybase_start", NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - BotVoiceChatOnly(bs, -1, VOICECHAT_ONOFFENSE); - bs->teammessage_time = 0; - } - switch(BotTeam(bs)) { - case TEAM_RED: memcpy(goal, &blueobelisk, sizeof(bot_goal_t)); break; - case TEAM_BLUE: memcpy(goal, &redobelisk, sizeof(bot_goal_t)); break; - default: bs->ltgtype = 0; return qfalse; - } - //if the bot no longer wants to attack the obelisk - if (BotFeelingBad(bs) > 50) { - return BotGetItemLongTermGoal(bs, tfl, goal); - } - //if touching the obelisk - if (trap_BotTouchingGoal(bs->origin, goal)) { - bs->attackaway_time = FloatTime() + 3 + 5 * random(); - } - // or very close to the obelisk - VectorSubtract(bs->origin, goal->origin, dir); - if (VectorLengthSquared(dir) < Square(60)) { - bs->attackaway_time = FloatTime() + 3 + 5 * random(); - } - //quit rushing after 2 minutes - if (bs->teamgoal_time < FloatTime()) { - bs->ltgtype = 0; - } - BotAlternateRoute(bs, goal); - //just move towards the obelisk - return qtrue; - } - } - else if (gametype == GT_HARVESTER) { - //if rushing to the base - if (bs->ltgtype == LTG_RUSHBASE) { - switch(BotTeam(bs)) { - case TEAM_RED: memcpy(goal, &blueobelisk, sizeof(bot_goal_t)); break; - case TEAM_BLUE: memcpy(goal, &redobelisk, sizeof(bot_goal_t)); break; - default: BotGoHarvest(bs); return qfalse; - } - //if not carrying any cubes - if (!BotHarvesterCarryingCubes(bs)) { - BotGoHarvest(bs); - return qfalse; - } - //quit rushing after 2 minutes - if (bs->teamgoal_time < FloatTime()) { - BotGoHarvest(bs); - return qfalse; - } - //if touching the base flag the bot should loose the enemy flag - if (trap_BotTouchingGoal(bs->origin, goal)) { - BotGoHarvest(bs); - return qfalse; - } - BotAlternateRoute(bs, goal); - return qtrue; - } - //attack the enemy base - if (bs->ltgtype == LTG_ATTACKENEMYBASE && - bs->attackaway_time < FloatTime()) { - //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { - BotAI_BotInitialChat(bs, "attackenemybase_start", NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - BotVoiceChatOnly(bs, -1, VOICECHAT_ONOFFENSE); - bs->teammessage_time = 0; - } - switch(BotTeam(bs)) { - case TEAM_RED: memcpy(goal, &blueobelisk, sizeof(bot_goal_t)); break; - case TEAM_BLUE: memcpy(goal, &redobelisk, sizeof(bot_goal_t)); break; - default: bs->ltgtype = 0; return qfalse; - } - //quit rushing after 2 minutes - if (bs->teamgoal_time < FloatTime()) { - bs->ltgtype = 0; - } - //if touching the base flag the bot should loose the enemy flag - if (trap_BotTouchingGoal(bs->origin, goal)) { - bs->attackaway_time = FloatTime() + 2 + 5 * random(); - } - return qtrue; - } - //harvest cubes - if (bs->ltgtype == LTG_HARVEST && - bs->harvestaway_time < FloatTime()) { - //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { - BotAI_BotInitialChat(bs, "harvest_start", NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - BotVoiceChatOnly(bs, -1, VOICECHAT_ONOFFENSE); - bs->teammessage_time = 0; - } - memcpy(goal, &neutralobelisk, sizeof(bot_goal_t)); - // - if (bs->teamgoal_time < FloatTime()) { - bs->ltgtype = 0; - } - // - if (trap_BotTouchingGoal(bs->origin, goal)) { - bs->harvestaway_time = FloatTime() + 4 + 3 * random(); - } - return qtrue; - } - } -#endif //normal goal stuff return BotGetItemLongTermGoal(bs, tfl, goal); } @@ -1044,7 +759,7 @@ BotLongTermGoal int BotLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) { aas_entityinfo_t entinfo; char teammate[MAX_MESSAGE_SIZE]; - float squaredist; + float dist; int areanum; vec3_t dir; @@ -1052,17 +767,16 @@ int BotLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) { // //if the bot is leading someone and not retreating if (bs->lead_time > 0 && !retreat) { - if (bs->lead_time < FloatTime()) { - BotAI_BotInitialChat(bs, "lead_stop", EasyClientName(bs->lead_teammate, teammate, sizeof(teammate)), NULL); - trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL); + if (bs->lead_time < trap_AAS_Time()) { + //FIXME: add chat to tell the team mate that he/she's on his/her own bs->lead_time = 0; return BotGetLongTermGoal(bs, tfl, retreat, goal); } // - if (bs->leadmessage_time < 0 && -bs->leadmessage_time < FloatTime()) { + if (bs->leadmessage_time < 0 && -bs->leadmessage_time < trap_AAS_Time()) { BotAI_BotInitialChat(bs, "followme", EasyClientName(bs->lead_teammate, teammate, sizeof(teammate)), NULL); - trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL); - bs->leadmessage_time = FloatTime(); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); + bs->leadmessage_time = trap_AAS_Time(); } //get entity information of the companion BotEntityInfo(bs->lead_teammate, &entinfo); @@ -1080,24 +794,24 @@ int BotLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) { } //if the team mate is visible if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->lead_teammate)) { - bs->leadvisible_time = FloatTime(); + bs->leadvisible_time = trap_AAS_Time(); } //if the team mate is not visible for 1 seconds - if (bs->leadvisible_time < FloatTime() - 1) { - bs->leadbackup_time = FloatTime() + 2; + if (bs->leadvisible_time < trap_AAS_Time() - 1) { + bs->leadbackup_time = trap_AAS_Time() + 2; } //distance towards the team mate VectorSubtract(bs->origin, bs->lead_teamgoal.origin, dir); - squaredist = VectorLengthSquared(dir); + dist = VectorLength(dir); //if backing up towards the team mate - if (bs->leadbackup_time > FloatTime()) { - if (bs->leadmessage_time < FloatTime() - 20) { + if (bs->leadbackup_time > trap_AAS_Time()) { + if (bs->leadmessage_time < trap_AAS_Time() - 20) { BotAI_BotInitialChat(bs, "followme", EasyClientName(bs->lead_teammate, teammate, sizeof(teammate)), NULL); - trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL); - bs->leadmessage_time = FloatTime(); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); + bs->leadmessage_time = trap_AAS_Time(); } //if very close to the team mate - if (squaredist < Square(100)) { + if (dist < 100) { bs->leadbackup_time = 0; } //the bot should go back to the team mate @@ -1106,11 +820,11 @@ int BotLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) { } else { //if quite distant from the team mate - if (squaredist > Square(500)) { - if (bs->leadmessage_time < FloatTime() - 20) { + if (dist > 500) { + if (bs->leadmessage_time < trap_AAS_Time() - 20) { BotAI_BotInitialChat(bs, "followme", EasyClientName(bs->lead_teammate, teammate, sizeof(teammate)), NULL); - trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL); - bs->leadmessage_time = FloatTime(); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); + bs->leadmessage_time = trap_AAS_Time(); } //look at the team mate VectorSubtract(entinfo.origin, bs->origin, dir); @@ -1129,13 +843,13 @@ int BotLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) { AIEnter_Intermission ================== */ -void AIEnter_Intermission(bot_state_t *bs, char *s) { - BotRecordNodeSwitch(bs, "intermission", "", s); +void AIEnter_Intermission(bot_state_t *bs) { + BotRecordNodeSwitch(bs, "intermission", ""); //reset the bot state BotResetState(bs); //check for end level chat if (BotChat_EndLevel(bs)) { - trap_BotEnterChat(bs->cs, 0, bs->chatto); + trap_BotEnterChat(bs->cs, bs->client, bs->chatto); } bs->ainode = AINode_Intermission; } @@ -1149,12 +863,12 @@ int AINode_Intermission(bot_state_t *bs) { //if the intermission ended if (!BotIntermission(bs)) { if (BotChat_StartLevel(bs)) { - bs->stand_time = FloatTime() + BotChatTime(bs); + bs->stand_time = trap_AAS_Time() + BotChatTime(bs); } else { - bs->stand_time = FloatTime() + 2; + bs->stand_time = trap_AAS_Time() + 2; } - AIEnter_Stand(bs, "intermission: chat"); + AIEnter_Stand(bs); } return qtrue; } @@ -1164,8 +878,8 @@ int AINode_Intermission(bot_state_t *bs) { AIEnter_Observer ================== */ -void AIEnter_Observer(bot_state_t *bs, char *s) { - BotRecordNodeSwitch(bs, "observer", "", s); +void AIEnter_Observer(bot_state_t *bs) { + BotRecordNodeSwitch(bs, "observer", ""); //reset the bot state BotResetState(bs); bs->ainode = AINode_Observer; @@ -1179,7 +893,7 @@ AINode_Observer int AINode_Observer(bot_state_t *bs) { //if the bot left observer mode if (!BotIsObserver(bs)) { - AIEnter_Stand(bs, "observer: left observer"); + AIEnter_Stand(bs); } return qtrue; } @@ -1189,9 +903,9 @@ int AINode_Observer(bot_state_t *bs) { AIEnter_Stand ================== */ -void AIEnter_Stand(bot_state_t *bs, char *s) { - BotRecordNodeSwitch(bs, "stand", "", s); - bs->standfindenemy_time = FloatTime() + 1; +void AIEnter_Stand(bot_state_t *bs) { + BotRecordNodeSwitch(bs, "stand", ""); + bs->standfindenemy_time = trap_AAS_Time() + 1; bs->ainode = AINode_Stand; } @@ -1205,23 +919,21 @@ int AINode_Stand(bot_state_t *bs) { //if the bot's health decreased if (bs->lastframe_health > bs->inventory[INVENTORY_HEALTH]) { if (BotChat_HitTalking(bs)) { - bs->standfindenemy_time = FloatTime() + BotChatTime(bs) + 0.1; - bs->stand_time = FloatTime() + BotChatTime(bs) + 0.1; + bs->standfindenemy_time = trap_AAS_Time() + BotChatTime(bs) + 0.1; + bs->stand_time = trap_AAS_Time() + BotChatTime(bs) + 0.1; } } - if (bs->standfindenemy_time < FloatTime()) { + if (bs->standfindenemy_time < trap_AAS_Time()) { if (BotFindEnemy(bs, -1)) { - AIEnter_Battle_Fight(bs, "stand: found enemy"); + AIEnter_Battle_Fight(bs); return qfalse; } - bs->standfindenemy_time = FloatTime() + 1; + bs->standfindenemy_time = trap_AAS_Time() + 1; } - // put up chat icon trap_EA_Talk(bs->client); - // when done standing - if (bs->stand_time < FloatTime()) { - trap_BotEnterChat(bs->cs, 0, bs->chatto); - AIEnter_Seek_LTG(bs, "stand: time out"); + if (bs->stand_time < trap_AAS_Time()) { + trap_BotEnterChat(bs->cs, bs->client, bs->chatto); + AIEnter_Seek_LTG(bs); return qfalse; } // @@ -1233,8 +945,8 @@ int AINode_Stand(bot_state_t *bs) { AIEnter_Respawn ================== */ -void AIEnter_Respawn(bot_state_t *bs, char *s) { - BotRecordNodeSwitch(bs, "respawn", "", s); +void AIEnter_Respawn(bot_state_t *bs) { + BotRecordNodeSwitch(bs, "respawn", ""); //reset some states trap_BotResetMoveState(bs->ms); trap_BotResetGoalState(bs->gs); @@ -1242,11 +954,11 @@ void AIEnter_Respawn(bot_state_t *bs, char *s) { trap_BotResetAvoidReach(bs->ms); //if the bot wants to chat if (BotChat_Death(bs)) { - bs->respawn_time = FloatTime() + BotChatTime(bs); - bs->respawnchat_time = FloatTime(); + bs->respawn_time = trap_AAS_Time() + BotChatTime(bs); + bs->respawnchat_time = trap_AAS_Time(); } else { - bs->respawn_time = FloatTime() + 1 + random(); + bs->respawn_time = trap_AAS_Time() + 1 + random(); bs->respawnchat_time = 0; } //set respawn state @@ -1260,184 +972,39 @@ AINode_Respawn ================== */ int AINode_Respawn(bot_state_t *bs) { - // if waiting for the actual respawn if (bs->respawn_wait) { if (!BotIsDead(bs)) { - AIEnter_Seek_LTG(bs, "respawn: respawned"); + AIEnter_Seek_LTG(bs); } else { trap_EA_Respawn(bs->client); } } - else if (bs->respawn_time < FloatTime()) { - // wait until respawned + else if (bs->respawn_time < trap_AAS_Time()) { + //wait until respawned bs->respawn_wait = qtrue; - // elementary action respawn + //elementary action respawn trap_EA_Respawn(bs->client); // if (bs->respawnchat_time) { - trap_BotEnterChat(bs->cs, 0, bs->chatto); + trap_BotEnterChat(bs->cs, bs->client, bs->chatto); bs->enemy = -1; } } - if (bs->respawnchat_time && bs->respawnchat_time < FloatTime() - 0.5) { + if (bs->respawnchat_time && bs->respawnchat_time < trap_AAS_Time() - 0.5) { trap_EA_Talk(bs->client); } // return qtrue; } -/* -================== -BotSelectActivateWeapon -================== -*/ -int BotSelectActivateWeapon(bot_state_t *bs) { - // - if (bs->inventory[INVENTORY_MACHINEGUN] > 0 && bs->inventory[INVENTORY_BULLETS] > 0) - return WEAPONINDEX_MACHINEGUN; - else if (bs->inventory[INVENTORY_SHOTGUN] > 0 && bs->inventory[INVENTORY_SHELLS] > 0) - return WEAPONINDEX_SHOTGUN; - else if (bs->inventory[INVENTORY_PLASMAGUN] > 0 && bs->inventory[INVENTORY_CELLS] > 0) - return WEAPONINDEX_PLASMAGUN; - else if (bs->inventory[INVENTORY_LIGHTNING] > 0 && bs->inventory[INVENTORY_LIGHTNINGAMMO] > 0) - return WEAPONINDEX_LIGHTNING; -#ifdef MISSIONPACK - else if (bs->inventory[INVENTORY_CHAINGUN] > 0 && bs->inventory[INVENTORY_BELT] > 0) - return WEAPONINDEX_CHAINGUN; - else if (bs->inventory[INVENTORY_NAILGUN] > 0 && bs->inventory[INVENTORY_NAILS] > 0) - return WEAPONINDEX_NAILGUN; - else if (bs->inventory[INVENTORY_PROXLAUNCHER] > 0 && bs->inventory[INVENTORY_MINES] > 0) - return WEAPONINDEX_PROXLAUNCHER; -#endif - else if (bs->inventory[INVENTORY_GRENADELAUNCHER] > 0 && bs->inventory[INVENTORY_GRENADES] > 0) - return WEAPONINDEX_GRENADE_LAUNCHER; - else if (bs->inventory[INVENTORY_RAILGUN] > 0 && bs->inventory[INVENTORY_SLUGS] > 0) - return WEAPONINDEX_RAILGUN; - else if (bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 && bs->inventory[INVENTORY_ROCKETS] > 0) - return WEAPONINDEX_ROCKET_LAUNCHER; - else if (bs->inventory[INVENTORY_BFG10K] > 0 && bs->inventory[INVENTORY_BFGAMMO] > 0) - return WEAPONINDEX_BFG; - else { - return -1; - } -} - -/* -================== -BotClearPath - - try to deactivate obstacles like proximity mines on the bot's path -================== -*/ -void BotClearPath(bot_state_t *bs, bot_moveresult_t *moveresult) { - int i, bestmine; - float dist, bestdist; - vec3_t target, dir; - bsp_trace_t bsptrace; - entityState_t state; - - // if there is a dead body wearing kamikze nearby - if (bs->kamikazebody) { - // if the bot's view angles and weapon are not used for movement - if ( !(moveresult->flags & (MOVERESULT_MOVEMENTVIEW | MOVERESULT_MOVEMENTWEAPON)) ) { - // - BotAI_GetEntityState(bs->kamikazebody, &state); - VectorCopy(state.pos.trBase, target); - target[2] += 8; - VectorSubtract(target, bs->eye, dir); - vectoangles(dir, moveresult->ideal_viewangles); - // - moveresult->weapon = BotSelectActivateWeapon(bs); - if (moveresult->weapon == -1) { - // FIXME: run away! - moveresult->weapon = 0; - } - if (moveresult->weapon) { - // - moveresult->flags |= MOVERESULT_MOVEMENTWEAPON | MOVERESULT_MOVEMENTVIEW; - // if holding the right weapon - if (bs->cur_ps.weapon == moveresult->weapon) { - // if the bot is pretty close with its aim - if (InFieldOfVision(bs->viewangles, 20, moveresult->ideal_viewangles)) { - // - BotAI_Trace(&bsptrace, bs->eye, NULL, NULL, target, bs->entitynum, MASK_SHOT); - // if the mine is visible from the current position - if (bsptrace.fraction >= 1.0 || bsptrace.ent == state.number) { - // shoot at the mine - trap_EA_Attack(bs->client); - } - } - } - } - } - } - if (moveresult->flags & MOVERESULT_BLOCKEDBYAVOIDSPOT) { - bs->blockedbyavoidspot_time = FloatTime() + 5; - } - // if blocked by an avoid spot and the view angles and weapon are used for movement - if (bs->blockedbyavoidspot_time > FloatTime() && - !(moveresult->flags & (MOVERESULT_MOVEMENTVIEW | MOVERESULT_MOVEMENTWEAPON)) ) { - bestdist = 300; - bestmine = -1; - for (i = 0; i < bs->numproxmines; i++) { - BotAI_GetEntityState(bs->proxmines[i], &state); - VectorSubtract(state.pos.trBase, bs->origin, dir); - dist = VectorLength(dir); - if (dist < bestdist) { - bestdist = dist; - bestmine = i; - } - } - if (bestmine != -1) { - // - // state->generic1 == TEAM_RED || state->generic1 == TEAM_BLUE - // - // deactivate prox mines in the bot's path by shooting - // rockets or plasma cells etc. at them - BotAI_GetEntityState(bs->proxmines[bestmine], &state); - VectorCopy(state.pos.trBase, target); - target[2] += 2; - VectorSubtract(target, bs->eye, dir); - vectoangles(dir, moveresult->ideal_viewangles); - // if the bot has a weapon that does splash damage - if (bs->inventory[INVENTORY_PLASMAGUN] > 0 && bs->inventory[INVENTORY_CELLS] > 0) - moveresult->weapon = WEAPONINDEX_PLASMAGUN; - else if (bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 && bs->inventory[INVENTORY_ROCKETS] > 0) - moveresult->weapon = WEAPONINDEX_ROCKET_LAUNCHER; - else if (bs->inventory[INVENTORY_BFG10K] > 0 && bs->inventory[INVENTORY_BFGAMMO] > 0) - moveresult->weapon = WEAPONINDEX_BFG; - else { - moveresult->weapon = 0; - } - if (moveresult->weapon) { - // - moveresult->flags |= MOVERESULT_MOVEMENTWEAPON | MOVERESULT_MOVEMENTVIEW; - // if holding the right weapon - if (bs->cur_ps.weapon == moveresult->weapon) { - // if the bot is pretty close with its aim - if (InFieldOfVision(bs->viewangles, 20, moveresult->ideal_viewangles)) { - // - BotAI_Trace(&bsptrace, bs->eye, NULL, NULL, target, bs->entitynum, MASK_SHOT); - // if the mine is visible from the current position - if (bsptrace.fraction >= 1.0 || bsptrace.ent == state.number) { - // shoot at the mine - trap_EA_Attack(bs->client); - } - } - } - } - } - } -} - /* ================== AIEnter_Seek_ActivateEntity ================== */ -void AIEnter_Seek_ActivateEntity(bot_state_t *bs, char *s) { - BotRecordNodeSwitch(bs, "activate entity", "", s); +void AIEnter_Seek_ActivateEntity(bot_state_t *bs) { + BotRecordNodeSwitch(bs, "activate entity", ""); bs->ainode = AINode_Seek_ActivateEntity; } @@ -1448,160 +1015,66 @@ AINode_Seek_Activate_Entity */ int AINode_Seek_ActivateEntity(bot_state_t *bs) { bot_goal_t *goal; - vec3_t target, dir, ideal_viewangles; + vec3_t target, dir; bot_moveresult_t moveresult; - int targetvisible; - bsp_trace_t bsptrace; - aas_entityinfo_t entinfo; if (BotIsObserver(bs)) { - BotClearActivateGoalStack(bs); - AIEnter_Observer(bs, "active entity: observer"); + AIEnter_Observer(bs); return qfalse; } //if in the intermission if (BotIntermission(bs)) { - BotClearActivateGoalStack(bs); - AIEnter_Intermission(bs, "activate entity: intermission"); + AIEnter_Intermission(bs); return qfalse; } //respawn if dead if (BotIsDead(bs)) { - BotClearActivateGoalStack(bs); - AIEnter_Respawn(bs, "activate entity: bot dead"); + AIEnter_Respawn(bs); return qfalse; } // bs->tfl = TFL_DEFAULT; if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK; - // if in lava or slime the bot should be able to get out + //if in lava or slime the bot should be able to get out if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME; - // map specific code + //map specific code BotMapScripts(bs); - // no enemy + //no enemy bs->enemy = -1; - // if the bot has no activate goal - if (!bs->activatestack) { - BotClearActivateGoalStack(bs); - AIEnter_Seek_NBG(bs, "activate entity: no goal"); + // + goal = &bs->activategoal; + //if the bot has no goal + if (!goal) bs->activate_time = 0; + //if the bot touches the current goal + else if (trap_BotTouchingGoal(bs->origin, goal)) { + BotChooseWeapon(bs); +#ifdef DEBUG + BotAI_Print(PRT_MESSAGE, "touched button or trigger\n"); +#endif //DEBUG + bs->activate_time = 0; + } + // + if (bs->activate_time < trap_AAS_Time()) { + AIEnter_Seek_NBG(bs); return qfalse; } + //initialize the movement state + BotSetupForMovement(bs); + //move towards the goal + trap_BotMoveToGoal(&moveresult, bs->ms, goal, bs->tfl); + //if the movement failed + if (moveresult.failure) { + //reset the avoid reach, otherwise bot is stuck in current area + trap_BotResetAvoidReach(bs->ms); + bs->nbg_time = 0; + } + //check if the bot is blocked + BotAIBlocked(bs, &moveresult, qtrue); // - goal = &bs->activatestack->goal; - // initialize target being visible to false - targetvisible = qfalse; - // if the bot has to shoot at a target to activate something - if (bs->activatestack->shoot) { - // - BotAI_Trace(&bsptrace, bs->eye, NULL, NULL, bs->activatestack->target, bs->entitynum, MASK_SHOT); - // if the shootable entity is visible from the current position - if (bsptrace.fraction >= 1.0 || bsptrace.ent == goal->entitynum) { - targetvisible = qtrue; - // if holding the right weapon - if (bs->cur_ps.weapon == bs->activatestack->weapon) { - VectorSubtract(bs->activatestack->target, bs->eye, dir); - vectoangles(dir, ideal_viewangles); - // if the bot is pretty close with its aim - if (InFieldOfVision(bs->viewangles, 20, ideal_viewangles)) { - trap_EA_Attack(bs->client); - } - } - } - } - // if the shoot target is visible - if (targetvisible) { - // get the entity info of the entity the bot is shooting at - BotEntityInfo(goal->entitynum, &entinfo); - // if the entity the bot shoots at moved - if (!VectorCompare(bs->activatestack->origin, entinfo.origin)) { -#ifdef DEBUG - BotAI_Print(PRT_MESSAGE, "hit shootable button or trigger\n"); -#endif //DEBUG - bs->activatestack->time = 0; - } - // if the activate goal has been activated or the bot takes too long - if (bs->activatestack->time < FloatTime()) { - BotPopFromActivateGoalStack(bs); - // if there are more activate goals on the stack - if (bs->activatestack) { - bs->activatestack->time = FloatTime() + 10; - return qfalse; - } - AIEnter_Seek_NBG(bs, "activate entity: time out"); - return qfalse; - } - memset(&moveresult, 0, sizeof(bot_moveresult_t)); - } - else { - // if the bot has no goal - if (!goal) { - bs->activatestack->time = 0; - } - // if the bot does not have a shoot goal - else if (!bs->activatestack->shoot) { - //if the bot touches the current goal - if (trap_BotTouchingGoal(bs->origin, goal)) { -#ifdef DEBUG - BotAI_Print(PRT_MESSAGE, "touched button or trigger\n"); -#endif //DEBUG - bs->activatestack->time = 0; - } - } - // if the activate goal has been activated or the bot takes too long - if (bs->activatestack->time < FloatTime()) { - BotPopFromActivateGoalStack(bs); - // if there are more activate goals on the stack - if (bs->activatestack) { - bs->activatestack->time = FloatTime() + 10; - return qfalse; - } - AIEnter_Seek_NBG(bs, "activate entity: activated"); - return qfalse; - } - //predict obstacles - if (BotAIPredictObstacles(bs, goal)) - return qfalse; - //initialize the movement state - BotSetupForMovement(bs); - //move towards the goal - trap_BotMoveToGoal(&moveresult, bs->ms, goal, bs->tfl); - //if the movement failed - if (moveresult.failure) { - //reset the avoid reach, otherwise bot is stuck in current area - trap_BotResetAvoidReach(bs->ms); - // - bs->activatestack->time = 0; - } - //check if the bot is blocked - BotAIBlocked(bs, &moveresult, qtrue); - } - // - BotClearPath(bs, &moveresult); - // if the bot has to shoot to activate - if (bs->activatestack->shoot) { - // if the view angles aren't yet used for the movement - if (!(moveresult.flags & MOVERESULT_MOVEMENTVIEW)) { - VectorSubtract(bs->activatestack->target, bs->eye, dir); - vectoangles(dir, moveresult.ideal_viewangles); - moveresult.flags |= MOVERESULT_MOVEMENTVIEW; - } - // if there's no weapon yet used for the movement - if (!(moveresult.flags & MOVERESULT_MOVEMENTWEAPON)) { - moveresult.flags |= MOVERESULT_MOVEMENTWEAPON; - // - bs->activatestack->weapon = BotSelectActivateWeapon(bs); - if (bs->activatestack->weapon == -1) { - //FIXME: find a decent weapon first - bs->activatestack->weapon = 0; - } - moveresult.weapon = bs->activatestack->weapon; - } - } - // if the ideal view angles are set for movement if (moveresult.flags & (MOVERESULT_MOVEMENTVIEWSET|MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) { VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles); } - // if waiting for something + //if waiting for something else if (moveresult.flags & MOVERESULT_WAITING) { if (random() < bs->thinktime * 0.8) { BotRoamGoal(bs, target); @@ -1616,27 +1089,25 @@ int AINode_Seek_ActivateEntity(bot_state_t *bs) { vectoangles(dir, bs->ideal_viewangles); } else { - vectoangles(moveresult.movedir, bs->ideal_viewangles); + //vectoangles(moveresult.movedir, bs->ideal_viewangles); } bs->ideal_viewangles[2] *= 0.5; } - // if the weapon is used for the bot movement - if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) - bs->weaponnum = moveresult.weapon; - // if there is an enemy + //if the weapon is used for the bot movement + if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs->weaponnum = moveresult.weapon; + //if there is an enemy if (BotFindEnemy(bs, -1)) { if (BotWantsToRetreat(bs)) { //keep the current long term goal and retreat - AIEnter_Battle_NBG(bs, "activate entity: found enemy"); + AIEnter_Battle_NBG(bs); } else { trap_BotResetLastAvoidReach(bs->ms); //empty the goal stack trap_BotEmptyGoalStack(bs->gs); //go fight - AIEnter_Battle_Fight(bs, "activate entity: found enemy"); + AIEnter_Battle_Fight(bs); } - BotClearActivateGoalStack(bs); } return qtrue; } @@ -1646,16 +1117,16 @@ int AINode_Seek_ActivateEntity(bot_state_t *bs) { AIEnter_Seek_NBG ================== */ -void AIEnter_Seek_NBG(bot_state_t *bs, char *s) { +void AIEnter_Seek_NBG(bot_state_t *bs) { bot_goal_t goal; char buf[144]; if (trap_BotGetTopGoal(bs->gs, &goal)) { trap_BotGoalName(goal.number, buf, 144); - BotRecordNodeSwitch(bs, "seek NBG", buf, s); + BotRecordNodeSwitch(bs, "seek NBG", buf); } else { - BotRecordNodeSwitch(bs, "seek NBG", "no goal", s); + BotRecordNodeSwitch(bs, "seek NBG", "no goal"); } bs->ainode = AINode_Seek_NBG; } @@ -1671,17 +1142,17 @@ int AINode_Seek_NBG(bot_state_t *bs) { bot_moveresult_t moveresult; if (BotIsObserver(bs)) { - AIEnter_Observer(bs, "seek nbg: observer"); + AIEnter_Observer(bs); return qfalse; } //if in the intermission if (BotIntermission(bs)) { - AIEnter_Intermission(bs, "seek nbg: intermision"); + AIEnter_Intermission(bs); return qfalse; } //respawn if dead if (BotIsDead(bs)) { - AIEnter_Respawn(bs, "seek nbg: bot dead"); + AIEnter_Respawn(bs); return qfalse; } // @@ -1705,19 +1176,16 @@ int AINode_Seek_NBG(bot_state_t *bs) { bs->nbg_time = 0; } // - if (bs->nbg_time < FloatTime()) { + if (bs->nbg_time < trap_AAS_Time()) { //pop the current goal from the stack trap_BotPopGoal(bs->gs); //check for new nearby items right away //NOTE: we canNOT reset the check_time to zero because it would create an endless loop of node switches - bs->check_time = FloatTime() + 0.05; + bs->check_time = trap_AAS_Time() + 0.05; //go back to seek ltg - AIEnter_Seek_LTG(bs, "seek nbg: time out"); + AIEnter_Seek_LTG(bs); return qfalse; } - //predict obstacles - if (BotAIPredictObstacles(bs, &goal)) - return qfalse; //initialize the movement state BotSetupForMovement(bs); //move towards the goal @@ -1730,8 +1198,6 @@ int AINode_Seek_NBG(bot_state_t *bs) { } //check if the bot is blocked BotAIBlocked(bs, &moveresult, qtrue); - // - BotClearPath(bs, &moveresult); //if the viewangles are used for the movement if (moveresult.flags & (MOVERESULT_MOVEMENTVIEWSET|MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) { VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles); @@ -1761,14 +1227,14 @@ int AINode_Seek_NBG(bot_state_t *bs) { if (BotFindEnemy(bs, -1)) { if (BotWantsToRetreat(bs)) { //keep the current long term goal and retreat - AIEnter_Battle_NBG(bs, "seek nbg: found enemy"); + AIEnter_Battle_NBG(bs); } else { trap_BotResetLastAvoidReach(bs->ms); //empty the goal stack trap_BotEmptyGoalStack(bs->gs); //go fight - AIEnter_Battle_Fight(bs, "seek nbg: found enemy"); + AIEnter_Battle_Fight(bs); } } return qtrue; @@ -1779,16 +1245,16 @@ int AINode_Seek_NBG(bot_state_t *bs) { AIEnter_Seek_LTG ================== */ -void AIEnter_Seek_LTG(bot_state_t *bs, char *s) { +void AIEnter_Seek_LTG(bot_state_t *bs) { bot_goal_t goal; char buf[144]; if (trap_BotGetTopGoal(bs->gs, &goal)) { trap_BotGoalName(goal.number, buf, 144); - BotRecordNodeSwitch(bs, "seek LTG", buf, s); + BotRecordNodeSwitch(bs, "seek LTG", buf); } else { - BotRecordNodeSwitch(bs, "seek LTG", "no goal", s); + BotRecordNodeSwitch(bs, "seek LTG", "no goal"); } bs->ainode = AINode_Seek_LTG; } @@ -1808,23 +1274,23 @@ int AINode_Seek_LTG(bot_state_t *bs) //bot_goal_t tmpgoal; if (BotIsObserver(bs)) { - AIEnter_Observer(bs, "seek ltg: observer"); + AIEnter_Observer(bs); return qfalse; } //if in the intermission if (BotIntermission(bs)) { - AIEnter_Intermission(bs, "seek ltg: intermission"); + AIEnter_Intermission(bs); return qfalse; } //respawn if dead if (BotIsDead(bs)) { - AIEnter_Respawn(bs, "seek ltg: bot dead"); + AIEnter_Respawn(bs); return qfalse; } // if (BotChat_Random(bs)) { - bs->stand_time = FloatTime() + BotChatTime(bs); - AIEnter_Stand(bs, "seek ltg: random chat"); + bs->stand_time = trap_AAS_Time() + BotChatTime(bs); + AIEnter_Stand(bs); return qfalse; } // @@ -1841,7 +1307,7 @@ int AINode_Seek_LTG(bot_state_t *bs) //no enemy bs->enemy = -1; // - if (bs->killedenemy_time > FloatTime() - 2) { + if (bs->killedenemy_time > trap_AAS_Time() - 2) { if (random() < bs->thinktime * 1) { trap_EA_Gesture(bs->client); } @@ -1850,7 +1316,7 @@ int AINode_Seek_LTG(bot_state_t *bs) if (BotFindEnemy(bs, -1)) { if (BotWantsToRetreat(bs)) { //keep the current long term goal and retreat - AIEnter_Battle_Retreat(bs, "seek ltg: found enemy"); + AIEnter_Battle_Retreat(bs); return qfalse; } else { @@ -1858,19 +1324,23 @@ int AINode_Seek_LTG(bot_state_t *bs) //empty the goal stack trap_BotEmptyGoalStack(bs->gs); //go fight - AIEnter_Battle_Fight(bs, "seek ltg: found enemy"); + AIEnter_Battle_Fight(bs); return qfalse; } } - // - BotTeamGoals(bs, qfalse); +#ifdef CTF + if (gametype == GT_CTF) { + //decide what to do in CTF mode + BotCTFSeekGoals(bs); + } +#endif //CTF //get the current long term goal if (!BotLongTermGoal(bs, bs->tfl, qfalse, &goal)) { return qtrue; } //check for nearby goals periodicly - if (bs->check_time < FloatTime()) { - bs->check_time = FloatTime() + 0.5; + if (bs->check_time < trap_AAS_Time()) { + bs->check_time = trap_AAS_Time() + 0.5; //check if the bot wants to camp BotWantsToCamp(bs); // @@ -1878,22 +1348,9 @@ int AINode_Seek_LTG(bot_state_t *bs) else range = 150; // #ifdef CTF - if (gametype == GT_CTF) { - //if carrying a flag the bot shouldn't be distracted too much - if (BotCTFCarryingFlag(bs)) - range = 50; - } + //if carrying a flag the bot shouldn't be distracted too much + if (BotCTFCarryingFlag(bs)) range = 50; #endif //CTF -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF) { - if (Bot1FCTFCarryingFlag(bs)) - range = 50; - } - else if (gametype == GT_HARVESTER) { - if (BotHarvesterCarryingCubes(bs)) - range = 80; - } -#endif // if (BotNearbyGoal(bs, bs->tfl, &goal, range)) { trap_BotResetLastAvoidReach(bs->ms); @@ -1902,14 +1359,11 @@ int AINode_Seek_LTG(bot_state_t *bs) //trap_BotGoalName(tmpgoal.number, buf, 144); //BotAI_Print(PRT_MESSAGE, "new nearby goal %s\n", buf); //time the bot gets to pick up the nearby goal item - bs->nbg_time = FloatTime() + 4 + range * 0.01; - AIEnter_Seek_NBG(bs, "ltg seek: nbg"); + bs->nbg_time = trap_AAS_Time() + 4 + range * 0.01; + AIEnter_Seek_NBG(bs); return qfalse; } } - //predict obstacles - if (BotAIPredictObstacles(bs, &goal)) - return qfalse; //initialize the movement state BotSetupForMovement(bs); //move towards the goal @@ -1923,8 +1377,6 @@ int AINode_Seek_LTG(bot_state_t *bs) } // BotAIBlocked(bs, &moveresult, qtrue); - // - BotClearPath(bs, &moveresult); //if the viewangles are used for the movement if (moveresult.flags & (MOVERESULT_MOVEMENTVIEWSET|MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) { VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles); @@ -1944,7 +1396,7 @@ int AINode_Seek_LTG(bot_state_t *bs) vectoangles(dir, bs->ideal_viewangles); } //FIXME: look at cluster portals? - else if (VectorLengthSquared(moveresult.movedir)) { + else if (VectorLength(moveresult.movedir)) { vectoangles(moveresult.movedir, bs->ideal_viewangles); } else if (random() < bs->thinktime * 0.8) { @@ -1966,20 +1418,19 @@ int AINode_Seek_LTG(bot_state_t *bs) AIEnter_Battle_Fight ================== */ -void AIEnter_Battle_Fight(bot_state_t *bs, char *s) { - BotRecordNodeSwitch(bs, "battle fight", "", s); +void AIEnter_Battle_Fight(bot_state_t *bs) { + BotRecordNodeSwitch(bs, "battle fight", ""); trap_BotResetLastAvoidReach(bs->ms); bs->ainode = AINode_Battle_Fight; - bs->flags &= ~BFL_FIGHTSUICIDAL; } /* ================== -AIEnter_Battle_SuicidalFight +AIEnter_Battle_Fight ================== */ -void AIEnter_Battle_SuicidalFight(bot_state_t *bs, char *s) { - BotRecordNodeSwitch(bs, "battle fight", "", s); +void AIEnter_Battle_SuicidalFight(bot_state_t *bs) { + BotRecordNodeSwitch(bs, "battle fight", ""); trap_BotResetLastAvoidReach(bs->ms); bs->ainode = AINode_Battle_Fight; bs->flags |= BFL_FIGHTSUICIDAL; @@ -1992,84 +1443,71 @@ AINode_Battle_Fight */ int AINode_Battle_Fight(bot_state_t *bs) { int areanum; - vec3_t target; aas_entityinfo_t entinfo; bot_moveresult_t moveresult; if (BotIsObserver(bs)) { - AIEnter_Observer(bs, "battle fight: observer"); + AIEnter_Observer(bs); return qfalse; } //if in the intermission if (BotIntermission(bs)) { - AIEnter_Intermission(bs, "battle fight: intermission"); + AIEnter_Intermission(bs); return qfalse; } //respawn if dead if (BotIsDead(bs)) { - AIEnter_Respawn(bs, "battle fight: bot dead"); + AIEnter_Respawn(bs); return qfalse; } //if there is another better enemy if (BotFindEnemy(bs, bs->enemy)) { #ifdef DEBUG - BotAI_Print(PRT_MESSAGE, "found new better enemy\n"); +// BotAI_Print(PRT_MESSAGE, "found new better enemy\n"); #endif } //if no enemy if (bs->enemy < 0) { - AIEnter_Seek_LTG(bs, "battle fight: no enemy"); + AIEnter_Seek_LTG(bs); return qfalse; } // BotEntityInfo(bs->enemy, &entinfo); //if the enemy is dead if (bs->enemydeath_time) { - if (bs->enemydeath_time < FloatTime() - 1.0) { + if (bs->enemydeath_time < trap_AAS_Time() - 1.0) { bs->enemydeath_time = 0; if (bs->enemysuicide) { BotChat_EnemySuicide(bs); } if (bs->lastkilledplayer == bs->enemy && BotChat_Kill(bs)) { - bs->stand_time = FloatTime() + BotChatTime(bs); - AIEnter_Stand(bs, "battle fight: enemy dead"); + bs->stand_time = trap_AAS_Time() + BotChatTime(bs); + AIEnter_Stand(bs); } else { bs->ltg_time = 0; - AIEnter_Seek_LTG(bs, "battle fight: enemy dead"); + AIEnter_Seek_LTG(bs); } return qfalse; } } else { if (EntityIsDead(&entinfo)) { - bs->enemydeath_time = FloatTime(); + bs->enemydeath_time = trap_AAS_Time(); } } //if the enemy is invisible and not shooting the bot looses track easily if (EntityIsInvisible(&entinfo) && !EntityIsShooting(&entinfo)) { if (random() < 0.2) { - AIEnter_Seek_LTG(bs, "battle fight: invisible"); + AIEnter_Seek_LTG(bs); return qfalse; } } - // - VectorCopy(entinfo.origin, target); - // if not a player enemy - if (bs->enemy >= MAX_CLIENTS) { -#ifdef MISSIONPACK - // if attacking an obelisk - if ( bs->enemy == redobelisk.entitynum || - bs->enemy == blueobelisk.entitynum ) { - target[2] += 16; - } -#endif - } //update the reachability area and origin if possible - areanum = BotPointAreaNum(target); + areanum = BotPointAreaNum(entinfo.origin); if (areanum && trap_AAS_AreaReachability(areanum)) { - VectorCopy(target, bs->lastenemyorigin); + VectorCopy(entinfo.origin, bs->lastenemyorigin); bs->lastenemyareanum = areanum; } //update the attack inventory values @@ -2077,33 +1515,29 @@ int AINode_Battle_Fight(bot_state_t *bs) { //if the bot's health decreased if (bs->lastframe_health > bs->inventory[INVENTORY_HEALTH]) { if (BotChat_HitNoDeath(bs)) { - bs->stand_time = FloatTime() + BotChatTime(bs); - AIEnter_Stand(bs, "battle fight: chat health decreased"); + bs->stand_time = trap_AAS_Time() + BotChatTime(bs); + AIEnter_Stand(bs); return qfalse; } } //if the bot hit someone - if (bs->cur_ps.persistant[PERS_HITS] > bs->lasthitcount) { - if (BotChat_HitNoKill(bs)) { - bs->stand_time = FloatTime() + BotChatTime(bs); - AIEnter_Stand(bs, "battle fight: chat hit someone"); + if (bs->cur_ps.persistant[PERS_HITS] > bs->lasthitcount) + { + if (BotChat_HitNoKill(bs)) + { + bs->stand_time = trap_AAS_Time() + BotChatTime(bs); + AIEnter_Stand(bs); return qfalse; } } //if the enemy is not visible if (!BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) { -#ifdef MISSIONPACK - if (bs->enemy == redobelisk.entitynum || bs->enemy == blueobelisk.entitynum) { - AIEnter_Battle_Chase(bs, "battle fight: obelisk out of sight"); - return qfalse; - } -#endif if (BotWantsToChase(bs)) { - AIEnter_Battle_Chase(bs, "battle fight: enemy out of sight"); + AIEnter_Battle_Chase(bs); return qfalse; } else { - AIEnter_Seek_LTG(bs, "battle fight: enemy out of sight"); + AIEnter_Seek_LTG(bs); return qfalse; } } @@ -2138,7 +1572,7 @@ int AINode_Battle_Fight(bot_state_t *bs) { //if the bot wants to retreat if (!(bs->flags & BFL_FIGHTSUICIDAL)) { if (BotWantsToRetreat(bs)) { - AIEnter_Battle_Retreat(bs, "battle fight: wants to retreat"); + AIEnter_Battle_Retreat(bs); return qtrue; } } @@ -2150,9 +1584,9 @@ int AINode_Battle_Fight(bot_state_t *bs) { AIEnter_Battle_Chase ================== */ -void AIEnter_Battle_Chase(bot_state_t *bs, char *s) { - BotRecordNodeSwitch(bs, "battle chase", "", s); - bs->chase_time = FloatTime(); +void AIEnter_Battle_Chase(bot_state_t *bs) { + BotRecordNodeSwitch(bs, "battle chase", ""); + bs->chase_time = trap_AAS_Time(); bs->ainode = AINode_Battle_Chase; } @@ -2169,37 +1603,37 @@ int AINode_Battle_Chase(bot_state_t *bs) float range; if (BotIsObserver(bs)) { - AIEnter_Observer(bs, "battle chase: observer"); + AIEnter_Observer(bs); return qfalse; } //if in the intermission if (BotIntermission(bs)) { - AIEnter_Intermission(bs, "battle chase: intermission"); + AIEnter_Intermission(bs); return qfalse; } //respawn if dead if (BotIsDead(bs)) { - AIEnter_Respawn(bs, "battle chase: bot dead"); + AIEnter_Respawn(bs); return qfalse; } //if no enemy if (bs->enemy < 0) { - AIEnter_Seek_LTG(bs, "battle chase: no enemy"); + AIEnter_Seek_LTG(bs); return qfalse; } //if the enemy is visible if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) { - AIEnter_Battle_Fight(bs, "battle chase"); + AIEnter_Battle_Fight(bs); return qfalse; } //if there is another enemy if (BotFindEnemy(bs, -1)) { - AIEnter_Battle_Fight(bs, "battle chase: better enemy"); + AIEnter_Battle_Fight(bs); return qfalse; } //there is no last enemy area if (!bs->lastenemyareanum) { - AIEnter_Seek_LTG(bs, "battle chase: no enemy area"); + AIEnter_Seek_LTG(bs); return qfalse; } // @@ -2222,20 +1656,20 @@ int AINode_Battle_Chase(bot_state_t *bs) //if the last seen enemy spot is reached the enemy could not be found if (trap_BotTouchingGoal(bs->origin, &goal)) bs->chase_time = 0; //if there's no chase time left - if (!bs->chase_time || bs->chase_time < FloatTime() - 10) { - AIEnter_Seek_LTG(bs, "battle chase: time out"); + if (!bs->chase_time || bs->chase_time < trap_AAS_Time() - 10) { + AIEnter_Seek_LTG(bs); return qfalse; } //check for nearby goals periodicly - if (bs->check_time < FloatTime()) { - bs->check_time = FloatTime() + 1; + if (bs->check_time < trap_AAS_Time()) { + bs->check_time = trap_AAS_Time() + 1; range = 150; // if (BotNearbyGoal(bs, bs->tfl, &goal, range)) { //the bot gets 5 seconds to pick up the nearby goal item - bs->nbg_time = FloatTime() + 0.1 * range + 1; + bs->nbg_time = trap_AAS_Time() + 0.1 * range + 1; trap_BotResetLastAvoidReach(bs->ms); - AIEnter_Battle_NBG(bs, "battle chase: nbg"); + AIEnter_Battle_NBG(bs); return qfalse; } } @@ -2259,7 +1693,7 @@ int AINode_Battle_Chase(bot_state_t *bs) VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles); } else if (!(bs->flags & BFL_IDEALVIEWSET)) { - if (bs->chase_time > FloatTime() - 2) { + if (bs->chase_time > trap_AAS_Time() - 2) { BotAimAtEnemy(bs); } else { @@ -2279,7 +1713,7 @@ int AINode_Battle_Chase(bot_state_t *bs) if (bs->areanum == bs->lastenemyareanum) bs->chase_time = 0; //if the bot wants to retreat (the bot could have been damage during the chase) if (BotWantsToRetreat(bs)) { - AIEnter_Battle_Retreat(bs, "battle chase: wants to retreat"); + AIEnter_Battle_Retreat(bs); return qtrue; } return qtrue; @@ -2290,8 +1724,8 @@ int AINode_Battle_Chase(bot_state_t *bs) AIEnter_Battle_Retreat ================== */ -void AIEnter_Battle_Retreat(bot_state_t *bs, char *s) { - BotRecordNodeSwitch(bs, "battle retreat", "", s); +void AIEnter_Battle_Retreat(bot_state_t *bs) { + BotRecordNodeSwitch(bs, "battle retreat", ""); bs->ainode = AINode_Battle_Retreat; } @@ -2309,36 +1743,30 @@ int AINode_Battle_Retreat(bot_state_t *bs) { int areanum; if (BotIsObserver(bs)) { - AIEnter_Observer(bs, "battle retreat: observer"); + AIEnter_Observer(bs); return qfalse; } //if in the intermission if (BotIntermission(bs)) { - AIEnter_Intermission(bs, "battle retreat: intermission"); + AIEnter_Intermission(bs); return qfalse; } //respawn if dead if (BotIsDead(bs)) { - AIEnter_Respawn(bs, "battle retreat: bot dead"); + AIEnter_Respawn(bs); return qfalse; } //if no enemy if (bs->enemy < 0) { - AIEnter_Seek_LTG(bs, "battle retreat: no enemy"); + AIEnter_Seek_LTG(bs); return qfalse; } // BotEntityInfo(bs->enemy, &entinfo); if (EntityIsDead(&entinfo)) { - AIEnter_Seek_LTG(bs, "battle retreat: enemy dead"); + AIEnter_Seek_LTG(bs); return qfalse; } - //if there is another better enemy - if (BotFindEnemy(bs, bs->enemy)) { -#ifdef DEBUG - BotAI_Print(PRT_MESSAGE, "found new better enemy\n"); -#endif - } // bs->tfl = TFL_DEFAULT; if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK; @@ -2353,79 +1781,59 @@ int AINode_Battle_Retreat(bot_state_t *bs) { //empty the goal stack, when chasing, only the enemy is the goal trap_BotEmptyGoalStack(bs->gs); //go chase the enemy - AIEnter_Battle_Chase(bs, "battle retreat: wants to chase"); + AIEnter_Battle_Chase(bs); return qfalse; } //update the last time the enemy was visible if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) { - bs->enemyvisible_time = FloatTime(); - VectorCopy(entinfo.origin, target); - // if not a player enemy - if (bs->enemy >= MAX_CLIENTS) { -#ifdef MISSIONPACK - // if attacking an obelisk - if ( bs->enemy == redobelisk.entitynum || - bs->enemy == blueobelisk.entitynum ) { - target[2] += 16; - } -#endif - } + bs->enemyvisible_time = trap_AAS_Time(); //update the reachability area and origin if possible - areanum = BotPointAreaNum(target); + areanum = BotPointAreaNum(entinfo.origin); if (areanum && trap_AAS_AreaReachability(areanum)) { - VectorCopy(target, bs->lastenemyorigin); + VectorCopy(entinfo.origin, bs->lastenemyorigin); bs->lastenemyareanum = areanum; } } //if the enemy is NOT visible for 4 seconds - if (bs->enemyvisible_time < FloatTime() - 4) { - AIEnter_Seek_LTG(bs, "battle retreat: lost enemy"); + if (bs->enemyvisible_time < trap_AAS_Time() - 4) { + AIEnter_Seek_LTG(bs); return qfalse; } //else if the enemy is NOT visible - else if (bs->enemyvisible_time < FloatTime()) { + else if (bs->enemyvisible_time < trap_AAS_Time()) { //if there is another enemy if (BotFindEnemy(bs, -1)) { - AIEnter_Battle_Fight(bs, "battle retreat: another enemy"); + AIEnter_Battle_Fight(bs); return qfalse; } } // - BotTeamGoals(bs, qtrue); +#ifdef CTF + if (gametype == GT_CTF) { + BotCTFRetreatGoals(bs); + } +#endif //CTF //use holdable items BotBattleUseItems(bs); //get the current long term goal while retreating if (!BotLongTermGoal(bs, bs->tfl, qtrue, &goal)) { - AIEnter_Battle_SuicidalFight(bs, "battle retreat: no way out"); + AIEnter_Battle_SuicidalFight(bs); return qfalse; } //check for nearby goals periodicly - if (bs->check_time < FloatTime()) { - bs->check_time = FloatTime() + 1; + if (bs->check_time < trap_AAS_Time()) { + bs->check_time = trap_AAS_Time() + 1; range = 150; #ifdef CTF - if (gametype == GT_CTF) { - //if carrying a flag the bot shouldn't be distracted too much - if (BotCTFCarryingFlag(bs)) - range = 50; - } + //if carrying a flag the bot shouldn't be distracted too much + if (BotCTFCarryingFlag(bs)) range = 100; #endif //CTF -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF) { - if (Bot1FCTFCarryingFlag(bs)) - range = 50; - } - else if (gametype == GT_HARVESTER) { - if (BotHarvesterCarryingCubes(bs)) - range = 80; - } -#endif // if (BotNearbyGoal(bs, bs->tfl, &goal, range)) { trap_BotResetLastAvoidReach(bs->ms); //time the bot gets to pick up the nearby goal item - bs->nbg_time = FloatTime() + range / 100 + 1; - AIEnter_Battle_NBG(bs, "battle retreat: nbg"); + bs->nbg_time = trap_AAS_Time() + range / 100 + 1; + AIEnter_Battle_NBG(bs); return qfalse; } } @@ -2448,9 +1856,9 @@ int AINode_Battle_Retreat(bot_state_t *bs) { if (moveresult.flags & (MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) { VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles); } - else if (!(moveresult.flags & MOVERESULT_MOVEMENTVIEWSET) - && !(bs->flags & BFL_IDEALVIEWSET) ) { - attack_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_ATTACK_SKILL, 0, 1); + else if (!(moveresult.flags & MOVERESULT_MOVEMENTVIEWSET) && !(bs->flags & BFL_IDEALVIEWSET) ) + { + attack_skill = 1; //if the bot is skilled anough if (attack_skill > 0.3) { BotAimAtEnemy(bs); @@ -2479,8 +1887,8 @@ int AINode_Battle_Retreat(bot_state_t *bs) { AIEnter_Battle_NBG ================== */ -void AIEnter_Battle_NBG(bot_state_t *bs, char *s) { - BotRecordNodeSwitch(bs, "battle NBG", "", s); +void AIEnter_Battle_NBG(bot_state_t *bs) { + BotRecordNodeSwitch(bs, "battle NBG", ""); bs->ainode = AINode_Battle_NBG; } @@ -2498,28 +1906,28 @@ int AINode_Battle_NBG(bot_state_t *bs) { vec3_t target, dir; if (BotIsObserver(bs)) { - AIEnter_Observer(bs, "battle nbg: observer"); + AIEnter_Observer(bs); return qfalse; } //if in the intermission if (BotIntermission(bs)) { - AIEnter_Intermission(bs, "battle nbg: intermission"); + AIEnter_Intermission(bs); return qfalse; } //respawn if dead if (BotIsDead(bs)) { - AIEnter_Respawn(bs, "battle nbg: bot dead"); + AIEnter_Respawn(bs); return qfalse; } //if no enemy if (bs->enemy < 0) { - AIEnter_Seek_NBG(bs, "battle nbg: no enemy"); + AIEnter_Seek_NBG(bs); return qfalse; } // BotEntityInfo(bs->enemy, &entinfo); if (EntityIsDead(&entinfo)) { - AIEnter_Seek_NBG(bs, "battle nbg: enemy dead"); + AIEnter_Seek_NBG(bs); return qfalse; } // @@ -2535,22 +1943,11 @@ int AINode_Battle_NBG(bot_state_t *bs) { BotMapScripts(bs); //update the last time the enemy was visible if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) { - bs->enemyvisible_time = FloatTime(); - VectorCopy(entinfo.origin, target); - // if not a player enemy - if (bs->enemy >= MAX_CLIENTS) { -#ifdef MISSIONPACK - // if attacking an obelisk - if ( bs->enemy == redobelisk.entitynum || - bs->enemy == blueobelisk.entitynum ) { - target[2] += 16; - } -#endif - } + bs->enemyvisible_time = trap_AAS_Time(); //update the reachability area and origin if possible - areanum = BotPointAreaNum(target); + areanum = BotPointAreaNum(entinfo.origin); if (areanum && trap_AAS_AreaReachability(areanum)) { - VectorCopy(target, bs->lastenemyorigin); + VectorCopy(entinfo.origin, bs->lastenemyorigin); bs->lastenemyareanum = areanum; } } @@ -2558,18 +1955,16 @@ int AINode_Battle_NBG(bot_state_t *bs) { if (!trap_BotGetTopGoal(bs->gs, &goal)) { bs->nbg_time = 0; } - else if (BotReachedGoal(bs, &goal)) { + else if (trap_BotTouchingGoal(bs->origin, &goal)) { bs->nbg_time = 0; } // - if (bs->nbg_time < FloatTime()) { + if (bs->nbg_time < trap_AAS_Time()) { //pop the current goal from the stack trap_BotPopGoal(bs->gs); //if the bot still has a goal - if (trap_BotGetTopGoal(bs->gs, &goal)) - AIEnter_Battle_Retreat(bs, "battle nbg: time out"); - else - AIEnter_Battle_Fight(bs, "battle nbg: time out"); + if (trap_BotGetTopGoal(bs->gs, &goal)) AIEnter_Battle_Retreat(bs); + else AIEnter_Battle_Fight(bs); // return qfalse; } @@ -2594,9 +1989,9 @@ int AINode_Battle_NBG(bot_state_t *bs) { if (moveresult.flags & (MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) { VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles); } - else if (!(moveresult.flags & MOVERESULT_MOVEMENTVIEWSET) - && !(bs->flags & BFL_IDEALVIEWSET)) { - attack_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_ATTACK_SKILL, 0, 1); + else if (!(moveresult.flags & MOVERESULT_MOVEMENTVIEWSET) && !(bs->flags & BFL_IDEALVIEWSET)) + { + attack_skill = 1; //if the bot is skilled anough and the enemy is visible if (attack_skill > 0.3) { //&& BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy) diff --git a/code/game/ai_dmnet.h b/code/game/ai_dmnet.h index 05ed2ed..7cabf3a 100644 --- a/code/game/ai_dmnet.h +++ b/code/game/ai_dmnet.h @@ -1,24 +1,4 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // /***************************************************************************** @@ -26,24 +6,28 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * desc: Quake3 bot AI * - * $Archive: /source/code/botai/ai_chat.c $ + * $Archive: /StarTrek/Code-DM/game/ai_dmnet.h $ + * $Author: Jmonroe $ + * $Revision: 1 $ + * $Modtime: 1/21/00 10:12p $ + * $Date: 1/25/00 6:26p $ * *****************************************************************************/ #define MAX_NODESWITCHES 50 -void AIEnter_Intermission(bot_state_t *bs, char *s); -void AIEnter_Observer(bot_state_t *bs, char *s); -void AIEnter_Respawn(bot_state_t *bs, char *s); -void AIEnter_Stand(bot_state_t *bs, char *s); -void AIEnter_Seek_ActivateEntity(bot_state_t *bs, char *s); -void AIEnter_Seek_NBG(bot_state_t *bs, char *s); -void AIEnter_Seek_LTG(bot_state_t *bs, char *s); -void AIEnter_Seek_Camp(bot_state_t *bs, char *s); -void AIEnter_Battle_Fight(bot_state_t *bs, char *s); -void AIEnter_Battle_Chase(bot_state_t *bs, char *s); -void AIEnter_Battle_Retreat(bot_state_t *bs, char *s); -void AIEnter_Battle_NBG(bot_state_t *bs, char *s); +void AIEnter_Intermission(bot_state_t *bs); +void AIEnter_Observer(bot_state_t *bs); +void AIEnter_Respawn(bot_state_t *bs); +void AIEnter_Stand(bot_state_t *bs); +void AIEnter_Seek_ActivateEntity(bot_state_t *bs); +void AIEnter_Seek_NBG(bot_state_t *bs); +void AIEnter_Seek_LTG(bot_state_t *bs); +void AIEnter_Seek_Camp(bot_state_t *bs); +void AIEnter_Battle_Fight(bot_state_t *bs); +void AIEnter_Battle_Chase(bot_state_t *bs); +void AIEnter_Battle_Retreat(bot_state_t *bs); +void AIEnter_Battle_NBG(bot_state_t *bs); int AINode_Intermission(bot_state_t *bs); int AINode_Observer(bot_state_t *bs); int AINode_Respawn(bot_state_t *bs); diff --git a/code/game/ai_dmq3.c b/code/game/ai_dmq3.c index ada5b5d..8ef2b4f 100644 --- a/code/game/ai_dmq3.c +++ b/code/game/ai_dmq3.c @@ -1,46 +1,29 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // - /***************************************************************************** * name: ai_dmq3.c * * desc: Quake3 bot AI * - * $Archive: /MissionPack/code/game/ai_dmq3.c $ + * $Archive: /StarTrek/Code-DM/game/ai_dmq3.c $ + * $Author: Mgummelt $ + * $Revision: 33 $ + * $Modtime: 4/04/01 5:01p $ + * $Date: 4/04/01 5:17p $ * *****************************************************************************/ #include "g_local.h" -#include "../botlib/botlib.h" -#include "../botlib/be_aas.h" -#include "../botlib/be_ea.h" -#include "../botlib/be_ai_char.h" -#include "../botlib/be_ai_chat.h" -#include "../botlib/be_ai_gen.h" -#include "../botlib/be_ai_goal.h" -#include "../botlib/be_ai_move.h" -#include "../botlib/be_ai_weap.h" +#include "botlib.h" +#include "be_aas.h" +#include "be_ea.h" +#include "be_ai_char.h" +#include "be_ai_chat.h" +#include "be_ai_gen.h" +#include "be_ai_goal.h" +#include "be_ai_move.h" +#include "be_ai_weap.h" // #include "ai_main.h" #include "ai_dmq3.h" @@ -54,16 +37,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "syn.h" //synonyms #include "match.h" //string matching types and vars -// for the voice chats -#include "../../ui/menudef.h" // sos001205 - for q3_ui also - -// from aasfile.h -#define AREACONTENTS_MOVER 1024 -#define AREACONTENTS_MODELNUMSHIFT 24 -#define AREACONTENTS_MAXMODELNUM 0xFF -#define AREACONTENTS_MODELNUM (AREACONTENTS_MAXMODELNUM << AREACONTENTS_MODELNUMSHIFT) - #define IDEAL_ATTACKDIST 140 +#define WEAPONINDEX_PHASER 2 #define MAX_WAYPOINTS 128 // @@ -80,10 +55,6 @@ vmCvar_t bot_fastchat; vmCvar_t bot_nochat; vmCvar_t bot_testrchat; vmCvar_t bot_challenge; -vmCvar_t bot_predictobstacles; -vmCvar_t g_spSkill; - -extern vmCvar_t bot_developer; vec3_t lastteleport_origin; //last teleport event origin float lastteleport_time; //last teleport event time @@ -92,36 +63,8 @@ int max_bspmodelindex; //maximum BSP model index //CTF flag goals bot_goal_t ctf_redflag; bot_goal_t ctf_blueflag; -#ifdef MISSIONPACK -bot_goal_t ctf_neutralflag; -bot_goal_t redobelisk; -bot_goal_t blueobelisk; -bot_goal_t neutralobelisk; -#endif - -#define MAX_ALTROUTEGOALS 32 - -int altroutegoals_setup; -aas_altroutegoal_t red_altroutegoals[MAX_ALTROUTEGOALS]; -int red_numaltroutegoals; -aas_altroutegoal_t blue_altroutegoals[MAX_ALTROUTEGOALS]; -int blue_numaltroutegoals; - - -/* -================== -BotSetUserInfo -================== -*/ -void BotSetUserInfo(bot_state_t *bs, char *key, char *value) { - char userinfo[MAX_INFO_STRING]; - - trap_GetUserinfo(bs->client, userinfo, sizeof(userinfo)); - Info_SetValueForKey(userinfo, key, value); - trap_SetUserinfo(bs->client, userinfo); - ClientUserinfoChanged( bs->client ); -} +#ifdef CTF /* ================== BotCTFCarryingFlag @@ -137,66 +80,41 @@ int BotCTFCarryingFlag(bot_state_t *bs) { /* ================== -BotTeam +BotCTFTeam ================== */ -int BotTeam(bot_state_t *bs) { +int BotCTFTeam(bot_state_t *bs) { + char info[1024]; + if (gametype != GT_CTF) return CTF_TEAM_NONE; if (bs->client < 0 || bs->client >= MAX_CLIENTS) { + //BotAI_Print(PRT_ERROR, "BotCTFTeam: client out of range\n"); return qfalse; } - - if (level.clients[bs->client].sess.sessionTeam == TEAM_RED) { - return TEAM_RED; - } else if (level.clients[bs->client].sess.sessionTeam == TEAM_BLUE) { - return TEAM_BLUE; - } - - return TEAM_FREE; + trap_GetConfigstring(CS_PLAYERS+bs->client, info, sizeof(info)); + // + if (atoi(Info_ValueForKey(info, "t")) == TEAM_RED) return CTF_TEAM_RED; + else if (atoi(Info_ValueForKey(info, "t")) == TEAM_BLUE) return CTF_TEAM_BLUE; + return CTF_TEAM_NONE; } /* ================== -BotOppositeTeam +BotCTFRetreatGoals ================== */ -int BotOppositeTeam(bot_state_t *bs) { - switch(BotTeam(bs)) { - case TEAM_RED: return TEAM_BLUE; - case TEAM_BLUE: return TEAM_RED; - default: return TEAM_FREE; +void BotCTFRetreatGoals(bot_state_t *bs) { + //when carrying a flag in ctf the bot should rush to the base + if (BotCTFCarryingFlag(bs)) { + //if not already rushing to the base + if (bs->ltgtype != LTG_RUSHBASE) { + bs->ltgtype = LTG_RUSHBASE; + bs->teamgoal_time = trap_AAS_Time() + CTF_RUSHBASE_TIME; + bs->rushbaseaway_time = 0; + } } } -/* -================== -BotEnemyFlag -================== -*/ -bot_goal_t *BotEnemyFlag(bot_state_t *bs) { - if (BotTeam(bs) == TEAM_RED) { - return &ctf_blueflag; - } - else { - return &ctf_redflag; - } -} - -/* -================== -BotTeamFlag -================== -*/ -bot_goal_t *BotTeamFlag(bot_state_t *bs) { - if (BotTeam(bs) == TEAM_RED) { - return &ctf_redflag; - } - else { - return &ctf_blueflag; - } -} - - /* ================== EntityIsDead @@ -215,34 +133,40 @@ qboolean EntityIsDead(aas_entityinfo_t *entinfo) { /* ================== -EntityCarriesFlag +EntityIsInvisible ================== */ -qboolean EntityCarriesFlag(aas_entityinfo_t *entinfo) { - if ( entinfo->powerups & ( 1 << PW_REDFLAG ) ) +qboolean EntityIsInvisible(aas_entityinfo_t *entinfo) { + if (entinfo->powerups & (1 << PW_GHOST)) + { // 50% chance of being visible? + if (((unsigned int)(level.time)/1024)&0x01) // Every second or so, the bot will see the player, so he doesn't jitter. + { + return qtrue; + } + else + { + return qfalse; + } + } + else if (entinfo->powerups & (1 << PW_INVIS)) + { return qtrue; - if ( entinfo->powerups & ( 1 << PW_BLUEFLAG ) ) + } + else if ( entinfo->flags & EF_NODRAW ) + { return qtrue; -#ifdef MISSIONPACK - if ( entinfo->powerups & ( 1 << PW_NEUTRALFLAG ) ) - return qtrue; -#endif + } return qfalse; } /* ================== -EntityIsInvisible +EntityCarriesFlag ================== */ -qboolean EntityIsInvisible(aas_entityinfo_t *entinfo) { - // the flag is always visible - if (EntityCarriesFlag(entinfo)) { - return qfalse; - } - if (entinfo->powerups & (1 << PW_INVIS)) { - return qtrue; - } +qboolean EntityCarriesFlag(aas_entityinfo_t *entinfo) { + /*if ( entinfo->powerups & ( 1 << PW_REDFLAG ) ) return qtrue;*/ + //if ( entinfo->powerups & ( 1 << PW_BORG_ADAPT ) ) return qtrue; return qfalse; } @@ -282,250 +206,25 @@ qboolean EntityHasQuad(aas_entityinfo_t *entinfo) { return qfalse; } -#ifdef MISSIONPACK -/* -================== -EntityHasKamikze -================== -*/ -qboolean EntityHasKamikaze(aas_entityinfo_t *entinfo) { - if (entinfo->flags & EF_KAMIKAZE) { - return qtrue; - } - return qfalse; -} - -/* -================== -EntityCarriesCubes -================== -*/ -qboolean EntityCarriesCubes(aas_entityinfo_t *entinfo) { - entityState_t state; - - if (gametype != GT_HARVESTER) - return qfalse; - //FIXME: get this info from the aas_entityinfo_t ? - BotAI_GetEntityState(entinfo->number, &state); - if (state.generic1 > 0) - return qtrue; - return qfalse; -} - -/* -================== -Bot1FCTFCarryingFlag -================== -*/ -int Bot1FCTFCarryingFlag(bot_state_t *bs) { - if (gametype != GT_1FCTF) return qfalse; - - if (bs->inventory[INVENTORY_NEUTRALFLAG] > 0) return qtrue; - return qfalse; -} - -/* -================== -BotHarvesterCarryingCubes -================== -*/ -int BotHarvesterCarryingCubes(bot_state_t *bs) { - if (gametype != GT_HARVESTER) return qfalse; - - if (bs->inventory[INVENTORY_REDCUBE] > 0) return qtrue; - if (bs->inventory[INVENTORY_BLUECUBE] > 0) return qtrue; - return qfalse; -} -#endif - -/* -================== -BotRememberLastOrderedTask -================== -*/ -void BotRememberLastOrderedTask(bot_state_t *bs) { - if (!bs->ordered) { - return; - } - bs->lastgoal_decisionmaker = bs->decisionmaker; - bs->lastgoal_ltgtype = bs->ltgtype; - memcpy(&bs->lastgoal_teamgoal, &bs->teamgoal, sizeof(bot_goal_t)); - bs->lastgoal_teammate = bs->teammate; -} - -/* -================== -BotSetTeamStatus -================== -*/ -void BotSetTeamStatus(bot_state_t *bs) { -#ifdef MISSIONPACK - int teamtask; - aas_entityinfo_t entinfo; - - teamtask = TEAMTASK_PATROL; - - switch(bs->ltgtype) { - case LTG_TEAMHELP: - break; - case LTG_TEAMACCOMPANY: - BotEntityInfo(bs->teammate, &entinfo); - if ( ( (gametype == GT_CTF || gametype == GT_1FCTF) && EntityCarriesFlag(&entinfo)) - || ( gametype == GT_HARVESTER && EntityCarriesCubes(&entinfo)) ) { - teamtask = TEAMTASK_ESCORT; - } - else { - teamtask = TEAMTASK_FOLLOW; - } - break; - case LTG_DEFENDKEYAREA: - teamtask = TEAMTASK_DEFENSE; - break; - case LTG_GETFLAG: - teamtask = TEAMTASK_OFFENSE; - break; - case LTG_RUSHBASE: - teamtask = TEAMTASK_DEFENSE; - break; - case LTG_RETURNFLAG: - teamtask = TEAMTASK_RETRIEVE; - break; - case LTG_CAMP: - case LTG_CAMPORDER: - teamtask = TEAMTASK_CAMP; - break; - case LTG_PATROL: - teamtask = TEAMTASK_PATROL; - break; - case LTG_GETITEM: - teamtask = TEAMTASK_PATROL; - break; - case LTG_KILL: - teamtask = TEAMTASK_PATROL; - break; - case LTG_HARVEST: - teamtask = TEAMTASK_OFFENSE; - break; - case LTG_ATTACKENEMYBASE: - teamtask = TEAMTASK_OFFENSE; - break; - default: - teamtask = TEAMTASK_PATROL; - break; - } - BotSetUserInfo(bs, "teamtask", va("%d", teamtask)); -#endif -} - -/* -================== -BotSetLastOrderedTask -================== -*/ -int BotSetLastOrderedTask(bot_state_t *bs) { - - if (gametype == GT_CTF) { - // don't go back to returning the flag if it's at the base - if ( bs->lastgoal_ltgtype == LTG_RETURNFLAG ) { - if ( BotTeam(bs) == TEAM_RED ) { - if ( bs->redflagstatus == 0 ) { - bs->lastgoal_ltgtype = 0; - } - } - else { - if ( bs->blueflagstatus == 0 ) { - bs->lastgoal_ltgtype = 0; - } - } - } - } - - if ( bs->lastgoal_ltgtype ) { - bs->decisionmaker = bs->lastgoal_decisionmaker; - bs->ordered = qtrue; - bs->ltgtype = bs->lastgoal_ltgtype; - memcpy(&bs->teamgoal, &bs->lastgoal_teamgoal, sizeof(bot_goal_t)); - bs->teammate = bs->lastgoal_teammate; - bs->teamgoal_time = FloatTime() + 300; - BotSetTeamStatus(bs); - // - if ( gametype == GT_CTF ) { - if ( bs->ltgtype == LTG_GETFLAG ) { - bot_goal_t *tb, *eb; - int tt, et; - - tb = BotTeamFlag(bs); - eb = BotEnemyFlag(bs); - tt = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, tb->areanum, TFL_DEFAULT); - et = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, eb->areanum, TFL_DEFAULT); - // if the travel time towards the enemy base is larger than towards our base - if (et > tt) { - //get an alternative route goal towards the enemy base - BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs)); - } - } - } - return qtrue; - } - return qfalse; -} - -/* -================== -BotRefuseOrder -================== -*/ -void BotRefuseOrder(bot_state_t *bs) { - if (!bs->ordered) - return; - // if the bot was ordered to do something - if ( bs->order_time && bs->order_time > FloatTime() - 10 ) { - trap_EA_Action(bs->client, ACTION_NEGATIVE); - BotVoiceChat(bs, bs->decisionmaker, VOICECHAT_NO); - bs->order_time = 0; - } -} - /* ================== BotCTFSeekGoals ================== */ void BotCTFSeekGoals(bot_state_t *bs) { - float rnd, l1, l2; + float rnd; int flagstatus, c; - vec3_t dir; - aas_entityinfo_t entinfo; //when carrying a flag in ctf the bot should rush to the base if (BotCTFCarryingFlag(bs)) { //if not already rushing to the base if (bs->ltgtype != LTG_RUSHBASE) { - BotRefuseOrder(bs); bs->ltgtype = LTG_RUSHBASE; - bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME; + bs->teamgoal_time = trap_AAS_Time() + CTF_RUSHBASE_TIME; bs->rushbaseaway_time = 0; - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - // - switch(BotTeam(bs)) { - case TEAM_RED: VectorSubtract(bs->origin, ctf_blueflag.origin, dir); break; - case TEAM_BLUE: VectorSubtract(bs->origin, ctf_redflag.origin, dir); break; - default: VectorSet(dir, 999, 999, 999); break; - } - // if the bot picked up the flag very close to the enemy base - if ( VectorLength(dir) < 128 ) { - // get an alternative route goal through the enemy base - BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs)); - } else { - // don't use any alt route goal, just get the hell out of the base - bs->altroutegoal.areanum = 0; - } - BotSetUserInfo(bs, "teamtask", va("%d", TEAMTASK_OFFENSE)); - BotVoiceChat(bs, -1, VOICECHAT_IHAVEFLAG); } - else if (bs->rushbaseaway_time > FloatTime()) { - if (BotTeam(bs) == TEAM_RED) flagstatus = bs->redflagstatus; + else if (bs->rushbaseaway_time > trap_AAS_Time()) { + if (BotCTFTeam(bs) == CTF_TEAM_RED) flagstatus = bs->redflagstatus; else flagstatus = bs->blueflagstatus; //if the flag is back if (flagstatus == 0) { @@ -534,408 +233,72 @@ void BotCTFSeekGoals(bot_state_t *bs) { } return; } - // if the bot decided to follow someone - if ( bs->ltgtype == LTG_TEAMACCOMPANY && !bs->ordered ) { - // if the team mate being accompanied no longer carries the flag - BotEntityInfo(bs->teammate, &entinfo); - if (!EntityCarriesFlag(&entinfo)) { - bs->ltgtype = 0; - } - } // - if (BotTeam(bs) == TEAM_RED) flagstatus = bs->redflagstatus * 2 + bs->blueflagstatus; + if (BotCTFTeam(bs) == CTF_TEAM_RED) flagstatus = bs->redflagstatus * 2 + bs->blueflagstatus; else flagstatus = bs->blueflagstatus * 2 + bs->redflagstatus; - //if our team has the enemy flag and our flag is at the base + //if the enemy flag is not at it's base if (flagstatus == 1) { - // - if (bs->owndecision_time < FloatTime()) { - //if Not defending the base already - if (!(bs->ltgtype == LTG_DEFENDKEYAREA && - (bs->teamgoal.number == ctf_redflag.number || - bs->teamgoal.number == ctf_blueflag.number))) { - //if there is a visible team mate flag carrier - c = BotTeamFlagCarrierVisible(bs); - if (c >= 0 && - // and not already following the team mate flag carrier - (bs->ltgtype != LTG_TEAMACCOMPANY || bs->teammate != c)) { - // - BotRefuseOrder(bs); - //follow the flag carrier - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - //the team mate - bs->teammate = c; - //last time the team mate was visible - bs->teammatevisible_time = FloatTime(); - //no message - bs->teammessage_time = 0; - //no arrive message - bs->arrive_time = 1; - // - BotVoiceChat(bs, bs->teammate, VOICECHAT_ONFOLLOW); - //get the team goal time - bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME; - bs->ltgtype = LTG_TEAMACCOMPANY; - bs->formation_dist = 3.5 * 32; //3.5 meter - BotSetTeamStatus(bs); - bs->owndecision_time = FloatTime() + 5; - } - } - } - return; - } - //if the enemy has our flag - else if (flagstatus == 2) { - // - if (bs->owndecision_time < FloatTime()) { - //if enemy flag carrier is visible - c = BotEnemyFlagCarrierVisible(bs); - if (c >= 0) { - //FIXME: fight enemy flag carrier - } - //if not already doing something important - if (bs->ltgtype != LTG_GETFLAG && - bs->ltgtype != LTG_RETURNFLAG && - bs->ltgtype != LTG_TEAMHELP && - bs->ltgtype != LTG_TEAMACCOMPANY && - bs->ltgtype != LTG_CAMPORDER && - bs->ltgtype != LTG_PATROL && - bs->ltgtype != LTG_GETITEM) { - - BotRefuseOrder(bs); - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - // - if (random() < 0.5) { - //go for the enemy flag - bs->ltgtype = LTG_GETFLAG; - } - else { - bs->ltgtype = LTG_RETURNFLAG; - } - //no team message - bs->teammessage_time = 0; - //set the time the bot will stop getting the flag - bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME; - //get an alternative route goal towards the enemy base - BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs)); - // - BotSetTeamStatus(bs); - bs->owndecision_time = FloatTime() + 5; - } - } - return; - } - //if both flags Not at their bases - else if (flagstatus == 3) { - // - if (bs->owndecision_time < FloatTime()) { - // if not trying to return the flag and not following the team flag carrier - if ( bs->ltgtype != LTG_RETURNFLAG && bs->ltgtype != LTG_TEAMACCOMPANY ) { - // - c = BotTeamFlagCarrierVisible(bs); - // if there is a visible team mate flag carrier - if (c >= 0) { - BotRefuseOrder(bs); - //follow the flag carrier - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - //the team mate - bs->teammate = c; - //last time the team mate was visible - bs->teammatevisible_time = FloatTime(); - //no message - bs->teammessage_time = 0; - //no arrive message - bs->arrive_time = 1; - // - BotVoiceChat(bs, bs->teammate, VOICECHAT_ONFOLLOW); - //get the team goal time - bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME; - bs->ltgtype = LTG_TEAMACCOMPANY; - bs->formation_dist = 3.5 * 32; //3.5 meter - // - BotSetTeamStatus(bs); - bs->owndecision_time = FloatTime() + 5; - } - else { - BotRefuseOrder(bs); - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - //get the enemy flag - bs->teammessage_time = FloatTime() + 2 * random(); - //get the flag - bs->ltgtype = LTG_RETURNFLAG; - //set the time the bot will stop getting the flag - bs->teamgoal_time = FloatTime() + CTF_RETURNFLAG_TIME; - //get an alternative route goal towards the enemy base - BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs)); - // - BotSetTeamStatus(bs); - bs->owndecision_time = FloatTime() + 5; - } - } - } - return; - } - // don't just do something wait for the bot team leader to give orders - if (BotTeamLeader(bs)) { - return; - } - // if the bot is ordered to do something - if ( bs->lastgoal_ltgtype ) { - bs->teamgoal_time += 60; - } - // if the bot decided to do something on its own and has a last ordered goal - if ( !bs->ordered && bs->lastgoal_ltgtype ) { - bs->ltgtype = 0; - } - //if already a CTF or team goal - if (bs->ltgtype == LTG_TEAMHELP || - bs->ltgtype == LTG_TEAMACCOMPANY || - bs->ltgtype == LTG_DEFENDKEYAREA || - bs->ltgtype == LTG_GETFLAG || - bs->ltgtype == LTG_RUSHBASE || - bs->ltgtype == LTG_RETURNFLAG || - bs->ltgtype == LTG_CAMPORDER || - bs->ltgtype == LTG_PATROL || - bs->ltgtype == LTG_GETITEM || - bs->ltgtype == LTG_MAKELOVE_UNDER || - bs->ltgtype == LTG_MAKELOVE_ONTOP) { - return; - } - // - if (BotSetLastOrderedTask(bs)) - return; - // - if (bs->owndecision_time > FloatTime()) - return;; - //if the bot is roaming - if (bs->ctfroam_time > FloatTime()) - return; - //if the bot has anough aggression to decide what to do - if (BotAggression(bs) < 50) - return; - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - // - if (bs->teamtaskpreference & (TEAMTP_ATTACKER|TEAMTP_DEFENDER)) { - if (bs->teamtaskpreference & TEAMTP_ATTACKER) { - l1 = 0.7f; - } - else { - l1 = 0.2f; - } - l2 = 0.9f; - } - else { - l1 = 0.4f; - l2 = 0.7f; - } - //get the flag or defend the base - rnd = random(); - if (rnd < l1 && ctf_redflag.areanum && ctf_blueflag.areanum) { - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - bs->ltgtype = LTG_GETFLAG; - //set the time the bot will stop getting the flag - bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME; - //get an alternative route goal towards the enemy base - BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs)); - BotSetTeamStatus(bs); - } - else if (rnd < l2 && ctf_redflag.areanum && ctf_blueflag.areanum) { - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - // - if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t)); - else memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t)); - //set the ltg type - bs->ltgtype = LTG_DEFENDKEYAREA; - //set the time the bot stops defending the base - bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME; - bs->defendaway_time = 0; - BotSetTeamStatus(bs); - } - else { - bs->ltgtype = 0; - //set the time the bot will stop roaming - bs->ctfroam_time = FloatTime() + CTF_ROAM_TIME; - BotSetTeamStatus(bs); - } - bs->owndecision_time = FloatTime() + 5; -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -BotCTFRetreatGoals -================== -*/ -void BotCTFRetreatGoals(bot_state_t *bs) { - //when carrying a flag in ctf the bot should rush to the base - if (BotCTFCarryingFlag(bs)) { - //if not already rushing to the base - if (bs->ltgtype != LTG_RUSHBASE) { - BotRefuseOrder(bs); - bs->ltgtype = LTG_RUSHBASE; - bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME; - bs->rushbaseaway_time = 0; - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - BotSetTeamStatus(bs); - } - } -} - -#ifdef MISSIONPACK -/* -================== -Bot1FCTFSeekGoals -================== -*/ -void Bot1FCTFSeekGoals(bot_state_t *bs) { - aas_entityinfo_t entinfo; - float rnd, l1, l2; - int c; - - //when carrying a flag in ctf the bot should rush to the base - if (Bot1FCTFCarryingFlag(bs)) { - //if not already rushing to the base - if (bs->ltgtype != LTG_RUSHBASE) { - BotRefuseOrder(bs); - bs->ltgtype = LTG_RUSHBASE; - bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME; - bs->rushbaseaway_time = 0; - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - //get an alternative route goal towards the enemy base - BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs)); - // - BotSetTeamStatus(bs); - BotVoiceChat(bs, -1, VOICECHAT_IHAVEFLAG); - } - return; - } - // if the bot decided to follow someone - if ( bs->ltgtype == LTG_TEAMACCOMPANY && !bs->ordered ) { - // if the team mate being accompanied no longer carries the flag - BotEntityInfo(bs->teammate, &entinfo); - if (!EntityCarriesFlag(&entinfo)) { - bs->ltgtype = 0; - } - } - //our team has the flag - if (bs->neutralflagstatus == 1) { - if (bs->owndecision_time < FloatTime()) { - // if not already following someone + //if Not defending the base + if (!(bs->ltgtype == LTG_DEFENDKEYAREA && + (bs->teamgoal.number == ctf_redflag.number || + bs->teamgoal.number == ctf_blueflag.number))) { + //if not already accompanying someone if (bs->ltgtype != LTG_TEAMACCOMPANY) { - //if there is a visible team mate flag carrier + //if there is avisible team mate flag carrier c = BotTeamFlagCarrierVisible(bs); if (c >= 0) { - BotRefuseOrder(bs); //follow the flag carrier - bs->decisionmaker = bs->client; - bs->ordered = qfalse; //the team mate bs->teammate = c; //last time the team mate was visible - bs->teammatevisible_time = FloatTime(); - //no message - bs->teammessage_time = 0; - //no arrive message - bs->arrive_time = 1; - // - BotVoiceChat(bs, bs->teammate, VOICECHAT_ONFOLLOW); + bs->teammatevisible_time = trap_AAS_Time(); + //set the time to send a message to the team mates + bs->teammessage_time = trap_AAS_Time() + 2 * random(); //get the team goal time - bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME; + bs->teamgoal_time = trap_AAS_Time() + TEAM_ACCOMPANY_TIME; bs->ltgtype = LTG_TEAMACCOMPANY; bs->formation_dist = 3.5 * 32; //3.5 meter - BotSetTeamStatus(bs); - bs->owndecision_time = FloatTime() + 5; + bs->arrive_time = 0; return; } } - //if already a CTF or team goal - if (bs->ltgtype == LTG_TEAMHELP || - bs->ltgtype == LTG_TEAMACCOMPANY || - bs->ltgtype == LTG_DEFENDKEYAREA || - bs->ltgtype == LTG_GETFLAG || - bs->ltgtype == LTG_RUSHBASE || - bs->ltgtype == LTG_CAMPORDER || - bs->ltgtype == LTG_PATROL || - bs->ltgtype == LTG_ATTACKENEMYBASE || - bs->ltgtype == LTG_GETITEM || - bs->ltgtype == LTG_MAKELOVE_UNDER || - bs->ltgtype == LTG_MAKELOVE_ONTOP) { - return; - } - //if not already attacking the enemy base - if (bs->ltgtype != LTG_ATTACKENEMYBASE) { - BotRefuseOrder(bs); - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - // - if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t)); - else memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t)); - //set the ltg type - bs->ltgtype = LTG_ATTACKENEMYBASE; + } + } + //if the base flag is stolen + else if (flagstatus == 2) { + //if not already going for the enemy flag + if (bs->ltgtype != LTG_GETFLAG) { + //if there's no bot team leader + if (!BotTeamLeader(bs)) { + //go for the enemy flag + bs->ltgtype = LTG_GETFLAG; + //no team message + bs->teammessage_time = 1; //set the time the bot will stop getting the flag - bs->teamgoal_time = FloatTime() + TEAM_ATTACKENEMYBASE_TIME; - BotSetTeamStatus(bs); - bs->owndecision_time = FloatTime() + 5; - } - } - return; - } - //enemy team has the flag - else if (bs->neutralflagstatus == 2) { - if (bs->owndecision_time < FloatTime()) { - c = BotEnemyFlagCarrierVisible(bs); - if (c >= 0) { - //FIXME: attack enemy flag carrier - } - //if already a CTF or team goal - if (bs->ltgtype == LTG_TEAMHELP || - bs->ltgtype == LTG_TEAMACCOMPANY || - bs->ltgtype == LTG_CAMPORDER || - bs->ltgtype == LTG_PATROL || - bs->ltgtype == LTG_GETITEM) { + bs->teamgoal_time = trap_AAS_Time() + CTF_GETFLAG_TIME; return; } - // if not already defending the base - if (bs->ltgtype != LTG_DEFENDKEYAREA) { - BotRefuseOrder(bs); - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - // - if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t)); - else memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t)); - //set the ltg type - bs->ltgtype = LTG_DEFENDKEYAREA; - //set the time the bot stops defending the base - bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME; - bs->defendaway_time = 0; - BotSetTeamStatus(bs); - bs->owndecision_time = FloatTime() + 5; - } } - return; } - // don't just do something wait for the bot team leader to give orders - if (BotTeamLeader(bs)) { - return; - } - // if the bot is ordered to do something - if ( bs->lastgoal_ltgtype ) { - bs->teamgoal_time += 60; - } - // if the bot decided to do something on its own and has a last ordered goal - if ( !bs->ordered && bs->lastgoal_ltgtype ) { - bs->ltgtype = 0; + //if both flags not at their bases + else if (flagstatus == 3) { + // + if (bs->ltgtype != LTG_GETFLAG && + bs->ltgtype != LTG_TEAMACCOMPANY) { + //if there is avisible team mate flag carrier + c = BotTeamFlagCarrierVisible(bs); + if (c >= 0) { + //follow the flag carrier + return; + } + else { + //otherwise attack the enemy base + } + return; + } } + //if the bot is roaming + if (bs->ctfroam_time > trap_AAS_Time()) return; //if already a CTF or team goal if (bs->ltgtype == LTG_TEAMHELP || bs->ltgtype == LTG_TEAMACCOMPANY || @@ -944,425 +307,41 @@ void Bot1FCTFSeekGoals(bot_state_t *bs) { bs->ltgtype == LTG_RUSHBASE || bs->ltgtype == LTG_RETURNFLAG || bs->ltgtype == LTG_CAMPORDER || - bs->ltgtype == LTG_PATROL || - bs->ltgtype == LTG_ATTACKENEMYBASE || - bs->ltgtype == LTG_GETITEM || - bs->ltgtype == LTG_MAKELOVE_UNDER || - bs->ltgtype == LTG_MAKELOVE_ONTOP) { + bs->ltgtype == LTG_PATROL) { return; } - // - if (BotSetLastOrderedTask(bs)) - return; - // - if (bs->owndecision_time > FloatTime()) - return;; - //if the bot is roaming - if (bs->ctfroam_time > FloatTime()) - return; //if the bot has anough aggression to decide what to do - if (BotAggression(bs) < 50) - return; + if (BotAggression(bs) < 50) return; //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - // - if (bs->teamtaskpreference & (TEAMTP_ATTACKER|TEAMTP_DEFENDER)) { - if (bs->teamtaskpreference & TEAMTP_ATTACKER) { - l1 = 0.7f; - } - else { - l1 = 0.2f; - } - l2 = 0.9f; - } - else { - l1 = 0.4f; - l2 = 0.7f; - } + bs->teammessage_time = trap_AAS_Time() + 2 * random(); //get the flag or defend the base rnd = random(); - if (rnd < l1 && ctf_neutralflag.areanum) { - bs->decisionmaker = bs->client; - bs->ordered = qfalse; + if (rnd < 0.33 && ctf_redflag.areanum && ctf_blueflag.areanum) { bs->ltgtype = LTG_GETFLAG; //set the time the bot will stop getting the flag - bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME; - BotSetTeamStatus(bs); + bs->teamgoal_time = trap_AAS_Time() + CTF_GETFLAG_TIME; } - else if (rnd < l2 && ctf_redflag.areanum && ctf_blueflag.areanum) { - bs->decisionmaker = bs->client; - bs->ordered = qfalse; + else if (rnd < 0.66 && ctf_redflag.areanum && ctf_blueflag.areanum) { // - if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t)); + if (BotCTFTeam(bs) == CTF_TEAM_RED) memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t)); else memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t)); //set the ltg type bs->ltgtype = LTG_DEFENDKEYAREA; //set the time the bot stops defending the base - bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME; + bs->teamgoal_time = trap_AAS_Time() + TEAM_DEFENDKEYAREA_TIME; bs->defendaway_time = 0; - BotSetTeamStatus(bs); } else { bs->ltgtype = 0; //set the time the bot will stop roaming - bs->ctfroam_time = FloatTime() + CTF_ROAM_TIME; - BotSetTeamStatus(bs); + bs->ctfroam_time = trap_AAS_Time() + CTF_ROAM_TIME; } - bs->owndecision_time = FloatTime() + 5; #ifdef DEBUG BotPrintTeamGoal(bs); #endif //DEBUG } -/* -================== -Bot1FCTFRetreatGoals -================== -*/ -void Bot1FCTFRetreatGoals(bot_state_t *bs) { - //when carrying a flag in ctf the bot should rush to the enemy base - if (Bot1FCTFCarryingFlag(bs)) { - //if not already rushing to the base - if (bs->ltgtype != LTG_RUSHBASE) { - BotRefuseOrder(bs); - bs->ltgtype = LTG_RUSHBASE; - bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME; - bs->rushbaseaway_time = 0; - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - //get an alternative route goal towards the enemy base - BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs)); - BotSetTeamStatus(bs); - } - } -} - -/* -================== -BotObeliskSeekGoals -================== -*/ -void BotObeliskSeekGoals(bot_state_t *bs) { - float rnd, l1, l2; - - // don't just do something wait for the bot team leader to give orders - if (BotTeamLeader(bs)) { - return; - } - // if the bot is ordered to do something - if ( bs->lastgoal_ltgtype ) { - bs->teamgoal_time += 60; - } - //if already a team goal - if (bs->ltgtype == LTG_TEAMHELP || - bs->ltgtype == LTG_TEAMACCOMPANY || - bs->ltgtype == LTG_DEFENDKEYAREA || - bs->ltgtype == LTG_GETFLAG || - bs->ltgtype == LTG_RUSHBASE || - bs->ltgtype == LTG_RETURNFLAG || - bs->ltgtype == LTG_CAMPORDER || - bs->ltgtype == LTG_PATROL || - bs->ltgtype == LTG_ATTACKENEMYBASE || - bs->ltgtype == LTG_GETITEM || - bs->ltgtype == LTG_MAKELOVE_UNDER || - bs->ltgtype == LTG_MAKELOVE_ONTOP) { - return; - } - // - if (BotSetLastOrderedTask(bs)) - return; - //if the bot is roaming - if (bs->ctfroam_time > FloatTime()) - return; - //if the bot has anough aggression to decide what to do - if (BotAggression(bs) < 50) - return; - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - // - if (bs->teamtaskpreference & (TEAMTP_ATTACKER|TEAMTP_DEFENDER)) { - if (bs->teamtaskpreference & TEAMTP_ATTACKER) { - l1 = 0.7f; - } - else { - l1 = 0.2f; - } - l2 = 0.9f; - } - else { - l1 = 0.4f; - l2 = 0.7f; - } - //get the flag or defend the base - rnd = random(); - if (rnd < l1 && redobelisk.areanum && blueobelisk.areanum) { - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - // - if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t)); - else memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t)); - //set the ltg type - bs->ltgtype = LTG_ATTACKENEMYBASE; - //set the time the bot will stop attacking the enemy base - bs->teamgoal_time = FloatTime() + TEAM_ATTACKENEMYBASE_TIME; - //get an alternate route goal towards the enemy base - BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs)); - BotSetTeamStatus(bs); - } - else if (rnd < l2 && redobelisk.areanum && blueobelisk.areanum) { - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - // - if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t)); - else memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t)); - //set the ltg type - bs->ltgtype = LTG_DEFENDKEYAREA; - //set the time the bot stops defending the base - bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME; - bs->defendaway_time = 0; - BotSetTeamStatus(bs); - } - else { - bs->ltgtype = 0; - //set the time the bot will stop roaming - bs->ctfroam_time = FloatTime() + CTF_ROAM_TIME; - BotSetTeamStatus(bs); - } -} - -/* -================== -BotGoHarvest -================== -*/ -void BotGoHarvest(bot_state_t *bs) { - // - if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t)); - else memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t)); - //set the ltg type - bs->ltgtype = LTG_HARVEST; - //set the time the bot will stop harvesting - bs->teamgoal_time = FloatTime() + TEAM_HARVEST_TIME; - bs->harvestaway_time = 0; - BotSetTeamStatus(bs); -} - -/* -================== -BotObeliskRetreatGoals -================== -*/ -void BotObeliskRetreatGoals(bot_state_t *bs) { - //nothing special -} - -/* -================== -BotHarvesterSeekGoals -================== -*/ -void BotHarvesterSeekGoals(bot_state_t *bs) { - aas_entityinfo_t entinfo; - float rnd, l1, l2; - int c; - - //when carrying cubes in harvester the bot should rush to the base - if (BotHarvesterCarryingCubes(bs)) { - //if not already rushing to the base - if (bs->ltgtype != LTG_RUSHBASE) { - BotRefuseOrder(bs); - bs->ltgtype = LTG_RUSHBASE; - bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME; - bs->rushbaseaway_time = 0; - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - //get an alternative route goal towards the enemy base - BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs)); - // - BotSetTeamStatus(bs); - } - return; - } - // don't just do something wait for the bot team leader to give orders - if (BotTeamLeader(bs)) { - return; - } - // if the bot decided to follow someone - if ( bs->ltgtype == LTG_TEAMACCOMPANY && !bs->ordered ) { - // if the team mate being accompanied no longer carries the flag - BotEntityInfo(bs->teammate, &entinfo); - if (!EntityCarriesCubes(&entinfo)) { - bs->ltgtype = 0; - } - } - // if the bot is ordered to do something - if ( bs->lastgoal_ltgtype ) { - bs->teamgoal_time += 60; - } - //if not yet doing something - if (bs->ltgtype == LTG_TEAMHELP || - bs->ltgtype == LTG_TEAMACCOMPANY || - bs->ltgtype == LTG_DEFENDKEYAREA || - bs->ltgtype == LTG_GETFLAG || - bs->ltgtype == LTG_CAMPORDER || - bs->ltgtype == LTG_PATROL || - bs->ltgtype == LTG_ATTACKENEMYBASE || - bs->ltgtype == LTG_HARVEST || - bs->ltgtype == LTG_GETITEM || - bs->ltgtype == LTG_MAKELOVE_UNDER || - bs->ltgtype == LTG_MAKELOVE_ONTOP) { - return; - } - // - if (BotSetLastOrderedTask(bs)) - return; - //if the bot is roaming - if (bs->ctfroam_time > FloatTime()) - return; - //if the bot has anough aggression to decide what to do - if (BotAggression(bs) < 50) - return; - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - // - c = BotEnemyCubeCarrierVisible(bs); - if (c >= 0) { - //FIXME: attack enemy cube carrier - } - if (bs->ltgtype != LTG_TEAMACCOMPANY) { - //if there is a visible team mate carrying cubes - c = BotTeamCubeCarrierVisible(bs); - if (c >= 0) { - //follow the team mate carrying cubes - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - //the team mate - bs->teammate = c; - //last time the team mate was visible - bs->teammatevisible_time = FloatTime(); - //no message - bs->teammessage_time = 0; - //no arrive message - bs->arrive_time = 1; - // - BotVoiceChat(bs, bs->teammate, VOICECHAT_ONFOLLOW); - //get the team goal time - bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME; - bs->ltgtype = LTG_TEAMACCOMPANY; - bs->formation_dist = 3.5 * 32; //3.5 meter - BotSetTeamStatus(bs); - return; - } - } - // - if (bs->teamtaskpreference & (TEAMTP_ATTACKER|TEAMTP_DEFENDER)) { - if (bs->teamtaskpreference & TEAMTP_ATTACKER) { - l1 = 0.7f; - } - else { - l1 = 0.2f; - } - l2 = 0.9f; - } - else { - l1 = 0.4f; - l2 = 0.7f; - } - // - rnd = random(); - if (rnd < l1 && redobelisk.areanum && blueobelisk.areanum) { - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - BotGoHarvest(bs); - } - else if (rnd < l2 && redobelisk.areanum && blueobelisk.areanum) { - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - // - if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t)); - else memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t)); - //set the ltg type - bs->ltgtype = LTG_DEFENDKEYAREA; - //set the time the bot stops defending the base - bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME; - bs->defendaway_time = 0; - BotSetTeamStatus(bs); - } - else { - bs->ltgtype = 0; - //set the time the bot will stop roaming - bs->ctfroam_time = FloatTime() + CTF_ROAM_TIME; - BotSetTeamStatus(bs); - } -} - -/* -================== -BotHarvesterRetreatGoals -================== -*/ -void BotHarvesterRetreatGoals(bot_state_t *bs) { - //when carrying cubes in harvester the bot should rush to the base - if (BotHarvesterCarryingCubes(bs)) { - //if not already rushing to the base - if (bs->ltgtype != LTG_RUSHBASE) { - BotRefuseOrder(bs); - bs->ltgtype = LTG_RUSHBASE; - bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME; - bs->rushbaseaway_time = 0; - bs->decisionmaker = bs->client; - bs->ordered = qfalse; - BotSetTeamStatus(bs); - } - return; - } -} -#endif - -/* -================== -BotTeamGoals -================== -*/ -void BotTeamGoals(bot_state_t *bs, int retreat) { - - if ( retreat ) { - if (gametype == GT_CTF) { - BotCTFRetreatGoals(bs); - } -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF) { - Bot1FCTFRetreatGoals(bs); - } - else if (gametype == GT_OBELISK) { - BotObeliskRetreatGoals(bs); - } - else if (gametype == GT_HARVESTER) { - BotHarvesterRetreatGoals(bs); - } -#endif - } - else { - if (gametype == GT_CTF) { - //decide what to do in CTF mode - BotCTFSeekGoals(bs); - } -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF) { - Bot1FCTFSeekGoals(bs); - } - else if (gametype == GT_OBELISK) { - BotObeliskSeekGoals(bs); - } - else if (gametype == GT_HARVESTER) { - BotHarvesterSeekGoals(bs); - } -#endif - } - // reset the order time which is used to see if - // we decided to refuse an order - bs->order_time = 0; -} +#endif //CTF /* ================== @@ -1427,33 +406,11 @@ ClientFromName int ClientFromName(char *name) { int i; char buf[MAX_INFO_STRING]; - static int maxclients; + static int maxclis; - if (!maxclients) - maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf)); - Q_CleanStr( buf ); - if (!Q_stricmp(Info_ValueForKey(buf, "n"), name)) return i; - } - return -1; -} - -/* -================== -ClientOnSameTeamFromName -================== -*/ -int ClientOnSameTeamFromName(bot_state_t *bs, char *name) { - int i; - char buf[MAX_INFO_STRING]; - static int maxclients; - - if (!maxclients) - maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - if (!BotSameTeam(bs, i)) - continue; + if (!maxclis) + maxclis = trap_Cvar_VariableIntegerValue("sv_maxclients"); + for (i = 0; i < maxclis && i < MAX_CLIENTS; i++) { trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf)); Q_CleanStr( buf ); if (!Q_stricmp(Info_ValueForKey(buf, "n"), name)) return i; @@ -1489,8 +446,7 @@ char *EasyClientName(int client, char *buf, int size) { char *str1, *str2, *ptr, c; char name[128]; - ClientName(client, name, sizeof(name)); - + strcpy(name, ClientName(client, name, sizeof(name))); for (i = 0; name[i]; i++) name[i] &= 127; //remove all spaces for (ptr = strstr(name, " "); ptr; ptr = strstr(name, " ")) { @@ -1529,52 +485,42 @@ char *EasyClientName(int client, char *buf, int size) { return buf; } -/* -================== -BotSynonymContext -================== -*/ -int BotSynonymContext(bot_state_t *bs) { - int context; - - context = CONTEXT_NORMAL|CONTEXT_NEARBYITEM|CONTEXT_NAMES; - // - if (gametype == GT_CTF -#ifdef MISSIONPACK - || gametype == GT_1FCTF -#endif - ) { - if (BotTeam(bs) == TEAM_RED) context |= CONTEXT_CTFREDTEAM; - else context |= CONTEXT_CTFBLUETEAM; +qboolean BotUseMeleeWeapon(bot_state_t *bs) { + if ( bs->inventory[ENEMY_HORIZONTAL_DIST] < 64 ) + { + /*if ( bs->cur_ps.persistant[PERS_CLASS] == PC_BORG || bs->cur_ps.persistant[PERS_CLASS] == PC_MEDIC ) + { + return qtrue; + }*/ } -#ifdef MISSIONPACK - else if (gametype == GT_OBELISK) { - if (BotTeam(bs) == TEAM_RED) context |= CONTEXT_OBELISKREDTEAM; - else context |= CONTEXT_OBELISKBLUETEAM; - } - else if (gametype == GT_HARVESTER) { - if (BotTeam(bs) == TEAM_RED) context |= CONTEXT_HARVESTERREDTEAM; - else context |= CONTEXT_HARVESTERBLUETEAM; - } -#endif - return context; + return qfalse; } - /* ================== BotChooseWeapon + + MCG - FIXME: This should really take into account: + Projectile vs. instant? + gravity on projectile? + Range to enemy vs range of weapon? + Some randomness on the weights? + ================== */ void BotChooseWeapon(bot_state_t *bs) { int newweaponnum; - if (bs->cur_ps.weaponstate == WEAPON_RAISING || - bs->cur_ps.weaponstate == WEAPON_DROPPING) { + if (bs->cur_ps.weaponstate == WEAPON_RAISING || bs->cur_ps.weaponstate == WEAPON_DROPPING) + { trap_EA_SelectWeapon(bs->client, bs->weaponnum); } - else { - newweaponnum = trap_BotChooseBestFightWeapon(bs->ws, bs->inventory); - if (bs->weaponnum != newweaponnum) bs->weaponchange_time = FloatTime(); + else + { + newweaponnum = trap_BotChooseBestFightWeapon(bs->ws, bs->inventory, BotUseMeleeWeapon(bs)); + if (bs->weaponnum != newweaponnum) + { + bs->weaponchange_time = trap_AAS_Time(); + } bs->weaponnum = newweaponnum; //BotAI_Print(PRT_MESSAGE, "bs->weaponnum = %d\n", bs->weaponnum); trap_EA_SelectWeapon(bs->client, bs->weaponnum); @@ -1592,7 +538,7 @@ void BotSetupForMovement(bot_state_t *bs) { memset(&initmove, 0, sizeof(bot_initmove_t)); VectorCopy(bs->cur_ps.origin, initmove.origin); VectorCopy(bs->cur_ps.velocity, initmove.velocity); - VectorClear(initmove.viewoffset); + VectorCopy(bs->cur_ps.origin, initmove.viewoffset); initmove.viewoffset[2] += bs->cur_ps.viewheight; initmove.entitynum = bs->entitynum; initmove.client = bs->client; @@ -1618,176 +564,53 @@ void BotSetupForMovement(bot_state_t *bs) { trap_BotInitMoveState(bs->ms, &initmove); } -/* -================== -BotCheckItemPickup -================== -*/ -void BotCheckItemPickup(bot_state_t *bs, int *oldinventory) { -#ifdef MISSIONPACK - int offence, leader; - - if (gametype <= GT_TEAM) - return; - - offence = -1; - // go into offence if picked up the kamikaze or invulnerability - if (!oldinventory[INVENTORY_KAMIKAZE] && bs->inventory[INVENTORY_KAMIKAZE] >= 1) { - offence = qtrue; - } - if (!oldinventory[INVENTORY_INVULNERABILITY] && bs->inventory[INVENTORY_INVULNERABILITY] >= 1) { - offence = qtrue; - } - // if not already wearing the kamikaze or invulnerability - if (!bs->inventory[INVENTORY_KAMIKAZE] && !bs->inventory[INVENTORY_INVULNERABILITY]) { - if (!oldinventory[INVENTORY_SCOUT] && bs->inventory[INVENTORY_SCOUT] >= 1) { - offence = qtrue; - } - if (!oldinventory[INVENTORY_GUARD] && bs->inventory[INVENTORY_GUARD] >= 1) { - offence = qtrue; - } - if (!oldinventory[INVENTORY_DOUBLER] && bs->inventory[INVENTORY_DOUBLER] >= 1) { - offence = qfalse; - } - if (!oldinventory[INVENTORY_AMMOREGEN] && bs->inventory[INVENTORY_AMMOREGEN] >= 1) { - offence = qfalse; - } - } - - if (offence >= 0) { - leader = ClientFromName(bs->teamleader); - if (offence) { - if (!(bs->teamtaskpreference & TEAMTP_ATTACKER)) { - // if we have a bot team leader - if (BotTeamLeader(bs)) { - // tell the leader we want to be on offence - BotVoiceChat(bs, leader, VOICECHAT_WANTONOFFENSE); - //BotAI_BotInitialChat(bs, "wantoffence", NULL); - //trap_BotEnterChat(bs->cs, leader, CHAT_TELL); - } - else if (g_spSkill.integer <= 3) { - if ( bs->ltgtype != LTG_GETFLAG && - bs->ltgtype != LTG_ATTACKENEMYBASE && - bs->ltgtype != LTG_HARVEST ) { - // - if ((gametype != GT_CTF || (bs->redflagstatus == 0 && bs->blueflagstatus == 0)) && - (gametype != GT_1FCTF || bs->neutralflagstatus == 0) ) { - // tell the leader we want to be on offence - BotVoiceChat(bs, leader, VOICECHAT_WANTONOFFENSE); - //BotAI_BotInitialChat(bs, "wantoffence", NULL); - //trap_BotEnterChat(bs->cs, leader, CHAT_TELL); - } - } - } - bs->teamtaskpreference |= TEAMTP_ATTACKER; - } - bs->teamtaskpreference &= ~TEAMTP_DEFENDER; - } - else { - if (!(bs->teamtaskpreference & TEAMTP_DEFENDER)) { - // if we have a bot team leader - if (BotTeamLeader(bs)) { - // tell the leader we want to be on defense - BotVoiceChat(bs, -1, VOICECHAT_WANTONDEFENSE); - //BotAI_BotInitialChat(bs, "wantdefence", NULL); - //trap_BotEnterChat(bs->cs, leader, CHAT_TELL); - } - else if (g_spSkill.integer <= 3) { - if ( bs->ltgtype != LTG_DEFENDKEYAREA ) { - // - if ((gametype != GT_CTF || (bs->redflagstatus == 0 && bs->blueflagstatus == 0)) && - (gametype != GT_1FCTF || bs->neutralflagstatus == 0) ) { - // tell the leader we want to be on defense - BotVoiceChat(bs, -1, VOICECHAT_WANTONDEFENSE); - //BotAI_BotInitialChat(bs, "wantdefence", NULL); - //trap_BotEnterChat(bs->cs, leader, CHAT_TELL); - } - } - } - bs->teamtaskpreference |= TEAMTP_DEFENDER; - } - bs->teamtaskpreference &= ~TEAMTP_ATTACKER; - } - } -#endif -} - /* ================== BotUpdateInventory ================== */ void BotUpdateInventory(bot_state_t *bs) { - int oldinventory[MAX_ITEMS]; - - memcpy(oldinventory, bs->inventory, sizeof(oldinventory)); //armor bs->inventory[INVENTORY_ARMOR] = bs->cur_ps.stats[STAT_ARMOR]; + //weapons - bs->inventory[INVENTORY_GAUNTLET] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_GAUNTLET)) != 0; - bs->inventory[INVENTORY_SHOTGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_SHOTGUN)) != 0; - bs->inventory[INVENTORY_MACHINEGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_MACHINEGUN)) != 0; - bs->inventory[INVENTORY_GRENADELAUNCHER] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_GRENADE_LAUNCHER)) != 0; - bs->inventory[INVENTORY_ROCKETLAUNCHER] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_ROCKET_LAUNCHER)) != 0; - bs->inventory[INVENTORY_LIGHTNING] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_LIGHTNING)) != 0; - bs->inventory[INVENTORY_RAILGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_RAILGUN)) != 0; - bs->inventory[INVENTORY_PLASMAGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_PLASMAGUN)) != 0; - bs->inventory[INVENTORY_BFG10K] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_BFG)) != 0; - bs->inventory[INVENTORY_GRAPPLINGHOOK] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_GRAPPLING_HOOK)) != 0; -#ifdef MISSIONPACK - bs->inventory[INVENTORY_NAILGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_NAILGUN)) != 0;; - bs->inventory[INVENTORY_PROXLAUNCHER] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_PROX_LAUNCHER)) != 0;; - bs->inventory[INVENTORY_CHAINGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_CHAINGUN)) != 0;; -#endif + bs->inventory[INVENTORY_GRENADELAUNCHER] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_8)) != 0; + bs->inventory[INVENTORY_STASIS] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_10)) != 0; + bs->inventory[INVENTORY_PHASER] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_5)) != 0; + bs->inventory[INVENTORY_DREADNOUGHT] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_13)) != 0; + bs->inventory[INVENTORY_IMOD] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_1)) != 0; + bs->inventory[INVENTORY_COMPRESSION] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_6)) != 0; + bs->inventory[INVENTORY_TETRION] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_7)) != 0; + bs->inventory[INVENTORY_SCAVENGER] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_4)) != 0; + bs->inventory[INVENTORY_QUANTUM] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_9)) != 0; + //ammo - bs->inventory[INVENTORY_SHELLS] = bs->cur_ps.ammo[WP_SHOTGUN]; - bs->inventory[INVENTORY_BULLETS] = bs->cur_ps.ammo[WP_MACHINEGUN]; - bs->inventory[INVENTORY_GRENADES] = bs->cur_ps.ammo[WP_GRENADE_LAUNCHER]; - bs->inventory[INVENTORY_CELLS] = bs->cur_ps.ammo[WP_PLASMAGUN]; - bs->inventory[INVENTORY_LIGHTNINGAMMO] = bs->cur_ps.ammo[WP_LIGHTNING]; - bs->inventory[INVENTORY_ROCKETS] = bs->cur_ps.ammo[WP_ROCKET_LAUNCHER]; - bs->inventory[INVENTORY_SLUGS] = bs->cur_ps.ammo[WP_RAILGUN]; - bs->inventory[INVENTORY_BFGAMMO] = bs->cur_ps.ammo[WP_BFG]; -#ifdef MISSIONPACK - bs->inventory[INVENTORY_NAILS] = bs->cur_ps.ammo[WP_NAILGUN]; - bs->inventory[INVENTORY_MINES] = bs->cur_ps.ammo[WP_PROX_LAUNCHER]; - bs->inventory[INVENTORY_BELT] = bs->cur_ps.ammo[WP_CHAINGUN]; -#endif + bs->inventory[INVENTORY_GRENADES] = bs->cur_ps.ammo[WP_8]; + bs->inventory[INVENTORY_STASISAMMO] = bs->cur_ps.ammo[WP_10]; + bs->inventory[INVENTORY_PHASERAMMO] = bs->cur_ps.ammo[WP_5]; + bs->inventory[INVENTORY_DREADNOUGHTAMMO] = bs->cur_ps.ammo[WP_13]; + bs->inventory[INVENTORY_IMODAMMO] = bs->cur_ps.ammo[WP_1]; + bs->inventory[INVENTORY_COMPRESSIONAMMO] = bs->cur_ps.ammo[WP_6]; + bs->inventory[INVENTORY_TETRIONAMMO] = bs->cur_ps.ammo[WP_7]; + bs->inventory[INVENTORY_SCAVENGERAMMO] = bs->cur_ps.ammo[WP_4]; + bs->inventory[INVENTORY_QUANTUMAMMO] = bs->cur_ps.ammo[WP_9]; + //powerups bs->inventory[INVENTORY_HEALTH] = bs->cur_ps.stats[STAT_HEALTH]; - bs->inventory[INVENTORY_TELEPORTER] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_TELEPORTER; + bs->inventory[INVENTORY_TRANSPORTER] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_TELEPORTER; bs->inventory[INVENTORY_MEDKIT] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_MEDKIT; -#ifdef MISSIONPACK - bs->inventory[INVENTORY_KAMIKAZE] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_KAMIKAZE; - bs->inventory[INVENTORY_PORTAL] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_PORTAL; - bs->inventory[INVENTORY_INVULNERABILITY] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_INVULNERABILITY; -#endif bs->inventory[INVENTORY_QUAD] = bs->cur_ps.powerups[PW_QUAD] != 0; - bs->inventory[INVENTORY_ENVIRONMENTSUIT] = bs->cur_ps.powerups[PW_BATTLESUIT] != 0; + bs->inventory[INVENTORY_ENVIRONMENTSUIT] = bs->cur_ps.powerups[PW_BOLTON] != 0; bs->inventory[INVENTORY_HASTE] = bs->cur_ps.powerups[PW_HASTE] != 0; bs->inventory[INVENTORY_INVISIBILITY] = bs->cur_ps.powerups[PW_INVIS] != 0; - bs->inventory[INVENTORY_REGEN] = bs->cur_ps.powerups[PW_REGEN] != 0; + bs->inventory[INVENTORY_REGEN] = bs->cur_ps.powerups[PW_LASER] != 0; bs->inventory[INVENTORY_FLIGHT] = bs->cur_ps.powerups[PW_FLIGHT] != 0; -#ifdef MISSIONPACK - bs->inventory[INVENTORY_SCOUT] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_SCOUT; - bs->inventory[INVENTORY_GUARD] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_GUARD; - bs->inventory[INVENTORY_DOUBLER] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_DOUBLER; - bs->inventory[INVENTORY_AMMOREGEN] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_AMMOREGEN; -#endif - bs->inventory[INVENTORY_REDFLAG] = bs->cur_ps.powerups[PW_REDFLAG] != 0; - bs->inventory[INVENTORY_BLUEFLAG] = bs->cur_ps.powerups[PW_BLUEFLAG] != 0; -#ifdef MISSIONPACK - bs->inventory[INVENTORY_NEUTRALFLAG] = bs->cur_ps.powerups[PW_NEUTRALFLAG] != 0; - if (BotTeam(bs) == TEAM_RED) { - bs->inventory[INVENTORY_REDCUBE] = bs->cur_ps.generic1; - bs->inventory[INVENTORY_BLUECUBE] = 0; - } - else { - bs->inventory[INVENTORY_REDCUBE] = 0; - bs->inventory[INVENTORY_BLUECUBE] = bs->cur_ps.generic1; - } -#endif - BotCheckItemPickup(bs, oldinventory); + //bs->inventory[INVENTORY_REDFLAG] = bs->cur_ps.powerups[PW_REDFLAG] != 0; + //bs->inventory[INVENTORY_BLUEFLAG] = bs->cur_ps.powerups[PW_REDFLAG] != 0; + bs->inventory[INVENTORY_SEEKER] = bs->cur_ps.powerups[PW_FLASHLIGHT] != 0; + bs->inventory[INVENTORY_SHIELD] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_SHIELD; + bs->inventory[INVENTORY_DETPACK] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_DETPACK; + // } /* @@ -1800,232 +623,88 @@ void BotUpdateBattleInventory(bot_state_t *bs, int enemy) { aas_entityinfo_t entinfo; BotEntityInfo(enemy, &entinfo); - VectorSubtract(entinfo.origin, bs->origin, dir); + VectorSubtract(entinfo.origin, bs->origin, dir); bs->inventory[ENEMY_HEIGHT] = (int) dir[2]; dir[2] = 0; bs->inventory[ENEMY_HORIZONTAL_DIST] = (int) VectorLength(dir); //FIXME: add num visible enemies and num visible team mates to the inventory } -#ifdef MISSIONPACK /* -================== -BotUseKamikaze -================== +========================= +BotShouldDetonateDetPack +========================= */ -#define KAMIKAZE_DIST 1024 +#define DETPACK_RADIUS 500 -void BotUseKamikaze(bot_state_t *bs) { - int c, teammates, enemies; - aas_entityinfo_t entinfo; - vec3_t dir, target; - bot_goal_t *goal; - bsp_trace_t trace; +qboolean BotShouldDetonateDetPack(bot_state_t *bs) +{ + int botNum = 0, detWeight = 0; + vec3_t packOrg, dir; + float dist; + aas_entityinfo_t botinfo; - //if the bot has no kamikaze - if (bs->inventory[INVENTORY_KAMIKAZE] <= 0) - return; - if (bs->kamikaze_time > FloatTime()) - return; - bs->kamikaze_time = FloatTime() + 0.2; - if (gametype == GT_CTF) { - //never use kamikaze if the team flag carrier is visible - if (BotCTFCarryingFlag(bs)) - return; - c = BotTeamFlagCarrierVisible(bs); - if (c >= 0) { - BotEntityInfo(c, &entinfo); - VectorSubtract(entinfo.origin, bs->origin, dir); - if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST)) - return; - } - c = BotEnemyFlagCarrierVisible(bs); - if (c >= 0) { - BotEntityInfo(c, &entinfo); - VectorSubtract(entinfo.origin, bs->origin, dir); - if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST)) { - trap_EA_Use(bs->client); - return; + // find the location of the DetPack + gentity_t *detpack = NULL; + char *classname = BG_FindClassnameForHoldable(HI_DETPACK); + + if (!classname) + { + return qfalse; + } + + //while ((detpack = G_Find (detpack, FOFS(classname), classname)) != NULL) + while ((detpack = G_Find (detpack, FOFS(classname), classname)) != NULL) + { + VectorCopy(detpack->r.currentOrigin, packOrg); + } + + // determine who would be killed in the blast radius + for (botNum = 0; botNum < MAX_CLIENTS; botNum++) + { + BotEntityInfo(botNum, &botinfo); + if (!botinfo.valid) continue; + + //calculate the distance towards the enemy + VectorSubtract(botinfo.origin, packOrg, dir); + dist = VectorLength(dir); + + if (dist < DETPACK_RADIUS) // bot would get caught in blast radius + { + if (BotSameTeam(bs, botNum)) // friendly casualty potential + { + if (botNum == bs->client) // suicide... bad + { + detWeight--; + } + if (EntityCarriesFlag(&botinfo)) // it's my teammate, and he's got the flag! + { + detWeight -= 11; + continue; + } + detWeight--; } - } - } - else if (gametype == GT_1FCTF) { - //never use kamikaze if the team flag carrier is visible - if (Bot1FCTFCarryingFlag(bs)) - return; - c = BotTeamFlagCarrierVisible(bs); - if (c >= 0) { - BotEntityInfo(c, &entinfo); - VectorSubtract(entinfo.origin, bs->origin, dir); - if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST)) - return; - } - c = BotEnemyFlagCarrierVisible(bs); - if (c >= 0) { - BotEntityInfo(c, &entinfo); - VectorSubtract(entinfo.origin, bs->origin, dir); - if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST)) { - trap_EA_Use(bs->client); - return; + else + { + if(EntityCarriesFlag(&botinfo)) // mwahaha + { + detWeight += 14; + } + detWeight++; } - } + } } - else if (gametype == GT_OBELISK) { - switch(BotTeam(bs)) { - case TEAM_RED: goal = &blueobelisk; break; - default: goal = &redobelisk; break; - } - //if the obelisk is visible - VectorCopy(goal->origin, target); - target[2] += 1; - VectorSubtract(bs->origin, target, dir); - if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST * 0.9)) { - BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID); - if (trace.fraction >= 1 || trace.ent == goal->entitynum) { - trap_EA_Use(bs->client); - return; - } - } - } - else if (gametype == GT_HARVESTER) { - // - if (BotHarvesterCarryingCubes(bs)) - return; - //never use kamikaze if a team mate carrying cubes is visible - c = BotTeamCubeCarrierVisible(bs); - if (c >= 0) { - BotEntityInfo(c, &entinfo); - VectorSubtract(entinfo.origin, bs->origin, dir); - if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST)) - return; - } - c = BotEnemyCubeCarrierVisible(bs); - if (c >= 0) { - BotEntityInfo(c, &entinfo); - VectorSubtract(entinfo.origin, bs->origin, dir); - if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST)) { - trap_EA_Use(bs->client); - return; - } - } - } - // - BotVisibleTeamMatesAndEnemies(bs, &teammates, &enemies, KAMIKAZE_DIST); - // - if (enemies > 2 && enemies > teammates+1) { - trap_EA_Use(bs->client); - return; + +// Com_Printf("detWeight %d\n", detWeight); + + if (detWeight > 0) + { + return qtrue; } + return qfalse; } -/* -================== -BotUseInvulnerability -================== -*/ -void BotUseInvulnerability(bot_state_t *bs) { - int c; - vec3_t dir, target; - bot_goal_t *goal; - bsp_trace_t trace; - //if the bot has no invulnerability - if (bs->inventory[INVENTORY_INVULNERABILITY] <= 0) - return; - if (bs->invulnerability_time > FloatTime()) - return; - bs->invulnerability_time = FloatTime() + 0.2; - if (gametype == GT_CTF) { - //never use kamikaze if the team flag carrier is visible - if (BotCTFCarryingFlag(bs)) - return; - c = BotEnemyFlagCarrierVisible(bs); - if (c >= 0) - return; - //if near enemy flag and the flag is visible - switch(BotTeam(bs)) { - case TEAM_RED: goal = &ctf_blueflag; break; - default: goal = &ctf_redflag; break; - } - //if the obelisk is visible - VectorCopy(goal->origin, target); - target[2] += 1; - VectorSubtract(bs->origin, target, dir); - if (VectorLengthSquared(dir) < Square(200)) { - BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID); - if (trace.fraction >= 1 || trace.ent == goal->entitynum) { - trap_EA_Use(bs->client); - return; - } - } - } - else if (gametype == GT_1FCTF) { - //never use kamikaze if the team flag carrier is visible - if (Bot1FCTFCarryingFlag(bs)) - return; - c = BotEnemyFlagCarrierVisible(bs); - if (c >= 0) - return; - //if near enemy flag and the flag is visible - switch(BotTeam(bs)) { - case TEAM_RED: goal = &ctf_blueflag; break; - default: goal = &ctf_redflag; break; - } - //if the obelisk is visible - VectorCopy(goal->origin, target); - target[2] += 1; - VectorSubtract(bs->origin, target, dir); - if (VectorLengthSquared(dir) < Square(200)) { - BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID); - if (trace.fraction >= 1 || trace.ent == goal->entitynum) { - trap_EA_Use(bs->client); - return; - } - } - } - else if (gametype == GT_OBELISK) { - switch(BotTeam(bs)) { - case TEAM_RED: goal = &blueobelisk; break; - default: goal = &redobelisk; break; - } - //if the obelisk is visible - VectorCopy(goal->origin, target); - target[2] += 1; - VectorSubtract(bs->origin, target, dir); - if (VectorLengthSquared(dir) < Square(300)) { - BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID); - if (trace.fraction >= 1 || trace.ent == goal->entitynum) { - trap_EA_Use(bs->client); - return; - } - } - } - else if (gametype == GT_HARVESTER) { - // - if (BotHarvesterCarryingCubes(bs)) - return; - c = BotEnemyCubeCarrierVisible(bs); - if (c >= 0) - return; - //if near enemy base and enemy base is visible - switch(BotTeam(bs)) { - case TEAM_RED: goal = &blueobelisk; break; - default: goal = &redobelisk; break; - } - //if the obelisk is visible - VectorCopy(goal->origin, target); - target[2] += 1; - VectorSubtract(bs->origin, target, dir); - if (VectorLengthSquared(dir) < Square(200)) { - BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID); - if (trace.fraction >= 1 || trace.ent == goal->entitynum) { - trap_EA_Use(bs->client); - return; - } - } - } -} -#endif /* ================== @@ -2033,27 +712,60 @@ BotBattleUseItems ================== */ void BotBattleUseItems(bot_state_t *bs) { - if (bs->inventory[INVENTORY_HEALTH] < 40) { - if (bs->inventory[INVENTORY_TELEPORTER] > 0) { - if (!BotCTFCarryingFlag(bs) -#ifdef MISSIONPACK - && !Bot1FCTFCarryingFlag(bs) - && !BotHarvesterCarryingCubes(bs) -#endif - ) { - trap_EA_Use(bs->client); + + + if (bs->inventory[INVENTORY_DETPACK] > 0) + { + // this needs to be in two stages: placement and detonation + if (bs->ltgtype == LTG_DEFENDKEYAREA) + { + if (bs->inventory[INVENTORY_DETPACK_PLACED] == 0) // not placed yet + { + bs->inventory[INVENTORY_DETPACK_PLACED] = 1; + trap_EA_Use(bs->client); // place it + return; } } + + if (bs->inventory[INVENTORY_DETPACK_PLACED] == 1) // placed + { + if (BotShouldDetonateDetPack(bs)) // logic + { + bs->inventory[INVENTORY_DETPACK_PLACED] = 0; + trap_EA_Use(bs->client); // BOOM + return; + } + return; + } + return; } - if (bs->inventory[INVENTORY_HEALTH] < 60) { - if (bs->inventory[INVENTORY_MEDKIT] > 0) { + + if (bs->inventory[INVENTORY_SHIELD] > 0) + { + if (BotWantsToRetreat(bs) && (bs->inventory[INVENTORY_HEALTH] < 50)) + { trap_EA_Use(bs->client); } + return; + } + + if (bs->inventory[INVENTORY_TRANSPORTER] > 0) + { + if (!BotCTFCarryingFlag(bs) && (bs->inventory[INVENTORY_HEALTH] < 50)) + { + trap_EA_Use(bs->client); + return; + } + } + + if (bs->inventory[INVENTORY_MEDKIT] > 0) + { + if (bs->inventory[INVENTORY_HEALTH] < 30) + { + trap_EA_Use(bs->client); + } + return; } -#ifdef MISSIONPACK - BotUseKamikaze(bs); - BotUseInvulnerability(bs); -#endif } /* @@ -2063,7 +775,7 @@ BotSetTeleportTime */ void BotSetTeleportTime(bot_state_t *bs) { if ((bs->cur_ps.eFlags ^ bs->last_eFlags) & EF_TELEPORT_BIT) { - bs->teleport_time = FloatTime(); + bs->teleport_time = trap_AAS_Time(); } bs->last_eFlags = bs->cur_ps.eFlags; } @@ -2190,7 +902,7 @@ TeamPlayIsOn ================== */ int TeamPlayIsOn(void) { - return ( gametype >= GT_TEAM ); + return ( gametype == GT_TEAM || gametype == GT_CTF ); } /* @@ -2202,8 +914,7 @@ float BotAggression(bot_state_t *bs) { //if the bot has quad if (bs->inventory[INVENTORY_QUAD]) { //if the bot is not holding the gauntlet or the enemy is really nearby - if (bs->weaponnum != WP_GAUNTLET || - bs->inventory[ENEMY_HORIZONTAL_DIST] < 80) { + if (bs->inventory[ENEMY_HORIZONTAL_DIST] < 80) { return 70; } } @@ -2216,49 +927,32 @@ float BotAggression(bot_state_t *bs) { //if the bot has insufficient armor if (bs->inventory[INVENTORY_ARMOR] < 40) return 0; } - //if the bot can use the bfg - if (bs->inventory[INVENTORY_BFG10K] > 0 && - bs->inventory[INVENTORY_BFGAMMO] > 7) return 100; - //if the bot can use the railgun - if (bs->inventory[INVENTORY_RAILGUN] > 0 && - bs->inventory[INVENTORY_SLUGS] > 5) return 95; - //if the bot can use the lightning gun - if (bs->inventory[INVENTORY_LIGHTNING] > 0 && - bs->inventory[INVENTORY_LIGHTNINGAMMO] > 50) return 90; - //if the bot can use the rocketlauncher - if (bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 && - bs->inventory[INVENTORY_ROCKETS] > 5) return 90; - //if the bot can use the plasmagun - if (bs->inventory[INVENTORY_PLASMAGUN] > 0 && - bs->inventory[INVENTORY_CELLS] > 40) return 85; - //if the bot can use the grenade launcher - if (bs->inventory[INVENTORY_GRENADELAUNCHER] > 0 && - bs->inventory[INVENTORY_GRENADES] > 10) return 80; - //if the bot can use the shotgun - if (bs->inventory[INVENTORY_SHOTGUN] > 0 && - bs->inventory[INVENTORY_SHELLS] > 10) return 50; - //otherwise the bot is not feeling too good - return 0; -} -/* -================== -BotFeelingBad -================== -*/ -float BotFeelingBad(bot_state_t *bs) { - if (bs->weaponnum == WP_GAUNTLET) { - return 100; - } - if (bs->inventory[INVENTORY_HEALTH] < 40) { - return 100; - } - if (bs->weaponnum == WP_MACHINEGUN) { - return 90; - } - if (bs->inventory[INVENTORY_HEALTH] < 60) { - return 80; - } + if (bs->inventory[INVENTORY_DREADNOUGHT] > 0 && + bs->inventory[INVENTORY_DREADNOUGHTAMMO] > 0) return 100; + + if (bs->inventory[INVENTORY_TETRION] > 0 && + bs->inventory[INVENTORY_TETRIONAMMO] > 0) return 95; + + if (bs->inventory[INVENTORY_QUANTUM] > 0 && + bs->inventory[INVENTORY_QUANTUMAMMO] > 0) return 90; + + if (bs->inventory[INVENTORY_STASIS] > 0 && + bs->inventory[INVENTORY_STASISAMMO] > 0) return 85; + + if (bs->inventory[INVENTORY_SCAVENGER] > 0 && + bs->inventory[INVENTORY_SCAVENGERAMMO] > 0) return 80; + + if (bs->inventory[INVENTORY_GRENADELAUNCHER] > 0 && + bs->inventory[INVENTORY_GRENADES] > 0) return 75; + + if (bs->inventory[INVENTORY_IMOD] > 0 && + bs->inventory[INVENTORY_IMODAMMO] > 0) return 70; + + if (bs->inventory[INVENTORY_COMPRESSION] > 0 && + bs->inventory[INVENTORY_COMPRESSIONAMMO] > 0) return 65; + + //otherwise the bot is not feeling too aggressive return 0; } @@ -2270,52 +964,18 @@ BotWantsToRetreat int BotWantsToRetreat(bot_state_t *bs) { aas_entityinfo_t entinfo; - if (gametype == GT_CTF) { - //always retreat when carrying a CTF flag - if (BotCTFCarryingFlag(bs)) - return qtrue; - } -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF) { - //if carrying the flag then always retreat - if (Bot1FCTFCarryingFlag(bs)) - return qtrue; - } - else if (gametype == GT_OBELISK) { - //the bots should be dedicated to attacking the enemy obelisk - if (bs->ltgtype == LTG_ATTACKENEMYBASE) { - if (bs->enemy != redobelisk.entitynum && - bs->enemy != blueobelisk.entitynum) { - return qtrue; - } - } - if (BotFeelingBad(bs) > 50) { - return qtrue; - } - return qfalse; - } - else if (gametype == GT_HARVESTER) { - //if carrying cubes then always retreat - if (BotHarvesterCarryingCubes(bs)) return qtrue; - } -#endif + //always retreat when carrying a CTF flag + if (BotCTFCarryingFlag(bs)) return qtrue; // if (bs->enemy >= 0) { //if the enemy is carrying a flag BotEntityInfo(bs->enemy, &entinfo); - // if the enemy is carrying a flag if (EntityCarriesFlag(&entinfo)) return qfalse; -#ifdef MISSIONPACK - // if the enemy is carrying cubes - if (EntityCarriesCubes(&entinfo)) return qfalse; -#endif } //if the bot is getting the flag - if (bs->ltgtype == LTG_GETFLAG) - return qtrue; + if (bs->ltgtype == LTG_GETFLAG) return qtrue; // - if (BotAggression(bs) < 50) - return qtrue; + if (BotAggression(bs) < 50) return qtrue; return qfalse; } @@ -2327,49 +987,15 @@ BotWantsToChase int BotWantsToChase(bot_state_t *bs) { aas_entityinfo_t entinfo; - if (gametype == GT_CTF) { - //never chase when carrying a CTF flag - if (BotCTFCarryingFlag(bs)) - return qfalse; - //always chase if the enemy is carrying a flag - BotEntityInfo(bs->enemy, &entinfo); - if (EntityCarriesFlag(&entinfo)) - return qtrue; - } -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF) { - //never chase if carrying the flag - if (Bot1FCTFCarryingFlag(bs)) - return qfalse; - //always chase if the enemy is carrying a flag - BotEntityInfo(bs->enemy, &entinfo); - if (EntityCarriesFlag(&entinfo)) - return qtrue; - } - else if (gametype == GT_OBELISK) { - //the bots should be dedicated to attacking the enemy obelisk - if (bs->ltgtype == LTG_ATTACKENEMYBASE) { - if (bs->enemy != redobelisk.entitynum && - bs->enemy != blueobelisk.entitynum) { - return qfalse; - } - } - } - else if (gametype == GT_HARVESTER) { - //never chase if carrying cubes - if (BotHarvesterCarryingCubes(bs)) return qfalse; - - BotEntityInfo(bs->enemy, &entinfo); - // always chase if the enemy is carrying cubes - if (EntityCarriesCubes(&entinfo)) return qtrue; - } -#endif + //always retreat when carrying a CTF flag + if (BotCTFCarryingFlag(bs)) return qfalse; + //if the enemy is carrying a flag + BotEntityInfo(bs->enemy, &entinfo); + if (EntityCarriesFlag(&entinfo)) return qtrue; //if the bot is getting the flag - if (bs->ltgtype == LTG_GETFLAG) - return qfalse; + if (bs->ltgtype == LTG_GETFLAG) return qfalse; // - if (BotAggression(bs) > 50) - return qtrue; + if (BotAggression(bs) > 50) return qtrue; return qfalse; } @@ -2393,72 +1019,39 @@ int BotCanAndWantsToRocketJump(bot_state_t *bs) { //if rocket jumping is disabled if (!bot_rocketjump.integer) return qfalse; //if no rocket launcher - if (bs->inventory[INVENTORY_ROCKETLAUNCHER] <= 0) return qfalse; + if (bs->inventory[INVENTORY_QUANTUM] <= 0) return qfalse; //if low on rockets - if (bs->inventory[INVENTORY_ROCKETS] < 3) return qfalse; + if (bs->inventory[INVENTORY_QUANTUMAMMO] < 1) return qfalse; //never rocket jump with the Quad - if (bs->inventory[INVENTORY_QUAD]) return qfalse; + if (bs->inventory[INVENTORY_QUAD]) + { + if ( rpg_selfdamage.integer != 0 ) + { + return qfalse; + } + } //if low on health - if (bs->inventory[INVENTORY_HEALTH] < 60) return qfalse; - //if not full health - if (bs->inventory[INVENTORY_HEALTH] < 90) { - //if the bot has insufficient armor - if (bs->inventory[INVENTORY_ARMOR] < 40) return qfalse; + if (bs->inventory[INVENTORY_HEALTH] < 50) + { //if not full health + if ( rpg_selfdamage.integer != 0 ) + { + return qfalse; + } } - rocketjumper = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_WEAPONJUMPING, 0, 1); - if (rocketjumper < 0.5) return qfalse; + if (bs->inventory[INVENTORY_HEALTH] < 60) + { //if the bot has insufficient armor + if (bs->inventory[INVENTORY_ARMOR] < 20) + { + if ( rpg_selfdamage.integer != 0 ) + { + return qfalse; + } + } + } + rocketjumper = 1; return qtrue; } -/* -================== -BotHasPersistantPowerupAndWeapon -================== -*/ -int BotHasPersistantPowerupAndWeapon(bot_state_t *bs) { -#ifdef MISSIONPACK - // if the bot does not have a persistant powerup - if (!bs->inventory[INVENTORY_SCOUT] && - !bs->inventory[INVENTORY_GUARD] && - !bs->inventory[INVENTORY_DOUBLER] && - !bs->inventory[INVENTORY_AMMOREGEN] ) { - return qfalse; - } -#endif - //if the bot is very low on health - if (bs->inventory[INVENTORY_HEALTH] < 60) return qfalse; - //if the bot is low on health - if (bs->inventory[INVENTORY_HEALTH] < 80) { - //if the bot has insufficient armor - if (bs->inventory[INVENTORY_ARMOR] < 40) return qfalse; - } - //if the bot can use the bfg - if (bs->inventory[INVENTORY_BFG10K] > 0 && - bs->inventory[INVENTORY_BFGAMMO] > 7) return qtrue; - //if the bot can use the railgun - if (bs->inventory[INVENTORY_RAILGUN] > 0 && - bs->inventory[INVENTORY_SLUGS] > 5) return qtrue; - //if the bot can use the lightning gun - if (bs->inventory[INVENTORY_LIGHTNING] > 0 && - bs->inventory[INVENTORY_LIGHTNINGAMMO] > 50) return qtrue; - //if the bot can use the rocketlauncher - if (bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 && - bs->inventory[INVENTORY_ROCKETS] > 5) return qtrue; - // - if (bs->inventory[INVENTORY_NAILGUN] > 0 && - bs->inventory[INVENTORY_NAILS] > 5) return qtrue; - // - if (bs->inventory[INVENTORY_PROXLAUNCHER] > 0 && - bs->inventory[INVENTORY_MINES] > 5) return qtrue; - // - if (bs->inventory[INVENTORY_CHAINGUN] > 0 && - bs->inventory[INVENTORY_BELT] > 40) return qtrue; - //if the bot can use the plasmagun - if (bs->inventory[INVENTORY_PLASMAGUN] > 0 && - bs->inventory[INVENTORY_CELLS] > 20) return qtrue; - return qfalse; -} - /* ================== BotGoCamp @@ -2467,7 +1060,6 @@ BotGoCamp void BotGoCamp(bot_state_t *bs, bot_goal_t *goal) { float camper; - bs->decisionmaker = bs->client; //set message time to zero so bot will NOT show any message bs->teammessage_time = 0; //set the ltg type @@ -2475,11 +1067,11 @@ void BotGoCamp(bot_state_t *bs, bot_goal_t *goal) { //set the team goal memcpy(&bs->teamgoal, goal, sizeof(bot_goal_t)); //get the team goal time - camper = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CAMPER, 0, 1); - if (camper > 0.99) bs->teamgoal_time = FloatTime() + 99999; - else bs->teamgoal_time = FloatTime() + 120 + 180 * camper + random() * 15; + camper = 0; + if (camper > 0.99) bs->teamgoal_time = 99999; + else bs->teamgoal_time = 120 + 180 * camper + random() * 15; //set the last time the bot started camping - bs->camp_time = FloatTime(); + bs->camp_time = trap_AAS_Time(); //the teammate that requested the camping bs->teammate = 0; //do NOT type arrive message @@ -2493,52 +1085,8 @@ BotWantsToCamp */ int BotWantsToCamp(bot_state_t *bs) { float camper; - int cs, traveltime, besttraveltime; - bot_goal_t goal, bestgoal; - - camper = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CAMPER, 0, 1); - if (camper < 0.1) return qfalse; - //if the bot has a team goal - if (bs->ltgtype == LTG_TEAMHELP || - bs->ltgtype == LTG_TEAMACCOMPANY || - bs->ltgtype == LTG_DEFENDKEYAREA || - bs->ltgtype == LTG_GETFLAG || - bs->ltgtype == LTG_RUSHBASE || - bs->ltgtype == LTG_CAMP || - bs->ltgtype == LTG_CAMPORDER || - bs->ltgtype == LTG_PATROL) { - return qfalse; - } - //if camped recently - if (bs->camp_time > FloatTime() - 60 + 300 * (1-camper)) return qfalse; - // - if (random() > camper) { - bs->camp_time = FloatTime(); - return qfalse; - } - //if the bot isn't healthy anough - if (BotAggression(bs) < 50) return qfalse; - //the bot should have at least have the rocket launcher, the railgun or the bfg10k with some ammo - if ((bs->inventory[INVENTORY_ROCKETLAUNCHER] <= 0 || bs->inventory[INVENTORY_ROCKETS] < 10) && - (bs->inventory[INVENTORY_RAILGUN] <= 0 || bs->inventory[INVENTORY_SLUGS] < 10) && - (bs->inventory[INVENTORY_BFG10K] <= 0 || bs->inventory[INVENTORY_BFGAMMO] < 10)) { - return qfalse; - } - //find the closest camp spot - besttraveltime = 99999; - for (cs = trap_BotGetNextCampSpotGoal(0, &goal); cs; cs = trap_BotGetNextCampSpotGoal(cs, &goal)) { - traveltime = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, goal.areanum, TFL_DEFAULT); - if (traveltime && traveltime < besttraveltime) { - besttraveltime = traveltime; - memcpy(&bestgoal, &goal, sizeof(bot_goal_t)); - } - } - if (besttraveltime > 150) return qfalse; - //ok found a camp spot, go camp there - BotGoCamp(bs, &bestgoal); - bs->ordered = qfalse; - // - return qtrue; + camper = 0; + return qfalse; } /* @@ -2565,12 +1113,13 @@ BotGoForPowerups void BotGoForPowerups(bot_state_t *bs) { //don't avoid any of the powerups anymore - BotDontAvoid(bs, "Quad Damage"); - BotDontAvoid(bs, "Regeneration"); - BotDontAvoid(bs, "Battle Suit"); - BotDontAvoid(bs, "Speed"); - BotDontAvoid(bs, "Invisibility"); - //BotDontAvoid(bs, "Flight"); + BotDontAvoid(bs, "Quantum Weapon Enhancer"); + BotDontAvoid(bs, "Nano-Regenerative Protoplasmer"); + BotDontAvoid(bs, "Metaphasic Shielding"); + BotDontAvoid(bs, "Temporal Accelerator"); + BotDontAvoid(bs, "Personal Cloaking Device"); + BotDontAvoid(bs, "Seeker Drone"); + BotDontAvoid(bs, "Anti-Gravity Pack"); //reset the long term goal time so the bot will go for the powerup //NOTE: the long term goal type doesn't change bs->ltg_time = 0; @@ -2638,7 +1187,7 @@ BotAttackMove ================== */ bot_moveresult_t BotAttackMove(bot_state_t *bs, int tfl) { - int movetype, i, attackentity; + int movetype, i; float attack_skill, jumper, croucher, dist, strafechange_time; float attack_dist, attack_range; vec3_t forward, backward, sideward, hordir, up = {0, 0, 1}; @@ -2646,11 +1195,9 @@ bot_moveresult_t BotAttackMove(bot_state_t *bs, int tfl) { bot_moveresult_t moveresult; bot_goal_t goal; - attackentity = bs->enemy; - // - if (bs->attackchase_time > FloatTime()) { + if (bs->attackchase_time > trap_AAS_Time()) { //create the chase goal - goal.entitynum = attackentity; + goal.entitynum = bs->enemy; goal.areanum = bs->lastenemyareanum; VectorCopy(bs->lastenemyorigin, goal.origin); VectorSet(goal.mins, -8, -8, -8); @@ -2664,15 +1211,13 @@ bot_moveresult_t BotAttackMove(bot_state_t *bs, int tfl) { // memset(&moveresult, 0, sizeof(bot_moveresult_t)); // - attack_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_ATTACK_SKILL, 0, 1); - jumper = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_JUMPER, 0, 1); - croucher = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CROUCHER, 0, 1); - //if the bot is really stupid - if (attack_skill < 0.2) return moveresult; + attack_skill = 1; + jumper = 1; + croucher = 1; //initialize the movement state BotSetupForMovement(bs); //get the enemy entity info - BotEntityInfo(attackentity, &entinfo); + BotEntityInfo(bs->enemy, &entinfo); //direction towards the enemy VectorSubtract(entinfo.origin, bs->origin, forward); //the distance towards the enemy @@ -2681,45 +1226,39 @@ bot_moveresult_t BotAttackMove(bot_state_t *bs, int tfl) { //walk, crouch or jump movetype = MOVE_WALK; // - if (bs->attackcrouch_time < FloatTime() - 1) { + if (bs->attackcrouch_time < trap_AAS_Time() - 1) { if (random() < jumper) { movetype = MOVE_JUMP; } //wait at least one second before crouching again - else if (bs->attackcrouch_time < FloatTime() - 1 && random() < croucher) { - bs->attackcrouch_time = FloatTime() + croucher * 5; + else if (bs->attackcrouch_time < trap_AAS_Time() - 1 && random() < croucher) { + bs->attackcrouch_time = trap_AAS_Time() + croucher * 5; } } - if (bs->attackcrouch_time > FloatTime()) movetype = MOVE_CROUCH; + if (bs->attackcrouch_time > trap_AAS_Time()) movetype = MOVE_CROUCH; //if the bot should jump if (movetype == MOVE_JUMP) { //if jumped last frame - if (bs->attackjump_time > FloatTime()) { + if (bs->attackjump_time > trap_AAS_Time()) { movetype = MOVE_WALK; } else { - bs->attackjump_time = FloatTime() + 1; + bs->attackjump_time = trap_AAS_Time() + 1; } } - if (bs->cur_ps.weapon == WP_GAUNTLET) { - attack_dist = 0; - attack_range = 0; + + //if using assimilator or alt-fire hypo... + if ( bs->weaponnum == WP_14 || bs->weaponnum == (WP_12+WP_NUM_WEAPONS) ) + {//get real close + attack_dist = 16; + attack_range = 16; } - else { + else + { attack_dist = IDEAL_ATTACKDIST; attack_range = 40; } - //if the bot is stupid - if (attack_skill <= 0.4) { - //just walk to or away from the enemy - if (dist > attack_dist + attack_range) { - if (trap_BotMoveInDirection(bs->ms, forward, 400, movetype)) return moveresult; - } - if (dist < attack_dist - attack_range) { - if (trap_BotMoveInDirection(bs->ms, backward, 400, movetype)) return moveresult; - } - return moveresult; - } + //increase the strafe time bs->attackstrafe_time += bs->thinktime; //get the strafe change time @@ -2750,16 +1289,11 @@ bot_moveresult_t BotAttackMove(bot_state_t *bs, int tfl) { } else { //walk forward or backward to get at the ideal attack distance - if (dist > attack_dist + attack_range) { - VectorAdd(sideward, forward, sideward); - } - else if (dist < attack_dist - attack_range) { - VectorAdd(sideward, backward, sideward); - } + if (dist > attack_dist + attack_range) VectorAdd(sideward, forward, sideward); + else if (dist < attack_dist - attack_range) VectorAdd(sideward, backward, sideward); } //perform the movement - if (trap_BotMoveInDirection(bs->ms, sideward, 400, movetype)) - return moveresult; + if (trap_BotMoveInDirection(bs->ms, sideward, 400, movetype)) return moveresult; //movement failed, flip the strafe direction bs->flags ^= BFL_STRAFERIGHT; bs->attackstrafe_time = 0; @@ -2775,19 +1309,22 @@ BotSameTeam ================== */ int BotSameTeam(bot_state_t *bs, int entnum) { + char info1[1024], info2[1024]; if (bs->client < 0 || bs->client >= MAX_CLIENTS) { + //BotAI_Print(PRT_ERROR, "BotSameTeam: client out of range\n"); return qfalse; } - if (entnum < 0 || entnum >= MAX_CLIENTS) { + //BotAI_Print(PRT_ERROR, "BotSameTeam: client out of range\n"); return qfalse; } - - if (gametype >= GT_TEAM) { - if (level.clients[bs->client].sess.sessionTeam == level.clients[entnum].sess.sessionTeam) return qtrue; + if (gametype == GT_TEAM || gametype == GT_CTF) { + trap_GetConfigstring(CS_PLAYERS+bs->client, info1, sizeof(info1)); + trap_GetConfigstring(CS_PLAYERS+entnum, info2, sizeof(info2)); + // + if (atoi(Info_ValueForKey(info1, "t")) == atoi(Info_ValueForKey(info2, "t"))) return qtrue; } - return qfalse; } @@ -2830,7 +1367,7 @@ returns visibility in the range [0, 1] taking fog and water surfaces into accoun */ float BotEntityVisible(int viewer, vec3_t eye, vec3_t viewangles, float fov, int ent) { int i, contents_mask, passent, hitent, infog, inwater, otherinfog, pc; - float squaredfogdist, waterfactor, vis, bestvis; + float fogdist, waterfactor, vis, bestvis; bsp_trace_t trace; aas_entityinfo_t entinfo; vec3_t dir, entangles, start, end, middle; @@ -2846,7 +1383,7 @@ float BotEntityVisible(int viewer, vec3_t eye, vec3_t viewangles, float fov, int if (!InFieldOfVision(viewangles, fov, entangles)) return 0; // pc = trap_AAS_PointContents(eye); - infog = (pc & CONTENTS_FOG); + infog = (pc & CONTENTS_SOLID); inwater = (pc & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER)); // bestvis = 0; @@ -2893,26 +1430,26 @@ float BotEntityVisible(int viewer, vec3_t eye, vec3_t viewangles, float fov, int otherinfog = (trap_AAS_PointContents(middle) & CONTENTS_FOG); if (infog && otherinfog) { VectorSubtract(trace.endpos, eye, dir); - squaredfogdist = VectorLengthSquared(dir); + fogdist = VectorLength(dir); } else if (infog) { VectorCopy(trace.endpos, start); BotAI_Trace(&trace, start, NULL, NULL, eye, viewer, CONTENTS_FOG); VectorSubtract(eye, trace.endpos, dir); - squaredfogdist = VectorLengthSquared(dir); + fogdist = VectorLength(dir); } else if (otherinfog) { VectorCopy(trace.endpos, end); BotAI_Trace(&trace, eye, NULL, NULL, end, viewer, CONTENTS_FOG); VectorSubtract(end, trace.endpos, dir); - squaredfogdist = VectorLengthSquared(dir); + fogdist = VectorLength(dir); } else { //if the entity and the viewer are not in fog assume there's no fog in between - squaredfogdist = 0; + fogdist = 0; } //decrease visibility with the view distance through fog - vis = 1 / ((squaredfogdist * 0.001) < 1 ? 1 : (squaredfogdist * 0.001)); + vis = 1 / ((fogdist * fogdist * 0.001) < 1 ? 1 : (fogdist * fogdist * 0.001)); //if entering water visibility is reduced vis *= waterfactor; // @@ -2934,13 +1471,12 @@ BotFindEnemy */ int BotFindEnemy(bot_state_t *bs, int curenemy) { int i, healthdecrease; - float f, alertness, easyfragger, vis; - float squaredist, cursquaredist; + float f, dist, curdist, alertness, easyfragger, vis; aas_entityinfo_t entinfo, curenemyinfo; vec3_t dir, angles; - alertness = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_ALERTNESS, 0, 1); - easyfragger = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_EASY_FRAGGER, 0, 1); + alertness = 1; + easyfragger = 1; //check if the health decreased healthdecrease = bs->lasthealth > bs->inventory[INVENTORY_HEALTH]; //remember the current health value @@ -2950,39 +1486,15 @@ int BotFindEnemy(bot_state_t *bs, int curenemy) { BotEntityInfo(curenemy, &curenemyinfo); if (EntityCarriesFlag(&curenemyinfo)) return qfalse; VectorSubtract(curenemyinfo.origin, bs->origin, dir); - cursquaredist = VectorLengthSquared(dir); + curdist = VectorLength(dir); } else { - cursquaredist = 0; + curdist = 0; } -#ifdef MISSIONPACK - if (gametype == GT_OBELISK) { - vec3_t target; - bot_goal_t *goal; - bsp_trace_t trace; - - if (BotTeam(bs) == TEAM_RED) - goal = &blueobelisk; - else - goal = &redobelisk; - //if the obelisk is visible - VectorCopy(goal->origin, target); - target[2] += 1; - BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID); - if (trace.fraction >= 1 || trace.ent == goal->entitynum) { - if (goal->entitynum == bs->enemy) { - return qfalse; - } - bs->enemy = goal->entitynum; - bs->enemysight_time = FloatTime(); - bs->enemysuicide = qfalse; - bs->enemydeath_time = 0; - bs->enemyvisible_time = FloatTime(); - return qtrue; - } - } -#endif // + + //FIXME: This only finds lowest numbered enemy, not the closest or best!!! + // 6/15/00 dpk changed this for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { if (i == bs->client) continue; @@ -2992,6 +1504,8 @@ int BotFindEnemy(bot_state_t *bs, int curenemy) { BotEntityInfo(i, &entinfo); // if (!entinfo.valid) continue; + //if on the same team + if (BotSameTeam(bs, i)) continue; //if the enemy isn't dead and the enemy isn't the bot self if (EntityIsDead(&entinfo) || entinfo.number == bs->entitynum) continue; //if the enemy is invisible and not shooting @@ -3001,52 +1515,58 @@ int BotFindEnemy(bot_state_t *bs, int curenemy) { //if not an easy fragger don't shoot at chatting players if (easyfragger < 0.5 && EntityIsChatting(&entinfo)) continue; // - if (lastteleport_time > FloatTime() - 3) { + if (lastteleport_time > trap_AAS_Time() - 3) { VectorSubtract(entinfo.origin, lastteleport_origin, dir); - if (VectorLengthSquared(dir) < Square(70)) continue; + if (VectorLength(dir) < 70) continue; } //calculate the distance towards the enemy VectorSubtract(entinfo.origin, bs->origin, dir); - squaredist = VectorLengthSquared(dir); + dist = VectorLength(dir); + + //if this entity is not carrying a flag if (!EntityCarriesFlag(&entinfo)) - { - //if this enemy is further away than the current one - if (curenemy >= 0 && squaredist > cursquaredist) continue; - } //end if - //if the bot has no - if (squaredist > Square(900.0 + alertness * 4000.0)) continue; - //if on the same team - if (BotSameTeam(bs, i)) continue; - //if the bot's health decreased or the enemy is shooting - if (curenemy < 0 && (healthdecrease || EntityIsShooting(&entinfo))) - f = 360; - else - f = 90 + 90 - (90 - (squaredist > Square(810) ? Square(810) : squaredist) / (810 * 9)); - //check if the enemy is visible - vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, f, i); - if (vis <= 0) continue; - //if the enemy is quite far away, not shooting and the bot is not damaged - if (curenemy < 0 && squaredist > Square(100) && !healthdecrease && !EntityIsShooting(&entinfo)) - { - //check if we can avoid this enemy - VectorSubtract(bs->origin, entinfo.origin, dir); - vectoangles(dir, angles); - //if the bot isn't in the fov of the enemy - if (!InFieldOfVision(entinfo.angles, 90, angles)) { - //update some stuff for this enemy - BotUpdateBattleInventory(bs, i); - //if the bot doesn't really want to fight - if (BotWantsToRetreat(bs)) continue; - } +// if (EntityCarriesFlag(&entinfo)) +/* { + // pick this one! } + else +*/ { + //if this enemy is further away than the current one + if (curenemy >= 0 && dist > curdist) continue; + } + + //if the bot in too far away for me to notice + if (dist > 900 + alertness * 4000) continue; + + + //if the bot's health decreased or the enemy is shooting + if (curenemy < 0 && (healthdecrease || EntityIsShooting(&entinfo))) f = 360; + else f = 90 + 90 - (90 - (dist > 810 ? 810 : dist) / 9); + //check if the enemy is visible + vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, f, i); + if (vis <= 0) continue; + //if the enemy is quite far away, not shooting and the bot is not damaged + if (curenemy < 0 && dist > 200 && !healthdecrease && !EntityIsShooting(&entinfo)) + { + //check if we can avoid this enemy + VectorSubtract(bs->origin, entinfo.origin, dir); + vectoangles(dir, angles); + //if the bot isn't in the fov of the enemy + if (!InFieldOfVision(entinfo.angles, 120, angles)) { + //update some stuff for this enemy + BotUpdateBattleInventory(bs, i); + //if the bot doesn't really want to fight + if (BotWantsToRetreat(bs)) continue; + } + } +// } //found an enemy bs->enemy = entinfo.number; - if (curenemy >= 0) bs->enemysight_time = FloatTime() - 2; - else bs->enemysight_time = FloatTime(); + if (curenemy >= 0) bs->enemysight_time = trap_AAS_Time() - 2; + else bs->enemysight_time = trap_AAS_Time(); bs->enemysuicide = qfalse; bs->enemydeath_time = 0; - bs->enemyvisible_time = FloatTime(); return qtrue; } return qfalse; @@ -3062,150 +1582,6 @@ int BotTeamFlagCarrierVisible(bot_state_t *bs) { float vis; aas_entityinfo_t entinfo; - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - if (i == bs->client) - continue; - // - BotEntityInfo(i, &entinfo); - //if this player is active - if (!entinfo.valid) - continue; - //if this player is carrying a flag - if (!EntityCarriesFlag(&entinfo)) - continue; - //if the flag carrier is not on the same team - if (!BotSameTeam(bs, i)) - continue; - //if the flag carrier is not visible - vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i); - if (vis <= 0) - continue; - // - return i; - } - return -1; -} - -/* -================== -BotTeamFlagCarrier -================== -*/ -int BotTeamFlagCarrier(bot_state_t *bs) { - int i; - aas_entityinfo_t entinfo; - - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - if (i == bs->client) - continue; - // - BotEntityInfo(i, &entinfo); - //if this player is active - if (!entinfo.valid) - continue; - //if this player is carrying a flag - if (!EntityCarriesFlag(&entinfo)) - continue; - //if the flag carrier is not on the same team - if (!BotSameTeam(bs, i)) - continue; - // - return i; - } - return -1; -} - -/* -================== -BotEnemyFlagCarrierVisible -================== -*/ -int BotEnemyFlagCarrierVisible(bot_state_t *bs) { - int i; - float vis; - aas_entityinfo_t entinfo; - - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - if (i == bs->client) - continue; - // - BotEntityInfo(i, &entinfo); - //if this player is active - if (!entinfo.valid) - continue; - //if this player is carrying a flag - if (!EntityCarriesFlag(&entinfo)) - continue; - //if the flag carrier is on the same team - if (BotSameTeam(bs, i)) - continue; - //if the flag carrier is not visible - vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i); - if (vis <= 0) - continue; - // - return i; - } - return -1; -} - -/* -================== -BotVisibleTeamMatesAndEnemies -================== -*/ -void BotVisibleTeamMatesAndEnemies(bot_state_t *bs, int *teammates, int *enemies, float range) { - int i; - float vis; - aas_entityinfo_t entinfo; - vec3_t dir; - - if (teammates) - *teammates = 0; - if (enemies) - *enemies = 0; - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - if (i == bs->client) - continue; - // - BotEntityInfo(i, &entinfo); - //if this player is active - if (!entinfo.valid) - continue; - //if this player is carrying a flag - if (!EntityCarriesFlag(&entinfo)) - continue; - //if not within range - VectorSubtract(entinfo.origin, bs->origin, dir); - if (VectorLengthSquared(dir) > Square(range)) - continue; - //if the flag carrier is not visible - vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i); - if (vis <= 0) - continue; - //if the flag carrier is on the same team - if (BotSameTeam(bs, i)) { - if (teammates) - (*teammates)++; - } - else { - if (enemies) - (*enemies)++; - } - } -} - -#ifdef MISSIONPACK -/* -================== -BotTeamCubeCarrierVisible -================== -*/ -int BotTeamCubeCarrierVisible(bot_state_t *bs) { - int i; - float vis; - aas_entityinfo_t entinfo; - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { if (i == bs->client) continue; // @@ -3213,7 +1589,7 @@ int BotTeamCubeCarrierVisible(bot_state_t *bs) { //if this player is active if (!entinfo.valid) continue; //if this player is carrying a flag - if (!EntityCarriesCubes(&entinfo)) continue; + if (!EntityCarriesFlag(&entinfo)) continue; //if the flag carrier is not on the same team if (!BotSameTeam(bs, i)) continue; //if the flag carrier is not visible @@ -3225,43 +1601,19 @@ int BotTeamCubeCarrierVisible(bot_state_t *bs) { return -1; } -/* -================== -BotEnemyCubeCarrierVisible -================== -*/ -int BotEnemyCubeCarrierVisible(bot_state_t *bs) { - int i; - float vis; - aas_entityinfo_t entinfo; - - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - if (i == bs->client) - continue; - // - BotEntityInfo(i, &entinfo); - //if this player is active - if (!entinfo.valid) - continue; - //if this player is carrying a flag - if (!EntityCarriesCubes(&entinfo)) continue; - //if the flag carrier is on the same team - if (BotSameTeam(bs, i)) - continue; - //if the flag carrier is not visible - vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i); - if (vis <= 0) - continue; - // - return i; - } - return -1; -} -#endif - /* ================== BotAimAtEnemy + + MCG - FIXME: This is not set up at all correctly in the following areas: + Needs to consider if weapon is an alt weapon for aim and accuracy as well as functionality + Need to consider range? + Grenade Primary and alt as well as Scavenger alt need to take into account gravity + Needs to pick our new weapons correctly to determine which ones they should: + lead with (projectiles have speed) + decay aim purposely (instant hit weaps) + shoot "around corners" (bouncers, mines, splashdamage?) + ================== */ void BotAimAtEnemy(bot_state_t *bs) { @@ -3276,88 +1628,71 @@ void BotAimAtEnemy(bot_state_t *bs) { vec3_t target; //if the bot has no enemy - if (bs->enemy < 0) { - return; - } - //get the enemy entity information - BotEntityInfo(bs->enemy, &entinfo); - //if this is not a player (should be an obelisk) - if (bs->enemy >= MAX_CLIENTS) { - //if the obelisk is visible - VectorCopy(entinfo.origin, target); -#ifdef MISSIONPACK - // if attacking an obelisk - if ( bs->enemy == redobelisk.entitynum || - bs->enemy == blueobelisk.entitynum ) { - target[2] += 32; - } -#endif - //aim at the obelisk - VectorSubtract(target, bs->eye, dir); - vectoangles(dir, bs->ideal_viewangles); - //set the aim target before trying to attack - VectorCopy(target, bs->aimtarget); - return; - } + if (bs->enemy < 0) return; // //BotAI_Print(PRT_MESSAGE, "client %d: aiming at client %d\n", bs->entitynum, bs->enemy); // - aim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL, 0, 1); - aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY, 0, 1); + aim_skill = 1; + aim_accuracy = 1; // - if (aim_skill > 0.95) { + if (aim_skill > 0.95) + { //don't aim too early - reactiontime = 0.5 * trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_REACTIONTIME, 0, 1); - if (bs->enemysight_time > FloatTime() - reactiontime) return; - if (bs->teleport_time > FloatTime() - reactiontime) return; + reactiontime = 0.5; + if (bs->enemysight_time > trap_AAS_Time() - reactiontime) return; + if (bs->teleport_time > trap_AAS_Time() - reactiontime) return; } //get the weapon information trap_BotGetWeaponInfo(bs->ws, bs->weaponnum, &wi); //get the weapon specific aim accuracy and or aim skill - if (wi.number == WP_MACHINEGUN) { - aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_MACHINEGUN, 0, 1); - } - else if (wi.number == WP_SHOTGUN) { - aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_SHOTGUN, 0, 1); - } - else if (wi.number == WP_GRENADE_LAUNCHER) { + + if (wi.number == WP_8) { aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_GRENADELAUNCHER, 0, 1); aim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL_GRENADELAUNCHER, 0, 1); } - else if (wi.number == WP_ROCKET_LAUNCHER) { - aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_ROCKETLAUNCHER, 0, 1); - aim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL_ROCKETLAUNCHER, 0, 1); + if (wi.number == WP_10) { + aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_STASIS, 0, 1); + aim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL_STASIS, 0, 1); } - else if (wi.number == WP_LIGHTNING) { - aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_LIGHTNING, 0, 1); + if (wi.number == WP_5) { + aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_PHASER, 0, 1); } - else if (wi.number == WP_RAILGUN) { - aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_RAILGUN, 0, 1); + if (wi.number == WP_1) { + aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_IMOD, 0, 1); } - else if (wi.number == WP_PLASMAGUN) { - aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_PLASMAGUN, 0, 1); - aim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL_PLASMAGUN, 0, 1); + if (wi.number == WP_6) { + aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_COMPRESSION, 0, 1); } - else if (wi.number == WP_BFG) { - aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_BFG10K, 0, 1); - aim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL_BFG10K, 0, 1); + if (wi.number == WP_7) { + aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_TETRION, 0, 1); } + if (wi.number == WP_13) { + aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_DREADNOUGHT, 0, 1); + } + if (wi.number == WP_9) { + aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_QUANTUM, 0, 1); + aim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL_QUANTUM, 0, 1); + } + if (wi.number == WP_4) { + aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_SCAVENGER, 0, 1); + } + // - if (aim_accuracy <= 0) aim_accuracy = 0.0001f; + if (aim_accuracy <= 0) aim_accuracy = 0.0001; //get the enemy entity information BotEntityInfo(bs->enemy, &entinfo); //if the enemy is invisible then shoot crappy most of the time if (EntityIsInvisible(&entinfo)) { - if (random() > 0.1) aim_accuracy *= 0.4f; + if (random() > 0.1) aim_accuracy *= 0.4; } // VectorSubtract(entinfo.origin, entinfo.lastvisorigin, enemyvelocity); VectorScale(enemyvelocity, 1 / entinfo.update_time, enemyvelocity); //enemy origin and velocity is remembered every 0.5 seconds - if (bs->enemyposition_time < FloatTime()) { + if (bs->enemyposition_time < trap_AAS_Time()) { // - bs->enemyposition_time = FloatTime() + 0.5; + bs->enemyposition_time = trap_AAS_Time() + 0.5; VectorCopy(enemyvelocity, bs->enemyvelocity); VectorCopy(entinfo.origin, bs->enemyorigin); } @@ -3365,11 +1700,11 @@ void BotAimAtEnemy(bot_state_t *bs) { if (aim_skill < 0.9) { VectorSubtract(entinfo.origin, bs->enemyorigin, dir); //if the enemy moved a bit - if (VectorLengthSquared(dir) > Square(48)) { + if (VectorLength(dir) > 48) { //if the enemy changed direction if (DotProduct(bs->enemyvelocity, enemyvelocity) < 0) { //aim accuracy should be worse now - aim_accuracy *= 0.7f; + aim_accuracy *= 0.7; } } } @@ -3398,7 +1733,7 @@ void BotAimAtEnemy(bot_state_t *bs) { dist = VectorLength(dir); VectorSubtract(entinfo.origin, bs->enemyorigin, dir); //if the enemy is NOT pretty far away and strafing just small steps left and right - if (!(dist > 100 && VectorLengthSquared(dir) < Square(32))) { + if (!(dist > 100 && VectorLength(dir) < 32)) { //if skilled anough do exact prediction if (aim_skill > 0.8 && //if the weapon is ready to fire @@ -3422,9 +1757,9 @@ void BotAimAtEnemy(bot_state_t *bs) { trap_AAS_PredictClientMovement(&move, bs->enemy, origin, PRESENCE_CROUCH, qfalse, dir, cmdmove, 0, - dist * 10 / wi.speed, 0.1f, 0, 0, qfalse); + dist * 10 / wi.speed, 0.1, 0, 0, qfalse); VectorCopy(move.endpos, bestorigin); - //BotAI_Print(PRT_MESSAGE, "%1.1f predicted speed = %f, frames = %f\n", FloatTime(), VectorLength(dir), dist * 10 / wi.speed); + //BotAI_Print(PRT_MESSAGE, "%1.1f predicted speed = %f, frames = %f\n", trap_AAS_Time(), VectorLength(dir), dist * 10 / wi.speed); } //if not that skilled do linear prediction else if (aim_skill > 0.4) { @@ -3460,10 +1795,10 @@ void BotAimAtEnemy(bot_state_t *bs) { if (fabs(trace.endpos[2] - groundtarget[2]) < 50) { VectorSubtract(trace.endpos, groundtarget, dir); //if the hitpoint is near anough the ground target - if (VectorLengthSquared(dir) < Square(60)) { + if (VectorLength(dir) < 60) { VectorSubtract(trace.endpos, start, dir); //if the hitpoint is far anough from the bot - if (VectorLengthSquared(dir) > Square(100)) { + if (VectorLength(dir) > 100) { //check if the bot is visible from the ground target trace.endpos[2] += 1; BotAI_Trace(&trace, trace.endpos, NULL, NULL, entinfo.origin, entinfo.number, MASK_SHOT); @@ -3487,9 +1822,9 @@ void BotAimAtEnemy(bot_state_t *bs) { //if the bot is skilled anough if (aim_skill > 0.5) { //do prediction shots around corners - if (wi.number == WP_BFG || - wi.number == WP_ROCKET_LAUNCHER || - wi.number == WP_GRENADE_LAUNCHER) { + if (wi.number == WP_10 || + wi.number == WP_8) + { //create the chase goal goal.entitynum = bs->client; goal.areanum = bs->areanum; @@ -3499,7 +1834,7 @@ void BotAimAtEnemy(bot_state_t *bs) { // if (trap_BotPredictVisiblePosition(bs->lastenemyorigin, bs->lastenemyareanum, &goal, TFL_DEFAULT, target)) { VectorSubtract(target, bs->eye, dir); - if (VectorLengthSquared(dir) > Square(80)) { + if (VectorLength(dir) > 80) { VectorCopy(target, bestorigin); bestorigin[2] -= 20; } @@ -3518,11 +1853,9 @@ void BotAimAtEnemy(bot_state_t *bs) { } //get aim direction VectorSubtract(bestorigin, bs->eye, dir); - // - if (wi.number == WP_MACHINEGUN || - wi.number == WP_SHOTGUN || - wi.number == WP_LIGHTNING || - wi.number == WP_RAILGUN) { + // kef -- fixme. i'm guessing this is listing all of the instant-hit weapons? + if (wi.number == WP_5 || + wi.number == WP_1) { //distance towards the enemy dist = VectorLength(dir); if (dist > 150) dist = 150; @@ -3542,14 +1875,16 @@ void BotAimAtEnemy(bot_state_t *bs) { bs->ideal_viewangles[YAW] += 6 * wi.hspread * crandom() * (1 - aim_accuracy); bs->ideal_viewangles[YAW] = AngleMod(bs->ideal_viewangles[YAW]); //if the bots should be really challenging - if (bot_challenge.integer) { - //if the bot is really accurate and has the enemy in view for some time - if (aim_accuracy > 0.9 && bs->enemysight_time < FloatTime() - 1) { - //set the view angles directly - if (bs->ideal_viewangles[PITCH] > 180) bs->ideal_viewangles[PITCH] -= 360; - VectorCopy(bs->ideal_viewangles, bs->viewangles); - trap_EA_View(bs->client, bs->viewangles); + //if the bot is really accurate and has the enemy in view for some time + if (aim_accuracy > 0.9 && bs->enemysight_time < trap_AAS_Time() - 1) + { + //set the view angles directly + if (bs->ideal_viewangles[PITCH] > 180) + { + bs->ideal_viewangles[PITCH] -= 360; } + VectorCopy(bs->ideal_viewangles, bs->viewangles); + trap_EA_View(bs->client, bs->viewangles); } } @@ -3560,7 +1895,6 @@ BotCheckAttack */ void BotCheckAttack(bot_state_t *bs) { float points, reactiontime, fov, firethrottle; - int attackentity; bsp_trace_t bsptrace; //float selfpreservation; vec3_t forward, right, start, end, dir, angles; @@ -3569,62 +1903,42 @@ void BotCheckAttack(bot_state_t *bs) { aas_entityinfo_t entinfo; vec3_t mins = {-8, -8, -8}, maxs = {8, 8, 8}; - attackentity = bs->enemy; + if (bs->enemy < 0) return; // - BotEntityInfo(attackentity, &entinfo); - // if not attacking a player - if (attackentity >= MAX_CLIENTS) { -#ifdef MISSIONPACK - // if attacking an obelisk - if ( entinfo.number == redobelisk.entitynum || - entinfo.number == blueobelisk.entitynum ) { - // if obelisk is respawning return - if ( g_entities[entinfo.number].activator && - g_entities[entinfo.number].activator->s.frame == 2 ) { - return; - } - } -#endif - } - // - reactiontime = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_REACTIONTIME, 0, 1); - if (bs->enemysight_time > FloatTime() - reactiontime) return; - if (bs->teleport_time > FloatTime() - reactiontime) return; + reactiontime = 0; + if (bs->enemysight_time > trap_AAS_Time() - reactiontime) return; + if (bs->teleport_time > trap_AAS_Time() - reactiontime) return; //if changing weapons - if (bs->weaponchange_time > FloatTime() - 0.1) return; + if (bs->weaponchange_time > trap_AAS_Time() - 0.1) return; //check fire throttle characteristic - if (bs->firethrottlewait_time > FloatTime()) return; - firethrottle = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_FIRETHROTTLE, 0, 1); - if (bs->firethrottleshoot_time < FloatTime()) { + if (bs->firethrottlewait_time > trap_AAS_Time()) return; + firethrottle = 1; + if (bs->firethrottleshoot_time < trap_AAS_Time()) { if (random() > firethrottle) { - bs->firethrottlewait_time = FloatTime() + firethrottle; + bs->firethrottlewait_time = trap_AAS_Time() + firethrottle; bs->firethrottleshoot_time = 0; } else { - bs->firethrottleshoot_time = FloatTime() + 1 - firethrottle; + bs->firethrottleshoot_time = trap_AAS_Time() + 1 - firethrottle; bs->firethrottlewait_time = 0; } } // + BotEntityInfo(bs->enemy, &entinfo); + VectorSubtract(entinfo.origin, bs->eye, dir); // - VectorSubtract(bs->aimtarget, bs->eye, dir); - // - if (bs->weaponnum == WP_GAUNTLET) { - if (VectorLengthSquared(dir) > Square(60)) { - return; - } - } - if (VectorLengthSquared(dir) < Square(100)) - fov = 120; - else - fov = 50; - // + if (VectorLength(dir) < 100) fov = 120; + else fov = 50; + /* + //if the enemy isn't visible + if (!BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, fov, bs->enemy)) { + //botimport.Print(PRT_MESSAGE, "enemy not visible\n"); + return; + }*/ vectoangles(dir, angles); - if (!InFieldOfVision(bs->viewangles, fov, angles)) - return; + if (!InFieldOfVision(bs->viewangles, fov, angles)) return; BotAI_Trace(&bsptrace, bs->eye, NULL, NULL, bs->aimtarget, bs->client, CONTENTS_SOLID|CONTENTS_PLAYERCLIP); - if (bsptrace.fraction < 1 && bsptrace.ent != attackentity) - return; + if (bsptrace.fraction < 1 && bsptrace.ent != bs->enemy) return; //get the weapon info trap_BotGetWeaponInfo(bs->ws, bs->weaponnum, &wi); @@ -3640,21 +1954,20 @@ void BotCheckAttack(bot_state_t *bs) { //a little back to make sure not inside a very close enemy VectorMA(start, -12, forward, start); BotAI_Trace(&trace, start, mins, maxs, end, bs->entitynum, MASK_SHOT); - //if the entity is a client - if (trace.ent >= 0 && trace.ent < MAX_CLIENTS) { - if (trace.ent != attackentity) { + //if won't hit the enemy + if (trace.ent != bs->enemy) { + //if the entity is a client + if (trace.ent > 0 && trace.ent <= MAX_CLIENTS) { //if a teammate is hit - if (BotSameTeam(bs, trace.ent)) - return; + if (BotSameTeam(bs, trace.ent)) return; } - } - //if won't hit the enemy or not attacking a player (obelisk) - if (trace.ent != attackentity || attackentity >= MAX_CLIENTS) { - //if the projectile does radial damage + //if the projectile does a radial damage if (wi.proj.damagetype & DAMAGETYPE_RADIAL) { if (trace.fraction * 1000 < wi.proj.radius) { points = (wi.proj.damage - 0.5 * trace.fraction * 1000) * 0.5; if (points > 0) { +// selfpreservation = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_SELFPRESERVATION, 0, 1); +// if (random() < selfpreservation) return; return; } } @@ -3663,12 +1976,30 @@ void BotCheckAttack(bot_state_t *bs) { } //if fire has to be release to activate weapon if (wi.flags & WFL_FIRERELEASED) { - if (bs->flags & BFL_ATTACKED) { - trap_EA_Attack(bs->client); + if (bs->flags & BFL_ATTACKED) + {// check in here to either call the alt_fire or not!! also, adjust the bots weapon... hackery? + if (bs->weaponnum > WP_NUM_WEAPONS) // it's an alt_fire! + { + bs->weaponnum -= WP_NUM_WEAPONS; + trap_EA_Alt_Attack(bs->client); + } + else + { + trap_EA_Attack(bs->client); + } } } - else { - trap_EA_Attack(bs->client); + else + { // check in here to either call the alt_fire or not!! also, adjust the bots weapon... hackery? + if (bs->weaponnum > WP_NUM_WEAPONS) // it's an alt_fire! + { + bs->weaponnum -= WP_NUM_WEAPONS; + trap_EA_Alt_Attack(bs->client); + } + else + { + trap_EA_Attack(bs->client); + } } bs->flags ^= BFL_ATTACKED; } @@ -3735,21 +2066,105 @@ void BotMapScripts(bot_state_t *bs) { bs->flags |= BFL_IDEALVIEWSET; VectorSubtract(buttonorg, bs->eye, dir); vectoangles(dir, bs->ideal_viewangles); - aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY, 0, 1); + aim_accuracy = 1; bs->ideal_viewangles[PITCH] += 8 * crandom() * (1 - aim_accuracy); bs->ideal_viewangles[PITCH] = AngleMod(bs->ideal_viewangles[PITCH]); bs->ideal_viewangles[YAW] += 8 * crandom() * (1 - aim_accuracy); bs->ideal_viewangles[YAW] = AngleMod(bs->ideal_viewangles[YAW]); // - if (InFieldOfVision(bs->viewangles, 20, bs->ideal_viewangles)) { - trap_EA_Attack(bs->client); + if (InFieldOfVision(bs->viewangles, 20, bs->ideal_viewangles)) + {// check in here to either call the alt_fire or not!! also, adjust the bots weapon... hackery? + if (bs->weaponnum > WP_NUM_WEAPONS) // it's an alt_fire! + { + bs->weaponnum -= WP_NUM_WEAPONS; + trap_EA_Alt_Attack(bs->client); + } + else + { + trap_EA_Attack(bs->client); + } } } } - else if (!Q_stricmp(mapname, "mpq3tourney6")) { - //NOTE: NEVER use the func_bobbing in mpq3tourney6 - bs->tfl &= ~TFL_FUNCBOB; +} + +/* +================== +BotEntityToActivate +================== +*/ +//#define OBSTACLEDEBUG + +int BotEntityToActivate(int entitynum) { + int i, ent, cur_entities[10]; + char model[MAX_INFO_STRING], tmpmodel[128]; + char target[128], classname[128]; + float health; + char targetname[10][128]; + aas_entityinfo_t entinfo; + + BotEntityInfo(entitynum, &entinfo); + Com_sprintf(model, sizeof( model ), "*%d", entinfo.modelindex); + for (ent = trap_AAS_NextBSPEntity(0); ent; ent = trap_AAS_NextBSPEntity(ent)) { + if (!trap_AAS_ValueForBSPEpairKey(ent, "model", tmpmodel, sizeof(tmpmodel))) continue; + if (!strcmp(model, tmpmodel)) break; } + if (!ent) { + BotAI_Print(PRT_ERROR, "BotEntityToActivate: no entity found with model %s\n", model); + return 0; + } + trap_AAS_ValueForBSPEpairKey(ent, "classname", classname, sizeof(classname)); + if (!classname[0]) { + BotAI_Print(PRT_ERROR, "BotEntityToActivate: entity with model %s has no classname\n", model); + return 0; + } + //if it is a door + if (!strcmp(classname, "func_door")) { + if (trap_AAS_FloatForBSPEpairKey(ent, "health", &health)) { + //if health the door must be shot to open + if (health) return ent; + } + } + //get the targetname so we can find an entity with a matching target + if (!trap_AAS_ValueForBSPEpairKey(ent, "targetname", targetname[0], sizeof(targetname[0]))) { +#ifdef OBSTACLEDEBUG + BotAI_Print(PRT_ERROR, "BotEntityToActivate: entity with model \"%s\" has no targetname\n", model); +#endif //OBSTACLEDEBUG + return 0; + } + //only allows single activation chains, tree-like activation can be added back in + cur_entities[0] = trap_AAS_NextBSPEntity(0); + for (i = 0; i >= 0 && i < 10;) { + for (ent = cur_entities[i]; ent; ent = trap_AAS_NextBSPEntity(ent)) { + if (!trap_AAS_ValueForBSPEpairKey(ent, "target", target, sizeof(target))) continue; + if (!strcmp(targetname[i], target)) { + cur_entities[i] = trap_AAS_NextBSPEntity(ent); + break; + } + } + if (!ent) { + BotAI_Print(PRT_ERROR, "BotEntityToActivate: no entity with target \"%s\"\n", targetname[i]); + i--; + continue; + } + if (!trap_AAS_ValueForBSPEpairKey(ent, "classname", classname, sizeof(classname))) { + BotAI_Print(PRT_ERROR, "BotEntityToActivate: entity with target \"%s\" has no classname\n", targetname[i]); + continue; + } + if (!strcmp(classname, "func_button")) { + //BSP button model + return ent; + } + else if (!strcmp(classname, "trigger_multiple")) { + //invisible trigger multiple box + return ent; + } + else { + i--; + } + } + BotAI_Print(PRT_ERROR, "BotEntityToActivate: unknown activator with classname \"%s\"\n", classname); + return 0; } /* @@ -3757,10 +2172,10 @@ void BotMapScripts(bot_state_t *bs) { BotSetMovedir ================== */ -static vec3_t VEC_UP = {0, -1, 0}; -static vec3_t MOVEDIR_UP = {0, 0, 1}; -static vec3_t VEC_DOWN = {0, -2, 0}; -static vec3_t MOVEDIR_DOWN = {0, 0, -1}; +vec3_t VEC_UP = {0, -1, 0}; +vec3_t MOVEDIR_UP = {0, 0, 1}; +vec3_t VEC_DOWN = {0, -2, 0}; +vec3_t MOVEDIR_DOWN = {0, 0, -1}; void BotSetMovedir(vec3_t angles, vec3_t movedir) { if (VectorCompare(angles, VEC_UP)) { @@ -3781,7 +2196,7 @@ BotModelMinsMaxs this is ugly ================== */ -int BotModelMinsMaxs(int modelindex, int eType, int contents, vec3_t mins, vec3_t maxs) { +void BotModelMinsMaxs(int modelindex, int eType, vec3_t mins, vec3_t maxs) { gentity_t *ent; int i; @@ -3790,703 +2205,203 @@ int BotModelMinsMaxs(int modelindex, int eType, int contents, vec3_t mins, vec3_ if ( !ent->inuse ) { continue; } - if ( eType && ent->s.eType != eType) { - continue; - } - if ( contents && ent->r.contents != contents) { + if ( ent->s.eType != eType) { continue; } if (ent->s.modelindex == modelindex) { - if (mins) - VectorAdd(ent->r.currentOrigin, ent->r.mins, mins); - if (maxs) - VectorAdd(ent->r.currentOrigin, ent->r.maxs, maxs); - return i; + VectorAdd(ent->r.currentOrigin, ent->r.mins, mins); + VectorAdd(ent->r.currentOrigin, ent->r.maxs, maxs); + return; } } - if (mins) - VectorClear(mins); - if (maxs) - VectorClear(maxs); - return 0; -} - -/* -================== -BotFuncButtonGoal -================== -*/ -int BotFuncButtonActivateGoal(bot_state_t *bs, int bspent, bot_activategoal_t *activategoal) { - int i, areas[10], numareas, modelindex, entitynum; - char model[128]; - float lip, dist, health, angle; - vec3_t size, start, end, mins, maxs, angles, points[10]; - vec3_t movedir, origin, goalorigin, bboxmins, bboxmaxs; - vec3_t extramins = {1, 1, 1}, extramaxs = {-1, -1, -1}; - bsp_trace_t bsptrace; - - activategoal->shoot = qfalse; - VectorClear(activategoal->target); - //create a bot goal towards the button - trap_AAS_ValueForBSPEpairKey(bspent, "model", model, sizeof(model)); - if (!*model) - return qfalse; - modelindex = atoi(model+1); - if (!modelindex) - return qfalse; - VectorClear(angles); - entitynum = BotModelMinsMaxs(modelindex, ET_MOVER, 0, mins, maxs); - //get the lip of the button - trap_AAS_FloatForBSPEpairKey(bspent, "lip", &lip); - if (!lip) lip = 4; - //get the move direction from the angle - trap_AAS_FloatForBSPEpairKey(bspent, "angle", &angle); - VectorSet(angles, 0, angle, 0); - BotSetMovedir(angles, movedir); - //button size - VectorSubtract(maxs, mins, size); - //button origin - VectorAdd(mins, maxs, origin); - VectorScale(origin, 0.5, origin); - //touch distance of the button - dist = fabs(movedir[0]) * size[0] + fabs(movedir[1]) * size[1] + fabs(movedir[2]) * size[2]; - dist *= 0.5; - // - trap_AAS_FloatForBSPEpairKey(bspent, "health", &health); - //if the button is shootable - if (health) { - //calculate the shoot target - VectorMA(origin, -dist, movedir, goalorigin); - // - VectorCopy(goalorigin, activategoal->target); - activategoal->shoot = qtrue; - // - BotAI_Trace(&bsptrace, bs->eye, NULL, NULL, goalorigin, bs->entitynum, MASK_SHOT); - // if the button is visible from the current position - if (bsptrace.fraction >= 1.0 || bsptrace.ent == entitynum) { - // - activategoal->goal.entitynum = entitynum; //NOTE: this is the entity number of the shootable button - activategoal->goal.number = 0; - activategoal->goal.flags = 0; - VectorCopy(bs->origin, activategoal->goal.origin); - activategoal->goal.areanum = bs->areanum; - VectorSet(activategoal->goal.mins, -8, -8, -8); - VectorSet(activategoal->goal.maxs, 8, 8, 8); - // - return qtrue; - } - else { - //create a goal from where the button is visible and shoot at the button from there - //add bounding box size to the dist - trap_AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, bboxmins, bboxmaxs); - for (i = 0; i < 3; i++) { - if (movedir[i] < 0) dist += fabs(movedir[i]) * fabs(bboxmaxs[i]); - else dist += fabs(movedir[i]) * fabs(bboxmins[i]); - } - //calculate the goal origin - VectorMA(origin, -dist, movedir, goalorigin); - // - VectorCopy(goalorigin, start); - start[2] += 24; - VectorCopy(start, end); - end[2] -= 512; - numareas = trap_AAS_TraceAreas(start, end, areas, points, 10); - // - for (i = numareas-1; i >= 0; i--) { - if (trap_AAS_AreaReachability(areas[i])) { - break; - } - } - if (i < 0) { - // FIXME: trace forward and maybe in other directions to find a valid area - } - if (i >= 0) { - // - VectorCopy(points[i], activategoal->goal.origin); - activategoal->goal.areanum = areas[i]; - VectorSet(activategoal->goal.mins, 8, 8, 8); - VectorSet(activategoal->goal.maxs, -8, -8, -8); - // - for (i = 0; i < 3; i++) - { - if (movedir[i] < 0) activategoal->goal.maxs[i] += fabs(movedir[i]) * fabs(extramaxs[i]); - else activategoal->goal.mins[i] += fabs(movedir[i]) * fabs(extramins[i]); - } //end for - // - activategoal->goal.entitynum = entitynum; - activategoal->goal.number = 0; - activategoal->goal.flags = 0; - return qtrue; - } - } - return qfalse; - } - else { - //add bounding box size to the dist - trap_AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, bboxmins, bboxmaxs); - for (i = 0; i < 3; i++) { - if (movedir[i] < 0) dist += fabs(movedir[i]) * fabs(bboxmaxs[i]); - else dist += fabs(movedir[i]) * fabs(bboxmins[i]); - } - //calculate the goal origin - VectorMA(origin, -dist, movedir, goalorigin); - // - VectorCopy(goalorigin, start); - start[2] += 24; - VectorCopy(start, end); - end[2] -= 100; - numareas = trap_AAS_TraceAreas(start, end, areas, NULL, 10); - // - for (i = 0; i < numareas; i++) { - if (trap_AAS_AreaReachability(areas[i])) { - break; - } - } - if (i < numareas) { - // - VectorCopy(origin, activategoal->goal.origin); - activategoal->goal.areanum = areas[i]; - VectorSubtract(mins, origin, activategoal->goal.mins); - VectorSubtract(maxs, origin, activategoal->goal.maxs); - // - for (i = 0; i < 3; i++) - { - if (movedir[i] < 0) activategoal->goal.maxs[i] += fabs(movedir[i]) * fabs(extramaxs[i]); - else activategoal->goal.mins[i] += fabs(movedir[i]) * fabs(extramins[i]); - } //end for - // - activategoal->goal.entitynum = entitynum; - activategoal->goal.number = 0; - activategoal->goal.flags = 0; - return qtrue; - } - } - return qfalse; -} - -/* -================== -BotFuncDoorGoal -================== -*/ -int BotFuncDoorActivateGoal(bot_state_t *bs, int bspent, bot_activategoal_t *activategoal) { - int modelindex, entitynum; - char model[MAX_INFO_STRING]; - vec3_t mins, maxs, origin, angles; - - //shoot at the shootable door - trap_AAS_ValueForBSPEpairKey(bspent, "model", model, sizeof(model)); - if (!*model) - return qfalse; - modelindex = atoi(model+1); - if (!modelindex) - return qfalse; - VectorClear(angles); - entitynum = BotModelMinsMaxs(modelindex, ET_MOVER, 0, mins, maxs); - //door origin - VectorAdd(mins, maxs, origin); - VectorScale(origin, 0.5, origin); - VectorCopy(origin, activategoal->target); - activategoal->shoot = qtrue; - // - activategoal->goal.entitynum = entitynum; //NOTE: this is the entity number of the shootable door - activategoal->goal.number = 0; - activategoal->goal.flags = 0; - VectorCopy(bs->origin, activategoal->goal.origin); - activategoal->goal.areanum = bs->areanum; - VectorSet(activategoal->goal.mins, -8, -8, -8); - VectorSet(activategoal->goal.maxs, 8, 8, 8); - return qtrue; -} - -/* -================== -BotTriggerMultipleGoal -================== -*/ -int BotTriggerMultipleActivateGoal(bot_state_t *bs, int bspent, bot_activategoal_t *activategoal) { - int i, areas[10], numareas, modelindex, entitynum; - char model[128]; - vec3_t start, end, mins, maxs, angles; - vec3_t origin, goalorigin; - - activategoal->shoot = qfalse; - VectorClear(activategoal->target); - //create a bot goal towards the trigger - trap_AAS_ValueForBSPEpairKey(bspent, "model", model, sizeof(model)); - if (!*model) - return qfalse; - modelindex = atoi(model+1); - if (!modelindex) - return qfalse; - VectorClear(angles); - entitynum = BotModelMinsMaxs(modelindex, 0, CONTENTS_TRIGGER, mins, maxs); - //trigger origin - VectorAdd(mins, maxs, origin); - VectorScale(origin, 0.5, origin); - VectorCopy(origin, goalorigin); - // - VectorCopy(goalorigin, start); - start[2] += 24; - VectorCopy(start, end); - end[2] -= 100; - numareas = trap_AAS_TraceAreas(start, end, areas, NULL, 10); - // - for (i = 0; i < numareas; i++) { - if (trap_AAS_AreaReachability(areas[i])) { - break; - } - } - if (i < numareas) { - VectorCopy(origin, activategoal->goal.origin); - activategoal->goal.areanum = areas[i]; - VectorSubtract(mins, origin, activategoal->goal.mins); - VectorSubtract(maxs, origin, activategoal->goal.maxs); - // - activategoal->goal.entitynum = entitynum; - activategoal->goal.number = 0; - activategoal->goal.flags = 0; - return qtrue; - } - return qfalse; -} - -/* -================== -BotPopFromActivateGoalStack -================== -*/ -int BotPopFromActivateGoalStack(bot_state_t *bs) { - if (!bs->activatestack) - return qfalse; - BotEnableActivateGoalAreas(bs->activatestack, qtrue); - bs->activatestack->inuse = qfalse; - bs->activatestack->justused_time = FloatTime(); - bs->activatestack = bs->activatestack->next; - return qtrue; -} - -/* -================== -BotPushOntoActivateGoalStack -================== -*/ -int BotPushOntoActivateGoalStack(bot_state_t *bs, bot_activategoal_t *activategoal) { - int i, best; - float besttime; - - best = -1; - besttime = FloatTime() + 9999; - // - for (i = 0; i < MAX_ACTIVATESTACK; i++) { - if (!bs->activategoalheap[i].inuse) { - if (bs->activategoalheap[i].justused_time < besttime) { - besttime = bs->activategoalheap[i].justused_time; - best = i; - } - } - } - if (best != -1) { - memcpy(&bs->activategoalheap[best], activategoal, sizeof(bot_activategoal_t)); - bs->activategoalheap[best].inuse = qtrue; - bs->activategoalheap[best].next = bs->activatestack; - bs->activatestack = &bs->activategoalheap[best]; - return qtrue; - } - return qfalse; -} - -/* -================== -BotClearActivateGoalStack -================== -*/ -void BotClearActivateGoalStack(bot_state_t *bs) { - while(bs->activatestack) - BotPopFromActivateGoalStack(bs); -} - -/* -================== -BotEnableActivateGoalAreas -================== -*/ -void BotEnableActivateGoalAreas(bot_activategoal_t *activategoal, int enable) { - int i; - - if (activategoal->areasdisabled == !enable) - return; - for (i = 0; i < activategoal->numareas; i++) - trap_AAS_EnableRoutingArea( activategoal->areas[i], enable ); - activategoal->areasdisabled = !enable; -} - -/* -================== -BotIsGoingToActivateEntity -================== -*/ -int BotIsGoingToActivateEntity(bot_state_t *bs, int entitynum) { - bot_activategoal_t *a; - int i; - - for (a = bs->activatestack; a; a = a->next) { - if (a->time < FloatTime()) - continue; - if (a->goal.entitynum == entitynum) - return qtrue; - } - for (i = 0; i < MAX_ACTIVATESTACK; i++) { - if (bs->activategoalheap[i].inuse) - continue; - // - if (bs->activategoalheap[i].goal.entitynum == entitynum) { - // if the bot went for this goal less than 2 seconds ago - if (bs->activategoalheap[i].justused_time > FloatTime() - 2) - return qtrue; - } - } - return qfalse; -} - -/* -================== -BotGetActivateGoal - - returns the number of the bsp entity to activate - goal->entitynum will be set to the game entity to activate -================== -*/ -//#define OBSTACLEDEBUG - -int BotGetActivateGoal(bot_state_t *bs, int entitynum, bot_activategoal_t *activategoal) { - int i, ent, cur_entities[10], spawnflags, modelindex, areas[MAX_ACTIVATEAREAS*2], numareas, t; - char model[MAX_INFO_STRING], tmpmodel[128]; - char target[128], classname[128]; - float health; - char targetname[10][128]; - aas_entityinfo_t entinfo; - aas_areainfo_t areainfo; - vec3_t origin, angles, absmins, absmaxs; - - memset(activategoal, 0, sizeof(bot_activategoal_t)); - BotEntityInfo(entitynum, &entinfo); - Com_sprintf(model, sizeof( model ), "*%d", entinfo.modelindex); - for (ent = trap_AAS_NextBSPEntity(0); ent; ent = trap_AAS_NextBSPEntity(ent)) { - if (!trap_AAS_ValueForBSPEpairKey(ent, "model", tmpmodel, sizeof(tmpmodel))) continue; - if (!strcmp(model, tmpmodel)) break; - } - if (!ent) { - BotAI_Print(PRT_ERROR, "BotGetActivateGoal: no entity found with model %s\n", model); - return 0; - } - trap_AAS_ValueForBSPEpairKey(ent, "classname", classname, sizeof(classname)); - if (!*classname) { - BotAI_Print(PRT_ERROR, "BotGetActivateGoal: entity with model %s has no classname\n", model); - return 0; - } - //if it is a door - if (!strcmp(classname, "func_door")) { - if (trap_AAS_FloatForBSPEpairKey(ent, "health", &health)) { - //if the door has health then the door must be shot to open - if (health) { - BotFuncDoorActivateGoal(bs, ent, activategoal); - return ent; - } - } - // - trap_AAS_IntForBSPEpairKey(ent, "spawnflags", &spawnflags); - // if the door starts open then just wait for the door to return - if ( spawnflags & 1 ) - return 0; - //get the door origin - if (!trap_AAS_VectorForBSPEpairKey(ent, "origin", origin)) { - VectorClear(origin); - } - //if the door is open or opening already - if (!VectorCompare(origin, entinfo.origin)) - return 0; - // store all the areas the door is in - trap_AAS_ValueForBSPEpairKey(ent, "model", model, sizeof(model)); - if (*model) { - modelindex = atoi(model+1); - if (modelindex) { - VectorClear(angles); - BotModelMinsMaxs(modelindex, ET_MOVER, 0, absmins, absmaxs); - // - numareas = trap_AAS_BBoxAreas(absmins, absmaxs, areas, MAX_ACTIVATEAREAS*2); - // store the areas with reachabilities first - for (i = 0; i < numareas; i++) { - if (activategoal->numareas >= MAX_ACTIVATEAREAS) - break; - if ( !trap_AAS_AreaReachability(areas[i]) ) { - continue; - } - trap_AAS_AreaInfo(areas[i], &areainfo); - if (areainfo.contents & AREACONTENTS_MOVER) { - activategoal->areas[activategoal->numareas++] = areas[i]; - } - } - // store any remaining areas - for (i = 0; i < numareas; i++) { - if (activategoal->numareas >= MAX_ACTIVATEAREAS) - break; - if ( trap_AAS_AreaReachability(areas[i]) ) { - continue; - } - trap_AAS_AreaInfo(areas[i], &areainfo); - if (areainfo.contents & AREACONTENTS_MOVER) { - activategoal->areas[activategoal->numareas++] = areas[i]; - } - } - } - } - } - // if the bot is blocked by or standing on top of a button - if (!strcmp(classname, "func_button")) { - return 0; - } - // get the targetname so we can find an entity with a matching target - if (!trap_AAS_ValueForBSPEpairKey(ent, "targetname", targetname[0], sizeof(targetname[0]))) { - if (bot_developer.integer) { - BotAI_Print(PRT_ERROR, "BotGetActivateGoal: entity with model \"%s\" has no targetname\n", model); - } - return 0; - } - // allow tree-like activation - cur_entities[0] = trap_AAS_NextBSPEntity(0); - for (i = 0; i >= 0 && i < 10;) { - for (ent = cur_entities[i]; ent; ent = trap_AAS_NextBSPEntity(ent)) { - if (!trap_AAS_ValueForBSPEpairKey(ent, "target", target, sizeof(target))) continue; - if (!strcmp(targetname[i], target)) { - cur_entities[i] = trap_AAS_NextBSPEntity(ent); - break; - } - } - if (!ent) { - if (bot_developer.integer) { - BotAI_Print(PRT_ERROR, "BotGetActivateGoal: no entity with target \"%s\"\n", targetname[i]); - } - i--; - continue; - } - if (!trap_AAS_ValueForBSPEpairKey(ent, "classname", classname, sizeof(classname))) { - if (bot_developer.integer) { - BotAI_Print(PRT_ERROR, "BotGetActivateGoal: entity with target \"%s\" has no classname\n", targetname[i]); - } - continue; - } - // BSP button model - if (!strcmp(classname, "func_button")) { - // - if (!BotFuncButtonActivateGoal(bs, ent, activategoal)) - continue; - // if the bot tries to activate this button already - if ( bs->activatestack && bs->activatestack->inuse && - bs->activatestack->goal.entitynum == activategoal->goal.entitynum && - bs->activatestack->time > FloatTime() && - bs->activatestack->start_time < FloatTime() - 2) - continue; - // if the bot is in a reachability area - if ( trap_AAS_AreaReachability(bs->areanum) ) { - // disable all areas the blocking entity is in - BotEnableActivateGoalAreas( activategoal, qfalse ); - // - t = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, activategoal->goal.areanum, bs->tfl); - // if the button is not reachable - if (!t) { - continue; - } - activategoal->time = FloatTime() + t * 0.01 + 5; - } - return ent; - } - // invisible trigger multiple box - else if (!strcmp(classname, "trigger_multiple")) { - // - if (!BotTriggerMultipleActivateGoal(bs, ent, activategoal)) - continue; - // if the bot tries to activate this trigger already - if ( bs->activatestack && bs->activatestack->inuse && - bs->activatestack->goal.entitynum == activategoal->goal.entitynum && - bs->activatestack->time > FloatTime() && - bs->activatestack->start_time < FloatTime() - 2) - continue; - // if the bot is in a reachability area - if ( trap_AAS_AreaReachability(bs->areanum) ) { - // disable all areas the blocking entity is in - BotEnableActivateGoalAreas( activategoal, qfalse ); - // - t = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, activategoal->goal.areanum, bs->tfl); - // if the trigger is not reachable - if (!t) { - continue; - } - activategoal->time = FloatTime() + t * 0.01 + 5; - } - return ent; - } - else if (!strcmp(classname, "func_timer")) { - // just skip the func_timer - continue; - } - // the actual button or trigger might be linked through a target_relay or target_delay - else if (!strcmp(classname, "target_relay") || !strcmp(classname, "target_delay")) { - if (trap_AAS_ValueForBSPEpairKey(ent, "targetname", targetname[i+1], sizeof(targetname[0]))) { - i++; - cur_entities[i] = trap_AAS_NextBSPEntity(0); - } - } - } -#ifdef OBSTACLEDEBUG - BotAI_Print(PRT_ERROR, "BotGetActivateGoal: no valid activator for entity with target \"%s\"\n", targetname[0]); -#endif - return 0; -} - -/* -================== -BotGoForActivateGoal -================== -*/ -int BotGoForActivateGoal(bot_state_t *bs, bot_activategoal_t *activategoal) { - aas_entityinfo_t activateinfo; - - activategoal->inuse = qtrue; - if (!activategoal->time) - activategoal->time = FloatTime() + 10; - activategoal->start_time = FloatTime(); - BotEntityInfo(activategoal->goal.entitynum, &activateinfo); - VectorCopy(activateinfo.origin, activategoal->origin); - // - if (BotPushOntoActivateGoalStack(bs, activategoal)) { - // enter the activate entity AI node - AIEnter_Seek_ActivateEntity(bs, "BotGoForActivateGoal"); - return qtrue; - } - else { - // enable any routing areas that were disabled - BotEnableActivateGoalAreas(activategoal, qtrue); - return qfalse; - } -} - -/* -================== -BotPrintActivateGoalInfo -================== -*/ -void BotPrintActivateGoalInfo(bot_state_t *bs, bot_activategoal_t *activategoal, int bspent) { - char netname[MAX_NETNAME]; - char classname[128]; - char buf[128]; - - ClientName(bs->client, netname, sizeof(netname)); - trap_AAS_ValueForBSPEpairKey(bspent, "classname", classname, sizeof(classname)); - if (activategoal->shoot) { - Com_sprintf(buf, sizeof(buf), "%s: I have to shoot at a %s from %1.1f %1.1f %1.1f in area %d\n", - netname, classname, - activategoal->goal.origin[0], - activategoal->goal.origin[1], - activategoal->goal.origin[2], - activategoal->goal.areanum); - } - else { - Com_sprintf(buf, sizeof(buf), "%s: I have to activate a %s at %1.1f %1.1f %1.1f in area %d\n", - netname, classname, - activategoal->goal.origin[0], - activategoal->goal.origin[1], - activategoal->goal.origin[2], - activategoal->goal.areanum); - } - trap_EA_Say(bs->client, buf); -} - -/* -================== -BotRandomMove -================== -*/ -void BotRandomMove(bot_state_t *bs, bot_moveresult_t *moveresult) { - vec3_t dir, angles; - - angles[0] = 0; - angles[1] = random() * 360; - angles[2] = 0; - AngleVectors(angles, dir, NULL, NULL); - - trap_BotMoveInDirection(bs->ms, dir, 400, MOVE_WALK); - - moveresult->failure = qfalse; - VectorCopy(dir, moveresult->movedir); + VectorClear(mins); + VectorClear(maxs); } /* ================== BotAIBlocked -Very basic handling of bots being blocked by other entities. -Check what kind of entity is blocking the bot and try to activate -it. If that's not an option then try to walk around or over the entity. -Before the bot ends in this part of the AI it should predict which doors to -open, which buttons to activate etc. +very basic handling of bots being blocked by other entities +check what kind of entity is blocking the bot and try to activate +it otherwise try to walk around the entity +before the bot ends in this part of the AI it should predict which doors to open, +which buttons to activate etc. ================== */ void BotAIBlocked(bot_state_t *bs, bot_moveresult_t *moveresult, int activate) { - int movetype, bspent; - vec3_t hordir, sideward, angles, up = {0, 0, 1}; - //vec3_t start, end, mins, maxs; + int movetype, ent, i, areas[10], numareas, modelindex; + char classname[128], model[128]; + float lip, dist, health, angle; + vec3_t hordir, size, start, end, mins, maxs, sideward, angles; + vec3_t movedir, origin, goalorigin, bboxmins, bboxmaxs; + vec3_t up = {0, 0, 1}, extramins = {1, 1, 1}, extramaxs = {-1, -1, -1}; aas_entityinfo_t entinfo; - bot_activategoal_t activategoal; + //bsp_trace_t bsptrace; +#ifdef OBSTACLEDEBUG + char netname[MAX_NETNAME]; + char buf[128]; +#endif - // if the bot is not blocked by anything if (!moveresult->blocked) { - bs->notblocked_time = FloatTime(); + bs->notblocked_time = trap_AAS_Time(); return; } - // if stuck in a solid area - if ( moveresult->type == RESULTTYPE_INSOLIDAREA ) { - // move in a random direction in the hope to get out - BotRandomMove(bs, moveresult); - // - return; - } - // get info for the entity that is blocking the bot + // BotEntityInfo(moveresult->blockentity, &entinfo); #ifdef OBSTACLEDEBUG ClientName(bs->client, netname, sizeof(netname)); BotAI_Print(PRT_MESSAGE, "%s: I'm blocked by model %d\n", netname, entinfo.modelindex); -#endif // OBSTACLEDEBUG - // if blocked by a bsp model and the bot wants to activate it - if (activate && entinfo.modelindex > 0 && entinfo.modelindex <= max_bspmodelindex) { - // find the bsp entity which should be activated in order to get the blocking entity out of the way - bspent = BotGetActivateGoal(bs, entinfo.number, &activategoal); - if (bspent) { - // - if (bs->activatestack && !bs->activatestack->inuse) - bs->activatestack = NULL; - // if not already trying to activate this entity - if (!BotIsGoingToActivateEntity(bs, activategoal.goal.entitynum)) { - // - BotGoForActivateGoal(bs, &activategoal); - } - // if ontop of an obstacle or - // if the bot is not in a reachability area it'll still - // need some dynamic obstacle avoidance, otherwise return - if (!(moveresult->flags & MOVERESULT_ONTOPOFOBSTACLE) && - trap_AAS_AreaReachability(bs->areanum)) - return; +#endif + //if blocked by a bsp model and the bot wants to activate it if possible + if (entinfo.modelindex > 0 && entinfo.modelindex <= max_bspmodelindex && activate) { + //find the bsp entity which should be activated in order to remove + //the blocking entity + ent = BotEntityToActivate(entinfo.number); + if (!ent) { + strcpy(classname, ""); +#ifdef OBSTACLEDEBUG + BotAI_Print(PRT_MESSAGE, "%s: can't find activator for blocking entity\n", ClientName(bs->client, netname, sizeof(netname))); +#endif } else { - // enable any routing areas that were disabled - BotEnableActivateGoalAreas(&activategoal, qtrue); + trap_AAS_ValueForBSPEpairKey(ent, "classname", classname, sizeof(classname)); +#ifdef OBSTACLEDEBUG + ClientName(bs->client, netname, sizeof(netname)); + BotAI_Print(PRT_MESSAGE, "%s: I should activate %s\n", netname, classname); +#endif + } + if (!strcmp(classname, "func_button")) { + //create a bot goal towards the button + trap_AAS_ValueForBSPEpairKey(ent, "model", model, sizeof(model)); + modelindex = atoi(model+1); + //if the model is not loaded + if (!modelindex) return; + VectorClear(angles); + BotModelMinsMaxs(modelindex, ET_MOVER, mins, maxs); + //get the lip of the button + trap_AAS_FloatForBSPEpairKey(ent, "lip", &lip); + if (!lip) lip = 4; + //get the move direction from the angle + trap_AAS_FloatForBSPEpairKey(ent, "angle", &angle); + VectorSet(angles, 0, angle, 0); + BotSetMovedir(angles, movedir); + //button size + VectorSubtract(maxs, mins, size); + //button origin + VectorAdd(mins, maxs, origin); + VectorScale(origin, 0.5, origin); + //touch distance of the button + dist = fabs(movedir[0]) * size[0] + fabs(movedir[1]) * size[1] + fabs(movedir[2]) * size[2]; + dist *= 0.5; + // + trap_AAS_FloatForBSPEpairKey(ent, "health", &health); + //if the button is shootable + if (health) { + //FIXME: walk to a point where the button is visible and shoot at the button + //calculate the goal origin + VectorMA(origin, -dist, movedir, goalorigin); + // + VectorSubtract(goalorigin, bs->origin, movedir); + vectoangles(movedir, moveresult->ideal_viewangles); + moveresult->flags |= MOVERESULT_MOVEMENTVIEW; + moveresult->flags |= MOVERESULT_MOVEMENTWEAPON; + //select the machinegun and shoot + trap_EA_SelectWeapon(bs->client, WEAPONINDEX_PHASER); + if (bs->cur_ps.weapon == WEAPONINDEX_PHASER) { + trap_EA_Attack(bs->client); + } + return; + } + else { + //add bounding box size to the dist + trap_AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, bboxmins, bboxmaxs); + for (i = 0; i < 3; i++) { + if (movedir[i] < 0) dist += fabs(movedir[i]) * fabs(bboxmaxs[i]); + else dist += fabs(movedir[i]) * fabs(bboxmins[i]); + } + //calculate the goal origin + VectorMA(origin, -dist, movedir, goalorigin); + // + VectorCopy(goalorigin, start); + start[2] += 24; + VectorCopy(start, end); + end[2] -= 100; + numareas = trap_AAS_TraceAreas(start, end, areas, NULL, 10); + // + for (i = 0; i < numareas; i++) { + if (trap_AAS_AreaReachability(areas[i])) { + break; + } + } + if (i < numareas) { + // +#ifdef OBSTACLEDEBUG + if (bs->activatemessage_time < trap_AAS_Time()) { + Com_sprintf(buf, sizeof(buf), "I have to activate a button at %1.1f %1.1f %1.1f in area %d\n", + goalorigin[0], goalorigin[1], goalorigin[2], areas[i]); + trap_EA_Say(bs->client, buf); + bs->activatemessage_time = trap_AAS_Time() + 5; + } +#endif //OBSTACLEDEBUG + // + VectorCopy(origin, bs->activategoal.origin); + bs->activategoal.areanum = areas[i]; + VectorSubtract(mins, origin, bs->activategoal.mins); + VectorSubtract(maxs, origin, bs->activategoal.maxs); + // + for (i = 0; i < 3; i++) + { + if (movedir[i] < 0) bs->activategoal.maxs[i] += fabs(movedir[i]) * fabs(extramaxs[i]); + else bs->activategoal.mins[i] += fabs(movedir[i]) * fabs(extramins[i]); + } //end for + // + bs->activategoal.entitynum = entinfo.number; + bs->activategoal.number = 0; + bs->activategoal.flags = 0; + bs->activate_time = trap_AAS_Time() + 10; + AIEnter_Seek_ActivateEntity(bs); + return; + } + else { +#ifdef OBSTACLEDEBUG + if (!numareas) BotAI_Print(PRT_MESSAGE, "button not in an area\n"); + else BotAI_Print(PRT_MESSAGE, "button area has no reachabilities\n"); +#endif //OBSTACLEDEBUG + if (bs->ainode == AINode_Seek_NBG) bs->nbg_time = 0; + else if (bs->ainode == AINode_Seek_LTG) bs->ltg_time = 0; + } + } + } + else if (!strcmp(classname, "func_door")) { + //shoot at the shootable door + trap_AAS_ValueForBSPEpairKey(ent, "model", model, sizeof(model)); + modelindex = atoi(model+1); + //if the model is not loaded + if (!modelindex) return; + VectorClear(angles); + BotModelMinsMaxs(modelindex, ET_MOVER, mins, maxs); + //door origin + VectorAdd(mins, maxs, origin); + VectorScale(origin, 0.5, origin); + // + VectorSubtract(origin, bs->eye, movedir); + vectoangles(movedir, moveresult->ideal_viewangles); + moveresult->flags |= MOVERESULT_MOVEMENTVIEW; + moveresult->flags |= MOVERESULT_MOVEMENTWEAPON; + //select the machinegun and shoot + trap_EA_SelectWeapon(bs->client, WEAPONINDEX_PHASER); + if (bs->cur_ps.weapon == WEAPONINDEX_PHASER) { + trap_EA_Attack(bs->client); + } + return; } } - // just some basic dynamic obstacle avoidance code + //just some basic dynamic obstacle avoidance code hordir[0] = moveresult->movedir[0]; hordir[1] = moveresult->movedir[1]; hordir[2] = 0; - // if no direction just take a random direction + //if no direction just take a random direction if (VectorNormalize(hordir) < 0.1) { VectorSet(angles, 0, 360 * random(), 0); AngleVectors(angles, hordir, NULL, NULL); @@ -4495,114 +2410,41 @@ void BotAIBlocked(bot_state_t *bs, bot_moveresult_t *moveresult, int activate) { //if (moveresult->flags & MOVERESULT_ONTOPOFOBSTACLE) movetype = MOVE_JUMP; //else movetype = MOVE_WALK; - // if there's an obstacle at the bot's feet and head then - // the bot might be able to crouch through - //VectorCopy(bs->origin, start); - //start[2] += 18; - //VectorMA(start, 5, hordir, end); - //VectorSet(mins, -16, -16, -24); - //VectorSet(maxs, 16, 16, 4); + //if there's an obstacle at the bot's feet and head then + //the bot might be able to crouch through + VectorCopy(bs->origin, start); + start[2] += 18; + VectorMA(start, 5, hordir, end); + VectorSet(mins, -16, -16, -24); + VectorSet(maxs, 16, 16, 4); // //bsptrace = AAS_Trace(start, mins, maxs, end, bs->entitynum, MASK_PLAYERSOLID); //if (bsptrace.fraction >= 1) movetype = MOVE_CROUCH; - // get the sideward vector + //get the sideward vector CrossProduct(hordir, up, sideward); // if (bs->flags & BFL_AVOIDRIGHT) VectorNegate(sideward, sideward); - // try to crouch straight forward? + //try to crouch straight forward? if (movetype != MOVE_CROUCH || !trap_BotMoveInDirection(bs->ms, hordir, 400, movetype)) { - // perform the movement + //perform the movement if (!trap_BotMoveInDirection(bs->ms, sideward, 400, movetype)) { - // flip the avoid direction flag + //flip the avoid direction flag bs->flags ^= BFL_AVOIDRIGHT; - // flip the direction - // VectorNegate(sideward, sideward); - VectorMA(sideward, -1, hordir, sideward); - // move in the other direction + //flip the direction + VectorNegate(sideward, sideward); + //move in the other direction trap_BotMoveInDirection(bs->ms, sideward, 400, movetype); } } // - if (bs->notblocked_time < FloatTime() - 0.4) { - // just reset goals and hope the bot will go into another direction? - // is this still needed?? + if (bs->notblocked_time < trap_AAS_Time() - 0.4) { + //just reset goals and hope the bot will go into another direction + //is this still needed?? if (bs->ainode == AINode_Seek_NBG) bs->nbg_time = 0; else if (bs->ainode == AINode_Seek_LTG) bs->ltg_time = 0; } } -/* -================== -BotAIPredictObstacles - -Predict the route towards the goal and check if the bot -will be blocked by certain obstacles. When the bot has obstacles -on its path the bot should figure out if they can be removed -by activating certain entities. -================== -*/ -int BotAIPredictObstacles(bot_state_t *bs, bot_goal_t *goal) { - int modelnum, entitynum, bspent; - bot_activategoal_t activategoal; - aas_predictroute_t route; - - if (!bot_predictobstacles.integer) - return qfalse; - - // always predict when the goal change or at regular intervals - if (bs->predictobstacles_goalareanum == goal->areanum && - bs->predictobstacles_time > FloatTime() - 6) { - return qfalse; - } - bs->predictobstacles_goalareanum = goal->areanum; - bs->predictobstacles_time = FloatTime(); - - // predict at most 100 areas or 10 seconds ahead - trap_AAS_PredictRoute(&route, bs->areanum, bs->origin, - goal->areanum, bs->tfl, 100, 1000, - RSE_USETRAVELTYPE|RSE_ENTERCONTENTS, - AREACONTENTS_MOVER, TFL_BRIDGE, 0); - // if bot has to travel through an area with a mover - if (route.stopevent & RSE_ENTERCONTENTS) { - // if the bot will run into a mover - if (route.endcontents & AREACONTENTS_MOVER) { - //NOTE: this only works with bspc 2.1 or higher - modelnum = (route.endcontents & AREACONTENTS_MODELNUM) >> AREACONTENTS_MODELNUMSHIFT; - if (modelnum) { - // - entitynum = BotModelMinsMaxs(modelnum, ET_MOVER, 0, NULL, NULL); - if (entitynum) { - //NOTE: BotGetActivateGoal already checks if the door is open or not - bspent = BotGetActivateGoal(bs, entitynum, &activategoal); - if (bspent) { - // - if (bs->activatestack && !bs->activatestack->inuse) - bs->activatestack = NULL; - // if not already trying to activate this entity - if (!BotIsGoingToActivateEntity(bs, activategoal.goal.entitynum)) { - // - //BotAI_Print(PRT_MESSAGE, "blocked by mover model %d, entity %d ?\n", modelnum, entitynum); - // - BotGoForActivateGoal(bs, &activategoal); - return qtrue; - } - else { - // enable any routing areas that were disabled - BotEnableActivateGoalAreas(&activategoal, qtrue); - } - } - } - } - } - } - else if (route.stopevent & RSE_USETRAVELTYPE) { - if (route.endtravelflags & TFL_BRIDGE) { - //FIXME: check if the bridge is available to travel over - } - } - return qfalse; -} - /* ================== BotCheckConsoleMessages @@ -4622,7 +2464,7 @@ void BotCheckConsoleMessages(bot_state_t *bs) { //if the chat state is flooded with messages the bot will read them quickly if (trap_BotNumConsoleMessages(bs->cs) < 10) { //if it is a chat message the bot needs some time to read it - if (m.type == CMS_CHAT && m.time > FloatTime() - (1 + random())) break; + if (m.type == CMS_CHAT && m.time > trap_AAS_Time() - (1 + random())) break; } // ptr = m.message; @@ -4637,7 +2479,9 @@ void BotCheckConsoleMessages(bot_state_t *bs) { //unify the white spaces in the message trap_UnifyWhiteSpaces(ptr); //replace synonyms in the right context - context = BotSynonymContext(bs); + context = CONTEXT_NORMAL|CONTEXT_NEARBYITEM|CONTEXT_NAMES; + if (BotCTFTeam(bs) == CTF_TEAM_RED) context |= CONTEXT_CTFREDTEAM; + else context |= CONTEXT_CTFBLUETEAM; trap_BotReplaceSynonyms(ptr, context); //if there's no match if (!BotMatchMessage(bs, m.message)) { @@ -4657,7 +2501,7 @@ void BotCheckConsoleMessages(bot_state_t *bs) { trap_BotMatchVariable(&match, NETNAME, netname, sizeof(netname)); trap_BotMatchVariable(&match, MESSAGE, message, sizeof(message)); //if this is a message from the bot self - if (bs->client == ClientFromName(netname)) { + if (!Q_stricmp(netname, botname)) { trap_BotRemoveConsoleMessage(bs->cs, handle); continue; } @@ -4680,9 +2524,9 @@ void BotCheckConsoleMessages(bot_state_t *bs) { BotAI_Print(PRT_MESSAGE, "**** no valid reply ****\n"); } } - //if at a valid chat position and not chatting already and not in teamplay - else if (bs->ainode != AINode_Stand && BotValidChatPosition(bs) && !TeamPlayIsOn()) { - chat_reply = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_REPLY, 0, 1); + //if at a valid chat position and not chatting already + else if (bs->ainode != AINode_Stand && BotValidChatPosition(bs)) { + chat_reply = 0; if (random() < 1.5 / (NumBots()+1) && random() < chat_reply) { //if bot replies with a chat message if (trap_BotReplyChat(bs->cs, message, context, CONTEXT_REPLY, @@ -4692,8 +2536,8 @@ void BotCheckConsoleMessages(bot_state_t *bs) { botname, netname)) { //remove the console message trap_BotRemoveConsoleMessage(bs->cs, handle); - bs->stand_time = FloatTime() + BotChatTime(bs); - AIEnter_Stand(bs, "BotCheckConsoleMessages: reply chat"); + bs->stand_time = trap_AAS_Time() + BotChatTime(bs); + AIEnter_Stand(bs); //EA_Say(bs->client, bs->cs.chatmessage); break; } @@ -4706,64 +2550,6 @@ void BotCheckConsoleMessages(bot_state_t *bs) { } } -/* -================== -BotCheckEvents -================== -*/ -void BotCheckForGrenades(bot_state_t *bs, entityState_t *state) { - // if this is not a grenade - if (state->eType != ET_MISSILE || state->weapon != WP_GRENADE_LAUNCHER) - return; - // try to avoid the grenade - trap_BotAddAvoidSpot(bs->ms, state->pos.trBase, 160, AVOID_ALWAYS); -} - -#ifdef MISSIONPACK -/* -================== -BotCheckForProxMines -================== -*/ -void BotCheckForProxMines(bot_state_t *bs, entityState_t *state) { - // if this is not a prox mine - if (state->eType != ET_MISSILE || state->weapon != WP_PROX_LAUNCHER) - return; - // if this prox mine is from someone on our own team - if (state->generic1 == BotTeam(bs)) - return; - // if the bot doesn't have a weapon to deactivate the mine - if (!(bs->inventory[INVENTORY_PLASMAGUN] > 0 && bs->inventory[INVENTORY_CELLS] > 0) && - !(bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 && bs->inventory[INVENTORY_ROCKETS] > 0) && - !(bs->inventory[INVENTORY_BFG10K] > 0 && bs->inventory[INVENTORY_BFGAMMO] > 0) ) { - return; - } - // try to avoid the prox mine - trap_BotAddAvoidSpot(bs->ms, state->pos.trBase, 160, AVOID_ALWAYS); - // - if (bs->numproxmines >= MAX_PROXMINES) - return; - bs->proxmines[bs->numproxmines] = state->number; - bs->numproxmines++; -} - -/* -================== -BotCheckForKamikazeBody -================== -*/ -void BotCheckForKamikazeBody(bot_state_t *bs, entityState_t *state) { - // if this entity is not wearing the kamikaze - if (!(state->eFlags & EF_KAMIKAZE)) - return; - // if this entity isn't dead - if (!(state->eFlags & EF_DEAD)) - return; - //remember this kamikaze body - bs->kamikazebody = state->number; -} -#endif - /* ================== BotCheckEvents @@ -4772,10 +2558,7 @@ BotCheckEvents void BotCheckEvents(bot_state_t *bs, entityState_t *state) { int event; char buf[128]; -#ifdef MISSIONPACK - aas_entityinfo_t entinfo; -#endif - + // //NOTE: this sucks, we're accessing the gentity_t directly //but there's no other fast way to do it right now if (bs->entityeventTime[state->number] == g_entities[state->number].eventTime) { @@ -4804,9 +2587,7 @@ void BotCheckEvents(bot_state_t *bs, entityState_t *state) { bs->botdeathtype = mod; bs->lastkilledby = attacker; // - if (target == attacker || - target == ENTITYNUM_NONE || - target == ENTITYNUM_WORLD) bs->botsuicide = qtrue; + if (target == attacker) bs->botsuicide = qtrue; else bs->botsuicide = qfalse; // bs->num_deaths++; @@ -4815,134 +2596,63 @@ void BotCheckEvents(bot_state_t *bs, entityState_t *state) { else if (attacker == bs->client) { bs->enemydeathtype = mod; bs->lastkilledplayer = target; - bs->killedenemy_time = FloatTime(); + bs->killedenemy_time = trap_AAS_Time(); // bs->num_kills++; } else if (attacker == bs->enemy && target == attacker) { bs->enemysuicide = qtrue; } - // -#ifdef MISSIONPACK - if (gametype == GT_1FCTF) { - // - BotEntityInfo(target, &entinfo); - if ( entinfo.powerups & ( 1 << PW_NEUTRALFLAG ) ) { - if (!BotSameTeam(bs, target)) { - bs->neutralflagstatus = 3; //enemy dropped the flag - bs->flagstatuschanged = qtrue; - } - } - } -#endif break; } + case EV_GLOBAL_SOUND: { if (state->eventParm < 0 || state->eventParm > MAX_SOUNDS) { BotAI_Print(PRT_ERROR, "EV_GLOBAL_SOUND: eventParm (%d) out of range\n", state->eventParm); break; } - trap_GetConfigstring(CS_SOUNDS + state->eventParm, buf, sizeof(buf)); - /* - if (!strcmp(buf, "sound/teamplay/flagret_red.wav")) { - //red flag is returned - bs->redflagstatus = 0; - bs->flagstatuschanged = qtrue; - } - else if (!strcmp(buf, "sound/teamplay/flagret_blu.wav")) { - //blue flag is returned - bs->blueflagstatus = 0; - bs->flagstatuschanged = qtrue; - } - else*/ -#ifdef MISSIONPACK - if (!strcmp(buf, "sound/items/kamikazerespawn.wav" )) { - //the kamikaze respawned so dont avoid it - BotDontAvoid(bs, "Kamikaze"); - } - else -#endif + else { + trap_GetConfigstring(CS_SOUNDS + state->eventParm, buf, sizeof(buf)); if (!strcmp(buf, "sound/items/poweruprespawn.wav")) { - //powerup respawned... go get it - BotGoForPowerups(bs); + //powerup respawned... go get it + BotGoForPowerups(bs); + } } break; } - case EV_GLOBAL_TEAM_SOUND: + + case EV_TEAM_SOUND: { - if (gametype == GT_CTF) { - switch(state->eventParm) { - case GTS_RED_CAPTURE: - bs->blueflagstatus = 0; - bs->redflagstatus = 0; - bs->flagstatuschanged = qtrue; - break; //see BotMatch_CTF - case GTS_BLUE_CAPTURE: - bs->blueflagstatus = 0; - bs->redflagstatus = 0; - bs->flagstatuschanged = qtrue; - break; //see BotMatch_CTF - case GTS_RED_RETURN: - //blue flag is returned - bs->blueflagstatus = 0; - bs->flagstatuschanged = qtrue; - break; - case GTS_BLUE_RETURN: - //red flag is returned - bs->redflagstatus = 0; - bs->flagstatuschanged = qtrue; - break; - case GTS_RED_TAKEN: - //blue flag is taken - bs->blueflagstatus = 1; - bs->flagstatuschanged = qtrue; - break; //see BotMatch_CTF - case GTS_BLUE_TAKEN: - //red flag is taken - bs->redflagstatus = 1; - bs->flagstatuschanged = qtrue; - break; //see BotMatch_CTF + if (state->eventParm < 0 || state->eventParm > MAX_TEAM_SOUNDS) { + BotAI_Print(PRT_ERROR, "EV_TEAM_SOUND: eventParm (%d) out of range\n", state->eventParm); + break; + } + + if (state->eventParm == RETURN_FLAG_SOUND) + { + if (state->otherEntityNum == TEAM_RED) + { + //red flag is returned + bs->redflagstatus = 0; + bs->flagstatuschanged = qtrue; + } + else + { + //blue flag is returned + bs->blueflagstatus = 0; + bs->flagstatuschanged = qtrue; } } -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF) { - switch(state->eventParm) { - case GTS_RED_CAPTURE: - bs->neutralflagstatus = 0; - bs->flagstatuschanged = qtrue; - break; - case GTS_BLUE_CAPTURE: - bs->neutralflagstatus = 0; - bs->flagstatuschanged = qtrue; - break; - case GTS_RED_RETURN: - //flag has returned - bs->neutralflagstatus = 0; - bs->flagstatuschanged = qtrue; - break; - case GTS_BLUE_RETURN: - //flag has returned - bs->neutralflagstatus = 0; - bs->flagstatuschanged = qtrue; - break; - case GTS_RED_TAKEN: - bs->neutralflagstatus = BotTeam(bs) == TEAM_RED ? 2 : 1; //FIXME: check Team_TakeFlagSound in g_team.c - bs->flagstatuschanged = qtrue; - break; - case GTS_BLUE_TAKEN: - bs->neutralflagstatus = BotTeam(bs) == TEAM_BLUE ? 2 : 1; //FIXME: check Team_TakeFlagSound in g_team.c - bs->flagstatuschanged = qtrue; - break; - } - } -#endif break; } + + + case EV_PLAYER_TELEPORT_IN: { VectorCopy(state->origin, lastteleport_origin); - lastteleport_time = FloatTime(); + lastteleport_time = trap_AAS_Time(); break; } case EV_GENERAL_SOUND: @@ -4958,7 +2668,7 @@ void BotCheckEvents(bot_state_t *bs, entityState_t *state) { //if falling into a death pit if (!strcmp(buf, "*falling1.wav")) { //if the bot has a personal teleporter - if (bs->inventory[INVENTORY_TELEPORTER] > 0) { + if (bs->inventory[INVENTORY_TRANSPORTER] > 0) { //use the holdable item trap_EA_Use(bs->client); } @@ -4966,48 +2676,6 @@ void BotCheckEvents(bot_state_t *bs, entityState_t *state) { } break; } - case EV_FOOTSTEP: - case EV_FOOTSTEP_METAL: - case EV_FOOTSPLASH: - case EV_FOOTWADE: - case EV_SWIM: - case EV_FALL_SHORT: - case EV_FALL_MEDIUM: - case EV_FALL_FAR: - case EV_STEP_4: - case EV_STEP_8: - case EV_STEP_12: - case EV_STEP_16: - case EV_JUMP_PAD: - case EV_JUMP: - case EV_TAUNT: - case EV_WATER_TOUCH: - case EV_WATER_LEAVE: - case EV_WATER_UNDER: - case EV_WATER_CLEAR: - case EV_ITEM_PICKUP: - case EV_GLOBAL_ITEM_PICKUP: - case EV_NOAMMO: - case EV_CHANGE_WEAPON: - case EV_FIRE_WEAPON: - //FIXME: either add to sound queue or mark player as someone making noise - break; - case EV_USE_ITEM0: - case EV_USE_ITEM1: - case EV_USE_ITEM2: - case EV_USE_ITEM3: - case EV_USE_ITEM4: - case EV_USE_ITEM5: - case EV_USE_ITEM6: - case EV_USE_ITEM7: - case EV_USE_ITEM8: - case EV_USE_ITEM9: - case EV_USE_ITEM10: - case EV_USE_ITEM11: - case EV_USE_ITEM12: - case EV_USE_ITEM13: - case EV_USE_ITEM14: - break; } } @@ -5020,26 +2688,11 @@ void BotCheckSnapshot(bot_state_t *bs) { int ent; entityState_t state; - //remove all avoid spots - trap_BotAddAvoidSpot(bs->ms, vec3_origin, 0, AVOID_CLEAR); - //reset kamikaze body - bs->kamikazebody = 0; - //reset number of proxmines - bs->numproxmines = 0; // ent = 0; while( ( ent = BotAI_GetSnapshotEntity( bs->client, ent, &state ) ) != -1 ) { //check the entity state for events BotCheckEvents(bs, &state); - //check for grenades the bot should avoid - BotCheckForGrenades(bs, &state); - // -#ifdef MISSIONPACK - //check for proximity mines which the bot should deactivate - BotCheckForProxMines(bs, &state); - //check for dead bodies with the kamikaze effect which should be gibbed - BotCheckForKamikazeBody(bs, &state); -#endif } //check the player state for events BotAI_GetEntityState(bs->client, &state); @@ -5061,151 +2714,7 @@ void BotCheckAir(bot_state_t *bs) { return; } } - bs->lastair_time = FloatTime(); -} - -/* -================== -BotAlternateRoute -================== -*/ -bot_goal_t *BotAlternateRoute(bot_state_t *bs, bot_goal_t *goal) { - int t; - - // if the bot has an alternative route goal - if (bs->altroutegoal.areanum) { - // - if (bs->reachedaltroutegoal_time) - return goal; - // travel time towards alternative route goal - t = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, bs->altroutegoal.areanum, bs->tfl); - if (t && t < 20) { - //BotAI_Print(PRT_MESSAGE, "reached alternate route goal\n"); - bs->reachedaltroutegoal_time = FloatTime(); - } - memcpy(goal, &bs->altroutegoal, sizeof(bot_goal_t)); - return &bs->altroutegoal; - } - return goal; -} - -/* -================== -BotGetAlternateRouteGoal -================== -*/ -int BotGetAlternateRouteGoal(bot_state_t *bs, int base) { - aas_altroutegoal_t *altroutegoals; - bot_goal_t *goal; - int numaltroutegoals, rnd; - - if (base == TEAM_RED) { - altroutegoals = red_altroutegoals; - numaltroutegoals = red_numaltroutegoals; - } - else { - altroutegoals = blue_altroutegoals; - numaltroutegoals = blue_numaltroutegoals; - } - if (!numaltroutegoals) - return qfalse; - rnd = (float) random() * numaltroutegoals; - if (rnd >= numaltroutegoals) - rnd = numaltroutegoals-1; - goal = &bs->altroutegoal; - goal->areanum = altroutegoals[rnd].areanum; - VectorCopy(altroutegoals[rnd].origin, goal->origin); - VectorSet(goal->mins, -8, -8, -8); - VectorSet(goal->maxs, 8, 8, 8); - goal->entitynum = 0; - goal->iteminfo = 0; - goal->number = 0; - goal->flags = 0; - // - bs->reachedaltroutegoal_time = 0; - return qtrue; -} - -/* -================== -BotSetupAlternateRouteGoals -================== -*/ -void BotSetupAlternativeRouteGoals(void) { - - if (altroutegoals_setup) - return; -#ifdef MISSIONPACK - if (gametype == GT_CTF) { - if (trap_BotGetLevelItemGoal(-1, "Neutral Flag", &ctf_neutralflag) < 0) - BotAI_Print(PRT_WARNING, "No alt routes without Neutral Flag\n"); - if (ctf_neutralflag.areanum) { - // - red_numaltroutegoals = trap_AAS_AlternativeRouteGoals( - ctf_neutralflag.origin, ctf_neutralflag.areanum, - ctf_redflag.origin, ctf_redflag.areanum, TFL_DEFAULT, - red_altroutegoals, MAX_ALTROUTEGOALS, - ALTROUTEGOAL_CLUSTERPORTALS| - ALTROUTEGOAL_VIEWPORTALS); - blue_numaltroutegoals = trap_AAS_AlternativeRouteGoals( - ctf_neutralflag.origin, ctf_neutralflag.areanum, - ctf_blueflag.origin, ctf_blueflag.areanum, TFL_DEFAULT, - blue_altroutegoals, MAX_ALTROUTEGOALS, - ALTROUTEGOAL_CLUSTERPORTALS| - ALTROUTEGOAL_VIEWPORTALS); - } - } - else if (gametype == GT_1FCTF) { - if (trap_BotGetLevelItemGoal(-1, "Neutral Obelisk", &neutralobelisk) < 0) - BotAI_Print(PRT_WARNING, "One Flag CTF without Neutral Obelisk\n"); - red_numaltroutegoals = trap_AAS_AlternativeRouteGoals( - ctf_neutralflag.origin, ctf_neutralflag.areanum, - ctf_redflag.origin, ctf_redflag.areanum, TFL_DEFAULT, - red_altroutegoals, MAX_ALTROUTEGOALS, - ALTROUTEGOAL_CLUSTERPORTALS| - ALTROUTEGOAL_VIEWPORTALS); - blue_numaltroutegoals = trap_AAS_AlternativeRouteGoals( - ctf_neutralflag.origin, ctf_neutralflag.areanum, - ctf_blueflag.origin, ctf_blueflag.areanum, TFL_DEFAULT, - blue_altroutegoals, MAX_ALTROUTEGOALS, - ALTROUTEGOAL_CLUSTERPORTALS| - ALTROUTEGOAL_VIEWPORTALS); - } - else if (gametype == GT_OBELISK) { - if (trap_BotGetLevelItemGoal(-1, "Neutral Obelisk", &neutralobelisk) < 0) - BotAI_Print(PRT_WARNING, "No alt routes without Neutral Obelisk\n"); - // - red_numaltroutegoals = trap_AAS_AlternativeRouteGoals( - neutralobelisk.origin, neutralobelisk.areanum, - redobelisk.origin, redobelisk.areanum, TFL_DEFAULT, - red_altroutegoals, MAX_ALTROUTEGOALS, - ALTROUTEGOAL_CLUSTERPORTALS| - ALTROUTEGOAL_VIEWPORTALS); - blue_numaltroutegoals = trap_AAS_AlternativeRouteGoals( - neutralobelisk.origin, neutralobelisk.areanum, - blueobelisk.origin, blueobelisk.areanum, TFL_DEFAULT, - blue_altroutegoals, MAX_ALTROUTEGOALS, - ALTROUTEGOAL_CLUSTERPORTALS| - ALTROUTEGOAL_VIEWPORTALS); - } - else if (gametype == GT_HARVESTER) { - if (trap_BotGetLevelItemGoal(-1, "Neutral Obelisk", &neutralobelisk) < 0) - BotAI_Print(PRT_WARNING, "Harvester without Neutral Obelisk\n"); - red_numaltroutegoals = trap_AAS_AlternativeRouteGoals( - neutralobelisk.origin, neutralobelisk.areanum, - redobelisk.origin, redobelisk.areanum, TFL_DEFAULT, - red_altroutegoals, MAX_ALTROUTEGOALS, - ALTROUTEGOAL_CLUSTERPORTALS| - ALTROUTEGOAL_VIEWPORTALS); - blue_numaltroutegoals = trap_AAS_AlternativeRouteGoals( - neutralobelisk.origin, neutralobelisk.areanum, - blueobelisk.origin, blueobelisk.areanum, TFL_DEFAULT, - blue_altroutegoals, MAX_ALTROUTEGOALS, - ALTROUTEGOAL_CLUSTERPORTALS| - ALTROUTEGOAL_VIEWPORTALS); - } -#endif - altroutegoals_setup = qtrue; + bs->lastair_time = trap_AAS_Time(); } /* @@ -5229,7 +2738,7 @@ void BotDeathmatchAI(bot_state_t *bs, float thinktime) { Info_SetValueForKey(userinfo, "sex", gender); trap_SetUserinfo(bs->client, userinfo); //set the team - if ( !bs->map_restart && g_gametype.integer != GT_TOURNAMENT ) { + if ( g_gametype.integer != GT_TOURNAMENT ) { Com_sprintf(buf, sizeof(buf), "team %s", bs->settings.team); trap_EA_Command(bs->client, buf); } @@ -5239,30 +2748,25 @@ void BotDeathmatchAI(bot_state_t *bs, float thinktime) { else trap_BotSetChatGender(bs->cs, CHAT_GENDERLESS); //set the chat name ClientName(bs->client, name, sizeof(name)); - trap_BotSetChatName(bs->cs, name, bs->client); + trap_BotSetChatName(bs->cs, name); // bs->lastframe_health = bs->inventory[INVENTORY_HEALTH]; bs->lasthitcount = bs->cur_ps.persistant[PERS_HITS]; // bs->setupcount = 0; - // - BotSetupAlternativeRouteGoals(); } //no ideal view set bs->flags &= ~BFL_IDEALVIEWSET; - // - if (!BotIntermission(bs)) { - //set the teleport time - BotSetTeleportTime(bs); - //update some inventory values - BotUpdateInventory(bs); - //check out the snapshot - BotCheckSnapshot(bs); - //check for air - BotCheckAir(bs); - } + //set the teleport time + BotSetTeleportTime(bs); + //update some inventory values + BotUpdateInventory(bs); //check the console messages BotCheckConsoleMessages(bs); + //check out the snapshot + BotCheckSnapshot(bs); + //check for air + BotCheckAir(bs); //if not in the intermission and not in observer mode if (!BotIntermission(bs) && !BotIsObserver(bs)) { //do team AI @@ -5270,13 +2774,13 @@ void BotDeathmatchAI(bot_state_t *bs, float thinktime) { } //if the bot has no ai node if (!bs->ainode) { - AIEnter_Seek_LTG(bs, "BotDeathmatchAI: no ai node"); + AIEnter_Seek_LTG(bs); } //if the bot entered the game less than 8 seconds ago - if (!bs->entergamechat && bs->entergame_time > FloatTime() - 8) { + if (!bs->entergamechat && bs->entergame_time > trap_AAS_Time() - 8) { if (BotChat_EnterGame(bs)) { - bs->stand_time = FloatTime() + BotChatTime(bs); - AIEnter_Stand(bs, "BotDeathmatchAI: chat enter game"); + bs->stand_time = trap_AAS_Time() + BotChatTime(bs); + AIEnter_Stand(bs); } bs->entergamechat = qtrue; } @@ -5294,101 +2798,13 @@ void BotDeathmatchAI(bot_state_t *bs, float thinktime) { trap_BotDumpAvoidGoals(bs->gs); BotDumpNodeSwitches(bs); ClientName(bs->client, name, sizeof(name)); - BotAI_Print(PRT_ERROR, "%s at %1.1f switched more than %d AI nodes\n", name, FloatTime(), MAX_NODESWITCHES); + BotAI_Print(PRT_ERROR, "%s at %1.1f switched more than %d AI nodes\n", name, trap_AAS_Time(), MAX_NODESWITCHES); } // bs->lastframe_health = bs->inventory[INVENTORY_HEALTH]; bs->lasthitcount = bs->cur_ps.persistant[PERS_HITS]; } -/* -================== -BotSetEntityNumForGoalWithModel -================== -*/ -void BotSetEntityNumForGoalWithModel(bot_goal_t *goal, int eType, char *modelname) { - gentity_t *ent; - int i, modelindex; - vec3_t dir; - - modelindex = G_ModelIndex( modelname ); - ent = &g_entities[0]; - for (i = 0; i < level.num_entities; i++, ent++) { - if ( !ent->inuse ) { - continue; - } - if ( eType && ent->s.eType != eType) { - continue; - } - if (ent->s.modelindex != modelindex) { - continue; - } - VectorSubtract(goal->origin, ent->s.origin, dir); - if (VectorLengthSquared(dir) < Square(10)) { - goal->entitynum = i; - return; - } - } -} - -/* -================== -BotSetEntityNumForGoal -================== -*/ -void BotSetEntityNumForGoal(bot_goal_t *goal, char *classname) { - gentity_t *ent; - int i; - vec3_t dir; - - ent = &g_entities[0]; - for (i = 0; i < level.num_entities; i++, ent++) { - if ( !ent->inuse ) { - continue; - } - if ( !Q_stricmp(ent->classname, classname) ) { - continue; - } - VectorSubtract(goal->origin, ent->s.origin, dir); - if (VectorLengthSquared(dir) < Square(10)) { - goal->entitynum = i; - return; - } - } -} - -/* -================== -BotGoalForBSPEntity -================== -*/ -int BotGoalForBSPEntity( char *classname, bot_goal_t *goal ) { - char value[MAX_INFO_STRING]; - vec3_t origin, start, end; - int ent, numareas, areas[10]; - - memset(goal, 0, sizeof(bot_goal_t)); - for (ent = trap_AAS_NextBSPEntity(0); ent; ent = trap_AAS_NextBSPEntity(ent)) { - if (!trap_AAS_ValueForBSPEpairKey(ent, "classname", value, sizeof(value))) - continue; - if (!strcmp(value, classname)) { - if (!trap_AAS_VectorForBSPEpairKey(ent, "origin", origin)) - return qfalse; - VectorCopy(origin, goal->origin); - VectorCopy(origin, start); - start[2] -= 32; - VectorCopy(origin, end); - end[2] += 32; - numareas = trap_AAS_TraceAreas(start, end, areas, NULL, 10); - if (!numareas) - return qfalse; - goal->areanum = areas[0]; - return qtrue; - } - } - return qfalse; -} - /* ================== BotSetupDeathmatchAI @@ -5407,8 +2823,6 @@ void BotSetupDeathmatchAI(void) { trap_Cvar_Register(&bot_nochat, "bot_nochat", "0", 0); trap_Cvar_Register(&bot_testrchat, "bot_testrchat", "0", 0); trap_Cvar_Register(&bot_challenge, "bot_challenge", "0", 0); - trap_Cvar_Register(&bot_predictobstacles, "bot_predictobstacles", "1", 0); - trap_Cvar_Register(&g_spSkill, "g_spSkill", "2", 0); // if (gametype == GT_CTF) { if (trap_BotGetLevelItemGoal(-1, "Red Flag", &ctf_redflag) < 0) @@ -5416,35 +2830,6 @@ void BotSetupDeathmatchAI(void) { if (trap_BotGetLevelItemGoal(-1, "Blue Flag", &ctf_blueflag) < 0) BotAI_Print(PRT_WARNING, "CTF without Blue Flag\n"); } -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF) { - if (trap_BotGetLevelItemGoal(-1, "Neutral Flag", &ctf_neutralflag) < 0) - BotAI_Print(PRT_WARNING, "One Flag CTF without Neutral Flag\n"); - if (trap_BotGetLevelItemGoal(-1, "Red Flag", &ctf_redflag) < 0) - BotAI_Print(PRT_WARNING, "One Flag CTF without Red Flag\n"); - if (trap_BotGetLevelItemGoal(-1, "Blue Flag", &ctf_blueflag) < 0) - BotAI_Print(PRT_WARNING, "One Flag CTF without Blue Flag\n"); - } - else if (gametype == GT_OBELISK) { - if (trap_BotGetLevelItemGoal(-1, "Red Obelisk", &redobelisk) < 0) - BotAI_Print(PRT_WARNING, "Overload without Red Obelisk\n"); - BotSetEntityNumForGoal(&redobelisk, "team_redobelisk"); - if (trap_BotGetLevelItemGoal(-1, "Blue Obelisk", &blueobelisk) < 0) - BotAI_Print(PRT_WARNING, "Overload without Blue Obelisk\n"); - BotSetEntityNumForGoal(&blueobelisk, "team_blueobelisk"); - } - else if (gametype == GT_HARVESTER) { - if (trap_BotGetLevelItemGoal(-1, "Red Obelisk", &redobelisk) < 0) - BotAI_Print(PRT_WARNING, "Harvester without Red Obelisk\n"); - BotSetEntityNumForGoal(&redobelisk, "team_redobelisk"); - if (trap_BotGetLevelItemGoal(-1, "Blue Obelisk", &blueobelisk) < 0) - BotAI_Print(PRT_WARNING, "Harvester without Blue Obelisk\n"); - BotSetEntityNumForGoal(&blueobelisk, "team_blueobelisk"); - if (trap_BotGetLevelItemGoal(-1, "Neutral Obelisk", &neutralobelisk) < 0) - BotAI_Print(PRT_WARNING, "Harvester without Neutral Obelisk\n"); - BotSetEntityNumForGoal(&neutralobelisk, "team_neutralobelisk"); - } -#endif max_bspmodelindex = 0; for (ent = trap_AAS_NextBSPEntity(0); ent; ent = trap_AAS_NextBSPEntity(ent)) { @@ -5465,5 +2850,5 @@ BotShutdownDeathmatchAI ================== */ void BotShutdownDeathmatchAI(void) { - altroutegoals_setup = qfalse; } + diff --git a/code/game/ai_dmq3.c.orig b/code/game/ai_dmq3.c.orig new file mode 100644 index 0000000..3bc9787 --- /dev/null +++ b/code/game/ai_dmq3.c.orig @@ -0,0 +1,2857 @@ +// Copyright (C) 1999-2000 Id Software, Inc. +// +/***************************************************************************** + * name: ai_dmq3.c + * + * desc: Quake3 bot AI + * + * $Archive: /StarTrek/Code-DM/game/ai_dmq3.c $ + * $Author: Mgummelt $ + * $Revision: 33 $ + * $Modtime: 4/04/01 5:01p $ + * $Date: 4/04/01 5:17p $ + * + *****************************************************************************/ + + +#include "g_local.h" +#include "botlib.h" +#include "be_aas.h" +#include "be_ea.h" +#include "be_ai_char.h" +#include "be_ai_chat.h" +#include "be_ai_gen.h" +#include "be_ai_goal.h" +#include "be_ai_move.h" +#include "be_ai_weap.h" +// +#include "ai_main.h" +#include "ai_dmq3.h" +#include "ai_chat.h" +#include "ai_cmd.h" +#include "ai_dmnet.h" +#include "ai_team.h" +// +#include "chars.h" //characteristics +#include "inv.h" //indexes into the inventory +#include "syn.h" //synonyms +#include "match.h" //string matching types and vars + +#define IDEAL_ATTACKDIST 140 +#define WEAPONINDEX_PHASER 2 + +#define MAX_WAYPOINTS 128 +// +bot_waypoint_t botai_waypoints[MAX_WAYPOINTS]; +bot_waypoint_t *botai_freewaypoints; + +//NOTE: not using a cvars which can be updated because the game should be reloaded anyway +int gametype; //game type +int maxclients; //maximum number of clients + +vmCvar_t bot_grapple; +vmCvar_t bot_rocketjump; +vmCvar_t bot_fastchat; +vmCvar_t bot_nochat; +vmCvar_t bot_testrchat; +vmCvar_t bot_challenge; + +vec3_t lastteleport_origin; //last teleport event origin +float lastteleport_time; //last teleport event time +int max_bspmodelindex; //maximum BSP model index + +//CTF flag goals +bot_goal_t ctf_redflag; +bot_goal_t ctf_blueflag; + +#ifdef CTF +/* +================== +BotCTFCarryingFlag +================== +*/ +int BotCTFCarryingFlag(bot_state_t *bs) { + if (gametype != GT_CTF) return CTF_FLAG_NONE; + + if (bs->inventory[INVENTORY_REDFLAG] > 0) return CTF_FLAG_RED; + else if (bs->inventory[INVENTORY_BLUEFLAG] > 0) return CTF_FLAG_BLUE; + return CTF_FLAG_NONE; +} + +/* +================== +BotCTFTeam +================== +*/ +int BotCTFTeam(bot_state_t *bs) { + char info[1024]; + + if (gametype != GT_CTF) return CTF_TEAM_NONE; + if (bs->client < 0 || bs->client >= MAX_CLIENTS) { + //BotAI_Print(PRT_ERROR, "BotCTFTeam: client out of range\n"); + return qfalse; + } + trap_GetConfigstring(CS_PLAYERS+bs->client, info, sizeof(info)); + // + if (atoi(Info_ValueForKey(info, "t")) == TEAM_RED) return CTF_TEAM_RED; + else if (atoi(Info_ValueForKey(info, "t")) == TEAM_BLUE) return CTF_TEAM_BLUE; + return CTF_TEAM_NONE; +} + +/* +================== +BotCTFRetreatGoals +================== +*/ +void BotCTFRetreatGoals(bot_state_t *bs) { + //when carrying a flag in ctf the bot should rush to the base + if (BotCTFCarryingFlag(bs)) { + //if not already rushing to the base + if (bs->ltgtype != LTG_RUSHBASE) { + bs->ltgtype = LTG_RUSHBASE; + bs->teamgoal_time = trap_AAS_Time() + CTF_RUSHBASE_TIME; + bs->rushbaseaway_time = 0; + } + } +} + +/* +================== +EntityIsDead +================== +*/ +qboolean EntityIsDead(aas_entityinfo_t *entinfo) { + playerState_t ps; + + if (entinfo->number >= 0 && entinfo->number < MAX_CLIENTS) { + //retrieve the current client state + BotAI_GetClientState( entinfo->number, &ps ); + if (ps.pm_type != PM_NORMAL) return qtrue; + } + return qfalse; +} + +/* +================== +EntityIsInvisible +================== +*/ +qboolean EntityIsInvisible(aas_entityinfo_t *entinfo) { + if (entinfo->powerups & (1 << PW_GHOST)) + { // 50% chance of being visible? + if (((unsigned int)(level.time)/1024)&0x01) // Every second or so, the bot will see the player, so he doesn't jitter. + { + return qtrue; + } + else + { + return qfalse; + } + } + else if (entinfo->powerups & (1 << PW_INVIS)) + { + return qtrue; + } + else if ( entinfo->flags & EF_NODRAW ) + { + return qtrue; + } + return qfalse; +} + +/* +================== +EntityCarriesFlag +================== +*/ +qboolean EntityCarriesFlag(aas_entityinfo_t *entinfo) { + if ( entinfo->powerups & ( 1 << PW_REDFLAG ) ) return qtrue; + if ( entinfo->powerups & ( 1 << PW_BLUEFLAG ) ) return qtrue; + return qfalse; +} + +/* +================== +EntityIsShooting +================== +*/ +qboolean EntityIsShooting(aas_entityinfo_t *entinfo) { + if (entinfo->flags & EF_FIRING) { + return qtrue; + } + return qfalse; +} + +/* +================== +EntityIsChatting +================== +*/ +qboolean EntityIsChatting(aas_entityinfo_t *entinfo) { + if (entinfo->flags & EF_TALK) { + return qtrue; + } + return qfalse; +} + +/* +================== +EntityHasQuad +================== +*/ +qboolean EntityHasQuad(aas_entityinfo_t *entinfo) { + if (entinfo->powerups & (1 << PW_QUAD)) { + return qtrue; + } + return qfalse; +} + +/* +================== +BotCTFSeekGoals +================== +*/ +void BotCTFSeekGoals(bot_state_t *bs) { + float rnd; + int flagstatus, c; + + //when carrying a flag in ctf the bot should rush to the base + if (BotCTFCarryingFlag(bs)) { + //if not already rushing to the base + if (bs->ltgtype != LTG_RUSHBASE) { + bs->ltgtype = LTG_RUSHBASE; + bs->teamgoal_time = trap_AAS_Time() + CTF_RUSHBASE_TIME; + bs->rushbaseaway_time = 0; + } + else if (bs->rushbaseaway_time > trap_AAS_Time()) { + if (BotCTFTeam(bs) == CTF_TEAM_RED) flagstatus = bs->redflagstatus; + else flagstatus = bs->blueflagstatus; + //if the flag is back + if (flagstatus == 0) { + bs->rushbaseaway_time = 0; + } + } + return; + } + // + if (BotCTFTeam(bs) == CTF_TEAM_RED) flagstatus = bs->redflagstatus * 2 + bs->blueflagstatus; + else flagstatus = bs->blueflagstatus * 2 + bs->redflagstatus; + //if the enemy flag is not at it's base + if (flagstatus == 1) { + //if Not defending the base + if (!(bs->ltgtype == LTG_DEFENDKEYAREA && + (bs->teamgoal.number == ctf_redflag.number || + bs->teamgoal.number == ctf_blueflag.number))) { + //if not already accompanying someone + if (bs->ltgtype != LTG_TEAMACCOMPANY) { + //if there is avisible team mate flag carrier + c = BotTeamFlagCarrierVisible(bs); + if (c >= 0) { + //follow the flag carrier + //the team mate + bs->teammate = c; + //last time the team mate was visible + bs->teammatevisible_time = trap_AAS_Time(); + //set the time to send a message to the team mates + bs->teammessage_time = trap_AAS_Time() + 2 * random(); + //get the team goal time + bs->teamgoal_time = trap_AAS_Time() + TEAM_ACCOMPANY_TIME; + bs->ltgtype = LTG_TEAMACCOMPANY; + bs->formation_dist = 3.5 * 32; //3.5 meter + bs->arrive_time = 0; + return; + } + } + } + } + //if the base flag is stolen + else if (flagstatus == 2) { + //if not already going for the enemy flag + if (bs->ltgtype != LTG_GETFLAG) { + //if there's no bot team leader + if (!BotTeamLeader(bs)) { + //go for the enemy flag + bs->ltgtype = LTG_GETFLAG; + //no team message + bs->teammessage_time = 1; + //set the time the bot will stop getting the flag + bs->teamgoal_time = trap_AAS_Time() + CTF_GETFLAG_TIME; + return; + } + } + } + //if both flags not at their bases + else if (flagstatus == 3) { + // + if (bs->ltgtype != LTG_GETFLAG && + bs->ltgtype != LTG_TEAMACCOMPANY) { + //if there is avisible team mate flag carrier + c = BotTeamFlagCarrierVisible(bs); + if (c >= 0) { + //follow the flag carrier + return; + } + else { + //otherwise attack the enemy base + } + return; + } + } + //if the bot is roaming + if (bs->ctfroam_time > trap_AAS_Time()) return; + //if already a CTF or team goal + if (bs->ltgtype == LTG_TEAMHELP || + bs->ltgtype == LTG_TEAMACCOMPANY || + bs->ltgtype == LTG_DEFENDKEYAREA || + bs->ltgtype == LTG_GETFLAG || + bs->ltgtype == LTG_RUSHBASE || + bs->ltgtype == LTG_RETURNFLAG || + bs->ltgtype == LTG_CAMPORDER || + bs->ltgtype == LTG_PATROL) { + return; + } + //if the bot has anough aggression to decide what to do + if (BotAggression(bs) < 50) return; + //set the time to send a message to the team mates + bs->teammessage_time = trap_AAS_Time() + 2 * random(); + //get the flag or defend the base + rnd = random(); + if (rnd < 0.33 && ctf_redflag.areanum && ctf_blueflag.areanum) { + bs->ltgtype = LTG_GETFLAG; + //set the time the bot will stop getting the flag + bs->teamgoal_time = trap_AAS_Time() + CTF_GETFLAG_TIME; + } + else if (rnd < 0.66 && ctf_redflag.areanum && ctf_blueflag.areanum) { + // + if (BotCTFTeam(bs) == CTF_TEAM_RED) memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t)); + else memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t)); + //set the ltg type + bs->ltgtype = LTG_DEFENDKEYAREA; + //set the time the bot stops defending the base + bs->teamgoal_time = trap_AAS_Time() + TEAM_DEFENDKEYAREA_TIME; + bs->defendaway_time = 0; + } + else { + bs->ltgtype = 0; + //set the time the bot will stop roaming + bs->ctfroam_time = trap_AAS_Time() + CTF_ROAM_TIME; + } +#ifdef DEBUG + BotPrintTeamGoal(bs); +#endif //DEBUG +} + +#endif //CTF + +/* +================== +BotPointAreaNum +================== +*/ +int BotPointAreaNum(vec3_t origin) { + int areanum, numareas, areas[10]; + vec3_t end; + + areanum = trap_AAS_PointAreaNum(origin); + if (areanum) return areanum; + VectorCopy(origin, end); + end[2] += 10; + numareas = trap_AAS_TraceAreas(origin, end, areas, NULL, 10); + if (numareas > 0) return areas[0]; + return 0; +} + +/* +================== +ClientName +================== +*/ +char *ClientName(int client, char *name, int size) { + char buf[MAX_INFO_STRING]; + + if (client < 0 || client >= MAX_CLIENTS) { + BotAI_Print(PRT_ERROR, "ClientName: client out of range\n"); + return "[client out of range]"; + } + trap_GetConfigstring(CS_PLAYERS+client, buf, sizeof(buf)); + strncpy(name, Info_ValueForKey(buf, "n"), size-1); + name[size-1] = '\0'; + Q_CleanStr( name ); + return name; +} + +/* +================== +ClientSkin +================== +*/ +char *ClientSkin(int client, char *skin, int size) { + char buf[MAX_INFO_STRING]; + + if (client < 0 || client >= MAX_CLIENTS) { + BotAI_Print(PRT_ERROR, "ClientSkin: client out of range\n"); + return "[client out of range]"; + } + trap_GetConfigstring(CS_PLAYERS+client, buf, sizeof(buf)); + strncpy(skin, Info_ValueForKey(buf, "model"), size-1); + skin[size-1] = '\0'; + return skin; +} + +/* +================== +ClientFromName +================== +*/ +int ClientFromName(char *name) { + int i; + char buf[MAX_INFO_STRING]; + static int maxclients; + + if (!maxclients) + maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); + for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { + trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf)); + Q_CleanStr( buf ); + if (!Q_stricmp(Info_ValueForKey(buf, "n"), name)) return i; + } + return -1; +} + +/* +================== +stristr +================== +*/ +char *stristr(char *str, char *charset) { + int i; + + while(*str) { + for (i = 0; charset[i] && str[i]; i++) { + if (toupper(charset[i]) != toupper(str[i])) break; + } + if (!charset[i]) return str; + str++; + } + return NULL; +} + +/* +================== +EasyClientName +================== +*/ +char *EasyClientName(int client, char *buf, int size) { + int i; + char *str1, *str2, *ptr, c; + char name[128]; + + strcpy(name, ClientName(client, name, sizeof(name))); + for (i = 0; name[i]; i++) name[i] &= 127; + //remove all spaces + for (ptr = strstr(name, " "); ptr; ptr = strstr(name, " ")) { + memmove(ptr, ptr+1, strlen(ptr+1)+1); + } + //check for [x] and ]x[ clan names + str1 = strstr(name, "["); + str2 = strstr(name, "]"); + if (str1 && str2) { + if (str2 > str1) memmove(str1, str2+1, strlen(str2+1)+1); + else memmove(str2, str1+1, strlen(str1+1)+1); + } + //remove Mr prefix + if ((name[0] == 'm' || name[0] == 'M') && + (name[1] == 'r' || name[1] == 'R')) { + memmove(name, name+2, strlen(name+2)+1); + } + //only allow lower case alphabet characters + ptr = name; + while(*ptr) { + c = *ptr; + if ((c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || c == '_') { + ptr++; + } + else if (c >= 'A' && c <= 'Z') { + *ptr += 'a' - 'A'; + ptr++; + } + else { + memmove(ptr, ptr+1, strlen(ptr + 1)+1); + } + } + strncpy(buf, name, size-1); + buf[size-1] = '\0'; + return buf; +} + +qboolean BotUseMeleeWeapon(bot_state_t *bs) { + if ( bs->inventory[ENEMY_HORIZONTAL_DIST] < 64 ) + { + if ( bs->cur_ps.persistant[PERS_CLASS] == PC_BORG || bs->cur_ps.persistant[PERS_CLASS] == PC_MEDIC ) + { + return qtrue; + } + } + return qfalse; +} +/* +================== +BotChooseWeapon + + MCG - FIXME: This should really take into account: + Projectile vs. instant? + gravity on projectile? + Range to enemy vs range of weapon? + Some randomness on the weights? + +================== +*/ +void BotChooseWeapon(bot_state_t *bs) { + int newweaponnum; + + if (bs->cur_ps.weaponstate == WEAPON_RAISING || bs->cur_ps.weaponstate == WEAPON_DROPPING) + { + trap_EA_SelectWeapon(bs->client, bs->weaponnum); + } + else + { + newweaponnum = trap_BotChooseBestFightWeapon(bs->ws, bs->inventory, BotUseMeleeWeapon(bs)); + if (bs->weaponnum != newweaponnum) + { + bs->weaponchange_time = trap_AAS_Time(); + } + bs->weaponnum = newweaponnum; + //BotAI_Print(PRT_MESSAGE, "bs->weaponnum = %d\n", bs->weaponnum); + trap_EA_SelectWeapon(bs->client, bs->weaponnum); + } +} + +/* +================== +BotSetupForMovement +================== +*/ +void BotSetupForMovement(bot_state_t *bs) { + bot_initmove_t initmove; + + memset(&initmove, 0, sizeof(bot_initmove_t)); + VectorCopy(bs->cur_ps.origin, initmove.origin); + VectorCopy(bs->cur_ps.velocity, initmove.velocity); + VectorCopy(bs->cur_ps.origin, initmove.viewoffset); + initmove.viewoffset[2] += bs->cur_ps.viewheight; + initmove.entitynum = bs->entitynum; + initmove.client = bs->client; + initmove.thinktime = bs->thinktime; + //set the onground flag + if (bs->cur_ps.groundEntityNum != ENTITYNUM_NONE) initmove.or_moveflags |= MFL_ONGROUND; + //set the teleported flag + if ((bs->cur_ps.pm_flags & PMF_TIME_KNOCKBACK) && (bs->cur_ps.pm_time > 0)) { + initmove.or_moveflags |= MFL_TELEPORTED; + } + //set the waterjump flag + if ((bs->cur_ps.pm_flags & PMF_TIME_WATERJUMP) && (bs->cur_ps.pm_time > 0)) { + initmove.or_moveflags |= MFL_WATERJUMP; + } + //set presence type + if (bs->cur_ps.pm_flags & PMF_DUCKED) initmove.presencetype = PRESENCE_CROUCH; + else initmove.presencetype = PRESENCE_NORMAL; + // + if (bs->walker > 0.5) initmove.or_moveflags |= MFL_WALK; + // + VectorCopy(bs->viewangles, initmove.viewangles); + // + trap_BotInitMoveState(bs->ms, &initmove); +} + +/* +================== +BotUpdateInventory +================== +*/ +void BotUpdateInventory(bot_state_t *bs) { + //armor + bs->inventory[INVENTORY_ARMOR] = bs->cur_ps.stats[STAT_ARMOR]; + + //weapons + bs->inventory[INVENTORY_GRENADELAUNCHER] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_GRENADE_LAUNCHER)) != 0; + bs->inventory[INVENTORY_STASIS] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_DISRUPTOR)) != 0; + bs->inventory[INVENTORY_PHASER] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_PHASER)) != 0; + bs->inventory[INVENTORY_DREADNOUGHT] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_DERMAL_REGEN)) != 0; + bs->inventory[INVENTORY_IMOD] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_NULL_HAND)) != 0; + bs->inventory[INVENTORY_COMPRESSION] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_COMPRESSION_RIFLE)) != 0; + bs->inventory[INVENTORY_TETRION] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_TR116)) != 0; + bs->inventory[INVENTORY_SCAVENGER] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_COFFEE)) != 0; + bs->inventory[INVENTORY_QUANTUM] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_QUANTUM_BURST)) != 0; + + //ammo + bs->inventory[INVENTORY_GRENADES] = bs->cur_ps.ammo[WP_GRENADE_LAUNCHER]; + bs->inventory[INVENTORY_STASISAMMO] = bs->cur_ps.ammo[WP_DISRUPTOR]; + bs->inventory[INVENTORY_PHASERAMMO] = bs->cur_ps.ammo[WP_PHASER]; + bs->inventory[INVENTORY_DREADNOUGHTAMMO] = bs->cur_ps.ammo[WP_DERMAL_REGEN]; + bs->inventory[INVENTORY_IMODAMMO] = bs->cur_ps.ammo[WP_NULL_HAND]; + bs->inventory[INVENTORY_COMPRESSIONAMMO] = bs->cur_ps.ammo[WP_COMPRESSION_RIFLE]; + bs->inventory[INVENTORY_TETRIONAMMO] = bs->cur_ps.ammo[WP_TR116]; + bs->inventory[INVENTORY_SCAVENGERAMMO] = bs->cur_ps.ammo[WP_COFFEE]; + bs->inventory[INVENTORY_QUANTUMAMMO] = bs->cur_ps.ammo[WP_QUANTUM_BURST]; + + //powerups + bs->inventory[INVENTORY_HEALTH] = bs->cur_ps.stats[STAT_HEALTH]; + bs->inventory[INVENTORY_TRANSPORTER] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_TELEPORTER; + bs->inventory[INVENTORY_MEDKIT] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_MEDKIT; + bs->inventory[INVENTORY_QUAD] = bs->cur_ps.powerups[PW_QUAD] != 0; + bs->inventory[INVENTORY_ENVIRONMENTSUIT] = bs->cur_ps.powerups[PW_BOLTON] != 0; + bs->inventory[INVENTORY_HASTE] = bs->cur_ps.powerups[PW_HASTE] != 0; + bs->inventory[INVENTORY_INVISIBILITY] = bs->cur_ps.powerups[PW_INVIS] != 0; + bs->inventory[INVENTORY_REGEN] = bs->cur_ps.powerups[PW_REGEN] != 0; + bs->inventory[INVENTORY_FLIGHT] = bs->cur_ps.powerups[PW_FLIGHT] != 0; + bs->inventory[INVENTORY_REDFLAG] = bs->cur_ps.powerups[PW_REDFLAG] != 0; + bs->inventory[INVENTORY_BLUEFLAG] = bs->cur_ps.powerups[PW_BLUEFLAG] != 0; + bs->inventory[INVENTORY_SEEKER] = bs->cur_ps.powerups[PW_SEEKER] != 0; + bs->inventory[INVENTORY_SHIELD] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_SHIELD; + bs->inventory[INVENTORY_DETPACK] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_DETPACK; + // +} + +/* +================== +BotUpdateBattleInventory +================== +*/ +void BotUpdateBattleInventory(bot_state_t *bs, int enemy) { + vec3_t dir; + aas_entityinfo_t entinfo; + + BotEntityInfo(enemy, &entinfo); + VectorSubtract(entinfo.origin, bs->origin, dir); + bs->inventory[ENEMY_HEIGHT] = (int) dir[2]; + dir[2] = 0; + bs->inventory[ENEMY_HORIZONTAL_DIST] = (int) VectorLength(dir); + //FIXME: add num visible enemies and num visible team mates to the inventory +} + +/* +========================= +BotShouldDetonateDetPack +========================= +*/ +#define DETPACK_RADIUS 500 + +qboolean BotShouldDetonateDetPack(bot_state_t *bs) +{ + int botNum = 0, detWeight = 0; + vec3_t packOrg, dir; + float dist; + aas_entityinfo_t botinfo; + + // find the location of the DetPack + gentity_t *detpack = NULL; + char *classname = BG_FindClassnameForHoldable(HI_DETPACK); + + if (!classname) + { + return qfalse; + } + + while ((detpack = G_Find (detpack, FOFS(classname), classname)) != NULL) + { + VectorCopy(detpack->r.currentOrigin, packOrg); + } + + // determine who would be killed in the blast radius + for (botNum = 0; botNum < MAX_CLIENTS; botNum++) + { + BotEntityInfo(botNum, &botinfo); + if (!botinfo.valid) continue; + + //calculate the distance towards the enemy + VectorSubtract(botinfo.origin, packOrg, dir); + dist = VectorLength(dir); + + if (dist < DETPACK_RADIUS) // bot would get caught in blast radius + { + if (BotSameTeam(bs, botNum)) // friendly casualty potential + { + if (botNum == bs->client) // suicide... bad + { + detWeight--; + } + if (EntityCarriesFlag(&botinfo)) // it's my teammate, and he's got the flag! + { + detWeight -= 11; + continue; + } + detWeight--; + } + else + { + if(EntityCarriesFlag(&botinfo)) // mwahaha + { + detWeight += 14; + } + detWeight++; + } + } + } + +// Com_Printf("detWeight %d\n", detWeight); + + if (detWeight > 0) + { + return qtrue; + } + return qfalse; +} + + + +/* +================== +BotBattleUseItems +================== +*/ +void BotBattleUseItems(bot_state_t *bs) { + + + if (bs->inventory[INVENTORY_DETPACK] > 0) + { + // this needs to be in two stages: placement and detonation + if (bs->ltgtype == LTG_DEFENDKEYAREA) + { + if (bs->inventory[INVENTORY_DETPACK_PLACED] == 0) // not placed yet + { + bs->inventory[INVENTORY_DETPACK_PLACED] = 1; + trap_EA_Use(bs->client); // place it + return; + } + } + + if (bs->inventory[INVENTORY_DETPACK_PLACED] == 1) // placed + { + if (BotShouldDetonateDetPack(bs)) // logic + { + bs->inventory[INVENTORY_DETPACK_PLACED] = 0; + trap_EA_Use(bs->client); // BOOM + return; + } + return; + } + return; + } + + if (bs->inventory[INVENTORY_SHIELD] > 0) + { + if (BotWantsToRetreat(bs) && (bs->inventory[INVENTORY_HEALTH] < 50)) + { + trap_EA_Use(bs->client); + } + return; + } + + if (bs->inventory[INVENTORY_TRANSPORTER] > 0) + { + if (!BotCTFCarryingFlag(bs) && (bs->inventory[INVENTORY_HEALTH] < 50)) + { + trap_EA_Use(bs->client); + return; + } + } + + if (bs->inventory[INVENTORY_MEDKIT] > 0) + { + if (bs->inventory[INVENTORY_HEALTH] < 30) + { + trap_EA_Use(bs->client); + } + return; + } +} + +/* +================== +BotSetTeleportTime +================== +*/ +void BotSetTeleportTime(bot_state_t *bs) { + if ((bs->cur_ps.eFlags ^ bs->last_eFlags) & EF_TELEPORT_BIT) { + bs->teleport_time = trap_AAS_Time(); + } + bs->last_eFlags = bs->cur_ps.eFlags; +} + +/* +================== +BotIsDead +================== +*/ +qboolean BotIsDead(bot_state_t *bs) { + return (bs->cur_ps.pm_type == PM_DEAD); +} + +/* +================== +BotIsObserver +================== +*/ +qboolean BotIsObserver(bot_state_t *bs) { + char buf[MAX_INFO_STRING]; + if (bs->cur_ps.pm_type == PM_SPECTATOR) return qtrue; + trap_GetConfigstring(CS_PLAYERS+bs->client, buf, sizeof(buf)); + if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) return qtrue; + return qfalse; +} + +/* +================== +BotIntermission +================== +*/ +qboolean BotIntermission(bot_state_t *bs) { + //NOTE: we shouldn't be looking at the game code... + if (level.intermissiontime) return qtrue; + return (bs->cur_ps.pm_type == PM_FREEZE || bs->cur_ps.pm_type == PM_INTERMISSION); +} + +/* +================== +BotInLavaOrSlime +================== +*/ +qboolean BotInLavaOrSlime(bot_state_t *bs) { + vec3_t feet; + + VectorCopy(bs->origin, feet); + feet[2] -= 23; + return (trap_AAS_PointContents(feet) & (CONTENTS_LAVA|CONTENTS_SLIME)); +} + +/* +================== +BotCreateWayPoint +================== +*/ +bot_waypoint_t *BotCreateWayPoint(char *name, vec3_t origin, int areanum) { + bot_waypoint_t *wp; + vec3_t waypointmins = {-8, -8, -8}, waypointmaxs = {8, 8, 8}; + + wp = botai_freewaypoints; + if ( !wp ) { + BotAI_Print( PRT_WARNING, "BotCreateWayPoint: Out of waypoints\n" ); + return NULL; + } + botai_freewaypoints = botai_freewaypoints->next; + + Q_strncpyz( wp->name, name, sizeof(wp->name) ); + VectorCopy(origin, wp->goal.origin); + VectorCopy(waypointmins, wp->goal.mins); + VectorCopy(waypointmaxs, wp->goal.maxs); + wp->goal.areanum = areanum; + wp->next = NULL; + wp->prev = NULL; + return wp; +} + +/* +================== +BotFindWayPoint +================== +*/ +bot_waypoint_t *BotFindWayPoint(bot_waypoint_t *waypoints, char *name) { + bot_waypoint_t *wp; + + for (wp = waypoints; wp; wp = wp->next) { + if (!Q_stricmp(wp->name, name)) return wp; + } + return NULL; +} + +/* +================== +BotFreeWaypoints +================== +*/ +void BotFreeWaypoints(bot_waypoint_t *wp) { + bot_waypoint_t *nextwp; + + for (; wp; wp = nextwp) { + nextwp = wp->next; + wp->next = botai_freewaypoints; + botai_freewaypoints = wp; + } +} + +/* +================== +BotInitWaypoints +================== +*/ +void BotInitWaypoints(void) { + int i; + + botai_freewaypoints = NULL; + for (i = 0; i < MAX_WAYPOINTS; i++) { + botai_waypoints[i].next = botai_freewaypoints; + botai_freewaypoints = &botai_waypoints[i]; + } +} + +/* +================== +TeamPlayIsOn +================== +*/ +int TeamPlayIsOn(void) { + return ( gametype == GT_TEAM || gametype == GT_CTF ); +} + +/* +================== +BotAggression +================== +*/ +float BotAggression(bot_state_t *bs) { + //if the bot has quad + if (bs->inventory[INVENTORY_QUAD]) { + //if the bot is not holding the gauntlet or the enemy is really nearby + if (bs->inventory[ENEMY_HORIZONTAL_DIST] < 80) { + return 70; + } + } + //if the enemy is located way higher than the bot + if (bs->inventory[ENEMY_HEIGHT] > 200) return 0; + //if the bot is very low on health + if (bs->inventory[INVENTORY_HEALTH] < 60) return 0; + //if the bot is low on health + if (bs->inventory[INVENTORY_HEALTH] < 80) { + //if the bot has insufficient armor + if (bs->inventory[INVENTORY_ARMOR] < 40) return 0; + } + + if (bs->inventory[INVENTORY_DREADNOUGHT] > 0 && + bs->inventory[INVENTORY_DREADNOUGHTAMMO] > 0) return 100; + + if (bs->inventory[INVENTORY_TETRION] > 0 && + bs->inventory[INVENTORY_TETRIONAMMO] > 0) return 95; + + if (bs->inventory[INVENTORY_QUANTUM] > 0 && + bs->inventory[INVENTORY_QUANTUMAMMO] > 0) return 90; + + if (bs->inventory[INVENTORY_STASIS] > 0 && + bs->inventory[INVENTORY_STASISAMMO] > 0) return 85; + + if (bs->inventory[INVENTORY_SCAVENGER] > 0 && + bs->inventory[INVENTORY_SCAVENGERAMMO] > 0) return 80; + + if (bs->inventory[INVENTORY_GRENADELAUNCHER] > 0 && + bs->inventory[INVENTORY_GRENADES] > 0) return 75; + + if (bs->inventory[INVENTORY_IMOD] > 0 && + bs->inventory[INVENTORY_IMODAMMO] > 0) return 70; + + if (bs->inventory[INVENTORY_COMPRESSION] > 0 && + bs->inventory[INVENTORY_COMPRESSIONAMMO] > 0) return 65; + + //otherwise the bot is not feeling too aggressive + return 0; +} + +/* +================== +BotWantsToRetreat +================== +*/ +int BotWantsToRetreat(bot_state_t *bs) { + aas_entityinfo_t entinfo; + + //always retreat when carrying a CTF flag + if (BotCTFCarryingFlag(bs)) return qtrue; + // + if (bs->enemy >= 0) { + //if the enemy is carrying a flag + BotEntityInfo(bs->enemy, &entinfo); + if (EntityCarriesFlag(&entinfo)) return qfalse; + } + //if the bot is getting the flag + if (bs->ltgtype == LTG_GETFLAG) return qtrue; + // + if (BotAggression(bs) < 50) return qtrue; + return qfalse; +} + +/* +================== +BotWantsToChase +================== +*/ +int BotWantsToChase(bot_state_t *bs) { + aas_entityinfo_t entinfo; + + //always retreat when carrying a CTF flag + if (BotCTFCarryingFlag(bs)) return qfalse; + //if the enemy is carrying a flag + BotEntityInfo(bs->enemy, &entinfo); + if (EntityCarriesFlag(&entinfo)) return qtrue; + //if the bot is getting the flag + if (bs->ltgtype == LTG_GETFLAG) return qfalse; + // + if (BotAggression(bs) > 50) return qtrue; + return qfalse; +} + +/* +================== +BotWantsToHelp +================== +*/ +int BotWantsToHelp(bot_state_t *bs) { + return qtrue; +} + +/* +================== +BotCanAndWantsToRocketJump +================== +*/ +int BotCanAndWantsToRocketJump(bot_state_t *bs) { + float rocketjumper; + + //if rocket jumping is disabled + if (!bot_rocketjump.integer) return qfalse; + //if no rocket launcher + if (bs->inventory[INVENTORY_QUANTUM] <= 0) return qfalse; + //if low on rockets + if (bs->inventory[INVENTORY_QUANTUMAMMO] < 1) return qfalse; + //never rocket jump with the Quad + if (bs->inventory[INVENTORY_QUAD]) + { + if ( rpg_selfdamage.integer != 0 ) + { + return qfalse; + } + } + //if low on health + if (bs->inventory[INVENTORY_HEALTH] < 50) + { //if not full health + if ( rpg_selfdamage.integer != 0 ) + { + return qfalse; + } + } + if (bs->inventory[INVENTORY_HEALTH] < 60) + { //if the bot has insufficient armor + if (bs->inventory[INVENTORY_ARMOR] < 20) + { + if ( rpg_selfdamage.integer != 0 ) + { + return qfalse; + } + } + } + rocketjumper = 1; + return qtrue; +} + +/* +================== +BotGoCamp +================== +*/ +void BotGoCamp(bot_state_t *bs, bot_goal_t *goal) { + float camper; + + //set message time to zero so bot will NOT show any message + bs->teammessage_time = 0; + //set the ltg type + bs->ltgtype = LTG_CAMP; + //set the team goal + memcpy(&bs->teamgoal, goal, sizeof(bot_goal_t)); + //get the team goal time + camper = 0; + if (camper > 0.99) bs->teamgoal_time = 99999; + else bs->teamgoal_time = 120 + 180 * camper + random() * 15; + //set the last time the bot started camping + bs->camp_time = trap_AAS_Time(); + //the teammate that requested the camping + bs->teammate = 0; + //do NOT type arrive message + bs->arrive_time = 1; +} + +/* +================== +BotWantsToCamp +================== +*/ +int BotWantsToCamp(bot_state_t *bs) { + float camper; + camper = 0; + return qfalse; +} + +/* +================== +BotDontAvoid +================== +*/ +void BotDontAvoid(bot_state_t *bs, char *itemname) { + bot_goal_t goal; + int num; + + num = trap_BotGetLevelItemGoal(-1, itemname, &goal); + while(num >= 0) { + trap_BotRemoveFromAvoidGoals(bs->gs, goal.number); + num = trap_BotGetLevelItemGoal(num, itemname, &goal); + } +} + +/* +================== +BotGoForPowerups +================== +*/ +void BotGoForPowerups(bot_state_t *bs) { + + //don't avoid any of the powerups anymore + BotDontAvoid(bs, "Quantum Weapon Enhancer"); + BotDontAvoid(bs, "Nano-Regenerative Protoplasmer"); + BotDontAvoid(bs, "Metaphasic Shielding"); + BotDontAvoid(bs, "Temporal Accelerator"); + BotDontAvoid(bs, "Personal Cloaking Device"); + BotDontAvoid(bs, "Seeker Drone"); + BotDontAvoid(bs, "Anti-Gravity Pack"); + //reset the long term goal time so the bot will go for the powerup + //NOTE: the long term goal type doesn't change + bs->ltg_time = 0; +} + +/* +================== +BotRoamGoal +================== +*/ +void BotRoamGoal(bot_state_t *bs, vec3_t goal) { + int pc, i; + float len, rnd; + vec3_t dir, bestorg, belowbestorg; + bsp_trace_t trace; + + for (i = 0; i < 10; i++) { + //start at the bot origin + VectorCopy(bs->origin, bestorg); + rnd = random(); + if (rnd > 0.25) { + //add a random value to the x-coordinate + if (random() < 0.5) bestorg[0] -= 800 * random() + 100; + else bestorg[0] += 800 * random() + 100; + } + if (rnd < 0.75) { + //add a random value to the y-coordinate + if (random() < 0.5) bestorg[1] -= 800 * random() + 100; + else bestorg[1] += 800 * random() + 100; + } + //add a random value to the z-coordinate (NOTE: 48 = maxjump?) + bestorg[2] += 2 * 48 * crandom(); + //trace a line from the origin to the roam target + BotAI_Trace(&trace, bs->origin, NULL, NULL, bestorg, bs->entitynum, MASK_SOLID); + //direction and length towards the roam target + VectorSubtract(trace.endpos, bs->origin, dir); + len = VectorNormalize(dir); + //if the roam target is far away anough + if (len > 200) { + //the roam target is in the given direction before walls + VectorScale(dir, len * trace.fraction - 40, dir); + VectorAdd(bs->origin, dir, bestorg); + //get the coordinates of the floor below the roam target + belowbestorg[0] = bestorg[0]; + belowbestorg[1] = bestorg[1]; + belowbestorg[2] = bestorg[2] - 800; + BotAI_Trace(&trace, bestorg, NULL, NULL, belowbestorg, bs->entitynum, MASK_SOLID); + // + if (!trace.startsolid) { + trace.endpos[2]++; + pc = trap_PointContents(trace.endpos, bs->entitynum); + if (!(pc & (CONTENTS_LAVA | CONTENTS_SLIME))) { + VectorCopy(bestorg, goal); + return; + } + } + } + } + VectorCopy(bestorg, goal); +} + +/* +================== +BotAttackMove +================== +*/ +bot_moveresult_t BotAttackMove(bot_state_t *bs, int tfl) { + int movetype, i; + float attack_skill, jumper, croucher, dist, strafechange_time; + float attack_dist, attack_range; + vec3_t forward, backward, sideward, hordir, up = {0, 0, 1}; + aas_entityinfo_t entinfo; + bot_moveresult_t moveresult; + bot_goal_t goal; + + if (bs->attackchase_time > trap_AAS_Time()) { + //create the chase goal + goal.entitynum = bs->enemy; + goal.areanum = bs->lastenemyareanum; + VectorCopy(bs->lastenemyorigin, goal.origin); + VectorSet(goal.mins, -8, -8, -8); + VectorSet(goal.maxs, 8, 8, 8); + //initialize the movement state + BotSetupForMovement(bs); + //move towards the goal + trap_BotMoveToGoal(&moveresult, bs->ms, &goal, tfl); + return moveresult; + } + // + memset(&moveresult, 0, sizeof(bot_moveresult_t)); + // + attack_skill = 1; + jumper = 1; + croucher = 1; + //initialize the movement state + BotSetupForMovement(bs); + //get the enemy entity info + BotEntityInfo(bs->enemy, &entinfo); + //direction towards the enemy + VectorSubtract(entinfo.origin, bs->origin, forward); + //the distance towards the enemy + dist = VectorNormalize(forward); + VectorNegate(forward, backward); + //walk, crouch or jump + movetype = MOVE_WALK; + // + if (bs->attackcrouch_time < trap_AAS_Time() - 1) { + if (random() < jumper) { + movetype = MOVE_JUMP; + } + //wait at least one second before crouching again + else if (bs->attackcrouch_time < trap_AAS_Time() - 1 && random() < croucher) { + bs->attackcrouch_time = trap_AAS_Time() + croucher * 5; + } + } + if (bs->attackcrouch_time > trap_AAS_Time()) movetype = MOVE_CROUCH; + //if the bot should jump + if (movetype == MOVE_JUMP) { + //if jumped last frame + if (bs->attackjump_time > trap_AAS_Time()) { + movetype = MOVE_WALK; + } + else { + bs->attackjump_time = trap_AAS_Time() + 1; + } + } + + //if using assimilator or alt-fire hypo... + if ( bs->weaponnum == WP_TOOLKIT || bs->weaponnum == (WP_VOYAGER_HYPO+WP_NUM_WEAPONS) ) + {//get real close + attack_dist = 16; + attack_range = 16; + } + else + { + attack_dist = IDEAL_ATTACKDIST; + attack_range = 40; + } + + //increase the strafe time + bs->attackstrafe_time += bs->thinktime; + //get the strafe change time + strafechange_time = 0.4 + (1 - attack_skill) * 0.2; + if (attack_skill > 0.7) strafechange_time += crandom() * 0.2; + //if the strafe direction should be changed + if (bs->attackstrafe_time > strafechange_time) { + //some magic number :) + if (random() > 0.935) { + //flip the strafe direction + bs->flags ^= BFL_STRAFERIGHT; + bs->attackstrafe_time = 0; + } + } + // + for (i = 0; i < 2; i++) { + hordir[0] = forward[0]; + hordir[1] = forward[1]; + hordir[2] = 0; + VectorNormalize(hordir); + //get the sideward vector + CrossProduct(hordir, up, sideward); + //reverse the vector depending on the strafe direction + if (bs->flags & BFL_STRAFERIGHT) VectorNegate(sideward, sideward); + //randomly go back a little + if (random() > 0.9) { + VectorAdd(sideward, backward, sideward); + } + else { + //walk forward or backward to get at the ideal attack distance + if (dist > attack_dist + attack_range) VectorAdd(sideward, forward, sideward); + else if (dist < attack_dist - attack_range) VectorAdd(sideward, backward, sideward); + } + //perform the movement + if (trap_BotMoveInDirection(bs->ms, sideward, 400, movetype)) return moveresult; + //movement failed, flip the strafe direction + bs->flags ^= BFL_STRAFERIGHT; + bs->attackstrafe_time = 0; + } + //bot couldn't do any usefull movement +// bs->attackchase_time = AAS_Time() + 6; + return moveresult; +} + +/* +================== +BotSameTeam +================== +*/ +int BotSameTeam(bot_state_t *bs, int entnum) { + char info1[1024], info2[1024]; + + if (bs->client < 0 || bs->client >= MAX_CLIENTS) { + //BotAI_Print(PRT_ERROR, "BotSameTeam: client out of range\n"); + return qfalse; + } + if (entnum < 0 || entnum >= MAX_CLIENTS) { + //BotAI_Print(PRT_ERROR, "BotSameTeam: client out of range\n"); + return qfalse; + } + if (gametype == GT_TEAM || gametype == GT_CTF) { + trap_GetConfigstring(CS_PLAYERS+bs->client, info1, sizeof(info1)); + trap_GetConfigstring(CS_PLAYERS+entnum, info2, sizeof(info2)); + // + if (atoi(Info_ValueForKey(info1, "t")) == atoi(Info_ValueForKey(info2, "t"))) return qtrue; + } + return qfalse; +} + +/* +================== +InFieldOfVision +================== +*/ +qboolean InFieldOfVision(vec3_t viewangles, float fov, vec3_t angles) +{ + int i; + float diff, angle; + + for (i = 0; i < 2; i++) { + angle = AngleMod(viewangles[i]); + angles[i] = AngleMod(angles[i]); + diff = angles[i] - angle; + if (angles[i] > angle) { + if (diff > 180.0) diff -= 360.0; + } + else { + if (diff < -180.0) diff += 360.0; + } + if (diff > 0) { + if (diff > fov * 0.5) return qfalse; + } + else { + if (diff < -fov * 0.5) return qfalse; + } + } + return qtrue; +} + +/* +================== +BotEntityVisible + +returns visibility in the range [0, 1] taking fog and water surfaces into account +================== +*/ +float BotEntityVisible(int viewer, vec3_t eye, vec3_t viewangles, float fov, int ent) { + int i, contents_mask, passent, hitent, infog, inwater, otherinfog, pc; + float fogdist, waterfactor, vis, bestvis; + bsp_trace_t trace; + aas_entityinfo_t entinfo; + vec3_t dir, entangles, start, end, middle; + + //calculate middle of bounding box + BotEntityInfo(ent, &entinfo); + VectorAdd(entinfo.mins, entinfo.maxs, middle); + VectorScale(middle, 0.5, middle); + VectorAdd(entinfo.origin, middle, middle); + //check if entity is within field of vision + VectorSubtract(middle, eye, dir); + vectoangles(dir, entangles); + if (!InFieldOfVision(viewangles, fov, entangles)) return 0; + // + pc = trap_AAS_PointContents(eye); + infog = (pc & CONTENTS_SOLID); + inwater = (pc & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER)); + // + bestvis = 0; + for (i = 0; i < 3; i++) { + //if the point is not in potential visible sight + //if (!AAS_inPVS(eye, middle)) continue; + // + contents_mask = CONTENTS_SOLID|CONTENTS_PLAYERCLIP; + passent = viewer; + hitent = ent; + VectorCopy(eye, start); + VectorCopy(middle, end); + //if the entity is in water, lava or slime + if (trap_AAS_PointContents(middle) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER)) { + contents_mask |= (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER); + } + //if eye is in water, lava or slime + if (inwater) { + if (!(contents_mask & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER))) { + passent = ent; + hitent = viewer; + VectorCopy(middle, start); + VectorCopy(eye, end); + } + contents_mask ^= (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER); + } + //trace from start to end + BotAI_Trace(&trace, start, NULL, NULL, end, passent, contents_mask); + //if water was hit + waterfactor = 1.0; + if (trace.contents & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER)) { + //if the water surface is translucent + if (1) { + //trace through the water + contents_mask &= ~(CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER); + BotAI_Trace(&trace, trace.endpos, NULL, NULL, end, passent, contents_mask); + waterfactor = 0.5; + } + } + //if a full trace or the hitent was hit + if (trace.fraction >= 1 || trace.ent == hitent) { + //check for fog, assuming there's only one fog brush where + //either the viewer or the entity is in or both are in + otherinfog = (trap_AAS_PointContents(middle) & CONTENTS_FOG); + if (infog && otherinfog) { + VectorSubtract(trace.endpos, eye, dir); + fogdist = VectorLength(dir); + } + else if (infog) { + VectorCopy(trace.endpos, start); + BotAI_Trace(&trace, start, NULL, NULL, eye, viewer, CONTENTS_FOG); + VectorSubtract(eye, trace.endpos, dir); + fogdist = VectorLength(dir); + } + else if (otherinfog) { + VectorCopy(trace.endpos, end); + BotAI_Trace(&trace, eye, NULL, NULL, end, viewer, CONTENTS_FOG); + VectorSubtract(end, trace.endpos, dir); + fogdist = VectorLength(dir); + } + else { + //if the entity and the viewer are not in fog assume there's no fog in between + fogdist = 0; + } + //decrease visibility with the view distance through fog + vis = 1 / ((fogdist * fogdist * 0.001) < 1 ? 1 : (fogdist * fogdist * 0.001)); + //if entering water visibility is reduced + vis *= waterfactor; + // + if (vis > bestvis) bestvis = vis; + //if pretty much no fog + if (bestvis >= 0.95) return bestvis; + } + //check bottom and top of bounding box as well + if (i == 0) middle[2] += entinfo.mins[2]; + else if (i == 1) middle[2] += entinfo.maxs[2] - entinfo.mins[2]; + } + return bestvis; +} + +/* +================== +BotFindEnemy +================== +*/ +int BotFindEnemy(bot_state_t *bs, int curenemy) { + int i, healthdecrease; + float f, dist, curdist, alertness, easyfragger, vis; + aas_entityinfo_t entinfo, curenemyinfo; + vec3_t dir, angles; + + alertness = 1; + easyfragger = 1; + //check if the health decreased + healthdecrease = bs->lasthealth > bs->inventory[INVENTORY_HEALTH]; + //remember the current health value + bs->lasthealth = bs->inventory[INVENTORY_HEALTH]; + // + if (curenemy >= 0) { + BotEntityInfo(curenemy, &curenemyinfo); + if (EntityCarriesFlag(&curenemyinfo)) return qfalse; + VectorSubtract(curenemyinfo.origin, bs->origin, dir); + curdist = VectorLength(dir); + } + else { + curdist = 0; + } + // + + //FIXME: This only finds lowest numbered enemy, not the closest or best!!! + // 6/15/00 dpk changed this + for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { + + if (i == bs->client) continue; + //if it's the current enemy + if (i == curenemy) continue; + // + BotEntityInfo(i, &entinfo); + // + if (!entinfo.valid) continue; + //if on the same team + if (BotSameTeam(bs, i)) continue; + //if the enemy isn't dead and the enemy isn't the bot self + if (EntityIsDead(&entinfo) || entinfo.number == bs->entitynum) continue; + //if the enemy is invisible and not shooting + if (EntityIsInvisible(&entinfo) && !EntityIsShooting(&entinfo)) { + continue; + } + //if not an easy fragger don't shoot at chatting players + if (easyfragger < 0.5 && EntityIsChatting(&entinfo)) continue; + // + if (lastteleport_time > trap_AAS_Time() - 3) { + VectorSubtract(entinfo.origin, lastteleport_origin, dir); + if (VectorLength(dir) < 70) continue; + } + //calculate the distance towards the enemy + VectorSubtract(entinfo.origin, bs->origin, dir); + dist = VectorLength(dir); + + + //if this entity is not carrying a flag + if (!EntityCarriesFlag(&entinfo)) +// if (EntityCarriesFlag(&entinfo)) +/* { + // pick this one! + } + else +*/ { + //if this enemy is further away than the current one + if (curenemy >= 0 && dist > curdist) continue; + } + + //if the bot in too far away for me to notice + if (dist > 900 + alertness * 4000) continue; + + + //if the bot's health decreased or the enemy is shooting + if (curenemy < 0 && (healthdecrease || EntityIsShooting(&entinfo))) f = 360; + else f = 90 + 90 - (90 - (dist > 810 ? 810 : dist) / 9); + //check if the enemy is visible + vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, f, i); + if (vis <= 0) continue; + //if the enemy is quite far away, not shooting and the bot is not damaged + if (curenemy < 0 && dist > 200 && !healthdecrease && !EntityIsShooting(&entinfo)) + { + //check if we can avoid this enemy + VectorSubtract(bs->origin, entinfo.origin, dir); + vectoangles(dir, angles); + //if the bot isn't in the fov of the enemy + if (!InFieldOfVision(entinfo.angles, 120, angles)) { + //update some stuff for this enemy + BotUpdateBattleInventory(bs, i); + //if the bot doesn't really want to fight + if (BotWantsToRetreat(bs)) continue; + } + } +// } + //found an enemy + bs->enemy = entinfo.number; + if (curenemy >= 0) bs->enemysight_time = trap_AAS_Time() - 2; + else bs->enemysight_time = trap_AAS_Time(); + bs->enemysuicide = qfalse; + bs->enemydeath_time = 0; + return qtrue; + } + return qfalse; +} + +/* +================== +BotTeamFlagCarrierVisible +================== +*/ +int BotTeamFlagCarrierVisible(bot_state_t *bs) { + int i; + float vis; + aas_entityinfo_t entinfo; + + for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { + if (i == bs->client) continue; + // + BotEntityInfo(i, &entinfo); + //if this player is active + if (!entinfo.valid) continue; + //if this player is carrying a flag + if (!EntityCarriesFlag(&entinfo)) continue; + //if the flag carrier is not on the same team + if (!BotSameTeam(bs, i)) continue; + //if the flag carrier is not visible + vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i); + if (vis <= 0) continue; + // + return i; + } + return -1; +} + +/* +================== +BotAimAtEnemy + + MCG - FIXME: This is not set up at all correctly in the following areas: + Needs to consider if weapon is an alt weapon for aim and accuracy as well as functionality + Need to consider range? + Grenade Primary and alt as well as Scavenger alt need to take into account gravity + Needs to pick our new weapons correctly to determine which ones they should: + lead with (projectiles have speed) + decay aim purposely (instant hit weaps) + shoot "around corners" (bouncers, mines, splashdamage?) + +================== +*/ +void BotAimAtEnemy(bot_state_t *bs) { + int i, enemyvisible; + float dist, f, aim_skill, aim_accuracy, speed, reactiontime; + vec3_t dir, bestorigin, end, start, groundtarget, cmdmove, enemyvelocity; + vec3_t mins = {-4,-4,-4}, maxs = {4, 4, 4}; + weaponinfo_t wi; + aas_entityinfo_t entinfo; + bot_goal_t goal; + bsp_trace_t trace; + vec3_t target; + + //if the bot has no enemy + if (bs->enemy < 0) return; + // + //BotAI_Print(PRT_MESSAGE, "client %d: aiming at client %d\n", bs->entitynum, bs->enemy); + // + aim_skill = 1; + aim_accuracy = 1; + // + if (aim_skill > 0.95) + { + //don't aim too early + reactiontime = 0.5; + if (bs->enemysight_time > trap_AAS_Time() - reactiontime) return; + if (bs->teleport_time > trap_AAS_Time() - reactiontime) return; + } + + //get the weapon information + trap_BotGetWeaponInfo(bs->ws, bs->weaponnum, &wi); + //get the weapon specific aim accuracy and or aim skill + + if (wi.number == WP_GRENADE_LAUNCHER) { + aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_GRENADELAUNCHER, 0, 1); + aim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL_GRENADELAUNCHER, 0, 1); + } + if (wi.number == WP_DISRUPTOR) { + aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_STASIS, 0, 1); + aim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL_STASIS, 0, 1); + } + if (wi.number == WP_PHASER) { + aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_PHASER, 0, 1); + } + if (wi.number == WP_NULL_HAND) { + aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_IMOD, 0, 1); + } + if (wi.number == WP_COMPRESSION_RIFLE) { + aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_COMPRESSION, 0, 1); + } + if (wi.number == WP_TR116) { + aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_TETRION, 0, 1); + } + if (wi.number == WP_DERMAL_REGEN) { + aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_DREADNOUGHT, 0, 1); + } + if (wi.number == WP_QUANTUM_BURST) { + aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_QUANTUM, 0, 1); + aim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL_QUANTUM, 0, 1); + } + if (wi.number == WP_COFFEE) { + aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_SCAVENGER, 0, 1); + } + + // + if (aim_accuracy <= 0) aim_accuracy = 0.0001; + //get the enemy entity information + BotEntityInfo(bs->enemy, &entinfo); + //if the enemy is invisible then shoot crappy most of the time + if (EntityIsInvisible(&entinfo)) { + if (random() > 0.1) aim_accuracy *= 0.4; + } + // + VectorSubtract(entinfo.origin, entinfo.lastvisorigin, enemyvelocity); + VectorScale(enemyvelocity, 1 / entinfo.update_time, enemyvelocity); + //enemy origin and velocity is remembered every 0.5 seconds + if (bs->enemyposition_time < trap_AAS_Time()) { + // + bs->enemyposition_time = trap_AAS_Time() + 0.5; + VectorCopy(enemyvelocity, bs->enemyvelocity); + VectorCopy(entinfo.origin, bs->enemyorigin); + } + //if not extremely skilled + if (aim_skill < 0.9) { + VectorSubtract(entinfo.origin, bs->enemyorigin, dir); + //if the enemy moved a bit + if (VectorLength(dir) > 48) { + //if the enemy changed direction + if (DotProduct(bs->enemyvelocity, enemyvelocity) < 0) { + //aim accuracy should be worse now + aim_accuracy *= 0.7; + } + } + } + //check visibility of enemy + enemyvisible = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy); + //if the enemy is visible + if (enemyvisible) { + // + VectorCopy(entinfo.origin, bestorigin); + bestorigin[2] += 8; + //get the start point shooting from + //NOTE: the x and y projectile start offsets are ignored + VectorCopy(bs->origin, start); + start[2] += bs->cur_ps.viewheight; + start[2] += wi.offset[2]; + // + BotAI_Trace(&trace, start, mins, maxs, bestorigin, bs->entitynum, MASK_SHOT); + //if the enemy is NOT hit + if (trace.fraction <= 1 && trace.ent != entinfo.number) { + bestorigin[2] += 16; + } + //if it is not an instant hit weapon the bot might want to predict the enemy + if (wi.speed) { + // + VectorSubtract(bestorigin, bs->origin, dir); + dist = VectorLength(dir); + VectorSubtract(entinfo.origin, bs->enemyorigin, dir); + //if the enemy is NOT pretty far away and strafing just small steps left and right + if (!(dist > 100 && VectorLength(dir) < 32)) { + //if skilled anough do exact prediction + if (aim_skill > 0.8 && + //if the weapon is ready to fire + bs->cur_ps.weaponstate == WEAPON_READY) { + aas_clientmove_t move; + vec3_t origin; + + VectorSubtract(entinfo.origin, bs->origin, dir); + //distance towards the enemy + dist = VectorLength(dir); + //direction the enemy is moving in + VectorSubtract(entinfo.origin, entinfo.lastvisorigin, dir); + // + VectorScale(dir, 1 / entinfo.update_time, dir); + // + VectorCopy(entinfo.origin, origin); + origin[2] += 1; + // + VectorClear(cmdmove); + //AAS_ClearShownDebugLines(); + trap_AAS_PredictClientMovement(&move, bs->enemy, origin, + PRESENCE_CROUCH, qfalse, + dir, cmdmove, 0, + dist * 10 / wi.speed, 0.1, 0, 0, qfalse); + VectorCopy(move.endpos, bestorigin); + //BotAI_Print(PRT_MESSAGE, "%1.1f predicted speed = %f, frames = %f\n", trap_AAS_Time(), VectorLength(dir), dist * 10 / wi.speed); + } + //if not that skilled do linear prediction + else if (aim_skill > 0.4) { + VectorSubtract(entinfo.origin, bs->origin, dir); + //distance towards the enemy + dist = VectorLength(dir); + //direction the enemy is moving in + VectorSubtract(entinfo.origin, entinfo.lastvisorigin, dir); + dir[2] = 0; + // + speed = VectorNormalize(dir) / entinfo.update_time; + //botimport.Print(PRT_MESSAGE, "speed = %f, wi->speed = %f\n", speed, wi->speed); + //best spot to aim at + VectorMA(entinfo.origin, (dist / wi.speed) * speed, dir, bestorigin); + } + } + } + //if the projectile does radial damage + if (aim_skill > 0.6 && wi.proj.damagetype & DAMAGETYPE_RADIAL) { + //if the enemy isn't standing significantly higher than the bot + if (entinfo.origin[2] < bs->origin[2] + 16) { + //try to aim at the ground in front of the enemy + VectorCopy(entinfo.origin, end); + end[2] -= 64; + BotAI_Trace(&trace, entinfo.origin, NULL, NULL, end, entinfo.number, MASK_SHOT); + // + VectorCopy(bestorigin, groundtarget); + if (trace.startsolid) groundtarget[2] = entinfo.origin[2] - 16; + else groundtarget[2] = trace.endpos[2] - 8; + //trace a line from projectile start to ground target + BotAI_Trace(&trace, start, NULL, NULL, groundtarget, bs->entitynum, MASK_SHOT); + //if hitpoint is not vertically too far from the ground target + if (fabs(trace.endpos[2] - groundtarget[2]) < 50) { + VectorSubtract(trace.endpos, groundtarget, dir); + //if the hitpoint is near anough the ground target + if (VectorLength(dir) < 60) { + VectorSubtract(trace.endpos, start, dir); + //if the hitpoint is far anough from the bot + if (VectorLength(dir) > 100) { + //check if the bot is visible from the ground target + trace.endpos[2] += 1; + BotAI_Trace(&trace, trace.endpos, NULL, NULL, entinfo.origin, entinfo.number, MASK_SHOT); + if (trace.fraction >= 1) { + //botimport.Print(PRT_MESSAGE, "%1.1f aiming at ground\n", AAS_Time()); + VectorCopy(groundtarget, bestorigin); + } + } + } + } + } + } + bestorigin[0] += 20 * crandom() * (1 - aim_accuracy); + bestorigin[1] += 20 * crandom() * (1 - aim_accuracy); + bestorigin[2] += 10 * crandom() * (1 - aim_accuracy); + } + else { + // + VectorCopy(bs->lastenemyorigin, bestorigin); + bestorigin[2] += 8; + //if the bot is skilled anough + if (aim_skill > 0.5) { + //do prediction shots around corners + if (wi.number == WP_DISRUPTOR || + wi.number == WP_GRENADE_LAUNCHER) + { + //create the chase goal + goal.entitynum = bs->client; + goal.areanum = bs->areanum; + VectorCopy(bs->eye, goal.origin); + VectorSet(goal.mins, -8, -8, -8); + VectorSet(goal.maxs, 8, 8, 8); + // + if (trap_BotPredictVisiblePosition(bs->lastenemyorigin, bs->lastenemyareanum, &goal, TFL_DEFAULT, target)) { + VectorSubtract(target, bs->eye, dir); + if (VectorLength(dir) > 80) { + VectorCopy(target, bestorigin); + bestorigin[2] -= 20; + } + } + aim_accuracy = 1; + } + } + } + // + if (enemyvisible) { + BotAI_Trace(&trace, bs->eye, NULL, NULL, bestorigin, bs->entitynum, MASK_SHOT); + VectorCopy(trace.endpos, bs->aimtarget); + } + else { + VectorCopy(bestorigin, bs->aimtarget); + } + //get aim direction + VectorSubtract(bestorigin, bs->eye, dir); + // kef -- fixme. i'm guessing this is listing all of the instant-hit weapons? + if (wi.number == WP_PHASER || + wi.number == WP_NULL_HAND) { + //distance towards the enemy + dist = VectorLength(dir); + if (dist > 150) dist = 150; + f = 0.6 + dist / 150 * 0.4; + aim_accuracy *= f; + } + //add some random stuff to the aim direction depending on the aim accuracy + if (aim_accuracy < 0.8) { + VectorNormalize(dir); + for (i = 0; i < 3; i++) dir[i] += 0.3 * crandom() * (1 - aim_accuracy); + } + //set the ideal view angles + vectoangles(dir, bs->ideal_viewangles); + //take the weapon spread into account for lower skilled bots + bs->ideal_viewangles[PITCH] += 6 * wi.vspread * crandom() * (1 - aim_accuracy); + bs->ideal_viewangles[PITCH] = AngleMod(bs->ideal_viewangles[PITCH]); + bs->ideal_viewangles[YAW] += 6 * wi.hspread * crandom() * (1 - aim_accuracy); + bs->ideal_viewangles[YAW] = AngleMod(bs->ideal_viewangles[YAW]); + //if the bots should be really challenging + //if the bot is really accurate and has the enemy in view for some time + if (aim_accuracy > 0.9 && bs->enemysight_time < trap_AAS_Time() - 1) + { + //set the view angles directly + if (bs->ideal_viewangles[PITCH] > 180) + { + bs->ideal_viewangles[PITCH] -= 360; + } + VectorCopy(bs->ideal_viewangles, bs->viewangles); + trap_EA_View(bs->client, bs->viewangles); + } +} + +/* +================== +BotCheckAttack +================== +*/ +void BotCheckAttack(bot_state_t *bs) { + float points, reactiontime, fov, firethrottle; + bsp_trace_t bsptrace; + //float selfpreservation; + vec3_t forward, right, start, end, dir, angles; + weaponinfo_t wi; + bsp_trace_t trace; + aas_entityinfo_t entinfo; + vec3_t mins = {-8, -8, -8}, maxs = {8, 8, 8}; + + if (bs->enemy < 0) return; + // + reactiontime = 0; + if (bs->enemysight_time > trap_AAS_Time() - reactiontime) return; + if (bs->teleport_time > trap_AAS_Time() - reactiontime) return; + //if changing weapons + if (bs->weaponchange_time > trap_AAS_Time() - 0.1) return; + //check fire throttle characteristic + if (bs->firethrottlewait_time > trap_AAS_Time()) return; + firethrottle = 1; + if (bs->firethrottleshoot_time < trap_AAS_Time()) { + if (random() > firethrottle) { + bs->firethrottlewait_time = trap_AAS_Time() + firethrottle; + bs->firethrottleshoot_time = 0; + } + else { + bs->firethrottleshoot_time = trap_AAS_Time() + 1 - firethrottle; + bs->firethrottlewait_time = 0; + } + } + // + BotEntityInfo(bs->enemy, &entinfo); + VectorSubtract(entinfo.origin, bs->eye, dir); + // + if (VectorLength(dir) < 100) fov = 120; + else fov = 50; + /* + //if the enemy isn't visible + if (!BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, fov, bs->enemy)) { + //botimport.Print(PRT_MESSAGE, "enemy not visible\n"); + return; + }*/ + vectoangles(dir, angles); + if (!InFieldOfVision(bs->viewangles, fov, angles)) return; + BotAI_Trace(&bsptrace, bs->eye, NULL, NULL, bs->aimtarget, bs->client, CONTENTS_SOLID|CONTENTS_PLAYERCLIP); + if (bsptrace.fraction < 1 && bsptrace.ent != bs->enemy) return; + + //get the weapon info + trap_BotGetWeaponInfo(bs->ws, bs->weaponnum, &wi); + //get the start point shooting from + VectorCopy(bs->origin, start); + start[2] += bs->cur_ps.viewheight; + AngleVectors(bs->viewangles, forward, right, NULL); + start[0] += forward[0] * wi.offset[0] + right[0] * wi.offset[1]; + start[1] += forward[1] * wi.offset[0] + right[1] * wi.offset[1]; + start[2] += forward[2] * wi.offset[0] + right[2] * wi.offset[1] + wi.offset[2]; + //end point aiming at + VectorMA(start, 1000, forward, end); + //a little back to make sure not inside a very close enemy + VectorMA(start, -12, forward, start); + BotAI_Trace(&trace, start, mins, maxs, end, bs->entitynum, MASK_SHOT); + //if won't hit the enemy + if (trace.ent != bs->enemy) { + //if the entity is a client + if (trace.ent > 0 && trace.ent <= MAX_CLIENTS) { + //if a teammate is hit + if (BotSameTeam(bs, trace.ent)) return; + } + //if the projectile does a radial damage + if (wi.proj.damagetype & DAMAGETYPE_RADIAL) { + if (trace.fraction * 1000 < wi.proj.radius) { + points = (wi.proj.damage - 0.5 * trace.fraction * 1000) * 0.5; + if (points > 0) { +// selfpreservation = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_SELFPRESERVATION, 0, 1); +// if (random() < selfpreservation) return; + return; + } + } + //FIXME: check if a teammate gets radial damage + } + } + //if fire has to be release to activate weapon + if (wi.flags & WFL_FIRERELEASED) { + if (bs->flags & BFL_ATTACKED) + {// check in here to either call the alt_fire or not!! also, adjust the bots weapon... hackery? + if (bs->weaponnum > WP_NUM_WEAPONS) // it's an alt_fire! + { + bs->weaponnum -= WP_NUM_WEAPONS; + trap_EA_Alt_Attack(bs->client); + } + else + { + trap_EA_Attack(bs->client); + } + } + } + else + { // check in here to either call the alt_fire or not!! also, adjust the bots weapon... hackery? + if (bs->weaponnum > WP_NUM_WEAPONS) // it's an alt_fire! + { + bs->weaponnum -= WP_NUM_WEAPONS; + trap_EA_Alt_Attack(bs->client); + } + else + { + trap_EA_Attack(bs->client); + } + } + bs->flags ^= BFL_ATTACKED; +} + +/* +================== +BotMapScripts +================== +*/ +void BotMapScripts(bot_state_t *bs) { + char info[1024]; + char mapname[128]; + int i, shootbutton; + float aim_accuracy; + aas_entityinfo_t entinfo; + vec3_t dir; + + trap_GetServerinfo(info, sizeof(info)); + + strncpy(mapname, Info_ValueForKey( info, "mapname" ), sizeof(mapname)-1); + mapname[sizeof(mapname)-1] = '\0'; + + if (!Q_stricmp(mapname, "q3tourney6")) { + vec3_t mins = {700, 204, 672}, maxs = {964, 468, 680}; + vec3_t buttonorg = {304, 352, 920}; + //NOTE: NEVER use the func_bobbing in q3tourney6 + bs->tfl &= ~TFL_FUNCBOB; + //if the bot is below the bounding box + if (bs->origin[0] > mins[0] && bs->origin[0] < maxs[0]) { + if (bs->origin[1] > mins[1] && bs->origin[1] < maxs[1]) { + if (bs->origin[2] < mins[2]) { + return; + } + } + } + shootbutton = qfalse; + //if an enemy is below this bounding box then shoot the button + for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { + + if (i == bs->client) continue; + // + BotEntityInfo(i, &entinfo); + // + if (!entinfo.valid) continue; + //if the enemy isn't dead and the enemy isn't the bot self + if (EntityIsDead(&entinfo) || entinfo.number == bs->entitynum) continue; + // + if (entinfo.origin[0] > mins[0] && entinfo.origin[0] < maxs[0]) { + if (entinfo.origin[1] > mins[1] && entinfo.origin[1] < maxs[1]) { + if (entinfo.origin[2] < mins[2]) { + //if there's a team mate below the crusher + if (BotSameTeam(bs, i)) { + shootbutton = qfalse; + break; + } + else { + shootbutton = qtrue; + } + } + } + } + } + if (shootbutton) { + bs->flags |= BFL_IDEALVIEWSET; + VectorSubtract(buttonorg, bs->eye, dir); + vectoangles(dir, bs->ideal_viewangles); + aim_accuracy = 1; + bs->ideal_viewangles[PITCH] += 8 * crandom() * (1 - aim_accuracy); + bs->ideal_viewangles[PITCH] = AngleMod(bs->ideal_viewangles[PITCH]); + bs->ideal_viewangles[YAW] += 8 * crandom() * (1 - aim_accuracy); + bs->ideal_viewangles[YAW] = AngleMod(bs->ideal_viewangles[YAW]); + // + if (InFieldOfVision(bs->viewangles, 20, bs->ideal_viewangles)) + {// check in here to either call the alt_fire or not!! also, adjust the bots weapon... hackery? + if (bs->weaponnum > WP_NUM_WEAPONS) // it's an alt_fire! + { + bs->weaponnum -= WP_NUM_WEAPONS; + trap_EA_Alt_Attack(bs->client); + } + else + { + trap_EA_Attack(bs->client); + } + } + } + } +} + +/* +================== +BotEntityToActivate +================== +*/ +//#define OBSTACLEDEBUG + +int BotEntityToActivate(int entitynum) { + int i, ent, cur_entities[10]; + char model[MAX_INFO_STRING], tmpmodel[128]; + char target[128], classname[128]; + float health; + char targetname[10][128]; + aas_entityinfo_t entinfo; + + BotEntityInfo(entitynum, &entinfo); + Com_sprintf(model, sizeof( model ), "*%d", entinfo.modelindex); + for (ent = trap_AAS_NextBSPEntity(0); ent; ent = trap_AAS_NextBSPEntity(ent)) { + if (!trap_AAS_ValueForBSPEpairKey(ent, "model", tmpmodel, sizeof(tmpmodel))) continue; + if (!strcmp(model, tmpmodel)) break; + } + if (!ent) { + BotAI_Print(PRT_ERROR, "BotEntityToActivate: no entity found with model %s\n", model); + return 0; + } + trap_AAS_ValueForBSPEpairKey(ent, "classname", classname, sizeof(classname)); + if (!classname) { + BotAI_Print(PRT_ERROR, "BotEntityToActivate: entity with model %s has no classname\n", model); + return 0; + } + //if it is a door + if (!strcmp(classname, "func_door")) { + if (trap_AAS_FloatForBSPEpairKey(ent, "health", &health)) { + //if health the door must be shot to open + if (health) return ent; + } + } + //get the targetname so we can find an entity with a matching target + if (!trap_AAS_ValueForBSPEpairKey(ent, "targetname", targetname[0], sizeof(targetname[0]))) { +#ifdef OBSTACLEDEBUG + BotAI_Print(PRT_ERROR, "BotEntityToActivate: entity with model \"%s\" has no targetname\n", model); +#endif //OBSTACLEDEBUG + return 0; + } + //only allows single activation chains, tree-like activation can be added back in + cur_entities[0] = trap_AAS_NextBSPEntity(0); + for (i = 0; i >= 0 && i < 10;) { + for (ent = cur_entities[i]; ent; ent = trap_AAS_NextBSPEntity(ent)) { + if (!trap_AAS_ValueForBSPEpairKey(ent, "target", target, sizeof(target))) continue; + if (!strcmp(targetname[i], target)) { + cur_entities[i] = trap_AAS_NextBSPEntity(ent); + break; + } + } + if (!ent) { + BotAI_Print(PRT_ERROR, "BotEntityToActivate: no entity with target \"%s\"\n", targetname[i]); + i--; + continue; + } + if (!trap_AAS_ValueForBSPEpairKey(ent, "classname", classname, sizeof(classname))) { + BotAI_Print(PRT_ERROR, "BotEntityToActivate: entity with target \"%s\" has no classname\n", targetname[i]); + continue; + } + if (!strcmp(classname, "func_button")) { + //BSP button model + return ent; + } + else if (!strcmp(classname, "trigger_multiple")) { + //invisible trigger multiple box + return ent; + } + else { + i--; + } + } + BotAI_Print(PRT_ERROR, "BotEntityToActivate: unknown activator with classname \"%s\"\n", classname); + return 0; +} + +/* +================== +BotSetMovedir +================== +*/ +vec3_t VEC_UP = {0, -1, 0}; +vec3_t MOVEDIR_UP = {0, 0, 1}; +vec3_t VEC_DOWN = {0, -2, 0}; +vec3_t MOVEDIR_DOWN = {0, 0, -1}; + +void BotSetMovedir(vec3_t angles, vec3_t movedir) { + if (VectorCompare(angles, VEC_UP)) { + VectorCopy(MOVEDIR_UP, movedir); + } + else if (VectorCompare(angles, VEC_DOWN)) { + VectorCopy(MOVEDIR_DOWN, movedir); + } + else { + AngleVectors(angles, movedir, NULL, NULL); + } +} + +/* +================== +BotModelMinsMaxs + +this is ugly +================== +*/ +void BotModelMinsMaxs(int modelindex, int eType, vec3_t mins, vec3_t maxs) { + gentity_t *ent; + int i; + + ent = &g_entities[0]; + for (i = 0; i < level.num_entities; i++, ent++) { + if ( !ent->inuse ) { + continue; + } + if ( ent->s.eType != eType) { + continue; + } + if (ent->s.modelindex == modelindex) { + VectorAdd(ent->r.currentOrigin, ent->r.mins, mins); + VectorAdd(ent->r.currentOrigin, ent->r.maxs, maxs); + return; + } + } + VectorClear(mins); + VectorClear(maxs); +} + +/* +================== +BotAIBlocked + +very basic handling of bots being blocked by other entities +check what kind of entity is blocking the bot and try to activate +it otherwise try to walk around the entity +before the bot ends in this part of the AI it should predict which doors to open, +which buttons to activate etc. +================== +*/ +void BotAIBlocked(bot_state_t *bs, bot_moveresult_t *moveresult, int activate) { + int movetype, ent, i, areas[10], numareas, modelindex; + char classname[128], model[128]; + float lip, dist, health, angle; + vec3_t hordir, size, start, end, mins, maxs, sideward, angles; + vec3_t movedir, origin, goalorigin, bboxmins, bboxmaxs; + vec3_t up = {0, 0, 1}, extramins = {1, 1, 1}, extramaxs = {-1, -1, -1}; + aas_entityinfo_t entinfo; + //bsp_trace_t bsptrace; +#ifdef OBSTACLEDEBUG + char netname[MAX_NETNAME]; + char buf[128]; +#endif + + if (!moveresult->blocked) { + bs->notblocked_time = trap_AAS_Time(); + return; + } + // + BotEntityInfo(moveresult->blockentity, &entinfo); +#ifdef OBSTACLEDEBUG + ClientName(bs->client, netname, sizeof(netname)); + BotAI_Print(PRT_MESSAGE, "%s: I'm blocked by model %d\n", netname, entinfo.modelindex); +#endif OBSTACLEDEBUG + //if blocked by a bsp model and the bot wants to activate it if possible + if (entinfo.modelindex > 0 && entinfo.modelindex <= max_bspmodelindex && activate) { + //find the bsp entity which should be activated in order to remove + //the blocking entity + ent = BotEntityToActivate(entinfo.number); + if (!ent) { + strcpy(classname, ""); +#ifdef OBSTACLEDEBUG + BotAI_Print(PRT_MESSAGE, "%s: can't find activator for blocking entity\n", ClientName(bs->client, netname, sizeof(netname))); +#endif //OBSTACLEDEBUG + } + else { + trap_AAS_ValueForBSPEpairKey(ent, "classname", classname, sizeof(classname)); +#ifdef OBSTACLEDEBUG + ClientName(bs->client, netname, sizeof(netname)); + BotAI_Print(PRT_MESSAGE, "%s: I should activate %s\n", netname, classname); +#endif OBSTACLEDEBUG + } + if (!strcmp(classname, "func_button")) { + //create a bot goal towards the button + trap_AAS_ValueForBSPEpairKey(ent, "model", model, sizeof(model)); + modelindex = atoi(model+1); + //if the model is not loaded + if (!modelindex) return; + VectorClear(angles); + BotModelMinsMaxs(modelindex, ET_MOVER, mins, maxs); + //get the lip of the button + trap_AAS_FloatForBSPEpairKey(ent, "lip", &lip); + if (!lip) lip = 4; + //get the move direction from the angle + trap_AAS_FloatForBSPEpairKey(ent, "angle", &angle); + VectorSet(angles, 0, angle, 0); + BotSetMovedir(angles, movedir); + //button size + VectorSubtract(maxs, mins, size); + //button origin + VectorAdd(mins, maxs, origin); + VectorScale(origin, 0.5, origin); + //touch distance of the button + dist = fabs(movedir[0]) * size[0] + fabs(movedir[1]) * size[1] + fabs(movedir[2]) * size[2]; + dist *= 0.5; + // + trap_AAS_FloatForBSPEpairKey(ent, "health", &health); + //if the button is shootable + if (health) { + //FIXME: walk to a point where the button is visible and shoot at the button + //calculate the goal origin + VectorMA(origin, -dist, movedir, goalorigin); + // + VectorSubtract(goalorigin, bs->origin, movedir); + vectoangles(movedir, moveresult->ideal_viewangles); + moveresult->flags |= MOVERESULT_MOVEMENTVIEW; + moveresult->flags |= MOVERESULT_MOVEMENTWEAPON; + //select the machinegun and shoot + trap_EA_SelectWeapon(bs->client, WEAPONINDEX_PHASER); + if (bs->cur_ps.weapon == WEAPONINDEX_PHASER) { + trap_EA_Attack(bs->client); + } + return; + } + else { + //add bounding box size to the dist + trap_AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, bboxmins, bboxmaxs); + for (i = 0; i < 3; i++) { + if (movedir[i] < 0) dist += fabs(movedir[i]) * fabs(bboxmaxs[i]); + else dist += fabs(movedir[i]) * fabs(bboxmins[i]); + } + //calculate the goal origin + VectorMA(origin, -dist, movedir, goalorigin); + // + VectorCopy(goalorigin, start); + start[2] += 24; + VectorCopy(start, end); + end[2] -= 100; + numareas = trap_AAS_TraceAreas(start, end, areas, NULL, 10); + // + for (i = 0; i < numareas; i++) { + if (trap_AAS_AreaReachability(areas[i])) { + break; + } + } + if (i < numareas) { + // +#ifdef OBSTACLEDEBUG + if (bs->activatemessage_time < trap_AAS_Time()) { + Com_sprintf(buf, sizeof(buf), "I have to activate a button at %1.1f %1.1f %1.1f in area %d\n", + goalorigin[0], goalorigin[1], goalorigin[2], areas[i]); + trap_EA_Say(bs->client, buf); + bs->activatemessage_time = trap_AAS_Time() + 5; + } +#endif //OBSTACLEDEBUG + // + VectorCopy(origin, bs->activategoal.origin); + bs->activategoal.areanum = areas[i]; + VectorSubtract(mins, origin, bs->activategoal.mins); + VectorSubtract(maxs, origin, bs->activategoal.maxs); + // + for (i = 0; i < 3; i++) + { + if (movedir[i] < 0) bs->activategoal.maxs[i] += fabs(movedir[i]) * fabs(extramaxs[i]); + else bs->activategoal.mins[i] += fabs(movedir[i]) * fabs(extramins[i]); + } //end for + // + bs->activategoal.entitynum = entinfo.number; + bs->activategoal.number = 0; + bs->activategoal.flags = 0; + bs->activate_time = trap_AAS_Time() + 10; + AIEnter_Seek_ActivateEntity(bs); + return; + } + else { +#ifdef OBSTACLEDEBUG + if (!numareas) BotAI_Print(PRT_MESSAGE, "button not in an area\n"); + else BotAI_Print(PRT_MESSAGE, "button area has no reachabilities\n"); +#endif //OBSTACLEDEBUG + if (bs->ainode == AINode_Seek_NBG) bs->nbg_time = 0; + else if (bs->ainode == AINode_Seek_LTG) bs->ltg_time = 0; + } + } + } + else if (!strcmp(classname, "func_door")) { + //shoot at the shootable door + trap_AAS_ValueForBSPEpairKey(ent, "model", model, sizeof(model)); + modelindex = atoi(model+1); + //if the model is not loaded + if (!modelindex) return; + VectorClear(angles); + BotModelMinsMaxs(modelindex, ET_MOVER, mins, maxs); + //door origin + VectorAdd(mins, maxs, origin); + VectorScale(origin, 0.5, origin); + // + VectorSubtract(origin, bs->eye, movedir); + vectoangles(movedir, moveresult->ideal_viewangles); + moveresult->flags |= MOVERESULT_MOVEMENTVIEW; + moveresult->flags |= MOVERESULT_MOVEMENTWEAPON; + //select the machinegun and shoot + trap_EA_SelectWeapon(bs->client, WEAPONINDEX_PHASER); + if (bs->cur_ps.weapon == WEAPONINDEX_PHASER) { + trap_EA_Attack(bs->client); + } + return; + } + } + //just some basic dynamic obstacle avoidance code + hordir[0] = moveresult->movedir[0]; + hordir[1] = moveresult->movedir[1]; + hordir[2] = 0; + //if no direction just take a random direction + if (VectorNormalize(hordir) < 0.1) { + VectorSet(angles, 0, 360 * random(), 0); + AngleVectors(angles, hordir, NULL, NULL); + } + // + //if (moveresult->flags & MOVERESULT_ONTOPOFOBSTACLE) movetype = MOVE_JUMP; + //else + movetype = MOVE_WALK; + //if there's an obstacle at the bot's feet and head then + //the bot might be able to crouch through + VectorCopy(bs->origin, start); + start[2] += 18; + VectorMA(start, 5, hordir, end); + VectorSet(mins, -16, -16, -24); + VectorSet(maxs, 16, 16, 4); + // + //bsptrace = AAS_Trace(start, mins, maxs, end, bs->entitynum, MASK_PLAYERSOLID); + //if (bsptrace.fraction >= 1) movetype = MOVE_CROUCH; + //get the sideward vector + CrossProduct(hordir, up, sideward); + // + if (bs->flags & BFL_AVOIDRIGHT) VectorNegate(sideward, sideward); + //try to crouch straight forward? + if (movetype != MOVE_CROUCH || !trap_BotMoveInDirection(bs->ms, hordir, 400, movetype)) { + //perform the movement + if (!trap_BotMoveInDirection(bs->ms, sideward, 400, movetype)) { + //flip the avoid direction flag + bs->flags ^= BFL_AVOIDRIGHT; + //flip the direction + VectorNegate(sideward, sideward); + //move in the other direction + trap_BotMoveInDirection(bs->ms, sideward, 400, movetype); + } + } + // + if (bs->notblocked_time < trap_AAS_Time() - 0.4) { + //just reset goals and hope the bot will go into another direction + //is this still needed?? + if (bs->ainode == AINode_Seek_NBG) bs->nbg_time = 0; + else if (bs->ainode == AINode_Seek_LTG) bs->ltg_time = 0; + } +} + +/* +================== +BotCheckConsoleMessages +================== +*/ +void BotCheckConsoleMessages(bot_state_t *bs) { + char botname[MAX_NETNAME], message[MAX_MESSAGE_SIZE], netname[MAX_NETNAME], *ptr; + float chat_reply; + int context, handle; + bot_consolemessage_t m; + bot_match_t match; + + //the name of this bot + ClientName(bs->client, botname, sizeof(botname)); + // + while((handle = trap_BotNextConsoleMessage(bs->cs, &m)) != 0) { + //if the chat state is flooded with messages the bot will read them quickly + if (trap_BotNumConsoleMessages(bs->cs) < 10) { + //if it is a chat message the bot needs some time to read it + if (m.type == CMS_CHAT && m.time > trap_AAS_Time() - (1 + random())) break; + } + // + ptr = m.message; + //if it is a chat message then don't unify white spaces and don't + //replace synonyms in the netname + if (m.type == CMS_CHAT) { + // + if (trap_BotFindMatch(m.message, &match, MTCONTEXT_REPLYCHAT)) { + ptr = m.message + match.variables[MESSAGE].offset; + } + } + //unify the white spaces in the message + trap_UnifyWhiteSpaces(ptr); + //replace synonyms in the right context + context = CONTEXT_NORMAL|CONTEXT_NEARBYITEM|CONTEXT_NAMES; + if (BotCTFTeam(bs) == CTF_TEAM_RED) context |= CONTEXT_CTFREDTEAM; + else context |= CONTEXT_CTFBLUETEAM; + trap_BotReplaceSynonyms(ptr, context); + //if there's no match + if (!BotMatchMessage(bs, m.message)) { + //if it is a chat message + if (m.type == CMS_CHAT && !bot_nochat.integer) { + // + if (!trap_BotFindMatch(m.message, &match, MTCONTEXT_REPLYCHAT)) { + trap_BotRemoveConsoleMessage(bs->cs, handle); + continue; + } + //don't use eliza chats with team messages + if (match.subtype & ST_TEAM) { + trap_BotRemoveConsoleMessage(bs->cs, handle); + continue; + } + // + trap_BotMatchVariable(&match, NETNAME, netname, sizeof(netname)); + trap_BotMatchVariable(&match, MESSAGE, message, sizeof(message)); + //if this is a message from the bot self + if (!Q_stricmp(netname, botname)) { + trap_BotRemoveConsoleMessage(bs->cs, handle); + continue; + } + //unify the message + trap_UnifyWhiteSpaces(message); + // + trap_Cvar_Update(&bot_testrchat); + if (bot_testrchat.integer) { + // + trap_BotLibVarSet("bot_testrchat", "1"); + //if bot replies with a chat message + if (trap_BotReplyChat(bs->cs, message, context, CONTEXT_REPLY, + NULL, NULL, + NULL, NULL, + NULL, NULL, + botname, netname)) { + BotAI_Print(PRT_MESSAGE, "------------------------\n"); + } + else { + BotAI_Print(PRT_MESSAGE, "**** no valid reply ****\n"); + } + } + //if at a valid chat position and not chatting already + else if (bs->ainode != AINode_Stand && BotValidChatPosition(bs)) { + chat_reply = 0; + if (random() < 1.5 / (NumBots()+1) && random() < chat_reply) { + //if bot replies with a chat message + if (trap_BotReplyChat(bs->cs, message, context, CONTEXT_REPLY, + NULL, NULL, + NULL, NULL, + NULL, NULL, + botname, netname)) { + //remove the console message + trap_BotRemoveConsoleMessage(bs->cs, handle); + bs->stand_time = trap_AAS_Time() + BotChatTime(bs); + AIEnter_Stand(bs); + //EA_Say(bs->client, bs->cs.chatmessage); + break; + } + } + } + } + } + //remove the console message + trap_BotRemoveConsoleMessage(bs->cs, handle); + } +} + +/* +================== +BotCheckEvents +================== +*/ +void BotCheckEvents(bot_state_t *bs, entityState_t *state) { + int event; + char buf[128]; + // + //NOTE: this sucks, we're accessing the gentity_t directly + //but there's no other fast way to do it right now + if (bs->entityeventTime[state->number] == g_entities[state->number].eventTime) { + return; + } + bs->entityeventTime[state->number] = g_entities[state->number].eventTime; + //if it's an event only entity + if (state->eType > ET_EVENTS) { + event = (state->eType - ET_EVENTS) & ~EV_EVENT_BITS; + } + else { + event = state->event & ~EV_EVENT_BITS; + } + // + switch(event) { + //client obituary event + case EV_OBITUARY: + { + int target, attacker, mod; + + target = state->otherEntityNum; + attacker = state->otherEntityNum2; + mod = state->eventParm; + // + if (target == bs->client) { + bs->botdeathtype = mod; + bs->lastkilledby = attacker; + // + if (target == attacker) bs->botsuicide = qtrue; + else bs->botsuicide = qfalse; + // + bs->num_deaths++; + } + //else if this client was killed by the bot + else if (attacker == bs->client) { + bs->enemydeathtype = mod; + bs->lastkilledplayer = target; + bs->killedenemy_time = trap_AAS_Time(); + // + bs->num_kills++; + } + else if (attacker == bs->enemy && target == attacker) { + bs->enemysuicide = qtrue; + } + break; + } + + case EV_GLOBAL_SOUND: + { + if (state->eventParm < 0 || state->eventParm > MAX_SOUNDS) { + BotAI_Print(PRT_ERROR, "EV_GLOBAL_SOUND: eventParm (%d) out of range\n", state->eventParm); + break; + } + else { + trap_GetConfigstring(CS_SOUNDS + state->eventParm, buf, sizeof(buf)); + if (!strcmp(buf, "sound/items/poweruprespawn.wav")) { + //powerup respawned... go get it + BotGoForPowerups(bs); + } + } + break; + } + + case EV_TEAM_SOUND: + { + if (state->eventParm < 0 || state->eventParm > MAX_TEAM_SOUNDS) { + BotAI_Print(PRT_ERROR, "EV_TEAM_SOUND: eventParm (%d) out of range\n", state->eventParm); + break; + } + + if (state->eventParm == RETURN_FLAG_SOUND) + { + if (state->otherEntityNum == TEAM_RED) + { + //red flag is returned + bs->redflagstatus = 0; + bs->flagstatuschanged = qtrue; + } + else + { + //blue flag is returned + bs->blueflagstatus = 0; + bs->flagstatuschanged = qtrue; + } + } + break; + } + + + + case EV_PLAYER_TELEPORT_IN: + { + VectorCopy(state->origin, lastteleport_origin); + lastteleport_time = trap_AAS_Time(); + break; + } + case EV_GENERAL_SOUND: + { + //if this sound is played on the bot + if (state->number == bs->client) { + if (state->eventParm < 0 || state->eventParm > MAX_SOUNDS) { + BotAI_Print(PRT_ERROR, "EV_GENERAL_SOUND: eventParm (%d) out of range\n", state->eventParm); + break; + } + //check out the sound + trap_GetConfigstring(CS_SOUNDS + state->eventParm, buf, sizeof(buf)); + //if falling into a death pit + if (!strcmp(buf, "*falling1.wav")) { + //if the bot has a personal teleporter + if (bs->inventory[INVENTORY_TRANSPORTER] > 0) { + //use the holdable item + trap_EA_Use(bs->client); + } + } + } + break; + } + } +} + +/* +================== +BotCheckSnapshot +================== +*/ +void BotCheckSnapshot(bot_state_t *bs) { + int ent; + entityState_t state; + + // + ent = 0; + while( ( ent = BotAI_GetSnapshotEntity( bs->client, ent, &state ) ) != -1 ) { + //check the entity state for events + BotCheckEvents(bs, &state); + } + //check the player state for events + BotAI_GetEntityState(bs->client, &state); + //copy the player state events to the entity state + state.event = bs->cur_ps.externalEvent; + state.eventParm = bs->cur_ps.externalEventParm; + // + BotCheckEvents(bs, &state); +} + +/* +================== +BotCheckAir +================== +*/ +void BotCheckAir(bot_state_t *bs) { + if (bs->inventory[INVENTORY_ENVIRONMENTSUIT] <= 0) { + if (trap_AAS_PointContents(bs->eye) & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA)) { + return; + } + } + bs->lastair_time = trap_AAS_Time(); +} + +/* +================== +BotDeathmatchAI +================== +*/ +void BotDeathmatchAI(bot_state_t *bs, float thinktime) { + char gender[144], name[144], buf[144]; + char userinfo[MAX_INFO_STRING]; + int i; + + //if the bot has just been setup + if (bs->setupcount > 0) { + bs->setupcount--; + if (bs->setupcount > 0) return; + //get the gender characteristic + trap_Characteristic_String(bs->character, CHARACTERISTIC_GENDER, gender, sizeof(gender)); + //set the bot gender + trap_GetUserinfo(bs->client, userinfo, sizeof(userinfo)); + Info_SetValueForKey(userinfo, "sex", gender); + trap_SetUserinfo(bs->client, userinfo); + //set the team + if ( g_gametype.integer != GT_TOURNAMENT ) { + Com_sprintf(buf, sizeof(buf), "team %s", bs->settings.team); + trap_EA_Command(bs->client, buf); + } + if ( g_pModSpecialties.integer ) { + Com_sprintf(buf, sizeof(buf), "class %s", bs->settings.pclass); + trap_EA_Command(bs->client, buf); + } + //set the chat gender + if (gender[0] == 'm') trap_BotSetChatGender(bs->cs, CHAT_GENDERMALE); + else if (gender[0] == 'f') trap_BotSetChatGender(bs->cs, CHAT_GENDERFEMALE); + else trap_BotSetChatGender(bs->cs, CHAT_GENDERLESS); + //set the chat name + ClientName(bs->client, name, sizeof(name)); + trap_BotSetChatName(bs->cs, name); + // + bs->lastframe_health = bs->inventory[INVENTORY_HEALTH]; + bs->lasthitcount = bs->cur_ps.persistant[PERS_HITS]; + // + bs->setupcount = 0; + } + //no ideal view set + bs->flags &= ~BFL_IDEALVIEWSET; + //set the teleport time + BotSetTeleportTime(bs); + //update some inventory values + BotUpdateInventory(bs); + //check the console messages + BotCheckConsoleMessages(bs); + //check out the snapshot + BotCheckSnapshot(bs); + //check for air + BotCheckAir(bs); + //if not in the intermission and not in observer mode + if (!BotIntermission(bs) && !BotIsObserver(bs)) { + //do team AI + BotTeamAI(bs); + } + //if the bot has no ai node + if (!bs->ainode) { + AIEnter_Seek_LTG(bs); + } + //if the bot entered the game less than 8 seconds ago + if (!bs->entergamechat && bs->entergame_time > trap_AAS_Time() - 8) { + if (BotChat_EnterGame(bs)) { + bs->stand_time = trap_AAS_Time() + BotChatTime(bs); + AIEnter_Stand(bs); + } + bs->entergamechat = qtrue; + } + //reset the node switches from the previous frame + BotResetNodeSwitches(); + //execute AI nodes + for (i = 0; i < MAX_NODESWITCHES; i++) { + if (bs->ainode(bs)) break; + } + //if the bot removed itself :) + if (!bs->inuse) return; + //if the bot executed too many AI nodes + if (i >= MAX_NODESWITCHES) { + trap_BotDumpGoalStack(bs->gs); + trap_BotDumpAvoidGoals(bs->gs); + BotDumpNodeSwitches(bs); + ClientName(bs->client, name, sizeof(name)); + BotAI_Print(PRT_ERROR, "%s at %1.1f switched more than %d AI nodes\n", name, trap_AAS_Time(), MAX_NODESWITCHES); + } + // + bs->lastframe_health = bs->inventory[INVENTORY_HEALTH]; + bs->lasthitcount = bs->cur_ps.persistant[PERS_HITS]; +} + +/* +================== +BotSetupDeathmatchAI +================== +*/ +void BotSetupDeathmatchAI(void) { + int ent, modelnum; + char model[128]; + + gametype = trap_Cvar_VariableIntegerValue("g_gametype"); + maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); + + trap_Cvar_Register(&bot_rocketjump, "bot_rocketjump", "1", 0); + trap_Cvar_Register(&bot_grapple, "bot_grapple", "0", 0); + trap_Cvar_Register(&bot_fastchat, "bot_fastchat", "0", 0); + trap_Cvar_Register(&bot_nochat, "bot_nochat", "0", 0); + trap_Cvar_Register(&bot_testrchat, "bot_testrchat", "0", 0); + trap_Cvar_Register(&bot_challenge, "bot_challenge", "0", 0); + // + if (gametype == GT_CTF) { + if (trap_BotGetLevelItemGoal(-1, "Red Flag", &ctf_redflag) < 0) + BotAI_Print(PRT_WARNING, "CTF without Red Flag\n"); + if (trap_BotGetLevelItemGoal(-1, "Blue Flag", &ctf_blueflag) < 0) + BotAI_Print(PRT_WARNING, "CTF without Blue Flag\n"); + } + + max_bspmodelindex = 0; + for (ent = trap_AAS_NextBSPEntity(0); ent; ent = trap_AAS_NextBSPEntity(ent)) { + if (!trap_AAS_ValueForBSPEpairKey(ent, "model", model, sizeof(model))) continue; + if (model[0] == '*') { + modelnum = atoi(model+1); + if (modelnum > max_bspmodelindex) + max_bspmodelindex = modelnum; + } + } + //initialize the waypoint heap + BotInitWaypoints(); +} + +/* +================== +BotShutdownDeathmatchAI +================== +*/ +void BotShutdownDeathmatchAI(void) { +} + diff --git a/code/game/ai_dmq3.h b/code/game/ai_dmq3.h index e124b1a..4769b4a 100644 --- a/code/game/ai_dmq3.h +++ b/code/game/ai_dmq3.h @@ -1,24 +1,4 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // /***************************************************************************** @@ -26,153 +6,102 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * desc: Quake3 bot AI * - * $Archive: /source/code/botai/ai_chat.c $ + * $Archive: /StarTrek/Code-DM/game/ai_dmq3.h $ + * $Author: Dkramer $ + * $Revision: 2 $ + * $Modtime: 6/21/00 4:35p $ + * $Date: 6/27/00 10:06a $ * *****************************************************************************/ -//setup the deathmatch AI +//!setup the deathmatch AI void BotSetupDeathmatchAI(void); -//shutdown the deathmatch AI +//!shutdown the deathmatch AI void BotShutdownDeathmatchAI(void); -//let the bot live within its deathmatch AI net +//!let the bot live within it's deathmatch AI net void BotDeathmatchAI(bot_state_t *bs, float thinktime); -//free waypoints +//!free waypoints void BotFreeWaypoints(bot_waypoint_t *wp); -//choose a weapon +//!choose a weapon void BotChooseWeapon(bot_state_t *bs); -//setup movement stuff +//!setup movement stuff void BotSetupForMovement(bot_state_t *bs); -//update the inventory +//!update the inventory void BotUpdateInventory(bot_state_t *bs); -//update the inventory during battle +//!update the inventory during battle void BotUpdateBattleInventory(bot_state_t *bs, int enemy); -//use holdable items during battle +//! should I detonate the detpack now +qboolean BotShouldDetonateDetPack(bot_state_t *bs); +//!use holdable items during battle void BotBattleUseItems(bot_state_t *bs); -//return true if the bot is dead +//!return true if the bot is dead qboolean BotIsDead(bot_state_t *bs); -//returns true if the bot is in observer mode +//!returns true if the bot is in observer mode qboolean BotIsObserver(bot_state_t *bs); -//returns true if the bot is in the intermission +//!returns true if the bot is in the intermission qboolean BotIntermission(bot_state_t *bs); -//returns true if the bot is in lava or slime +//!returns true if the bot is in lava or slime qboolean BotInLavaOrSlime(bot_state_t *bs); -//returns true if the entity is dead +//!returns true if the entity is dead qboolean EntityIsDead(aas_entityinfo_t *entinfo); -//returns true if the entity is invisible +//!returns true if the entity is invisible qboolean EntityIsInvisible(aas_entityinfo_t *entinfo); -//returns true if the entity is shooting +//!returns true if the entity is shooting qboolean EntityIsShooting(aas_entityinfo_t *entinfo); -#ifdef MISSIONPACK -//returns true if this entity has the kamikaze -qboolean EntityHasKamikaze(aas_entityinfo_t *entinfo); -#endif -// set a user info key/value pair -void BotSetUserInfo(bot_state_t *bs, char *key, char *value); -// set the team status (offense, defense etc.) -void BotSetTeamStatus(bot_state_t *bs); -//returns the name of the client +//!returns the name of the client char *ClientName(int client, char *name, int size); -//returns an simplyfied client name +//!returns an simplyfied client name char *EasyClientName(int client, char *name, int size); -//returns the skin used by the client +//!returns the skin used by the client char *ClientSkin(int client, char *skin, int size); -// returns the appropriate synonym context for the current game type and situation -int BotSynonymContext(bot_state_t *bs); -// set last ordered task -int BotSetLastOrderedTask(bot_state_t *bs); -// selection of goals for teamplay -void BotTeamGoals(bot_state_t *bs, int retreat); -//returns the aggression of the bot in the range [0, 100] +//!returns the aggression of the bot in the range [0, 100] float BotAggression(bot_state_t *bs); -//returns how bad the bot feels -float BotFeelingBad(bot_state_t *bs); -//returns true if the bot wants to retreat +//!returns true if the bot wants to retreat int BotWantsToRetreat(bot_state_t *bs); -//returns true if the bot wants to chase +//!returns true if the bot wants to chase int BotWantsToChase(bot_state_t *bs); -//returns true if the bot wants to help +//!returns true if the bot wants to help int BotWantsToHelp(bot_state_t *bs); -//returns true if the bot can and wants to rocketjump +//!returns true if the bot can and wants to rocketjump int BotCanAndWantsToRocketJump(bot_state_t *bs); -// returns true if the bot has a persistant powerup and a weapon -int BotHasPersistantPowerupAndWeapon(bot_state_t *bs); -//returns true if the bot wants to and goes camping +//!returns true if the bot wants to and goes camping int BotWantsToCamp(bot_state_t *bs); -//the bot will perform attack movements +//!the bot will perform attack movements bot_moveresult_t BotAttackMove(bot_state_t *bs, int tfl); -//returns true if the bot and the entity are in the same team +//!returns true if the bot and the entity are in the same team int BotSameTeam(bot_state_t *bs, int entnum); -//returns true if teamplay is on +//!returns true if teamplay is on int TeamPlayIsOn(void); -// returns the client number of the team mate flag carrier (-1 if none) -int BotTeamFlagCarrier(bot_state_t *bs); -//returns visible team mate flag carrier if available +//!returns visible team mate flag carrier if available int BotTeamFlagCarrierVisible(bot_state_t *bs); -//returns visible enemy flag carrier if available -int BotEnemyFlagCarrierVisible(bot_state_t *bs); -//get the number of visible teammates and enemies -void BotVisibleTeamMatesAndEnemies(bot_state_t *bs, int *teammates, int *enemies, float range); -//returns true if within the field of vision for the given angles -qboolean InFieldOfVision(vec3_t viewangles, float fov, vec3_t angles); -//returns true and sets the .enemy field when an enemy is found +//!returns true and sets the .enemy field when an enemy is found int BotFindEnemy(bot_state_t *bs, int curenemy); -//returns a roam goal +//!returns a roam goal void BotRoamGoal(bot_state_t *bs, vec3_t goal); -//returns entity visibility in the range [0, 1] +//!returns entity visibility in the range [0, 1] float BotEntityVisible(int viewer, vec3_t eye, vec3_t viewangles, float fov, int ent); -//the bot will aim at the current enemy +//!the bot will aim at the current enemy void BotAimAtEnemy(bot_state_t *bs); -//check if the bot should attack +//!check if the bot should attack void BotCheckAttack(bot_state_t *bs); -//AI when the bot is blocked +//!AI when the bot is blocked void BotAIBlocked(bot_state_t *bs, bot_moveresult_t *moveresult, int activate); -//AI to predict obstacles -int BotAIPredictObstacles(bot_state_t *bs, bot_goal_t *goal); -//enable or disable the areas the blocking entity is in -void BotEnableActivateGoalAreas(bot_activategoal_t *activategoal, int enable); -//pop an activate goal from the stack -int BotPopFromActivateGoalStack(bot_state_t *bs); -//clear the activate goal stack -void BotClearActivateGoalStack(bot_state_t *bs); -//returns the team the bot is in -int BotTeam(bot_state_t *bs); -//retuns the opposite team of the bot -int BotOppositeTeam(bot_state_t *bs); -//returns the flag the bot is carrying (CTFFLAG_?) +//!returns the CTF team the bot is in +int BotCTFTeam(bot_state_t *bs); +//!returns the flag the bot is carrying (CTFFLAG_?) int BotCTFCarryingFlag(bot_state_t *bs); -//remember the last ordered task -void BotRememberLastOrderedTask(bot_state_t *bs); -//set ctf goals (defend base, get enemy flag) during seek +//!set ctf goals (defend base, get enemy flag) during seek void BotCTFSeekGoals(bot_state_t *bs); -//set ctf goals (defend base, get enemy flag) during retreat +//!set ctf goals (defend base, get enemy flag) during retreat void BotCTFRetreatGoals(bot_state_t *bs); -// -#ifdef MISSIONPACK -int Bot1FCTFCarryingFlag(bot_state_t *bs); -int BotHarvesterCarryingCubes(bot_state_t *bs); -void Bot1FCTFSeekGoals(bot_state_t *bs); -void Bot1FCTFRetreatGoals(bot_state_t *bs); -void BotObeliskSeekGoals(bot_state_t *bs); -void BotObeliskRetreatGoals(bot_state_t *bs); -void BotGoHarvest(bot_state_t *bs); -void BotHarvesterSeekGoals(bot_state_t *bs); -void BotHarvesterRetreatGoals(bot_state_t *bs); -int BotTeamCubeCarrierVisible(bot_state_t *bs); -int BotEnemyCubeCarrierVisible(bot_state_t *bs); -#endif -//get a random alternate route goal towards the given base -int BotGetAlternateRouteGoal(bot_state_t *bs, int base); -//returns either the alternate route goal or the given goal -bot_goal_t *BotAlternateRoute(bot_state_t *bs, bot_goal_t *goal); -//create a new waypoint +//!create a new waypoint bot_waypoint_t *BotCreateWayPoint(char *name, vec3_t origin, int areanum); -//find a waypoint with the given name +//!find a waypoint with the given name bot_waypoint_t *BotFindWayPoint(bot_waypoint_t *waypoints, char *name); -//strstr but case insensitive +//!strstr but case insensitive char *stristr(char *str, char *charset); -//returns the number of the client with the given name +//!returns the number of the client with the given name int ClientFromName(char *name); -int ClientOnSameTeamFromName(bot_state_t *bs, char *name); // int BotPointAreaNum(vec3_t origin); // @@ -185,9 +114,13 @@ void BotMapScripts(bot_state_t *bs); //CTF skins #define CTF_SKIN_REDTEAM "red" #define CTF_SKIN_BLUETEAM "blue" +//CTF teams +#define CTF_TEAM_NONE 0 +#define CTF_TEAM_RED 1 +#define CTF_TEAM_BLUE 2 -extern int gametype; //game type -extern int maxclients; //maximum number of clients +extern int gametype; //!cs, type, mcontext, vars[0], vars[1], vars[2], vars[3], vars[4], vars[5], vars[6], vars[7] ); } @@ -243,31 +221,23 @@ void QDECL BotAI_BotInitialChat( bot_state_t *bs, char *type, ... ) { /* ================== -BotTestAAS +BotTestSolid ================== */ -void BotTestAAS(vec3_t origin) { +void BotTestSolid(vec3_t origin) { int areanum; - aas_areainfo_t info; + + if( !bot_setupComplete ) { + return; + } trap_Cvar_Update(&bot_testsolid); - trap_Cvar_Update(&bot_testclusters); if (bot_testsolid.integer) { if (!trap_AAS_Initialized()) return; areanum = BotPointAreaNum(origin); if (areanum) BotAI_Print(PRT_MESSAGE, "\remtpy area"); else BotAI_Print(PRT_MESSAGE, "\r^1SOLID area"); } - else if (bot_testclusters.integer) { - if (!trap_AAS_Initialized()) return; - areanum = BotPointAreaNum(origin); - if (!areanum) - BotAI_Print(PRT_MESSAGE, "\r^1Solid! "); - else { - trap_AAS_AreaInfo(areanum, &info); - BotAI_Print(PRT_MESSAGE, "\rarea %d, cluster %d ", areanum, info.cluster); - } - } } /* @@ -278,34 +248,18 @@ BotReportStatus void BotReportStatus(bot_state_t *bs) { char goalname[MAX_MESSAGE_SIZE]; char netname[MAX_MESSAGE_SIZE]; - char *leader, flagstatus[32]; + char *leader, *flagstatus; // ClientName(bs->client, netname, sizeof(netname)); if (Q_stricmp(netname, bs->teamleader) == 0) leader = "L"; else leader = " "; - - strcpy(flagstatus, " "); - if (gametype == GT_CTF) { - if (BotCTFCarryingFlag(bs)) { - if (BotTeam(bs) == TEAM_RED) strcpy(flagstatus, S_COLOR_RED"F "); - else strcpy(flagstatus, S_COLOR_BLUE"F "); - } + if (BotCTFCarryingFlag(bs)) { + if (BotCTFTeam(bs) == TEAM_RED) flagstatus = S_COLOR_RED"F"; + else flagstatus = S_COLOR_BLUE"F"; } -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF) { - if (Bot1FCTFCarryingFlag(bs)) { - if (BotTeam(bs) == TEAM_RED) strcpy(flagstatus, S_COLOR_RED"F "); - else strcpy(flagstatus, S_COLOR_BLUE"F "); - } + else { + flagstatus = " "; } - else if (gametype == GT_HARVESTER) { - if (BotHarvesterCarryingCubes(bs)) { - if (BotTeam(bs) == TEAM_RED) Com_sprintf(flagstatus, sizeof(flagstatus), S_COLOR_RED"%2d", bs->inventory[INVENTORY_REDCUBE]); - else Com_sprintf(flagstatus, sizeof(flagstatus), S_COLOR_BLUE"%2d", bs->inventory[INVENTORY_BLUECUBE]); - } - } -#endif - switch(bs->ltgtype) { case LTG_TEAMHELP: { @@ -363,16 +317,6 @@ void BotReportStatus(bot_state_t *bs) { BotAI_Print(PRT_MESSAGE, "%-20s%s%s: returning flag\n", netname, leader, flagstatus); break; } - case LTG_ATTACKENEMYBASE: - { - BotAI_Print(PRT_MESSAGE, "%-20s%s%s: attacking the enemy base\n", netname, leader, flagstatus); - break; - } - case LTG_HARVEST: - { - BotAI_Print(PRT_MESSAGE, "%-20s%s%s: harvesting\n", netname, leader, flagstatus); - break; - } default: { BotAI_Print(PRT_MESSAGE, "%-20s%s%s: roaming\n", netname, leader, flagstatus); @@ -418,146 +362,6 @@ void BotTeamplayReport(void) { } } -/* -================== -BotSetInfoConfigString -================== -*/ -void BotSetInfoConfigString(bot_state_t *bs) { - char goalname[MAX_MESSAGE_SIZE]; - char netname[MAX_MESSAGE_SIZE]; - char action[MAX_MESSAGE_SIZE]; - char *leader, carrying[32], *cs; - bot_goal_t goal; - // - ClientName(bs->client, netname, sizeof(netname)); - if (Q_stricmp(netname, bs->teamleader) == 0) leader = "L"; - else leader = " "; - - strcpy(carrying, " "); - if (gametype == GT_CTF) { - if (BotCTFCarryingFlag(bs)) { - strcpy(carrying, "F "); - } - } -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF) { - if (Bot1FCTFCarryingFlag(bs)) { - strcpy(carrying, "F "); - } - } - else if (gametype == GT_HARVESTER) { - if (BotHarvesterCarryingCubes(bs)) { - if (BotTeam(bs) == TEAM_RED) Com_sprintf(carrying, sizeof(carrying), "%2d", bs->inventory[INVENTORY_REDCUBE]); - else Com_sprintf(carrying, sizeof(carrying), "%2d", bs->inventory[INVENTORY_BLUECUBE]); - } - } -#endif - - switch(bs->ltgtype) { - case LTG_TEAMHELP: - { - EasyClientName(bs->teammate, goalname, sizeof(goalname)); - Com_sprintf(action, sizeof(action), "helping %s", goalname); - break; - } - case LTG_TEAMACCOMPANY: - { - EasyClientName(bs->teammate, goalname, sizeof(goalname)); - Com_sprintf(action, sizeof(action), "accompanying %s", goalname); - break; - } - case LTG_DEFENDKEYAREA: - { - trap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname)); - Com_sprintf(action, sizeof(action), "defending %s", goalname); - break; - } - case LTG_GETITEM: - { - trap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname)); - Com_sprintf(action, sizeof(action), "getting item %s", goalname); - break; - } - case LTG_KILL: - { - ClientName(bs->teamgoal.entitynum, goalname, sizeof(goalname)); - Com_sprintf(action, sizeof(action), "killing %s", goalname); - break; - } - case LTG_CAMP: - case LTG_CAMPORDER: - { - Com_sprintf(action, sizeof(action), "camping"); - break; - } - case LTG_PATROL: - { - Com_sprintf(action, sizeof(action), "patrolling"); - break; - } - case LTG_GETFLAG: - { - Com_sprintf(action, sizeof(action), "capturing flag"); - break; - } - case LTG_RUSHBASE: - { - Com_sprintf(action, sizeof(action), "rushing base"); - break; - } - case LTG_RETURNFLAG: - { - Com_sprintf(action, sizeof(action), "returning flag"); - break; - } - case LTG_ATTACKENEMYBASE: - { - Com_sprintf(action, sizeof(action), "attacking the enemy base"); - break; - } - case LTG_HARVEST: - { - Com_sprintf(action, sizeof(action), "harvesting"); - break; - } - default: - { - trap_BotGetTopGoal(bs->gs, &goal); - trap_BotGoalName(goal.number, goalname, sizeof(goalname)); - Com_sprintf(action, sizeof(action), "roaming %s", goalname); - break; - } - } - cs = va("l\\%s\\c\\%s\\a\\%s", - leader, - carrying, - action); - trap_SetConfigstring (CS_BOTINFO + bs->client, cs); -} - -/* -============== -BotUpdateInfoConfigStrings -============== -*/ -void BotUpdateInfoConfigStrings(void) { - int i; - char buf[MAX_INFO_STRING]; - - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - // - if ( !botstates[i] || !botstates[i]->inuse ) - continue; - // - trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf)); - //if no config string or no name - if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) - continue; - BotSetInfoConfigString(botstates[i]); - } -} - /* ============== BotInterbreedBots @@ -663,7 +467,7 @@ void BotInterbreeding(void) { //shutdown all the bots for (i = 0; i < MAX_CLIENTS; i++) { if (botstates[i] && botstates[i]->inuse) { - BotAIShutdownClient(botstates[i]->client, qfalse); + BotAIShutdownClient(botstates[i]->client); } } //make sure all item weight configs are reloaded and Not shared @@ -761,48 +565,25 @@ BotChangeViewAngles ============== */ void BotChangeViewAngles(bot_state_t *bs, float thinktime) { - float diff, factor, maxchange, anglespeed, disired_speed; + float diff, factor, maxchange, anglespeed; int i; if (bs->ideal_viewangles[PITCH] > 180) bs->ideal_viewangles[PITCH] -= 360; - // - if (bs->enemy >= 0) { - factor = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_VIEW_FACTOR, 0.01f, 1); - maxchange = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_VIEW_MAXCHANGE, 1, 1800); - } - else { - factor = 0.05f; - maxchange = 360; - } - if (maxchange < 240) maxchange = 240; + + factor = 1; + maxchange = 1800; + maxchange *= thinktime; - for (i = 0; i < 2; i++) { - // - if (bot_challenge.integer) { - //smooth slowdown view model - diff = abs(AngleDifference(bs->viewangles[i], bs->ideal_viewangles[i])); - anglespeed = diff * factor; - if (anglespeed > maxchange) anglespeed = maxchange; - bs->viewangles[i] = BotChangeViewAngle(bs->viewangles[i], - bs->ideal_viewangles[i], anglespeed); - } - else { - //over reaction view model - bs->viewangles[i] = AngleMod(bs->viewangles[i]); - bs->ideal_viewangles[i] = AngleMod(bs->ideal_viewangles[i]); - diff = AngleDifference(bs->viewangles[i], bs->ideal_viewangles[i]); - disired_speed = diff * factor; - bs->viewanglespeed[i] += (bs->viewanglespeed[i] - disired_speed); - if (bs->viewanglespeed[i] > 180) bs->viewanglespeed[i] = maxchange; - if (bs->viewanglespeed[i] < -180) bs->viewanglespeed[i] = -maxchange; - anglespeed = bs->viewanglespeed[i]; - if (anglespeed > maxchange) anglespeed = maxchange; - if (anglespeed < -maxchange) anglespeed = -maxchange; - bs->viewangles[i] += anglespeed; - bs->viewangles[i] = AngleMod(bs->viewangles[i]); - //demping - bs->viewanglespeed[i] *= 0.45 * (1 - factor); + for (i = 0; i < 2; i++) + { + //smooth slowdown view model + diff = abs(AngleDifference(bs->viewangles[i], bs->ideal_viewangles[i])); + anglespeed = diff * factor; + if (anglespeed > maxchange) + { + anglespeed = maxchange; } + bs->viewangles[i] = BotChangeViewAngle(bs->viewangles[i], bs->ideal_viewangles[i], anglespeed); //BotAI_Print(PRT_MESSAGE, "ideal_angles %f %f\n", bs->ideal_viewangles[0], bs->ideal_viewangles[1], bs->ideal_viewangles[2]);` //bs->viewangles[i] = bs->ideal_viewangles[i]; } @@ -821,10 +602,11 @@ void BotInputToUserCommand(bot_input_t *bi, usercmd_t *ucmd, int delta_angles[3] vec3_t angles, forward, right; short temp; int j; - float f, r, u, m; //clear the whole structure memset(ucmd, 0, sizeof(usercmd_t)); + // + //Com_Printf("dir = %f %f %f speed = %f\n", bi->dir[0], bi->dir[1], bi->dir[2], bi->speed); //the duration for the user command in milli seconds ucmd->serverTime = time; // @@ -839,13 +621,11 @@ void BotInputToUserCommand(bot_input_t *bi, usercmd_t *ucmd, int delta_angles[3] if (bi->actionflags & ACTION_GESTURE) ucmd->buttons |= BUTTON_GESTURE; if (bi->actionflags & ACTION_USE) ucmd->buttons |= BUTTON_USE_HOLDABLE; if (bi->actionflags & ACTION_WALK) ucmd->buttons |= BUTTON_WALKING; - if (bi->actionflags & ACTION_AFFIRMATIVE) ucmd->buttons |= BUTTON_AFFIRMATIVE; - if (bi->actionflags & ACTION_NEGATIVE) ucmd->buttons |= BUTTON_NEGATIVE; - if (bi->actionflags & ACTION_GETFLAG) ucmd->buttons |= BUTTON_GETFLAG; - if (bi->actionflags & ACTION_GUARDBASE) ucmd->buttons |= BUTTON_GUARDBASE; - if (bi->actionflags & ACTION_PATROL) ucmd->buttons |= BUTTON_PATROL; - if (bi->actionflags & ACTION_FOLLOWME) ucmd->buttons |= BUTTON_FOLLOWME; - // + if (bi->actionflags & ACTION_ALT_ATTACK) + { + ucmd->buttons |= BUTTON_ALT_ATTACK; + } + ucmd->weapon = bi->weapon; //set the view angles //NOTE: the ucmd->angles are the angles WITHOUT the delta angles @@ -875,37 +655,21 @@ void BotInputToUserCommand(bot_input_t *bi, usercmd_t *ucmd, int delta_angles[3] //bot input speed is in the range [0, 400] bi->speed = bi->speed * 127 / 400; //set the view independent movement - f = DotProduct(forward, bi->dir); - r = DotProduct(right, bi->dir); - u = abs(forward[2]) * bi->dir[2]; - m = fabs(f); - - if (fabs(r) > m) { - m = fabs(r); - } - - if (fabs(u) > m) { - m = fabs(u); - } - - if (m > 0) { - f *= bi->speed / m; - r *= bi->speed / m; - u *= bi->speed / m; - } - - ucmd->forwardmove = f; - ucmd->rightmove = r; - ucmd->upmove = u; - - if (bi->actionflags & ACTION_MOVEFORWARD) ucmd->forwardmove = 127; - if (bi->actionflags & ACTION_MOVEBACK) ucmd->forwardmove = -127; - if (bi->actionflags & ACTION_MOVELEFT) ucmd->rightmove = -127; - if (bi->actionflags & ACTION_MOVERIGHT) ucmd->rightmove = 127; + ucmd->forwardmove = DotProduct(forward, bi->dir) * bi->speed; + ucmd->rightmove = DotProduct(right, bi->dir) * bi->speed; + ucmd->upmove = abs(forward[2]) * bi->dir[2] * bi->speed; + //normal keyboard movement + if (bi->actionflags & ACTION_MOVEFORWARD) ucmd->forwardmove += 127; + if (bi->actionflags & ACTION_MOVEBACK) ucmd->forwardmove -= 127; + if (bi->actionflags & ACTION_MOVELEFT) ucmd->rightmove -= 127; + if (bi->actionflags & ACTION_MOVERIGHT) ucmd->rightmove += 127; //jump/moveup - if (bi->actionflags & ACTION_JUMP) ucmd->upmove = 127; + if (bi->actionflags & ACTION_JUMP) ucmd->upmove += 127; //crouch/movedown - if (bi->actionflags & ACTION_CROUCH) ucmd->upmove = -127; + if (bi->actionflags & ACTION_CROUCH) ucmd->upmove -= 127; + // + //Com_Printf("forward = %d right = %d up = %d\n", ucmd.forwardmove, ucmd.rightmove, ucmd.upmove); + //Com_Printf("ucmd->serverTime = %d\n", ucmd->serverTime); } /* @@ -943,33 +707,12 @@ BotAIRegularUpdate ============== */ void BotAIRegularUpdate(void) { - if (regularupdate_time < FloatTime()) { + if (regularupdate_time < trap_AAS_Time()) { trap_BotUpdateEntityItems(); - regularupdate_time = FloatTime() + 0.3; + regularupdate_time = trap_AAS_Time() + 0.3; } } -/* -============== -RemoveColorEscapeSequences -============== -*/ -void RemoveColorEscapeSequences( char *text ) { - int i, l; - - l = 0; - for ( i = 0; text[i]; i++ ) { - if (Q_IsColorString(&text[i])) { - i++; - continue; - } - if (text[i] > 0x7E) - continue; - text[l++] = text[i]; - } - text[l] = '\0'; -} - /* ============== BotAI @@ -991,15 +734,15 @@ int BotAI(int client, float thinktime) { //retrieve the current client state BotAI_GetClientState( client, &bs->cur_ps ); - //retrieve any waiting server commands - while( trap_BotGetServerCommand(client, buf, sizeof(buf)) ) { + //retrieve any waiting console messages + while( trap_BotGetConsoleMessage(client, buf, sizeof(buf)) ) { //have buf point to the command and args to the command arguments args = strchr( buf, ' '); if (!args) continue; *args++ = '\0'; //remove color espace sequences from the arguments - RemoveColorEscapeSequences( args ); + Q_CleanStr( args ); if (!Q_stricmp(buf, "cp ")) { /*CenterPrintf*/ } @@ -1023,17 +766,6 @@ int BotAI(int client, float thinktime) { args[strlen(args)-1] = '\0'; trap_BotQueueConsoleMessage(bs->cs, CMS_CHAT, args); } -#ifdef MISSIONPACK - else if (!Q_stricmp(buf, "vchat")) { - BotVoiceChatCommand(bs, SAY_ALL, args); - } - else if (!Q_stricmp(buf, "vtchat")) { - BotVoiceChatCommand(bs, SAY_TEAM, args); - } - else if (!Q_stricmp(buf, "vtell")) { - BotVoiceChatCommand(bs, SAY_TELL, args); - } -#endif else if (!Q_stricmp(buf, "scores")) { /*FIXME: parse scores?*/ } else if (!Q_stricmp(buf, "clientLevelShot")) @@ -1086,94 +818,21 @@ void BotScheduleBotThink(void) { } } -/* -============== -BotWriteSessionData -============== -*/ -void BotWriteSessionData(bot_state_t *bs) { - const char *s; - const char *var; - - s = va( - "%i %i %i %i %i %i %i %i" - " %f %f %f" - " %f %f %f" - " %f %f %f", - bs->lastgoal_decisionmaker, - bs->lastgoal_ltgtype, - bs->lastgoal_teammate, - bs->lastgoal_teamgoal.areanum, - bs->lastgoal_teamgoal.entitynum, - bs->lastgoal_teamgoal.flags, - bs->lastgoal_teamgoal.iteminfo, - bs->lastgoal_teamgoal.number, - bs->lastgoal_teamgoal.origin[0], - bs->lastgoal_teamgoal.origin[1], - bs->lastgoal_teamgoal.origin[2], - bs->lastgoal_teamgoal.mins[0], - bs->lastgoal_teamgoal.mins[1], - bs->lastgoal_teamgoal.mins[2], - bs->lastgoal_teamgoal.maxs[0], - bs->lastgoal_teamgoal.maxs[1], - bs->lastgoal_teamgoal.maxs[2] - ); - - var = va( "botsession%i", bs->client ); - - trap_Cvar_Set( var, s ); -} - -/* -============== -BotReadSessionData -============== -*/ -void BotReadSessionData(bot_state_t *bs) { - char s[MAX_STRING_CHARS]; - const char *var; - - var = va( "botsession%i", bs->client ); - trap_Cvar_VariableStringBuffer( var, s, sizeof(s) ); - - sscanf(s, - "%i %i %i %i %i %i %i %i" - " %f %f %f" - " %f %f %f" - " %f %f %f", - &bs->lastgoal_decisionmaker, - &bs->lastgoal_ltgtype, - &bs->lastgoal_teammate, - &bs->lastgoal_teamgoal.areanum, - &bs->lastgoal_teamgoal.entitynum, - &bs->lastgoal_teamgoal.flags, - &bs->lastgoal_teamgoal.iteminfo, - &bs->lastgoal_teamgoal.number, - &bs->lastgoal_teamgoal.origin[0], - &bs->lastgoal_teamgoal.origin[1], - &bs->lastgoal_teamgoal.origin[2], - &bs->lastgoal_teamgoal.mins[0], - &bs->lastgoal_teamgoal.mins[1], - &bs->lastgoal_teamgoal.mins[2], - &bs->lastgoal_teamgoal.maxs[0], - &bs->lastgoal_teamgoal.maxs[1], - &bs->lastgoal_teamgoal.maxs[2] - ); -} - /* ============== BotAISetupClient ============== */ -int BotAISetupClient(int client, struct bot_settings_s *settings, qboolean restart) { - char filename[MAX_PATH], name[MAX_PATH], gender[MAX_PATH]; +int BotAISetupClient(int client, struct bot_settings_s *settings) { + char filename[AI_MAX_PATH], name[AI_MAX_PATH], gender[AI_MAX_PATH]; bot_state_t *bs; int errnum; if (!botstates[client]) botstates[client] = G_Alloc(sizeof(bot_state_t)); bs = botstates[client]; + if(!bs) return qfalse; + if (bs && bs->inuse) { BotAI_Print(PRT_FATAL, "BotAISetupClient: client %d already setup\n", client); return qfalse; @@ -1187,7 +846,7 @@ int BotAISetupClient(int client, struct bot_settings_s *settings, qboolean resta //load the bot character bs->character = trap_BotLoadCharacter(settings->characterfile, settings->skill); if (!bs->character) { - BotAI_Print(PRT_FATAL, "couldn't load skill %f from %s\n", settings->skill, settings->characterfile); + BotAI_Print(PRT_FATAL, "couldn't load skill %d from %s\n", settings->skill, settings->characterfile); return qfalse; } //copy the settings @@ -1195,7 +854,7 @@ int BotAISetupClient(int client, struct bot_settings_s *settings, qboolean resta //allocate a goal state bs->gs = trap_BotAllocGoalState(client); //load the item weights - trap_Characteristic_String(bs->character, CHARACTERISTIC_ITEMWEIGHTS, filename, MAX_PATH); + trap_Characteristic_String(bs->character, CHARACTERISTIC_ITEMWEIGHTS, filename, AI_MAX_PATH); errnum = trap_BotLoadItemWeights(bs->gs, filename); if (errnum != BLERR_NOERROR) { trap_BotFreeGoalState(bs->gs); @@ -1204,7 +863,7 @@ int BotAISetupClient(int client, struct bot_settings_s *settings, qboolean resta //allocate a weapon state bs->ws = trap_BotAllocWeaponState(); //load the weapon weights - trap_Characteristic_String(bs->character, CHARACTERISTIC_WEAPONWEIGHTS, filename, MAX_PATH); + trap_Characteristic_String(bs->character, CHARACTERISTIC_WEAPONWEIGHTS, filename, AI_MAX_PATH); errnum = trap_BotLoadWeaponWeights(bs->ws, filename); if (errnum != BLERR_NOERROR) { trap_BotFreeGoalState(bs->gs); @@ -1214,8 +873,8 @@ int BotAISetupClient(int client, struct bot_settings_s *settings, qboolean resta //allocate a chat state bs->cs = trap_BotAllocChatState(); //load the chat file - trap_Characteristic_String(bs->character, CHARACTERISTIC_CHAT_FILE, filename, MAX_PATH); - trap_Characteristic_String(bs->character, CHARACTERISTIC_CHAT_NAME, name, MAX_PATH); + trap_Characteristic_String(bs->character, CHARACTERISTIC_CHAT_FILE, filename, AI_MAX_PATH); + trap_Characteristic_String(bs->character, CHARACTERISTIC_CHAT_NAME, name, AI_MAX_PATH); errnum = trap_BotLoadChatFile(bs->cs, filename, name); if (errnum != BLERR_NOERROR) { trap_BotFreeChatState(bs->cs); @@ -1224,7 +883,7 @@ int BotAISetupClient(int client, struct bot_settings_s *settings, qboolean resta return qfalse; } //get the gender characteristic - trap_Characteristic_String(bs->character, CHARACTERISTIC_GENDER, gender, MAX_PATH); + trap_Characteristic_String(bs->character, CHARACTERISTIC_GENDER, gender, AI_MAX_PATH); //set the chat gender if (*gender == 'f' || *gender == 'F') trap_BotSetChatGender(bs->cs, CHAT_GENDERFEMALE); else if (*gender == 'm' || *gender == 'M') trap_BotSetChatGender(bs->cs, CHAT_GENDERMALE); @@ -1234,9 +893,9 @@ int BotAISetupClient(int client, struct bot_settings_s *settings, qboolean resta bs->client = client; bs->entitynum = client; bs->setupcount = 4; - bs->entergame_time = FloatTime(); + bs->entergame_time = trap_AAS_Time(); bs->ms = trap_BotAllocMoveState(); - bs->walker = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_WALKER, 0, 1); + bs->walker = 0; numbots++; if (trap_Cvar_VariableIntegerValue("bot_testichat")) { @@ -1249,10 +908,6 @@ int BotAISetupClient(int client, struct bot_settings_s *settings, qboolean resta if (bot_interbreed) { trap_BotMutateGoalFuzzyLogic(bs->gs, 1); } - // if we kept the bot client - if (restart) { - BotReadSessionData(bs); - } //bot has been setup succesfully return qtrue; } @@ -1262,7 +917,7 @@ int BotAISetupClient(int client, struct bot_settings_s *settings, qboolean resta BotAIShutdownClient ============== */ -int BotAIShutdownClient(int client, qboolean restart) { +int BotAIShutdownClient(int client) { bot_state_t *bs; bs = botstates[client]; @@ -1271,10 +926,6 @@ int BotAIShutdownClient(int client, qboolean restart) { return qfalse; } - if (restart) { - BotWriteSessionData(bs); - } - if (BotChat_ExitGame(bs)) { trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL); } @@ -1291,8 +942,6 @@ int BotAIShutdownClient(int client, qboolean restart) { // BotFreeWaypoints(bs->checkpoints); BotFreeWaypoints(bs->patrolpoints); - //clear activate goal stack - BotClearActivateGoalStack(bs); //clear the bot state memset(bs, 0, sizeof(bot_state_t)); //set the inuse flag to qfalse @@ -1382,10 +1031,6 @@ int BotAILoadMap( int restart ) { return qtrue; } -#ifdef MISSIONPACK -void ProximityMine_Trigger( gentity_t *trigger, gentity_t *other, trace_t *trace ); -#endif - /* ================== BotAIStartFrame @@ -1409,14 +1054,12 @@ int BotAIStartFrame(int time) { trap_Cvar_Update(&bot_testrchat); trap_Cvar_Update(&bot_thinktime); trap_Cvar_Update(&bot_memorydump); - trap_Cvar_Update(&bot_saveroutingcache); trap_Cvar_Update(&bot_pause); trap_Cvar_Update(&bot_report); if (bot_report.integer) { -// BotTeamplayReport(); -// trap_Cvar_Set("bot_report", "0"); - BotUpdateInfoConfigStrings(); + BotTeamplayReport(); + trap_Cvar_Set("bot_report", "0"); } if (bot_pause.integer) { @@ -1442,10 +1085,6 @@ int BotAIStartFrame(int time) { trap_BotLibVarSet("memorydump", "1"); trap_Cvar_Set("bot_memorydump", "0"); } - if (bot_saveroutingcache.integer) { - trap_BotLibVarSet("saveroutingcache", "1"); - trap_Cvar_Set("bot_saveroutingcache", "0"); - } //check if bot interbreeding is activated BotInterbreeding(); //cap the bot think time @@ -1490,7 +1129,7 @@ int BotAIStartFrame(int time) { continue; } // do not update missiles - if (ent->s.eType == ET_MISSILE && ent->s.weapon != WP_GRAPPLING_HOOK) { + if (ent->s.eType == ET_MISSILE) { trap_BotLibUpdateEntity(i, NULL); continue; } @@ -1499,15 +1138,6 @@ int BotAIStartFrame(int time) { trap_BotLibUpdateEntity(i, NULL); continue; } -#ifdef MISSIONPACK - // never link prox mine triggers - if (ent->r.contents == CONTENTS_TRIGGER) { - if (ent->touch == ProximityMine_Trigger) { - trap_BotLibUpdateEntity(i, NULL); - continue; - } - } -#endif // memset(&state, 0, sizeof(bot_entitystate_t)); // @@ -1541,8 +1171,6 @@ int BotAIStartFrame(int time) { BotAIRegularUpdate(); } - floattime = trap_AAS_Time(); - // execute scheduled bot AI for( i = 0; i < MAX_CLIENTS; i++ ) { if( !botstates[i] || !botstates[i]->inuse ) { @@ -1585,7 +1213,8 @@ BotInitLibrary ============== */ int BotInitLibrary(void) { - char buf[144]; + int gt; + char buf[144]; //set the maxclients and maxentities library variables before calling BotSetupLibrary trap_Cvar_VariableStringBuffer("sv_maxclients", buf, sizeof(buf)); @@ -1603,16 +1232,25 @@ int BotInitLibrary(void) { trap_Cvar_VariableStringBuffer("max_levelitems", buf, sizeof(buf)); if (strlen(buf)) trap_BotLibVarSet("max_levelitems", buf); //game type - trap_Cvar_VariableStringBuffer("g_gametype", buf, sizeof(buf)); - if (!strlen(buf)) strcpy(buf, "0"); - trap_BotLibVarSet("g_gametype", buf); + gt = trap_Cvar_VariableIntegerValue("g_gametype"); + if( gt == GT_SINGLE_PLAYER ) { + gt = AIGT_SINGLE_PLAYER; + } + else if( gt >= GT_TEAM ) { + gt = AIGT_TEAM; + } + else { + gt = AIGT_OTHER; + } + trap_BotLibVarSet("ai_gametype", va("%i", gt)); //bot developer mode and log file - trap_BotLibVarSet("bot_developer", bot_developer.string); - trap_Cvar_VariableStringBuffer("logfile", buf, sizeof(buf)); + trap_Cvar_VariableStringBuffer("bot_developer", buf, sizeof(buf)); + if (!strlen(buf)) strcpy(buf, "0"); + trap_BotLibVarSet("bot_developer", buf); trap_BotLibVarSet("log", buf); //no chatting trap_Cvar_VariableStringBuffer("bot_nochat", buf, sizeof(buf)); - if (strlen(buf)) trap_BotLibVarSet("nochat", buf); + if (strlen(buf)) trap_BotLibVarSet("nochat", "0"); //visualize jump pads trap_Cvar_VariableStringBuffer("bot_visualizejumppads", buf, sizeof(buf)); if (strlen(buf)) trap_BotLibVarSet("bot_visualizejumppads", buf); @@ -1628,9 +1266,6 @@ int BotInitLibrary(void) { //no AAS optimization trap_Cvar_VariableStringBuffer("bot_aasoptimize", buf, sizeof(buf)); if (strlen(buf)) trap_BotLibVarSet("aasoptimize", buf); - // - trap_Cvar_VariableStringBuffer("bot_saveroutingcache", buf, sizeof(buf)); - if (strlen(buf)) trap_BotLibVarSet("saveroutingcache", buf); //reload instead of cache bot character files trap_Cvar_VariableStringBuffer("bot_reloadcharacters", buf, sizeof(buf)); if (!strlen(buf)) strcpy(buf, "0"); @@ -1641,13 +1276,9 @@ int BotInitLibrary(void) { //game directory trap_Cvar_VariableStringBuffer("fs_game", buf, sizeof(buf)); if (strlen(buf)) trap_BotLibVarSet("gamedir", buf); - //home directory - trap_Cvar_VariableStringBuffer("fs_homepath", buf, sizeof(buf)); - if (strlen(buf)) trap_BotLibVarSet("homedir", buf); - // -#ifdef MISSIONPACK - trap_BotLibDefine("MISSIONPACK"); -#endif + //cd directory + trap_Cvar_VariableStringBuffer("fs_cdpath", buf, sizeof(buf)); + if (strlen(buf)) trap_BotLibVarSet("cddir", buf); //setup the bot library return trap_BotLibSetup(); } @@ -1660,14 +1291,17 @@ BotAISetup int BotAISetup( int restart ) { int errnum; +#ifdef RANDOMIZE + srand((unsigned)time(NULL)); +#endif //RANDOMIZE + + bot_setupComplete = qtrue; + trap_Cvar_Register(&bot_thinktime, "bot_thinktime", "100", CVAR_CHEAT); trap_Cvar_Register(&bot_memorydump, "bot_memorydump", "0", CVAR_CHEAT); - trap_Cvar_Register(&bot_saveroutingcache, "bot_saveroutingcache", "0", CVAR_CHEAT); trap_Cvar_Register(&bot_pause, "bot_pause", "0", CVAR_CHEAT); trap_Cvar_Register(&bot_report, "bot_report", "0", CVAR_CHEAT); trap_Cvar_Register(&bot_testsolid, "bot_testsolid", "0", CVAR_CHEAT); - trap_Cvar_Register(&bot_testclusters, "bot_testclusters", "0", CVAR_CHEAT); - trap_Cvar_Register(&bot_developer, "bot_developer", "0", CVAR_CHEAT); trap_Cvar_Register(&bot_interbreedchar, "bot_interbreedchar", "", 0); trap_Cvar_Register(&bot_interbreedbots, "bot_interbreedbots", "10", 0); trap_Cvar_Register(&bot_interbreedcycle, "bot_interbreedcycle", "20", 0); @@ -1700,7 +1334,7 @@ int BotAIShutdown( int restart ) { //shutdown all the bots in the botlib for (i = 0; i < MAX_CLIENTS; i++) { if (botstates[i] && botstates[i]->inuse) { - BotAIShutdownClient(botstates[i]->client, restart); + BotAIShutdownClient(botstates[i]->client); } } //don't shutdown the bot library diff --git a/code/game/ai_main.h b/code/game/ai_main.h index ff258a0..f682376 100644 --- a/code/game/ai_main.h +++ b/code/game/ai_main.h @@ -1,24 +1,4 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // /***************************************************************************** @@ -26,7 +6,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * desc: Quake3 bot AI * - * $Archive: /source/code/botai/ai_chat.c $ + * $Archive: /StarTrek/Code-DM/game/ai_main.h $ + * $Author: Jmonroe $ + * $Revision: 1 $ + * $Modtime: 1/21/00 10:12p $ + * $Date: 1/25/00 6:26p $ * *****************************************************************************/ @@ -35,61 +19,53 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define MAX_ITEMS 256 //bot flags -#define BFL_STRAFERIGHT 1 //strafe to the right -#define BFL_ATTACKED 2 //bot has attacked last ai frame -#define BFL_ATTACKJUMPED 4 //bot jumped during attack last frame -#define BFL_AIMATENEMY 8 //bot aimed at the enemy this frame -#define BFL_AVOIDRIGHT 16 //avoid obstacles by going to the right -#define BFL_IDEALVIEWSET 32 //bot has ideal view angles set -#define BFL_FIGHTSUICIDAL 64 //bot is in a suicidal fight +#define BFL_STRAFERIGHT 1 //!= numteammates) { + traveltimes[j] = traveltime; + teammates[j] = i; + } numteammates++; if (numteammates >= maxteammates) break; } @@ -180,10 +150,10 @@ int BotSortTeamMatesByBaseTravelTime(bot_state_t *bs, int *teammates, int maxtea /* ================== -BotSetTeamMateTaskPreference +BotGetTeamMateCTFPreference ================== */ -void BotSetTeamMateTaskPreference(bot_state_t *bs, int teammate, int preference) { +void BotSetTeamMateCTFPreference(bot_state_t *bs, int teammate, int preference) { char teammatename[MAX_NETNAME]; ctftaskpreferences[teammate].preference = preference; @@ -193,10 +163,10 @@ void BotSetTeamMateTaskPreference(bot_state_t *bs, int teammate, int preference) /* ================== -BotGetTeamMateTaskPreference +BotGetTeamMateCTFPreference ================== */ -int BotGetTeamMateTaskPreference(bot_state_t *bs, int teammate) { +int BotGetTeamMateCTFPreference(bot_state_t *bs, int teammate) { char teammatename[MAX_NETNAME]; if (!ctftaskpreferences[teammate].preference) return 0; @@ -207,10 +177,10 @@ int BotGetTeamMateTaskPreference(bot_state_t *bs, int teammate) { /* ================== -BotSortTeamMatesByTaskPreference +BotSortTeamMatesByCTFPreference ================== */ -int BotSortTeamMatesByTaskPreference(bot_state_t *bs, int *teammates, int numteammates) { +int BotSortTeamMatesByCTFPreference(bot_state_t *bs, int *teammates, int numteammates) { int defenders[MAX_CLIENTS], numdefenders; int attackers[MAX_CLIENTS], numattackers; int roamers[MAX_CLIENTS], numroamers; @@ -218,11 +188,11 @@ int BotSortTeamMatesByTaskPreference(bot_state_t *bs, int *teammates, int numtea numdefenders = numattackers = numroamers = 0; for (i = 0; i < numteammates; i++) { - preference = BotGetTeamMateTaskPreference(bs, teammates[i]); - if (preference & TEAMTP_DEFENDER) { + preference = BotGetTeamMateCTFPreference(bs, teammates[i]); + if (preference & CTFTP_DEFENDER) { defenders[numdefenders++] = teammates[i]; } - else if (preference & TEAMTP_ATTACKER) { + else if (preference & CTFTP_ATTACKER) { attackers[numattackers++] = teammates[i]; } else { @@ -231,13 +201,13 @@ int BotSortTeamMatesByTaskPreference(bot_state_t *bs, int *teammates, int numtea } numteammates = 0; //defenders at the front of the list - memcpy(&teammates[numteammates], defenders, numdefenders * sizeof(int)); + memcpy(&teammates[numteammates], defenders, numdefenders); numteammates += numdefenders; //roamers in the middle - memcpy(&teammates[numteammates], roamers, numroamers * sizeof(int)); + memcpy(&teammates[numteammates], roamers, numroamers); numteammates += numroamers; //attacker in the back of the list - memcpy(&teammates[numteammates], attackers, numattackers * sizeof(int)); + memcpy(&teammates[numteammates], attackers, numattackers); numteammates += numattackers; return numteammates; @@ -248,7 +218,7 @@ int BotSortTeamMatesByTaskPreference(bot_state_t *bs, int *teammates, int numtea BotSayTeamOrders ================== */ -void BotSayTeamOrderAlways(bot_state_t *bs, int toclient) { +void BotSayTeamOrder(bot_state_t *bs, int toclient) { char teamchat[MAX_MESSAGE_SIZE]; char buf[MAX_MESSAGE_SIZE]; char name[MAX_NETNAME]; @@ -258,73 +228,14 @@ void BotSayTeamOrderAlways(bot_state_t *bs, int toclient) { //don't show the message just put it in the console message queue trap_BotGetChatMessage(bs->cs, buf, sizeof(buf)); ClientName(bs->client, name, sizeof(name)); - Com_sprintf(teamchat, sizeof(teamchat), EC"(%s"EC")"EC": %s", name, buf); + Com_sprintf(teamchat, sizeof(teamchat), "(%s): %s", name, buf); trap_BotQueueConsoleMessage(bs->cs, CMS_CHAT, teamchat); } else { - trap_BotEnterChat(bs->cs, toclient, CHAT_TELL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); } } -/* -================== -BotSayTeamOrders -================== -*/ -void BotSayTeamOrder(bot_state_t *bs, int toclient) { -#ifdef MISSIONPACK - // voice chats only - char buf[MAX_MESSAGE_SIZE]; - - trap_BotGetChatMessage(bs->cs, buf, sizeof(buf)); -#else - BotSayTeamOrderAlways(bs, toclient); -#endif -} - -/* -================== -BotVoiceChat -================== -*/ -void BotVoiceChat(bot_state_t *bs, int toclient, char *voicechat) { -#ifdef MISSIONPACK - if (toclient == -1) - // voice only say team - trap_EA_Command(bs->client, va("vsay_team %s", voicechat)); - else - // voice only tell single player - trap_EA_Command(bs->client, va("vtell %d %s", toclient, voicechat)); -#endif -} - -/* -================== -BotVoiceChatOnly -================== -*/ -void BotVoiceChatOnly(bot_state_t *bs, int toclient, char *voicechat) { -#ifdef MISSIONPACK - if (toclient == -1) - // voice only say team - trap_EA_Command(bs->client, va("vosay_team %s", voicechat)); - else - // voice only tell single player - trap_EA_Command(bs->client, va("votell %d %s", toclient, voicechat)); -#endif -} - -/* -================== -BotSayVoiceTeamOrder -================== -*/ -void BotSayVoiceTeamOrder(bot_state_t *bs, int toclient, char *voicechat) { -#ifdef MISSIONPACK - BotVoiceChat(bs, toclient, voicechat); -#endif -} - /* ================== BotCTFOrders @@ -336,7 +247,7 @@ void BotCTFOrders_BothFlagsNotAtBase(bot_state_t *bs) { char name[MAX_NETNAME], carriername[MAX_NETNAME]; numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates)); - BotSortTeamMatesByTaskPreference(bs, teammates, numteammates); + BotSortTeamMatesByCTFPreference(bs, teammates, numteammates); //different orders based on the number of team mates switch(bs->numteammates) { case 1: break; @@ -348,7 +259,6 @@ void BotCTFOrders_BothFlagsNotAtBase(bot_state_t *bs) { ClientName(other, name, sizeof(name)); BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); BotSayTeamOrder(bs, other); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_GETFLAG); break; } case 3: @@ -357,21 +267,12 @@ void BotCTFOrders_BothFlagsNotAtBase(bot_state_t *bs) { if (teammates[0] != bs->flagcarrier) other = teammates[0]; else other = teammates[1]; ClientName(other, name, sizeof(name)); - if ( bs->flagcarrier != -1 ) { - ClientName(bs->flagcarrier, carriername, sizeof(carriername)); - if (bs->flagcarrier == bs->client) { - BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWME); - } - else { - BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWFLAGCARRIER); - } + ClientName(bs->flagcarrier, carriername, sizeof(carriername)); + if (bs->flagcarrier == bs->client) { + BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL); } else { - // - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_GETFLAG); + BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL); } BotSayTeamOrder(bs, other); //tell the one furthest from the the base not carrying the flag to get the enemy flag @@ -380,47 +281,28 @@ void BotCTFOrders_BothFlagsNotAtBase(bot_state_t *bs) { ClientName(other, name, sizeof(name)); BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); BotSayTeamOrder(bs, other); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_RETURNFLAG); break; } default: { defenders = (int) (float) numteammates * 0.4 + 0.5; - if (defenders > 4) defenders = 4; + if (defenders > 1) defenders = 1; attackers = (int) (float) numteammates * 0.5 + 0.5; - if (attackers > 5) attackers = 5; - if (bs->flagcarrier != -1) { - ClientName(bs->flagcarrier, carriername, sizeof(carriername)); - for (i = 0; i < defenders; i++) { - // - if (teammates[i] == bs->flagcarrier) { - continue; - } - // - ClientName(teammates[i], name, sizeof(name)); - if (bs->flagcarrier == bs->client) { - BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_FOLLOWME); - } - else { - BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_FOLLOWFLAGCARRIER); - } - BotSayTeamOrder(bs, teammates[i]); + ClientName(bs->flagcarrier, carriername, sizeof(carriername)); + for (i = 0; i < defenders; i++) { + // + if (teammates[i] == bs->flagcarrier) { + continue; } - } - else { - for (i = 0; i < defenders; i++) { - // - if (teammates[i] == bs->flagcarrier) { - continue; - } - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_GETFLAG); - BotSayTeamOrder(bs, teammates[i]); + // + ClientName(teammates[i], name, sizeof(name)); + if (bs->flagcarrier == bs->client) { + BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL); } + else { + BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL); + } + BotSayTeamOrder(bs, teammates[i]); } for (i = 0; i < attackers; i++) { // @@ -431,7 +313,6 @@ void BotCTFOrders_BothFlagsNotAtBase(bot_state_t *bs) { ClientName(teammates[numteammates - i - 1], name, sizeof(name)); BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_RETURNFLAG); } // break; @@ -450,132 +331,60 @@ void BotCTFOrders_FlagNotAtBase(bot_state_t *bs) { char name[MAX_NETNAME]; numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates)); - BotSortTeamMatesByTaskPreference(bs, teammates, numteammates); - //passive strategy - if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) { - //different orders based on the number of team mates - switch(bs->numteammates) { - case 1: break; - case 2: - { - // keep one near the base for when the flag is returned - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - // - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG); - break; - } - case 3: - { - //keep one near the base for when the flag is returned - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the other two get the flag - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG); - // - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG); - break; - } - default: - { - //keep some people near the base for when the flag is returned - defenders = (int) (float) numteammates * 0.3 + 0.5; - if (defenders > 3) defenders = 3; - attackers = (int) (float) numteammates * 0.6 + 0.5; - if (attackers > 6) attackers = 6; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG); - } - // - break; - } + BotSortTeamMatesByCTFPreference(bs, teammates, numteammates); + //agressive + //different orders based on the number of team mates + switch(bs->numteammates) + { + case 1: break; + case 2: + { + //both will go for the enemy flag + ClientName(teammates[0], name, sizeof(name)); + BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); + BotSayTeamOrder(bs, teammates[0]); + // + ClientName(teammates[1], name, sizeof(name)); + BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); + BotSayTeamOrder(bs, teammates[1]); + break; } - } - else { - //different orders based on the number of team mates - switch(bs->numteammates) { - case 1: break; - case 2: - { - //both will go for the enemy flag - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG); + case 3: + { + //everyone go for the flag + ClientName(teammates[0], name, sizeof(name)); + BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); + BotSayTeamOrder(bs, teammates[0]); + // + ClientName(teammates[1], name, sizeof(name)); + BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); + BotSayTeamOrder(bs, teammates[1]); + // + ClientName(teammates[2], name, sizeof(name)); + BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); + BotSayTeamOrder(bs, teammates[2]); + break; + } + default: + { + //keep some people near the base for when the flag is returned + defenders = (int) (float) numteammates * 0.2 + 0.5; + if (defenders > 1) defenders = 1; + attackers = (int) (float) numteammates * 0.7 + 0.5; + for (i = 0; i < defenders; i++) { // - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG); - break; + ClientName(teammates[i], name, sizeof(name)); + BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); + BotSayTeamOrder(bs, teammates[i]); } - case 3: - { - //everyone go for the flag - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG); + for (i = 0; i < attackers; i++) { // - ClientName(teammates[1], name, sizeof(name)); + ClientName(teammates[numteammates - i - 1], name, sizeof(name)); BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG); - // - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG); - break; - } - default: - { - //keep some people near the base for when the flag is returned - defenders = (int) (float) numteammates * 0.2 + 0.5; - if (defenders > 2) defenders = 2; - attackers = (int) (float) numteammates * 0.7 + 0.5; - if (attackers > 7) attackers = 7; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG); - } - // - break; + BotSayTeamOrder(bs, teammates[numteammates - i - 1]); } + // + break; } } } @@ -591,7 +400,7 @@ void BotCTFOrders_EnemyFlagNotAtBase(bot_state_t *bs) { char name[MAX_NETNAME], carriername[MAX_NETNAME]; numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates)); - BotSortTeamMatesByTaskPreference(bs, teammates, numteammates); + BotSortTeamMatesByCTFPreference(bs, teammates, numteammates); //different orders based on the number of team mates switch(numteammates) { case 1: break; @@ -603,7 +412,6 @@ void BotCTFOrders_EnemyFlagNotAtBase(bot_state_t *bs) { ClientName(other, name, sizeof(name)); BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); BotSayTeamOrder(bs, other); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND); break; } case 3: @@ -614,24 +422,27 @@ void BotCTFOrders_EnemyFlagNotAtBase(bot_state_t *bs) { ClientName(other, name, sizeof(name)); BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); BotSayTeamOrder(bs, other); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND); - //tell the other also to defend the base + //tell the one furthest from the base not carrying the flag to accompany the flag carrier if (teammates[2] != bs->flagcarrier) other = teammates[2]; else other = teammates[1]; ClientName(other, name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); + ClientName(bs->flagcarrier, carriername, sizeof(carriername)); + if (bs->flagcarrier == bs->client) { + BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL); + } + else { + BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL); + } BotSayTeamOrder(bs, other); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND); break; } default: { - //60% will defend the base - defenders = (int) (float) numteammates * 0.6 + 0.5; - if (defenders > 6) defenders = 6; - //30% accompanies the flag carrier - attackers = (int) (float) numteammates * 0.3 + 0.5; - if (attackers > 3) attackers = 3; + //40% will defend the base + defenders = (int) (float) numteammates * 0.4 + 0.5; + if (defenders > 1) defenders = 1; + //50% accompanies the flag carrier + attackers = (int) (float) numteammates * 0.5 + 0.5; for (i = 0; i < defenders; i++) { // if (teammates[i] == bs->flagcarrier) { @@ -640,41 +451,22 @@ void BotCTFOrders_EnemyFlagNotAtBase(bot_state_t *bs) { ClientName(teammates[i], name, sizeof(name)); BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); } - // if we have a flag carrier - if ( bs->flagcarrier != -1 ) { - ClientName(bs->flagcarrier, carriername, sizeof(carriername)); - for (i = 0; i < attackers; i++) { - // - if (teammates[numteammates - i - 1] == bs->flagcarrier) { - continue; - } - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - if (bs->flagcarrier == bs->client) { - BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWME); - } - else { - BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWFLAGCARRIER); - } - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); + ClientName(bs->flagcarrier, carriername, sizeof(carriername)); + for (i = 0; i < attackers; i++) { + // + if (teammates[numteammates - i - 1] == bs->flagcarrier) { + continue; } - } - else { - for (i = 0; i < attackers; i++) { - // - if (teammates[numteammates - i - 1] == bs->flagcarrier) { - continue; - } - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); + // + ClientName(teammates[numteammates - i - 1], name, sizeof(name)); + if (bs->flagcarrier == bs->client) { + BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL); } + else { + BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL); + } + BotSayTeamOrder(bs, teammates[numteammates - i - 1]); } // break; @@ -696,1231 +488,73 @@ void BotCTFOrders_BothFlagsAtBase(bot_state_t *bs) { //sort team mates by travel time to base numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates)); //sort team mates by CTF preference - BotSortTeamMatesByTaskPreference(bs, teammates, numteammates); - //passive strategy - if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) { - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the other will get the flag - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG); - break; - } - case 3: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the second one closest to the base will defend the base - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND); - //the other will get the flag - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG); - break; - } - default: - { - defenders = (int) (float) numteammates * 0.5 + 0.5; - if (defenders > 5) defenders = 5; - attackers = (int) (float) numteammates * 0.4 + 0.5; - if (attackers > 4) attackers = 4; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG); - } - // - break; - } - } - } - else { - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the other will get the flag - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG); - break; - } - case 3: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the others should go for the enemy flag - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG); - // - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG); - break; - } - default: - { - defenders = (int) (float) numteammates * 0.4 + 0.5; - if (defenders > 4) defenders = 4; - attackers = (int) (float) numteammates * 0.5 + 0.5; - if (attackers > 5) attackers = 5; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG); - } - // - break; - } - } - } -} - -/* -================== -BotCTFOrders -================== -*/ -void BotCTFOrders(bot_state_t *bs) { - int flagstatus; - - // - if (BotTeam(bs) == TEAM_RED) flagstatus = bs->redflagstatus * 2 + bs->blueflagstatus; - else flagstatus = bs->blueflagstatus * 2 + bs->redflagstatus; - // - switch(flagstatus) { - case 0: BotCTFOrders_BothFlagsAtBase(bs); break; - case 1: BotCTFOrders_EnemyFlagNotAtBase(bs); break; - case 2: BotCTFOrders_FlagNotAtBase(bs); break; - case 3: BotCTFOrders_BothFlagsNotAtBase(bs); break; - } -} - - -/* -================== -BotCreateGroup -================== -*/ -void BotCreateGroup(bot_state_t *bs, int *teammates, int groupsize) { - char name[MAX_NETNAME], leadername[MAX_NETNAME]; - int i; - - // the others in the group will follow the teammates[0] - ClientName(teammates[0], leadername, sizeof(leadername)); - for (i = 1; i < groupsize; i++) + BotSortTeamMatesByCTFPreference(bs, teammates, numteammates); + //agressive + //different orders based on the number of team mates + switch(numteammates) { - ClientName(teammates[i], name, sizeof(name)); - if (teammates[0] == bs->client) { - BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL); - } - else { - BotAI_BotInitialChat(bs, "cmd_accompany", name, leadername, NULL); - } - BotSayTeamOrderAlways(bs, teammates[i]); - } -} - -/* -================== -BotTeamOrders - - FIXME: defend key areas? -================== -*/ -void BotTeamOrders(bot_state_t *bs) { - int teammates[MAX_CLIENTS]; - int numteammates, i; - char buf[MAX_INFO_STRING]; - static int maxclients; - - if (!maxclients) - maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients"); - - numteammates = 0; - for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) { - trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf)); - //if no config string or no name - if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue; - //skip spectators - if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue; - // - if (BotSameTeam(bs, i)) { - teammates[numteammates] = i; - numteammates++; - } - } - // - switch(numteammates) { case 1: break; case 2: { - //nothing special + //the one closest to the base will defend the base + ClientName(teammates[0], name, sizeof(name)); + BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); + BotSayTeamOrder(bs, teammates[0]); + //the other will get the flag + ClientName(teammates[1], name, sizeof(name)); + BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); + BotSayTeamOrder(bs, teammates[1]); break; } case 3: { - //have one follow another and one free roaming - BotCreateGroup(bs, teammates, 2); - break; - } - case 4: - { - BotCreateGroup(bs, teammates, 2); //a group of 2 - BotCreateGroup(bs, &teammates[2], 2); //a group of 2 - break; - } - case 5: - { - BotCreateGroup(bs, teammates, 2); //a group of 2 - BotCreateGroup(bs, &teammates[2], 3); //a group of 3 + //the one closest to the base will defend the base + ClientName(teammates[0], name, sizeof(name)); + BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); + BotSayTeamOrder(bs, teammates[0]); + //the others should go for the enemy flag + ClientName(teammates[1], name, sizeof(name)); + BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); + BotSayTeamOrder(bs, teammates[1]); + // + ClientName(teammates[2], name, sizeof(name)); + BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); + BotSayTeamOrder(bs, teammates[2]); break; } default: { - if (numteammates <= 10) { - for (i = 0; i < numteammates / 2; i++) { - BotCreateGroup(bs, &teammates[i*2], 2); //groups of 2 - } + defenders = (int) (float) numteammates * 0.4 + 0.5; + if (defenders > 1) defenders = 1; + attackers = (int) (float) numteammates * 0.5 + 0.5; + for (i = 0; i < defenders; i++) { + // + ClientName(teammates[i], name, sizeof(name)); + BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); + BotSayTeamOrder(bs, teammates[i]); } + for (i = 0; i < attackers; i++) { + // + ClientName(teammates[numteammates - i - 1], name, sizeof(name)); + BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); + BotSayTeamOrder(bs, teammates[numteammates - i - 1]); + } + // break; } } } -#ifdef MISSIONPACK /* ================== -Bot1FCTFOrders_FlagAtCenter - - X% defend the base, Y% get the flag +BotTeamOrders ================== */ -void Bot1FCTFOrders_FlagAtCenter(bot_state_t *bs) { - int numteammates, defenders, attackers, i; - int teammates[MAX_CLIENTS]; - char name[MAX_NETNAME]; - - //sort team mates by travel time to base - numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates)); - //sort team mates by CTF preference - BotSortTeamMatesByTaskPreference(bs, teammates, numteammates); - //passive strategy - if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) { - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the other will get the flag - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG); - break; - } - case 3: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the second one closest to the base will defend the base - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the other will get the flag - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG); - break; - } - default: - { - //50% defend the base - defenders = (int) (float) numteammates * 0.5 + 0.5; - if (defenders > 5) defenders = 5; - //40% get the flag - attackers = (int) (float) numteammates * 0.4 + 0.5; - if (attackers > 4) attackers = 4; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG); - } - // - break; - } - } - } - else { //agressive - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the other will get the flag - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG); - break; - } - case 3: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the others should go for the enemy flag - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG); - // - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG); - break; - } - default: - { - //30% defend the base - defenders = (int) (float) numteammates * 0.3 + 0.5; - if (defenders > 3) defenders = 3; - //60% get the flag - attackers = (int) (float) numteammates * 0.6 + 0.5; - if (attackers > 6) attackers = 6; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG); - } - // - break; - } - } - } +void BotTeamOrders(bot_state_t *bs) { + //no teamplay orders at this time } -/* -================== -Bot1FCTFOrders_TeamHasFlag - - X% towards neutral flag, Y% go towards enemy base and accompany flag carrier if visible -================== -*/ -void Bot1FCTFOrders_TeamHasFlag(bot_state_t *bs) { - int numteammates, defenders, attackers, i, other; - int teammates[MAX_CLIENTS]; - char name[MAX_NETNAME], carriername[MAX_NETNAME]; - - //sort team mates by travel time to base - numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates)); - //sort team mates by CTF preference - BotSortTeamMatesByTaskPreference(bs, teammates, numteammates); - //passive strategy - if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) { - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //tell the one not carrying the flag to attack the enemy base - if (teammates[0] == bs->flagcarrier) other = teammates[1]; - else other = teammates[0]; - ClientName(other, name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL); - BotSayTeamOrder(bs, other); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_OFFENSE); - break; - } - case 3: - { - //tell the one closest to the base not carrying the flag to defend the base - if (teammates[0] != bs->flagcarrier) other = teammates[0]; - else other = teammates[1]; - ClientName(other, name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, other); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND); - //tell the one furthest from the base not carrying the flag to accompany the flag carrier - if (teammates[2] != bs->flagcarrier) other = teammates[2]; - else other = teammates[1]; - ClientName(other, name, sizeof(name)); - if ( bs->flagcarrier != -1 ) { - ClientName(bs->flagcarrier, carriername, sizeof(carriername)); - if (bs->flagcarrier == bs->client) { - BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWME); - } - else { - BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWFLAGCARRIER); - } - } - else { - // - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_GETFLAG); - } - BotSayTeamOrder(bs, other); - break; - } - default: - { - //30% will defend the base - defenders = (int) (float) numteammates * 0.3 + 0.5; - if (defenders > 3) defenders = 3; - //70% accompanies the flag carrier - attackers = (int) (float) numteammates * 0.7 + 0.5; - if (attackers > 7) attackers = 7; - for (i = 0; i < defenders; i++) { - // - if (teammates[i] == bs->flagcarrier) { - continue; - } - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - if (bs->flagcarrier != -1) { - ClientName(bs->flagcarrier, carriername, sizeof(carriername)); - for (i = 0; i < attackers; i++) { - // - if (teammates[numteammates - i - 1] == bs->flagcarrier) { - continue; - } - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - if (bs->flagcarrier == bs->client) { - BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWME); - } - else { - BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWFLAGCARRIER); - } - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - } - } - else { - for (i = 0; i < attackers; i++) { - // - if (teammates[numteammates - i - 1] == bs->flagcarrier) { - continue; - } - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG); - } - } - // - break; - } - } - } - else { //agressive - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //tell the one not carrying the flag to defend the base - if (teammates[0] == bs->flagcarrier) other = teammates[1]; - else other = teammates[0]; - ClientName(other, name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, other); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND); - break; - } - case 3: - { - //tell the one closest to the base not carrying the flag to defend the base - if (teammates[0] != bs->flagcarrier) other = teammates[0]; - else other = teammates[1]; - ClientName(other, name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, other); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND); - //tell the one furthest from the base not carrying the flag to accompany the flag carrier - if (teammates[2] != bs->flagcarrier) other = teammates[2]; - else other = teammates[1]; - ClientName(other, name, sizeof(name)); - ClientName(bs->flagcarrier, carriername, sizeof(carriername)); - if (bs->flagcarrier == bs->client) { - BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWME); - } - else { - BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL); - BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWFLAGCARRIER); - } - BotSayTeamOrder(bs, other); - break; - } - default: - { - //20% will defend the base - defenders = (int) (float) numteammates * 0.2 + 0.5; - if (defenders > 2) defenders = 2; - //80% accompanies the flag carrier - attackers = (int) (float) numteammates * 0.8 + 0.5; - if (attackers > 8) attackers = 8; - for (i = 0; i < defenders; i++) { - // - if (teammates[i] == bs->flagcarrier) { - continue; - } - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - ClientName(bs->flagcarrier, carriername, sizeof(carriername)); - for (i = 0; i < attackers; i++) { - // - if (teammates[numteammates - i - 1] == bs->flagcarrier) { - continue; - } - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - if (bs->flagcarrier == bs->client) { - BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWME); - } - else { - BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWFLAGCARRIER); - } - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - } - // - break; - } - } - } -} - -/* -================== -Bot1FCTFOrders_EnemyHasFlag - - X% defend the base, Y% towards neutral flag -================== -*/ -void Bot1FCTFOrders_EnemyHasFlag(bot_state_t *bs) { - int numteammates, defenders, attackers, i; - int teammates[MAX_CLIENTS]; - char name[MAX_NETNAME]; - - //sort team mates by travel time to base - numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates)); - //sort team mates by CTF preference - BotSortTeamMatesByTaskPreference(bs, teammates, numteammates); - //passive strategy - if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) { - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //both defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - // - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND); - break; - } - case 3: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the second one closest to the base will defend the base - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND); - //the other will also defend the base - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_DEFEND); - break; - } - default: - { - //80% will defend the base - defenders = (int) (float) numteammates * 0.8 + 0.5; - if (defenders > 8) defenders = 8; - //10% will try to return the flag - attackers = (int) (float) numteammates * 0.1 + 0.5; - if (attackers > 1) attackers = 1; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_returnflag", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG); - } - // - break; - } - } - } - else { //agressive - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the other will get the flag - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND); - break; - } - case 3: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the others should go for the enemy flag - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND); - // - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_returnflag", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG); - break; - } - default: - { - //70% defend the base - defenders = (int) (float) numteammates * 0.7 + 0.5; - if (defenders > 7) defenders = 7; - //20% try to return the flag - attackers = (int) (float) numteammates * 0.2 + 0.5; - if (attackers > 2) attackers = 2; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_returnflag", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG); - } - // - break; - } - } - } -} - -/* -================== -Bot1FCTFOrders_EnemyDroppedFlag - - X% defend the base, Y% get the flag -================== -*/ -void Bot1FCTFOrders_EnemyDroppedFlag(bot_state_t *bs) { - int numteammates, defenders, attackers, i; - int teammates[MAX_CLIENTS]; - char name[MAX_NETNAME]; - - //sort team mates by travel time to base - numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates)); - //sort team mates by CTF preference - BotSortTeamMatesByTaskPreference(bs, teammates, numteammates); - //passive strategy - if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) { - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the other will get the flag - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG); - break; - } - case 3: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the second one closest to the base will defend the base - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND); - //the other will get the flag - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG); - break; - } - default: - { - //50% defend the base - defenders = (int) (float) numteammates * 0.5 + 0.5; - if (defenders > 5) defenders = 5; - //40% get the flag - attackers = (int) (float) numteammates * 0.4 + 0.5; - if (attackers > 4) attackers = 4; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG); - } - // - break; - } - } - } - else { //agressive - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the other will get the flag - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG); - break; - } - case 3: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the others should go for the enemy flag - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG); - // - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG); - break; - } - default: - { - //30% defend the base - defenders = (int) (float) numteammates * 0.3 + 0.5; - if (defenders > 3) defenders = 3; - //60% get the flag - attackers = (int) (float) numteammates * 0.6 + 0.5; - if (attackers > 6) attackers = 6; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG); - } - // - break; - } - } - } -} - -/* -================== -Bot1FCTFOrders -================== -*/ -void Bot1FCTFOrders(bot_state_t *bs) { - switch(bs->neutralflagstatus) { - case 0: Bot1FCTFOrders_FlagAtCenter(bs); break; - case 1: Bot1FCTFOrders_TeamHasFlag(bs); break; - case 2: Bot1FCTFOrders_EnemyHasFlag(bs); break; - case 3: Bot1FCTFOrders_EnemyDroppedFlag(bs); break; - } -} - -/* -================== -BotObeliskOrders - - X% in defence Y% in offence -================== -*/ -void BotObeliskOrders(bot_state_t *bs) { - int numteammates, defenders, attackers, i; - int teammates[MAX_CLIENTS]; - char name[MAX_NETNAME]; - - //sort team mates by travel time to base - numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates)); - //sort team mates by CTF preference - BotSortTeamMatesByTaskPreference(bs, teammates, numteammates); - //passive strategy - if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) { - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the other will attack the enemy base - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE); - break; - } - case 3: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the one second closest to the base also defends the base - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND); - //the other one attacks the enemy base - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE); - break; - } - default: - { - //50% defend the base - defenders = (int) (float) numteammates * 0.5 + 0.5; - if (defenders > 5) defenders = 5; - //40% attack the enemy base - attackers = (int) (float) numteammates * 0.4 + 0.5; - if (attackers > 4) attackers = 4; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE); - } - // - break; - } - } - } - else { - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the other will attack the enemy base - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE); - break; - } - case 3: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the others attack the enemy base - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE); - // - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE); - break; - } - default: - { - //30% defend the base - defenders = (int) (float) numteammates * 0.3 + 0.5; - if (defenders > 3) defenders = 3; - //70% attack the enemy base - attackers = (int) (float) numteammates * 0.7 + 0.5; - if (attackers > 7) attackers = 7; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE); - } - // - break; - } - } - } -} - -/* -================== -BotHarvesterOrders - - X% defend the base, Y% harvest -================== -*/ -void BotHarvesterOrders(bot_state_t *bs) { - int numteammates, defenders, attackers, i; - int teammates[MAX_CLIENTS]; - char name[MAX_NETNAME]; - - //sort team mates by travel time to base - numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates)); - //sort team mates by CTF preference - BotSortTeamMatesByTaskPreference(bs, teammates, numteammates); - //passive strategy - if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) { - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the other will harvest - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE); - break; - } - case 3: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the one second closest to the base also defends the base - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND); - //the other one goes harvesting - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE); - break; - } - default: - { - //50% defend the base - defenders = (int) (float) numteammates * 0.5 + 0.5; - if (defenders > 5) defenders = 5; - //40% goes harvesting - attackers = (int) (float) numteammates * 0.4 + 0.5; - if (attackers > 4) attackers = 4; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE); - } - // - break; - } - } - } - else { - //different orders based on the number of team mates - switch(numteammates) { - case 1: break; - case 2: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the other will harvest - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE); - break; - } - case 3: - { - //the one closest to the base will defend the base - ClientName(teammates[0], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[0]); - BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND); - //the others go harvesting - ClientName(teammates[1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL); - BotSayTeamOrder(bs, teammates[1]); - BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE); - // - ClientName(teammates[2], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL); - BotSayTeamOrder(bs, teammates[2]); - BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE); - break; - } - default: - { - //30% defend the base - defenders = (int) (float) numteammates * 0.3 + 0.5; - if (defenders > 3) defenders = 3; - //70% go harvesting - attackers = (int) (float) numteammates * 0.7 + 0.5; - if (attackers > 7) attackers = 7; - for (i = 0; i < defenders; i++) { - // - ClientName(teammates[i], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL); - BotSayTeamOrder(bs, teammates[i]); - BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); - } - for (i = 0; i < attackers; i++) { - // - ClientName(teammates[numteammates - i - 1], name, sizeof(name)); - BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL); - BotSayTeamOrder(bs, teammates[numteammates - i - 1]); - BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE); - } - // - break; - } - } - } -} -#endif - -/* -================== -FindHumanTeamLeader -================== -*/ -int FindHumanTeamLeader(bot_state_t *bs) { - int i; - - for (i = 0; i < MAX_CLIENTS; i++) { - if ( g_entities[i].inuse ) { - // if this player is not a bot - if ( !(g_entities[i].r.svFlags & SVF_BOT) ) { - // if this player is ok with being the leader - if (!notleader[i]) { - // if this player is on the same team - if ( BotSameTeam(bs, i) ) { - ClientName(i, bs->teamleader, sizeof(bs->teamleader)); - // if not yet ordered to do anything - if ( !BotSetLastOrderedTask(bs) ) { - // go on defense by default - BotVoiceChat_Defend(bs, i, SAY_TELL); - } - return qtrue; - } - } - } - } - } - return qfalse; -} /* ================== @@ -1928,43 +562,40 @@ BotTeamAI ================== */ void BotTeamAI(bot_state_t *bs) { - int numteammates; + int numteammates, flagstatus; char netname[MAX_NETNAME]; + if(!bs) return; + // - if ( gametype < GT_TEAM ) - return; - // make sure we've got a valid team leader + if (gametype != GT_TEAM && gametype != GT_CTF) return; + //make sure we've got a valid team leader if (!BotValidTeamLeader(bs)) { // - if (!FindHumanTeamLeader(bs)) { - // - if (!bs->askteamleader_time && !bs->becometeamleader_time) { - if (bs->entergame_time + 10 > FloatTime()) { - bs->askteamleader_time = FloatTime() + 5 + random() * 10; - } - else { - bs->becometeamleader_time = FloatTime() + 5 + random() * 10; - } + if (!bs->askteamleader_time && !bs->becometeamleader_time) { + if (bs->entergame_time + 10 > trap_AAS_Time()) { + bs->askteamleader_time = trap_AAS_Time() + 5 + random() * 10; } - if (bs->askteamleader_time && bs->askteamleader_time < FloatTime()) { - // if asked for a team leader and no response - BotAI_BotInitialChat(bs, "whoisteamleader", NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - bs->askteamleader_time = 0; - bs->becometeamleader_time = FloatTime() + 8 + random() * 10; + else { + bs->becometeamleader_time = trap_AAS_Time() + 5 + random() * 10; } - if (bs->becometeamleader_time && bs->becometeamleader_time < FloatTime()) { - BotAI_BotInitialChat(bs, "iamteamleader", NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - BotSayVoiceTeamOrder(bs, -1, VOICECHAT_STARTLEADER); - ClientName(bs->client, netname, sizeof(netname)); - strncpy(bs->teamleader, netname, sizeof(bs->teamleader)); - bs->teamleader[sizeof(bs->teamleader)-1] = '\0'; - bs->becometeamleader_time = 0; - } - return; } + if (bs->askteamleader_time && bs->askteamleader_time < trap_AAS_Time()) { + //if asked for a team leader and no repsonse + BotAI_BotInitialChat(bs, "whoisteamleader", NULL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); + bs->askteamleader_time = 0; + bs->becometeamleader_time = trap_AAS_Time() + 15 + random() * 10; + } + if (bs->becometeamleader_time && bs->becometeamleader_time < trap_AAS_Time()) { + BotAI_BotInitialChat(bs, "iamteamleader", NULL); + trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM); + ClientName(bs->client, netname, sizeof(netname)); + strncpy(bs->teamleader, netname, sizeof(bs->teamleader)); + bs->teamleader[sizeof(bs->teamleader)-1] = '\0'; + bs->becometeamleader_time = 0; + } + return; } bs->askteamleader_time = 0; bs->becometeamleader_time = 0; @@ -1973,21 +604,23 @@ void BotTeamAI(bot_state_t *bs) { ClientName(bs->client, netname, sizeof(netname)); if (Q_stricmp(netname, bs->teamleader) != 0) return; // + //if the game starts OR a new player comes onto the team OR a player leaves the team + // numteammates = BotNumTeamMates(bs); //give orders switch(gametype) { case GT_TEAM: { if (bs->numteammates != numteammates || bs->forceorders) { - bs->teamgiveorders_time = FloatTime(); + bs->teamgiveorders_time = trap_AAS_Time(); bs->numteammates = numteammates; bs->forceorders = qfalse; } //if it's time to give orders - if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 5) { + if (bs->teamgiveorders_time < trap_AAS_Time() - 5) { BotTeamOrders(bs); - //give orders again after 120 seconds - bs->teamgiveorders_time = FloatTime() + 120; + // + bs->teamgiveorders_time = 0; } break; } @@ -1996,85 +629,37 @@ void BotTeamAI(bot_state_t *bs) { //if the number of team mates changed or the flag status changed //or someone wants to know what to do if (bs->numteammates != numteammates || bs->flagstatuschanged || bs->forceorders) { - bs->teamgiveorders_time = FloatTime(); + bs->teamgiveorders_time = trap_AAS_Time(); bs->numteammates = numteammates; bs->flagstatuschanged = qfalse; bs->forceorders = qfalse; } //if there were no flag captures the last 3 minutes - if (bs->lastflagcapture_time < FloatTime() - 240) { - bs->lastflagcapture_time = FloatTime(); + if (bs->lastflagcapture_time < trap_AAS_Time() - 240) { + bs->lastflagcapture_time = trap_AAS_Time(); //randomly change the CTF strategy if (random() < 0.4) { - bs->ctfstrategy ^= CTFS_AGRESSIVE; - bs->teamgiveorders_time = FloatTime(); + bs->ctfstrategy ^= CTFS_PASSIVE; + bs->teamgiveorders_time = trap_AAS_Time(); } } //if it's time to give orders - if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 3) { - BotCTFOrders(bs); + if (bs->teamgiveorders_time && bs->teamgiveorders_time < trap_AAS_Time() - 3) { + // + if (BotCTFTeam(bs) == CTF_TEAM_RED) flagstatus = bs->redflagstatus * 2 + bs->blueflagstatus; + else flagstatus = bs->blueflagstatus * 2 + bs->redflagstatus; + // + switch(flagstatus) { + case 0: BotCTFOrders_BothFlagsAtBase(bs); break; + case 1: BotCTFOrders_EnemyFlagNotAtBase(bs); break; + case 2: BotCTFOrders_FlagNotAtBase(bs); break; + case 3: BotCTFOrders_BothFlagsNotAtBase(bs); break; + } // bs->teamgiveorders_time = 0; } break; } -#ifdef MISSIONPACK - case GT_1FCTF: - { - if (bs->numteammates != numteammates || bs->flagstatuschanged || bs->forceorders) { - bs->teamgiveorders_time = FloatTime(); - bs->numteammates = numteammates; - bs->flagstatuschanged = qfalse; - bs->forceorders = qfalse; - } - //if there were no flag captures the last 4 minutes - if (bs->lastflagcapture_time < FloatTime() - 240) { - bs->lastflagcapture_time = FloatTime(); - //randomly change the CTF strategy - if (random() < 0.4) { - bs->ctfstrategy ^= CTFS_AGRESSIVE; - bs->teamgiveorders_time = FloatTime(); - } - } - //if it's time to give orders - if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 2) { - Bot1FCTFOrders(bs); - // - bs->teamgiveorders_time = 0; - } - break; - } - case GT_OBELISK: - { - if (bs->numteammates != numteammates || bs->forceorders) { - bs->teamgiveorders_time = FloatTime(); - bs->numteammates = numteammates; - bs->forceorders = qfalse; - } - //if it's time to give orders - if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 5) { - BotObeliskOrders(bs); - //give orders again after 30 seconds - bs->teamgiveorders_time = FloatTime() + 30; - } - break; - } - case GT_HARVESTER: - { - if (bs->numteammates != numteammates || bs->forceorders) { - bs->teamgiveorders_time = FloatTime(); - bs->numteammates = numteammates; - bs->forceorders = qfalse; - } - //if it's time to give orders - if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 5) { - BotHarvesterOrders(bs); - //give orders again after 30 seconds - bs->teamgiveorders_time = FloatTime() + 30; - } - break; - } -#endif } } diff --git a/code/game/ai_team.h b/code/game/ai_team.h index 252e9e1..519642e 100644 --- a/code/game/ai_team.h +++ b/code/game/ai_team.h @@ -1,24 +1,4 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // /***************************************************************************** @@ -26,14 +6,14 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * desc: Quake3 bot AI * - * $Archive: /source/code/botai/ai_chat.c $ + * $Archive: /StarTrek/Code-DM/game/ai_team.h $ + * $Author: Jmonroe $ + * $Revision: 1 $ + * $Modtime: 1/21/00 10:12p $ + * $Date: 1/25/00 6:26p $ * *****************************************************************************/ void BotTeamAI(bot_state_t *bs); -int BotGetTeamMateTaskPreference(bot_state_t *bs, int teammate); -void BotSetTeamMateTaskPreference(bot_state_t *bs, int teammate, int preference); -void BotVoiceChat(bot_state_t *bs, int toclient, char *voicechat); -void BotVoiceChatOnly(bot_state_t *bs, int toclient, char *voicechat); - - +int BotGetTeamMateCTFPreference(bot_state_t *bs, int teammate); +void BotSetTeamMateCTFPreference(bot_state_t *bs, int teammate, int preference); diff --git a/code/game/ai_vcmd.c b/code/game/ai_vcmd.c deleted file mode 100644 index 93db55f..0000000 --- a/code/game/ai_vcmd.c +++ /dev/null @@ -1,551 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// - -/***************************************************************************** - * name: ai_vcmd.c - * - * desc: Quake3 bot AI - * - * $Archive: /MissionPack/code/game/ai_vcmd.c $ - * - *****************************************************************************/ - -#include "g_local.h" -#include "../botlib/botlib.h" -#include "../botlib/be_aas.h" -#include "../botlib/be_ea.h" -#include "../botlib/be_ai_char.h" -#include "../botlib/be_ai_chat.h" -#include "../botlib/be_ai_gen.h" -#include "../botlib/be_ai_goal.h" -#include "../botlib/be_ai_move.h" -#include "../botlib/be_ai_weap.h" -// -#include "ai_main.h" -#include "ai_dmq3.h" -#include "ai_chat.h" -#include "ai_cmd.h" -#include "ai_dmnet.h" -#include "ai_team.h" -#include "ai_vcmd.h" -// -#include "chars.h" //characteristics -#include "inv.h" //indexes into the inventory -#include "syn.h" //synonyms -#include "match.h" //string matching types and vars - -// for the voice chats -#include "../../ui/menudef.h" - - -typedef struct voiceCommand_s -{ - char *cmd; - void (*func)(bot_state_t *bs, int client, int mode); -} voiceCommand_t; - -/* -================== -BotVoiceChat_GetFlag -================== -*/ -void BotVoiceChat_GetFlag(bot_state_t *bs, int client, int mode) { - // - if (gametype == GT_CTF) { - if (!ctf_redflag.areanum || !ctf_blueflag.areanum) - return; - } -#ifdef MISSIONPACK - else if (gametype == GT_1FCTF) { - if (!ctf_neutralflag.areanum || !ctf_redflag.areanum || !ctf_blueflag.areanum) - return; - } -#endif - else { - return; - } - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - //set the ltg type - bs->ltgtype = LTG_GETFLAG; - //set the team goal time - bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME; - // get an alternate route in ctf - if (gametype == GT_CTF) { - //get an alternative route goal towards the enemy base - BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs)); - } - // - BotSetTeamStatus(bs); - // remember last ordered task - BotRememberLastOrderedTask(bs); -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -BotVoiceChat_Offense -================== -*/ -void BotVoiceChat_Offense(bot_state_t *bs, int client, int mode) { - if ( gametype == GT_CTF -#ifdef MISSIONPACK - || gametype == GT_1FCTF -#endif - ) { - BotVoiceChat_GetFlag(bs, client, mode); - return; - } -#ifdef MISSIONPACK - if (gametype == GT_HARVESTER) { - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - //set the ltg type - bs->ltgtype = LTG_HARVEST; - //set the team goal time - bs->teamgoal_time = FloatTime() + TEAM_HARVEST_TIME; - bs->harvestaway_time = 0; - // - BotSetTeamStatus(bs); - // remember last ordered task - BotRememberLastOrderedTask(bs); - } - else -#endif - { - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - //set the ltg type - bs->ltgtype = LTG_ATTACKENEMYBASE; - //set the team goal time - bs->teamgoal_time = FloatTime() + TEAM_ATTACKENEMYBASE_TIME; - bs->attackaway_time = 0; - // - BotSetTeamStatus(bs); - // remember last ordered task - BotRememberLastOrderedTask(bs); - } -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -BotVoiceChat_Defend -================== -*/ -void BotVoiceChat_Defend(bot_state_t *bs, int client, int mode) { -#ifdef MISSIONPACK - if ( gametype == GT_OBELISK || gametype == GT_HARVESTER) { - // - switch(BotTeam(bs)) { - case TEAM_RED: memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t)); break; - case TEAM_BLUE: memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t)); break; - default: return; - } - } - else -#endif - if (gametype == GT_CTF -#ifdef MISSIONPACK - || gametype == GT_1FCTF -#endif - ) { - // - switch(BotTeam(bs)) { - case TEAM_RED: memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t)); break; - case TEAM_BLUE: memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t)); break; - default: return; - } - } - else { - return; - } - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - //set the ltg type - bs->ltgtype = LTG_DEFENDKEYAREA; - //get the team goal time - bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME; - //away from defending - bs->defendaway_time = 0; - // - BotSetTeamStatus(bs); - // remember last ordered task - BotRememberLastOrderedTask(bs); -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -BotVoiceChat_DefendFlag -================== -*/ -void BotVoiceChat_DefendFlag(bot_state_t *bs, int client, int mode) { - BotVoiceChat_Defend(bs, client, mode); -} - -/* -================== -BotVoiceChat_Patrol -================== -*/ -void BotVoiceChat_Patrol(bot_state_t *bs, int client, int mode) { - // - bs->decisionmaker = client; - // - bs->ltgtype = 0; - bs->lead_time = 0; - bs->lastgoal_ltgtype = 0; - // - BotAI_BotInitialChat(bs, "dismissed", NULL); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); - BotVoiceChatOnly(bs, -1, VOICECHAT_ONPATROL); - // - BotSetTeamStatus(bs); -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -BotVoiceChat_Camp -================== -*/ -void BotVoiceChat_Camp(bot_state_t *bs, int client, int mode) { - int areanum; - aas_entityinfo_t entinfo; - char netname[MAX_NETNAME]; - - // - bs->teamgoal.entitynum = -1; - BotEntityInfo(client, &entinfo); - //if info is valid (in PVS) - if (entinfo.valid) { - areanum = BotPointAreaNum(entinfo.origin); - if (areanum) { // && trap_AAS_AreaReachability(areanum)) { - //NOTE: just assume the bot knows where the person is - //if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, client)) { - bs->teamgoal.entitynum = client; - bs->teamgoal.areanum = areanum; - VectorCopy(entinfo.origin, bs->teamgoal.origin); - VectorSet(bs->teamgoal.mins, -8, -8, -8); - VectorSet(bs->teamgoal.maxs, 8, 8, 8); - //} - } - } - //if the other is not visible - if (bs->teamgoal.entitynum < 0) { - BotAI_BotInitialChat(bs, "whereareyou", EasyClientName(client, netname, sizeof(netname)), NULL); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); - return; - } - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - //set the ltg type - bs->ltgtype = LTG_CAMPORDER; - //get the team goal time - bs->teamgoal_time = FloatTime() + TEAM_CAMP_TIME; - //the teammate that requested the camping - bs->teammate = client; - //not arrived yet - bs->arrive_time = 0; - // - BotSetTeamStatus(bs); - // remember last ordered task - BotRememberLastOrderedTask(bs); -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -BotVoiceChat_FollowMe -================== -*/ -void BotVoiceChat_FollowMe(bot_state_t *bs, int client, int mode) { - int areanum; - aas_entityinfo_t entinfo; - char netname[MAX_NETNAME]; - - bs->teamgoal.entitynum = -1; - BotEntityInfo(client, &entinfo); - //if info is valid (in PVS) - if (entinfo.valid) { - areanum = BotPointAreaNum(entinfo.origin); - if (areanum) { // && trap_AAS_AreaReachability(areanum)) { - bs->teamgoal.entitynum = client; - bs->teamgoal.areanum = areanum; - VectorCopy(entinfo.origin, bs->teamgoal.origin); - VectorSet(bs->teamgoal.mins, -8, -8, -8); - VectorSet(bs->teamgoal.maxs, 8, 8, 8); - } - } - //if the other is not visible - if (bs->teamgoal.entitynum < 0) { - BotAI_BotInitialChat(bs, "whereareyou", EasyClientName(client, netname, sizeof(netname)), NULL); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); - return; - } - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); - //the team mate - bs->teammate = client; - //last time the team mate was assumed visible - bs->teammatevisible_time = FloatTime(); - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - //get the team goal time - bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME; - //set the ltg type - bs->ltgtype = LTG_TEAMACCOMPANY; - bs->formation_dist = 3.5 * 32; //3.5 meter - bs->arrive_time = 0; - // - BotSetTeamStatus(bs); - // remember last ordered task - BotRememberLastOrderedTask(bs); -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -BotVoiceChat_FollowFlagCarrier -================== -*/ -void BotVoiceChat_FollowFlagCarrier(bot_state_t *bs, int client, int mode) { - int carrier; - - carrier = BotTeamFlagCarrier(bs); - if (carrier >= 0) - BotVoiceChat_FollowMe(bs, carrier, mode); -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -BotVoiceChat_ReturnFlag -================== -*/ -void BotVoiceChat_ReturnFlag(bot_state_t *bs, int client, int mode) { - //if not in CTF mode - if ( - gametype != GT_CTF -#ifdef MISSIONPACK - && gametype != GT_1FCTF -#endif - ) { - return; - } - // - bs->decisionmaker = client; - bs->ordered = qtrue; - bs->order_time = FloatTime(); - //set the time to send a message to the team mates - bs->teammessage_time = FloatTime() + 2 * random(); - //set the ltg type - bs->ltgtype = LTG_RETURNFLAG; - //set the team goal time - bs->teamgoal_time = FloatTime() + CTF_RETURNFLAG_TIME; - bs->rushbaseaway_time = 0; - BotSetTeamStatus(bs); -#ifdef DEBUG - BotPrintTeamGoal(bs); -#endif //DEBUG -} - -/* -================== -BotVoiceChat_StartLeader -================== -*/ -void BotVoiceChat_StartLeader(bot_state_t *bs, int client, int mode) { - ClientName(client, bs->teamleader, sizeof(bs->teamleader)); -} - -/* -================== -BotVoiceChat_StopLeader -================== -*/ -void BotVoiceChat_StopLeader(bot_state_t *bs, int client, int mode) { - char netname[MAX_MESSAGE_SIZE]; - - if (!Q_stricmp(bs->teamleader, ClientName(client, netname, sizeof(netname)))) { - bs->teamleader[0] = '\0'; - notleader[client] = qtrue; - } -} - -/* -================== -BotVoiceChat_WhoIsLeader -================== -*/ -void BotVoiceChat_WhoIsLeader(bot_state_t *bs, int client, int mode) { - char netname[MAX_MESSAGE_SIZE]; - - if (!TeamPlayIsOn()) return; - - ClientName(bs->client, netname, sizeof(netname)); - //if this bot IS the team leader - if (!Q_stricmp(netname, bs->teamleader)) { - BotAI_BotInitialChat(bs, "iamteamleader", NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - BotVoiceChatOnly(bs, -1, VOICECHAT_STARTLEADER); - } -} - -/* -================== -BotVoiceChat_WantOnDefense -================== -*/ -void BotVoiceChat_WantOnDefense(bot_state_t *bs, int client, int mode) { - char netname[MAX_NETNAME]; - int preference; - - preference = BotGetTeamMateTaskPreference(bs, client); - preference &= ~TEAMTP_ATTACKER; - preference |= TEAMTP_DEFENDER; - BotSetTeamMateTaskPreference(bs, client, preference); - // - EasyClientName(client, netname, sizeof(netname)); - BotAI_BotInitialChat(bs, "keepinmind", netname, NULL); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); - BotVoiceChatOnly(bs, client, VOICECHAT_YES); - trap_EA_Action(bs->client, ACTION_AFFIRMATIVE); -} - -/* -================== -BotVoiceChat_WantOnOffense -================== -*/ -void BotVoiceChat_WantOnOffense(bot_state_t *bs, int client, int mode) { - char netname[MAX_NETNAME]; - int preference; - - preference = BotGetTeamMateTaskPreference(bs, client); - preference &= ~TEAMTP_DEFENDER; - preference |= TEAMTP_ATTACKER; - BotSetTeamMateTaskPreference(bs, client, preference); - // - EasyClientName(client, netname, sizeof(netname)); - BotAI_BotInitialChat(bs, "keepinmind", netname, NULL); - trap_BotEnterChat(bs->cs, client, CHAT_TELL); - BotVoiceChatOnly(bs, client, VOICECHAT_YES); - trap_EA_Action(bs->client, ACTION_AFFIRMATIVE); -} - -void BotVoiceChat_Dummy(bot_state_t *bs, int client, int mode) { -} - -voiceCommand_t voiceCommands[] = { - {VOICECHAT_GETFLAG, BotVoiceChat_GetFlag}, - {VOICECHAT_OFFENSE, BotVoiceChat_Offense }, - {VOICECHAT_DEFEND, BotVoiceChat_Defend }, - {VOICECHAT_DEFENDFLAG, BotVoiceChat_DefendFlag }, - {VOICECHAT_PATROL, BotVoiceChat_Patrol }, - {VOICECHAT_CAMP, BotVoiceChat_Camp }, - {VOICECHAT_FOLLOWME, BotVoiceChat_FollowMe }, - {VOICECHAT_FOLLOWFLAGCARRIER, BotVoiceChat_FollowFlagCarrier }, - {VOICECHAT_RETURNFLAG, BotVoiceChat_ReturnFlag }, - {VOICECHAT_STARTLEADER, BotVoiceChat_StartLeader }, - {VOICECHAT_STOPLEADER, BotVoiceChat_StopLeader }, - {VOICECHAT_WHOISLEADER, BotVoiceChat_WhoIsLeader }, - {VOICECHAT_WANTONDEFENSE, BotVoiceChat_WantOnDefense }, - {VOICECHAT_WANTONOFFENSE, BotVoiceChat_WantOnOffense }, - {NULL, BotVoiceChat_Dummy} -}; - -int BotVoiceChatCommand(bot_state_t *bs, int mode, char *voiceChat) { - int i, clientNum; - //int voiceOnly, color; - char *ptr, buf[MAX_MESSAGE_SIZE], *cmd; - - if (!TeamPlayIsOn()) { - return qfalse; - } - - if ( mode == SAY_ALL ) { - return qfalse; // don't do anything with voice chats to everyone - } - - Q_strncpyz(buf, voiceChat, sizeof(buf)); - cmd = buf; - for (ptr = cmd; *cmd && *cmd > ' '; cmd++); - while (*cmd && *cmd <= ' ') *cmd++ = '\0'; - //voiceOnly = atoi(ptr); - for (ptr = cmd; *cmd && *cmd > ' '; cmd++); - while (*cmd && *cmd <= ' ') *cmd++ = '\0'; - clientNum = atoi(ptr); - for (ptr = cmd; *cmd && *cmd > ' '; cmd++); - while (*cmd && *cmd <= ' ') *cmd++ = '\0'; - //color = atoi(ptr); - - if (!BotSameTeam(bs, clientNum)) { - return qfalse; - } - - for (i = 0; voiceCommands[i].cmd; i++) { - if (!Q_stricmp(cmd, voiceCommands[i].cmd)) { - voiceCommands[i].func(bs, clientNum, mode); - return qtrue; - } - } - return qfalse; -} diff --git a/code/game/ai_vcmd.h b/code/game/ai_vcmd.h deleted file mode 100644 index 9a50b14..0000000 --- a/code/game/ai_vcmd.h +++ /dev/null @@ -1,36 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// - -/***************************************************************************** - * name: ai_vcmd.h - * - * desc: Quake3 bot AI - * - * $Archive: /source/code/botai/ai_vcmd.c $ - * - *****************************************************************************/ - -int BotVoiceChatCommand(bot_state_t *bs, int mode, char *voicechat); -void BotVoiceChat_Defend(bot_state_t *bs, int client, int mode); - - diff --git a/code/game/be_aas.h b/code/game/be_aas.h new file mode 100644 index 0000000..66b2efb --- /dev/null +++ b/code/game/be_aas.h @@ -0,0 +1,165 @@ +// Copyright (C) 1999-2000 Id Software, Inc. +// + +/***************************************************************************** + * name: be_aas.h + * + * desc: Area Awareness System, stuff exported to the AI + * + * $Archive: /StarTrek/Code-DM/game/be_aas.h $ + * $Author: Jmonroe $ + * $Revision: 1 $ + * $Modtime: 1/21/00 10:12p $ + * $Date: 1/25/00 6:26p $ + * + *****************************************************************************/ + +#ifndef MAX_STRINGFIELD +#define MAX_STRINGFIELD 80 +#endif + +//travel flags +#define TFL_INVALID 0x0000001 //! es) qsort(a, r / es, es, cmp); @@ -178,7 +187,10 @@ loop: SWAPINIT(a, es); /* qsort(pn - r, r / es, es, cmp);*/ } -//================================================================================== +/*==================================================================================*/ + + +/* this file is excluded from release builds because of intrinsics */ size_t strlen( const char *string ) { const char *s; @@ -233,29 +245,7 @@ char *strchr( const char *string, int c ) { } string++; } - - if(c) - return NULL; - else - return (char *) string; -} - -char *strrchr(const char *string, int c) -{ - const char *found = NULL; - - while(*string) - { - if(*string == c) - found = string; - - string++; - } - - if(c) - return (char *) found; - else - return (char *) string; + return (char *)0; } char *strstr( const char *string, const char *strCharSet ) { @@ -275,6 +265,8 @@ char *strstr( const char *string, const char *strCharSet ) { return (char *)0; } +#if !defined ( _MSC_VER ) && ! defined ( __linux__ ) + int tolower( int c ) { if ( c >= 'A' && c <= 'Z' ) { c += 'a' - 'A'; @@ -290,29 +282,21 @@ int toupper( int c ) { return c; } -void *memmove(void *dest, const void *src, size_t count) -{ - size_t i; +#endif +/*#ifndef _MSC_VER*/ - if(count) - { - if(dest > src) - { - i = count; - - do - { - i--; - ((char *) dest)[i] = ((char *) src)[i]; - } while(i > 0); +void *memmove( void *dest, const void *src, size_t count ) { + int i; + + if ( dest > src ) { + for ( i = count-1 ; i >= 0 ; i-- ) { + ((char *)dest)[i] = ((char *)src)[i]; } - else - { - for(i = 0; i < count; i++) - ((char *) dest)[i] = ((char *) src)[i]; + } else { + for ( i = 0 ; i < count ; i++ ) { + ((char *)dest)[i] = ((char *)src)[i]; } } - return dest; } @@ -360,10 +344,10 @@ double sqrt( double x ) { return 0; } - // initial guess + /* initial guess */ y = x / 2; - // refine + /* refine */ maxError = x * 0.001; do { @@ -548,167 +532,6 @@ double cos( double x ) { } -/* -void create_acostable( void ) { - int i; - FILE *fp; - float a; - - fp = fopen("c:\\acostable.txt", "w"); - fprintf(fp, "float acostable[] = {"); - for (i = 0; i < 1024; i++) { - if (!(i & 7)) - fprintf(fp, "\n"); - a = acos( (float) -1 + i / 512 ); - fprintf(fp, "%1.8f,", a); - } - fprintf(fp, "\n}\n"); - fclose(fp); -} -*/ - -float acostable[] = { -3.14159265,3.07908248,3.05317551,3.03328655,3.01651113,3.00172442,2.98834964,2.97604422, -2.96458497,2.95381690,2.94362719,2.93393068,2.92466119,2.91576615,2.90720289,2.89893629, -2.89093699,2.88318015,2.87564455,2.86831188,2.86116621,2.85419358,2.84738169,2.84071962, -2.83419760,2.82780691,2.82153967,2.81538876,2.80934770,2.80341062,2.79757211,2.79182724, -2.78617145,2.78060056,2.77511069,2.76969824,2.76435988,2.75909250,2.75389319,2.74875926, -2.74368816,2.73867752,2.73372510,2.72882880,2.72398665,2.71919677,2.71445741,2.70976688, -2.70512362,2.70052613,2.69597298,2.69146283,2.68699438,2.68256642,2.67817778,2.67382735, -2.66951407,2.66523692,2.66099493,2.65678719,2.65261279,2.64847088,2.64436066,2.64028133, -2.63623214,2.63221238,2.62822133,2.62425835,2.62032277,2.61641398,2.61253138,2.60867440, -2.60484248,2.60103507,2.59725167,2.59349176,2.58975488,2.58604053,2.58234828,2.57867769, -2.57502832,2.57139977,2.56779164,2.56420354,2.56063509,2.55708594,2.55355572,2.55004409, -2.54655073,2.54307530,2.53961750,2.53617701,2.53275354,2.52934680,2.52595650,2.52258238, -2.51922417,2.51588159,2.51255441,2.50924238,2.50594525,2.50266278,2.49939476,2.49614096, -2.49290115,2.48967513,2.48646269,2.48326362,2.48007773,2.47690482,2.47374472,2.47059722, -2.46746215,2.46433933,2.46122860,2.45812977,2.45504269,2.45196720,2.44890314,2.44585034, -2.44280867,2.43977797,2.43675809,2.43374890,2.43075025,2.42776201,2.42478404,2.42181622, -2.41885841,2.41591048,2.41297232,2.41004380,2.40712480,2.40421521,2.40131491,2.39842379, -2.39554173,2.39266863,2.38980439,2.38694889,2.38410204,2.38126374,2.37843388,2.37561237, -2.37279910,2.36999400,2.36719697,2.36440790,2.36162673,2.35885335,2.35608768,2.35332964, -2.35057914,2.34783610,2.34510044,2.34237208,2.33965094,2.33693695,2.33423003,2.33153010, -2.32883709,2.32615093,2.32347155,2.32079888,2.31813284,2.31547337,2.31282041,2.31017388, -2.30753373,2.30489988,2.30227228,2.29965086,2.29703556,2.29442632,2.29182309,2.28922580, -2.28663439,2.28404881,2.28146900,2.27889490,2.27632647,2.27376364,2.27120637,2.26865460, -2.26610827,2.26356735,2.26103177,2.25850149,2.25597646,2.25345663,2.25094195,2.24843238, -2.24592786,2.24342836,2.24093382,2.23844420,2.23595946,2.23347956,2.23100444,2.22853408, -2.22606842,2.22360742,2.22115104,2.21869925,2.21625199,2.21380924,2.21137096,2.20893709, -2.20650761,2.20408248,2.20166166,2.19924511,2.19683280,2.19442469,2.19202074,2.18962092, -2.18722520,2.18483354,2.18244590,2.18006225,2.17768257,2.17530680,2.17293493,2.17056692, -2.16820274,2.16584236,2.16348574,2.16113285,2.15878367,2.15643816,2.15409630,2.15175805, -2.14942338,2.14709226,2.14476468,2.14244059,2.14011997,2.13780279,2.13548903,2.13317865, -2.13087163,2.12856795,2.12626757,2.12397047,2.12167662,2.11938600,2.11709859,2.11481435, -2.11253326,2.11025530,2.10798044,2.10570867,2.10343994,2.10117424,2.09891156,2.09665185, -2.09439510,2.09214129,2.08989040,2.08764239,2.08539725,2.08315496,2.08091550,2.07867884, -2.07644495,2.07421383,2.07198545,2.06975978,2.06753681,2.06531651,2.06309887,2.06088387, -2.05867147,2.05646168,2.05425445,2.05204979,2.04984765,2.04764804,2.04545092,2.04325628, -2.04106409,2.03887435,2.03668703,2.03450211,2.03231957,2.03013941,2.02796159,2.02578610, -2.02361292,2.02144204,2.01927344,2.01710710,2.01494300,2.01278113,2.01062146,2.00846399, -2.00630870,2.00415556,2.00200457,1.99985570,1.99770895,1.99556429,1.99342171,1.99128119, -1.98914271,1.98700627,1.98487185,1.98273942,1.98060898,1.97848051,1.97635399,1.97422942, -1.97210676,1.96998602,1.96786718,1.96575021,1.96363511,1.96152187,1.95941046,1.95730088, -1.95519310,1.95308712,1.95098292,1.94888050,1.94677982,1.94468089,1.94258368,1.94048818, -1.93839439,1.93630228,1.93421185,1.93212308,1.93003595,1.92795046,1.92586659,1.92378433, -1.92170367,1.91962459,1.91754708,1.91547113,1.91339673,1.91132385,1.90925250,1.90718266, -1.90511432,1.90304746,1.90098208,1.89891815,1.89685568,1.89479464,1.89273503,1.89067683, -1.88862003,1.88656463,1.88451060,1.88245794,1.88040664,1.87835668,1.87630806,1.87426076, -1.87221477,1.87017008,1.86812668,1.86608457,1.86404371,1.86200412,1.85996577,1.85792866, -1.85589277,1.85385809,1.85182462,1.84979234,1.84776125,1.84573132,1.84370256,1.84167495, -1.83964848,1.83762314,1.83559892,1.83357582,1.83155381,1.82953289,1.82751305,1.82549429, -1.82347658,1.82145993,1.81944431,1.81742973,1.81541617,1.81340362,1.81139207,1.80938151, -1.80737194,1.80536334,1.80335570,1.80134902,1.79934328,1.79733848,1.79533460,1.79333164, -1.79132959,1.78932843,1.78732817,1.78532878,1.78333027,1.78133261,1.77933581,1.77733985, -1.77534473,1.77335043,1.77135695,1.76936428,1.76737240,1.76538132,1.76339101,1.76140148, -1.75941271,1.75742470,1.75543743,1.75345090,1.75146510,1.74948002,1.74749565,1.74551198, -1.74352900,1.74154672,1.73956511,1.73758417,1.73560389,1.73362426,1.73164527,1.72966692, -1.72768920,1.72571209,1.72373560,1.72175971,1.71978441,1.71780969,1.71583556,1.71386199, -1.71188899,1.70991653,1.70794462,1.70597325,1.70400241,1.70203209,1.70006228,1.69809297, -1.69612416,1.69415584,1.69218799,1.69022062,1.68825372,1.68628727,1.68432127,1.68235571, -1.68039058,1.67842588,1.67646160,1.67449772,1.67253424,1.67057116,1.66860847,1.66664615, -1.66468420,1.66272262,1.66076139,1.65880050,1.65683996,1.65487975,1.65291986,1.65096028, -1.64900102,1.64704205,1.64508338,1.64312500,1.64116689,1.63920905,1.63725148,1.63529416, -1.63333709,1.63138026,1.62942366,1.62746728,1.62551112,1.62355517,1.62159943,1.61964388, -1.61768851,1.61573332,1.61377831,1.61182346,1.60986877,1.60791422,1.60595982,1.60400556, -1.60205142,1.60009739,1.59814349,1.59618968,1.59423597,1.59228235,1.59032882,1.58837536, -1.58642196,1.58446863,1.58251535,1.58056211,1.57860891,1.57665574,1.57470259,1.57274945, -1.57079633,1.56884320,1.56689007,1.56493692,1.56298375,1.56103055,1.55907731,1.55712403, -1.55517069,1.55321730,1.55126383,1.54931030,1.54735668,1.54540297,1.54344917,1.54149526, -1.53954124,1.53758710,1.53563283,1.53367843,1.53172389,1.52976919,1.52781434,1.52585933, -1.52390414,1.52194878,1.51999323,1.51803748,1.51608153,1.51412537,1.51216900,1.51021240, -1.50825556,1.50629849,1.50434117,1.50238360,1.50042576,1.49846765,1.49650927,1.49455060, -1.49259163,1.49063237,1.48867280,1.48671291,1.48475270,1.48279215,1.48083127,1.47887004, -1.47690845,1.47494650,1.47298419,1.47102149,1.46905841,1.46709493,1.46513106,1.46316677, -1.46120207,1.45923694,1.45727138,1.45530538,1.45333893,1.45137203,1.44940466,1.44743682, -1.44546850,1.44349969,1.44153038,1.43956057,1.43759024,1.43561940,1.43364803,1.43167612, -1.42970367,1.42773066,1.42575709,1.42378296,1.42180825,1.41983295,1.41785705,1.41588056, -1.41390346,1.41192573,1.40994738,1.40796840,1.40598877,1.40400849,1.40202755,1.40004594, -1.39806365,1.39608068,1.39409701,1.39211264,1.39012756,1.38814175,1.38615522,1.38416795, -1.38217994,1.38019117,1.37820164,1.37621134,1.37422025,1.37222837,1.37023570,1.36824222, -1.36624792,1.36425280,1.36225684,1.36026004,1.35826239,1.35626387,1.35426449,1.35226422, -1.35026307,1.34826101,1.34625805,1.34425418,1.34224937,1.34024364,1.33823695,1.33622932, -1.33422072,1.33221114,1.33020059,1.32818904,1.32617649,1.32416292,1.32214834,1.32013273, -1.31811607,1.31609837,1.31407960,1.31205976,1.31003885,1.30801684,1.30599373,1.30396951, -1.30194417,1.29991770,1.29789009,1.29586133,1.29383141,1.29180031,1.28976803,1.28773456, -1.28569989,1.28366400,1.28162688,1.27958854,1.27754894,1.27550809,1.27346597,1.27142257, -1.26937788,1.26733189,1.26528459,1.26323597,1.26118602,1.25913471,1.25708205,1.25502803, -1.25297262,1.25091583,1.24885763,1.24679802,1.24473698,1.24267450,1.24061058,1.23854519, -1.23647833,1.23440999,1.23234015,1.23026880,1.22819593,1.22612152,1.22404557,1.22196806, -1.21988898,1.21780832,1.21572606,1.21364219,1.21155670,1.20946958,1.20738080,1.20529037, -1.20319826,1.20110447,1.19900898,1.19691177,1.19481283,1.19271216,1.19060973,1.18850553, -1.18639955,1.18429178,1.18218219,1.18007079,1.17795754,1.17584244,1.17372548,1.17160663, -1.16948589,1.16736324,1.16523866,1.16311215,1.16098368,1.15885323,1.15672081,1.15458638, -1.15244994,1.15031147,1.14817095,1.14602836,1.14388370,1.14173695,1.13958808,1.13743709, -1.13528396,1.13312866,1.13097119,1.12881153,1.12664966,1.12448556,1.12231921,1.12015061, -1.11797973,1.11580656,1.11363107,1.11145325,1.10927308,1.10709055,1.10490563,1.10271831, -1.10052856,1.09833638,1.09614174,1.09394462,1.09174500,1.08954287,1.08733820,1.08513098, -1.08292118,1.08070879,1.07849378,1.07627614,1.07405585,1.07183287,1.06960721,1.06737882, -1.06514770,1.06291382,1.06067715,1.05843769,1.05619540,1.05395026,1.05170226,1.04945136, -1.04719755,1.04494080,1.04268110,1.04041841,1.03815271,1.03588399,1.03361221,1.03133735, -1.02905939,1.02677830,1.02449407,1.02220665,1.01991603,1.01762219,1.01532509,1.01302471, -1.01072102,1.00841400,1.00610363,1.00378986,1.00147268,0.99915206,0.99682798,0.99450039, -0.99216928,0.98983461,0.98749636,0.98515449,0.98280898,0.98045980,0.97810691,0.97575030, -0.97338991,0.97102573,0.96865772,0.96628585,0.96391009,0.96153040,0.95914675,0.95675912, -0.95436745,0.95197173,0.94957191,0.94716796,0.94475985,0.94234754,0.93993099,0.93751017, -0.93508504,0.93265556,0.93022170,0.92778341,0.92534066,0.92289341,0.92044161,0.91798524, -0.91552424,0.91305858,0.91058821,0.90811309,0.90563319,0.90314845,0.90065884,0.89816430, -0.89566479,0.89316028,0.89065070,0.88813602,0.88561619,0.88309116,0.88056088,0.87802531, -0.87548438,0.87293806,0.87038629,0.86782901,0.86526619,0.86269775,0.86012366,0.85754385, -0.85495827,0.85236686,0.84976956,0.84716633,0.84455709,0.84194179,0.83932037,0.83669277, -0.83405893,0.83141877,0.82877225,0.82611928,0.82345981,0.82079378,0.81812110,0.81544172, -0.81275556,0.81006255,0.80736262,0.80465570,0.80194171,0.79922057,0.79649221,0.79375655, -0.79101352,0.78826302,0.78550497,0.78273931,0.77996593,0.77718475,0.77439569,0.77159865, -0.76879355,0.76598029,0.76315878,0.76032891,0.75749061,0.75464376,0.75178826,0.74892402, -0.74605092,0.74316887,0.74027775,0.73737744,0.73446785,0.73154885,0.72862033,0.72568217, -0.72273425,0.71977644,0.71680861,0.71383064,0.71084240,0.70784376,0.70483456,0.70181469, -0.69878398,0.69574231,0.69268952,0.68962545,0.68654996,0.68346288,0.68036406,0.67725332, -0.67413051,0.67099544,0.66784794,0.66468783,0.66151492,0.65832903,0.65512997,0.65191753, -0.64869151,0.64545170,0.64219789,0.63892987,0.63564741,0.63235028,0.62903824,0.62571106, -0.62236849,0.61901027,0.61563615,0.61224585,0.60883911,0.60541564,0.60197515,0.59851735, -0.59504192,0.59154856,0.58803694,0.58450672,0.58095756,0.57738911,0.57380101,0.57019288, -0.56656433,0.56291496,0.55924437,0.55555212,0.55183778,0.54810089,0.54434099,0.54055758, -0.53675018,0.53291825,0.52906127,0.52517867,0.52126988,0.51733431,0.51337132,0.50938028, -0.50536051,0.50131132,0.49723200,0.49312177,0.48897987,0.48480547,0.48059772,0.47635573, -0.47207859,0.46776530,0.46341487,0.45902623,0.45459827,0.45012983,0.44561967,0.44106652, -0.43646903,0.43182577,0.42713525,0.42239588,0.41760600,0.41276385,0.40786755,0.40291513, -0.39790449,0.39283339,0.38769946,0.38250016,0.37723277,0.37189441,0.36648196,0.36099209, -0.35542120,0.34976542,0.34402054,0.33818204,0.33224495,0.32620390,0.32005298,0.31378574, -0.30739505,0.30087304,0.29421096,0.28739907,0.28042645,0.27328078,0.26594810,0.25841250, -0.25065566,0.24265636,0.23438976,0.22582651,0.21693146,0.20766198,0.19796546,0.18777575, -0.17700769,0.16554844,0.15324301,0.13986823,0.12508152,0.10830610,0.08841715,0.06251018, -} - -double acos( double x ) { - int index; - - if (x < -1) - x = -1; - if (x > 1) - x = 1; - index = (float) (1.0 + x) * 511.9; - return acostable[index]; -} - double atan2( double y, double x ) { float base; float temp; @@ -718,20 +541,20 @@ double atan2( double y, double x ) { if ( x < 0 ) { if ( y >= 0 ) { - // quad 1 + /* quad 1 */ base = M_PI / 2; temp = x; x = y; y = -temp; } else { - // quad 2 + /* quad 2 */ base = M_PI; x = -x; y = -y; } } else { if ( y < 0 ) { - // quad 3 + /* quad 3 */ base = 3 * M_PI / 2; temp = x; x = -y; @@ -749,7 +572,7 @@ double atan2( double y, double x ) { dir = 1; } - // calcualte angle in octant 0 + /* calcualte angle in octant 0 */ if ( x == 0 ) { return base; } @@ -790,7 +613,7 @@ double atof( const char *string ) { int c; - // skip whitespace + /* skip whitespace */ while ( *string <= ' ' ) { if ( !*string ) { return 0; @@ -798,7 +621,7 @@ double atof( const char *string ) { string++; } - // check sign + /* check sign */ switch ( *string ) { case '+': string++; @@ -813,7 +636,7 @@ double atof( const char *string ) { break; } - // read digits + /* read digits */ value = 0; c = string[0]; if ( c != '.' ) { @@ -829,7 +652,7 @@ double atof( const char *string ) { string++; } - // check for decimal point + /* check for decimal point */ if ( c == '.' ) { double fraction; @@ -846,7 +669,7 @@ double atof( const char *string ) { } - // not handling 10e10 notation... + /* not handling 10e10 notation... */ return value * sign; } @@ -855,11 +678,11 @@ double _atof( const char **stringPtr ) { const char *string; float sign; float value; - int c = '0'; + int c; string = *stringPtr; - // skip whitespace + /* skip whitespace */ while ( *string <= ' ' ) { if ( !*string ) { *stringPtr = string; @@ -868,7 +691,7 @@ double _atof( const char **stringPtr ) { string++; } - // check sign + /* check sign */ switch ( *string ) { case '+': string++; @@ -883,7 +706,7 @@ double _atof( const char **stringPtr ) { break; } - // read digits + /* read digits */ value = 0; if ( string[0] != '.' ) { do { @@ -896,7 +719,7 @@ double _atof( const char **stringPtr ) { } while ( 1 ); } - // check for decimal point + /* check for decimal point */ if ( c == '.' ) { double fraction; @@ -913,240 +736,14 @@ double _atof( const char **stringPtr ) { } - // not handling 10e10 notation... + /* not handling 10e10 notation... */ *stringPtr = string; return value * sign; } -/* -============== -strtod -Without an errno variable, this is a fair bit less useful than it is in libc -but it's still a fair bit more capable than atof or _atof -Handles inf[inity], nan (ignoring case), hexadecimals, and decimals -Handles decimal exponents like 10e10 and hex exponents like 0x7f8p20 -10e10 == 10000000000 (power of ten) -0x7f8p20 == 0x7f800000 (decimal power of two) -The variable pointed to by endptr will hold the location of the first character -in the nptr string that was not used in the conversion -============== -*/ -double strtod( const char *nptr, char **endptr ) -{ - double res; - qboolean neg = qfalse; - - // skip whitespace - while( isspace( *nptr ) ) - nptr++; - - // special string parsing - if( Q_stricmpn( nptr, "nan", 3 ) == 0 ) - { - floatint_t nan; - - if( endptr ) - *endptr = (char *)&nptr[3]; - - // nan can be followed by a bracketed number (in hex, octal, - // or decimal) which is then put in the mantissa - // this can be used to generate signalling or quiet NaNs, for - // example (though I doubt it'll ever be used) - // note that nan(0) is infinity! - if( nptr[3] == '(' ) - { - char *end; - int mantissa = strtol( &nptr[4], &end, 0 ); - if( *end == ')' ) - { - nan.ui = 0x7f800000 | ( mantissa & 0x7fffff ); - if( endptr ) - *endptr = &end[1]; - return nan.f; - } - } - nan.ui = 0x7fffffff; - return nan.f; - } - if( Q_stricmpn( nptr, "inf", 3 ) == 0 ) - { - floatint_t inf; - inf.ui = 0x7f800000; - if( endptr == NULL ) - return inf.f; - if( Q_stricmpn( &nptr[3], "inity", 5 ) == 0 ) - *endptr = (char *)&nptr[8]; - else - *endptr = (char *)&nptr[3]; - return inf.f; - } - - // normal numeric parsing - // sign - if( *nptr == '-' ) - { - nptr++; - neg = qtrue; - } - else if( *nptr == '+' ) - nptr++; - // hex - if( Q_stricmpn( nptr, "0x", 2 ) == 0 ) - { - // track if we use any digits - const char *s = &nptr[1], *end = s; - nptr += 2; - res = 0; - while( qtrue ) - { - if( isdigit( *nptr ) ) - res = 16 * res + ( *nptr++ - '0' ); - else if( *nptr >= 'A' && *nptr <= 'F' ) - res = 16 * res + 10 + *nptr++ - 'A'; - else if( *nptr >= 'a' && *nptr <= 'f' ) - res = 16 * res + 10 + *nptr++ - 'a'; - else - break; - } - // if nptr moved, save it - if( end + 1 < nptr ) - end = nptr; - if( *nptr == '.' ) - { - float place; - nptr++; - // 1.0 / 16.0 == 0.0625 - // I don't expect the float accuracy to hold out for - // very long but since we need to know the length of - // the string anyway we keep on going regardless - for( place = 0.0625;; place /= 16.0 ) - { - if( isdigit( *nptr ) ) - res += place * ( *nptr++ - '0' ); - else if( *nptr >= 'A' && *nptr <= 'F' ) - res += place * ( 10 + *nptr++ - 'A' ); - else if( *nptr >= 'a' && *nptr <= 'f' ) - res += place * ( 10 + *nptr++ - 'a' ); - else - break; - } - if( end < nptr ) - end = nptr; - } - // parse an optional exponent, representing multiplication - // by a power of two - // exponents are only valid if we encountered at least one - // digit already (and have therefore set end to something) - if( end != s && tolower( *nptr ) == 'p' ) - { - int exp; - float res2; - // apparently (confusingly) the exponent should be - // decimal - exp = strtol( &nptr[1], (char **)&end, 10 ); - if( &nptr[1] == end ) - { - // no exponent - if( endptr ) - *endptr = (char *)nptr; - return res; - } - if( exp > 0 ) - { - while( exp-- > 0 ) - { - res2 = res * 2; - // check for infinity - if( res2 <= res ) - break; - res = res2; - } - } - else - { - while( exp++ < 0 ) - { - res2 = res / 2; - // check for underflow - if( res2 >= res ) - break; - res = res2; - } - } - } - if( endptr ) - *endptr = (char *)end; - return res; - } - // decimal - else - { - // track if we find any digits - const char *end = nptr, *p = nptr; - // this is most of the work - for( res = 0; isdigit( *nptr ); - res = 10 * res + *nptr++ - '0' ); - // if nptr moved, we read something - if( end < nptr ) - end = nptr; - if( *nptr == '.' ) - { - // fractional part - float place; - nptr++; - for( place = 0.1; isdigit( *nptr ); place /= 10.0 ) - res += ( *nptr++ - '0' ) * place; - // if nptr moved, we read something - if( end + 1 < nptr ) - end = nptr; - } - // exponent - // meaningless without having already read digits, so check - // we've set end to something - if( p != end && tolower( *nptr ) == 'e' ) - { - int exp; - float res10; - exp = strtol( &nptr[1], (char **)&end, 10 ); - if( &nptr[1] == end ) - { - // no exponent - if( endptr ) - *endptr = (char *)nptr; - return res; - } - if( exp > 0 ) - { - while( exp-- > 0 ) - { - res10 = res * 10; - // check for infinity to save us time - if( res10 <= res ) - break; - res = res10; - } - } - else if( exp < 0 ) - { - while( exp++ < 0 ) - { - res10 = res / 10; - // check for underflow - // (test for 0 would probably be just - // as good) - if( res10 >= res ) - break; - res = res10; - } - } - } - if( endptr ) - *endptr = (char *)end; - return res; - } -} +#if !defined( _MSC_VER ) && !defined( __linux__ ) int atoi( const char *string ) { int sign; @@ -1154,7 +751,7 @@ int atoi( const char *string ) { int c; - // skip whitespace + /* skip whitespace */ while ( *string <= ' ' ) { if ( !*string ) { return 0; @@ -1162,7 +759,7 @@ int atoi( const char *string ) { string++; } - // check sign + /* check sign */ switch ( *string ) { case '+': string++; @@ -1177,7 +774,7 @@ int atoi( const char *string ) { break; } - // read digits + /* read digits */ value = 0; do { c = *string++; @@ -1188,7 +785,7 @@ int atoi( const char *string ) { value = value * 10 + c; } while ( 1 ); - // not handling 10e10 notation... + /* not handling 10e10 notation... */ return value * sign; } @@ -1202,7 +799,7 @@ int _atoi( const char **stringPtr ) { string = *stringPtr; - // skip whitespace + /* skip whitespace */ while ( *string <= ' ' ) { if ( !*string ) { return 0; @@ -1210,7 +807,7 @@ int _atoi( const char **stringPtr ) { string++; } - // check sign + /* check sign */ switch ( *string ) { case '+': string++; @@ -1225,7 +822,7 @@ int _atoi( const char **stringPtr ) { break; } - // read digits + /* read digits */ value = 0; do { c = *string++; @@ -1236,104 +833,13 @@ int _atoi( const char **stringPtr ) { value = value * 10 + c; } while ( 1 ); - // not handling 10e10 notation... + /* not handling 10e10 notation... */ *stringPtr = string; return value * sign; } -/* -============== -strtol - -Handles any base from 2 to 36. If base is 0 then it guesses -decimal, hex, or octal based on the format of the number (leading 0 or 0x) -Will not overflow - returns LONG_MIN or LONG_MAX as appropriate -*endptr is set to the location of the first character not used -============== -*/ -long strtol( const char *nptr, char **endptr, int base ) -{ - long res; - qboolean pos = qtrue; - - if( endptr ) - *endptr = (char *)nptr; - // bases other than 0, 2, 8, 16 are very rarely used, but they're - // not much extra effort to support - if( base < 0 || base == 1 || base > 36 ) - return 0; - // skip leading whitespace - while( isspace( *nptr ) ) - nptr++; - // sign - if( *nptr == '-' ) - { - nptr++; - pos = qfalse; - } - else if( *nptr == '+' ) - nptr++; - // look for base-identifying sequences e.g. 0x for hex, 0 for octal - if( nptr[0] == '0' ) - { - nptr++; - // 0 is always a valid digit - if( endptr ) - *endptr = (char *)nptr; - if( *nptr == 'x' || *nptr == 'X' ) - { - if( base != 0 && base != 16 ) - { - // can't be hex, reject x (accept 0) - if( endptr ) - *endptr = (char *)nptr; - return 0; - } - nptr++; - base = 16; - } - else if( base == 0 ) - base = 8; - } - else if( base == 0 ) - base = 10; - res = 0; - while( qtrue ) - { - int val; - if( isdigit( *nptr ) ) - val = *nptr - '0'; - else if( islower( *nptr ) ) - val = 10 + *nptr - 'a'; - else if( isupper( *nptr ) ) - val = 10 + *nptr - 'A'; - else - break; - if( val >= base ) - break; - // we go negative because LONG_MIN is further from 0 than - // LONG_MAX - if( res < ( LONG_MIN + val ) / base ) - res = LONG_MIN; // overflow - else - res = res * base - val; - nptr++; - if( endptr ) - *endptr = (char *)nptr; - } - if( pos ) - { - // can't represent LONG_MIN positive - if( res == LONG_MIN ) - res = LONG_MAX; - else - res = -res; - } - return res; -} - int abs( int n ) { return n < 0 ? -n : n; } @@ -1344,753 +850,425 @@ double fabs( double x ) { -//========================================================= +/*=========================================================*/ -/* - * New implementation by Patrick Powell and others for vsnprintf. - * Supports length checking in strings. -*/ -/* - * Copyright Patrick Powell 1995 - * This code is based on code written by Patrick Powell (papowell@astart.com) - * It may be used for any purpose as long as this notice remains intact - * on all source code distributions - */ +#define ALT 0x00000001 /* alternate form */ +#define HEXPREFIX 0x00000002 /* add 0x or 0X prefix */ +#define LADJUST 0x00000004 /* left adjustment */ +#define LONGDBL 0x00000008 /* long double */ +#define LONGINT 0x00000010 /* long integer */ +#define QUADINT 0x00000020 /* quad integer */ +#define SHORTINT 0x00000040 /* short integer */ +#define ZEROPAD 0x00000080 /* zero (as opposed to blank) pad */ +#define FPT 0x00000100 /* floating point number */ -/************************************************************** - * Original: - * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 - * A bombproof version of doprnt (dopr) included. - * Sigh. This sort of thing is always nasty do deal with. Note that - * the version here does not include floating point... - * - * snprintf() is used instead of sprintf() as it does limit checks - * for string length. This covers a nasty loophole. - * - * The other functions are there to prevent NULL pointers from - * causing nast effects. - * - * More Recently: - * Brandon Long 9/15/96 for mutt 0.43 - * This was ugly. It is still ugly. I opted out of floating point - * numbers, but the formatter understands just about everything - * from the normal C string format, at least as far as I can tell from - * the Solaris 2.5 printf(3S) man page. - * - * Brandon Long 10/22/97 for mutt 0.87.1 - * Ok, added some minimal floating point support, which means this - * probably requires libm on most operating systems. Don't yet - * support the exponent (e,E) and sigfig (g,G). Also, fmtint() - * was pretty badly broken, it just wasn't being exercised in ways - * which showed it, so that's been fixed. Also, formated the code - * to mutt conventions, and removed dead code left over from the - * original. Also, there is now a builtin-test, just compile with: - * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm - * and run snprintf for results. - * - * Thomas Roessler 01/27/98 for mutt 0.89i - * The PGP code was using unsigned hexadecimal formats. - * Unfortunately, unsigned formats simply didn't work. - * - * Michael Elkins 03/05/98 for mutt 0.90.8 - * The original code assumed that both snprintf() and vsnprintf() were - * missing. Some systems only have snprintf() but not vsnprintf(), so - * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. - * - * Andrew Tridgell (tridge@samba.org) Oct 1998 - * fixed handling of %.0f - * added test for HAVE_LONG_DOUBLE - * - * Russ Allbery 2000-08-26 - * fixed return value to comply with C99 - * fixed handling of snprintf(NULL, ...) - * - * Hrvoje Niksic 2000-11-04 - * include instead of "config.h". - * moved TEST_SNPRINTF stuff out of HAVE_SNPRINTF ifdef. - * include for NULL. - * added support and test cases for long long. - * don't declare argument types to (v)snprintf if stdarg is not used. - * use int instead of short int as 2nd arg to va_arg. - * - **************************************************************/ +#define to_digit(c) ((c) - '0') +#define is_digit(c) ((unsigned)to_digit(c) <= 9) +#define to_char(n) ((n) + '0') -/* BDR 2002-01-13 %e and %g were being ignored. Now do something, - if not necessarily correctly */ +void AddInt( char **buf_p, int val, int width, int flags ) { + char text[32]; + int digits; + int signedVal; + char *buf; -#if (SIZEOF_LONG_DOUBLE > 0) -/* #ifdef HAVE_LONG_DOUBLE */ -#define LDOUBLE long double -#else -#define LDOUBLE double -#endif - -#if (SIZEOF_LONG_LONG > 0) -/* #ifdef HAVE_LONG_LONG */ -# define LLONG long long -#else -# define LLONG long -#endif - -static int dopr (char *buffer, size_t maxlen, const char *format, - va_list args); -static int fmtstr (char *buffer, size_t *currlen, size_t maxlen, - char *value, int flags, int min, int max); -static int fmtint (char *buffer, size_t *currlen, size_t maxlen, - LLONG value, int base, int min, int max, int flags); -static int fmtfp (char *buffer, size_t *currlen, size_t maxlen, - LDOUBLE fvalue, int min, int max, int flags); -static int dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c ); - -/* - * dopr(): poor man's version of doprintf - */ - -/* format read states */ -#define DP_S_DEFAULT 0 -#define DP_S_FLAGS 1 -#define DP_S_MIN 2 -#define DP_S_DOT 3 -#define DP_S_MAX 4 -#define DP_S_MOD 5 -#define DP_S_MOD_L 6 -#define DP_S_CONV 7 -#define DP_S_DONE 8 - -/* format flags - Bits */ -#define DP_F_MINUS (1 << 0) -#define DP_F_PLUS (1 << 1) -#define DP_F_SPACE (1 << 2) -#define DP_F_NUM (1 << 3) -#define DP_F_ZERO (1 << 4) -#define DP_F_UP (1 << 5) -#define DP_F_UNSIGNED (1 << 6) - -/* Conversion Flags */ -#define DP_C_SHORT 1 -#define DP_C_LONG 2 -#define DP_C_LLONG 3 -#define DP_C_LDOUBLE 4 - -#define char_to_int(p) (p - '0') - -static int dopr (char *buffer, size_t maxlen, const char *format, va_list args) -{ - char ch; - LLONG value; - LDOUBLE fvalue; - char *strvalue; - int min; - int max; - int state; - int flags; - int cflags; - int total; - size_t currlen; - - state = DP_S_DEFAULT; - currlen = flags = cflags = min = 0; - max = -1; - ch = *format++; - total = 0; - - while (state != DP_S_DONE) - { - if (ch == '\0') - state = DP_S_DONE; - - switch(state) - { - case DP_S_DEFAULT: - if (ch == '%') - state = DP_S_FLAGS; - else - total += dopr_outch (buffer, &currlen, maxlen, ch); - ch = *format++; - break; - case DP_S_FLAGS: - switch (ch) - { - case '-': - flags |= DP_F_MINUS; - ch = *format++; - break; - case '+': - flags |= DP_F_PLUS; - ch = *format++; - break; - case ' ': - flags |= DP_F_SPACE; - ch = *format++; - break; - case '#': - flags |= DP_F_NUM; - ch = *format++; - break; - case '0': - flags |= DP_F_ZERO; - ch = *format++; - break; - default: - state = DP_S_MIN; - break; - } - break; - case DP_S_MIN: - if ('0' <= ch && ch <= '9') - { - min = 10*min + char_to_int (ch); - ch = *format++; - } - else if (ch == '*') - { - min = va_arg (args, int); - ch = *format++; - state = DP_S_DOT; - } - else - state = DP_S_DOT; - break; - case DP_S_DOT: - if (ch == '.') - { - state = DP_S_MAX; - ch = *format++; - } - else - state = DP_S_MOD; - break; - case DP_S_MAX: - if ('0' <= ch && ch <= '9') - { - if (max < 0) - max = 0; - max = 10*max + char_to_int (ch); - ch = *format++; - } - else if (ch == '*') - { - max = va_arg (args, int); - ch = *format++; - state = DP_S_MOD; - } - else - state = DP_S_MOD; - break; - case DP_S_MOD: - switch (ch) - { - case 'h': - cflags = DP_C_SHORT; - ch = *format++; - break; - case 'l': - cflags = DP_C_LONG; - ch = *format++; - break; - case 'L': - cflags = DP_C_LDOUBLE; - ch = *format++; - break; - default: - break; - } - if (cflags != DP_C_LONG) - state = DP_S_CONV; - else - state = DP_S_MOD_L; - break; - case DP_S_MOD_L: - switch (ch) - { - case 'l': - cflags = DP_C_LLONG; - ch = *format++; - break; - default: - break; + digits = 0; + signedVal = val; + if ( val < 0 ) { + val = -val; } - state = DP_S_CONV; - break; - case DP_S_CONV: - switch (ch) - { - case 'd': - case 'i': - if (cflags == DP_C_SHORT) - value = (short int)va_arg (args, int); - else if (cflags == DP_C_LONG) - value = va_arg (args, long int); - else if (cflags == DP_C_LLONG) - value = va_arg (args, LLONG); - else - value = va_arg (args, int); - total += fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); - break; - case 'o': - flags |= DP_F_UNSIGNED; - if (cflags == DP_C_SHORT) -// value = (unsigned short int) va_arg (args, unsigned short int); // Thilo: This does not work because the rcc compiler cannot do that cast correctly. - value = va_arg (args, unsigned int) & ( (1 << sizeof(unsigned short int) * 8) - 1); // Using this workaround instead. - else if (cflags == DP_C_LONG) - value = va_arg (args, unsigned long int); - else if (cflags == DP_C_LLONG) - value = va_arg (args, unsigned LLONG); - else - value = va_arg (args, unsigned int); - total += fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags); - break; - case 'u': - flags |= DP_F_UNSIGNED; - if (cflags == DP_C_SHORT) - value = va_arg (args, unsigned int) & ( (1 << sizeof(unsigned short int) * 8) - 1); - else if (cflags == DP_C_LONG) - value = va_arg (args, unsigned long int); - else if (cflags == DP_C_LLONG) - value = va_arg (args, unsigned LLONG); - else - value = va_arg (args, unsigned int); - total += fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); - break; - case 'X': - flags |= DP_F_UP; - case 'x': - flags |= DP_F_UNSIGNED; - if (cflags == DP_C_SHORT) - value = va_arg (args, unsigned int) & ( (1 << sizeof(unsigned short int) * 8) - 1); - else if (cflags == DP_C_LONG) - value = va_arg (args, unsigned long int); - else if (cflags == DP_C_LLONG) - value = va_arg (args, unsigned LLONG); - else - value = va_arg (args, unsigned int); - total += fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags); - break; - case 'f': - if (cflags == DP_C_LDOUBLE) - fvalue = va_arg (args, LDOUBLE); - else - fvalue = va_arg (args, double); - /* um, floating point? */ - total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); - break; - case 'E': - flags |= DP_F_UP; - case 'e': - if (cflags == DP_C_LDOUBLE) - fvalue = va_arg (args, LDOUBLE); - else - fvalue = va_arg (args, double); - /* um, floating point? */ - total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); - break; - case 'G': - flags |= DP_F_UP; - case 'g': - if (cflags == DP_C_LDOUBLE) - fvalue = va_arg (args, LDOUBLE); - else - fvalue = va_arg (args, double); - /* um, floating point? */ - total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); - break; - case 'c': - total += dopr_outch (buffer, &currlen, maxlen, va_arg (args, int)); - break; - case 's': - strvalue = va_arg (args, char *); - total += fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max); - break; - case 'p': - strvalue = va_arg (args, void *); - total += fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, - max, flags); - break; - case 'n': - if (cflags == DP_C_SHORT) - { - short int *num; - num = va_arg (args, short int *); - *num = currlen; - } - else if (cflags == DP_C_LONG) - { - long int *num; - num = va_arg (args, long int *); - *num = currlen; - } - else if (cflags == DP_C_LLONG) - { - LLONG *num; - num = va_arg (args, LLONG *); - *num = currlen; - } - else - { - int *num; - num = va_arg (args, int *); - *num = currlen; - } - break; - case '%': - total += dopr_outch (buffer, &currlen, maxlen, ch); - break; - case 'w': - /* not supported yet, treat as next char */ - ch = *format++; - break; - default: - /* Unknown, skip */ - break; - } - ch = *format++; - state = DP_S_DEFAULT; - flags = cflags = min = 0; - max = -1; - break; - case DP_S_DONE: - break; - default: - /* hmm? */ - break; /* some picky compilers need this */ - } - } - if (maxlen > 0) - buffer[currlen] = '\0'; - return total; + do { + text[digits++] = '0' + val % 10; + val /= 10; + } while ( val ); + + if ( signedVal < 0 ) { + text[digits++] = '-'; + } + + buf = *buf_p; + + if( !( flags & LADJUST ) ) { + while ( digits < width ) { + *buf++ = ( flags & ZEROPAD ) ? '0' : ' '; + width--; + } + } + + while ( digits-- ) { + *buf++ = text[digits]; + width--; + } + + if( flags & LADJUST ) { + while ( width-- ) { + *buf++ = ( flags & ZEROPAD ) ? '0' : ' '; + } + } + + *buf_p = buf; } -static int fmtstr (char *buffer, size_t *currlen, size_t maxlen, - char *value, int flags, int min, int max) -{ - int padlen, strln; /* amount to pad */ - int cnt = 0; - int total = 0; - - if (value == 0) - { - value = ""; - } +/* + * TiM - Required since the native QVM code can't handle UInts... >_< + * This is AddInt horribly mutilated. ;P + */ +void AddULong( char **buf_p, unsigned long val, int width, int flags ) { + char text[32]; + int digits; + /*int signedVal;*/ + char *buf; - for (strln = 0; value[strln]; ++strln); /* strlen */ - if (max >= 0 && max < strln) - strln = max; - padlen = min - strln; - if (padlen < 0) - padlen = 0; - if (flags & DP_F_MINUS) - padlen = -padlen; /* Left Justify */ + digits = 0; + /*signedVal = val; + if ( val < 0 ) { + val = -val; + }*/ + do { + text[digits++] = '0' + val % 10; + val /= 10; + } while ( val ); - while (padlen > 0) - { - total += dopr_outch (buffer, currlen, maxlen, ' '); - --padlen; - } - while (*value && ((max < 0) || (cnt < max))) - { - total += dopr_outch (buffer, currlen, maxlen, *value++); - ++cnt; - } - while (padlen < 0) - { - total += dopr_outch (buffer, currlen, maxlen, ' '); - ++padlen; - } - return total; + /*if ( signedVal < 0 ) { + text[digits++] = '-'; + }*/ + + buf = *buf_p; + + if( !( flags & LADJUST ) ) { + while ( digits < width ) { + *buf++ = ( flags & ZEROPAD ) ? '0' : ' '; + width--; + } + } + + while ( digits-- ) { + *buf++ = text[digits]; + width--; + } + + if( flags & LADJUST ) { + while ( width-- ) { + *buf++ = ( flags & ZEROPAD ) ? '0' : ' '; + } + } + + *buf_p = buf; } -/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ +/* + * TiM - 'borrowed' from Q3 1.32 and modified so it can handle the + * rounding up system that EF has. + * I'm going to bet it was because of this id Software chose to + * round down floats from then on + */ +void AddFloat( char **buf_p, float fval, int width, int prec ) { + char text[32]; + int digits; + float signedVal; + char *buf; + int val; -static int fmtint (char *buffer, size_t *currlen, size_t maxlen, - LLONG value, int base, int min, int max, int flags) -{ - int signvalue = 0; - unsigned LLONG uvalue; - char convert[24]; - int place = 0; - int spadlen = 0; /* amount to space pad */ - int zpadlen = 0; /* amount to zero pad */ - const char *digits; - int total = 0; - - if (max < 0) - max = 0; + /* get the sign */ + signedVal = fval; + if ( fval < 0 ) { + fval = -fval; + } - uvalue = value; + /*Com_Printf( "wholeNumber = %i, roundsUp = %i\n", fval, wholeNumber, roundsUp );*/ - if(!(flags & DP_F_UNSIGNED)) - { - if( value < 0 ) { - signvalue = '-'; - uvalue = -value; - } - else - if (flags & DP_F_PLUS) /* Do a sign (+/i) */ - signvalue = '+'; - else - if (flags & DP_F_SPACE) - signvalue = ' '; - } - - if (flags & DP_F_UP) - /* Should characters be upper case? */ - digits = "0123456789ABCDEF"; - else - digits = "0123456789abcdef"; + /* write the float number */ + digits = 0; + val = (int)fval; + if ( fval - val < 0.0f ) + val--; - do { - convert[place++] = digits[uvalue % (unsigned)base]; - uvalue = (uvalue / (unsigned)base ); - } while(uvalue && (place < sizeof (convert))); - if (place == sizeof (convert)) place--; - convert[place] = 0; + do { + text[digits++] = '0' + (val % 10); + val /= 10; + } while ( val ); - zpadlen = max - place; - spadlen = min - MAX (max, place) - (signvalue ? 1 : 0); - if (zpadlen < 0) zpadlen = 0; - if (spadlen < 0) spadlen = 0; - if (flags & DP_F_ZERO) - { - zpadlen = MAX(zpadlen, spadlen); - spadlen = 0; - } - if (flags & DP_F_MINUS) - spadlen = -spadlen; /* Left Justifty */ + if ( signedVal < 0 ) { + text[digits++] = '-'; + } -#ifdef DEBUG_SNPRINTF - dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n", - zpadlen, spadlen, min, max, place)); + buf = *buf_p; + + while ( digits < width ) { + *buf++ = ' '; + width--; + } + + while ( digits-- ) { + *buf++ = text[digits]; + } + + *buf_p = buf; + + if (prec < 0) + prec = 6; + /* write the fraction */ + digits = 0; + while (digits < prec) { + fval -= (int)fval; + fval = Q_fabs(fval); /* if it gets rounded up, it becomes neg, so just abs it */ + fval *= 10.0; + val = (int)fval; + text[digits++] = '0' + (val % 10); + } + + if (digits > 0) { + buf = *buf_p; + *buf++ = '.'; + for (prec = 0; prec < digits; prec++) { + *buf++ = text[prec]; + } + *buf_p = buf; + } +} + + +/*void AddFloat( char **buf_p, float fval, int width, int prec ) { + char text[32]; + int digits; + float signedVal; + char *buf; + int val; + //decimal points + float decVal; + int decScaled; + //flipping loop + char temp; + int i; + //rounding check + qboolean wholeNumber = qfalse; + qboolean roundsUp = qfalse; + float decimal = 0.9f; + + // FIXME!!!! handle fractions + //TiM - WHAT THE HELL!? YOU LEFT OUT FRACTIONS!?! WTF MAN WTF?!?! >_ 2 ) + //ioEF casts by rounding down. ( 1.5 -> 1 ) + //as this can create a sizeable variance, we have to account for it + roundsUp = (int)decimal; + + digits = 0; + signedVal = fval; + if ( fval < 0 ) { + fval = -fval; + } + + //determine if it's a whole number or not (ie = x.000 ) + wholeNumber = (fval - (float)((int)fval) == 0); + + //isolate the whole number portion of it, rounding down to maintain precision + val = (int)fval - (!wholeNumber && roundsUp ? 1 : 0); //3.452 : 4 - 1 = 3 + + //isolate the decimal number portion + decVal = (fval - (float)val); //3.452 - 3 = 0.452 + do { + decScaled = 0; + decVal *= 10.0f; //scale it up one int at a time - 0.452*10 = 4.52 + decScaled = ((int)decVal - (!wholeNumber && roundsUp ? 1 : 0)); // = 4 + //Com_Printf( "decScaled = %i\n", decScaled ); + text[digits++] = '0' + decScaled % 10; //'0' + 4 = '4' + decVal = decVal - (float)decScaled; //4.52 - 4 = 0.52 + } while ( (prec >= 0) ? digits < prec : digits < 6 ); + + //now swap it around so it's backwards (I brought it in forwards, but the whole section is done backwards) + for ( i=0; i < digits>>1; i++ ) + { + temp = text[i]; + text[i] = text[(digits-1)-i]; + text[(digits-1)-i] = temp; + } + + //add a dot + text[digits++] = '.'; + + //handle the whole number part + do { + text[digits++] = '0' + val % 10; + val /= 10; + } while ( val ); + + if ( signedVal < 0 ) { + text[digits++] = '-'; + } + + buf = *buf_p; + + while ( digits < width ) { + *buf++ = ' '; + width--; + } + + while ( digits-- ) { + *buf++ = text[digits]; + } + + *buf_p = buf; +}*/ + + +void AddString( char **buf_p, char *string, int width, int prec ) { + int size; + char *buf; + + buf = *buf_p; + + if ( string == NULL ) { + string = "(null)"; + prec = -1; + } + + if ( prec >= 0 ) { + for( size = 0; size < prec; size++ ) { + if( string[size] == '\0' ) { + break; + } + } + } + else { + size = strlen( string ); + } + + width -= size; + + while( size-- ) { + *buf++ = *string++; + } + + while( width-- > 0 ) { + *buf++ = ' '; + } + + *buf_p = buf; +} + +/* +vsprintf + +I'm not going to support a bunch of the more arcane stuff in here +just to keep it simpler. For example, the '*' and '$' are not +currently supported. I've tried to make it so that it will just +parse and ignore formats we don't support. +*/ +int vsprintf( char *buffer, const char *fmt, va_list argptr ) { + int *arg; + char *buf_p; + char ch; + int flags; + int width; + int prec; + int n; + char sign; + + buf_p = buffer; + arg = (int *)argptr; + + while( qtrue ) { + /* run through the format string until we hit a '%' or '\0' */ + for ( ch = *fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++ ) { + *buf_p++ = ch; + } + if ( ch == '\0' ) { + goto done; + } + + /* skip over the '%' */ + fmt++; + + /* reset formatting state */ + flags = 0; + width = 0; + prec = -1; + sign = '\0'; + +rflag: + ch = *fmt++; +reswitch: + switch( ch ) { + case '-': + flags |= LADJUST; + goto rflag; + case '.': + n = 0; + while( is_digit( ( ch = *fmt++ ) ) ) { + n = 10 * n + ( ch - '0' ); + } + prec = n < 0 ? -1 : n; + goto reswitch; + case '0': + flags |= ZEROPAD; + goto rflag; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + n = 0; + do { + n = 10 * n + ( ch - '0' ); + ch = *fmt++; + } while( is_digit( ch ) ); + width = n; + goto reswitch; + case 'c': + *buf_p++ = (char)*arg; + arg++; + break; + case 'd': + case 'i': + AddInt( &buf_p, *arg, width, flags ); + arg++; + break; + case 'f': + AddFloat( &buf_p, *(double *)arg, width, prec ); +#ifdef __LCC__ + arg += 1; /* everything is 32 bit in my compiler */ +#else + arg += 2; #endif + break; + case 's': + AddString( &buf_p, (char *)*arg, width, prec ); + arg++; + break; + /* TiM */ + case 'u': + AddULong( &buf_p, *(unsigned long *)arg, width, flags ); + arg++; + break; + case '%': + *buf_p++ = ch; + break; + default: + *buf_p++ = (char)*arg; + arg++; + break; + } + } - /* Spaces */ - while (spadlen > 0) - { - total += dopr_outch (buffer, currlen, maxlen, ' '); - --spadlen; - } - - /* Sign */ - if (signvalue) - total += dopr_outch (buffer, currlen, maxlen, signvalue); - - /* Zeros */ - if (zpadlen > 0) - { - while (zpadlen > 0) - { - total += dopr_outch (buffer, currlen, maxlen, '0'); - --zpadlen; - } - } - - /* Digits */ - while (place > 0) - total += dopr_outch (buffer, currlen, maxlen, convert[--place]); - - /* Left Justified spaces */ - while (spadlen < 0) { - total += dopr_outch (buffer, currlen, maxlen, ' '); - ++spadlen; - } - - return total; +done: + *buf_p = 0; + return buf_p - buffer; } -static LDOUBLE abs_val (LDOUBLE value) -{ - LDOUBLE result = value; - - if (value < 0) - result = -value; - - return result; -} - -static LDOUBLE pow10 (int exp) -{ - LDOUBLE result = 1; - - while (exp) - { - result *= 10; - exp--; - } - - return result; -} - -static long round (LDOUBLE value) -{ - long intpart; - - intpart = value; - value = value - intpart; - if (value >= 0.5) - intpart++; - - return intpart; -} - -static int fmtfp (char *buffer, size_t *currlen, size_t maxlen, - LDOUBLE fvalue, int min, int max, int flags) -{ - int signvalue = 0; - LDOUBLE ufvalue; - char iconvert[20]; - char fconvert[20]; - int iplace = 0; - int fplace = 0; - int padlen = 0; /* amount to pad */ - int zpadlen = 0; - int caps = 0; - int total = 0; - long intpart; - long fracpart; - - /* - * AIX manpage says the default is 0, but Solaris says the default - * is 6, and sprintf on AIX defaults to 6 - */ - if (max < 0) - max = 6; - - ufvalue = abs_val (fvalue); - - if (fvalue < 0) - signvalue = '-'; - else - if (flags & DP_F_PLUS) /* Do a sign (+/i) */ - signvalue = '+'; - else - if (flags & DP_F_SPACE) - signvalue = ' '; - -#if 0 - if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ -#endif - - intpart = ufvalue; - - /* - * Sorry, we only support 9 digits past the decimal because of our - * conversion method - */ - if (max > 9) - max = 9; - - /* We "cheat" by converting the fractional part to integer by - * multiplying by a factor of 10 - */ - fracpart = round ((pow10 (max)) * (ufvalue - intpart)); - - if (fracpart >= pow10 (max)) - { - intpart++; - fracpart -= pow10 (max); - } - -#ifdef DEBUG_SNPRINTF - dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart)); -#endif - - /* Convert integer part */ - do { - iconvert[iplace++] = - (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10]; - intpart = (intpart / 10); - } while(intpart && (iplace < 20)); - if (iplace == 20) iplace--; - iconvert[iplace] = 0; - - /* Convert fractional part */ - do { - fconvert[fplace++] = - (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10]; - fracpart = (fracpart / 10); - } while(fracpart && (fplace < 20)); - if (fplace == 20) fplace--; - fconvert[fplace] = 0; - - /* -1 for decimal point, another -1 if we are printing a sign */ - padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); - zpadlen = max - fplace; - if (zpadlen < 0) - zpadlen = 0; - if (padlen < 0) - padlen = 0; - if (flags & DP_F_MINUS) - padlen = -padlen; /* Left Justifty */ - - if ((flags & DP_F_ZERO) && (padlen > 0)) - { - if (signvalue) - { - total += dopr_outch (buffer, currlen, maxlen, signvalue); - --padlen; - signvalue = 0; - } - while (padlen > 0) - { - total += dopr_outch (buffer, currlen, maxlen, '0'); - --padlen; - } - } - while (padlen > 0) - { - total += dopr_outch (buffer, currlen, maxlen, ' '); - --padlen; - } - if (signvalue) - total += dopr_outch (buffer, currlen, maxlen, signvalue); - - while (iplace > 0) - total += dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]); - - /* - * Decimal point. This should probably use locale to find the correct - * char to print out. - */ - if (max > 0) - { - total += dopr_outch (buffer, currlen, maxlen, '.'); - - while (zpadlen-- > 0) - total += dopr_outch (buffer, currlen, maxlen, '0'); - - while (fplace > 0) - total += dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]); - } - - while (padlen < 0) - { - total += dopr_outch (buffer, currlen, maxlen, ' '); - ++padlen; - } - - return total; -} - -static int dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c) -{ - if (*currlen + 1 < maxlen) - buffer[(*currlen)++] = c; - return 1; -} - -int Q_vsnprintf(char *str, size_t length, const char *fmt, va_list args) -{ - return dopr(str, length, fmt, args); -} /* this is really crappy */ int sscanf( const char *buffer, const char *fmt, ... ) { int cmd; - va_list ap; + int **arg; int count; - size_t len; - va_start (ap, fmt); + arg = (int **)&fmt + 1; count = 0; while ( *fmt ) { @@ -2099,40 +1277,22 @@ int sscanf( const char *buffer, const char *fmt, ... ) { continue; } - fmt++; - cmd = *fmt; - - if (isdigit (cmd)) { - len = (size_t)_atoi (&fmt); - cmd = *(fmt - 1); - } else { - len = MAX_STRING_CHARS - 1; - fmt++; - } + cmd = fmt[1]; + fmt += 2; switch ( cmd ) { case 'i': case 'd': case 'u': - *(va_arg (ap, int *)) = _atoi( &buffer ); + **arg = _atoi( &buffer ); break; case 'f': - *(va_arg (ap, float *)) = _atof( &buffer ); + *(float *)*arg = _atof( &buffer ); break; - case 's': - { - char *s = va_arg (ap, char *); - while (isspace (*buffer)) - buffer++; - while (*buffer && !isspace (*buffer) && len-- > 0 ) - *s++ = *buffer++; - *s++ = '\0'; - break; - } } + arg++; } - va_end (ap); return count; } diff --git a/code/game/bg_lib.h b/code/game/bg_lib.h index 75e3a44..97242d2 100644 --- a/code/game/bg_lib.h +++ b/code/game/bg_lib.h @@ -1,43 +1,12 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ // bg_lib.h -- standard C library replacement routines used by code // compiled for the virtual machine // This file is NOT included on native builds -#if !defined( BG_LIB_H ) && defined( Q3_VM ) -#define BG_LIB_H -//Ignore __attribute__ on non-gcc platforms -#ifndef __GNUC__ -#ifndef __attribute__ -#define __attribute__(x) -#endif -#endif +#ifdef Q3_VM +#error "Q3_VM is defined - QVMs are no longer supported by RPG-X2" -#ifndef NULL -#define NULL ((void *)0) -#endif - -typedef unsigned int size_t; +typedef int size_t; typedef char * va_list; #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) @@ -45,37 +14,21 @@ typedef char * va_list; #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) #define va_end(ap) ( ap = (va_list)0 ) -#define CHAR_BIT 8 /* number of bits in a char */ -#define SCHAR_MAX 0x7f /* maximum signed char value */ -#define SCHAR_MIN (-SCHAR_MAX - 1) /* minimum signed char value */ -#define UCHAR_MAX 0xff /* maximum unsigned char value */ +#define CHAR_BIT 8 /* number of bits in a char */ +#define SCHAR_MIN (-128) /* minimum signed char value */ +#define SCHAR_MAX 127 /* maximum signed char value */ +#define UCHAR_MAX 0xff /* maximum unsigned char value */ -#define SHRT_MAX 0x7fff /* maximum (signed) short value */ -#define SHRT_MIN (-SHRT_MAX - 1) /* minimum (signed) short value */ +#define SHRT_MIN (-32768) /* minimum (signed) short value */ +#define SHRT_MAX 32767 /* maximum (signed) short value */ #define USHRT_MAX 0xffff /* maximum unsigned short value */ -#define INT_MAX 0x7fffffff /* maximum (signed) int value */ -#define INT_MIN (-INT_MAX - 1) /* minimum (signed) int value */ +#define INT_MIN (-2147483647 - 1) /* minimum (signed) int value */ +#define INT_MAX 2147483647 /* maximum (signed) int value */ #define UINT_MAX 0xffffffff /* maximum unsigned int value */ -#define LONG_MAX 0x7fffffffL /* maximum (signed) long value */ -#define LONG_MIN (-LONG_MAX - 1) /* minimum (signed) long value */ +#define LONG_MIN (-2147483647L - 1) /* minimum (signed) long value */ +#define LONG_MAX 2147483647L /* maximum (signed) long value */ #define ULONG_MAX 0xffffffffUL /* maximum unsigned long value */ -#define isalnum(c) (isalpha(c) || isdigit(c)) -#define isalpha(c) (isupper(c) || islower(c)) -#define isascii(c) ((c) > 0 && (c) <= 0x7f) -#define iscntrl(c) (((c) >= 0) && (((c) <= 0x1f) || ((c) == 0x7f))) -#define isdigit(c) ((c) >= '0' && (c) <= '9') -#define isgraph(c) ((c) != ' ' && isprint(c)) -#define islower(c) ((c) >= 'a' && (c) <= 'z') -#define isprint(c) ((c) >= ' ' && (c) <= '~') -#define ispunct(c) (((c) > ' ' && (c) <= '~') && !isalnum(c)) -#define isspace(c) ((c) == ' ' || (c) == '\f' || (c) == '\n' || (c) == '\r' || \ - (c) == '\t' || (c) == '\v') -#define isupper(c) ((c) >= 'A' && (c) <= 'Z') -#define isxdigit(c) (isxupper(c) || isxlower(c)) -#define isxlower(c) (isdigit(c) || (c >= 'a' && c <= 'f')) -#define isxupper(c) (isdigit(c) || (c >= 'A' && c <= 'F')) - // Misc functions typedef int cmp_t(const void *, const void *); void qsort(void *a, size_t n, size_t es, cmp_t *cmp); @@ -88,7 +41,6 @@ char *strcat( char *strDestination, const char *strSource ); char *strcpy( char *strDestination, const char *strSource ); int strcmp( const char *string1, const char *string2 ); char *strchr( const char *string, int c ); -char *strrchr(const char *string, int c); char *strstr( const char *string, const char *strCharSet ); char *strncpy( char *strDest, const char *strSource, size_t count ); int tolower( int c ); @@ -96,14 +48,11 @@ int toupper( int c ); double atof( const char *string ); double _atof( const char **stringPtr ); -double strtod( const char *nptr, char **endptr ); int atoi( const char *string ); int _atoi( const char **stringPtr ); -long strtol( const char *nptr, char **endptr, int base ); -int Q_vsnprintf( char *buffer, size_t length, const char *fmt, va_list argptr ); - -int sscanf( const char *buffer, const char *fmt, ... ) __attribute__ ((format (scanf, 2, 3))); +int vsprintf( char *buffer, const char *fmt, va_list argptr ); +int sscanf( const char *buffer, const char *fmt, ... ); // Memory functions void *memmove( void *dest, const void *src, size_t count ); @@ -120,6 +69,5 @@ double atan2( double y, double x ); double tan( double x ); int abs( int n ); double fabs( double x ); -double acos( double x ); -#endif // BG_LIB_H +#endif // Q3_VM diff --git a/code/game/bg_local.h b/code/game/bg_local.h index 1e785f0..b4a8d01 100644 --- a/code/game/bg_local.h +++ b/code/game/bg_local.h @@ -1,28 +1,8 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // // bg_local.h -- local definitions for the bg (both games) files -#define MIN_WALK_NORMAL 0.7f // can't walk on very steep slopes +#define MIN_WALK_NORMAL 0.7 // can't walk on very steep slopes #define STEPSIZE 18 @@ -31,7 +11,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define TIMER_LAND 130 #define TIMER_GESTURE (34*66+50) -#define OVERCLIP 1.001f + +#define OVERCLIP 1.001 // all of the locals will be zeroed before each // pmove, just to make damn sure we don't have @@ -56,20 +37,6 @@ typedef struct { extern pmove_t *pm; extern pml_t pml; -// movement parameters -extern float pm_stopspeed; -extern float pm_duckScale; -extern float pm_swimScale; - -extern float pm_accelerate; -extern float pm_airaccelerate; -extern float pm_wateraccelerate; -extern float pm_flyaccelerate; - -extern float pm_friction; -extern float pm_waterfriction; -extern float pm_flightfriction; - extern int c_pmove; void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce ); @@ -80,3 +47,4 @@ qboolean PM_SlideMove( qboolean gravity ); void PM_StepSlideMove( qboolean gravity ); + diff --git a/code/game/bg_misc.c b/code/game/bg_misc.c index 597b492..07cdade 100644 --- a/code/game/bg_misc.c +++ b/code/game/bg_misc.c @@ -1,30 +1,62 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. +/* Copyright (C) 1999-2000 Id Software, Inc. + * + * bg_misc.c -- both games misc functions, all completely stateless + */ -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// -// bg_misc.c -- both games misc functions, all completely stateless - -#include "../qcommon/q_shared.h" +#include "q_shared.h" #include "bg_public.h" +int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode ); +void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ); +void trap_FS_FCloseFile( fileHandle_t f ); +void trap_FS_Read( void *buffer, int len, fileHandle_t f ); + +/* If you change these: PLEASE CHANGE THE COMMENTS ON THE AMMO PICKUPS, WHICH DETAIL THE QUANTITY IN THE CLIP*/ +#define AMMO_PHASER_CLIP 50 +#define AMMO_COMPRESSION_CLIP 32 +#define AMMO_IMOD_CLIP 15 +#define AMMO_SCAVENGER_CLIP 30 +#define AMMO_STASIS_CLIP 15 +#define AMMO_GRENADE_CLIP 10 +#define AMMO_TETRION_CLIP 40 +#define AMMO_QUANTUM_CLIP 6 +#define AMMO_DREADNOUGHT_CLIP 40 + +char races[256]; + +/* + * TiM : Tidied up for programmer easability... O_o + * Marcin: not used since 30/12/2008*/ +/** +* Max ammo for each weapon. Unused. +*/ +int Max_Ammo[WP_NUM_WEAPONS] = +{ + 0, // WP_0, + + 5, // WP_1 + + 5, // WP_2, + 5, // WP_3, + 5, // WP_4, + + 5, // WP_5, !! this should match PHASER_AMMO_MAX defined in bg_public + 5, // WP_6, + 5, // WP_7, + 5, // WP_8, + 5, // WP_9, + 5, // WP_10, + + 5, // WP_11, + 5, // WP_12, + 5, // WP_13 + + 5, // WP_14, + 5, // WP_NEUTRINO_PROBE, + + //64 // WP_7 +}; + /*QUAKED item_***** ( 0 0 0 ) (-16 -16 -16) (16 16 16) suspended DO NOT USE THIS CLASS, IT JUST HOLDS GENERAL INFORMATION. The suspended flag will allow items to hang in the air, otherwise they are dropped to the next surface. @@ -44,193 +76,133 @@ An item fires all of its targets when it is picked up. If the toucher can't car gitem_t bg_itemlist[] = { { - NULL, - NULL, - { NULL, - NULL, - NULL, NULL} , -/* icon */ NULL, -/* pickup */ NULL, - 0, - 0, - 0, -/* precache */ "", -/* sounds */ "" - }, // leave index 0 alone + NULL, /* char *classname; */ + NULL, /* char *pickup_sound;*/ + NULL, /* char *world_model;*/ + NULL, /* char *view_model;*/ + NULL, /* char *icon;*/ + NULL, /* char *pickup_name; */ /* for printing on pickup */ + 0, /* int quantity; */ /* for ammo how much, or duration of powerup */ + 0, /* itemType_t giType; */ /* IT_* flags */ + 0, /* int giTag; */ + "", /* char *precaches; */ /* string of all models and images this item will use */ + "" /* char *sounds; */ /* string of all sounds this item will use */ + }, /* leave index 0 alone */ - // - // ARMOR - // + /* + * WEAPONS + */ -/*QUAKED item_armor_shard (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +/* WP_1 */ +/*QUAKED weapon_imod (.3 .3 1) (-16 -16 -16) (16 16 16) suspended */ { - "item_armor_shard", - "sound/misc/ar1_pkup.wav", - { "models/powerups/armor/shard.md3", - "models/powerups/armor/shard_sphere.md3", - NULL, NULL} , -/* icon */ "icons/iconr_shard", -/* pickup */ "Armor Shard", - 5, - IT_ARMOR, - 0, -/* precache */ "", -/* sounds */ "" - }, - -/*QUAKED item_armor_combat (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "item_armor_combat", - "sound/misc/ar2_pkup.wav", - { "models/powerups/armor/armor_yel.md3", - NULL, NULL, NULL}, -/* icon */ "icons/iconr_yellow", -/* pickup */ "Armor", - 50, - IT_ARMOR, - 0, -/* precache */ "", -/* sounds */ "" - }, - -/*QUAKED item_armor_body (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "item_armor_body", - "sound/misc/ar2_pkup.wav", - { "models/powerups/armor/armor_red.md3", - NULL, NULL, NULL}, -/* icon */ "icons/iconr_red", -/* pickup */ "Heavy Armor", - 100, - IT_ARMOR, - 0, -/* precache */ "", -/* sounds */ "" - }, - - // - // health - // -/*QUAKED item_health_small (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "item_health_small", - "sound/items/s_health.wav", - { "models/powerups/health/small_cross.md3", - "models/powerups/health/small_sphere.md3", - NULL, NULL }, -/* icon */ "icons/iconh_green", -/* pickup */ "5 Health", - 5, - IT_HEALTH, - 0, -/* precache */ "", -/* sounds */ "" - }, - -/*QUAKED item_health (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "item_health", - "sound/items/n_health.wav", - { "models/powerups/health/medium_cross.md3", - "models/powerups/health/medium_sphere.md3", - NULL, NULL }, -/* icon */ "icons/iconh_yellow", -/* pickup */ "25 Health", - 25, - IT_HEALTH, - 0, -/* precache */ "", -/* sounds */ "" - }, - -/*QUAKED item_health_large (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "item_health_large", - "sound/items/l_health.wav", - { "models/powerups/health/large_cross.md3", - "models/powerups/health/large_sphere.md3", - NULL, NULL }, -/* icon */ "icons/iconh_red", -/* pickup */ "50 Health", - 50, - IT_HEALTH, - 0, -/* precache */ "", -/* sounds */ "" - }, - -/*QUAKED item_health_mega (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "item_health_mega", - "sound/items/m_health.wav", - { "models/powerups/health/mega_cross.md3", - "models/powerups/health/mega_sphere.md3", - NULL, NULL }, -/* icon */ "icons/iconh_mega", -/* pickup */ "Mega Health", - 100, - IT_HEALTH, - 0, -/* precache */ "", -/* sounds */ "" - }, - - - // - // WEAPONS - // - -/*QUAKED weapon_gauntlet (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_gauntlet", - "sound/misc/w_pkup.wav", - { "models/weapons2/gauntlet/gauntlet.md3", - NULL, NULL, NULL}, -/* icon */ "icons/iconw_gauntlet", -/* pickup */ "Gauntlet", - 0, + "weapon_null_hand", + "sound/silence.wav", /* "sound/weapons/w_pkup.wav", */ + "models/weapons2/hand/hand_w.md3", /* "models/weapons2/imod/imod2_w.md3", */ /* world */ + "models/weapons2/hand/hand.md3", /* "models/weapons2/imod/imod2.md3", */ /* view */ + "icons/w_icon_hand", /* icon */ + " ", /* pickup */ + AMMO_IMOD_CLIP, IT_WEAPON, - WP_GAUNTLET, + WP_1, + "", /* precache */ + "" /* sounds */ + }, + + +/*QUAKED weapon_tricorder (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +*/ + { + "weapon_tricorder", + "sound/weapons/w_pkup.wav", + "models/weapons2/tricorder/tricorder_w.md3", /* world */ + "models/weapons2/tricorder/tricorder.md3", /* view */ + "icons/w_icon_tricorder", /* icon */ + "Tricorder", /* pickup */ + AMMO_PHASER_CLIP, + IT_WEAPON, + WP_2, + "", /* precache */ + "" /* sounds */ + }, + +/*QUAKED weapon_padd (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +*/ + { + "weapon_padd", + "sound/weapons/w_pkup.wav", + "models/weapons2/padd/padd_w.md3", /* world */ + "models/weapons2/padd/padd.md3", /* view */ + "icons/w_icon_padd", /* icon */ + "Padd", /* pickup */ + AMMO_PHASER_CLIP, + IT_WEAPON, + WP_3, + "", /* precache */ + "", /* sounds */ + }, + +/*QUAKED weapon_scavenger (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +*/ + { + "weapon_coffee", + "sound/weapons/w_pkup.wav", + "models/weapons2/coffeecup/coffee_cup_w.md3", /* world */ + "models/weapons2/coffeecup/coffee_cup.md3", /* view */ + "icons/w_icon_coffee", /* icon */ + "Coffee, Black", /* pickup */ + AMMO_SCAVENGER_CLIP, + IT_WEAPON, + WP_4, + "", /* precache */ + "" /* sounds */ + }, + +/*QUAKED weapon_phaser (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +*/ + { + "weapon_phaser", + "sound/weapons/w_pkup.wav", + "models/weapons2/phaser/phaser_w.md3", /* world */ + "models/weapons2/phaser/phaser.md3", /* view */ + "icons/w_icon_phaser", /* icon */ + "Phaser", /* pickup */ + AMMO_PHASER_CLIP, + IT_WEAPON, + WP_5, + "", /* precache */ + "" /* sounds */ + }, + +/*QUAKED weapon_compressionrifle (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +*/ + { + "weapon_compressionrifle", + "sound/weapons/w_pkup.wav", + "models/weapons2/prifle/prifle_w.md3", //world + "models/weapons2/prifle/prifle.md3", //view +/* icon */ "icons/w_icon_rifle", +/* pickup */ "Phaser Compression Rifle", + AMMO_COMPRESSION_CLIP, + IT_WEAPON, + WP_6, /* precache */ "", /* sounds */ "" }, -/*QUAKED weapon_shotgun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +/*QUAKED weapon_tetriondisruptor (.3 .3 1) (-16 -16 -16) (16 16 16) suspended */ { - "weapon_shotgun", - "sound/misc/w_pkup.wav", - { "models/weapons2/shotgun/shotgun.md3", - NULL, NULL, NULL}, -/* icon */ "icons/iconw_shotgun", -/* pickup */ "Shotgun", - 10, + "weapon_tr116", + "sound/weapons/w_pkup.wav", + "models/weapons2/tr116/tr-116_w.md3",//world + "models/weapons2/tr116/tr-116.md3", //view +/* icon */ "icons/w_icon_tr116", +/* pickup */ "TR-116", + AMMO_TETRION_CLIP, IT_WEAPON, - WP_SHOTGUN, -/* precache */ "", -/* sounds */ "" - }, - -/*QUAKED weapon_machinegun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_machinegun", - "sound/misc/w_pkup.wav", - { "models/weapons2/machinegun/machinegun.md3", - NULL, NULL, NULL}, -/* icon */ "icons/iconw_machinegun", -/* pickup */ "Machinegun", - 40, - IT_WEAPON, - WP_MACHINEGUN, + WP_7, /* precache */ "", /* sounds */ "" }, @@ -239,110 +211,126 @@ gitem_t bg_itemlist[] = */ { "weapon_grenadelauncher", - "sound/misc/w_pkup.wav", - { "models/weapons2/grenadel/grenadel.md3", - NULL, NULL, NULL}, -/* icon */ "icons/iconw_grenade", -/* pickup */ "Grenade Launcher", - 10, + "sound/weapons/w_pkup.wav", + "models/weapons2/launcher/launcher_w.md3", //world + "models/weapons2/launcher/launcher.md3", //view +/* icon */ "icons/w_icon_grenade", +/* pickup */ "Compound Grenade Launcher", + AMMO_GRENADE_CLIP, IT_WEAPON, - WP_GRENADE_LAUNCHER, + WP_8, /* precache */ "", -/* sounds */ "sound/weapons/grenade/hgrenb1a.wav sound/weapons/grenade/hgrenb2a.wav" +/* sounds */ "sound/weapons/glauncher/bounce1.wav sound/weapons/glauncher/bounce2.wav" }, -/*QUAKED weapon_rocketlauncher (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +/*QUAKED weapon_quantumburst (.3 .3 1) (-16 -16 -16) (16 16 16) suspended */ { - "weapon_rocketlauncher", - "sound/misc/w_pkup.wav", - { "models/weapons2/rocketl/rocketl.md3", - NULL, NULL, NULL}, -/* icon */ "icons/iconw_rocket", -/* pickup */ "Rocket Launcher", - 10, + "weapon_quantumburst", + "sound/weapons/w_pkup.wav", + "models/weapons2/q_burst/q_burst_w.md3", //world + "models/weapons2/q_burst/q_burst.md3", //view +/* icon */ "icons/w_icon_quantum", +/* pickup */ "Photon Burst", + AMMO_QUANTUM_CLIP, IT_WEAPON, - WP_ROCKET_LAUNCHER, + WP_9, /* precache */ "", /* sounds */ "" }, -/*QUAKED weapon_lightning (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +/*QUAKED weapon_stasisweapon (.3 .3 1) (-16 -16 -16) (16 16 16) suspended */ { - "weapon_lightning", - "sound/misc/w_pkup.wav", - { "models/weapons2/lightning/lightning.md3", - NULL, NULL, NULL}, -/* icon */ "icons/iconw_lightning", -/* pickup */ "Lightning Gun", - 100, + "weapon_disruptor", + "sound/weapons/w_pkup.wav", + "models/weapons2/alien_disruptor/disruptor_w.md3", //world + "models/weapons2/alien_disruptor/disruptor.md3", //view +/* icon */ "icons/w_icon_disruptor", +/* pickup */ "Disruptor", + AMMO_STASIS_CLIP, IT_WEAPON, - WP_LIGHTNING, + WP_10, /* precache */ "", /* sounds */ "" }, -/*QUAKED weapon_railgun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +/*QUAKED weapon_borg_weapon (.3 .3 1) (-16 -16 -16) (16 16 16) suspended */ { - "weapon_railgun", - "sound/misc/w_pkup.wav", - { "models/weapons2/railgun/railgun.md3", - NULL, NULL, NULL}, -/* icon */ "icons/iconw_railgun", -/* pickup */ "Railgun", - 10, + "weapon_medkit", + "sound/weapons/w_pkup.wav", + "models/weapons2/medkit/medkit_w.md3", //world + "models/weapons2/medkit/medkit.md3", //view +/* icon */ "icons/w_icon_medkit", +/* pickup */ "Medkit", + AMMO_PHASER_CLIP, IT_WEAPON, - WP_RAILGUN, + WP_11, /* precache */ "", /* sounds */ "" }, -/*QUAKED weapon_plasmagun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +/*QUAKED weapon_voyager_hypo (.3 .3 1) (-16 -16 -16) (16 16 16) suspended */ { - "weapon_plasmagun", - "sound/misc/w_pkup.wav", - { "models/weapons2/plasma/plasma.md3", - NULL, NULL, NULL}, -/* icon */ "icons/iconw_plasma", -/* pickup */ "Plasma Gun", - 50, + "weapon_voyager_hypo", + "sound/weapons/w_pkup.wav", + "models/weapons2/hypospray/hypospray_w.md3", //world + "models/weapons2/hypospray/hypospray.md3", //view +/* icon */ "icons/w_icon_hypo", +/* pickup */ "Hypo", + AMMO_PHASER_CLIP, IT_WEAPON, - WP_PLASMAGUN, + WP_12, +/* precache */ "", +/* sounds */ "" + }, + +/*QUAKED weapon_dreadnought (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +*/ + { + "weapon_dermal_regen", + "sound/weapons/w_pkup.wav", + "models/weapons2/dermal_regen/dermal_regen_w.md3", + "models/weapons2/dermal_regen/dermal_regen.md3", +/* icon */ "icons/w_icon_dermalregen", +/* pickup */ "Dermal Regenerator", + AMMO_DREADNOUGHT_CLIP, + IT_WEAPON, + WP_13, /* precache */ "", /* sounds */ "" }, -/*QUAKED weapon_bfg (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +/*QUAKED weapon_borg_assimilator (.3 .3 1) (-16 -16 -16) (16 16 16) suspended */ { - "weapon_bfg", - "sound/misc/w_pkup.wav", - { "models/weapons2/bfg/bfg.md3", - NULL, NULL, NULL}, -/* icon */ "icons/iconw_bfg", -/* pickup */ "BFG10K", - 20, + "weapon_toolkit", + "sound/weapons/w_pkup.wav", + "models/weapons2/toolkit/toolkit_w.md3", //world + "models/weapons2/toolkit/toolkit.md3", //view +/* icon */ "icons/w_icon_toolkit", +/* pickup */ "Toolkit", + AMMO_PHASER_CLIP, IT_WEAPON, - WP_BFG, + WP_14, /* precache */ "", /* sounds */ "" }, -/*QUAKED weapon_grapplinghook (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +/*QUAKED weapon_engtool (.3 .3 1) (-16 -16 -16) (16 16 16) suspended */ { - "weapon_grapplinghook", - "sound/misc/w_pkup.wav", - { "models/weapons2/grapple/grapple.md3", - NULL, NULL, NULL}, -/* icon */ "icons/iconw_grapple", -/* pickup */ "Grappling Hook", - 0, + "weapon_hyperspanner", + "sound/weapons/w_pkup.wav", + "models/weapons2/hyperspanner/hyperspanner_w.md3", //world + "models/weapons2/hyperspanner/hyperspanner.md3", //view +/* icon */ "icons/w_icon_hyperspanner", +/* pickup */ "Hyperspanner", + AMMO_PHASER_CLIP, IT_WEAPON, - WP_GRAPPLING_HOOK, + WP_15, /* precache */ "", /* sounds */ "" }, @@ -351,130 +339,231 @@ gitem_t bg_itemlist[] = // AMMO ITEMS // -/*QUAKED ammo_shells (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +/*QUAKED ammo_compressionrifle (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +32 ammo for the compression rifle */ { - "ammo_shells", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/shotgunam.md3", - NULL, NULL, NULL}, -/* icon */ "icons/icona_shotgun", -/* pickup */ "Shells", - 10, + "ammo_compressionrifle", + "sound/player/pickupenergy.wav", + "models/powerups/trek/prifle_ammo.md3", //world + NULL, +/* icon */ "icons/dm_phaser_sm", +/* pickup */ "Phaser Compression Rifle Ammo", + AMMO_COMPRESSION_CLIP, IT_AMMO, - WP_SHOTGUN, + WP_6, /* precache */ "", /* sounds */ "" }, -/*QUAKED ammo_bullets (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +/*QUAKED ammo_imod (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +15 ammo for the I-MOD */ { - "ammo_bullets", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/machinegunam.md3", - NULL, NULL, NULL}, -/* icon */ "icons/icona_machinegun", -/* pickup */ "Bullets", - 50, + "ammo_imod", + "sound/player/pickupenergy.wav", + "models/powerups/trek/imod_ammo.md3", //world + NULL, +/* icon */ "icons/dm_imod", +/* pickup */ "I-MOD Ammo", + AMMO_IMOD_CLIP, IT_AMMO, - WP_MACHINEGUN, + WP_1, +/* precache */ "", +/* sounds */ "" + }, + +/*QUAKED ammo_scavenger (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +30 ammo for the scavenger rifle +*/ + { + "ammo_scavenger", + "sound/player/pickupenergy.wav", + "models/powerups/trek/scavenger_ammo.md3", //world + NULL, +/* icon */ "icons/dm_scav", +/* pickup */ "Scavenger Weapon Ammo", + AMMO_SCAVENGER_CLIP, + IT_AMMO, + WP_4, +/* precache */ "", +/* sounds */ "" + }, + +/*QUAKED ammo_stasis (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +15 ammo for the stasis weapon +*/ + { + "ammo_stasis", + "sound/player/pickupenergy.wav", + "models/powerups/trek/stasis_ammo.md3", //world + NULL, +/* icon */ "icons/dm_stasis_sm", +/* pickup */ "Stasis Weapon Ammo", + AMMO_STASIS_CLIP, + IT_AMMO, + WP_10, /* precache */ "", /* sounds */ "" }, /*QUAKED ammo_grenades (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +10 ammo for the grenade launcher */ { "ammo_grenades", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/grenadeam.md3", - NULL, NULL, NULL}, -/* icon */ "icons/icona_grenade", -/* pickup */ "Grenades", + "sound/player/pickupenergy.wav", + "models/powerups/trek/glauncher_ammo.md3", //world + NULL, +/* icon */ "icons/dm_glauncher_sm", +/* pickup */ "Compound Grenade Launcher Ammo", + AMMO_GRENADE_CLIP, + IT_AMMO, + WP_8, +/* precache */ "", +/* sounds */ "" + }, + +/*QUAKED ammo_tetriondisruptor (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +40 ammo for the tetrYon disruptor +*/ + { + "ammo_tetriondisruptor", + "sound/player/pickupenergy.wav", + "models/powerups/trek/tetrion_ammo.md3", //world + NULL, +/* icon */ "icons/dm_tetrion_sm", +/* pickup */ "Tetryon Pulse Disruptor Ammo", + AMMO_TETRION_CLIP, + IT_AMMO, + WP_7, +/* precache */ "", +/* sounds */ "" + }, + +/*QUAKED ammo_quantumburst (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +6 ammo for the quantum burst weapon +*/ + { + "ammo_quantumburst", + "sound/player/pickupenergy.wav", + "models/powerups/trek/torpedo.md3", //world + NULL, +/* icon */ "icons/dm_torpedo_sm", +/* pickup */ "Photon Burst Ammo", + AMMO_QUANTUM_CLIP, + IT_AMMO, + WP_9, +/* precache */ "", +/* sounds */ "" + }, + +/*QUAKED ammo_dreadnought (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +40 ammo for the dreadnought/arc welder +*/ + { + "ammo_dreadnought", + "sound/player/pickupenergy.wav", + "models/powerups/trek/arc_ammo.md3", //world + NULL, +/* icon */ "icons/dm_a_arc_sm", +/* pickup */ "Dermal Regenerator Ammo", + AMMO_DREADNOUGHT_CLIP, + IT_AMMO, + WP_13, +/* precache */ "", +/* sounds */ "" + }, + + // + // ARMOR + // + +/*QUAKED item_armor_shard (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +5 points of shields +*/ + { + "item_armor_shard", + "sound/player/pickupenergy.wav", + "models/powerups/trek/armor_shard.md3", //world + NULL, +/* icon */ "icons/icon_shards", +/* pickup */ "Incremental Shield Boost", 5, - IT_AMMO, - WP_GRENADE_LAUNCHER, + IT_ARMOR, + 0, /* precache */ "", /* sounds */ "" }, -/*QUAKED ammo_cells (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +/*QUAKED item_armor_combat (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +50 points of shields */ { - "ammo_cells", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/plasmaam.md3", - NULL, NULL, NULL}, -/* icon */ "icons/icona_plasma", -/* pickup */ "Cells", - 30, - IT_AMMO, - WP_PLASMAGUN, + "item_armor_combat", + "sound/player/pickupenergy.wav", + "models/powerups/trek/armor.md3", //world + NULL, +/* icon */ "icons/dm_armor_sm", +/* pickup */ "Personal Deflector Screen", + 50, + IT_ARMOR, + 0, /* precache */ "", /* sounds */ "" }, -/*QUAKED ammo_lightning (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +/*QUAKED item_armor_body (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +100 points of shields */ { - "ammo_lightning", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/lightningam.md3", - NULL, NULL, NULL}, -/* icon */ "icons/icona_lightning", -/* pickup */ "Lightning", - 60, - IT_AMMO, - WP_LIGHTNING, + "item_armor_body", + "sound/player/suitenergy.wav", + "models/powerups/trek/armor2.md3", //world + NULL, +/* icon */ "icons/dm_superarmor_sm", +/* pickup */ "Isokinetic Deflector Screen", + 100, + IT_ARMOR, + 0, /* precache */ "", /* sounds */ "" }, -/*QUAKED ammo_rockets (.3 .3 1) (-16 -16 -16) (16 16 16) suspended + // + // HEALTH + // + +/*QUAKED item_hypo_small (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +5 points of health, max of 200 */ { - "ammo_rockets", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/rocketam.md3", - NULL, NULL, NULL}, -/* icon */ "icons/icona_rocket", -/* pickup */ "Rockets", + "item_hypo_small", + "sound/player/pickuphealth.wav", + "models/powerups/trek/hypo_single.md3", //world + NULL, +/* icon */ "icons/dm_health_sm", +/* pickup */ "Booster Hypospray", 5, - IT_AMMO, - WP_ROCKET_LAUNCHER, + IT_HEALTH, + 0, /* precache */ "", /* sounds */ "" }, -/*QUAKED ammo_slugs (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +/*QUAKED item_hypo (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +25 points of health, max of 100 */ { - "ammo_slugs", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/railgunam.md3", - NULL, NULL, NULL}, -/* icon */ "icons/icona_railgun", -/* pickup */ "Slugs", - 10, - IT_AMMO, - WP_RAILGUN, -/* precache */ "", -/* sounds */ "" - }, - -/*QUAKED ammo_bfg (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "ammo_bfg", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/bfgam.md3", - NULL, NULL, NULL}, -/* icon */ "icons/icona_bfg", -/* pickup */ "Bfg Ammo", - 15, - IT_AMMO, - WP_BFG, + "item_hypo", + "sound/player/suithealth.wav", + "models/powerups/trek/hypo_double.md3", //world + NULL, +/* icon */ "icons/dm_health2_sm", +/* pickup */ "Emergency Hypospray", + 25, + IT_HEALTH, + 0, /* precache */ "", /* sounds */ "" }, @@ -482,32 +571,35 @@ gitem_t bg_itemlist[] = // // HOLDABLE ITEMS // -/*QUAKED holdable_teleporter (.3 .3 1) (-16 -16 -16) (16 16 16) suspended + +/*QUAKED holdable_transporter (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +pick it up and it stays in your inventory until used, at which time you drop it in front of you and it still +kind of resides in your inventory. when you use it _again_ it activates and anyone can walk through the transporter. */ { - "holdable_teleporter", + "holdable_transporter", "sound/items/holdable.wav", - { "models/powerups/holdable/teleporter.md3", - NULL, NULL, NULL}, -/* icon */ "icons/teleporter", -/* pickup */ "Personal Teleporter", + "models/powerups/trek/transporter.md3", //world + NULL, +/* icon */ "icons/dm_transport_sm", +/* pickup */ "Personal Transporter Device", 60, IT_HOLDABLE, - HI_TELEPORTER, + HI_TRANSPORTER, /* precache */ "", /* sounds */ "" }, + /*QUAKED holdable_medkit (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +pick it up and it stays in your inventory until used, at which time it sets your health to 100 */ { "holdable_medkit", "sound/items/holdable.wav", - { - "models/powerups/holdable/medkit.md3", - "models/powerups/holdable/medkit_sphere.md3", - NULL, NULL}, -/* icon */ "icons/medkit", -/* pickup */ "Medkit", + "models/powerups/trek/med_kit.md3", //world + NULL, +/* icon */ "icons/dm_health3_sm", +/* pickup */ "Portable Medkit", 60, IT_HOLDABLE, HI_MEDKIT, @@ -518,50 +610,17 @@ gitem_t bg_itemlist[] = // // POWERUP ITEMS // -/*QUAKED item_quad (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "item_quad", - "sound/items/quaddamage.wav", - { "models/powerups/instant/quad.md3", - "models/powerups/instant/quad_ring.md3", - NULL, NULL }, -/* icon */ "icons/quad", -/* pickup */ "Quad Damage", - 30, - IT_POWERUP, - PW_QUAD, -/* precache */ "", -/* sounds */ "sound/items/damage2.wav sound/items/damage3.wav" - }, - -/*QUAKED item_enviro (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "item_enviro", - "sound/items/protect.wav", - { "models/powerups/instant/enviro.md3", - "models/powerups/instant/enviro_ring.md3", - NULL, NULL }, -/* icon */ "icons/envirosuit", -/* pickup */ "Battle Suit", - 30, - IT_POWERUP, - PW_BATTLESUIT, -/* precache */ "", -/* sounds */ "sound/items/airout.wav sound/items/protect3.wav" - }, /*QUAKED item_haste (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +for 30 seconds you run at %150 of your normal speed and your firing delays are 3/4 as long */ { "item_haste", "sound/items/haste.wav", - { "models/powerups/instant/haste.md3", - "models/powerups/instant/haste_ring.md3", - NULL, NULL }, -/* icon */ "icons/haste", -/* pickup */ "Speed", + "models/powerups/trek/haste.md3", //world + NULL, +/* icon */ "icons/dm_haste", +/* pickup */ "Temporal Accelerator", 30, IT_POWERUP, PW_HASTE, @@ -570,371 +629,389 @@ gitem_t bg_itemlist[] = }, /*QUAKED item_invis (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +20 seconds of invisibility */ { "item_invis", "sound/items/invisibility.wav", - { "models/powerups/instant/invis.md3", - "models/powerups/instant/invis_ring.md3", - NULL, NULL }, -/* icon */ "icons/invis", -/* pickup */ "Invisibility", - 30, + "models/powerups/trek/invisible.md3", //world + NULL, +/* icon */ "icons/dm_invisibility", +/* pickup */ "Personal Cloaking Device", + 20, IT_POWERUP, PW_INVIS, /* precache */ "", /* sounds */ "" }, -/*QUAKED item_regen (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "item_regen", - "sound/items/regeneration.wav", - { "models/powerups/instant/regen.md3", - "models/powerups/instant/regen_ring.md3", - NULL, NULL }, -/* icon */ "icons/regen", -/* pickup */ "Regeneration", - 30, - IT_POWERUP, - PW_REGEN, -/* precache */ "", -/* sounds */ "sound/items/regen.wav" - }, - /*QUAKED item_flight (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +30 seconds of flight */ { "item_flight", "sound/items/flight.wav", - { "models/powerups/instant/flight.md3", - "models/powerups/instant/flight_ring.md3", - NULL, NULL }, -/* icon */ "icons/flight", -/* pickup */ "Flight", - 60, + "models/powerups/trek/flight.md3", //world + NULL, +/* icon */ "icons/dm_flight", +/* pickup */ "Anti-Gravity Pack", + 30, IT_POWERUP, PW_FLIGHT, /* precache */ "", /* sounds */ "sound/items/flight.wav" }, -/*QUAKED team_CTF_redflag (1 0 0) (-16 -16 -16) (16 16 16) -Only in CTF games +/*QUAKED holdable_detpack (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +BLAMMO! */ { - "team_CTF_redflag", + "holdable_detpack", + "sound/player/pickupenergy.wav", + "models/powerups/trek/detpak.md3", //world NULL, - { "models/flags/r_flag.md3", - NULL, NULL, NULL }, -/* icon */ "icons/iconf_red1", -/* pickup */ "Red Flag", - 0, - IT_TEAM, - PW_REDFLAG, +/* icon */ "icons/icon_detpack", +/* pickup */ "Ultritium Explosive Charge", + 1, // 5, + IT_HOLDABLE, + HI_DETPACK, /* precache */ "", -/* sounds */ "" +/* sounds */ "sound/weapons/detpacklatch.wav sound/weapons/explosions/detpakexplode.wav" }, -/*QUAKED team_CTF_blueflag (0 0 1) (-16 -16 -16) (16 16 16) -Only in CTF games +/*QUAKED holdable_shield (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +About 25 seconds or 250 hit points of a portashield. */ { - "team_CTF_blueflag", + "holdable_shield", + "sound/player/pickupenergy.wav", + "models/powerups/trek/shield_gen.md3", //world NULL, - { "models/flags/b_flag.md3", - NULL, NULL, NULL }, -/* icon */ "icons/iconf_blu1", -/* pickup */ "Blue Flag", - 0, - IT_TEAM, - PW_BLUEFLAG, -/* precache */ "", -/* sounds */ "" - }, - -#ifdef MISSIONPACK -/*QUAKED holdable_kamikaze (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "holdable_kamikaze", - "sound/items/holdable.wav", - { "models/powerups/kamikazi.md3", - NULL, NULL, NULL}, -/* icon */ "icons/kamikaze", -/* pickup */ "Kamikaze", - 60, +/* icon */ "icons/icon_shield", +/* pickup */ "Portable Force Field", + 1, IT_HOLDABLE, - HI_KAMIKAZE, + HI_SHIELD, /* precache */ "", -/* sounds */ "sound/items/kamikazerespawn.wav" - }, +/* sounds */ "sound/weapons/detpacklatch.wav sound/movers/forceup.wav sound/ambience/spark5.wav" + }, -/*QUAKED holdable_portal (.3 .3 1) (-16 -16 -16) (16 16 16) suspended + +/*QUAKED Holographic_decoy (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +About 1 minute of a holographic decoy. */ { - "holdable_portal", + "Holographic_decoy", "sound/items/holdable.wav", - { "models/powerups/holdable/porter.md3", - NULL, NULL, NULL}, -/* icon */ "icons/portal", -/* pickup */ "Portal", - 60, + "models/powerups/trek/decoy.md3", //world + NULL, +/* icon */ "icons/icon_decoy", +/* pickup */ "Holographic Decoy", + 1, IT_HOLDABLE, - HI_PORTAL, + HI_DECOY, /* precache */ "", /* sounds */ "" - }, - -/*QUAKED holdable_invulnerability (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "holdable_invulnerability", - "sound/items/holdable.wav", - { "models/powerups/holdable/invulnerability.md3", - NULL, NULL, NULL}, -/* icon */ "icons/invulnerability", -/* pickup */ "Invulnerability", - 60, - IT_HOLDABLE, - HI_INVULNERABILITY, -/* precache */ "", -/* sounds */ "" - }, - -/*QUAKED ammo_nails (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "ammo_nails", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/nailgunam.md3", - NULL, NULL, NULL}, -/* icon */ "icons/icona_nailgun", -/* pickup */ "Nails", - 20, - IT_AMMO, - WP_NAILGUN, -/* precache */ "", -/* sounds */ "" - }, - -/*QUAKED ammo_mines (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "ammo_mines", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/proxmineam.md3", - NULL, NULL, NULL}, -/* icon */ "icons/icona_proxlauncher", -/* pickup */ "Proximity Mines", - 10, - IT_AMMO, - WP_PROX_LAUNCHER, -/* precache */ "", -/* sounds */ "" - }, - -/*QUAKED ammo_belt (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "ammo_belt", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/chaingunam.md3", - NULL, NULL, NULL}, -/* icon */ "icons/icona_chaingun", -/* pickup */ "Chaingun Belt", - 100, - IT_AMMO, - WP_CHAINGUN, -/* precache */ "", -/* sounds */ "" - }, + }, // - // PERSISTANT POWERUP ITEMS + // New Weapons // -/*QUAKED item_scout (.3 .3 1) (-16 -16 -16) (16 16 16) suspended redTeam blueTeam -*/ - { - "item_scout", - "sound/items/scout.wav", - { "models/powerups/scout.md3", - NULL, NULL, NULL }, -/* icon */ "icons/scout", -/* pickup */ "Scout", - 30, - IT_PERSISTANT_POWERUP, - PW_SCOUT, -/* precache */ "", -/* sounds */ "" - }, - -/*QUAKED item_guard (.3 .3 1) (-16 -16 -16) (16 16 16) suspended redTeam blueTeam -*/ - { - "item_guard", - "sound/items/guard.wav", - { "models/powerups/guard.md3", - NULL, NULL, NULL }, -/* icon */ "icons/guard", -/* pickup */ "Guard", - 30, - IT_PERSISTANT_POWERUP, - PW_GUARD, -/* precache */ "", -/* sounds */ "" - }, - -/*QUAKED item_doubler (.3 .3 1) (-16 -16 -16) (16 16 16) suspended redTeam blueTeam -*/ - { - "item_doubler", - "sound/items/doubler.wav", - { "models/powerups/doubler.md3", - NULL, NULL, NULL }, -/* icon */ "icons/doubler", -/* pickup */ "Doubler", - 30, - IT_PERSISTANT_POWERUP, - PW_DOUBLER, -/* precache */ "", -/* sounds */ "" - }, - -/*QUAKED item_doubler (.3 .3 1) (-16 -16 -16) (16 16 16) suspended redTeam blueTeam -*/ - { - "item_ammoregen", - "sound/items/ammoregen.wav", - { "models/powerups/ammo.md3", - NULL, NULL, NULL }, -/* icon */ "icons/ammo_regen", -/* pickup */ "Ammo Regen", - 30, - IT_PERSISTANT_POWERUP, - PW_AMMOREGEN, -/* precache */ "", -/* sounds */ "" - }, - - /*QUAKED team_CTF_neutralflag (0 0 1) (-16 -16 -16) (16 16 16) -Only in One Flag CTF games -*/ - { - "team_CTF_neutralflag", - NULL, - { "models/flags/n_flag.md3", - NULL, NULL, NULL }, -/* icon */ "icons/iconf_neutral1", -/* pickup */ "Neutral Flag", - 0, - IT_TEAM, - PW_NEUTRALFLAG, -/* precache */ "", -/* sounds */ "" - }, - - { - "item_redcube", - "sound/misc/am_pkup.wav", - { "models/powerups/orb/r_orb.md3", - NULL, NULL, NULL }, -/* icon */ "icons/iconh_rorb", -/* pickup */ "Red Cube", - 0, - IT_TEAM, - 0, -/* precache */ "", -/* sounds */ "" - }, - - { - "item_bluecube", - "sound/misc/am_pkup.wav", - { "models/powerups/orb/b_orb.md3", - NULL, NULL, NULL }, -/* icon */ "icons/iconh_borb", -/* pickup */ "Blue Cube", - 0, - IT_TEAM, - 0, -/* precache */ "", -/* sounds */ "" - }, -/*QUAKED weapon_nailgun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_nailgun", - "sound/misc/w_pkup.wav", - { "models/weapons/nailgun/nailgun.md3", - NULL, NULL, NULL}, -/* icon */ "icons/iconw_nailgun", -/* pickup */ "Nailgun", - 10, - IT_WEAPON, - WP_NAILGUN, -/* precache */ "", -/* sounds */ "" - }, - -/*QUAKED weapon_prox_launcher (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_prox_launcher", - "sound/misc/w_pkup.wav", - { "models/weapons/proxmine/proxmine.md3", - NULL, NULL, NULL}, -/* icon */ "icons/iconw_proxlauncher", -/* pickup */ "Prox Launcher", - 5, - IT_WEAPON, - WP_PROX_LAUNCHER, -/* precache */ "", -/* sounds */ "sound/weapons/proxmine/wstbtick.wav " - "sound/weapons/proxmine/wstbactv.wav " - "sound/weapons/proxmine/wstbimpl.wav " - "sound/weapons/proxmine/wstbimpm.wav " - "sound/weapons/proxmine/wstbimpd.wav " - "sound/weapons/proxmine/wstbactv.wav" - }, - -/*QUAKED weapon_chaingun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_chaingun", - "sound/misc/w_pkup.wav", - { "models/weapons/vulcan/vulcan.md3", - NULL, NULL, NULL}, -/* icon */ "icons/iconw_chaingun", -/* pickup */ "Chaingun", - 80, - IT_WEAPON, - WP_CHAINGUN, -/* precache */ "", -/* sounds */ "sound/weapons/vulcan/wvulwind.wav" - }, -#endif // end of list marker {NULL} }; -int bg_numItems = ARRAY_LEN( bg_itemlist ) - 1; +int bg_numItems = sizeof(bg_itemlist) / sizeof(bg_itemlist[0]) - 1; +#define STAND_VIEWHEIGHT (DEFAULT_VIEWHEIGHT) +#define SITTING_VIEWHEIGHT (22) /* TiM: To reduce redundancy here */ +#define CROUCHING_VIEWHEIGHT (CROUCH_VIEWHEIGHT) +#define HITBOX_DEFAULT 32 +#define HITBOX_CROUCH 16 +#define HITBOX_NULL -23 /*0 //-24 doesn't work on patch meshes apparently. That might be more the mapper's fault than mine tho lol */ +#define NULL_ANIM -1 /* -============== -BG_FindItemForPowerup -============== + * !Main emotes definition arrayzor + * Suffice it to say... my hands hurt after writing this thing >.< + */ +emoteList_t bg_emoteList[] = { + //name //type //enumName //enumLoop //viewHeight //hitBox Height //bodyFlags //animFlags + { "alert", TYPE_MISC, -1, NULL_ANIM, 0, 0, 0, 0, }, + { "alert2", TYPE_MISC, -1, NULL_ANIM, 0, 0, 0, 0, }, + { "assimilated", TYPE_FULLBODY, BOTH_ASSIMILATED1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_ALL | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "", TYPE_NONE, -1, NULL_ANIM, 0, 0, 0, 0, }, + { "benchsit1_2stand", TYPE_SITTING, BOTH_BENCHSIT1_2STAND, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "benchsit1_fixboot", TYPE_SITTING, BOTH_BENCHSIT1_FIXBOOT, BOTH_BENCHSIT1_IDLE, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_REVERTLOOP_BOTH }, + { "benchsit1_idle", TYPE_SITTING, BOTH_BENCHSIT1_IDLE, NULL_ANIM, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_LOOP_BOTH | EMOTE_OVERRIDE_BOTH }, + { "benchsit1to2", TYPE_SITTING, BOTH_BENCHSIT1TO2, BOTH_BENCHSIT2_IDLE, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "benchsit2_idle", TYPE_SITTING, BOTH_BENCHSIT2_IDLE, NULL_ANIM, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_LOOP_BOTH | EMOTE_OVERRIDE_BOTH }, + { "benchsit2to1", TYPE_SITTING, BOTH_BENCHSIT2TO1, BOTH_BENCHSIT1_IDLE, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "catch1", TYPE_FULLBODY, BOTH_CATCH1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "console1", TYPE_CONSOLE, BOTH_CONSOLE1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER | EMOTE_LOOP_BOTH }, + { "console1_idle", TYPE_CONSOLE, BOTH_CONSOLE1IDLE, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "console1_left", TYPE_CONSOLE, BOTH_CONSOLE1LEFT, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER | EMOTE_LOOP_BOTH }, + { "console1_right", TYPE_CONSOLE, BOTH_CONSOLE1RIGHT, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER | EMOTE_LOOP_BOTH }, + { "console2", TYPE_CONSOLE, BOTH_CONSOLE2, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_LOOP_BOTH | EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "console3", TYPE_CONSOLE, BOTH_CONSOLE3, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER | EMOTE_LOOP_BOTH }, + { "console3_idle", TYPE_CONSOLE, BOTH_CONSOLE3IDLE, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER | EMOTE_LOOP_BOTH }, + { "console3_left", TYPE_CONSOLE, BOTH_CONSOLE3LEFT, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER | EMOTE_LOOP_BOTH }, + { "console3_right", TYPE_CONSOLE, BOTH_CONSOLE3RIGHT, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER | EMOTE_LOOP_BOTH }, + { "console4", TYPE_CONSOLE, BOTH_CONSOLE4, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER | EMOTE_LOOP_BOTH }, + { "console5", TYPE_CONSOLE, BOTH_CONSOLE5, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER | EMOTE_LOOP_BOTH }, + { "couchsit1_2stand", TYPE_SITTING, BOTH_COUCHSIT1_2STAND1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "couchsit1_left", TYPE_SITTING, BOTH_COUCHSIT1_GESTURELEFT, BOTH_COUCHSIT1_IDLE, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "couchsit1_right", TYPE_SITTING, BOTH_COUCHSIT1_GESTURERIGHT,BOTH_COUCHSIT1_IDLE, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "couchsit1_idle", TYPE_SITTING, BOTH_COUCHSIT1_IDLE, NULL_ANIM, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "couchsit1_talk", TYPE_SITTING, BOTH_COUCHSIT1_TALKGESTURE, BOTH_COUCHSIT1_IDLE, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "couchsit2to1", TYPE_SITTING, BOTH_COUCHSIT1_TO2, BOTH_COUCHSIT1_IDLE, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_REVERTLOOP_UPPER }, + { "couchsit2_idle", TYPE_SITTING, BOTH_COUCHSIT2, NULL_ANIM, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "coverup1_end", TYPE_FULLBODY, BOTH_COVERUP1_END, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER }, + { "coverup1_loop", TYPE_FULLBODY, BOTH_COVERUP1_LOOP, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER | EMOTE_LOOP_BOTH }, + { "coverup1_start", TYPE_FULLBODY, BOTH_COVERUP1_START, BOTH_COVERUP1_LOOP, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER }, + { "cowar1", TYPE_FULLBODY, BOTH_COWAR1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "crowdlook1", TYPE_FULLBODY, BOTH_CROWDLOOK1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "crowdlook2", TYPE_FULLBODY, BOTH_CROWDLOOK2, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "crowdlook3", TYPE_MISC, BOTH_CROWDLOOK3, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH | EMOTE_LOOP_BOTH }, + { "crowdlook4", TYPE_MISC, BOTH_CROWDLOOK4, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "dive1", TYPE_FULLBODY, BOTH_DIVE1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_ALL | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "eyes_shut", TYPE_MISC, -1, 0, 0, 0, 0, 0, }, + { "eyes_angry", TYPE_MISC, -1, 0, 0, 0, 0, 0, }, + { "gesture2", TYPE_GESTURE, BOTH_GESTURE2, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "gesture3", TYPE_GESTURE, BOTH_GESTURE3, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "get_up1", TYPE_FULLBODY, BOTH_GET_UP1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "grab1", TYPE_FULLBODY, BOTH_GRAB1, BOTH_GRAB2, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "grab2", TYPE_FULLBODY, BOTH_GRAB2, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "grab3", TYPE_FULLBODY, BOTH_GRAB3, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER }, + { "grab4", TYPE_FULLBODY, BOTH_GRAB4, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER | EMOTE_LOOP_BOTH }, + { "grabbed1", TYPE_FULLBODY, BOTH_GRABBED1, BOTH_GRABBED2, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "grabbed2", TYPE_FULLBODY, BOTH_GRABBED2, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "groundshake1", TYPE_FULLBODY, BOTH_GROUNDSHAKE1, BOTH_GROUNDSHAKE1LOOP, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "groundshake1loop", TYPE_FULLBODY, BOTH_GROUNDSHAKE1LOOP, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "groundshake2", TYPE_FULLBODY, BOTH_GROUNDSHAKE2, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "guard_idle1", TYPE_MISC, BOTH_GUARD_IDLE1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "guard_lkrt1", TYPE_MISC, BOTH_GUARD_LKRT1, BOTH_GUARD_IDLE1, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "guard_lookaround1", TYPE_MISC, BOTH_GUARD_LOOKAROUND1, BOTH_GUARD_IDLE1, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "guilt1", TYPE_FULLBODY, BOTH_GUILT1, NULL_ANIM, CROUCHING_VIEWHEIGHT, HITBOX_CROUCH, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "hitwall1", TYPE_FULLBODY, BOTH_HITWALL1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "help1", TYPE_FULLBODY, BOTH_HELP1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "injured1", TYPE_INJURED, BOTH_INJURED1, NULL_ANIM, DEAD_VIEWHEIGHT, HITBOX_CROUCH, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH, }, + { "injured2", TYPE_INJURED, BOTH_INJURED2, NULL_ANIM, DEAD_VIEWHEIGHT, HITBOX_CROUCH, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH, }, + { "injured3", TYPE_INJURED, BOTH_INJURED3, NULL_ANIM, DEAD_VIEWHEIGHT, HITBOX_CROUCH, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH, }, + { "injured4", TYPE_INJURED, BOTH_INJURED4, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH, }, + { "injured4to5", TYPE_INJURED, BOTH_INJURED4TO5, BOTH_INJURED5, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "injured5", TYPE_INJURED, BOTH_INJURED5, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "injured6", TYPE_INJURED, BOTH_INJURED6, NULL_ANIM, DEAD_VIEWHEIGHT, HITBOX_CROUCH, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "injured6_combadge", TYPE_INJURED, BOTH_INJURED6COMBADGE, BOTH_INJURED6, DEAD_VIEWHEIGHT, HITBOX_CROUCH, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "injured6_point", TYPE_INJURED, BOTH_INJURED6POINT, BOTH_INJURED6, DEAD_VIEWHEIGHT, HITBOX_CROUCH, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "kneel_hand1", TYPE_MISC, BOTH_KNEELHAND1, NULL_ANIM, CROUCHING_VIEWHEIGHT, HITBOX_CROUCH, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "laugh1", TYPE_FULLBODY, BOTH_LAUGH2, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER }, + { "laugh2", TYPE_FULLBODY, BOTH_LAUGH1, NULL_ANIM, SITTING_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "lean1", TYPE_MISC, BOTH_LEAN1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "pain2writhe1", TYPE_FULLBODY, BOTH_PAIN2WRITHE1, BOTH_WRITHING1, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "possessed1", TYPE_FULLBODY, BOTH_POSSESSED1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "possessed2", TYPE_FULLBODY, BOTH_POSSESSED2, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER | EMOTE_LOOP_BOTH }, + { "psychicshock1", TYPE_FULLBODY, BOTH_PSYCHICSHOCK1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "psychicshock2", TYPE_FULLBODY, BOTH_PSYCHICSHOCK2, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "scared2", TYPE_FULLBODY, BOTH_SCARED2, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER }, + { "shield1", TYPE_FULLBODY, BOTH_SHIELD1, BOTH_SHIELD2, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER }, + { "shield2", TYPE_FULLBODY, BOTH_SHIELD2, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER | EMOTE_LOOP_BOTH }, + { "sit1stand", TYPE_SITTING, BOTH_SIT1STAND, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_BOTH }, + { "sit1to2", TYPE_SITTING, BOTH_SIT1TO2, BOTH_SIT2, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "sit1to3", TYPE_SITTING, BOTH_SIT1TO3, BOTH_SIT3, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "sit1", TYPE_SITTING, BOTH_SIT1, NULL_ANIM, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "sit2to1", TYPE_SITTING, BOTH_SIT2TO1, BOTH_SIT1, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "sit2to3", TYPE_SITTING, BOTH_SIT2TO3, BOTH_SIT3, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "sit2", TYPE_SITTING, BOTH_SIT2, NULL_ANIM, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "sit3to1", TYPE_SITTING, BOTH_SIT3TO1, BOTH_SIT1, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "sit3to2", TYPE_SITTING, BOTH_SIT3TO2, BOTH_SIT2, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "sit3", TYPE_SITTING, BOTH_SIT3, NULL_ANIM, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "sit4to5", TYPE_SITTING, BOTH_SIT4TO5, BOTH_SIT5, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "sit4to6", TYPE_SITTING, BOTH_SIT4TO6, BOTH_SIT6, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "sit4", TYPE_SITTING, BOTH_SIT4, NULL_ANIM, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "sit5to4", TYPE_SITTING, BOTH_SIT5TO4, BOTH_SIT4, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "sit5to6", TYPE_SITTING, BOTH_SIT5TO6, BOTH_SIT6, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "sit5", TYPE_SITTING, BOTH_SIT5, NULL_ANIM, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "sit6to4", TYPE_SITTING, BOTH_SIT6TO4, BOTH_SIT4, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "sit6to5", TYPE_SITTING, BOTH_SIT6TO5, BOTH_SIT5, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "sit6", TYPE_SITTING, BOTH_SIT6, NULL_ANIM, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "sit7", TYPE_SITTING, BOTH_SIT7, NULL_ANIM, DEAD_VIEWHEIGHT, HITBOX_CROUCH, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_LOOP_BOTH, }, + { "sit7tostand1", TYPE_SITTING, BOTH_SIT7TOSTAND1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "sleep1", TYPE_MISC, BOTH_SLEEP1, NULL_ANIM, DEAD_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "sleep1_nose", TYPE_MISC, BOTH_SLEEP1_NOSE, BOTH_SLEEP1, DEAD_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "sleep1_getup", TYPE_MISC, BOTH_SLEEP1GETUP, NULL_ANIM, DEAD_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "sleep2", TYPE_MISC, BOTH_SLEEP2, NULL_ANIM, DEAD_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "sleep2_shift", TYPE_MISC, BOTH_SLEEP2_SHIFT, BOTH_SLEEP2, DEAD_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "sleep2_getup", TYPE_MISC, BOTH_SLEEP2GETUP, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "sleep3", TYPE_MISC, BOTH_SLEEP3, NULL_ANIM, DEAD_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "sleep3getup", TYPE_MISC, BOTH_SLEEP3GETUP, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "snapto1", TYPE_FULLBODY, BOTH_SNAPTO1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "snapto2", TYPE_FULLBODY, BOTH_SNAPTO2, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "stand1_random1", TYPE_GESTURE, BOTH_STAND1_RANDOM2, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "stand1_random2", TYPE_GESTURE, BOTH_STAND1_RANDOM3, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "stand1_random3", TYPE_GESTURE, BOTH_STAND1_RANDOM4, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "stand1_random4", TYPE_GESTURE, BOTH_STAND1_RANDOM5, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "stand1_random5", TYPE_GESTURE, BOTH_STAND1_RANDOM6, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "stand1_random6", TYPE_GESTURE, BOTH_STAND1_RANDOM7, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "stand1_random7", TYPE_GESTURE, BOTH_STAND1_RANDOM8, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "stand1_random8", TYPE_GESTURE, BOTH_STAND1_RANDOM9, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "stand1_random9", TYPE_GESTURE, BOTH_STAND1_RANDOM10, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "stand1_random10", TYPE_GESTURE, BOTH_STAND1_RANDOM11, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "stand2_random1", TYPE_GESTURE, BOTH_STAND2_RANDOM1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "stand2_random2", TYPE_GESTURE, BOTH_STAND2_RANDOM2, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "stand2_random3", TYPE_GESTURE, BOTH_STAND2_RANDOM3, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "stand2_random4", TYPE_GESTURE, BOTH_STAND2_RANDOM4, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "stand2_random5", TYPE_GESTURE, BOTH_STAND2_RANDOM5, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "stand2_random6", TYPE_GESTURE, BOTH_STAND2_RANDOM6, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "stand2_random7", TYPE_GESTURE, BOTH_STAND2_RANDOM7, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "stand2_random8", TYPE_GESTURE, BOTH_STAND2_RANDOM8, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "stand2_random9", TYPE_GESTURE, BOTH_STAND2_RANDOM9, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "stand2_random10", TYPE_GESTURE, BOTH_STAND2_RANDOM10, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "stand2_random11", TYPE_GESTURE, BOTH_STAND2_RANDOM11, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "stand2_random12", TYPE_GESTURE, BOTH_STAND2_RANDOM12, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_BOTH }, + { "stand3", TYPE_MISC, BOTH_STAND3, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "standup1", TYPE_FULLBODY, BOTH_STANDUP1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "surprised1", TYPE_FULLBODY, BOTH_SURPRISED1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER }, + { "surprised2", TYPE_FULLBODY, BOTH_SURPRISED2, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER }, + { "surprised3", TYPE_FULLBODY, BOTH_SURPRISED3, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER }, + { "surprised4", TYPE_FULLBODY, BOTH_SURPRISED4, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH }, + { "surprised5", TYPE_FULLBODY, BOTH_SURPRISED5, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_OVERRIDE_UPPER }, + { "table_eat1", TYPE_MISC, BOTH_TABLE_EAT1, BOTH_TABLE_IDLE1, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER }, + { "table_getup1", TYPE_MISC, BOTH_TABLE_GETUP1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER }, + { "table_idle1", TYPE_MISC, BOTH_TABLE_IDLE1, NULL_ANIM, SITTING_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "table_talkgesture1", TYPE_MISC, BOTH_TABLE_TALKGESTURE1, BOTH_TABLE_IDLE1, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_UPPER }, + { "talkgesture1", TYPE_GESTURE, BOTH_TALKGESTURE1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_DEFAULT, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "talkgesture2", TYPE_GESTURE, BOTH_TALKGESTURE2, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "talkgesture3", TYPE_GESTURE, TORSO_TALKGESTURE4, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "talkgesture4", TYPE_GESTURE, TORSO_TALKGESTURE5, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "writhing2", TYPE_FULLBODY, BOTH_WRITHING2, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_BOTH, EMOTE_CLAMP_BODY | EMOTE_OVERRIDE_BOTH | EMOTE_LOOP_BOTH }, + { "combadge1", TYPE_GESTURE, TORSO_COMBADGE1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "combadge2", TYPE_GESTURE, TORSO_COMBADGE2, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "combadge3", TYPE_GESTURE, TORSO_COMBADGE3, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "combadge4", TYPE_GESTURE, TORSO_COMBADGE4, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "equipment1", TYPE_GESTURE, TORSO_EQUIPMENT1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "equipment2", TYPE_GESTURE, TORSO_EQUIPMENT2, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "equipment3", TYPE_GESTURE, TORSO_EQUIPMENT3, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "grablbackl", TYPE_GESTURE, TORSO_GRABLBACKL, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "hand1", TYPE_GESTURE, TORSO_HAND1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "hand2", TYPE_GESTURE, TORSO_HAND2, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "handgesture1", TYPE_GESTURE, TORSO_HANDGESTURE1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "handgesture2", TYPE_GESTURE, TORSO_HANDGESTURE2, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "handgesture3", TYPE_GESTURE, TORSO_HANDGESTURE3, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "handgesture4", TYPE_GESTURE, TORSO_HANDGESTURE4, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "handgesture5", TYPE_GESTURE, TORSO_HANDGESTURE5, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "handgesture6", TYPE_GESTURE, TORSO_HANDGESTURE6, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "handgesture7", TYPE_GESTURE, TORSO_HANDGESTURE7, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "handgesture8", TYPE_GESTURE, TORSO_HANDGESTURE8, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "handgesture9", TYPE_GESTURE, TORSO_HANDGESTURE9, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "handgesture10", TYPE_GESTURE, TORSO_HANDGESTURE10, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "handgesture11", TYPE_GESTURE, TORSO_HANDGESTURE11, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "handgesture12", TYPE_GESTURE, TORSO_HANDGESTURE12, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "handgesture13", TYPE_GESTURE, TORSO_HANDGESTURE13, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "hypospray", TYPE_GESTURE, TORSO_HYPOSPRAY1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "pokeridle1", TYPE_GESTURE, TORSO_POKERIDLE1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_LOOP_UPPER }, + { "pokeridle2", TYPE_GESTURE, TORSO_POKERIDLE2, TORSO_POKERIDLE1, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER }, + { "pokeridle3", TYPE_GESTURE, TORSO_POKERIDLE3, TORSO_POKERIDLE1, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "shout1", TYPE_GESTURE, TORSO_SHOUT1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_LOOP_UPPER }, + { "speechless1", TYPE_GESTURE, TORSO_SPEECHLESS1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_LOOP_UPPER }, + { "speechless2", TYPE_GESTURE, TORSO_SPEECHLESS2, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_LOOP_UPPER }, + { "taunt", TYPE_GESTURE, TORSO_GESTURE, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, + { "wrist1", TYPE_GESTURE, TORSO_WRIST1, NULL_ANIM, STAND_VIEWHEIGHT, HITBOX_NULL, EMOTE_UPPER, EMOTE_OVERRIDE_UPPER | EMOTE_REVERTLOOP_UPPER }, +}; + +/* + * TiM : Hrmm... this may have been why it was crashing on some people's PCs... + *Let's try the old fashioned way... + * int bg_numEmotes = sizeof( emoteList ) / sizeof ( emoteList[0] ); + */ +int bg_numEmotes = 180; + +/* + * TiM: + * !In order to set up a list of items we can use in the 'give' command. + * */ +giveItem_t bg_giveItem[] = { + //consoleName giveType giveValue + { "all", TYPE_ALL, 0 }, + { "health", TYPE_HEALTH, 0 }, + { "weapons", TYPE_WEAPONS, 0 }, + { "ammo", TYPE_AMMO, 0 }, + { "transporter", TYPE_HOLDABLE, HI_TRANSPORTER }, + { "forcefield", TYPE_HOLDABLE, HI_SHIELD }, + { "phaser", TYPE_WEAPON, WP_5 }, + { "phaser_rifle", TYPE_WEAPON, WP_6 }, + { "coffee", TYPE_WEAPON, WP_4 }, + { "disruptor", TYPE_WEAPON, WP_10 }, + { "coffee", TYPE_WEAPON, WP_4 }, + { "admin_gun", TYPE_WEAPON, WP_8 }, + { "tr-116", TYPE_WEAPON, WP_7 }, + { "photon_burst", TYPE_WEAPON, WP_9 }, + { "dermal_regen", TYPE_WEAPON, WP_13 }, + { "hypospray", TYPE_WEAPON, WP_12 }, + { "toolkit", TYPE_WEAPON, WP_14 }, + { "medkit", TYPE_WEAPON, WP_11 }, + { "tricorder", TYPE_WEAPON, WP_2 }, + { "padd", TYPE_WEAPON, WP_3 }, + { "hyperspanner", TYPE_WEAPON, WP_15 }, + { "cloak", TYPE_POWERUP, 0 }, + { "flight", TYPE_POWERUP, 0 }, + { "god", TYPE_POWERUP, 0 } +}; + +/* TiM - Meh... just define the number... doing fancy array stuff seems to make PCs 'splode O_o */ +int bg_numGiveItems = 24; + +/** +* \brief Finds an item by it's classname +* +* \return the item +*/ +gitem_t *BG_FindItemWithClassname(const char *name) +{ + int i = 0; + gitem_t *item = NULL; + + if ( (NULL == name) || (0 == name[0]) ) + { + return NULL; + } + for (i = 0; i < bg_numItems; i++) + { + item = &bg_itemlist[i]; + if (!strcmp(name, item->classname)) + { + return item; + } + } + return NULL; +} + +/** +* Finds the classname for a holdable. +* \return classname for holdable +*/ +char *BG_FindClassnameForHoldable(holdable_t pw) +{ + gitem_t *item = BG_FindItemForHoldable(pw); + + if (item) + { + return item->classname; + } + return NULL; +} + +/** +* Finds item for a powerup. +* \return the item */ gitem_t *BG_FindItemForPowerup( powerup_t pw ) { int i; for ( i = 0 ; i < bg_numItems ; i++ ) { if ( (bg_itemlist[i].giType == IT_POWERUP || - bg_itemlist[i].giType == IT_TEAM || - bg_itemlist[i].giType == IT_PERSISTANT_POWERUP) && + bg_itemlist[i].giType == IT_TEAM) && bg_itemlist[i].giTag == pw ) { return &bg_itemlist[i]; } @@ -944,10 +1021,9 @@ gitem_t *BG_FindItemForPowerup( powerup_t pw ) { } -/* -============== -BG_FindItemForHoldable -============== +/** +* Finds item for a holdable. +* \return the item */ gitem_t *BG_FindItemForHoldable( holdable_t pw ) { int i; @@ -964,15 +1040,12 @@ gitem_t *BG_FindItemForHoldable( holdable_t pw ) { } -/* -=============== -BG_FindItemForWeapon - -=============== +/** +* Finds item for a weapon. +* \return the item */ gitem_t *BG_FindItemForWeapon( weapon_t weapon ) { gitem_t *it; - for ( it = bg_itemlist + 1 ; it->classname ; it++) { if ( it->giType == IT_WEAPON && it->giTag == weapon ) { return it; @@ -983,37 +1056,50 @@ gitem_t *BG_FindItemForWeapon( weapon_t weapon ) { return NULL; } -/* -=============== -BG_FindItem - -=============== +/** +* Finds item for ammo. +* \return the item */ -gitem_t *BG_FindItem( const char *pickupName ) { +gitem_t *BG_FindItemForAmmo( weapon_t weapon ) { + gitem_t *it; + + for ( it = bg_itemlist + 1 ; it->classname ; it++) { + if ( it->giType == IT_AMMO && it->giTag == weapon ) { + return it; + } + } + + Com_Error( ERR_DROP, "Couldn't find item for ammo %i", weapon); + return NULL; +} + +/** +* Find a tiem by pickupName. +* \return the item +*/ +gitem_t *BG_FindItem( const char *pickupName/*const char *classname*/ ) { gitem_t *it; for ( it = bg_itemlist + 1 ; it->classname ; it++ ) { - if ( !Q_stricmp( it->pickup_name, pickupName ) ) + if ( !Q_stricmp( it->pickup_name, pickupName )/*!Q_stricmp( it->classname, classname)*/ ) /* RPG-X: RedTechie - Trying to fix give cmd */ return it; } return NULL; } -/* -============ -BG_PlayerTouchesItem - -Items can be picked up without actually touching their physical bounds to make -grabbing them easier -============ +/** +* \brief Checks if player is touching an item. +* +* Items can be picked up without actually touching their physical bounds to make +* grabbing them easier */ qboolean BG_PlayerTouchesItem( playerState_t *ps, entityState_t *item, int atTime ) { vec3_t origin; BG_EvaluateTrajectory( &item->pos, atTime, origin ); - // we are ignoring ducked differences here + /* we are ignoring ducked differences here */ if ( ps->origin[0] - origin[0] > 44 || ps->origin[0] - origin[0] < -50 || ps->origin[1] - origin[1] > 36 @@ -1028,172 +1114,38 @@ qboolean BG_PlayerTouchesItem( playerState_t *ps, entityState_t *item, int atTim -/* -================ -BG_CanItemBeGrabbed - -Returns false if the item should not be picked up. -This needs to be the same for client side prediction and server use. -================ +/** +* \brief Check if item can be grabbed. +* +* Returns false if the item should not be picked up. +* This needs to be the same for client side prediction and server use. */ -qboolean BG_CanItemBeGrabbed( int gametype, const entityState_t *ent, const playerState_t *ps ) { + +qboolean BG_CanItemBeGrabbed( const entityState_t *ent, const playerState_t *ps, int maxWeap ) { gitem_t *item; -#ifdef MISSIONPACK - int upperBound; -#endif + +//_______________________________________________________________ if ( ent->modelindex < 1 || ent->modelindex >= bg_numItems ) { - Com_Error( ERR_DROP, "BG_CanItemBeGrabbed: index out of range" ); + /*Com_Error( ERR_DROP, "BG_CanItemBeGrabbed: index out of range" ); + Com_Printf ("BG_CanItemBeGrabbed: index out of range\n");*/ + return qfalse; } item = &bg_itemlist[ent->modelindex]; - switch( item->giType ) { - case IT_WEAPON: - return qtrue; // weapons are always picked up - - case IT_AMMO: - if ( ps->ammo[ item->giTag ] >= 200 ) { - return qfalse; // can't hold any more - } - return qtrue; - - case IT_ARMOR: -#ifdef MISSIONPACK - if( bg_itemlist[ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_SCOUT ) { - return qfalse; - } - - // we also clamp armor to the maxhealth for handicapping - if( bg_itemlist[ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) { - upperBound = ps->stats[STAT_MAX_HEALTH]; - } - else { - upperBound = ps->stats[STAT_MAX_HEALTH] * 2; - } - - if ( ps->stats[STAT_ARMOR] >= upperBound ) { - return qfalse; - } -#else - if ( ps->stats[STAT_ARMOR] >= ps->stats[STAT_MAX_HEALTH] * 2 ) { - return qfalse; - } -#endif - return qtrue; - - case IT_HEALTH: - // small and mega healths will go over the max, otherwise - // don't pick up if already at max -#ifdef MISSIONPACK - if( bg_itemlist[ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) { - upperBound = ps->stats[STAT_MAX_HEALTH]; - } - else -#endif - if ( item->quantity == 5 || item->quantity == 100 ) { - if ( ps->stats[STAT_HEALTH] >= ps->stats[STAT_MAX_HEALTH] * 2 ) { - return qfalse; - } - return qtrue; - } - - if ( ps->stats[STAT_HEALTH] >= ps->stats[STAT_MAX_HEALTH] ) { - return qfalse; - } - return qtrue; - - case IT_POWERUP: - return qtrue; // powerups are always picked up - -#ifdef MISSIONPACK - case IT_PERSISTANT_POWERUP: - // can only hold one item at a time - if ( ps->stats[STAT_PERSISTANT_POWERUP] ) { - return qfalse; - } - - // check team only - if( ( ent->generic1 & 2 ) && ( ps->persistant[PERS_TEAM] != TEAM_RED ) ) { - return qfalse; - } - if( ( ent->generic1 & 4 ) && ( ps->persistant[PERS_TEAM] != TEAM_BLUE ) ) { - return qfalse; - } - - return qtrue; -#endif - - case IT_TEAM: // team items, such as flags -#ifdef MISSIONPACK - if( gametype == GT_1FCTF ) { - // neutral flag can always be picked up - if( item->giTag == PW_NEUTRALFLAG ) { - return qtrue; - } - if (ps->persistant[PERS_TEAM] == TEAM_RED) { - if (item->giTag == PW_BLUEFLAG && ps->powerups[PW_NEUTRALFLAG] ) { - return qtrue; - } - } else if (ps->persistant[PERS_TEAM] == TEAM_BLUE) { - if (item->giTag == PW_REDFLAG && ps->powerups[PW_NEUTRALFLAG] ) { - return qtrue; - } - } - } -#endif - if( gametype == GT_CTF ) { - // ent->modelindex2 is non-zero on items if they are dropped - // we need to know this because we can pick up our dropped flag (and return it) - // but we can't pick up our flag at base - if (ps->persistant[PERS_TEAM] == TEAM_RED) { - if (item->giTag == PW_BLUEFLAG || - (item->giTag == PW_REDFLAG && ent->modelindex2) || - (item->giTag == PW_REDFLAG && ps->powerups[PW_BLUEFLAG]) ) - return qtrue; - } else if (ps->persistant[PERS_TEAM] == TEAM_BLUE) { - if (item->giTag == PW_REDFLAG || - (item->giTag == PW_BLUEFLAG && ent->modelindex2) || - (item->giTag == PW_BLUEFLAG && ps->powerups[PW_REDFLAG]) ) - return qtrue; - } - } - -#ifdef MISSIONPACK - if( gametype == GT_HARVESTER ) { - return qtrue; - } -#endif + /* Marcin| 30/12/2008 */ + if (ps->ammo[item->giTag] >= maxWeap) { return qfalse; - - case IT_HOLDABLE: - // can only hold one item at a time - if ( ps->stats[STAT_HOLDABLE_ITEM] ) { - return qfalse; - } + } else { return qtrue; - - case IT_BAD: - Com_Error( ERR_DROP, "BG_CanItemBeGrabbed: IT_BAD" ); - default: -#ifndef Q3_VM -#ifndef NDEBUG - Com_Printf("BG_CanItemBeGrabbed: unknown enum %d\n", item->giType ); -#endif -#endif - break; } - - return qfalse; } //====================================================================== -/* -================ -BG_EvaluateTrajectory - -================ +/** +* Evaluates a trajectory. */ void BG_EvaluateTrajectory( const trajectory_t *tr, int atTime, vec3_t result ) { float deltaTime; @@ -1205,7 +1157,7 @@ void BG_EvaluateTrajectory( const trajectory_t *tr, int atTime, vec3_t result ) VectorCopy( tr->trBase, result ); break; case TR_LINEAR: - deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds + deltaTime = ( atTime - tr->trTime ) * 0.001; /* milliseconds to seconds */ VectorMA( tr->trBase, deltaTime, tr->trDelta, result ); break; case TR_SINE: @@ -1217,16 +1169,16 @@ void BG_EvaluateTrajectory( const trajectory_t *tr, int atTime, vec3_t result ) if ( atTime > tr->trTime + tr->trDuration ) { atTime = tr->trTime + tr->trDuration; } - deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds + deltaTime = ( atTime - tr->trTime ) * 0.001; /* milliseconds to seconds */ if ( deltaTime < 0 ) { deltaTime = 0; } VectorMA( tr->trBase, deltaTime, tr->trDelta, result ); break; case TR_GRAVITY: - deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds + deltaTime = ( atTime - tr->trTime ) * 0.001; /* milliseconds to seconds */ VectorMA( tr->trBase, deltaTime, tr->trDelta, result ); - result[2] -= 0.5 * DEFAULT_GRAVITY * deltaTime * deltaTime; // FIXME: local gravity... + result[2] -= 0.5 * DEFAULT_GRAVITY * deltaTime * deltaTime; /* FIXME: local gravity... */ break; default: Com_Error( ERR_DROP, "BG_EvaluateTrajectory: unknown trType: %i", tr->trTime ); @@ -1234,12 +1186,8 @@ void BG_EvaluateTrajectory( const trajectory_t *tr, int atTime, vec3_t result ) } } -/* -================ -BG_EvaluateTrajectoryDelta - -For determining velocity at a given time -================ +/** +* Determining velocity at a given time */ void BG_EvaluateTrajectoryDelta( const trajectory_t *tr, int atTime, vec3_t result ) { float deltaTime; @@ -1255,7 +1203,7 @@ void BG_EvaluateTrajectoryDelta( const trajectory_t *tr, int atTime, vec3_t resu break; case TR_SINE: deltaTime = ( atTime - tr->trTime ) / (float) tr->trDuration; - phase = cos( deltaTime * M_PI * 2 ); // derivative of sin = cos + phase = cos( deltaTime * M_PI * 2 ); /* derivative of sin = cos */ phase *= 0.5; VectorScale( tr->trDelta, phase, result ); break; @@ -1267,9 +1215,9 @@ void BG_EvaluateTrajectoryDelta( const trajectory_t *tr, int atTime, vec3_t resu VectorCopy( tr->trDelta, result ); break; case TR_GRAVITY: - deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds + deltaTime = ( atTime - tr->trTime ) * 0.001; /* milliseconds to seconds */ VectorCopy( tr->trDelta, result ); - result[2] -= DEFAULT_GRAVITY * deltaTime; // FIXME: local gravity... + result[2] -= DEFAULT_GRAVITY * deltaTime; /* FIXME: local gravity... */ break; default: Com_Error( ERR_DROP, "BG_EvaluateTrajectoryDelta: unknown trType: %i", tr->trTime ); @@ -1277,198 +1225,38 @@ void BG_EvaluateTrajectoryDelta( const trajectory_t *tr, int atTime, vec3_t resu } } -char *eventnames[] = { - "EV_NONE", - - "EV_FOOTSTEP", - "EV_FOOTSTEP_METAL", - "EV_FOOTSPLASH", - "EV_FOOTWADE", - "EV_SWIM", - - "EV_STEP_4", - "EV_STEP_8", - "EV_STEP_12", - "EV_STEP_16", - - "EV_FALL_SHORT", - "EV_FALL_MEDIUM", - "EV_FALL_FAR", - - "EV_JUMP_PAD", // boing sound at origin", jump sound on player - - "EV_JUMP", - "EV_WATER_TOUCH", // foot touches - "EV_WATER_LEAVE", // foot leaves - "EV_WATER_UNDER", // head touches - "EV_WATER_CLEAR", // head leaves - - "EV_ITEM_PICKUP", // normal item pickups are predictable - "EV_GLOBAL_ITEM_PICKUP", // powerup / team sounds are broadcast to everyone - - "EV_NOAMMO", - "EV_CHANGE_WEAPON", - "EV_FIRE_WEAPON", - - "EV_USE_ITEM0", - "EV_USE_ITEM1", - "EV_USE_ITEM2", - "EV_USE_ITEM3", - "EV_USE_ITEM4", - "EV_USE_ITEM5", - "EV_USE_ITEM6", - "EV_USE_ITEM7", - "EV_USE_ITEM8", - "EV_USE_ITEM9", - "EV_USE_ITEM10", - "EV_USE_ITEM11", - "EV_USE_ITEM12", - "EV_USE_ITEM13", - "EV_USE_ITEM14", - "EV_USE_ITEM15", - - "EV_ITEM_RESPAWN", - "EV_ITEM_POP", - "EV_PLAYER_TELEPORT_IN", - "EV_PLAYER_TELEPORT_OUT", - - "EV_GRENADE_BOUNCE", // eventParm will be the soundindex - - "EV_GENERAL_SOUND", - "EV_GLOBAL_SOUND", // no attenuation - "EV_GLOBAL_TEAM_SOUND", - - "EV_BULLET_HIT_FLESH", - "EV_BULLET_HIT_WALL", - - "EV_MISSILE_HIT", - "EV_MISSILE_MISS", - "EV_MISSILE_MISS_METAL", - "EV_RAILTRAIL", - "EV_SHOTGUN", - "EV_BULLET", // otherEntity is the shooter - - "EV_PAIN", - "EV_DEATH1", - "EV_DEATH2", - "EV_DEATH3", - "EV_OBITUARY", - - "EV_POWERUP_QUAD", - "EV_POWERUP_BATTLESUIT", - "EV_POWERUP_REGEN", - - "EV_GIB_PLAYER", // gib a previously living player - "EV_SCOREPLUM", // score plum - -//#ifdef MISSIONPACK - "EV_PROXIMITY_MINE_STICK", - "EV_PROXIMITY_MINE_TRIGGER", - "EV_KAMIKAZE", // kamikaze explodes - "EV_OBELISKEXPLODE", // obelisk explodes - "EV_OBELISKPAIN", // obelisk pain - "EV_INVUL_IMPACT", // invulnerability sphere impact - "EV_JUICED", // invulnerability juiced effect - "EV_LIGHTNINGBOLT", // lightning bolt bounced of invulnerability sphere -//#endif - - "EV_DEBUG_LINE", - "EV_STOPLOOPINGSOUND", - "EV_TAUNT", - "EV_TAUNT_YES", - "EV_TAUNT_NO", - "EV_TAUNT_FOLLOWME", - "EV_TAUNT_GETFLAG", - "EV_TAUNT_GUARDBASE", - "EV_TAUNT_PATROL" - -}; - -/* -=============== -BG_AddPredictableEventToPlayerstate - -Handles the sequence numbers -=============== +/** +* Handles the sequence numbers */ - -void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ); - void BG_AddPredictableEventToPlayerstate( int newEvent, int eventParm, playerState_t *ps ) { - -#ifdef _DEBUG - { - char buf[256]; - trap_Cvar_VariableStringBuffer("showevents", buf, sizeof(buf)); - if ( atof(buf) != 0 ) { -#ifdef QAGAME - Com_Printf(" game event svt %5d -> %5d: num = %20s parm %d\n", ps->pmove_framecount/*ps->commandTime*/, ps->eventSequence, eventnames[newEvent], eventParm); -#else - Com_Printf("Cgame event svt %5d -> %5d: num = %20s parm %d\n", ps->pmove_framecount/*ps->commandTime*/, ps->eventSequence, eventnames[newEvent], eventParm); -#endif - } - } -#endif ps->events[ps->eventSequence & (MAX_PS_EVENTS-1)] = newEvent; ps->eventParms[ps->eventSequence & (MAX_PS_EVENTS-1)] = eventParm; ps->eventSequence++; } -/* -======================== -BG_TouchJumpPad -======================== -*/ -void BG_TouchJumpPad( playerState_t *ps, entityState_t *jumppad ) { - vec3_t angles; - float p; - int effectNum; - // spectators don't use jump pads - if ( ps->pm_type != PM_NORMAL ) { - return; - } - - // flying characters don't hit bounce pads - if ( ps->powerups[PW_FLIGHT] ) { - return; - } - - // if we didn't hit this same jumppad the previous frame - // then don't play the event sound again if we are in a fat trigger - if ( ps->jumppad_ent != jumppad->number ) { - - vectoangles( jumppad->origin2, angles); - p = fabs( AngleNormalize180( angles[PITCH] ) ); - if( p < 45 ) { - effectNum = 0; - } else { - effectNum = 1; - } - BG_AddPredictableEventToPlayerstate( EV_JUMP_PAD, effectNum, ps ); - } - // remember hitting this jumppad this frame - ps->jumppad_ent = jumppad->number; - ps->jumppad_frame = ps->pmove_framecount; - // give the player the velocity from the jumppad - VectorCopy( jumppad->origin2, ps->velocity ); -} - -/* -======================== -BG_PlayerStateToEntityState - -This is done after each set of usercmd_t on the server, -and after local prediction on the client -======================== +/** +* \brief Playerstate to entitystate +* +* This is done after each set of usercmd_t on the server, +* and after local prediction on the client */ void BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean snap ) { int i; - + char medicrevive[32]; + int medicrevive_int; + + /* RPG-X: RedTechie - Attempted to fix player going invisible now they just dont go invisible (me being picky) a player is never going to notice this */ + trap_Cvar_VariableStringBuffer( "rpg_medicsrevive", medicrevive, 32 ); + medicrevive_int = atoi(medicrevive); if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPECTATOR ) { s->eType = ET_INVISIBLE; } else if ( ps->stats[STAT_HEALTH] <= GIB_HEALTH ) { - s->eType = ET_INVISIBLE; + if(medicrevive_int == 1){ + s->eType = ET_PLAYER; /* RPG-X: RedTechie - No gibbing! Before it was s->eType = ET_INVISIBLE; */ + }else{ + s->eType = ET_INVISIBLE; + } } else { s->eType = ET_PLAYER; } @@ -1480,8 +1268,13 @@ void BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean if ( snap ) { SnapVector( s->pos.trBase ); } - // set the trDelta for flag direction + + /* TiM - Get velocity as well */ VectorCopy( ps->velocity, s->pos.trDelta ); + if ( snap ) + { + SnapVector( s->pos.trDelta ); + } s->apos.trType = TR_INTERPOLATE; VectorCopy( ps->viewangles, s->apos.trBase ); @@ -1490,21 +1283,71 @@ void BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean } s->angles2[YAW] = ps->movementDir; - s->legsAnim = ps->legsAnim; - s->torsoAnim = ps->torsoAnim; - s->clientNum = ps->clientNum; // ET_PLAYER looks here instead of at number - // so corpses can also reference the proper config + + /* TiM */ + s->torsoAnim = ps->stats[TORSOANIM]; + s->legsAnim = ps->stats[LEGSANIM]; + + /* TiM : Mental note : DON'T FREEAKIN ACCIDENTLY COMMENT THIS OUT AGAIN! IT'S KINDA IMPORTANT!!!!!!!!!!!!!!!! */ + s->clientNum = ps->clientNum; /* ET_PLAYER looks here instead of at number + so corpses can also reference the proper config*/ + s->eFlags = ps->eFlags; - if ( ps->stats[STAT_HEALTH] <= 0 ) { - s->eFlags |= EF_DEAD; + if ( ( !medicrevive_int && ps->stats[STAT_HEALTH] <= 0 ) || + ( medicrevive_int > 0 && ps->stats[STAT_HEALTH] <= 1 ) ) + { /* RPG-X: TiM: Bah Red... u gotta account for these flags with ur system */ + s->eFlags |= EF_DEAD; /* or it screws up the model system */ } else { s->eFlags &= ~EF_DEAD; } + /*========================================================================== + * TiM: ^&$*#^^.... T_T + * Okay it's official. eFlags is buggy. Turns out the Ravensoft programmers were + * wreaking grief with it too. :P + * Although hacky, transposing these flags here is the only way I know to get this data from G to CG. + */ + + /* Clamp body (not head) flag */ + if ( ps->stats[EMOTES] & EMOTE_CLAMP_BODY ) { + s->eFlags |= EF_CLAMP_BODY; + } + else { + s->eFlags &= ~EF_CLAMP_BODY; + } + + /* Clamp whole body flags */ + if ( ps->stats[EMOTES] & EMOTE_CLAMP_ALL ) { + s->eFlags |= EF_CLAMP_ALL; + } + else { + s->eFlags &= ~EF_CLAMP_ALL; + } + + if ( ps->stats[EMOTES] & EMOTE_EYES_SHUT ) + { + s->eFlags |= EF_EYES_SHUT; + /* Com_Printf( "Eyes were shutted.\n" ); */ + } + else { + s->eFlags &= ~EF_EYES_SHUT; + } + + if ( ps->stats[EMOTES] & EMOTE_EYES_PISSED ) { + s->eFlags |= EF_EYES_ANGRY; + } + else { + s->eFlags &= ~EF_EYES_ANGRY; + } + + /*==========================================================================*/ + if ( ps->externalEvent ) { s->event = ps->externalEvent; s->eventParm = ps->externalEventParm; - } else if ( ps->entityEventSequence < ps->eventSequence ) { + } + else if ( ps->entityEventSequence < ps->eventSequence ) + { int seq; if ( ps->entityEventSequence < ps->eventSequence - MAX_PS_EVENTS) { @@ -1520,92 +1363,486 @@ void BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean s->groundEntityNum = ps->groundEntityNum; s->powerups = 0; - for ( i = 0 ; i < MAX_POWERUPS ; i++ ) { + for ( i = 0 ; i < MAX_POWERUPS ; i++ ) + { if ( ps->powerups[ i ] ) { s->powerups |= 1 << i; } } - s->loopSound = ps->loopSound; - s->generic1 = ps->generic1; + if ( s->powerups & (1 << PW_FLIGHT) || (ps->powerups[PW_EVOSUIT] && ps->gravity == 0 ) ) + { + s->eFlags |= EF_FULL_ROTATE; + } + else + { + s->eFlags &= ~EF_FULL_ROTATE; + } + + /* TiM: Extra - Transmit the weapons stats as a flag for the 'equip' command */ + s->time2 = ps->stats[STAT_WEAPONS]; +} + +#define MAX_ITEMNAMES 45 + +const char *itemnames[MAX_ITEMNAMES] = +{ + +"nothing", +"WEAPON_NULL_HAND", +"WEAPON_TRICORDER", +"WEAPON_PADD", +"WEAPON_COFFEE", +"WEAPON_PHASER", +"WEAPON_COMPRESSIONRIFLE", +"WEAPON_TR116", +"WEAPON_GRENADELAUNCHER", +"WEAPON_QUANTUM", +"WEAPON_DISRUPTOR", +"WEAPON_MEDKIT", +"WEAPON_VOYAGER_HYPO", +"WEAPON_DERMAL_REGEN", +"WEAPON_TOOLKIT", +"WEAPON_NEUTRINO_PROBE", + +"AMMO_COMPRESSIONRIFLE", +"AMMO_IMOD", +"AMMO_SCAVENGERRIFLE", +"AMMO_STASIS", +"AMMO_GRENADELAUNCHER", +"AMMO_DISRUPTOR", +"AMMO_QUANTUM", +"AMMO_DREADNOUGHT", + +"ITEM_ARMOR_SHARD", +"ITEM_ARMOR", +"ITEM_HEAVY_ARMOR", +"ITEM_HYPO_SMALL", +"ITEM_HYPO", + +"HOLDABLE_TRANSPORTER", +"HOLDABLE_MEDKIT", +"HOLDABLE_QUADDAMAGE", +"HOLDABLE_BATTLESUIT", +"HOLDABLE_SPEED", +"HOLDABLE_INVISIBILITY", +"HOLDABLE_REGENERATION", +"HOLDABLE_FLIGHT", +"HOLDABLE_REDFLAG", +"HOLDABLE_BLUEFLAG", +"HOLDABLE_DETPACK", +"ITEM_SEEKER", +"HOLDABLE_SHIELD", +"HOLOGRAPHIC_DECOY", /* decoy temp */ + +"WEAPON_TR116", + +NULL +}; + + +#define MAX_ITEMNAMEFILE 10000 /* 5000 har har */ +char itemNameBuffer[MAX_ITEMNAMEFILE]; + +/** +* Explains itself. +*/ +void BG_ParseItemsText(char *buff) +{ + char *token; + char *buffer; + int i,len; + + COM_BeginParseSession(); + + buffer = buff; + while ( buffer ) + { + token = COM_ParseExt( &buffer, qtrue ); + + i=0; + while (itemnames[i]) + { + if (Q_stricmp(token, itemnames[i])==0) + { + token = COM_ParseExt( &buffer, qtrue ); + if (token[0]) + { + len = strlen(token); + if (len) + { + bg_itemlist[i].pickup_name = (buffer - (len + 1)); /* The +1 is to get rid of the " at the beginning of the sting. */ + *(buffer - 1) = '\0'; /* Place an string end where is belongs. */ + } + } + + break; + } + i++; + } + + } } /* -======================== -BG_PlayerStateToEntityStateExtraPolate - -This is done after each set of usercmd_t on the server, -and after local prediction on the client -======================== +* Creates a filename with an extension based on the value in g_language */ -void BG_PlayerStateToEntityStateExtraPolate( playerState_t *ps, entityState_t *s, int time, qboolean snap ) { - int i; +void BG_LanguageFilename(char *baseName,char *baseExtension,char *finalName) +{ + char language[32]; + fileHandle_t file; - if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPECTATOR ) { - s->eType = ET_INVISIBLE; - } else if ( ps->stats[STAT_HEALTH] <= GIB_HEALTH ) { - s->eType = ET_INVISIBLE; - } else { - s->eType = ET_PLAYER; + trap_Cvar_VariableStringBuffer( "g_language", language, 32 ); + + /* If it's English then no extension */ + if (language[0]=='\0' || Q_stricmp ("ENGLISH",language)==0) + { + Com_sprintf(finalName,MAX_QPATH,"%s.%s",baseName,baseExtension); } + else + { + Com_sprintf(finalName,MAX_QPATH,"%s_%s.%s",baseName,language,baseExtension); - s->number = ps->clientNum; + /* Attempt to load the file */ + trap_FS_FOpenFile( finalName, &file, FS_READ ); - s->pos.trType = TR_LINEAR_STOP; - VectorCopy( ps->origin, s->pos.trBase ); - if ( snap ) { - SnapVector( s->pos.trBase ); - } - // set the trDelta for flag direction and linear prediction - VectorCopy( ps->velocity, s->pos.trDelta ); - // set the time for linear prediction - s->pos.trTime = time; - // set maximum extra polation time - s->pos.trDuration = 50; // 1000 / sv_fps (default = 20) - - s->apos.trType = TR_INTERPOLATE; - VectorCopy( ps->viewangles, s->apos.trBase ); - if ( snap ) { - SnapVector( s->apos.trBase ); - } - - s->angles2[YAW] = ps->movementDir; - s->legsAnim = ps->legsAnim; - s->torsoAnim = ps->torsoAnim; - s->clientNum = ps->clientNum; // ET_PLAYER looks here instead of at number - // so corpses can also reference the proper config - s->eFlags = ps->eFlags; - if ( ps->stats[STAT_HEALTH] <= 0 ) { - s->eFlags |= EF_DEAD; - } else { - s->eFlags &= ~EF_DEAD; - } - - if ( ps->externalEvent ) { - s->event = ps->externalEvent; - s->eventParm = ps->externalEventParm; - } else if ( ps->entityEventSequence < ps->eventSequence ) { - int seq; - - if ( ps->entityEventSequence < ps->eventSequence - MAX_PS_EVENTS) { - ps->entityEventSequence = ps->eventSequence - MAX_PS_EVENTS; + if ( file == 0 ) /* This extension doesn't exist, go English. */ + { + Com_sprintf(finalName,MAX_QPATH,"%s.%s",baseName,baseExtension); /* the caller will give the error if this isn't there */ } - seq = ps->entityEventSequence & (MAX_PS_EVENTS-1); - s->event = ps->events[ seq ] | ( ( ps->entityEventSequence & 3 ) << 8 ); - s->eventParm = ps->eventParms[ seq ]; - ps->entityEventSequence++; - } - - s->weapon = ps->weapon; - s->groundEntityNum = ps->groundEntityNum; - - s->powerups = 0; - for ( i = 0 ; i < MAX_POWERUPS ; i++ ) { - if ( ps->powerups[ i ] ) { - s->powerups |= 1 << i; + else + { + trap_FS_FCloseFile( file ); } } - - s->loopSound = ps->loopSound; - s->generic1 = ps->generic1; +} + +/** +* Loads item names. +*/ +void BG_LoadItemNames(void) +{ + char fileName[MAX_QPATH]; + int len; + fileHandle_t f; + + BG_LanguageFilename("ext_data/mp_itemnames","dat",fileName); + + len = trap_FS_FOpenFile( fileName, &f, FS_READ ); + + if ( !f ) + { + Com_Printf( S_COLOR_RED "BG_LoadItemNames : MP_ITEMNAMES.DAT file not found!\n"); + return; + } + + if ( len > MAX_ITEMNAMEFILE ) + { + Com_Printf( S_COLOR_RED "BG_LoadItemNames : MP_ITEMNAMES.DAT too big!\n"); + return; + } + + /* initialise the data area */ + memset(itemNameBuffer, 0, sizeof(itemNameBuffer)); + + trap_FS_Read( itemNameBuffer, len, f ); + + trap_FS_FCloseFile( f ); + + BG_ParseItemsText(itemNameBuffer); + +} + +/** +* Read a configuration file to get the sex +* models/players_rpgx/munro/animation.cfg +*/ +static gender_t G_ParseAnimationFileSex( const char *filename) { + char *text_p; + int len; + char *token; + char text[20000]; + fileHandle_t f; + char animfile[MAX_QPATH]; + + /* strcpy(animfile, filename); */ + Q_strncpyz(animfile, filename, sizeof(animfile)); + len = strlen(animfile); + strcpy(&animfile[len-strlen("groups.cfg")], "animation.cfg"); + + /* load the file */ + len = trap_FS_FOpenFile( animfile, &f, FS_READ ); + if ( len <= 0 ) { + return GENDER_NEUTER; + } + if ( len >= sizeof( text ) - 1 ) { + Com_Printf( "File %s too long\n", animfile ); + trap_FS_FCloseFile( f ); + return GENDER_NEUTER; + } + trap_FS_Read( text, len, f ); + text[len] = 0; + trap_FS_FCloseFile( f ); + + /* parse the text */ + text_p = text; + + /* read optional parameters */ + while ( 1 ) { + token = COM_Parse( &text_p ); + if ( !token[0] ) { + break; + } + if ( !Q_stricmp( token, "sex" ) ) { + token = COM_Parse( &text_p ); + if ( !token[0] ) { + break; + } + if ( token[0] == 'f' || token[0] == 'F' ) { + return GENDER_FEMALE; + } else if ( token[0] == 'n' || token[0] == 'N' ) { + return GENDER_NEUTER; + } else { + return GENDER_MALE; + } + } + } + return GENDER_MALE; +} + +/** +* Registers an item. +*/ +#define MAX_GROUP_FILE_SIZE 5000 +char* BG_RegisterRace( const char *name ) { + char *text_p; + char *token; + int len; + fileHandle_t f; + char text[MAX_GROUP_FILE_SIZE]; + gender_t theSex; + + memset (races, 0, sizeof(races)); + memset (text, 0, sizeof(text)); + + /* load and parse the skin file */ + len = trap_FS_FOpenFile( name, &f, FS_READ ); + if ( !f ) { + /* if we didn't get a races file, use an empty one. */ + Com_sprintf(races, sizeof(races), "unknown"); + return races; + } + if ( len >= sizeof( text ) - 1) + { + Com_Printf( S_COLOR_RED "file too large: %s is %i, max allowed is %i", name, len, sizeof( text ) ); + trap_FS_FCloseFile( f ); + return races; + } + + trap_FS_Read( text, len, f ); + trap_FS_FCloseFile( f ); + + theSex = G_ParseAnimationFileSex(name); + if (theSex == GENDER_MALE) { + strcat(races, "Male,"); + } else if (theSex == GENDER_FEMALE) { + strcat(races, "Female,"); + } + + text_p = text; + while ( *text_p ) { + /* get surface name */ + token = COM_Parse( &text_p ); + + if ( !token[0] ) { + break; + } + + /* if we about to break the races size list then dump us out */ + if (strlen(races) + strlen(token) > 256) { + break; + } + + /* add it into the race list */ + strcat(races, token); + /* put a comma between the names */ + strcat(races, ","); + + if ( *text_p == ',' ) { + text_p++; + } + + if (!Q_stricmp ("borg", token) ) { + if (theSex == GENDER_MALE) { + /* add it into the race list */ + strcat(races, "BorgMale,"); + } else if (theSex == GENDER_FEMALE) { + strcat(races, "BorgFemale,"); + } else { + } + } + + } + + /* just in case */ + if (!races[0]) + { + Com_sprintf(races, sizeof(races), "unknown"); + } + else + { /* lose the last comma */ + races[strlen(races)-1] = 0; + } + + return races; +} + +/** +* Parses the rank names. +*/ +qboolean BG_ParseRankNames( char* fileName, rankNames_t rankNames[] ) { + fileHandle_t f; + int file_len; + char charText[20000]; + char* textPtr; + char* token; + int i = 0; + + file_len = trap_FS_FOpenFile( fileName, &f, FS_READ ); + + if ( file_len<= 0 ) { + return qfalse; + } + + if ( file_len >= ( sizeof(charText) - 1) ) { + Com_Printf( S_COLOR_RED "File length of %s is too long.\n", fileName ); + return qfalse; + } + + memset( &charText, 0, sizeof( charText ) ); + memset( rankNames, 0, sizeof( rankNames ) ); + + trap_FS_Read( charText, file_len, f ); + + charText[file_len] = 0; + + trap_FS_FCloseFile( f ); + + COM_BeginParseSession(); + + textPtr = charText; + + token = COM_Parse( &textPtr ); + + if ( !token[0] ) { + Com_Printf( S_COLOR_RED "No data found in buffer: %s\n", fileName ); + return qfalse; + } + + if ( Q_stricmpn( token, "{", 1 ) ) { + Com_Printf( S_COLOR_RED "No beginning { found in %s\n", fileName ); + return qfalse; + } + + /* Parse out the default cell. Default has no names anyway, + but in case a n00bie modder put names in anyway. */ + SkipBracedSection( &textPtr ); + + while( 1 ) { + /* lastPtr = textPtr; */ + token = COM_Parse( &textPtr ); + if( !token[0] ) { + break; + } + + if ( i >= MAX_RANKS ) { + break; + } + + /* If we hit an open brace (ie, assuming we hit the start of a new rank cell) */ + if ( !Q_stricmpn( token, "{", 1 ) ) { + while ( 1 ) { + token = COM_Parse( &textPtr ); + if( !token[0] ) { + break; + } + + /* We hit a MenuTexture entry, since this uses { symbols, we'll skip these to stop errors. */ + if ( !Q_stricmpn( token, "MenuTexture", 11 ) ) { + SkipRestOfLine( &textPtr ); + continue; + } + + if ( !Q_stricmpn( token, "ConsoleName", 11) ) { + if ( COM_ParseString( &textPtr, &token ) ) { + continue; + } + + Q_strncpyz( rankNames[i].consoleName, token, sizeof( rankNames[i].consoleName ) ); + + continue; + } + else if ( !Q_stricmpn( token, "FormalName", 10) ) { + if ( COM_ParseString( &textPtr, &token ) ) { + continue; + } + + Q_strncpyz( rankNames[i].formalName, token, sizeof( rankNames[i].formalName ) ); + + continue; + } + /* We hit the end of the cell. */ + else if ( !Q_stricmpn( token, "}", 1 ) ) { + break; + } + } + + /* Error check. If we didn't get both a formal and console name, pwn the caller. ;P */ + if ( !rankNames[i].consoleName[0] || !rankNames[i].formalName[0] ) { + Com_Printf( S_COLOR_RED "One or more rank names were not found in rank#: %i\n", i ); + return qfalse; + } + else { + i++; + } + } + } + return qtrue; +} + +/* +=========== +NextWordEndsHere +=========== +*/ +char *NextWordEndsHere(char *p) +{ + if (*p != ' ') { + return p; + } + + while (*p && *p == ' ') { /* first pass */ + ++p; + } + + while (*p && *p != ' ') { /* second pass */ + ++p; + } + + return p; +} + +/* +=========== +EndWord +=========== +Returns a pointer to the position of the next space, null, or newline. +*/ +char *EndWord(char *pos) +{ + while (!*pos && *pos != ' ' && *pos != '\n') { + ++pos; + } + + return pos; } diff --git a/code/game/bg_oums.c b/code/game/bg_oums.c new file mode 100644 index 0000000..139597f --- /dev/null +++ b/code/game/bg_oums.c @@ -0,0 +1,2 @@ + + diff --git a/code/game/bg_oums.h b/code/game/bg_oums.h new file mode 100644 index 0000000..2529dfb --- /dev/null +++ b/code/game/bg_oums.h @@ -0,0 +1,4 @@ +/* +bg_OUMS.h +ONLINE USER MANAGEMENT SYSTEM +*/ diff --git a/code/game/bg_panimate.c b/code/game/bg_panimate.c new file mode 100644 index 0000000..7ebc184 --- /dev/null +++ b/code/game/bg_panimate.c @@ -0,0 +1,12 @@ +//=========================================================== +// Name: bg_panimate.c +// Developer: Timothy 'TiM' Oliver +// Date: 16/2/2006 +// Function: Global character animation functions. Utilised +// in CG and G for animation loading + handling. +// Based off of logic from EF SP. +//=========================================================== + +#include "q_shared.h" +#include "bg_public.h" + diff --git a/code/game/bg_pmove.c b/code/game/bg_pmove.c index a3c6f6e..8c809d5 100644 --- a/code/game/bg_pmove.c +++ b/code/game/bg_pmove.c @@ -1,29 +1,9 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // // bg_pmove.c -- both games player movement code // takes a playerstate and a usercmd as input and returns a modifed playerstate -#include "../qcommon/q_shared.h" +#include "q_shared.h" #include "bg_public.h" #include "bg_local.h" @@ -31,38 +11,805 @@ pmove_t *pm; pml_t pml; // movement parameters -float pm_stopspeed = 100.0f; -float pm_duckScale = 0.25f; -float pm_swimScale = 0.50f; +const float pm_stopspeed = 100; +const float pm_duckScale = 0.50; +const float pm_swimScale = 0.50; +const float pm_ladderScale = 0.7f; -float pm_accelerate = 10.0f; -float pm_airaccelerate = 1.0f; -float pm_wateraccelerate = 4.0f; -float pm_flyaccelerate = 8.0f; +const float pm_accelerate = 10; +const float pm_airaccelerate = 1; +const float pm_wateraccelerate = 4; +const float pm_flyaccelerate = 8; -float pm_friction = 6.0f; -float pm_waterfriction = 1.0f; -float pm_flightfriction = 3.0f; -float pm_spectatorfriction = 5.0f; +const float pm_friction = 6; +const float pm_waterfriction = 1; +const float pm_flightfriction = 3; +const float pm_evosuitfriction = 0.25; //RPG-X | Phenix | 8/8/2004 int c_pmove = 0; +#define PHASER_RECHARGE_TIME 100 -/* -=============== -PM_AddEvent +//RPG-X | Marcin | Big hack but it appears to work | 06/12/2008 +#ifdef QAGAME +extern vmCvar_t rpg_rifleDelay; +extern vmCvar_t rpg_disruptorDelay; +extern vmCvar_t rpg_photonDelay; +extern vmCvar_t rpg_altPhotonDelay; +extern vmCvar_t rpg_TR116Delay; +extern vmCvar_t rpg_altTricorderDelay; +#define RIFLE_DELAY rpg_rifleDelay.integer +#define DISRUPTOR_DELAY rpg_disruptorDelay.integer +#define PHOTON_DELAY rpg_photonDelay.integer +#define ALT_PHOTON_DELAY rpg_altPhotonDelay.integer +#define TR116_DELAY rpg_TR116Delay.integer +#define ALT_TRICORDER_DELAY rpg_altTricorderDelay.integer +#else +#define RIFLE_DELAY 250 +#define DISRUPTOR_DELAY 700 +#define PHOTON_DELAY 1600 +#define ALT_PHOTON_DELAY 1600 +#define TR116_DELAY 500 +#define ALT_TRICORDER_DELAY 1000 +#endif -=============== +//qboolean BG_BorgTransporting( playerState_t *ps ) +//{ +// if ( ps->persistant[PERS_CLASS] == PC_BORG && bg_itemlist[ps->stats[STAT_HOLDABLE_ITEM]].giTag == HI_TRANSPORTER && ps->stats[STAT_USEABLE_PLACED] == 2 ) +// {//A player who has an item and it's set to 2 - meaning flight +// return qtrue; +// } +// return qfalse; +//} + +/*typedef enum { + ANIM_CROUCH, + ANIM_DOCROUCH, + ANIM_UNCROUCH, + ANIM_STAND, + ANIM_FIRE, + ANIM_JUMP, + ANIM_JUMPB, + ANIM_RUN, + ANIM_RUNB, + ANIM_WALK, + ANIM_WALKB, + ANIM_CROUCHWALK, + ANIM_CROUCHWALKB, + ANIM_SWIM, + ANIM_TURN, + ANIM_FLY, +} animList_t;*/ + +//TiM - Copied from the UI module. +//My aim here is to adapt the checks code here so the function can be used both for +//ingame animation, as well as UI animation + +// RPG-X UI Required Ones +#define ANIM_IDLE 0 +#define ANIM_RUN 1 +#define ANIM_WALK 2 +#define ANIM_BACK 3 +#define ANIM_JUMP 4 +#define ANIM_CROUCH 5 +#define ANIM_ATTACK 22 +//Ingame required ones +#define ANIM_JUMPB 6 +#define ANIM_RUNB 7 +#define ANIM_WALKB 8 +#define ANIM_CROUCHWALK 9 +#define ANIM_CROUCHWALKB 10 +#define ANIM_SWIM 11 +#define ANIM_FLY 12 +#define ANIM_TURN 13 + +/** +* Checks if the player holding a two handed weapon. +*/ +qboolean PM_Holding2HandedWeapon ( void ) { + switch (pm->ps->weapon) { + case WP_7: + case WP_8: + case WP_9: + case WP_6: + return qtrue; + } + return qfalse; +} + +/** +* Checks if the player is crouching. +*/ +qboolean PM_PlayerCrouching ( int legsAnim ) { + //switch( pm->ps->legsAnim ) { + switch( ( legsAnim & ~ANIM_TOGGLEBIT) ) { + //case BOTH_CROUCH1: + case BOTH_CROUCH1IDLE: + case BOTH_CROUCH1WALK: + case BOTH_CROUCH2IDLE: + //case BOTH_CROUCH2TOSTAND1: + return qtrue; + } + return qfalse; +} + +/** +* Check if player is idling. +*/ +qboolean PM_PlayerIdling ( int torsoAnim, int legsAnim ) { + //switch( pm->ps->legsAnim ) { + //TiM : Cool hacky way to make sure both upper and lower anims are the same + switch( ( legsAnim & ~ANIM_TOGGLEBIT) ) //+ ( torsoAnim & ~ANIM_TOGGLEBIT)) >> 1 + { + case BOTH_STAND1: + case BOTH_STAND2: + case BOTH_STAND3: + case BOTH_STAND4: + case BOTH_CROWDLOOK3: + { + switch ( ( torsoAnim & ~ANIM_TOGGLEBIT) ) + { + case BOTH_STAND1: + case BOTH_STAND2: + case BOTH_STAND3: + case BOTH_STAND4: + case BOTH_CROWDLOOK3: + case TORSO_TRICORDER1: + case TORSO_HYPOSPRAY1: + case TORSO_HYPO1: + case TORSO_DROPWEAP1: + case TORSO_RAISEWEAP1: + case TORSO_PADD1: + case TORSO_COFFEE: + return qtrue; + } + } + } + return qfalse; +} + + +/** +* \brief Checks if player is holding a loppable weapon. +* +* A weapon that can have its +* firing animation looped, +* like the PADD or tricorder, etc +*/ +qboolean PM_HoldingLoopableWeapon ( void ) { + switch (pm->ps->weapon) { + case WP_13: + case WP_2: + case WP_3: + case WP_11: + case WP_4: + return qtrue; + } + return qfalse; +} + +/** +* \brief Checks if player is holding a spillable weapon. +* +* Player is holding a weapon that +* shouldn't let players do the +* 'slowing down' anim +*/ +qboolean PM_HoldingSpillableWeapon( void ) { + switch ( pm->ps->weapon ) { + case WP_4: + case WP_6: + case WP_9: + case WP_8: + case WP_7: + return qtrue; + } + return qfalse; +} + + +/** +* Check to see if the player is moving at all +*/ +qboolean PM_PlayerWalking( int anim ) +{ + switch( anim & ~ANIM_TOGGLEBIT ) + { + case BOTH_WALK1: + case BOTH_WALK2: + case BOTH_WALK3: + case BOTH_WALK4: + case BOTH_WALK7: + case LEGS_WALKBACK1: + return qtrue; + } + + return qfalse; +} + +/** +* Check to see if the player is running +*/ +qboolean PM_PlayerRunning( int anim ) +{ + switch( anim & ~ANIM_TOGGLEBIT ) + { + case BOTH_RUN1: + case BOTH_RUN2: + case LEGS_RUNBACK2: + return qtrue; + } + + return qfalse; +} + +/** +* Check to see if the player is moving while crouching +*/ +qboolean PM_PlayerCrouchWalking( int anim ) +{ + switch( anim & ~ANIM_TOGGLEBIT ) + { + case BOTH_CROUCH1WALK: + return qtrue; + } + + return qfalse; +} + +/** +* TiM: An index is defined, and depending +* on which weapon is active, a specific +* animation is returned. +* I could have used pm->ps->weapon instead +* of manually defining it as an paramter, +* but I'm going to use this in the UI module, +* which is out of pm's scope. +*/ +int PM_GetAnim ( int anim, int weapon, qboolean injured, qboolean upper ) +{ + playerState_t *ps = pm->ps; + // Called when player is in idle crouching + switch ( anim ) { + case ANIM_CROUCH: + //2 handed weapon - "heavy" + switch (weapon) { + case WP_7: + case WP_8: + case WP_9: + if ( ps->pm_flags & ANIM_ALERT2 && upper ) + return TORSO_WEAPONREADY2; + else if (upper) + return BOTH_STAND2; + else + return LEGS_KNEEL1; + break; + //2 handed weapon - "light" + case WP_6: + //case WP_7: + if ( ps->pm_flags & ANIM_ALERT && upper ) + return BOTH_STAND2; + else if (upper) + return TORSO_WEAPONREADY2; + else + return LEGS_KNEEL1; + break; + //1 handed weapon - "phaser" + case WP_5: + case WP_10: + if ( upper ) + return TORSO_WEAPONPOSE1; + else + return BOTH_CROUCH1IDLE; + break; + case WP_4: + if (upper) + return TORSO_COFFEE; + //break; + //Generic tools - "everything else" + default: + return BOTH_CROUCH2IDLE; + break; + } + break; + + //Called when player is in idle standing + case ANIM_IDLE: + //2 handed weapon - "heavy" + switch (weapon) { + //case WP_7: + case WP_8: + case WP_9: + case WP_7: + if (injured) + return BOTH_INJURED4; + else + { + if ( ps->pm_flags & ANIM_ALERT ) + return BOTH_STAND2; + else if ( ps->pm_flags & ANIM_ALERT2 ) + { + if ( upper ) + return TORSO_WEAPONREADY2; + else + return BOTH_STAND2; + } + else + return BOTH_STAND4; + } + break; + //2 handed weapon - "light" + case WP_6: + if (injured) + return BOTH_INJURED4; + else + { + if ( ps->pm_flags & ANIM_ALERT ) + return BOTH_STAND2; + else if ( ps->pm_flags & ANIM_ALERT2 ) + { + if ( upper ) + return TORSO_WEAPONREADY2; + else + return BOTH_STAND2; + } + else + return BOTH_STAND4; + } + break; + //1 handed weapon - "phaser" + case WP_5: + case WP_10: + if (injured) + return BOTH_INJURED4; + else { + if ( ps->pm_flags & ANIM_ALERT && upper ) + return TORSO_WEAPONIDLE1; + else if ( ps->pm_flags & ANIM_ALERT2 && upper ) + return TORSO_WEAPONREADY1; + else + return BOTH_STAND1; + } + break; + //Generic tools - "everything else" + case WP_4: + if (upper) + return TORSO_COFFEE; + else + return BOTH_STAND1; + break; + default: + if (injured) + return BOTH_INJURED4; + else + return BOTH_STAND1; + break; + } + break; + + //Called when player fires their weapon + case ANIM_ATTACK: + //2 handed weapon - "heavy" + switch (weapon) { + //case WP_7: + case WP_8: + case WP_9: + case WP_7: + if ( ps->pm_flags & ANIM_ALERT2 ) + return BOTH_ATTACK2; + else + return BOTH_ATTACK3; + break; + //2 handed weapon - "light" + case WP_6: + if ( ps->pm_flags & ANIM_ALERT2 ) + return BOTH_ATTACK2; + else + { + if (upper) + return BOTH_ATTACK3; + else + return BOTH_ATTACK3; + } + break; + //1 handed weapon - "phaser" + case WP_5: + case WP_10: + case WP_15: + case WP_13: + if (upper) + return TORSO_WEAPONREADY1; + else + return BOTH_STAND1; + break; + //Other Tools "padd" + case WP_3: + if (upper) + return TORSO_PADD1; + else + return BOTH_STAND1; + break; + //Other Tools "tricorder" + case WP_2: + if (upper) + { + if ( !pm->medic ) + return TORSO_TRICORDER1; + else + return TORSO_MEDICORDER1; + } + else + return BOTH_STAND1; + break; + //Other: "Medkit" + case WP_11: + if (upper) + return TORSO_ACTIVATEMEDKIT1; + else + return BOTH_STAND1; + break; + //Other: "Hypo + case WP_12: + if (upper) + //return TORSO_HYPOSPRAY1; + return TORSO_HYPO1; + else + return BOTH_STAND1; + //Other: "Toolkit" + /*case WP_14: + //Return nothing. + //A bit hacky, but the engine accepts it :P + break;*/ + //Other Tools "everything else" + /*case WP_1: + switch(rand()%13) + { + case 0: return TORSO_HANDGESTURE1; + case 1: return TORSO_HANDGESTURE2; + case 2: return TORSO_HANDGESTURE3; + case 3: return TORSO_HANDGESTURE4; + case 4: //PM_StartTorsoAnim( TORSO_HANDGESTURE5 ); break; + case 5: return TORSO_HANDGESTURE6; + case 6: return TORSO_HANDGESTURE7; + case 7: return TORSO_HANDGESTURE8; + case 8: return TORSO_HANDGESTURE9; + case 9: return TORSO_HANDGESTURE10; + case 10: return TORSO_HANDGESTURE11; + case 11: return TORSO_HANDGESTURE12; + case 12: return TORSO_HANDGESTURE13; + } + break;*/ + case WP_4: + if (upper) + return TORSO_COFFEE; + //break; + default: + if (upper) + return TORSO_WEAPONREADY1; + else + return BOTH_STAND1; + break; + } + break; + + //When the player jumps + case ANIM_JUMP: + return BOTH_JUMP1; + //Wen the player jumps backwards + case ANIM_JUMPB: + return BOTH_JUMPBACK1; + + //When the player runs + case ANIM_RUN: + if (injured) { + return BOTH_RUNINJURED1; + } + + //2 handed weapons + switch (weapon) { + //case WP_7: + case WP_8: + case WP_9: + case WP_6: + case WP_7: + if (upper) + return BOTH_RUN2; + else + return BOTH_RUN1; + break; + case WP_4: + if (upper) + return TORSO_COFFEE; + //break; + //EVERYTHING ELSE + default: + return BOTH_RUN1; + } + break; + + //When the player runs back + case ANIM_RUNB: + //2 handed weapons + switch (weapon) { + //case WP_7: + case WP_8: + case WP_9: + case WP_6: + case WP_7: + if (upper) + return BOTH_WALK2; + else + if ( injured ) + return LEGS_WALKBACK1; + else + return LEGS_RUNBACK2; + break; + //EVERYTHING ELSE + case WP_4: + if (upper) + return TORSO_COFFEE; + //break; + default: + if (upper) + return BOTH_WALK1; + else + if ( injured ) + return LEGS_WALKBACK1; + else + return LEGS_RUNBACK2; + break; + } + break; + + //When the player walks + case ANIM_WALK: + if ( ps->legsTimer > 0 && bg_emoteList[ps->legsTimer].enumName == BOTH_STAND3 ) + return BOTH_WALK3; + + //2 handed weapons + switch (weapon) { + //case WP_7: + case WP_8: + case WP_9: + case WP_6: + case WP_7: + if ( ps->pm_flags & ANIM_ALERT ) + return BOTH_WALK2; + else if ( ps->pm_flags & ANIM_ALERT2 ) + { + if ( upper ) + return TORSO_WEAPONREADY2; + else + return BOTH_WALK2; + } + else + return BOTH_WALK4; + break; + //Other Tools "everything else" + case WP_4: + if (upper) + return TORSO_COFFEE; + case WP_5: + case WP_10: + if ( ps->pm_flags & ANIM_ALERT ) + { + if ( upper ) + return TORSO_WEAPONIDLE1; + } + else if ( ps->pm_flags & ANIM_ALERT2 ) + { + if ( upper ) + return TORSO_WEAPONREADY1; + } + + default: + return BOTH_WALK1; + break; + } + break; + + //When the player walks baaaack + case ANIM_WALKB: + //2 handed weapons + switch (weapon) { + //case WP_7: + case WP_8: + case WP_9: + case WP_6: + case WP_7: + if ( ps->pm_flags & ANIM_ALERT ) + { + if ( upper ) + return BOTH_WALK2; + else + return LEGS_WALKBACK1; + } + else if ( ps->pm_flags & ANIM_ALERT2 ) + { + if ( upper ) + return TORSO_WEAPONREADY2; + else + return LEGS_WALKBACK1; + } + else + { + if ( upper ) + return BOTH_WALK4; + else + return LEGS_WALKBACK1; + } + break; + case WP_4: + if (upper) + return TORSO_COFFEE; + //break; + case WP_5: + case WP_10: + if ( ps->pm_flags & ANIM_ALERT && upper) + return TORSO_WEAPONIDLE1; + else if ( ps->pm_flags & ANIM_ALERT2 && upper ) + return TORSO_WEAPONREADY1; + + //Other Tools "everything else" + default: + if ( upper ) + return BOTH_WALK1; + else + return LEGS_WALKBACK1; + break; + } + break; + + //When the player crouch walks + case ANIM_CROUCHWALK: + //2 handed weapons + switch (weapon) { + //case WP_7: + case WP_6: + case WP_7: + if ( upper ) + return TORSO_WEAPONREADY2; + else + return BOTH_CROUCH1WALK; + break; + case WP_8: + case WP_9: + if ( ps->pm_flags & ANIM_ALERT2 && upper ) + return TORSO_WEAPONREADY2; + else if ( upper ) + return BOTH_WALK2; + else + return BOTH_CROUCH1WALK; + break; + case WP_4: + if (upper) + return TORSO_COFFEE; + //break; + case WP_5: + case WP_10: + if ( ps->pm_flags & ANIM_ALERT && upper ) + return TORSO_WEAPONIDLE1; + else if ( ps->pm_flags & ANIM_ALERT2 && upper ) + return TORSO_WEAPONREADY1; + //Other Tools "everything else" + default: + return BOTH_CROUCH1WALK; + break; + } + break; + + //When the player crouch walks bak + case ANIM_CROUCHWALKB: + //2 handed weapons + switch (weapon) { + //case WP_7: + case WP_8: + case WP_9: + case WP_6: + case WP_7: + if ( ps->pm_flags & ANIM_ALERT2 ) + return TORSO_WEAPONREADY2; + else if ( upper ) + return BOTH_WALK2; + else + return BOTH_CROUCH1WALK; + break; + case WP_4: + if (upper) + return TORSO_COFFEE; + //break; + case WP_5: + case WP_10: + if ( ps->pm_flags & ANIM_ALERT && upper ) + return TORSO_WEAPONIDLE1; + else if ( ps->pm_flags & ANIM_ALERT2 && upper ) + return TORSO_WEAPONREADY1; + + //Other Tools "everything else" + default: + return BOTH_CROUCH1WALK; + break; + } + break; + + case ANIM_SWIM: + if ( !upper ) { + if ( pm->cmd.forwardmove + || pm->cmd.rightmove + || pm->cmd.upmove ) + { + return LEGS_SWIM; + } + } + + return BOTH_FLOAT1; + + /*if ( ps->velocity[2] >= 0 ) { + return BOTH_FLOAT1; + } + else { + return BOTH_FLOAT2; + }*/ + case ANIM_FLY: + return BOTH_FLOAT1; + } + + return BOTH_STAND1; +} + + + +/** +* Adds a predictable event to playerstate */ void PM_AddEvent( int newEvent ) { BG_AddPredictableEventToPlayerstate( newEvent, 0, pm->ps ); } +/* +============== +PM_Use + +Generates a use event +============== +*/ +#define USE_DELAY 2000 + +/** +* Generates a use event +*/ +void PM_Use( void ) +{ + playerState_t *ps = pm->ps; + + if ( ps->useTime > 0 ) + ps->useTime -= 100;//pm->cmd.msec; + + if ( ps->useTime > 0 ) { + return; + } + + if ( ! (pm->cmd.buttons & BUTTON_USE ) ) + { + pm->useEvent = 0; + ps->useTime = 0; + //PM_StartTorsoAnim( BOTH_CONSOLE1 ); + + return; + } + + pm->useEvent = EV_USE; + ps->useTime = USE_DELAY; +} + /* =============== PM_AddTouchEnt =============== */ +/** +* Adds a touchEnt event. +*/ void PM_AddTouchEnt( int entityNum ) { int i; @@ -85,62 +832,221 @@ void PM_AddTouchEnt( int entityNum ) { pm->numtouch++; } -/* -=================== -PM_StartTorsoAnim -=================== +/** +* Start torso animation */ -static void PM_StartTorsoAnim( int anim ) { - if ( pm->ps->pm_type >= PM_DEAD ) { + +static void PM_StartTorsoAnim( int anim, qboolean overrideEmotes ) { + playerState_t *ps = pm->ps; + if ( ps->stats[EMOTES] & EMOTE_UPPER && !overrideEmotes ) { return; } - pm->ps->torsoAnim = ( ( pm->ps->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) + + if ( ps->pm_type >= PM_DEAD && + anim != BOTH_FALLDEATH1INAIR && + anim != BOTH_FALLDEATH1LAND ) + { //TiM: UberHack :P + return; + } + + //if ( ps->torsoTimer > 0 ) { + if ( ps->stats[TORSOTIMER] > 0 ) { + return; // a high priority animation is running + } + + //ps->torsoAnim + ps->stats[TORSOANIM] = ( ( ps->stats[TORSOANIM] & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim; } + +/** +* Start leg animation +*/ static void PM_StartLegsAnim( int anim ) { - if ( pm->ps->pm_type >= PM_DEAD ) { + playerState_t *ps = pm->ps; + + /*if ( ps->stats[EMOTES] & EMOTE_CLAMP ) { + return; + }*/ + + if ( ps->pm_type >= PM_DEAD && + anim != BOTH_FALLDEATH1INAIR && + anim != BOTH_FALLDEATH1LAND ) + { return; } - if ( pm->ps->legsTimer > 0 ) { + + //if ( ps->introTime > 0 ) { //legsTimer + /*if ( ps->stats[LEGSTIMER] > 0 ) { //legsTimer return; // a high priority animation is running - } - pm->ps->legsAnim = ( ( pm->ps->legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) + }*/ + + //ps->legsAnim + ps->stats[LEGSANIM] = ( ( ps->stats[LEGSANIM] & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim; } -static void PM_ContinueLegsAnim( int anim ) { - if ( ( pm->ps->legsAnim & ~ANIM_TOGGLEBIT ) == anim ) { +/** +* Continues the legs animation. +*/ +static void PM_ContinueLegsAnim( int anim, qboolean overrideEmote ) { + playerState_t *ps = pm->ps; + + //override to return to idle after moving in an emote + if ( (ps->stats[EMOTES] & EMOTE_LOWER ) && ( !( ps->stats[EMOTES] & EMOTE_CLAMP_BODY) && !( ps->stats[EMOTES] & EMOTE_CLAMP_ALL) ) && !overrideEmote ) { + if ( ps->legsTimer>0 && ( ps->stats[LEGSANIM] & ~ANIM_TOGGLEBIT ) != bg_emoteList[ ps->legsTimer ].enumName && ( ps->stats[LEGSANIM] & ~ANIM_TOGGLEBIT ) != BOTH_GET_UP1 ) { + int anim2 = PM_GetAnim( ANIM_IDLE, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qfalse ); + + //Com_Printf( "KILL!\n"); + ps->stats[LEGSANIM] = ( ( ps->stats[LEGSANIM] & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim2; + } + } + + if ( (ps->stats[EMOTES] & EMOTE_CLAMP_BODY || ps->stats[EMOTES] & EMOTE_CLAMP_ALL ) && !overrideEmote ) { //EMOTE_LOWER return; } - if ( pm->ps->legsTimer > 0 ) { + + //if ( ( ps->legsAnim & ~ANIM_TOGGLEBIT ) == anim ) { + if ( ( ps->stats[LEGSANIM] & ~ANIM_TOGGLEBIT ) == anim ) { + return; + } + //if ( ps->introTime > 0 ) { //legsTimer + if ( ps->stats[LEGSTIMER] > 0 && !overrideEmote ) { //legsTimer return; // a high priority animation is running } PM_StartLegsAnim( anim ); } -static void PM_ContinueTorsoAnim( int anim ) { - if ( ( pm->ps->torsoAnim & ~ANIM_TOGGLEBIT ) == anim ) { +/** +* Continues the torso animation +*/ +static void PM_ContinueTorsoAnim( int anim, qboolean overrideEmote ) { + playerState_t *ps = pm->ps; + + if ( ps->stats[EMOTES] & EMOTE_UPPER && !overrideEmote ) { return; } - if ( pm->ps->torsoTimer > 0 ) { + + //if ( ( ps->torsoAnim & ~ANIM_TOGGLEBIT ) == anim ) { + if ( ( ps->stats[TORSOANIM] & ~ANIM_TOGGLEBIT ) == anim ) { + return; + } + + //if ( ps->torsoTimer > 0 ) { + if ( ps->stats[TORSOTIMER] > 0 ) { return; // a high priority animation is running } - PM_StartTorsoAnim( anim ); + PM_StartTorsoAnim( anim, overrideEmote ); } +/** +* Force a legs animation +*/ static void PM_ForceLegsAnim( int anim ) { - pm->ps->legsTimer = 0; + playerState_t *ps = pm->ps; + + //OMFG UBERHACK + //I'm lazy... client revive spawns players 1 unit over the ground. + //THat small fall enacts this, and subsequently screws up client revive animations + if ( ( ps->stats[LEGSANIM] & ~ANIM_TOGGLEBIT) != BOTH_GET_UP1 ) { + ps->stats[EMOTES] &= ~EMOTE_MASK_LOWER; + ps->stats[LEGSTIMER] = 0; //legsTimer + } + PM_StartLegsAnim( anim ); } +/** +* Force a torso animation +*/ +static void PM_ForceTorsoAnim( int anim, qboolean overrideEmotes ) { + playerState_t *ps = pm->ps; + + if ( overrideEmotes && ( ps->stats[TORSOANIM] & ~ANIM_TOGGLEBIT) != BOTH_GET_UP1 ) { + ps->stats[EMOTES] &= ~EMOTE_MASK_UPPER; + ps->stats[TORSOTIMER] = 0; + } + //ps->stats[TORSOTIMER] = 0; + + PM_StartTorsoAnim( anim, overrideEmotes ); +} + +/* +================ +PM_Animate (RPG-X:J2J) + +TiM: Bookmark... this shows promise :) +LATER: Nope... scratch that. +Although it's good in the fact it assigns +the anim right, it doesn't take the timers +into account, meaning this would play for a +total of one clock cycle :P +================ +*/ +/*static void PM_DoEmote( void ) +{ + if ( pm->ps->stats[EMOTES] & EMOTE_LOWER ) { + pm->ps->viewheight = emoteList[pm->ps->legsAnim].viewHeight; + } +}*/ + +/*static void PM_DoEmote( void ) +{ + int EmoteType = 0; //0 = legs, 1 = torso, 2 = both + + //Bail out if no new emote or invalid. + if(CurrentEmote[pm->ps->clientNum] < 0 || CurrentEmote[pm->ps->clientNum] >= MAX_ANIMATIONS) + return; + + //Get animation type + if(CurrentEmote[pm->ps->clientNum] >= LEGS_WALKBACK1) + EmoteType = 0; + if(CurrentEmote[pm->ps->clientNum] >= TORSO_DROPWEAP1 && CurrentEmote[pm->ps->clientNum] <= TORSO_CARRY1) + EmoteType = 1; + if(CurrentEmote[pm->ps->clientNum] >= BOTH_DEATH1 && CurrentEmote[pm->ps->clientNum] <= BOTH_POWERUP1) + EmoteType = 2; + +//Check for higher priority animations + if(EmoteType == 0) + { + //ToDo: insert checking for high priority anims + } + else if(EmoteType == 1) + { + //ToDo: insert checking for high priority anims + } + else //Implies EmoteType == 2 + { + //ToDo: insert checking for high priority anims + } + + //Do the emote (play the anim) + if(EmoteType == 0 || EmoteType == 2) + { + PM_ForceLegsAnim(CurrentEmote[pm->ps->clientNum]); //CurrentEmote[pm->ps->clientNum] + //pm->ps->legsAnim = ( ( pm->ps->legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) + //| CurrentEmote[pm->ps->clientNum]; + } + if(EmoteType == 1 || EmoteType == 2) + { + PM_ForceTorsoAnim(CurrentEmote[pm->ps->clientNum]); + //pm->ps->torsoAnim = ( ( pm->ps->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) + //| CurrentEmote[pm->ps->clientNum]; + } + + //Make -1 so it doesnt start the anim again. + CurrentEmote[pm->ps->clientNum] = -1; +}*/ + /* ================== PM_ClipVelocity - -Slide off of the impacting surface ================== */ +/** +* Slide off of the impacting surface +*/ void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce ) { float backoff; float change; @@ -164,17 +1070,19 @@ void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce ) { /* ================== PM_Friction - -Handles both ground friction and water friction ================== */ +/** +* Handles both ground friction and water friction +*/ static void PM_Friction( void ) { vec3_t vec; float *vel; float speed, newspeed, control; float drop; + playerState_t *ps = pm->ps; - vel = pm->ps->velocity; + vel = ps->velocity; VectorCopy( vel, vec ); if ( pml.walking ) { @@ -192,10 +1100,10 @@ static void PM_Friction( void ) { drop = 0; // apply ground friction - if ( pm->waterlevel <= 1 ) { - if ( pml.walking && !(pml.groundTrace.surfaceFlags & SURF_SLICK) ) { + if ( (pm->watertype & CONTENTS_LADDER) || pm->waterlevel <= 1 ) { + if ( (pm->watertype & CONTENTS_LADDER) || (pml.walking && !(pml.groundTrace.surfaceFlags & SURF_SLICK)) ) { // if getting knocked back, no friction - if ( ! (pm->ps->pm_flags & PMF_TIME_KNOCKBACK) ) { + if ( ! (ps->pm_flags & PMF_TIME_KNOCKBACK) ) { control = speed < pm_stopspeed ? pm_stopspeed : speed; drop += control*pm_friction*pml.frametime; } @@ -203,17 +1111,20 @@ static void PM_Friction( void ) { } // apply water friction even if just wading - if ( pm->waterlevel ) { + if ( pm->waterlevel && !(pm->watertype & CONTENTS_LADDER) ) { drop += speed*pm_waterfriction*pm->waterlevel*pml.frametime; } - // apply flying friction - if ( pm->ps->powerups[PW_FLIGHT]) { - drop += speed*pm_flightfriction*pml.frametime; + //RPG-X | Phenix | 8/8/2004 + //Apply EVOSUIT friction (small) + if ( ps->powerups[PW_EVOSUIT] ) + { + drop += speed*pm_evosuitfriction*pml.frametime; } - if ( pm->ps->pm_type == PM_SPECTATOR) { - drop += speed*pm_spectatorfriction*pml.frametime; + // apply flying friction + if ( ps->powerups[PW_FLIGHT] || ps->pm_type == PM_SPECTATOR ) { + drop += speed*pm_flightfriction*pml.frametime; } // scale the velocity @@ -232,10 +1143,11 @@ static void PM_Friction( void ) { /* ============== PM_Accelerate - -Handles user intended acceleration ============== */ +/** +* Handles user intended acceleration +*/ static void PM_Accelerate( vec3_t wishdir, float wishspeed, float accel ) { #if 1 // q2 style @@ -280,12 +1192,14 @@ static void PM_Accelerate( vec3_t wishdir, float wishspeed, float accel ) { /* ============ PM_CmdScale - -Returns the scale factor to apply to cmd movements -This allows the clients to use axial -127 to 127 values for all directions -without getting a sqrt(2) distortion in speed. ============ */ +/** +* \return the scale factor to apply to cmd movements +* +* This allows the clients to use axial -127 to 127 values for all directions +* without getting a sqrt(2) distortion in speed. +*/ static float PM_CmdScale( usercmd_t *cmd ) { int max; float total; @@ -313,38 +1227,42 @@ static float PM_CmdScale( usercmd_t *cmd ) { /* ================ PM_SetMovementDir - -Determine the rotation of the legs reletive -to the facing dir ================ */ +/** +* Determines the rotation of the legs reletive +* to the facing dir +*/ static void PM_SetMovementDir( void ) { - if ( pm->cmd.forwardmove || pm->cmd.rightmove ) { - if ( pm->cmd.rightmove == 0 && pm->cmd.forwardmove > 0 ) { - pm->ps->movementDir = 0; - } else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove > 0 ) { - pm->ps->movementDir = 1; - } else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove == 0 ) { - pm->ps->movementDir = 2; - } else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove < 0 ) { - pm->ps->movementDir = 3; - } else if ( pm->cmd.rightmove == 0 && pm->cmd.forwardmove < 0 ) { - pm->ps->movementDir = 4; - } else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove < 0 ) { - pm->ps->movementDir = 5; - } else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove == 0 ) { - pm->ps->movementDir = 6; - } else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove > 0 ) { - pm->ps->movementDir = 7; + playerState_t *ps = pm->ps; + usercmd_t *cmd = &pm->cmd; + + if ( cmd->forwardmove || cmd->rightmove ) { + if ( cmd->rightmove == 0 && cmd->forwardmove > 0 ) { + ps->movementDir = 0; + } else if ( cmd->rightmove < 0 && cmd->forwardmove > 0 ) { + ps->movementDir = 1; + } else if ( cmd->rightmove < 0 && cmd->forwardmove == 0 ) { + ps->movementDir = 2; + } else if ( cmd->rightmove < 0 && cmd->forwardmove < 0 ) { + ps->movementDir = 3; + } else if ( cmd->rightmove == 0 && cmd->forwardmove < 0 ) { + ps->movementDir = 4; + } else if ( cmd->rightmove > 0 && cmd->forwardmove < 0 ) { + ps->movementDir = 5; + } else if ( cmd->rightmove > 0 && cmd->forwardmove == 0 ) { + ps->movementDir = 6; + } else if ( cmd->rightmove > 0 && cmd->forwardmove > 0 ) { + ps->movementDir = 7; } } else { // if they aren't actively going directly sideways, // change the animation to the diagonal so they // don't stop too crooked - if ( pm->ps->movementDir == 2 ) { - pm->ps->movementDir = 1; - } else if ( pm->ps->movementDir == 6 ) { - pm->ps->movementDir = 7; + if ( ps->movementDir == 2 ) { + ps->movementDir = 1; + } else if ( ps->movementDir == 6 ) { + ps->movementDir = 7; } } } @@ -355,8 +1273,13 @@ static void PM_SetMovementDir( void ) { PM_CheckJump ============= */ +/** +* Checks if jumping is allowed +*/ static qboolean PM_CheckJump( void ) { - if ( pm->ps->pm_flags & PMF_RESPAWNED ) { + playerState_t *ps = pm->ps; + + if ( ps->pm_flags & PMF_RESPAWNED ) { return qfalse; // don't allow jump until all buttons are up } @@ -366,7 +1289,7 @@ static qboolean PM_CheckJump( void ) { } // must wait for jump to be released - if ( pm->ps->pm_flags & PMF_JUMP_HELD ) { + if ( ps->pm_flags & PMF_JUMP_HELD ) { // clear upmove so cmdscale doesn't lower running speed pm->cmd.upmove = 0; return qfalse; @@ -374,20 +1297,26 @@ static qboolean PM_CheckJump( void ) { pml.groundPlane = qfalse; // jumping away pml.walking = qfalse; - pm->ps->pm_flags |= PMF_JUMP_HELD; + ps->pm_flags |= PMF_JUMP_HELD; + + ps->groundEntityNum = ENTITYNUM_NONE; + ps->velocity[2] = JUMP_VELOCITY; - pm->ps->groundEntityNum = ENTITYNUM_NONE; - pm->ps->velocity[2] = JUMP_VELOCITY; PM_AddEvent( EV_JUMP ); if ( pm->cmd.forwardmove >= 0 ) { - PM_ForceLegsAnim( LEGS_JUMP ); - pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP; + PM_ForceLegsAnim( PM_GetAnim( ANIM_JUMP, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qfalse ) ); //BOTH_JUMP + if ( ps->weaponstate == WEAPON_READY ) + PM_ForceTorsoAnim( PM_GetAnim( ANIM_JUMP, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qtrue ), qtrue ); + ps->pm_flags &= ~PMF_BACKWARDS_JUMP; } else { - PM_ForceLegsAnim( LEGS_JUMPB ); - pm->ps->pm_flags |= PMF_BACKWARDS_JUMP; + if ( ps->weaponstate == WEAPON_READY ) + PM_ForceTorsoAnim( PM_GetAnim( ANIM_JUMPB, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qfalse ), qtrue ); + PM_ForceLegsAnim( PM_GetAnim( ANIM_JUMPB, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qtrue ) ); //LEGS_JUMPB + ps->pm_flags |= PMF_BACKWARDS_JUMP; } + return qtrue; } @@ -396,12 +1325,16 @@ static qboolean PM_CheckJump( void ) { PM_CheckWaterJump ============= */ +/** +* Checks if jumping out of water is allowed +*/ static qboolean PM_CheckWaterJump( void ) { vec3_t spot; int cont; vec3_t flatforward; + playerState_t *ps = pm->ps; - if (pm->ps->pm_time) { + if (ps->pm_time) { return qfalse; } @@ -410,30 +1343,35 @@ static qboolean PM_CheckWaterJump( void ) { return qfalse; } + if ( pm->watertype & CONTENTS_LADDER ) { + if (ps->velocity[2] <= 0) + return qfalse; + } + flatforward[0] = pml.forward[0]; flatforward[1] = pml.forward[1]; flatforward[2] = 0; VectorNormalize (flatforward); - VectorMA (pm->ps->origin, 30, flatforward, spot); + VectorMA (ps->origin, 30, flatforward, spot); spot[2] += 4; - cont = pm->pointcontents (spot, pm->ps->clientNum ); + cont = pm->pointcontents (spot, ps->clientNum ); if ( !(cont & CONTENTS_SOLID) ) { return qfalse; } spot[2] += 16; - cont = pm->pointcontents (spot, pm->ps->clientNum ); - if ( cont & (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_BODY) ) { + cont = pm->pointcontents (spot, ps->clientNum ); + if ( cont ) { return qfalse; } // jump out of water - VectorScale (pml.forward, 200, pm->ps->velocity); - pm->ps->velocity[2] = 350; + VectorScale (pml.forward, 200, ps->velocity); + ps->velocity[2] = 350; - pm->ps->pm_flags |= PMF_TIME_WATERJUMP; - pm->ps->pm_time = 2000; + ps->pm_flags |= PMF_TIME_WATERJUMP; + ps->pm_time = 2000; return qtrue; } @@ -444,20 +1382,22 @@ static qboolean PM_CheckWaterJump( void ) { /* =================== PM_WaterJumpMove - -Flying out of the water =================== */ +/** +* Flying out of the water +*/ static void PM_WaterJumpMove( void ) { + playerState_t *ps = pm->ps; // waterjump has no control, but falls PM_StepSlideMove( qtrue ); - pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime; - if (pm->ps->velocity[2] < 0) { + ps->velocity[2] -= ps->gravity * pml.frametime; + if (ps->velocity[2] < 0) { // cancel as soon as we are falling down again - pm->ps->pm_flags &= ~PMF_ALL_TIMES; - pm->ps->pm_time = 0; + ps->pm_flags &= ~PMF_ALL_TIMES; + ps->pm_time = 0; } } @@ -467,6 +1407,9 @@ PM_WaterMove =================== */ +/** +* Handles movement in water +*/ static void PM_WaterMove( void ) { int i; vec3_t wishvel; @@ -474,6 +1417,7 @@ static void PM_WaterMove( void ) { vec3_t wishdir; float scale; float vel; + playerState_t *ps = pm->ps; if ( PM_CheckWaterJump() ) { PM_WaterJumpMove(); @@ -482,13 +1426,13 @@ static void PM_WaterMove( void ) { #if 0 // jump = head for surface if ( pm->cmd.upmove >= 10 ) { - if (pm->ps->velocity[2] > -300) { + if (ps->velocity[2] > -300) { if ( pm->watertype == CONTENTS_WATER ) { - pm->ps->velocity[2] = 100; + ps->velocity[2] = 100; } else if (pm->watertype == CONTENTS_SLIME) { - pm->ps->velocity[2] = 80; + ps->velocity[2] = 80; } else { - pm->ps->velocity[2] = 50; + ps->velocity[2] = 50; } } } @@ -502,66 +1446,70 @@ static void PM_WaterMove( void ) { if ( !scale ) { wishvel[0] = 0; wishvel[1] = 0; - wishvel[2] = -60; // sink towards bottom + if ( pm->watertype & CONTENTS_LADDER ) { + wishvel[2] = 0; + } else { + wishvel[2] = -60; // sink towards bottom + } } else { - for (i=0 ; i<3 ; i++) + for (i=0 ; i<3 ; i++) { wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove; - + } wishvel[2] += scale * pm->cmd.upmove; } VectorCopy (wishvel, wishdir); wishspeed = VectorNormalize(wishdir); - if ( wishspeed > pm->ps->speed * pm_swimScale ) { - wishspeed = pm->ps->speed * pm_swimScale; + if ( pm->watertype & CONTENTS_LADDER ) //ladder + { + if ( wishspeed > ps->speed * pm_ladderScale ) { + wishspeed = ps->speed * pm_ladderScale; + } + PM_Accelerate( wishdir, wishspeed, pm_flyaccelerate ); + } else { + if ( wishspeed > ps->speed * pm_swimScale ) { + wishspeed = ps->speed * pm_swimScale; + } + PM_Accelerate( wishdir, wishspeed, pm_wateraccelerate ); } - PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate); - // make sure we can go up slopes easily under water - if ( pml.groundPlane && DotProduct( pm->ps->velocity, pml.groundTrace.plane.normal ) < 0 ) { - vel = VectorLength(pm->ps->velocity); + if ( pml.groundPlane && DotProduct( ps->velocity, pml.groundTrace.plane.normal ) < 0 ) { + vel = VectorLength(ps->velocity); // slide along the ground plane - PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, - pm->ps->velocity, OVERCLIP ); + PM_ClipVelocity (ps->velocity, pml.groundTrace.plane.normal, + ps->velocity, OVERCLIP ); - VectorNormalize(pm->ps->velocity); - VectorScale(pm->ps->velocity, vel, pm->ps->velocity); + VectorNormalize(ps->velocity); + VectorScale(ps->velocity, vel, ps->velocity); } PM_SlideMove( qfalse ); } -#ifdef MISSIONPACK -/* -=================== -PM_InvulnerabilityMove -Only with the invulnerability powerup -=================== -*/ -static void PM_InvulnerabilityMove( void ) { - pm->cmd.forwardmove = 0; - pm->cmd.rightmove = 0; - pm->cmd.upmove = 0; - VectorClear(pm->ps->velocity); -} -#endif /* =================== PM_FlyMove Only with the flight powerup +TiM: Good... if this handles +spectators too, I'm sunk >.< +Oh crap... it does lol =================== */ +/** +* Handles fly movement (e.g. flight powerup or spectator movement) +*/ static void PM_FlyMove( void ) { int i; vec3_t wishvel; float wishspeed; vec3_t wishdir; float scale; + playerState_t *ps = pm->ps; // normal slowdown PM_Friction (); @@ -576,16 +1524,32 @@ static void PM_FlyMove( void ) { wishvel[2] = 0; } else { for (i=0 ; i<3 ; i++) { - wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove; + if ( ps->pm_type == PM_SPECTATOR ) { + wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove; + } + else { + //TiM - Vertical is no longer a hardcoded constant direction + wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + + scale * pml.right[i]*pm->cmd.rightmove + + scale * pml.up[i]* pm->cmd.upmove; + + //TiM - Set directions + PM_SetMovementDir(); + } } - wishvel[2] += scale * pm->cmd.upmove; + if ( ps->pm_type == PM_SPECTATOR ) + wishvel[2] += scale * pm->cmd.upmove; } VectorCopy (wishvel, wishdir); wishspeed = VectorNormalize(wishdir); PM_Accelerate (wishdir, wishspeed, pm_flyaccelerate); + + if ( ps->weaponstate == WEAPON_READY ) + PM_ContinueTorsoAnim( PM_GetAnim( ANIM_FLY, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qtrue ), qfalse ); + PM_ContinueLegsAnim( PM_GetAnim( ANIM_FLY, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qfalse ), qtrue ); PM_StepSlideMove( qfalse ); } @@ -597,6 +1561,9 @@ PM_AirMove =================== */ +/** +* Handles movement during air time (e.g. falling) +*/ static void PM_AirMove( void ) { int i; vec3_t wishvel; @@ -643,50 +1610,16 @@ static void PM_AirMove( void ) { pm->ps->velocity, OVERCLIP ); } -#if 0 - //ZOID: If we are on the grapple, try stair-stepping - //this allows a player to use the grapple to pull himself - //over a ledge - if (pm->ps->pm_flags & PMF_GRAPPLE_PULL) - PM_StepSlideMove ( qtrue ); - else - PM_SlideMove ( qtrue ); -#endif - PM_StepSlideMove ( qtrue ); } /* =================== -PM_GrappleMove - +PM_WalkMove =================== */ -static void PM_GrappleMove( void ) { - vec3_t vel, v; - float vlen; - - VectorScale(pml.forward, -16, v); - VectorAdd(pm->ps->grapplePoint, v, v); - VectorSubtract(v, pm->ps->origin, vel); - vlen = VectorLength(vel); - VectorNormalize( vel ); - - if (vlen <= 100) - VectorScale(vel, 10 * vlen, vel); - else - VectorScale(vel, 800, vel); - - VectorCopy(vel, pm->ps->velocity); - - pml.groundPlane = qfalse; -} - -/* -=================== -PM_WalkMove - -=================== +/** +* Handles walk movement */ static void PM_WalkMove( void ) { int i; @@ -698,6 +1631,7 @@ static void PM_WalkMove( void ) { usercmd_t cmd; float accelerate; float vel; + playerState_t *ps = pm->ps; if ( pm->waterlevel > 2 && DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 ) { // begin swimming @@ -723,6 +1657,7 @@ static void PM_WalkMove( void ) { cmd = pm->cmd; scale = PM_CmdScale( &cmd ); + //scale = 0.4; //TiM // set the movementDir so clients can rotate the legs for strafing PM_SetMovementDir(); @@ -749,9 +1684,9 @@ static void PM_WalkMove( void ) { wishspeed *= scale; // clamp the speed lower if ducking - if ( pm->ps->pm_flags & PMF_DUCKED ) { - if ( wishspeed > pm->ps->speed * pm_duckScale ) { - wishspeed = pm->ps->speed * pm_duckScale; + if ( ps->pm_flags & PMF_DUCKED ) { + if ( wishspeed > ps->speed * pm_duckScale ) { + wishspeed = ps->speed * pm_duckScale; } } @@ -761,14 +1696,14 @@ static void PM_WalkMove( void ) { waterScale = pm->waterlevel / 3.0; waterScale = 1.0 - ( 1.0 - pm_swimScale ) * waterScale; - if ( wishspeed > pm->ps->speed * waterScale ) { - wishspeed = pm->ps->speed * waterScale; + if ( wishspeed > ps->speed * waterScale ) { + wishspeed = ps->speed * waterScale; } } // when a player gets hit, they temporarily lose // full control, which allows them to be moved a bit - if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) { + if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || ps->pm_flags & PMF_TIME_KNOCKBACK ) { accelerate = pm_airaccelerate; } else { accelerate = pm_accelerate; @@ -776,34 +1711,34 @@ static void PM_WalkMove( void ) { PM_Accelerate (wishdir, wishspeed, accelerate); - //Com_Printf("velocity = %1.1f %1.1f %1.1f\n", pm->ps->velocity[0], pm->ps->velocity[1], pm->ps->velocity[2]); - //Com_Printf("velocity1 = %1.1f\n", VectorLength(pm->ps->velocity)); + //Com_Printf("velocity = %1.1f %1.1f %1.1f\n", ps->velocity[0], ps->velocity[1], ps->velocity[2]); + //Com_Printf("velocity1 = %1.1f\n", VectorLength(ps->velocity)); - if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) { - pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime; + if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || ps->pm_flags & PMF_TIME_KNOCKBACK ) { + ps->velocity[2] -= ps->gravity * pml.frametime; } else { // don't reset the z velocity for slopes -// pm->ps->velocity[2] = 0; +// ps->velocity[2] = 0; } - vel = VectorLength(pm->ps->velocity); + vel = VectorLength(ps->velocity); // slide along the ground plane - PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, - pm->ps->velocity, OVERCLIP ); + PM_ClipVelocity (ps->velocity, pml.groundTrace.plane.normal, + ps->velocity, OVERCLIP ); // don't decrease velocity when going up or down a slope - VectorNormalize(pm->ps->velocity); - VectorScale(pm->ps->velocity, vel, pm->ps->velocity); + VectorNormalize(ps->velocity); + VectorScale(ps->velocity, vel, ps->velocity); // don't do anything if standing still - if (!pm->ps->velocity[0] && !pm->ps->velocity[1]) { + if (!ps->velocity[0] && !ps->velocity[1]) { return; } PM_StepSlideMove( qfalse ); - //Com_Printf("velocity2 = %1.1f\n", VectorLength(pm->ps->velocity)); + //Com_Printf("velocity2 = %1.1f\n", VectorLength(ps->velocity)); } @@ -813,8 +1748,12 @@ static void PM_WalkMove( void ) { PM_DeadMove ============== */ +/** +* Handles movement while dead +*/ static void PM_DeadMove( void ) { float forward; + playerState_t *ps = pm->ps; if ( !pml.walking ) { return; @@ -822,13 +1761,13 @@ static void PM_DeadMove( void ) { // extra friction - forward = VectorLength (pm->ps->velocity); + forward = VectorLength (ps->velocity); forward -= 20; if ( forward <= 0 ) { - VectorClear (pm->ps->velocity); + VectorClear (ps->velocity); } else { - VectorNormalize (pm->ps->velocity); - VectorScale (pm->ps->velocity, forward, pm->ps->velocity); + VectorNormalize (ps->velocity); + VectorScale (ps->velocity, forward, ps->velocity); } } @@ -838,6 +1777,9 @@ static void PM_DeadMove( void ) { PM_NoclipMove =============== */ +/** +* Handles noclip movement +*/ static void PM_NoclipMove( void ) { float speed, drop, friction, control, newspeed; int i; @@ -846,15 +1788,16 @@ static void PM_NoclipMove( void ) { vec3_t wishdir; float wishspeed; float scale; + playerState_t *ps = pm->ps; - pm->ps->viewheight = DEFAULT_VIEWHEIGHT; + ps->viewheight = DEFAULT_VIEWHEIGHT; // friction - speed = VectorLength (pm->ps->velocity); + speed = VectorLength (ps->velocity); if (speed < 1) { - VectorCopy (vec3_origin, pm->ps->velocity); + VectorCopy (vec3_origin, ps->velocity); } else { @@ -870,7 +1813,7 @@ static void PM_NoclipMove( void ) { newspeed = 0; newspeed /= speed; - VectorScale (pm->ps->velocity, newspeed, pm->ps->velocity); + VectorScale (ps->velocity, newspeed, ps->velocity); } // accelerate @@ -890,25 +1833,184 @@ static void PM_NoclipMove( void ) { PM_Accelerate( wishdir, wishspeed, pm_accelerate ); // move - VectorMA (pm->ps->origin, pml.frametime, pm->ps->velocity, pm->ps->origin); + VectorMA (ps->origin, pml.frametime, ps->velocity, ps->origin); } + +/* +=================== +PM_FreezeMove +=================== +*/ +/** +* Handles movement whole freezed +*/ +static void PM_FreezeMove( void ) +{ + trace_t trace; + short temp, i; + vec3_t moveto; + playerState_t *ps = pm->ps; + + pm->mins[0] = DEFAULT_MINS_0; //-15 + pm->mins[1] = DEFAULT_MINS_1; + + pm->maxs[0] = DEFAULT_MAXS_0; //15 + pm->maxs[1] = DEFAULT_MAXS_1; + + pm->mins[2] = MINS_Z; + // stand up if possible + if (ps->pm_flags & PMF_DUCKED) + { + // try to stand up + pm->maxs[2] = 36; //32 + pm->trace (&trace, ps->origin, pm->mins, pm->maxs, ps->origin, ps->clientNum, pm->tracemask ); + if (!trace.allsolid) + ps->pm_flags &= ~PMF_DUCKED; + } + + if (ps->pm_flags & PMF_DUCKED && ( !(ps->stats[EMOTES] & EMOTE_LOWER) && !ps->powerups[PW_FLIGHT] && !( ( ps->powerups[PW_EVOSUIT] ) && ( ps->gravity == 0 ) ) ) ) + { + pm->maxs[2] = 16; + ps->viewheight = CROUCH_VIEWHEIGHT; + } + else + { + if ( ps->stats[EMOTES] & EMOTE_LOWER && ps->legsTimer > 0 ) { + pm->maxs[2] = bg_emoteList[ps->legsTimer].hitBoxHeight; + ps->viewheight = bg_emoteList[ps->legsTimer].viewHeight; + //Com_Printf( S_COLOR_RED "%f", bg_emoteList[ps->legsTimer].viewHeight ); + } + else { + //TiM - essentially flip the bounding box + /*if ( ps->powerups[PW_FLIGHT] && Q_fabs( ps->viewangles[PITCH] ) > 89.0f ) { + pm->maxs[2] = 92; + pm->mins[2] = 32; + ps->viewheight = DEFAULT_VIEWHEIGHT; + }*/ + //else { + //TiM - Copied above + /*pm->maxs[2] = 36; + pm->mins[2] = MINS_Z; + ps->viewheight = DEFAULT_VIEWHEIGHT;*/ + //} + ps->viewheight = DEFAULT_VIEWHEIGHT; + } + } + + // circularly clamp the angles with deltas + for (i=0 ; i<3 ; i++) { + temp = pm->cmd.angles[i] + ps->delta_angles[i]; + if ( i == PITCH ) { + // don't let the player look up or down more than 90 degrees + if ( temp > 16000 ) { + ps->delta_angles[i] = 16000 - pm->cmd.angles[i]; + temp = 16000; + } else if ( temp < -16000 ) { + ps->delta_angles[i] = -16000 - pm->cmd.angles[i]; + temp = -16000; + } + } +// ps->viewangles[i] = SHORT2ANGLE(temp); // Clear the view angles, but don't set them. + } + + VectorCopy (ps->origin, moveto); + moveto[2] -= 16; + + // test the player position if they were a stepheight higher + pm->trace (&trace, ps->origin, pm->mins, pm->maxs, moveto, ps->clientNum, pm->tracemask); + if ( trace.fraction < 1.0) + { // Something just below, snap to it, to prevent a little "hop" after the holodeck fades in. + VectorCopy (trace.endpos, ps->origin); + ps->groundEntityNum = trace.entityNum; + + // Touch it. + PM_AddTouchEnt( trace.entityNum ); + + } +} + + //============================================================================ +//RPG-X | GSIO01 | 20/05/2009: +/** +* Get the corresponding landing sound for each surface type +*/ +static int PM_LandsoundForSurface( int fallType ) { + if( pm->ps->stats[PW_INVIS] ) + return 0; + + switch(fallType) { + case 1: + if(pml.groundTrace.surfaceFlags & SURF_GRASS) + return EV_FALL_MEDIUM_GRASS; + else if(pml.groundTrace.surfaceFlags & SURF_GRAVEL) + return EV_FALL_MEDIUM_GRAVEL; + else if(pml.groundTrace.surfaceFlags & SURF_SNOW) + return EV_FALL_MEDIUM_SNOW; + else if(pml.groundTrace.surfaceFlags & SURF_WOOD) + return EV_FALL_MEDIUM_WOOD; + else + return EV_FALL_MEDIUM; + break; + case 2: + if(pml.groundTrace.surfaceFlags & SURF_GRASS) + return EV_FALL_FAR_GRASS; + else if(pml.groundTrace.surfaceFlags & SURF_GRAVEL) + return EV_FALL_FAR_GRAVEL; + else if(pml.groundTrace.surfaceFlags & SURF_SNOW) + return EV_FALL_FAR_SNOW; + else if(pml.groundTrace.surfaceFlags & SURF_WOOD) + return EV_FALL_FAR_WOOD; + else + return EV_FALL_FAR; + break; + default: + if(pml.groundTrace.surfaceFlags & SURF_GRASS) + return EV_FALL_SHORT_GRASS; + else if(pml.groundTrace.surfaceFlags & SURF_GRAVEL) + return EV_FALL_SHORT_GRAVEL; + else if(pml.groundTrace.surfaceFlags & SURF_SNOW) + return EV_FALL_SHORT_SNOW; + else if(pml.groundTrace.surfaceFlags & SURF_WOOD) + return EV_FALL_SHORT_WOOD; + else + return EV_FALL_SHORT; + break; + } +} + /* ================ PM_FootstepForSurface - -Returns an event number apropriate for the groundsurface ================ */ +/** +* \return an event number apropriate for the groundsurface +*/ static int PM_FootstepForSurface( void ) { - if ( pml.groundTrace.surfaceFlags & SURF_NOSTEPS ) { + //cloaked people make no noise + if ( pml.groundTrace.surfaceFlags & SURF_NOSTEPS || pm->ps->stats[PW_INVIS] ) { return 0; } if ( pml.groundTrace.surfaceFlags & SURF_METALSTEPS ) { return EV_FOOTSTEP_METAL; } + //RPG-X | GSIO01 | 20.05.2009 | START MOD + if ( pml.groundTrace.surfaceFlags & SURF_GRASS ) { + return EV_FOOTSTEP_GRASS; + } + if ( pml.groundTrace.surfaceFlags & SURF_GRAVEL ) { + return EV_FOOTSTEP_GRAVEL; + } + if ( pml.groundTrace.surfaceFlags & SURF_SNOW ) { + return EV_FOOTSTEP_SNOW; + } + if ( pml.groundTrace.surfaceFlags & SURF_WOOD ) { + return EV_FOOTSTEP_WOOD; + } + //RPG-X | GSIO01 | 20.05.2009 | END MOD return EV_FOOTSTEP; } @@ -916,30 +2018,32 @@ static int PM_FootstepForSurface( void ) { /* ================= PM_CrashLand - -Check for hard landings that generate sound events ================= */ +/** +* Check for hard landings that generate sound events +*/ static void PM_CrashLand( void ) { float delta; float dist; float vel, acc; float t; float a, b, c, den; + playerState_t *ps = pm->ps; // decide which landing animation to use - if ( pm->ps->pm_flags & PMF_BACKWARDS_JUMP ) { - PM_ForceLegsAnim( LEGS_LANDB ); + if ( ps->pm_flags & PMF_BACKWARDS_JUMP ) { + // PM_ForceLegsAnim( LEGS_LANDB ); } else { - PM_ForceLegsAnim( LEGS_LAND ); + // PM_ForceLegsAnim( LEGS_LAND ); } - pm->ps->legsTimer = TIMER_LAND; +// ps->legsTimer = 0; //TIMER_LAND // calculate the exact velocity on landing - dist = pm->ps->origin[2] - pml.previous_origin[2]; + dist = ps->origin[2] - pml.previous_origin[2]; vel = pml.previous_velocity[2]; - acc = -pm->ps->gravity; + acc = -ps->gravity; a = acc / 2; b = vel; @@ -955,7 +2059,7 @@ static void PM_CrashLand( void ) { delta = delta*delta * 0.0001; // ducking while falling doubles damage - if ( pm->ps->pm_flags & PMF_DUCKED ) { + if ( ps->pm_flags & PMF_DUCKED ) { delta *= 2; } @@ -981,95 +2085,58 @@ static void PM_CrashLand( void ) { // SURF_NODAMAGE is used for bounce pads where you don't ever // want to take damage or play a crunch sound if ( !(pml.groundTrace.surfaceFlags & SURF_NODAMAGE) ) { - if ( delta > 60 ) { - PM_AddEvent( EV_FALL_FAR ); - } else if ( delta > 40 ) { + if ( delta > 55 || ps->stats[STAT_HEALTH] <= 1 ) { //60 //TiM a bit hacky, but I want this to play any time we fall when dead + PM_AddEvent( /*EV_FALL_FAR*/PM_LandsoundForSurface(2) ); //GSIO01 | 20/05/2009 + } else if ( delta > 35 ) { //40 // this is a pain grunt, so don't play it if dead - if ( pm->ps->stats[STAT_HEALTH] > 0 ) { - PM_AddEvent( EV_FALL_MEDIUM ); + if ( ps->stats[STAT_HEALTH] > 1 ) { //0 + PM_AddEvent( /*EV_FALL_MEDIUM*/PM_LandsoundForSurface(1) ); //GSIO01 | 20/05/2009 } - } else if ( delta > 7 ) { - PM_AddEvent( EV_FALL_SHORT ); + } else if ( delta > 5 ) { //7 + PM_AddEvent( /*EV_FALL_SHORT*/ PM_LandsoundForSurface(0) ); //GSIO01 | 20/05/2009 } else { PM_AddEvent( PM_FootstepForSurface() ); } } // start footstep cycle over - pm->ps->bobCycle = 0; + ps->bobCycle = 0; //TiM: was commented out... :P } -/* -============= -PM_CheckStuck -============= -*/ -/* -void PM_CheckStuck(void) { - trace_t trace; - pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, pm->ps->origin, pm->ps->clientNum, pm->tracemask); - if (trace.allsolid) { - //int shit = qtrue; - } -} -*/ /* ============= PM_CorrectAllSolid ============= */ -static int PM_CorrectAllSolid( trace_t *trace ) { - int i, j, k; - vec3_t point; - +static void PM_CorrectAllSolid( void ) { if ( pm->debugLevel ) { Com_Printf("%i:allsolid\n", c_pmove); } - // jitter around - for (i = -1; i <= 1; i++) { - for (j = -1; j <= 1; j++) { - for (k = -1; k <= 1; k++) { - VectorCopy(pm->ps->origin, point); - point[0] += (float) i; - point[1] += (float) j; - point[2] += (float) k; - pm->trace (trace, point, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - if ( !trace->allsolid ) { - point[0] = pm->ps->origin[0]; - point[1] = pm->ps->origin[1]; - point[2] = pm->ps->origin[2] - 0.25; - - pm->trace (trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - pml.groundTrace = *trace; - return qtrue; - } - } - } - } + // FIXME: jitter around pm->ps->groundEntityNum = ENTITYNUM_NONE; pml.groundPlane = qfalse; pml.walking = qfalse; - - return qfalse; } /* ============= PM_GroundTraceMissed - -The ground trace didn't hit a surface, so we are in freefall ============= */ +/** +* The ground trace didn't hit a surface, so we are in freefall +*/ static void PM_GroundTraceMissed( void ) { trace_t trace; vec3_t point; + playerState_t *ps = pm->ps; - if ( pm->ps->groundEntityNum != ENTITYNUM_NONE ) { + if ( ps->groundEntityNum != ENTITYNUM_NONE ) { // we just transitioned into freefall if ( pm->debugLevel ) { Com_Printf("%i:lift\n", c_pmove); @@ -1077,22 +2144,27 @@ static void PM_GroundTraceMissed( void ) { // if they aren't in a jumping animation and the ground is a ways away, force into it // if we didn't do the trace, the player would be backflipping down staircases - VectorCopy( pm->ps->origin, point ); + VectorCopy( ps->origin, point ); point[2] -= 64; - pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - if ( trace.fraction == 1.0 ) { + pm->trace (&trace, ps->origin, pm->mins, pm->maxs, point, ps->clientNum, pm->tracemask); + if ( trace.fraction == 1.0 && ( ps->stats[LEGSANIM] & ~ANIM_TOGGLEBIT) != BOTH_GET_UP1 ) { if ( pm->cmd.forwardmove >= 0 ) { - PM_ForceLegsAnim( LEGS_JUMP ); - pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP; + PM_ForceLegsAnim( PM_GetAnim( ANIM_JUMP, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qfalse ) ); + if ( ps->weaponstate == WEAPON_READY ) + PM_ForceTorsoAnim( PM_GetAnim( ANIM_JUMP, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qtrue ), qtrue ); + ps->pm_flags &= ~PMF_BACKWARDS_JUMP; } else { - PM_ForceLegsAnim( LEGS_JUMPB ); - pm->ps->pm_flags |= PMF_BACKWARDS_JUMP; + PM_ForceLegsAnim( PM_GetAnim( ANIM_JUMPB, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qfalse ) ); + if ( ps->weaponstate == WEAPON_READY ) + PM_ForceTorsoAnim( PM_GetAnim( ANIM_JUMPB, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qtrue ), qtrue ); + ps->pm_flags |= PMF_BACKWARDS_JUMP; } + } } - pm->ps->groundEntityNum = ENTITYNUM_NONE; + ps->groundEntityNum = ENTITYNUM_NONE; pml.groundPlane = qfalse; pml.walking = qfalse; } @@ -1103,21 +2175,25 @@ static void PM_GroundTraceMissed( void ) { PM_GroundTrace ============= */ +/** +* Does ad trace to the ground +*/ static void PM_GroundTrace( void ) { vec3_t point; trace_t trace; + playerState_t *ps = pm->ps; - point[0] = pm->ps->origin[0]; - point[1] = pm->ps->origin[1]; - point[2] = pm->ps->origin[2] - 0.25; + point[0] = ps->origin[0]; + point[1] = ps->origin[1]; + point[2] = ps->origin[2] - 0.25; - pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); + pm->trace (&trace, ps->origin, pm->mins, pm->maxs, point, ps->clientNum, pm->tracemask); pml.groundTrace = trace; // do something corrective if the trace starts in a solid... if ( trace.allsolid ) { - if ( !PM_CorrectAllSolid(&trace) ) - return; + PM_CorrectAllSolid(); + return; } // if the trace didn't hit anything, we are in free fall @@ -1129,20 +2205,24 @@ static void PM_GroundTrace( void ) { } // check if getting thrown off the ground - if ( pm->ps->velocity[2] > 0 && DotProduct( pm->ps->velocity, trace.plane.normal ) > 10 ) { + if ( ps->velocity[2] > 0 && DotProduct( ps->velocity, trace.plane.normal ) > 10 && ( ps->stats[LEGSANIM] & ~ANIM_TOGGLEBIT) != BOTH_GET_UP1 ) { if ( pm->debugLevel ) { Com_Printf("%i:kickoff\n", c_pmove); } // go into jump animation if ( pm->cmd.forwardmove >= 0 ) { - PM_ForceLegsAnim( LEGS_JUMP ); - pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP; + PM_ForceLegsAnim( PM_GetAnim( ANIM_JUMP, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qfalse ) ); + if ( ps->weaponstate == WEAPON_READY ) + PM_ForceTorsoAnim( PM_GetAnim( ANIM_JUMP, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qtrue ), qtrue ); + ps->pm_flags &= ~PMF_BACKWARDS_JUMP; } else { - PM_ForceLegsAnim( LEGS_JUMPB ); - pm->ps->pm_flags |= PMF_BACKWARDS_JUMP; + PM_ForceLegsAnim( PM_GetAnim( ANIM_JUMPB, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qfalse ) ); + if ( ps->weaponstate == WEAPON_READY ) + PM_ForceTorsoAnim( PM_GetAnim( ANIM_JUMPB, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qtrue ), qtrue ); + ps->pm_flags |= PMF_BACKWARDS_JUMP; } - pm->ps->groundEntityNum = ENTITYNUM_NONE; + ps->groundEntityNum = ENTITYNUM_NONE; pml.groundPlane = qfalse; pml.walking = qfalse; return; @@ -1155,7 +2235,7 @@ static void PM_GroundTrace( void ) { } // FIXME: if they can't slide down the slope, let them // walk (sharp crevices) - pm->ps->groundEntityNum = ENTITYNUM_NONE; + ps->groundEntityNum = ENTITYNUM_NONE; pml.groundPlane = qtrue; pml.walking = qfalse; return; @@ -1165,13 +2245,13 @@ static void PM_GroundTrace( void ) { pml.walking = qtrue; // hitting solid ground will end a waterjump - if (pm->ps->pm_flags & PMF_TIME_WATERJUMP) + if (ps->pm_flags & PMF_TIME_WATERJUMP) { - pm->ps->pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND); - pm->ps->pm_time = 0; + ps->pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND); + ps->pm_time = 0; } - if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) { + if ( ps->groundEntityNum == ENTITYNUM_NONE ) { // just hit the ground if ( pm->debugLevel ) { Com_Printf("%i:Land\n", c_pmove); @@ -1182,12 +2262,12 @@ static void PM_GroundTrace( void ) { // don't do landing time if we were just going down a slope if ( pml.previous_velocity[2] < -200 ) { // don't allow another jump for a little while - pm->ps->pm_flags |= PMF_TIME_LAND; - pm->ps->pm_time = 250; + ps->pm_flags |= PMF_TIME_LAND; + ps->pm_time = 250; } } - pm->ps->groundEntityNum = trace.entityNum; + ps->groundEntityNum = trace.entityNum; // don't reset the z velocity for slopes // pm->ps->velocity[2] = 0; @@ -1201,11 +2281,15 @@ static void PM_GroundTrace( void ) { PM_SetWaterLevel FIXME: avoid this twice? certainly if not moving ============= */ +/** +* Set water level +*/ static void PM_SetWaterLevel( void ) { vec3_t point; int cont; int sample1; int sample2; + playerState_t *ps = pm->ps; // // get waterlevel, accounting for ducking @@ -1213,24 +2297,24 @@ static void PM_SetWaterLevel( void ) { pm->waterlevel = 0; pm->watertype = 0; - point[0] = pm->ps->origin[0]; - point[1] = pm->ps->origin[1]; - point[2] = pm->ps->origin[2] + MINS_Z + 1; - cont = pm->pointcontents( point, pm->ps->clientNum ); + point[0] = ps->origin[0]; + point[1] = ps->origin[1]; + point[2] = ps->origin[2] + MINS_Z + 1; + cont = pm->pointcontents( point, ps->clientNum ); - if ( cont & MASK_WATER ) { - sample2 = pm->ps->viewheight - MINS_Z; + if ( cont & (MASK_WATER|CONTENTS_LADDER) ) { + sample2 = ps->viewheight - MINS_Z; sample1 = sample2 / 2; pm->watertype = cont; pm->waterlevel = 1; - point[2] = pm->ps->origin[2] + MINS_Z + sample1; - cont = pm->pointcontents (point, pm->ps->clientNum ); - if ( cont & MASK_WATER ) { + point[2] = ps->origin[2] + MINS_Z + sample1; + cont = pm->pointcontents (point, ps->clientNum ); + if ( cont & (MASK_WATER|CONTENTS_LADDER) ) { pm->waterlevel = 2; - point[2] = pm->ps->origin[2] + MINS_Z + sample2; - cont = pm->pointcontents (point, pm->ps->clientNum ); - if ( cont & MASK_WATER ){ + point[2] = ps->origin[2] + MINS_Z + sample2; + cont = pm->pointcontents (point, ps->clientNum ); + if ( cont & (MASK_WATER|CONTENTS_LADDER) ){ pm->waterlevel = 3; } } @@ -1238,173 +2322,429 @@ static void PM_SetWaterLevel( void ) { } + + /* ============== PM_CheckDuck - -Sets mins, maxs, and pm->ps->viewheight ============== */ +/** +* Sets mins, maxs, and pm->ps->viewheight +*/ static void PM_CheckDuck (void) { trace_t trace; + playerState_t *ps = pm->ps; - if ( pm->ps->powerups[PW_INVULNERABILITY] ) { - if ( pm->ps->pm_flags & PMF_INVULEXPAND ) { - // invulnerability sphere has a 42 units radius - VectorSet( pm->mins, -42, -42, -42 ); - VectorSet( pm->maxs, 42, 42, 42 ); - } - else { - VectorSet( pm->mins, -15, -15, MINS_Z ); - VectorSet( pm->maxs, 15, 15, 16 ); - } - pm->ps->pm_flags |= PMF_DUCKED; - pm->ps->viewheight = CROUCH_VIEWHEIGHT; - return; - } - pm->ps->pm_flags &= ~PMF_INVULEXPAND; + pm->mins[0] = DEFAULT_MINS_0; //-15 + pm->mins[1] = DEFAULT_MINS_1; - pm->mins[0] = -15; - pm->mins[1] = -15; - - pm->maxs[0] = 15; - pm->maxs[1] = 15; + pm->maxs[0] = DEFAULT_MAXS_0; + pm->maxs[1] = DEFAULT_MAXS_1; pm->mins[2] = MINS_Z; - if (pm->ps->pm_type == PM_DEAD) + if (ps->pm_type == PM_DEAD) { pm->maxs[2] = -8; - pm->ps->viewheight = DEAD_VIEWHEIGHT; + ps->viewheight = DEAD_VIEWHEIGHT; return; } if (pm->cmd.upmove < 0) { // duck - pm->ps->pm_flags |= PMF_DUCKED; + ps->pm_flags |= PMF_DUCKED; } else { // stand up if possible - if (pm->ps->pm_flags & PMF_DUCKED) + if (ps->pm_flags & PMF_DUCKED) { // try to stand up - pm->maxs[2] = 32; - pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, pm->ps->origin, pm->ps->clientNum, pm->tracemask ); + pm->maxs[2] = 36; //32 + pm->trace (&trace, ps->origin, pm->mins, pm->maxs, ps->origin, ps->clientNum, pm->tracemask ); if (!trace.allsolid) - pm->ps->pm_flags &= ~PMF_DUCKED; + ps->pm_flags &= ~PMF_DUCKED; } } - if (pm->ps->pm_flags & PMF_DUCKED) + if ( ps->pm_flags & PMF_DUCKED && !( (ps->stats[EMOTES] & EMOTE_LOWER) || ps->powerups[PW_FLIGHT] || ( ps->powerups[PW_EVOSUIT] && ps->gravity == 0 ) ) ) { pm->maxs[2] = 16; - pm->ps->viewheight = CROUCH_VIEWHEIGHT; + ps->viewheight = CROUCH_VIEWHEIGHT; } else { - pm->maxs[2] = 32; - pm->ps->viewheight = DEFAULT_VIEWHEIGHT; + if ( ps->stats[EMOTES] & EMOTE_LOWER && ps->legsTimer > 0 ) { + pm->maxs[2] = bg_emoteList[ps->legsTimer].hitBoxHeight; + ps->viewheight = bg_emoteList[ps->legsTimer].viewHeight; + + //Com_Printf( S_COLOR_RED "legsTimer = %i, viewHeight = %i\n", ps->legsTimer, ps->viewheight ); + } + else { + //TiM - essentially flip the bounding box + /*if ( ps->powerups[PW_FLIGHT] && Q_fabs( ps->viewangles[PITCH] ) > 89.0f ) { + pm->maxs[2] = 92; + pm->mins[2] = 32; + ps->viewheight = DEFAULT_VIEWHEIGHT; + }*/ + //else { + pm->maxs[2] = 36; + pm->mins[2] = MINS_Z; + ps->viewheight = DEFAULT_VIEWHEIGHT; + //} + } } + + //Com_Printf( "Viewheight is %i\n", ps->viewheight ); } //=================================================================== +//static qboolean ps->didFly; +//static /* =============== PM_Footsteps =============== */ +/** +* Does what it name suggests it handles footsteps. +*/ static void PM_Footsteps( void ) { float bobmove; int old; qboolean footstep; + playerState_t *ps = pm->ps; + //qboolean didFly; // // calculate speed and cycle to be used for // all cyclic walking effects // - pm->xyspeed = sqrt( pm->ps->velocity[0] * pm->ps->velocity[0] - + pm->ps->velocity[1] * pm->ps->velocity[1] ); + pm->xyspeed = sqrt( ps->velocity[0] * ps->velocity[0] + + ps->velocity[1] * ps->velocity[1] ); - if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) { + pm->xyzspeed = sqrt( ps->velocity[0] * ps->velocity[0] //XVel - left + right + + ps->velocity[1] * ps->velocity[1] //YVel - forward + back + + ps->velocity[2] * ps->velocity[2] ); //ZVel - up + down - if ( pm->ps->powerups[PW_INVULNERABILITY] ) { - PM_ContinueLegsAnim( LEGS_IDLECR ); + //RPG-X : TiM ***************************************************** + //Cheesy Halo style death flying! + if ( ps->stats[STAT_HEALTH] <= 1 && !ps->powerups[PW_QUAD] && !ps->powerups[PW_BEAM_OUT] ) { //if dead + /*TiM: clip brushes register as ENTITYNUM_NONE + (So if they landed on a shuttle model for instance, the fall anim would still loop O_o ) + so they gotta be moving as well to trigger this*/ + + //Com_Printf("groundEnt = %i, speed = %f, animState = %i\n",ps->groundEntityNum, pm->xyzspeed, ps->pm_flags); + + if ( ps->groundEntityNum == ENTITYNUM_NONE && pm->xyzspeed && pm->waterlevel < 2 ) { + + ps->pm_flags |= ANIM_DIDFLY; + + PM_ContinueLegsAnim( BOTH_FALLDEATH1INAIR, qtrue ); + + if ( ps->weaponstate == WEAPON_READY ) + { + PM_ContinueTorsoAnim( BOTH_FALLDEATH1INAIR, qtrue ); + } } - // airborne leaves position in cycle intact, but doesn't advance - if ( pm->waterlevel > 1 ) { - PM_ContinueLegsAnim( LEGS_SWIM ); - } - return; - } + + else { + if ( ps->pm_flags & ANIM_DIDFLY ) { + //TiM: Save flags. Use anim nums if possible + //if (ps->torsoAnim == BOTH_FALLDEATH1INAIR && ps->legsAnim == BOTH_FALLDEATH1INAIR ) { + PM_ContinueLegsAnim( BOTH_FALLDEATH1LAND, qtrue ); - // if not trying to move - if ( !pm->cmd.forwardmove && !pm->cmd.rightmove ) { - if ( pm->xyspeed < 5 ) { - pm->ps->bobCycle = 0; // start at beginning of cycle again - if ( pm->ps->pm_flags & PMF_DUCKED ) { - PM_ContinueLegsAnim( LEGS_IDLECR ); - } else { - PM_ContinueLegsAnim( LEGS_IDLE ); + + if ( ps->weaponstate == WEAPON_READY ) + { + PM_ContinueTorsoAnim( BOTH_FALLDEATH1LAND, qtrue ); + } + } } return; } + else { //Reset splat boolean + if ( ps->pm_flags & ANIM_DIDFLY && ps->pm_type != PM_DEAD ) { + ps->pm_flags &= ~ANIM_DIDFLY; + } + } + + //RPG-X : TiM ***************************************************** + //Ladder Animations + + //If not on ladder, reset + if ( !(pm->watertype & CONTENTS_LADDER) ) + { + if ( ps->pm_flags & ANIM_ONLADDER ) { + ps->pm_flags &= ~( ANIM_ONLADDER ); + } + + if ( ( !(ps->stats[EMOTES] & EMOTE_UPPER ) || !(ps->stats[EMOTES] & EMOTE_LOWER ) ) + && ps->stats[EMOTES] & EMOTE_CLAMP_BODY ) { + ps->stats[EMOTES] &= ~EMOTE_CLAMP_BODY; + } + //ps->pm_flags &= ~( ANIM_OFFLADDER ); + } + //If on ladder, but not touching the ground + if ( (pm->watertype & CONTENTS_LADDER) && ( ps->groundEntityNum == ENTITYNUM_NONE ) ) + { + if ( !(ps->pm_flags & ANIM_ONLADDER) ) { + ps->pm_flags |= ANIM_ONLADDER ; + ps->stats[EMOTES] |= EMOTE_CLAMP_BODY; + } + //ps->pm_flags &= ~( ANIM_OFFLADDER ); + } + + //If was going down the ladder, and hit the floor +/* if ( !(ps->pm_flags & (ANIM_ONLADDER) ) && + !(ps->pm_flags & (ANIM_OFFLADDER) ) && + ( pm->watertype & CONTENTS_LADDER) && + ( ps->groundEntityNum != ENTITYNUM_NONE ) ) + { + ps->pm_flags |= (ANIM_ONLADDER); + ps->pm_flags &= ~(ANIM_OFFLADDER); + + if ( ps->legsAnim == BOTH_LADDER_DWN1 || ps->legsAnim == BOTH_LADDER_IDLE) { //Going DOWN! + ps->pm_flags &= ~(ANIM_ONLADDER); + ps->pm_flags |= (ANIM_OFFLADDER); + } + } +*/ + //Com_Printf("pm->onLadder = %i, pm->offLadder = %i, vel = %i\n", pm->onLadder, pm->offLadder, ps->velocity[2] ); + + //Transition anim to get off ladder + if ( ( pm->watertype & CONTENTS_LADDER) && ( ps->groundEntityNum != ENTITYNUM_NONE ) && (ps->pm_flags & ANIM_ONLADDER) ) {//We JUST hit a ladder on the ground + PM_ContinueLegsAnim( BOTH_OFFLADDER_BOT1, qtrue ); + //ps->legsTimer = TIMER_GESTURE; + + if ( ps->weaponstate == WEAPON_READY ) + { + PM_ContinueTorsoAnim( BOTH_OFFLADDER_BOT1, qtrue ); + //ps->torsoTimer = TIMER_GESTURE; + } + //pm->offLadder = qtrue; + //if ( !(ps->pm_flags & ANIM_UPPER_LOOPING) ) { + ps->stats[EMOTES] &= ~EMOTE_CLAMP_BODY; + //} + + return; + } + + //Transition anim to get on ladder + if ( ( pm->watertype & CONTENTS_LADDER) && ( ps->groundEntityNum != ENTITYNUM_NONE ) && !(ps->pm_flags & ANIM_ONLADDER) ) {//We JUST hit a ladder on the ground + PM_ContinueLegsAnim( BOTH_ONLADDER_BOT1, qtrue ); + //ps->legsTimer = TIMER_GESTURE; + + if ( ps->weaponstate == WEAPON_READY ) + { + PM_ContinueTorsoAnim( BOTH_ONLADDER_BOT1, qtrue ); + //ps->torsoTimer = TIMER_GESTURE; + } + //pm->onLadder = qfalse; + + return; + } + + if ( ps->groundEntityNum == ENTITYNUM_NONE ) { + if (pm->watertype & CONTENTS_LADDER) + {//FIXME: check for watertype, save waterlevel for whether to play + //the get off ladder transition anim + + if ( ps->velocity[2] ) + {//going up or down it + int anim; + if ( ps->velocity[2] > 0 ) + { + anim = BOTH_LADDER_UP1; + } + else + { + anim = BOTH_LADDER_DWN1; + } + PM_ContinueLegsAnim( anim, qtrue ); + //if ( pm->waterlevel >= 2 ) //arms on ladder + if ( ps->weaponstate == WEAPON_READY ) + { + PM_ContinueTorsoAnim( anim, qtrue ); + } + if (fabs(ps->velocity[2]) >5) { + bobmove = 0.005 * fabs(ps->velocity[2]); // climbing bobs slow + if (bobmove > 0.3) + bobmove = 0.3F; + } + } + else + { + PM_ContinueLegsAnim( BOTH_LADDER_IDLE, qtrue ); + //ps->legsTimer += 300; + //if ( pm->waterlevel >= 2 ) //arms on ladder + if ( ps->weaponstate == WEAPON_READY ) + { + PM_ContinueTorsoAnim( BOTH_LADDER_IDLE, qtrue ); + //ps->torsoTimer += 300; + } + } + return; + }//****************************************************************** + else { + // airborne leaves position in cycle intact, but doesn't advance + if ( pm->waterlevel > 2 ) { //TiM: swimming is more hardcore now //1 + if ( ps->weaponstate == WEAPON_READY ) + PM_ContinueTorsoAnim( PM_GetAnim( ANIM_SWIM, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qtrue ), qtrue ); + PM_ContinueLegsAnim( PM_GetAnim( ANIM_SWIM, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qfalse ), qtrue ); + } /*else if ( ps->pm_flags & PMF_DUCKED ) { + PM_ContinueLegsAnim( BOTH_CROUCH2IDLE ); //BOTH_CROUCH1IDLE + }*/ + + return; + } + } + + + //Com_Printf( "Speed: %f\n", pm->xyspeed ); + + // if not trying to move + if ( ( !ps->speed || pm->xyspeed < 1.0f || !(pm->cmd.forwardmove || pm->cmd.rightmove) ) + && pm->waterlevel < 3 + && !ps->powerups[PW_FLIGHT] && !(( ps->powerups[PW_EVOSUIT] ) && ( ps->gravity == 0 )) + /*&& !( pm->watertype & MASK_WATER )*/ ) + { + //Com_Printf("Truuue\n" ); + + if ( pm->xyspeed > 1.0f && !( ps->pm_flags & PMF_DUCKED ) && !( ps->stats[EMOTES] & EMOTE_LOWER ) ) + { //TiM: When you want to duck, you will duck. no delays + if ( !( pm->cmd.buttons & BUTTON_WALKING ) && !(ps->pm_flags & PMF_DUCKED) ) { + if ( ps->weaponstate == WEAPON_READY && !PM_HoldingSpillableWeapon() ) { + PM_ContinueTorsoAnim( BOTH_RUN1STOP, qtrue ); //BOTH_RUN1STOP + } + PM_ContinueLegsAnim( BOTH_RUN1STOP, qtrue ); + } + + return; + } + else { // <5 + ps->bobCycle = 0; // start at beginning of cycle again + if ( ps->pm_flags & PMF_DUCKED && !(ps->stats[EMOTES] & EMOTE_LOWER ) ) { + + if ( ps->weaponstate == WEAPON_READY ) { + PM_ContinueTorsoAnim( PM_GetAnim( ANIM_CROUCH, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qtrue ), qfalse ); + } + PM_ContinueLegsAnim( PM_GetAnim( ANIM_CROUCH, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qfalse ), qtrue ); + + /*if ( !(ps->pm_flags & ANIM_CROUCHING) ) { //okay, we've obviously JUST crouched... + ps->pm_flags |= ANIM_CROUCHING; + if ( ps->weaponstate == WEAPON_READY ) { + PM_StartTorsoAnim( PM_GetAnim( "docrouch", qtrue ) ); + ps->torsoTimer += 1200; + } + + PM_StartLegsAnim( PM_GetAnim( "docrouch", qfalse ) ); + ps->legsTimer += 1200; + }*/ + + } else { + + if ( ps->weaponstate == WEAPON_READY ) + PM_ContinueTorsoAnim( PM_GetAnim( ANIM_IDLE, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qtrue ), qfalse ); + PM_ContinueLegsAnim( PM_GetAnim( ANIM_IDLE, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qfalse ), qfalse ); + + /*if ( (ps->pm_flags & ANIM_CROUCHING) ) { //okay, we've obviously JUST uncrouched... + ps->pm_flags &= ~ANIM_CROUCHING; + + if ( ps->weaponstate == WEAPON_READY ) { + PM_StartTorsoAnim( PM_GetAnim( ANIM_UNCROUCH, qtrue ) ); + ps->torsoTimer = 1100; + //Com_Printf("Anim: %i, timer: %i\n", ps->torsoAnim, ps->torsoTimer); + } + + PM_StartLegsAnim( PM_GetAnim( ANIM_UNCROUCH, qfalse ) ); + ps->introTime = 1100; //legsTimer + }*/ + + } + } + return; + } footstep = qfalse; - if ( pm->ps->pm_flags & PMF_DUCKED ) { + //TiM : in case we're part-way thru a transition anim, + //reset the anim timer + //ps->torsoTimer = 0; + //ps->legsTimer = 0; + + //TiM : Kill this when swimming as it screws up animations + //Also... kill when speed is 0.. running on the spot is silly lol + //Also, disable when flying. It looks ludricrous if we run upside down lol + if ( pm->waterlevel == 3 || ps->speed == 0 || ps->powerups[PW_FLIGHT] > 0 || pm->xyspeed < 1.0f || (( ps->powerups[PW_EVOSUIT] ) && ( ps->gravity == 0 )) ) + { + return; + } + + if ( ps->pm_flags & PMF_DUCKED ) { bobmove = 0.5; // ducked characters bob much faster - if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) { - PM_ContinueLegsAnim( LEGS_BACKCR ); - } - else { - PM_ContinueLegsAnim( LEGS_WALKCR ); + //HACK coz this damn thing screws up crouch firing anims otherwise T_T + if ( ps->weaponstate == WEAPON_READY ) { + PM_ContinueTorsoAnim( PM_GetAnim( ANIM_CROUCHWALK, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qtrue ), qfalse ); } + + PM_ContinueLegsAnim( PM_GetAnim( ANIM_CROUCHWALK, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qfalse ), qtrue ); // ducked characters never play footsteps - /* - } else if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) { + } + else if ( ps->pm_flags & PMF_BACKWARDS_RUN ) + { if ( !( pm->cmd.buttons & BUTTON_WALKING ) ) { bobmove = 0.4; // faster speeds bob faster footstep = qtrue; + + if ( ps->weaponstate == WEAPON_READY ) + PM_ContinueTorsoAnim( PM_GetAnim( ANIM_RUNB, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qtrue ), qfalse ); + PM_ContinueLegsAnim( PM_GetAnim( ANIM_RUNB, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qfalse ), qtrue ); //LEGS_BACK } else { bobmove = 0.3; + + if ( ps->weaponstate == WEAPON_READY ) + PM_ContinueTorsoAnim( PM_GetAnim( ANIM_WALKB, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qtrue ), qfalse ); + PM_ContinueLegsAnim( PM_GetAnim( ANIM_WALKB, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qfalse ), qtrue ); //LEGS_BACK } - PM_ContinueLegsAnim( LEGS_BACK ); - */ + } else { + if ( !( pm->cmd.buttons & BUTTON_WALKING ) ) { - bobmove = 0.4f; // faster speeds bob faster - if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) { - PM_ContinueLegsAnim( LEGS_BACK ); - } - else { - PM_ContinueLegsAnim( LEGS_RUN ); - } + bobmove = 0.4; // faster speeds bob faster footstep = qtrue; + + if ( ps->weaponstate == WEAPON_READY ) + PM_ContinueTorsoAnim( PM_GetAnim( ANIM_RUN, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qtrue ), qfalse ); + PM_ContinueLegsAnim( PM_GetAnim( ANIM_RUN, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qfalse ), qtrue ); //LEGS_RUN + } else { - bobmove = 0.3f; // walking bobs slow - if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) { - PM_ContinueLegsAnim( LEGS_BACKWALK ); - } - else { - PM_ContinueLegsAnim( LEGS_WALK ); - } + bobmove = 0.3; // walking bobs slow //0.3 + if ( ps->weaponstate == WEAPON_READY ) + PM_ContinueTorsoAnim( PM_GetAnim( ANIM_WALK, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qtrue ), qfalse ); + + PM_ContinueLegsAnim( PM_GetAnim( ANIM_WALK, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qfalse ), qtrue ); //LEGS_WALK } } // check for footstep / splash sounds - old = pm->ps->bobCycle; - pm->ps->bobCycle = (int)( old + bobmove * pml.msec ) & 255; + old = ps->bobCycle; + ps->bobCycle = (int)( old + bobmove * pml.msec ) & 255; // if we just crossed a cycle boundary, play an apropriate footstep event - if ( ( ( old + 64 ) ^ ( pm->ps->bobCycle + 64 ) ) & 128 ) { - if ( pm->waterlevel == 0 ) { + if ( ( ( old + 64 ) ^ ( ps->bobCycle + 64 ) ) & 128 && !ps->stats[PW_INVIS] ) { + if ( pm->watertype & CONTENTS_LADDER ) {// on ladder + if ( !pm->noFootsteps ) { + PM_AddEvent( EV_FOOTSTEP_METAL ); + } + } else if ( pm->waterlevel == 0 ) { // on ground will only play sounds if running if ( footstep && !pm->noFootsteps ) { PM_AddEvent( PM_FootstepForSurface() ); @@ -1425,11 +2765,16 @@ static void PM_Footsteps( void ) { /* ============== PM_WaterEvents - -Generate sound events for entering and leaving water ============== */ +/** +* Generate sound events for entering and leaving water +*/ static void PM_WaterEvents( void ) { // FIXME? + if ( pm->watertype & CONTENTS_LADDER || pm->ps->stats[PW_INVIS] ) //fake water for ladder + { + return; + } // // if just entered a water volume, play a sound // @@ -1465,23 +2810,28 @@ static void PM_WaterEvents( void ) { // FIXME? PM_BeginWeaponChange =============== */ +/** +* Begins weapon change +*/ static void PM_BeginWeaponChange( int weapon ) { - if ( weapon <= WP_NONE || weapon >= WP_NUM_WEAPONS ) { + playerState_t *ps = pm->ps; + + if ( weapon <= WP_0 || weapon >= WP_NUM_WEAPONS ) { return; } - if ( !( pm->ps->stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) { + if ( !( ps->stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) { return; } - if ( pm->ps->weaponstate == WEAPON_DROPPING ) { + if ( ps->weaponstate == WEAPON_DROPPING ) { return; } PM_AddEvent( EV_CHANGE_WEAPON ); - pm->ps->weaponstate = WEAPON_DROPPING; - pm->ps->weaponTime += 200; - PM_StartTorsoAnim( TORSO_DROP ); + ps->weaponstate = WEAPON_DROPPING; + ps->weaponTime += 200; + PM_ForceTorsoAnim( TORSO_DROPWEAP1, qfalse ); } @@ -1490,22 +2840,26 @@ static void PM_BeginWeaponChange( int weapon ) { PM_FinishWeaponChange =============== */ +/** +* Finishs weapon change +*/ static void PM_FinishWeaponChange( void ) { int weapon; + playerState_t *ps = pm->ps; weapon = pm->cmd.weapon; - if ( weapon < WP_NONE || weapon >= WP_NUM_WEAPONS ) { - weapon = WP_NONE; + if ( weapon < WP_0 || weapon >= WP_NUM_WEAPONS ) { + weapon = WP_0; } - if ( !( pm->ps->stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) { - weapon = WP_NONE; + if ( !( ps->stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) { + weapon = WP_0; } - pm->ps->weapon = weapon; - pm->ps->weaponstate = WEAPON_RAISING; - pm->ps->weaponTime += 250; - PM_StartTorsoAnim( TORSO_RAISE ); + ps->weapon = weapon; + ps->weaponstate = WEAPON_RAISING; + ps->weaponTime += 250; + PM_ForceTorsoAnim( TORSO_RAISEWEAP1, qfalse ); } @@ -1515,193 +2869,451 @@ PM_TorsoAnimation ============== */ -static void PM_TorsoAnimation( void ) { - if ( pm->ps->weaponstate == WEAPON_READY ) { - if ( pm->ps->weapon == WP_GAUNTLET ) { - PM_ContinueTorsoAnim( TORSO_STAND2 ); - } else { - PM_ContinueTorsoAnim( TORSO_STAND ); +/** +* Once handled torso animation +*/ +static void PM_TorsoAnimation( void ) +{ + + if ( pm->ps->weaponstate == WEAPON_READY ) + { + /*if ( pm->ps->weapon == WP_5 || //RPG-X - TiM: Making the default pose anim better + pm->ps->weapon == WP_10 ) + { + PM_ContinueTorsoAnim( TORSO_WEAPONIDLE1 ); + } + else + { + PM_ContinueTorsoAnim( TORSO_WEAPONREADY2 ); } - return; + if ( !( pm->cmd.buttons & BUTTON_WALKING ) ) { + //PM_ContinueTorsoAnim( BOTH_RUN1 ); + } + else { + PM_ContinueTorsoAnim( BOTH_WALK1 ); + }*/ } + + //PM_ContinueTorsoAnim( TORSO_STAND2 ); + return; } +#define PHASER_AMMO_PER_SHOT 1 +#define PHASER_ALT_AMMO_PER_SHOT 2 + +//! alt ammo usage +int altAmmoUsage[WP_NUM_WEAPONS] = +{ + 0, //!ps; // don't allow attack until all buttons are up - if ( pm->ps->pm_flags & PMF_RESPAWNED ) { + if ( ps->pm_flags & PMF_RESPAWNED ) { return; } // ignore if spectator - if ( pm->ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) { + if ( ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) { return; } + //Check for phaser ammo recharge + //RPG-X: Marcin: don't! - 30/12/2008 + if ( 0 ) //( (ps->rechargeTime <= 0) && ( ps->ammo[WP_5] < PHASER_AMMO_MAX) ) + { + ps->rechargeTime = PHASER_RECHARGE_TIME; + ps->ammo[WP_5]++; + } + else + { + ps->rechargeTime -= pml.msec; + } + // check for dead player - if ( pm->ps->stats[STAT_HEALTH] <= 0 ) { - pm->ps->weapon = WP_NONE; + if ( ps->stats[STAT_HEALTH] <= 0 ) { + ps->weapon = WP_0; return; } // check for item using - if ( pm->cmd.buttons & BUTTON_USE_HOLDABLE ) { - if ( ! ( pm->ps->pm_flags & PMF_USE_ITEM_HELD ) ) { - if ( bg_itemlist[pm->ps->stats[STAT_HOLDABLE_ITEM]].giTag == HI_MEDKIT - && pm->ps->stats[STAT_HEALTH] >= (pm->ps->stats[STAT_MAX_HEALTH] + 25) ) { - // don't use medkit if at max health - } else { - pm->ps->pm_flags |= PMF_USE_ITEM_HELD; - PM_AddEvent( EV_USE_ITEM0 + bg_itemlist[pm->ps->stats[STAT_HOLDABLE_ITEM]].giTag ); - pm->ps->stats[STAT_HOLDABLE_ITEM] = 0; + if ( pm->cmd.buttons & BUTTON_USE_HOLDABLE ) + { + if ( ! ( ps->pm_flags +& PMF_USE_ITEM_HELD ) ) + { + // I have commented out this code because, we want the medkit to ALWAYS be used. + +// if ( bg_itemlist[ps->stats[STAT_HOLDABLE_ITEM]].giTag == HI_MEDKIT +// && ps->stats[STAT_HEALTH] >= ps->stats[STAT_MAX_HEALTH] ) +// { +// // don't use medkit if at max health +// } +// else + { + int tag = bg_itemlist[ps->stats[STAT_HOLDABLE_ITEM]].giTag; + ps->pm_flags |= PMF_USE_ITEM_HELD; + PM_AddEvent( EV_USE_ITEM0 + tag ); + // if we're placing the detpack, don't remove it from our "inventory" + if ( (HI_DETPACK == tag) /* || (HI_TRANSPORTER == tag)) */ && + (IT_HOLDABLE == bg_itemlist[ps->stats[STAT_HOLDABLE_ITEM]].giType) ) + { + // are we placing it? + if (2 == ps->stats[STAT_USEABLE_PLACED]) + { + // we've placed the first stage of a 2-stage transporter + } + else if (ps->stats[STAT_USEABLE_PLACED]) + { + // we already placed it, we're activating it. + ps->stats[STAT_HOLDABLE_ITEM] = 0; + } + } + else + { + ps->stats[STAT_HOLDABLE_ITEM] = 0; + } } return; } - } else { - pm->ps->pm_flags &= ~PMF_USE_ITEM_HELD; + } + else + { + ps->pm_flags &= ~PMF_USE_ITEM_HELD; } // make weapon function - if ( pm->ps->weaponTime > 0 ) { - pm->ps->weaponTime -= pml.msec; + if ( ps->weaponTime > 0 ) { + ps->weaponTime -= pml.msec; } // check for weapon change // can't change if weapon is firing, but can change // again if lowering or raising - if ( pm->ps->weaponTime <= 0 || pm->ps->weaponstate != WEAPON_FIRING ) { - if ( pm->ps->weapon != pm->cmd.weapon ) { + if ( ps->weaponTime <= 0 || ps->weaponstate != WEAPON_FIRING ) { + if ( ps->weapon != pm->cmd.weapon ) { PM_BeginWeaponChange( pm->cmd.weapon ); } } - if ( pm->ps->weaponTime > 0 ) { + if ( ps->weaponTime > 0 ) { return; } // change weapon if time - if ( pm->ps->weaponstate == WEAPON_DROPPING ) { + if ( ps->weaponstate == WEAPON_DROPPING ) { PM_FinishWeaponChange(); return; } - if ( pm->ps->weaponstate == WEAPON_RAISING ) { - pm->ps->weaponstate = WEAPON_READY; - if ( pm->ps->weapon == WP_GAUNTLET ) { - PM_StartTorsoAnim( TORSO_STAND2 ); - } else { - PM_StartTorsoAnim( TORSO_STAND ); - } + if ( ps->weaponstate == WEAPON_RAISING ) + { + ps->weaponstate = WEAPON_READY; + /*if ( ps->weapon == WP_5 || //RPG-X - TiM: Making the default pose anim better + ps->weapon == WP_10 ) + { + PM_StartTorsoAnim( TORSO_WEAPONREADY2 ); + } + else + { + PM_StartTorsoAnim( TORSO_WEAPONIDLE1 ); + }*/ + + PM_StartTorsoAnim( PM_GetAnim( ANIM_IDLE, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qtrue ), qfalse ); + return; } // check for fire - if ( ! (pm->cmd.buttons & BUTTON_ATTACK) ) { - pm->ps->weaponTime = 0; - pm->ps->weaponstate = WEAPON_READY; - return; - } + if ( !(pm->cmd.buttons & (BUTTON_ATTACK | BUTTON_ALT_ATTACK) ) ) + { + ps->weaponTime = 0; + ps->weaponstate = WEAPON_READY; - // start the animation even if out of ammo - if ( pm->ps->weapon == WP_GAUNTLET ) { - // the guantlet only "fires" when it actually hits something - if ( !pm->gauntletHit ) { - pm->ps->weaponTime = 0; - pm->ps->weaponstate = WEAPON_READY; - return; - } - PM_StartTorsoAnim( TORSO_ATTACK2 ); - } else { - PM_StartTorsoAnim( TORSO_ATTACK ); - } - - pm->ps->weaponstate = WEAPON_FIRING; - - // check for out of ammo - if ( ! pm->ps->ammo[ pm->ps->weapon ] ) { - PM_AddEvent( EV_NOAMMO ); - pm->ps->weaponTime += 500; return; } // take an ammo away if not infinite - if ( pm->ps->ammo[ pm->ps->weapon ] != -1 ) { - pm->ps->ammo[ pm->ps->weapon ]--; + if ( ps->ammo[ ps->weapon ] != -1 ) + { + if (pm->cmd.buttons & BUTTON_ALT_ATTACK) + { + // alt fire + // check for out of ammo + if ( ps->ammo[ps->weapon] < altAmmoUsage[ps->weapon]) + { + //FIXME: flash a message and sound that indicates not enough ammo +// PM_AddEvent( EV_NOAMMO_ALT ); +// ps->weaponTime += 500; +// ps->eFlags &= ~EF_ALT_FIRING; +// ps->eFlags &= ~EF_FIRING; +/// ps->weaponstate = WEAPON_READY; + + /* + RPG-X | Phenix | 27/02/2005 + if ( ps->weapon == WP_5 ) // phaser out of ammo is special case + { + ps->ammo[ps->weapon] = 0; + } + else + { + PM_AddEvent( EV_NOAMMO_ALT ); // Just try to switch weapons like any other. + + // check out the EV_NOAMMO_ALT event + + ps->weaponTime += 500; + return; + }*/ + } + else + { + //ps->ammo[ps->weapon] -= altAmmoUsage[ps->weapon]; + //RPG-X | Phenix | 27/02/2005 + //altfired = qtrue; + } + altfired = qtrue; + } + else + { + // check for out of ammo + if ( ! ps->ammo[ ps->weapon ] ) + { + if ( ps->weapon == WP_5 ) // phaser out of ammo is special case + { + ps->ammo[ps->weapon] = 0; + } + //else //TiM - No ammo no more... this is lagging us up + //{ + // PM_AddEvent( EV_NOAMMO ); + // ps->weaponTime += 500; + // return; + //} + } + else + { + // main fire (always uses 1 ammo) + //ps->ammo[ps->weapon]--; + //RPG-X | Phenix | 27/02/2005 + } + } + } + + // *don't* start the animation if out of ammo + /*if ( ps->weapon == WP_5 || //RPG-X - TiM: Making the default pose anim better + ps->weapon == WP_10 ) + { + PM_StartTorsoAnim( TORSO_ATTACK2 ); + } + else + { + PM_StartTorsoAnim( BOTH_ATTACK1 ); + }*/ + + if ( ps->weapon != WP_14 && ps->weapon != WP_4 && ps->weapon != WP_1 ) + { + //Little hack. I like the idle poses for these when it crouches :) + if ( ( ( ps->weapon == WP_5 ) + || ( ps->weapon == WP_6 ) + || ( ps->weapon == WP_10 ) + || ( ps->weapon == WP_7 ) ) + && ( ps->pm_flags & PMF_DUCKED /*&& !pm->xyspeed*/ ) ) + { + PM_ForceTorsoAnim( PM_GetAnim( ANIM_CROUCH, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qtrue ), qfalse ); + /*BWEEE*/ + //PM_ContinueTorsoAnim( PM_GetAnim( ANIM_ATTACK, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qtrue ), qfalse ); + } + else + { + /*if ( !PM_HoldingLoopableWeapon() ) { + PM_ForceTorsoAnim( PM_GetAnim( ANIM_FIRE, qtrue ), qtrue ); + } + else {*/ + //PM_ContinueLegsAnim( PM_GetAnim( ANIM_ATTACK, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qfalse ), qfalse ); + PM_ContinueTorsoAnim( PM_GetAnim( ANIM_ATTACK, ps->weapon, ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH), qtrue ), qfalse ); + //} + } + /*else + PM_StartTorsoAnim( PM_GetAnim( "fire", qtrue ) );*/ + + //Put in this scope, so holding down the trigger on these 'no-anim' weapons won't lock + //other animations. + //Bots were locked in the jumping anim >.< + + ps->weaponstate = WEAPON_FIRING; + } + else + { + ps->weaponstate = WEAPON_READY; + } // fire weapon - PM_AddEvent( EV_FIRE_WEAPON ); - - switch( pm->ps->weapon ) { - default: - case WP_GAUNTLET: - addTime = 400; - break; - case WP_LIGHTNING: - addTime = 50; - break; - case WP_SHOTGUN: - addTime = 1000; - break; - case WP_MACHINEGUN: - addTime = 100; - break; - case WP_GRENADE_LAUNCHER: - addTime = 800; - break; - case WP_ROCKET_LAUNCHER: - addTime = 800; - break; - case WP_PLASMAGUN: - addTime = 100; - break; - case WP_RAILGUN: - addTime = 1500; - break; - case WP_BFG: - addTime = 200; - break; - case WP_GRAPPLING_HOOK: - addTime = 400; - break; -#ifdef MISSIONPACK - case WP_NAILGUN: - addTime = 1000; - break; - case WP_PROX_LAUNCHER: - addTime = 800; - break; - case WP_CHAINGUN: - addTime = 30; - break; -#endif - } - -#ifdef MISSIONPACK - if( bg_itemlist[pm->ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_SCOUT ) { - addTime /= 1.5; + if ( pm->cmd.buttons & BUTTON_ALT_ATTACK ) + { + if (altfired) // it's either a legally altfirable non-phaser, or it's a phaser with ammo left + { + PM_AddEvent( EV_ALT_FIRE ); // fixme, because I'm deducting ammo earlier, the last alt-fire shot turns into a main fire + } + else + { + PM_AddEvent( EV_FIRE_EMPTY_PHASER ); + } + switch( ps->weapon ) { + default: + case WP_5: + addTime = 100; + //If the phaser has been fired, delay the next recharge time + ps->rechargeTime = PHASER_RECHARGE_TIME; + break; + case WP_13: + addTime = 0; //500 + break; + case WP_8: + addTime = 600;//RPG-X: RedTechie use to be 700 + break; + case WP_10: + addTime = DISRUPTOR_DELAY; + break; + case WP_4: + addTime = 0; //700 + break; + case WP_9: + addTime = ALT_PHOTON_DELAY; + break; + case WP_1: + addTime = 460; //700 + break; + case WP_6: + addTime = 100; + break; + case WP_7: + addTime = 500; //RPG-X: RedTechie - Use to be 1200 + break; + case WP_12: + //RPG-X: RedTechie - Admins get faster alt fire for steam effects + if(/*ps->persistant[PERS_CLASS] == PC_ADMIN*/ pm->admin){ + addTime = 80; + }else{ + addTime = 1000; + } + break; + case WP_14: + addTime = 2000; + break; + case WP_11: + addTime = 0; //1000 + break; + case WP_2: + if(pm->admin /*ps->persistant[PERS_CLASS] == PC_ADMIN*/){ + addTime = ALT_TRICORDER_DELAY; + }else{ + addTime = 0; + } + break; + case WP_3: + addTime = 0; //500 + break; + case WP_15: + addTime = 0; //1000 + break; +/* case WP_7: + addTime = 500; //RPG-X: RedTechie - Use to be 1200 + break;*/ + } } else - if( bg_itemlist[pm->ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_AMMOREGEN ) { - addTime /= 1.3; - } - else -#endif - if ( pm->ps->powerups[PW_HASTE] ) { + { + if (ps->ammo[ps->weapon]) + { + PM_AddEvent( EV_FIRE_WEAPON ); + } + else + { + PM_AddEvent( EV_FIRE_EMPTY_PHASER ); + } + switch( ps->weapon ) { + default: + case WP_5: + addTime = 100; + //If the phaser has been fired, delay the next recharge time + ps->rechargeTime = PHASER_RECHARGE_TIME; + break; + case WP_13: + addTime = 1000; //1000 + break; + case WP_8: + addTime = 460;//RPG-X: RedTechie use to be 700 + break; + case WP_1: + addTime = 460; + break; + case WP_10: + addTime = 100; + break; + case WP_4: + addTime = 0; //100 + break; + case WP_9: + addTime = PHOTON_DELAY; + break; + case WP_6: + addTime = RIFLE_DELAY; + break; + case WP_7: + addTime = TR116_DELAY; //RPG-X: RedTechie - Use to be 1200 + break; + case WP_12: + addTime = 1000; + break; + case WP_14: + addTime = 2000; //1000 + break; + case WP_11: + addTime = 0; //1000 + break; + case WP_2: + addTime = ALT_TRICORDER_DELAY; //1000 + break; + case WP_3: + addTime = 0; //500 + break; + case WP_15: + addTime = 0; //1000 + break; +/* case WP_7: + addTime = 500; //RPG-X: RedTechie - Use to be 1200 + break;*/ + } + } + + if ( ps->powerups[PW_HASTE] ) { addTime /= 1.3; } - pm->ps->weaponTime += addTime; + ps->weaponTime += addTime; } /* @@ -1709,46 +3321,25 @@ static void PM_Weapon( void ) { PM_Animate ================ */ - static void PM_Animate( void ) { + playerState_t *ps = pm->ps; + if ( pm->cmd.buttons & BUTTON_GESTURE ) { - if ( pm->ps->torsoTimer == 0 ) { - PM_StartTorsoAnim( TORSO_GESTURE ); - pm->ps->torsoTimer = TIMER_GESTURE; - PM_AddEvent( EV_TAUNT ); + if (ps->pm_type < PM_DEAD ) { + //if ( ps->torsoTimer == 0 ) { + //PM_StartTorsoAnim( BOTH_CONSOLE1 ); + //PM_StartLegsAnim( BOTH_CONSOLE1 ); + //ps->introTime = ps->torsoTimer = 4000; //TIMER_GESTURE //legsTimer + //PM_AddEvent( EV_TAUNT ); + + if ( !( ps->eFlags & EF_TALKING ) ) { + ps->eFlags |= EF_TALKING; + } } -#ifdef MISSIONPACK - } else if ( pm->cmd.buttons & BUTTON_GETFLAG ) { - if ( pm->ps->torsoTimer == 0 ) { - PM_StartTorsoAnim( TORSO_GETFLAG ); - pm->ps->torsoTimer = 600; //TIMER_GESTURE; + } else { + if ( ( ps->eFlags & EF_TALKING ) ) { + ps->eFlags &= ~EF_TALKING; } - } else if ( pm->cmd.buttons & BUTTON_GUARDBASE ) { - if ( pm->ps->torsoTimer == 0 ) { - PM_StartTorsoAnim( TORSO_GUARDBASE ); - pm->ps->torsoTimer = 600; //TIMER_GESTURE; - } - } else if ( pm->cmd.buttons & BUTTON_PATROL ) { - if ( pm->ps->torsoTimer == 0 ) { - PM_StartTorsoAnim( TORSO_PATROL ); - pm->ps->torsoTimer = 600; //TIMER_GESTURE; - } - } else if ( pm->cmd.buttons & BUTTON_FOLLOWME ) { - if ( pm->ps->torsoTimer == 0 ) { - PM_StartTorsoAnim( TORSO_FOLLOWME ); - pm->ps->torsoTimer = 600; //TIMER_GESTURE; - } - } else if ( pm->cmd.buttons & BUTTON_AFFIRMATIVE ) { - if ( pm->ps->torsoTimer == 0 ) { - PM_StartTorsoAnim( TORSO_AFFIRMATIVE); - pm->ps->torsoTimer = 600; //TIMER_GESTURE; - } - } else if ( pm->cmd.buttons & BUTTON_NEGATIVE ) { - if ( pm->ps->torsoTimer == 0 ) { - PM_StartTorsoAnim( TORSO_NEGATIVE ); - pm->ps->torsoTimer = 600; //TIMER_GESTURE; - } -#endif } } @@ -1759,56 +3350,154 @@ PM_DropTimers ================ */ static void PM_DropTimers( void ) { + int newFlags; + playerState_t *ps = pm->ps; + // drop misc timing counter - if ( pm->ps->pm_time ) { - if ( pml.msec >= pm->ps->pm_time ) { - pm->ps->pm_flags &= ~PMF_ALL_TIMES; - pm->ps->pm_time = 0; - } else { - pm->ps->pm_time -= pml.msec; + if ( ps->pm_time ) { + if ( pml.msec >= ps->pm_time ) + { + ps->pm_flags &= ~PMF_ALL_TIMES; + ps->pm_time = 0; + } + else + { + ps->pm_time -= pml.msec; + } + } + + //Count down the legs anim timer + if ( ps->stats[LEGSTIMER] > 0 ) { //legsTimer + ps->stats[LEGSTIMER] -= pml.msec; + if ( ps->stats[LEGSTIMER] < 0 ) + { + ps->stats[LEGSTIMER] = 0; + } + } + + //if legs anim timer hit 0 + if ( ps->stats[LEGSTIMER] == 0 ) { + if ( (ps->stats[EMOTES] & EMOTE_LOWER ) && + !(ps->stats[EMOTES] & EMOTE_LOOP_LOWER ) ) + { + ps->stats[EMOTES] &= ~EMOTE_MASK_LOWER; + + if ( ps->legsAnim > 0 ) + { + PM_ForceLegsAnim( bg_emoteList[ps->legsAnim].enumName ); + + //TiM - Remove any data about torsos here. it's not necessary and it invalidates the check below + newFlags = ( bg_emoteList[ps->legsAnim].animFlags | bg_emoteList[ps->legsAnim].bodyFlags ); + newFlags &= ~EMOTE_MASK_UPPER; + ps->stats[EMOTES] |= newFlags; + //Com_Printf( S_COLOR_RED "Set anim to %i\n", ps->legsAnim ); + + ps->legsTimer = ps->legsAnim; + //ps->torsoTimer = emoteList[ps->torsoAnim].hitBoxHeight; + } + else + { + ps->legsTimer = 0; + ps->legsAnim = 0; + } + //Com_Printf(S_COLOR_RED "Acknowledge Lower change!!\n"); + } + } + + if ( ps->stats[TORSOTIMER] > 0 ) { //torsoTimer + ps->stats[TORSOTIMER] -= pml.msec; + if ( ps->stats[TORSOTIMER] < 0 ) + { + ps->stats[TORSOTIMER] = 0; + + /*if (ps->eFlags & EF_EMOTING ) { + ps->eFlags &= ~EF_EMOTING; + }*/ + } + } + + if ( ps->stats[TORSOTIMER] == 0 ) { + if ( (ps->stats[EMOTES] & EMOTE_UPPER) && + !(ps->stats[EMOTES] & EMOTE_LOOP_UPPER ) ) + { + ps->stats[EMOTES] &= ~EMOTE_MASK_UPPER; + + if ( ps->torsoAnim > 0 ) + { + PM_ForceTorsoAnim( bg_emoteList[ps->torsoAnim].enumName, qtrue ); + + //TiM - Remove any data about legs here. it's not necessary and it invalidates any subsequent checks + newFlags = ( bg_emoteList[ps->torsoAnim].animFlags | bg_emoteList[ps->torsoAnim].bodyFlags ); + newFlags &= ~EMOTE_MASK_LOWER; + ps->stats[EMOTES] |= newFlags; + //ps->stats[EMOTES] |= ( emoteList[ps->torsoAnim].animFlags | emoteList[ps->torsoAnim].bodyFlags ); + + } + else + { + ps->torsoTimer = 0; + ps->torsoAnim = 0; + } } } // drop animation counter - if ( pm->ps->legsTimer > 0 ) { - pm->ps->legsTimer -= pml.msec; - if ( pm->ps->legsTimer < 0 ) { - pm->ps->legsTimer = 0; +/* if ( ps->introTime > 0 ) { //legsTimer + ps->introTime -= pml.msec; + if ( ps->introTime < 0 ) { + ps->introTime = 0; + + if (ps->eFlags & EF_EMOTING ) { + ps->eFlags &= ~EF_EMOTING; + } } } - if ( pm->ps->torsoTimer > 0 ) { - pm->ps->torsoTimer -= pml.msec; - if ( pm->ps->torsoTimer < 0 ) { - pm->ps->torsoTimer = 0; + if ( ps->torsoTimer > 0 ) { + ps->torsoTimer -= pml.msec; + if ( ps->torsoTimer < 0 ) { + ps->torsoTimer = 0; } - } + }*/ } /* ================ PM_UpdateViewAngles - -This can be used as another entry point when only the viewangles -are being updated isntead of a full move ================ */ +/** +* This can be used as another entry point when only the viewangles +* are being updated isntead of a full move +*/ void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd ) { short temp; int i; - if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPINTERMISSION) { + if ( ps->pm_type == PM_INTERMISSION ) { return; // no view changes at all } - if ( ps->pm_type != PM_SPECTATOR && ps->stats[STAT_HEALTH] <= 0 ) { + if ( ps->pm_type == PM_CCAM) { + return; + } + + if ( ps->pm_type != PM_SPECTATOR && ps->stats[STAT_HEALTH] <= 1 ) { //RPG-X: RedTechie - This use to be 0 but in rpg-x with or without medics revive 1 health means you die! return; // no view changes at all } + + //TiM - Bookmark + //With a flag here, a change to the client side player rotation code there, + //we could actually make it EVA suit users could rotate fully in all directions + //when in space. :) + + //Com_Printf( "Before: %f %f %f\n", ps->viewangles[0], ps->viewangles[1], ps->viewangles[2]); + // circularly clamp the angles with deltas for (i=0 ; i<3 ; i++) { temp = cmd->angles[i] + ps->delta_angles[i]; - if ( i == PITCH ) { + if ( i == PITCH && !pm->ps->powerups[PW_FLIGHT] && !(( pm->ps->powerups[PW_EVOSUIT] ) && ( pm->ps->gravity == 0 )) ) { // don't let the player look up or down more than 90 degrees if ( temp > 16000 ) { ps->delta_angles[i] = 16000 - cmd->angles[i]; @@ -1818,9 +3507,9 @@ void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd ) { temp = -16000; } } + ps->viewangles[i] = SHORT2ANGLE(temp); } - } @@ -1830,11 +3519,12 @@ PmoveSingle ================ */ -void trap_SnapVector( float *v ); - void PmoveSingle (pmove_t *pmove) { + playerState_t *ps = pmove->ps; + pm = pmove; + // this counter lets us debug movement problems with a journal // by setting a conditional breakpoint fot the previous frame c_pmove++; @@ -1844,7 +3534,11 @@ void PmoveSingle (pmove_t *pmove) { pm->watertype = 0; pm->waterlevel = 0; - if ( pm->ps->stats[STAT_HEALTH] <= 0 ) { + //if(ps->legsTimer > 0 ) { + // Com_Printf("%i, %i\n", ps->legsTimer, ps->torsoTimer); + //} + + if ( ps->stats[STAT_HEALTH] <= 0 ) { pm->tracemask &= ~CONTENTS_BODY; // corpses can fly through bodies } @@ -1856,104 +3550,199 @@ void PmoveSingle (pmove_t *pmove) { // set the talk balloon flag if ( pm->cmd.buttons & BUTTON_TALK ) { - pm->ps->eFlags |= EF_TALK; + ps->eFlags |= EF_TALK; } else { - pm->ps->eFlags &= ~EF_TALK; + ps->eFlags &= ~EF_TALK; } // set the firing flag for continuous beam weapons - if ( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION && pm->ps->pm_type != PM_NOCLIP - && ( pm->cmd.buttons & BUTTON_ATTACK ) && pm->ps->ammo[ pm->ps->weapon ] ) { - pm->ps->eFlags |= EF_FIRING; - } else { - pm->ps->eFlags &= ~EF_FIRING; + if ( !(ps->pm_flags & PMF_RESPAWNED) && + ps->pm_type != PM_INTERMISSION && + ps->pm_type != PM_CCAM && + ( (pm->cmd.buttons & BUTTON_ATTACK) || (pm->cmd.buttons & BUTTON_ALT_ATTACK) ) && + (ps->ammo[ ps->weapon ] || ps->weapon == WP_5)) + { + if (((ps->weapon == WP_5) && (!ps->ammo[ ps->weapon ])) || (!(pm->cmd.buttons & BUTTON_ALT_ATTACK))) + { + ps->eFlags &= ~EF_ALT_FIRING; + } + else // if ( pm->cmd.buttons & BUTTON_ALT_ATTACK ) <-- implied + { + ps->eFlags |= EF_ALT_FIRING; + } + + /*if ( ps->weapon == WP_10 ) + {//tech can't use alt attack + pm->cmd.buttons &=~BUTTON_ALT_ATTACK; + pm->cmd.buttons |= BUTTON_ATTACK; + }*/ + //TiM - good riddance to bad coding + + // This flag should always get set, even when alt-firing + ps->eFlags |= EF_FIRING; + } + else + { + ps->eFlags &= ~EF_FIRING; + ps->eFlags &= ~EF_ALT_FIRING; } // clear the respawned flag if attack and use are cleared - if ( pm->ps->stats[STAT_HEALTH] > 0 && + if ( ps->stats[STAT_HEALTH] > 0 && !( pm->cmd.buttons & (BUTTON_ATTACK | BUTTON_USE_HOLDABLE) ) ) { - pm->ps->pm_flags &= ~PMF_RESPAWNED; + ps->pm_flags &= ~PMF_RESPAWNED; } // if talk button is down, dissallow all other input // this is to prevent any possible intercept proxy from // adding fake talk balloons - if ( pmove->cmd.buttons & BUTTON_TALK ) { - // keep the talk button set tho for when the cmd.serverTime > 66 msec - // and the same cmd is used multiple times in Pmove - pmove->cmd.buttons = BUTTON_TALK; + if ( pmove->cmd.buttons & BUTTON_TALK ) + { + pmove->cmd.buttons = 0; pmove->cmd.forwardmove = 0; pmove->cmd.rightmove = 0; - pmove->cmd.upmove = 0; + if (pmove->cmd.upmove) + { + if (pmove->cmd.upmove > 0) + { + pmove->cmd.upmove = 1; + } + else + { + pmove->cmd.upmove = -1;//allow a tiny bit to keep the duck anim + } + } } + //ph34r teh cheezy hack + //Disable the ability to jump when getting up animating. + //This is for the purporse of the medics revive animation + if ( ( ps->stats[LEGSANIM] & ~ANIM_TOGGLEBIT ) == BOTH_GET_UP1 ) { + pm->cmd.upmove = 0; + } + + //If the legs are playing a non infinite loop, disable the movement keys. + //Else the player slides on their feet :S + if ( (ps->stats[EMOTES] & EMOTE_LOWER &&( ps->stats[EMOTES] & EMOTE_CLAMP_BODY )) || ( ps->stats[EMOTES] & EMOTE_CLAMP_ALL ) ) { //EMOTE_LOWER + pmove->cmd.forwardmove = 0; + pmove->cmd.rightmove = 0; + //pmove->cmd.upmove = Q_fabs( pmove->cmd.upmove ); + } + + if ( ps->stats[EMOTES] & ( EMOTE_LOWER | EMOTE_UPPER ) ) { + if (pmove->cmd.buttons & MASK_KILL_EMOTES || pmove->cmd.upmove != 0 ) { + ps->stats[EMOTES] &= ~EMOTE_MASK_BOTH; + + ps->legsTimer = 0; + ps->stats[LEGSTIMER] = 0; + } + } + + //TiM: Injured system + //Disable the ability to toggle walking, + //and slow player down. :) + if ( ps->stats[STAT_HEALTH] <= INJURED_MODE_HEALTH ) { + pm->cmd.buttons &= ~BUTTON_WALKING; + } + + //TiM : Override for looping animation emotes + //If player touches move keys, cancel emotes + /*if ( pmove->cmd.upmove || pmove->cmd.rightmove || pmove->cmd.forwardmove || ( pmove->cmd.buttons & MASK_KILL_EMOTES ) ) { + //if ( ( ps->pm_flags & ANIM_LOWER_LOOPING ) || ( ps->pm_flags & ANIM_UPPER_LOOPING ) ) { + if ( ps->stats[EMOTES] & EMOTE_LOWER || ps->stats[EMOTES] & EMOTE_UPPER ) { + ps->stats[EMOTES] &= ~EMOTE_MASK_BOTH; + + ps->legsTimer = -1; + //ps->torsoTimer = 0; + } + }*/ + // clear all pmove local vars memset (&pml, 0, sizeof(pml)); // determine the time - pml.msec = pmove->cmd.serverTime - pm->ps->commandTime; + pml.msec = pmove->cmd.serverTime - ps->commandTime; if ( pml.msec < 1 ) { pml.msec = 1; } else if ( pml.msec > 200 ) { pml.msec = 200; } - pm->ps->commandTime = pmove->cmd.serverTime; + ps->commandTime = pmove->cmd.serverTime; // save old org in case we get stuck - VectorCopy (pm->ps->origin, pml.previous_origin); + VectorCopy (ps->origin, pml.previous_origin); // save old velocity for crashlanding - VectorCopy (pm->ps->velocity, pml.previous_velocity); + VectorCopy (ps->velocity, pml.previous_velocity); pml.frametime = pml.msec * 0.001; - // update the viewangles - PM_UpdateViewAngles( pm->ps, &pm->cmd ); + if (ps->pm_type == PM_FREEZE /*|| ps->introTime > pm->cmd.serverTime*/ ) + { + PM_FreezeMove(); + return; // no movement at all + } - AngleVectors (pm->ps->viewangles, pml.forward, pml.right, pml.up); + // update the viewangles + PM_UpdateViewAngles( ps, &pm->cmd ); + + AngleVectors (ps->viewangles, pml.forward, pml.right, pml.up); if ( pm->cmd.upmove < 10 ) { // not holding jump - pm->ps->pm_flags &= ~PMF_JUMP_HELD; + ps->pm_flags &= ~PMF_JUMP_HELD; } // decide if backpedaling animations should be used if ( pm->cmd.forwardmove < 0 ) { - pm->ps->pm_flags |= PMF_BACKWARDS_RUN; + ps->pm_flags |= PMF_BACKWARDS_RUN; } else if ( pm->cmd.forwardmove > 0 || ( pm->cmd.forwardmove == 0 && pm->cmd.rightmove ) ) { - pm->ps->pm_flags &= ~PMF_BACKWARDS_RUN; + ps->pm_flags &= ~PMF_BACKWARDS_RUN; } - if ( pm->ps->pm_type >= PM_DEAD ) { + if ( ps->pm_type >= PM_DEAD ) { pm->cmd.forwardmove = 0; pm->cmd.rightmove = 0; pm->cmd.upmove = 0; } - if ( pm->ps->pm_type == PM_SPECTATOR ) { + + if ( ps->pm_type == PM_SPECTATOR ) { PM_CheckDuck (); PM_FlyMove (); PM_DropTimers (); return; } + - if ( pm->ps->pm_type == PM_NOCLIP ) { + if ( ps->pm_type == PM_SPECTATOR ) + { + PM_CheckDuck (); + PM_FlyMove(); + PM_DropTimers (); + return; + } + + if ( ps->pm_type == PM_NOCLIP ) { PM_NoclipMove (); PM_DropTimers (); return; } - if (pm->ps->pm_type == PM_FREEZE) { - return; // no movement at all + if ( ps->pm_type == PM_CCAM) { + return; } - if ( pm->ps->pm_type == PM_INTERMISSION || pm->ps->pm_type == PM_SPINTERMISSION) { + if ( ps->pm_type == PM_INTERMISSION ) { return; // no movement at all } // set watertype, and waterlevel PM_SetWaterLevel(); - pml.previous_waterlevel = pmove->waterlevel; + if ( !(pm->watertype & CONTENTS_LADDER) ) + {//Don't want to remember this for ladders, is only for waterlevel change events (sounds) + pml.previous_waterlevel = pmove->waterlevel; + } // set mins, maxs, and viewheight PM_CheckDuck (); @@ -1961,25 +3750,18 @@ void PmoveSingle (pmove_t *pmove) { // set groundentity PM_GroundTrace(); - if ( pm->ps->pm_type == PM_DEAD ) { + if ( ps->pm_type == PM_DEAD ) { PM_DeadMove (); } - PM_DropTimers(); - -#ifdef MISSIONPACK - if ( pm->ps->powerups[PW_INVULNERABILITY] ) { - PM_InvulnerabilityMove(); - } else -#endif - if ( pm->ps->powerups[PW_FLIGHT] ) { + if ( ps->powerups[PW_FLIGHT] ) { // flight powerup doesn't allow jump and has different friction PM_FlyMove(); - } else if (pm->ps->pm_flags & PMF_GRAPPLE_PULL) { - PM_GrappleMove(); - // We can wiggle a bit - PM_AirMove(); - } else if (pm->ps->pm_flags & PMF_TIME_WATERJUMP) { + } else if ((( ps->powerups[PW_EVOSUIT] ) && ( ps->gravity == 0 ))) { + //RPG-X | Phenix | 8/8/2004 + //The player is in 0 G and is wearing an evo suit... + PM_FlyMove(); + } else if (ps->pm_flags & PMF_TIME_WATERJUMP) { PM_WaterJumpMove(); } else if ( pm->waterlevel > 1 ) { // swimming @@ -2001,6 +3783,8 @@ void PmoveSingle (pmove_t *pmove) { // weapons PM_Weapon(); + PM_Use(); + // torso animation PM_TorsoAnimation(); @@ -2010,18 +3794,23 @@ void PmoveSingle (pmove_t *pmove) { // entering / leaving water splashes PM_WaterEvents(); + //PM_DoEmote(); + + PM_DropTimers(); + // snap some parts of playerstate to save network bandwidth - trap_SnapVector( pm->ps->velocity ); + SnapVector( ps->velocity ); } /* ================ Pmove - -Can be called by either the server or the client ================ */ +/** +* Can be called by either the server or the client +*/ void Pmove (pmove_t *pmove) { int finalTime; @@ -2035,8 +3824,6 @@ void Pmove (pmove_t *pmove) { pmove->ps->commandTime = finalTime - 1000; } - pmove->ps->pmove_framecount = (pmove->ps->pmove_framecount+1) & ((1<ps->commandTime != finalTime ) { @@ -2044,25 +3831,11 @@ void Pmove (pmove_t *pmove) { msec = finalTime - pmove->ps->commandTime; - if ( pmove->pmove_fixed ) { - if ( msec > pmove->pmove_msec ) { - msec = pmove->pmove_msec; - } - } - else { - if ( msec > 66 ) { - msec = 66; - } + if ( msec > 66 ) { + msec = 66; } pmove->cmd.serverTime = pmove->ps->commandTime + msec; PmoveSingle( pmove ); - - if ( pmove->ps->pm_flags & PMF_JUMP_HELD ) { - pmove->cmd.upmove = 20; - } } - //PM_CheckStuck(); - } - diff --git a/code/game/bg_public.h b/code/game/bg_public.h index 60f3a6e..0cfaae1 100644 --- a/code/game/bg_public.h +++ b/code/game/bg_public.h @@ -1,116 +1,230 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ +// Copyright (C) 1999-2000 Id Software, Inc. // // bg_public.h -- definitions shared by both the server game and client game modules +// meh somehow preprocessor G_LUA won't work for me +#define G_LUA 1 +#define CG_LUA 1 + // because games can change separately from the main system version, we need a // second version that must match between game and cgame +#define RPGX_VERSION "RPG-X v2.2 wc18072012" +#define RPGX_COMPILEDATE "20/05/11" +#define RPGX_COMPILEDBY "GSIO01" +//const char GAME_VERSION[] = strcat("RPG-X v",RPGX_VERSION); +//ehem why not: +#define GAME_VERSION "RPG-X v" RPGX_VERSION -#define GAME_VERSION BASEGAME "-1" +#define INJURED_MODE_HEALTH 20 //! MAX_CONFIGSTRINGS #error overflow: (CS_MAX) > MAX_CONFIGSTRINGS #endif typedef enum { - GT_FFA, // free for all - GT_TOURNAMENT, // one on one tournament - GT_SINGLE_PLAYER, // single player ffa + GT_FFA, //!< free for all + GT_TOURNAMENT, //!< one on one tournament + GT_SINGLE_PLAYER, //!< single player tournament //-- team games go after this -- - GT_TEAM, // team deathmatch - GT_CTF, // capture the flag - GT_1FCTF, - GT_OBELISK, - GT_HARVESTER, + GT_TEAM, //!< team deathmatch + GT_CTF, //!< capture the flag + GT_MAX_GAME_TYPE } gametype_t; typedef enum { GENDER_MALE, GENDER_FEMALE, GENDER_NEUTER } gender_t; +//TiM - Global variables for the player weight/height system +#define BASE_HEIGHT 185.0 +#define BASE_WEIGHT 90.0 + +#define FEMALE_OFFSET 0.73 + +#define MAX_HEIGHT 1.15 +#define MIN_HEIGHT 0.9 + +#define MAX_WEIGHT 1.1 +#define MIN_WEIGHT 0.9 + +#define HEIGHT_UNIT "cm" +#define WEIGHT_UNIT "kg" + /* =================================================================================== @@ -122,214 +236,432 @@ movement on the server game. =================================================================================== */ +//RPG-X - Player Model System. Anim on or off states +/*typedef enum { + ANIM_ONLADDER, + ANIM_OFFLADDER, + ANIM_DIDFLY +} animtype_t;*/ + +/** \enum pmtype_t +* +*/ typedef enum { - PM_NORMAL, // can accelerate and turn - PM_NOCLIP, // noclip movement - PM_SPECTATOR, // still run into walls - PM_DEAD, // no acceleration or turning, but free falling - PM_FREEZE, // stuck in place with no control - PM_INTERMISSION, // no movement or status bar - PM_SPINTERMISSION // no movement or status bar + PM_NORMAL, //!< can accelerate and turn + PM_NOCLIP, //!< noclip movement + PM_SPECTATOR, //!< still run into walls + PM_DEAD, //!< no acceleration or turning, but free falling + PM_FREEZE, //!< stuck in place with no control + PM_INTERMISSION,//!< no movement or status bar + PM_CCAM //!< cinematic cam mode } pmtype_t; +/** \enum weaponstate_t +* +*/ typedef enum { - WEAPON_READY, + WEAPON_READY, WEAPON_RAISING, WEAPON_DROPPING, WEAPON_FIRING } weaponstate_t; // pmove->pm_flags -#define PMF_DUCKED 1 -#define PMF_JUMP_HELD 2 -#define PMF_BACKWARDS_JUMP 8 // go into backwards land -#define PMF_BACKWARDS_RUN 16 // coast down to backwards run -#define PMF_TIME_LAND 32 // pm_time is time before rejump -#define PMF_TIME_KNOCKBACK 64 // pm_time is an air-accelerate only time -#define PMF_TIME_WATERJUMP 256 // pm_time is waterjump -#define PMF_RESPAWNED 512 // clear after attack and jump buttons come up + +#define PMF_DUCKED 1 //1 //2 +#define PMF_JUMP_HELD 2 //2 //4 +#define PMF_BACKWARDS_JUMP 8 //!< go into backwards land +#define PMF_BACKWARDS_RUN 16 //!< coast down to backwards run +#define PMF_TIME_LAND 32 //!< pm_time is time before rejump +#define PMF_TIME_KNOCKBACK 64 //!< pm_time is an air-accelerate only time +#define PMF_TIME_WATERJUMP 256 //!< pm_time is waterjump +#define PMF_RESPAWNED 512 //!< clear after attack and jump buttons come up #define PMF_USE_ITEM_HELD 1024 -#define PMF_GRAPPLE_PULL 2048 // pull towards grapple location -#define PMF_FOLLOW 4096 // spectate following another player -#define PMF_SCOREBOARD 8192 // spectate as a scoreboard -#define PMF_INVULEXPAND 16384 // invulnerability sphere set to full size +//#define PMF_GRAPPLE_PULL 2048 //!< pull towards grapple location +#define PMF_FOLLOW 4096 //!< spectate following another player +#define PMF_SCOREBOARD 8192 //!< spectate as a scoreboard + +#define ANIM_ONLADDER 16384 +#define ANIM_DIDFLY 32768 +#define ANIM_ALERT 128 //TiM: How was this missed!? +#define ANIM_ALERT2 2048 //TiM: This makes it full I think +//#define ANIM_LOWER_LOOPING 2048 #define PMF_ALL_TIMES (PMF_TIME_WATERJUMP|PMF_TIME_LAND|PMF_TIME_KNOCKBACK) #define MAXTOUCH 32 + +/** +* \struct pmove_t +*/ typedef struct { // state (in / out) playerState_t *ps; // command (in) usercmd_t cmd; - int tracemask; // collide against these types of surfaces - int debugLevel; // if set, diagnostic output will be printed - qboolean noFootsteps; // if the game is setup for no footsteps by the server - qboolean gauntletHit; // true if a gauntlet attack would actually hit something - - int framecount; + int tracemask; //!< collide against these types of surfaces + int debugLevel; //!< if set, diagnostic output will be printed + qboolean noFootsteps; //!< if the game is setup for no footsteps by the server + qboolean pModDisintegration; //!< true if the Disintegration playerMod is on // results (out) int numtouch; int touchents[MAXTOUCH]; - vec3_t mins, maxs; // bounding box size + int useEvent; + + vec3_t mins, maxs; //!< bounding box size int watertype; int waterlevel; float xyspeed; + float xyzspeed; //TiM : in case body is falling as well - // for fixed msec Pmove - int pmove_fixed; - int pmove_msec; + qboolean admin; + qboolean medic; + qboolean borg; + + //RPG-X - J2J - Adding a last fire timer for weapon animations + ///int LastFireTime; // callbacks to test the world // these will be different functions during game and cgame void (*trace)( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentMask ); int (*pointcontents)( const vec3_t point, int passEntityNum ); + } pmove_t; // if a full pmove isn't done on the client, you can just update the angles void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd ); void Pmove (pmove_t *pmove); +//RPG-X: J2J - Emote Vars (shared for server and client) +//int CurrentEmote[MAX_CLIENTS]; +//QVM HACK! + //=================================================================================== // player_state->stats[] indexes -// NOTE: may not have more than 16 +// +// maximum of MAX_STATS...currently 16 +//TiM: Ooohhh! Usable space! +/** \enum statIndex_t +* Each of these array cells can store data up to 2^16 bits of data! +* This is good in the fact that we are capable of using this place to store data +* that is larger for its previous cells, for example, animation data. +*/ typedef enum { STAT_HEALTH, STAT_HOLDABLE_ITEM, -#ifdef MISSIONPACK - STAT_PERSISTANT_POWERUP, -#endif - STAT_WEAPONS, // 16 bit fields - STAT_ARMOR, - STAT_DEAD_YAW, // look this direction when dead (FIXME: get rid of?) - STAT_CLIENTS_READY, // bit mask of clients wishing to exit the intermission (FIXME: configstring?) - STAT_MAX_HEALTH // health / armor limit, changable by handicap + STAT_WEAPONS, //!< 16 bit fields + STAT_ARMOR, + STAT_DEAD_YAW, //!< look this direction when dead (FIXME: get rid of?) + STAT_CLIENTS_READY, //!< bit mask of clients wishing to exit the intermission (FIXME: configstring?) + STAT_MAX_HEALTH, //!< health / armor limit, changable by handicap + STAT_USEABLE_PLACED, //!< have we placed the detpack yet? + + //TiM : Placeholder for emotes data and anim holding + TORSOTIMER, //!