diff --git a/Projects/Android/android.debug.keystore b/Projects/Android/android.debug.keystore new file mode 100644 index 0000000..cdc70bf Binary files /dev/null and b/Projects/Android/android.debug.keystore differ diff --git a/Projects/Android/jni/Application.mk b/Projects/Android/jni/Application.mk index 10b9bd3..823b506 100644 --- a/Projects/Android/jni/Application.mk +++ b/Projects/Android/jni/Application.mk @@ -12,12 +12,12 @@ APPLICATIONMK_PATH = $(call my-dir) TOP_DIR := $(APPLICATIONMK_PATH) GL4ES_PATH := $(TOP_DIR)/SupportLibs/gl4es -OPENJK_PATH := $(TOP_DIR)/OpenJK -MPDir := $(OPENJK_PATH)/MPDir +OPENJK_PATH := $(TOP_DIR)/OpenJK +SPDir := $(OPENJK_PATH)/code APP_ALLOW_MISSING_DEPS=true -APP_MODULES := gl4es rd-gles_arm jampgamearm uiarm cgamearm jk3mp +APP_MODULES := gl4es rd-gles_arm jagamearm uiarm cgamearm openjk_sp APP_STL := c++_shared diff --git a/Projects/Android/jni/OpenJK/Android.mk b/Projects/Android/jni/OpenJK/Android.mk index d983e93..6ec46a5 100644 --- a/Projects/Android/jni/OpenJK/Android.mk +++ b/Projects/Android/jni/OpenJK/Android.mk @@ -1,5 +1,5 @@ LOCAL_PATH := $(call my-dir) -MPDir = codemp +SPDir = codemp JK3_BASE_CFLAGS = -O1 -DHAVE_GLES -DFINAL_BUILD -DARCH_STRING=arm -fexceptions -Wall -Wno-write-strings -Wno-comment -fno-caller-saves -fno-tree-vectorize -Wno-unused-but-set-variable @@ -11,8 +11,8 @@ JK3_BASE_LDLIBS = JK3_BASE_CFLAGS += -mfloat-abi=softfp JK3_BASE_LDLIBS += -Wl -JK3_BASE_C_INCLUDES := $(LOCAL_PATH)/lib $(TOP_DIR)/../../Serial/jni $(TOP_DIR)/SDL2/include $(TOP_DIR)/openal/include $(LOCAL_PATH)/$(MPDir)/client $(LOCAL_PATH)/$(MPDir)/qclib $(LOCAL_PATH)/$(MPDir)/botlib $(LOCAL_PATH)/$(MPDir)/d3d $(LOCAL_PATH)/$(MPDir)/server $(LOCAL_PATH)/$(MPDir)/sw $(LOCAL_PATH)/$(MPDir)/libs/freetype2/include $(LOCAL_PATH)/$(MPDir)/common $(LOCAL_PATH)/$(MPDir)/gl -JK3_BASE_C_INCLUDES += $(LOCAL_PATH)/$(MPDir)/ +JK3_BASE_C_INCLUDES := $(LOCAL_PATH)/lib $(LOCAL_PATH)/$(SPDir)/client $(LOCAL_PATH)/$(SPDir)/qclib $(LOCAL_PATH)/$(SPDir)/botlib $(LOCAL_PATH)/$(SPDir)/d3d $(LOCAL_PATH)/$(SPDir)/server $(LOCAL_PATH)/$(SPDir)/sw $(LOCAL_PATH)/$(SPDir)/libs/freetype2/include $(LOCAL_PATH)/$(SPDir)/common $(LOCAL_PATH)/$(SPDir)/gl +JK3_BASE_C_INCLUDES += $(LOCAL_PATH)/$(SPDir)/ $(OPENJK_PATH)/code/ $(OPENJK_PATH)/shared/ include $(OPENJK_PATH)/Android_client.mk include $(OPENJK_PATH)/Android_game.mk diff --git a/Projects/Android/jni/OpenJK/Android_cgame.mk b/Projects/Android/jni/OpenJK/Android_cgame.mk index ff24a27..304ae8d 100644 --- a/Projects/Android/jni/OpenJK/Android_cgame.mk +++ b/Projects/Android/jni/OpenJK/Android_cgame.mk @@ -18,60 +18,61 @@ LOCAL_LDLIBS += -llog -lz #LOCAL_STATIC_LIBRARIES := lz #LOCAL_SHARED_LIBRARIES := lz -LOCAL_C_INCLUDES := $(JK3_BASE_C_INCLUDES) $(TOP_DIR) $(GL4ES_PATH) $(GL4ES_PATH)/include $(TOP_DIR)/SupportLibs/openal/include $(TOP_DIR)/jk2/shared +LOCAL_C_INCLUDES := $(JK3_BASE_C_INCLUDES) $(TOP_DIR) $(GL4ES_PATH) $(GL4ES_PATH)/include $(TOP_DIR)/SupportLibs/openal/include JK3_SRC = \ - ${MPDir}/game/AnimalNPC.c \ - ${MPDir}/game/bg_g2_utils.c \ - ${MPDir}/game/bg_misc.c \ - ${MPDir}/game/bg_panimate.c \ - ${MPDir}/game/bg_pmove.c \ - ${MPDir}/game/bg_saber.c \ - ${MPDir}/game/bg_saberLoad.c \ - ${MPDir}/game/bg_saga.c \ - ${MPDir}/game/bg_slidemove.c \ - ${MPDir}/game/bg_vehicleLoad.c \ - ${MPDir}/game/bg_weapons.c \ - ${MPDir}/game/FighterNPC.c \ - ${MPDir}/game/SpeederNPC.c \ - ${MPDir}/game/WalkerNPC.c \ - ${MPDir}/cgame/cg_consolecmds.c \ - ${MPDir}/cgame/cg_cvar.c \ - ${MPDir}/cgame/cg_draw.c \ - ${MPDir}/cgame/cg_drawtools.c \ - ${MPDir}/cgame/cg_effects.c \ - ${MPDir}/cgame/cg_ents.c \ - ${MPDir}/cgame/cg_event.c \ - ${MPDir}/cgame/cg_info.c \ - ${MPDir}/cgame/cg_light.c \ - ${MPDir}/cgame/cg_localents.c \ - ${MPDir}/cgame/cg_main.c \ - ${MPDir}/cgame/cg_marks.c \ - ${MPDir}/cgame/cg_newDraw.c \ - ${MPDir}/cgame/cg_players.c \ - ${MPDir}/cgame/cg_playerstate.c \ - ${MPDir}/cgame/cg_predict.c \ - ${MPDir}/cgame/cg_saga.c \ - ${MPDir}/cgame/cg_scoreboard.c \ - ${MPDir}/cgame/cg_servercmds.c \ - ${MPDir}/cgame/cg_snapshot.c \ - ${MPDir}/cgame/cg_spawn.c \ - ${MPDir}/cgame/cg_syscalls.c \ - ${MPDir}/cgame/cg_turret.c \ - ${MPDir}/cgame/cg_view.c \ - ${MPDir}/cgame/cg_weaponinit.c \ - ${MPDir}/cgame/cg_weapons.c \ - ${MPDir}/cgame/fx_blaster.c \ - ${MPDir}/cgame/fx_bowcaster.c \ - ${MPDir}/cgame/fx_bryarpistol.c \ - ${MPDir}/cgame/fx_demp2.c \ - ${MPDir}/cgame/fx_disruptor.c \ - ${MPDir}/cgame/fx_flechette.c \ - ${MPDir}/cgame/fx_force.c \ - ${MPDir}/cgame/fx_heavyrepeater.c \ - ${MPDir}/cgame/fx_rocketlauncher.c \ - ${MPDir}/ui/ui_shared.c \ - ${MPDir}/qcommon/q_shared.c \ + ${SPDir}/game/bg_misc.cpp \ + ${SPDir}/game/bg_panimate.cpp \ + ${SPDir}/game/bg_pmove.cpp \ + ${SPDir}/game/bg_slidemove.cpp \ + ${SPDir}/game/bg_vehicleLoad.cpp \ + ${SPDir}/game/FighterNPC.cpp \ + ${SPDir}/game/SpeederNPC.cpp \ + ${SPDir}/game/WalkerNPC.cpp \ + ${SPDir}/cgame/cg_camera.cpp \ + ${SPDir}/cgame/cg_consolecmds.cpp \ + ${SPDir}/cgame/cg_credits.cpp \ + ${SPDir}/cgame/cg_draw.cpp \ + ${SPDir}/cgame/cg_drawtools.cpp \ + ${SPDir}/cgame/cg_effects.cpp \ + ${SPDir}/cgame/cg_ents.cpp \ + ${SPDir}/cgame/cg_event.cpp \ + ${SPDir}/cgame/cg_headers.cpp \ + ${SPDir}/cgame/cg_info.cpp \ + ${SPDir}/cgame/cg_lights.cpp \ + ${SPDir}/cgame/cg_localents.cpp \ + ${SPDir}/cgame/cg_main.cpp \ + ${SPDir}/cgame/cg_marks.cpp \ + ${SPDir}/cgame/cg_players.cpp \ + ${SPDir}/cgame/cg_playerstate.cpp \ + ${SPDir}/cgame/cg_predict.cpp \ + ${SPDir}/cgame/cg_scoreboard.cpp \ + ${SPDir}/cgame/cg_servercmds.cpp \ + ${SPDir}/cgame/cg_snapshot.cpp \ + ${SPDir}/cgame/cg_syscalls.cpp \ + ${SPDir}/cgame/cg_text.cpp \ + ${SPDir}/cgame/cg_view.cpp \ + ${SPDir}/cgame/cg_weapons.cpp \ + ${SPDir}/cgame/FxPrimitives.cpp \ + ${SPDir}/cgame/FxScheduler.cpp \ + ${SPDir}/cgame/FxSystem.cpp \ + ${SPDir}/cgame/FxTemplate.cpp \ + ${SPDir}/cgame/FxUtil.cpp \ + ${SPDir}/cgame/FX_ATSTMain.cpp \ + ${SPDir}/cgame/FX_Blaster.cpp \ + ${SPDir}/cgame/FX_Bowcaster.cpp \ + ${SPDir}/cgame/FX_BryarPistol.cpp \ + ${SPDir}/cgame/FX_Concussion.cpp \ + ${SPDir}/cgame/FX_DEMP2.cpp \ + ${SPDir}/cgame/FX_Disruptor.cpp \ + ${SPDir}/cgame/FX_Emplaced.cpp \ + ${SPDir}/cgame/FX_Flechette.cpp \ + ${SPDir}/cgame/FX_HeavyRepeater.cpp \ + ${SPDir}/cgame/FX_NoghriShot.cpp \ + ${SPDir}/cgame/FX_RocketLauncher.cpp \ + ${SPDir}/cgame/FX_TuskenShot.cpp \ + ${SPDir}/ui/ui_shared.cpp \ + ${SPDir}/qcommon/q_shared.cpp \ ${OPENJK_PATH}/shared/qcommon/q_math.c \ ${OPENJK_PATH}/shared/qcommon/q_color.c \ ${OPENJK_PATH}/shared/qcommon/q_string.c \ diff --git a/Projects/Android/jni/OpenJK/Android_client.mk b/Projects/Android/jni/OpenJK/Android_client.mk index 2d6e5cb..2e08cb4 100644 --- a/Projects/Android/jni/OpenJK/Android_client.mk +++ b/Projects/Android/jni/OpenJK/Android_client.mk @@ -5,7 +5,7 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_MODULE := jk3mp +LOCAL_MODULE := openjk_sp LOCAL_CFLAGS := $(JK3_BASE_CFLAGS) @@ -22,11 +22,11 @@ LOCAL_LDLIBS += -fuse-ld=bfd #Hacky hack hack # LOCAL_LDLIBS += -L$(TOP_DIR)/openssl/libs/ -lcrypto -LOCAL_STATIC_LIBRARIES := sigc libzip libpng +LOCAL_STATIC_LIBRARIES := sigc libzip libpng libminizip LOCAL_SHARED_LIBRARIES := openal vrapi -LOCAL_C_INCLUDES := $(JK3_BASE_C_INCLUDES) $(TOP_DIR) $(GL4ES_PATH) $(GL4ES_PATH)/include $(TOP_DIR)/SupportLibs/openal/include $(JK2_PATH)/shared +LOCAL_C_INCLUDES := $(JK3_BASE_C_INCLUDES) $(TOP_DIR) $(GL4ES_PATH) $(GL4ES_PATH)/include $(TOP_DIR)/SupportLibs/openal/include $(TOP_DIR)/SupportLibs/minizip/include ############################################################################# @@ -34,169 +34,169 @@ LOCAL_C_INCLUDES := $(JK3_BASE_C_INCLUDES) $(TOP_DIR) $(GL4ES_PATH) $(GL4ES_PAT ############################################################################# -# ${MPDir}/qcommon/cm_draw.cpp \ -# ${MPDir}/qcommon/cm_randomterrain.cpp \ -# ${MPDir}/qcommon/cm_terrain.cpp \ -# ${MPDir}/qcommon/cm_shader.cpp \ +# ${SPDir}/qcommon/cm_draw.cpp \ +# ${SPDir}/qcommon/cm_randomterrain.cpp \ +# ${SPDir}/qcommon/cm_terrain.cpp \ +# ${SPDir}/qcommon/cm_shader.cpp \ # \ -# ${MPDir}/RMG/RM_Area.cpp \ -# ${MPDir}/RMG/RM_Instance.cpp \ -# ${MPDir}/RMG/RM_Instance_BSP.cpp \ -# ${MPDir}/RMG/RM_Instance_Group.cpp \ -# ${MPDir}/RMG/RM_Instance_Random.cpp \ -# ${MPDir}/RMG/RM_Instance_Void.cpp \ -# ${MPDir}/RMG/RM_InstanceFile.cpp \ -# ${MPDir}/RMG/RM_Manager.cpp \ -# ${MPDir}/RMG/RM_Mission.cpp \ -# ${MPDir}/RMG/RM_Objective.cpp \ -# ${MPDir}/RMG/RM_Path.cpp \ -# ${MPDir}/RMG/RM_Terrain.cpp \ +# ${SPDir}/RMG/RM_Area.cpp \ +# ${SPDir}/RMG/RM_Instance.cpp \ +# ${SPDir}/RMG/RM_Instance_BSP.cpp \ +# ${SPDir}/RMG/RM_Instance_Group.cpp \ +# ${SPDir}/RMG/RM_Instance_Random.cpp \ +# ${SPDir}/RMG/RM_Instance_Void.cpp \ +# ${SPDir}/RMG/RM_InstanceFile.cpp \ +# ${SPDir}/RMG/RM_Manager.cpp \ +# ${SPDir}/RMG/RM_Mission.cpp \ +# ${SPDir}/RMG/RM_Objective.cpp \ +# ${SPDir}/RMG/RM_Path.cpp \ +# ${SPDir}/RMG/RM_Terrain.cpp \ # \ -# ${MPDir}/qcommon/unzip.cpp \ +# ${SPDir}/qcommon/unzip.cpp \ # \ -# ${MPDir}/sys/snapvector.cpp \ +# ${SPDir}/sys/snapvector.cpp \ # \ -# ${MPDir}/qcommon/hstring.cpp \ -# ${MPDir}/qcommon/cm_terrainmap.cpp \ -# ${MPDir}/qcommon/CNetProfile.cpp \ -# ${MPDir}/qcommon/exe_headers.cpp \ +# ${SPDir}/qcommon/hstring.cpp \ +# ${SPDir}/qcommon/cm_terrainmap.cpp \ +# ${SPDir}/qcommon/CNetProfile.cpp \ +# ${SPDir}/qcommon/exe_headers.cpp \ # \ # lib/zlib/ioapi.c \ # \ -# ${MPDir}/sdl/sdl_input.cpp \ -# ${MPDir}/sdl/sdl_snd.cpp \ -# ${MPDir}/sys/sys_unix.cpp \ +# ${SPDir}/sdl/sdl_input.cpp \ +# ${SPDir}/sdl/sdl_snd.cpp \ +# ${SPDir}/sys/sys_unix.cpp \ +# ${SPDir}/qcommon/vm.cpp \ JK3_SRC = \ - ${MPDir}/android/in_android.cpp \ - ${MPDir}/android/android_main.cpp \ + ${SPDir}/android/in_android.cpp \ + ${SPDir}/android/android_main.cpp \ \ - ${MPDir}/qcommon/cm_load.cpp \ - ${MPDir}/qcommon/cm_patch.cpp \ - ${MPDir}/qcommon/cm_polylib.cpp \ - ${MPDir}/qcommon/cm_test.cpp \ - ${MPDir}/qcommon/cm_trace.cpp \ - ${MPDir}/qcommon/cmd.cpp \ - ${MPDir}/qcommon/common.cpp \ - ${MPDir}/qcommon/cvar.cpp \ - ${MPDir}/qcommon/files.cpp \ - ${MPDir}/qcommon/GenericParser2.cpp \ - ${MPDir}/qcommon/huffman.cpp \ - ${MPDir}/qcommon/md4.cpp \ - ${MPDir}/qcommon/md5.cpp \ - ${MPDir}/qcommon/msg.cpp \ - ${MPDir}/qcommon/matcomp.cpp \ - ${MPDir}/qcommon/net_chan.cpp \ - ${MPDir}/qcommon/net_ip.cpp \ - ${MPDir}/qcommon/persistence.cpp \ + ${SPDir}/qcommon/cm_load.cpp \ + ${SPDir}/qcommon/cm_patch.cpp \ + ${SPDir}/qcommon/cm_polylib.cpp \ + ${SPDir}/qcommon/cm_test.cpp \ + ${SPDir}/qcommon/cm_trace.cpp \ + ${SPDir}/qcommon/cmd.cpp \ + ${SPDir}/qcommon/common.cpp \ + ${SPDir}/qcommon/cvar.cpp \ + ${SPDir}/qcommon/files.cpp \ + ${SPDir}/qcommon/GenericParser2.cpp \ + ${SPDir}/qcommon/huffman.cpp \ + ${SPDir}/qcommon/md4.cpp \ + ${SPDir}/qcommon/md5.cpp \ + ${SPDir}/qcommon/msg.cpp \ + ${SPDir}/qcommon/matcomp.cpp \ + ${SPDir}/qcommon/net_chan.cpp \ + ${SPDir}/qcommon/net_ip.cpp \ + ${SPDir}/qcommon/persistence.cpp \ ${OPENJK_PATH}/shared/qcommon/q_math.c \ - ${MPDir}/qcommon/q_shared.cpp \ - ${MPDir}/qcommon/RoffSystem.cpp \ - ${MPDir}/qcommon/stringed_ingame.cpp \ - ${MPDir}/qcommon/stringed_interface.cpp \ - ${MPDir}/qcommon/vm.cpp \ - ${MPDir}/qcommon/z_memman_pc.cpp \ + ${SPDir}/qcommon/q_shared.cpp \ + ${SPDir}/qcommon/RoffSystem.cpp \ + ${SPDir}/qcommon/stringed_ingame.cpp \ + ${SPDir}/qcommon/stringed_interface.cpp \ + ${SPDir}/qcommon/z_memman_pc.cpp \ \ - ${MPDir}/botlib/be_aas_bspq3.cpp \ - ${MPDir}/botlib/be_aas_cluster.cpp \ - ${MPDir}/botlib/be_aas_debug.cpp \ - ${MPDir}/botlib/be_aas_entity.cpp \ - ${MPDir}/botlib/be_aas_file.cpp \ - ${MPDir}/botlib/be_aas_main.cpp \ - ${MPDir}/botlib/be_aas_move.cpp \ - ${MPDir}/botlib/be_aas_optimize.cpp \ - ${MPDir}/botlib/be_aas_reach.cpp \ - ${MPDir}/botlib/be_aas_route.cpp \ - ${MPDir}/botlib/be_aas_routealt.cpp \ - ${MPDir}/botlib/be_aas_sample.cpp \ - ${MPDir}/botlib/be_ai_char.cpp \ - ${MPDir}/botlib/be_ai_chat.cpp \ - ${MPDir}/botlib/be_ai_gen.cpp \ - ${MPDir}/botlib/be_ai_goal.cpp \ - ${MPDir}/botlib/be_ai_move.cpp \ - ${MPDir}/botlib/be_ai_weap.cpp \ - ${MPDir}/botlib/be_ai_weight.cpp \ - ${MPDir}/botlib/be_ea.cpp \ - ${MPDir}/botlib/be_interface.cpp \ - ${MPDir}/botlib/l_crc.cpp \ - ${MPDir}/botlib/l_libvar.cpp \ - ${MPDir}/botlib/l_log.cpp \ - ${MPDir}/botlib/l_memory.cpp \ - ${MPDir}/botlib/l_precomp.cpp \ - ${MPDir}/botlib/l_script.cpp \ - ${MPDir}/botlib/l_struct.cpp \ + ${SPDir}/botlib/be_aas_bspq3.cpp \ + ${SPDir}/botlib/be_aas_cluster.cpp \ + ${SPDir}/botlib/be_aas_debug.cpp \ + ${SPDir}/botlib/be_aas_entity.cpp \ + ${SPDir}/botlib/be_aas_file.cpp \ + ${SPDir}/botlib/be_aas_main.cpp \ + ${SPDir}/botlib/be_aas_move.cpp \ + ${SPDir}/botlib/be_aas_optimize.cpp \ + ${SPDir}/botlib/be_aas_reach.cpp \ + ${SPDir}/botlib/be_aas_route.cpp \ + ${SPDir}/botlib/be_aas_routealt.cpp \ + ${SPDir}/botlib/be_aas_sample.cpp \ + ${SPDir}/botlib/be_ai_char.cpp \ + ${SPDir}/botlib/be_ai_chat.cpp \ + ${SPDir}/botlib/be_ai_gen.cpp \ + ${SPDir}/botlib/be_ai_goal.cpp \ + ${SPDir}/botlib/be_ai_move.cpp \ + ${SPDir}/botlib/be_ai_weap.cpp \ + ${SPDir}/botlib/be_ai_weight.cpp \ + ${SPDir}/botlib/be_ea.cpp \ + ${SPDir}/botlib/be_interface.cpp \ + ${SPDir}/botlib/l_crc.cpp \ + ${SPDir}/botlib/l_libvar.cpp \ + ${SPDir}/botlib/l_log.cpp \ + ${SPDir}/botlib/l_memory.cpp \ + ${SPDir}/botlib/l_precomp.cpp \ + ${SPDir}/botlib/l_script.cpp \ + ${SPDir}/botlib/l_struct.cpp \ \ - ${MPDir}/icarus/BlockStream.cpp \ - ${MPDir}/icarus/GameInterface.cpp \ - ${MPDir}/icarus/Instance.cpp \ - ${MPDir}/icarus/Interface.cpp \ - ${MPDir}/icarus/Memory.cpp \ - ${MPDir}/icarus/Q3_Interface.cpp \ - ${MPDir}/icarus/Q3_Registers.cpp \ - ${MPDir}/icarus/Sequence.cpp \ - ${MPDir}/icarus/Sequencer.cpp \ - ${MPDir}/icarus/TaskManager.cpp \ + ${SPDir}/icarus/BlockStream.cpp \ + ${SPDir}/icarus/GameInterface.cpp \ + ${SPDir}/icarus/Instance.cpp \ + ${SPDir}/icarus/Interface.cpp \ + ${SPDir}/icarus/Memory.cpp \ + ${SPDir}/icarus/Q3_Interface.cpp \ + ${SPDir}/icarus/Q3_Registers.cpp \ + ${SPDir}/icarus/Sequence.cpp \ + ${SPDir}/icarus/Sequencer.cpp \ + ${SPDir}/icarus/TaskManager.cpp \ \ - ${MPDir}/server/NPCNav/navigator.cpp \ - ${MPDir}/server/sv_bot.cpp \ - ${MPDir}/server/sv_ccmds.cpp \ - ${MPDir}/server/sv_client.cpp \ - ${MPDir}/server/sv_game.cpp \ - ${MPDir}/server/sv_init.cpp \ - ${MPDir}/server/sv_main.cpp \ - ${MPDir}/server/sv_net_chan.cpp \ - ${MPDir}/server/sv_snapshot.cpp \ - ${MPDir}/server/sv_world.cpp \ - ${MPDir}/server/sv_gameapi.cpp \ + ${SPDir}/server/NPCNav/navigator.cpp \ + ${SPDir}/server/sv_bot.cpp \ + ${SPDir}/server/sv_ccmds.cpp \ + ${SPDir}/server/sv_client.cpp \ + ${SPDir}/server/sv_game.cpp \ + ${SPDir}/server/sv_init.cpp \ + ${SPDir}/server/sv_main.cpp \ + ${SPDir}/server/sv_net_chan.cpp \ + ${SPDir}/server/sv_snapshot.cpp \ + ${SPDir}/server/sv_world.cpp \ + ${SPDir}/server/sv_gameapi.cpp \ \ - ${MPDir}/client/cl_avi.cpp \ - ${MPDir}/client/cl_cgame.cpp \ - ${MPDir}/client/cl_cgameapi.cpp \ - ${MPDir}/client/cl_cin.cpp \ - ${MPDir}/client/cl_console.cpp \ - ${MPDir}/client/cl_input.cpp \ - ${MPDir}/client/cl_keys.cpp \ - ${MPDir}/client/cl_lan.cpp \ - ${MPDir}/client/cl_main.cpp \ - ${MPDir}/client/cl_net_chan.cpp \ - ${MPDir}/client/cl_parse.cpp \ - ${MPDir}/client/cl_scrn.cpp \ - ${MPDir}/client/cl_ui.cpp \ - ${MPDir}/client/cl_uiapi.cpp \ - ${MPDir}/client/FXExport.cpp \ - ${MPDir}/client/FxPrimitives.cpp \ - ${MPDir}/client/FxScheduler.cpp \ - ${MPDir}/client/FxSystem.cpp \ - ${MPDir}/client/FxTemplate.cpp \ - ${MPDir}/client/FxUtil.cpp \ - ${MPDir}/client/snd_ambient.cpp \ - ${MPDir}/client/snd_dma.cpp \ - ${MPDir}/client/snd_mem.cpp \ - ${MPDir}/client/snd_mix.cpp \ - ${MPDir}/client/snd_mp3.cpp \ - ${MPDir}/client/snd_music.cpp \ + ${SPDir}/client/cl_avi.cpp \ + ${SPDir}/client/cl_cgame.cpp \ + ${SPDir}/client/cl_cgameapi.cpp \ + ${SPDir}/client/cl_cin.cpp \ + ${SPDir}/client/cl_console.cpp \ + ${SPDir}/client/cl_input.cpp \ + ${SPDir}/client/cl_keys.cpp \ + ${SPDir}/client/cl_lan.cpp \ + ${SPDir}/client/cl_main.cpp \ + ${SPDir}/client/cl_net_chan.cpp \ + ${SPDir}/client/cl_parse.cpp \ + ${SPDir}/client/cl_scrn.cpp \ + ${SPDir}/client/cl_ui.cpp \ + ${SPDir}/client/cl_uiapi.cpp \ + ${SPDir}/client/FXExport.cpp \ + ${SPDir}/client/FxPrimitives.cpp \ + ${SPDir}/client/FxScheduler.cpp \ + ${SPDir}/client/FxSystem.cpp \ + ${SPDir}/client/FxTemplate.cpp \ + ${SPDir}/client/FxUtil.cpp \ + ${SPDir}/client/snd_ambient.cpp \ + ${SPDir}/client/snd_dma.cpp \ + ${SPDir}/client/snd_mem.cpp \ + ${SPDir}/client/snd_mix.cpp \ + ${SPDir}/client/snd_mp3.cpp \ + ${SPDir}/client/snd_music.cpp \ \ - ${MPDir}/mp3code/cdct.c \ - ${MPDir}/mp3code/csbt.c \ - ${MPDir}/mp3code/csbtb.c \ - ${MPDir}/mp3code/csbtl3.c \ - ${MPDir}/mp3code/cup.c \ - ${MPDir}/mp3code/cupini.c \ - ${MPDir}/mp3code/cupl1.c \ - ${MPDir}/mp3code/cupl3.c \ - ${MPDir}/mp3code/cwin.c \ - ${MPDir}/mp3code/cwinb.c \ - ${MPDir}/mp3code/cwinm.c \ - ${MPDir}/mp3code/hwin.c \ - ${MPDir}/mp3code/l3dq.c \ - ${MPDir}/mp3code/l3init.c \ - ${MPDir}/mp3code/mdct.c \ - ${MPDir}/mp3code/mhead.c \ - ${MPDir}/mp3code/msis.c \ - ${MPDir}/mp3code/towave.c \ - ${MPDir}/mp3code/uph.c \ - ${MPDir}/mp3code/upsf.c \ - ${MPDir}/mp3code/wavep.c \ + ${SPDir}/mp3code/cdct.c \ + ${SPDir}/mp3code/csbt.c \ + ${SPDir}/mp3code/csbtb.c \ + ${SPDir}/mp3code/csbtl3.c \ + ${SPDir}/mp3code/cup.c \ + ${SPDir}/mp3code/cupini.c \ + ${SPDir}/mp3code/cupl1.c \ + ${SPDir}/mp3code/cupl3.c \ + ${SPDir}/mp3code/cwin.c \ + ${SPDir}/mp3code/cwinb.c \ + ${SPDir}/mp3code/cwinm.c \ + ${SPDir}/mp3code/hwin.c \ + ${SPDir}/mp3code/l3dq.c \ + ${SPDir}/mp3code/l3init.c \ + ${SPDir}/mp3code/mdct.c \ + ${SPDir}/mp3code/mhead.c \ + ${SPDir}/mp3code/msis.c \ + ${SPDir}/mp3code/towave.c \ + ${SPDir}/mp3code/uph.c \ + ${SPDir}/mp3code/upsf.c \ + ${SPDir}/mp3code/wavep.c \ JK2VR_SRC_FILES := ${TOP_DIR}/JKVR/JKVR_SurfaceView.cpp \ diff --git a/Projects/Android/jni/OpenJK/Android_game.mk b/Projects/Android/jni/OpenJK/Android_game.mk index a33df30..a3d9c49 100644 --- a/Projects/Android/jni/OpenJK/Android_game.mk +++ b/Projects/Android/jni/OpenJK/Android_game.mk @@ -5,7 +5,7 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_MODULE := jampgamearm +LOCAL_MODULE := jagamearm LOCAL_CFLAGS := $(JK3_BASE_CFLAGS) -D_GAME @@ -18,95 +18,124 @@ LOCAL_LDLIBS += -llog -lz #LOCAL_STATIC_LIBRARIES := s-setup lz LOCAL_SHARED_LIBRARIES := -LOCAL_C_INCLUDES := $(JK3_BASE_C_INCLUDES) $(TOP_DIR) $(GL4ES_PATH) $(GL4ES_PATH)/include $(TOP_DIR)/SupportLibs/openal/include $(TOP_DIR)/jk2/shared +LOCAL_C_INCLUDES := $(JK3_BASE_C_INCLUDES) $(TOP_DIR) $(GL4ES_PATH) $(GL4ES_PATH)/include $(TOP_DIR)/SupportLibs/openal/include JK3_SRC = \ - ${MPDir}/game/ai_main.c \ - ${MPDir}/game/ai_util.c \ - ${MPDir}/game/ai_wpnav.c \ - ${MPDir}/game/AnimalNPC.c \ - ${MPDir}/game/bg_g2_utils.c \ - ${MPDir}/game/bg_misc.c \ - ${MPDir}/game/bg_panimate.c \ - ${MPDir}/game/bg_pmove.c \ - ${MPDir}/game/bg_saber.c \ - ${MPDir}/game/bg_saberLoad.c \ - ${MPDir}/game/bg_saga.c \ - ${MPDir}/game/bg_slidemove.c \ - ${MPDir}/game/bg_vehicleLoad.c \ - ${MPDir}/game/bg_weapons.c \ - ${MPDir}/game/FighterNPC.c \ - ${MPDir}/game/g_active.c \ - ${MPDir}/game/g_bot.c \ - ${MPDir}/game/g_client.c \ - ${MPDir}/game/g_cmds.c \ - ${MPDir}/game/g_combat.c \ - ${MPDir}/game/g_cvar.c \ - ${MPDir}/game/g_exphysics.c \ - ${MPDir}/game/g_ICARUScb.c \ - ${MPDir}/game/g_items.c \ - ${MPDir}/game/g_log.c \ - ${MPDir}/game/g_main.c \ - ${MPDir}/game/g_mem.c \ - ${MPDir}/game/g_misc.c \ - ${MPDir}/game/g_missile.c \ - ${MPDir}/game/g_mover.c \ - ${MPDir}/game/g_nav.c \ - ${MPDir}/game/g_navnew.c \ - ${MPDir}/game/g_object.c \ - ${MPDir}/game/g_saga.c \ - ${MPDir}/game/g_session.c \ - ${MPDir}/game/g_spawn.c \ - ${MPDir}/game/g_svcmds.c \ - ${MPDir}/game/g_syscalls.c \ - ${MPDir}/game/g_target.c \ - ${MPDir}/game/g_team.c \ - ${MPDir}/game/g_timer.c \ - ${MPDir}/game/g_trigger.c \ - ${MPDir}/game/g_turret.c \ - ${MPDir}/game/g_turret_G2.c \ - ${MPDir}/game/g_utils.c \ - ${MPDir}/game/g_vehicles.c \ - ${MPDir}/game/g_vehicleTurret.c \ - ${MPDir}/game/g_weapon.c \ - ${MPDir}/game/NPC.c \ - ${MPDir}/game/NPC_AI_Atst.c \ - ${MPDir}/game/NPC_AI_Default.c \ - ${MPDir}/game/NPC_AI_Droid.c \ - ${MPDir}/game/NPC_AI_GalakMech.c \ - ${MPDir}/game/NPC_AI_Grenadier.c \ - ${MPDir}/game/NPC_AI_Howler.c \ - ${MPDir}/game/NPC_AI_ImperialProbe.c \ - ${MPDir}/game/NPC_AI_Interrogator.c \ - ${MPDir}/game/NPC_AI_Jedi.c \ - ${MPDir}/game/NPC_AI_Mark1.c \ - ${MPDir}/game/NPC_AI_Mark2.c \ - ${MPDir}/game/NPC_AI_MineMonster.c \ - ${MPDir}/game/NPC_AI_Rancor.c \ - ${MPDir}/game/NPC_AI_Remote.c \ - ${MPDir}/game/NPC_AI_Seeker.c \ - ${MPDir}/game/NPC_AI_Sentry.c \ - ${MPDir}/game/NPC_AI_Sniper.c \ - ${MPDir}/game/NPC_AI_Stormtrooper.c \ - ${MPDir}/game/NPC_AI_Utils.c \ - ${MPDir}/game/NPC_AI_Wampa.c \ - ${MPDir}/game/NPC_behavior.c \ - ${MPDir}/game/NPC_combat.c \ - ${MPDir}/game/NPC_goal.c \ - ${MPDir}/game/NPC_misc.c \ - ${MPDir}/game/NPC_move.c \ - ${MPDir}/game/NPC_reactions.c \ - ${MPDir}/game/NPC_senses.c \ - ${MPDir}/game/NPC_sounds.c \ - ${MPDir}/game/NPC_spawn.c \ - ${MPDir}/game/NPC_stats.c \ - ${MPDir}/game/NPC_utils.c \ - ${MPDir}/game/SpeederNPC.c \ - ${MPDir}/game/tri_coll_test.c \ - ${MPDir}/game/w_force.c \ - ${MPDir}/game/w_saber.c \ - ${MPDir}/game/WalkerNPC.c \ - ${MPDir}/qcommon/q_shared.c \ + ${SPDir}/game/AI_Animal.cpp \ + ${SPDir}/game/AI_AssassinDroid.cpp \ + ${SPDir}/game/AI_Atst.cpp \ + ${SPDir}/game/AI_BobaFett.cpp \ + ${SPDir}/game/AI_Civilian.cpp \ + ${SPDir}/game/AI_Default.cpp \ + ${SPDir}/game/AI_Droid.cpp \ + ${SPDir}/game/AI_GalakMech.cpp \ + ${SPDir}/game/AI_Grenadier.cpp \ + ${SPDir}/game/AI_HazardTrooper.cpp \ + ${SPDir}/game/AI_Howler.cpp \ + ${SPDir}/game/AI_ImperialProbe.cpp \ + ${SPDir}/game/AI_Interrogator.cpp \ + ${SPDir}/game/AI_Jedi.cpp \ + ${SPDir}/game/AI_Mark1.cpp \ + ${SPDir}/game/AI_Mark2.cpp \ + ${SPDir}/game/AI_MineMonster.cpp \ + ${SPDir}/game/AI_Rancor.cpp \ + ${SPDir}/game/AI_Remote.cpp \ + ${SPDir}/game/AI_RocketTrooper.cpp \ + ${SPDir}/game/AI_SaberDroid.cpp \ + ${SPDir}/game/AI_SandCreature.cpp \ + ${SPDir}/game/AI_Seeker.cpp \ + ${SPDir}/game/AI_Sentry.cpp \ + ${SPDir}/game/AI_Sniper.cpp \ + ${SPDir}/game/AI_Stormtrooper.cpp \ + ${SPDir}/game/AI_Tusken.cpp \ + ${SPDir}/game/AI_Utils.cpp \ + ${SPDir}/game/AI_Wampa.cpp \ + ${SPDir}/game/AnimalNPC.cpp \ + ${SPDir}/game/bg_misc.cpp \ + ${SPDir}/game/bg_pangles.cpp \ + ${SPDir}/game/bg_panimate.cpp \ + ${SPDir}/game/bg_pmove.cpp \ + ${SPDir}/game/bg_slidemove.cpp \ + ${SPDir}/game/bg_vehicleLoad.cpp \ + ${SPDir}/game/FighterNPC.cpp \ + ${SPDir}/game/genericparser2.cpp \ + ${SPDir}/game/g_active.cpp \ + ${SPDir}/game/g_breakable.cpp \ + ${SPDir}/game/g_camera.cpp \ + ${SPDir}/game/g_client.cpp \ + ${SPDir}/game/g_cmds.cpp \ + ${SPDir}/game/g_combat.cpp \ + ${SPDir}/game/g_emplaced.cpp \ + ${SPDir}/game/g_functions.cpp \ + ${SPDir}/game/g_fx.cpp \ + ${SPDir}/game/g_inventory.cpp \ + ${SPDir}/game/g_itemLoad.cpp \ + ${SPDir}/game/g_items.cpp \ + ${SPDir}/game/g_main.cpp \ + ${SPDir}/game/g_mem.cpp \ + ${SPDir}/game/g_misc.cpp \ + ${SPDir}/game/g_misc_model.cpp \ + ${SPDir}/game/g_missile.cpp \ + ${SPDir}/game/g_mover.cpp \ + ${SPDir}/game/g_nav.cpp \ + ${SPDir}/game/g_navigator.cpp \ + ${SPDir}/game/g_navnew.cpp \ + ${SPDir}/game/g_object.cpp \ + ${SPDir}/game/g_objectives.cpp \ + ${SPDir}/game/g_rail.cpp \ + ${SPDir}/game/g_ref.cpp \ + ${SPDir}/game/g_roff.cpp \ + ${SPDir}/game/g_savegame.cpp \ + ${SPDir}/game/g_session.cpp \ + ${SPDir}/game/g_spawn.cpp \ + ${SPDir}/game/g_svcmds.cpp \ + ${SPDir}/game/g_target.cpp \ + ${SPDir}/game/G_Timer.cpp \ + ${SPDir}/game/g_trigger.cpp \ + ${SPDir}/game/g_turret.cpp \ + ${SPDir}/game/g_usable.cpp \ + ${SPDir}/game/g_utils.cpp \ + ${SPDir}/game/g_vehicleLoad.cpp \ + ${SPDir}/game/g_vehicles.cpp \ + ${SPDir}/game/g_weapon.cpp \ + ${SPDir}/game/g_weaponLoad.cpp \ + ${SPDir}/game/NPC.cpp \ + ${SPDir}/game/NPC_behavior.cpp \ + ${SPDir}/game/NPC_combat.cpp \ + ${SPDir}/game/NPC_goal.cpp \ + ${SPDir}/game/NPC_misc.cpp \ + ${SPDir}/game/NPC_move.cpp \ + ${SPDir}/game/NPC_reactions.cpp \ + ${SPDir}/game/NPC_senses.cpp \ + ${SPDir}/game/NPC_sounds.cpp \ + ${SPDir}/game/NPC_spawn.cpp \ + ${SPDir}/game/NPC_stats.cpp \ + ${SPDir}/game/NPC_utils.cpp \ + ${SPDir}/game/Q3_Interface.cpp \ + ${SPDir}/game/SpeederNPC.cpp \ + ${SPDir}/game/WalkerNPC.cpp \ + ${SPDir}/game/wp_atst.cpp \ + ${SPDir}/game/wp_blaster_pistol.cpp \ + ${SPDir}/game/wp_blaster_rifle.cpp \ + ${SPDir}/game/wp_bot_laser.cpp \ + ${SPDir}/game/wp_bowcaster.cpp \ + ${SPDir}/game/wp_concussion.cpp \ + ${SPDir}/game/wp_demp2.cpp \ + ${SPDir}/game/wp_det_pack.cpp \ + ${SPDir}/game/wp_disruptor.cpp \ + ${SPDir}/game/wp_emplaced_gun.cpp \ + ${SPDir}/game/wp_flechette.cpp \ + ${SPDir}/game/wp_melee.cpp \ + ${SPDir}/game/wp_noghri_stick.cpp \ + ${SPDir}/game/wp_repeater.cpp \ + ${SPDir}/game/wp_rocket_launcher.cpp \ + ${SPDir}/game/wp_saber.cpp \ + ${SPDir}/game/wp_saberLoad.cpp \ + ${SPDir}/game/wp_stun_baton.cpp \ + ${SPDir}/game/wp_thermal.cpp \ + ${SPDir}/game/wp_trip_mine.cpp \ + ${SPDir}/game/wp_tusken.cpp \ + ${SPDir}/qcommon/q_shared.cpp \ ${OPENJK_PATH}/shared/qcommon/q_math.c \ ${OPENJK_PATH}/shared/qcommon/q_color.c \ ${OPENJK_PATH}/shared/qcommon/q_string.c \ diff --git a/Projects/Android/jni/OpenJK/Android_gles.mk b/Projects/Android/jni/OpenJK/Android_gles.mk index fbe5899..0c3af0f 100644 --- a/Projects/Android/jni/OpenJK/Android_gles.mk +++ b/Projects/Android/jni/OpenJK/Android_gles.mk @@ -18,54 +18,54 @@ LOCAL_LDLIBS += -lGLESv3 -landroid -lEGL -ldl -llog LOCAL_STATIC_LIBRARIES := libpng libjpeg #LOCAL_SHARED_LIBRARIES := -LOCAL_C_INCLUDES := $(JK3_BASE_C_INCLUDES) $(TOP_DIR)/libpng $(LOCAL_PATH)/$(MPDir)/rd-gles $(TOP_DIR) +LOCAL_C_INCLUDES := $(JK3_BASE_C_INCLUDES) $(TOP_DIR)/libpng $(LOCAL_PATH)/$(SPDir)/rd-gles $(TOP_DIR) JK3_SRC = \ - ${MPDir}/rd-gles/G2_API.cpp \ - ${MPDir}/rd-gles/G2_bolts.cpp \ - ${MPDir}/rd-gles/G2_bones.cpp \ - ${MPDir}/rd-gles/G2_misc.cpp \ - ${MPDir}/rd-gles/G2_surfaces.cpp \ - ${MPDir}/rd-gles/tr_arioche.cpp \ - ${MPDir}/rd-gles/tr_backend.cpp \ - ${MPDir}/rd-gles/tr_bsp.cpp \ - ${MPDir}/rd-gles/tr_cmds.cpp \ - ${MPDir}/rd-gles/tr_curve.cpp \ - ${MPDir}/rd-gles/tr_decals.cpp \ - ${MPDir}/rd-gles/tr_ghoul2.cpp \ - ${MPDir}/rd-gles/tr_image.cpp \ - ${MPDir}/rd-gles/tr_init.cpp \ - ${MPDir}/rd-gles/tr_light.cpp \ - ${MPDir}/rd-gles/tr_main.cpp \ - ${MPDir}/rd-gles/tr_marks.cpp \ - ${MPDir}/rd-gles/tr_mesh.cpp \ - ${MPDir}/rd-gles/tr_model.cpp \ - ${MPDir}/rd-gles/tr_quicksprite.cpp \ - ${MPDir}/rd-gles/tr_scene.cpp \ - ${MPDir}/rd-gles/tr_shade.cpp \ - ${MPDir}/rd-gles/tr_shade_calc.cpp \ - ${MPDir}/rd-gles/tr_shader.cpp \ - ${MPDir}/rd-gles/tr_shadows.cpp \ - ${MPDir}/rd-gles/tr_skin.cpp \ - ${MPDir}/rd-gles/tr_sky.cpp \ - ${MPDir}/rd-gles/tr_subs.cpp \ - ${MPDir}/rd-gles/tr_surface.cpp \ - ${MPDir}/rd-gles/tr_surfacesprites.cpp \ - ${MPDir}/rd-gles/tr_terrain.cpp \ - ${MPDir}/rd-gles/tr_world.cpp \ - ${MPDir}/rd-gles/tr_WorldEffects.cpp \ - ${MPDir}/ghoul2/G2_gore.cpp \ - ${MPDir}/rd-common/tr_font.cpp \ - ${MPDir}/rd-common/tr_image_load.cpp \ - ${MPDir}/rd-common/tr_image_manipulation.cpp \ - ${MPDir}/rd-common/tr_image_jpg.cpp \ - ${MPDir}/rd-common/tr_image_tga.cpp \ - ${MPDir}/rd-common/tr_image_png.cpp \ - ${MPDir}/rd-common/tr_noise.cpp \ - ${MPDir}/qcommon/GenericParser2.cpp \ - ${MPDir}/qcommon/matcomp.cpp \ - ${MPDir}/android/android_glimp.cpp \ - ${MPDir}/qcommon/q_shared.c \ + ${SPDir}/rd-gles/G2_API.cpp \ + ${SPDir}/rd-gles/G2_bolts.cpp \ + ${SPDir}/rd-gles/G2_bones.cpp \ + ${SPDir}/rd-gles/G2_misc.cpp \ + ${SPDir}/rd-gles/G2_surfaces.cpp \ + ${SPDir}/rd-gles/tr_arioche.cpp \ + ${SPDir}/rd-gles/tr_backend.cpp \ + ${SPDir}/rd-gles/tr_bsp.cpp \ + ${SPDir}/rd-gles/tr_cmds.cpp \ + ${SPDir}/rd-gles/tr_curve.cpp \ + ${SPDir}/rd-gles/tr_decals.cpp \ + ${SPDir}/rd-gles/tr_ghoul2.cpp \ + ${SPDir}/rd-gles/tr_image.cpp \ + ${SPDir}/rd-gles/tr_init.cpp \ + ${SPDir}/rd-gles/tr_light.cpp \ + ${SPDir}/rd-gles/tr_main.cpp \ + ${SPDir}/rd-gles/tr_marks.cpp \ + ${SPDir}/rd-gles/tr_mesh.cpp \ + ${SPDir}/rd-gles/tr_model.cpp \ + ${SPDir}/rd-gles/tr_quicksprite.cpp \ + ${SPDir}/rd-gles/tr_scene.cpp \ + ${SPDir}/rd-gles/tr_shade.cpp \ + ${SPDir}/rd-gles/tr_shade_calc.cpp \ + ${SPDir}/rd-gles/tr_shader.cpp \ + ${SPDir}/rd-gles/tr_shadows.cpp \ + ${SPDir}/rd-gles/tr_skin.cpp \ + ${SPDir}/rd-gles/tr_sky.cpp \ + ${SPDir}/rd-gles/tr_subs.cpp \ + ${SPDir}/rd-gles/tr_surface.cpp \ + ${SPDir}/rd-gles/tr_surfacesprites.cpp \ + ${SPDir}/rd-gles/tr_terrain.cpp \ + ${SPDir}/rd-gles/tr_world.cpp \ + ${SPDir}/rd-gles/tr_WorldEffects.cpp \ + ${SPDir}/ghoul2/G2_gore.cpp \ + ${SPDir}/rd-common/tr_font.cpp \ + ${SPDir}/rd-common/tr_image_load.cpp \ + ${SPDir}/rd-common/tr_image_manipulation.cpp \ + ${SPDir}/rd-common/tr_image_jpg.cpp \ + ${SPDir}/rd-common/tr_image_tga.cpp \ + ${SPDir}/rd-common/tr_image_png.cpp \ + ${SPDir}/rd-common/tr_noise.cpp \ + ${SPDir}/qcommon/GenericParser2.cpp \ + ${SPDir}/qcommon/matcomp.cpp \ + ${SPDir}/android/android_glimp.cpp \ + ${SPDir}/qcommon/q_shared.cpp \ ${OPENJK_PATH}/shared/qcommon/q_math.c \ ${OPENJK_PATH}/shared/qcommon/q_color.c \ ${OPENJK_PATH}/shared/qcommon/q_string.c \ diff --git a/Projects/Android/jni/OpenJK/Android_ui.mk b/Projects/Android/jni/OpenJK/Android_ui.mk index a37265b..b907c55 100644 --- a/Projects/Android/jni/OpenJK/Android_ui.mk +++ b/Projects/Android/jni/OpenJK/Android_ui.mk @@ -21,20 +21,16 @@ LOCAL_SHARED_LIBRARIES := LOCAL_C_INCLUDES := $(JK3_BASE_C_INCLUDES) JK3_SRC = \ - ${MPDir}/game/bg_misc.c \ - ${MPDir}/game/bg_saberLoad.c \ - ${MPDir}/game/bg_saga.c \ - ${MPDir}/game/bg_vehicleLoad.c \ - ${MPDir}/game/bg_weapons.c \ - ${MPDir}/ui/ui_atoms.c \ - ${MPDir}/ui/ui_cvar.c \ - ${MPDir}/ui/ui_force.c \ - ${MPDir}/ui/ui_gameinfo.c \ - ${MPDir}/ui/ui_main.c \ - ${MPDir}/ui/ui_saber.c \ - ${MPDir}/ui/ui_shared.c \ - ${MPDir}/ui/ui_syscalls.c \ - ${MPDir}/qcommon/q_shared.c \ + ${SPDir}/game/bg_misc.cpp \ + ${SPDir}/game/bg_vehicleLoad.cpp \ + ${SPDir}/ui/gameinfo.cpp \ + ${SPDir}/ui/ui_atoms.cpp \ + ${SPDir}/ui/ui_connect.cpp \ + ${SPDir}/ui/ui_main.cpp \ + ${SPDir}/ui/ui_saber.cpp \ + ${SPDir}/ui/ui_shared.cpp \ + ${SPDir}/ui/ui_syscalls.cpp \ + ${SPDir}/qcommon/q_shared.cpp \ ${OPENJK_PATH}/shared/qcommon/q_math.c \ ${OPENJK_PATH}/shared/qcommon/q_color.c \ ${OPENJK_PATH}/shared/qcommon/q_string.c \ diff --git a/Projects/Android/jni/OpenJK/codemp/android/android-jni.cpp b/Projects/Android/jni/OpenJK/code/android/android-jni.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/android/android-jni.cpp rename to Projects/Android/jni/OpenJK/code/android/android-jni.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/android/android_glimp.cpp b/Projects/Android/jni/OpenJK/code/android/android_glimp.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/android/android_glimp.cpp rename to Projects/Android/jni/OpenJK/code/android/android_glimp.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/android/android_local.h b/Projects/Android/jni/OpenJK/code/android/android_local.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/android/android_local.h rename to Projects/Android/jni/OpenJK/code/android/android_local.h diff --git a/Projects/Android/jni/OpenJK/codemp/android/android_main.cpp b/Projects/Android/jni/OpenJK/code/android/android_main.cpp similarity index 99% rename from Projects/Android/jni/OpenJK/codemp/android/android_main.cpp rename to Projects/Android/jni/OpenJK/code/android/android_main.cpp index bd3327d..3d8b4f9 100644 --- a/Projects/Android/jni/OpenJK/codemp/android/android_main.cpp +++ b/Projects/Android/jni/OpenJK/code/android/android_main.cpp @@ -4,6 +4,7 @@ #endif #include "qcommon/q_shared.h" #include "qcommon/qcommon.h" +#include "qcommon/q_platform.h" #include "sys_loadlib.h" #ifdef DEDICATED diff --git a/Projects/Android/jni/OpenJK/codemp/android/android_snd.c b/Projects/Android/jni/OpenJK/code/android/android_snd.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/android/android_snd.c rename to Projects/Android/jni/OpenJK/code/android/android_snd.c diff --git a/Projects/Android/jni/OpenJK/codemp/android/in_android.cpp b/Projects/Android/jni/OpenJK/code/android/in_android.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/android/in_android.cpp rename to Projects/Android/jni/OpenJK/code/android/in_android.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/android/in_android.h b/Projects/Android/jni/OpenJK/code/android/in_android.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/android/in_android.h rename to Projects/Android/jni/OpenJK/code/android/in_android.h diff --git a/Projects/Android/jni/OpenJK/codemp/android/sys_loadlib.h b/Projects/Android/jni/OpenJK/code/android/sys_loadlib.h similarity index 70% rename from Projects/Android/jni/OpenJK/codemp/android/sys_loadlib.h rename to Projects/Android/jni/OpenJK/code/android/sys_loadlib.h index 385727f..2eeb56e 100644 --- a/Projects/Android/jni/OpenJK/codemp/android/sys_loadlib.h +++ b/Projects/Android/jni/OpenJK/code/android/sys_loadlib.h @@ -1,5 +1,5 @@ #pragma once -/* + #ifdef DEDICATED # ifdef _WIN32 # include @@ -15,12 +15,12 @@ # define Sys_LibraryError() dlerror() # endif #else -# include -# include -# define Sys_LoadLibrary(f) SDL_LoadObject(f) -# define Sys_UnloadLibrary(h) SDL_UnloadObject(h) -# define Sys_LoadFunction(h,fn) SDL_LoadFunction(h,fn) -# define Sys_LibraryError() SDL_GetError() +//# include +//# include +# define Sys_LoadLibrary(f) dlopen(f, RTLD_LAZY) +# define Sys_UnloadLibrary(h) dlclose(h) +# define Sys_LoadFunction(h,fn) dlsym(h,fn) +# define Sys_LibraryError() dlerror() #endif -*/ + void * QDECL Sys_LoadDll(const char *name, qboolean useSystemLib); diff --git a/Projects/Android/jni/OpenJK/codemp/android/sys_local.h b/Projects/Android/jni/OpenJK/code/android/sys_local.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/android/sys_local.h rename to Projects/Android/jni/OpenJK/code/android/sys_local.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/aasfile.h b/Projects/Android/jni/OpenJK/code/botlib/aasfile.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/aasfile.h rename to Projects/Android/jni/OpenJK/code/botlib/aasfile.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_aas.h b/Projects/Android/jni/OpenJK/code/botlib/be_aas.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_aas.h rename to Projects/Android/jni/OpenJK/code/botlib/be_aas.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_aas_bsp.h b/Projects/Android/jni/OpenJK/code/botlib/be_aas_bsp.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_aas_bsp.h rename to Projects/Android/jni/OpenJK/code/botlib/be_aas_bsp.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_aas_bspq3.cpp b/Projects/Android/jni/OpenJK/code/botlib/be_aas_bspq3.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_aas_bspq3.cpp rename to Projects/Android/jni/OpenJK/code/botlib/be_aas_bspq3.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_aas_cluster.cpp b/Projects/Android/jni/OpenJK/code/botlib/be_aas_cluster.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_aas_cluster.cpp rename to Projects/Android/jni/OpenJK/code/botlib/be_aas_cluster.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_aas_cluster.h b/Projects/Android/jni/OpenJK/code/botlib/be_aas_cluster.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_aas_cluster.h rename to Projects/Android/jni/OpenJK/code/botlib/be_aas_cluster.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_aas_debug.cpp b/Projects/Android/jni/OpenJK/code/botlib/be_aas_debug.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_aas_debug.cpp rename to Projects/Android/jni/OpenJK/code/botlib/be_aas_debug.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_aas_debug.h b/Projects/Android/jni/OpenJK/code/botlib/be_aas_debug.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_aas_debug.h rename to Projects/Android/jni/OpenJK/code/botlib/be_aas_debug.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_aas_def.h b/Projects/Android/jni/OpenJK/code/botlib/be_aas_def.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_aas_def.h rename to Projects/Android/jni/OpenJK/code/botlib/be_aas_def.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_aas_entity.cpp b/Projects/Android/jni/OpenJK/code/botlib/be_aas_entity.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_aas_entity.cpp rename to Projects/Android/jni/OpenJK/code/botlib/be_aas_entity.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_aas_entity.h b/Projects/Android/jni/OpenJK/code/botlib/be_aas_entity.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_aas_entity.h rename to Projects/Android/jni/OpenJK/code/botlib/be_aas_entity.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_aas_file.cpp b/Projects/Android/jni/OpenJK/code/botlib/be_aas_file.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_aas_file.cpp rename to Projects/Android/jni/OpenJK/code/botlib/be_aas_file.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_aas_file.h b/Projects/Android/jni/OpenJK/code/botlib/be_aas_file.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_aas_file.h rename to Projects/Android/jni/OpenJK/code/botlib/be_aas_file.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_aas_funcs.h b/Projects/Android/jni/OpenJK/code/botlib/be_aas_funcs.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_aas_funcs.h rename to Projects/Android/jni/OpenJK/code/botlib/be_aas_funcs.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_aas_main.cpp b/Projects/Android/jni/OpenJK/code/botlib/be_aas_main.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_aas_main.cpp rename to Projects/Android/jni/OpenJK/code/botlib/be_aas_main.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_aas_main.h b/Projects/Android/jni/OpenJK/code/botlib/be_aas_main.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_aas_main.h rename to Projects/Android/jni/OpenJK/code/botlib/be_aas_main.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_aas_move.cpp b/Projects/Android/jni/OpenJK/code/botlib/be_aas_move.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_aas_move.cpp rename to Projects/Android/jni/OpenJK/code/botlib/be_aas_move.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_aas_move.h b/Projects/Android/jni/OpenJK/code/botlib/be_aas_move.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_aas_move.h rename to Projects/Android/jni/OpenJK/code/botlib/be_aas_move.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_aas_optimize.cpp b/Projects/Android/jni/OpenJK/code/botlib/be_aas_optimize.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_aas_optimize.cpp rename to Projects/Android/jni/OpenJK/code/botlib/be_aas_optimize.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_aas_optimize.h b/Projects/Android/jni/OpenJK/code/botlib/be_aas_optimize.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_aas_optimize.h rename to Projects/Android/jni/OpenJK/code/botlib/be_aas_optimize.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_aas_reach.cpp b/Projects/Android/jni/OpenJK/code/botlib/be_aas_reach.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_aas_reach.cpp rename to Projects/Android/jni/OpenJK/code/botlib/be_aas_reach.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_aas_reach.h b/Projects/Android/jni/OpenJK/code/botlib/be_aas_reach.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_aas_reach.h rename to Projects/Android/jni/OpenJK/code/botlib/be_aas_reach.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_aas_route.cpp b/Projects/Android/jni/OpenJK/code/botlib/be_aas_route.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_aas_route.cpp rename to Projects/Android/jni/OpenJK/code/botlib/be_aas_route.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_aas_route.h b/Projects/Android/jni/OpenJK/code/botlib/be_aas_route.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_aas_route.h rename to Projects/Android/jni/OpenJK/code/botlib/be_aas_route.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_aas_routealt.cpp b/Projects/Android/jni/OpenJK/code/botlib/be_aas_routealt.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_aas_routealt.cpp rename to Projects/Android/jni/OpenJK/code/botlib/be_aas_routealt.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_aas_routealt.h b/Projects/Android/jni/OpenJK/code/botlib/be_aas_routealt.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_aas_routealt.h rename to Projects/Android/jni/OpenJK/code/botlib/be_aas_routealt.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_aas_sample.cpp b/Projects/Android/jni/OpenJK/code/botlib/be_aas_sample.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_aas_sample.cpp rename to Projects/Android/jni/OpenJK/code/botlib/be_aas_sample.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_aas_sample.h b/Projects/Android/jni/OpenJK/code/botlib/be_aas_sample.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_aas_sample.h rename to Projects/Android/jni/OpenJK/code/botlib/be_aas_sample.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_ai_char.cpp b/Projects/Android/jni/OpenJK/code/botlib/be_ai_char.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_ai_char.cpp rename to Projects/Android/jni/OpenJK/code/botlib/be_ai_char.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_ai_char.h b/Projects/Android/jni/OpenJK/code/botlib/be_ai_char.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_ai_char.h rename to Projects/Android/jni/OpenJK/code/botlib/be_ai_char.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_ai_chat.cpp b/Projects/Android/jni/OpenJK/code/botlib/be_ai_chat.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_ai_chat.cpp rename to Projects/Android/jni/OpenJK/code/botlib/be_ai_chat.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_ai_chat.h b/Projects/Android/jni/OpenJK/code/botlib/be_ai_chat.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_ai_chat.h rename to Projects/Android/jni/OpenJK/code/botlib/be_ai_chat.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_ai_gen.cpp b/Projects/Android/jni/OpenJK/code/botlib/be_ai_gen.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_ai_gen.cpp rename to Projects/Android/jni/OpenJK/code/botlib/be_ai_gen.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_ai_gen.h b/Projects/Android/jni/OpenJK/code/botlib/be_ai_gen.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_ai_gen.h rename to Projects/Android/jni/OpenJK/code/botlib/be_ai_gen.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_ai_goal.cpp b/Projects/Android/jni/OpenJK/code/botlib/be_ai_goal.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_ai_goal.cpp rename to Projects/Android/jni/OpenJK/code/botlib/be_ai_goal.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_ai_goal.h b/Projects/Android/jni/OpenJK/code/botlib/be_ai_goal.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_ai_goal.h rename to Projects/Android/jni/OpenJK/code/botlib/be_ai_goal.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_ai_move.cpp b/Projects/Android/jni/OpenJK/code/botlib/be_ai_move.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_ai_move.cpp rename to Projects/Android/jni/OpenJK/code/botlib/be_ai_move.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_ai_move.h b/Projects/Android/jni/OpenJK/code/botlib/be_ai_move.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_ai_move.h rename to Projects/Android/jni/OpenJK/code/botlib/be_ai_move.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_ai_weap.cpp b/Projects/Android/jni/OpenJK/code/botlib/be_ai_weap.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_ai_weap.cpp rename to Projects/Android/jni/OpenJK/code/botlib/be_ai_weap.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_ai_weap.h b/Projects/Android/jni/OpenJK/code/botlib/be_ai_weap.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_ai_weap.h rename to Projects/Android/jni/OpenJK/code/botlib/be_ai_weap.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_ai_weight.cpp b/Projects/Android/jni/OpenJK/code/botlib/be_ai_weight.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_ai_weight.cpp rename to Projects/Android/jni/OpenJK/code/botlib/be_ai_weight.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_ai_weight.h b/Projects/Android/jni/OpenJK/code/botlib/be_ai_weight.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_ai_weight.h rename to Projects/Android/jni/OpenJK/code/botlib/be_ai_weight.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_ea.cpp b/Projects/Android/jni/OpenJK/code/botlib/be_ea.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_ea.cpp rename to Projects/Android/jni/OpenJK/code/botlib/be_ea.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_ea.h b/Projects/Android/jni/OpenJK/code/botlib/be_ea.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_ea.h rename to Projects/Android/jni/OpenJK/code/botlib/be_ea.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_interface.cpp b/Projects/Android/jni/OpenJK/code/botlib/be_interface.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_interface.cpp rename to Projects/Android/jni/OpenJK/code/botlib/be_interface.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/be_interface.h b/Projects/Android/jni/OpenJK/code/botlib/be_interface.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/be_interface.h rename to Projects/Android/jni/OpenJK/code/botlib/be_interface.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/botlib.h b/Projects/Android/jni/OpenJK/code/botlib/botlib.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/botlib.h rename to Projects/Android/jni/OpenJK/code/botlib/botlib.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/l_crc.cpp b/Projects/Android/jni/OpenJK/code/botlib/l_crc.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/l_crc.cpp rename to Projects/Android/jni/OpenJK/code/botlib/l_crc.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/l_crc.h b/Projects/Android/jni/OpenJK/code/botlib/l_crc.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/l_crc.h rename to Projects/Android/jni/OpenJK/code/botlib/l_crc.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/l_libvar.cpp b/Projects/Android/jni/OpenJK/code/botlib/l_libvar.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/l_libvar.cpp rename to Projects/Android/jni/OpenJK/code/botlib/l_libvar.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/l_libvar.h b/Projects/Android/jni/OpenJK/code/botlib/l_libvar.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/l_libvar.h rename to Projects/Android/jni/OpenJK/code/botlib/l_libvar.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/l_log.cpp b/Projects/Android/jni/OpenJK/code/botlib/l_log.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/l_log.cpp rename to Projects/Android/jni/OpenJK/code/botlib/l_log.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/l_log.h b/Projects/Android/jni/OpenJK/code/botlib/l_log.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/l_log.h rename to Projects/Android/jni/OpenJK/code/botlib/l_log.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/l_memory.cpp b/Projects/Android/jni/OpenJK/code/botlib/l_memory.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/l_memory.cpp rename to Projects/Android/jni/OpenJK/code/botlib/l_memory.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/l_memory.h b/Projects/Android/jni/OpenJK/code/botlib/l_memory.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/l_memory.h rename to Projects/Android/jni/OpenJK/code/botlib/l_memory.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/l_precomp.cpp b/Projects/Android/jni/OpenJK/code/botlib/l_precomp.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/l_precomp.cpp rename to Projects/Android/jni/OpenJK/code/botlib/l_precomp.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/l_precomp.h b/Projects/Android/jni/OpenJK/code/botlib/l_precomp.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/l_precomp.h rename to Projects/Android/jni/OpenJK/code/botlib/l_precomp.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/l_script.cpp b/Projects/Android/jni/OpenJK/code/botlib/l_script.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/l_script.cpp rename to Projects/Android/jni/OpenJK/code/botlib/l_script.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/l_script.h b/Projects/Android/jni/OpenJK/code/botlib/l_script.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/l_script.h rename to Projects/Android/jni/OpenJK/code/botlib/l_script.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/l_struct.cpp b/Projects/Android/jni/OpenJK/code/botlib/l_struct.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/l_struct.cpp rename to Projects/Android/jni/OpenJK/code/botlib/l_struct.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/l_struct.h b/Projects/Android/jni/OpenJK/code/botlib/l_struct.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/l_struct.h rename to Projects/Android/jni/OpenJK/code/botlib/l_struct.h diff --git a/Projects/Android/jni/OpenJK/codemp/botlib/l_utils.h b/Projects/Android/jni/OpenJK/code/botlib/l_utils.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/botlib/l_utils.h rename to Projects/Android/jni/OpenJK/code/botlib/l_utils.h diff --git a/Projects/Android/jni/OpenJK/code/cgame/list.txt b/Projects/Android/jni/OpenJK/code/cgame/list.txt new file mode 100644 index 0000000..44e48e8 --- /dev/null +++ b/Projects/Android/jni/OpenJK/code/cgame/list.txt @@ -0,0 +1,49 @@ + Volume in drive C is Windows + Volume Serial Number is 7008-7702 + + Directory of C:\Dev\Quest\JKQuest\VrSamples\JKQuest\Projects\Android\jni\OpenJK\code\cgame + +02/09/2022 14:48 47,931 cg_camera.cpp +02/09/2022 14:48 8,913 cg_consolecmds.cpp +02/09/2022 14:48 16,080 cg_credits.cpp +02/09/2022 14:48 99,541 cg_draw.cpp +02/09/2022 14:48 10,553 cg_drawtools.cpp +02/09/2022 14:48 30,480 cg_effects.cpp +02/09/2022 14:48 76,147 cg_ents.cpp +02/09/2022 14:48 30,598 cg_event.cpp +02/09/2022 14:48 913 cg_headers.cpp +02/09/2022 14:48 22,260 cg_info.cpp +02/09/2022 14:48 2,535 cg_lights.cpp +02/09/2022 14:48 15,400 cg_localents.cpp +02/09/2022 14:48 113,024 cg_main.cpp +02/09/2022 14:48 7,540 cg_marks.cpp +02/09/2022 14:48 276,685 cg_players.cpp +02/09/2022 14:48 9,028 cg_playerstate.cpp +02/09/2022 14:48 20,454 cg_predict.cpp +02/09/2022 14:48 15,771 cg_scoreboard.cpp +02/09/2022 14:48 7,744 cg_servercmds.cpp +02/09/2022 14:48 10,910 cg_snapshot.cpp +02/09/2022 14:48 17,374 cg_syscalls.cpp +02/09/2022 14:48 22,832 cg_text.cpp +02/09/2022 14:48 66,616 cg_view.cpp +02/09/2022 14:48 86,447 cg_weapons.cpp +02/09/2022 14:48 55,007 FxPrimitives.cpp +02/09/2022 14:48 55,226 FxScheduler.cpp +02/09/2022 14:48 6,858 FxSystem.cpp +02/09/2022 14:48 48,720 FxTemplate.cpp +02/09/2022 14:48 33,999 FxUtil.cpp +02/09/2022 14:48 3,114 FX_ATSTMain.cpp +02/09/2022 14:48 3,172 FX_Blaster.cpp +02/09/2022 14:48 2,290 FX_Bowcaster.cpp +02/09/2022 14:48 4,340 FX_BryarPistol.cpp +02/09/2022 14:48 3,005 FX_Concussion.cpp +02/09/2022 14:48 2,960 FX_DEMP2.cpp +02/09/2022 14:48 3,171 FX_Disruptor.cpp +02/09/2022 14:48 4,021 FX_Emplaced.cpp +02/09/2022 14:48 2,430 FX_Flechette.cpp +02/09/2022 14:48 2,956 FX_HeavyRepeater.cpp +02/09/2022 14:48 2,675 FX_NoghriShot.cpp +02/09/2022 14:48 2,167 FX_RocketLauncher.cpp +02/09/2022 14:48 2,609 FX_TuskenShot.cpp + 42 File(s) 1,254,496 bytes + 0 Dir(s) 726,423,838,720 bytes free diff --git a/Projects/Android/jni/OpenJK/codemp/client/FXExport.cpp b/Projects/Android/jni/OpenJK/code/client/FXExport.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/FXExport.cpp rename to Projects/Android/jni/OpenJK/code/client/FXExport.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/client/FXExport.h b/Projects/Android/jni/OpenJK/code/client/FXExport.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/FXExport.h rename to Projects/Android/jni/OpenJK/code/client/FXExport.h diff --git a/Projects/Android/jni/OpenJK/codemp/client/FxPrimitives.cpp b/Projects/Android/jni/OpenJK/code/client/FxPrimitives.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/FxPrimitives.cpp rename to Projects/Android/jni/OpenJK/code/client/FxPrimitives.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/client/FxPrimitives.h b/Projects/Android/jni/OpenJK/code/client/FxPrimitives.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/FxPrimitives.h rename to Projects/Android/jni/OpenJK/code/client/FxPrimitives.h diff --git a/Projects/Android/jni/OpenJK/codemp/client/FxScheduler.cpp b/Projects/Android/jni/OpenJK/code/client/FxScheduler.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/FxScheduler.cpp rename to Projects/Android/jni/OpenJK/code/client/FxScheduler.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/client/FxScheduler.h b/Projects/Android/jni/OpenJK/code/client/FxScheduler.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/FxScheduler.h rename to Projects/Android/jni/OpenJK/code/client/FxScheduler.h diff --git a/Projects/Android/jni/OpenJK/codemp/client/FxSystem.cpp b/Projects/Android/jni/OpenJK/code/client/FxSystem.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/FxSystem.cpp rename to Projects/Android/jni/OpenJK/code/client/FxSystem.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/client/FxSystem.h b/Projects/Android/jni/OpenJK/code/client/FxSystem.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/FxSystem.h rename to Projects/Android/jni/OpenJK/code/client/FxSystem.h diff --git a/Projects/Android/jni/OpenJK/codemp/client/FxTemplate.cpp b/Projects/Android/jni/OpenJK/code/client/FxTemplate.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/FxTemplate.cpp rename to Projects/Android/jni/OpenJK/code/client/FxTemplate.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/client/FxUtil.cpp b/Projects/Android/jni/OpenJK/code/client/FxUtil.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/FxUtil.cpp rename to Projects/Android/jni/OpenJK/code/client/FxUtil.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/client/FxUtil.h b/Projects/Android/jni/OpenJK/code/client/FxUtil.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/FxUtil.h rename to Projects/Android/jni/OpenJK/code/client/FxUtil.h diff --git a/Projects/Android/jni/OpenJK/codemp/client/cl_avi.cpp b/Projects/Android/jni/OpenJK/code/client/cl_avi.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/cl_avi.cpp rename to Projects/Android/jni/OpenJK/code/client/cl_avi.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/client/cl_cgameapi.cpp b/Projects/Android/jni/OpenJK/code/client/cl_cgameapi.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/cl_cgameapi.cpp rename to Projects/Android/jni/OpenJK/code/client/cl_cgameapi.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/client/cl_cgameapi.h b/Projects/Android/jni/OpenJK/code/client/cl_cgameapi.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/cl_cgameapi.h rename to Projects/Android/jni/OpenJK/code/client/cl_cgameapi.h diff --git a/Projects/Android/jni/OpenJK/codemp/client/cl_lan.cpp b/Projects/Android/jni/OpenJK/code/client/cl_lan.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/cl_lan.cpp rename to Projects/Android/jni/OpenJK/code/client/cl_lan.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/client/cl_lan.h b/Projects/Android/jni/OpenJK/code/client/cl_lan.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/cl_lan.h rename to Projects/Android/jni/OpenJK/code/client/cl_lan.h diff --git a/Projects/Android/jni/OpenJK/codemp/client/cl_net_chan.cpp b/Projects/Android/jni/OpenJK/code/client/cl_net_chan.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/cl_net_chan.cpp rename to Projects/Android/jni/OpenJK/code/client/cl_net_chan.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/client/cl_uiapi.cpp b/Projects/Android/jni/OpenJK/code/client/cl_uiapi.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/cl_uiapi.cpp rename to Projects/Android/jni/OpenJK/code/client/cl_uiapi.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/client/cl_uiapi.h b/Projects/Android/jni/OpenJK/code/client/cl_uiapi.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/cl_uiapi.h rename to Projects/Android/jni/OpenJK/code/client/cl_uiapi.h diff --git a/Projects/Android/jni/OpenJK/codemp/client/snd_mp3.cpp b/Projects/Android/jni/OpenJK/code/client/snd_mp3.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/snd_mp3.cpp rename to Projects/Android/jni/OpenJK/code/client/snd_mp3.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/client/snd_mp3.h b/Projects/Android/jni/OpenJK/code/client/snd_mp3.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/snd_mp3.h rename to Projects/Android/jni/OpenJK/code/client/snd_mp3.h diff --git a/Projects/Android/jni/OpenJK/code/game/common_headers.h b/Projects/Android/jni/OpenJK/code/game/common_headers.h index cff7b9e..420cfd6 100644 --- a/Projects/Android/jni/OpenJK/code/game/common_headers.h +++ b/Projects/Android/jni/OpenJK/code/game/common_headers.h @@ -25,7 +25,7 @@ along with this program; if not, see . #define COMMON_HEADERS_H_INC #if !defined(__Q_SHARED_H) - #include "../qcommon/q_shared.h" + #include "qcommon/q_shared.h" #endif //#if !defined(Q_SHAREDBASIC_H_INC) diff --git a/Projects/Android/jni/OpenJK/code/game/list.txt b/Projects/Android/jni/OpenJK/code/game/list.txt new file mode 100644 index 0000000..f1ec597 --- /dev/null +++ b/Projects/Android/jni/OpenJK/code/game/list.txt @@ -0,0 +1,121 @@ + Volume in drive C is Windows + Volume Serial Number is 7008-7702 + + Directory of C:\Dev\Quest\JKQuest\VrSamples\JKQuest\Projects\Android\jni\OpenJK\code\game + +02/09/2022 14:48 10,369 AI_Animal.cpp +02/09/2022 14:48 6,414 AI_AssassinDroid.cpp +02/09/2022 14:48 8,061 AI_Atst.cpp +02/09/2022 14:48 38,723 AI_BobaFett.cpp +02/09/2022 14:48 2,318 AI_Civilian.cpp +02/09/2022 14:48 25,672 AI_Default.cpp +02/09/2022 14:48 13,147 AI_Droid.cpp +02/09/2022 14:48 20,640 AI_GalakMech.cpp +02/09/2022 14:48 18,640 AI_Grenadier.cpp +02/09/2022 14:48 43,560 AI_HazardTrooper.cpp +02/09/2022 14:48 25,130 AI_Howler.cpp +02/09/2022 14:48 14,540 AI_ImperialProbe.cpp +02/09/2022 14:48 11,170 AI_Interrogator.cpp +02/09/2022 14:48 239,826 AI_Jedi.cpp +02/09/2022 14:48 19,806 AI_Mark1.cpp +02/09/2022 14:48 9,822 AI_Mark2.cpp +02/09/2022 14:48 7,359 AI_MineMonster.cpp +02/09/2022 14:48 55,079 AI_Rancor.cpp +02/09/2022 14:48 9,163 AI_Remote.cpp +02/09/2022 14:48 25,793 AI_RocketTrooper.cpp +02/09/2022 14:48 12,556 AI_SaberDroid.cpp +02/09/2022 14:48 24,108 AI_SandCreature.cpp +02/09/2022 14:48 14,274 AI_Seeker.cpp +02/09/2022 14:48 13,755 AI_Sentry.cpp +02/09/2022 14:48 25,442 AI_Sniper.cpp +02/09/2022 14:48 80,117 AI_Stormtrooper.cpp +02/09/2022 14:48 14,337 AI_Tusken.cpp +02/09/2022 14:48 27,178 AI_Utils.cpp +02/09/2022 14:48 28,388 AI_Wampa.cpp +02/09/2022 14:48 31,078 AnimalNPC.cpp +02/09/2022 14:48 23,041 bg_misc.cpp +02/09/2022 14:48 61,981 bg_pangles.cpp +02/09/2022 14:48 216,144 bg_panimate.cpp +02/09/2022 14:48 431,239 bg_pmove.cpp +02/09/2022 14:48 16,822 bg_slidemove.cpp +02/09/2022 14:48 66,012 bg_vehicleLoad.cpp +02/09/2022 14:48 54,983 FighterNPC.cpp +02/09/2022 14:48 6,854 genericparser2.cpp +02/09/2022 14:48 175,059 g_active.cpp +02/09/2022 14:48 47,753 g_breakable.cpp +02/09/2022 14:48 7,011 g_camera.cpp +02/09/2022 14:48 84,114 g_client.cpp +02/09/2022 14:48 36,354 g_cmds.cpp +02/09/2022 14:48 197,488 g_combat.cpp +02/09/2022 14:48 36,176 g_emplaced.cpp +02/09/2022 14:48 11,572 g_functions.cpp +02/09/2022 14:48 35,351 g_fx.cpp +02/09/2022 14:48 3,388 g_inventory.cpp +02/09/2022 14:48 17,868 g_itemLoad.cpp +02/09/2022 14:48 44,034 g_items.cpp +02/09/2022 14:48 59,517 g_main.cpp +02/09/2022 14:48 1,481 g_mem.cpp +02/09/2022 14:48 93,353 g_misc.cpp +02/09/2022 14:48 23,309 g_misc_model.cpp +02/09/2022 14:48 44,248 g_missile.cpp +02/09/2022 14:48 72,076 g_mover.cpp +02/09/2022 14:48 12,540 g_nav.cpp +02/09/2022 14:48 157,774 g_navigator.cpp +02/09/2022 14:48 7,232 g_navnew.cpp +02/09/2022 14:48 11,135 g_object.cpp +02/09/2022 14:48 2,388 g_objectives.cpp +02/09/2022 14:48 28,469 g_rail.cpp +02/09/2022 14:48 9,292 g_ref.cpp +02/09/2022 14:48 23,886 g_roff.cpp +02/09/2022 14:48 32,329 g_savegame.cpp +02/09/2022 14:48 6,362 g_session.cpp +02/09/2022 14:48 49,135 g_spawn.cpp +02/09/2022 14:48 28,795 g_svcmds.cpp +02/09/2022 14:48 33,780 g_target.cpp +02/09/2022 14:48 8,700 G_Timer.cpp +02/09/2022 14:48 46,871 g_trigger.cpp +02/09/2022 14:48 71,207 g_turret.cpp +02/09/2022 14:48 8,066 g_usable.cpp +02/09/2022 14:48 49,422 g_utils.cpp +02/09/2022 14:48 19,992 g_vehicleLoad.cpp +02/09/2022 14:48 95,055 g_vehicles.cpp +02/09/2022 14:48 48,347 g_weapon.cpp +02/09/2022 14:48 37,705 g_weaponLoad.cpp +02/09/2022 14:48 66,406 NPC.cpp +02/09/2022 14:48 57,635 NPC_behavior.cpp +02/09/2022 14:48 82,822 NPC_combat.cpp +02/09/2022 14:48 4,588 NPC_goal.cpp +02/09/2022 14:48 2,373 NPC_misc.cpp +02/09/2022 14:48 23,236 NPC_move.cpp +02/09/2022 14:48 30,175 NPC_reactions.cpp +02/09/2022 14:48 30,332 NPC_senses.cpp +02/09/2022 14:48 3,977 NPC_sounds.cpp +02/09/2022 14:48 121,818 NPC_spawn.cpp +02/09/2022 14:48 98,933 NPC_stats.cpp +02/09/2022 14:48 37,250 NPC_utils.cpp +02/09/2022 14:48 260,991 Q3_Interface.cpp +02/09/2022 14:48 34,947 SpeederNPC.cpp +02/09/2022 14:48 16,788 WalkerNPC.cpp +02/09/2022 14:48 4,794 wp_atst.cpp +02/09/2022 14:48 3,841 wp_blaster_pistol.cpp +02/09/2022 14:48 4,741 wp_blaster_rifle.cpp +02/09/2022 14:48 1,442 wp_bot_laser.cpp +02/09/2022 14:48 5,967 wp_bowcaster.cpp +02/09/2022 14:48 11,062 wp_concussion.cpp +02/09/2022 14:48 7,624 wp_demp2.cpp +02/09/2022 14:48 4,755 wp_det_pack.cpp +02/09/2022 14:48 11,258 wp_disruptor.cpp +02/09/2022 14:48 3,583 wp_emplaced_gun.cpp +02/09/2022 14:48 8,660 wp_flechette.cpp +02/09/2022 14:48 2,391 wp_melee.cpp +02/09/2022 14:48 2,902 wp_noghri_stick.cpp +02/09/2022 14:48 5,896 wp_repeater.cpp +02/09/2022 14:48 8,845 wp_rocket_launcher.cpp +02/09/2022 14:48 473,936 wp_saber.cpp +02/09/2022 14:48 74,379 wp_saberLoad.cpp +02/09/2022 14:48 2,391 wp_stun_baton.cpp +02/09/2022 14:48 14,118 wp_thermal.cpp +02/09/2022 14:48 9,188 wp_trip_mine.cpp +02/09/2022 14:48 2,940 wp_tusken.cpp + 114 File(s) 5,069,159 bytes + 0 Dir(s) 726,504,615,936 bytes free diff --git a/Projects/Android/jni/OpenJK/codemp/ghoul2/G2_gore.cpp b/Projects/Android/jni/OpenJK/code/ghoul2/G2_gore.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/ghoul2/G2_gore.cpp rename to Projects/Android/jni/OpenJK/code/ghoul2/G2_gore.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/ghoul2/G2_gore.h b/Projects/Android/jni/OpenJK/code/ghoul2/G2_gore.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/ghoul2/G2_gore.h rename to Projects/Android/jni/OpenJK/code/ghoul2/G2_gore.h diff --git a/Projects/Android/jni/OpenJK/codemp/ghoul2/g2_local.h b/Projects/Android/jni/OpenJK/code/ghoul2/g2_local.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/ghoul2/g2_local.h rename to Projects/Android/jni/OpenJK/code/ghoul2/g2_local.h diff --git a/Projects/Android/jni/OpenJK/codemp/ghoul2/ghoul2_shared.h b/Projects/Android/jni/OpenJK/code/ghoul2/ghoul2_shared.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/ghoul2/ghoul2_shared.h rename to Projects/Android/jni/OpenJK/code/ghoul2/ghoul2_shared.h diff --git a/Projects/Android/jni/OpenJK/codemp/icarus/GameInterface.cpp b/Projects/Android/jni/OpenJK/code/icarus/GameInterface.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/icarus/GameInterface.cpp rename to Projects/Android/jni/OpenJK/code/icarus/GameInterface.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/icarus/GameInterface.h b/Projects/Android/jni/OpenJK/code/icarus/GameInterface.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/icarus/GameInterface.h rename to Projects/Android/jni/OpenJK/code/icarus/GameInterface.h diff --git a/Projects/Android/jni/OpenJK/codemp/icarus/Instance.cpp b/Projects/Android/jni/OpenJK/code/icarus/Instance.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/icarus/Instance.cpp rename to Projects/Android/jni/OpenJK/code/icarus/Instance.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/icarus/Interface.cpp b/Projects/Android/jni/OpenJK/code/icarus/Interface.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/icarus/Interface.cpp rename to Projects/Android/jni/OpenJK/code/icarus/Interface.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/icarus/Interpreter.cpp b/Projects/Android/jni/OpenJK/code/icarus/Interpreter.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/icarus/Interpreter.cpp rename to Projects/Android/jni/OpenJK/code/icarus/Interpreter.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/icarus/Memory.cpp b/Projects/Android/jni/OpenJK/code/icarus/Memory.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/icarus/Memory.cpp rename to Projects/Android/jni/OpenJK/code/icarus/Memory.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/icarus/Q3_Interface.cpp b/Projects/Android/jni/OpenJK/code/icarus/Q3_Interface.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/icarus/Q3_Interface.cpp rename to Projects/Android/jni/OpenJK/code/icarus/Q3_Interface.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/icarus/Q3_Interface.h b/Projects/Android/jni/OpenJK/code/icarus/Q3_Interface.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/icarus/Q3_Interface.h rename to Projects/Android/jni/OpenJK/code/icarus/Q3_Interface.h diff --git a/Projects/Android/jni/OpenJK/codemp/icarus/Q3_Registers.cpp b/Projects/Android/jni/OpenJK/code/icarus/Q3_Registers.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/icarus/Q3_Registers.cpp rename to Projects/Android/jni/OpenJK/code/icarus/Q3_Registers.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/icarus/Q3_Registers.h b/Projects/Android/jni/OpenJK/code/icarus/Q3_Registers.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/icarus/Q3_Registers.h rename to Projects/Android/jni/OpenJK/code/icarus/Q3_Registers.h diff --git a/Projects/Android/jni/OpenJK/codemp/icarus/Tokenizer.cpp b/Projects/Android/jni/OpenJK/code/icarus/Tokenizer.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/icarus/Tokenizer.cpp rename to Projects/Android/jni/OpenJK/code/icarus/Tokenizer.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/icarus/icarus.h b/Projects/Android/jni/OpenJK/code/icarus/icarus.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/icarus/icarus.h rename to Projects/Android/jni/OpenJK/code/icarus/icarus.h diff --git a/Projects/Android/jni/OpenJK/codemp/icarus/instance.h b/Projects/Android/jni/OpenJK/code/icarus/instance.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/icarus/instance.h rename to Projects/Android/jni/OpenJK/code/icarus/instance.h diff --git a/Projects/Android/jni/OpenJK/codemp/icarus/interface.h b/Projects/Android/jni/OpenJK/code/icarus/interface.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/icarus/interface.h rename to Projects/Android/jni/OpenJK/code/icarus/interface.h diff --git a/Projects/Android/jni/OpenJK/codemp/icarus/interpreter.h b/Projects/Android/jni/OpenJK/code/icarus/interpreter.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/icarus/interpreter.h rename to Projects/Android/jni/OpenJK/code/icarus/interpreter.h diff --git a/Projects/Android/jni/OpenJK/codemp/icarus/tokenizer.h b/Projects/Android/jni/OpenJK/code/icarus/tokenizer.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/icarus/tokenizer.h rename to Projects/Android/jni/OpenJK/code/icarus/tokenizer.h diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/GenericParser2.cpp b/Projects/Android/jni/OpenJK/code/qcommon/GenericParser2.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/GenericParser2.cpp rename to Projects/Android/jni/OpenJK/code/qcommon/GenericParser2.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/GenericParser2.h b/Projects/Android/jni/OpenJK/code/qcommon/GenericParser2.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/GenericParser2.h rename to Projects/Android/jni/OpenJK/code/qcommon/GenericParser2.h diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/RoffSystem.cpp b/Projects/Android/jni/OpenJK/code/qcommon/RoffSystem.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/RoffSystem.cpp rename to Projects/Android/jni/OpenJK/code/qcommon/RoffSystem.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/RoffSystem.h b/Projects/Android/jni/OpenJK/code/qcommon/RoffSystem.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/RoffSystem.h rename to Projects/Android/jni/OpenJK/code/qcommon/RoffSystem.h diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/huffman.cpp b/Projects/Android/jni/OpenJK/code/qcommon/huffman.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/huffman.cpp rename to Projects/Android/jni/OpenJK/code/qcommon/huffman.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/md5.cpp b/Projects/Android/jni/OpenJK/code/qcommon/md5.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/md5.cpp rename to Projects/Android/jni/OpenJK/code/qcommon/md5.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/md5.h b/Projects/Android/jni/OpenJK/code/qcommon/md5.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/md5.h rename to Projects/Android/jni/OpenJK/code/qcommon/md5.h diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/net_ip.cpp b/Projects/Android/jni/OpenJK/code/qcommon/net_ip.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/net_ip.cpp rename to Projects/Android/jni/OpenJK/code/qcommon/net_ip.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-common/tr_image_manipulation.cpp b/Projects/Android/jni/OpenJK/code/rd-common/tr_image_manipulation.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-common/tr_image_manipulation.cpp rename to Projects/Android/jni/OpenJK/code/rd-common/tr_image_manipulation.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/CMakeLists.txt b/Projects/Android/jni/OpenJK/code/rd-gles/CMakeLists.txt similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/CMakeLists.txt rename to Projects/Android/jni/OpenJK/code/rd-gles/CMakeLists.txt diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/G2_API.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/G2_API.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/G2_API.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/G2_API.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/G2_bolts.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/G2_bolts.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/G2_bolts.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/G2_bolts.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/G2_bones.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/G2_bones.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/G2_bones.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/G2_bones.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/G2_misc.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/G2_misc.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/G2_misc.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/G2_misc.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/G2_surfaces.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/G2_surfaces.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/G2_surfaces.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/G2_surfaces.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/glext.h b/Projects/Android/jni/OpenJK/code/rd-gles/glext.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/glext.h rename to Projects/Android/jni/OpenJK/code/rd-gles/glext.h diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/qgl.h b/Projects/Android/jni/OpenJK/code/rd-gles/qgl.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/qgl.h rename to Projects/Android/jni/OpenJK/code/rd-gles/qgl.h diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/qgl_linked.h b/Projects/Android/jni/OpenJK/code/rd-gles/qgl_linked.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/qgl_linked.h rename to Projects/Android/jni/OpenJK/code/rd-gles/qgl_linked.h diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_WorldEffects.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_WorldEffects.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_WorldEffects.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_WorldEffects.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_WorldEffects.h b/Projects/Android/jni/OpenJK/code/rd-gles/tr_WorldEffects.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_WorldEffects.h rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_WorldEffects.h diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_arioche.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_arioche.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_arioche.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_arioche.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_backend.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_backend.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_backend.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_backend.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_bsp.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_bsp.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_bsp.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_bsp.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_cmds.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_cmds.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_cmds.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_cmds.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_curve.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_curve.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_curve.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_curve.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_decals.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_decals.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_decals.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_decals.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_ghoul2.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_ghoul2.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_ghoul2.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_ghoul2.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_image.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_image.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_image.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_image.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_init.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_init.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_init.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_init.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_landscape.h b/Projects/Android/jni/OpenJK/code/rd-gles/tr_landscape.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_landscape.h rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_landscape.h diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_light.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_light.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_light.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_light.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_local.h b/Projects/Android/jni/OpenJK/code/rd-gles/tr_local.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_local.h rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_local.h diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_main.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_main.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_main.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_main.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_marks.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_marks.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_marks.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_marks.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_mesh.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_mesh.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_mesh.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_mesh.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_model.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_model.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_model.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_model.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_quicksprite.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_quicksprite.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_quicksprite.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_quicksprite.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_quicksprite.h b/Projects/Android/jni/OpenJK/code/rd-gles/tr_quicksprite.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_quicksprite.h rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_quicksprite.h diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_scene.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_scene.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_scene.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_scene.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_shade.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_shade.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_shade.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_shade.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_shade_calc.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_shade_calc.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_shade_calc.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_shade_calc.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_shader.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_shader.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_shader.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_shader.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_shadows.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_shadows.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_shadows.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_shadows.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_skin.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_skin.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_skin.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_skin.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_sky.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_sky.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_sky.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_sky.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_subs.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_subs.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_subs.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_subs.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_surface.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_surface.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_surface.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_surface.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_surfacesprites.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_surfacesprites.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_surfacesprites.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_surfacesprites.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_terrain.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_terrain.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_terrain.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_terrain.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-gles/tr_world.cpp b/Projects/Android/jni/OpenJK/code/rd-gles/tr_world.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-gles/tr_world.cpp rename to Projects/Android/jni/OpenJK/code/rd-gles/tr_world.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/server/NPCNav/navigator.cpp b/Projects/Android/jni/OpenJK/code/server/NPCNav/navigator.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/server/NPCNav/navigator.cpp rename to Projects/Android/jni/OpenJK/code/server/NPCNav/navigator.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/server/NPCNav/navigator.h b/Projects/Android/jni/OpenJK/code/server/NPCNav/navigator.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/server/NPCNav/navigator.h rename to Projects/Android/jni/OpenJK/code/server/NPCNav/navigator.h diff --git a/Projects/Android/jni/OpenJK/codemp/server/sv_bot.cpp b/Projects/Android/jni/OpenJK/code/server/sv_bot.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/server/sv_bot.cpp rename to Projects/Android/jni/OpenJK/code/server/sv_bot.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/server/sv_challenge.cpp b/Projects/Android/jni/OpenJK/code/server/sv_challenge.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/server/sv_challenge.cpp rename to Projects/Android/jni/OpenJK/code/server/sv_challenge.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/server/sv_gameapi.cpp b/Projects/Android/jni/OpenJK/code/server/sv_gameapi.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/server/sv_gameapi.cpp rename to Projects/Android/jni/OpenJK/code/server/sv_gameapi.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/server/sv_gameapi.h b/Projects/Android/jni/OpenJK/code/server/sv_gameapi.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/server/sv_gameapi.h rename to Projects/Android/jni/OpenJK/code/server/sv_gameapi.h diff --git a/Projects/Android/jni/OpenJK/codemp/server/sv_net_chan.cpp b/Projects/Android/jni/OpenJK/code/server/sv_net_chan.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/server/sv_net_chan.cpp rename to Projects/Android/jni/OpenJK/code/server/sv_net_chan.cpp diff --git a/Projects/Android/jni/OpenJK/code/ui/list.txt b/Projects/Android/jni/OpenJK/code/ui/list.txt new file mode 100644 index 0000000..a8a913d --- /dev/null +++ b/Projects/Android/jni/OpenJK/code/ui/list.txt @@ -0,0 +1,14 @@ + Volume in drive C is Windows + Volume Serial Number is 7008-7702 + + Directory of C:\Dev\Quest\JKQuest\VrSamples\JKQuest\Projects\Android\jni\OpenJK\code\ui + +02/09/2022 14:48 1,323 gameinfo.cpp +02/09/2022 14:48 10,803 ui_atoms.cpp +02/09/2022 14:48 3,142 ui_connect.cpp +02/09/2022 14:48 167,750 ui_main.cpp +02/09/2022 14:48 23,618 ui_saber.cpp +02/09/2022 14:48 239,737 ui_shared.cpp +02/09/2022 14:48 4,007 ui_syscalls.cpp + 7 File(s) 450,380 bytes + 0 Dir(s) 726,378,385,408 bytes free diff --git a/Projects/Android/jni/OpenJK/codemp/README.md b/Projects/Android/jni/OpenJK/codemp_delete/README.md similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/README.md rename to Projects/Android/jni/OpenJK/codemp_delete/README.md diff --git a/Projects/Android/jni/OpenJK/codemp/Ratl/bits_vs.h b/Projects/Android/jni/OpenJK/codemp_delete/Ratl/bits_vs.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/Ratl/bits_vs.h rename to Projects/Android/jni/OpenJK/codemp_delete/Ratl/bits_vs.h diff --git a/Projects/Android/jni/OpenJK/codemp/Ratl/ratl_common.h b/Projects/Android/jni/OpenJK/codemp_delete/Ratl/ratl_common.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/Ratl/ratl_common.h rename to Projects/Android/jni/OpenJK/codemp_delete/Ratl/ratl_common.h diff --git a/Projects/Android/jni/OpenJK/codemp/Ratl/vector_vs.h b/Projects/Android/jni/OpenJK/codemp_delete/Ratl/vector_vs.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/Ratl/vector_vs.h rename to Projects/Android/jni/OpenJK/codemp_delete/Ratl/vector_vs.h diff --git a/Projects/Android/jni/OpenJK/codemp/Ravl/CVec.h b/Projects/Android/jni/OpenJK/codemp_delete/Ravl/CVec.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/Ravl/CVec.h rename to Projects/Android/jni/OpenJK/codemp_delete/Ravl/CVec.h diff --git a/Projects/Android/jni/OpenJK/codemp_delete/android/android-jni.cpp b/Projects/Android/jni/OpenJK/codemp_delete/android/android-jni.cpp new file mode 100644 index 0000000..1d04348 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/android/android-jni.cpp @@ -0,0 +1,791 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include +#include + +//#include "TouchControlsContainer.h" +//#include "JNITouchControlsUtils.h" + +extern "C" +{ + +#include "src/ui/keycodes.h" + +#include "in_android.h" + + +#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO,"JNI", __VA_ARGS__)) +#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "JNI", __VA_ARGS__)) +#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR,"JNI", __VA_ARGS__)) + +#define JAVA_FUNC(x) Java_com_beloko_opengames_rtcw_NativeLib_##x + +int android_screen_width; +int android_screen_height; + + +#define KEY_SHOW_WEAPONS 0x1000 +#define KEY_SHOOT 0x1001 + +#define KEY_SHOW_INV 0x1006 +#define KEY_QUICK_CMD 0x1007 + +#define KEY_SHOW_KEYB 0x1009 + +float gameControlsAlpha = 0.5; +bool showWeaponCycle = false; +bool turnMouseMode = true; +bool invertLook = false; +bool precisionShoot = false; +bool showSticks = true; +bool hideTouchControls = true; +bool enableWeaponWheel = true; + +bool shooting = false; + +//set when holding down reload +bool sniperMode = false; + +static int controlsCreated = 0; +touchcontrols::TouchControlsContainer controlsContainer; + +touchcontrols::TouchControls *tcMenuMain=0; +touchcontrols::TouchControls *tcGameMain=0; +touchcontrols::TouchControls *tcGameWeapons=0; +touchcontrols::TouchControls *tcInventory=0; +touchcontrols::TouchControls *tcWeaponWheel=0; + +//So can hide and show these buttons +touchcontrols::Button *nextWeapon=0; +touchcontrols::Button *prevWeapon=0; +touchcontrols::TouchJoy *touchJoyLeft; +touchcontrols::TouchJoy *touchJoyRight; + +extern JNIEnv* env_; +JavaVM* jvm_; + + +void openGLStart() +{ + + glPushMatrix(); + //glClearColor(1.0f, 1.0f, 0.0f, 1.0f); + //glClear(GL_COLOR_BUFFER_BIT); + //LOGI("openGLStart"); + glDisable(GL_ALPHA_TEST); + glDisableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY ); + + //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glEnable (GL_BLEND); + //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + //glEnable(GL_TEXTURE_2D); + glDisable(GL_CULL_FACE); + glMatrixMode(GL_MODELVIEW); + + glPushMatrix(); + + +} + +void openGLEnd() +{ + + glPopMatrix(); + + glPopMatrix(); + +} + +void gameSettingsButton(int state) +{ + if (state == 1) + { + showTouchSettings(); + } +} + + + +extern unsigned int Sys_Milliseconds(void); + +static unsigned int reload_time_down; +void gameButton(int state,int code) +{ + if (code == KEY_SHOOT) + { + shooting = state; + PortableAction(state,PORT_ACT_ATTACK); + } + else if (code == PORT_ACT_RELOAD) + { + //If holding down the reload button, do not reload + if (state) //key down + { + reload_time_down = Sys_Milliseconds(); + } + else //up + { + //if less than 0.5 sec, reload + if (( Sys_Milliseconds() - reload_time_down) < 500) + { + PortableAction(1, PORT_ACT_RELOAD); + PortableAction(0, PORT_ACT_RELOAD); + } + } + + sniperMode = state; //Use reload button for precision aim also + } + else if (code == KEY_SHOW_WEAPONS) + { + if (state == 1) + if (!tcGameWeapons->enabled) + { + tcInventory->animateOut(5); + tcGameWeapons->animateIn(5); + } + } + else if (code == KEY_SHOW_INV) + { + if (state == 1) + { + if (!tcInventory->enabled) + { + tcGameWeapons->animateOut(5); + tcInventory->animateIn(5); + } + else + tcInventory->animateOut(5); + } + } + else if (code == KEY_QUICK_CMD){ + //if (state == 1) + // showCustomCommands(); + PortableKeyEvent(state, '~', 0); + if (state) + toggleKeyboard(); + } + else + { + PortableAction(state, code); + } +} + + +//Weapon wheel callbacks +void weaponWheelSelected(int enabled) +{ + if (enabled) + tcWeaponWheel->fade(touchcontrols::FADE_IN,5); //fade in + +} +void weaponWheel(int segment) +{ + LOGI("weaponWheel %d",segment); + int code; + if (segment == 9) + code = '0'; + else + code = '1' + segment; + + PortableKeyEvent(1,code,0); + PortableKeyEvent(0, code,0); +} + +void menuButton(int state,int code) +{ + if (code == KEY_SHOW_KEYB) + { + if (state) + toggleKeyboard(); + return; + } + PortableKeyEvent(state, code, 0); +} + +void inventoryButton(int state,int code) +{ + PortableAction(state,code); +} + +int left_double_action; +int right_double_action; + +void left_double_tap(int state) +{ + //LOGTOUCH("L double %d",state); + if (left_double_action) + PortableAction(state,left_double_action); +} + +void right_double_tap(int state) +{ + //LOGTOUCH("R double %d",state); + if (right_double_action) + PortableAction(state,right_double_action); +} + +void mouse_move(int action,float x, float y,float dx, float dy) +{ + //PortableMouse(mouse_x,mouse_y); + PortableMouseAbs(x * 640,y * 480); + if (action == TOUCHMOUSE_TAP) + { + PortableKeyEvent(1, K_MOUSE1, 0); + PortableKeyEvent(0, K_MOUSE1, 0); + } +} + +//To be set by android +float strafe_sens,forward_sens; +float pitch_sens,yaw_sens; + +void left_stick(float joy_x, float joy_y,float mouse_x, float mouse_y) +{ + joy_x *=10; + //float strafe = joy_x*joy_x; + float strafe = joy_x; + //if (joy_x < 0) + // strafe *= -1; + + PortableMove(joy_y * 15 * forward_sens,-strafe * strafe_sens); +} +void right_stick(float joy_x, float joy_y,float mouse_x, float mouse_y) +{ + //LOGI(" mouse x = %f",mouse_x); + int invert = invertLook?-1:1; + + float scale; + + if (sniperMode) + scale = 0.1; + else + scale = (shooting && precisionShoot)?0.3:1; + + if (1) + { + PortableLookPitch(LOOK_MODE_MOUSE,-mouse_y * pitch_sens * invert * scale); + + if (turnMouseMode) + PortableLookYaw(LOOK_MODE_MOUSE,mouse_x*2*yaw_sens * scale); + else + PortableLookYaw(LOOK_MODE_JOYSTICK,joy_x*6*yaw_sens * scale); + } + else + { + float y = mouse_y * mouse_y; + y *= 50; + if (mouse_y < 0) + y *= -1; + + PortableLookPitch(LOOK_MODE_MOUSE,-y * pitch_sens * invert * scale); + + float x = mouse_x * mouse_x; + x *= 100; + if (mouse_x < 0) + x *= -1; + + if (turnMouseMode) + PortableLookYaw(LOOK_MODE_MOUSE,x*2*yaw_sens * scale); + else + PortableLookYaw(LOOK_MODE_JOYSTICK,joy_x*6*yaw_sens * scale); + + } +} + +//Weapon select callbacks +void selectWeaponButton(int state, int code) +{ + PortableKeyEvent(state, code, 0); + if (state == 0) + tcGameWeapons->animateOut(5); +} + +void weaponCycle(bool v) +{ + if (v) + { + if (nextWeapon) nextWeapon->setEnabled(true); + if (prevWeapon) prevWeapon->setEnabled(true); + } + else + { + if (nextWeapon) nextWeapon->setEnabled(false); + if (prevWeapon) prevWeapon->setEnabled(false); + } +} + +void setHideSticks(bool v) +{ + if (touchJoyLeft) touchJoyLeft->setHideGraphics(v); + if (touchJoyRight) touchJoyRight->setHideGraphics(v); +} + + +void initControls(int width, int height,const char * graphics_path,const char *settings_file) +{ + touchcontrols::GLScaleWidth = (float)width; + touchcontrols::GLScaleHeight = (float)height; + + LOGI("initControls %d x %d,x path = %s, settings = %s",width,height,graphics_path,settings_file); + + if (!controlsCreated) + { + LOGI("creating controls"); + + touchcontrols::setGraphicsBasePath(graphics_path); + setControlsContainer(&controlsContainer); + + controlsContainer.openGL_start.connect( sigc::ptr_fun(&openGLStart)); + controlsContainer.openGL_end.connect( sigc::ptr_fun(&openGLEnd)); + + + tcMenuMain = new touchcontrols::TouchControls("menu",true,false); + tcGameMain = new touchcontrols::TouchControls("game",false,true,1); + tcGameWeapons = new touchcontrols::TouchControls("weapons",false,true,1); + tcInventory = new touchcontrols::TouchControls("inventory",false,true,1); + tcWeaponWheel = new touchcontrols::TouchControls("weapon_wheel",false,true,1); + + tcGameMain->signal_settingsButton.connect( sigc::ptr_fun(&gameSettingsButton) ); + + //Menu + tcMenuMain->signal_button.connect( sigc::ptr_fun(&menuButton) ); + + touchcontrols::Mouse *mouse = new touchcontrols::Mouse("mouse",touchcontrols::RectF(0,0,26,16),""); + mouse->setHideGraphics(true); + tcMenuMain->addControl(mouse); + mouse->signal_action.connect(sigc::ptr_fun(&mouse_move) ); + + tcMenuMain->setAlpha(0.3); + + + //Game + tcGameMain->setAlpha(gameControlsAlpha); + tcGameMain->addControl(new touchcontrols::Button("jump",touchcontrols::RectF(24,4,26,6),"jump",PORT_ACT_JUMP)); + tcGameMain->addControl(new touchcontrols::Button("crouch",touchcontrols::RectF(24,14,26,16),"crouch",PORT_ACT_DOWN)); + tcGameMain->addControl(new touchcontrols::Button("attack",touchcontrols::RectF(20,7,23,10),"shoot",KEY_SHOOT)); + tcGameMain->addControl(new touchcontrols::Button("use",touchcontrols::RectF(23,6,26,9),"use",PORT_ACT_USE)); + tcGameMain->addControl(new touchcontrols::Button("binocular",touchcontrols::RectF(21,5,23,7),"binocular",PORT_ACT_ZOOM_IN)); + tcGameMain->addControl(new touchcontrols::Button("kick",touchcontrols::RectF(3,5,5,7),"kick",PORT_ACT_KICK)); + + tcGameMain->addControl(new touchcontrols::Button("notebook",touchcontrols::RectF(14,0,16,2),"notebook",PORT_ACT_HELPCOMP)); + tcGameMain->addControl(new touchcontrols::Button("use_inventory",touchcontrols::RectF(16,0,18,2),"inv",KEY_SHOW_INV)); + tcGameMain->addControl(new touchcontrols::Button("quick_save",touchcontrols::RectF(24,0,26,2),"save",PORT_ACT_QUICKSAVE)); + tcGameMain->addControl(new touchcontrols::Button("quick_load",touchcontrols::RectF(20,0,22,2),"load",PORT_ACT_QUICKLOAD)); + tcGameMain->addControl( new touchcontrols::Button("prompt",touchcontrols::RectF(9,0,11,2),"keyboard",KEY_QUICK_CMD)); + + + tcGameMain->addControl(new touchcontrols::Button("reload",touchcontrols::RectF(0,5,3,7),"reload_sniper",PORT_ACT_RELOAD)); + tcGameMain->addControl(new touchcontrols::Button("alt_fire",touchcontrols::RectF(13,14,15,16),"Custom_2",PORT_ACT_ALT_FIRE)); + + tcGameMain->addControl(new touchcontrols::Button("show_weapons",touchcontrols::RectF(11,14,13,16),"show_weapons",KEY_SHOW_WEAPONS)); + + nextWeapon = new touchcontrols::Button("next_weapon",touchcontrols::RectF(0,3,3,5),"next_weap",PORT_ACT_NEXT_WEP); + tcGameMain->addControl(nextWeapon); + prevWeapon = new touchcontrols::Button("prev_weapon",touchcontrols::RectF(0,7,3,9),"prev_weap",PORT_ACT_PREV_WEP); + tcGameMain->addControl(prevWeapon); + + touchJoyLeft = new touchcontrols::TouchJoy("stick",touchcontrols::RectF(0,7,8,16),"strafe_arrow"); + tcGameMain->addControl(touchJoyLeft); + touchJoyLeft->signal_move.connect(sigc::ptr_fun(&left_stick) ); + touchJoyLeft->signal_double_tap.connect(sigc::ptr_fun(&left_double_tap) ); + + touchJoyRight = new touchcontrols::TouchJoy("touch",touchcontrols::RectF(17,4,26,16),"look_arrow"); + tcGameMain->addControl(touchJoyRight); + touchJoyRight->signal_move.connect(sigc::ptr_fun(&right_stick) ); + touchJoyRight->signal_double_tap.connect(sigc::ptr_fun(&right_double_tap) ); + + tcGameMain->signal_button.connect( sigc::ptr_fun(&gameButton) ); + + //Weapons + tcGameWeapons->addControl(new touchcontrols::Button("weapon1",touchcontrols::RectF(1,14,3,16),"key_1",'1')); + tcGameWeapons->addControl(new touchcontrols::Button("weapon2",touchcontrols::RectF(3,14,5,16),"key_2",'2')); + tcGameWeapons->addControl(new touchcontrols::Button("weapon3",touchcontrols::RectF(5,14,7,16),"key_3",'3')); + tcGameWeapons->addControl(new touchcontrols::Button("weapon4",touchcontrols::RectF(7,14,9,16),"key_4",'4')); + tcGameWeapons->addControl(new touchcontrols::Button("weapon5",touchcontrols::RectF(9,14,11,16),"key_5",'5')); + + tcGameWeapons->addControl(new touchcontrols::Button("weapon6",touchcontrols::RectF(15,14,17,16),"key_6",'6')); + tcGameWeapons->addControl(new touchcontrols::Button("weapon7",touchcontrols::RectF(17,14,19,16),"key_7",'7')); + tcGameWeapons->addControl(new touchcontrols::Button("weapon8",touchcontrols::RectF(19,14,21,16),"key_8",'8')); + tcGameWeapons->addControl(new touchcontrols::Button("weapon9",touchcontrols::RectF(21,14,23,16),"key_9",'9')); + tcGameWeapons->addControl(new touchcontrols::Button("weapon0",touchcontrols::RectF(23,14,25,16),"key_0",'0')); + tcGameWeapons->signal_button.connect( sigc::ptr_fun(&selectWeaponButton) ); + tcGameWeapons->setAlpha(0.8); + + //Weapon wheel + touchcontrols::WheelSelect *wheel = new touchcontrols::WheelSelect("weapon_wheel",touchcontrols::RectF(7,2,19,14),"weapon_wheel",10); + wheel->signal_selected.connect(sigc::ptr_fun(&weaponWheel) ); + wheel->signal_enabled.connect(sigc::ptr_fun(&weaponWheelSelected)); + tcWeaponWheel->addControl(wheel); + tcWeaponWheel->setAlpha(0.5); + + //Inventory + tcInventory->addControl(new touchcontrols::Button("invuse",touchcontrols::RectF(3,14,5,16),"enter",PORT_ACT_INVUSE)); + tcInventory->addControl(new touchcontrols::Button("invprev",touchcontrols::RectF(6,14,8,16),"arrow_left",PORT_ACT_INVPREV)); + tcInventory->addControl(new touchcontrols::Button("invnext",touchcontrols::RectF(8,14,10,16),"arrow_right",PORT_ACT_INVNEXT)); + + tcInventory->signal_button.connect( sigc::ptr_fun(&inventoryButton) ); + tcInventory->setAlpha(0.5); + + + controlsContainer.addControlGroup(tcGameMain); + controlsContainer.addControlGroup(tcGameWeapons); + controlsContainer.addControlGroup(tcMenuMain); + controlsContainer.addControlGroup(tcInventory); + controlsContainer.addControlGroup(tcWeaponWheel); + controlsCreated = 1; + + tcGameMain->setXMLFile(settings_file); + tcGameWeapons->setXMLFile((std::string)graphics_path + "/weapons.xml"); + tcInventory->setXMLFile((std::string)graphics_path + "/inventory.xml"); + tcWeaponWheel->setXMLFile((std::string)graphics_path + "/weaponwheel.xml"); + } + else + LOGI("NOT creating controls"); + + controlsContainer.initGL(); +} + + +int inMenuLast = 1; +int inAutomapLast = 0; +void frameControls() +{ + int inMenuNew = PortableInMenu(); + if (inMenuLast != inMenuNew) + { + inMenuLast = inMenuNew; + if (!inMenuNew) + { + tcGameMain->setEnabled(true); + if (enableWeaponWheel) + tcWeaponWheel->setEnabled(true); + tcMenuMain->setEnabled(false); + } + else + { + tcGameMain->setEnabled(false); + tcGameWeapons->setEnabled(false); + tcWeaponWheel->setEnabled(false); + tcMenuMain->setEnabled(true); + } + } + + + weaponCycle(showWeaponCycle); + setHideSticks(!showSticks); + controlsContainer.draw(); +} + + +void setTouchSettings(float alpha,float strafe,float fwd,float pitch,float yaw,int other) +{ + + gameControlsAlpha = alpha; + if (tcGameMain) + tcGameMain->setAlpha(gameControlsAlpha); + + showWeaponCycle = other & 0x1?true:false; + turnMouseMode = other & 0x2?true:false; + invertLook = other & 0x4?true:false; + precisionShoot = other & 0x8?true:false; + showSticks = other & 0x1000?true:false; + enableWeaponWheel = other & 0x2000?true:false; + + if (tcWeaponWheel) + tcWeaponWheel->setEnabled(enableWeaponWheel); + + + hideTouchControls = other & 0x80000000?true:false; + + + switch ((other>>4) & 0xF) + { + case 1: + left_double_action = PORT_ACT_ATTACK; + break; + case 2: + left_double_action = PORT_ACT_JUMP; + break; + case 3: + left_double_action = PORT_ACT_USE; + break; + default: + left_double_action = 0; + } + + switch ((other>>8) & 0xF) + { + case 1: + right_double_action = PORT_ACT_ATTACK; + break; + case 2: + right_double_action = PORT_ACT_JUMP; + break; + case 3: + right_double_action = PORT_ACT_USE; + break; + default: + right_double_action = 0; + } + + strafe_sens = strafe; + forward_sens = fwd; + pitch_sens = pitch; + yaw_sens = yaw; + +} + +int quit_now = 0; + +#define EXPORT_ME __attribute__ ((visibility("default"))) + +JNIEnv* env_; + +int argc=1; +const char * argv[32]; +std::string graphicpath; + + +std::string game_path; +const char * getGamePath() +{ + return game_path.c_str(); +} + +std::string lib_path; +const char * getLibPath() +{ + return lib_path.c_str(); +} + +jint EXPORT_ME +JAVA_FUNC(init) ( JNIEnv* env, jobject thiz,jstring graphics_dir,jint mem_mb,jobjectArray argsArray,jint renderer,jstring game_path_ ,jstring lib_path_ ) +{ + env_ = env; + + argv[0] = "quake"; + int argCount = (env)->GetArrayLength( argsArray); + LOGI("argCount = %d",argCount); + for (int i=0; iGetObjectArrayElement( argsArray, i); + argv[argc] = (char *)(env)->GetStringUTFChars( string, 0); + LOGI("arg = %s",argv[argc]); + argc++; + } + + + game_path = (char *)(env)->GetStringUTFChars( game_path_, 0); + lib_path = (char *)(env)->GetStringUTFChars( lib_path_, 0); + + LOGI("game_path = %s",getGamePath()); + LOGI("lib_path = %s",getLibPath()); + + + PortableInit(argc,argv); + + const char * p = env->GetStringUTFChars(graphics_dir,NULL); + graphicpath = std::string(p); + + + + initControls(android_screen_width,-android_screen_height,graphicpath.c_str(),(graphicpath + "/game_controls.xml").c_str()); + + + return 0; +} + +extern int androidSwapped; + +jint EXPORT_ME +JAVA_FUNC(frame) ( JNIEnv* env, jobject thiz ) +{ + + //LOGI("frame"); + + androidSwapped = 1; + + PortableFrame(); + + if (quit_now) + { + LOGI("frame QUIT"); + return 128; + } + + + frameControls(); + + int ret = 0; + + return ret; +} + +__attribute__((visibility("default"))) jint JNI_OnLoad(JavaVM* vm, void* reserved) +{ + LOGI("JNI_OnLoad"); + jvm_ = vm; + setTCJNIEnv(vm); + + return JNI_VERSION_1_4; +} + + +void EXPORT_ME +JAVA_FUNC(keypress) (JNIEnv *env, jobject obj, jint down, jint keycode, jint unicode) +{ + LOGI("keypress %d",keycode); + if (controlsContainer.isEditing()) + { + if (down && (keycode == K_ESCAPE )) + controlsContainer.finishEditing(); + return; + } + + PortableKeyEvent(down,keycode,unicode); +} + + +void EXPORT_ME +JAVA_FUNC(touchEvent) (JNIEnv *env, jobject obj,jint action, jint pid, jfloat x, jfloat y) +{ + //LOGI("TOUCHED"); + controlsContainer.processPointer(action,pid,x,y); +} + + +void EXPORT_ME +JAVA_FUNC(doAction) (JNIEnv *env, jobject obj, jint state, jint action) +{ + //gamepadButtonPressed(); + if (hideTouchControls) + if (tcGameMain) + { + if (tcGameMain->isEnabled()) + tcGameMain->animateOut(30); + + if (tcWeaponWheel->isEnabled()) + tcWeaponWheel->animateOut(30); + } + LOGI("doAction %d %d",state,action); + + //Sniper mode for gamepad + if (action == PORT_ACT_RELOAD) + { + if (state) //key down + { + reload_time_down = Sys_Milliseconds(); + } + else //up + { + //if less than 0.5 sec, reload + if (( Sys_Milliseconds() - reload_time_down) < 500) + { + PortableAction(1, PORT_ACT_RELOAD); + PortableAction(0, PORT_ACT_RELOAD); + } + } + + sniperMode = state; //Use reload button for precision aim also + return; + } + + PortableAction(state,action); +} + +void EXPORT_ME +JAVA_FUNC(analogFwd) (JNIEnv *env, jobject obj, jfloat v) +{ + PortableMoveFwd(v); +} + +void EXPORT_ME +JAVA_FUNC(analogSide) (JNIEnv *env, jobject obj,jfloat v) +{ + PortableMoveSide(v); +} + +void EXPORT_ME +JAVA_FUNC(analogPitch) (JNIEnv *env, jobject obj,jint mode,jfloat v) +{ + if (sniperMode) + v *= 0.1; + + PortableLookPitch(mode, v); +} + +void EXPORT_ME +JAVA_FUNC(analogYaw) (JNIEnv *env, jobject obj, jint mode,jfloat v) +{ + if (sniperMode) + v *= 0.1; + + PortableLookYaw(mode, v); +} + +void EXPORT_ME +JAVA_FUNC(setTouchSettings) (JNIEnv *env, jobject obj, jfloat alpha,jfloat strafe,jfloat fwd,jfloat pitch,jfloat yaw,int other) +{ + setTouchSettings(alpha,strafe,fwd,pitch,yaw,other); +} + +std::string quickCommandString; +jint EXPORT_ME +JAVA_FUNC(quickCommand) (JNIEnv *env, jobject obj, jstring command) +{ + const char * p = env->GetStringUTFChars(command,NULL); + quickCommandString = std::string(p) + "\n"; + env->ReleaseStringUTFChars(command, p); + PortableCommand(quickCommandString.c_str()); + return 0; +} + + +void EXPORT_ME +JAVA_FUNC(setScreenSize) ( JNIEnv* env, jobject thiz, jint width, jint height) +{ + android_screen_width = width; + android_screen_height = height; +} + + +void bqPause(int p); +void EXPORT_ME +JAVA_FUNC(pauseAudio) ( JNIEnv* env, jobject thiz, jint v) +{ + bqPause(v); +} + + + +static JNIEnv *my_getJNIEnv ( ) +{ + JNIEnv *pJNIEnv ; + + if ( jvm_ && ( jvm_->GetEnv ( (void**) &pJNIEnv, JNI_VERSION_1_4 ) >= 0 ) ) + { + return pJNIEnv ; + } + return NULL ; +} + +} diff --git a/Projects/Android/jni/OpenJK/codemp_delete/android/android_glimp.cpp b/Projects/Android/jni/OpenJK/codemp_delete/android/android_glimp.cpp new file mode 100644 index 0000000..c26d4d3 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/android/android_glimp.cpp @@ -0,0 +1,736 @@ +/* +=========================================================================== + +Return to Castle Wolfenstein single player GPL Source Code +Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company. + +This file is part of the Return to Castle Wolfenstein single player GPL Source Code (“RTCW SP Source Code”). + +RTCW SP 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 3 of the License, or +(at your option) any later version. + +RTCW SP 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 RTCW SP Source Code. If not, see . + +In addition, the RTCW SP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW SP Source Code. If not, please request a copy in writing from id Software at the address below. + +If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. + +=========================================================================== + */ + +/* + ** GLW_IMP.C + ** + ** This file contains ALL Linux specific stuff having to do with the + ** OpenGL refresh. When a port is being made the following functions + ** must be implemented by the port: + ** + ** GLimp_EndFrame + ** GLimp_Init + ** GLimp_Shutdown + ** GLimp_SwitchFullscreen + ** GLimp_SetGamma + ** + */ + +#include +#include +#ifdef __linux__ +#include +#include +#endif +#include +#include +#include +#include +#include + +// bk001204 +#include + +// bk001206 - from my Heretic2 by way of Ryan's Fakk2 +// Needed for the new X11_PendingInput() function. +#include +#include +#include + +#include "../renderer/tr_local.h" +#include "../client/client.h" +#include "android_local.h" // bk001130 +#include "EGL/egl.h" + +#define WINDOW_CLASS_NAME "Return to Castle Wolfenstein" + +typedef enum +{ + RSERR_OK, + + RSERR_INVALID_FULLSCREEN, + RSERR_INVALID_MODE, + + RSERR_UNKNOWN +} rserr_t; + + + +void myglMultiTexCoord2f( GLenum texture, GLfloat s, GLfloat t ) +{ + glMultiTexCoord4f(texture, s, t, 0, 1); +} + + + +static cvar_t *in_mouse; +static cvar_t *in_dgamouse; + +// bk001130 - from cvs1.17 (mkv), but not static +cvar_t *in_joystick = NULL; +cvar_t *in_joystickDebug = NULL; +cvar_t *joy_threshold = NULL; + +cvar_t *r_allowSoftwareGL; // don't abort out if the pixelformat claims software +cvar_t *r_previousglDriver; + +//static int default_dotclock_vidmode; // bk001204 - unused +static int num_vidmodes; +static qboolean vidmode_active = qfalse; + + +/* + * Find the first occurrence of find in s. + */ +// bk001130 - from cvs1.17 (mkv), const +// bk001130 - made first argument const +static const char *Q_stristr( const char *s, const char *find ) { + register char c, sc; + register size_t len; + + if ( ( c = *find++ ) != 0 ) { + if ( c >= 'a' && c <= 'z' ) { + c -= ( 'a' - 'A' ); + } + len = strlen( find ); + do + { + do + { + if ( ( sc = *s++ ) == 0 ) { + return NULL; + } + if ( sc >= 'a' && sc <= 'z' ) { + sc -= ( 'a' - 'A' ); + } + } while ( sc != c ); + } while ( Q_stricmpn( s, find, len ) != 0 ); + s--; + } + return s; +} + + + +void IN_ActivateMouse( void ) { + +} + +void IN_DeactivateMouse( void ) { + +} +/*****************************************************************************/ + +static qboolean signalcaught = qfalse;; + +void Sys_Exit( int ); // bk010104 - abstraction + +static void signal_handler( int sig ) { // bk010104 - replace this... (NOTE TTimo huh?) + if ( signalcaught ) { + printf( "DOUBLE SIGNAL FAULT: Received signal %d, exiting...\n", sig ); + Sys_Exit( 1 ); // bk010104 - abstraction + } + + signalcaught = qtrue; + printf( "Received signal %d, exiting...\n", sig ); + GLimp_Shutdown(); // bk010104 - shouldn't this be CL_Shutdown + Sys_Exit( 0 ); // bk010104 - abstraction NOTE TTimo send a 0 to avoid DOUBLE SIGNAL FAULT +} + +static void InitSig( void ) { + + return; + + + signal( SIGHUP, signal_handler ); + signal( SIGQUIT, signal_handler ); + signal( SIGILL, signal_handler ); + signal( SIGTRAP, signal_handler ); + signal( SIGIOT, signal_handler ); + signal( SIGBUS, signal_handler ); + signal( SIGFPE, signal_handler ); + signal( SIGSEGV, signal_handler ); + signal( SIGTERM, signal_handler ); +} + +/* + ** GLimp_SetGamma + ** + ** This routine should only be called if glConfig.deviceSupportsGamma is TRUE + */ +void GLimp_SetGamma( unsigned char red[256], unsigned char green[256], unsigned char blue[256] ) { + +} + +/* + ** GLimp_Shutdown + ** + ** This routine does all OS specific shutdown procedures for the OpenGL + ** subsystem. Under OpenGL this means NULLing out the current DC and + ** HGLRC, deleting the rendering context, and releasing the DC acquired + ** for the window. The state structure is also nulled out. + ** + */ +void GLimp_Shutdown( void ) { + + memset( &glConfig, 0, sizeof( glConfig ) ); + memset( &glState, 0, sizeof( glState ) ); + + QGL_Shutdown(); +} + +/* + ** GLimp_LogComment + */ +void GLimp_LogComment( char *comment ) { + +} + +/* + ** GLW_StartDriverAndSetMode + */ +// bk001204 - prototype needed +int GLW_SetMode( const char *drivername, int mode, qboolean fullscreen ); +static qboolean GLW_StartDriverAndSetMode( const char *drivername, + int mode, + qboolean fullscreen ) { + rserr_t err; + + // don't ever bother going into fullscreen with a voodoo card +#if 1 // JDC: I reenabled this + if ( Q_stristr( drivername, "Voodoo" ) ) { + ri.Cvar_Set( "r_fullscreen", "0" ); + r_fullscreen->modified = qfalse; + fullscreen = qfalse; + } +#endif + + err = GLW_SetMode( drivername, mode, fullscreen ); + + switch ( err ) + { + case RSERR_INVALID_FULLSCREEN: + ri.Printf( PRINT_ALL, "...WARNING: fullscreen unavailable in this mode\n" ); + return qfalse; + case RSERR_INVALID_MODE: + ri.Printf( PRINT_ALL, "...WARNING: could not set the given mode (%d)\n", mode ); + return qfalse; + default: + break; + } + return qtrue; +} + + +void VR_GetScreenRes(int *width, int *height); + +/* + ** GLW_InitExtensions + */ +static void GLW_InitExtensions( void ) { + if ( !r_allowExtensions->integer ) { + ri.Printf( PRINT_ALL, "*** IGNORING OPENGL EXTENSIONS ***\n" ); + return; + } + + ri.Printf( PRINT_ALL, "Initializing OpenGL extensions\n" ); + +#ifndef HAVE_GLES + // GL_S3_s3tc + if ( Q_stristr( glConfig.extensions_string, "GL_S3_s3tc" ) ) { + if ( r_ext_compressed_textures->value ) { + glConfig.textureCompression = TC_S3TC; + ri.Printf( PRINT_ALL, "...using GL_S3_s3tc\n" ); + } else + { + glConfig.textureCompression = TC_NONE; + ri.Printf( PRINT_ALL, "...ignoring GL_S3_s3tc\n" ); + } + } else +#endif + { + glConfig.textureCompression = TC_NONE; + ri.Printf( PRINT_ALL, "...GL_S3_s3tc not found\n" ); + } + + // GL_EXT_texture_env_add +#ifdef HAVE_GLES + glConfig.textureEnvAddAvailable = qtrue; + ri.Printf( PRINT_ALL, "...using GL_EXT_texture_env_add\n" ); +#else + glConfig.textureEnvAddAvailable = qfalse; + if ( Q_stristr( glConfig.extensions_string, "EXT_texture_env_add" ) ) { + if ( r_ext_texture_env_add->integer ) { + glConfig.textureEnvAddAvailable = qtrue; + ri.Printf( PRINT_ALL, "...using GL_EXT_texture_env_add\n" ); + } else + { + glConfig.textureEnvAddAvailable = qfalse; + ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_env_add\n" ); + } + } else + { + ri.Printf( PRINT_ALL, "...GL_EXT_texture_env_add not found\n" ); + } +#endif + + // GL_ARB_multitexture + qglMultiTexCoord2fARB = NULL; + qglActiveTextureARB = NULL; + qglClientActiveTextureARB = NULL; +#ifdef HAVE_GLES + qglGetIntegerv( GL_MAX_TEXTURE_UNITS, &glConfig.maxActiveTextures ); + //ri.Printf( PRINT_ALL, "...not using GL_ARB_multitexture, %i texture units\n", glConfig.maxActiveTextures ); + //glConfig.maxActiveTextures=4; + qglMultiTexCoord2fARB = myglMultiTexCoord2f; + qglActiveTextureARB = glActiveTexture; + qglClientActiveTextureARB = glClientActiveTexture; + if ( glConfig.maxActiveTextures > 1 ) + { + ri.Printf( PRINT_ALL, "...using GL_ARB_multitexture (%i texture units)\n", glConfig.maxActiveTextures ); + } + else + { + qglMultiTexCoord2fARB = NULL; + qglActiveTextureARB = NULL; + qglClientActiveTextureARB = NULL; + ri.Printf( PRINT_ALL, "...not using GL_ARB_multitexture, < 2 texture units\n" ); + } +#else + if ( Q_stristr( glConfig.extensions_string, "GL_ARB_multitexture" ) ) { + if ( r_ext_multitexture->value ) { + qglMultiTexCoord2fARB = ( PFNGLMULTITEXCOORD2FARBPROC ) dlsym( glw_state.OpenGLLib, "glMultiTexCoord2fARB" ); + qglActiveTextureARB = ( PFNGLACTIVETEXTUREARBPROC ) dlsym( glw_state.OpenGLLib, "glActiveTextureARB" ); + qglClientActiveTextureARB = ( PFNGLCLIENTACTIVETEXTUREARBPROC ) dlsym( glw_state.OpenGLLib, "glClientActiveTextureARB" ); + + if ( qglActiveTextureARB ) { + qglGetIntegerv( GL_MAX_ACTIVE_TEXTURES_ARB, &glConfig.maxActiveTextures ); + + if ( glConfig.maxActiveTextures > 1 ) { + ri.Printf( PRINT_ALL, "...using GL_ARB_multitexture\n" ); + } else + { + qglMultiTexCoord2fARB = NULL; + qglActiveTextureARB = NULL; + qglClientActiveTextureARB = NULL; + ri.Printf( PRINT_ALL, "...not using GL_ARB_multitexture, < 2 texture units\n" ); + } + } + } else + { + ri.Printf( PRINT_ALL, "...ignoring GL_ARB_multitexture\n" ); + } + } else + { + ri.Printf( PRINT_ALL, "...GL_ARB_multitexture not found\n" ); + } +#endif + + // GL_EXT_compiled_vertex_array +#ifndef HAVE_GLES + if ( Q_stristr( glConfig.extensions_string, "GL_EXT_compiled_vertex_array" ) ) { + if ( r_ext_compiled_vertex_array->value ) { + ri.Printf( PRINT_ALL, "...using GL_EXT_compiled_vertex_array\n" ); + qglLockArraysEXT = ( void ( APIENTRY * )( int, int ) )dlsym( glw_state.OpenGLLib, "glLockArraysEXT" ); + qglUnlockArraysEXT = ( void ( APIENTRY * )( void ) )dlsym( glw_state.OpenGLLib, "glUnlockArraysEXT" ); + if ( !qglLockArraysEXT || !qglUnlockArraysEXT ) { + ri.Error( ERR_FATAL, "bad getprocaddress" ); + } + } else + { + ri.Printf( PRINT_ALL, "...ignoring GL_EXT_compiled_vertex_array\n" ); + } + } else +#endif + { + ri.Printf( PRINT_ALL, "...GL_EXT_compiled_vertex_array not found\n" ); + } + + // GL_NV_fog_distance +#ifndef HAVE_GLES + if ( Q_stristr( glConfig.extensions_string, "GL_NV_fog_distance" ) ) { + if ( r_ext_NV_fog_dist->integer ) { + glConfig.NVFogAvailable = qtrue; + ri.Printf( PRINT_ALL, "...using GL_NV_fog_distance\n" ); + } else { + ri.Printf( PRINT_ALL, "...ignoring GL_NV_fog_distance\n" ); + ri.Cvar_Set( "r_ext_NV_fog_dist", "0" ); + } + } else +#endif + { + ri.Printf( PRINT_ALL, "...GL_NV_fog_distance not found\n" ); + ri.Cvar_Set( "r_ext_NV_fog_dist", "0" ); + } + +} + +static void GLW_InitGamma() { + + glConfig.deviceSupportsGamma = qfalse; + +} + +/* + ** GLW_LoadOpenGL + ** + ** GLimp_win.c internal function that that attempts to load and use + ** a specific OpenGL DLL. + */ +static qboolean GLW_LoadOpenGL( const char *name ) { + qboolean fullscreen; + + ri.Printf( PRINT_ALL, "...loading %s: ", name ); + +#ifndef HAVE_GLES + // disable the 3Dfx splash screen and set gamma + // we do this all the time, but it shouldn't hurt anything + // on non-3Dfx stuff + putenv( "FX_GLIDE_NO_SPLASH=0" ); + + // Mesa VooDoo hacks + putenv( "MESA_GLX_FX=fullscreen\n" ); +#endif + // load the QGL layer + if ( QGL_Init( name ) ) { +#ifdef PANDORA + fullscreen = 1; +#else + fullscreen = r_fullscreen->integer; +#endif + + // create the window and set up the context + if ( !GLW_StartDriverAndSetMode( name, r_mode->integer, fullscreen ) ) { + if ( r_mode->integer != 3 ) { + if ( !GLW_StartDriverAndSetMode( name, 3, fullscreen ) ) { + goto fail; + } + } else { + goto fail; + } + } + + return qtrue; + } else + { + ri.Printf( PRINT_ALL, "failed\n" ); + } + fail: + + QGL_Shutdown(); + + return qfalse; +} + + + +/* + ** GLimp_Init + ** + ** This routine is responsible for initializing the OS specific portions + ** of OpenGL. + */ +void GLimp_Init( void ) { + qboolean attemptedlibGL = qfalse; + qboolean attempted3Dfx = qfalse; + qboolean success = qfalse; + char buf[1024]; + cvar_t *lastValidRenderer = ri.Cvar_Get( "r_lastValidRenderer", "(uninitialized)", CVAR_ARCHIVE ); + // cvar_t *cv; // bk001204 - unused + + r_allowSoftwareGL = ri.Cvar_Get( "r_allowSoftwareGL", "0", CVAR_LATCH ); + + r_previousglDriver = ri.Cvar_Get( "r_previousglDriver", "", CVAR_ROM ); + + InitSig(); + + // Hack here so that if the UI + if ( *r_previousglDriver->string ) { + // The UI changed it on us, hack it back + // This means the renderer can't be changed on the fly + ri.Cvar_Set( "r_glDriver", r_previousglDriver->string ); + } + + int android_screen_width; + int android_screen_height; + VR_GetScreenRes(&android_screen_width, &android_screen_height); + glConfig.vidWidth = android_screen_width; + glConfig.vidHeight = android_screen_height; + glConfig.colorBits = 32; + glConfig.depthBits = 16; + glConfig.stencilBits = 8; + + + + // Save it in case the UI stomps it + ri.Cvar_Set( "r_previousglDriver", r_glDriver->string ); + + // This values force the UI to disable driver selection + glConfig.driverType = GLDRV_ICD; + glConfig.hardwareType = GLHW_GENERIC; + + // get our config strings + Q_strncpyz( glConfig.vendor_string, qglGetString( GL_VENDOR ), sizeof( glConfig.vendor_string ) ); + Q_strncpyz( glConfig.renderer_string, qglGetString( GL_RENDERER ), sizeof( glConfig.renderer_string ) ); + if ( *glConfig.renderer_string && glConfig.renderer_string[strlen( glConfig.renderer_string ) - 1] == '\n' ) { + glConfig.renderer_string[strlen( glConfig.renderer_string ) - 1] = 0; + } + Q_strncpyz( glConfig.version_string, qglGetString( GL_VERSION ), sizeof( glConfig.version_string ) ); + Q_strncpyz( glConfig.extensions_string, qglGetString( GL_EXTENSIONS ), sizeof( glConfig.extensions_string ) ); + + // + // chipset specific configuration + // + strcpy( buf, glConfig.renderer_string ); + strlwr( buf ); + + // + // NOTE: if changing cvars, do it within this block. This allows them + // to be overridden when testing driver fixes, etc. but only sets + // them to their default state when the hardware is first installed/run. + // + /*if ( Q_stricmp( lastValidRenderer->string, glConfig.renderer_string ) ) { + glConfig.hardwareType = GLHW_GENERIC; + + ri.Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_LINEAR" ); + + // VOODOO GRAPHICS w/ 2MB + if ( Q_stristr( buf, "voodoo graphics/1 tmu/2 mb" ) ) { + ri.Cvar_Set( "r_picmip", "2" ); + ri.Cvar_Get( "r_picmip", "1", CVAR_ARCHIVE | CVAR_LATCH ); + } else + { + ri.Cvar_Set( "r_picmip", "1" ); + + if ( Q_stristr( buf, "rage 128" ) || Q_stristr( buf, "rage128" ) ) { + ri.Cvar_Set( "r_finish", "0" ); + } + // Savage3D and Savage4 should always have trilinear enabled + else if ( Q_stristr( buf, "savage3d" ) || Q_stristr( buf, "s3 savage4" ) ) { + ri.Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" ); + } + } + }*/ + + // + // this is where hardware specific workarounds that should be + // detected/initialized every startup should go. + // + if ( Q_stristr( buf, "banshee" ) || Q_stristr( buf, "Voodoo_Graphics" ) ) { + glConfig.hardwareType = GLHW_3DFX_2D3D; + } else if ( Q_stristr( buf, "rage pro" ) || Q_stristr( buf, "RagePro" ) ) { + glConfig.hardwareType = GLHW_RAGEPRO; + } else if ( Q_stristr( buf, "permedia2" ) ) { + glConfig.hardwareType = GLHW_PERMEDIA2; + } else if ( Q_stristr( buf, "riva 128" ) ) { + glConfig.hardwareType = GLHW_RIVA128; + } else if ( Q_stristr( buf, "riva tnt " ) ) { + } + + ri.Cvar_Set( "r_lastValidRenderer", glConfig.renderer_string ); + + //TEST!!! + //ri.Cvar_Set( "r_picmip", "0" ); + //ri.Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" ); + //!!!! + + + // initialize extensions + GLW_InitExtensions(); + GLW_InitGamma(); + + InitSig(); + + return; +} + +void RTCWVR_submitFrame(); + +//int androidSwapped = 1; //If loading, then draw frame does not return, so detect this +/* + ** GLimp_EndFrame + ** + ** Responsible for doing a swapbuffers and possibly for other stuff + ** as yet to be determined. Probably better not to make this a GLimp + ** function and instead do a call to GLimp_SwapBuffers. + */ +void GLimp_EndFrame( void ) { + + // check logging + //QGL_EnableLogging( (qboolean)r_logFile->integer ); // bk001205 - was ->value +// if (!androidSwapped) +// eglSwapBuffers( eglGetCurrentDisplay(), eglGetCurrentSurface( EGL_DRAW ) ); + + //androidSwapped = 0; + RTCWVR_submitFrame(); +} + +#ifdef SMP +/* +=========================================================== + +SMP acceleration + +=========================================================== + */ + +sem_t renderCommandsEvent; +sem_t renderCompletedEvent; +sem_t renderActiveEvent; + +void ( *glimpRenderThread )( void ); + +void *GLimp_RenderThreadWrapper( void *stub ) { + glimpRenderThread(); + return NULL; +} + + +/* +======================= +GLimp_SpawnRenderThread +======================= + */ +pthread_t renderThreadHandle; +qboolean GLimp_SpawnRenderThread( void ( *function )( void ) ) { + + sem_init( &renderCommandsEvent, 0, 0 ); + sem_init( &renderCompletedEvent, 0, 0 ); + sem_init( &renderActiveEvent, 0, 0 ); + + glimpRenderThread = function; + + if ( pthread_create( &renderThreadHandle, NULL, + GLimp_RenderThreadWrapper, NULL ) ) { + return qfalse; + } + + return qtrue; +} + +static void *smpData; +//static int glXErrors; // bk001204 - unused + +void *GLimp_RendererSleep( void ) { + void *data; + + // after this, the front end can exit GLimp_FrontEndSleep + sem_post( &renderCompletedEvent ); + + sem_wait( &renderCommandsEvent ); + + data = smpData; + + // after this, the main thread can exit GLimp_WakeRenderer + sem_post( &renderActiveEvent ); + + return data; +} + + +void GLimp_FrontEndSleep( void ) { + sem_wait( &renderCompletedEvent ); +} + + +void GLimp_WakeRenderer( void *data ) { + smpData = data; + + // after this, the renderer can continue through GLimp_RendererSleep + sem_post( &renderCommandsEvent ); + + sem_wait( &renderActiveEvent ); +} + +#else + +void GLimp_RenderThreadWrapper( void *stub ) {} +qboolean GLimp_SpawnRenderThread( void ( *function )( void ) ) { + return qfalse; +} +void *GLimp_RendererSleep( void ) { + return NULL; +} +void GLimp_FrontEndSleep( void ) {} +void GLimp_WakeRenderer( void *data ) {} + +#endif + +/*****************************************************************************/ +/* MOUSE */ +/*****************************************************************************/ + +void IN_Init( void ) { + // mouse variables + in_mouse = Cvar_Get( "in_mouse", "1", CVAR_ARCHIVE ); + in_dgamouse = Cvar_Get( "in_dgamouse", "1", CVAR_ARCHIVE ); + +} + +void IN_Shutdown( void ) { + +} +/* +void IN_Frame( void ) { + + + if ( cls.keyCatchers & KEYCATCH_CONSOLE ) { + // temporarily deactivate if not in the game and + // running on the desktop + // voodoo always counts as full screen + if ( Cvar_VariableValue( "r_fullscreen" ) == 0 + && strcmp( Cvar_VariableString( "r_glDriver" ), _3DFX_DRIVER_NAME ) ) { + IN_DeactivateMouse(); + return; + } + } + + IN_ActivateMouse(); +} + */ + +void IN_Activate( void ) { +} + +// bk001130 - cvs1.17 joystick code (mkv) was here, no linux_joystick.c + +void Sys_SendKeyEvents( void ) { + // XEvent event; // bk001204 - unused + + + //HandleEvents(); +} + + +// bk010216 - added stubs for non-Linux UNIXes here +// FIXME - use NO_JOYSTICK or something else generic + +#if defined( __FreeBSD__ ) // rb010123 +void IN_StartupJoystick( void ) {} +void IN_JoyMove( void ) {} +#endif diff --git a/Projects/Android/jni/OpenJK/codemp_delete/android/android_local.h b/Projects/Android/jni/OpenJK/codemp_delete/android/android_local.h new file mode 100644 index 0000000..1ce496a --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/android/android_local.h @@ -0,0 +1,57 @@ +/* +=========================================================================== + +Return to Castle Wolfenstein single player GPL Source Code +Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company. + +This file is part of the Return to Castle Wolfenstein single player GPL Source Code (“RTCW SP Source Code”). + +RTCW SP 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 3 of the License, or +(at your option) any later version. + +RTCW SP 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 RTCW SP Source Code. If not, see . + +In addition, the RTCW SP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW SP Source Code. If not, please request a copy in writing from id Software at the address below. + +If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. + +=========================================================================== +*/ + +// linux_local.h: Linux-specific Quake3 header file + +void Sys_QueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr ); +qboolean Sys_GetPacket( netadr_t *net_from, msg_t *net_message ); +void Sys_SendKeyEvents( void ); + +// Input subsystem + +void IN_Init( void ); +void IN_Frame( void ); +void IN_Shutdown( void ); + + +void IN_JoyMove( void ); +void IN_StartupJoystick( void ); + +// GL subsystem +qboolean QGL_Init( const char *dllname ); +void QGL_EnableLogging( qboolean enable ); +void QGL_Shutdown( void ); + + + + + +// bk001130 - win32 +// void IN_JoystickCommands (void); + +char *strlwr( char *s ); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/android/android_main.cpp b/Projects/Android/jni/OpenJK/codemp_delete/android/android_main.cpp new file mode 100644 index 0000000..3d8b4f9 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/android/android_main.cpp @@ -0,0 +1,815 @@ +#include +#ifdef DEDICATED +#include +#endif +#include "qcommon/q_shared.h" +#include "qcommon/qcommon.h" +#include "qcommon/q_platform.h" + +#include "sys_loadlib.h" +#ifdef DEDICATED +#include "unix_local.h" +#else +#include "sys_local.h" +#endif + +#if defined(MACOS_X) || defined(__linux__) || defined(__FreeBSD_kernel__) +#include +#endif + +static char binaryPath[ MAX_OSPATH ] = { 0 }; +static char installPath[ MAX_OSPATH ] = { 0 }; + +char *Sys_Cwd( void ) { + static char cwd[MAX_OSPATH]; + + getcwd( cwd, sizeof( cwd ) - 1 ); + cwd[MAX_OSPATH - 1] = 0; + + return cwd; +} + +#if defined( DO_LOADDLL_WRAP ) +void *Sys_LoadDll_Wrapped( const char *name, + int( **entryPoint ) ( int, ... ), + int ( *systemcalls )( int, ... ) ) +#else +void *Sys_LoadDll( const char *name) +#endif +{ + void *libHandle; + //void ( *dllEntry )( intptr_t ( *syscallptr )( intptr_t, ... ) ); + char fname[MAX_OSPATH]; + char *homepath; + char *basepath; + char *pwdpath; + char *gamedir; + char *fn; + const char* err = NULL; // bk001206 // rb0101023 - now const + + // bk001206 - let's have some paranoia + assert( name ); + + snprintf( fname, sizeof( fname ), "../%sarm.so", name ); + +// bk001129 - was RTLD_LAZY +#define Q_RTLD RTLD_NOW + + homepath = Cvar_VariableString( "fs_homepath" ); + basepath = Cvar_VariableString( "fs_basepath" ); + gamedir = Cvar_VariableString( "fs_game" ); + + pwdpath = Sys_Cwd(); + fn = FS_BuildOSPath( pwdpath, gamedir, fname ); + // bk001206 - verbose + Com_Printf( "Sys_LoadDll(%s)... ", fn ); + +#ifdef __ANDROID__ + char path[500]; + char *libdir = (char*)getenv("RTCW_GAMELIBDIR"); + +#ifdef WOLF_SP_DEMO + snprintf( path, sizeof( path ), "%s/lib%sarm_d.so", getLibPath(), name ); +#else + snprintf( path, sizeof( path ), "%s/lib%sarm.so", libdir, name ); +#endif + + //LOGI("Trying to load Android lib: %s",path); + libHandle = dlopen (path, RTLD_LAZY ); + + +#else + // bk001129 - from cvs1.17 (mkv), was fname not fn + libHandle = dlopen( fn, Q_RTLD ); +#endif + + + if ( !libHandle ) { + Com_Printf( "failed (%s)\n", dlerror() ); + // homepath + fn = FS_BuildOSPath( homepath, gamedir, fname ); + Com_Printf( "Sys_LoadDll(%s)... ", fn ); + libHandle = dlopen( fn, Q_RTLD ); + + if ( !libHandle ) { + Com_Printf( "failed (%s)\n", dlerror() ); + // basepath + fn = FS_BuildOSPath( basepath, gamedir, fname ); + Com_Printf( "Sys_LoadDll(%s)... ", fn ); + libHandle = dlopen( fn, Q_RTLD ); + + if ( !libHandle ) { + Com_Printf( "failed (%s)\n", dlerror() ); + + if ( strlen( gamedir ) && Q_stricmp( gamedir, BASEGAME ) ) { // begin BASEGAME != fs_game section + + // media-only mods: no DLL whatsoever in the fs_game + // start the loop again using the hardcoded BASEDIRNAME + fn = FS_BuildOSPath( pwdpath, BASEGAME, fname ); + Com_Printf( "Sys_LoadDll(%s)... ", fn ); + libHandle = dlopen( fn, Q_RTLD ); + + if ( !libHandle ) { + Com_Printf( "failed (%s)\n", dlerror() ); + // homepath + fn = FS_BuildOSPath( homepath, BASEGAME, fname ); + Com_Printf( "Sys_LoadDll(%s)... ", fn ); + libHandle = dlopen( fn, Q_RTLD ); + + if ( !libHandle ) { + Com_Printf( "failed (%s)\n", dlerror() ); + // homepath + fn = FS_BuildOSPath( basepath, BASEGAME, fname ); + Com_Printf( "Sys_LoadDll(%s)... ", fn ); + libHandle = dlopen( fn, Q_RTLD ); + + if ( !libHandle ) { + // ok, this time things are really fucked + Com_Printf( "failed (%s)\n", dlerror() ); + } else { + Com_Printf( "ok\n" ); + } + } else { + Com_Printf( "ok\n" ); + } + } else { + Com_Printf( "ok\n" ); + } + } // end BASEGAME != fs_game section + } else { + Com_Printf( "ok\n" ); + } + } else { + Com_Printf( "ok\n" ); + } + } else { + Com_Printf( "ok\n" ); + } + + if ( !libHandle ) { +#ifndef NDEBUG // in debug, abort on failure + Com_Error( ERR_FATAL, "Sys_LoadDll(%s) failed dlopen() completely!\n", name ); +#else + Com_Printf( "Sys_LoadDll(%s) failed dlopen() completely!\n", name ); +#endif + return NULL; + } + + Com_Printf( "Sys_LoadDll handle = %p", libHandle ); + + typedef void QDECL DllEntryProc( SystemCallProc *syscallptr ); + + DllEntryProc *dllEntry = (DllEntryProc *)dlsym( libHandle, "dllEntry" ); + void *entryPoint = dlsym( libHandle, "vmMain" ); + + +// dllEntry = dlsym( libHandle, "dllEntry" ); +// *entryPoint = dlsym( libHandle, "vmMain" ); + if ( !entryPoint || !dllEntry ) { + err = dlerror(); +#ifndef NDEBUG // bk001206 - in debug abort on failure + Com_Error( ERR_FATAL, "Sys_LoadDll(%s) failed dlsym(vmMain):\n\"%s\" !\n", name, err ); +#else + Com_Printf( "Sys_LoadDll(%s) failed dlsym(vmMain):\n\"%s\" !\n", name, err ); +#endif + dlclose( libHandle ); + err = dlerror(); + if ( err != NULL ) { + Com_Printf( "Sys_LoadDll(%s) failed dlcose:\n\"%s\"\n", name, err ); + } + return NULL; + } + Com_Printf( "Sys_LoadDll(%s) found **vmMain** at %p \n", name, entryPoint ); // bk001212 + //dllEntry( systemcalls ); + Com_Printf( "Sys_LoadDll(%s) succeeded!\n", name ); + return libHandle; +} + + +/* +================= +Sys_SetBinaryPath +================= +*/ +void Sys_SetBinaryPath(const char *path) +{ + Q_strncpyz(binaryPath, path, sizeof(binaryPath)); +} + +/* +================= +Sys_BinaryPath +================= +*/ +char *Sys_BinaryPath(void) +{ + return binaryPath; +} + +/* +================= +Sys_SetDefaultInstallPath +================= +*/ +void Sys_SetDefaultInstallPath(const char *path) +{ + Q_strncpyz(installPath, path, sizeof(installPath)); +} + +/* +================= +Sys_DefaultInstallPath +================= +*/ +char *Sys_DefaultInstallPath(void) +{ + if (*installPath) + return installPath; + else + return Sys_Cwd(); +} + +/* +================= +Sys_DefaultAppPath +================= +*/ +char *Sys_DefaultAppPath(void) +{ + return Sys_BinaryPath(); +} + +// We now expect newlines instead of always appending +// otherwise sectioned prints get messed up. +#define MAXPRINTMSG 4096 +void Conbuf_AppendText( const char *pMsg ) +{ + char msg[MAXPRINTMSG] = {0}; + Q_strncpyz(msg, pMsg, sizeof(msg)); + Q_StripColor(msg); + //((void)__android_log_print(ANDROID_LOG_INFO,"JK3","%s", msg)); + //printf("%s", msg); +} + +void Sys_Print( const char *msg ) { + // TTimo - prefix for text that shows up in console but not in notify + // backported from RTCW + if ( !Q_strncmp( msg, "[skipnotify]", 12 ) ) { + msg += 12; + } + if ( msg[0] == '*' ) { + msg += 1; + } + Conbuf_AppendText( msg ); +} + +/* +================= +Sys_In_Restart_f +================= +*/ +void Sys_In_Restart_f( void ) +{ +#ifdef DEDICATED + IN_Shutdown(); + IN_Init(); +#else + IN_Restart( ); +#endif +} + +void Sys_Init (void) { + Cmd_AddCommand ("in_restart", Sys_In_Restart_f); + Cvar_Set( "arch", "arm" ); + Cvar_Set( "username", Sys_GetCurrentUser( ) ); +} + +void Sys_Exit( int ex ) __attribute__((noreturn)); +void Sys_Exit( int ex ) { +#ifndef DEDICATED + //SDL_Quit( ); +#endif + +#ifdef NDEBUG // regular behavior + // We can't do this + // as long as GL DLL's keep installing with atexit... + //exit(ex); + _exit(ex); +#else + // Give me a backtrace on error exits. + assert( ex == 0 ); + exit(ex); +#endif +} + +void Sys_Error( const char *error, ... ) +{ + va_list argptr; + char string[1024]; + + va_start (argptr,error); + Q_vsnprintf (string, sizeof(string), error, argptr); + va_end (argptr); + //((void)__android_log_print(ANDROID_LOG_ERROR,"JK3","%s", string)); + //Sys_ErrorDialog( string ); + Sys_Print( string ); + + Sys_Exit( 3 ); +} + +void Sys_Quit (void) { + IN_Shutdown(); + + Com_ShutdownZoneMemory(); + Com_ShutdownHunkMemory(); + +#ifdef DEDICATED + fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY); +#endif + Sys_Exit(0); +} + +/* +================= +Sys_UnloadDll +================= +*/ +void Sys_UnloadDll( void *dllHandle ) +{ + if( !dllHandle ) + { + Com_Printf("Sys_UnloadDll(NULL)\n"); + return; + } + + //Sys_UnloadLibrary(dllHandle); +} + + + +extern "C" +{ +extern const char * getLibPath(); +} + +/* +================= +Sys_LoadDll + +First try to load library name from system library path, +from executable path, then fs_basepath. +================= + + +void *Sys_LoadDll(const char *name, qboolean useSystemLib) +{ + void *dllhandle = NULL; + + + char lib_path[512]; + sprintf(lib_path,"%s/lib%s", getLibPath(),name); + //LOGI("Trying to load Android lib: %s",lib_path); + dllhandle = dlopen (lib_path, RTLD_LAZY ); + + return dllhandle; + + if(useSystemLib) + Com_Printf("Trying to load \"%s\"...\n", name); + + //if(!useSystemLib || !(dllhandle = Sys_LoadLibrary(name))) + { + const char *topDir; + char libPath[MAX_OSPATH]; + + topDir = Sys_BinaryPath(); + + if(!*topDir) + topDir = "."; + + Com_Printf("Trying to load \"%s\" from \"%s\"...\n", name, topDir); + Com_sprintf(libPath, sizeof(libPath), "%s%c%s", topDir, PATH_SEP, name); + + if(!(dllhandle = Sys_LoadLibrary(libPath))) + { + const char *basePath = Cvar_VariableString("fs_basepath"); + + if(!basePath || !*basePath) + basePath = "."; + + if(FS_FilenameCompare(topDir, basePath)) + { + Com_Printf("Trying to load \"%s\" from \"%s\"...\n", name, basePath); + Com_sprintf(libPath, sizeof(libPath), "%s%c%s", basePath, PATH_SEP, name); + dllhandle = Sys_LoadLibrary(libPath); + } + + if(!dllhandle) + { + Com_Printf("Loading \"%s\" failed\n", name); + } + } + } + + return dllhandle; +}*/ + +#ifdef MACOS_X +void *Sys_LoadMachOBundle( const char *name ) +{ + if ( !FS_LoadMachOBundle(name) ) + return NULL; + + char *homepath = Cvar_VariableString( "fs_homepath" ); + char *gamedir = Cvar_VariableString( "fs_game" ); + char dllName[MAX_QPATH]; + + Com_sprintf( dllName, sizeof(dllName), "%s_pk3" DLL_EXT, name ); + + //load the unzipped library + char *fn = FS_BuildOSPath( homepath, gamedir, dllName ); + + void *libHandle = Sys_LoadLibrary( fn ); + + if ( libHandle != NULL ) { + Com_Printf( "Loaded pk3 bundle %s.\n", name ); + } + + return libHandle; +} +#endif + +/* + ================= + Sys_LoadGameDll + + Used to load a development dll instead of a virtual machine + ================= + */ + +//TODO: load mac dlls that are inside zip things inside pk3s. + +void *Sys_LoadLegacyGameDll( const char *name, intptr_t (QDECL **vmMain)(int, ...), intptr_t (QDECL *systemcalls)(intptr_t, ...) ) +{ + void *libHandle = NULL; + void (QDECL *dllEntry)( intptr_t (QDECL *syscallptr)(intptr_t, ...) ); + char *basepath; + char *homepath; + char *cdpath; + char *gamedir; +#ifdef MACOS_X + char *apppath; +#endif + char *fn; + char filename[MAX_OSPATH]; + + Com_sprintf (filename, sizeof(filename), "%sarm" DLL_EXT, name); + +#if 0 + libHandle = Sys_LoadLibrary( filename ); +#endif + +#ifdef MACOS_X + //First, look for the old-style mac .bundle that's inside a pk3 + //It's actually zipped, and the zipfile has the same name as 'name' + libHandle = Sys_LoadMachOBundle( name ); +#endif + + if (!libHandle) { + //Com_Printf( "Sys_LoadGameDll(%s) failed: \"%s\"\n", filename, Sys_LibraryError() ); + + basepath = Cvar_VariableString( "fs_basepath" ); + homepath = Cvar_VariableString( "fs_homepath" ); + cdpath = Cvar_VariableString( "fs_cdpath" ); + gamedir = Cvar_VariableString( "fs_game" ); +#ifdef MACOS_X + apppath = Cvar_VariableString( "fs_apppath" ); +#endif + + fn = FS_BuildOSPath( basepath, gamedir, filename ); + libHandle = Sys_LoadLibrary( fn ); + + if ( !libHandle ) { + Com_Printf( "Sys_LoadGameDll(%s) failed: \"%s\"\n", fn, Sys_LibraryError() ); + if( homepath[0] ) { + Com_Printf( "Sys_LoadGameDll(%s) failed: \"%s\"\n", fn, Sys_LibraryError() ); + fn = FS_BuildOSPath( homepath, gamedir, filename ); + libHandle = Sys_LoadLibrary( fn ); + } + if ( !libHandle ) { + Com_Printf( "Sys_LoadGameDll(%s) failed: \"%s\"\n", fn, Sys_LibraryError() ); +#ifdef MACOS_X + if( apppath[0] ) { + fn = FS_BuildOSPath( apppath, gamedir, filename ); + libHandle = Sys_LoadLibrary( fn ); + } + if ( !libHandle ) { + Com_Printf( "Sys_LoadGameDll(%s) failed: \"%s\"\n", fn, Sys_LibraryError() ); +#endif + if( cdpath[0] ) { + fn = FS_BuildOSPath( cdpath, gamedir, filename ); + libHandle = Sys_LoadLibrary( fn ); + } + if ( !libHandle ) { + Com_Printf( "Sys_LoadGameDll(%s) failed: \"%s\"\n", fn, Sys_LibraryError() ); + // now we try base + fn = FS_BuildOSPath( basepath, BASEGAME, filename ); + libHandle = Sys_LoadLibrary( fn ); + if ( !libHandle ) { + if( homepath[0] ) { + Com_Printf( "Sys_LoadGameDll(%s) failed: \"%s\"\n", fn, Sys_LibraryError() ); + fn = FS_BuildOSPath( homepath, BASEGAME, filename ); + libHandle = Sys_LoadLibrary( fn ); + } + if ( !libHandle ) { + Com_Printf( "Sys_LoadGameDll(%s) failed: \"%s\"\n", fn, Sys_LibraryError() ); +#ifdef MACOS_X + if( apppath[0] ) { + fn = FS_BuildOSPath( apppath, BASEGAME, filename); + libHandle = Sys_LoadLibrary( fn ); + } + if ( !libHandle ) { + Com_Printf( "Sys_LoadGameDll(%s) failed: \"%s\"\n", fn, Sys_LibraryError() ); +#endif + if( cdpath[0] ) { + fn = FS_BuildOSPath( cdpath, BASEGAME, filename ); + libHandle = Sys_LoadLibrary( fn ); + } + if ( !libHandle ) { + Com_Printf( "Sys_LoadGameDll(%s) failed: \"%s\"\n", fn, Sys_LibraryError() ); + return NULL; + } +#ifdef MACOS_X + } +#endif + } + } + } +#ifdef MACOS_X + } +#endif + } + } + } + + dllEntry = ( void (QDECL *)( intptr_t (QDECL *)( intptr_t, ... ) ) )Sys_LoadFunction( libHandle, "dllEntry" ); + *vmMain = (intptr_t (QDECL *)(int,...))Sys_LoadFunction( libHandle, "vmMain" ); + if ( !*vmMain || !dllEntry ) { + Com_Printf ( "Sys_LoadGameDll(%s) failed to find vmMain function:\n\"%s\" !\n", name, Sys_LibraryError() ); + Sys_UnloadLibrary( libHandle ); + return NULL; + } + + Com_Printf ( "Sys_LoadGameDll(%s) found vmMain function at %p\n", name, *vmMain ); + dllEntry( systemcalls ); + + return libHandle; +} + +void *Sys_LoadGameDll( const char *name, void *(QDECL **moduleAPI)(int, ...) ) +{ + void *libHandle = NULL; + char *basepath; + char *homepath; + char *cdpath; + char *gamedir; +#ifdef MACOS_X + char *apppath; +#endif + char *fn; + char filename[MAX_OSPATH]; + + Com_sprintf (filename, sizeof(filename), "%s" ARCH_STRING DLL_EXT, name); + +#if 0 + libHandle = Sys_LoadLibrary( filename ); +#endif + +#ifdef MACOS_X + //First, look for the old-style mac .bundle that's inside a pk3 + //It's actually zipped, and the zipfile has the same name as 'name' + libHandle = Sys_LoadMachOBundle( name ); +#endif + + + char lib_path[512]; + sprintf(lib_path,"%s/lib%s", getLibPath(),filename); + LOGI("Trying to load Android lib: %s",lib_path); + libHandle = dlopen (lib_path, RTLD_LAZY ); + + + + if (!libHandle) { + //Com_Printf( "Sys_LoadGameDll(%s) failed: \"%s\"\n", filename, Sys_LibraryError() ); + + basepath = Cvar_VariableString( "fs_basepath" ); + homepath = Cvar_VariableString( "fs_homepath" ); + cdpath = Cvar_VariableString( "fs_cdpath" ); + gamedir = Cvar_VariableString( "fs_game" ); +#ifdef MACOS_X + apppath = Cvar_VariableString( "fs_apppath" ); +#endif + + fn = FS_BuildOSPath( basepath, gamedir, filename ); + libHandle = Sys_LoadLibrary( fn ); + + if ( !libHandle ) { + Com_Printf( "Sys_LoadGameDll(%s) failed: \"%s\"\n", fn, Sys_LibraryError() ); + if( homepath[0] ) { + Com_Printf( "Sys_LoadGameDll(%s) failed: \"%s\"\n", fn, Sys_LibraryError() ); + fn = FS_BuildOSPath( homepath, gamedir, filename ); + libHandle = Sys_LoadLibrary( fn ); + } + if ( !libHandle ) { + Com_Printf( "Sys_LoadGameDll(%s) failed: \"%s\"\n", fn, Sys_LibraryError() ); +#ifdef MACOS_X + if( apppath[0] ) { + fn = FS_BuildOSPath( apppath, gamedir, filename ); + libHandle = Sys_LoadLibrary( fn ); + } + if ( !libHandle ) { + Com_Printf( "Sys_LoadGameDll(%s) failed: \"%s\"\n", fn, Sys_LibraryError() ); +#endif + if( cdpath[0] ) { + fn = FS_BuildOSPath( cdpath, gamedir, filename ); + libHandle = Sys_LoadLibrary( fn ); + } + if ( !libHandle ) { + Com_Printf( "Sys_LoadGameDll(%s) failed: \"%s\"\n", fn, Sys_LibraryError() ); + // now we try base + fn = FS_BuildOSPath( basepath, BASEGAME, filename ); + libHandle = Sys_LoadLibrary( fn ); + if ( !libHandle ) { + if( homepath[0] ) { + Com_Printf( "Sys_LoadGameDll(%s) failed: \"%s\"\n", fn, Sys_LibraryError() ); + fn = FS_BuildOSPath( homepath, BASEGAME, filename ); + libHandle = Sys_LoadLibrary( fn ); + } + if ( !libHandle ) { + Com_Printf( "Sys_LoadGameDll(%s) failed: \"%s\"\n", fn, Sys_LibraryError() ); +#ifdef MACOS_X + if( apppath[0] ) { + fn = FS_BuildOSPath( apppath, BASEGAME, filename); + libHandle = Sys_LoadLibrary( fn ); + } + if ( !libHandle ) { + Com_Printf( "Sys_LoadGameDll(%s) failed: \"%s\"\n", fn, Sys_LibraryError() ); +#endif + if( cdpath[0] ) { + fn = FS_BuildOSPath( cdpath, BASEGAME, filename ); + libHandle = Sys_LoadLibrary( fn ); + } + if ( !libHandle ) { + Com_Printf( "Sys_LoadGameDll(%s) failed: \"%s\"\n", fn, Sys_LibraryError() ); + return NULL; + } +#ifdef MACOS_X + } +#endif + } + } + } +#ifdef MACOS_X + } +#endif + } + } + } + + *moduleAPI = (void *(QDECL *)(int,...))Sys_LoadFunction( libHandle, "GetModuleAPI" ); + if ( !*moduleAPI ) { + Com_Printf ( "Sys_LoadGameDll(%s) failed to find GetModuleAPI function:\n\"%s\" !\n", name, Sys_LibraryError() ); + Sys_UnloadLibrary( libHandle ); + return NULL; + } + + return libHandle; +} + +void Sys_ConfigureFPU() { // bk001213 - divide by zero +#ifdef __linux2__ + #ifdef __i386 +#ifndef NDEBUG + // bk0101022 - enable FPE's in debug mode + static int fpu_word = _FPU_DEFAULT & ~(_FPU_MASK_ZM | _FPU_MASK_IM); + int current = 0; + _FPU_GETCW(current); + if ( current!=fpu_word) { +#if 0 + Com_Printf("FPU Control 0x%x (was 0x%x)\n", fpu_word, current ); + _FPU_SETCW( fpu_word ); + _FPU_GETCW( current ); + assert(fpu_word==current); +#endif + } +#else // NDEBUG + static int fpu_word = _FPU_DEFAULT; + _FPU_SETCW( fpu_word ); +#endif // NDEBUG +#endif // __i386 +#endif // __linux +} + +#ifdef MACOS_X +/* + ================= + Sys_StripAppBundle + + Discovers if passed dir is suffixed with the directory structure of a Mac OS X + .app bundle. If it is, the .app directory structure is stripped off the end and + the result is returned. If not, dir is returned untouched. + ================= + */ +char *Sys_StripAppBundle( char *dir ) +{ + static char cwd[MAX_OSPATH]; + + Q_strncpyz(cwd, dir, sizeof(cwd)); + if(strcmp(Sys_Basename(cwd), "MacOS")) + return dir; + Q_strncpyz(cwd, Sys_Dirname(cwd), sizeof(cwd)); + if(strcmp(Sys_Basename(cwd), "Contents")) + return dir; + Q_strncpyz(cwd, Sys_Dirname(cwd), sizeof(cwd)); + if(!strstr(Sys_Basename(cwd), ".app")) + return dir; + Q_strncpyz(cwd, Sys_Dirname(cwd), sizeof(cwd)); + return cwd; +} +#endif + +#ifndef DEFAULT_BASEDIR +# ifdef MACOS_X +# define DEFAULT_BASEDIR Sys_StripAppBundle(Sys_BinaryPath()) +# else +# define DEFAULT_BASEDIR Sys_BinaryPath() +# endif +#endif + +int main ( int argc, char* argv[] ) +{ + int i; + char commandLine[ MAX_STRING_CHARS ] = { 0 }; + + // done before Com/Sys_Init since we need this for error output + //Sys_CreateConsole(); + + // no abort/retry/fail errors + //SetErrorMode (SEM_FAILCRITICALERRORS); + + // get the initial time base + Sys_Milliseconds(); + +#ifdef MACOS_X + // This is passed if we are launched by double-clicking + if ( argc >= 2 && Q_strncmp ( argv[1], "-psn", 4 ) == 0 ) + argc = 1; +#endif + + Sys_SetBinaryPath( Sys_Dirname( argv[ 0 ] ) ); + Sys_SetDefaultInstallPath( DEFAULT_BASEDIR ); + + // Concatenate the command line for passing to Com_Init + for( i = 1; i < argc; i++ ) + { + const bool containsSpaces = (strchr(argv[i], ' ') != NULL); + if (containsSpaces) + Q_strcat( commandLine, sizeof( commandLine ), "\"" ); + + Q_strcat( commandLine, sizeof( commandLine ), argv[ i ] ); + + if (containsSpaces) + Q_strcat( commandLine, sizeof( commandLine ), "\"" ); + + Q_strcat( commandLine, sizeof( commandLine ), " " ); + } + + Com_Init (commandLine); + + NET_Init(); + +#ifdef DEDICATED + fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY); +#else + // hide the early console since we've reached the point where we + // have a working graphics subsystems + if (!com_dedicated->integer && !com_viewlog->integer) + { + Sys_ShowConsole(0, qfalse); + } +#endif + + // main game loop + while (1) + { +#if defined __linux__ && defined DEDICATED + Sys_ConfigureFPU();//FIXME: what's this for? +#endif + // make sure mouse and joystick are only called once a frame + IN_Frame(); + + // run the game + Com_Frame(); + } + + // never gets here +} diff --git a/Projects/Android/jni/OpenJK/codemp_delete/android/android_snd.c b/Projects/Android/jni/OpenJK/codemp_delete/android/android_snd.c new file mode 100644 index 0000000..0378ac5 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/android/android_snd.c @@ -0,0 +1,319 @@ +/* +=========================================================================== + +Return to Castle Wolfenstein single player GPL Source Code +Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company. + +This file is part of the Return to Castle Wolfenstein single player GPL Source Code (“RTCW SP Source Code”). + +RTCW SP 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 3 of the License, or +(at your option) any later version. + +RTCW SP 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 RTCW SP Source Code. If not, see . + +In addition, the RTCW SP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW SP Source Code. If not, please request a copy in writing from id Software at the address below. + +If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. + +=========================================================================== + */ + +#include +#include +#include +#include +#include +#include +//#include +#include +#ifdef __linux__ // rb0101023 - guard this +#include +#endif +#ifdef __FreeBSD__ // rb0101023 - added +#include +#endif +#include + +#include "../game/q_shared.h" +#include "../client/snd_local.h" + +//Updated by Emile Belanger for OpenSL + +// for native audio +#include +#include +#include + +pthread_mutex_t dma_mutex; + +// engine interfaces +static SLObjectItf engineObject = NULL; +static SLEngineItf engineEngine; + +// output mix interfaces +static SLObjectItf outputMixObject = NULL; + +// buffer queue player interfaces +static SLObjectItf bqPlayerObject = NULL; +static SLPlayItf bqPlayerPlay; +#ifdef ANDROID_NDK +static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue; +#else +static SLBufferQueueItf bqPlayerBufferQueue; +#endif + +static SLEffectSendItf bqPlayerEffectSend; +static SLMuteSoloItf bqPlayerMuteSolo; +static SLVolumeItf bqPlayerVolume; + +void myassert(int v,const char * message) +{ + if (!v) + Com_Printf("myassert: %s",message); +} + +int audio_fd; +int snd_inited = 0; + +cvar_t *sndbits; +cvar_t *sndspeed; +cvar_t *sndchannels; + +cvar_t *snddevice; + +/* Some devices may work only with 48000 */ +static int tryrates[] = { 22050, 11025, 44100, 48000, 8000 }; + +static int dmapos = 0; +static int dmasize = 0; + +#define OPENSL_BUFF_LEN 1024 + +static unsigned char play_buffer[OPENSL_BUFF_LEN]; + +void bqPause(int p) +{ + int result; + if (p) + { + result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PAUSED); + myassert(SL_RESULT_SUCCESS == result,"SetPlayState"); + } + else + { + result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING); + myassert(SL_RESULT_SUCCESS == result,"SetPlayState"); + + result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, "\0", 1); + myassert(SL_RESULT_SUCCESS == result,"Enqueue first buffer"); + } +} + +//NOTE!! There are definetly threading issues with this, but it appears to work for now... + +// TEST is me testing black screen issue! + +void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) +{ + //LOGI("bqPlayerCallback"); + // TEST pthread_mutex_lock(&dma_mutex); + + int pos = (dmapos * (dma.samplebits/8)); + if (pos >= dmasize) + dmapos = pos = 0; + + int len = OPENSL_BUFF_LEN; + int factor = 2*2; + int FrameCount = (unsigned int)OPENSL_BUFF_LEN / factor; + + if (!snd_inited) /* shouldn't happen, but just in case... */ + { + memset(play_buffer, '\0', len); + return; + } + else + { + int tobufend = dmasize - pos; /* bytes to buffer's end. */ + int len1 = len; + int len2 = 0; + + if (len1 > tobufend) + { + len1 = tobufend; + len2 = len - len1; + } + memcpy(play_buffer, dma.buffer + pos, len1); + if (len2 <= 0) + dmapos += (len1 / (dma.samplebits/8)); + else /* wraparound? */ + { + memcpy(play_buffer+len1, dma.buffer, len2); + dmapos = (len2 / (dma.samplebits/8)); + } + } + + if (dmapos >= dmasize) + dmapos = 0; + + SLresult result; + //LOGI("Frame count = %d",FrameCount); + if (FrameCount == 0) + FrameCount = 1; + result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, play_buffer,FrameCount * factor); + myassert(SL_RESULT_SUCCESS == result,"Enqueue failed"); + + // TEST pthread_mutex_unlock(&dma_mutex); +} + +qboolean SNDDMA_Init( void ) { + int rc; + int fmt; + int tmp; + int i; + // char *s; // bk001204 - unused + struct audio_buf_info info; + int caps; + extern uid_t saved_euid; + + if ( snd_inited ) { + return 1; + } + + dmapos = 0; + dma.samplebits = 16; + dma.channels = 2; + dma.samples = 1024*16; + dma.submission_chunk = 1024*2; + //dma.submission_chunk = 1; + dma.speed = 44100; + dma.speed = 22050; + dmasize = (dma.samples * (dma.samplebits/8)); + dma.buffer = calloc(1, dmasize); + + SLresult result; + + // create engine + result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); + myassert(SL_RESULT_SUCCESS == result,"slCreateEngine"); + + // realize the engine + result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); + myassert(SL_RESULT_SUCCESS == result,"Realize"); + + // get the engine interface, which is needed in order to create other objects + result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); + myassert(SL_RESULT_SUCCESS == result,"GetInterface"); + + // create output mix + result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL); + myassert(SL_RESULT_SUCCESS == result,"CreateOutputMix"); + + // realize the output mix + result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE); + myassert(SL_RESULT_SUCCESS == result,"Realize output mix"); + + //CREATE THE PLAYER + + // configure audio source + SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 1}; + SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, 2, SL_SAMPLINGRATE_22_05, + SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16, + SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT, SL_BYTEORDER_LITTLEENDIAN}; + SLDataSource audioSrc = {&loc_bufq, &format_pcm}; + + // configure audio sink + SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject}; + SLDataSink audioSnk = {&loc_outmix, NULL}; + + // create audio player + Com_Printf("create audio player"); + const SLInterfaceID ids[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE}; + const SLboolean req[1] = {SL_BOOLEAN_TRUE}; + result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk, + 1, ids, req); + myassert(SL_RESULT_SUCCESS == result,"CreateAudioPlayer"); + + + // realize the player + result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE); + myassert(SL_RESULT_SUCCESS == result,"Realize AudioPlayer"); + + // get the play interface + result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay); + myassert(SL_RESULT_SUCCESS == result,"GetInterface AudioPlayer"); + + // get the buffer queue interface + result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE, + &bqPlayerBufferQueue); + myassert(SL_RESULT_SUCCESS == result,"GetInterface buffer queue"); + + // register callback on the buffer queue + result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL); + myassert(SL_RESULT_SUCCESS == result,"RegisterCallback"); + + snd_inited = 1; + + // set the player's state to playing + result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING); + myassert(SL_RESULT_SUCCESS == result,"SetPlayState"); + + + + result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, "\0", 1); + myassert(SL_RESULT_SUCCESS == result,"Enqueue first buffer"); + + + + + return 1; +} + +int SNDDMA_GetDMAPos( void ) { + struct count_info count; + + if ( !snd_inited ) { + return 0; + } + + // TEST pthread_mutex_lock(&dma_mutex); + + //LOGI("SNDDMA_GetDMAPos"); + return dmapos; +} + +void SNDDMA_Shutdown( void ) { + LOGI("shutdown Sound"); + bqPause(1); + (*bqPlayerObject)->Destroy(bqPlayerObject); + (*outputMixObject)->Destroy(outputMixObject); + (*engineObject)->Destroy(engineObject); + + bqPlayerObject = NULL; + outputMixObject = NULL; + engineObject = NULL; +} + +/* +============== +SNDDMA_Submit + +Send sound to device if buffer isn't really the dma buffer +=============== + */ +void SNDDMA_Submit( void ) { + //LOGI("SNDDMA_Submit"); + // TEST pthread_mutex_unlock(&dma_mutex); +} + +void SNDDMA_BeginPainting( void ) { + //LOGI("SNDDMA_BeginPainting"); + //pthread_mutex_lock(&dma_mutex); +} diff --git a/Projects/Android/jni/OpenJK/codemp_delete/android/in_android.cpp b/Projects/Android/jni/OpenJK/codemp_delete/android/in_android.cpp new file mode 100644 index 0000000..0a06b83 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/android/in_android.cpp @@ -0,0 +1,470 @@ + +#include "in_android.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../client/client.h" + + +#include +#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO,"JNI", __VA_ARGS__)) +#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "JNI", __VA_ARGS__)) +#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR,"JNI", __VA_ARGS__)) + + + +// FIFO STUFF //////////////////// +// Copied from FTEQW, I don't know if this is thread safe, but it's safe enough for a game :) +#define EVENTQUEUELENGTH 128 +struct eventlist_s +{ + + int scancode, unicode,state; + +} eventlist[EVENTQUEUELENGTH]; + +volatile int events_avail; /*volatile to make sure the cc doesn't try leaving these cached in a register*/ +volatile int events_used; + +static struct eventlist_s *in_newevent(void) +{ + if (events_avail >= events_used + EVENTQUEUELENGTH) + return 0; + return &eventlist[events_avail & (EVENTQUEUELENGTH-1)]; +} + +static void in_finishevent(void) +{ + events_avail++; +} +/////////////////////// + + + +int PortableKeyEvent(int state, int code, int unicode){ + + LOGI("PortableKeyEvent state = %d, code = %d, unicode = %d",state,code,unicode); + struct eventlist_s *ev = in_newevent(); + if (!ev) + return 0; + + ev->scancode = code; + ev->unicode = unicode; + ev->state = state; + in_finishevent(); + return 0; + +} + + +//extern void KeyDownPort( kbutton_t *b ); +//extern void KeyUpPort( kbutton_t *b ); +//extern kbutton_t kb[NUM_BUTTONS]; + +void KeyUpPort (int b) +{ +// kb[b].active = qfalse; +} +void KeyDownPort (int b) +{ +// kb[b].active = qtrue; +// kb[b].wasPressed = qtrue; +} + +void KeyTogglePort (int b) +{ +// kb[b].active = !kb[b].active; +} + +/* +char* postedCommand = 0; +void postCommand(const char * cmd) +{ + postedCommand = cmd; +} +/* +extern kbutton_t in_left, in_right, in_forward, in_back; +extern kbutton_t in_lookup, in_lookdown, in_moveleft, in_moveright; +extern kbutton_t in_strafe, in_speed; +extern kbutton_t in_up, in_down; +extern kbutton_t in_buttons[16]; + */ +/* +void PortableAction(int state, int action) +{ + LOGI("PortableAction %d %d",state,action); + + int key = -1; + + switch (action) + { + case PORT_ACT_LEFT: + key = KB_LEFT; + break; + case PORT_ACT_RIGHT: + key = KB_RIGHT; + break; + case PORT_ACT_FWD: + key = KB_FORWARD; + break; + case PORT_ACT_BACK: + key = KB_BACK; + break; + case PORT_ACT_LOOK_UP: + key = KB_LOOKUP; + break; + case PORT_ACT_LOOK_DOWN: + key = KB_LOOKDOWN; + break; + case PORT_ACT_MOVE_LEFT: + key = KB_MOVELEFT; + break; + case PORT_ACT_MOVE_RIGHT: + key = KB_MOVERIGHT; + break; + case PORT_ACT_STRAFE: + key = KB_STRAFE; + break; + case PORT_ACT_SPEED: + key = KB_SPEED; + break; + case PORT_ACT_USE: + key = KB_BUTTONS6; + break; + case PORT_ACT_ATTACK: + key = KB_BUTTONS0; + break; + case PORT_ACT_JUMP: + //Jump is same as up + case PORT_ACT_UP: + key = KB_UP; + break; + case PORT_ACT_DOWN: + if (state) //TOGGLE + KeyTogglePort(KB_DOWN); + break; + case PORT_ACT_KICK: + key = KB_KICK; + break; + //TODO make fifo, possibly not thread safe!! + case PORT_ACT_NEXT_WEP: + if (state) + postCommand("weapnext\n"); + break; + case PORT_ACT_PREV_WEP: + if (state) + postCommand("weapprev\n"); + break; + case PORT_ACT_ZOOM_IN: + key = KB_WBUTTONS1; + break; + case PORT_ACT_ALT_FIRE: + if (state) + postCommand("weapalt\n"); + break; + case PORT_ACT_HELPCOMP: + if (state) + postCommand("notebook\n"); + break; + case PORT_ACT_INVUSE: + key = KB_BUTTONS2; + break; + case PORT_ACT_INVPREV: + if (state) + postCommand("itemprev\n"); + break; + case PORT_ACT_INVNEXT: + if (state) + postCommand("itemnext\n"); + break; + case PORT_ACT_RELOAD: + key = KB_WBUTTONS3; + break; + case PORT_ACT_QUICKSAVE: + if (state) + postCommand("savegame quicksave\n"); + break; + case PORT_ACT_QUICKLOAD: + if (state) + postCommand("loadgame quicksave\n"); + break; + case PORT_ACT_LEAN_LEFT: + key = KB_WBUTTONS4; + break; + case PORT_ACT_LEAN_RIGHT: + key = KB_WBUTTONS5; + break; + } + + if (key != -1) + (state)?KeyDownPort(key):KeyUpPort(key); + +}*/ + +int mdx=0,mdy=0; +void PortableMouse(float dx,float dy) +{ + //LOGI("dx = %f, dy = %f",dx,dy); + dx *= 1500; + dy *= 1200; + + mdx += dx; + mdy += dy; + + + //Sys_QueEvent( t, SE_MOUSE, mx, my, 0, NULL ); +} + +int absx=0,absy=0; +void VR_GetScreenRes(int *width, int *height); +void PortableMouseAbs(float x,float y) +{ + int width; + int height; + VR_GetScreenRes(&width, &height); + absx = x * width; + absy = y * height; +} + + +// =================== FORWARD and SIDE MOVMENT ============== + +float forwardmove, sidemove; //Joystick mode + +void PortableMoveFwd(float fwd) +{ + if (fwd > 1) + fwd = 1; + else if (fwd < -1) + fwd = -1; + + forwardmove = fwd; +} + +void PortableMoveSide(float strafe) +{ + if (strafe > 1) + strafe = 1; + else if (strafe < -1) + strafe = -1; + + sidemove = strafe; +} + +void PortableMove(float fwd, float strafe) +{ + PortableMoveFwd(fwd); + PortableMoveSide(strafe); +} + +//====================================================================== + +//Look up and down +int look_pitch_mode; +float look_pitch_mouse,look_pitch_abs,look_pitch_joy; +/* +void PortableLookPitch(int mode, float pitch) +{ + look_pitch_mode = mode; + switch(mode) + { + case LOOK_MODE_MOUSE: + look_pitch_mouse += pitch; + break; + case LOOK_MODE_ABSOLUTE: + look_pitch_abs = pitch; + break; + case LOOK_MODE_JOYSTICK: + look_pitch_joy = pitch; + break; + } +} +*/ +//left right +int look_yaw_mode; +float look_yaw_mouse,look_yaw_joy; +/* +void PortableLookYaw(int mode, float yaw) +{ + look_yaw_mode = mode; + switch(mode) + { + case LOOK_MODE_MOUSE: + look_yaw_mouse += yaw; + break; + case LOOK_MODE_JOYSTICK: + look_yaw_joy = yaw; + break; + } +} + + + +void PortableCommand(const char * cmd){ + postCommand(cmd); +} +*/ +void PortableInit(int argc,const char ** argv){ + //Copied form sys_main.c + int len, i; + char *cmdline; + void Sys_SetDefaultCDPath( const char *path ); + + // go back to real user for config loads + + + //Sys_ParseArgs( argc, argv ); // bk010104 - added this for support + + // TTimo: no CD path + Sys_SetDefaultCDPath( "" ); + + // merge the command line, this is kinda silly + for ( len = 1, i = 1; i < argc; i++ ) + len += strlen( argv[i] ) + 1; + cmdline = (char*)malloc( len ); + *cmdline = 0; + for ( i = 1; i < argc; i++ ) + { + if ( i > 1 ) { + strcat( cmdline, " " ); + } + strcat( cmdline, argv[i] ); + } + + // bk000306 - clear queues + //memset( &eventQue[0], 0, MAX_QUED_EVENTS * sizeof( sysEvent_t ) ); + //memset( &sys_packetReceived[0], 0, MAX_MSGLEN * sizeof( byte ) ); + + Com_Init( cmdline ); + NET_Init(); + + //Sys_ConsoleInputInit(); + + +} + +/* +void pumpEvents(void) +{ + struct eventlist_s *ev; + + if (events_used != events_avail) + { + ev = &eventlist[events_used & (EVENTQUEUELENGTH-1)]; + + LOGI("Queue event"); + Sys_QueEvent( 0, SE_KEY, ev->scancode, ev->state?qtrue:qfalse, 0, NULL ); + + if( ev->unicode && ev->state) + Sys_QueEvent( 0, SE_CHAR,ev->unicode, 0, 0, NULL ); + + events_used++; + } + + //Ok so can not issue commands more than 60 times/sec, who cares! + if (postedCommand) + { + Cmd_ExecuteString(postedCommand); + postedCommand = 0; + } + + + if (mdx || mdy) + Sys_QueEvent( 0, SE_MOUSE, -mdx, -mdy, 0, NULL ); + mdx=mdy=0; + + + if ( Key_GetCatcher( ) & KEYCATCH_UI ) { + if (absx || absy) + VM_Call( uivm, UI_MOUSE_EVENT_ABS, absx, absy ); + absx = 0; + absy = 0; + } + +} + +/* +void CL_AndroidMove( usercmd_t *cmd ) +{ + + //cmd->forwardmove += forwardmove * cl_forwardspeed->value * 2; //Always run! (x2) + //cmd->rightmove += sidemove * cl_sidespeed->value * 2; + cmd->forwardmove = ClampChar(cmd->forwardmove + forwardmove * 127 ); + cmd->rightmove = ClampChar(cmd->rightmove + sidemove * 127 ); + + switch(look_pitch_mode) + { + case LOOK_MODE_MOUSE: + cl.viewangles[PITCH] += look_pitch_mouse * 300; + look_pitch_mouse = 0; + break; + case LOOK_MODE_ABSOLUTE: + cl.viewangles[PITCH] = look_pitch_abs * 80; + break; + case LOOK_MODE_JOYSTICK: + cl.viewangles[PITCH] += look_pitch_joy * 6; + break; + } + + + switch(look_yaw_mode) + { + case LOOK_MODE_MOUSE: + cl.viewangles[YAW] += look_yaw_mouse * 300; + look_yaw_mouse = 0; + break; + case LOOK_MODE_JOYSTICK: + cl.viewangles[YAW] += look_yaw_joy * 6; + break; + } + +} +*/ + +void IN_Frame( void ) { + //pumpEvents(); +} + +pthread_t thread1; +int thread_has_run = 0; +extern void launchSSetup(); +void PortableFrame(void){ + + // qglBindTexture (GL_TEXTURE_2D, glState.currenttextures[glState.currenttmu]); + //LOGI("PortableFrame"); + + + //pumpEvents(); + //IN_Frame( ); + Com_Frame( ); +} + +int PortableInMenu(void){ + + if ((Key_GetCatcher( ) & KEYCATCH_UI) || + (Key_GetCatcher( ) & KEYCATCH_CGAME) ) + return 1; + else + return 0; +} + +int PortableInAutomap(void) +{ + return 0; +} + +int PortableShowKeyboard(void){ + + return 0; +} + diff --git a/Projects/Android/jni/OpenJK/codemp_delete/android/in_android.h b/Projects/Android/jni/OpenJK/codemp_delete/android/in_android.h new file mode 100644 index 0000000..20dd4ad --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/android/in_android.h @@ -0,0 +1,33 @@ +//#include "beloko_common/port_act_defs.h" + + + +#ifdef __cplusplus +extern "C" +{ +#endif +int PortableKeyEvent(int state, int code ,int unitcode); +void PortableAction(int state, int action); + +void PortableMove(float fwd, float strafe); +void PortableMoveFwd(float fwd); +void PortableMoveSide(float strafe); +void PortableLookPitch(int mode, float pitch); +void PortableLookYaw(int mode, float pitch); +void PortableCommand(const char * cmd); + +void PortableMouse(float dx,float dy); + +void PortableMouseAbs(float x,float y); + +void PortableInit(int argc,const char ** argv); +void PortableFrame(void); + +int PortableInMenu(void); +int PortableShowKeyboard(void); +int PortableInAutomap(void); + + +#ifdef __cplusplus +} +#endif diff --git a/Projects/Android/jni/OpenJK/codemp_delete/android/sys_loadlib.h b/Projects/Android/jni/OpenJK/codemp_delete/android/sys_loadlib.h new file mode 100644 index 0000000..2eeb56e --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/android/sys_loadlib.h @@ -0,0 +1,26 @@ +#pragma once + +#ifdef DEDICATED +# ifdef _WIN32 +# include +# define Sys_LoadLibrary(f) (void*)LoadLibrary(f) +# define Sys_UnloadLibrary(h) FreeLibrary((HMODULE)h) +# define Sys_LoadFunction(h,fn) (void*)GetProcAddress((HMODULE)h,fn) +# define Sys_LibraryError() "unknown" +# else +# include +# define Sys_LoadLibrary(f) dlopen(f,RTLD_NOW) +# define Sys_UnloadLibrary(h) dlclose(h) +# define Sys_LoadFunction(h,fn) dlsym(h,fn) +# define Sys_LibraryError() dlerror() +# endif +#else +//# include +//# include +# define Sys_LoadLibrary(f) dlopen(f, RTLD_LAZY) +# define Sys_UnloadLibrary(h) dlclose(h) +# define Sys_LoadFunction(h,fn) dlsym(h,fn) +# define Sys_LibraryError() dlerror() +#endif + +void * QDECL Sys_LoadDll(const char *name, qboolean useSystemLib); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/android/sys_local.h b/Projects/Android/jni/OpenJK/codemp_delete/android/sys_local.h new file mode 100644 index 0000000..792875a --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/android/sys_local.h @@ -0,0 +1,13 @@ +#pragma once + +void IN_Init( void *windowData ); +void IN_Frame (void); +void IN_Shutdown( void ); +void IN_Restart( void ); + +qboolean Sys_GetPacket ( netadr_t *net_from, msg_t *net_message ); +char *Sys_ConsoleInput (void); +void Sys_QueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr ); +void Sys_ListFilteredFiles( const char *basedir, char *subdirs, char *filter, char **psList, int *numfiles ); + +void Sys_Exit( int ex ); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/aasfile.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/aasfile.h new file mode 100644 index 0000000..d20e2fb --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/aasfile.h @@ -0,0 +1,268 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#pragma once + +//NOTE: int = default signed +// default long + +#define AASID (('S'<<24)+('A'<<16)+('A'<<8)+'E') +#define AASVERSION_OLD 4 +#define AASVERSION 5 + +//presence types +#define PRESENCE_NONE 1 +#define PRESENCE_NORMAL 2 +#define PRESENCE_CROUCH 4 + +//travel types +#define MAX_TRAVELTYPES 32 +#define TRAVEL_INVALID 1 //temporary not possible +#define TRAVEL_WALK 2 //walking +#define TRAVEL_CROUCH 3 //crouching +#define TRAVEL_BARRIERJUMP 4 //jumping onto a barrier +#define TRAVEL_JUMP 5 //jumping +#define TRAVEL_LADDER 6 //climbing a ladder +#define TRAVEL_WALKOFFLEDGE 7 //walking of a ledge +#define TRAVEL_SWIM 8 //swimming +#define TRAVEL_WATERJUMP 9 //jump out of the water +#define TRAVEL_TELEPORT 10 //teleportation +#define TRAVEL_ELEVATOR 11 //travel by elevator +#define TRAVEL_ROCKETJUMP 12 //rocket jumping required for travel +#define TRAVEL_BFGJUMP 13 //bfg jumping required for travel +#define TRAVEL_GRAPPLEHOOK 14 //grappling hook required for travel +#define TRAVEL_DOUBLEJUMP 15 //double jump +#define TRAVEL_RAMPJUMP 16 //ramp jump +#define TRAVEL_STRAFEJUMP 17 //strafe jump +#define TRAVEL_JUMPPAD 18 //jump pad +#define TRAVEL_FUNCBOB 19 //func bob + +//additional travel flags +#define TRAVELTYPE_MASK 0xFFFFFF +#define TRAVELFLAG_NOTTEAM1 (1 << 24) +#define TRAVELFLAG_NOTTEAM2 (2 << 24) + +//face flags +#define FACE_SOLID 1 //just solid at the other side +#define FACE_LADDER 2 //ladder +#define FACE_GROUND 4 //standing on ground when in this face +#define FACE_GAP 8 //gap in the ground +#define FACE_LIQUID 16 //face separating two areas with liquid +#define FACE_LIQUIDSURFACE 32 //face separating liquid and air +#define FACE_BRIDGE 64 //can walk over this face if bridge is closed + +//area contents +#define AREACONTENTS_WATER 1 +#define AREACONTENTS_LAVA 2 +#define AREACONTENTS_SLIME 4 +#define AREACONTENTS_CLUSTERPORTAL 8 +#define AREACONTENTS_TELEPORTAL 16 +#define AREACONTENTS_ROUTEPORTAL 32 +#define AREACONTENTS_TELEPORTER 64 +#define AREACONTENTS_JUMPPAD 128 +#define AREACONTENTS_DONOTENTER 256 +#define AREACONTENTS_VIEWPORTAL 512 +#define AREACONTENTS_MOVER 1024 +#define AREACONTENTS_NOTTEAM1 2048 +#define AREACONTENTS_NOTTEAM2 4096 +//number of model of the mover inside this area +#define AREACONTENTS_MODELNUMSHIFT 24 +#define AREACONTENTS_MAXMODELNUM 0xFF +#define AREACONTENTS_MODELNUM (AREACONTENTS_MAXMODELNUM << AREACONTENTS_MODELNUMSHIFT) + +//area flags +#define AREA_GROUNDED 1 //bot can stand on the ground +#define AREA_LADDER 2 //area contains one or more ladder faces +#define AREA_LIQUID 4 //area contains a liquid +#define AREA_DISABLED 8 //area is disabled for routing when set +#define AREA_BRIDGE 16 //area ontop of a bridge + +//aas file header lumps +#define AAS_LUMPS 14 +#define AASLUMP_BBOXES 0 +#define AASLUMP_VERTEXES 1 +#define AASLUMP_PLANES 2 +#define AASLUMP_EDGES 3 +#define AASLUMP_EDGEINDEX 4 +#define AASLUMP_FACES 5 +#define AASLUMP_FACEINDEX 6 +#define AASLUMP_AREAS 7 +#define AASLUMP_AREASETTINGS 8 +#define AASLUMP_REACHABILITY 9 +#define AASLUMP_NODES 10 +#define AASLUMP_PORTALS 11 +#define AASLUMP_PORTALINDEX 12 +#define AASLUMP_CLUSTERS 13 + +//========== bounding box ========= + +//bounding box +typedef struct aas_bbox_s +{ + int presencetype; + int flags; + vec3_t mins, maxs; +} aas_bbox_t; + +//============ settings =========== + +//reachability to another area +typedef struct aas_reachability_s +{ + int areanum; //number of the reachable area + int facenum; //number of the face towards the other area + int edgenum; //number of the edge towards the other area + vec3_t start; //start point of inter area movement + vec3_t end; //end point of inter area movement + int traveltype; //type of travel required to get to the area + unsigned short int traveltime;//travel time of the inter area movement +} aas_reachability_t; + +//area settings +typedef struct aas_areasettings_s +{ + //could also add all kind of statistic fields + int contents; //contents of the area + int areaflags; //several area flags + int presencetype; //how a bot can be present in this area + int cluster; //cluster the area belongs to, if negative it's a portal + int clusterareanum; //number of the area in the cluster + int numreachableareas; //number of reachable areas from this one + int firstreachablearea; //first reachable area in the reachable area index +} aas_areasettings_t; + +//cluster portal +typedef struct aas_portal_s +{ + int areanum; //area that is the actual portal + int frontcluster; //cluster at front of portal + int backcluster; //cluster at back of portal + int clusterareanum[2]; //number of the area in the front and back cluster +} aas_portal_t; + +//cluster portal index +typedef int aas_portalindex_t; + +//cluster +typedef struct aas_cluster_s +{ + int numareas; //number of areas in the cluster + int numreachabilityareas; //number of areas with reachabilities + int numportals; //number of cluster portals + int firstportal; //first cluster portal in the index +} aas_cluster_t; + +//============ 3d definition ============ + +typedef vec3_t aas_vertex_t; + +//just a plane in the third dimension +typedef struct aas_plane_s +{ + vec3_t normal; //normal vector of the plane + float dist; //distance of the plane (normal vector * distance = point in plane) + int type; +} aas_plane_t; + +//edge +typedef struct aas_edge_s +{ + int v[2]; //numbers of the vertexes of this edge +} aas_edge_t; + +//edge index, negative if vertexes are reversed +typedef int aas_edgeindex_t; + +//a face bounds an area, often it will also seperate two areas +typedef struct aas_face_s +{ + int planenum; //number of the plane this face is in + int faceflags; //face flags (no use to create face settings for just this field) + int numedges; //number of edges in the boundary of the face + int firstedge; //first edge in the edge index + int frontarea; //area at the front of this face + int backarea; //area at the back of this face +} aas_face_t; + +//face index, stores a negative index if backside of face +typedef int aas_faceindex_t; + +//area with a boundary of faces +typedef struct aas_area_s +{ + int areanum; //number of this area + //3d definition + int numfaces; //number of faces used for the boundary of the area + int firstface; //first face in the face index used for the boundary of the area + vec3_t mins; //mins of the area + vec3_t maxs; //maxs of the area + vec3_t center; //'center' of the area +} aas_area_t; + +//nodes of the bsp tree +typedef struct aas_node_s +{ + int planenum; + int children[2]; //child nodes of this node, or areas as leaves when negative + //when a child is zero it's a solid leaf +} aas_node_t; + +//=========== aas file =============== + +//header lump +typedef struct aas_lump_s { + int fileofs; + int filelen; +} aas_lump_t; + +//aas file header +typedef struct aas_header_s +{ + int ident; + int version; + int bspchecksum; + //data entries + aas_lump_t lumps[AAS_LUMPS]; +} aas_header_t; + + +//====== additional information ====== +/* + +- when a node child is a solid leaf the node child number is zero +- two adjacent areas (sharing a plane at opposite sides) share a face + this face is a portal between the areas +- when an area uses a face from the faceindex with a positive index + then the face plane normal points into the area +- the face edges are stored counter clockwise using the edgeindex +- two adjacent convex areas (sharing a face) only share One face + this is a simple result of the areas being convex +- the areas can't have a mixture of ground and gap faces + other mixtures of faces in one area are allowed +- areas with the AREACONTENTS_CLUSTERPORTAL in the settings have + the cluster number set to the negative portal number +- edge zero is a dummy +- face zero is a dummy +- area zero is a dummy +- node zero is a dummy +*/ diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas.h new file mode 100644 index 0000000..e57e798 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas.h @@ -0,0 +1,228 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_aas.h + * + * desc: Area Awareness System, stuff exported to the AI + * + * $Archive: /source/code/botlib/be_aas.h $ + * $Author: osman $ + * $Revision: 1.4 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 2003/03/15 23:43:59 $ + * + *****************************************************************************/ +#pragma once + +#define AASINTERN + +#ifndef MAX_STRINGFIELD +#define MAX_STRINGFIELD 80 +#endif + +//travel flags +#define TFL_INVALID 0x00000001 //traveling temporary not possible +#define TFL_WALK 0x00000002 //walking +#define TFL_CROUCH 0x00000004 //crouching +#define TFL_BARRIERJUMP 0x00000008 //jumping onto a barrier +#define TFL_JUMP 0x00000010 //jumping +#define TFL_LADDER 0x00000020 //climbing a ladder +#define TFL_WALKOFFLEDGE 0x00000080 //walking of a ledge +#define TFL_SWIM 0x00000100 //swimming +#define TFL_WATERJUMP 0x00000200 //jumping out of the water +#define TFL_TELEPORT 0x00000400 //teleporting +#define TFL_ELEVATOR 0x00000800 //elevator +#define TFL_ROCKETJUMP 0x00001000 //rocket jumping +#define TFL_BFGJUMP 0x00002000 //bfg jumping +#define TFL_GRAPPLEHOOK 0x00004000 //grappling hook +#define TFL_DOUBLEJUMP 0x00008000 //double jump +#define TFL_RAMPJUMP 0x00010000 //ramp jump +#define TFL_STRAFEJUMP 0x00020000 //strafe jump +#define TFL_JUMPPAD 0x00040000 //jump pad +#define TFL_AIR 0x00080000 //travel through air +#define TFL_WATER 0x00100000 //travel through water +#define TFL_SLIME 0x00200000 //travel through slime +#define TFL_LAVA 0x00400000 //travel through lava +#define TFL_DONOTENTER 0x00800000 //travel through donotenter area +#define TFL_FUNCBOB 0x01000000 //func bobbing +#define TFL_FLIGHT 0x02000000 //flight +#define TFL_BRIDGE 0x04000000 //move over a bridge +// +#define TFL_NOTTEAM1 0x08000000 //not team 1 +#define TFL_NOTTEAM2 0x10000000 //not team 2 + +//default travel flags +#define TFL_DEFAULT TFL_WALK|TFL_CROUCH|TFL_BARRIERJUMP|\ + TFL_JUMP|TFL_LADDER|\ + TFL_WALKOFFLEDGE|TFL_SWIM|TFL_WATERJUMP|\ + TFL_TELEPORT|TFL_ELEVATOR|\ + TFL_AIR|TFL_WATER|TFL_JUMPPAD|TFL_FUNCBOB + +typedef enum +{ + SOLID_NOT, // no interaction with other objects + SOLID_TRIGGER, // only touch when inside, after moving + SOLID_BBOX, // touch on edge + SOLID_BSP // bsp clip, touch on edge +} solid_t; + +//a trace is returned when a box is swept through the AAS world +typedef struct aas_trace_s +{ + qboolean startsolid; // if true, the initial point was in a solid area + float fraction; // time completed, 1.0 = didn't hit anything + vec3_t endpos; // final position + int ent; // entity blocking the trace + int lastarea; // last area the trace was in (zero if none) + int area; // area blocking the trace (zero if none) + int planenum; // number of the plane that was hit +} aas_trace_t; + +/* Defined in botlib.h + +//bsp_trace_t hit surface +typedef struct bsp_surface_s +{ + char name[16]; + int flags; + int value; +} bsp_surface_t; + +//a trace is returned when a box is swept through the BSP world +typedef struct bsp_trace_s +{ + qboolean allsolid; // if true, plane is not valid + qboolean startsolid; // if true, the initial point was in a solid area + float fraction; // time completed, 1.0 = didn't hit anything + vec3_t endpos; // final position + cplane_t plane; // surface normal at impact + float exp_dist; // expanded plane distance + int sidenum; // number of the brush side hit + bsp_surface_t surface; // hit surface + int contents; // contents on other side of surface hit + int ent; // number of entity hit +} bsp_trace_t; +// +*/ + +//entity info +typedef struct aas_entityinfo_s +{ + int valid; // true if updated this frame + int type; // entity type + int flags; // entity flags + float ltime; // local time + float update_time; // time between last and current update + int number; // number of the entity + vec3_t origin; // origin of the entity + vec3_t angles; // angles of the model + vec3_t old_origin; // for lerping + vec3_t lastvisorigin; // last visible origin + vec3_t mins; // bounding box minimums + vec3_t maxs; // bounding box maximums + int groundent; // ground entity + int solid; // solid type + int modelindex; // model used + int modelindex2; // weapons, CTF flags, etc + int frame; // model frame number + int event; // impulse events -- muzzle flashes, footsteps, etc + int eventParm; // even parameter + int powerups; // bit flags + int weapon; // determines weapon and flash model, etc + int legsAnim; // current legs anim + int torsoAnim; // current torso anim +} aas_entityinfo_t; + +// area info +typedef struct aas_areainfo_s +{ + int contents; + int flags; + int presencetype; + int cluster; + vec3_t mins; + vec3_t maxs; + vec3_t center; +} aas_areainfo_t; + +// client movement prediction stop events, stop as soon as: +#define SE_NONE 0 +#define SE_HITGROUND 1 // the ground is hit +#define SE_LEAVEGROUND 2 // there's no ground +#define SE_ENTERWATER 4 // water is entered +#define SE_ENTERSLIME 8 // slime is entered +#define SE_ENTERLAVA 16 // lava is entered +#define SE_HITGROUNDDAMAGE 32 // the ground is hit with damage +#define SE_GAP 64 // there's a gap +#define SE_TOUCHJUMPPAD 128 // touching a jump pad area +#define SE_TOUCHTELEPORTER 256 // touching teleporter +#define SE_ENTERAREA 512 // the given stoparea is entered +#define SE_HITGROUNDAREA 1024 // a ground face in the area is hit +#define SE_HITBOUNDINGBOX 2048 // hit the specified bounding box +#define SE_TOUCHCLUSTERPORTAL 4096 // touching a cluster portal + +typedef struct aas_clientmove_s +{ + vec3_t endpos; //position at the end of movement prediction + int endarea; //area at end of movement prediction + vec3_t velocity; //velocity at the end of movement prediction + aas_trace_t trace; //last trace + int presencetype; //presence type at end of movement prediction + int stopevent; //event that made the prediction stop + int endcontents; //contents at the end of movement prediction + float time; //time predicted ahead + int frames; //number of frames predicted ahead +} aas_clientmove_t; + +// alternate route goals +#define ALTROUTEGOAL_ALL 1 +#define ALTROUTEGOAL_CLUSTERPORTALS 2 +#define ALTROUTEGOAL_VIEWPORTALS 4 + +typedef struct aas_altroutegoal_s +{ + vec3_t origin; + int areanum; + unsigned short starttraveltime; + unsigned short goaltraveltime; + unsigned short extratraveltime; +} aas_altroutegoal_t; + +// route prediction stop events +#define RSE_NONE 0 +#define RSE_NOROUTE 1 //no route to goal +#define RSE_USETRAVELTYPE 2 //stop as soon as on of the given travel types is used +#define RSE_ENTERCONTENTS 4 //stop when entering the given contents +#define RSE_ENTERAREA 8 //stop when entering the given area + +typedef struct aas_predictroute_s +{ + vec3_t endpos; //position at the end of movement prediction + int endarea; //area at end of movement prediction + int stopevent; //event that made the prediction stop + int endcontents; //contents at the end of movement prediction + int endtravelflags; //end travel flags + int numareas; //number of areas predicted ahead + int time; //time predicted ahead (in hundreth of a sec) +} aas_predictroute_t; diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_bsp.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_bsp.h new file mode 100644 index 0000000..024ceaa --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_bsp.h @@ -0,0 +1,94 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_aas_bsp.h + * + * desc: AAS + * + * $Archive: /source/code/botlib/be_aas_bsp.h $ + * $Author: Mrelusive $ + * $Revision: 2 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 10/05/99 3:42p $ + * + *****************************************************************************/ +#pragma once + +#ifdef AASINTERN +//loads the given BSP file +int AAS_LoadBSPFile(void); +//dump the loaded BSP data +void AAS_DumpBSPData(void); +//unlink the given entity from the bsp tree leaves +void AAS_UnlinkFromBSPLeaves(bsp_link_t *leaves); +//link the given entity to the bsp tree leaves of the given model +bsp_link_t *AAS_BSPLinkEntity(vec3_t absmins, + vec3_t absmaxs, + int entnum, + int modelnum); + +//calculates collision with given entity +qboolean AAS_EntityCollision(int entnum, + vec3_t start, + vec3_t boxmins, + vec3_t boxmaxs, + vec3_t end, + int contentmask, + bsp_trace_t *trace); +//for debugging +void AAS_PrintFreeBSPLinks(char *str); +// +#endif //AASINTERN + +#define MAX_EPAIRKEY 128 + +//trace through the world +bsp_trace_t AAS_Trace( vec3_t start, + vec3_t mins, + vec3_t maxs, + vec3_t end, + int passent, + int contentmask); +//returns the contents at the given point +int AAS_PointContents(vec3_t point); +//returns true when p2 is in the PVS of p1 +qboolean AAS_inPVS(vec3_t p1, vec3_t p2); +//returns true when p2 is in the PHS of p1 +qboolean AAS_inPHS(vec3_t p1, vec3_t p2); +//returns true if the given areas are connected +qboolean AAS_AreasConnected(int area1, int area2); +//creates a list with entities totally or partly within the given box +int AAS_BoxEntities(vec3_t absmins, vec3_t absmaxs, int *list, int maxcount); +//gets the mins, maxs and origin of a BSP model +void AAS_BSPModelMinsMaxsOrigin(int modelnum, vec3_t angles, vec3_t mins, vec3_t maxs, vec3_t origin); +//handle to the next bsp entity +int AAS_NextBSPEntity(int ent); +//return the value of the BSP epair key +int AAS_ValueForBSPEpairKey(int ent, char *key, char *value, int size); +//get a vector for the BSP epair key +int AAS_VectorForBSPEpairKey(int ent, char *key, vec3_t v); +//get a float for the BSP epair key +int AAS_FloatForBSPEpairKey(int ent, char *key, float *value); +//get an integer for the BSP epair key +int AAS_IntForBSPEpairKey(int ent, char *key, int *value); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_bspq3.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_bspq3.cpp new file mode 100644 index 0000000..522b825 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_bspq3.cpp @@ -0,0 +1,491 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_aas_bspq3.c + * + * desc: BSP, Environment Sampling + * + * $Archive: /MissionPack/code/botlib/be_aas_bspq3.c $ + * $Author: Ttimo $ + * $Revision: 5 $ + * $Modtime: 4/22/01 8:52a $ + * $Date: 4/22/01 8:52a $ + * + *****************************************************************************/ + +#include "qcommon/q_shared.h" +#include "l_memory.h" +#include "l_script.h" +#include "l_precomp.h" +#include "l_struct.h" +#include "aasfile.h" +#include "botlib.h" +#include "be_aas.h" +#include "be_aas_funcs.h" +#include "be_aas_def.h" + +extern botlib_import_t botimport; + +//#define TRACE_DEBUG + +#define ON_EPSILON 0.005 + +#define MAX_BSPENTITIES 2048 + +typedef struct rgb_s +{ + int red; + int green; + int blue; +} rgb_t; + +//bsp entity epair +typedef struct bsp_epair_s +{ + char *key; + char *value; + struct bsp_epair_s *next; +} bsp_epair_t; + +//bsp data entity +typedef struct bsp_entity_s +{ + bsp_epair_t *epairs; +} bsp_entity_t; + +//id Sofware BSP data +typedef struct bsp_s +{ + //true when bsp file is loaded + int loaded; + //entity data + int entdatasize; + char *dentdata; + //bsp entities + int numentities; + bsp_entity_t entities[MAX_BSPENTITIES]; +} bsp_t; + +//global bsp +bsp_t bspworld; + + +#ifdef BSP_DEBUG +typedef struct cname_s +{ + int value; + char *name; +} cname_t; + +cname_t contentnames[] = +{ + {CONTENTS_SOLID,"CONTENTS_SOLID"}, + {CONTENTS_WINDOW,"CONTENTS_WINDOW"}, + {CONTENTS_AUX,"CONTENTS_AUX"}, + {CONTENTS_LAVA,"CONTENTS_LAVA"}, + {CONTENTS_SLIME,"CONTENTS_SLIME"}, + {CONTENTS_WATER,"CONTENTS_WATER"}, + {CONTENTS_MIST,"CONTENTS_MIST"}, + {LAST_VISIBLE_CONTENTS,"LAST_VISIBLE_CONTENTS"}, + + {CONTENTS_AREAPORTAL,"CONTENTS_AREAPORTAL"}, + {CONTENTS_PLAYERCLIP,"CONTENTS_PLAYERCLIP"}, + {CONTENTS_MONSTERCLIP,"CONTENTS_MONSTERCLIP"}, + {CONTENTS_CURRENT_0,"CONTENTS_CURRENT_0"}, + {CONTENTS_CURRENT_90,"CONTENTS_CURRENT_90"}, + {CONTENTS_CURRENT_180,"CONTENTS_CURRENT_180"}, + {CONTENTS_CURRENT_270,"CONTENTS_CURRENT_270"}, + {CONTENTS_CURRENT_UP,"CONTENTS_CURRENT_UP"}, + {CONTENTS_CURRENT_DOWN,"CONTENTS_CURRENT_DOWN"}, + {CONTENTS_ORIGIN,"CONTENTS_ORIGIN"}, + {CONTENTS_MONSTER,"CONTENTS_MONSTER"}, + {CONTENTS_DEADMONSTER,"CONTENTS_DEADMONSTER"}, + {CONTENTS_DETAIL,"CONTENTS_DETAIL"}, + {CONTENTS_TRANSLUCENT,"CONTENTS_TRANSLUCENT"}, + {CONTENTS_LADDER,"CONTENTS_LADDER"}, + {0, 0} +}; + +void PrintContents(int contents) +{ + int i; + + for (i = 0; contentnames[i].value; i++) + { + if (contents & contentnames[i].value) + { + botimport.Print(PRT_MESSAGE, "%s\n", contentnames[i].name); + } //end if + } //end for +} //end of the function PrintContents + +#endif // BSP_DEBUG +//=========================================================================== +// traces axial boxes of any size through the world +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bsp_trace_t AAS_Trace(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask) +{ + bsp_trace_t bsptrace; + botimport.Trace(&bsptrace, start, mins, maxs, end, passent, contentmask); + return bsptrace; +} //end of the function AAS_Trace +//=========================================================================== +// returns the contents at the given point +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_PointContents(vec3_t point) +{ + return botimport.PointContents(point); +} //end of the function AAS_PointContents +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +qboolean AAS_EntityCollision(int entnum, + vec3_t start, vec3_t boxmins, vec3_t boxmaxs, vec3_t end, + int contentmask, bsp_trace_t *trace) +{ + bsp_trace_t enttrace; + + botimport.EntityTrace(&enttrace, start, boxmins, boxmaxs, end, entnum, contentmask); + if (enttrace.fraction < trace->fraction) + { + Com_Memcpy(trace, &enttrace, sizeof(bsp_trace_t)); + return qtrue; + } //end if + return qfalse; +} //end of the function AAS_EntityCollision +//=========================================================================== +// returns true if in Potentially Hearable Set +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +qboolean AAS_inPVS(vec3_t p1, vec3_t p2) +{ + return (qboolean)botimport.inPVS(p1, p2); +} //end of the function AAS_InPVS +//=========================================================================== +// returns true if in Potentially Visible Set +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +qboolean AAS_inPHS(vec3_t p1, vec3_t p2) +{ + return qtrue; +} //end of the function AAS_inPHS +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_BSPModelMinsMaxsOrigin(int modelnum, vec3_t angles, vec3_t mins, vec3_t maxs, vec3_t origin) +{ + botimport.BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin); +} //end of the function AAS_BSPModelMinsMaxs +//=========================================================================== +// unlinks the entity from all leaves +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_UnlinkFromBSPLeaves(bsp_link_t *leaves) +{ +} //end of the function AAS_UnlinkFromBSPLeaves +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bsp_link_t *AAS_BSPLinkEntity(vec3_t absmins, vec3_t absmaxs, int entnum, int modelnum) +{ + return NULL; +} //end of the function AAS_BSPLinkEntity +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_BoxEntities(vec3_t absmins, vec3_t absmaxs, int *list, int maxcount) +{ + return 0; +} //end of the function AAS_BoxEntities +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_NextBSPEntity(int ent) +{ + ent++; + if (ent >= 1 && ent < bspworld.numentities) return ent; + return 0; +} //end of the function AAS_NextBSPEntity +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_BSPEntityInRange(int ent) +{ + if (ent <= 0 || ent >= bspworld.numentities) + { + botimport.Print(PRT_MESSAGE, "bsp entity out of range\n"); + return qfalse; + } //end if + return qtrue; +} //end of the function AAS_BSPEntityInRange +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_ValueForBSPEpairKey(int ent, char *key, char *value, int size) +{ + bsp_epair_t *epair; + + value[0] = '\0'; + if (!AAS_BSPEntityInRange(ent)) return qfalse; + for (epair = bspworld.entities[ent].epairs; epair; epair = epair->next) + { + if (!strcmp(epair->key, key)) + { + strncpy(value, epair->value, size-1); + value[size-1] = '\0'; + return qtrue; + } //end if + } //end for + return qfalse; +} //end of the function AAS_FindBSPEpair +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_VectorForBSPEpairKey(int ent, char *key, vec3_t v) +{ + char buf[MAX_EPAIRKEY]; + double v1, v2, v3; + + VectorClear(v); + if (!AAS_ValueForBSPEpairKey(ent, key, buf, MAX_EPAIRKEY)) return qfalse; + //scanf into doubles, then assign, so it is float size independent + v1 = v2 = v3 = 0; + sscanf(buf, "%lf %lf %lf", &v1, &v2, &v3); + v[0] = v1; + v[1] = v2; + v[2] = v3; + return qtrue; +} //end of the function AAS_VectorForBSPEpairKey +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_FloatForBSPEpairKey(int ent, char *key, float *value) +{ + char buf[MAX_EPAIRKEY]; + + *value = 0; + if (!AAS_ValueForBSPEpairKey(ent, key, buf, MAX_EPAIRKEY)) return qfalse; + *value = atof(buf); + return qtrue; +} //end of the function AAS_FloatForBSPEpairKey +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_IntForBSPEpairKey(int ent, char *key, int *value) +{ + char buf[MAX_EPAIRKEY]; + + *value = 0; + if (!AAS_ValueForBSPEpairKey(ent, key, buf, MAX_EPAIRKEY)) return qfalse; + *value = atoi(buf); + return qtrue; +} //end of the function AAS_IntForBSPEpairKey +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_FreeBSPEntities(void) +{ + int i; + bsp_entity_t *ent; + bsp_epair_t *epair, *nextepair; + + for (i = 1; i < bspworld.numentities; i++) + { + ent = &bspworld.entities[i]; + for (epair = ent->epairs; epair; epair = nextepair) + { + nextepair = epair->next; + // + if (epair->key) FreeMemory(epair->key); + if (epair->value) FreeMemory(epair->value); + FreeMemory(epair); + } //end for + } //end for + bspworld.numentities = 0; +} //end of the function AAS_FreeBSPEntities +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_ParseBSPEntities(void) +{ + script_t *script; + token_t token; + bsp_entity_t *ent; + bsp_epair_t *epair; + + script = LoadScriptMemory(bspworld.dentdata, bspworld.entdatasize, "entdata"); + SetScriptFlags(script, SCFL_NOSTRINGWHITESPACES|SCFL_NOSTRINGESCAPECHARS);//SCFL_PRIMITIVE); + + bspworld.numentities = 1; + + while(PS_ReadToken(script, &token)) + { + if (strcmp(token.string, "{")) + { + ScriptError(script, "invalid %s", token.string); + AAS_FreeBSPEntities(); + FreeScript(script); + return; + } //end if + if (bspworld.numentities >= MAX_BSPENTITIES) + { + botimport.Print(PRT_MESSAGE, "too many entities in BSP file\n"); + break; + } //end if + ent = &bspworld.entities[bspworld.numentities]; + bspworld.numentities++; + ent->epairs = NULL; + while(PS_ReadToken(script, &token)) + { + if (!strcmp(token.string, "}")) break; + epair = (bsp_epair_t *) GetClearedHunkMemory(sizeof(bsp_epair_t)); + epair->next = ent->epairs; + ent->epairs = epair; + if (token.type != TT_STRING) + { + ScriptError(script, "invalid %s", token.string); + AAS_FreeBSPEntities(); + FreeScript(script); + return; + } //end if + StripDoubleQuotes(token.string); + epair->key = (char *) GetHunkMemory(strlen(token.string) + 1); + strcpy(epair->key, token.string); + if (!PS_ExpectTokenType(script, TT_STRING, 0, &token)) + { + AAS_FreeBSPEntities(); + FreeScript(script); + return; + } //end if + StripDoubleQuotes(token.string); + epair->value = (char *) GetHunkMemory(strlen(token.string) + 1); + strcpy(epair->value, token.string); + } //end while + if (strcmp(token.string, "}")) + { + ScriptError(script, "missing }"); + AAS_FreeBSPEntities(); + FreeScript(script); + return; + } //end if + } //end while + FreeScript(script); +} //end of the function AAS_ParseBSPEntities +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_BSPTraceLight(vec3_t start, vec3_t end, vec3_t endpos, int *red, int *green, int *blue) +{ + return 0; +} //end of the function AAS_BSPTraceLight +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_DumpBSPData(void) +{ + AAS_FreeBSPEntities(); + + if (bspworld.dentdata) FreeMemory(bspworld.dentdata); + bspworld.dentdata = NULL; + bspworld.entdatasize = 0; + // + bspworld.loaded = qfalse; + Com_Memset( &bspworld, 0, sizeof(bspworld) ); +} //end of the function AAS_DumpBSPData +//=========================================================================== +// load a .bsp file +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_LoadBSPFile(void) +{ + AAS_DumpBSPData(); + bspworld.entdatasize = strlen(botimport.BSPEntityData()) + 1; + bspworld.dentdata = (char *) GetClearedHunkMemory(bspworld.entdatasize); + Com_Memcpy(bspworld.dentdata, botimport.BSPEntityData(), bspworld.entdatasize); + AAS_ParseBSPEntities(); + bspworld.loaded = qtrue; + return BLERR_NOERROR; +} //end of the function AAS_LoadBSPFile diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_cluster.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_cluster.cpp new file mode 100644 index 0000000..c4b3152 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_cluster.cpp @@ -0,0 +1,1550 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_aas_cluster.c + * + * desc: area clustering + * + * $Archive: /MissionPack/code/botlib/be_aas_cluster.c $ + * $Author: Ttimo $ + * $Revision: 10 $ + * $Modtime: 4/21/01 9:15a $ + * $Date: 4/21/01 9:15a $ + * + *****************************************************************************/ + +#include "qcommon/q_shared.h" +#include "l_memory.h" +#include "l_script.h" +#include "l_precomp.h" +#include "l_struct.h" +#include "l_log.h" +#include "l_memory.h" +#include "l_libvar.h" +#include "aasfile.h" +#include "botlib.h" +#include "be_aas.h" +#include "be_aas_funcs.h" +#include "be_aas_def.h" + +extern botlib_import_t botimport; + +#define AAS_MAX_PORTALS 65536 +#define AAS_MAX_PORTALINDEXSIZE 65536 +#define AAS_MAX_CLUSTERS 65536 +// +#define MAX_PORTALAREAS 1024 + +// do not flood through area faces, only use reachabilities +int nofaceflood = qtrue; + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_RemoveClusterAreas(void) +{ + int i; + + for (i = 1; i < aasworld.numareas; i++) + { + aasworld.areasettings[i].cluster = 0; + } //end for +} //end of the function AAS_RemoveClusterAreas +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_ClearCluster(int clusternum) +{ + int i; + + for (i = 1; i < aasworld.numareas; i++) + { + if (aasworld.areasettings[i].cluster == clusternum) + { + aasworld.areasettings[i].cluster = 0; + } //end if + } //end for +} //end of the function AAS_ClearCluster +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_RemovePortalsClusterReference(int clusternum) +{ + int portalnum; + + for (portalnum = 1; portalnum < aasworld.numportals; portalnum++) + { + if (aasworld.portals[portalnum].frontcluster == clusternum) + { + aasworld.portals[portalnum].frontcluster = 0; + } //end if + if (aasworld.portals[portalnum].backcluster == clusternum) + { + aasworld.portals[portalnum].backcluster = 0; + } //end if + } //end for +} //end of the function AAS_RemovePortalsClusterReference +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_UpdatePortal(int areanum, int clusternum) +{ + int portalnum; + aas_portal_t *portal; + aas_cluster_t *cluster; + + //find the portal of the area + for (portalnum = 1; portalnum < aasworld.numportals; portalnum++) + { + if (aasworld.portals[portalnum].areanum == areanum) break; + } //end for + // + if (portalnum == aasworld.numportals) + { + AAS_Error("no portal of area %d\n", areanum); + return qtrue; + } //end if + // + portal = &aasworld.portals[portalnum]; + //if the portal is already fully updated + if (portal->frontcluster == clusternum) return qtrue; + if (portal->backcluster == clusternum) return qtrue; + //if the portal has no front cluster yet + if (!portal->frontcluster) + { + portal->frontcluster = clusternum; + } //end if + //if the portal has no back cluster yet + else if (!portal->backcluster) + { + portal->backcluster = clusternum; + } //end else if + else + { + //remove the cluster portal flag contents + aasworld.areasettings[areanum].contents &= ~AREACONTENTS_CLUSTERPORTAL; + Log_Write("portal area %d is separating more than two clusters\r\n", areanum); + return qfalse; + } //end else + if (aasworld.portalindexsize >= AAS_MAX_PORTALINDEXSIZE) + { + AAS_Error("AAS_MAX_PORTALINDEXSIZE\n"); + return qtrue; + } //end if + //set the area cluster number to the negative portal number + aasworld.areasettings[areanum].cluster = -portalnum; + //add the portal to the cluster using the portal index + cluster = &aasworld.clusters[clusternum]; + aasworld.portalindex[cluster->firstportal + cluster->numportals] = portalnum; + aasworld.portalindexsize++; + cluster->numportals++; + return qtrue; +} //end of the function AAS_UpdatePortal +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_FloodClusterAreas_r(int areanum, int clusternum) +{ + aas_area_t *area; + aas_face_t *face; + int facenum, i; + + // + if (areanum <= 0 || areanum >= aasworld.numareas) + { + AAS_Error("AAS_FloodClusterAreas_r: areanum out of range\n"); + return qfalse; + } //end if + //if the area is already part of a cluster + if (aasworld.areasettings[areanum].cluster > 0) + { + if (aasworld.areasettings[areanum].cluster == clusternum) return qtrue; + // + //there's a reachability going from one cluster to another only in one direction + // + AAS_Error("cluster %d touched cluster %d at area %d\n", + clusternum, aasworld.areasettings[areanum].cluster, areanum); + return qfalse; + } //end if + //don't add the cluster portal areas to the clusters + if (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL) + { + return AAS_UpdatePortal(areanum, clusternum); + } //end if + //set the area cluster number + aasworld.areasettings[areanum].cluster = clusternum; + aasworld.areasettings[areanum].clusterareanum = + aasworld.clusters[clusternum].numareas; + //the cluster has an extra area + aasworld.clusters[clusternum].numareas++; + + area = &aasworld.areas[areanum]; + //use area faces to flood into adjacent areas + if (!nofaceflood) + { + for (i = 0; i < area->numfaces; i++) + { + facenum = abs(aasworld.faceindex[area->firstface + i]); + face = &aasworld.faces[facenum]; + if (face->frontarea == areanum) + { + if (face->backarea) if (!AAS_FloodClusterAreas_r(face->backarea, clusternum)) return qfalse; + } //end if + else + { + if (face->frontarea) if (!AAS_FloodClusterAreas_r(face->frontarea, clusternum)) return qfalse; + } //end else + } //end for + } //end if + //use the reachabilities to flood into other areas + for (i = 0; i < aasworld.areasettings[areanum].numreachableareas; i++) + { + if (!aasworld.reachability[ + aasworld.areasettings[areanum].firstreachablearea + i].areanum) + { + continue; + } //end if + if (!AAS_FloodClusterAreas_r(aasworld.reachability[ + aasworld.areasettings[areanum].firstreachablearea + i].areanum, clusternum)) return qfalse; + } //end for + return qtrue; +} //end of the function AAS_FloodClusterAreas_r +//=========================================================================== +// try to flood from all areas without cluster into areas with a cluster set +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_FloodClusterAreasUsingReachabilities(int clusternum) +{ + int i, j, areanum; + + for (i = 1; i < aasworld.numareas; i++) + { + //if this area already has a cluster set + if (aasworld.areasettings[i].cluster) + continue; + //if this area is a cluster portal + if (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL) + continue; + //loop over the reachable areas from this area + for (j = 0; j < aasworld.areasettings[i].numreachableareas; j++) + { + //the reachable area + areanum = aasworld.reachability[aasworld.areasettings[i].firstreachablearea + j].areanum; + //if this area is a cluster portal + if (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL) + continue; + //if this area has a cluster set + if (aasworld.areasettings[areanum].cluster) + { + if (!AAS_FloodClusterAreas_r(i, clusternum)) + return qfalse; + i = 0; + break; + } //end if + } //end for + } //end for + return qtrue; +} //end of the function AAS_FloodClusterAreasUsingReachabilities +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_NumberClusterPortals(int clusternum) +{ + int i, portalnum; + aas_cluster_t *cluster; + aas_portal_t *portal; + + cluster = &aasworld.clusters[clusternum]; + for (i = 0; i < cluster->numportals; i++) + { + portalnum = aasworld.portalindex[cluster->firstportal + i]; + portal = &aasworld.portals[portalnum]; + if (portal->frontcluster == clusternum) + { + portal->clusterareanum[0] = cluster->numareas++; + } //end if + else + { + portal->clusterareanum[1] = cluster->numareas++; + } //end else + } //end for +} //end of the function AAS_NumberClusterPortals +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_NumberClusterAreas(int clusternum) +{ + int i, portalnum; + aas_cluster_t *cluster; + aas_portal_t *portal; + + aasworld.clusters[clusternum].numareas = 0; + aasworld.clusters[clusternum].numreachabilityareas = 0; + //number all areas in this cluster WITH reachabilities + for (i = 1; i < aasworld.numareas; i++) + { + // + if (aasworld.areasettings[i].cluster != clusternum) continue; + // + if (!AAS_AreaReachability(i)) continue; + // + aasworld.areasettings[i].clusterareanum = aasworld.clusters[clusternum].numareas; + //the cluster has an extra area + aasworld.clusters[clusternum].numareas++; + aasworld.clusters[clusternum].numreachabilityareas++; + } //end for + //number all portals in this cluster WITH reachabilities + cluster = &aasworld.clusters[clusternum]; + for (i = 0; i < cluster->numportals; i++) + { + portalnum = aasworld.portalindex[cluster->firstportal + i]; + portal = &aasworld.portals[portalnum]; + if (!AAS_AreaReachability(portal->areanum)) continue; + if (portal->frontcluster == clusternum) + { + portal->clusterareanum[0] = cluster->numareas++; + aasworld.clusters[clusternum].numreachabilityareas++; + } //end if + else + { + portal->clusterareanum[1] = cluster->numareas++; + aasworld.clusters[clusternum].numreachabilityareas++; + } //end else + } //end for + //number all areas in this cluster WITHOUT reachabilities + for (i = 1; i < aasworld.numareas; i++) + { + // + if (aasworld.areasettings[i].cluster != clusternum) continue; + // + if (AAS_AreaReachability(i)) continue; + // + aasworld.areasettings[i].clusterareanum = aasworld.clusters[clusternum].numareas; + //the cluster has an extra area + aasworld.clusters[clusternum].numareas++; + } //end for + //number all portals in this cluster WITHOUT reachabilities + cluster = &aasworld.clusters[clusternum]; + for (i = 0; i < cluster->numportals; i++) + { + portalnum = aasworld.portalindex[cluster->firstportal + i]; + portal = &aasworld.portals[portalnum]; + if (AAS_AreaReachability(portal->areanum)) continue; + if (portal->frontcluster == clusternum) + { + portal->clusterareanum[0] = cluster->numareas++; + } //end if + else + { + portal->clusterareanum[1] = cluster->numareas++; + } //end else + } //end for +} //end of the function AAS_NumberClusterAreas +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_FindClusters(void) +{ + int i; + aas_cluster_t *cluster; + + AAS_RemoveClusterAreas(); + // + for (i = 1; i < aasworld.numareas; i++) + { + //if the area is already part of a cluster + if (aasworld.areasettings[i].cluster) + continue; + // if not flooding through faces only use areas that have reachabilities + if (nofaceflood) + { + if (!aasworld.areasettings[i].numreachableareas) + continue; + } //end if + //if the area is a cluster portal + if (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL) + continue; + if (aasworld.numclusters >= AAS_MAX_CLUSTERS) + { + AAS_Error("AAS_MAX_CLUSTERS\n"); + return qfalse; + } //end if + cluster = &aasworld.clusters[aasworld.numclusters]; + cluster->numareas = 0; + cluster->numreachabilityareas = 0; + cluster->firstportal = aasworld.portalindexsize; + cluster->numportals = 0; + //flood the areas in this cluster + if (!AAS_FloodClusterAreas_r(i, aasworld.numclusters)) + return qfalse; + if (!AAS_FloodClusterAreasUsingReachabilities(aasworld.numclusters)) + return qfalse; + //number the cluster areas + //AAS_NumberClusterPortals(aasworld.numclusters); + AAS_NumberClusterAreas(aasworld.numclusters); + //Log_Write("cluster %d has %d areas\r\n", aasworld.numclusters, cluster->numareas); + aasworld.numclusters++; + } //end for + return qtrue; +} //end of the function AAS_FindClusters +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_CreatePortals(void) +{ + int i; + aas_portal_t *portal; + + for (i = 1; i < aasworld.numareas; i++) + { + //if the area is a cluster portal + if (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL) + { + if (aasworld.numportals >= AAS_MAX_PORTALS) + { + AAS_Error("AAS_MAX_PORTALS\n"); + return; + } //end if + portal = &aasworld.portals[aasworld.numportals]; + portal->areanum = i; + portal->frontcluster = 0; + portal->backcluster = 0; + aasworld.numportals++; + } //end if + } //end for +} //end of the function AAS_CreatePortals +/* +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_MapContainsTeleporters(void) +{ + bsp_entity_t *entities, *ent; + char *classname; + + entities = AAS_ParseBSPEntities(); + + for (ent = entities; ent; ent = ent->next) + { + classname = AAS_ValueForBSPEpairKey(ent, "classname"); + if (classname && !strcmp(classname, "misc_teleporter")) + { + AAS_FreeBSPEntities(entities); + return qtrue; + } //end if + } //end for + return qfalse; +} //end of the function AAS_MapContainsTeleporters +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_NonConvexFaces(aas_face_t *face1, aas_face_t *face2, int side1, int side2) +{ + int i, j, edgenum; + aas_plane_t *plane1, *plane2; + aas_edge_t *edge; + + + plane1 = &aasworld.planes[face1->planenum ^ side1]; + plane2 = &aasworld.planes[face2->planenum ^ side2]; + + //check if one of the points of face1 is at the back of the plane of face2 + for (i = 0; i < face1->numedges; i++) + { + edgenum = abs(aasworld.edgeindex[face1->firstedge + i]); + edge = &aasworld.edges[edgenum]; + for (j = 0; j < 2; j++) + { + if (DotProduct(plane2->normal, aasworld.vertexes[edge->v[j]]) - + plane2->dist < -0.01) return qtrue; + } //end for + } //end for + for (i = 0; i < face2->numedges; i++) + { + edgenum = abs(aasworld.edgeindex[face2->firstedge + i]); + edge = &aasworld.edges[edgenum]; + for (j = 0; j < 2; j++) + { + if (DotProduct(plane1->normal, aasworld.vertexes[edge->v[j]]) - + plane1->dist < -0.01) return qtrue; + } //end for + } //end for + + return qfalse; +} //end of the function AAS_NonConvexFaces +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +qboolean AAS_CanMergeAreas(int *areanums, int numareas) +{ + int i, j, s, face1num, face2num, side1, side2, fn1, fn2; + aas_face_t *face1, *face2; + aas_area_t *area1, *area2; + + for (i = 0; i < numareas; i++) + { + area1 = &aasworld.areas[areanums[i]]; + for (fn1 = 0; fn1 < area1->numfaces; fn1++) + { + face1num = abs(aasworld.faceindex[area1->firstface + fn1]); + face1 = &aasworld.faces[face1num]; + side1 = face1->frontarea != areanums[i]; + //check if the face isn't a shared one with one of the other areas + for (s = 0; s < numareas; s++) + { + if (s == i) continue; + if (face1->frontarea == s || face1->backarea == s) break; + } //end for + //if the face was a shared one + if (s != numareas) continue; + // + for (j = 0; j < numareas; j++) + { + if (j == i) continue; + area2 = &aasworld.areas[areanums[j]]; + for (fn2 = 0; fn2 < area2->numfaces; fn2++) + { + face2num = abs(aasworld.faceindex[area2->firstface + fn2]); + face2 = &aasworld.faces[face2num]; + side2 = face2->frontarea != areanums[j]; + //check if the face isn't a shared one with one of the other areas + for (s = 0; s < numareas; s++) + { + if (s == j) continue; + if (face2->frontarea == s || face2->backarea == s) break; + } //end for + //if the face was a shared one + if (s != numareas) continue; + // + if (AAS_NonConvexFaces(face1, face2, side1, side2)) return qfalse; + } //end for + } //end for + } //end for + } //end for + return qtrue; +} //end of the function AAS_CanMergeAreas +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +qboolean AAS_NonConvexEdges(aas_edge_t *edge1, aas_edge_t *edge2, int side1, int side2, int planenum) +{ + int i; + vec3_t edgevec1, edgevec2, normal1, normal2; + float dist1, dist2; + aas_plane_t *plane; + + plane = &aasworld.planes[planenum]; + VectorSubtract(aasworld.vertexes[edge1->v[1]], aasworld.vertexes[edge1->v[0]], edgevec1); + VectorSubtract(aasworld.vertexes[edge2->v[1]], aasworld.vertexes[edge2->v[0]], edgevec2); + if (side1) VectorInverse(edgevec1); + if (side2) VectorInverse(edgevec2); + // + CrossProduct(edgevec1, plane->normal, normal1); + dist1 = DotProduct(normal1, aasworld.vertexes[edge1->v[0]]); + CrossProduct(edgevec2, plane->normal, normal2); + dist2 = DotProduct(normal2, aasworld.vertexes[edge2->v[0]]); + + for (i = 0; i < 2; i++) + { + if (DotProduct(aasworld.vertexes[edge1->v[i]], normal2) - dist2 < -0.01) return qfalse; + } //end for + for (i = 0; i < 2; i++) + { + if (DotProduct(aasworld.vertexes[edge2->v[i]], normal1) - dist1 < -0.01) return qfalse; + } //end for + return qtrue; +} //end of the function AAS_NonConvexEdges +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +qboolean AAS_CanMergeFaces(int *facenums, int numfaces, int planenum) +{ + int i, j, s, edgenum1, edgenum2, side1, side2, en1, en2, ens; + aas_face_t *face1, *face2, *otherface; + aas_edge_t *edge1, *edge2; + + for (i = 0; i < numfaces; i++) + { + face1 = &aasworld.faces[facenums[i]]; + for (en1 = 0; en1 < face1->numedges; en1++) + { + edgenum1 = aasworld.edgeindex[face1->firstedge + en1]; + side1 = (edgenum1 < 0) ^ (face1->planenum != planenum); + edgenum1 = abs(edgenum1); + edge1 = &aasworld.edges[edgenum1]; + //check if the edge is shared with another face + for (s = 0; s < numfaces; s++) + { + if (s == i) continue; + otherface = &aasworld.faces[facenums[s]]; + for (ens = 0; ens < otherface->numedges; ens++) + { + if (edgenum1 == abs(aasworld.edgeindex[otherface->firstedge + ens])) break; + } //end for + if (ens != otherface->numedges) break; + } //end for + //if the edge was shared + if (s != numfaces) continue; + // + for (j = 0; j < numfaces; j++) + { + if (j == i) continue; + face2 = &aasworld.faces[facenums[j]]; + for (en2 = 0; en2 < face2->numedges; en2++) + { + edgenum2 = aasworld.edgeindex[face2->firstedge + en2]; + side2 = (edgenum2 < 0) ^ (face2->planenum != planenum); + edgenum2 = abs(edgenum2); + edge2 = &aasworld.edges[edgenum2]; + //check if the edge is shared with another face + for (s = 0; s < numfaces; s++) + { + if (s == i) continue; + otherface = &aasworld.faces[facenums[s]]; + for (ens = 0; ens < otherface->numedges; ens++) + { + if (edgenum2 == abs(aasworld.edgeindex[otherface->firstedge + ens])) break; + } //end for + if (ens != otherface->numedges) break; + } //end for + //if the edge was shared + if (s != numfaces) continue; + // + if (AAS_NonConvexEdges(edge1, edge2, side1, side2, planenum)) return qfalse; + } //end for + } //end for + } //end for + } //end for + return qtrue; +} //end of the function AAS_CanMergeFaces*/ +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_ConnectedAreas_r(int *areanums, int numareas, int *connectedareas, int curarea) +{ + int i, j, otherareanum, facenum; + aas_area_t *area; + aas_face_t *face; + + connectedareas[curarea] = qtrue; + area = &aasworld.areas[areanums[curarea]]; + for (i = 0; i < area->numfaces; i++) + { + facenum = abs(aasworld.faceindex[area->firstface + i]); + face = &aasworld.faces[facenum]; + //if the face is solid + if (face->faceflags & FACE_SOLID) continue; + //get the area at the other side of the face + if (face->frontarea != areanums[curarea]) otherareanum = face->frontarea; + else otherareanum = face->backarea; + //check if the face is leading to one of the other areas + for (j = 0; j < numareas; j++) + { + if (areanums[j] == otherareanum) break; + } //end for + //if the face isn't leading to one of the other areas + if (j == numareas) continue; + //if the other area is already connected + if (connectedareas[j]) continue; + //recursively proceed with the other area + AAS_ConnectedAreas_r(areanums, numareas, connectedareas, j); + } //end for +} //end of the function AAS_ConnectedAreas_r +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +qboolean AAS_ConnectedAreas(int *areanums, int numareas) +{ + int connectedareas[MAX_PORTALAREAS], i; + + Com_Memset(connectedareas, 0, sizeof(connectedareas)); + if (numareas < 1) return qfalse; + if (numareas == 1) return qtrue; + AAS_ConnectedAreas_r(areanums, numareas, connectedareas, 0); + for (i = 0; i < numareas; i++) + { + if (!connectedareas[i]) return qfalse; + } //end for + return qtrue; +} //end of the function AAS_ConnectedAreas +//=========================================================================== +// gets adjacent areas with less presence types recursively +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_GetAdjacentAreasWithLessPresenceTypes_r(int *areanums, int numareas, int curareanum) +{ + int i, j, presencetype, otherpresencetype, otherareanum, facenum; + aas_area_t *area; + aas_face_t *face; + + areanums[numareas++] = curareanum; + area = &aasworld.areas[curareanum]; + presencetype = aasworld.areasettings[curareanum].presencetype; + for (i = 0; i < area->numfaces; i++) + { + facenum = abs(aasworld.faceindex[area->firstface + i]); + face = &aasworld.faces[facenum]; + //if the face is solid + if (face->faceflags & FACE_SOLID) continue; + //the area at the other side of the face + if (face->frontarea != curareanum) otherareanum = face->frontarea; + else otherareanum = face->backarea; + // + otherpresencetype = aasworld.areasettings[otherareanum].presencetype; + //if the other area has less presence types + if ((presencetype & ~otherpresencetype) && + !(otherpresencetype & ~presencetype)) + { + //check if the other area isn't already in the list + for (j = 0; j < numareas; j++) + { + if (otherareanum == areanums[j]) break; + } //end for + //if the other area isn't already in the list + if (j == numareas) + { + if (numareas >= MAX_PORTALAREAS) + { + AAS_Error("MAX_PORTALAREAS\n"); + return numareas; + } //end if + numareas = AAS_GetAdjacentAreasWithLessPresenceTypes_r(areanums, numareas, otherareanum); + } //end if + } //end if + } //end for + return numareas; +} //end of the function AAS_GetAdjacentAreasWithLessPresenceTypes_r +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_CheckAreaForPossiblePortals(int areanum) +{ + int i, j, k, fen, ben, frontedgenum, backedgenum, facenum; + int areanums[MAX_PORTALAREAS], numareas, otherareanum; + int numareafrontfaces[MAX_PORTALAREAS], numareabackfaces[MAX_PORTALAREAS]; + int frontfacenums[MAX_PORTALAREAS], backfacenums[MAX_PORTALAREAS]; + int numfrontfaces, numbackfaces; + int frontareanums[MAX_PORTALAREAS], backareanums[MAX_PORTALAREAS]; + int numfrontareas, numbackareas; + int frontplanenum, backplanenum, faceplanenum; + aas_area_t *area; + aas_face_t *frontface, *backface, *face; + + //if it isn't already a portal + if (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL) return 0; + //it must be a grounded area + if (!(aasworld.areasettings[areanum].areaflags & AREA_GROUNDED)) return 0; + // + Com_Memset(numareafrontfaces, 0, sizeof(numareafrontfaces)); + Com_Memset(numareabackfaces, 0, sizeof(numareabackfaces)); + numareas = numfrontfaces = numbackfaces = 0; + numfrontareas = numbackareas = 0; + frontplanenum = backplanenum = -1; + //add any adjacent areas with less presence types + numareas = AAS_GetAdjacentAreasWithLessPresenceTypes_r(areanums, 0, areanum); + // + for (i = 0; i < numareas; i++) + { + area = &aasworld.areas[areanums[i]]; + for (j = 0; j < area->numfaces; j++) + { + facenum = abs(aasworld.faceindex[area->firstface + j]); + face = &aasworld.faces[facenum]; + //if the face is solid + if (face->faceflags & FACE_SOLID) continue; + //check if the face is shared with one of the other areas + for (k = 0; k < numareas; k++) + { + if (k == i) continue; + if (face->frontarea == areanums[k] || face->backarea == areanums[k]) break; + } //end for + //if the face is shared + if (k != numareas) continue; + //the number of the area at the other side of the face + if (face->frontarea == areanums[i]) otherareanum = face->backarea; + else otherareanum = face->frontarea; + //if the other area already is a cluter portal + if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) return 0; + //number of the plane of the area + faceplanenum = face->planenum & ~1; + // + if (frontplanenum < 0 || faceplanenum == frontplanenum) + { + frontplanenum = faceplanenum; + frontfacenums[numfrontfaces++] = facenum; + for (k = 0; k < numfrontareas; k++) + { + if (frontareanums[k] == otherareanum) break; + } //end for + if (k == numfrontareas) frontareanums[numfrontareas++] = otherareanum; + numareafrontfaces[i]++; + } //end if + else if (backplanenum < 0 || faceplanenum == backplanenum) + { + backplanenum = faceplanenum; + backfacenums[numbackfaces++] = facenum; + for (k = 0; k < numbackareas; k++) + { + if (backareanums[k] == otherareanum) break; + } //end for + if (k == numbackareas) backareanums[numbackareas++] = otherareanum; + numareabackfaces[i]++; + } //end else + else + { + return 0; + } //end else + } //end for + } //end for + //every area should have at least one front face and one back face + for (i = 0; i < numareas; i++) + { + if (!numareafrontfaces[i] || !numareabackfaces[i]) return 0; + } //end for + //the front areas should all be connected + if (!AAS_ConnectedAreas(frontareanums, numfrontareas)) return 0; + //the back areas should all be connected + if (!AAS_ConnectedAreas(backareanums, numbackareas)) return 0; + //none of the front faces should have a shared edge with a back face + for (i = 0; i < numfrontfaces; i++) + { + frontface = &aasworld.faces[frontfacenums[i]]; + for (fen = 0; fen < frontface->numedges; fen++) + { + frontedgenum = abs(aasworld.edgeindex[frontface->firstedge + fen]); + for (j = 0; j < numbackfaces; j++) + { + backface = &aasworld.faces[backfacenums[j]]; + for (ben = 0; ben < backface->numedges; ben++) + { + backedgenum = abs(aasworld.edgeindex[backface->firstedge + ben]); + if (frontedgenum == backedgenum) break; + } //end for + if (ben != backface->numedges) break; + } //end for + if (j != numbackfaces) break; + } //end for + if (fen != frontface->numedges) break; + } //end for + if (i != numfrontfaces) return 0; + //set the cluster portal contents + for (i = 0; i < numareas; i++) + { + aasworld.areasettings[areanums[i]].contents |= AREACONTENTS_CLUSTERPORTAL; + //this area can be used as a route portal + aasworld.areasettings[areanums[i]].contents |= AREACONTENTS_ROUTEPORTAL; + Log_Write("possible portal: %d\r\n", areanums[i]); + } //end for + // + return numareas; +} //end of the function AAS_CheckAreaForPossiblePortals +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_FindPossiblePortals(void) +{ + int i, numpossibleportals; + + numpossibleportals = 0; + for (i = 1; i < aasworld.numareas; i++) + { + numpossibleportals += AAS_CheckAreaForPossiblePortals(i); + } //end for + botimport.Print(PRT_MESSAGE, "\r%6d possible portal areas\n", numpossibleportals); +} //end of the function AAS_FindPossiblePortals +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_RemoveAllPortals(void) +{ + int i; + + for (i = 1; i < aasworld.numareas; i++) + { + aasworld.areasettings[i].contents &= ~AREACONTENTS_CLUSTERPORTAL; + } //end for +} //end of the function AAS_RemoveAllPortals + +#if 0 +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_FloodCluster_r(int areanum, int clusternum) +{ + int i, otherareanum; + aas_face_t *face; + aas_area_t *area; + + //set cluster mark + aasworld.areasettings[areanum].cluster = clusternum; + //if the area is a portal + //if (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL) return; + // + area = &aasworld.areas[areanum]; + //use area faces to flood into adjacent areas + for (i = 0; i < area->numfaces; i++) + { + face = &aasworld.faces[abs(aasworld.faceindex[area->firstface + i])]; + // + if (face->frontarea != areanum) otherareanum = face->frontarea; + else otherareanum = face->backarea; + //if there's no area at the other side + if (!otherareanum) continue; + //if the area is a portal + if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) continue; + //if the area is already marked + if (aasworld.areasettings[otherareanum].cluster) continue; + // + AAS_FloodCluster_r(otherareanum, clusternum); + } //end for + //use the reachabilities to flood into other areas + for (i = 0; i < aasworld.areasettings[areanum].numreachableareas; i++) + { + otherareanum = aasworld.reachability[ + aasworld.areasettings[areanum].firstreachablearea + i].areanum; + if (!otherareanum) + { + continue; + AAS_Error("reachability %d has zero area\n", aasworld.areasettings[areanum].firstreachablearea + i); + } //end if + //if the area is a portal + if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) continue; + //if the area is already marked + if (aasworld.areasettings[otherareanum].cluster) continue; + // + AAS_FloodCluster_r(otherareanum, clusternum); + } //end for +} //end of the function AAS_FloodCluster_r +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_RemoveTeleporterPortals(void) +{ + int i, j, areanum; + + for (i = 1; i < aasworld.numareas; i++) + { + for (j = 0; j < aasworld.areasettings[i].numreachableareas; j++) + { + areanum = aasworld.reachability[aasworld.areasettings[i].firstreachablearea + j].areanum; + if (aasworld.reachability[aasworld.areasettings[i].firstreachablearea + j].traveltype == TRAVEL_TELEPORT) + { + aasworld.areasettings[i].contents &= ~AREACONTENTS_CLUSTERPORTAL; + aasworld.areasettings[areanum].contents &= ~AREACONTENTS_CLUSTERPORTAL; + break; + } //end if + } //end for + } //end for +} //end of the function AAS_RemoveTeleporterPortals +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_FloodClusterReachabilities(int clusternum) +{ + int i, j, areanum; + + for (i = 1; i < aasworld.numareas; i++) + { + //if this area already has a cluster set + if (aasworld.areasettings[i].cluster) continue; + //if this area is a cluster portal + if (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL) continue; + //loop over the reachable areas from this area + for (j = 0; j < aasworld.areasettings[i].numreachableareas; j++) + { + //the reachable area + areanum = aasworld.reachability[aasworld.areasettings[i].firstreachablearea + j].areanum; + //if this area is a cluster portal + if (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL) continue; + //if this area has a cluster set + if (aasworld.areasettings[areanum].cluster == clusternum) + { + AAS_FloodCluster_r(i, clusternum); + i = 0; + break; + } //end if + } //end for + } //end for +} //end of the function AAS_FloodClusterReachabilities + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_RemoveNotClusterClosingPortals(void) +{ + int i, j, k, facenum, otherareanum, nonclosingportals; + aas_area_t *area; + aas_face_t *face; + + AAS_RemoveTeleporterPortals(); + // + nonclosingportals = 0; + for (i = 1; i < aasworld.numareas; i++) + { + if (!(aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL)) continue; + //find a non-portal area adjacent to the portal area and flood + //the cluster from there + area = &aasworld.areas[i]; + for (j = 0; j < area->numfaces; j++) + { + facenum = abs(aasworld.faceindex[area->firstface + j]); + face = &aasworld.faces[facenum]; + // + if (face->frontarea != i) otherareanum = face->frontarea; + else otherareanum = face->backarea; + // + if (!otherareanum) continue; + // + if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) + { + continue; + } //end if + //reset all cluster fields + AAS_RemoveClusterAreas(); + // + AAS_FloodCluster_r(otherareanum, 1); + AAS_FloodClusterReachabilities(1); + //check if all adjacent non-portal areas have a cluster set + for (k = 0; k < area->numfaces; k++) + { + facenum = abs(aasworld.faceindex[area->firstface + k]); + face = &aasworld.faces[facenum]; + // + if (face->frontarea != i) otherareanum = face->frontarea; + else otherareanum = face->backarea; + // + if (!otherareanum) continue; + // + if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) + { + continue; + } //end if + // + if (!aasworld.areasettings[otherareanum].cluster) break; + } //end for + //if all adjacent non-portal areas have a cluster set then the portal + //didn't seal a cluster + if (k >= area->numfaces) + { + aasworld.areasettings[i].contents &= ~AREACONTENTS_CLUSTERPORTAL; + nonclosingportals++; + //recheck all the other portals again + i = 0; + break; + } //end if + } //end for + } //end for + botimport.Print(PRT_MESSAGE, "\r%6d non closing portals removed\n", nonclosingportals); +} //end of the function AAS_RemoveNotClusterClosingPortals + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== + +void AAS_RemoveNotClusterClosingPortals(void) +{ + int i, j, facenum, otherareanum, nonclosingportals, numseperatedclusters; + aas_area_t *area; + aas_face_t *face; + + AAS_RemoveTeleporterPortals(); + // + nonclosingportals = 0; + for (i = 1; i < aasworld.numareas; i++) + { + if (!(aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL)) continue; + // + numseperatedclusters = 0; + //reset all cluster fields + AAS_RemoveClusterAreas(); + //find a non-portal area adjacent to the portal area and flood + //the cluster from there + area = &aasworld.areas[i]; + for (j = 0; j < area->numfaces; j++) + { + facenum = abs(aasworld.faceindex[area->firstface + j]); + face = &aasworld.faces[facenum]; + // + if (face->frontarea != i) otherareanum = face->frontarea; + else otherareanum = face->backarea; + //if not solid at the other side of the face + if (!otherareanum) continue; + //don't flood into other portals + if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) continue; + //if the area already has a cluster set + if (aasworld.areasettings[otherareanum].cluster) continue; + //another cluster is seperated by this portal + numseperatedclusters++; + //flood the cluster + AAS_FloodCluster_r(otherareanum, numseperatedclusters); + AAS_FloodClusterReachabilities(numseperatedclusters); + } //end for + //use the reachabilities to flood into other areas + for (j = 0; j < aasworld.areasettings[i].numreachableareas; j++) + { + otherareanum = aasworld.reachability[ + aasworld.areasettings[i].firstreachablearea + j].areanum; + //this should never be qtrue but we check anyway + if (!otherareanum) continue; + //don't flood into other portals + if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) continue; + //if the area already has a cluster set + if (aasworld.areasettings[otherareanum].cluster) continue; + //another cluster is seperated by this portal + numseperatedclusters++; + //flood the cluster + AAS_FloodCluster_r(otherareanum, numseperatedclusters); + AAS_FloodClusterReachabilities(numseperatedclusters); + } //end for + //a portal must seperate no more and no less than 2 clusters + if (numseperatedclusters != 2) + { + aasworld.areasettings[i].contents &= ~AREACONTENTS_CLUSTERPORTAL; + nonclosingportals++; + //recheck all the other portals again + i = 0; + } //end if + } //end for + botimport.Print(PRT_MESSAGE, "\r%6d non closing portals removed\n", nonclosingportals); +} //end of the function AAS_RemoveNotClusterClosingPortals + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== + +void AAS_AddTeleporterPortals(void) +{ + int j, area2num, facenum, otherareanum; + char *target, *targetname, *classname; + bsp_entity_t *entities, *ent, *dest; + vec3_t origin, destorigin, mins, maxs, end; + vec3_t bbmins, bbmaxs; + aas_area_t *area; + aas_face_t *face; + aas_trace_t trace; + aas_link_t *areas, *link; + + entities = AAS_ParseBSPEntities(); + + for (ent = entities; ent; ent = ent->next) + { + classname = AAS_ValueForBSPEpairKey(ent, "classname"); + if (classname && !strcmp(classname, "misc_teleporter")) + { + if (!AAS_VectorForBSPEpairKey(ent, "origin", origin)) + { + botimport.Print(PRT_ERROR, "teleporter (%s) without origin\n", target); + continue; + } //end if + // + target = AAS_ValueForBSPEpairKey(ent, "target"); + if (!target) + { + botimport.Print(PRT_ERROR, "teleporter (%s) without target\n", target); + continue; + } //end if + for (dest = entities; dest; dest = dest->next) + { + classname = AAS_ValueForBSPEpairKey(dest, "classname"); + if (classname && !strcmp(classname, "misc_teleporter_dest")) + { + targetname = AAS_ValueForBSPEpairKey(dest, "targetname"); + if (targetname && !strcmp(targetname, target)) + { + break; + } //end if + } //end if + } //end for + if (!dest) + { + botimport.Print(PRT_ERROR, "teleporter without destination (%s)\n", target); + continue; + } //end if + if (!AAS_VectorForBSPEpairKey(dest, "origin", destorigin)) + { + botimport.Print(PRT_ERROR, "teleporter destination (%s) without origin\n", target); + continue; + } //end if + destorigin[2] += 24; //just for q2e1m2, the dork has put the telepads in the ground + VectorCopy(destorigin, end); + end[2] -= 100; + trace = AAS_TraceClientBBox(destorigin, end, PRESENCE_CROUCH, -1); + if (trace.startsolid) + { + botimport.Print(PRT_ERROR, "teleporter destination (%s) in solid\n", target); + continue; + } //end if + VectorCopy(trace.endpos, destorigin); + area2num = AAS_PointAreaNum(destorigin); + //reset all cluster fields + for (j = 0; j < aasworld.numareas; j++) + { + aasworld.areasettings[j].cluster = 0; + } //end for + // + VectorSet(mins, -8, -8, 8); + VectorSet(maxs, 8, 8, 24); + // + AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, bbmins, bbmaxs); + // + VectorAdd(origin, mins, mins); + VectorAdd(origin, maxs, maxs); + //add bounding box size + VectorSubtract(mins, bbmaxs, mins); + VectorSubtract(maxs, bbmins, maxs); + //link an invalid (-1) entity + areas = AAS_AASLinkEntity(mins, maxs, -1); + // + for (link = areas; link; link = link->next_area) + { + if (!AAS_AreaGrounded(link->areanum)) continue; + //add the teleporter portal mark + aasworld.areasettings[link->areanum].contents |= AREACONTENTS_CLUSTERPORTAL | + AREACONTENTS_TELEPORTAL; + } //end for + // + for (link = areas; link; link = link->next_area) + { + if (!AAS_AreaGrounded(link->areanum)) continue; + //find a non-portal area adjacent to the portal area and flood + //the cluster from there + area = &aasworld.areas[link->areanum]; + for (j = 0; j < area->numfaces; j++) + { + facenum = abs(aasworld.faceindex[area->firstface + j]); + face = &aasworld.faces[facenum]; + // + if (face->frontarea != link->areanum) otherareanum = face->frontarea; + else otherareanum = face->backarea; + // + if (!otherareanum) continue; + // + if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) + { + continue; + } //end if + // + AAS_FloodCluster_r(otherareanum, 1); + } //end for + } //end for + //if the teleport destination IS in the same cluster + if (aasworld.areasettings[area2num].cluster) + { + for (link = areas; link; link = link->next_area) + { + if (!AAS_AreaGrounded(link->areanum)) continue; + //add the teleporter portal mark + aasworld.areasettings[link->areanum].contents &= ~(AREACONTENTS_CLUSTERPORTAL | + AREACONTENTS_TELEPORTAL); + } //end for + } //end if + } //end if + } //end for + AAS_FreeBSPEntities(entities); +} //end of the function AAS_AddTeleporterPortals + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_AddTeleporterPortals(void) +{ + int i, j, areanum; + + for (i = 1; i < aasworld.numareas; i++) + { + for (j = 0; j < aasworld.areasettings[i].numreachableareas; j++) + { + if (aasworld.reachability[aasworld.areasettings[i].firstreachablearea + j].traveltype != TRAVEL_TELEPORT) continue; + areanum = aasworld.reachability[aasworld.areasettings[i].firstreachablearea + j].areanum; + aasworld.areasettings[areanum].contents |= AREACONTENTS_CLUSTERPORTAL; + } //end for + } //end for +} //end of the function AAS_AddTeleporterPortals + +#endif + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_TestPortals(void) +{ + int i; + aas_portal_t *portal; + + for (i = 1; i < aasworld.numportals; i++) + { + portal = &aasworld.portals[i]; + if (!portal->frontcluster) + { + aasworld.areasettings[portal->areanum].contents &= ~AREACONTENTS_CLUSTERPORTAL; + Log_Write("portal area %d has no front cluster\r\n", portal->areanum); + return qfalse; + } //end if + if (!portal->backcluster) + { + aasworld.areasettings[portal->areanum].contents &= ~AREACONTENTS_CLUSTERPORTAL; + Log_Write("portal area %d has no back cluster\r\n", portal->areanum); + return qfalse; + } //end if + } //end for + return qtrue; +} //end of the function +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_CountForcedClusterPortals(void) +{ + int num, i; + + num = 0; + for (i = 1; i < aasworld.numareas; i++) + { + if (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL) + { + Log_Write("area %d is a forced portal area\r\n", i); + num++; + } //end if + } //end for + botimport.Print(PRT_MESSAGE, "%6d forced portal areas\n", num); +} //end of the function AAS_CountForcedClusterPortals +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_CreateViewPortals(void) +{ + int i; + + for (i = 1; i < aasworld.numareas; i++) + { + if (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL) + { + aasworld.areasettings[i].contents |= AREACONTENTS_VIEWPORTAL; + } //end if + } //end for +} //end of the function AAS_CreateViewPortals +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_SetViewPortalsAsClusterPortals(void) +{ + int i; + + for (i = 1; i < aasworld.numareas; i++) + { + if (aasworld.areasettings[i].contents & AREACONTENTS_VIEWPORTAL) + { + aasworld.areasettings[i].contents |= AREACONTENTS_CLUSTERPORTAL; + } //end if + } //end for +} //end of the function AAS_SetViewPortalsAsClusterPortals +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_InitClustering(void) +{ + int i, removedPortalAreas; + int n, total, numreachabilityareas; + + if (!aasworld.loaded) return; + //if there are clusters + if (aasworld.numclusters >= 1) + { +#ifndef BSPC + //if clustering isn't forced + if (!((int)LibVarGetValue("forceclustering")) && + !((int)LibVarGetValue("forcereachability"))) return; +#endif + } //end if + //set all view portals as cluster portals in case we re-calculate the reachabilities and clusters (with -reach) + AAS_SetViewPortalsAsClusterPortals(); + //count the number of forced cluster portals + AAS_CountForcedClusterPortals(); + //remove all area cluster marks + AAS_RemoveClusterAreas(); + //find possible cluster portals + AAS_FindPossiblePortals(); + //craete portals to for the bot view + AAS_CreateViewPortals(); + //remove all portals that are not closing a cluster + //AAS_RemoveNotClusterClosingPortals(); + //initialize portal memory + if (aasworld.portals) FreeMemory(aasworld.portals); + aasworld.portals = (aas_portal_t *) GetClearedMemory(AAS_MAX_PORTALS * sizeof(aas_portal_t)); + //initialize portal index memory + if (aasworld.portalindex) FreeMemory(aasworld.portalindex); + aasworld.portalindex = (aas_portalindex_t *) GetClearedMemory(AAS_MAX_PORTALINDEXSIZE * sizeof(aas_portalindex_t)); + //initialize cluster memory + if (aasworld.clusters) FreeMemory(aasworld.clusters); + aasworld.clusters = (aas_cluster_t *) GetClearedMemory(AAS_MAX_CLUSTERS * sizeof(aas_cluster_t)); + // + removedPortalAreas = 0; + botimport.Print(PRT_MESSAGE, "\r%6d removed portal areas", removedPortalAreas); + while(1) + { + botimport.Print(PRT_MESSAGE, "\r%6d", removedPortalAreas); + //initialize the number of portals and clusters + aasworld.numportals = 1; //portal 0 is a dummy + aasworld.portalindexsize = 0; + aasworld.numclusters = 1; //cluster 0 is a dummy + //create the portals from the portal areas + AAS_CreatePortals(); + // + removedPortalAreas++; + //find the clusters + if (!AAS_FindClusters()) + continue; + //test the portals + if (!AAS_TestPortals()) + continue; + // + break; + } //end while + botimport.Print(PRT_MESSAGE, "\n"); + //the AAS file should be saved + aasworld.savefile = qtrue; + //write the portal areas to the log file + for (i = 1; i < aasworld.numportals; i++) + { + Log_Write("portal %d: area %d\r\n", i, aasworld.portals[i].areanum); + } //end for + // report cluster info + botimport.Print(PRT_MESSAGE, "%6d portals created\n", aasworld.numportals); + botimport.Print(PRT_MESSAGE, "%6d clusters created\n", aasworld.numclusters); + for (i = 1; i < aasworld.numclusters; i++) + { + botimport.Print(PRT_MESSAGE, "cluster %d has %d reachability areas\n", i, + aasworld.clusters[i].numreachabilityareas); + } //end for + // report AAS file efficiency + numreachabilityareas = 0; + total = 0; + for (i = 0; i < aasworld.numclusters; i++) { + n = aasworld.clusters[i].numreachabilityareas; + numreachabilityareas += n; + total += n * n; + } + total += numreachabilityareas * aasworld.numportals; + // + botimport.Print(PRT_MESSAGE, "%6i total reachability areas\n", numreachabilityareas); + botimport.Print(PRT_MESSAGE, "%6i AAS memory/CPU usage (the lower the better)\n", total * 3); +} //end of the function AAS_InitClustering diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_cluster.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_cluster.h new file mode 100644 index 0000000..dedd9c6 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_cluster.h @@ -0,0 +1,43 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_aas_cluster.h + * + * desc: AAS + * + * $Archive: /source/code/botlib/be_aas_cluster.h $ + * $Author: Mrelusive $ + * $Revision: 2 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 10/05/99 3:42p $ + * + *****************************************************************************/ +#pragma once + +#ifdef AASINTERN +//initialize the AAS clustering +void AAS_InitClustering(void); +// +void AAS_SetViewPortalsAsClusterPortals(void); +#endif //AASINTERN diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_debug.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_debug.cpp new file mode 100644 index 0000000..855d256 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_debug.cpp @@ -0,0 +1,782 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_aas_debug.c + * + * desc: AAS debug code + * + * $Archive: /MissionPack/code/botlib/be_aas_debug.c $ + * $Author: Ttimo $ + * $Revision: 8 $ + * $Modtime: 4/22/01 8:52a $ + * $Date: 4/22/01 8:52a $ + * + *****************************************************************************/ + +#include "qcommon/q_shared.h" +#include "l_memory.h" +#include "l_script.h" +#include "l_precomp.h" +#include "l_struct.h" +#include "l_libvar.h" +#include "aasfile.h" +#include "botlib.h" +#include "be_aas.h" +#include "be_interface.h" +#include "be_aas_funcs.h" +#include "be_aas_def.h" + +#define MAX_DEBUGLINES 1024 +#define MAX_DEBUGPOLYGONS 8192 + +int debuglines[MAX_DEBUGLINES]; +int debuglinevisible[MAX_DEBUGLINES]; +int numdebuglines; + +static int debugpolygons[MAX_DEBUGPOLYGONS]; + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_ClearShownPolygons(void) +{ + int i; +//* + for (i = 0; i < MAX_DEBUGPOLYGONS; i++) + { + if (debugpolygons[i]) botimport.DebugPolygonDelete(debugpolygons[i]); + debugpolygons[i] = 0; + } //end for +//*/ +/* + for (i = 0; i < MAX_DEBUGPOLYGONS; i++) + { + botimport.DebugPolygonDelete(i); + debugpolygons[i] = 0; + } //end for +*/ +} //end of the function AAS_ClearShownPolygons +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_ShowPolygon(int color, int numpoints, vec3_t *points) +{ + int i; + + for (i = 0; i < MAX_DEBUGPOLYGONS; i++) + { + if (!debugpolygons[i]) + { + debugpolygons[i] = botimport.DebugPolygonCreate(color, numpoints, points); + break; + } //end if + } //end for +} //end of the function AAS_ShowPolygon +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_ClearShownDebugLines(void) +{ + int i; + + //make all lines invisible + for (i = 0; i < MAX_DEBUGLINES; i++) + { + if (debuglines[i]) + { + //botimport.DebugLineShow(debuglines[i], NULL, NULL, LINECOLOR_NONE); + botimport.DebugLineDelete(debuglines[i]); + debuglines[i] = 0; + debuglinevisible[i] = qfalse; + } //end if + } //end for +} //end of the function AAS_ClearShownDebugLines +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_DebugLine(vec3_t start, vec3_t end, int color) +{ + int line; + + for (line = 0; line < MAX_DEBUGLINES; line++) + { + if (!debuglines[line]) + { + debuglines[line] = botimport.DebugLineCreate(); + debuglinevisible[line] = qfalse; + numdebuglines++; + } //end if + if (!debuglinevisible[line]) + { + botimport.DebugLineShow(debuglines[line], start, end, color); + debuglinevisible[line] = qtrue; + return; + } //end else + } //end for +} //end of the function AAS_DebugLine +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_PermanentLine(vec3_t start, vec3_t end, int color) +{ + int line; + + line = botimport.DebugLineCreate(); + botimport.DebugLineShow(line, start, end, color); +} //end of the function AAS_PermenentLine +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_DrawPermanentCross(vec3_t origin, float size, int color) +{ + int i, debugline; + vec3_t start, end; + + for (i = 0; i < 3; i++) + { + VectorCopy(origin, start); + start[i] += size; + VectorCopy(origin, end); + end[i] -= size; + AAS_DebugLine(start, end, color); + debugline = botimport.DebugLineCreate(); + botimport.DebugLineShow(debugline, start, end, color); + } //end for +} //end of the function AAS_DrawPermanentCross +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_DrawPlaneCross(vec3_t point, vec3_t normal, float dist, int type, int color) +{ + int n0, n1, n2, j, line, lines[2]; + vec3_t start1, end1, start2, end2; + + //make a cross in the hit plane at the hit point + VectorCopy(point, start1); + VectorCopy(point, end1); + VectorCopy(point, start2); + VectorCopy(point, end2); + + n0 = type % 3; + n1 = (type + 1) % 3; + n2 = (type + 2) % 3; + start1[n1] -= 6; + start1[n2] -= 6; + end1[n1] += 6; + end1[n2] += 6; + start2[n1] += 6; + start2[n2] -= 6; + end2[n1] -= 6; + end2[n2] += 6; + + start1[n0] = (dist - (start1[n1] * normal[n1] + + start1[n2] * normal[n2])) / normal[n0]; + end1[n0] = (dist - (end1[n1] * normal[n1] + + end1[n2] * normal[n2])) / normal[n0]; + start2[n0] = (dist - (start2[n1] * normal[n1] + + start2[n2] * normal[n2])) / normal[n0]; + end2[n0] = (dist - (end2[n1] * normal[n1] + + end2[n2] * normal[n2])) / normal[n0]; + + for (j = 0, line = 0; j < 2 && line < MAX_DEBUGLINES; line++) + { + if (!debuglines[line]) + { + debuglines[line] = botimport.DebugLineCreate(); + lines[j++] = debuglines[line]; + debuglinevisible[line] = qtrue; + numdebuglines++; + } //end if + else if (!debuglinevisible[line]) + { + lines[j++] = debuglines[line]; + debuglinevisible[line] = qtrue; + } //end else + } //end for + botimport.DebugLineShow(lines[0], start1, end1, color); + botimport.DebugLineShow(lines[1], start2, end2, color); +} //end of the function AAS_DrawPlaneCross +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_ShowBoundingBox(vec3_t origin, vec3_t mins, vec3_t maxs) +{ + vec3_t bboxcorners[8]; + int lines[3]; + int i, j, line; + + //upper corners + bboxcorners[0][0] = origin[0] + maxs[0]; + bboxcorners[0][1] = origin[1] + maxs[1]; + bboxcorners[0][2] = origin[2] + maxs[2]; + // + bboxcorners[1][0] = origin[0] + mins[0]; + bboxcorners[1][1] = origin[1] + maxs[1]; + bboxcorners[1][2] = origin[2] + maxs[2]; + // + bboxcorners[2][0] = origin[0] + mins[0]; + bboxcorners[2][1] = origin[1] + mins[1]; + bboxcorners[2][2] = origin[2] + maxs[2]; + // + bboxcorners[3][0] = origin[0] + maxs[0]; + bboxcorners[3][1] = origin[1] + mins[1]; + bboxcorners[3][2] = origin[2] + maxs[2]; + //lower corners + Com_Memcpy(bboxcorners[4], bboxcorners[0], sizeof(vec3_t) * 4); + for (i = 0; i < 4; i++) bboxcorners[4 + i][2] = origin[2] + mins[2]; + //draw bounding box + for (i = 0; i < 4; i++) + { + for (j = 0, line = 0; j < 3 && line < MAX_DEBUGLINES; line++) + { + if (!debuglines[line]) + { + debuglines[line] = botimport.DebugLineCreate(); + lines[j++] = debuglines[line]; + debuglinevisible[line] = qtrue; + numdebuglines++; + } //end if + else if (!debuglinevisible[line]) + { + lines[j++] = debuglines[line]; + debuglinevisible[line] = qtrue; + } //end else + } //end for + //top plane + botimport.DebugLineShow(lines[0], bboxcorners[i], + bboxcorners[(i+1)&3], LINECOLOR_RED); + //bottom plane + botimport.DebugLineShow(lines[1], bboxcorners[4+i], + bboxcorners[4+((i+1)&3)], LINECOLOR_RED); + //vertical lines + botimport.DebugLineShow(lines[2], bboxcorners[i], + bboxcorners[4+i], LINECOLOR_RED); + } //end for +} //end of the function AAS_ShowBoundingBox +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_ShowFace(int facenum) +{ + int i, color, edgenum; + aas_edge_t *edge; + aas_face_t *face; + aas_plane_t *plane; + vec3_t start, end; + + color = LINECOLOR_YELLOW; + //check if face number is in range + if (facenum >= aasworld.numfaces) + { + botimport.Print(PRT_ERROR, "facenum %d out of range\n", facenum); + } //end if + face = &aasworld.faces[facenum]; + //walk through the edges of the face + for (i = 0; i < face->numedges; i++) + { + //edge number + edgenum = abs(aasworld.edgeindex[face->firstedge + i]); + //check if edge number is in range + if (edgenum >= aasworld.numedges) + { + botimport.Print(PRT_ERROR, "edgenum %d out of range\n", edgenum); + } //end if + edge = &aasworld.edges[edgenum]; + if (color == LINECOLOR_RED) color = LINECOLOR_GREEN; + else if (color == LINECOLOR_GREEN) color = LINECOLOR_BLUE; + else if (color == LINECOLOR_BLUE) color = LINECOLOR_YELLOW; + else color = LINECOLOR_RED; + AAS_DebugLine(aasworld.vertexes[edge->v[0]], + aasworld.vertexes[edge->v[1]], + color); + } //end for + plane = &aasworld.planes[face->planenum]; + edgenum = abs(aasworld.edgeindex[face->firstedge]); + edge = &aasworld.edges[edgenum]; + VectorCopy(aasworld.vertexes[edge->v[0]], start); + VectorMA(start, 20, plane->normal, end); + AAS_DebugLine(start, end, LINECOLOR_RED); +} //end of the function AAS_ShowFace +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_ShowFacePolygon(int facenum, int color, int flip) +{ + int i, edgenum, numpoints; + vec3_t points[128]; + aas_edge_t *edge; + aas_face_t *face; + + //check if face number is in range + if (facenum >= aasworld.numfaces) + { + botimport.Print(PRT_ERROR, "facenum %d out of range\n", facenum); + } //end if + face = &aasworld.faces[facenum]; + //walk through the edges of the face + numpoints = 0; + if (flip) + { + for (i = face->numedges-1; i >= 0; i--) + { + //edge number + edgenum = aasworld.edgeindex[face->firstedge + i]; + edge = &aasworld.edges[abs(edgenum)]; + VectorCopy(aasworld.vertexes[edge->v[edgenum < 0]], points[numpoints]); + numpoints++; + } //end for + } //end if + else + { + for (i = 0; i < face->numedges; i++) + { + //edge number + edgenum = aasworld.edgeindex[face->firstedge + i]; + edge = &aasworld.edges[abs(edgenum)]; + VectorCopy(aasworld.vertexes[edge->v[edgenum < 0]], points[numpoints]); + numpoints++; + } //end for + } //end else + AAS_ShowPolygon(color, numpoints, points); +} //end of the function AAS_ShowFacePolygon +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_ShowArea(int areanum, int groundfacesonly) +{ + int areaedges[MAX_DEBUGLINES]; + int numareaedges, i, j, n, color = 0, line; + int facenum, edgenum; + aas_area_t *area; + aas_face_t *face; + aas_edge_t *edge; + + // + numareaedges = 0; + // + if (areanum < 0 || areanum >= aasworld.numareas) + { + botimport.Print(PRT_ERROR, "area %d out of range [0, %d]\n", + areanum, aasworld.numareas); + return; + } //end if + //pointer to the convex area + area = &aasworld.areas[areanum]; + //walk through the faces of the area + for (i = 0; i < area->numfaces; i++) + { + facenum = abs(aasworld.faceindex[area->firstface + i]); + //check if face number is in range + if (facenum >= aasworld.numfaces) + { + botimport.Print(PRT_ERROR, "facenum %d out of range\n", facenum); + } //end if + face = &aasworld.faces[facenum]; + //ground faces only + if (groundfacesonly) + { + if (!(face->faceflags & (FACE_GROUND | FACE_LADDER))) continue; + } //end if + //walk through the edges of the face + for (j = 0; j < face->numedges; j++) + { + //edge number + edgenum = abs(aasworld.edgeindex[face->firstedge + j]); + //check if edge number is in range + if (edgenum >= aasworld.numedges) + { + botimport.Print(PRT_ERROR, "edgenum %d out of range\n", edgenum); + } //end if + //check if the edge is stored already + for (n = 0; n < numareaedges; n++) + { + if (areaedges[n] == edgenum) break; + } //end for + if (n == numareaedges && numareaedges < MAX_DEBUGLINES) + { + areaedges[numareaedges++] = edgenum; + } //end if + } //end for + //AAS_ShowFace(facenum); + } //end for + //draw all the edges + for (n = 0; n < numareaedges; n++) + { + for (line = 0; line < MAX_DEBUGLINES; line++) + { + if (!debuglines[line]) + { + debuglines[line] = botimport.DebugLineCreate(); + debuglinevisible[line] = qfalse; + numdebuglines++; + } //end if + if (!debuglinevisible[line]) + { + break; + } //end else + } //end for + if (line >= MAX_DEBUGLINES) return; + edge = &aasworld.edges[areaedges[n]]; + if (color == LINECOLOR_RED) color = LINECOLOR_BLUE; + else if (color == LINECOLOR_BLUE) color = LINECOLOR_GREEN; + else if (color == LINECOLOR_GREEN) color = LINECOLOR_YELLOW; + else color = LINECOLOR_RED; + botimport.DebugLineShow(debuglines[line], + aasworld.vertexes[edge->v[0]], + aasworld.vertexes[edge->v[1]], + color); + debuglinevisible[line] = qtrue; + } //end for*/ +} //end of the function AAS_ShowArea +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_ShowAreaPolygons(int areanum, int color, int groundfacesonly) +{ + int i, facenum; + aas_area_t *area; + aas_face_t *face; + + // + if (areanum < 0 || areanum >= aasworld.numareas) + { + botimport.Print(PRT_ERROR, "area %d out of range [0, %d]\n", + areanum, aasworld.numareas); + return; + } //end if + //pointer to the convex area + area = &aasworld.areas[areanum]; + //walk through the faces of the area + for (i = 0; i < area->numfaces; i++) + { + facenum = abs(aasworld.faceindex[area->firstface + i]); + //check if face number is in range + if (facenum >= aasworld.numfaces) + { + botimport.Print(PRT_ERROR, "facenum %d out of range\n", facenum); + } //end if + face = &aasworld.faces[facenum]; + //ground faces only + if (groundfacesonly) + { + if (!(face->faceflags & (FACE_GROUND | FACE_LADDER))) continue; + } //end if + AAS_ShowFacePolygon(facenum, color, face->frontarea != areanum); + } //end for +} //end of the function AAS_ShowAreaPolygons +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_DrawCross(vec3_t origin, float size, int color) +{ + int i; + vec3_t start, end; + + for (i = 0; i < 3; i++) + { + VectorCopy(origin, start); + start[i] += size; + VectorCopy(origin, end); + end[i] -= size; + AAS_DebugLine(start, end, color); + } //end for +} //end of the function AAS_DrawCross +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_PrintTravelType(int traveltype) +{ +#ifdef DEBUG + char *str; + // + switch(traveltype & TRAVELTYPE_MASK) + { + case TRAVEL_INVALID: str = "TRAVEL_INVALID"; break; + case TRAVEL_WALK: str = "TRAVEL_WALK"; break; + case TRAVEL_CROUCH: str = "TRAVEL_CROUCH"; break; + case TRAVEL_BARRIERJUMP: str = "TRAVEL_BARRIERJUMP"; break; + case TRAVEL_JUMP: str = "TRAVEL_JUMP"; break; + case TRAVEL_LADDER: str = "TRAVEL_LADDER"; break; + case TRAVEL_WALKOFFLEDGE: str = "TRAVEL_WALKOFFLEDGE"; break; + case TRAVEL_SWIM: str = "TRAVEL_SWIM"; break; + case TRAVEL_WATERJUMP: str = "TRAVEL_WATERJUMP"; break; + case TRAVEL_TELEPORT: str = "TRAVEL_TELEPORT"; break; + case TRAVEL_ELEVATOR: str = "TRAVEL_ELEVATOR"; break; + case TRAVEL_ROCKETJUMP: str = "TRAVEL_ROCKETJUMP"; break; + case TRAVEL_BFGJUMP: str = "TRAVEL_BFGJUMP"; break; + case TRAVEL_GRAPPLEHOOK: str = "TRAVEL_GRAPPLEHOOK"; break; + case TRAVEL_JUMPPAD: str = "TRAVEL_JUMPPAD"; break; + case TRAVEL_FUNCBOB: str = "TRAVEL_FUNCBOB"; break; + default: str = "UNKNOWN TRAVEL TYPE"; break; + } //end switch + botimport.Print(PRT_MESSAGE, "%s", str); +#endif +} //end of the function AAS_PrintTravelType +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_DrawArrow(vec3_t start, vec3_t end, int linecolor, int arrowcolor) +{ + vec3_t dir, cross, p1, p2, up = {0, 0, 1}; + float dot; + + VectorSubtract(end, start, dir); + VectorNormalize(dir); + dot = DotProduct(dir, up); + if (dot > 0.99 || dot < -0.99) VectorSet(cross, 1, 0, 0); + else CrossProduct(dir, up, cross); + + VectorMA(end, -6, dir, p1); + VectorCopy(p1, p2); + VectorMA(p1, 6, cross, p1); + VectorMA(p2, -6, cross, p2); + + AAS_DebugLine(start, end, linecolor); + AAS_DebugLine(p1, end, arrowcolor); + AAS_DebugLine(p2, end, arrowcolor); +} //end of the function AAS_DrawArrow +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_ShowReachability(aas_reachability_t *reach) +{ + vec3_t dir, cmdmove, velocity; + float speed, zvel; + aas_clientmove_t move; + + AAS_ShowAreaPolygons(reach->areanum, 5, qtrue); + //AAS_ShowArea(reach->areanum, qtrue); + AAS_DrawArrow(reach->start, reach->end, LINECOLOR_BLUE, LINECOLOR_YELLOW); + // + if ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMP || + (reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_WALKOFFLEDGE) + { + AAS_HorizontalVelocityForJump(aassettings.phys_jumpvel, reach->start, reach->end, &speed); + // + VectorSubtract(reach->end, reach->start, dir); + dir[2] = 0; + VectorNormalize(dir); + //set the velocity + VectorScale(dir, speed, velocity); + //set the command movement + VectorClear(cmdmove); + cmdmove[2] = aassettings.phys_jumpvel; + // + AAS_PredictClientMovement(&move, -1, reach->start, PRESENCE_NORMAL, qtrue, + velocity, cmdmove, 3, 30, 0.1f, + SE_HITGROUND|SE_ENTERWATER|SE_ENTERSLIME| + SE_ENTERLAVA|SE_HITGROUNDDAMAGE, 0, qtrue); + // + if ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMP) + { + AAS_JumpReachRunStart(reach, dir); + AAS_DrawCross(dir, 4, LINECOLOR_BLUE); + } //end if + } //end if + else if ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_ROCKETJUMP) + { + zvel = AAS_RocketJumpZVelocity(reach->start); + AAS_HorizontalVelocityForJump(zvel, reach->start, reach->end, &speed); + // + VectorSubtract(reach->end, reach->start, dir); + dir[2] = 0; + VectorNormalize(dir); + //get command movement + VectorScale(dir, speed, cmdmove); + VectorSet(velocity, 0, 0, zvel); + // + AAS_PredictClientMovement(&move, -1, reach->start, PRESENCE_NORMAL, qtrue, + velocity, cmdmove, 30, 30, 0.1f, + SE_ENTERWATER|SE_ENTERSLIME| + SE_ENTERLAVA|SE_HITGROUNDDAMAGE| + SE_TOUCHJUMPPAD|SE_HITGROUNDAREA, reach->areanum, qtrue); + } //end else if + else if ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMPPAD) + { + VectorSet(cmdmove, 0, 0, 0); + // + VectorSubtract(reach->end, reach->start, dir); + dir[2] = 0; + VectorNormalize(dir); + //set the velocity + //NOTE: the edgenum is the horizontal velocity + VectorScale(dir, reach->edgenum, velocity); + //NOTE: the facenum is the Z velocity + velocity[2] = reach->facenum; + // + AAS_PredictClientMovement(&move, -1, reach->start, PRESENCE_NORMAL, qtrue, + velocity, cmdmove, 30, 30, 0.1f, + SE_ENTERWATER|SE_ENTERSLIME| + SE_ENTERLAVA|SE_HITGROUNDDAMAGE| + SE_TOUCHJUMPPAD|SE_HITGROUNDAREA, reach->areanum, qtrue); + } //end else if +} //end of the function AAS_ShowReachability +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_ShowReachableAreas(int areanum) +{ + aas_areasettings_t *settings; + static aas_reachability_t reach; + static int index, lastareanum; + static float lasttime; + + if (areanum != lastareanum) + { + index = 0; + lastareanum = areanum; + } //end if + settings = &aasworld.areasettings[areanum]; + // + if (!settings->numreachableareas) return; + // + if (index >= settings->numreachableareas) index = 0; + // + if (AAS_Time() - lasttime > 1.5) + { + Com_Memcpy(&reach, &aasworld.reachability[settings->firstreachablearea + index], sizeof(aas_reachability_t)); + index++; + lasttime = AAS_Time(); + AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK); + botimport.Print(PRT_MESSAGE, "\n"); + } //end if + AAS_ShowReachability(&reach); +} //end of the function ShowReachableAreas + +void AAS_FloodAreas_r(int areanum, int cluster, int *done) +{ + int nextareanum, i, facenum; + aas_area_t *area; + aas_face_t *face; + aas_areasettings_t *settings; + aas_reachability_t *reach; + + AAS_ShowAreaPolygons(areanum, 1, qtrue); + //pointer to the convex area + area = &aasworld.areas[areanum]; + settings = &aasworld.areasettings[areanum]; + //walk through the faces of the area + for (i = 0; i < area->numfaces; i++) + { + facenum = abs(aasworld.faceindex[area->firstface + i]); + face = &aasworld.faces[facenum]; + if (face->frontarea == areanum) + nextareanum = face->backarea; + else + nextareanum = face->frontarea; + if (!nextareanum) + continue; + if (done[nextareanum]) + continue; + done[nextareanum] = qtrue; + if (aasworld.areasettings[nextareanum].contents & AREACONTENTS_VIEWPORTAL) + continue; + if (AAS_AreaCluster(nextareanum) != cluster) + continue; + AAS_FloodAreas_r(nextareanum, cluster, done); + } //end for + // + for (i = 0; i < settings->numreachableareas; i++) + { + reach = &aasworld.reachability[settings->firstreachablearea + i]; + nextareanum = reach->areanum; + if (!nextareanum) + continue; + if (done[nextareanum]) + continue; + done[nextareanum] = qtrue; + if (aasworld.areasettings[nextareanum].contents & AREACONTENTS_VIEWPORTAL) + continue; + if (AAS_AreaCluster(nextareanum) != cluster) + continue; + /* + if ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_WALKOFFLEDGE) + { + AAS_DebugLine(reach->start, reach->end, 1); + } + */ + AAS_FloodAreas_r(nextareanum, cluster, done); + } +} + +void AAS_FloodAreas(vec3_t origin) +{ + int areanum, cluster, *done; + + done = (int *) GetClearedMemory(aasworld.numareas * sizeof(int)); + areanum = AAS_PointAreaNum(origin); + cluster = AAS_AreaCluster(areanum); + AAS_FloodAreas_r(areanum, cluster, done); +} diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_debug.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_debug.h new file mode 100644 index 0000000..3cc4b96 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_debug.h @@ -0,0 +1,67 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_aas_debug.h + * + * desc: AAS + * + * $Archive: /source/code/botlib/be_aas_debug.h $ + * $Author: Mrelusive $ + * $Revision: 2 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 10/05/99 3:42p $ + * + *****************************************************************************/ +#pragma once + +//clear the shown debug lines +void AAS_ClearShownDebugLines(void); +// +void AAS_ClearShownPolygons(void); +//show a debug line +void AAS_DebugLine(vec3_t start, vec3_t end, int color); +//show a permenent line +void AAS_PermanentLine(vec3_t start, vec3_t end, int color); +//show a permanent cross +void AAS_DrawPermanentCross(vec3_t origin, float size, int color); +//draw a cross in the plane +void AAS_DrawPlaneCross(vec3_t point, vec3_t normal, float dist, int type, int color); +//show a bounding box +void AAS_ShowBoundingBox(vec3_t origin, vec3_t mins, vec3_t maxs); +//show a face +void AAS_ShowFace(int facenum); +//show an area +void AAS_ShowArea(int areanum, int groundfacesonly); +// +void AAS_ShowAreaPolygons(int areanum, int color, int groundfacesonly); +//draw a cros +void AAS_DrawCross(vec3_t origin, float size, int color); +//print the travel type +void AAS_PrintTravelType(int traveltype); +//draw an arrow +void AAS_DrawArrow(vec3_t start, vec3_t end, int linecolor, int arrowcolor); +//visualize the given reachability +void AAS_ShowReachability(struct aas_reachability_s *reach); +//show the reachable areas from the given area +void AAS_ShowReachableAreas(int areanum); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_def.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_def.h new file mode 100644 index 0000000..856a001 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_def.h @@ -0,0 +1,293 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_aas_def.h + * + * desc: AAS + * + * $Archive: /source/code/botlib/be_aas_def.h $ + * $Author: osman $ + * $Revision: 1.4 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 2003/03/15 23:43:54 $ + * + *****************************************************************************/ +#pragma once + +#include "../qcommon/q_shared.h" + +//debugging on +#define AAS_DEBUG + +#define DF_AASENTNUMBER(x) (x - aasworld.entities) +#define DF_NUMBERAASENT(x) (&aasworld.entities[x]) +#define DF_AASENTCLIENT(x) (x - aasworld.entities - 1) +#define DF_CLIENTAASENT(x) (&aasworld.entities[x + 1]) + +#ifndef MAX_PATH + #define MAX_PATH MAX_QPATH +#endif + +//structure to link entities to areas and areas to entities +typedef struct aas_link_s +{ + int entnum; + int areanum; + struct aas_link_s *next_ent, *prev_ent; + struct aas_link_s *next_area, *prev_area; +} aas_link_t; + +//structure to link entities to leaves and leaves to entities +typedef struct bsp_link_s +{ + int entnum; + int leafnum; + struct bsp_link_s *next_ent, *prev_ent; + struct bsp_link_s *next_leaf, *prev_leaf; +} bsp_link_t; + +typedef struct bsp_entdata_s +{ + vec3_t origin; + vec3_t angles; + vec3_t absmins; + vec3_t absmaxs; + int solid; + int modelnum; +} bsp_entdata_t; + +//entity +typedef struct aas_entity_s +{ + //entity info + aas_entityinfo_t i; + //links into the AAS areas + aas_link_t *areas; + //links into the BSP leaves + bsp_link_t *leaves; +} aas_entity_t; + +typedef struct aas_settings_s +{ + vec3_t phys_gravitydirection; + float phys_friction; + float phys_stopspeed; + float phys_gravity; + float phys_waterfriction; + float phys_watergravity; + float phys_maxvelocity; + float phys_maxwalkvelocity; + float phys_maxcrouchvelocity; + float phys_maxswimvelocity; + float phys_walkaccelerate; + float phys_airaccelerate; + float phys_swimaccelerate; + float phys_maxstep; + float phys_maxsteepness; + float phys_maxwaterjump; + float phys_maxbarrier; + float phys_jumpvel; + float phys_falldelta5; + float phys_falldelta10; + float rs_waterjump; + float rs_teleport; + float rs_barrierjump; + float rs_startcrouch; + float rs_startgrapple; + float rs_startwalkoffledge; + float rs_startjump; + float rs_rocketjump; + float rs_bfgjump; + float rs_jumppad; + float rs_aircontrolledjumppad; + float rs_funcbob; + float rs_startelevator; + float rs_falldamage5; + float rs_falldamage10; + float rs_maxfallheight; + float rs_maxjumpfallheight; +} aas_settings_t; + +#define CACHETYPE_PORTAL 0 +#define CACHETYPE_AREA 1 + +//routing cache +typedef struct aas_routingcache_s +{ + byte type; //portal or area cache + float time; //last time accessed or updated + int size; //size of the routing cache + int cluster; //cluster the cache is for + int areanum; //area the cache is created for + vec3_t origin; //origin within the area + float starttraveltime; //travel time to start with + int travelflags; //combinations of the travel flags + struct aas_routingcache_s *prev, *next; + struct aas_routingcache_s *time_prev, *time_next; + unsigned char *reachabilities; //reachabilities used for routing + unsigned short int traveltimes[1]; //travel time for every area (variable sized) +} aas_routingcache_t; + +//fields for the routing algorithm +typedef struct aas_routingupdate_s +{ + int cluster; + int areanum; //area number of the update + vec3_t start; //start point the area was entered + unsigned short int tmptraveltime; //temporary travel time + unsigned short int *areatraveltimes; //travel times within the area + qboolean inlist; //true if the update is in the list + struct aas_routingupdate_s *next; + struct aas_routingupdate_s *prev; +} aas_routingupdate_t; + +//reversed reachability link +typedef struct aas_reversedlink_s +{ + int linknum; //the aas_areareachability_t + int areanum; //reachable from this area + struct aas_reversedlink_s *next; //next link +} aas_reversedlink_t; + +//reversed area reachability +typedef struct aas_reversedreachability_s +{ + int numlinks; + aas_reversedlink_t *first; +} aas_reversedreachability_t; + +//areas a reachability goes through +typedef struct aas_reachabilityareas_s +{ + int firstarea, numareas; +} aas_reachabilityareas_t; + +typedef struct aas_s +{ + int loaded; //true when an AAS file is loaded + int initialized; //true when AAS has been initialized + int savefile; //set true when file should be saved + int bspchecksum; + //current time + float time; + int numframes; + //name of the aas file + char filename[MAX_PATH]; + char mapname[MAX_PATH]; + //bounding boxes + int numbboxes; + aas_bbox_t *bboxes; + //vertexes + int numvertexes; + aas_vertex_t *vertexes; + //planes + int numplanes; + aas_plane_t *planes; + //edges + int numedges; + aas_edge_t *edges; + //edge index + int edgeindexsize; + aas_edgeindex_t *edgeindex; + //faces + int numfaces; + aas_face_t *faces; + //face index + int faceindexsize; + aas_faceindex_t *faceindex; + //convex areas + int numareas; + aas_area_t *areas; + //convex area settings + int numareasettings; + aas_areasettings_t *areasettings; + //reachablity list + int reachabilitysize; + aas_reachability_t *reachability; + //nodes of the bsp tree + int numnodes; + aas_node_t *nodes; + //cluster portals + int numportals; + aas_portal_t *portals; + //cluster portal index + int portalindexsize; + aas_portalindex_t *portalindex; + //clusters + int numclusters; + aas_cluster_t *clusters; + // + int numreachabilityareas; + float reachabilitytime; + //enities linked in the areas + aas_link_t *linkheap; //heap with link structures + int linkheapsize; //size of the link heap + aas_link_t *freelinks; //first free link + aas_link_t **arealinkedentities; //entities linked into areas + //entities + int maxentities; + int maxclients; + aas_entity_t *entities; + //index to retrieve travel flag for a travel type + int travelflagfortype[MAX_TRAVELTYPES]; + //travel flags for each area based on contents + int *areacontentstravelflags; + //routing update + aas_routingupdate_t *areaupdate; + aas_routingupdate_t *portalupdate; + //number of routing updates during a frame (reset every frame) + int frameroutingupdates; + //reversed reachability links + aas_reversedreachability_t *reversedreachability; + //travel times within the areas + unsigned short ***areatraveltimes; + //array of size numclusters with cluster cache + aas_routingcache_t ***clusterareacache; + aas_routingcache_t **portalcache; + //cache list sorted on time + aas_routingcache_t *oldestcache; // start of cache list sorted on time + aas_routingcache_t *newestcache; // end of cache list sorted on time + //maximum travel time through portal areas + int *portalmaxtraveltimes; + //areas the reachabilities go through + int *reachabilityareaindex; + aas_reachabilityareas_t *reachabilityareas; +} aas_t; + +#ifndef BSPCINCLUDE + +#include "be_aas_main.h" +#include "be_aas_entity.h" +#include "be_aas_sample.h" +#include "be_aas_cluster.h" +#include "be_aas_reach.h" +#include "be_aas_route.h" +#include "be_aas_routealt.h" +#include "be_aas_debug.h" +#include "be_aas_file.h" +#include "be_aas_optimize.h" +#include "be_aas_bsp.h" +#include "be_aas_move.h" + +#endif //BSPCINCLUDE diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_entity.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_entity.cpp new file mode 100644 index 0000000..4ca8bdf --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_entity.cpp @@ -0,0 +1,442 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_aas_entity.c + * + * desc: AAS entities + * + * $Archive: /MissionPack/code/botlib/be_aas_entity.c $ + * $Author: Zaphod $ + * $Revision: 11 $ + * $Modtime: 11/22/00 8:50a $ + * $Date: 11/22/00 8:55a $ + * + *****************************************************************************/ + +#include "qcommon/q_shared.h" +#include "l_memory.h" +#include "l_script.h" +#include "l_precomp.h" +#include "l_struct.h" +#include "l_utils.h" +#include "l_log.h" +#include "aasfile.h" +#include "botlib.h" +#include "be_aas.h" +#include "be_aas_funcs.h" +#include "be_interface.h" +#include "be_aas_def.h" + +#define MASK_SOLID CONTENTS_PLAYERCLIP + +//FIXME: these might change +enum { + ET_GENERAL, + ET_PLAYER, + ET_ITEM, + ET_MISSILE, + ET_MOVER +}; + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_UpdateEntity(int entnum, bot_entitystate_t *state) +{ + int relink; + aas_entity_t *ent; + vec3_t absmins, absmaxs; + + if (!aasworld.loaded) + { + botimport.Print(PRT_MESSAGE, "AAS_UpdateEntity: not loaded\n"); + return BLERR_NOAASFILE; + } //end if + + ent = &aasworld.entities[entnum]; + + if (!state) { + //unlink the entity + AAS_UnlinkFromAreas(ent->areas); + //unlink the entity from the BSP leaves + AAS_UnlinkFromBSPLeaves(ent->leaves); + // + ent->areas = NULL; + // + ent->leaves = NULL; + return BLERR_NOERROR; + } + + ent->i.update_time = AAS_Time() - ent->i.ltime; + ent->i.type = state->type; + ent->i.flags = state->flags; + ent->i.ltime = AAS_Time(); + VectorCopy(ent->i.origin, ent->i.lastvisorigin); + VectorCopy(state->old_origin, ent->i.old_origin); + ent->i.solid = state->solid; + ent->i.groundent = state->groundent; + ent->i.modelindex = state->modelindex; + ent->i.modelindex2 = state->modelindex2; + ent->i.frame = state->frame; + ent->i.event = state->event; + ent->i.eventParm = state->eventParm; + ent->i.powerups = state->powerups; + ent->i.weapon = state->weapon; + ent->i.legsAnim = state->legsAnim; + ent->i.torsoAnim = state->torsoAnim; + //number of the entity + ent->i.number = entnum; + //updated so set valid flag + ent->i.valid = qtrue; + //link everything the first frame + if (aasworld.numframes == 1) relink = qtrue; + else relink = qfalse; + // + if (ent->i.solid == SOLID_BSP) + { + //if the angles of the model changed + if (!VectorCompare(state->angles, ent->i.angles)) + { + VectorCopy(state->angles, ent->i.angles); + relink = qtrue; + } //end if + //get the mins and maxs of the model + //FIXME: rotate mins and maxs + AAS_BSPModelMinsMaxsOrigin(ent->i.modelindex, ent->i.angles, ent->i.mins, ent->i.maxs, NULL); + } //end if + else if (ent->i.solid == SOLID_BBOX) + { + //if the bounding box size changed + if (!VectorCompare(state->mins, ent->i.mins) || + !VectorCompare(state->maxs, ent->i.maxs)) + { + VectorCopy(state->mins, ent->i.mins); + VectorCopy(state->maxs, ent->i.maxs); + relink = qtrue; + } //end if + VectorCopy(state->angles, ent->i.angles); + } //end if + //if the origin changed + if (!VectorCompare(state->origin, ent->i.origin)) + { + VectorCopy(state->origin, ent->i.origin); + relink = qtrue; + } //end if + //if the entity should be relinked + if (relink) + { + //don't link the world model + if (entnum != ENTITYNUM_WORLD) + { + //absolute mins and maxs + VectorAdd(ent->i.mins, ent->i.origin, absmins); + VectorAdd(ent->i.maxs, ent->i.origin, absmaxs); + //unlink the entity + AAS_UnlinkFromAreas(ent->areas); + //relink the entity to the AAS areas (use the larges bbox) + ent->areas = AAS_LinkEntityClientBBox(absmins, absmaxs, entnum, PRESENCE_NORMAL); + //unlink the entity from the BSP leaves + AAS_UnlinkFromBSPLeaves(ent->leaves); + //link the entity to the world BSP tree + ent->leaves = AAS_BSPLinkEntity(absmins, absmaxs, entnum, 0); + } //end if + } //end if + return BLERR_NOERROR; +} //end of the function AAS_UpdateEntity +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_EntityInfo(int entnum, aas_entityinfo_t *info) +{ + if (!aasworld.initialized) + { + botimport.Print(PRT_FATAL, "AAS_EntityInfo: aasworld not initialized\n"); + Com_Memset(info, 0, sizeof(aas_entityinfo_t)); + return; + } //end if + + if (entnum < 0 || entnum >= aasworld.maxentities) + { + botimport.Print(PRT_FATAL, "AAS_EntityInfo: entnum %d out of range\n", entnum); + Com_Memset(info, 0, sizeof(aas_entityinfo_t)); + return; + } //end if + + Com_Memcpy(info, &aasworld.entities[entnum].i, sizeof(aas_entityinfo_t)); +} //end of the function AAS_EntityInfo +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_EntityOrigin(int entnum, vec3_t origin) +{ + if (entnum < 0 || entnum >= aasworld.maxentities) + { + botimport.Print(PRT_FATAL, "AAS_EntityOrigin: entnum %d out of range\n", entnum); + VectorClear(origin); + return; + } //end if + + VectorCopy(aasworld.entities[entnum].i.origin, origin); +} //end of the function AAS_EntityOrigin +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_EntityModelindex(int entnum) +{ + if (entnum < 0 || entnum >= aasworld.maxentities) + { + botimport.Print(PRT_FATAL, "AAS_EntityModelindex: entnum %d out of range\n", entnum); + return 0; + } //end if + return aasworld.entities[entnum].i.modelindex; +} //end of the function AAS_EntityModelindex +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_EntityType(int entnum) +{ + if (!aasworld.initialized) return 0; + + if (entnum < 0 || entnum >= aasworld.maxentities) + { + botimport.Print(PRT_FATAL, "AAS_EntityType: entnum %d out of range\n", entnum); + return 0; + } //end if + return aasworld.entities[entnum].i.type; +} //end of the AAS_EntityType +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_EntityModelNum(int entnum) +{ + if (!aasworld.initialized) return 0; + + if (entnum < 0 || entnum >= aasworld.maxentities) + { + botimport.Print(PRT_FATAL, "AAS_EntityModelNum: entnum %d out of range\n", entnum); + return 0; + } //end if + return aasworld.entities[entnum].i.modelindex; +} //end of the function AAS_EntityModelNum +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_OriginOfMoverWithModelNum(int modelnum, vec3_t origin) +{ + int i; + aas_entity_t *ent; + + for (i = 0; i < aasworld.maxentities; i++) + { + ent = &aasworld.entities[i]; + if (ent->i.type == ET_MOVER) + { + if (ent->i.modelindex == modelnum) + { + VectorCopy(ent->i.origin, origin); + return qtrue; + } //end if + } //end if + } //end for + return qfalse; +} //end of the function AAS_OriginOfMoverWithModelNum +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_EntitySize(int entnum, vec3_t mins, vec3_t maxs) +{ + aas_entity_t *ent; + + if (!aasworld.initialized) return; + + if (entnum < 0 || entnum >= aasworld.maxentities) + { + botimport.Print(PRT_FATAL, "AAS_EntitySize: entnum %d out of range\n", entnum); + return; + } //end if + + ent = &aasworld.entities[entnum]; + VectorCopy(ent->i.mins, mins); + VectorCopy(ent->i.maxs, maxs); +} //end of the function AAS_EntitySize +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_EntityBSPData(int entnum, bsp_entdata_t *entdata) +{ + aas_entity_t *ent; + + ent = &aasworld.entities[entnum]; + VectorCopy(ent->i.origin, entdata->origin); + VectorCopy(ent->i.angles, entdata->angles); + VectorAdd(ent->i.origin, ent->i.mins, entdata->absmins); + VectorAdd(ent->i.origin, ent->i.maxs, entdata->absmaxs); + entdata->solid = ent->i.solid; + entdata->modelnum = ent->i.modelindex - 1; +} //end of the function AAS_EntityBSPData +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_ResetEntityLinks(void) +{ + int i; + for (i = 0; i < aasworld.maxentities; i++) + { + aasworld.entities[i].areas = NULL; + aasworld.entities[i].leaves = NULL; + } //end for +} //end of the function AAS_ResetEntityLinks +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_InvalidateEntities(void) +{ + int i; + for (i = 0; i < aasworld.maxentities; i++) + { + aasworld.entities[i].i.valid = qfalse; + aasworld.entities[i].i.number = i; + } //end for +} //end of the function AAS_InvalidateEntities +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_UnlinkInvalidEntities(void) +{ + int i; + aas_entity_t *ent; + + for (i = 0; i < aasworld.maxentities; i++) + { + ent = &aasworld.entities[i]; + if (!ent->i.valid) + { + AAS_UnlinkFromAreas( ent->areas ); + ent->areas = NULL; + AAS_UnlinkFromBSPLeaves( ent->leaves ); + ent->leaves = NULL; + } //end for + } //end for +} //end of the function AAS_UnlinkInvalidEntities +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_NearestEntity(vec3_t origin, int modelindex) +{ + int i, bestentnum; + float dist, bestdist; + aas_entity_t *ent; + vec3_t dir; + + bestentnum = 0; + bestdist = 99999; + for (i = 0; i < aasworld.maxentities; i++) + { + ent = &aasworld.entities[i]; + if (ent->i.modelindex != modelindex) continue; + VectorSubtract(ent->i.origin, origin, dir); + if (fabs(dir[0]) < 40) + { + if (fabs(dir[1]) < 40) + { + dist = VectorLength(dir); + if (dist < bestdist) + { + bestdist = dist; + bestentnum = i; + } //end if + } //end if + } //end if + } //end for + return bestentnum; +} //end of the function AAS_NearestEntity +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_BestReachableEntityArea(int entnum) +{ + aas_entity_t *ent; + + ent = &aasworld.entities[entnum]; + return AAS_BestReachableLinkArea(ent->areas); +} //end of the function AAS_BestReachableEntityArea +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_NextEntity(int entnum) +{ + if (!aasworld.loaded) return 0; + + if (entnum < 0) entnum = -1; + while(++entnum < aasworld.maxentities) + { + if (aasworld.entities[entnum].i.valid) return entnum; + } //end while + return 0; +} //end of the function AAS_NextEntity diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_entity.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_entity.h new file mode 100644 index 0000000..1be5948 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_entity.h @@ -0,0 +1,69 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_aas_entity.h + * + * desc: AAS + * + * $Archive: /source/code/botlib/be_aas_entity.h $ + * $Author: Mrelusive $ + * $Revision: 2 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 10/05/99 3:42p $ + * + *****************************************************************************/ + +#pragma once + +#ifdef AASINTERN +//invalidates all entity infos +void AAS_InvalidateEntities(void); +//unlink not updated entities +void AAS_UnlinkInvalidEntities(void); +//resets the entity AAS and BSP links (sets areas and leaves pointers to NULL) +void AAS_ResetEntityLinks(void); +//updates an entity +int AAS_UpdateEntity(int ent, bot_entitystate_t *state); +//gives the entity data used for collision detection +void AAS_EntityBSPData(int entnum, bsp_entdata_t *entdata); +#endif //AASINTERN + +//returns the size of the entity bounding box in mins and maxs +void AAS_EntitySize(int entnum, vec3_t mins, vec3_t maxs); +//returns the BSP model number of the entity +int AAS_EntityModelNum(int entnum); +//returns the origin of an entity with the given model number +int AAS_OriginOfMoverWithModelNum(int modelnum, vec3_t origin); +//returns the best reachable area the entity is situated in +int AAS_BestReachableEntityArea(int entnum); +//returns the info of the given entity +void AAS_EntityInfo(int entnum, aas_entityinfo_t *info); +//returns the next entity +int AAS_NextEntity(int entnum); +//returns the origin of the entity +void AAS_EntityOrigin(int entnum, vec3_t origin); +//returns the entity type +int AAS_EntityType(int entnum); +//returns the model index of the entity +int AAS_EntityModelindex(int entnum); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_file.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_file.cpp new file mode 100644 index 0000000..9f9a2fa --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_file.cpp @@ -0,0 +1,587 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_aas_file.c + * + * desc: AAS file loading/writing + * + * $Archive: /MissionPack/code/botlib/be_aas_file.c $ + * $Author: Zaphod $ + * $Revision: 5 $ + * $Modtime: 5/16/01 2:36p $ + * $Date: 5/16/01 2:41p $ + * + *****************************************************************************/ + +#include "qcommon/q_shared.h" +#include "l_memory.h" +#include "l_script.h" +#include "l_precomp.h" +#include "l_struct.h" +#include "l_libvar.h" +#include "l_utils.h" +#include "aasfile.h" +#include "botlib.h" +#include "be_aas.h" +#include "be_aas_funcs.h" +#include "be_interface.h" +#include "be_aas_def.h" + +//#define AASFILEDEBUG + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_SwapAASData(void) +{ + int i, j; + //bounding boxes + for (i = 0; i < aasworld.numbboxes; i++) + { + aasworld.bboxes[i].presencetype = LittleLong(aasworld.bboxes[i].presencetype); + aasworld.bboxes[i].flags = LittleLong(aasworld.bboxes[i].flags); + for (j = 0; j < 3; j++) + { + aasworld.bboxes[i].mins[j] = LittleLong(aasworld.bboxes[i].mins[j]); + aasworld.bboxes[i].maxs[j] = LittleLong(aasworld.bboxes[i].maxs[j]); + } //end for + } //end for + //vertexes + for (i = 0; i < aasworld.numvertexes; i++) + { + for (j = 0; j < 3; j++) + aasworld.vertexes[i][j] = LittleFloat(aasworld.vertexes[i][j]); + } //end for + //planes + for (i = 0; i < aasworld.numplanes; i++) + { + for (j = 0; j < 3; j++) + aasworld.planes[i].normal[j] = LittleFloat(aasworld.planes[i].normal[j]); + aasworld.planes[i].dist = LittleFloat(aasworld.planes[i].dist); + aasworld.planes[i].type = LittleLong(aasworld.planes[i].type); + } //end for + //edges + for (i = 0; i < aasworld.numedges; i++) + { + aasworld.edges[i].v[0] = LittleLong(aasworld.edges[i].v[0]); + aasworld.edges[i].v[1] = LittleLong(aasworld.edges[i].v[1]); + } //end for + //edgeindex + for (i = 0; i < aasworld.edgeindexsize; i++) + { + aasworld.edgeindex[i] = LittleLong(aasworld.edgeindex[i]); + } //end for + //faces + for (i = 0; i < aasworld.numfaces; i++) + { + aasworld.faces[i].planenum = LittleLong(aasworld.faces[i].planenum); + aasworld.faces[i].faceflags = LittleLong(aasworld.faces[i].faceflags); + aasworld.faces[i].numedges = LittleLong(aasworld.faces[i].numedges); + aasworld.faces[i].firstedge = LittleLong(aasworld.faces[i].firstedge); + aasworld.faces[i].frontarea = LittleLong(aasworld.faces[i].frontarea); + aasworld.faces[i].backarea = LittleLong(aasworld.faces[i].backarea); + } //end for + //face index + for (i = 0; i < aasworld.faceindexsize; i++) + { + aasworld.faceindex[i] = LittleLong(aasworld.faceindex[i]); + } //end for + //convex areas + for (i = 0; i < aasworld.numareas; i++) + { + aasworld.areas[i].areanum = LittleLong(aasworld.areas[i].areanum); + aasworld.areas[i].numfaces = LittleLong(aasworld.areas[i].numfaces); + aasworld.areas[i].firstface = LittleLong(aasworld.areas[i].firstface); + for (j = 0; j < 3; j++) + { + aasworld.areas[i].mins[j] = LittleFloat(aasworld.areas[i].mins[j]); + aasworld.areas[i].maxs[j] = LittleFloat(aasworld.areas[i].maxs[j]); + aasworld.areas[i].center[j] = LittleFloat(aasworld.areas[i].center[j]); + } //end for + } //end for + //area settings + for (i = 0; i < aasworld.numareasettings; i++) + { + aasworld.areasettings[i].contents = LittleLong(aasworld.areasettings[i].contents); + aasworld.areasettings[i].areaflags = LittleLong(aasworld.areasettings[i].areaflags); + aasworld.areasettings[i].presencetype = LittleLong(aasworld.areasettings[i].presencetype); + aasworld.areasettings[i].cluster = LittleLong(aasworld.areasettings[i].cluster); + aasworld.areasettings[i].clusterareanum = LittleLong(aasworld.areasettings[i].clusterareanum); + aasworld.areasettings[i].numreachableareas = LittleLong(aasworld.areasettings[i].numreachableareas); + aasworld.areasettings[i].firstreachablearea = LittleLong(aasworld.areasettings[i].firstreachablearea); + } //end for + //area reachability + for (i = 0; i < aasworld.reachabilitysize; i++) + { + aasworld.reachability[i].areanum = LittleLong(aasworld.reachability[i].areanum); + aasworld.reachability[i].facenum = LittleLong(aasworld.reachability[i].facenum); + aasworld.reachability[i].edgenum = LittleLong(aasworld.reachability[i].edgenum); + for (j = 0; j < 3; j++) + { + aasworld.reachability[i].start[j] = LittleFloat(aasworld.reachability[i].start[j]); + aasworld.reachability[i].end[j] = LittleFloat(aasworld.reachability[i].end[j]); + } //end for + aasworld.reachability[i].traveltype = LittleLong(aasworld.reachability[i].traveltype); + aasworld.reachability[i].traveltime = LittleShort(aasworld.reachability[i].traveltime); + } //end for + //nodes + for (i = 0; i < aasworld.numnodes; i++) + { + aasworld.nodes[i].planenum = LittleLong(aasworld.nodes[i].planenum); + aasworld.nodes[i].children[0] = LittleLong(aasworld.nodes[i].children[0]); + aasworld.nodes[i].children[1] = LittleLong(aasworld.nodes[i].children[1]); + } //end for + //cluster portals + for (i = 0; i < aasworld.numportals; i++) + { + aasworld.portals[i].areanum = LittleLong(aasworld.portals[i].areanum); + aasworld.portals[i].frontcluster = LittleLong(aasworld.portals[i].frontcluster); + aasworld.portals[i].backcluster = LittleLong(aasworld.portals[i].backcluster); + aasworld.portals[i].clusterareanum[0] = LittleLong(aasworld.portals[i].clusterareanum[0]); + aasworld.portals[i].clusterareanum[1] = LittleLong(aasworld.portals[i].clusterareanum[1]); + } //end for + //cluster portal index + for (i = 0; i < aasworld.portalindexsize; i++) + { + aasworld.portalindex[i] = LittleLong(aasworld.portalindex[i]); + } //end for + //cluster + for (i = 0; i < aasworld.numclusters; i++) + { + aasworld.clusters[i].numareas = LittleLong(aasworld.clusters[i].numareas); + aasworld.clusters[i].numreachabilityareas = LittleLong(aasworld.clusters[i].numreachabilityareas); + aasworld.clusters[i].numportals = LittleLong(aasworld.clusters[i].numportals); + aasworld.clusters[i].firstportal = LittleLong(aasworld.clusters[i].firstportal); + } //end for +} //end of the function AAS_SwapAASData +//=========================================================================== +// dump the current loaded aas file +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_DumpAASData(void) +{ + aasworld.numbboxes = 0; + if (aasworld.bboxes) FreeMemory(aasworld.bboxes); + aasworld.bboxes = NULL; + aasworld.numvertexes = 0; + if (aasworld.vertexes) FreeMemory(aasworld.vertexes); + aasworld.vertexes = NULL; + aasworld.numplanes = 0; + if (aasworld.planes) FreeMemory(aasworld.planes); + aasworld.planes = NULL; + aasworld.numedges = 0; + if (aasworld.edges) FreeMemory(aasworld.edges); + aasworld.edges = NULL; + aasworld.edgeindexsize = 0; + if (aasworld.edgeindex) FreeMemory(aasworld.edgeindex); + aasworld.edgeindex = NULL; + aasworld.numfaces = 0; + if (aasworld.faces) FreeMemory(aasworld.faces); + aasworld.faces = NULL; + aasworld.faceindexsize = 0; + if (aasworld.faceindex) FreeMemory(aasworld.faceindex); + aasworld.faceindex = NULL; + aasworld.numareas = 0; + if (aasworld.areas) FreeMemory(aasworld.areas); + aasworld.areas = NULL; + aasworld.numareasettings = 0; + if (aasworld.areasettings) FreeMemory(aasworld.areasettings); + aasworld.areasettings = NULL; + aasworld.reachabilitysize = 0; + if (aasworld.reachability) FreeMemory(aasworld.reachability); + aasworld.reachability = NULL; + aasworld.numnodes = 0; + if (aasworld.nodes) FreeMemory(aasworld.nodes); + aasworld.nodes = NULL; + aasworld.numportals = 0; + if (aasworld.portals) FreeMemory(aasworld.portals); + aasworld.portals = NULL; + aasworld.numportals = 0; + if (aasworld.portalindex) FreeMemory(aasworld.portalindex); + aasworld.portalindex = NULL; + aasworld.portalindexsize = 0; + if (aasworld.clusters) FreeMemory(aasworld.clusters); + aasworld.clusters = NULL; + aasworld.numclusters = 0; + // + aasworld.loaded = qfalse; + aasworld.initialized = qfalse; + aasworld.savefile = qfalse; +} //end of the function AAS_DumpAASData +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +#ifdef AASFILEDEBUG +void AAS_FileInfo(void) +{ + int i, n, optimized; + + botimport.Print(PRT_MESSAGE, "version = %d\n", AASVERSION); + botimport.Print(PRT_MESSAGE, "numvertexes = %d\n", aasworld.numvertexes); + botimport.Print(PRT_MESSAGE, "numplanes = %d\n", aasworld.numplanes); + botimport.Print(PRT_MESSAGE, "numedges = %d\n", aasworld.numedges); + botimport.Print(PRT_MESSAGE, "edgeindexsize = %d\n", aasworld.edgeindexsize); + botimport.Print(PRT_MESSAGE, "numfaces = %d\n", aasworld.numfaces); + botimport.Print(PRT_MESSAGE, "faceindexsize = %d\n", aasworld.faceindexsize); + botimport.Print(PRT_MESSAGE, "numareas = %d\n", aasworld.numareas); + botimport.Print(PRT_MESSAGE, "numareasettings = %d\n", aasworld.numareasettings); + botimport.Print(PRT_MESSAGE, "reachabilitysize = %d\n", aasworld.reachabilitysize); + botimport.Print(PRT_MESSAGE, "numnodes = %d\n", aasworld.numnodes); + botimport.Print(PRT_MESSAGE, "numportals = %d\n", aasworld.numportals); + botimport.Print(PRT_MESSAGE, "portalindexsize = %d\n", aasworld.portalindexsize); + botimport.Print(PRT_MESSAGE, "numclusters = %d\n", aasworld.numclusters); + // + for (n = 0, i = 0; i < aasworld.numareasettings; i++) + { + if (aasworld.areasettings[i].areaflags & AREA_GROUNDED) n++; + } //end for + botimport.Print(PRT_MESSAGE, "num grounded areas = %d\n", n); + // + botimport.Print(PRT_MESSAGE, "planes size %d bytes\n", aasworld.numplanes * sizeof(aas_plane_t)); + botimport.Print(PRT_MESSAGE, "areas size %d bytes\n", aasworld.numareas * sizeof(aas_area_t)); + botimport.Print(PRT_MESSAGE, "areasettings size %d bytes\n", aasworld.numareasettings * sizeof(aas_areasettings_t)); + botimport.Print(PRT_MESSAGE, "nodes size %d bytes\n", aasworld.numnodes * sizeof(aas_node_t)); + botimport.Print(PRT_MESSAGE, "reachability size %d bytes\n", aasworld.reachabilitysize * sizeof(aas_reachability_t)); + botimport.Print(PRT_MESSAGE, "portals size %d bytes\n", aasworld.numportals * sizeof(aas_portal_t)); + botimport.Print(PRT_MESSAGE, "clusters size %d bytes\n", aasworld.numclusters * sizeof(aas_cluster_t)); + + optimized = aasworld.numplanes * sizeof(aas_plane_t) + + aasworld.numareas * sizeof(aas_area_t) + + aasworld.numareasettings * sizeof(aas_areasettings_t) + + aasworld.numnodes * sizeof(aas_node_t) + + aasworld.reachabilitysize * sizeof(aas_reachability_t) + + aasworld.numportals * sizeof(aas_portal_t) + + aasworld.numclusters * sizeof(aas_cluster_t); + botimport.Print(PRT_MESSAGE, "optimzed size %d KB\n", optimized >> 10); +} //end of the function AAS_FileInfo +#endif //AASFILEDEBUG +//=========================================================================== +// allocate memory and read a lump of a AAS file +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +char *AAS_LoadAASLump(fileHandle_t fp, int offset, int length, int *lastoffset, int size) +{ + char *buf; + // + if (!length) + { + //just alloc a dummy + return (char *) GetClearedHunkMemory(size+1); + } //end if + //seek to the data + if (offset != *lastoffset) + { + botimport.Print(PRT_WARNING, "AAS file not sequentially read\n"); + if (botimport.FS_Seek(fp, offset, FS_SEEK_SET)) + { + AAS_Error("can't seek to aas lump\n"); + AAS_DumpAASData(); + botimport.FS_FCloseFile(fp); + return 0; + } //end if + } //end if + //allocate memory + buf = (char *) GetClearedHunkMemory(length+1); + //read the data + if (length) + { + botimport.FS_Read(buf, length, fp ); + *lastoffset += length; + } //end if + return buf; +} //end of the function AAS_LoadAASLump +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_DData(unsigned char *data, int size) +{ + int i; + + for (i = 0; i < size; i++) + { + data[i] ^= (unsigned char) i * 119; + } //end for +} //end of the function AAS_DData +//=========================================================================== +// load an aas file +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_LoadAASFile(char *filename) +{ + fileHandle_t fp; + aas_header_t header; + int offset, length, lastoffset; + + botimport.Print(PRT_MESSAGE, "trying to load %s\n", filename); + //dump current loaded aas file + AAS_DumpAASData(); + //open the file + botimport.FS_FOpenFile( filename, &fp, FS_READ ); + if (!fp) + { + AAS_Error("can't open %s\n", filename); + return BLERR_CANNOTOPENAASFILE; + } //end if + //read the header + botimport.FS_Read(&header, sizeof(aas_header_t), fp ); + lastoffset = sizeof(aas_header_t); + //check header identification + header.ident = LittleLong(header.ident); + if (header.ident != AASID) + { + AAS_Error("%s is not an AAS file\n", filename); + botimport.FS_FCloseFile(fp); + return BLERR_WRONGAASFILEID; + } //end if + //check the version + header.version = LittleLong(header.version); + // + if (header.version != AASVERSION_OLD && header.version != AASVERSION) + { + AAS_Error("aas file %s is version %i, not %i\n", filename, header.version, AASVERSION); + botimport.FS_FCloseFile(fp); + return BLERR_WRONGAASFILEVERSION; + } //end if + // + if (header.version == AASVERSION) + { + AAS_DData((unsigned char *) &header + 8, sizeof(aas_header_t) - 8); + } //end if + // + aasworld.bspchecksum = atoi(LibVarGetString( "sv_mapChecksum")); + if (LittleLong(header.bspchecksum) != aasworld.bspchecksum) + { + AAS_Error("aas file %s is out of date\n", filename); + botimport.FS_FCloseFile(fp); + return BLERR_WRONGAASFILEVERSION; + } //end if + //load the lumps: + //bounding boxes + offset = LittleLong(header.lumps[AASLUMP_BBOXES].fileofs); + length = LittleLong(header.lumps[AASLUMP_BBOXES].filelen); + aasworld.bboxes = (aas_bbox_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_bbox_t)); + aasworld.numbboxes = length / sizeof(aas_bbox_t); + if (aasworld.numbboxes && !aasworld.bboxes) return BLERR_CANNOTREADAASLUMP; + //vertexes + offset = LittleLong(header.lumps[AASLUMP_VERTEXES].fileofs); + length = LittleLong(header.lumps[AASLUMP_VERTEXES].filelen); + aasworld.vertexes = (aas_vertex_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_vertex_t)); + aasworld.numvertexes = length / sizeof(aas_vertex_t); + if (aasworld.numvertexes && !aasworld.vertexes) return BLERR_CANNOTREADAASLUMP; + //planes + offset = LittleLong(header.lumps[AASLUMP_PLANES].fileofs); + length = LittleLong(header.lumps[AASLUMP_PLANES].filelen); + aasworld.planes = (aas_plane_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_plane_t)); + aasworld.numplanes = length / sizeof(aas_plane_t); + if (aasworld.numplanes && !aasworld.planes) return BLERR_CANNOTREADAASLUMP; + //edges + offset = LittleLong(header.lumps[AASLUMP_EDGES].fileofs); + length = LittleLong(header.lumps[AASLUMP_EDGES].filelen); + aasworld.edges = (aas_edge_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_edge_t)); + aasworld.numedges = length / sizeof(aas_edge_t); + if (aasworld.numedges && !aasworld.edges) return BLERR_CANNOTREADAASLUMP; + //edgeindex + offset = LittleLong(header.lumps[AASLUMP_EDGEINDEX].fileofs); + length = LittleLong(header.lumps[AASLUMP_EDGEINDEX].filelen); + aasworld.edgeindex = (aas_edgeindex_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_edgeindex_t)); + aasworld.edgeindexsize = length / sizeof(aas_edgeindex_t); + if (aasworld.edgeindexsize && !aasworld.edgeindex) return BLERR_CANNOTREADAASLUMP; + //faces + offset = LittleLong(header.lumps[AASLUMP_FACES].fileofs); + length = LittleLong(header.lumps[AASLUMP_FACES].filelen); + aasworld.faces = (aas_face_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_face_t)); + aasworld.numfaces = length / sizeof(aas_face_t); + if (aasworld.numfaces && !aasworld.faces) return BLERR_CANNOTREADAASLUMP; + //faceindex + offset = LittleLong(header.lumps[AASLUMP_FACEINDEX].fileofs); + length = LittleLong(header.lumps[AASLUMP_FACEINDEX].filelen); + aasworld.faceindex = (aas_faceindex_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_faceindex_t)); + aasworld.faceindexsize = length / sizeof(aas_faceindex_t); + if (aasworld.faceindexsize && !aasworld.faceindex) return BLERR_CANNOTREADAASLUMP; + //convex areas + offset = LittleLong(header.lumps[AASLUMP_AREAS].fileofs); + length = LittleLong(header.lumps[AASLUMP_AREAS].filelen); + aasworld.areas = (aas_area_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_area_t)); + aasworld.numareas = length / sizeof(aas_area_t); + if (aasworld.numareas && !aasworld.areas) return BLERR_CANNOTREADAASLUMP; + //area settings + offset = LittleLong(header.lumps[AASLUMP_AREASETTINGS].fileofs); + length = LittleLong(header.lumps[AASLUMP_AREASETTINGS].filelen); + aasworld.areasettings = (aas_areasettings_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_areasettings_t)); + aasworld.numareasettings = length / sizeof(aas_areasettings_t); + if (aasworld.numareasettings && !aasworld.areasettings) return BLERR_CANNOTREADAASLUMP; + //reachability list + offset = LittleLong(header.lumps[AASLUMP_REACHABILITY].fileofs); + length = LittleLong(header.lumps[AASLUMP_REACHABILITY].filelen); + aasworld.reachability = (aas_reachability_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_reachability_t)); + aasworld.reachabilitysize = length / sizeof(aas_reachability_t); + if (aasworld.reachabilitysize && !aasworld.reachability) return BLERR_CANNOTREADAASLUMP; + //nodes + offset = LittleLong(header.lumps[AASLUMP_NODES].fileofs); + length = LittleLong(header.lumps[AASLUMP_NODES].filelen); + aasworld.nodes = (aas_node_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_node_t)); + aasworld.numnodes = length / sizeof(aas_node_t); + if (aasworld.numnodes && !aasworld.nodes) return BLERR_CANNOTREADAASLUMP; + //cluster portals + offset = LittleLong(header.lumps[AASLUMP_PORTALS].fileofs); + length = LittleLong(header.lumps[AASLUMP_PORTALS].filelen); + aasworld.portals = (aas_portal_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_portal_t)); + aasworld.numportals = length / sizeof(aas_portal_t); + if (aasworld.numportals && !aasworld.portals) return BLERR_CANNOTREADAASLUMP; + //cluster portal index + offset = LittleLong(header.lumps[AASLUMP_PORTALINDEX].fileofs); + length = LittleLong(header.lumps[AASLUMP_PORTALINDEX].filelen); + aasworld.portalindex = (aas_portalindex_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_portalindex_t)); + aasworld.portalindexsize = length / sizeof(aas_portalindex_t); + if (aasworld.portalindexsize && !aasworld.portalindex) return BLERR_CANNOTREADAASLUMP; + //clusters + offset = LittleLong(header.lumps[AASLUMP_CLUSTERS].fileofs); + length = LittleLong(header.lumps[AASLUMP_CLUSTERS].filelen); + aasworld.clusters = (aas_cluster_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_cluster_t)); + aasworld.numclusters = length / sizeof(aas_cluster_t); + if (aasworld.numclusters && !aasworld.clusters) return BLERR_CANNOTREADAASLUMP; + //swap everything + AAS_SwapAASData(); + //aas file is loaded + aasworld.loaded = qtrue; + //close the file + botimport.FS_FCloseFile(fp); + // +#ifdef AASFILEDEBUG + AAS_FileInfo(); +#endif //AASFILEDEBUG + // + return BLERR_NOERROR; +} //end of the function AAS_LoadAASFile +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +static int AAS_WriteAASLump_offset; + +int AAS_WriteAASLump(fileHandle_t fp, aas_header_t *h, int lumpnum, void *data, int length) +{ + aas_lump_t *lump; + + lump = &h->lumps[lumpnum]; + + lump->fileofs = LittleLong(AAS_WriteAASLump_offset); //LittleLong(ftell(fp)); + lump->filelen = LittleLong(length); + + if (length > 0) + { + botimport.FS_Write(data, length, fp ); + } //end if + + AAS_WriteAASLump_offset += length; + + return qtrue; +} //end of the function AAS_WriteAASLump +//=========================================================================== +// aas data is useless after writing to file because it is byte swapped +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +qboolean AAS_WriteAASFile(char *filename) +{ + aas_header_t header; + fileHandle_t fp; + + botimport.Print(PRT_MESSAGE, "writing %s\n", filename); + //swap the aas data + AAS_SwapAASData(); + //initialize the file header + Com_Memset(&header, 0, sizeof(aas_header_t)); + header.ident = LittleLong(AASID); + header.version = LittleLong(AASVERSION); + header.bspchecksum = LittleLong(aasworld.bspchecksum); + //open a new file + botimport.FS_FOpenFile( filename, &fp, FS_WRITE ); + if (!fp) + { + botimport.Print(PRT_ERROR, "error opening %s\n", filename); + return qfalse; + } //end if + //write the header + botimport.FS_Write(&header, sizeof(aas_header_t), fp); + AAS_WriteAASLump_offset = sizeof(aas_header_t); + //add the data lumps to the file + if (!AAS_WriteAASLump(fp, &header, AASLUMP_BBOXES, aasworld.bboxes, + aasworld.numbboxes * sizeof(aas_bbox_t))) return qfalse; + if (!AAS_WriteAASLump(fp, &header, AASLUMP_VERTEXES, aasworld.vertexes, + aasworld.numvertexes * sizeof(aas_vertex_t))) return qfalse; + if (!AAS_WriteAASLump(fp, &header, AASLUMP_PLANES, aasworld.planes, + aasworld.numplanes * sizeof(aas_plane_t))) return qfalse; + if (!AAS_WriteAASLump(fp, &header, AASLUMP_EDGES, aasworld.edges, + aasworld.numedges * sizeof(aas_edge_t))) return qfalse; + if (!AAS_WriteAASLump(fp, &header, AASLUMP_EDGEINDEX, aasworld.edgeindex, + aasworld.edgeindexsize * sizeof(aas_edgeindex_t))) return qfalse; + if (!AAS_WriteAASLump(fp, &header, AASLUMP_FACES, aasworld.faces, + aasworld.numfaces * sizeof(aas_face_t))) return qfalse; + if (!AAS_WriteAASLump(fp, &header, AASLUMP_FACEINDEX, aasworld.faceindex, + aasworld.faceindexsize * sizeof(aas_faceindex_t))) return qfalse; + if (!AAS_WriteAASLump(fp, &header, AASLUMP_AREAS, aasworld.areas, + aasworld.numareas * sizeof(aas_area_t))) return qfalse; + if (!AAS_WriteAASLump(fp, &header, AASLUMP_AREASETTINGS, aasworld.areasettings, + aasworld.numareasettings * sizeof(aas_areasettings_t))) return qfalse; + if (!AAS_WriteAASLump(fp, &header, AASLUMP_REACHABILITY, aasworld.reachability, + aasworld.reachabilitysize * sizeof(aas_reachability_t))) return qfalse; + if (!AAS_WriteAASLump(fp, &header, AASLUMP_NODES, aasworld.nodes, + aasworld.numnodes * sizeof(aas_node_t))) return qfalse; + if (!AAS_WriteAASLump(fp, &header, AASLUMP_PORTALS, aasworld.portals, + aasworld.numportals * sizeof(aas_portal_t))) return qfalse; + if (!AAS_WriteAASLump(fp, &header, AASLUMP_PORTALINDEX, aasworld.portalindex, + aasworld.portalindexsize * sizeof(aas_portalindex_t))) return qfalse; + if (!AAS_WriteAASLump(fp, &header, AASLUMP_CLUSTERS, aasworld.clusters, + aasworld.numclusters * sizeof(aas_cluster_t))) return qfalse; + //rewrite the header with the added lumps + botimport.FS_Seek(fp, 0, FS_SEEK_SET); + AAS_DData((unsigned char *) &header + 8, sizeof(aas_header_t) - 8); + botimport.FS_Write(&header, sizeof(aas_header_t), fp); + //close the file + botimport.FS_FCloseFile(fp); + return qtrue; +} //end of the function AAS_WriteAASFile diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_file.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_file.h new file mode 100644 index 0000000..ed46c66 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_file.h @@ -0,0 +1,48 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_aas_file.h + * + * desc: AAS + * + * $Archive: /source/code/botlib/be_aas_file.h $ + * $Author: Mrelusive $ + * $Revision: 2 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 10/05/99 3:42p $ + * + *****************************************************************************/ + +#pragma once + +#ifdef AASINTERN +//loads the AAS file with the given name +int AAS_LoadAASFile(char *filename); +//writes an AAS file with the given name +qboolean AAS_WriteAASFile(char *filename); +//dumps the loaded AAS data +void AAS_DumpAASData(void); +//print AAS file information +void AAS_FileInfo(void); +#endif //AASINTERN diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_funcs.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_funcs.h new file mode 100644 index 0000000..d2ddbff --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_funcs.h @@ -0,0 +1,54 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_aas_funcs.h + * + * desc: AAS + * + * $Archive: /source/code/botlib/be_aas_funcs.h $ + * $Author: Mrelusive $ + * $Revision: 2 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 10/05/99 3:42p $ + * + *****************************************************************************/ + +#pragma once + +#ifndef BSPCINCLUDE + +#include "be_aas_main.h" +#include "be_aas_entity.h" +#include "be_aas_sample.h" +#include "be_aas_cluster.h" +#include "be_aas_reach.h" +#include "be_aas_route.h" +#include "be_aas_routealt.h" +#include "be_aas_debug.h" +#include "be_aas_file.h" +#include "be_aas_optimize.h" +#include "be_aas_bsp.h" +#include "be_aas_move.h" + +#endif //BSPCINCLUDE diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_main.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_main.cpp new file mode 100644 index 0000000..60093cb --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_main.cpp @@ -0,0 +1,344 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_aas_main.c + * + * desc: AAS + * + * $Archive: /MissionPack/code/botlib/be_aas_main.c $ + * $Author: Mrelusive $ + * $Revision: 8 $ + * $Modtime: 11/28/00 7:52a $ + * $Date: 11/28/00 7:52a $ + * + *****************************************************************************/ + +#include "qcommon/q_shared.h" +#include "l_memory.h" +#include "l_libvar.h" +#include "l_utils.h" +#include "l_script.h" +#include "l_precomp.h" +#include "l_struct.h" +#include "l_log.h" +#include "aasfile.h" +#include "botlib.h" +#include "be_aas.h" +#include "be_aas_funcs.h" +#include "be_interface.h" +#include "be_aas_def.h" + +aas_t aasworld; + +libvar_t *saveroutingcache; + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void QDECL AAS_Error(char *fmt, ...) +{ + char str[1024]; + va_list arglist; + + va_start(arglist, fmt); + Q_vsnprintf(str, sizeof(str), fmt, arglist); + va_end(arglist); + botimport.Print(PRT_FATAL, "%s", str); +} //end of the function AAS_Error +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_Loaded(void) +{ + return aasworld.loaded; +} //end of the function AAS_Loaded +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_Initialized(void) +{ + return aasworld.initialized; +} //end of the function AAS_Initialized +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_SetInitialized(void) +{ + aasworld.initialized = qtrue; + botimport.Print(PRT_MESSAGE, "AAS initialized.\n"); +#ifdef DEBUG + //create all the routing cache + //AAS_CreateAllRoutingCache(); + // + //AAS_RoutingInfo(); +#endif +} //end of the function AAS_SetInitialized +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_ContinueInit(float time) +{ + //if no AAS file loaded + if (!aasworld.loaded) return; + //if AAS is already initialized + if (aasworld.initialized) return; + //calculate reachability, if not finished return + if (AAS_ContinueInitReachability(time)) return; + //initialize clustering for the new map + AAS_InitClustering(); + //if reachability has been calculated and an AAS file should be written + //or there is a forced data optimization + if (aasworld.savefile || ((int)LibVarGetValue("forcewrite"))) + { + //optimize the AAS data + if ((int)LibVarValue("aasoptimize", "0")) AAS_Optimize(); + //save the AAS file + if (AAS_WriteAASFile(aasworld.filename)) + { + botimport.Print(PRT_MESSAGE, "%s written successfully\n", aasworld.filename); + } //end if + else + { + botimport.Print(PRT_ERROR, "couldn't write %s\n", aasworld.filename); + } //end else + } //end if + //initialize the routing + AAS_InitRouting(); + //at this point AAS is initialized + AAS_SetInitialized(); +} //end of the function AAS_ContinueInit +//=========================================================================== +// called at the start of every frame +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_StartFrame(float time) +{ + aasworld.time = time; + //unlink all entities that were not updated last frame + AAS_UnlinkInvalidEntities(); + //invalidate the entities + AAS_InvalidateEntities(); + //initialize AAS + AAS_ContinueInit(time); + // + aasworld.frameroutingupdates = 0; + // + if (botDeveloper) + { + if (LibVarGetValue("showcacheupdates")) + { + AAS_RoutingInfo(); + LibVarSet("showcacheupdates", "0"); + } //end if + if (LibVarGetValue("showmemoryusage")) + { + PrintUsedMemorySize(); + LibVarSet("showmemoryusage", "0"); + } //end if + if (LibVarGetValue("memorydump")) + { + PrintMemoryLabels(); + LibVarSet("memorydump", "0"); + } //end if + } //end if + // + if (saveroutingcache->value) + { + AAS_WriteRouteCache(); + LibVarSet("saveroutingcache", "0"); + } //end if + // + aasworld.numframes++; + return BLERR_NOERROR; +} //end of the function AAS_StartFrame +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float AAS_Time(void) +{ + return aasworld.time; +} //end of the function AAS_Time +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_ProjectPointOntoVector( vec3_t point, vec3_t vStart, vec3_t vEnd, vec3_t vProj ) +{ + vec3_t pVec, vec; + + VectorSubtract( point, vStart, pVec ); + VectorSubtract( vEnd, vStart, vec ); + VectorNormalize( vec ); + // project onto the directional vector for this segment + VectorMA( vStart, DotProduct( pVec, vec ), vec, vProj ); +} //end of the function AAS_ProjectPointOntoVector +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_LoadFiles(const char *mapname) +{ + int errnum; + char aasfile[MAX_PATH]; +// char bspfile[MAX_PATH]; + + strcpy(aasworld.mapname, mapname); + //NOTE: first reset the entity links into the AAS areas and BSP leaves + // the AAS link heap and BSP link heap are reset after respectively the + // AAS file and BSP file are loaded + AAS_ResetEntityLinks(); + // load bsp info + AAS_LoadBSPFile(); + + //load the aas file + Com_sprintf(aasfile, MAX_PATH, "maps/%s.aas", mapname); + errnum = AAS_LoadAASFile(aasfile); + if (errnum != BLERR_NOERROR) + return errnum; + + botimport.Print(PRT_MESSAGE, "loaded %s\n", aasfile); + strncpy(aasworld.filename, aasfile, MAX_PATH); + return BLERR_NOERROR; +} //end of the function AAS_LoadFiles +//=========================================================================== +// called everytime a map changes +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_LoadMap(const char *mapname) +{ + int errnum; + + //if no mapname is provided then the string indexes are updated + if (!mapname) + { + return 0; + } //end if + // + aasworld.initialized = qfalse; + //NOTE: free the routing caches before loading a new map because + // to free the caches the old number of areas, number of clusters + // and number of areas in a clusters must be available + AAS_FreeRoutingCaches(); + //load the map + errnum = AAS_LoadFiles(mapname); + if (errnum != BLERR_NOERROR) + { + aasworld.loaded = qfalse; + return errnum; + } //end if + // + AAS_InitSettings(); + //initialize the AAS link heap for the new map + AAS_InitAASLinkHeap(); + //initialize the AAS linked entities for the new map + AAS_InitAASLinkedEntities(); + //initialize reachability for the new map + AAS_InitReachability(); + //initialize the alternative routing + AAS_InitAlternativeRouting(); + //everything went ok + return 0; +} //end of the function AAS_LoadMap +//=========================================================================== +// called when the library is first loaded +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_Setup(void) +{ + aasworld.maxclients = (int) LibVarValue("maxclients", "128"); + aasworld.maxentities = (int) LibVarValue("maxentities", "1024"); + // as soon as it's set to 1 the routing cache will be saved + saveroutingcache = LibVar("saveroutingcache", "0"); + //allocate memory for the entities + if (aasworld.entities) FreeMemory(aasworld.entities); + aasworld.entities = (aas_entity_t *) GetClearedHunkMemory(aasworld.maxentities * sizeof(aas_entity_t)); + //invalidate all the entities + AAS_InvalidateEntities(); + //force some recalculations + //LibVarSet("forceclustering", "1"); //force clustering calculation + //LibVarSet("forcereachability", "1"); //force reachability calculation + aasworld.numframes = 0; + return BLERR_NOERROR; +} //end of the function AAS_Setup +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_Shutdown(void) +{ + AAS_ShutdownAlternativeRouting(); + // + AAS_DumpBSPData(); + //free routing caches + AAS_FreeRoutingCaches(); + //free aas link heap + AAS_FreeAASLinkHeap(); + //free aas linked entities + AAS_FreeAASLinkedEntities(); + //free the aas data + AAS_DumpAASData(); + //free the entities + if (aasworld.entities) FreeMemory(aasworld.entities); + //clear the aasworld structure + Com_Memset(&aasworld, 0, sizeof(aas_t)); + //aas has not been initialized + aasworld.initialized = qfalse; + //NOTE: as soon as a new .bsp file is loaded the .bsp file memory is + // freed and reallocated, so there's no need to free that memory here + //print shutdown +// botimport.Print(PRT_MESSAGE, "AAS shutdown.\n"); +} //end of the function AAS_Shutdown diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_main.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_main.h new file mode 100644 index 0000000..861809f --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_main.h @@ -0,0 +1,67 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_aas_main.h + * + * desc: AAS + * + * $Archive: /source/code/botlib/be_aas_main.h $ + * $Author: Mrelusive $ + * $Revision: 2 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 10/05/99 3:42p $ + * + *****************************************************************************/ + +#pragma once + +#include "be_aas_def.h" + +#ifdef AASINTERN + +extern aas_t aasworld; + +//AAS error message +void QDECL AAS_Error(char *fmt, ...) __attribute__ ((format (printf, 1, 2))); +//set AAS initialized +void AAS_SetInitialized(void); +//setup AAS with the given number of entities and clients +int AAS_Setup(void); +//shutdown AAS +void AAS_Shutdown(void); +//start a new map +int AAS_LoadMap(const char *mapname); +//start a new time frame +int AAS_StartFrame(float time); + +#endif //AASINTERN + +//returns true if AAS is initialized +int AAS_Initialized(void); +//returns true if the AAS file is loaded +int AAS_Loaded(void); +//returns the current time +float AAS_Time(void); +// +void AAS_ProjectPointOntoVector( vec3_t point, vec3_t vStart, vec3_t vEnd, vec3_t vProj ); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_move.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_move.cpp new file mode 100644 index 0000000..bcfcd01 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_move.cpp @@ -0,0 +1,1095 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_aas_move.c + * + * desc: AAS + * + * $Archive: /MissionPack/code/botlib/be_aas_move.c $ + * $Author: Ttimo $ + * $Revision: 9 $ + * $Modtime: 4/13/01 4:45p $ + * $Date: 4/13/01 4:45p $ + * + *****************************************************************************/ + +#include "qcommon/q_shared.h" +#include "l_memory.h" +#include "l_script.h" +#include "l_precomp.h" +#include "l_struct.h" +#include "l_libvar.h" +#include "aasfile.h" +#include "botlib.h" +#include "be_aas.h" +#include "be_aas_funcs.h" +#include "be_aas_def.h" + +extern botlib_import_t botimport; + +aas_settings_t aassettings; + +//#define AAS_MOVE_DEBUG + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_DropToFloor(vec3_t origin, vec3_t mins, vec3_t maxs) +{ + vec3_t end; + bsp_trace_t trace; + + VectorCopy(origin, end); + end[2] -= 100; + trace = AAS_Trace(origin, mins, maxs, end, 0, CONTENTS_SOLID); + if (trace.startsolid) return qfalse; + VectorCopy(trace.endpos, origin); + return qtrue; +} //end of the function AAS_DropToFloor +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_InitSettings(void) +{ + aassettings.phys_gravitydirection[0] = 0; + aassettings.phys_gravitydirection[1] = 0; + aassettings.phys_gravitydirection[2] = -1; + aassettings.phys_friction = LibVarValue("phys_friction", "6"); + aassettings.phys_stopspeed = LibVarValue("phys_stopspeed", "100"); + aassettings.phys_gravity = LibVarValue("phys_gravity", "800"); + aassettings.phys_waterfriction = LibVarValue("phys_waterfriction", "1"); + aassettings.phys_watergravity = LibVarValue("phys_watergravity", "400"); + aassettings.phys_maxvelocity = LibVarValue("phys_maxvelocity", "320"); + aassettings.phys_maxwalkvelocity = LibVarValue("phys_maxwalkvelocity", "320"); + aassettings.phys_maxcrouchvelocity = LibVarValue("phys_maxcrouchvelocity", "100"); + aassettings.phys_maxswimvelocity = LibVarValue("phys_maxswimvelocity", "150"); + aassettings.phys_walkaccelerate = LibVarValue("phys_walkaccelerate", "10"); + aassettings.phys_airaccelerate = LibVarValue("phys_airaccelerate", "1"); + aassettings.phys_swimaccelerate = LibVarValue("phys_swimaccelerate", "4"); + aassettings.phys_maxstep = LibVarValue("phys_maxstep", "19"); + aassettings.phys_maxsteepness = LibVarValue("phys_maxsteepness", "0.7"); + aassettings.phys_maxwaterjump = LibVarValue("phys_maxwaterjump", "18"); + aassettings.phys_maxbarrier = LibVarValue("phys_maxbarrier", "33"); + aassettings.phys_jumpvel = LibVarValue("phys_jumpvel", "270"); + aassettings.phys_falldelta5 = LibVarValue("phys_falldelta5", "40"); + aassettings.phys_falldelta10 = LibVarValue("phys_falldelta10", "60"); + aassettings.rs_waterjump = LibVarValue("rs_waterjump", "400"); + aassettings.rs_teleport = LibVarValue("rs_teleport", "50"); + aassettings.rs_barrierjump = LibVarValue("rs_barrierjump", "100"); + aassettings.rs_startcrouch = LibVarValue("rs_startcrouch", "300"); + aassettings.rs_startgrapple = LibVarValue("rs_startgrapple", "500"); + aassettings.rs_startwalkoffledge = LibVarValue("rs_startwalkoffledge", "70"); + aassettings.rs_startjump = LibVarValue("rs_startjump", "300"); + aassettings.rs_rocketjump = LibVarValue("rs_rocketjump", "500"); + aassettings.rs_bfgjump = LibVarValue("rs_bfgjump", "500"); + aassettings.rs_jumppad = LibVarValue("rs_jumppad", "250"); + aassettings.rs_aircontrolledjumppad = LibVarValue("rs_aircontrolledjumppad", "300"); + aassettings.rs_funcbob = LibVarValue("rs_funcbob", "300"); + aassettings.rs_startelevator = LibVarValue("rs_startelevator", "50"); + aassettings.rs_falldamage5 = LibVarValue("rs_falldamage5", "300"); + aassettings.rs_falldamage10 = LibVarValue("rs_falldamage10", "500"); + aassettings.rs_maxfallheight = LibVarValue("rs_maxfallheight", "0"); + aassettings.rs_maxjumpfallheight = LibVarValue("rs_maxjumpfallheight", "450"); +} //end of the function AAS_InitSettings +//=========================================================================== +// returns qtrue if the bot is against a ladder +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_AgainstLadder(vec3_t origin) +{ + int areanum, i, facenum, side; + vec3_t org; + aas_plane_t *plane; + aas_face_t *face; + aas_area_t *area; + + VectorCopy(origin, org); + areanum = AAS_PointAreaNum(org); + if (!areanum) + { + org[0] += 1; + areanum = AAS_PointAreaNum(org); + if (!areanum) + { + org[1] += 1; + areanum = AAS_PointAreaNum(org); + if (!areanum) + { + org[0] -= 2; + areanum = AAS_PointAreaNum(org); + if (!areanum) + { + org[1] -= 2; + areanum = AAS_PointAreaNum(org); + } //end if + } //end if + } //end if + } //end if + //if in solid... wrrr shouldn't happen + if (!areanum) return qfalse; + //if not in a ladder area + if (!(aasworld.areasettings[areanum].areaflags & AREA_LADDER)) return qfalse; + //if a crouch only area + if (!(aasworld.areasettings[areanum].presencetype & PRESENCE_NORMAL)) return qfalse; + // + area = &aasworld.areas[areanum]; + for (i = 0; i < area->numfaces; i++) + { + facenum = aasworld.faceindex[area->firstface + i]; + side = facenum < 0; + face = &aasworld.faces[abs(facenum)]; + //if the face isn't a ladder face + if (!(face->faceflags & FACE_LADDER)) continue; + //get the plane the face is in + plane = &aasworld.planes[face->planenum ^ side]; + //if the origin is pretty close to the plane + if (fabs(DotProduct(plane->normal, origin) - plane->dist) < 3) + { + if (AAS_PointInsideFace(abs(facenum), origin, 0.1f)) return qtrue; + } //end if + } //end for + return qfalse; +} //end of the function AAS_AgainstLadder +//=========================================================================== +// returns qtrue if the bot is on the ground +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_OnGround(vec3_t origin, int presencetype, int passent) +{ + aas_trace_t trace; + vec3_t end, up = {0, 0, 1}; + aas_plane_t *plane; + + VectorCopy(origin, end); + end[2] -= 10; + + trace = AAS_TraceClientBBox(origin, end, presencetype, passent); + + //if in solid + if (trace.startsolid) return qfalse; + //if nothing hit at all + if (trace.fraction >= 1.0) return qfalse; + //if too far from the hit plane + if (origin[2] - trace.endpos[2] > 10) return qfalse; + //check if the plane isn't too steep + plane = AAS_PlaneFromNum(trace.planenum); + if (DotProduct(plane->normal, up) < aassettings.phys_maxsteepness) return qfalse; + //the bot is on the ground + return qtrue; +} //end of the function AAS_OnGround +//=========================================================================== +// returns qtrue if a bot at the given position is swimming +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_Swimming(vec3_t origin) +{ + vec3_t testorg; + + VectorCopy(origin, testorg); + testorg[2] -= 2; + if (AAS_PointContents(testorg) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER)) return qtrue; + return qfalse; +} //end of the function AAS_Swimming +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +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}; + +void AAS_SetMovedir(vec3_t angles, vec3_t movedir) +{ + if (VectorCompare(angles, VEC_UP)) + { + VectorCopy(MOVEDIR_UP, movedir); + } //end if + else if (VectorCompare(angles, VEC_DOWN)) + { + VectorCopy(MOVEDIR_DOWN, movedir); + } //end else if + else + { + AngleVectors(angles, movedir, NULL, NULL); + } //end else +} //end of the function AAS_SetMovedir +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_JumpReachRunStart(aas_reachability_t *reach, vec3_t runstart) +{ + vec3_t hordir, start, cmdmove; + aas_clientmove_t move; + + // + hordir[0] = reach->start[0] - reach->end[0]; + hordir[1] = reach->start[1] - reach->end[1]; + hordir[2] = 0; + VectorNormalize(hordir); + //start point + VectorCopy(reach->start, start); + start[2] += 1; + //get command movement + VectorScale(hordir, 400, cmdmove); + // + AAS_PredictClientMovement(&move, -1, start, PRESENCE_NORMAL, qtrue, + vec3_origin, cmdmove, 1, 2, 0.1f, + SE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA| + SE_HITGROUNDDAMAGE|SE_GAP, 0, qfalse); + VectorCopy(move.endpos, runstart); + //don't enter slime or lava and don't fall from too high + if (move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE)) + { + VectorCopy(start, runstart); + } //end if +} //end of the function AAS_JumpReachRunStart +//=========================================================================== +// returns the Z velocity when rocket jumping at the origin +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float AAS_WeaponJumpZVelocity(vec3_t origin, float radiusdamage) +{ + vec3_t kvel, v, start, end, forward, right, viewangles, dir; + float mass, knockback, points; + vec3_t rocketoffset = {8, 8, -8}; + vec3_t botmins = {-16, -16, -24}; + vec3_t botmaxs = {16, 16, 32}; + bsp_trace_t bsptrace; + + //look down (90 degrees) + viewangles[PITCH] = 90; + viewangles[YAW] = 0; + viewangles[ROLL] = 0; + //get the start point shooting from + VectorCopy(origin, start); + start[2] += 8; //view offset Z + AngleVectors(viewangles, forward, right, NULL); + start[0] += forward[0] * rocketoffset[0] + right[0] * rocketoffset[1]; + start[1] += forward[1] * rocketoffset[0] + right[1] * rocketoffset[1]; + start[2] += forward[2] * rocketoffset[0] + right[2] * rocketoffset[1] + rocketoffset[2]; + //end point of the trace + VectorMA(start, 500, forward, end); + //trace a line to get the impact point + bsptrace = AAS_Trace(start, NULL, NULL, end, 1, CONTENTS_SOLID); + //calculate the damage the bot will get from the rocket impact + VectorAdd(botmins, botmaxs, v); + VectorMA(origin, 0.5, v, v); + VectorSubtract(bsptrace.endpos, v, v); + // + points = radiusdamage - 0.5 * VectorLength(v); + if (points < 0) points = 0; + //the owner of the rocket gets half the damage + points *= 0.5; + //mass of the bot (p_client.c: PutClientInServer) + mass = 200; + //knockback is the same as the damage points + knockback = points; + //direction of the damage (from trace.endpos to bot origin) + VectorSubtract(origin, bsptrace.endpos, dir); + VectorNormalize(dir); + //damage velocity + VectorScale(dir, 1600.0 * (float)knockback / mass, kvel); //the rocket jump hack... + //rocket impact velocity + jump velocity + return kvel[2] + aassettings.phys_jumpvel; +} //end of the function AAS_WeaponJumpZVelocity +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float AAS_RocketJumpZVelocity(vec3_t origin) +{ + //rocket radius damage is 120 (p_weapon.c: Weapon_RocketLauncher_Fire) + return AAS_WeaponJumpZVelocity(origin, 120); +} //end of the function AAS_RocketJumpZVelocity +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float AAS_BFGJumpZVelocity(vec3_t origin) +{ + //bfg radius damage is 1000 (p_weapon.c: weapon_bfg_fire) + return AAS_WeaponJumpZVelocity(origin, 120); +} //end of the function AAS_BFGJumpZVelocity +//=========================================================================== +// applies ground friction to the given velocity +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_Accelerate(vec3_t velocity, float frametime, vec3_t wishdir, float wishspeed, float accel) +{ + // q2 style + int i; + float addspeed, accelspeed, currentspeed; + + currentspeed = DotProduct(velocity, wishdir); + addspeed = wishspeed - currentspeed; + if (addspeed <= 0) { + return; + } + accelspeed = accel*frametime*wishspeed; + if (accelspeed > addspeed) { + accelspeed = addspeed; + } + + for (i=0 ; i<3 ; i++) { + velocity[i] += accelspeed*wishdir[i]; + } +} //end of the function AAS_Accelerate +//=========================================================================== +// applies ground friction to the given velocity +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_ApplyFriction(vec3_t vel, float friction, float stopspeed, + float frametime) +{ + float speed, control, newspeed; + + //horizontal speed + speed = sqrt(vel[0] * vel[0] + vel[1] * vel[1]); + if (speed) + { + control = speed < stopspeed ? stopspeed : speed; + newspeed = speed - frametime * control * friction; + if (newspeed < 0) newspeed = 0; + newspeed /= speed; + vel[0] *= newspeed; + vel[1] *= newspeed; + } //end if +} //end of the function AAS_ApplyFriction +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_ClipToBBox(aas_trace_t *trace, vec3_t start, vec3_t end, int presencetype, vec3_t mins, vec3_t maxs) +{ + int i, j, side; + float front, back, frac, planedist; + vec3_t bboxmins, bboxmaxs, absmins, absmaxs, dir, mid; + + AAS_PresenceTypeBoundingBox(presencetype, bboxmins, bboxmaxs); + VectorSubtract(mins, bboxmaxs, absmins); + VectorSubtract(maxs, bboxmins, absmaxs); + // + VectorCopy(end, trace->endpos); + trace->fraction = 1; + for (i = 0; i < 3; i++) + { + if (start[i] < absmins[i] && end[i] < absmins[i]) return qfalse; + if (start[i] > absmaxs[i] && end[i] > absmaxs[i]) return qfalse; + } //end for + //check bounding box collision + VectorSubtract(end, start, dir); + frac = 1; + for (i = 0; i < 3; i++) + { + //get plane to test collision with for the current axis direction + if (dir[i] > 0) planedist = absmins[i]; + else planedist = absmaxs[i]; + //calculate collision fraction + front = start[i] - planedist; + back = end[i] - planedist; + frac = front / (front-back); + //check if between bounding planes of next axis + side = i + 1; + if (side > 2) side = 0; + mid[side] = start[side] + dir[side] * frac; + if (mid[side] > absmins[side] && mid[side] < absmaxs[side]) + { + //check if between bounding planes of next axis + side++; + if (side > 2) side = 0; + mid[side] = start[side] + dir[side] * frac; + if (mid[side] > absmins[side] && mid[side] < absmaxs[side]) + { + mid[i] = planedist; + break; + } //end if + } //end if + } //end for + //if there was a collision + if (i != 3) + { + trace->startsolid = qfalse; + trace->fraction = frac; + trace->ent = 0; + trace->planenum = 0; + trace->area = 0; + trace->lastarea = 0; + //trace endpos + for (j = 0; j < 3; j++) trace->endpos[j] = start[j] + dir[j] * frac; + return qtrue; + } //end if + return qfalse; +} //end of the function AAS_ClipToBBox +//=========================================================================== +// predicts the movement +// assumes regular bounding box sizes +// NOTE: out of water jumping is not included +// NOTE: grappling hook is not included +// +// Parameter: origin : origin to start with +// presencetype : presence type to start with +// velocity : velocity to start with +// cmdmove : client command movement +// cmdframes : number of frame cmdmove is valid +// maxframes : maximum number of predicted frames +// frametime : duration of one predicted frame +// stopevent : events that stop the prediction +// stopareanum : stop as soon as entered this area +// Returns: aas_clientmove_t +// Changes Globals: - +//=========================================================================== +int AAS_ClientMovementPrediction(struct aas_clientmove_s *move, + int entnum, vec3_t origin, + int presencetype, int onground, + vec3_t velocity, vec3_t cmdmove, + int cmdframes, + int maxframes, float frametime, + int stopevent, int stopareanum, + vec3_t mins, vec3_t maxs, int visualize) +{ + float phys_friction, phys_stopspeed, phys_gravity, phys_waterfriction; + float phys_watergravity; + float phys_walkaccelerate, phys_airaccelerate, phys_swimaccelerate; + float phys_maxwalkvelocity, phys_maxcrouchvelocity, phys_maxswimvelocity; + float phys_maxstep, phys_maxsteepness, phys_jumpvel, friction; + float gravity, delta, maxvel, wishspeed, accelerate; + //float velchange, newvel; + //int ax; + int n, i, j, pc, step, swimming, crouch, event, jump_frame, areanum; + int areas[20], numareas; + vec3_t points[20]; + vec3_t org, end, feet, start, stepend, lastorg, wishdir; + vec3_t frame_test_vel, old_frame_test_vel, left_test_vel; + vec3_t up = {0, 0, 1}; + aas_plane_t *plane, *plane2; + aas_trace_t trace, steptrace; + + if (frametime <= 0) frametime = 0.1f; + // + phys_friction = aassettings.phys_friction; + phys_stopspeed = aassettings.phys_stopspeed; + phys_gravity = aassettings.phys_gravity; + phys_waterfriction = aassettings.phys_waterfriction; + phys_watergravity = aassettings.phys_watergravity; + phys_maxwalkvelocity = aassettings.phys_maxwalkvelocity;// * frametime; + phys_maxcrouchvelocity = aassettings.phys_maxcrouchvelocity;// * frametime; + phys_maxswimvelocity = aassettings.phys_maxswimvelocity;// * frametime; + phys_walkaccelerate = aassettings.phys_walkaccelerate; + phys_airaccelerate = aassettings.phys_airaccelerate; + phys_swimaccelerate = aassettings.phys_swimaccelerate; + phys_maxstep = aassettings.phys_maxstep; + phys_maxsteepness = aassettings.phys_maxsteepness; + phys_jumpvel = aassettings.phys_jumpvel * frametime; + // + Com_Memset(move, 0, sizeof(aas_clientmove_t)); + Com_Memset(&trace, 0, sizeof(aas_trace_t)); + //start at the current origin + VectorCopy(origin, org); + org[2] += 0.25; + //velocity to test for the first frame + VectorScale(velocity, frametime, frame_test_vel); + // + jump_frame = -1; + //predict a maximum of 'maxframes' ahead + for (n = 0; n < maxframes; n++) + { + swimming = AAS_Swimming(org); + //get gravity depending on swimming or not + gravity = swimming ? phys_watergravity : phys_gravity; + //apply gravity at the START of the frame + frame_test_vel[2] = frame_test_vel[2] - (gravity * 0.1 * frametime); + //if on the ground or swimming + if (onground || swimming) + { + friction = swimming ? phys_friction : phys_waterfriction; + //apply friction + VectorScale(frame_test_vel, 1/frametime, frame_test_vel); + AAS_ApplyFriction(frame_test_vel, friction, phys_stopspeed, frametime); + VectorScale(frame_test_vel, frametime, frame_test_vel); + } //end if + crouch = qfalse; + //apply command movement + if (n < cmdframes) + { + //ax = 0; + maxvel = phys_maxwalkvelocity; + accelerate = phys_airaccelerate; + VectorCopy(cmdmove, wishdir); + if (onground) + { + if (cmdmove[2] < -300) + { + crouch = qtrue; + maxvel = phys_maxcrouchvelocity; + } //end if + //if not swimming and upmove is positive then jump + if (!swimming && cmdmove[2] > 1) + { + //jump velocity minus the gravity for one frame + 5 for safety + frame_test_vel[2] = phys_jumpvel - (gravity * 0.1 * frametime) + 5; + jump_frame = n; + //jumping so air accelerate + accelerate = phys_airaccelerate; + } //end if + else + { + accelerate = phys_walkaccelerate; + } //end else + //ax = 2; + } //end if + if (swimming) + { + maxvel = phys_maxswimvelocity; + accelerate = phys_swimaccelerate; + //ax = 3; + } //end if + else + { + wishdir[2] = 0; + } //end else + // + wishspeed = VectorNormalize(wishdir); + if (wishspeed > maxvel) wishspeed = maxvel; + VectorScale(frame_test_vel, 1/frametime, frame_test_vel); + AAS_Accelerate(frame_test_vel, frametime, wishdir, wishspeed, accelerate); + VectorScale(frame_test_vel, frametime, frame_test_vel); + /* + for (i = 0; i < ax; i++) + { + velchange = (cmdmove[i] * frametime) - frame_test_vel[i]; + if (velchange > phys_maxacceleration) velchange = phys_maxacceleration; + else if (velchange < -phys_maxacceleration) velchange = -phys_maxacceleration; + newvel = frame_test_vel[i] + velchange; + // + if (frame_test_vel[i] <= maxvel && newvel > maxvel) frame_test_vel[i] = maxvel; + else if (frame_test_vel[i] >= -maxvel && newvel < -maxvel) frame_test_vel[i] = -maxvel; + else frame_test_vel[i] = newvel; + } //end for + */ + } //end if + if (crouch) + { + presencetype = PRESENCE_CROUCH; + } //end if + else if (presencetype == PRESENCE_CROUCH) + { + if (AAS_PointPresenceType(org) & PRESENCE_NORMAL) + { + presencetype = PRESENCE_NORMAL; + } //end if + } //end else + //save the current origin + VectorCopy(org, lastorg); + //move linear during one frame + VectorCopy(frame_test_vel, left_test_vel); + j = 0; + do + { + VectorAdd(org, left_test_vel, end); + //trace a bounding box + trace = AAS_TraceClientBBox(org, end, presencetype, entnum); + // +//#ifdef AAS_MOVE_DEBUG + if (visualize) + { + if (trace.startsolid) botimport.Print(PRT_MESSAGE, "PredictMovement: start solid\n"); + AAS_DebugLine(org, trace.endpos, LINECOLOR_RED); + } //end if +//#endif //AAS_MOVE_DEBUG + // + if (stopevent & (SE_ENTERAREA|SE_TOUCHJUMPPAD|SE_TOUCHTELEPORTER|SE_TOUCHCLUSTERPORTAL)) + { + numareas = AAS_TraceAreas(org, trace.endpos, areas, points, 20); + for (i = 0; i < numareas; i++) + { + if (stopevent & SE_ENTERAREA) + { + if (areas[i] == stopareanum) + { + VectorCopy(points[i], move->endpos); + VectorScale(frame_test_vel, 1/frametime, move->velocity); + move->endarea = areas[i]; + move->trace = trace; + move->stopevent = SE_ENTERAREA; + move->presencetype = presencetype; + move->endcontents = 0; + move->time = n * frametime; + move->frames = n; + return qtrue; + } //end if + } //end if + //NOTE: if not the first frame + if ((stopevent & SE_TOUCHJUMPPAD) && n) + { + if (aasworld.areasettings[areas[i]].contents & AREACONTENTS_JUMPPAD) + { + VectorCopy(points[i], move->endpos); + VectorScale(frame_test_vel, 1/frametime, move->velocity); + move->endarea = areas[i]; + move->trace = trace; + move->stopevent = SE_TOUCHJUMPPAD; + move->presencetype = presencetype; + move->endcontents = 0; + move->time = n * frametime; + move->frames = n; + return qtrue; + } //end if + } //end if + if (stopevent & SE_TOUCHTELEPORTER) + { + if (aasworld.areasettings[areas[i]].contents & AREACONTENTS_TELEPORTER) + { + VectorCopy(points[i], move->endpos); + move->endarea = areas[i]; + VectorScale(frame_test_vel, 1/frametime, move->velocity); + move->trace = trace; + move->stopevent = SE_TOUCHTELEPORTER; + move->presencetype = presencetype; + move->endcontents = 0; + move->time = n * frametime; + move->frames = n; + return qtrue; + } //end if + } //end if + if (stopevent & SE_TOUCHCLUSTERPORTAL) + { + if (aasworld.areasettings[areas[i]].contents & AREACONTENTS_CLUSTERPORTAL) + { + VectorCopy(points[i], move->endpos); + move->endarea = areas[i]; + VectorScale(frame_test_vel, 1/frametime, move->velocity); + move->trace = trace; + move->stopevent = SE_TOUCHCLUSTERPORTAL; + move->presencetype = presencetype; + move->endcontents = 0; + move->time = n * frametime; + move->frames = n; + return qtrue; + } //end if + } //end if + } //end for + } //end if + // + if (stopevent & SE_HITBOUNDINGBOX) + { + if (AAS_ClipToBBox(&trace, org, trace.endpos, presencetype, mins, maxs)) + { + VectorCopy(trace.endpos, move->endpos); + move->endarea = AAS_PointAreaNum(move->endpos); + VectorScale(frame_test_vel, 1/frametime, move->velocity); + move->trace = trace; + move->stopevent = SE_HITBOUNDINGBOX; + move->presencetype = presencetype; + move->endcontents = 0; + move->time = n * frametime; + move->frames = n; + return qtrue; + } //end if + } //end if + //move the entity to the trace end point + VectorCopy(trace.endpos, org); + //if there was a collision + if (trace.fraction < 1.0) + { + //get the plane the bounding box collided with + plane = AAS_PlaneFromNum(trace.planenum); + // + if (stopevent & SE_HITGROUNDAREA) + { + if (DotProduct(plane->normal, up) > phys_maxsteepness) + { + VectorCopy(org, start); + start[2] += 0.5; + if (AAS_PointAreaNum(start) == stopareanum) + { + VectorCopy(start, move->endpos); + move->endarea = stopareanum; + VectorScale(frame_test_vel, 1/frametime, move->velocity); + move->trace = trace; + move->stopevent = SE_HITGROUNDAREA; + move->presencetype = presencetype; + move->endcontents = 0; + move->time = n * frametime; + move->frames = n; + return qtrue; + } //end if + } //end if + } //end if + //assume there's no step + step = qfalse; + //if it is a vertical plane and the bot didn't jump recently + if (plane->normal[2] == 0 && (jump_frame < 0 || n - jump_frame > 2)) + { + //check for a step + VectorMA(org, -0.25, plane->normal, start); + VectorCopy(start, stepend); + start[2] += phys_maxstep; + steptrace = AAS_TraceClientBBox(start, stepend, presencetype, entnum); + // + if (!steptrace.startsolid) + { + plane2 = AAS_PlaneFromNum(steptrace.planenum); + if (DotProduct(plane2->normal, up) > phys_maxsteepness) + { + VectorSubtract(end, steptrace.endpos, left_test_vel); + left_test_vel[2] = 0; + frame_test_vel[2] = 0; +//#ifdef AAS_MOVE_DEBUG + if (visualize) + { + if (steptrace.endpos[2] - org[2] > 0.125) + { + VectorCopy(org, start); + start[2] = steptrace.endpos[2]; + AAS_DebugLine(org, start, LINECOLOR_BLUE); + } //end if + } //end if +//#endif //AAS_MOVE_DEBUG + org[2] = steptrace.endpos[2]; + step = qtrue; + } //end if + } //end if + } //end if + // + if (!step) + { + //velocity left to test for this frame is the projection + //of the current test velocity into the hit plane + VectorMA(left_test_vel, -DotProduct(left_test_vel, plane->normal), + plane->normal, left_test_vel); + //store the old velocity for landing check + VectorCopy(frame_test_vel, old_frame_test_vel); + //test velocity for the next frame is the projection + //of the velocity of the current frame into the hit plane + VectorMA(frame_test_vel, -DotProduct(frame_test_vel, plane->normal), + plane->normal, frame_test_vel); + //check for a landing on an almost horizontal floor + if (DotProduct(plane->normal, up) > phys_maxsteepness) + { + onground = qtrue; + } //end if + if (stopevent & SE_HITGROUNDDAMAGE) + { + delta = 0; + if (old_frame_test_vel[2] < 0 && + frame_test_vel[2] > old_frame_test_vel[2] && + !onground) + { + delta = old_frame_test_vel[2]; + } //end if + else if (onground) + { + delta = frame_test_vel[2] - old_frame_test_vel[2]; + } //end else + if (delta) + { + delta = delta * 10; + delta = delta * delta * 0.0001; + if (swimming) delta = 0; + // never take falling damage if completely underwater + /* + if (ent->waterlevel == 3) return; + if (ent->waterlevel == 2) delta *= 0.25; + if (ent->waterlevel == 1) delta *= 0.5; + */ + if (delta > 40) + { + VectorCopy(org, move->endpos); + move->endarea = AAS_PointAreaNum(org); + VectorCopy(frame_test_vel, move->velocity); + move->trace = trace; + move->stopevent = SE_HITGROUNDDAMAGE; + move->presencetype = presencetype; + move->endcontents = 0; + move->time = n * frametime; + move->frames = n; + return qtrue; + } //end if + } //end if + } //end if + } //end if + } //end if + //extra check to prevent endless loop + if (++j > 20) return qfalse; + //while there is a plane hit + } while(trace.fraction < 1.0); + //if going down + if (frame_test_vel[2] <= 10) + { + //check for a liquid at the feet of the bot + VectorCopy(org, feet); + feet[2] -= 22; + pc = AAS_PointContents(feet); + //get event from pc + event = SE_NONE; + if (pc & CONTENTS_LAVA) event |= SE_ENTERLAVA; + if (pc & CONTENTS_SLIME) event |= SE_ENTERSLIME; + if (pc & CONTENTS_WATER) event |= SE_ENTERWATER; + // + areanum = AAS_PointAreaNum(org); + if (aasworld.areasettings[areanum].contents & AREACONTENTS_LAVA) + event |= SE_ENTERLAVA; + if (aasworld.areasettings[areanum].contents & AREACONTENTS_SLIME) + event |= SE_ENTERSLIME; + if (aasworld.areasettings[areanum].contents & AREACONTENTS_WATER) + event |= SE_ENTERWATER; + //if in lava or slime + if (event & stopevent) + { + VectorCopy(org, move->endpos); + move->endarea = areanum; + VectorScale(frame_test_vel, 1/frametime, move->velocity); + move->stopevent = event & stopevent; + move->presencetype = presencetype; + move->endcontents = pc; + move->time = n * frametime; + move->frames = n; + return qtrue; + } //end if + } //end if + // + onground = AAS_OnGround(org, presencetype, entnum); + //if onground and on the ground for at least one whole frame + if (onground) + { + if (stopevent & SE_HITGROUND) + { + VectorCopy(org, move->endpos); + move->endarea = AAS_PointAreaNum(org); + VectorScale(frame_test_vel, 1/frametime, move->velocity); + move->trace = trace; + move->stopevent = SE_HITGROUND; + move->presencetype = presencetype; + move->endcontents = 0; + move->time = n * frametime; + move->frames = n; + return qtrue; + } //end if + } //end if + else if (stopevent & SE_LEAVEGROUND) + { + VectorCopy(org, move->endpos); + move->endarea = AAS_PointAreaNum(org); + VectorScale(frame_test_vel, 1/frametime, move->velocity); + move->trace = trace; + move->stopevent = SE_LEAVEGROUND; + move->presencetype = presencetype; + move->endcontents = 0; + move->time = n * frametime; + move->frames = n; + return qtrue; + } //end else if + else if (stopevent & SE_GAP) + { + aas_trace_t gaptrace; + + VectorCopy(org, start); + VectorCopy(start, end); + end[2] -= 48 + aassettings.phys_maxbarrier; + gaptrace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1); + //if solid is found the bot cannot walk any further and will not fall into a gap + if (!gaptrace.startsolid) + { + //if it is a gap (lower than one step height) + if (gaptrace.endpos[2] < org[2] - aassettings.phys_maxstep - 1) + { + if (!(AAS_PointContents(end) & CONTENTS_WATER)) + { + VectorCopy(lastorg, move->endpos); + move->endarea = AAS_PointAreaNum(lastorg); + VectorScale(frame_test_vel, 1/frametime, move->velocity); + move->trace = trace; + move->stopevent = SE_GAP; + move->presencetype = presencetype; + move->endcontents = 0; + move->time = n * frametime; + move->frames = n; + return qtrue; + } //end if + } //end if + } //end if + } //end else if + } //end for + // + VectorCopy(org, move->endpos); + move->endarea = AAS_PointAreaNum(org); + VectorScale(frame_test_vel, 1/frametime, move->velocity); + move->stopevent = SE_NONE; + move->presencetype = presencetype; + move->endcontents = 0; + move->time = n * frametime; + move->frames = n; + // + return qtrue; +} //end of the function AAS_ClientMovementPrediction +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_PredictClientMovement(struct aas_clientmove_s *move, + int entnum, vec3_t origin, + int presencetype, int onground, + vec3_t velocity, vec3_t cmdmove, + int cmdframes, + int maxframes, float frametime, + int stopevent, int stopareanum, int visualize) +{ + vec3_t mins, maxs; + return AAS_ClientMovementPrediction(move, entnum, origin, presencetype, onground, + velocity, cmdmove, cmdframes, maxframes, + frametime, stopevent, stopareanum, + mins, maxs, visualize); +} //end of the function AAS_PredictClientMovement +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_ClientMovementHitBBox(struct aas_clientmove_s *move, + int entnum, vec3_t origin, + int presencetype, int onground, + vec3_t velocity, vec3_t cmdmove, + int cmdframes, + int maxframes, float frametime, + vec3_t mins, vec3_t maxs, int visualize) +{ + return AAS_ClientMovementPrediction(move, entnum, origin, presencetype, onground, + velocity, cmdmove, cmdframes, maxframes, + frametime, SE_HITBOUNDINGBOX, 0, + mins, maxs, visualize); +} //end of the function AAS_ClientMovementHitBBox +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_TestMovementPrediction(int entnum, vec3_t origin, vec3_t dir) +{ + vec3_t velocity, cmdmove; + aas_clientmove_t move; + + VectorClear(velocity); + if (!AAS_Swimming(origin)) dir[2] = 0; + VectorNormalize(dir); + VectorScale(dir, 400, cmdmove); + cmdmove[2] = 224; + AAS_ClearShownDebugLines(); + AAS_PredictClientMovement(&move, entnum, origin, PRESENCE_NORMAL, qtrue, + velocity, cmdmove, 13, 13, 0.1f, SE_HITGROUND, 0, qtrue);//SE_LEAVEGROUND); + if (move.stopevent & SE_LEAVEGROUND) + { + botimport.Print(PRT_MESSAGE, "leave ground\n"); + } //end if +} //end of the function TestMovementPrediction +//=========================================================================== +// calculates the horizontal velocity needed to perform a jump from start +// to end +// +// Parameter: zvel : z velocity for jump +// start : start position of jump +// end : end position of jump +// *speed : returned speed for jump +// Returns: qfalse if too high or too far from start to end +// Changes Globals: - +//=========================================================================== +int AAS_HorizontalVelocityForJump(float zvel, vec3_t start, vec3_t end, float *velocity) +{ + float phys_gravity, phys_maxvelocity; + float maxjump, height2fall, t, top; + vec3_t dir; + + phys_gravity = aassettings.phys_gravity; + phys_maxvelocity = aassettings.phys_maxvelocity; + + //maximum height a player can jump with the given initial z velocity + maxjump = 0.5 * phys_gravity * (zvel / phys_gravity) * (zvel / phys_gravity); + //top of the parabolic jump + top = start[2] + maxjump; + //height the bot will fall from the top + height2fall = top - end[2]; + //if the goal is to high to jump to + if (height2fall < 0) + { + *velocity = phys_maxvelocity; + return 0; + } //end if + //time a player takes to fall the height + t = sqrt(height2fall / (0.5 * phys_gravity)); + //direction from start to end + VectorSubtract(end, start, dir); + // + if ( (t + zvel / phys_gravity) == 0.0f ) { + *velocity = phys_maxvelocity; + return 0; + } + //calculate horizontal speed + *velocity = sqrt(dir[0]*dir[0] + dir[1]*dir[1]) / (t + zvel / phys_gravity); + //the horizontal speed must be lower than the max speed + if (*velocity > phys_maxvelocity) + { + *velocity = phys_maxvelocity; + return 0; + } //end if + return 1; +} //end of the function AAS_HorizontalVelocityForJump diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_move.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_move.h new file mode 100644 index 0000000..4934340 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_move.h @@ -0,0 +1,78 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_aas_move.h + * + * desc: AAS + * + * $Archive: /source/code/botlib/be_aas_move.h $ + * $Author: Mrelusive $ + * $Revision: 2 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 10/05/99 3:42p $ + * + *****************************************************************************/ + +#pragma once + +#ifdef AASINTERN +extern aas_settings_t aassettings; +#endif //AASINTERN + +//movement prediction +int AAS_PredictClientMovement(struct aas_clientmove_s *move, + int entnum, vec3_t origin, + int presencetype, int onground, + vec3_t velocity, vec3_t cmdmove, + int cmdframes, + int maxframes, float frametime, + int stopevent, int stopareanum, int visualize); +//predict movement until bounding box is hit +int AAS_ClientMovementHitBBox(struct aas_clientmove_s *move, + int entnum, vec3_t origin, + int presencetype, int onground, + vec3_t velocity, vec3_t cmdmove, + int cmdframes, + int maxframes, float frametime, + vec3_t mins, vec3_t maxs, int visualize); +//returns true if on the ground at the given origin +int AAS_OnGround(vec3_t origin, int presencetype, int passent); +//returns true if swimming at the given origin +int AAS_Swimming(vec3_t origin); +//returns the jump reachability run start point +void AAS_JumpReachRunStart(struct aas_reachability_s *reach, vec3_t runstart); +//returns true if against a ladder at the given origin +int AAS_AgainstLadder(vec3_t origin); +//rocket jump Z velocity when rocket-jumping at origin +float AAS_RocketJumpZVelocity(vec3_t origin); +//bfg jump Z velocity when bfg-jumping at origin +float AAS_BFGJumpZVelocity(vec3_t origin); +//calculates the horizontal velocity needed for a jump and returns true this velocity could be calculated +int AAS_HorizontalVelocityForJump(float zvel, vec3_t start, vec3_t end, float *velocity); +// +void AAS_SetMovedir(vec3_t angles, vec3_t movedir); +// +int AAS_DropToFloor(vec3_t origin, vec3_t mins, vec3_t maxs); +// +void AAS_InitSettings(void); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_optimize.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_optimize.cpp new file mode 100644 index 0000000..6a8508b --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_optimize.cpp @@ -0,0 +1,317 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_aas_optimize.c + * + * desc: decreases the .aas file size after the reachabilities have + * been calculated, just dumps all the faces, edges and vertexes + * + * $Archive: /MissionPack/code/botlib/be_aas_optimize.c $ + * $Author: Zaphod $ + * $Revision: 5 $ + * $Modtime: 11/22/00 8:50a $ + * $Date: 11/22/00 8:55a $ + * + *****************************************************************************/ + +#include "qcommon/q_shared.h" +#include "l_libvar.h" +#include "l_memory.h" +#include "l_script.h" +#include "l_precomp.h" +#include "l_struct.h" +#include "aasfile.h" +#include "botlib.h" +#include "be_aas.h" +#include "be_aas_funcs.h" +#include "be_interface.h" +#include "be_aas_def.h" + +typedef struct optimized_s +{ + //vertexes + int numvertexes; + aas_vertex_t *vertexes; + //edges + int numedges; + aas_edge_t *edges; + //edge index + int edgeindexsize; + aas_edgeindex_t *edgeindex; + //faces + int numfaces; + aas_face_t *faces; + //face index + int faceindexsize; + aas_faceindex_t *faceindex; + //convex areas + int numareas; + aas_area_t *areas; + // + int *vertexoptimizeindex; + int *edgeoptimizeindex; + int *faceoptimizeindex; +} optimized_t; + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_KeepEdge(aas_edge_t *edge) +{ + return 1; +} //end of the function AAS_KeepFace +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_OptimizeEdge(optimized_t *optimized, int edgenum) +{ + int i, optedgenum; + aas_edge_t *edge, *optedge; + + edge = &aasworld.edges[abs(edgenum)]; + if (!AAS_KeepEdge(edge)) return 0; + + optedgenum = optimized->edgeoptimizeindex[abs(edgenum)]; + if (optedgenum) + { + //keep the edge reversed sign + if (edgenum > 0) return optedgenum; + else return -optedgenum; + } //end if + + optedge = &optimized->edges[optimized->numedges]; + + for (i = 0; i < 2; i++) + { + if (optimized->vertexoptimizeindex[edge->v[i]]) + { + optedge->v[i] = optimized->vertexoptimizeindex[edge->v[i]]; + } //end if + else + { + VectorCopy(aasworld.vertexes[edge->v[i]], optimized->vertexes[optimized->numvertexes]); + optedge->v[i] = optimized->numvertexes; + optimized->vertexoptimizeindex[edge->v[i]] = optimized->numvertexes; + optimized->numvertexes++; + } //end else + } //end for + optimized->edgeoptimizeindex[abs(edgenum)] = optimized->numedges; + optedgenum = optimized->numedges; + optimized->numedges++; + //keep the edge reversed sign + if (edgenum > 0) return optedgenum; + else return -optedgenum; +} //end of the function AAS_OptimizeEdge +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_KeepFace(aas_face_t *face) +{ + if (!(face->faceflags & FACE_LADDER)) return 0; + else return 1; +} //end of the function AAS_KeepFace +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_OptimizeFace(optimized_t *optimized, int facenum) +{ + int i, edgenum, optedgenum, optfacenum; + aas_face_t *face, *optface; + + face = &aasworld.faces[abs(facenum)]; + if (!AAS_KeepFace(face)) return 0; + + optfacenum = optimized->faceoptimizeindex[abs(facenum)]; + if (optfacenum) + { + //keep the face side sign + if (facenum > 0) return optfacenum; + else return -optfacenum; + } //end if + + optface = &optimized->faces[optimized->numfaces]; + Com_Memcpy(optface, face, sizeof(aas_face_t)); + + optface->numedges = 0; + optface->firstedge = optimized->edgeindexsize; + for (i = 0; i < face->numedges; i++) + { + edgenum = aasworld.edgeindex[face->firstedge + i]; + optedgenum = AAS_OptimizeEdge(optimized, edgenum); + if (optedgenum) + { + optimized->edgeindex[optface->firstedge + optface->numedges] = optedgenum; + optface->numedges++; + optimized->edgeindexsize++; + } //end if + } //end for + optimized->faceoptimizeindex[abs(facenum)] = optimized->numfaces; + optfacenum = optimized->numfaces; + optimized->numfaces++; + //keep the face side sign + if (facenum > 0) return optfacenum; + else return -optfacenum; +} //end of the function AAS_OptimizeFace +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_OptimizeArea(optimized_t *optimized, int areanum) +{ + int i, facenum, optfacenum; + aas_area_t *area, *optarea; + + area = &aasworld.areas[areanum]; + optarea = &optimized->areas[areanum]; + Com_Memcpy(optarea, area, sizeof(aas_area_t)); + + optarea->numfaces = 0; + optarea->firstface = optimized->faceindexsize; + for (i = 0; i < area->numfaces; i++) + { + facenum = aasworld.faceindex[area->firstface + i]; + optfacenum = AAS_OptimizeFace(optimized, facenum); + if (optfacenum) + { + optimized->faceindex[optarea->firstface + optarea->numfaces] = optfacenum; + optarea->numfaces++; + optimized->faceindexsize++; + } //end if + } //end for +} //end of the function AAS_OptimizeArea +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_OptimizeAlloc(optimized_t *optimized) +{ + optimized->vertexes = (aas_vertex_t *) GetClearedMemory(aasworld.numvertexes * sizeof(aas_vertex_t)); + optimized->numvertexes = 0; + optimized->edges = (aas_edge_t *) GetClearedMemory(aasworld.numedges * sizeof(aas_edge_t)); + optimized->numedges = 1; //edge zero is a dummy + optimized->edgeindex = (aas_edgeindex_t *) GetClearedMemory(aasworld.edgeindexsize * sizeof(aas_edgeindex_t)); + optimized->edgeindexsize = 0; + optimized->faces = (aas_face_t *) GetClearedMemory(aasworld.numfaces * sizeof(aas_face_t)); + optimized->numfaces = 1; //face zero is a dummy + optimized->faceindex = (aas_faceindex_t *) GetClearedMemory(aasworld.faceindexsize * sizeof(aas_faceindex_t)); + optimized->faceindexsize = 0; + optimized->areas = (aas_area_t *) GetClearedMemory(aasworld.numareas * sizeof(aas_area_t)); + optimized->numareas = aasworld.numareas; + // + optimized->vertexoptimizeindex = (int *) GetClearedMemory(aasworld.numvertexes * sizeof(int)); + optimized->edgeoptimizeindex = (int *) GetClearedMemory(aasworld.numedges * sizeof(int)); + optimized->faceoptimizeindex = (int *) GetClearedMemory(aasworld.numfaces * sizeof(int)); +} //end of the function AAS_OptimizeAlloc +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_OptimizeStore(optimized_t *optimized) +{ + //store the optimized vertexes + if (aasworld.vertexes) FreeMemory(aasworld.vertexes); + aasworld.vertexes = optimized->vertexes; + aasworld.numvertexes = optimized->numvertexes; + //store the optimized edges + if (aasworld.edges) FreeMemory(aasworld.edges); + aasworld.edges = optimized->edges; + aasworld.numedges = optimized->numedges; + //store the optimized edge index + if (aasworld.edgeindex) FreeMemory(aasworld.edgeindex); + aasworld.edgeindex = optimized->edgeindex; + aasworld.edgeindexsize = optimized->edgeindexsize; + //store the optimized faces + if (aasworld.faces) FreeMemory(aasworld.faces); + aasworld.faces = optimized->faces; + aasworld.numfaces = optimized->numfaces; + //store the optimized face index + if (aasworld.faceindex) FreeMemory(aasworld.faceindex); + aasworld.faceindex = optimized->faceindex; + aasworld.faceindexsize = optimized->faceindexsize; + //store the optimized areas + if (aasworld.areas) FreeMemory(aasworld.areas); + aasworld.areas = optimized->areas; + aasworld.numareas = optimized->numareas; + //free optimize indexes + FreeMemory(optimized->vertexoptimizeindex); + FreeMemory(optimized->edgeoptimizeindex); + FreeMemory(optimized->faceoptimizeindex); +} //end of the function AAS_OptimizeStore +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_Optimize(void) +{ + int i, sign; + optimized_t optimized; + + AAS_OptimizeAlloc(&optimized); + for (i = 1; i < aasworld.numareas; i++) + { + AAS_OptimizeArea(&optimized, i); + } //end for + //reset the reachability face pointers + for (i = 0; i < aasworld.reachabilitysize; i++) + { + //NOTE: for TRAVEL_ELEVATOR the facenum is the model number of + // the elevator + if ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == TRAVEL_ELEVATOR) continue; + //NOTE: for TRAVEL_JUMPPAD the facenum is the Z velocity and the edgenum is the hor velocity + if ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMPPAD) continue; + //NOTE: for TRAVEL_FUNCBOB the facenum and edgenum contain other coded information + if ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == TRAVEL_FUNCBOB) continue; + // + sign = aasworld.reachability[i].facenum; + aasworld.reachability[i].facenum = optimized.faceoptimizeindex[abs(aasworld.reachability[i].facenum)]; + if (sign < 0) aasworld.reachability[i].facenum = -aasworld.reachability[i].facenum; + sign = aasworld.reachability[i].edgenum; + aasworld.reachability[i].edgenum = optimized.edgeoptimizeindex[abs(aasworld.reachability[i].edgenum)]; + if (sign < 0) aasworld.reachability[i].edgenum = -aasworld.reachability[i].edgenum; + } //end for + //store the optimized AAS data into aasworld + AAS_OptimizeStore(&optimized); + //print some nice stuff :) + botimport.Print(PRT_MESSAGE, "AAS data optimized.\n"); +} //end of the function AAS_Optimize diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_optimize.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_optimize.h new file mode 100644 index 0000000..cce146f --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_optimize.h @@ -0,0 +1,39 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_aas_optimize.h + * + * desc: AAS + * + * $Archive: /source/code/botlib/be_aas_optimize.h $ + * $Author: Mrelusive $ + * $Revision: 2 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 10/05/99 3:42p $ + * + *****************************************************************************/ + +#pragma once + +void AAS_Optimize(void); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_reach.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_reach.cpp new file mode 100644 index 0000000..4c393b1 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_reach.cpp @@ -0,0 +1,4535 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_aas_reach.c + * + * desc: reachability calculations + * + * $Archive: /MissionPack/code/botlib/be_aas_reach.c $ + * $Author: Ttimo $ + * $Revision: 12 $ + * $Modtime: 4/21/01 9:15a $ + * $Date: 4/21/01 9:15a $ + * + *****************************************************************************/ + +#include "qcommon/q_shared.h" +#include "l_log.h" +#include "l_memory.h" +#include "l_script.h" +#include "l_libvar.h" +#include "l_precomp.h" +#include "l_struct.h" +#include "aasfile.h" +#include "botlib.h" +#include "be_aas.h" +#include "be_aas_funcs.h" +#include "be_aas_def.h" + +extern int Sys_MilliSeconds(void); + + +extern botlib_import_t botimport; + +//#define REACH_DEBUG + +//NOTE: all travel times are in hundreth of a second +//maximum number of reachability links +#define AAS_MAX_REACHABILITYSIZE 65536 +//number of areas reachability is calculated for each frame +#define REACHABILITYAREASPERCYCLE 15 +//number of units reachability points are placed inside the areas +#define INSIDEUNITS 2 +#define INSIDEUNITS_WALKEND 5 +#define INSIDEUNITS_WALKSTART 0.1 +#define INSIDEUNITS_WATERJUMP 15 +//area flag used for weapon jumping +#define AREA_WEAPONJUMP 8192 //valid area to weapon jump to +//number of reachabilities of each type +int reach_swim; //swim +int reach_equalfloor; //walk on floors with equal height +int reach_step; //step up +int reach_walk; //walk of step +int reach_barrier; //jump up to a barrier +int reach_waterjump; //jump out of water +int reach_walkoffledge; //walk of a ledge +int reach_jump; //jump +int reach_ladder; //climb or descent a ladder +int reach_teleport; //teleport +int reach_elevator; //use an elevator +int reach_funcbob; //use a func bob +int reach_grapple; //grapple hook +int reach_doublejump; //double jump +int reach_rampjump; //ramp jump +int reach_strafejump; //strafe jump (just normal jump but further) +int reach_rocketjump; //rocket jump +int reach_bfgjump; //bfg jump +int reach_jumppad; //jump pads +//if true grapple reachabilities are skipped +int calcgrapplereach; +//linked reachability +typedef struct aas_lreachability_s +{ + int areanum; //number of the reachable area + int facenum; //number of the face towards the other area + int edgenum; //number of the edge towards the other area + vec3_t start; //start point of inter area movement + vec3_t end; //end point of inter area movement + int traveltype; //type of travel required to get to the area + unsigned short int traveltime; //travel time of the inter area movement + // + struct aas_lreachability_s *next; +} aas_lreachability_t; +//temporary reachabilities +aas_lreachability_t *reachabilityheap; //heap with reachabilities +aas_lreachability_t *nextreachability; //next free reachability from the heap +aas_lreachability_t **areareachability; //reachability links for every area +int numlreachabilities; + +//=========================================================================== +// returns the surface area of the given face +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float AAS_FaceArea(aas_face_t *face) +{ + int i, edgenum, side; + float total; + float *v; + vec3_t d1, d2, cross; + aas_edge_t *edge; + + edgenum = aasworld.edgeindex[face->firstedge]; + side = edgenum < 0; + edge = &aasworld.edges[abs(edgenum)]; + v = aasworld.vertexes[edge->v[side]]; + + total = 0; + for (i = 1; i < face->numedges - 1; i++) + { + edgenum = aasworld.edgeindex[face->firstedge + i]; + side = edgenum < 0; + edge = &aasworld.edges[abs(edgenum)]; + VectorSubtract(aasworld.vertexes[edge->v[side]], v, d1); + VectorSubtract(aasworld.vertexes[edge->v[!side]], v, d2); + CrossProduct(d1, d2, cross); + total += 0.5 * VectorLength(cross); + } //end for + return total; +} //end of the function AAS_FaceArea +//=========================================================================== +// returns the volume of an area +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float AAS_AreaVolume(int areanum) +{ + int i, edgenum, facenum, side; + float d, a, volume; + vec3_t corner; + aas_plane_t *plane; + aas_edge_t *edge; + aas_face_t *face; + aas_area_t *area; + + area = &aasworld.areas[areanum]; + facenum = aasworld.faceindex[area->firstface]; + face = &aasworld.faces[abs(facenum)]; + edgenum = aasworld.edgeindex[face->firstedge]; + edge = &aasworld.edges[abs(edgenum)]; + // + VectorCopy(aasworld.vertexes[edge->v[0]], corner); + + //make tetrahedrons to all other faces + volume = 0; + for (i = 0; i < area->numfaces; i++) + { + facenum = abs(aasworld.faceindex[area->firstface + i]); + face = &aasworld.faces[facenum]; + side = face->backarea != areanum; + plane = &aasworld.planes[face->planenum ^ side]; + d = -(DotProduct (corner, plane->normal) - plane->dist); + a = AAS_FaceArea(face); + volume += d * a; + } //end for + + volume /= 3; + return volume; +} //end of the function AAS_AreaVolume +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_BestReachableLinkArea(aas_link_t *areas) +{ + aas_link_t *link; + + for (link = areas; link; link = link->next_area) + { + if (AAS_AreaGrounded(link->areanum) || AAS_AreaSwim(link->areanum)) + { + return link->areanum; + } //end if + } //end for + // + for (link = areas; link; link = link->next_area) + { + if (link->areanum) return link->areanum; + //FIXME: this is a bad idea when the reachability is not yet + // calculated when the level items are loaded + if (AAS_AreaReachability(link->areanum)) + return link->areanum; + } //end for + return 0; +} //end of the function AAS_BestReachableLinkArea +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_GetJumpPadInfo(int ent, vec3_t areastart, vec3_t absmins, vec3_t absmaxs, vec3_t velocity) +{ + int modelnum, ent2; + float speed, height, gravity, time, dist, forward; + vec3_t origin, angles, teststart, ent2origin; + aas_trace_t trace; + char model[MAX_EPAIRKEY]; + char target[MAX_EPAIRKEY], targetname[MAX_EPAIRKEY]; + + // + AAS_FloatForBSPEpairKey(ent, "speed", &speed); + if (!speed) speed = 1000; + VectorClear(angles); + //get the mins, maxs and origin of the model + AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY); + if (model[0]) modelnum = atoi(model+1); + else modelnum = 0; + AAS_BSPModelMinsMaxsOrigin(modelnum, angles, absmins, absmaxs, origin); + VectorAdd(origin, absmins, absmins); + VectorAdd(origin, absmaxs, absmaxs); + VectorAdd(absmins, absmaxs, origin); + VectorScale (origin, 0.5, origin); + + //get the start areas + VectorCopy(origin, teststart); + teststart[2] += 64; + trace = AAS_TraceClientBBox(teststart, origin, PRESENCE_CROUCH, -1); + if (trace.startsolid) + { + botimport.Print(PRT_MESSAGE, "trigger_push start solid\n"); + VectorCopy(origin, areastart); + } //end if + else + { + VectorCopy(trace.endpos, areastart); + } //end else + areastart[2] += 0.125; + // + //AAS_DrawPermanentCross(origin, 4, 4); + //get the target entity + AAS_ValueForBSPEpairKey(ent, "target", target, MAX_EPAIRKEY); + for (ent2 = AAS_NextBSPEntity(0); ent2; ent2 = AAS_NextBSPEntity(ent2)) + { + if (!AAS_ValueForBSPEpairKey(ent2, "targetname", targetname, MAX_EPAIRKEY)) continue; + if (!strcmp(targetname, target)) break; + } //end for + if (!ent2) + { + botimport.Print(PRT_MESSAGE, "trigger_push without target entity %s\n", target); + return qfalse; + } //end if + AAS_VectorForBSPEpairKey(ent2, "origin", ent2origin); + // + height = ent2origin[2] - origin[2]; + gravity = aassettings.phys_gravity; + time = sqrt( height / ( 0.5 * gravity ) ); + if (!time) + { + botimport.Print(PRT_MESSAGE, "trigger_push without time\n"); + return qfalse; + } //end if + // set s.origin2 to the push velocity + VectorSubtract ( ent2origin, origin, velocity); + dist = VectorNormalize( velocity); + forward = dist / time; + //FIXME: why multiply by 1.1 + forward *= 1.1f; + VectorScale(velocity, forward, velocity); + velocity[2] = time * gravity; + return qtrue; +} //end of the function AAS_GetJumpPadInfo +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_BestReachableFromJumpPadArea(vec3_t origin, vec3_t mins, vec3_t maxs) +{ + int ent, bot_visualizejumppads, bestareanum; + float volume, bestareavolume; + vec3_t areastart, cmdmove, bboxmins, bboxmaxs; + vec3_t absmins, absmaxs, velocity; + aas_clientmove_t move; + aas_link_t *areas, *link; + char classname[MAX_EPAIRKEY]; + +#ifdef BSPC + bot_visualizejumppads = 0; +#else + bot_visualizejumppads = LibVarValue("bot_visualizejumppads", "0"); +#endif + VectorAdd(origin, mins, bboxmins); + VectorAdd(origin, maxs, bboxmaxs); + for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent)) + { + if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue; + if (strcmp(classname, "trigger_push")) continue; + // + if (!AAS_GetJumpPadInfo(ent, areastart, absmins, absmaxs, velocity)) continue; + //get the areas the jump pad brush is in + areas = AAS_LinkEntityClientBBox(absmins, absmaxs, -1, PRESENCE_CROUCH); + for (link = areas; link; link = link->next_area) + { + if (AAS_AreaJumpPad(link->areanum)) break; + } //end for + if (!link) + { + botimport.Print(PRT_MESSAGE, "trigger_push not in any jump pad area\n"); + AAS_UnlinkFromAreas(areas); + continue; + } //end if + // + //botimport.Print(PRT_MESSAGE, "found a trigger_push with velocity %f %f %f\n", velocity[0], velocity[1], velocity[2]); + // + VectorSet(cmdmove, 0, 0, 0); + Com_Memset(&move, 0, sizeof(aas_clientmove_t)); + AAS_ClientMovementHitBBox(&move, -1, areastart, PRESENCE_NORMAL, qfalse, + velocity, cmdmove, 0, 30, 0.1f, bboxmins, bboxmaxs, bot_visualizejumppads); + if (move.frames < 30) + { + bestareanum = 0; + bestareavolume = 0; + for (link = areas; link; link = link->next_area) + { + if (!AAS_AreaJumpPad(link->areanum)) continue; + volume = AAS_AreaVolume(link->areanum); + if (volume >= bestareavolume) + { + bestareanum = link->areanum; + bestareavolume = volume; + } //end if + } //end if + AAS_UnlinkFromAreas(areas); + return bestareanum; + } //end if + AAS_UnlinkFromAreas(areas); + } //end for + return 0; +} //end of the function AAS_BestReachableFromJumpPadArea +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_BestReachableArea(vec3_t origin, vec3_t mins, vec3_t maxs, vec3_t goalorigin) +{ + int areanum, i, j, k, l; + aas_link_t *areas; + vec3_t absmins, absmaxs; + //vec3_t bbmins, bbmaxs; + vec3_t start, end; + aas_trace_t trace; + + if (!aasworld.loaded) + { + botimport.Print(PRT_ERROR, "AAS_BestReachableArea: aas not loaded\n"); + return 0; + } //end if + //find a point in an area + VectorCopy(origin, start); + areanum = AAS_PointAreaNum(start); + //while no area found fudge around a little + for (i = 0; i < 5 && !areanum; i++) + { + for (j = 0; j < 5 && !areanum; j++) + { + for (k = -1; k <= 1 && !areanum; k++) + { + for (l = -1; l <= 1 && !areanum; l++) + { + VectorCopy(origin, start); + start[0] += (float) j * 4 * k; + start[1] += (float) j * 4 * l; + start[2] += (float) i * 4; + areanum = AAS_PointAreaNum(start); + } //end for + } //end for + } //end for + } //end for + //if an area was found + if (areanum) + { + //drop client bbox down and try again + VectorCopy(start, end); + start[2] += 0.25; + end[2] -= 50; + trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1); + if (!trace.startsolid) + { + areanum = AAS_PointAreaNum(trace.endpos); + VectorCopy(trace.endpos, goalorigin); + //FIXME: cannot enable next line right now because the reachability + // does not have to be calculated when the level items are loaded + //if the origin is in an area with reachability + //if (AAS_AreaReachability(areanum)) return areanum; + if (areanum) return areanum; + } //end if + else + { + //it can very well happen that the AAS_PointAreaNum function tells that + //a point is in an area and that starting an AAS_TraceClientBBox from that + //point will return trace.startsolid qtrue +#if 0 + if (AAS_PointAreaNum(start)) + { + Log_Write("point %f %f %f in area %d but trace startsolid", start[0], start[1], start[2], areanum); + AAS_DrawPermanentCross(start, 4, LINECOLOR_RED); + } //end if + botimport.Print(PRT_MESSAGE, "AAS_BestReachableArea: start solid\n"); +#endif + VectorCopy(start, goalorigin); + return areanum; + } //end else + } //end if + // + //AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, bbmins, bbmaxs); + //NOTE: the goal origin does not have to be in the goal area + // because the bot will have to move towards the item origin anyway + VectorCopy(origin, goalorigin); + // + VectorAdd(origin, mins, absmins); + VectorAdd(origin, maxs, absmaxs); + //add bounding box size + //VectorSubtract(absmins, bbmaxs, absmins); + //VectorSubtract(absmaxs, bbmins, absmaxs); + //link an invalid (-1) entity + areas = AAS_LinkEntityClientBBox(absmins, absmaxs, -1, PRESENCE_CROUCH); + //get the reachable link arae + areanum = AAS_BestReachableLinkArea(areas); + //unlink the invalid entity + AAS_UnlinkFromAreas(areas); + // + return areanum; +} //end of the function AAS_BestReachableArea +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_SetupReachabilityHeap(void) +{ + int i; + + reachabilityheap = (aas_lreachability_t *) GetClearedMemory( + AAS_MAX_REACHABILITYSIZE * sizeof(aas_lreachability_t)); + for (i = 0; i < AAS_MAX_REACHABILITYSIZE-1; i++) + { + reachabilityheap[i].next = &reachabilityheap[i+1]; + } //end for + reachabilityheap[AAS_MAX_REACHABILITYSIZE-1].next = NULL; + nextreachability = reachabilityheap; + numlreachabilities = 0; +} //end of the function AAS_InitReachabilityHeap +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_ShutDownReachabilityHeap(void) +{ + FreeMemory(reachabilityheap); + numlreachabilities = 0; +} //end of the function AAS_ShutDownReachabilityHeap +//=========================================================================== +// returns a reachability link +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +aas_lreachability_t *AAS_AllocReachability(void) +{ + aas_lreachability_t *r; + + if (!nextreachability) return NULL; + //make sure the error message only shows up once + if (!nextreachability->next) AAS_Error("AAS_MAX_REACHABILITYSIZE\n"); + // + r = nextreachability; + nextreachability = nextreachability->next; + numlreachabilities++; + return r; +} //end of the function AAS_AllocReachability +//=========================================================================== +// frees a reachability link +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_FreeReachability(aas_lreachability_t *lreach) +{ + Com_Memset(lreach, 0, sizeof(aas_lreachability_t)); + + lreach->next = nextreachability; + nextreachability = lreach; + numlreachabilities--; +} //end of the function AAS_FreeReachability +//=========================================================================== +// returns qtrue if the area has reachability links +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_AreaReachability(int areanum) +{ + if (areanum < 0 || areanum >= aasworld.numareas) + { + AAS_Error("AAS_AreaReachability: areanum %d out of range\n", areanum); + return 0; + } //end if + return aasworld.areasettings[areanum].numreachableareas; +} //end of the function AAS_AreaReachability +//=========================================================================== +// returns the surface area of all ground faces together of the area +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float AAS_AreaGroundFaceArea(int areanum) +{ + int i; + float total; + aas_area_t *area; + aas_face_t *face; + + total = 0; + area = &aasworld.areas[areanum]; + for (i = 0; i < area->numfaces; i++) + { + face = &aasworld.faces[abs(aasworld.faceindex[area->firstface + i])]; + if (!(face->faceflags & FACE_GROUND)) continue; + // + total += AAS_FaceArea(face); + } //end for + return total; +} //end of the function AAS_AreaGroundFaceArea +//=========================================================================== +// returns the center of a face +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_FaceCenter(int facenum, vec3_t center) +{ + int i; + float scale; + aas_face_t *face; + aas_edge_t *edge; + + face = &aasworld.faces[facenum]; + + VectorClear(center); + for (i = 0; i < face->numedges; i++) + { + edge = &aasworld.edges[abs(aasworld.edgeindex[face->firstedge + i])]; + VectorAdd(center, aasworld.vertexes[edge->v[0]], center); + VectorAdd(center, aasworld.vertexes[edge->v[1]], center); + } //end for + scale = 0.5 / face->numedges; + VectorScale(center, scale, center); +} //end of the function AAS_FaceCenter +//=========================================================================== +// returns the maximum distance a player can fall before being damaged +// damage = deltavelocity*deltavelocity * 0.0001 +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_FallDamageDistance(void) +{ + float maxzvelocity, gravity, t; + + maxzvelocity = sqrt((float)(30 * 10000)); + gravity = aassettings.phys_gravity; + t = maxzvelocity / gravity; + return 0.5 * gravity * t * t; +} //end of the function AAS_FallDamageDistance +//=========================================================================== +// distance = 0.5 * gravity * t * t +// vel = t * gravity +// damage = vel * vel * 0.0001 +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float AAS_FallDelta(float distance) +{ + float t, delta, gravity; + + gravity = aassettings.phys_gravity; + t = sqrt(fabs(distance) * 2 / gravity); + delta = t * gravity; + return delta * delta * 0.0001; +} //end of the function AAS_FallDelta +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float AAS_MaxJumpHeight(float phys_jumpvel) +{ + float phys_gravity; + + phys_gravity = aassettings.phys_gravity; + //maximum height a player can jump with the given initial z velocity + return 0.5 * phys_gravity * (phys_jumpvel / phys_gravity) * (phys_jumpvel / phys_gravity); +} //end of the function MaxJumpHeight +//=========================================================================== +// returns true if a player can only crouch in the area +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float AAS_MaxJumpDistance(float phys_jumpvel) +{ + float phys_gravity, phys_maxvelocity, t; + + phys_gravity = aassettings.phys_gravity; + phys_maxvelocity = aassettings.phys_maxvelocity; + //time a player takes to fall the height + t = sqrt(aassettings.rs_maxjumpfallheight / (0.5 * phys_gravity)); + //maximum distance + return phys_maxvelocity * (t + phys_jumpvel / phys_gravity); +} //end of the function AAS_MaxJumpDistance +//=========================================================================== +// returns true if a player can only crouch in the area +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_AreaCrouch(int areanum) +{ + if (!(aasworld.areasettings[areanum].presencetype & PRESENCE_NORMAL)) return qtrue; + else return qfalse; +} //end of the function AAS_AreaCrouch +//=========================================================================== +// returns qtrue if it is possible to swim in the area +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_AreaSwim(int areanum) +{ + if (aasworld.areasettings[areanum].areaflags & AREA_LIQUID) return qtrue; + else return qfalse; +} //end of the function AAS_AreaSwim +//=========================================================================== +// returns qtrue if the area contains a liquid +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_AreaLiquid(int areanum) +{ + if (aasworld.areasettings[areanum].areaflags & AREA_LIQUID) return qtrue; + else return qfalse; +} //end of the function AAS_AreaLiquid +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_AreaLava(int areanum) +{ + return (aasworld.areasettings[areanum].contents & AREACONTENTS_LAVA); +} //end of the function AAS_AreaLava +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_AreaSlime(int areanum) +{ + return (aasworld.areasettings[areanum].contents & AREACONTENTS_SLIME); +} //end of the function AAS_AreaSlime +//=========================================================================== +// returns qtrue if the area contains ground faces +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_AreaGrounded(int areanum) +{ + return (aasworld.areasettings[areanum].areaflags & AREA_GROUNDED); +} //end of the function AAS_AreaGround +//=========================================================================== +// returns true if the area contains ladder faces +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_AreaLadder(int areanum) +{ + return (aasworld.areasettings[areanum].areaflags & AREA_LADDER); +} //end of the function AAS_AreaLadder +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_AreaJumpPad(int areanum) +{ + return (aasworld.areasettings[areanum].contents & AREACONTENTS_JUMPPAD); +} //end of the function AAS_AreaJumpPad +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_AreaTeleporter(int areanum) +{ + return (aasworld.areasettings[areanum].contents & AREACONTENTS_TELEPORTER); +} //end of the function AAS_AreaTeleporter +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_AreaClusterPortal(int areanum) +{ + return (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL); +} //end of the function AAS_AreaClusterPortal +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_AreaDoNotEnter(int areanum) +{ + return (aasworld.areasettings[areanum].contents & AREACONTENTS_DONOTENTER); +} //end of the function AAS_AreaDoNotEnter +//=========================================================================== +// returns the time it takes perform a barrier jump +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +unsigned short int AAS_BarrierJumpTravelTime(void) +{ + return aassettings.phys_jumpvel / (aassettings.phys_gravity * 0.1); +} //end op the function AAS_BarrierJumpTravelTime +//=========================================================================== +// returns true if there already exists a reachability from area1 to area2 +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +qboolean AAS_ReachabilityExists(int area1num, int area2num) +{ + aas_lreachability_t *r; + + for (r = areareachability[area1num]; r; r = r->next) + { + if (r->areanum == area2num) return qtrue; + } //end for + return qfalse; +} //end of the function AAS_ReachabilityExists +//=========================================================================== +// returns true if there is a solid just after the end point when going +// from start to end +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_NearbySolidOrGap(vec3_t start, vec3_t end) +{ + vec3_t dir, testpoint; + int areanum; + + VectorSubtract(end, start, dir); + dir[2] = 0; + VectorNormalize(dir); + VectorMA(end, 48, dir, testpoint); + + areanum = AAS_PointAreaNum(testpoint); + if (!areanum) + { + testpoint[2] += 16; + areanum = AAS_PointAreaNum(testpoint); + if (!areanum) return qtrue; + } //end if + VectorMA(end, 64, dir, testpoint); + areanum = AAS_PointAreaNum(testpoint); + if (areanum) + { + if (!AAS_AreaSwim(areanum) && !AAS_AreaGrounded(areanum)) return qtrue; + } //end if + return qfalse; +} //end of the function AAS_SolidGapTime +//=========================================================================== +// searches for swim reachabilities between adjacent areas +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_Reachability_Swim(int area1num, int area2num) +{ + int i, j, face1num, face2num, side1; + aas_area_t *area1, *area2; + aas_lreachability_t *lreach; + aas_face_t *face1; + aas_plane_t *plane; + vec3_t start; + + if (!AAS_AreaSwim(area1num) || !AAS_AreaSwim(area2num)) return qfalse; + //if the second area is crouch only + if (!(aasworld.areasettings[area2num].presencetype & PRESENCE_NORMAL)) return qfalse; + + area1 = &aasworld.areas[area1num]; + area2 = &aasworld.areas[area2num]; + + //if the areas are not near anough + for (i = 0; i < 3; i++) + { + if (area1->mins[i] > area2->maxs[i] + 10) return qfalse; + if (area1->maxs[i] < area2->mins[i] - 10) return qfalse; + } //end for + //find a shared face and create a reachability link + for (i = 0; i < area1->numfaces; i++) + { + face1num = aasworld.faceindex[area1->firstface + i]; + side1 = face1num < 0; + face1num = abs(face1num); + // + for (j = 0; j < area2->numfaces; j++) + { + face2num = abs(aasworld.faceindex[area2->firstface + j]); + // + if (face1num == face2num) + { + AAS_FaceCenter(face1num, start); + // + if (AAS_PointContents(start) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER)) + { + // + face1 = &aasworld.faces[face1num]; + //create a new reachability link + lreach = AAS_AllocReachability(); + if (!lreach) return qfalse; + lreach->areanum = area2num; + lreach->facenum = face1num; + lreach->edgenum = 0; + VectorCopy(start, lreach->start); + plane = &aasworld.planes[face1->planenum ^ side1]; + VectorMA(lreach->start, -INSIDEUNITS, plane->normal, lreach->end); + lreach->traveltype = TRAVEL_SWIM; + lreach->traveltime = 1; + //if the volume of the area is rather small + if (AAS_AreaVolume(area2num) < 800) + lreach->traveltime += 200; + //if (!(AAS_PointContents(start) & MASK_WATER)) lreach->traveltime += 500; + //link the reachability + lreach->next = areareachability[area1num]; + areareachability[area1num] = lreach; + reach_swim++; + return qtrue; + } //end if + } //end if + } //end for + } //end for + return qfalse; +} //end of the function AAS_Reachability_Swim +//=========================================================================== +// searches for reachabilities between adjacent areas with equal floor +// heights +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_Reachability_EqualFloorHeight(int area1num, int area2num) +{ + int i, j, edgenum, edgenum1, edgenum2, foundreach, side; + float height, bestheight, length, bestlength; + vec3_t dir, start, end, normal, invgravity, gravitydirection = {0, 0, -1}; + vec3_t edgevec; + aas_area_t *area1, *area2; + aas_face_t *face1, *face2; + aas_edge_t *edge; + aas_plane_t *plane2; + aas_lreachability_t lr, *lreach; + + if (!AAS_AreaGrounded(area1num) || !AAS_AreaGrounded(area2num)) return qfalse; + + area1 = &aasworld.areas[area1num]; + area2 = &aasworld.areas[area2num]; + //if the areas are not near anough in the x-y direction + for (i = 0; i < 2; i++) + { + if (area1->mins[i] > area2->maxs[i] + 10) return qfalse; + if (area1->maxs[i] < area2->mins[i] - 10) return qfalse; + } //end for + //if area 2 is too high above area 1 + if (area2->mins[2] > area1->maxs[2]) return qfalse; + // + VectorCopy(gravitydirection, invgravity); + VectorInverse(invgravity); + // + bestheight = 99999; + bestlength = 0; + foundreach = qfalse; + Com_Memset(&lr, 0, sizeof(aas_lreachability_t)); //make the compiler happy + // + //check if the areas have ground faces with a common edge + //if existing use the lowest common edge for a reachability link + for (i = 0; i < area1->numfaces; i++) + { + face1 = &aasworld.faces[abs(aasworld.faceindex[area1->firstface + i])]; + if (!(face1->faceflags & FACE_GROUND)) continue; + // + for (j = 0; j < area2->numfaces; j++) + { + face2 = &aasworld.faces[abs(aasworld.faceindex[area2->firstface + j])]; + if (!(face2->faceflags & FACE_GROUND)) continue; + //if there is a common edge + for (edgenum1 = 0; edgenum1 < face1->numedges; edgenum1++) + { + for (edgenum2 = 0; edgenum2 < face2->numedges; edgenum2++) + { + if (abs(aasworld.edgeindex[face1->firstedge + edgenum1]) != + abs(aasworld.edgeindex[face2->firstedge + edgenum2])) + continue; + edgenum = aasworld.edgeindex[face1->firstedge + edgenum1]; + side = edgenum < 0; + edge = &aasworld.edges[abs(edgenum)]; + //get the length of the edge + VectorSubtract(aasworld.vertexes[edge->v[1]], + aasworld.vertexes[edge->v[0]], dir); + length = VectorLength(dir); + //get the start point + VectorAdd(aasworld.vertexes[edge->v[0]], + aasworld.vertexes[edge->v[1]], start); + VectorScale(start, 0.5, start); + VectorCopy(start, end); + //get the end point several units inside area2 + //and the start point several units inside area1 + //NOTE: normal is pointing into area2 because the + //face edges are stored counter clockwise + VectorSubtract(aasworld.vertexes[edge->v[side]], + aasworld.vertexes[edge->v[!side]], edgevec); + plane2 = &aasworld.planes[face2->planenum]; + CrossProduct(edgevec, plane2->normal, normal); + VectorNormalize(normal); + // + //VectorMA(start, -1, normal, start); + VectorMA(end, INSIDEUNITS_WALKEND, normal, end); + VectorMA(start, INSIDEUNITS_WALKSTART, normal, start); + end[2] += 0.125; + // + height = DotProduct(invgravity, start); + //NOTE: if there's nearby solid or a gap area after this area + //disabled this crap + //if (AAS_NearbySolidOrGap(start, end)) height += 200; + //NOTE: disabled because it disables reachabilities to very small areas + //if (AAS_PointAreaNum(end) != area2num) continue; + //get the longest lowest edge + if (height < bestheight || + (height < bestheight + 1 && length > bestlength)) + { + bestheight = height; + bestlength = length; + //create a new reachability link + lr.areanum = area2num; + lr.facenum = 0; + lr.edgenum = edgenum; + VectorCopy(start, lr.start); + VectorCopy(end, lr.end); + lr.traveltype = TRAVEL_WALK; + lr.traveltime = 1; + foundreach = qtrue; + } //end if + } //end for + } //end for + } //end for + } //end for + if (foundreach) + { + //create a new reachability link + lreach = AAS_AllocReachability(); + if (!lreach) return qfalse; + lreach->areanum = lr.areanum; + lreach->facenum = lr.facenum; + lreach->edgenum = lr.edgenum; + VectorCopy(lr.start, lreach->start); + VectorCopy(lr.end, lreach->end); + lreach->traveltype = lr.traveltype; + lreach->traveltime = lr.traveltime; + lreach->next = areareachability[area1num]; + areareachability[area1num] = lreach; + //if going into a crouch area + if (!AAS_AreaCrouch(area1num) && AAS_AreaCrouch(area2num)) + { + lreach->traveltime += aassettings.rs_startcrouch; + } //end if + /* + //NOTE: if there's nearby solid or a gap area after this area + if (!AAS_NearbySolidOrGap(lreach->start, lreach->end)) + { + lreach->traveltime += 100; + } //end if + */ + //avoid rather small areas + //if (AAS_AreaGroundFaceArea(lreach->areanum) < 500) lreach->traveltime += 100; + // + reach_equalfloor++; + return qtrue; + } //end if + return qfalse; +} //end of the function AAS_Reachability_EqualFloorHeight +//=========================================================================== +// searches step, barrier, waterjump and walk off ledge reachabilities +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_Reachability_Step_Barrier_WaterJump_WalkOffLedge(int area1num, int area2num) +{ + int i, j, k, l, edge1num, edge2num, areas[10], numareas; + int ground_bestarea2groundedgenum, ground_foundreach; + int water_bestarea2groundedgenum, water_foundreach; + int side1, area1swim, faceside1, groundface1num; + float dist, dist1, dist2, diff, ortdot; + //float invgravitydot; + float x1, x2, x3, x4, y1, y2, y3, y4, tmp, y; + float length, ground_bestlength, water_bestlength, ground_bestdist, water_bestdist; + vec3_t v1, v2, v3, v4, tmpv, p1area1, p1area2, p2area1, p2area2; + vec3_t normal, ort, edgevec, start, end, dir; + vec3_t ground_beststart = {0, 0, 0}, ground_bestend = {0, 0, 0}, ground_bestnormal = {0, 0, 0}; + vec3_t water_beststart = {0, 0, 0}, water_bestend = {0, 0, 0}, water_bestnormal = {0, 0, 0}; + vec3_t invgravity = {0, 0, 1}; + vec3_t testpoint; + aas_plane_t *plane; + aas_area_t *area1, *area2; + aas_face_t *groundface1, *groundface2; + aas_edge_t *edge1, *edge2; + aas_lreachability_t *lreach; + aas_trace_t trace; + + //must be able to walk or swim in the first area + if (!AAS_AreaGrounded(area1num) && !AAS_AreaSwim(area1num)) return qfalse; + // + if (!AAS_AreaGrounded(area2num) && !AAS_AreaSwim(area2num)) return qfalse; + // + area1 = &aasworld.areas[area1num]; + area2 = &aasworld.areas[area2num]; + //if the first area contains a liquid + area1swim = AAS_AreaSwim(area1num); + //if the areas are not near enough in the x-y direction + for (i = 0; i < 2; i++) + { + if (area1->mins[i] > area2->maxs[i] + 10) return qfalse; + if (area1->maxs[i] < area2->mins[i] - 10) return qfalse; + } //end for + // + ground_foundreach = qfalse; + ground_bestdist = 99999; + ground_bestlength = 0; + ground_bestarea2groundedgenum = 0; + // + water_foundreach = qfalse; + water_bestdist = 99999; + water_bestlength = 0; + water_bestarea2groundedgenum = 0; + // + for (i = 0; i < area1->numfaces; i++) + { + groundface1num = aasworld.faceindex[area1->firstface + i]; + faceside1 = groundface1num < 0; + groundface1 = &aasworld.faces[abs(groundface1num)]; + //if this isn't a ground face + if (!(groundface1->faceflags & FACE_GROUND)) + { + //if we can swim in the first area + if (area1swim) + { + //face plane must be more or less horizontal + plane = &aasworld.planes[groundface1->planenum ^ (!faceside1)]; + if (DotProduct(plane->normal, invgravity) < 0.7) continue; + } //end if + else + { + //if we can't swim in the area it must be a ground face + continue; + } //end else + } //end if + // + for (k = 0; k < groundface1->numedges; k++) + { + edge1num = aasworld.edgeindex[groundface1->firstedge + k]; + side1 = (edge1num < 0); + //NOTE: for water faces we must take the side area 1 is + // on into account because the face is shared and doesn't + // have to be oriented correctly + if (!(groundface1->faceflags & FACE_GROUND)) side1 = (side1 == faceside1); + edge1num = abs(edge1num); + edge1 = &aasworld.edges[edge1num]; + //vertexes of the edge + VectorCopy(aasworld.vertexes[edge1->v[!side1]], v1); + VectorCopy(aasworld.vertexes[edge1->v[side1]], v2); + //get a vertical plane through the edge + //NOTE: normal is pointing into area 2 because the + //face edges are stored counter clockwise + VectorSubtract(v2, v1, edgevec); + CrossProduct(edgevec, invgravity, normal); + VectorNormalize(normal); + dist = DotProduct(normal, v1); + //check the faces from the second area + for (j = 0; j < area2->numfaces; j++) + { + groundface2 = &aasworld.faces[abs(aasworld.faceindex[area2->firstface + j])]; + //must be a ground face + if (!(groundface2->faceflags & FACE_GROUND)) continue; + //check the edges of this ground face + for (l = 0; l < groundface2->numedges; l++) + { + edge2num = abs(aasworld.edgeindex[groundface2->firstedge + l]); + edge2 = &aasworld.edges[edge2num]; + //vertexes of the edge + VectorCopy(aasworld.vertexes[edge2->v[0]], v3); + VectorCopy(aasworld.vertexes[edge2->v[1]], v4); + //check the distance between the two points and the vertical plane + //through the edge of area1 + diff = DotProduct(normal, v3) - dist; + if (diff < -0.1 || diff > 0.1) continue; + diff = DotProduct(normal, v4) - dist; + if (diff < -0.1 || diff > 0.1) continue; + // + //project the two ground edges into the step side plane + //and calculate the shortest distance between the two + //edges if they overlap in the direction orthogonal to + //the gravity direction + CrossProduct(invgravity, normal, ort); + //invgravitydot = DotProduct(invgravity, invgravity); + ortdot = DotProduct(ort, ort); + //projection into the step plane + //NOTE: since gravity is vertical this is just the z coordinate + y1 = v1[2];//DotProduct(v1, invgravity) / invgravitydot; + y2 = v2[2];//DotProduct(v2, invgravity) / invgravitydot; + y3 = v3[2];//DotProduct(v3, invgravity) / invgravitydot; + y4 = v4[2];//DotProduct(v4, invgravity) / invgravitydot; + // + x1 = DotProduct(v1, ort) / ortdot; + x2 = DotProduct(v2, ort) / ortdot; + x3 = DotProduct(v3, ort) / ortdot; + x4 = DotProduct(v4, ort) / ortdot; + // + if (x1 > x2) + { + tmp = x1; x1 = x2; x2 = tmp; + tmp = y1; y1 = y2; y2 = tmp; + VectorCopy(v1, tmpv); VectorCopy(v2, v1); VectorCopy(tmpv, v2); + } //end if + if (x3 > x4) + { + tmp = x3; x3 = x4; x4 = tmp; + tmp = y3; y3 = y4; y4 = tmp; + VectorCopy(v3, tmpv); VectorCopy(v4, v3); VectorCopy(tmpv, v4); + } //end if + //if the two projected edge lines have no overlap + if (x2 <= x3 || x4 <= x1) + { +// Log_Write("lines no overlap: from area %d to %d\r\n", area1num, area2num); + continue; + } //end if + //if the two lines fully overlap + if ((x1 - 0.5 < x3 && x4 < x2 + 0.5) && + (x3 - 0.5 < x1 && x2 < x4 + 0.5)) + { + dist1 = y3 - y1; + dist2 = y4 - y2; + VectorCopy(v1, p1area1); + VectorCopy(v2, p2area1); + VectorCopy(v3, p1area2); + VectorCopy(v4, p2area2); + } //end if + else + { + //if the points are equal + if (x1 > x3 - 0.1 && x1 < x3 + 0.1) + { + dist1 = y3 - y1; + VectorCopy(v1, p1area1); + VectorCopy(v3, p1area2); + } //end if + else if (x1 < x3) + { + y = y1 + (x3 - x1) * (y2 - y1) / (x2 - x1); + dist1 = y3 - y; + VectorCopy(v3, p1area1); + p1area1[2] = y; + VectorCopy(v3, p1area2); + } //end if + else + { + y = y3 + (x1 - x3) * (y4 - y3) / (x4 - x3); + dist1 = y - y1; + VectorCopy(v1, p1area1); + VectorCopy(v1, p1area2); + p1area2[2] = y; + } //end if + //if the points are equal + if (x2 > x4 - 0.1 && x2 < x4 + 0.1) + { + dist2 = y4 - y2; + VectorCopy(v2, p2area1); + VectorCopy(v4, p2area2); + } //end if + else if (x2 < x4) + { + y = y3 + (x2 - x3) * (y4 - y3) / (x4 - x3); + dist2 = y - y2; + VectorCopy(v2, p2area1); + VectorCopy(v2, p2area2); + p2area2[2] = y; + } //end if + else + { + y = y1 + (x4 - x1) * (y2 - y1) / (x2 - x1); + dist2 = y4 - y; + VectorCopy(v4, p2area1); + p2area1[2] = y; + VectorCopy(v4, p2area2); + } //end else + } //end else + //if both distances are pretty much equal + //then we take the middle of the points + if (dist1 > dist2 - 1 && dist1 < dist2 + 1) + { + dist = dist1; + VectorAdd(p1area1, p2area1, start); + VectorScale(start, 0.5, start); + VectorAdd(p1area2, p2area2, end); + VectorScale(end, 0.5, end); + } //end if + else if (dist1 < dist2) + { + dist = dist1; + VectorCopy(p1area1, start); + VectorCopy(p1area2, end); + } //end else if + else + { + dist = dist2; + VectorCopy(p2area1, start); + VectorCopy(p2area2, end); + } //end else + //get the length of the overlapping part of the edges of the two areas + VectorSubtract(p2area2, p1area2, dir); + length = VectorLength(dir); + // + if (groundface1->faceflags & FACE_GROUND) + { + //if the vertical distance is smaller + if (dist < ground_bestdist || + //or the vertical distance is pretty much the same + //but the overlapping part of the edges is longer + (dist < ground_bestdist + 1 && length > ground_bestlength)) + { + ground_bestdist = dist; + ground_bestlength = length; + ground_foundreach = qtrue; + ground_bestarea2groundedgenum = edge1num; + //best point towards area1 + VectorCopy(start, ground_beststart); + //normal is pointing into area2 + VectorCopy(normal, ground_bestnormal); + //best point towards area2 + VectorCopy(end, ground_bestend); + } //end if + } //end if + else + { + //if the vertical distance is smaller + if (dist < water_bestdist || + //or the vertical distance is pretty much the same + //but the overlapping part of the edges is longer + (dist < water_bestdist + 1 && length > water_bestlength)) + { + water_bestdist = dist; + water_bestlength = length; + water_foundreach = qtrue; + water_bestarea2groundedgenum = edge1num; + //best point towards area1 + VectorCopy(start, water_beststart); + //normal is pointing into area2 + VectorCopy(normal, water_bestnormal); + //best point towards area2 + VectorCopy(end, water_bestend); + } //end if + } //end else + } //end for + } //end for + } //end for + } //end for + // + // NOTE: swim reachabilities are already filtered out + // + // Steps + // + // --------- + // | step height -> TRAVEL_WALK + //--------| + // + // --------- + //~~~~~~~~| step height and low water -> TRAVEL_WALK + //--------| + // + //~~~~~~~~~~~~~~~~~~ + // --------- + // | step height and low water up to the step -> TRAVEL_WALK + //--------| + // + //check for a step reachability + if (ground_foundreach) + { + //if area2 is higher but lower than the maximum step height + //NOTE: ground_bestdist >= 0 also catches equal floor reachabilities + if (ground_bestdist >= 0 && ground_bestdist < aassettings.phys_maxstep) + { + //create walk reachability from area1 to area2 + lreach = AAS_AllocReachability(); + if (!lreach) return qfalse; + lreach->areanum = area2num; + lreach->facenum = 0; + lreach->edgenum = ground_bestarea2groundedgenum; + VectorMA(ground_beststart, INSIDEUNITS_WALKSTART, ground_bestnormal, lreach->start); + VectorMA(ground_bestend, INSIDEUNITS_WALKEND, ground_bestnormal, lreach->end); + lreach->traveltype = TRAVEL_WALK; + lreach->traveltime = 0;//1; + //if going into a crouch area + if (!AAS_AreaCrouch(area1num) && AAS_AreaCrouch(area2num)) + { + lreach->traveltime += aassettings.rs_startcrouch; + } //end if + lreach->next = areareachability[area1num]; + areareachability[area1num] = lreach; + //NOTE: if there's nearby solid or a gap area after this area + /* + if (!AAS_NearbySolidOrGap(lreach->start, lreach->end)) + { + lreach->traveltime += 100; + } //end if + */ + //avoid rather small areas + //if (AAS_AreaGroundFaceArea(lreach->areanum) < 500) lreach->traveltime += 100; + // + reach_step++; + return qtrue; + } //end if + } //end if + // + // Water Jumps + // + // --------- + // | + //~~~~~~~~| + // | + // | higher than step height and water up to waterjump height -> TRAVEL_WATERJUMP + //--------| + // + //~~~~~~~~~~~~~~~~~~ + // --------- + // | + // | + // | + // | higher than step height and low water up to the step -> TRAVEL_WATERJUMP + //--------| + // + //check for a waterjump reachability + if (water_foundreach) + { + //get a test point a little bit towards area1 + VectorMA(water_bestend, -INSIDEUNITS, water_bestnormal, testpoint); + //go down the maximum waterjump height + testpoint[2] -= aassettings.phys_maxwaterjump; + //if there IS water the sv_maxwaterjump height below the bestend point + if (aasworld.areasettings[AAS_PointAreaNum(testpoint)].areaflags & AREA_LIQUID) + { + //don't create rediculous water jump reachabilities from areas very far below + //the water surface + if (water_bestdist < aassettings.phys_maxwaterjump + 24) + { + //waterjumping from or towards a crouch only area is not possible in Quake2 + if ((aasworld.areasettings[area1num].presencetype & PRESENCE_NORMAL) && + (aasworld.areasettings[area2num].presencetype & PRESENCE_NORMAL)) + { + //create water jump reachability from area1 to area2 + lreach = AAS_AllocReachability(); + if (!lreach) return qfalse; + lreach->areanum = area2num; + lreach->facenum = 0; + lreach->edgenum = water_bestarea2groundedgenum; + VectorCopy(water_beststart, lreach->start); + VectorMA(water_bestend, INSIDEUNITS_WATERJUMP, water_bestnormal, lreach->end); + lreach->traveltype = TRAVEL_WATERJUMP; + lreach->traveltime = aassettings.rs_waterjump; + lreach->next = areareachability[area1num]; + areareachability[area1num] = lreach; + //we've got another waterjump reachability + reach_waterjump++; + return qtrue; + } //end if + } //end if + } //end if + } //end if + // + // Barrier Jumps + // + // --------- + // | + // | + // | + // | higher than step height lower than barrier height -> TRAVEL_BARRIERJUMP + //--------| + // + // --------- + // | + // | + // | + //~~~~~~~~| higher than step height lower than barrier height + //--------| and a thin layer of water in the area to jump from -> TRAVEL_BARRIERJUMP + // + //check for a barrier jump reachability + if (ground_foundreach) + { + //if area2 is higher but lower than the maximum barrier jump height + if (ground_bestdist > 0 && ground_bestdist < aassettings.phys_maxbarrier) + { + //if no water in area1 or a very thin layer of water on the ground + if (!water_foundreach || (ground_bestdist - water_bestdist < 16)) + { + //cannot perform a barrier jump towards or from a crouch area in Quake2 + if (!AAS_AreaCrouch(area1num) && !AAS_AreaCrouch(area2num)) + { + //create barrier jump reachability from area1 to area2 + lreach = AAS_AllocReachability(); + if (!lreach) return qfalse; + lreach->areanum = area2num; + lreach->facenum = 0; + lreach->edgenum = ground_bestarea2groundedgenum; + VectorMA(ground_beststart, INSIDEUNITS_WALKSTART, ground_bestnormal, lreach->start); + VectorMA(ground_bestend, INSIDEUNITS_WALKEND, ground_bestnormal, lreach->end); + lreach->traveltype = TRAVEL_BARRIERJUMP; + lreach->traveltime = aassettings.rs_barrierjump;//AAS_BarrierJumpTravelTime(); + lreach->next = areareachability[area1num]; + areareachability[area1num] = lreach; + //we've got another barrierjump reachability + reach_barrier++; + return qtrue; + } //end if + } //end if + } //end if + } //end if + // + // Walk and Walk Off Ledge + // + //--------| + // | can walk or step back -> TRAVEL_WALK + // --------- + // + //--------| + // | + // | + // | + // | cannot walk/step back -> TRAVEL_WALKOFFLEDGE + // --------- + // + //--------| + // | + // |~~~~~~~~ + // | + // | cannot step back but can waterjump back -> TRAVEL_WALKOFFLEDGE + // --------- FIXME: create TRAVEL_WALK reach?? + // + //check for a walk or walk off ledge reachability + if (ground_foundreach) + { + if (ground_bestdist < 0) + { + if (ground_bestdist > -aassettings.phys_maxstep) + { + //create walk reachability from area1 to area2 + lreach = AAS_AllocReachability(); + if (!lreach) return qfalse; + lreach->areanum = area2num; + lreach->facenum = 0; + lreach->edgenum = ground_bestarea2groundedgenum; + VectorMA(ground_beststart, INSIDEUNITS_WALKSTART, ground_bestnormal, lreach->start); + VectorMA(ground_bestend, INSIDEUNITS_WALKEND, ground_bestnormal, lreach->end); + lreach->traveltype = TRAVEL_WALK; + lreach->traveltime = 1; + lreach->next = areareachability[area1num]; + areareachability[area1num] = lreach; + //we've got another walk reachability + reach_walk++; + return qtrue; + } //end if + // if no maximum fall height set or less than the max + if (!aassettings.rs_maxfallheight || fabs(ground_bestdist) < aassettings.rs_maxfallheight) { + //trace a bounding box vertically to check for solids + VectorMA(ground_bestend, INSIDEUNITS, ground_bestnormal, ground_bestend); + VectorCopy(ground_bestend, start); + start[2] = ground_beststart[2]; + VectorCopy(ground_bestend, end); + end[2] += 4; + trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, -1); + //if no solids were found + if (!trace.startsolid && trace.fraction >= 1.0) + { + //the trace end point must be in the goal area + trace.endpos[2] += 1; + if (AAS_PointAreaNum(trace.endpos) == area2num) + { + //if not going through a cluster portal + numareas = AAS_TraceAreas(start, end, areas, NULL, ARRAY_LEN(areas)); + for (i = 0; i < numareas; i++) + if (AAS_AreaClusterPortal(areas[i])) + break; + if (i >= numareas) + { + //create a walk off ledge reachability from area1 to area2 + lreach = AAS_AllocReachability(); + if (!lreach) return qfalse; + lreach->areanum = area2num; + lreach->facenum = 0; + lreach->edgenum = ground_bestarea2groundedgenum; + VectorCopy(ground_beststart, lreach->start); + VectorCopy(ground_bestend, lreach->end); + lreach->traveltype = TRAVEL_WALKOFFLEDGE; + lreach->traveltime = aassettings.rs_startwalkoffledge + fabs(ground_bestdist) * 50 / aassettings.phys_gravity; + //if falling from too high and not falling into water + if (!AAS_AreaSwim(area2num) && !AAS_AreaJumpPad(area2num)) + { + if (AAS_FallDelta(ground_bestdist) > aassettings.phys_falldelta5) + { + lreach->traveltime += aassettings.rs_falldamage5; + } //end if + if (AAS_FallDelta(ground_bestdist) > aassettings.phys_falldelta10) + { + lreach->traveltime += aassettings.rs_falldamage10; + } //end if + } //end if + lreach->next = areareachability[area1num]; + areareachability[area1num] = lreach; + // + reach_walkoffledge++; + //NOTE: don't create a weapon (rl, bfg) jump reachability here + //because it interferes with other reachabilities + //like the ladder reachability + return qtrue; + } //end if + } //end if + } //end if + } //end if + } //end else + } //end if + return qfalse; +} //end of the function AAS_Reachability_Step_Barrier_WaterJump_WalkOffLedge +//=========================================================================== +// returns the distance between the two vectors +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float VectorDistance(vec3_t v1, vec3_t v2) +{ + vec3_t dir; + + VectorSubtract(v2, v1, dir); + return VectorLength(dir); +} //end of the function VectorDistance +//=========================================================================== +// returns true if the first vector is between the last two vectors +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int VectorBetweenVectors(vec3_t v, vec3_t v1, vec3_t v2) +{ + vec3_t dir1, dir2; + + VectorSubtract(v, v1, dir1); + VectorSubtract(v, v2, dir2); + return (DotProduct(dir1, dir2) <= 0); +} //end of the function VectorBetweenVectors +//=========================================================================== +// returns the mid point between the two vectors +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void VectorMiddle(vec3_t v1, vec3_t v2, vec3_t middle) +{ + VectorAdd(v1, v2, middle); + VectorScale(middle, 0.5, middle); +} //end of the function VectorMiddle +//=========================================================================== +// calculate a range of points closest to each other on both edges +// +// Parameter: beststart1 start of the range of points on edge v1-v2 +// beststart2 end of the range of points on edge v1-v2 +// bestend1 start of the range of points on edge v3-v4 +// bestend2 end of the range of points on edge v3-v4 +// bestdist best distance so far +// Returns: - +// Changes Globals: - +//=========================================================================== +/* +float AAS_ClosestEdgePoints(vec3_t v1, vec3_t v2, vec3_t v3, vec3_t v4, + aas_plane_t *plane1, aas_plane_t *plane2, + vec3_t beststart, vec3_t bestend, float bestdist) +{ + vec3_t dir1, dir2, p1, p2, p3, p4; + float a1, a2, b1, b2, dist; + int founddist; + + //edge vectors + VectorSubtract(v2, v1, dir1); + VectorSubtract(v4, v3, dir2); + //get the horizontal directions + dir1[2] = 0; + dir2[2] = 0; + // + // p1 = point on an edge vector of area2 closest to v1 + // p2 = point on an edge vector of area2 closest to v2 + // p3 = point on an edge vector of area1 closest to v3 + // p4 = point on an edge vector of area1 closest to v4 + // + if (dir2[0]) + { + a2 = dir2[1] / dir2[0]; + b2 = v3[1] - a2 * v3[0]; + //point on the edge vector of area2 closest to v1 + p1[0] = (DotProduct(v1, dir2) - (a2 * dir2[0] + b2 * dir2[1])) / dir2[0]; + p1[1] = a2 * p1[0] + b2; + //point on the edge vector of area2 closest to v2 + p2[0] = (DotProduct(v2, dir2) - (a2 * dir2[0] + b2 * dir2[1])) / dir2[0]; + p2[1] = a2 * p2[0] + b2; + } //end if + else + { + //point on the edge vector of area2 closest to v1 + p1[0] = v3[0]; + p1[1] = v1[1]; + //point on the edge vector of area2 closest to v2 + p2[0] = v3[0]; + p2[1] = v2[1]; + } //end else + // + if (dir1[0]) + { + // + a1 = dir1[1] / dir1[0]; + b1 = v1[1] - a1 * v1[0]; + //point on the edge vector of area1 closest to v3 + p3[0] = (DotProduct(v3, dir1) - (a1 * dir1[0] + b1 * dir1[1])) / dir1[0]; + p3[1] = a1 * p3[0] + b1; + //point on the edge vector of area1 closest to v4 + p4[0] = (DotProduct(v4, dir1) - (a1 * dir1[0] + b1 * dir1[1])) / dir1[0]; + p4[1] = a1 * p4[0] + b1; + } //end if + else + { + //point on the edge vector of area1 closest to v3 + p3[0] = v1[0]; + p3[1] = v3[1]; + //point on the edge vector of area1 closest to v4 + p4[0] = v1[0]; + p4[1] = v4[1]; + } //end else + //start with zero z-coordinates + p1[2] = 0; + p2[2] = 0; + p3[2] = 0; + p4[2] = 0; + //calculate the z-coordinates from the ground planes + p1[2] = (plane2->dist - DotProduct(plane2->normal, p1)) / plane2->normal[2]; + p2[2] = (plane2->dist - DotProduct(plane2->normal, p2)) / plane2->normal[2]; + p3[2] = (plane1->dist - DotProduct(plane1->normal, p3)) / plane1->normal[2]; + p4[2] = (plane1->dist - DotProduct(plane1->normal, p4)) / plane1->normal[2]; + // + founddist = qfalse; + // + if (VectorBetweenVectors(p1, v3, v4)) + { + dist = VectorDistance(v1, p1); + if (dist > bestdist - 0.5 && dist < bestdist + 0.5) + { + VectorMiddle(beststart, v1, beststart); + VectorMiddle(bestend, p1, bestend); + } //end if + else if (dist < bestdist) + { + bestdist = dist; + VectorCopy(v1, beststart); + VectorCopy(p1, bestend); + } //end if + founddist = qtrue; + } //end if + if (VectorBetweenVectors(p2, v3, v4)) + { + dist = VectorDistance(v2, p2); + if (dist > bestdist - 0.5 && dist < bestdist + 0.5) + { + VectorMiddle(beststart, v2, beststart); + VectorMiddle(bestend, p2, bestend); + } //end if + else if (dist < bestdist) + { + bestdist = dist; + VectorCopy(v2, beststart); + VectorCopy(p2, bestend); + } //end if + founddist = qtrue; + } //end else if + if (VectorBetweenVectors(p3, v1, v2)) + { + dist = VectorDistance(v3, p3); + if (dist > bestdist - 0.5 && dist < bestdist + 0.5) + { + VectorMiddle(beststart, p3, beststart); + VectorMiddle(bestend, v3, bestend); + } //end if + else if (dist < bestdist) + { + bestdist = dist; + VectorCopy(p3, beststart); + VectorCopy(v3, bestend); + } //end if + founddist = qtrue; + } //end else if + if (VectorBetweenVectors(p4, v1, v2)) + { + dist = VectorDistance(v4, p4); + if (dist > bestdist - 0.5 && dist < bestdist + 0.5) + { + VectorMiddle(beststart, p4, beststart); + VectorMiddle(bestend, v4, bestend); + } //end if + else if (dist < bestdist) + { + bestdist = dist; + VectorCopy(p4, beststart); + VectorCopy(v4, bestend); + } //end if + founddist = qtrue; + } //end else if + //if no shortest distance was found the shortest distance + //is between one of the vertexes of edge1 and one of edge2 + if (!founddist) + { + dist = VectorDistance(v1, v3); + if (dist < bestdist) + { + bestdist = dist; + VectorCopy(v1, beststart); + VectorCopy(v3, bestend); + } //end if + dist = VectorDistance(v1, v4); + if (dist < bestdist) + { + bestdist = dist; + VectorCopy(v1, beststart); + VectorCopy(v4, bestend); + } //end if + dist = VectorDistance(v2, v3); + if (dist < bestdist) + { + bestdist = dist; + VectorCopy(v2, beststart); + VectorCopy(v3, bestend); + } //end if + dist = VectorDistance(v2, v4); + if (dist < bestdist) + { + bestdist = dist; + VectorCopy(v2, beststart); + VectorCopy(v4, bestend); + } //end if + } //end if + return bestdist; +} //end of the function AAS_ClosestEdgePoints*/ + +float AAS_ClosestEdgePoints(vec3_t v1, vec3_t v2, vec3_t v3, vec3_t v4, + aas_plane_t *plane1, aas_plane_t *plane2, + vec3_t beststart1, vec3_t bestend1, + vec3_t beststart2, vec3_t bestend2, float bestdist) +{ + vec3_t dir1, dir2, p1, p2, p3, p4; + float a1, a2, b1, b2, dist, dist1, dist2; + int founddist; + + //edge vectors + VectorSubtract(v2, v1, dir1); + VectorSubtract(v4, v3, dir2); + //get the horizontal directions + dir1[2] = 0; + dir2[2] = 0; + // + // p1 = point on an edge vector of area2 closest to v1 + // p2 = point on an edge vector of area2 closest to v2 + // p3 = point on an edge vector of area1 closest to v3 + // p4 = point on an edge vector of area1 closest to v4 + // + if (dir2[0]) + { + a2 = dir2[1] / dir2[0]; + b2 = v3[1] - a2 * v3[0]; + //point on the edge vector of area2 closest to v1 + p1[0] = (DotProduct(v1, dir2) - (a2 * dir2[0] + b2 * dir2[1])) / dir2[0]; + p1[1] = a2 * p1[0] + b2; + //point on the edge vector of area2 closest to v2 + p2[0] = (DotProduct(v2, dir2) - (a2 * dir2[0] + b2 * dir2[1])) / dir2[0]; + p2[1] = a2 * p2[0] + b2; + } //end if + else + { + //point on the edge vector of area2 closest to v1 + p1[0] = v3[0]; + p1[1] = v1[1]; + //point on the edge vector of area2 closest to v2 + p2[0] = v3[0]; + p2[1] = v2[1]; + } //end else + // + if (dir1[0]) + { + // + a1 = dir1[1] / dir1[0]; + b1 = v1[1] - a1 * v1[0]; + //point on the edge vector of area1 closest to v3 + p3[0] = (DotProduct(v3, dir1) - (a1 * dir1[0] + b1 * dir1[1])) / dir1[0]; + p3[1] = a1 * p3[0] + b1; + //point on the edge vector of area1 closest to v4 + p4[0] = (DotProduct(v4, dir1) - (a1 * dir1[0] + b1 * dir1[1])) / dir1[0]; + p4[1] = a1 * p4[0] + b1; + } //end if + else + { + //point on the edge vector of area1 closest to v3 + p3[0] = v1[0]; + p3[1] = v3[1]; + //point on the edge vector of area1 closest to v4 + p4[0] = v1[0]; + p4[1] = v4[1]; + } //end else + //start with zero z-coordinates + p1[2] = 0; + p2[2] = 0; + p3[2] = 0; + p4[2] = 0; + //calculate the z-coordinates from the ground planes + p1[2] = (plane2->dist - DotProduct(plane2->normal, p1)) / plane2->normal[2]; + p2[2] = (plane2->dist - DotProduct(plane2->normal, p2)) / plane2->normal[2]; + p3[2] = (plane1->dist - DotProduct(plane1->normal, p3)) / plane1->normal[2]; + p4[2] = (plane1->dist - DotProduct(plane1->normal, p4)) / plane1->normal[2]; + // + founddist = qfalse; + // + if (VectorBetweenVectors(p1, v3, v4)) + { + dist = VectorDistance(v1, p1); + if (dist > bestdist - 0.5 && dist < bestdist + 0.5) + { + dist1 = VectorDistance(beststart1, v1); + dist2 = VectorDistance(beststart2, v1); + if (dist1 > dist2) + { + if (dist1 > VectorDistance(beststart1, beststart2)) VectorCopy(v1, beststart2); + } //end if + else + { + if (dist2 > VectorDistance(beststart1, beststart2)) VectorCopy(v1, beststart1); + } //end else + dist1 = VectorDistance(bestend1, p1); + dist2 = VectorDistance(bestend2, p1); + if (dist1 > dist2) + { + if (dist1 > VectorDistance(bestend1, bestend2)) VectorCopy(p1, bestend2); + } //end if + else + { + if (dist2 > VectorDistance(bestend1, bestend2)) VectorCopy(p1, bestend1); + } //end else + } //end if + else if (dist < bestdist) + { + bestdist = dist; + VectorCopy(v1, beststart1); + VectorCopy(v1, beststart2); + VectorCopy(p1, bestend1); + VectorCopy(p1, bestend2); + } //end if + founddist = qtrue; + } //end if + if (VectorBetweenVectors(p2, v3, v4)) + { + dist = VectorDistance(v2, p2); + if (dist > bestdist - 0.5 && dist < bestdist + 0.5) + { + dist1 = VectorDistance(beststart1, v2); + dist2 = VectorDistance(beststart2, v2); + if (dist1 > dist2) + { + if (dist1 > VectorDistance(beststart1, beststart2)) VectorCopy(v2, beststart2); + } //end if + else + { + if (dist2 > VectorDistance(beststart1, beststart2)) VectorCopy(v2, beststart1); + } //end else + dist1 = VectorDistance(bestend1, p2); + dist2 = VectorDistance(bestend2, p2); + if (dist1 > dist2) + { + if (dist1 > VectorDistance(bestend1, bestend2)) VectorCopy(p2, bestend2); + } //end if + else + { + if (dist2 > VectorDistance(bestend1, bestend2)) VectorCopy(p2, bestend1); + } //end else + } //end if + else if (dist < bestdist) + { + bestdist = dist; + VectorCopy(v2, beststart1); + VectorCopy(v2, beststart2); + VectorCopy(p2, bestend1); + VectorCopy(p2, bestend2); + } //end if + founddist = qtrue; + } //end else if + if (VectorBetweenVectors(p3, v1, v2)) + { + dist = VectorDistance(v3, p3); + if (dist > bestdist - 0.5 && dist < bestdist + 0.5) + { + dist1 = VectorDistance(beststart1, p3); + dist2 = VectorDistance(beststart2, p3); + if (dist1 > dist2) + { + if (dist1 > VectorDistance(beststart1, beststart2)) VectorCopy(p3, beststart2); + } //end if + else + { + if (dist2 > VectorDistance(beststart1, beststart2)) VectorCopy(p3, beststart1); + } //end else + dist1 = VectorDistance(bestend1, v3); + dist2 = VectorDistance(bestend2, v3); + if (dist1 > dist2) + { + if (dist1 > VectorDistance(bestend1, bestend2)) VectorCopy(v3, bestend2); + } //end if + else + { + if (dist2 > VectorDistance(bestend1, bestend2)) VectorCopy(v3, bestend1); + } //end else + } //end if + else if (dist < bestdist) + { + bestdist = dist; + VectorCopy(p3, beststart1); + VectorCopy(p3, beststart2); + VectorCopy(v3, bestend1); + VectorCopy(v3, bestend2); + } //end if + founddist = qtrue; + } //end else if + if (VectorBetweenVectors(p4, v1, v2)) + { + dist = VectorDistance(v4, p4); + if (dist > bestdist - 0.5 && dist < bestdist + 0.5) + { + dist1 = VectorDistance(beststart1, p4); + dist2 = VectorDistance(beststart2, p4); + if (dist1 > dist2) + { + if (dist1 > VectorDistance(beststart1, beststart2)) VectorCopy(p4, beststart2); + } //end if + else + { + if (dist2 > VectorDistance(beststart1, beststart2)) VectorCopy(p4, beststart1); + } //end else + dist1 = VectorDistance(bestend1, v4); + dist2 = VectorDistance(bestend2, v4); + if (dist1 > dist2) + { + if (dist1 > VectorDistance(bestend1, bestend2)) VectorCopy(v4, bestend2); + } //end if + else + { + if (dist2 > VectorDistance(bestend1, bestend2)) VectorCopy(v4, bestend1); + } //end else + } //end if + else if (dist < bestdist) + { + bestdist = dist; + VectorCopy(p4, beststart1); + VectorCopy(p4, beststart2); + VectorCopy(v4, bestend1); + VectorCopy(v4, bestend2); + } //end if + founddist = qtrue; + } //end else if + //if no shortest distance was found the shortest distance + //is between one of the vertexes of edge1 and one of edge2 + if (!founddist) + { + dist = VectorDistance(v1, v3); + if (dist < bestdist) + { + bestdist = dist; + VectorCopy(v1, beststart1); + VectorCopy(v1, beststart2); + VectorCopy(v3, bestend1); + VectorCopy(v3, bestend2); + } //end if + dist = VectorDistance(v1, v4); + if (dist < bestdist) + { + bestdist = dist; + VectorCopy(v1, beststart1); + VectorCopy(v1, beststart2); + VectorCopy(v4, bestend1); + VectorCopy(v4, bestend2); + } //end if + dist = VectorDistance(v2, v3); + if (dist < bestdist) + { + bestdist = dist; + VectorCopy(v2, beststart1); + VectorCopy(v2, beststart2); + VectorCopy(v3, bestend1); + VectorCopy(v3, bestend2); + } //end if + dist = VectorDistance(v2, v4); + if (dist < bestdist) + { + bestdist = dist; + VectorCopy(v2, beststart1); + VectorCopy(v2, beststart2); + VectorCopy(v4, bestend1); + VectorCopy(v4, bestend2); + } //end if + } //end if + return bestdist; +} //end of the function AAS_ClosestEdgePoints +//=========================================================================== +// creates possible jump reachabilities between the areas +// +// The two closest points on the ground of the areas are calculated +// One of the points will be on an edge of a ground face of area1 and +// one on an edge of a ground face of area2. +// If there is a range of closest points the point in the middle of this range +// is selected. +// Between these two points there must be one or more gaps. +// If the gaps exist a potential jump is predicted. +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_Reachability_Jump(int area1num, int area2num) +{ + int i, j, k, l, face1num, face2num, edge1num, edge2num, traveltype; + int stopevent, areas[10], numareas; + float phys_jumpvel, maxjumpdistance, maxjumpheight, height, bestdist, speed; + float *v1, *v2, *v3, *v4; + vec3_t beststart, beststart2, bestend, bestend2; + vec3_t teststart, testend, dir, velocity, cmdmove, up = {0, 0, 1}, sidewards; + aas_area_t *area1, *area2; + aas_face_t *face1, *face2; + aas_edge_t *edge1, *edge2; + aas_plane_t *plane1, *plane2, *plane; + aas_trace_t trace; + aas_clientmove_t move; + aas_lreachability_t *lreach; + + if (!AAS_AreaGrounded(area1num) || !AAS_AreaGrounded(area2num)) return qfalse; + //cannot jump from or to a crouch area + if (AAS_AreaCrouch(area1num) || AAS_AreaCrouch(area2num)) return qfalse; + // + area1 = &aasworld.areas[area1num]; + area2 = &aasworld.areas[area2num]; + // + phys_jumpvel = aassettings.phys_jumpvel; + //maximum distance a player can jump + maxjumpdistance = 2 * AAS_MaxJumpDistance(phys_jumpvel); + //maximum height a player can jump with the given initial z velocity + maxjumpheight = AAS_MaxJumpHeight(phys_jumpvel); + + //if the areas are not near anough in the x-y direction + for (i = 0; i < 2; i++) + { + if (area1->mins[i] > area2->maxs[i] + maxjumpdistance) return qfalse; + if (area1->maxs[i] < area2->mins[i] - maxjumpdistance) return qfalse; + } //end for + //if area2 is way to high to jump up to + if (area2->mins[2] > area1->maxs[2] + maxjumpheight) return qfalse; + // + bestdist = 999999; + // + for (i = 0; i < area1->numfaces; i++) + { + face1num = aasworld.faceindex[area1->firstface + i]; + face1 = &aasworld.faces[abs(face1num)]; + //if not a ground face + if (!(face1->faceflags & FACE_GROUND)) continue; + // + for (j = 0; j < area2->numfaces; j++) + { + face2num = aasworld.faceindex[area2->firstface + j]; + face2 = &aasworld.faces[abs(face2num)]; + //if not a ground face + if (!(face2->faceflags & FACE_GROUND)) continue; + // + for (k = 0; k < face1->numedges; k++) + { + edge1num = abs(aasworld.edgeindex[face1->firstedge + k]); + edge1 = &aasworld.edges[edge1num]; + for (l = 0; l < face2->numedges; l++) + { + edge2num = abs(aasworld.edgeindex[face2->firstedge + l]); + edge2 = &aasworld.edges[edge2num]; + //calculate the minimum distance between the two edges + v1 = aasworld.vertexes[edge1->v[0]]; + v2 = aasworld.vertexes[edge1->v[1]]; + v3 = aasworld.vertexes[edge2->v[0]]; + v4 = aasworld.vertexes[edge2->v[1]]; + //get the ground planes + plane1 = &aasworld.planes[face1->planenum]; + plane2 = &aasworld.planes[face2->planenum]; + // + bestdist = AAS_ClosestEdgePoints(v1, v2, v3, v4, plane1, plane2, + beststart, bestend, + beststart2, bestend2, bestdist); + } //end for + } //end for + } //end for + } //end for + VectorMiddle(beststart, beststart2, beststart); + VectorMiddle(bestend, bestend2, bestend); + if (bestdist > 4 && bestdist < maxjumpdistance) + { +// Log_Write("shortest distance between %d and %d is %f\r\n", area1num, area2num, bestdist); + // if very close and almost no height difference then the bot can walk + if (bestdist <= 48 && fabs(beststart[2] - bestend[2]) < 8) + { + speed = 400; + traveltype = TRAVEL_WALKOFFLEDGE; + } //end if + else if (AAS_HorizontalVelocityForJump(0, beststart, bestend, &speed)) + { + //FIXME: why multiply with 1.2??? + speed *= 1.2f; + traveltype = TRAVEL_WALKOFFLEDGE; + } //end else if + else + { + //get the horizontal speed for the jump, if it isn't possible to calculate this + //speed (the jump is not possible) then there's no jump reachability created + if (!AAS_HorizontalVelocityForJump(phys_jumpvel, beststart, bestend, &speed)) + return qfalse; + speed *= 1.05f; + traveltype = TRAVEL_JUMP; + // + //NOTE: test if the horizontal distance isn't too small + VectorSubtract(bestend, beststart, dir); + dir[2] = 0; + if (VectorLength(dir) < 10) + return qfalse; + } //end if + // + VectorSubtract(bestend, beststart, dir); + VectorNormalize(dir); + VectorMA(beststart, 1, dir, teststart); + // + VectorCopy(teststart, testend); + testend[2] -= 100; + trace = AAS_TraceClientBBox(teststart, testend, PRESENCE_NORMAL, -1); + // + if (trace.startsolid) + return qfalse; + if (trace.fraction < 1) + { + plane = &aasworld.planes[trace.planenum]; + // if the bot can stand on the surface + if (DotProduct(plane->normal, up) >= 0.7) + { + // if no lava or slime below + if (!(AAS_PointContents(trace.endpos) & (CONTENTS_LAVA|CONTENTS_SLIME))) + { + if (teststart[2] - trace.endpos[2] <= aassettings.phys_maxbarrier) + return qfalse; + } //end if + } //end if + } //end if + // + VectorMA(bestend, -1, dir, teststart); + // + VectorCopy(teststart, testend); + testend[2] -= 100; + trace = AAS_TraceClientBBox(teststart, testend, PRESENCE_NORMAL, -1); + // + if (trace.startsolid) + return qfalse; + if (trace.fraction < 1) + { + plane = &aasworld.planes[trace.planenum]; + // if the bot can stand on the surface + if (DotProduct(plane->normal, up) >= 0.7) + { + // if no lava or slime below + if (!(AAS_PointContents(trace.endpos) & (CONTENTS_LAVA|CONTENTS_SLIME))) + { + if (teststart[2] - trace.endpos[2] <= aassettings.phys_maxbarrier) + return qfalse; + } //end if + } //end if + } //end if + // + // get command movement + VectorClear(cmdmove); + if ((traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMP) + cmdmove[2] = aassettings.phys_jumpvel; + else + cmdmove[2] = 0; + // + VectorSubtract(bestend, beststart, dir); + dir[2] = 0; + VectorNormalize(dir); + CrossProduct(dir, up, sidewards); + // + stopevent = SE_HITGROUND|SE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE; + if (!AAS_AreaClusterPortal(area1num) && !AAS_AreaClusterPortal(area2num)) + stopevent |= SE_TOUCHCLUSTERPORTAL; + // + for (i = 0; i < 3; i++) + { + // + if (i == 1) + VectorAdd(testend, sidewards, testend); + else if (i == 2) + VectorSubtract(bestend, sidewards, testend); + else + VectorCopy(bestend, testend); + VectorSubtract(testend, beststart, dir); + dir[2] = 0; + VectorNormalize(dir); + VectorScale(dir, speed, velocity); + // + AAS_PredictClientMovement(&move, -1, beststart, PRESENCE_NORMAL, qtrue, + velocity, cmdmove, 3, 30, 0.1f, + stopevent, 0, qfalse); + // if prediction time wasn't enough to fully predict the movement + if (move.frames >= 30) + return qfalse; + // don't enter slime or lava and don't fall from too high + if (move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA)) + return qfalse; + // never jump or fall through a cluster portal + if (move.stopevent & SE_TOUCHCLUSTERPORTAL) + return qfalse; + //the end position should be in area2, also test a little bit back + //because the predicted jump could have rushed through the area + VectorMA(move.endpos, -64, dir, teststart); + teststart[2] += 1; + numareas = AAS_TraceAreas(move.endpos, teststart, areas, NULL, ARRAY_LEN(areas)); + for (j = 0; j < numareas; j++) + { + if (areas[j] == area2num) + break; + } //end for + if (j < numareas) + break; + } + if (i >= 3) + return qfalse; + // +#ifdef REACH_DEBUG + //create the reachability + Log_Write("jump reachability between %d and %d\r\n", area1num, area2num); +#endif //REACH_DEBUG + //create a new reachability link + lreach = AAS_AllocReachability(); + if (!lreach) return qfalse; + lreach->areanum = area2num; + lreach->facenum = 0; + lreach->edgenum = 0; + VectorCopy(beststart, lreach->start); + VectorCopy(bestend, lreach->end); + lreach->traveltype = traveltype; + + VectorSubtract(bestend, beststart, dir); + height = dir[2]; + dir[2] = 0; + if ((traveltype & TRAVELTYPE_MASK) == TRAVEL_WALKOFFLEDGE && height > VectorLength(dir)) + { + lreach->traveltime = aassettings.rs_startwalkoffledge + height * 50 / aassettings.phys_gravity; + } + else + { + lreach->traveltime = aassettings.rs_startjump + VectorDistance(bestend, beststart) * 240 / aassettings.phys_maxwalkvelocity; + } //end if + // + if (!AAS_AreaJumpPad(area2num)) + { + if (AAS_FallDelta(beststart[2] - bestend[2]) > aassettings.phys_falldelta5) + { + lreach->traveltime += aassettings.rs_falldamage5; + } //end if + else if (AAS_FallDelta(beststart[2] - bestend[2]) > aassettings.phys_falldelta10) + { + lreach->traveltime += aassettings.rs_falldamage10; + } //end if + } //end if + lreach->next = areareachability[area1num]; + areareachability[area1num] = lreach; + // + if ((traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMP) + reach_jump++; + else + reach_walkoffledge++; + } //end if + return qfalse; +} //end of the function AAS_Reachability_Jump +//=========================================================================== +// create a possible ladder reachability from area1 to area2 +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_Reachability_Ladder(int area1num, int area2num) +{ + int i, j, k, l, edge1num, edge2num, sharededgenum = 0, lowestedgenum = 0; + int face1num, face2num, ladderface1num = 0, ladderface2num = 0; + int ladderface1vertical, ladderface2vertical, firstv; + float face1area, face2area, bestface1area = -9999, bestface2area = -9999; + float phys_jumpvel, maxjumpheight; + vec3_t area1point, area2point, v1, v2, up = {0, 0, 1}; + vec3_t mid, lowestpoint = {0, 0}, start, end, sharededgevec, dir; + aas_area_t *area1, *area2; + aas_face_t *face1, *face2, *ladderface1 = NULL, *ladderface2 = NULL; + aas_plane_t *plane1, *plane2; + aas_edge_t *sharededge, *edge1; + aas_lreachability_t *lreach; + aas_trace_t trace; + + if (!AAS_AreaLadder(area1num) || !AAS_AreaLadder(area2num)) return qfalse; + // + phys_jumpvel = aassettings.phys_jumpvel; + //maximum height a player can jump with the given initial z velocity + maxjumpheight = AAS_MaxJumpHeight(phys_jumpvel); + + area1 = &aasworld.areas[area1num]; + area2 = &aasworld.areas[area2num]; + + for (i = 0; i < area1->numfaces; i++) + { + face1num = aasworld.faceindex[area1->firstface + i]; + face1 = &aasworld.faces[abs(face1num)]; + //if not a ladder face + if (!(face1->faceflags & FACE_LADDER)) continue; + // + for (j = 0; j < area2->numfaces; j++) + { + face2num = aasworld.faceindex[area2->firstface + j]; + face2 = &aasworld.faces[abs(face2num)]; + //if not a ladder face + if (!(face2->faceflags & FACE_LADDER)) continue; + //check if the faces share an edge + for (k = 0; k < face1->numedges; k++) + { + edge1num = aasworld.edgeindex[face1->firstedge + k]; + for (l = 0; l < face2->numedges; l++) + { + edge2num = aasworld.edgeindex[face2->firstedge + l]; + if (abs(edge1num) == abs(edge2num)) + { + //get the face with the largest area + face1area = AAS_FaceArea(face1); + face2area = AAS_FaceArea(face2); + if (face1area > bestface1area && face2area > bestface2area) + { + bestface1area = face1area; + bestface2area = face2area; + ladderface1 = face1; + ladderface2 = face2; + ladderface1num = face1num; + ladderface2num = face2num; + sharededgenum = edge1num; + } //end if + break; + } //end if + } //end for + if (l != face2->numedges) break; + } //end for + } //end for + } //end for + // + if (ladderface1 && ladderface2) + { + //get the middle of the shared edge + sharededge = &aasworld.edges[abs(sharededgenum)]; + firstv = sharededgenum < 0; + // + VectorCopy(aasworld.vertexes[sharededge->v[firstv]], v1); + VectorCopy(aasworld.vertexes[sharededge->v[!firstv]], v2); + VectorAdd(v1, v2, area1point); + VectorScale(area1point, 0.5, area1point); + VectorCopy(area1point, area2point); + // + //if the face plane in area 1 is pretty much vertical + plane1 = &aasworld.planes[ladderface1->planenum ^ (ladderface1num < 0)]; + plane2 = &aasworld.planes[ladderface2->planenum ^ (ladderface2num < 0)]; + // + //get the points really into the areas + VectorSubtract(v2, v1, sharededgevec); + CrossProduct(plane1->normal, sharededgevec, dir); + VectorNormalize(dir); + //NOTE: 32 because that's larger than 16 (bot bbox x,y) + VectorMA(area1point, -32, dir, area1point); + VectorMA(area2point, 32, dir, area2point); + // + ladderface1vertical = fabs(DotProduct(plane1->normal, up)) < 0.1; + ladderface2vertical = fabs(DotProduct(plane2->normal, up)) < 0.1; + //there's only reachability between vertical ladder faces + if (!ladderface1vertical && !ladderface2vertical) return qfalse; + //if both vertical ladder faces + if (ladderface1vertical && ladderface2vertical + //and the ladder faces do not make a sharp corner + && DotProduct(plane1->normal, plane2->normal) > 0.7 + //and the shared edge is not too vertical + && fabs(DotProduct(sharededgevec, up)) < 0.7) + { + //create a new reachability link + lreach = AAS_AllocReachability(); + if (!lreach) return qfalse; + lreach->areanum = area2num; + lreach->facenum = ladderface1num; + lreach->edgenum = abs(sharededgenum); + VectorCopy(area1point, lreach->start); + //VectorCopy(area2point, lreach->end); + VectorMA(area2point, -3, plane1->normal, lreach->end); + lreach->traveltype = TRAVEL_LADDER; + lreach->traveltime = 10; + lreach->next = areareachability[area1num]; + areareachability[area1num] = lreach; + // + reach_ladder++; + //create a new reachability link + lreach = AAS_AllocReachability(); + if (!lreach) return qfalse; + lreach->areanum = area1num; + lreach->facenum = ladderface2num; + lreach->edgenum = abs(sharededgenum); + VectorCopy(area2point, lreach->start); + //VectorCopy(area1point, lreach->end); + VectorMA(area1point, -3, plane1->normal, lreach->end); + lreach->traveltype = TRAVEL_LADDER; + lreach->traveltime = 10; + lreach->next = areareachability[area2num]; + areareachability[area2num] = lreach; + // + reach_ladder++; + // + return qtrue; + } //end if + //if the second ladder face is also a ground face + //create ladder end (just ladder) reachability and + //walk off a ladder (ledge) reachability + if (ladderface1vertical && (ladderface2->faceflags & FACE_GROUND)) + { + //create a new reachability link + lreach = AAS_AllocReachability(); + if (!lreach) return qfalse; + lreach->areanum = area2num; + lreach->facenum = ladderface1num; + lreach->edgenum = abs(sharededgenum); + VectorCopy(area1point, lreach->start); + VectorCopy(area2point, lreach->end); + lreach->end[2] += 16; + VectorMA(lreach->end, -15, plane1->normal, lreach->end); + lreach->traveltype = TRAVEL_LADDER; + lreach->traveltime = 10; + lreach->next = areareachability[area1num]; + areareachability[area1num] = lreach; + // + reach_ladder++; + //create a new reachability link + lreach = AAS_AllocReachability(); + if (!lreach) return qfalse; + lreach->areanum = area1num; + lreach->facenum = ladderface2num; + lreach->edgenum = abs(sharededgenum); + VectorCopy(area2point, lreach->start); + VectorCopy(area1point, lreach->end); + lreach->traveltype = TRAVEL_WALKOFFLEDGE; + lreach->traveltime = 10; + lreach->next = areareachability[area2num]; + areareachability[area2num] = lreach; + // + reach_walkoffledge++; + // + return qtrue; + } //end if + // + if (ladderface1vertical) + { + //find lowest edge of the ladder face + lowestpoint[2] = 99999; + for (i = 0; i < ladderface1->numedges; i++) + { + edge1num = abs(aasworld.edgeindex[ladderface1->firstedge + i]); + edge1 = &aasworld.edges[edge1num]; + // + VectorCopy(aasworld.vertexes[edge1->v[0]], v1); + VectorCopy(aasworld.vertexes[edge1->v[1]], v2); + // + VectorAdd(v1, v2, mid); + VectorScale(mid, 0.5, mid); + // + if (mid[2] < lowestpoint[2]) + { + VectorCopy(mid, lowestpoint); + lowestedgenum = edge1num; + } //end if + } //end for + // + plane1 = &aasworld.planes[ladderface1->planenum]; + //trace down in the middle of this edge + VectorMA(lowestpoint, 5, plane1->normal, start); + VectorCopy(start, end); + start[2] += 5; + end[2] -= 100; + //trace without entity collision + trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, -1); + // + // +#ifdef REACH_DEBUG + if (trace.startsolid) + { + Log_Write("trace from area %d started in solid\r\n", area1num); + } //end if +#endif //REACH_DEBUG + // + trace.endpos[2] += 1; + area2num = AAS_PointAreaNum(trace.endpos); + // + area2 = &aasworld.areas[area2num]; + for (i = 0; i < area2->numfaces; i++) + { + face2num = aasworld.faceindex[area2->firstface + i]; + face2 = &aasworld.faces[abs(face2num)]; + // + if (face2->faceflags & FACE_LADDER) + { + plane2 = &aasworld.planes[face2->planenum]; + if (fabs(DotProduct(plane2->normal, up)) < 0.1) break; + } //end if + } //end for + //if from another area without vertical ladder faces + if (i >= area2->numfaces && area2num != area1num && + //the reachabilities shouldn't exist already + !AAS_ReachabilityExists(area1num, area2num) && + !AAS_ReachabilityExists(area2num, area1num)) + { + //if the height is jumpable + if (start[2] - trace.endpos[2] < maxjumpheight) + { + //create a new reachability link + lreach = AAS_AllocReachability(); + if (!lreach) return qfalse; + lreach->areanum = area2num; + lreach->facenum = ladderface1num; + lreach->edgenum = lowestedgenum; + VectorCopy(lowestpoint, lreach->start); + VectorCopy(trace.endpos, lreach->end); + lreach->traveltype = TRAVEL_LADDER; + lreach->traveltime = 10; + lreach->next = areareachability[area1num]; + areareachability[area1num] = lreach; + // + reach_ladder++; + //create a new reachability link + lreach = AAS_AllocReachability(); + if (!lreach) return qfalse; + lreach->areanum = area1num; + lreach->facenum = ladderface1num; + lreach->edgenum = lowestedgenum; + VectorCopy(trace.endpos, lreach->start); + //get the end point a little bit into the ladder + VectorMA(lowestpoint, -5, plane1->normal, lreach->end); + //get the end point a little higher + lreach->end[2] += 10; + lreach->traveltype = TRAVEL_JUMP; + lreach->traveltime = 10; + lreach->next = areareachability[area2num]; + areareachability[area2num] = lreach; + // + reach_jump++; + // + return qtrue; +#ifdef REACH_DEBUG + Log_Write("jump up to ladder reach between %d and %d\r\n", area2num, area1num); +#endif //REACH_DEBUG + } //end if +#ifdef REACH_DEBUG + else Log_Write("jump too high between area %d and %d\r\n", area2num, area1num); +#endif //REACH_DEBUG + } //end if + /*//if slime or lava below the ladder + //try jump reachability from far towards the ladder + if (aasworld.areasettings[area2num].contents & (AREACONTENTS_SLIME + | AREACONTENTS_LAVA)) + { + for (i = 20; i <= 120; i += 20) + { + //trace down in the middle of this edge + VectorMA(lowestpoint, i, plane1->normal, start); + VectorCopy(start, end); + start[2] += 5; + end[2] -= 100; + //trace without entity collision + trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, -1); + // + if (trace.startsolid) break; + trace.endpos[2] += 1; + area2num = AAS_PointAreaNum(trace.endpos); + if (area2num == area1num) continue; + // + if (start[2] - trace.endpos[2] > maxjumpheight) continue; + if (aasworld.areasettings[area2num].contents & (AREACONTENTS_SLIME + | AREACONTENTS_LAVA)) continue; + // + //create a new reachability link + lreach = AAS_AllocReachability(); + if (!lreach) return qfalse; + lreach->areanum = area1num; + lreach->facenum = ladderface1num; + lreach->edgenum = lowestedgenum; + VectorCopy(trace.endpos, lreach->start); + VectorCopy(lowestpoint, lreach->end); + lreach->end[2] += 5; + lreach->traveltype = TRAVEL_JUMP; + lreach->traveltime = 10; + lreach->next = areareachability[area2num]; + areareachability[area2num] = lreach; + // + reach_jump++; + // + Log_Write("jump far to ladder reach between %d and %d\r\n", area2num, area1num); + // + break; + } //end for + } //end if*/ + } //end if + } //end if + return qfalse; +} //end of the function AAS_Reachability_Ladder +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_TravelFlagsForTeam(int ent) +{ + int notteam; + + if (!AAS_IntForBSPEpairKey(ent, "bot_notteam", ¬team)) + return 0; + if (notteam == 1) + return TRAVELFLAG_NOTTEAM1; + if (notteam == 2) + return TRAVELFLAG_NOTTEAM2; + return 0; +} //end of the function AAS_TravelFlagsForTeam +//=========================================================================== +// create possible teleporter reachabilities +// this is very game dependent.... :( +// +// classname = trigger_multiple or trigger_teleport +// target = "t1" +// +// classname = target_teleporter +// targetname = "t1" +// target = "t2" +// +// classname = misc_teleporter_dest +// targetname = "t2" +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_Reachability_Teleport(void) +{ + int area1num, area2num; + char target[MAX_EPAIRKEY], targetname[MAX_EPAIRKEY]; + char classname[MAX_EPAIRKEY], model[MAX_EPAIRKEY]; + int ent, dest; + float angle; + vec3_t origin, destorigin, mins, maxs, end, angles; + vec3_t mid, velocity, cmdmove; + aas_lreachability_t *lreach; + aas_clientmove_t move; + aas_trace_t trace; + aas_link_t *areas, *link; + + for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent)) + { + if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue; + if (!strcmp(classname, "trigger_multiple")) + { + AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY); +//#ifdef REACH_DEBUG + botimport.Print(PRT_MESSAGE, "trigger_multiple model = \"%s\"\n", model); +//#endif REACH_DEBUG + VectorClear(angles); + AAS_BSPModelMinsMaxsOrigin(atoi(model+1), angles, mins, maxs, origin); + // + if (!AAS_ValueForBSPEpairKey(ent, "target", target, MAX_EPAIRKEY)) + { + botimport.Print(PRT_ERROR, "trigger_multiple at %1.0f %1.0f %1.0f without target\n", + origin[0], origin[1], origin[2]); + continue; + } //end if + for (dest = AAS_NextBSPEntity(0); dest; dest = AAS_NextBSPEntity(dest)) + { + if (!AAS_ValueForBSPEpairKey(dest, "classname", classname, MAX_EPAIRKEY)) continue; + if (!strcmp(classname, "target_teleporter")) + { + if (!AAS_ValueForBSPEpairKey(dest, "targetname", targetname, MAX_EPAIRKEY)) continue; + if (!strcmp(targetname, target)) + { + break; + } //end if + } //end if + } //end for + if (!dest) + { + continue; + } //end if + if (!AAS_ValueForBSPEpairKey(dest, "target", target, MAX_EPAIRKEY)) + { + botimport.Print(PRT_ERROR, "target_teleporter without target\n"); + continue; + } //end if + } //end else + else if (!strcmp(classname, "trigger_teleport")) + { + AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY); +//#ifdef REACH_DEBUG + botimport.Print(PRT_MESSAGE, "trigger_teleport model = \"%s\"\n", model); +//#endif REACH_DEBUG + VectorClear(angles); + AAS_BSPModelMinsMaxsOrigin(atoi(model+1), angles, mins, maxs, origin); + // + if (!AAS_ValueForBSPEpairKey(ent, "target", target, MAX_EPAIRKEY)) + { + botimport.Print(PRT_ERROR, "trigger_teleport at %1.0f %1.0f %1.0f without target\n", + origin[0], origin[1], origin[2]); + continue; + } //end if + } //end if + else + { + continue; + } //end else + // + for (dest = AAS_NextBSPEntity(0); dest; dest = AAS_NextBSPEntity(dest)) + { + //classname should be misc_teleporter_dest + //but I've also seen target_position and actually any + //entity could be used... burp + if (AAS_ValueForBSPEpairKey(dest, "targetname", targetname, MAX_EPAIRKEY)) + { + if (!strcmp(targetname, target)) + { + break; + } //end if + } //end if + } //end for + if (!dest) + { + botimport.Print(PRT_ERROR, "teleporter without misc_teleporter_dest (%s)\n", target); + continue; + } //end if + if (!AAS_VectorForBSPEpairKey(dest, "origin", destorigin)) + { + botimport.Print(PRT_ERROR, "teleporter destination (%s) without origin\n", target); + continue; + } //end if + // + area2num = AAS_PointAreaNum(destorigin); + //if not teleported into a teleporter or into a jumppad + if (!AAS_AreaTeleporter(area2num) && !AAS_AreaJumpPad(area2num)) + { + VectorCopy(destorigin, end); + end[2] -= 64; + trace = AAS_TraceClientBBox(destorigin, end, PRESENCE_CROUCH, -1); + if (trace.startsolid) + { + botimport.Print(PRT_ERROR, "teleporter destination (%s) in solid\n", target); + continue; + } //end if + /* + area2num = AAS_PointAreaNum(trace.endpos); + // + if (!AAS_AreaTeleporter(area2num) && + !AAS_AreaJumpPad(area2num) && + !AAS_AreaGrounded(area2num)) + { + VectorCopy(trace.endpos, destorigin); + } + else*/ + { + //predict where you'll end up + AAS_FloatForBSPEpairKey(dest, "angle", &angle); + if (angle) + { + VectorSet(angles, 0, angle, 0); + AngleVectors(angles, velocity, NULL, NULL); + VectorScale(velocity, 400, velocity); + } //end if + else + { + VectorClear(velocity); + } //end else + VectorClear(cmdmove); + AAS_PredictClientMovement(&move, -1, destorigin, PRESENCE_NORMAL, qfalse, + velocity, cmdmove, 0, 30, 0.1f, + SE_HITGROUND|SE_ENTERWATER|SE_ENTERSLIME| + SE_ENTERLAVA|SE_HITGROUNDDAMAGE|SE_TOUCHJUMPPAD|SE_TOUCHTELEPORTER, 0, qfalse); //qtrue); + area2num = AAS_PointAreaNum(move.endpos); + if (move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA)) + { + botimport.Print(PRT_WARNING, "teleported into slime or lava at dest %s\n", target); + } //end if + VectorCopy(move.endpos, destorigin); + } //end else + } //end if + // + //botimport.Print(PRT_MESSAGE, "teleporter brush origin at %f %f %f\n", origin[0], origin[1], origin[2]); + //botimport.Print(PRT_MESSAGE, "teleporter brush mins = %f %f %f\n", mins[0], mins[1], mins[2]); + //botimport.Print(PRT_MESSAGE, "teleporter brush maxs = %f %f %f\n", maxs[0], maxs[1], maxs[2]); + VectorAdd(origin, mins, mins); + VectorAdd(origin, maxs, maxs); + // + VectorAdd(mins, maxs, mid); + VectorScale(mid, 0.5, mid); + //link an invalid (-1) entity + areas = AAS_LinkEntityClientBBox(mins, maxs, -1, PRESENCE_CROUCH); + if (!areas) botimport.Print(PRT_MESSAGE, "trigger_multiple not in any area\n"); + // + for (link = areas; link; link = link->next_area) + { + //if (!AAS_AreaGrounded(link->areanum)) continue; + if (!AAS_AreaTeleporter(link->areanum)) continue; + // + area1num = link->areanum; + //create a new reachability link + lreach = AAS_AllocReachability(); + if (!lreach) break; + lreach->areanum = area2num; + lreach->facenum = 0; + lreach->edgenum = 0; + VectorCopy(mid, lreach->start); + VectorCopy(destorigin, lreach->end); + lreach->traveltype = TRAVEL_TELEPORT; + lreach->traveltype |= AAS_TravelFlagsForTeam(ent); + lreach->traveltime = aassettings.rs_teleport; + lreach->next = areareachability[area1num]; + areareachability[area1num] = lreach; + // + reach_teleport++; + } //end for + //unlink the invalid entity + AAS_UnlinkFromAreas(areas); + } //end for +} //end of the function AAS_Reachability_Teleport +//=========================================================================== +// create possible elevator (func_plat) reachabilities +// this is very game dependent.... :( +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_Reachability_Elevator(void) +{ + int area1num, area2num, modelnum, i, j, k, l, n, p; + float lip, height, speed; + char model[MAX_EPAIRKEY], classname[MAX_EPAIRKEY]; + int ent; + vec3_t mins, maxs, origin, angles = {0, 0, 0}; + vec3_t pos1, pos2, mids, platbottom, plattop; + vec3_t bottomorg, toporg, start, end, dir; + float xvals[8], yvals[8], xvals_top[8], yvals_top[8]; + aas_lreachability_t *lreach; + aas_trace_t trace; + +#ifdef REACH_DEBUG + Log_Write("AAS_Reachability_Elevator\r\n"); +#endif //REACH_DEBUG + for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent)) + { + if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue; + if (!strcmp(classname, "func_plat")) + { +#ifdef REACH_DEBUG + Log_Write("found func plat\r\n"); +#endif //REACH_DEBUG + if (!AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY)) + { + botimport.Print(PRT_ERROR, "func_plat without model\n"); + continue; + } //end if + //get the model number, and skip the leading * + modelnum = atoi(model+1); + if (modelnum <= 0) + { + botimport.Print(PRT_ERROR, "func_plat with invalid model number\n"); + continue; + } //end if + //get the mins, maxs and origin of the model + //NOTE: the origin is usually (0,0,0) and the mins and maxs + // are the absolute mins and maxs + AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin); + // + AAS_VectorForBSPEpairKey(ent, "origin", origin); + //pos1 is the top position, pos2 is the bottom + VectorCopy(origin, pos1); + VectorCopy(origin, pos2); + //get the lip of the plat + AAS_FloatForBSPEpairKey(ent, "lip", &lip); + if (!lip) lip = 8; + //get the movement height of the plat + AAS_FloatForBSPEpairKey(ent, "height", &height); + if (!height) height = (maxs[2] - mins[2]) - lip; + //get the speed of the plat + AAS_FloatForBSPEpairKey(ent, "speed", &speed); + if (!speed) speed = 200; + //get bottom position below pos1 + pos2[2] -= height; + // + //get a point just above the plat in the bottom position + VectorAdd(mins, maxs, mids); + VectorMA(pos2, 0.5, mids, platbottom); + platbottom[2] = maxs[2] - (pos1[2] - pos2[2]) + 2; + //get a point just above the plat in the top position + VectorAdd(mins, maxs, mids); + VectorMA(pos2, 0.5, mids, plattop); + plattop[2] = maxs[2] + 2; + // + /*if (!area1num) + { + Log_Write("no grounded area near plat bottom\r\n"); + continue; + } //end if*/ + //get the mins and maxs a little larger + for (i = 0; i < 3; i++) + { + mins[i] -= 1; + maxs[i] += 1; + } //end for + // + //botimport.Print(PRT_MESSAGE, "platbottom[2] = %1.1f plattop[2] = %1.1f\n", platbottom[2], plattop[2]); + // + VectorAdd(mins, maxs, mids); + VectorScale(mids, 0.5, mids); + // + xvals[0] = mins[0]; xvals[1] = mids[0]; xvals[2] = maxs[0]; xvals[3] = mids[0]; + yvals[0] = mids[1]; yvals[1] = maxs[1]; yvals[2] = mids[1]; yvals[3] = mins[1]; + // + xvals[4] = mins[0]; xvals[5] = maxs[0]; xvals[6] = maxs[0]; xvals[7] = mins[0]; + yvals[4] = maxs[1]; yvals[5] = maxs[1]; yvals[6] = mins[1]; yvals[7] = mins[1]; + //find adjacent areas around the bottom of the plat + for (i = 0; i < 9; i++) + { + if (i < 8) //check at the sides of the plat + { + bottomorg[0] = origin[0] + xvals[i]; + bottomorg[1] = origin[1] + yvals[i]; + bottomorg[2] = platbottom[2] + 16; + //get a grounded or swim area near the plat in the bottom position + area1num = AAS_PointAreaNum(bottomorg); + for (k = 0; k < 16; k++) + { + if (area1num) + { + if (AAS_AreaGrounded(area1num) || AAS_AreaSwim(area1num)) break; + } //end if + bottomorg[2] += 4; + area1num = AAS_PointAreaNum(bottomorg); + } //end if + //if in solid + if (k >= 16) + { + continue; + } //end if + } //end if + else //at the middle of the plat + { + VectorCopy(plattop, bottomorg); + bottomorg[2] += 24; + area1num = AAS_PointAreaNum(bottomorg); + if (!area1num) continue; + VectorCopy(platbottom, bottomorg); + bottomorg[2] += 24; + } //end else + //look at adjacent areas around the top of the plat + //make larger steps to outside the plat everytime + for (n = 0; n < 3; n++) + { + for (k = 0; k < 3; k++) + { + mins[k] -= 4; + maxs[k] += 4; + } //end for + xvals_top[0] = mins[0]; xvals_top[1] = mids[0]; xvals_top[2] = maxs[0]; xvals_top[3] = mids[0]; + yvals_top[0] = mids[1]; yvals_top[1] = maxs[1]; yvals_top[2] = mids[1]; yvals_top[3] = mins[1]; + // + xvals_top[4] = mins[0]; xvals_top[5] = maxs[0]; xvals_top[6] = maxs[0]; xvals_top[7] = mins[0]; + yvals_top[4] = maxs[1]; yvals_top[5] = maxs[1]; yvals_top[6] = mins[1]; yvals_top[7] = mins[1]; + // + for (j = 0; j < 8; j++) + { + toporg[0] = origin[0] + xvals_top[j]; + toporg[1] = origin[1] + yvals_top[j]; + toporg[2] = plattop[2] + 16; + //get a grounded or swim area near the plat in the top position + area2num = AAS_PointAreaNum(toporg); + for (l = 0; l < 16; l++) + { + if (area2num) + { + if (AAS_AreaGrounded(area2num) || AAS_AreaSwim(area2num)) + { + VectorCopy(plattop, start); + start[2] += 32; + VectorCopy(toporg, end); + end[2] += 1; + trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1); + if (trace.fraction >= 1) break; + } //end if + } //end if + toporg[2] += 4; + area2num = AAS_PointAreaNum(toporg); + } //end if + //if in solid + if (l >= 16) continue; + //never create a reachability in the same area + if (area2num == area1num) continue; + //if the area isn't grounded + if (!AAS_AreaGrounded(area2num)) continue; + //if there already exists reachability between the areas + if (AAS_ReachabilityExists(area1num, area2num)) continue; + //if the reachability start is within the elevator bounding box + VectorSubtract(bottomorg, platbottom, dir); + VectorNormalize(dir); + dir[0] = bottomorg[0] + 24 * dir[0]; + dir[1] = bottomorg[1] + 24 * dir[1]; + dir[2] = bottomorg[2]; + // + for (p = 0; p < 3; p++) + if (dir[p] < origin[p] + mins[p] || dir[p] > origin[p] + maxs[p]) break; + if (p >= 3) continue; + //create a new reachability link + lreach = AAS_AllocReachability(); + if (!lreach) continue; + lreach->areanum = area2num; + //the facenum is the model number + lreach->facenum = modelnum; + //the edgenum is the height + lreach->edgenum = (int) height; + // + VectorCopy(dir, lreach->start); + VectorCopy(toporg, lreach->end); + lreach->traveltype = TRAVEL_ELEVATOR; + lreach->traveltype |= AAS_TravelFlagsForTeam(ent); + lreach->traveltime = aassettings.rs_startelevator + height * 100 / speed; + lreach->next = areareachability[area1num]; + areareachability[area1num] = lreach; + //don't go any further to the outside + n = 9999; + // +#ifdef REACH_DEBUG + Log_Write("elevator reach from %d to %d\r\n", area1num, area2num); +#endif //REACH_DEBUG + // + reach_elevator++; + } //end for + } //end for + } //end for + } //end if + } //end for +} //end of the function AAS_Reachability_Elevator +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +aas_lreachability_t *AAS_FindFaceReachabilities(vec3_t *facepoints, int numpoints, aas_plane_t *plane, int towardsface) +{ + int i, j, k, l; + int facenum, edgenum, bestfacenum; + float *v1, *v2, *v3, *v4; + float bestdist, speed, hordist, dist; + vec3_t beststart, beststart2, bestend, bestend2, tmp, hordir, testpoint; + aas_lreachability_t *lreach, *lreachabilities; + aas_area_t *area; + aas_face_t *face; + aas_edge_t *edge; + aas_plane_t *faceplane, *bestfaceplane; + + // + lreachabilities = NULL; + bestfacenum = 0; + bestfaceplane = NULL; + // + for (i = 1; i < aasworld.numareas; i++) + { + area = &aasworld.areas[i]; + // get the shortest distance between one of the func_bob start edges and + // one of the face edges of area1 + bestdist = 999999; + for (j = 0; j < area->numfaces; j++) + { + facenum = aasworld.faceindex[area->firstface + j]; + face = &aasworld.faces[abs(facenum)]; + //if not a ground face + if (!(face->faceflags & FACE_GROUND)) continue; + //get the ground planes + faceplane = &aasworld.planes[face->planenum]; + // + for (k = 0; k < face->numedges; k++) + { + edgenum = abs(aasworld.edgeindex[face->firstedge + k]); + edge = &aasworld.edges[edgenum]; + //calculate the minimum distance between the two edges + v1 = aasworld.vertexes[edge->v[0]]; + v2 = aasworld.vertexes[edge->v[1]]; + // + for (l = 0; l < numpoints; l++) + { + v3 = facepoints[l]; + v4 = facepoints[(l+1) % numpoints]; + dist = AAS_ClosestEdgePoints(v1, v2, v3, v4, faceplane, plane, + beststart, bestend, + beststart2, bestend2, bestdist); + if (dist < bestdist) + { + bestfacenum = facenum; + bestfaceplane = faceplane; + bestdist = dist; + } //end if + } //end for + } //end for + } //end for + // + if (bestdist > 192) continue; + // + VectorMiddle(beststart, beststart2, beststart); + VectorMiddle(bestend, bestend2, bestend); + // + if (!towardsface) + { + VectorCopy(beststart, tmp); + VectorCopy(bestend, beststart); + VectorCopy(tmp, bestend); + } //end if + // + VectorSubtract(bestend, beststart, hordir); + hordir[2] = 0; + hordist = VectorLength(hordir); + // + if (hordist > 2 * AAS_MaxJumpDistance(aassettings.phys_jumpvel)) continue; + //the end point should not be significantly higher than the start point + if (bestend[2] - 32 > beststart[2]) continue; + //don't fall down too far + if (bestend[2] < beststart[2] - 128) continue; + //the distance should not be too far + if (hordist > 32) + { + //check for walk off ledge + if (!AAS_HorizontalVelocityForJump(0, beststart, bestend, &speed)) continue; + } //end if + // + beststart[2] += 1; + bestend[2] += 1; + // + if (towardsface) VectorCopy(bestend, testpoint); + else VectorCopy(beststart, testpoint); + testpoint[2] = 0; + testpoint[2] = (bestfaceplane->dist - DotProduct(bestfaceplane->normal, testpoint)) / bestfaceplane->normal[2]; + // + if (!AAS_PointInsideFace(bestfacenum, testpoint, 0.1f)) + { + //if the faces are not overlapping then only go down + if (bestend[2] - 16 > beststart[2]) continue; + } //end if + lreach = AAS_AllocReachability(); + if (!lreach) return lreachabilities; + lreach->areanum = i; + lreach->facenum = 0; + lreach->edgenum = 0; + VectorCopy(beststart, lreach->start); + VectorCopy(bestend, lreach->end); + lreach->traveltype = 0; + lreach->traveltime = 0; + lreach->next = lreachabilities; + lreachabilities = lreach; +#ifndef BSPC + if (towardsface) AAS_PermanentLine(lreach->start, lreach->end, 1); + else AAS_PermanentLine(lreach->start, lreach->end, 2); +#endif + } //end for + return lreachabilities; +} //end of the function AAS_FindFaceReachabilities +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_Reachability_FuncBobbing(void) +{ + int ent, spawnflags, modelnum, axis; + int i, numareas, areas[10]; + char classname[MAX_EPAIRKEY], model[MAX_EPAIRKEY]; + vec3_t origin, move_end, move_start, move_start_top, move_end_top; + vec3_t mins, maxs, angles = {0, 0, 0}; + vec3_t start_edgeverts[4], end_edgeverts[4], mid; + vec3_t org, start, end, dir, points[10]; + float height; + aas_plane_t start_plane, end_plane; + aas_lreachability_t *startreach, *endreach, *nextstartreach, *nextendreach, *lreach; + aas_lreachability_t *firststartreach, *firstendreach; + + for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent)) + { + if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue; + if (strcmp(classname, "func_bobbing")) continue; + AAS_FloatForBSPEpairKey(ent, "height", &height); + if (!height) height = 32; + // + if (!AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY)) + { + botimport.Print(PRT_ERROR, "func_bobbing without model\n"); + continue; + } //end if + //get the model number, and skip the leading * + modelnum = atoi(model+1); + if (modelnum <= 0) + { + botimport.Print(PRT_ERROR, "func_bobbing with invalid model number\n"); + continue; + } //end if + //if the entity has an origin set then use it + if (!AAS_VectorForBSPEpairKey(ent, "origin", origin)) + VectorSet(origin, 0, 0, 0); + // + AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, NULL); + // + VectorAdd(mins, origin, mins); + VectorAdd(maxs, origin, maxs); + // + VectorAdd(mins, maxs, mid); + VectorScale(mid, 0.5, mid); + VectorCopy(mid, origin); + // + VectorCopy(origin, move_end); + VectorCopy(origin, move_start); + // + AAS_IntForBSPEpairKey(ent, "spawnflags", &spawnflags); + // set the axis of bobbing + if (spawnflags & 1) axis = 0; + else if (spawnflags & 2) axis = 1; + else axis = 2; + // + move_start[axis] -= height; + move_end[axis] += height; + // + Log_Write("funcbob model %d, start = {%1.1f, %1.1f, %1.1f} end = {%1.1f, %1.1f, %1.1f}\n", + modelnum, move_start[0], move_start[1], move_start[2], move_end[0], move_end[1], move_end[2]); + // +#ifndef BSPC + /* + AAS_DrawPermanentCross(move_start, 4, 1); + AAS_DrawPermanentCross(move_end, 4, 2); + */ +#endif + // + for (i = 0; i < 4; i++) + { + VectorCopy(move_start, start_edgeverts[i]); + start_edgeverts[i][2] += maxs[2] - mid[2]; //+ bbox maxs z + start_edgeverts[i][2] += 24; //+ player origin to ground dist + } //end for + start_edgeverts[0][0] += maxs[0] - mid[0]; + start_edgeverts[0][1] += maxs[1] - mid[1]; + start_edgeverts[1][0] += maxs[0] - mid[0]; + start_edgeverts[1][1] += mins[1] - mid[1]; + start_edgeverts[2][0] += mins[0] - mid[0]; + start_edgeverts[2][1] += mins[1] - mid[1]; + start_edgeverts[3][0] += mins[0] - mid[0]; + start_edgeverts[3][1] += maxs[1] - mid[1]; + // + start_plane.dist = start_edgeverts[0][2]; + VectorSet(start_plane.normal, 0, 0, 1); + // + for (i = 0; i < 4; i++) + { + VectorCopy(move_end, end_edgeverts[i]); + end_edgeverts[i][2] += maxs[2] - mid[2]; //+ bbox maxs z + end_edgeverts[i][2] += 24; //+ player origin to ground dist + } //end for + end_edgeverts[0][0] += maxs[0] - mid[0]; + end_edgeverts[0][1] += maxs[1] - mid[1]; + end_edgeverts[1][0] += maxs[0] - mid[0]; + end_edgeverts[1][1] += mins[1] - mid[1]; + end_edgeverts[2][0] += mins[0] - mid[0]; + end_edgeverts[2][1] += mins[1] - mid[1]; + end_edgeverts[3][0] += mins[0] - mid[0]; + end_edgeverts[3][1] += maxs[1] - mid[1]; + // + end_plane.dist = end_edgeverts[0][2]; + VectorSet(end_plane.normal, 0, 0, 1); + // +#ifndef BSPC +#if 0 + for (i = 0; i < 4; i++) + { + AAS_PermanentLine(start_edgeverts[i], start_edgeverts[(i+1)%4], 1); + AAS_PermanentLine(end_edgeverts[i], end_edgeverts[(i+1)%4], 1); + } //end for +#endif +#endif + VectorCopy(move_start, move_start_top); + move_start_top[2] += maxs[2] - mid[2] + 24; //+ bbox maxs z + VectorCopy(move_end, move_end_top); + move_end_top[2] += maxs[2] - mid[2] + 24; //+ bbox maxs z + // + if (!AAS_PointAreaNum(move_start_top)) continue; + if (!AAS_PointAreaNum(move_end_top)) continue; + // + for (i = 0; i < 2; i++) + { + // + if (i == 0) + { + firststartreach = AAS_FindFaceReachabilities(start_edgeverts, 4, &start_plane, qtrue); + firstendreach = AAS_FindFaceReachabilities(end_edgeverts, 4, &end_plane, qfalse); + } //end if + else + { + firststartreach = AAS_FindFaceReachabilities(end_edgeverts, 4, &end_plane, qtrue); + firstendreach = AAS_FindFaceReachabilities(start_edgeverts, 4, &start_plane, qfalse); + } //end else + // + //create reachabilities from start to end + for (startreach = firststartreach; startreach; startreach = nextstartreach) + { + nextstartreach = startreach->next; + // + //trace = AAS_TraceClientBBox(startreach->start, move_start_top, PRESENCE_NORMAL, -1); + //if (trace.fraction < 1) continue; + // + for (endreach = firstendreach; endreach; endreach = nextendreach) + { + nextendreach = endreach->next; + // + //trace = AAS_TraceClientBBox(endreach->end, move_end_top, PRESENCE_NORMAL, -1); + //if (trace.fraction < 1) continue; + // + Log_Write("funcbob reach from area %d to %d\n", startreach->areanum, endreach->areanum); + // + // + if (i == 0) VectorCopy(move_start_top, org); + else VectorCopy(move_end_top, org); + VectorSubtract(startreach->start, org, dir); + dir[2] = 0; + VectorNormalize(dir); + VectorCopy(startreach->start, start); + VectorMA(startreach->start, 1, dir, start); + start[2] += 1; + VectorMA(startreach->start, 16, dir, end); + end[2] += 1; + // + numareas = AAS_TraceAreas(start, end, areas, points, 10); + if (numareas <= 0) continue; + if (numareas > 1) VectorCopy(points[1], startreach->start); + else VectorCopy(end, startreach->start); + // + if (!AAS_PointAreaNum(startreach->start)) continue; + if (!AAS_PointAreaNum(endreach->end)) continue; + // + lreach = AAS_AllocReachability(); + lreach->areanum = endreach->areanum; + if (i == 0) lreach->edgenum = ((int)move_start[axis] << 16) | ((int) move_end[axis] & 0x0000ffff); + else lreach->edgenum = ((int)move_end[axis] << 16) | ((int) move_start[axis] & 0x0000ffff); + lreach->facenum = (spawnflags << 16) | modelnum; + VectorCopy(startreach->start, lreach->start); + VectorCopy(endreach->end, lreach->end); +#ifndef BSPC +// AAS_DrawArrow(lreach->start, lreach->end, LINECOLOR_BLUE, LINECOLOR_YELLOW); +// AAS_PermanentLine(lreach->start, lreach->end, 1); +#endif + lreach->traveltype = TRAVEL_FUNCBOB; + lreach->traveltype |= AAS_TravelFlagsForTeam(ent); + lreach->traveltime = aassettings.rs_funcbob; + reach_funcbob++; + lreach->next = areareachability[startreach->areanum]; + areareachability[startreach->areanum] = lreach; + // + } //end for + } //end for + for (startreach = firststartreach; startreach; startreach = nextstartreach) + { + nextstartreach = startreach->next; + AAS_FreeReachability(startreach); + } //end for + for (endreach = firstendreach; endreach; endreach = nextendreach) + { + nextendreach = endreach->next; + AAS_FreeReachability(endreach); + } //end for + //only go up with func_bobbing entities that go up and down + if (!(spawnflags & 1) && !(spawnflags & 2)) break; + } //end for + } //end for +} //end of the function AAS_Reachability_FuncBobbing +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_Reachability_JumpPad(void) +{ + int face2num, i, ret, area2num, visualize, ent, bot_visualizejumppads; + //int modelnum, ent2; + //float dist, time, height, gravity, forward; + float speed, zvel; + //float hordist; + aas_face_t *face2; + aas_area_t *area2; + aas_lreachability_t *lreach; + vec3_t areastart, facecenter, dir, cmdmove; + vec3_t velocity, absmins, absmaxs; + //vec3_t origin, ent2origin, angles, teststart; + aas_clientmove_t move; + //aas_trace_t trace; + aas_link_t *areas, *link; + //char target[MAX_EPAIRKEY], targetname[MAX_EPAIRKEY], model[MAX_EPAIRKEY]; + char classname[MAX_EPAIRKEY]; + +#ifdef BSPC + bot_visualizejumppads = 0; +#else + bot_visualizejumppads = LibVarValue("bot_visualizejumppads", "0"); +#endif + for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent)) + { + if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue; + if (strcmp(classname, "trigger_push")) continue; + // + if (!AAS_GetJumpPadInfo(ent, areastart, absmins, absmaxs, velocity)) continue; + /* + // + AAS_FloatForBSPEpairKey(ent, "speed", &speed); + if (!speed) speed = 1000; +// AAS_VectorForBSPEpairKey(ent, "angles", angles); +// AAS_SetMovedir(angles, velocity); +// VectorScale(velocity, speed, velocity); + VectorClear(angles); + //get the mins, maxs and origin of the model + AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY); + if (model[0]) modelnum = atoi(model+1); + else modelnum = 0; + AAS_BSPModelMinsMaxsOrigin(modelnum, angles, absmins, absmaxs, origin); + VectorAdd(origin, absmins, absmins); + VectorAdd(origin, absmaxs, absmaxs); + // +#ifdef REACH_DEBUG + botimport.Print(PRT_MESSAGE, "absmins = %f %f %f\n", absmins[0], absmins[1], absmins[2]); + botimport.Print(PRT_MESSAGE, "absmaxs = %f %f %f\n", absmaxs[0], absmaxs[1], absmaxs[2]); +#endif REACH_DEBUG + VectorAdd(absmins, absmaxs, origin); + VectorScale (origin, 0.5, origin); + + //get the start areas + VectorCopy(origin, teststart); + teststart[2] += 64; + trace = AAS_TraceClientBBox(teststart, origin, PRESENCE_CROUCH, -1); + if (trace.startsolid) + { + botimport.Print(PRT_MESSAGE, "trigger_push start solid\n"); + VectorCopy(origin, areastart); + } //end if + else + { + VectorCopy(trace.endpos, areastart); + } //end else + areastart[2] += 0.125; + // + //AAS_DrawPermanentCross(origin, 4, 4); + //get the target entity + AAS_ValueForBSPEpairKey(ent, "target", target, MAX_EPAIRKEY); + for (ent2 = AAS_NextBSPEntity(0); ent2; ent2 = AAS_NextBSPEntity(ent2)) + { + if (!AAS_ValueForBSPEpairKey(ent2, "targetname", targetname, MAX_EPAIRKEY)) continue; + if (!strcmp(targetname, target)) break; + } //end for + if (!ent2) + { + botimport.Print(PRT_MESSAGE, "trigger_push without target entity %s\n", target); + continue; + } //end if + AAS_VectorForBSPEpairKey(ent2, "origin", ent2origin); + // + height = ent2origin[2] - origin[2]; + gravity = aassettings.sv_gravity; + time = sqrt( height / ( 0.5 * gravity ) ); + if (!time) + { + botimport.Print(PRT_MESSAGE, "trigger_push without time\n"); + continue; + } //end if + // set s.origin2 to the push velocity + VectorSubtract ( ent2origin, origin, velocity); + dist = VectorNormalize( velocity); + forward = dist / time; + //FIXME: why multiply by 1.1 + forward *= 1.1; + VectorScale(velocity, forward, velocity); + velocity[2] = time * gravity; + */ + //get the areas the jump pad brush is in + areas = AAS_LinkEntityClientBBox(absmins, absmaxs, -1, PRESENCE_CROUCH); + /* + for (link = areas; link; link = link->next_area) + { + if (link->areanum == 563) + { + ret = qfalse; + } + } + */ + for (link = areas; link; link = link->next_area) + { + if (AAS_AreaJumpPad(link->areanum)) break; + } //end for + if (!link) + { + botimport.Print(PRT_MESSAGE, "trigger_push not in any jump pad area\n"); + AAS_UnlinkFromAreas(areas); + continue; + } //end if + // + botimport.Print(PRT_MESSAGE, "found a trigger_push with velocity %f %f %f\n", velocity[0], velocity[1], velocity[2]); + //if there is a horizontal velocity check for a reachability without air control + if (velocity[0] || velocity[1]) + { + VectorSet(cmdmove, 0, 0, 0); + //VectorCopy(velocity, cmdmove); + //cmdmove[2] = 0; + Com_Memset(&move, 0, sizeof(aas_clientmove_t)); + area2num = 0; + for (i = 0; i < 20; i++) + { + AAS_PredictClientMovement(&move, -1, areastart, PRESENCE_NORMAL, qfalse, + velocity, cmdmove, 0, 30, 0.1f, + SE_HITGROUND|SE_ENTERWATER|SE_ENTERSLIME| + SE_ENTERLAVA|SE_HITGROUNDDAMAGE|SE_TOUCHJUMPPAD|SE_TOUCHTELEPORTER, 0, bot_visualizejumppads); + area2num = move.endarea; + for (link = areas; link; link = link->next_area) + { + if (!AAS_AreaJumpPad(link->areanum)) continue; + if (link->areanum == area2num) break; + } //end if + if (!link) break; + VectorCopy(move.endpos, areastart); + VectorCopy(move.velocity, velocity); + } //end for + if (area2num && i < 20) + { + for (link = areas; link; link = link->next_area) + { + if (!AAS_AreaJumpPad(link->areanum)) continue; + if (AAS_ReachabilityExists(link->areanum, area2num)) continue; + //create a rocket or bfg jump reachability from area1 to area2 + lreach = AAS_AllocReachability(); + if (!lreach) + { + AAS_UnlinkFromAreas(areas); + return; + } //end if + lreach->areanum = area2num; + //NOTE: the facenum is the Z velocity + lreach->facenum = velocity[2]; + //NOTE: the edgenum is the horizontal velocity + lreach->edgenum = sqrt(velocity[0] * velocity[0] + velocity[1] * velocity[1]); + VectorCopy(areastart, lreach->start); + VectorCopy(move.endpos, lreach->end); + lreach->traveltype = TRAVEL_JUMPPAD; + lreach->traveltype |= AAS_TravelFlagsForTeam(ent); + lreach->traveltime = aassettings.rs_jumppad; + lreach->next = areareachability[link->areanum]; + areareachability[link->areanum] = lreach; + // + reach_jumppad++; + } //end for + } //end if + } //end if + // + if (fabs(velocity[0]) > 100 || fabs(velocity[1]) > 100) continue; + //check for areas we can reach with air control + for (area2num = 1; area2num < aasworld.numareas; area2num++) + { + visualize = qfalse; + /* + if (area2num == 3568) + { + for (link = areas; link; link = link->next_area) + { + if (link->areanum == 3380) + { + visualize = qtrue; + botimport.Print(PRT_MESSAGE, "bah\n"); + } //end if + } //end for + } //end if*/ + //never try to go back to one of the original jumppad areas + //and don't create reachabilities if they already exist + for (link = areas; link; link = link->next_area) + { + if (AAS_ReachabilityExists(link->areanum, area2num)) break; + if (AAS_AreaJumpPad(link->areanum)) + { + if (link->areanum == area2num) break; + } //end if + } //end if + if (link) continue; + // + area2 = &aasworld.areas[area2num]; + for (i = 0; i < area2->numfaces; i++) + { + face2num = aasworld.faceindex[area2->firstface + i]; + face2 = &aasworld.faces[abs(face2num)]; + //if it is not a ground face + if (!(face2->faceflags & FACE_GROUND)) continue; + //get the center of the face + AAS_FaceCenter(face2num, facecenter); + //only go higher up + if (facecenter[2] < areastart[2]) continue; + //get the jumppad jump z velocity + zvel = velocity[2]; + //get the horizontal speed for the jump, if it isn't possible to calculate this + //speed + ret = AAS_HorizontalVelocityForJump(zvel, areastart, facecenter, &speed); + if (ret && speed < 150) + { + //direction towards the face center + VectorSubtract(facecenter, areastart, dir); + dir[2] = 0; + //hordist = VectorNormalize(dir); + //if (hordist < 1.6 * facecenter[2] - areastart[2]) + { + //get command movement + VectorScale(dir, speed, cmdmove); + // + AAS_PredictClientMovement(&move, -1, areastart, PRESENCE_NORMAL, qfalse, + velocity, cmdmove, 30, 30, 0.1f, + SE_ENTERWATER|SE_ENTERSLIME| + SE_ENTERLAVA|SE_HITGROUNDDAMAGE| + SE_TOUCHJUMPPAD|SE_TOUCHTELEPORTER|SE_HITGROUNDAREA, area2num, visualize); + //if prediction time wasn't enough to fully predict the movement + //don't enter slime or lava and don't fall from too high + if (move.frames < 30 && + !(move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE)) + && (move.stopevent & (SE_HITGROUNDAREA|SE_TOUCHJUMPPAD|SE_TOUCHTELEPORTER))) + { + //never go back to the same jumppad + for (link = areas; link; link = link->next_area) + { + if (link->areanum == move.endarea) break; + } + if (!link) + { + for (link = areas; link; link = link->next_area) + { + if (!AAS_AreaJumpPad(link->areanum)) continue; + if (AAS_ReachabilityExists(link->areanum, area2num)) continue; + //create a jumppad reachability from area1 to area2 + lreach = AAS_AllocReachability(); + if (!lreach) + { + AAS_UnlinkFromAreas(areas); + return; + } //end if + lreach->areanum = move.endarea; + //NOTE: the facenum is the Z velocity + lreach->facenum = velocity[2]; + //NOTE: the edgenum is the horizontal velocity + lreach->edgenum = sqrt(cmdmove[0] * cmdmove[0] + cmdmove[1] * cmdmove[1]); + VectorCopy(areastart, lreach->start); + VectorCopy(facecenter, lreach->end); + lreach->traveltype = TRAVEL_JUMPPAD; + lreach->traveltype |= AAS_TravelFlagsForTeam(ent); + lreach->traveltime = aassettings.rs_aircontrolledjumppad; + lreach->next = areareachability[link->areanum]; + areareachability[link->areanum] = lreach; + // + reach_jumppad++; + } //end for + } + } //end if + } //end if + } //end for + } //end for + } //end for + AAS_UnlinkFromAreas(areas); + } //end for +} //end of the function AAS_Reachability_JumpPad +//=========================================================================== +// never point at ground faces +// always a higher and pretty far area +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_Reachability_Grapple(int area1num, int area2num) +{ + int face2num, i, j, areanum, numareas, areas[20]; + float mingrappleangle, z, hordist; + bsp_trace_t bsptrace; + aas_trace_t trace; + aas_face_t *face2; + aas_area_t *area1, *area2; + aas_lreachability_t *lreach; + vec3_t areastart, facecenter, start, end, dir, down = {0, 0, -1}; + float *v; + + //only grapple when on the ground or swimming + if (!AAS_AreaGrounded(area1num) && !AAS_AreaSwim(area1num)) return qfalse; + //don't grapple from a crouch area + if (!(AAS_AreaPresenceType(area1num) & PRESENCE_NORMAL)) return qfalse; + //NOTE: disabled area swim it doesn't work right + if (AAS_AreaSwim(area1num)) return qfalse; + // + area1 = &aasworld.areas[area1num]; + area2 = &aasworld.areas[area2num]; + //don't grapple towards way lower areas + if (area2->maxs[2] < area1->mins[2]) return qfalse; + // + VectorCopy(aasworld.areas[area1num].center, start); + //if not a swim area + if (!AAS_AreaSwim(area1num)) + { + if (!AAS_PointAreaNum(start)) Log_Write("area %d center %f %f %f in solid?\r\n", area1num, + start[0], start[1], start[2]); + VectorCopy(start, end); + end[2] -= 1000; + trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1); + if (trace.startsolid) return qfalse; + VectorCopy(trace.endpos, areastart); + } //end if + else + { + if (!(AAS_PointContents(start) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER))) return qfalse; + } //end else + // + //start is now the start point + // + for (i = 0; i < area2->numfaces; i++) + { + face2num = aasworld.faceindex[area2->firstface + i]; + face2 = &aasworld.faces[abs(face2num)]; + //if it is not a solid face + if (!(face2->faceflags & FACE_SOLID)) continue; + //direction towards the first vertex of the face + v = aasworld.vertexes[aasworld.edges[abs(aasworld.edgeindex[face2->firstedge])].v[0]]; + VectorSubtract(v, areastart, dir); + //if the face plane is facing away + if (DotProduct(aasworld.planes[face2->planenum].normal, dir) > 0) continue; + //get the center of the face + AAS_FaceCenter(face2num, facecenter); + //only go higher up with the grapple + if (facecenter[2] < areastart[2] + 64) continue; + //only use vertical faces or downward facing faces + if (DotProduct(aasworld.planes[face2->planenum].normal, down) < 0) continue; + //direction towards the face center + VectorSubtract(facecenter, areastart, dir); + // + z = dir[2]; + dir[2] = 0; + hordist = VectorLength(dir); + if (!hordist) continue; + //if too far + if (hordist > 2000) continue; + //check the minimal angle of the movement + mingrappleangle = 15; //15 degrees + if (z / hordist < tan(2 * M_PI * mingrappleangle / 360)) continue; + // + VectorCopy(facecenter, start); + VectorMA(facecenter, -500, aasworld.planes[face2->planenum].normal, end); + // + bsptrace = AAS_Trace(start, NULL, NULL, end, 0, CONTENTS_SOLID); + //the grapple won't stick to the sky and the grapple point should be near the AAS wall + if ((bsptrace.surface.flags & SURF_SKY) || (bsptrace.fraction * 500 > 32)) continue; + //trace a full bounding box from the area center on the ground to + //the center of the face + VectorSubtract(facecenter, areastart, dir); + VectorNormalize(dir); + VectorMA(areastart, 4, dir, start); + VectorCopy(bsptrace.endpos, end); + trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, -1); + VectorSubtract(trace.endpos, facecenter, dir); + if (VectorLength(dir) > 24) continue; + // + VectorCopy(trace.endpos, start); + VectorCopy(trace.endpos, end); + end[2] -= AAS_FallDamageDistance(); + trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, -1); + if (trace.fraction >= 1) continue; + //area to end in + areanum = AAS_PointAreaNum(trace.endpos); + //if not in lava or slime + if (aasworld.areasettings[areanum].contents & (AREACONTENTS_SLIME|AREACONTENTS_LAVA)) + { + continue; + } //end if + //do not go the the source area + if (areanum == area1num) continue; + //don't create reachabilities if they already exist + if (AAS_ReachabilityExists(area1num, areanum)) continue; + //only end in areas we can stand + if (!AAS_AreaGrounded(areanum)) continue; + //never go through cluster portals!! + numareas = AAS_TraceAreas(areastart, bsptrace.endpos, areas, NULL, 20); + if (numareas >= 20) continue; + for (j = 0; j < numareas; j++) + { + if (aasworld.areasettings[areas[j]].contents & AREACONTENTS_CLUSTERPORTAL) break; + } //end for + if (j < numareas) continue; + //create a new reachability link + lreach = AAS_AllocReachability(); + if (!lreach) return qfalse; + lreach->areanum = areanum; + lreach->facenum = face2num; + lreach->edgenum = 0; + VectorCopy(areastart, lreach->start); + //VectorCopy(facecenter, lreach->end); + VectorCopy(bsptrace.endpos, lreach->end); + lreach->traveltype = TRAVEL_GRAPPLEHOOK; + VectorSubtract(lreach->end, lreach->start, dir); + lreach->traveltime = aassettings.rs_startgrapple + VectorLength(dir) * 0.25; + lreach->next = areareachability[area1num]; + areareachability[area1num] = lreach; + // + reach_grapple++; + } //end for + // + return qfalse; +} //end of the function AAS_Reachability_Grapple +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_SetWeaponJumpAreaFlags(void) +{ + int ent, i; + vec3_t mins = {-15, -15, -15}, maxs = {15, 15, 15}; + vec3_t origin; + int areanum, weaponjumpareas, spawnflags; + char classname[MAX_EPAIRKEY]; + + weaponjumpareas = 0; + for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent)) + { + if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue; + if ( + !strcmp(classname, "item_armor_body") || + !strcmp(classname, "item_health") || + !strcmp(classname, "weapon_disruptor") || + !strcmp(classname, "weapon_repeater") || + !strcmp(classname, "weapon_demp2") || + !strcmp(classname, "weapon_flechette") || + !strcmp(classname, "weapon_rocket_launcher")) + { + if (AAS_VectorForBSPEpairKey(ent, "origin", origin)) + { + spawnflags = 0; + AAS_IntForBSPEpairKey(ent, "spawnflags", &spawnflags); + //if not a stationary item + if (!(spawnflags & 1)) + { + if (!AAS_DropToFloor(origin, mins, maxs)) + { + botimport.Print(PRT_MESSAGE, "%s in solid at (%1.1f %1.1f %1.1f)\n", + classname, origin[0], origin[1], origin[2]); + } //end if + } //end if + //areanum = AAS_PointAreaNum(origin); + areanum = AAS_BestReachableArea(origin, mins, maxs, origin); + //the bot may rocket jump towards this area + aasworld.areasettings[areanum].areaflags |= AREA_WEAPONJUMP; + // + //if (!AAS_AreaGrounded(areanum)) + // botimport.Print(PRT_MESSAGE, "area not grounded\n"); + // + weaponjumpareas++; + } //end if + } //end if + } //end for + for (i = 1; i < aasworld.numareas; i++) + { + if (aasworld.areasettings[i].contents & AREACONTENTS_JUMPPAD) + { + aasworld.areasettings[i].areaflags |= AREA_WEAPONJUMP; + weaponjumpareas++; + } //end if + } //end for + botimport.Print(PRT_MESSAGE, "%d weapon jump areas\n", weaponjumpareas); +} //end of the function AAS_SetWeaponJumpAreaFlags +//=========================================================================== +// create a possible weapon jump reachability from area1 to area2 +// +// check if there's a cool item in the second area +// check if area1 is lower than area2 +// check if the bot can rocketjump from area1 to area2 +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_Reachability_WeaponJump(int area1num, int area2num) +{ + int face2num, i, n, ret, visualize; + float speed, zvel; + //float hordist; + aas_face_t *face2; + aas_area_t *area1, *area2; + aas_lreachability_t *lreach; + vec3_t areastart, facecenter, start, end, dir, cmdmove;// teststart; + vec3_t velocity; + aas_clientmove_t move; + aas_trace_t trace; + + visualize = qfalse; +// if (area1num == 4436 && area2num == 4318) +// { +// visualize = qtrue; +// } + if (!AAS_AreaGrounded(area1num) || AAS_AreaSwim(area1num)) return qfalse; + if (!AAS_AreaGrounded(area2num)) return qfalse; + //NOTE: only weapon jump towards areas with an interesting item in it?? + if (!(aasworld.areasettings[area2num].areaflags & AREA_WEAPONJUMP)) return qfalse; + // + area1 = &aasworld.areas[area1num]; + area2 = &aasworld.areas[area2num]; + //don't weapon jump towards way lower areas + if (area2->maxs[2] < area1->mins[2]) return qfalse; + // + VectorCopy(aasworld.areas[area1num].center, start); + //if not a swim area + if (!AAS_PointAreaNum(start)) Log_Write("area %d center %f %f %f in solid?\r\n", area1num, + start[0], start[1], start[2]); + VectorCopy(start, end); + end[2] -= 1000; + trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1); + if (trace.startsolid) return qfalse; + VectorCopy(trace.endpos, areastart); + // + //areastart is now the start point + // + for (i = 0; i < area2->numfaces; i++) + { + face2num = aasworld.faceindex[area2->firstface + i]; + face2 = &aasworld.faces[abs(face2num)]; + //if it is not a solid face + if (!(face2->faceflags & FACE_GROUND)) continue; + //get the center of the face + AAS_FaceCenter(face2num, facecenter); + //only go higher up with weapon jumps + if (facecenter[2] < areastart[2] + 64) continue; + //NOTE: set to 2 to allow bfg jump reachabilities + for (n = 0; n < 1/*2*/; n++) + { + //get the rocket jump z velocity + if (n) zvel = AAS_BFGJumpZVelocity(areastart); + else zvel = AAS_RocketJumpZVelocity(areastart); + //get the horizontal speed for the jump, if it isn't possible to calculate this + //speed (the jump is not possible) then there's no jump reachability created + ret = AAS_HorizontalVelocityForJump(zvel, areastart, facecenter, &speed); + if (ret && speed < 300) + { + //direction towards the face center + VectorSubtract(facecenter, areastart, dir); + dir[2] = 0; + //hordist = VectorNormalize(dir); + //if (hordist < 1.6 * (facecenter[2] - areastart[2])) + { + //get command movement + VectorScale(dir, speed, cmdmove); + VectorSet(velocity, 0, 0, zvel); + /* + //get command movement + VectorScale(dir, speed, velocity); + velocity[2] = zvel; + VectorSet(cmdmove, 0, 0, 0); + */ + // + AAS_PredictClientMovement(&move, -1, areastart, PRESENCE_NORMAL, qtrue, + velocity, cmdmove, 30, 30, 0.1f, + SE_ENTERWATER|SE_ENTERSLIME| + SE_ENTERLAVA|SE_HITGROUNDDAMAGE| + SE_TOUCHJUMPPAD|SE_HITGROUND|SE_HITGROUNDAREA, area2num, visualize); + //if prediction time wasn't enough to fully predict the movement + //don't enter slime or lava and don't fall from too high + if (move.frames < 30 && + !(move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE)) + && (move.stopevent & (SE_HITGROUNDAREA|SE_TOUCHJUMPPAD))) + { + //create a rocket or bfg jump reachability from area1 to area2 + lreach = AAS_AllocReachability(); + if (!lreach) return qfalse; + lreach->areanum = area2num; + lreach->facenum = 0; + lreach->edgenum = 0; + VectorCopy(areastart, lreach->start); + VectorCopy(facecenter, lreach->end); + if (n) + { + lreach->traveltype = TRAVEL_BFGJUMP; + lreach->traveltime = aassettings.rs_bfgjump; + } //end if + else + { + lreach->traveltype = TRAVEL_ROCKETJUMP; + lreach->traveltime = aassettings.rs_rocketjump; + } //end else + lreach->next = areareachability[area1num]; + areareachability[area1num] = lreach; + // + reach_rocketjump++; + return qtrue; + } //end if + } //end if + } //end if + } //end for + } //end for + // + return qfalse; +} //end of the function AAS_Reachability_WeaponJump +//=========================================================================== +// calculates additional walk off ledge reachabilities for the given area +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_Reachability_WalkOffLedge(int areanum) +{ + int i, j, k, l, m, n, p, areas[10], numareas; + int face1num, face2num, face3num, edge1num, edge2num, edge3num; + int otherareanum, gap, reachareanum, side; + aas_area_t *area, *area2; + aas_face_t *face1, *face2, *face3; + aas_edge_t *edge; + aas_plane_t *plane; + float *v1, *v2; + vec3_t sharededgevec, mid, dir, testend; + aas_lreachability_t *lreach; + aas_trace_t trace; + + if (!AAS_AreaGrounded(areanum) || AAS_AreaSwim(areanum)) return; + // + area = &aasworld.areas[areanum]; + // + for (i = 0; i < area->numfaces; i++) + { + face1num = aasworld.faceindex[area->firstface + i]; + face1 = &aasworld.faces[abs(face1num)]; + //face 1 must be a ground face + if (!(face1->faceflags & FACE_GROUND)) continue; + //go through all the edges of this ground face + for (k = 0; k < face1->numedges; k++) + { + edge1num = aasworld.edgeindex[face1->firstedge + k]; + //find another not ground face using this same edge + for (j = 0; j < area->numfaces; j++) + { + face2num = aasworld.faceindex[area->firstface + j]; + face2 = &aasworld.faces[abs(face2num)]; + //face 2 may not be a ground face + if (face2->faceflags & FACE_GROUND) continue; + //compare all the edges + for (l = 0; l < face2->numedges; l++) + { + edge2num = aasworld.edgeindex[face2->firstedge + l]; + if (abs(edge1num) == abs(edge2num)) + { + //get the area at the other side of the face + if (face2->frontarea == areanum) otherareanum = face2->backarea; + else otherareanum = face2->frontarea; + // + area2 = &aasworld.areas[otherareanum]; + //if the other area is grounded! + if (aasworld.areasettings[otherareanum].areaflags & AREA_GROUNDED) + { + //check for a possible gap + gap = qfalse; + for (n = 0; n < area2->numfaces; n++) + { + face3num = aasworld.faceindex[area2->firstface + n]; + //may not be the shared face of the two areas + if (abs(face3num) == abs(face2num)) continue; + // + face3 = &aasworld.faces[abs(face3num)]; + //find an edge shared by all three faces + for (m = 0; m < face3->numedges; m++) + { + edge3num = aasworld.edgeindex[face3->firstedge + m]; + //but the edge should be shared by all three faces + if (abs(edge3num) == abs(edge1num)) + { + if (!(face3->faceflags & FACE_SOLID)) + { + gap = qtrue; + break; + } //end if + // + if (face3->faceflags & FACE_GROUND) + { + gap = qfalse; + break; + } //end if + //FIXME: there are more situations to be handled + gap = qtrue; + break; + } //end if + } //end for + if (m < face3->numedges) break; + } //end for + if (!gap) break; + } //end if + //check for a walk off ledge reachability + edge = &aasworld.edges[abs(edge1num)]; + side = edge1num < 0; + // + v1 = aasworld.vertexes[edge->v[side]]; + v2 = aasworld.vertexes[edge->v[!side]]; + // + plane = &aasworld.planes[face1->planenum]; + //get the points really into the areas + VectorSubtract(v2, v1, sharededgevec); + CrossProduct(plane->normal, sharededgevec, dir); + VectorNormalize(dir); + // + VectorAdd(v1, v2, mid); + VectorScale(mid, 0.5, mid); + VectorMA(mid, 8, dir, mid); + // + VectorCopy(mid, testend); + testend[2] -= 1000; + trace = AAS_TraceClientBBox(mid, testend, PRESENCE_CROUCH, -1); + // + if (trace.startsolid) + { + //Log_Write("area %d: trace.startsolid\r\n", areanum); + break; + } //end if + reachareanum = AAS_PointAreaNum(trace.endpos); + if (reachareanum == areanum) + { + //Log_Write("area %d: same area\r\n", areanum); + break; + } //end if + if (AAS_ReachabilityExists(areanum, reachareanum)) + { + //Log_Write("area %d: reachability already exists\r\n", areanum); + break; + } //end if + if (!AAS_AreaGrounded(reachareanum) && !AAS_AreaSwim(reachareanum)) + { + //Log_Write("area %d, reach area %d: not grounded and not swim\r\n", areanum, reachareanum); + break; + } //end if + // + if (aasworld.areasettings[reachareanum].contents & (AREACONTENTS_SLIME + | AREACONTENTS_LAVA)) + { + //Log_Write("area %d, reach area %d: lava or slime\r\n", areanum, reachareanum); + break; + } //end if + //if not going through a cluster portal + numareas = AAS_TraceAreas(mid, testend, areas, NULL, ARRAY_LEN(areas)); + for (p = 0; p < numareas; p++) + if (AAS_AreaClusterPortal(areas[p])) + break; + if (p < numareas) + break; + // if a maximum fall height is set and the bot would fall down further + if (aassettings.rs_maxfallheight && fabs(mid[2] - trace.endpos[2]) > aassettings.rs_maxfallheight) + break; + // + lreach = AAS_AllocReachability(); + if (!lreach) break; + lreach->areanum = reachareanum; + lreach->facenum = 0; + lreach->edgenum = edge1num; + VectorCopy(mid, lreach->start); + VectorCopy(trace.endpos, lreach->end); + lreach->traveltype = TRAVEL_WALKOFFLEDGE; + lreach->traveltime = aassettings.rs_startwalkoffledge + fabs(mid[2] - trace.endpos[2]) * 50 / aassettings.phys_gravity; + if (!AAS_AreaSwim(reachareanum) && !AAS_AreaJumpPad(reachareanum)) + { + if (AAS_FallDelta(mid[2] - trace.endpos[2]) > aassettings.phys_falldelta5) + { + lreach->traveltime += aassettings.rs_falldamage5; + } //end if + else if (AAS_FallDelta(mid[2] - trace.endpos[2]) > aassettings.phys_falldelta10) + { + lreach->traveltime += aassettings.rs_falldamage10; + } //end if + } //end if + lreach->next = areareachability[areanum]; + areareachability[areanum] = lreach; + //we've got another walk off ledge reachability + reach_walkoffledge++; + } //end if + } //end for + } //end for + } //end for + } //end for +} //end of the function AAS_Reachability_WalkOffLedge +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_StoreReachability(void) +{ + int i; + aas_areasettings_t *areasettings; + aas_lreachability_t *lreach; + aas_reachability_t *reach; + + if (aasworld.reachability) FreeMemory(aasworld.reachability); + aasworld.reachability = (aas_reachability_t *) GetClearedMemory((numlreachabilities + 10) * sizeof(aas_reachability_t)); + aasworld.reachabilitysize = 1; + for (i = 0; i < aasworld.numareas; i++) + { + areasettings = &aasworld.areasettings[i]; + areasettings->firstreachablearea = aasworld.reachabilitysize; + areasettings->numreachableareas = 0; + for (lreach = areareachability[i]; lreach; lreach = lreach->next) + { + reach = &aasworld.reachability[areasettings->firstreachablearea + + areasettings->numreachableareas]; + reach->areanum = lreach->areanum; + reach->facenum = lreach->facenum; + reach->edgenum = lreach->edgenum; + VectorCopy(lreach->start, reach->start); + VectorCopy(lreach->end, reach->end); + reach->traveltype = lreach->traveltype; + reach->traveltime = lreach->traveltime; + // + areasettings->numreachableareas++; + } //end for + aasworld.reachabilitysize += areasettings->numreachableareas; + } //end for +} //end of the function AAS_StoreReachability +//=========================================================================== +// +// TRAVEL_WALK 100% equal floor height + steps +// TRAVEL_CROUCH 100% +// TRAVEL_BARRIERJUMP 100% +// TRAVEL_JUMP 80% +// TRAVEL_LADDER 100% + fall down from ladder + jump up to ladder +// TRAVEL_WALKOFFLEDGE 90% walk off very steep walls? +// TRAVEL_SWIM 100% +// TRAVEL_WATERJUMP 100% +// TRAVEL_TELEPORT 100% +// TRAVEL_ELEVATOR 100% +// TRAVEL_GRAPPLEHOOK 100% +// TRAVEL_DOUBLEJUMP 0% +// TRAVEL_RAMPJUMP 0% +// TRAVEL_STRAFEJUMP 0% +// TRAVEL_ROCKETJUMP 100% (currently limited towards areas with items) +// TRAVEL_BFGJUMP 0% (currently disabled) +// TRAVEL_JUMPPAD 100% +// TRAVEL_FUNCBOB 100% +// +// Parameter: - +// Returns: true if NOT finished +// Changes Globals: - +//=========================================================================== +int AAS_ContinueInitReachability(float time) +{ + int i, j, todo, start_time; + static float framereachability, reachability_delay; + static int lastpercentage; + + if (!aasworld.loaded) return qfalse; + //if reachability is calculated for all areas + if (aasworld.numreachabilityareas >= aasworld.numareas + 2) return qfalse; + //if starting with area 1 (area 0 is a dummy) + if (aasworld.numreachabilityareas == 1) + { + botimport.Print(PRT_MESSAGE, "calculating reachability...\n"); + lastpercentage = 0; + framereachability = 2000; + reachability_delay = 1000; + } //end if + //number of areas to calculate reachability for this cycle + todo = aasworld.numreachabilityareas + (int) framereachability; + start_time = Sys_MilliSeconds(); + //loop over the areas + for (i = aasworld.numreachabilityareas; i < aasworld.numareas && i < todo; i++) + { + aasworld.numreachabilityareas++; + //only create jumppad reachabilities from jumppad areas + if (aasworld.areasettings[i].contents & AREACONTENTS_JUMPPAD) + { + continue; + } //end if + //loop over the areas + for (j = 1; j < aasworld.numareas; j++) + { + if (i == j) continue; + //never create reachabilities from teleporter or jumppad areas to regular areas + if (aasworld.areasettings[i].contents & (AREACONTENTS_TELEPORTER|AREACONTENTS_JUMPPAD)) + { + if (!(aasworld.areasettings[j].contents & (AREACONTENTS_TELEPORTER|AREACONTENTS_JUMPPAD))) + { + continue; + } //end if + } //end if + //if there already is a reachability link from area i to j + if (AAS_ReachabilityExists(i, j)) continue; + //check for a swim reachability + if (AAS_Reachability_Swim(i, j)) continue; + //check for a simple walk on equal floor height reachability + if (AAS_Reachability_EqualFloorHeight(i, j)) continue; + //check for step, barrier, waterjump and walk off ledge reachabilities + if (AAS_Reachability_Step_Barrier_WaterJump_WalkOffLedge(i, j)) continue; + //check for ladder reachabilities + if (AAS_Reachability_Ladder(i, j)) continue; + //check for a jump reachability + if (AAS_Reachability_Jump(i, j)) continue; + } //end for + //never create these reachabilities from teleporter or jumppad areas + if (aasworld.areasettings[i].contents & (AREACONTENTS_TELEPORTER|AREACONTENTS_JUMPPAD)) + { + continue; + } //end if + //loop over the areas + for (j = 1; j < aasworld.numareas; j++) + { + if (i == j) continue; + // + if (AAS_ReachabilityExists(i, j)) continue; + //check for a grapple hook reachability + if (calcgrapplereach) AAS_Reachability_Grapple(i, j); + //check for a weapon jump reachability + AAS_Reachability_WeaponJump(i, j); + } //end for + //if the calculation took more time than the max reachability delay + if (Sys_MilliSeconds() - start_time > (int) reachability_delay) break; + // + if (aasworld.numreachabilityareas * 1000 / aasworld.numareas > lastpercentage) break; + } //end for + // + if (aasworld.numreachabilityareas == aasworld.numareas) + { + botimport.Print(PRT_MESSAGE, "\r%6.1f%%", (float) 100.0); + botimport.Print(PRT_MESSAGE, "\nplease wait while storing reachability...\n"); + aasworld.numreachabilityareas++; + } //end if + //if this is the last step in the reachability calculations + else if (aasworld.numreachabilityareas == aasworld.numareas + 1) + { + //create additional walk off ledge reachabilities for every area + for (i = 1; i < aasworld.numareas; i++) + { + //only create jumppad reachabilities from jumppad areas + if (aasworld.areasettings[i].contents & AREACONTENTS_JUMPPAD) + { + continue; + } //end if + AAS_Reachability_WalkOffLedge(i); + } //end for + //create jump pad reachabilities + AAS_Reachability_JumpPad(); + //create teleporter reachabilities + AAS_Reachability_Teleport(); + //create elevator (func_plat) reachabilities + AAS_Reachability_Elevator(); + //create func_bobbing reachabilities + AAS_Reachability_FuncBobbing(); + // +#ifdef DEBUG + botimport.Print(PRT_MESSAGE, "%6d reach swim\n", reach_swim); + botimport.Print(PRT_MESSAGE, "%6d reach equal floor\n", reach_equalfloor); + botimport.Print(PRT_MESSAGE, "%6d reach step\n", reach_step); + botimport.Print(PRT_MESSAGE, "%6d reach barrier\n", reach_barrier); + botimport.Print(PRT_MESSAGE, "%6d reach waterjump\n", reach_waterjump); + botimport.Print(PRT_MESSAGE, "%6d reach walkoffledge\n", reach_walkoffledge); + botimport.Print(PRT_MESSAGE, "%6d reach jump\n", reach_jump); + botimport.Print(PRT_MESSAGE, "%6d reach ladder\n", reach_ladder); + botimport.Print(PRT_MESSAGE, "%6d reach walk\n", reach_walk); + botimport.Print(PRT_MESSAGE, "%6d reach teleport\n", reach_teleport); + botimport.Print(PRT_MESSAGE, "%6d reach funcbob\n", reach_funcbob); + botimport.Print(PRT_MESSAGE, "%6d reach elevator\n", reach_elevator); + botimport.Print(PRT_MESSAGE, "%6d reach grapple\n", reach_grapple); + botimport.Print(PRT_MESSAGE, "%6d reach rocketjump\n", reach_rocketjump); + botimport.Print(PRT_MESSAGE, "%6d reach jumppad\n", reach_jumppad); +#endif + //*/ + //store all the reachabilities + AAS_StoreReachability(); + //free the reachability link heap + AAS_ShutDownReachabilityHeap(); + // + FreeMemory(areareachability); + // + aasworld.numreachabilityareas++; + // + botimport.Print(PRT_MESSAGE, "calculating clusters...\n"); + } //end if + else + { + lastpercentage = aasworld.numreachabilityareas * 1000 / aasworld.numareas; + botimport.Print(PRT_MESSAGE, "\r%6.1f%%", (float) lastpercentage / 10); + } //end else + //not yet finished + return qtrue; +} //end of the function AAS_ContinueInitReachability +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_InitReachability(void) +{ + if (!aasworld.loaded) return; + + if (aasworld.reachabilitysize) + { +#ifndef BSPC + if (!((int)LibVarGetValue("forcereachability"))) + { + aasworld.numreachabilityareas = aasworld.numareas + 2; + return; + } //end if +#else + aasworld.numreachabilityareas = aasworld.numareas + 2; + return; +#endif //BSPC + } //end if +#ifndef BSPC + calcgrapplereach = LibVarGetValue("grapplereach"); +#endif + aasworld.savefile = qtrue; + //start with area 1 because area zero is a dummy + aasworld.numreachabilityareas = 1; + ////aasworld.numreachabilityareas = aasworld.numareas + 1; //only calculate entity reachabilities + //setup the heap with reachability links + AAS_SetupReachabilityHeap(); + //allocate area reachability link array + areareachability = (aas_lreachability_t **) GetClearedMemory( + aasworld.numareas * sizeof(aas_lreachability_t *)); + // + AAS_SetWeaponJumpAreaFlags(); +} //end of the function AAS_InitReachable diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_reach.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_reach.h new file mode 100644 index 0000000..e5759a3 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_reach.h @@ -0,0 +1,75 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_aas_reach.h + * + * desc: AAS + * + * $Archive: /source/code/botlib/be_aas_reach.h $ + * $Author: Mrelusive $ + * $Revision: 2 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 10/05/99 3:42p $ + * + *****************************************************************************/ + +#pragma once + +#ifdef AASINTERN +//initialize calculating the reachabilities +void AAS_InitReachability(void); +//continue calculating the reachabilities +int AAS_ContinueInitReachability(float time); +// +int AAS_BestReachableLinkArea(aas_link_t *areas); +#endif //AASINTERN + +//returns true if the are has reachabilities to other areas +int AAS_AreaReachability(int areanum); +//returns the best reachable area and goal origin for a bounding box at the given origin +int AAS_BestReachableArea(vec3_t origin, vec3_t mins, vec3_t maxs, vec3_t goalorigin); +//returns the best jumppad area from which the bbox at origin is reachable +int AAS_BestReachableFromJumpPadArea(vec3_t origin, vec3_t mins, vec3_t maxs); +//returns the next reachability using the given model +int AAS_NextModelReachability(int num, int modelnum); +//returns the total area of the ground faces of the given area +float AAS_AreaGroundFaceArea(int areanum); +//returns true if the area is crouch only +int AAS_AreaCrouch(int areanum); +//returns true if a player can swim in this area +int AAS_AreaSwim(int areanum); +//returns true if the area is filled with a liquid +int AAS_AreaLiquid(int areanum); +//returns true if the area contains lava +int AAS_AreaLava(int areanum); +//returns true if the area contains slime +int AAS_AreaSlime(int areanum); +//returns true if the area has one or more ground faces +int AAS_AreaGrounded(int areanum); +//returns true if the area has one or more ladder faces +int AAS_AreaLadder(int areanum); +//returns true if the area is a jump pad +int AAS_AreaJumpPad(int areanum); +//returns true if the area is donotenter +int AAS_AreaDoNotEnter(int areanum); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_route.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_route.cpp new file mode 100644 index 0000000..e00e067 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_route.cpp @@ -0,0 +1,2216 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_aas_route.c + * + * desc: AAS + * + * $Archive: /MissionPack/code/botlib/be_aas_route.c $ + * $Author: Mrelusive $ + * $Revision: 18 $ + * $Modtime: 12/01/00 1:11p $ + * $Date: 12/01/00 1:11p $ + * + *****************************************************************************/ + +#include "qcommon/q_shared.h" +#include "l_utils.h" +#include "l_memory.h" +#include "l_log.h" +#include "l_crc.h" +#include "l_libvar.h" +#include "l_script.h" +#include "l_precomp.h" +#include "l_struct.h" +#include "aasfile.h" +#include "botlib.h" +#include "be_aas.h" +#include "be_aas_funcs.h" +#include "be_interface.h" +#include "be_aas_def.h" + +#define ROUTING_DEBUG + +//travel time in hundreths of a second = distance * 100 / speed +#define DISTANCEFACTOR_CROUCH 1.3f //crouch speed = 100 +#define DISTANCEFACTOR_SWIM 1 //should be 0.66, swim speed = 150 +#define DISTANCEFACTOR_WALK 0.33f //walk speed = 300 + +//cache refresh time +#define CACHE_REFRESHTIME 15.0f //15 seconds refresh time + +//maximum number of routing updates each frame +#define MAX_FRAMEROUTINGUPDATES 10 + + +/* + + area routing cache: + stores the distances within one cluster to a specific goal area + this goal area is in this same cluster and could be a cluster portal + for every cluster there's a list with routing cache for every area + in that cluster (including the portals of that cluster) + area cache stores aasworld.clusters[?].numreachabilityareas travel times + + portal routing cache: + stores the distances of all portals to a specific goal area + this goal area could be in any cluster and could also be a cluster portal + for every area (aasworld.numareas) the portal cache stores + aasworld.numportals travel times + +*/ + +#ifdef ROUTING_DEBUG +int numareacacheupdates; +int numportalcacheupdates; +#endif //ROUTING_DEBUG + +int routingcachesize; +int max_routingcachesize; + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +#ifdef ROUTING_DEBUG +void AAS_RoutingInfo(void) +{ + botimport.Print(PRT_MESSAGE, "%d area cache updates\n", numareacacheupdates); + botimport.Print(PRT_MESSAGE, "%d portal cache updates\n", numportalcacheupdates); + botimport.Print(PRT_MESSAGE, "%d bytes routing cache\n", routingcachesize); +} //end of the function AAS_RoutingInfo +#endif //ROUTING_DEBUG +//=========================================================================== +// returns the number of the area in the cluster +// assumes the given area is in the given cluster or a portal of the cluster +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +static QINLINE int AAS_ClusterAreaNum(int cluster, int areanum) +{ + int side, areacluster; + + areacluster = aasworld.areasettings[areanum].cluster; + if (areacluster > 0) return aasworld.areasettings[areanum].clusterareanum; + else + { +/*#ifdef ROUTING_DEBUG + if (aasworld.portals[-areacluster].frontcluster != cluster && + aasworld.portals[-areacluster].backcluster != cluster) + { + botimport.Print(PRT_ERROR, "portal %d: does not belong to cluster %d\n" + , -areacluster, cluster); + } //end if +#endif //ROUTING_DEBUG*/ + side = aasworld.portals[-areacluster].frontcluster != cluster; + return aasworld.portals[-areacluster].clusterareanum[side]; + } //end else +} //end of the function AAS_ClusterAreaNum +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_InitTravelFlagFromType(void) +{ + int i; + + for (i = 0; i < MAX_TRAVELTYPES; i++) + { + aasworld.travelflagfortype[i] = TFL_INVALID; + } //end for + aasworld.travelflagfortype[TRAVEL_INVALID] = TFL_INVALID; + aasworld.travelflagfortype[TRAVEL_WALK] = TFL_WALK; + aasworld.travelflagfortype[TRAVEL_CROUCH] = TFL_CROUCH; + aasworld.travelflagfortype[TRAVEL_BARRIERJUMP] = TFL_BARRIERJUMP; + aasworld.travelflagfortype[TRAVEL_JUMP] = TFL_JUMP; + aasworld.travelflagfortype[TRAVEL_LADDER] = TFL_LADDER; + aasworld.travelflagfortype[TRAVEL_WALKOFFLEDGE] = TFL_WALKOFFLEDGE; + aasworld.travelflagfortype[TRAVEL_SWIM] = TFL_SWIM; + aasworld.travelflagfortype[TRAVEL_WATERJUMP] = TFL_WATERJUMP; + aasworld.travelflagfortype[TRAVEL_TELEPORT] = TFL_TELEPORT; + aasworld.travelflagfortype[TRAVEL_ELEVATOR] = TFL_ELEVATOR; + aasworld.travelflagfortype[TRAVEL_ROCKETJUMP] = TFL_ROCKETJUMP; + aasworld.travelflagfortype[TRAVEL_BFGJUMP] = TFL_BFGJUMP; + aasworld.travelflagfortype[TRAVEL_GRAPPLEHOOK] = TFL_GRAPPLEHOOK; + aasworld.travelflagfortype[TRAVEL_DOUBLEJUMP] = TFL_DOUBLEJUMP; + aasworld.travelflagfortype[TRAVEL_RAMPJUMP] = TFL_RAMPJUMP; + aasworld.travelflagfortype[TRAVEL_STRAFEJUMP] = TFL_STRAFEJUMP; + aasworld.travelflagfortype[TRAVEL_JUMPPAD] = TFL_JUMPPAD; + aasworld.travelflagfortype[TRAVEL_FUNCBOB] = TFL_FUNCBOB; +} //end of the function AAS_InitTravelFlagFromType +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +static QINLINE int AAS_TravelFlagForType_inline(int traveltype) +{ + int tfl; + + tfl = 0; + if (tfl & TRAVELFLAG_NOTTEAM1) + tfl |= TFL_NOTTEAM1; + if (tfl & TRAVELFLAG_NOTTEAM2) + tfl |= TFL_NOTTEAM2; + traveltype &= TRAVELTYPE_MASK; + if (traveltype < 0 || traveltype >= MAX_TRAVELTYPES) + return TFL_INVALID; + tfl |= aasworld.travelflagfortype[traveltype]; + return tfl; +} //end of the function AAS_TravelFlagForType_inline +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_TravelFlagForType(int traveltype) +{ + return AAS_TravelFlagForType_inline(traveltype); +} //end of the function AAS_TravelFlagForType_inline +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_UnlinkCache(aas_routingcache_t *cache) +{ + if (cache->time_next) cache->time_next->time_prev = cache->time_prev; + else aasworld.newestcache = cache->time_prev; + if (cache->time_prev) cache->time_prev->time_next = cache->time_next; + else aasworld.oldestcache = cache->time_next; + cache->time_next = NULL; + cache->time_prev = NULL; +} //end of the function AAS_UnlinkCache +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_LinkCache(aas_routingcache_t *cache) +{ + if (aasworld.newestcache) + { + aasworld.newestcache->time_next = cache; + cache->time_prev = aasworld.newestcache; + } //end if + else + { + aasworld.oldestcache = cache; + cache->time_prev = NULL; + } //end else + cache->time_next = NULL; + aasworld.newestcache = cache; +} //end of the function AAS_LinkCache +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_FreeRoutingCache(aas_routingcache_t *cache) +{ + AAS_UnlinkCache(cache); + routingcachesize -= cache->size; + FreeMemory(cache); +} //end of the function AAS_FreeRoutingCache +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_RemoveRoutingCacheInCluster( int clusternum ) +{ + int i; + aas_routingcache_t *cache, *nextcache; + aas_cluster_t *cluster; + + if (!aasworld.clusterareacache) + return; + cluster = &aasworld.clusters[clusternum]; + for (i = 0; i < cluster->numareas; i++) + { + for (cache = aasworld.clusterareacache[clusternum][i]; cache; cache = nextcache) + { + nextcache = cache->next; + AAS_FreeRoutingCache(cache); + } //end for + aasworld.clusterareacache[clusternum][i] = NULL; + } //end for +} //end of the function AAS_RemoveRoutingCacheInCluster +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_RemoveRoutingCacheUsingArea( int areanum ) +{ + int i, clusternum; + aas_routingcache_t *cache, *nextcache; + + clusternum = aasworld.areasettings[areanum].cluster; + if (clusternum > 0) + { + //remove all the cache in the cluster the area is in + AAS_RemoveRoutingCacheInCluster( clusternum ); + } //end if + else + { + // if this is a portal remove all cache in both the front and back cluster + AAS_RemoveRoutingCacheInCluster( aasworld.portals[-clusternum].frontcluster ); + AAS_RemoveRoutingCacheInCluster( aasworld.portals[-clusternum].backcluster ); + } //end else + // remove all portal cache + for (i = 0; i < aasworld.numareas; i++) + { + //refresh portal cache + for (cache = aasworld.portalcache[i]; cache; cache = nextcache) + { + nextcache = cache->next; + AAS_FreeRoutingCache(cache); + } //end for + aasworld.portalcache[i] = NULL; + } //end for +} //end of the function AAS_RemoveRoutingCacheUsingArea +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_EnableRoutingArea(int areanum, int enable) +{ + int flags; + + if (areanum <= 0 || areanum >= aasworld.numareas) + { + if (botDeveloper) + { + botimport.Print(PRT_ERROR, "AAS_EnableRoutingArea: areanum %d out of range\n", areanum); + } //end if + return 0; + } //end if + flags = aasworld.areasettings[areanum].areaflags & AREA_DISABLED; + if (enable < 0) + return !flags; + + if (enable) + aasworld.areasettings[areanum].areaflags &= ~AREA_DISABLED; + else + aasworld.areasettings[areanum].areaflags |= AREA_DISABLED; + // if the status of the area changed + if ( (flags & AREA_DISABLED) != (aasworld.areasettings[areanum].areaflags & AREA_DISABLED) ) + { + //remove all routing cache involving this area + AAS_RemoveRoutingCacheUsingArea( areanum ); + } //end if + return !flags; +} //end of the function AAS_EnableRoutingArea +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +static QINLINE float AAS_RoutingTime(void) +{ + return AAS_Time(); +} //end of the function AAS_RoutingTime +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_GetAreaContentsTravelFlags(int areanum) +{ + int contents, tfl; + + contents = aasworld.areasettings[areanum].contents; + tfl = 0; + if (contents & AREACONTENTS_WATER) + tfl |= TFL_WATER; + else if (contents & AREACONTENTS_SLIME) + tfl |= TFL_SLIME; + else if (contents & AREACONTENTS_LAVA) + tfl |= TFL_LAVA; + else + tfl |= TFL_AIR; + if (contents & AREACONTENTS_DONOTENTER) + tfl |= TFL_DONOTENTER; + if (contents & AREACONTENTS_NOTTEAM1) + tfl |= TFL_NOTTEAM1; + if (contents & AREACONTENTS_NOTTEAM2) + tfl |= TFL_NOTTEAM2; + if (aasworld.areasettings[areanum].areaflags & AREA_BRIDGE) + tfl |= TFL_BRIDGE; + return tfl; +} //end of the function AAS_GetAreaContentsTravelFlags +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +static QINLINE int AAS_AreaContentsTravelFlags_inline(int areanum) +{ + return aasworld.areacontentstravelflags[areanum]; +} //end of the function AAS_AreaContentsTravelFlags +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_AreaContentsTravelFlags(int areanum) +{ + return aasworld.areacontentstravelflags[areanum]; +} //end of the function AAS_AreaContentsTravelFlags +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_InitAreaContentsTravelFlags(void) +{ + int i; + + if (aasworld.areacontentstravelflags) FreeMemory(aasworld.areacontentstravelflags); + aasworld.areacontentstravelflags = (int *) GetClearedMemory(aasworld.numareas * sizeof(int)); + // + for (i = 0; i < aasworld.numareas; i++) { + aasworld.areacontentstravelflags[i] = AAS_GetAreaContentsTravelFlags(i); + } +} //end of the function AAS_InitAreaContentsTravelFlags +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_CreateReversedReachability(void) +{ + int i, n; + aas_reversedlink_t *revlink; + aas_reachability_t *reach; + aas_areasettings_t *settings; + char *ptr; +#ifdef DEBUG + int starttime; + + starttime = Sys_MilliSeconds(); +#endif + //free reversed links that have already been created + if (aasworld.reversedreachability) FreeMemory(aasworld.reversedreachability); + //allocate memory for the reversed reachability links + ptr = (char *) GetClearedMemory(aasworld.numareas * sizeof(aas_reversedreachability_t) + + aasworld.reachabilitysize * sizeof(aas_reversedlink_t)); + // + aasworld.reversedreachability = (aas_reversedreachability_t *) ptr; + //pointer to the memory for the reversed links + ptr += aasworld.numareas * sizeof(aas_reversedreachability_t); + //check all reachabilities of all areas + for (i = 1; i < aasworld.numareas; i++) + { + //settings of the area + settings = &aasworld.areasettings[i]; + // + if (settings->numreachableareas >= 128) + botimport.Print(PRT_WARNING, "area %d has more than 128 reachabilities\n", i); + //create reversed links for the reachabilities + for (n = 0; n < settings->numreachableareas && n < 128; n++) + { + //reachability link + reach = &aasworld.reachability[settings->firstreachablearea + n]; + // + revlink = (aas_reversedlink_t *) ptr; + ptr += sizeof(aas_reversedlink_t); + // + revlink->areanum = i; + revlink->linknum = settings->firstreachablearea + n; + revlink->next = aasworld.reversedreachability[reach->areanum].first; + aasworld.reversedreachability[reach->areanum].first = revlink; + aasworld.reversedreachability[reach->areanum].numlinks++; + } //end for + } //end for +#ifdef DEBUG + botimport.Print(PRT_MESSAGE, "reversed reachability %d msec\n", Sys_MilliSeconds() - starttime); +#endif +} //end of the function AAS_CreateReversedReachability +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +unsigned short int AAS_AreaTravelTime(int areanum, vec3_t start, vec3_t end) +{ + int intdist; + float dist; + vec3_t dir; + + VectorSubtract(start, end, dir); + dist = VectorLength(dir); + //if crouch only area + if (AAS_AreaCrouch(areanum)) dist *= DISTANCEFACTOR_CROUCH; + //if swim area + else if (AAS_AreaSwim(areanum)) dist *= DISTANCEFACTOR_SWIM; + //normal walk area + else dist *= DISTANCEFACTOR_WALK; + // + intdist = (int) dist; + //make sure the distance isn't zero + if (intdist <= 0) intdist = 1; + return intdist; +} //end of the function AAS_AreaTravelTime +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_CalculateAreaTravelTimes(void) +{ + int i, l, n, size; + char *ptr; + vec3_t end; + aas_reversedreachability_t *revreach; + aas_reversedlink_t *revlink; + aas_reachability_t *reach; + aas_areasettings_t *settings; +#ifdef DEBUG + int starttime; + + starttime = Sys_MilliSeconds(); +#endif + //if there are still area travel times, free the memory + if (aasworld.areatraveltimes) FreeMemory(aasworld.areatraveltimes); + //get the total size of all the area travel times + size = aasworld.numareas * sizeof(unsigned short **); + for (i = 0; i < aasworld.numareas; i++) + { + revreach = &aasworld.reversedreachability[i]; + //settings of the area + settings = &aasworld.areasettings[i]; + // + size += settings->numreachableareas * sizeof(unsigned short *); + // + size += settings->numreachableareas * + PAD(revreach->numlinks, sizeof(long)) * sizeof(unsigned short); + } //end for + //allocate memory for the area travel times + ptr = (char *) GetClearedMemory(size); + aasworld.areatraveltimes = (unsigned short ***) ptr; + ptr += aasworld.numareas * sizeof(unsigned short **); + //calcluate the travel times for all the areas + for (i = 0; i < aasworld.numareas; i++) + { + //reversed reachabilities of this area + revreach = &aasworld.reversedreachability[i]; + //settings of the area + settings = &aasworld.areasettings[i]; + // + aasworld.areatraveltimes[i] = (unsigned short **) ptr; + ptr += settings->numreachableareas * sizeof(unsigned short *); + // + for (l = 0; l < settings->numreachableareas; l++) + { + aasworld.areatraveltimes[i][l] = (unsigned short *) ptr; + ptr += PAD(revreach->numlinks, sizeof(long)) * sizeof(unsigned short); + //reachability link + reach = &aasworld.reachability[settings->firstreachablearea + l]; + // + for (n = 0, revlink = revreach->first; revlink; revlink = revlink->next, n++) + { + VectorCopy(aasworld.reachability[revlink->linknum].end, end); + // + aasworld.areatraveltimes[i][l][n] = AAS_AreaTravelTime(i, end, reach->start); + } //end for + } //end for + } //end for +#ifdef DEBUG + botimport.Print(PRT_MESSAGE, "area travel times %d msec\n", Sys_MilliSeconds() - starttime); +#endif +} //end of the function AAS_CalculateAreaTravelTimes +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_PortalMaxTravelTime(int portalnum) +{ + int l, n, t, maxt; + aas_portal_t *portal; + aas_reversedreachability_t *revreach; + aas_reversedlink_t *revlink; + aas_areasettings_t *settings; + + portal = &aasworld.portals[portalnum]; + //reversed reachabilities of this portal area + revreach = &aasworld.reversedreachability[portal->areanum]; + //settings of the portal area + settings = &aasworld.areasettings[portal->areanum]; + // + maxt = 0; + for (l = 0; l < settings->numreachableareas; l++) + { + for (n = 0, revlink = revreach->first; revlink; revlink = revlink->next, n++) + { + t = aasworld.areatraveltimes[portal->areanum][l][n]; + if (t > maxt) + { + maxt = t; + } //end if + } //end for + } //end for + return maxt; +} //end of the function AAS_PortalMaxTravelTime +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_InitPortalMaxTravelTimes(void) +{ + int i; + + if (aasworld.portalmaxtraveltimes) FreeMemory(aasworld.portalmaxtraveltimes); + + aasworld.portalmaxtraveltimes = (int *) GetClearedMemory(aasworld.numportals * sizeof(int)); + + for (i = 0; i < aasworld.numportals; i++) + { + aasworld.portalmaxtraveltimes[i] = AAS_PortalMaxTravelTime(i); + //botimport.Print(PRT_MESSAGE, "portal %d max tt = %d\n", i, aasworld.portalmaxtraveltimes[i]); + } //end for +} //end of the function AAS_InitPortalMaxTravelTimes +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +/* +int AAS_FreeOldestCache(void) +{ + int i, j, bestcluster, bestarea, freed; + float besttime; + aas_routingcache_t *cache, *bestcache; + + freed = qfalse; + besttime = 999999999; + bestcache = NULL; + bestcluster = 0; + bestarea = 0; + //refresh cluster cache + for (i = 0; i < aasworld.numclusters; i++) + { + for (j = 0; j < aasworld.clusters[i].numareas; j++) + { + for (cache = aasworld.clusterareacache[i][j]; cache; cache = cache->next) + { + //never remove cache leading towards a portal + if (aasworld.areasettings[cache->areanum].cluster < 0) continue; + //if this cache is older than the cache we found so far + if (cache->time < besttime) + { + bestcache = cache; + bestcluster = i; + bestarea = j; + besttime = cache->time; + } //end if + } //end for + } //end for + } //end for + if (bestcache) + { + cache = bestcache; + if (cache->prev) cache->prev->next = cache->next; + else aasworld.clusterareacache[bestcluster][bestarea] = cache->next; + if (cache->next) cache->next->prev = cache->prev; + AAS_FreeRoutingCache(cache); + freed = qtrue; + } //end if + besttime = 999999999; + bestcache = NULL; + bestarea = 0; + for (i = 0; i < aasworld.numareas; i++) + { + //refresh portal cache + for (cache = aasworld.portalcache[i]; cache; cache = cache->next) + { + if (cache->time < besttime) + { + bestcache = cache; + bestarea = i; + besttime = cache->time; + } //end if + } //end for + } //end for + if (bestcache) + { + cache = bestcache; + if (cache->prev) cache->prev->next = cache->next; + else aasworld.portalcache[bestarea] = cache->next; + if (cache->next) cache->next->prev = cache->prev; + AAS_FreeRoutingCache(cache); + freed = qtrue; + } //end if + return freed; +} //end of the function AAS_FreeOldestCache +*/ +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_FreeOldestCache(void) +{ + int clusterareanum; + aas_routingcache_t *cache; + + for (cache = aasworld.oldestcache; cache; cache = cache->time_next) { + // never free area cache leading towards a portal + if (cache->type == CACHETYPE_AREA && aasworld.areasettings[cache->areanum].cluster < 0) { + continue; + } + break; + } + if (cache) { + // unlink the cache + if (cache->type == CACHETYPE_AREA) { + //number of the area in the cluster + clusterareanum = AAS_ClusterAreaNum(cache->cluster, cache->areanum); + // unlink from cluster area cache + if (cache->prev) cache->prev->next = cache->next; + else aasworld.clusterareacache[cache->cluster][clusterareanum] = cache->next; + if (cache->next) cache->next->prev = cache->prev; + } + else { + // unlink from portal cache + if (cache->prev) cache->prev->next = cache->next; + else aasworld.portalcache[cache->areanum] = cache->next; + if (cache->next) cache->next->prev = cache->prev; + } + AAS_FreeRoutingCache(cache); + return qtrue; + } + return qfalse; +} //end of the function AAS_FreeOldestCache +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +aas_routingcache_t *AAS_AllocRoutingCache(int numtraveltimes) +{ + aas_routingcache_t *cache; + int size; + + // + size = sizeof(aas_routingcache_t) + + numtraveltimes * sizeof(unsigned short int) + + numtraveltimes * sizeof(unsigned char); + // + routingcachesize += size; + // + cache = (aas_routingcache_t *) GetClearedMemory(size); + cache->reachabilities = (unsigned char *) cache + sizeof(aas_routingcache_t) + + numtraveltimes * sizeof(unsigned short int); + cache->size = size; + return cache; +} //end of the function AAS_AllocRoutingCache +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_FreeAllClusterAreaCache(void) +{ + int i, j; + aas_routingcache_t *cache, *nextcache; + aas_cluster_t *cluster; + + //free all cluster cache if existing + if (!aasworld.clusterareacache) return; + //free caches + for (i = 0; i < aasworld.numclusters; i++) + { + cluster = &aasworld.clusters[i]; + for (j = 0; j < cluster->numareas; j++) + { + for (cache = aasworld.clusterareacache[i][j]; cache; cache = nextcache) + { + nextcache = cache->next; + AAS_FreeRoutingCache(cache); + } //end for + aasworld.clusterareacache[i][j] = NULL; + } //end for + } //end for + //free the cluster cache array + FreeMemory(aasworld.clusterareacache); + aasworld.clusterareacache = NULL; +} //end of the function AAS_FreeAllClusterAreaCache +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_InitClusterAreaCache(void) +{ + int i, size; + char *ptr; + + // + for (size = 0, i = 0; i < aasworld.numclusters; i++) + { + size += aasworld.clusters[i].numareas; + } //end for + //two dimensional array with pointers for every cluster to routing cache + //for every area in that cluster + ptr = (char *) GetClearedMemory( + aasworld.numclusters * sizeof(aas_routingcache_t **) + + size * sizeof(aas_routingcache_t *)); + aasworld.clusterareacache = (aas_routingcache_t ***) ptr; + ptr += aasworld.numclusters * sizeof(aas_routingcache_t **); + for (i = 0; i < aasworld.numclusters; i++) + { + aasworld.clusterareacache[i] = (aas_routingcache_t **) ptr; + ptr += aasworld.clusters[i].numareas * sizeof(aas_routingcache_t *); + } //end for +} //end of the function AAS_InitClusterAreaCache +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_FreeAllPortalCache(void) +{ + int i; + aas_routingcache_t *cache, *nextcache; + + //free all portal cache if existing + if (!aasworld.portalcache) return; + //free portal caches + for (i = 0; i < aasworld.numareas; i++) + { + for (cache = aasworld.portalcache[i]; cache; cache = nextcache) + { + nextcache = cache->next; + AAS_FreeRoutingCache(cache); + } //end for + aasworld.portalcache[i] = NULL; + } //end for + FreeMemory(aasworld.portalcache); + aasworld.portalcache = NULL; +} //end of the function AAS_FreeAllPortalCache +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_InitPortalCache(void) +{ + // + aasworld.portalcache = (aas_routingcache_t **) GetClearedMemory( + aasworld.numareas * sizeof(aas_routingcache_t *)); +} //end of the function AAS_InitPortalCache +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_InitRoutingUpdate(void) +{ + int i, maxreachabilityareas; + + //free routing update fields if already existing + if (aasworld.areaupdate) FreeMemory(aasworld.areaupdate); + // + maxreachabilityareas = 0; + for (i = 0; i < aasworld.numclusters; i++) + { + if (aasworld.clusters[i].numreachabilityareas > maxreachabilityareas) + { + maxreachabilityareas = aasworld.clusters[i].numreachabilityareas; + } //end if + } //end for + //allocate memory for the routing update fields + aasworld.areaupdate = (aas_routingupdate_t *) GetClearedMemory( + maxreachabilityareas * sizeof(aas_routingupdate_t)); + // + if (aasworld.portalupdate) FreeMemory(aasworld.portalupdate); + //allocate memory for the portal update fields + aasworld.portalupdate = (aas_routingupdate_t *) GetClearedMemory( + (aasworld.numportals+1) * sizeof(aas_routingupdate_t)); +} //end of the function AAS_InitRoutingUpdate +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_CreateAllRoutingCache(void) +{ + int i, j; + //int t; + + aasworld.initialized = qtrue; + botimport.Print(PRT_MESSAGE, "AAS_CreateAllRoutingCache\n"); + for (i = 1; i < aasworld.numareas; i++) + { + if (!AAS_AreaReachability(i)) continue; + for (j = 1; j < aasworld.numareas; j++) + { + if (i == j) continue; + if (!AAS_AreaReachability(j)) continue; + AAS_AreaTravelTimeToGoalArea(i, aasworld.areas[i].center, j, TFL_DEFAULT); + //t = AAS_AreaTravelTimeToGoalArea(i, aasworld.areas[i].center, j, TFL_DEFAULT); + //Log_Write("traveltime from %d to %d is %d", i, j, t); + } //end for + } //end for + aasworld.initialized = qfalse; +} //end of the function AAS_CreateAllRoutingCache +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== + +//the route cache header +//this header is followed by numportalcache + numareacache aas_routingcache_t +//structures that store routing cache +typedef struct routecacheheader_s +{ + int ident; + int version; + int numareas; + int numclusters; + int areacrc; + int clustercrc; + int numportalcache; + int numareacache; +} routecacheheader_t; + +#define RCID (('C'<<24)+('R'<<16)+('E'<<8)+'M') +#define RCVERSION 2 + +void AAS_WriteRouteCache(void) +{ + int i, j, numportalcache, numareacache, totalsize; + aas_routingcache_t *cache; + aas_cluster_t *cluster; + fileHandle_t fp; + char filename[MAX_QPATH]; + routecacheheader_t routecacheheader; + + numportalcache = 0; + for (i = 0; i < aasworld.numareas; i++) + { + for (cache = aasworld.portalcache[i]; cache; cache = cache->next) + { + numportalcache++; + } //end for + } //end for + numareacache = 0; + for (i = 0; i < aasworld.numclusters; i++) + { + cluster = &aasworld.clusters[i]; + for (j = 0; j < cluster->numareas; j++) + { + for (cache = aasworld.clusterareacache[i][j]; cache; cache = cache->next) + { + numareacache++; + } //end for + } //end for + } //end for + // open the file for writing + Com_sprintf(filename, MAX_QPATH, "maps/%s.rcd", aasworld.mapname); + botimport.FS_FOpenFile( filename, &fp, FS_WRITE ); + if (!fp) + { + AAS_Error("Unable to open file: %s\n", filename); + return; + } //end if + //create the header + routecacheheader.ident = RCID; + routecacheheader.version = RCVERSION; + routecacheheader.numareas = aasworld.numareas; + routecacheheader.numclusters = aasworld.numclusters; + routecacheheader.areacrc = CRC_ProcessString( (unsigned char *)aasworld.areas, sizeof(aas_area_t) * aasworld.numareas ); + routecacheheader.clustercrc = CRC_ProcessString( (unsigned char *)aasworld.clusters, sizeof(aas_cluster_t) * aasworld.numclusters ); + routecacheheader.numportalcache = numportalcache; + routecacheheader.numareacache = numareacache; + //write the header + botimport.FS_Write(&routecacheheader, sizeof(routecacheheader_t), fp); + // + totalsize = 0; + //write all the cache + for (i = 0; i < aasworld.numareas; i++) + { + for (cache = aasworld.portalcache[i]; cache; cache = cache->next) + { + botimport.FS_Write(cache, cache->size, fp); + totalsize += cache->size; + } //end for + } //end for + for (i = 0; i < aasworld.numclusters; i++) + { + cluster = &aasworld.clusters[i]; + for (j = 0; j < cluster->numareas; j++) + { + for (cache = aasworld.clusterareacache[i][j]; cache; cache = cache->next) + { + botimport.FS_Write(cache, cache->size, fp); + totalsize += cache->size; + } //end for + } //end for + } //end for + // write the visareas + /* + for (i = 0; i < aasworld.numareas; i++) + { + if (!aasworld.areavisibility[i]) { + size = 0; + botimport.FS_Write(&size, sizeof(int), fp); + continue; + } + AAS_DecompressVis( aasworld.areavisibility[i], aasworld.numareas, aasworld.decompressedvis ); + size = AAS_CompressVis( aasworld.decompressedvis, aasworld.numareas, aasworld.decompressedvis ); + botimport.FS_Write(&size, sizeof(int), fp); + botimport.FS_Write(aasworld.decompressedvis, size, fp); + } + */ + // + botimport.FS_FCloseFile(fp); + botimport.Print(PRT_MESSAGE, "\nroute cache written to %s\n", filename); + botimport.Print(PRT_MESSAGE, "written %d bytes of routing cache\n", totalsize); +} //end of the function AAS_WriteRouteCache +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +aas_routingcache_t *AAS_ReadCache(fileHandle_t fp) +{ + int size; + aas_routingcache_t *cache; + + botimport.FS_Read(&size, sizeof(size), fp); + cache = (aas_routingcache_t *) GetMemory(size); + cache->size = size; + botimport.FS_Read((unsigned char *)cache + sizeof(size), size - sizeof(size), fp); + cache->reachabilities = (unsigned char *) cache + sizeof(aas_routingcache_t) - sizeof(unsigned short) + + (size - sizeof(aas_routingcache_t) + sizeof(unsigned short)) / 3 * 2; + return cache; +} //end of the function AAS_ReadCache +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_ReadRouteCache(void) +{ + int i, clusterareanum;//, size; + fileHandle_t fp; + char filename[MAX_QPATH]; + routecacheheader_t routecacheheader; + aas_routingcache_t *cache; + + Com_sprintf(filename, MAX_QPATH, "maps/%s.rcd", aasworld.mapname); + botimport.FS_FOpenFile( filename, &fp, FS_READ ); + if (!fp) + { + return qfalse; + } //end if + botimport.FS_Read(&routecacheheader, sizeof(routecacheheader_t), fp ); + if (routecacheheader.ident != RCID) + { + AAS_Error("%s is not a route cache dump\n", filename); + return qfalse; + } //end if + if (routecacheheader.version != RCVERSION) + { + AAS_Error("route cache dump has wrong version %d, should be %d", routecacheheader.version, RCVERSION); + return qfalse; + } //end if + if (routecacheheader.numareas != aasworld.numareas) + { + //AAS_Error("route cache dump has wrong number of areas\n"); + return qfalse; + } //end if + if (routecacheheader.numclusters != aasworld.numclusters) + { + //AAS_Error("route cache dump has wrong number of clusters\n"); + return qfalse; + } //end if + if (routecacheheader.areacrc != + CRC_ProcessString( (unsigned char *)aasworld.areas, sizeof(aas_area_t) * aasworld.numareas )) + { + //AAS_Error("route cache dump area CRC incorrect\n"); + return qfalse; + } //end if + if (routecacheheader.clustercrc != + CRC_ProcessString( (unsigned char *)aasworld.clusters, sizeof(aas_cluster_t) * aasworld.numclusters )) + { + //AAS_Error("route cache dump cluster CRC incorrect\n"); + return qfalse; + } //end if + //read all the portal cache + for (i = 0; i < routecacheheader.numportalcache; i++) + { + cache = AAS_ReadCache(fp); + cache->next = aasworld.portalcache[cache->areanum]; + cache->prev = NULL; + if (aasworld.portalcache[cache->areanum]) + aasworld.portalcache[cache->areanum]->prev = cache; + aasworld.portalcache[cache->areanum] = cache; + } //end for + //read all the cluster area cache + for (i = 0; i < routecacheheader.numareacache; i++) + { + cache = AAS_ReadCache(fp); + clusterareanum = AAS_ClusterAreaNum(cache->cluster, cache->areanum); + cache->next = aasworld.clusterareacache[cache->cluster][clusterareanum]; + cache->prev = NULL; + if (aasworld.clusterareacache[cache->cluster][clusterareanum]) + aasworld.clusterareacache[cache->cluster][clusterareanum]->prev = cache; + aasworld.clusterareacache[cache->cluster][clusterareanum] = cache; + } //end for + // read the visareas + /* + aasworld.areavisibility = (byte **) GetClearedMemory(aasworld.numareas * sizeof(byte *)); + aasworld.decompressedvis = (byte *) GetClearedMemory(aasworld.numareas * sizeof(byte)); + for (i = 0; i < aasworld.numareas; i++) + { + botimport.FS_Read(&size, sizeof(size), fp ); + if (size) { + aasworld.areavisibility[i] = (byte *) GetMemory(size); + botimport.FS_Read(aasworld.areavisibility[i], size, fp ); + } + } + */ + // + botimport.FS_FCloseFile(fp); + return qtrue; +} //end of the function AAS_ReadRouteCache +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +#define MAX_REACHABILITYPASSAREAS 32 + +void AAS_InitReachabilityAreas(void) +{ + int i, j, numareas, areas[MAX_REACHABILITYPASSAREAS]; + int numreachareas; + aas_reachability_t *reach; + vec3_t start, end; + + if (aasworld.reachabilityareas) + FreeMemory(aasworld.reachabilityareas); + if (aasworld.reachabilityareaindex) + FreeMemory(aasworld.reachabilityareaindex); + + aasworld.reachabilityareas = (aas_reachabilityareas_t *) + GetClearedMemory(aasworld.reachabilitysize * sizeof(aas_reachabilityareas_t)); + aasworld.reachabilityareaindex = (int *) + GetClearedMemory(aasworld.reachabilitysize * MAX_REACHABILITYPASSAREAS * sizeof(int)); + numreachareas = 0; + for (i = 0; i < aasworld.reachabilitysize; i++) + { + reach = &aasworld.reachability[i]; + numareas = 0; + switch(reach->traveltype & TRAVELTYPE_MASK) + { + //trace areas from start to end + case TRAVEL_BARRIERJUMP: + case TRAVEL_WATERJUMP: + VectorCopy(reach->start, end); + end[2] = reach->end[2]; + numareas = AAS_TraceAreas(reach->start, end, areas, NULL, MAX_REACHABILITYPASSAREAS); + break; + case TRAVEL_WALKOFFLEDGE: + VectorCopy(reach->end, start); + start[2] = reach->start[2]; + numareas = AAS_TraceAreas(start, reach->end, areas, NULL, MAX_REACHABILITYPASSAREAS); + break; + case TRAVEL_GRAPPLEHOOK: + numareas = AAS_TraceAreas(reach->start, reach->end, areas, NULL, MAX_REACHABILITYPASSAREAS); + break; + + //trace arch + case TRAVEL_JUMP: break; + case TRAVEL_ROCKETJUMP: break; + case TRAVEL_BFGJUMP: break; + case TRAVEL_JUMPPAD: break; + + //trace from reach->start to entity center, along entity movement + //and from entity center to reach->end + case TRAVEL_ELEVATOR: break; + case TRAVEL_FUNCBOB: break; + + //no areas in between + case TRAVEL_WALK: break; + case TRAVEL_CROUCH: break; + case TRAVEL_LADDER: break; + case TRAVEL_SWIM: break; + case TRAVEL_TELEPORT: break; + default: break; + } //end switch + aasworld.reachabilityareas[i].firstarea = numreachareas; + aasworld.reachabilityareas[i].numareas = numareas; + for (j = 0; j < numareas; j++) + { + aasworld.reachabilityareaindex[numreachareas++] = areas[j]; + } //end for + } //end for +} //end of the function AAS_InitReachabilityAreas +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_InitRouting(void) +{ + AAS_InitTravelFlagFromType(); + // + AAS_InitAreaContentsTravelFlags(); + //initialize the routing update fields + AAS_InitRoutingUpdate(); + //create reversed reachability links used by the routing update algorithm + AAS_CreateReversedReachability(); + //initialize the cluster cache + AAS_InitClusterAreaCache(); + //initialize portal cache + AAS_InitPortalCache(); + //initialize the area travel times + AAS_CalculateAreaTravelTimes(); + //calculate the maximum travel times through portals + AAS_InitPortalMaxTravelTimes(); + //get the areas reachabilities go through + AAS_InitReachabilityAreas(); + // +#ifdef ROUTING_DEBUG + numareacacheupdates = 0; + numportalcacheupdates = 0; +#endif //ROUTING_DEBUG + // + routingcachesize = 0; + max_routingcachesize = 1024 * (int) LibVarValue("max_routingcache", "4096"); + // read any routing cache if available + AAS_ReadRouteCache(); +} //end of the function AAS_InitRouting +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_FreeRoutingCaches(void) +{ + // free all the existing cluster area cache + AAS_FreeAllClusterAreaCache(); + // free all the existing portal cache + AAS_FreeAllPortalCache(); + // free cached travel times within areas + if (aasworld.areatraveltimes) FreeMemory(aasworld.areatraveltimes); + aasworld.areatraveltimes = NULL; + // free cached maximum travel time through cluster portals + if (aasworld.portalmaxtraveltimes) FreeMemory(aasworld.portalmaxtraveltimes); + aasworld.portalmaxtraveltimes = NULL; + // free reversed reachability links + if (aasworld.reversedreachability) FreeMemory(aasworld.reversedreachability); + aasworld.reversedreachability = NULL; + // free routing algorithm memory + if (aasworld.areaupdate) FreeMemory(aasworld.areaupdate); + aasworld.areaupdate = NULL; + if (aasworld.portalupdate) FreeMemory(aasworld.portalupdate); + aasworld.portalupdate = NULL; + // free lists with areas the reachabilities go through + if (aasworld.reachabilityareas) FreeMemory(aasworld.reachabilityareas); + aasworld.reachabilityareas = NULL; + // free the reachability area index + if (aasworld.reachabilityareaindex) FreeMemory(aasworld.reachabilityareaindex); + aasworld.reachabilityareaindex = NULL; + // free area contents travel flags look up table + if (aasworld.areacontentstravelflags) FreeMemory(aasworld.areacontentstravelflags); + aasworld.areacontentstravelflags = NULL; +} //end of the function AAS_FreeRoutingCaches +//=========================================================================== +// update the given routing cache +// +// Parameter: areacache : routing cache to update +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_UpdateAreaRoutingCache(aas_routingcache_t *areacache) +{ + int i, nextareanum, cluster, badtravelflags, clusterareanum, linknum; + int numreachabilityareas; + unsigned short int t, startareatraveltimes[128]; //NOTE: not more than 128 reachabilities per area allowed + aas_routingupdate_t *updateliststart, *updatelistend, *curupdate, *nextupdate; + aas_reachability_t *reach; + aas_reversedreachability_t *revreach; + aas_reversedlink_t *revlink; + +#ifdef ROUTING_DEBUG + numareacacheupdates++; +#endif //ROUTING_DEBUG + //number of reachability areas within this cluster + numreachabilityareas = aasworld.clusters[areacache->cluster].numreachabilityareas; + // + aasworld.frameroutingupdates++; + //clear the routing update fields +// Com_Memset(aasworld.areaupdate, 0, aasworld.numareas * sizeof(aas_routingupdate_t)); + // + badtravelflags = ~areacache->travelflags; + // + clusterareanum = AAS_ClusterAreaNum(areacache->cluster, areacache->areanum); + if (clusterareanum >= numreachabilityareas) return; + // + Com_Memset(startareatraveltimes, 0, sizeof(startareatraveltimes)); + // + curupdate = &aasworld.areaupdate[clusterareanum]; + curupdate->areanum = areacache->areanum; + //VectorCopy(areacache->origin, curupdate->start); + curupdate->areatraveltimes = startareatraveltimes; + curupdate->tmptraveltime = areacache->starttraveltime; + // + areacache->traveltimes[clusterareanum] = areacache->starttraveltime; + //put the area to start with in the current read list + curupdate->next = NULL; + curupdate->prev = NULL; + updateliststart = curupdate; + updatelistend = curupdate; + //while there are updates in the current list + while (updateliststart) + { + curupdate = updateliststart; + // + if (curupdate->next) curupdate->next->prev = NULL; + else updatelistend = NULL; + updateliststart = curupdate->next; + // + curupdate->inlist = qfalse; + //check all reversed reachability links + revreach = &aasworld.reversedreachability[curupdate->areanum]; + // + for (i = 0, revlink = revreach->first; revlink; revlink = revlink->next, i++) + { + linknum = revlink->linknum; + reach = &aasworld.reachability[linknum]; + //if there is used an undesired travel type + if (AAS_TravelFlagForType_inline(reach->traveltype) & badtravelflags) continue; + //if not allowed to enter the next area + if (aasworld.areasettings[reach->areanum].areaflags & AREA_DISABLED) continue; + //if the next area has a not allowed travel flag + if (AAS_AreaContentsTravelFlags_inline(reach->areanum) & badtravelflags) continue; + //number of the area the reversed reachability leads to + nextareanum = revlink->areanum; + //get the cluster number of the area + cluster = aasworld.areasettings[nextareanum].cluster; + //don't leave the cluster + if (cluster > 0 && cluster != areacache->cluster) continue; + //get the number of the area in the cluster + clusterareanum = AAS_ClusterAreaNum(areacache->cluster, nextareanum); + if (clusterareanum >= numreachabilityareas) continue; + //time already travelled plus the traveltime through + //the current area plus the travel time from the reachability + t = curupdate->tmptraveltime + + //AAS_AreaTravelTime(curupdate->areanum, curupdate->start, reach->end) + + curupdate->areatraveltimes[i] + + reach->traveltime; + // + if (!areacache->traveltimes[clusterareanum] || + areacache->traveltimes[clusterareanum] > t) + { + areacache->traveltimes[clusterareanum] = t; + areacache->reachabilities[clusterareanum] = linknum - aasworld.areasettings[nextareanum].firstreachablearea; + nextupdate = &aasworld.areaupdate[clusterareanum]; + nextupdate->areanum = nextareanum; + nextupdate->tmptraveltime = t; + //VectorCopy(reach->start, nextupdate->start); + nextupdate->areatraveltimes = aasworld.areatraveltimes[nextareanum][linknum - + aasworld.areasettings[nextareanum].firstreachablearea]; + if (!nextupdate->inlist) + { + // we add the update to the end of the list + // we could also use a B+ tree to have a real sorted list + // on travel time which makes for faster routing updates + nextupdate->next = NULL; + nextupdate->prev = updatelistend; + if (updatelistend) updatelistend->next = nextupdate; + else updateliststart = nextupdate; + updatelistend = nextupdate; + nextupdate->inlist = qtrue; + } //end if + } //end if + } //end for + } //end while +} //end of the function AAS_UpdateAreaRoutingCache +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +aas_routingcache_t *AAS_GetAreaRoutingCache(int clusternum, int areanum, int travelflags) +{ + int clusterareanum; + aas_routingcache_t *cache, *clustercache; + + //number of the area in the cluster + clusterareanum = AAS_ClusterAreaNum(clusternum, areanum); + //pointer to the cache for the area in the cluster + clustercache = aasworld.clusterareacache[clusternum][clusterareanum]; + //find the cache without undesired travel flags + for (cache = clustercache; cache; cache = cache->next) + { + //if there aren't used any undesired travel types for the cache + if (cache->travelflags == travelflags) break; + } //end for + //if there was no cache + if (!cache) + { + cache = AAS_AllocRoutingCache(aasworld.clusters[clusternum].numreachabilityareas); + cache->cluster = clusternum; + cache->areanum = areanum; + VectorCopy(aasworld.areas[areanum].center, cache->origin); + cache->starttraveltime = 1; + cache->travelflags = travelflags; + cache->prev = NULL; + cache->next = clustercache; + if (clustercache) clustercache->prev = cache; + aasworld.clusterareacache[clusternum][clusterareanum] = cache; + AAS_UpdateAreaRoutingCache(cache); + } //end if + else + { + AAS_UnlinkCache(cache); + } //end else + //the cache has been accessed + cache->time = AAS_RoutingTime(); + cache->type = CACHETYPE_AREA; + AAS_LinkCache(cache); + return cache; +} //end of the function AAS_GetAreaRoutingCache +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_UpdatePortalRoutingCache(aas_routingcache_t *portalcache) +{ + int i, portalnum, clusterareanum, clusternum; + unsigned short int t; + aas_portal_t *portal; + aas_cluster_t *cluster; + aas_routingcache_t *cache; + aas_routingupdate_t *updateliststart, *updatelistend, *curupdate, *nextupdate; + +#ifdef ROUTING_DEBUG + numportalcacheupdates++; +#endif //ROUTING_DEBUG + //clear the routing update fields +// Com_Memset(aasworld.portalupdate, 0, (aasworld.numportals+1) * sizeof(aas_routingupdate_t)); + // + curupdate = &aasworld.portalupdate[aasworld.numportals]; + curupdate->cluster = portalcache->cluster; + curupdate->areanum = portalcache->areanum; + curupdate->tmptraveltime = portalcache->starttraveltime; + //if the start area is a cluster portal, store the travel time for that portal + clusternum = aasworld.areasettings[portalcache->areanum].cluster; + if (clusternum < 0) + { + portalcache->traveltimes[-clusternum] = portalcache->starttraveltime; + } //end if + //put the area to start with in the current read list + curupdate->next = NULL; + curupdate->prev = NULL; + updateliststart = curupdate; + updatelistend = curupdate; + //while there are updates in the current list + while (updateliststart) + { + curupdate = updateliststart; + //remove the current update from the list + if (curupdate->next) curupdate->next->prev = NULL; + else updatelistend = NULL; + updateliststart = curupdate->next; + //current update is removed from the list + curupdate->inlist = qfalse; + // + cluster = &aasworld.clusters[curupdate->cluster]; + // + cache = AAS_GetAreaRoutingCache(curupdate->cluster, + curupdate->areanum, portalcache->travelflags); + //take all portals of the cluster + for (i = 0; i < cluster->numportals; i++) + { + portalnum = aasworld.portalindex[cluster->firstportal + i]; + portal = &aasworld.portals[portalnum]; + //if this is the portal of the current update continue + if (portal->areanum == curupdate->areanum) continue; + // + clusterareanum = AAS_ClusterAreaNum(curupdate->cluster, portal->areanum); + if (clusterareanum >= cluster->numreachabilityareas) continue; + // + t = cache->traveltimes[clusterareanum]; + if (!t) continue; + t += curupdate->tmptraveltime; + // + if (!portalcache->traveltimes[portalnum] || + portalcache->traveltimes[portalnum] > t) + { + portalcache->traveltimes[portalnum] = t; + nextupdate = &aasworld.portalupdate[portalnum]; + if (portal->frontcluster == curupdate->cluster) + { + nextupdate->cluster = portal->backcluster; + } //end if + else + { + nextupdate->cluster = portal->frontcluster; + } //end else + nextupdate->areanum = portal->areanum; + //add travel time through the actual portal area for the next update + nextupdate->tmptraveltime = t + aasworld.portalmaxtraveltimes[portalnum]; + if (!nextupdate->inlist) + { + // we add the update to the end of the list + // we could also use a B+ tree to have a real sorted list + // on travel time which makes for faster routing updates + nextupdate->next = NULL; + nextupdate->prev = updatelistend; + if (updatelistend) updatelistend->next = nextupdate; + else updateliststart = nextupdate; + updatelistend = nextupdate; + nextupdate->inlist = qtrue; + } //end if + } //end if + } //end for + } //end while +} //end of the function AAS_UpdatePortalRoutingCache +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +aas_routingcache_t *AAS_GetPortalRoutingCache(int clusternum, int areanum, int travelflags) +{ + aas_routingcache_t *cache; + + //find the cached portal routing if existing + for (cache = aasworld.portalcache[areanum]; cache; cache = cache->next) + { + if (cache->travelflags == travelflags) break; + } //end for + //if the portal routing isn't cached + if (!cache) + { + cache = AAS_AllocRoutingCache(aasworld.numportals); + cache->cluster = clusternum; + cache->areanum = areanum; + VectorCopy(aasworld.areas[areanum].center, cache->origin); + cache->starttraveltime = 1; + cache->travelflags = travelflags; + //add the cache to the cache list + cache->prev = NULL; + cache->next = aasworld.portalcache[areanum]; + if (aasworld.portalcache[areanum]) aasworld.portalcache[areanum]->prev = cache; + aasworld.portalcache[areanum] = cache; + //update the cache + AAS_UpdatePortalRoutingCache(cache); + } //end if + else + { + AAS_UnlinkCache(cache); + } //end else + //the cache has been accessed + cache->time = AAS_RoutingTime(); + cache->type = CACHETYPE_PORTAL; + AAS_LinkCache(cache); + return cache; +} //end of the function AAS_GetPortalRoutingCache +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_AreaRouteToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags, int *traveltime, int *reachnum) +{ + int clusternum, goalclusternum, portalnum, i, clusterareanum, bestreachnum; + unsigned short int t, besttime; + aas_portal_t *portal; + aas_cluster_t *cluster; + aas_routingcache_t *areacache, *portalcache; + aas_reachability_t *reach; + + if (!aasworld.initialized) return qfalse; + + if (areanum == goalareanum) + { + *traveltime = 1; + *reachnum = 0; + return qtrue; + } + // + if (areanum <= 0 || areanum >= aasworld.numareas) + { + if (botDeveloper) + { + botimport.Print(PRT_ERROR, "AAS_AreaTravelTimeToGoalArea: areanum %d out of range\n", areanum); + } //end if + return qfalse; + } //end if + if (goalareanum <= 0 || goalareanum >= aasworld.numareas) + { + if (botDeveloper) + { + botimport.Print(PRT_ERROR, "AAS_AreaTravelTimeToGoalArea: goalareanum %d out of range\n", goalareanum); + } //end if + return qfalse; + } //end if + // make sure the routing cache doesn't grow to large + while(AvailableMemory() < 1 * 1024 * 1024) { + if (!AAS_FreeOldestCache()) break; + } + // + if (AAS_AreaDoNotEnter(areanum) || AAS_AreaDoNotEnter(goalareanum)) + { + travelflags |= TFL_DONOTENTER; + } //end if + //NOTE: the number of routing updates is limited per frame + /* + if (aasworld.frameroutingupdates > MAX_FRAMEROUTINGUPDATES) + { +#ifdef DEBUG + //Log_Write("WARNING: AAS_AreaTravelTimeToGoalArea: frame routing updates overflowed"); +#endif + return 0; + } //end if + */ + // + clusternum = aasworld.areasettings[areanum].cluster; + goalclusternum = aasworld.areasettings[goalareanum].cluster; + //check if the area is a portal of the goal area cluster + if (clusternum < 0 && goalclusternum > 0) + { + portal = &aasworld.portals[-clusternum]; + if (portal->frontcluster == goalclusternum || + portal->backcluster == goalclusternum) + { + clusternum = goalclusternum; + } //end if + } //end if + //check if the goalarea is a portal of the area cluster + else if (clusternum > 0 && goalclusternum < 0) + { + portal = &aasworld.portals[-goalclusternum]; + if (portal->frontcluster == clusternum || + portal->backcluster == clusternum) + { + goalclusternum = clusternum; + } //end if + } //end if + //if both areas are in the same cluster + //NOTE: there might be a shorter route via another cluster!!! but we don't care + if (clusternum > 0 && goalclusternum > 0 && clusternum == goalclusternum) + { + // + areacache = AAS_GetAreaRoutingCache(clusternum, goalareanum, travelflags); + //the number of the area in the cluster + clusterareanum = AAS_ClusterAreaNum(clusternum, areanum); + //the cluster the area is in + cluster = &aasworld.clusters[clusternum]; + //if the area is NOT a reachability area + if (clusterareanum >= cluster->numreachabilityareas) return 0; + //if it is possible to travel to the goal area through this cluster + if (areacache->traveltimes[clusterareanum] != 0) + { + *reachnum = aasworld.areasettings[areanum].firstreachablearea + + areacache->reachabilities[clusterareanum]; + if (!origin) { + *traveltime = areacache->traveltimes[clusterareanum]; + return qtrue; + } + reach = &aasworld.reachability[*reachnum]; + *traveltime = areacache->traveltimes[clusterareanum] + + AAS_AreaTravelTime(areanum, origin, reach->start); + // + return qtrue; + } //end if + } //end if + // + clusternum = aasworld.areasettings[areanum].cluster; + goalclusternum = aasworld.areasettings[goalareanum].cluster; + //if the goal area is a portal + if (goalclusternum < 0) + { + //just assume the goal area is part of the front cluster + portal = &aasworld.portals[-goalclusternum]; + goalclusternum = portal->frontcluster; + } //end if + //get the portal routing cache + portalcache = AAS_GetPortalRoutingCache(goalclusternum, goalareanum, travelflags); + //if the area is a cluster portal, read directly from the portal cache + if (clusternum < 0) + { + *traveltime = portalcache->traveltimes[-clusternum]; + *reachnum = aasworld.areasettings[areanum].firstreachablearea + + portalcache->reachabilities[-clusternum]; + return qtrue; + } //end if + // + besttime = 0; + bestreachnum = -1; + //the cluster the area is in + cluster = &aasworld.clusters[clusternum]; + //find the portal of the area cluster leading towards the goal area + for (i = 0; i < cluster->numportals; i++) + { + portalnum = aasworld.portalindex[cluster->firstportal + i]; + //if the goal area isn't reachable from the portal + if (!portalcache->traveltimes[portalnum]) continue; + // + portal = &aasworld.portals[portalnum]; + //get the cache of the portal area + areacache = AAS_GetAreaRoutingCache(clusternum, portal->areanum, travelflags); + //current area inside the current cluster + clusterareanum = AAS_ClusterAreaNum(clusternum, areanum); + //if the area is NOT a reachability area + if (clusterareanum >= cluster->numreachabilityareas) continue; + //if the portal is NOT reachable from this area + if (!areacache->traveltimes[clusterareanum]) continue; + //total travel time is the travel time the portal area is from + //the goal area plus the travel time towards the portal area + t = portalcache->traveltimes[portalnum] + areacache->traveltimes[clusterareanum]; + //FIXME: add the exact travel time through the actual portal area + //NOTE: for now we just add the largest travel time through the portal area + // because we can't directly calculate the exact travel time + // to be more specific we don't know which reachability was used to travel + // into the portal area + t += aasworld.portalmaxtraveltimes[portalnum]; + // + if (origin) + { + *reachnum = aasworld.areasettings[areanum].firstreachablearea + + areacache->reachabilities[clusterareanum]; + reach = aasworld.reachability + *reachnum; + t += AAS_AreaTravelTime(areanum, origin, reach->start); + } //end if + //if the time is better than the one already found + if (!besttime || t < besttime) + { + bestreachnum = *reachnum; + besttime = t; + } //end if + } //end for + if (bestreachnum < 0) { + return qfalse; + } + *reachnum = bestreachnum; + *traveltime = besttime; + return qtrue; +} //end of the function AAS_AreaRouteToGoalArea +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_AreaTravelTimeToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags) +{ + int traveltime, reachnum = 0; + + if (AAS_AreaRouteToGoalArea(areanum, origin, goalareanum, travelflags, &traveltime, &reachnum)) + { + return traveltime; + } + return 0; +} //end of the function AAS_AreaTravelTimeToGoalArea +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_AreaReachabilityToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags) +{ + int traveltime, reachnum = 0; + + if (AAS_AreaRouteToGoalArea(areanum, origin, goalareanum, travelflags, &traveltime, &reachnum)) + { + return reachnum; + } + return 0; +} //end of the function AAS_AreaReachabilityToGoalArea +//=========================================================================== +// predict the route and stop on one of the stop events +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_PredictRoute(struct aas_predictroute_s *route, int areanum, vec3_t origin, + int goalareanum, int travelflags, int maxareas, int maxtime, + int stopevent, int stopcontents, int stoptfl, int stopareanum) +{ + int curareanum, reachnum, i, j, testareanum; + vec3_t curorigin; + aas_reachability_t *reach; + aas_reachabilityareas_t *reachareas; + + //init output + route->stopevent = RSE_NONE; + route->endarea = goalareanum; + route->endcontents = 0; + route->endtravelflags = 0; + VectorCopy(origin, route->endpos); + route->time = 0; + + curareanum = areanum; + VectorCopy(origin, curorigin); + + for (i = 0; curareanum != goalareanum && (!maxareas || i < maxareas) && i < aasworld.numareas; i++) + { + reachnum = AAS_AreaReachabilityToGoalArea(curareanum, curorigin, goalareanum, travelflags); + if (!reachnum) + { + route->stopevent = RSE_NOROUTE; + return qfalse; + } //end if + reach = &aasworld.reachability[reachnum]; + // + if (stopevent & RSE_USETRAVELTYPE) + { + if (AAS_TravelFlagForType_inline(reach->traveltype) & stoptfl) + { + route->stopevent = RSE_USETRAVELTYPE; + route->endarea = curareanum; + route->endcontents = aasworld.areasettings[curareanum].contents; + route->endtravelflags = AAS_TravelFlagForType_inline(reach->traveltype); + VectorCopy(reach->start, route->endpos); + return qtrue; + } //end if + if (AAS_AreaContentsTravelFlags_inline(reach->areanum) & stoptfl) + { + route->stopevent = RSE_USETRAVELTYPE; + route->endarea = reach->areanum; + route->endcontents = aasworld.areasettings[reach->areanum].contents; + route->endtravelflags = AAS_AreaContentsTravelFlags_inline(reach->areanum); + VectorCopy(reach->end, route->endpos); + route->time += AAS_AreaTravelTime(areanum, origin, reach->start); + route->time += reach->traveltime; + return qtrue; + } //end if + } //end if + reachareas = &aasworld.reachabilityareas[reachnum]; + for (j = 0; j < reachareas->numareas + 1; j++) + { + if (j >= reachareas->numareas) + testareanum = reach->areanum; + else + testareanum = aasworld.reachabilityareaindex[reachareas->firstarea + j]; + if (stopevent & RSE_ENTERCONTENTS) + { + if (aasworld.areasettings[testareanum].contents & stopcontents) + { + route->stopevent = RSE_ENTERCONTENTS; + route->endarea = testareanum; + route->endcontents = aasworld.areasettings[testareanum].contents; + VectorCopy(reach->end, route->endpos); + route->time += AAS_AreaTravelTime(areanum, origin, reach->start); + route->time += reach->traveltime; + return qtrue; + } //end if + } //end if + if (stopevent & RSE_ENTERAREA) + { + if (testareanum == stopareanum) + { + route->stopevent = RSE_ENTERAREA; + route->endarea = testareanum; + route->endcontents = aasworld.areasettings[testareanum].contents; + VectorCopy(reach->start, route->endpos); + return qtrue; + } //end if + } //end if + } //end for + + route->time += AAS_AreaTravelTime(areanum, origin, reach->start); + route->time += reach->traveltime; + route->endarea = reach->areanum; + route->endcontents = aasworld.areasettings[reach->areanum].contents; + route->endtravelflags = AAS_TravelFlagForType_inline(reach->traveltype); + VectorCopy(reach->end, route->endpos); + // + curareanum = reach->areanum; + VectorCopy(reach->end, curorigin); + // + if (maxtime && route->time > maxtime) + break; + } //end while + if (curareanum != goalareanum) + return qfalse; + return qtrue; +} //end of the function AAS_PredictRoute +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_BridgeWalkable(int areanum) +{ + return qfalse; +} //end of the function AAS_BridgeWalkable +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_ReachabilityFromNum(int num, struct aas_reachability_s *reach) +{ + if (!aasworld.initialized) + { + Com_Memset(reach, 0, sizeof(aas_reachability_t)); + return; + } //end if + if (num < 0 || num >= aasworld.reachabilitysize) + { + Com_Memset(reach, 0, sizeof(aas_reachability_t)); + return; + } //end if + Com_Memcpy(reach, &aasworld.reachability[num], sizeof(aas_reachability_t));; +} //end of the function AAS_ReachabilityFromNum +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_NextAreaReachability(int areanum, int reachnum) +{ + aas_areasettings_t *settings; + + if (!aasworld.initialized) return 0; + + if (areanum <= 0 || areanum >= aasworld.numareas) + { + botimport.Print(PRT_ERROR, "AAS_NextAreaReachability: areanum %d out of range\n", areanum); + return 0; + } //end if + + settings = &aasworld.areasettings[areanum]; + if (!reachnum) + { + return settings->firstreachablearea; + } //end if + if (reachnum < settings->firstreachablearea) + { + botimport.Print(PRT_FATAL, "AAS_NextAreaReachability: reachnum < settings->firstreachableara"); + return 0; + } //end if + reachnum++; + if (reachnum >= settings->firstreachablearea + settings->numreachableareas) + { + return 0; + } //end if + return reachnum; +} //end of the function AAS_NextAreaReachability +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_NextModelReachability(int num, int modelnum) +{ + int i; + + if (num <= 0) num = 1; + else if (num >= aasworld.reachabilitysize) return 0; + else num++; + // + for (i = num; i < aasworld.reachabilitysize; i++) + { + if ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == TRAVEL_ELEVATOR) + { + if (aasworld.reachability[i].facenum == modelnum) return i; + } //end if + else if ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == TRAVEL_FUNCBOB) + { + if ((aasworld.reachability[i].facenum & 0x0000FFFF) == modelnum) return i; + } //end if + } //end for + return 0; +} //end of the function AAS_NextModelReachability +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_RandomGoalArea(int areanum, int travelflags, int *goalareanum, vec3_t goalorigin) +{ + int i, n, t; + vec3_t start, end; + aas_trace_t trace; + + //if the area has no reachabilities + if (!AAS_AreaReachability(areanum)) return qfalse; + // + n = aasworld.numareas * Q_flrand(0.0f, 1.0f); + for (i = 0; i < aasworld.numareas; i++) + { + if (n <= 0) n = 1; + if (n >= aasworld.numareas) n = 1; + if (AAS_AreaReachability(n)) + { + t = AAS_AreaTravelTimeToGoalArea(areanum, aasworld.areas[areanum].center, n, travelflags); + //if the goal is reachable + if (t > 0) + { + if (AAS_AreaSwim(n)) + { + *goalareanum = n; + VectorCopy(aasworld.areas[n].center, goalorigin); + //botimport.Print(PRT_MESSAGE, "found random goal area %d\n", *goalareanum); + return qtrue; + } //end if + VectorCopy(aasworld.areas[n].center, start); + if (!AAS_PointAreaNum(start)) + Log_Write("area %d center %f %f %f in solid?", n, start[0], start[1], start[2]); + VectorCopy(start, end); + end[2] -= 300; + trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1); + if (!trace.startsolid && trace.fraction < 1 && AAS_PointAreaNum(trace.endpos) == n) + { + if (AAS_AreaGroundFaceArea(n) > 300) + { + *goalareanum = n; + VectorCopy(trace.endpos, goalorigin); + //botimport.Print(PRT_MESSAGE, "found random goal area %d\n", *goalareanum); + return qtrue; + } //end if + } //end if + } //end if + } //end if + n++; + } //end for + return qfalse; +} //end of the function AAS_RandomGoalArea +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_AreaVisible(int srcarea, int destarea) +{ + return qfalse; +} //end of the function AAS_AreaVisible +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float DistancePointToLine(vec3_t v1, vec3_t v2, vec3_t point) +{ + vec3_t vec, p2; + + AAS_ProjectPointOntoVector(point, v1, v2, p2); + VectorSubtract(point, p2, vec); + return VectorLength(vec); +} //end of the function DistancePointToLine +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_NearestHideArea(int srcnum, vec3_t origin, int areanum, int enemynum, vec3_t enemyorigin, int enemyareanum, int travelflags) +{ + int i, j, nextareanum, badtravelflags, numreach, bestarea; + unsigned short int t, besttraveltime; + static unsigned short int *hidetraveltimes; + aas_routingupdate_t *updateliststart, *updatelistend, *curupdate, *nextupdate; + aas_reachability_t *reach; + float dist1, dist2; + vec3_t v1, v2, p; + qboolean startVisible; + + // + if (!hidetraveltimes) + { + hidetraveltimes = (unsigned short int *) GetClearedMemory(aasworld.numareas * sizeof(unsigned short int)); + } //end if + else + { + Com_Memset(hidetraveltimes, 0, aasworld.numareas * sizeof(unsigned short int)); + } //end else + besttraveltime = 0; + bestarea = 0; + //assume visible + startVisible = qtrue; + // + badtravelflags = ~travelflags; + // + curupdate = &aasworld.areaupdate[areanum]; + curupdate->areanum = areanum; + VectorCopy(origin, curupdate->start); + curupdate->areatraveltimes = aasworld.areatraveltimes[areanum][0]; + curupdate->tmptraveltime = 0; + //put the area to start with in the current read list + curupdate->next = NULL; + curupdate->prev = NULL; + updateliststart = curupdate; + updatelistend = curupdate; + //while there are updates in the list + while (updateliststart) + { + curupdate = updateliststart; + // + if (curupdate->next) curupdate->next->prev = NULL; + else updatelistend = NULL; + updateliststart = curupdate->next; + // + curupdate->inlist = qfalse; + //check all reversed reachability links + numreach = aasworld.areasettings[curupdate->areanum].numreachableareas; + reach = &aasworld.reachability[aasworld.areasettings[curupdate->areanum].firstreachablearea]; + // + for (i = 0; i < numreach; i++, reach++) + { + //if an undesired travel type is used + if (AAS_TravelFlagForType_inline(reach->traveltype) & badtravelflags) continue; + // + if (AAS_AreaContentsTravelFlags_inline(reach->areanum) & badtravelflags) continue; + //number of the area the reachability leads to + nextareanum = reach->areanum; + // if this moves us into the enemies area, skip it + if (nextareanum == enemyareanum) continue; + //time already travelled plus the traveltime through + //the current area plus the travel time from the reachability + t = curupdate->tmptraveltime + + AAS_AreaTravelTime(curupdate->areanum, curupdate->start, reach->start) + + reach->traveltime; + + //avoid going near the enemy + AAS_ProjectPointOntoVector(enemyorigin, curupdate->start, reach->end, p); + for (j = 0; j < 3; j++) + if ((p[j] > curupdate->start[j] && p[j] > reach->end[j]) || + (p[j] < curupdate->start[j] && p[j] < reach->end[j])) + break; + if (j < 3) + { + VectorSubtract(enemyorigin, reach->end, v2); + } //end if + else + { + VectorSubtract(enemyorigin, p, v2); + } //end else + dist2 = VectorLength(v2); + //never go through the enemy + if (dist2 < 40) continue; + // + VectorSubtract(enemyorigin, curupdate->start, v1); + dist1 = VectorLength(v1); + // + if (dist2 < dist1) + { + t += (dist1 - dist2) * 10; + } + // if we weren't visible when starting, make sure we don't move into their view + if (!startVisible && AAS_AreaVisible(enemyareanum, nextareanum)) { + continue; + } + // + if (besttraveltime && t >= besttraveltime) continue; + // + if (!hidetraveltimes[nextareanum] || + hidetraveltimes[nextareanum] > t) + { + //if the nextarea is not visible from the enemy area + if (!AAS_AreaVisible(enemyareanum, nextareanum)) + { + besttraveltime = t; + bestarea = nextareanum; + } //end if + hidetraveltimes[nextareanum] = t; + nextupdate = &aasworld.areaupdate[nextareanum]; + nextupdate->areanum = nextareanum; + nextupdate->tmptraveltime = t; + //remember where we entered this area + VectorCopy(reach->end, nextupdate->start); + //if this update is not in the list yet + if (!nextupdate->inlist) + { + //add the new update to the end of the list + nextupdate->next = NULL; + nextupdate->prev = updatelistend; + if (updatelistend) updatelistend->next = nextupdate; + else updateliststart = nextupdate; + updatelistend = nextupdate; + nextupdate->inlist = qtrue; + } //end if + } //end if + } //end for + } //end while + return bestarea; +} //end of the function AAS_NearestHideArea diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_route.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_route.h new file mode 100644 index 0000000..7f59d8b --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_route.h @@ -0,0 +1,72 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_aas_route.h + * + * desc: AAS + * + * $Archive: /source/code/botlib/be_aas_route.h $ + * $Author: Mrelusive $ + * $Revision: 2 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 10/05/99 3:42p $ + * + *****************************************************************************/ + +#pragma once + +#ifdef AASINTERN +//initialize the AAS routing +void AAS_InitRouting(void); +//free the AAS routing caches +void AAS_FreeRoutingCaches(void); +//returns the travel time from start to end in the given area +unsigned short int AAS_AreaTravelTime(int areanum, vec3_t start, vec3_t end); +// +void AAS_CreateAllRoutingCache(void); +void AAS_WriteRouteCache(void); +// +void AAS_RoutingInfo(void); +#endif //AASINTERN + +//returns the travel flag for the given travel type +int AAS_TravelFlagForType(int traveltype); +//return the travel flag(s) for traveling through this area +int AAS_AreaContentsTravelFlags(int areanum); +//returns the index of the next reachability for the given area +int AAS_NextAreaReachability(int areanum, int reachnum); +//returns the reachability with the given index +void AAS_ReachabilityFromNum(int num, struct aas_reachability_s *reach); +//returns a random goal area and goal origin +int AAS_RandomGoalArea(int areanum, int travelflags, int *goalareanum, vec3_t goalorigin); +//enable or disable an area for routing +int AAS_EnableRoutingArea(int areanum, int enable); +//returns the travel time within the given area from start to end +unsigned short int AAS_AreaTravelTime(int areanum, vec3_t start, vec3_t end); +//returns the travel time from the area to the goal area using the given travel flags +int AAS_AreaTravelTimeToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags); +//predict a route up to a stop event +int AAS_PredictRoute(struct aas_predictroute_s *route, int areanum, vec3_t origin, + int goalareanum, int travelflags, int maxareas, int maxtime, + int stopevent, int stopcontents, int stoptfl, int stopareanum); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_routealt.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_routealt.cpp new file mode 100644 index 0000000..4017597 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_routealt.cpp @@ -0,0 +1,245 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_aas_routealt.c + * + * desc: AAS + * + * $Archive: /MissionPack/code/botlib/be_aas_routealt.c $ + * $Author: Zaphod $ + * $Revision: 5 $ + * $Modtime: 11/22/00 8:47a $ + * $Date: 11/22/00 8:55a $ + * + *****************************************************************************/ + +#include "qcommon/q_shared.h" +#include "l_utils.h" +#include "l_memory.h" +#include "l_log.h" +#include "l_script.h" +#include "l_precomp.h" +#include "l_struct.h" +#include "aasfile.h" +#include "botlib.h" +#include "be_aas.h" +#include "be_aas_funcs.h" +#include "be_interface.h" +#include "be_aas_def.h" + +#define ENABLE_ALTROUTING +//#define ALTROUTE_DEBUG + +typedef struct midrangearea_s +{ + int valid; + unsigned short starttime; + unsigned short goaltime; +} midrangearea_t; + +midrangearea_t *midrangeareas; +int *clusterareas; +int numclusterareas; + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_AltRoutingFloodCluster_r(int areanum) +{ + int i, otherareanum; + aas_area_t *area; + aas_face_t *face; + + //add the current area to the areas of the current cluster + clusterareas[numclusterareas] = areanum; + numclusterareas++; + //remove the area from the mid range areas + midrangeareas[areanum].valid = qfalse; + //flood to other areas through the faces of this area + area = &aasworld.areas[areanum]; + for (i = 0; i < area->numfaces; i++) + { + face = &aasworld.faces[abs(aasworld.faceindex[area->firstface + i])]; + //get the area at the other side of the face + if (face->frontarea == areanum) otherareanum = face->backarea; + else otherareanum = face->frontarea; + //if there is an area at the other side of this face + if (!otherareanum) continue; + //if the other area is not a midrange area + if (!midrangeareas[otherareanum].valid) continue; + // + AAS_AltRoutingFloodCluster_r(otherareanum); + } //end for +} //end of the function AAS_AltRoutingFloodCluster_r +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_AlternativeRouteGoals(vec3_t start, int startareanum, vec3_t goal, int goalareanum, int travelflags, + aas_altroutegoal_t *altroutegoals, int maxaltroutegoals, + int type) +{ +#ifndef ENABLE_ALTROUTING + return 0; +#else + int i, j, bestareanum; + int numaltroutegoals, nummidrangeareas; + int starttime, goaltime, goaltraveltime; + float dist, bestdist; + vec3_t mid, dir; +#ifdef ALTROUTE_DEBUG + int startmillisecs; + + startmillisecs = Sys_MilliSeconds(); +#endif + + if (!startareanum || !goalareanum) + return 0; + //travel time towards the goal area + goaltraveltime = AAS_AreaTravelTimeToGoalArea(startareanum, start, goalareanum, travelflags); + //clear the midrange areas + Com_Memset(midrangeareas, 0, aasworld.numareas * sizeof(midrangearea_t)); + numaltroutegoals = 0; + // + nummidrangeareas = 0; + // + for (i = 1; i < aasworld.numareas; i++) + { + // + if (!(type & ALTROUTEGOAL_ALL)) + { + if (!(type & ALTROUTEGOAL_CLUSTERPORTALS && (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL))) + { + if (!(type & ALTROUTEGOAL_VIEWPORTALS && (aasworld.areasettings[i].contents & AREACONTENTS_VIEWPORTAL))) + { + continue; + } //end if + } //end if + } //end if + //if the area has no reachabilities + if (!AAS_AreaReachability(i)) continue; + //tavel time from the area to the start area + starttime = AAS_AreaTravelTimeToGoalArea(startareanum, start, i, travelflags); + if (!starttime) continue; + //if the travel time from the start to the area is greater than the shortest goal travel time + if (starttime > (float) 1.1 * goaltraveltime) continue; + //travel time from the area to the goal area + goaltime = AAS_AreaTravelTimeToGoalArea(i, NULL, goalareanum, travelflags); + if (!goaltime) continue; + //if the travel time from the area to the goal is greater than the shortest goal travel time + if (goaltime > (float) 0.8 * goaltraveltime) continue; + //this is a mid range area + midrangeareas[i].valid = qtrue; + midrangeareas[i].starttime = starttime; + midrangeareas[i].goaltime = goaltime; + Log_Write("%d midrange area %d", nummidrangeareas, i); + nummidrangeareas++; + } //end for + // + for (i = 1; i < aasworld.numareas; i++) + { + if (!midrangeareas[i].valid) continue; + //get the areas in one cluster + numclusterareas = 0; + AAS_AltRoutingFloodCluster_r(i); + //now we've got a cluster with areas through which an alternative route could go + //get the 'center' of the cluster + VectorClear(mid); + for (j = 0; j < numclusterareas; j++) + { + VectorAdd(mid, aasworld.areas[clusterareas[j]].center, mid); + } //end for + VectorScale(mid, 1.0 / numclusterareas, mid); + //get the area closest to the center of the cluster + bestdist = 999999; + bestareanum = 0; + for (j = 0; j < numclusterareas; j++) + { + VectorSubtract(mid, aasworld.areas[clusterareas[j]].center, dir); + dist = VectorLength(dir); + if (dist < bestdist) + { + bestdist = dist; + bestareanum = clusterareas[j]; + } //end if + } //end for + //now we've got an area for an alternative route + //FIXME: add alternative goal origin + VectorCopy(aasworld.areas[bestareanum].center, altroutegoals[numaltroutegoals].origin); + altroutegoals[numaltroutegoals].areanum = bestareanum; + altroutegoals[numaltroutegoals].starttraveltime = midrangeareas[bestareanum].starttime; + altroutegoals[numaltroutegoals].goaltraveltime = midrangeareas[bestareanum].goaltime; + altroutegoals[numaltroutegoals].extratraveltime = + (midrangeareas[bestareanum].starttime + midrangeareas[bestareanum].goaltime) - + goaltraveltime; + numaltroutegoals++; + // +#ifdef ALTROUTE_DEBUG + AAS_ShowAreaPolygons(bestareanum, 1, qtrue); +#endif + //don't return more than the maximum alternative route goals + if (numaltroutegoals >= maxaltroutegoals) break; + } //end for +#ifdef ALTROUTE_DEBUG + botimport.Print(PRT_MESSAGE, "alternative route goals in %d msec\n", Sys_MilliSeconds() - startmillisecs); +#endif + return numaltroutegoals; +#endif +} //end of the function AAS_AlternativeRouteGoals +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_InitAlternativeRouting(void) +{ +#ifdef ENABLE_ALTROUTING + if (midrangeareas) FreeMemory(midrangeareas); + midrangeareas = (midrangearea_t *) GetMemory(aasworld.numareas * sizeof(midrangearea_t)); + if (clusterareas) FreeMemory(clusterareas); + clusterareas = (int *) GetMemory(aasworld.numareas * sizeof(int)); +#endif +} //end of the function AAS_InitAlternativeRouting +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_ShutdownAlternativeRouting(void) +{ +#ifdef ENABLE_ALTROUTING + if (midrangeareas) FreeMemory(midrangeareas); + midrangeareas = NULL; + if (clusterareas) FreeMemory(clusterareas); + clusterareas = NULL; + numclusterareas = 0; +#endif +} //end of the function AAS_ShutdownAlternativeRouting diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_routealt.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_routealt.h new file mode 100644 index 0000000..0ab1f08 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_routealt.h @@ -0,0 +1,47 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_aas_routealt.h + * + * desc: AAS + * + * $Archive: /source/code/botlib/be_aas_routealt.h $ + * $Author: Mrelusive $ + * $Revision: 2 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 10/05/99 3:42p $ + * + *****************************************************************************/ + +#pragma once + +#ifdef AASINTERN +void AAS_InitAlternativeRouting(void); +void AAS_ShutdownAlternativeRouting(void); +#endif //AASINTERN + + +int AAS_AlternativeRouteGoals(vec3_t start, int startareanum, vec3_t goal, int goalareanum, int travelflags, + aas_altroutegoal_t *altroutegoals, int maxaltroutegoals, + int type); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_sample.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_sample.cpp new file mode 100644 index 0000000..64d8cda --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_sample.cpp @@ -0,0 +1,1398 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_aas_sample.c + * + * desc: AAS environment sampling + * + * $Archive: /MissionPack/code/botlib/be_aas_sample.c $ + * $Author: Ttimo $ + * $Revision: 13 $ + * $Modtime: 4/13/01 4:45p $ + * $Date: 4/13/01 4:45p $ + * + *****************************************************************************/ + +#include "qcommon/q_shared.h" +#include "l_memory.h" +#include "l_script.h" +#include "l_precomp.h" +#include "l_struct.h" +#ifndef BSPC +#include "l_libvar.h" +#endif +#include "aasfile.h" +#include "botlib.h" +#include "be_aas.h" +#include "be_interface.h" +#include "be_aas_funcs.h" +#include "be_aas_def.h" + +extern botlib_import_t botimport; + +//#define AAS_SAMPLE_DEBUG + +#define BBOX_NORMAL_EPSILON 0.001 + +#define ON_EPSILON 0 //0.0005 + +#define TRACEPLANE_EPSILON 0.125 + +typedef struct aas_tracestack_s +{ + vec3_t start; //start point of the piece of line to trace + vec3_t end; //end point of the piece of line to trace + int planenum; //last plane used as splitter + int nodenum; //node found after splitting with planenum +} aas_tracestack_t; + +int numaaslinks; + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_PresenceTypeBoundingBox(int presencetype, vec3_t mins, vec3_t maxs) +{ + int index; + //bounding box size for each presence type + vec3_t boxmins[3] = {{0, 0, 0}, {-15, -15, -24}, {-15, -15, -24}}; + vec3_t boxmaxs[3] = {{0, 0, 0}, { 15, 15, 32}, { 15, 15, 8}}; + + if (presencetype == PRESENCE_NORMAL) index = 1; + else if (presencetype == PRESENCE_CROUCH) index = 2; + else + { + botimport.Print(PRT_FATAL, "AAS_PresenceTypeBoundingBox: unknown presence type\n"); + index = 2; + } //end if + VectorCopy(boxmins[index], mins); + VectorCopy(boxmaxs[index], maxs); +} //end of the function AAS_PresenceTypeBoundingBox +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_InitAASLinkHeap(void) +{ + int i, max_aaslinks; + + max_aaslinks = aasworld.linkheapsize; + //if there's no link heap present + if (!aasworld.linkheap) + { +#ifdef BSPC + max_aaslinks = 6144; +#else + max_aaslinks = (int) LibVarValue("max_aaslinks", "6144"); +#endif + if (max_aaslinks < 0) max_aaslinks = 0; + aasworld.linkheapsize = max_aaslinks; + aasworld.linkheap = (aas_link_t *) GetHunkMemory(max_aaslinks * sizeof(aas_link_t)); + } //end if + //link the links on the heap + aasworld.linkheap[0].prev_ent = NULL; + aasworld.linkheap[0].next_ent = &aasworld.linkheap[1]; + for (i = 1; i < max_aaslinks-1; i++) + { + aasworld.linkheap[i].prev_ent = &aasworld.linkheap[i - 1]; + aasworld.linkheap[i].next_ent = &aasworld.linkheap[i + 1]; + } //end for + aasworld.linkheap[max_aaslinks-1].prev_ent = &aasworld.linkheap[max_aaslinks-2]; + aasworld.linkheap[max_aaslinks-1].next_ent = NULL; + //pointer to the first free link + aasworld.freelinks = &aasworld.linkheap[0]; + // + numaaslinks = max_aaslinks; +} //end of the function AAS_InitAASLinkHeap +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_FreeAASLinkHeap(void) +{ + if (aasworld.linkheap) FreeMemory(aasworld.linkheap); + aasworld.linkheap = NULL; + aasworld.linkheapsize = 0; +} //end of the function AAS_FreeAASLinkHeap +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +aas_link_t *AAS_AllocAASLink(void) +{ + aas_link_t *link; + + link = aasworld.freelinks; + if (!link) + { +#ifndef BSPC + if (botDeveloper) +#endif + { + botimport.Print(PRT_FATAL, "empty aas link heap\n"); + } //end if + return NULL; + } //end if + if (aasworld.freelinks) aasworld.freelinks = aasworld.freelinks->next_ent; + if (aasworld.freelinks) aasworld.freelinks->prev_ent = NULL; + numaaslinks--; + return link; +} //end of the function AAS_AllocAASLink +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_DeAllocAASLink(aas_link_t *link) +{ + if (aasworld.freelinks) aasworld.freelinks->prev_ent = link; + link->prev_ent = NULL; + link->next_ent = aasworld.freelinks; + link->prev_area = NULL; + link->next_area = NULL; + aasworld.freelinks = link; + numaaslinks++; +} //end of the function AAS_DeAllocAASLink +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_InitAASLinkedEntities(void) +{ + if (!aasworld.loaded) return; + if (aasworld.arealinkedentities) FreeMemory(aasworld.arealinkedentities); + aasworld.arealinkedentities = (aas_link_t **) GetClearedHunkMemory( + aasworld.numareas * sizeof(aas_link_t *)); +} //end of the function AAS_InitAASLinkedEntities +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_FreeAASLinkedEntities(void) +{ + if (aasworld.arealinkedentities) FreeMemory(aasworld.arealinkedentities); + aasworld.arealinkedentities = NULL; +} //end of the function AAS_InitAASLinkedEntities +//=========================================================================== +// returns the AAS area the point is in +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_PointAreaNum(vec3_t point) +{ + int nodenum; + float dist; + aas_node_t *node; + aas_plane_t *plane; + + if (!aasworld.loaded) + { + botimport.Print(PRT_ERROR, "AAS_PointAreaNum: aas not loaded\n"); + return 0; + } //end if + + //start with node 1 because node zero is a dummy used for solid leafs + nodenum = 1; + while (nodenum > 0) + { +// botimport.Print(PRT_MESSAGE, "[%d]", nodenum); +#ifdef AAS_SAMPLE_DEBUG + if (nodenum >= aasworld.numnodes) + { + botimport.Print(PRT_ERROR, "nodenum = %d >= aasworld.numnodes = %d\n", nodenum, aasworld.numnodes); + return 0; + } //end if +#endif //AAS_SAMPLE_DEBUG + node = &aasworld.nodes[nodenum]; +#ifdef AAS_SAMPLE_DEBUG + if (node->planenum < 0 || node->planenum >= aasworld.numplanes) + { + botimport.Print(PRT_ERROR, "node->planenum = %d >= aasworld.numplanes = %d\n", node->planenum, aasworld.numplanes); + return 0; + } //end if +#endif //AAS_SAMPLE_DEBUG + plane = &aasworld.planes[node->planenum]; + dist = DotProduct(point, plane->normal) - plane->dist; + if (dist > 0) nodenum = node->children[0]; + else nodenum = node->children[1]; + } //end while + if (!nodenum) + { +#ifdef AAS_SAMPLE_DEBUG + botimport.Print(PRT_MESSAGE, "in solid\n"); +#endif //AAS_SAMPLE_DEBUG + return 0; + } //end if + return -nodenum; +} //end of the function AAS_PointAreaNum +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_PointReachabilityAreaIndex( vec3_t origin ) +{ + int areanum, cluster, i, index; + + if (!aasworld.initialized) + return 0; + + if ( !origin ) + { + index = 0; + for (i = 0; i < aasworld.numclusters; i++) + { + index += aasworld.clusters[i].numreachabilityareas; + } //end for + return index; + } //end if + + areanum = AAS_PointAreaNum( origin ); + if ( !areanum || !AAS_AreaReachability(areanum) ) + return 0; + cluster = aasworld.areasettings[areanum].cluster; + areanum = aasworld.areasettings[areanum].clusterareanum; + if (cluster < 0) + { + cluster = aasworld.portals[-cluster].frontcluster; + areanum = aasworld.portals[-cluster].clusterareanum[0]; + } //end if + + index = 0; + for (i = 0; i < cluster; i++) + { + index += aasworld.clusters[i].numreachabilityareas; + } //end for + index += areanum; + return index; +} //end of the function AAS_PointReachabilityAreaIndex +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_AreaCluster(int areanum) +{ + if (areanum <= 0 || areanum >= aasworld.numareas) + { + botimport.Print(PRT_ERROR, "AAS_AreaCluster: invalid area number\n"); + return 0; + } //end if + return aasworld.areasettings[areanum].cluster; +} //end of the function AAS_AreaCluster +//=========================================================================== +// returns the presence types of the given area +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_AreaPresenceType(int areanum) +{ + if (!aasworld.loaded) return 0; + if (areanum <= 0 || areanum >= aasworld.numareas) + { + botimport.Print(PRT_ERROR, "AAS_AreaPresenceType: invalid area number\n"); + return 0; + } //end if + return aasworld.areasettings[areanum].presencetype; +} //end of the function AAS_AreaPresenceType +//=========================================================================== +// returns the presence type at the given point +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_PointPresenceType(vec3_t point) +{ + int areanum; + + if (!aasworld.loaded) return 0; + + areanum = AAS_PointAreaNum(point); + if (!areanum) return PRESENCE_NONE; + return aasworld.areasettings[areanum].presencetype; +} //end of the function AAS_PointPresenceType +//=========================================================================== +// calculates the minimum distance between the origin of the box and the +// given plane when both will collide on the given side of the plane +// +// normal = normal vector of plane to calculate distance from +// mins = minimums of box relative to origin +// maxs = maximums of box relative to origin +// side = side of the plane we want to calculate the distance from +// 0 normal vector side +// 1 not normal vector side +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float AAS_BoxOriginDistanceFromPlane(vec3_t normal, vec3_t mins, vec3_t maxs, int side) +{ + vec3_t v1, v2; + int i; + + //swap maxs and mins when on the other side of the plane + if (side) + { + //get a point of the box that would be one of the first + //to collide with the plane + for (i = 0; i < 3; i++) + { + if (normal[i] > BBOX_NORMAL_EPSILON) v1[i] = maxs[i]; + else if (normal[i] < -BBOX_NORMAL_EPSILON) v1[i] = mins[i]; + else v1[i] = 0; + } //end for + } //end if + else + { + //get a point of the box that would be one of the first + //to collide with the plane + for (i = 0; i < 3; i++) + { + if (normal[i] > BBOX_NORMAL_EPSILON) v1[i] = mins[i]; + else if (normal[i] < -BBOX_NORMAL_EPSILON) v1[i] = maxs[i]; + else v1[i] = 0; + } //end for + } //end else + // + VectorCopy(normal, v2); + VectorInverse(v2); +// VectorNegate(normal, v2); + return DotProduct(v1, v2); +} //end of the function AAS_BoxOriginDistanceFromPlane +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +qboolean AAS_AreaEntityCollision(int areanum, vec3_t start, vec3_t end, + int presencetype, int passent, aas_trace_t *trace) +{ + int collision; + vec3_t boxmins, boxmaxs; + aas_link_t *link; + bsp_trace_t bsptrace; + + AAS_PresenceTypeBoundingBox(presencetype, boxmins, boxmaxs); + + Com_Memset(&bsptrace, 0, sizeof(bsp_trace_t)); //make compiler happy + //assume no collision + bsptrace.fraction = 1; + collision = qfalse; + for (link = aasworld.arealinkedentities[areanum]; link; link = link->next_ent) + { + //ignore the pass entity + if (link->entnum == passent) continue; + // + if (AAS_EntityCollision(link->entnum, start, boxmins, boxmaxs, end, + CONTENTS_SOLID|CONTENTS_PLAYERCLIP, &bsptrace)) + { + collision = qtrue; + } //end if + } //end for + if (collision) + { + trace->startsolid = bsptrace.startsolid; + trace->ent = bsptrace.ent; + VectorCopy(bsptrace.endpos, trace->endpos); + trace->area = 0; + trace->planenum = 0; + return qtrue; + } //end if + return qfalse; +} //end of the function AAS_AreaEntityCollision +//=========================================================================== +// recursive subdivision of the line by the BSP tree. +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +aas_trace_t AAS_TraceClientBBox(vec3_t start, vec3_t end, int presencetype, + int passent) +{ + int side, nodenum, tmpplanenum; + float front, back, frac; + vec3_t cur_start, cur_end, cur_mid, v1, v2; + aas_tracestack_t tracestack[127]; + aas_tracestack_t *tstack_p; + aas_node_t *aasnode; + aas_plane_t *plane; + aas_trace_t trace; + + //clear the trace structure + Com_Memset(&trace, 0, sizeof(aas_trace_t)); + + if (!aasworld.loaded) return trace; + + tstack_p = tracestack; + //we start with the whole line on the stack + VectorCopy(start, tstack_p->start); + VectorCopy(end, tstack_p->end); + tstack_p->planenum = 0; + //start with node 1 because node zero is a dummy for a solid leaf + tstack_p->nodenum = 1; //starting at the root of the tree + tstack_p++; + + while (1) + { + //pop up the stack + tstack_p--; + //if the trace stack is empty (ended up with a piece of the + //line to be traced in an area) + if (tstack_p < tracestack) + { + tstack_p++; + //nothing was hit + trace.startsolid = qfalse; + trace.fraction = 1.0; + //endpos is the end of the line + VectorCopy(end, trace.endpos); + //nothing hit + trace.ent = 0; + trace.area = 0; + trace.planenum = 0; + return trace; + } //end if + //number of the current node to test the line against + nodenum = tstack_p->nodenum; + //if it is an area + if (nodenum < 0) + { +#ifdef AAS_SAMPLE_DEBUG + if (-nodenum > aasworld.numareasettings) + { + botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: -nodenum out of range\n"); + return trace; + } //end if +#endif //AAS_SAMPLE_DEBUG + //botimport.Print(PRT_MESSAGE, "areanum = %d, must be %d\n", -nodenum, AAS_PointAreaNum(start)); + //if can't enter the area because it hasn't got the right presence type + if (!(aasworld.areasettings[-nodenum].presencetype & presencetype)) + { + //if the start point is still the initial start point + //NOTE: no need for epsilons because the points will be + //exactly the same when they're both the start point + if (tstack_p->start[0] == start[0] && + tstack_p->start[1] == start[1] && + tstack_p->start[2] == start[2]) + { + trace.startsolid = qtrue; + trace.fraction = 0.0; + VectorClear(v1); + } //end if + else + { + trace.startsolid = qfalse; + VectorSubtract(end, start, v1); + VectorSubtract(tstack_p->start, start, v2); + trace.fraction = VectorLength(v2) / VectorNormalize(v1); + VectorMA(tstack_p->start, -0.125, v1, tstack_p->start); + } //end else + VectorCopy(tstack_p->start, trace.endpos); + trace.ent = 0; + trace.area = -nodenum; +// VectorSubtract(end, start, v1); + trace.planenum = tstack_p->planenum; + //always take the plane with normal facing towards the trace start + plane = &aasworld.planes[trace.planenum]; + if (DotProduct(v1, plane->normal) > 0) trace.planenum ^= 1; + return trace; + } //end if + else + { + if (passent >= 0) + { + if (AAS_AreaEntityCollision(-nodenum, tstack_p->start, + tstack_p->end, presencetype, passent, + &trace)) + { + if (!trace.startsolid) + { + VectorSubtract(end, start, v1); + VectorSubtract(trace.endpos, start, v2); + trace.fraction = VectorLength(v2) / VectorLength(v1); + } //end if + return trace; + } //end if + } //end if + } //end else + trace.lastarea = -nodenum; + continue; + } //end if + //if it is a solid leaf + if (!nodenum) + { + //if the start point is still the initial start point + //NOTE: no need for epsilons because the points will be + //exactly the same when they're both the start point + if (tstack_p->start[0] == start[0] && + tstack_p->start[1] == start[1] && + tstack_p->start[2] == start[2]) + { + trace.startsolid = qtrue; + trace.fraction = 0.0; + VectorClear(v1); + } //end if + else + { + trace.startsolid = qfalse; + VectorSubtract(end, start, v1); + VectorSubtract(tstack_p->start, start, v2); + trace.fraction = VectorLength(v2) / VectorNormalize(v1); + VectorMA(tstack_p->start, -0.125, v1, tstack_p->start); + } //end else + VectorCopy(tstack_p->start, trace.endpos); + trace.ent = 0; + trace.area = 0; //hit solid leaf +// VectorSubtract(end, start, v1); + trace.planenum = tstack_p->planenum; + //always take the plane with normal facing towards the trace start + plane = &aasworld.planes[trace.planenum]; + if (DotProduct(v1, plane->normal) > 0) trace.planenum ^= 1; + return trace; + } //end if +#ifdef AAS_SAMPLE_DEBUG + if (nodenum > aasworld.numnodes) + { + botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: nodenum out of range\n"); + return trace; + } //end if +#endif //AAS_SAMPLE_DEBUG + //the node to test against + aasnode = &aasworld.nodes[nodenum]; + //start point of current line to test against node + VectorCopy(tstack_p->start, cur_start); + //end point of the current line to test against node + VectorCopy(tstack_p->end, cur_end); + //the current node plane + plane = &aasworld.planes[aasnode->planenum]; + +// switch(plane->type) + {/*FIXME: wtf doesn't this work? obviously the axial node planes aren't always facing positive!!! + //check for axial planes + case PLANE_X: + { + front = cur_start[0] - plane->dist; + back = cur_end[0] - plane->dist; + break; + } //end case + case PLANE_Y: + { + front = cur_start[1] - plane->dist; + back = cur_end[1] - plane->dist; + break; + } //end case + case PLANE_Z: + { + front = cur_start[2] - plane->dist; + back = cur_end[2] - plane->dist; + break; + } //end case*/ +// default: //gee it's not an axial plane + { + front = DotProduct(cur_start, plane->normal) - plane->dist; + back = DotProduct(cur_end, plane->normal) - plane->dist; +// break; + } //end default + } //end switch + // bk010221 - old location of FPE hack and divide by zero expression + //if the whole to be traced line is totally at the front of this node + //only go down the tree with the front child + if ((front >= -ON_EPSILON && back >= -ON_EPSILON)) + { + //keep the current start and end point on the stack + //and go down the tree with the front child + tstack_p->nodenum = aasnode->children[0]; + tstack_p++; + if (tstack_p >= &tracestack[127]) + { + botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n"); + return trace; + } //end if + } //end if + //if the whole to be traced line is totally at the back of this node + //only go down the tree with the back child + else if ((front < ON_EPSILON && back < ON_EPSILON)) + { + //keep the current start and end point on the stack + //and go down the tree with the back child + tstack_p->nodenum = aasnode->children[1]; + tstack_p++; + if (tstack_p >= &tracestack[127]) + { + botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n"); + return trace; + } //end if + } //end if + //go down the tree both at the front and back of the node + else + { + tmpplanenum = tstack_p->planenum; + // bk010221 - new location of divide by zero (see above) + if ( front == back ) front -= 0.001f; // bk0101022 - hack/FPE + //calculate the hitpoint with the node (split point of the line) + //put the crosspoint TRACEPLANE_EPSILON pixels on the near side + if (front < 0) frac = (front + TRACEPLANE_EPSILON)/(front-back); + else frac = (front - TRACEPLANE_EPSILON)/(front-back); // bk010221 + // + if (frac < 0) + frac = 0.001f; //0 + else if (frac > 1) + frac = 0.999f; //1 + //frac = front / (front-back); + // + cur_mid[0] = cur_start[0] + (cur_end[0] - cur_start[0]) * frac; + cur_mid[1] = cur_start[1] + (cur_end[1] - cur_start[1]) * frac; + cur_mid[2] = cur_start[2] + (cur_end[2] - cur_start[2]) * frac; + +// AAS_DrawPlaneCross(cur_mid, plane->normal, plane->dist, plane->type, LINECOLOR_RED); + //side the front part of the line is on + side = front < 0; + //first put the end part of the line on the stack (back side) + VectorCopy(cur_mid, tstack_p->start); + //not necesary to store because still on stack + //VectorCopy(cur_end, tstack_p->end); + tstack_p->planenum = aasnode->planenum; + tstack_p->nodenum = aasnode->children[!side]; + tstack_p++; + if (tstack_p >= &tracestack[127]) + { + botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n"); + return trace; + } //end if + //now put the part near the start of the line on the stack so we will + //continue with thats part first. This way we'll find the first + //hit of the bbox + VectorCopy(cur_start, tstack_p->start); + VectorCopy(cur_mid, tstack_p->end); + tstack_p->planenum = tmpplanenum; + tstack_p->nodenum = aasnode->children[side]; + tstack_p++; + if (tstack_p >= &tracestack[127]) + { + botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n"); + return trace; + } //end if + } //end else + } //end while +// return trace; +} //end of the function AAS_TraceClientBBox +//=========================================================================== +// recursive subdivision of the line by the BSP tree. +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_TraceAreas(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas) +{ + int side, nodenum, tmpplanenum; + int numareas; + float front, back, frac; + vec3_t cur_start, cur_end, cur_mid; + aas_tracestack_t tracestack[127]; + aas_tracestack_t *tstack_p; + aas_node_t *aasnode; + aas_plane_t *plane; + + numareas = 0; + areas[0] = 0; + if (!aasworld.loaded) return numareas; + + tstack_p = tracestack; + //we start with the whole line on the stack + VectorCopy(start, tstack_p->start); + VectorCopy(end, tstack_p->end); + tstack_p->planenum = 0; + //start with node 1 because node zero is a dummy for a solid leaf + tstack_p->nodenum = 1; //starting at the root of the tree + tstack_p++; + + while (1) + { + //pop up the stack + tstack_p--; + //if the trace stack is empty (ended up with a piece of the + //line to be traced in an area) + if (tstack_p < tracestack) + { + return numareas; + } //end if + //number of the current node to test the line against + nodenum = tstack_p->nodenum; + //if it is an area + if (nodenum < 0) + { +#ifdef AAS_SAMPLE_DEBUG + if (-nodenum > aasworld.numareasettings) + { + botimport.Print(PRT_ERROR, "AAS_TraceAreas: -nodenum = %d out of range\n", -nodenum); + return numareas; + } //end if +#endif //AAS_SAMPLE_DEBUG + //botimport.Print(PRT_MESSAGE, "areanum = %d, must be %d\n", -nodenum, AAS_PointAreaNum(start)); + areas[numareas] = -nodenum; + if (points) VectorCopy(tstack_p->start, points[numareas]); + numareas++; + if (numareas >= maxareas) return numareas; + continue; + } //end if + //if it is a solid leaf + if (!nodenum) + { + continue; + } //end if +#ifdef AAS_SAMPLE_DEBUG + if (nodenum > aasworld.numnodes) + { + botimport.Print(PRT_ERROR, "AAS_TraceAreas: nodenum out of range\n"); + return numareas; + } //end if +#endif //AAS_SAMPLE_DEBUG + //the node to test against + aasnode = &aasworld.nodes[nodenum]; + //start point of current line to test against node + VectorCopy(tstack_p->start, cur_start); + //end point of the current line to test against node + VectorCopy(tstack_p->end, cur_end); + //the current node plane + plane = &aasworld.planes[aasnode->planenum]; + +// switch(plane->type) + {/*FIXME: wtf doesn't this work? obviously the node planes aren't always facing positive!!! + //check for axial planes + case PLANE_X: + { + front = cur_start[0] - plane->dist; + back = cur_end[0] - plane->dist; + break; + } //end case + case PLANE_Y: + { + front = cur_start[1] - plane->dist; + back = cur_end[1] - plane->dist; + break; + } //end case + case PLANE_Z: + { + front = cur_start[2] - plane->dist; + back = cur_end[2] - plane->dist; + break; + } //end case*/ +// default: //gee it's not an axial plane + { + front = DotProduct(cur_start, plane->normal) - plane->dist; + back = DotProduct(cur_end, plane->normal) - plane->dist; +// break; + } //end default + } //end switch + + //if the whole to be traced line is totally at the front of this node + //only go down the tree with the front child + if (front > 0 && back > 0) + { + //keep the current start and end point on the stack + //and go down the tree with the front child + tstack_p->nodenum = aasnode->children[0]; + tstack_p++; + if (tstack_p >= &tracestack[127]) + { + botimport.Print(PRT_ERROR, "AAS_TraceAreas: stack overflow\n"); + return numareas; + } //end if + } //end if + //if the whole to be traced line is totally at the back of this node + //only go down the tree with the back child + else if (front <= 0 && back <= 0) + { + //keep the current start and end point on the stack + //and go down the tree with the back child + tstack_p->nodenum = aasnode->children[1]; + tstack_p++; + if (tstack_p >= &tracestack[127]) + { + botimport.Print(PRT_ERROR, "AAS_TraceAreas: stack overflow\n"); + return numareas; + } //end if + } //end if + //go down the tree both at the front and back of the node + else + { + tmpplanenum = tstack_p->planenum; + //calculate the hitpoint with the node (split point of the line) + //put the crosspoint TRACEPLANE_EPSILON pixels on the near side + if (front < 0) frac = (front)/(front-back); + else frac = (front)/(front-back); + if (frac < 0) frac = 0; + else if (frac > 1) frac = 1; + //frac = front / (front-back); + // + cur_mid[0] = cur_start[0] + (cur_end[0] - cur_start[0]) * frac; + cur_mid[1] = cur_start[1] + (cur_end[1] - cur_start[1]) * frac; + cur_mid[2] = cur_start[2] + (cur_end[2] - cur_start[2]) * frac; + +// AAS_DrawPlaneCross(cur_mid, plane->normal, plane->dist, plane->type, LINECOLOR_RED); + //side the front part of the line is on + side = front < 0; + //first put the end part of the line on the stack (back side) + VectorCopy(cur_mid, tstack_p->start); + //not necesary to store because still on stack + //VectorCopy(cur_end, tstack_p->end); + tstack_p->planenum = aasnode->planenum; + tstack_p->nodenum = aasnode->children[!side]; + tstack_p++; + if (tstack_p >= &tracestack[127]) + { + botimport.Print(PRT_ERROR, "AAS_TraceAreas: stack overflow\n"); + return numareas; + } //end if + //now put the part near the start of the line on the stack so we will + //continue with thats part first. This way we'll find the first + //hit of the bbox + VectorCopy(cur_start, tstack_p->start); + VectorCopy(cur_mid, tstack_p->end); + tstack_p->planenum = tmpplanenum; + tstack_p->nodenum = aasnode->children[side]; + tstack_p++; + if (tstack_p >= &tracestack[127]) + { + botimport.Print(PRT_ERROR, "AAS_TraceAreas: stack overflow\n"); + return numareas; + } //end if + } //end else + } //end while +// return numareas; +} //end of the function AAS_TraceAreas +//=========================================================================== +// a simple cross product +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +// void AAS_OrthogonalToVectors(vec3_t v1, vec3_t v2, vec3_t res) +#define AAS_OrthogonalToVectors(v1, v2, res) \ + (res)[0] = ((v1)[1] * (v2)[2]) - ((v1)[2] * (v2)[1]);\ + (res)[1] = ((v1)[2] * (v2)[0]) - ((v1)[0] * (v2)[2]);\ + (res)[2] = ((v1)[0] * (v2)[1]) - ((v1)[1] * (v2)[0]); +//=========================================================================== +// tests if the given point is within the face boundaries +// +// Parameter: face : face to test if the point is in it +// pnormal : normal of the plane to use for the face +// point : point to test if inside face boundaries +// Returns: qtrue if the point is within the face boundaries +// Changes Globals: - +//=========================================================================== +qboolean AAS_InsideFace(aas_face_t *face, vec3_t pnormal, vec3_t point, float epsilon) +{ + int i, firstvertex, edgenum; + vec3_t v0; + vec3_t edgevec, pointvec, sepnormal; + aas_edge_t *edge; +#ifdef AAS_SAMPLE_DEBUG + int lastvertex = 0; +#endif //AAS_SAMPLE_DEBUG + + if (!aasworld.loaded) return qfalse; + + for (i = 0; i < face->numedges; i++) + { + edgenum = aasworld.edgeindex[face->firstedge + i]; + edge = &aasworld.edges[abs(edgenum)]; + //get the first vertex of the edge + firstvertex = edgenum < 0; + VectorCopy(aasworld.vertexes[edge->v[firstvertex]], v0); + //edge vector + VectorSubtract(aasworld.vertexes[edge->v[!firstvertex]], v0, edgevec); + // +#ifdef AAS_SAMPLE_DEBUG + if (lastvertex && lastvertex != edge->v[firstvertex]) + { + botimport.Print(PRT_MESSAGE, "winding not counter clockwise\n"); + } //end if + lastvertex = edge->v[!firstvertex]; +#endif //AAS_SAMPLE_DEBUG + //vector from first edge point to point possible in face + VectorSubtract(point, v0, pointvec); + //get a vector pointing inside the face orthogonal to both the + //edge vector and the normal vector of the plane the face is in + //this vector defines a plane through the origin (first vertex of + //edge) and through both the edge vector and the normal vector + //of the plane + AAS_OrthogonalToVectors(edgevec, pnormal, sepnormal); + //check on wich side of the above plane the point is + //this is done by checking the sign of the dot product of the + //vector orthogonal vector from above and the vector from the + //origin (first vertex of edge) to the point + //if the dotproduct is smaller than zero the point is outside the face + if (DotProduct(pointvec, sepnormal) < -epsilon) return qfalse; + } //end for + return qtrue; +} //end of the function AAS_InsideFace +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +qboolean AAS_PointInsideFace(int facenum, vec3_t point, float epsilon) +{ + int i, firstvertex, edgenum; + float *v1, *v2; + vec3_t edgevec, pointvec, sepnormal; + aas_edge_t *edge; + aas_plane_t *plane; + aas_face_t *face; + + if (!aasworld.loaded) return qfalse; + + face = &aasworld.faces[facenum]; + plane = &aasworld.planes[face->planenum]; + // + for (i = 0; i < face->numedges; i++) + { + edgenum = aasworld.edgeindex[face->firstedge + i]; + edge = &aasworld.edges[abs(edgenum)]; + //get the first vertex of the edge + firstvertex = edgenum < 0; + v1 = aasworld.vertexes[edge->v[firstvertex]]; + v2 = aasworld.vertexes[edge->v[!firstvertex]]; + //edge vector + VectorSubtract(v2, v1, edgevec); + //vector from first edge point to point possible in face + VectorSubtract(point, v1, pointvec); + // + CrossProduct(edgevec, plane->normal, sepnormal); + // + if (DotProduct(pointvec, sepnormal) < -epsilon) return qfalse; + } //end for + return qtrue; +} //end of the function AAS_PointInsideFace +//=========================================================================== +// returns the ground face the given point is above in the given area +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +aas_face_t *AAS_AreaGroundFace(int areanum, vec3_t point) +{ + int i, facenum; + vec3_t up = {0, 0, 1}; + vec3_t normal; + aas_area_t *area; + aas_face_t *face; + + if (!aasworld.loaded) return NULL; + + area = &aasworld.areas[areanum]; + for (i = 0; i < area->numfaces; i++) + { + facenum = aasworld.faceindex[area->firstface + i]; + face = &aasworld.faces[abs(facenum)]; + //if this is a ground face + if (face->faceflags & FACE_GROUND) + { + //get the up or down normal + if (aasworld.planes[face->planenum].normal[2] < 0) VectorNegate(up, normal); + else VectorCopy(up, normal); + //check if the point is in the face + if (AAS_InsideFace(face, normal, point, 0.01f)) return face; + } //end if + } //end for + return NULL; +} //end of the function AAS_AreaGroundFace +//=========================================================================== +// returns the face the trace end position is situated in +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_FacePlane(int facenum, vec3_t normal, float *dist) +{ + aas_plane_t *plane; + + plane = &aasworld.planes[aasworld.faces[facenum].planenum]; + VectorCopy(plane->normal, normal); + *dist = plane->dist; +} //end of the function AAS_FacePlane +//=========================================================================== +// returns the face the trace end position is situated in +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +aas_face_t *AAS_TraceEndFace(aas_trace_t *trace) +{ + int i, facenum; + aas_area_t *area; + aas_face_t *face, *firstface = NULL; + + if (!aasworld.loaded) return NULL; + + //if started in solid no face was hit + if (trace->startsolid) return NULL; + //trace->lastarea is the last area the trace was in + area = &aasworld.areas[trace->lastarea]; + //check which face the trace.endpos was in + for (i = 0; i < area->numfaces; i++) + { + facenum = aasworld.faceindex[area->firstface + i]; + face = &aasworld.faces[abs(facenum)]; + //if the face is in the same plane as the trace end point + if ((face->planenum & ~1) == (trace->planenum & ~1)) + { + //firstface is used for optimization, if theres only one + //face in the plane then it has to be the good one + //if there are more faces in the same plane then always + //check the one with the fewest edges first +/* if (firstface) + { + if (firstface->numedges < face->numedges) + { + if (AAS_InsideFace(firstface, + aasworld.planes[face->planenum].normal, trace->endpos)) + { + return firstface; + } //end if + firstface = face; + } //end if + else + { + if (AAS_InsideFace(face, + aasworld.planes[face->planenum].normal, trace->endpos)) + { + return face; + } //end if + } //end else + } //end if + else + { + firstface = face; + } //end else*/ + if (AAS_InsideFace(face, + aasworld.planes[face->planenum].normal, trace->endpos, 0.01f)) return face; + } //end if + } //end for + return firstface; +} //end of the function AAS_TraceEndFace +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_BoxOnPlaneSide2(vec3_t absmins, vec3_t absmaxs, aas_plane_t *p) +{ + int i, sides; + float dist1, dist2; + vec3_t corners[2]; + + for (i = 0; i < 3; i++) + { + if (p->normal[i] < 0) + { + corners[0][i] = absmins[i]; + corners[1][i] = absmaxs[i]; + } //end if + else + { + corners[1][i] = absmins[i]; + corners[0][i] = absmaxs[i]; + } //end else + } //end for + dist1 = DotProduct(p->normal, corners[0]) - p->dist; + dist2 = DotProduct(p->normal, corners[1]) - p->dist; + sides = 0; + if (dist1 >= 0) sides = 1; + if (dist2 < 0) sides |= 2; + + return sides; +} //end of the function AAS_BoxOnPlaneSide2 +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +//int AAS_BoxOnPlaneSide(vec3_t absmins, vec3_t absmaxs, aas_plane_t *p) +#define AAS_BoxOnPlaneSide(absmins, absmaxs, p) (\ + ( (p)->type < 3) ?\ + (\ + ( (p)->dist <= (absmins)[(p)->type]) ?\ + (\ + 1\ + )\ + :\ + (\ + ( (p)->dist >= (absmaxs)[(p)->type]) ?\ + (\ + 2\ + )\ + :\ + (\ + 3\ + )\ + )\ + )\ + :\ + (\ + AAS_BoxOnPlaneSide2((absmins), (absmaxs), (p))\ + )\ +) //end of the function AAS_BoxOnPlaneSide +//=========================================================================== +// remove the links to this entity from all areas +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_UnlinkFromAreas(aas_link_t *areas) +{ + aas_link_t *link, *nextlink; + + for (link = areas; link; link = nextlink) + { + //next area the entity is linked in + nextlink = link->next_area; + //remove the entity from the linked list of this area + if (link->prev_ent) link->prev_ent->next_ent = link->next_ent; + else aasworld.arealinkedentities[link->areanum] = link->next_ent; + if (link->next_ent) link->next_ent->prev_ent = link->prev_ent; + //deallocate the link structure + AAS_DeAllocAASLink(link); + } //end for +} //end of the function AAS_UnlinkFromAreas +//=========================================================================== +// link the entity to the areas the bounding box is totally or partly +// situated in. This is done with recursion down the tree using the +// bounding box to test for plane sides +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== + +typedef struct aas_linkstack_s { + int nodenum; //node found after splitting +} aas_linkstack_t; + +aas_link_t *AAS_AASLinkEntity(vec3_t absmins, vec3_t absmaxs, int entnum) +{ + int side, nodenum; + aas_linkstack_t linkstack[128]; + aas_linkstack_t *lstack_p; + aas_node_t *aasnode; + aas_plane_t *plane; + aas_link_t *link, *areas; + + if (!aasworld.loaded) + { + botimport.Print(PRT_ERROR, "AAS_LinkEntity: aas not loaded\n"); + return NULL; + } //end if + + areas = NULL; + // + lstack_p = linkstack; + //we start with the whole line on the stack + //start with node 1 because node zero is a dummy used for solid leafs + lstack_p->nodenum = 1; //starting at the root of the tree + lstack_p++; + + while (1) + { + //pop up the stack + lstack_p--; + //if the trace stack is empty (ended up with a piece of the + //line to be traced in an area) + if (lstack_p < linkstack) break; + //number of the current node to test the line against + nodenum = lstack_p->nodenum; + //if it is an area + if (nodenum < 0) + { + //NOTE: the entity might have already been linked into this area + // because several node children can point to the same area + for (link = aasworld.arealinkedentities[-nodenum]; link; link = link->next_ent) + { + if (link->entnum == entnum) break; + } //end for + if (link) continue; + // + link = AAS_AllocAASLink(); + if (!link) return areas; + link->entnum = entnum; + link->areanum = -nodenum; + //put the link into the double linked area list of the entity + link->prev_area = NULL; + link->next_area = areas; + if (areas) areas->prev_area = link; + areas = link; + //put the link into the double linked entity list of the area + link->prev_ent = NULL; + link->next_ent = aasworld.arealinkedentities[-nodenum]; + if (aasworld.arealinkedentities[-nodenum]) + aasworld.arealinkedentities[-nodenum]->prev_ent = link; + aasworld.arealinkedentities[-nodenum] = link; + // + continue; + } //end if + //if solid leaf + if (!nodenum) continue; + //the node to test against + aasnode = &aasworld.nodes[nodenum]; + //the current node plane + plane = &aasworld.planes[aasnode->planenum]; + //get the side(s) the box is situated relative to the plane + side = AAS_BoxOnPlaneSide2(absmins, absmaxs, plane); + //if on the front side of the node + if (side & 1) + { + lstack_p->nodenum = aasnode->children[0]; + lstack_p++; + } //end if + if (lstack_p >= &linkstack[127]) + { + botimport.Print(PRT_ERROR, "AAS_LinkEntity: stack overflow\n"); + break; + } //end if + //if on the back side of the node + if (side & 2) + { + lstack_p->nodenum = aasnode->children[1]; + lstack_p++; + } //end if + if (lstack_p >= &linkstack[127]) + { + botimport.Print(PRT_ERROR, "AAS_LinkEntity: stack overflow\n"); + break; + } //end if + } //end while + return areas; +} //end of the function AAS_AASLinkEntity +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +aas_link_t *AAS_LinkEntityClientBBox(vec3_t absmins, vec3_t absmaxs, int entnum, int presencetype) +{ + vec3_t mins, maxs; + vec3_t newabsmins, newabsmaxs; + + AAS_PresenceTypeBoundingBox(presencetype, mins, maxs); + VectorSubtract(absmins, maxs, newabsmins); + VectorSubtract(absmaxs, mins, newabsmaxs); + //relink the entity + return AAS_AASLinkEntity(newabsmins, newabsmaxs, entnum); +} //end of the function AAS_LinkEntityClientBBox +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_BBoxAreas(vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas) +{ + aas_link_t *linkedareas, *link; + int num; + + linkedareas = AAS_AASLinkEntity(absmins, absmaxs, -1); + num = 0; + for (link = linkedareas; link; link = link->next_area) + { + areas[num] = link->areanum; + num++; + if (num >= maxareas) + break; + } //end for + AAS_UnlinkFromAreas(linkedareas); + return num; +} //end of the function AAS_BBoxAreas +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AAS_AreaInfo( int areanum, aas_areainfo_t *info ) +{ + aas_areasettings_t *settings; + if (!info) + return 0; + if (areanum <= 0 || areanum >= aasworld.numareas) + { + botimport.Print(PRT_ERROR, "AAS_AreaInfo: areanum %d out of range\n", areanum); + return 0; + } //end if + settings = &aasworld.areasettings[areanum]; + info->cluster = settings->cluster; + info->contents = settings->contents; + info->flags = settings->areaflags; + info->presencetype = settings->presencetype; + VectorCopy(aasworld.areas[areanum].mins, info->mins); + VectorCopy(aasworld.areas[areanum].maxs, info->maxs); + VectorCopy(aasworld.areas[areanum].center, info->center); + return sizeof(aas_areainfo_t); +} //end of the function AAS_AreaInfo +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +aas_plane_t *AAS_PlaneFromNum(int planenum) +{ + if (!aasworld.loaded) return 0; + + return &aasworld.planes[planenum]; +} //end of the function AAS_PlaneFromNum diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_sample.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_sample.h new file mode 100644 index 0000000..752cd8e --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_aas_sample.h @@ -0,0 +1,75 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_aas_sample.h + * + * desc: AAS + * + * $Archive: /source/code/botlib/be_aas_sample.h $ + * $Author: Mrelusive $ + * $Revision: 2 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 10/05/99 3:42p $ + * + *****************************************************************************/ + +#pragma once + +#ifdef AASINTERN +void AAS_InitAASLinkHeap(void); +void AAS_InitAASLinkedEntities(void); +void AAS_FreeAASLinkHeap(void); +void AAS_FreeAASLinkedEntities(void); +aas_face_t *AAS_AreaGroundFace(int areanum, vec3_t point); +aas_face_t *AAS_TraceEndFace(aas_trace_t *trace); +aas_plane_t *AAS_PlaneFromNum(int planenum); +aas_link_t *AAS_AASLinkEntity(vec3_t absmins, vec3_t absmaxs, int entnum); +aas_link_t *AAS_LinkEntityClientBBox(vec3_t absmins, vec3_t absmaxs, int entnum, int presencetype); +qboolean AAS_PointInsideFace(int facenum, vec3_t point, float epsilon); +qboolean AAS_InsideFace(aas_face_t *face, vec3_t pnormal, vec3_t point, float epsilon); +void AAS_UnlinkFromAreas(aas_link_t *areas); +#endif //AASINTERN + +//returns the mins and maxs of the bounding box for the given presence type +void AAS_PresenceTypeBoundingBox(int presencetype, vec3_t mins, vec3_t maxs); +//returns the cluster the area is in (negative portal number if the area is a portal) +int AAS_AreaCluster(int areanum); +//returns the presence type(s) of the area +int AAS_AreaPresenceType(int areanum); +//returns the presence type(s) at the given point +int AAS_PointPresenceType(vec3_t point); +//returns the result of the trace of a client bbox +aas_trace_t AAS_TraceClientBBox(vec3_t start, vec3_t end, int presencetype, int passent); +//stores the areas the trace went through and returns the number of passed areas +int AAS_TraceAreas(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas); +//returns the areas the bounding box is in +int AAS_BBoxAreas(vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas); +//return area information +int AAS_AreaInfo( int areanum, aas_areainfo_t *info ); +//returns the area the point is in +int AAS_PointAreaNum(vec3_t point); +// +int AAS_PointReachabilityAreaIndex( vec3_t point ); +//returns the plane the given face is in +void AAS_FacePlane(int facenum, vec3_t normal, float *dist); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_char.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_char.cpp new file mode 100644 index 0000000..413d83e --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_char.cpp @@ -0,0 +1,795 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_ai_char.c + * + * desc: bot characters + * + * $Archive: /MissionPack/code/botlib/be_ai_char.c $ + * $Author: Ttimo $ + * $Revision: 6 $ + * $Modtime: 4/22/01 8:52a $ + * $Date: 4/22/01 8:52a $ + * + *****************************************************************************/ + +#include "qcommon/q_shared.h" +#include "l_log.h" +#include "l_memory.h" +#include "l_utils.h" +#include "l_script.h" +#include "l_precomp.h" +#include "l_struct.h" +#include "l_libvar.h" +#include "aasfile.h" +#include "botlib.h" +#include "be_aas.h" +#include "be_aas_funcs.h" +#include "be_interface.h" +#include "be_ai_char.h" + +#define MAX_CHARACTERISTICS 80 + +#define CT_INTEGER 1 +#define CT_FLOAT 2 +#define CT_STRING 3 + +#define DEFAULT_CHARACTER "bots/default_c.c" + +//characteristic value +union cvalue +{ + int integer; + float _float; + char *string; +}; +//a characteristic +typedef struct bot_characteristic_s +{ + char type; //characteristic type + union cvalue value; //characteristic value +} bot_characteristic_t; + +//a bot character +typedef struct bot_character_s +{ + char filename[MAX_QPATH]; + float skill; + bot_characteristic_t c[1]; //variable sized +} bot_character_t; + +bot_character_t *botcharacters[MAX_CLIENTS + 1]; + +//======================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//======================================================================== +bot_character_t *BotCharacterFromHandle(int handle) +{ + if (handle <= 0 || handle > MAX_CLIENTS) + { + botimport.Print(PRT_FATAL, "character handle %d out of range\n", handle); + return NULL; + } //end if + if (!botcharacters[handle]) + { + botimport.Print(PRT_FATAL, "invalid character %d\n", handle); + return NULL; + } //end if + return botcharacters[handle]; +} //end of the function BotCharacterFromHandle +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotDumpCharacter(bot_character_t *ch) +{ + int i; + + Log_Write("%s\n", ch->filename); + Log_Write("skill %.1f\n", ch->skill); + Log_Write("{\n"); + for (i = 0; i < MAX_CHARACTERISTICS; i++) + { + switch(ch->c[i].type) + { + case CT_INTEGER: Log_Write(" %4d %d\n", i, ch->c[i].value.integer); break; + case CT_FLOAT: Log_Write(" %4d %f\n", i, ch->c[i].value._float); break; + case CT_STRING: Log_Write(" %4d %s\n", i, ch->c[i].value.string); break; + } //end case + } //end for + Log_Write("}\n"); +} //end of the function BotDumpCharacter +//======================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//======================================================================== +void BotFreeCharacterStrings(bot_character_t *ch) +{ + int i; + + for (i = 0; i < MAX_CHARACTERISTICS; i++) + { + if (ch->c[i].type == CT_STRING) + { + FreeMemory(ch->c[i].value.string); + } //end if + } //end for +} //end of the function BotFreeCharacterStrings +//======================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//======================================================================== +void BotFreeCharacter2(int handle) +{ + if (handle <= 0 || handle > MAX_CLIENTS) + { + botimport.Print(PRT_FATAL, "character handle %d out of range\n", handle); + return; + } //end if + if (!botcharacters[handle]) + { + botimport.Print(PRT_FATAL, "invalid character %d\n", handle); + return; + } //end if + BotFreeCharacterStrings(botcharacters[handle]); + FreeMemory(botcharacters[handle]); + botcharacters[handle] = NULL; +} //end of the function BotFreeCharacter2 +//======================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//======================================================================== +void BotFreeCharacter(int handle) +{ + if (!LibVarGetValue("bot_reloadcharacters")) return; + BotFreeCharacter2(handle); +} //end of the function BotFreeCharacter +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotDefaultCharacteristics(bot_character_t *ch, bot_character_t *defaultch) +{ + int i; + + for (i = 0; i < MAX_CHARACTERISTICS; i++) + { + if (ch->c[i].type) continue; + // + if (defaultch->c[i].type == CT_FLOAT) + { + ch->c[i].type = CT_FLOAT; + ch->c[i].value._float = defaultch->c[i].value._float; + } //end if + else if (defaultch->c[i].type == CT_INTEGER) + { + ch->c[i].type = CT_INTEGER; + ch->c[i].value.integer = defaultch->c[i].value.integer; + } //end else if + else if (defaultch->c[i].type == CT_STRING) + { + ch->c[i].type = CT_STRING; + ch->c[i].value.string = (char *) GetMemory(strlen(defaultch->c[i].value.string)+1); + strcpy(ch->c[i].value.string, defaultch->c[i].value.string); + } //end else if + } //end for +} //end of the function BotDefaultCharacteristics +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_character_t *BotLoadCharacterFromFile(char *charfile, int skill) +{ + int indent, index, foundcharacter; + bot_character_t *ch; + source_t *source; + token_t token; + + foundcharacter = qfalse; + //a bot character is parsed in two phases + PC_SetBaseFolder(BOTFILESBASEFOLDER); + source = LoadSourceFile(charfile); + if (!source) + { + botimport.Print(PRT_ERROR, "counldn't load %s\n", charfile); + return NULL; + } //end if + ch = (bot_character_t *) GetClearedMemory(sizeof(bot_character_t) + + MAX_CHARACTERISTICS * sizeof(bot_characteristic_t)); + strcpy(ch->filename, charfile); + while(PC_ReadToken(source, &token)) + { + if (!strcmp(token.string, "skill")) + { + if (!PC_ExpectTokenType(source, TT_NUMBER, 0, &token)) + { + FreeSource(source); + BotFreeCharacterStrings(ch); + FreeMemory(ch); + return NULL; + } //end if + if (!PC_ExpectTokenString(source, "{")) + { + FreeSource(source); + BotFreeCharacterStrings(ch); + FreeMemory(ch); + return NULL; + } //end if + //if it's the correct skill + if (skill < 0 || (int)token.intvalue == skill) + { + foundcharacter = qtrue; + ch->skill = token.intvalue; + while(PC_ExpectAnyToken(source, &token)) + { + if (!strcmp(token.string, "}")) break; + if (token.type != TT_NUMBER || !(token.subtype & TT_INTEGER)) + { + SourceError(source, "expected integer index, found %s", token.string); + FreeSource(source); + BotFreeCharacterStrings(ch); + FreeMemory(ch); + return NULL; + } //end if + index = token.intvalue; + if (index < 0 || index > MAX_CHARACTERISTICS) + { + SourceError(source, "characteristic index out of range [0, %d]", MAX_CHARACTERISTICS); + FreeSource(source); + BotFreeCharacterStrings(ch); + FreeMemory(ch); + return NULL; + } //end if + if (ch->c[index].type) + { + SourceError(source, "characteristic %d already initialized", index); + FreeSource(source); + BotFreeCharacterStrings(ch); + FreeMemory(ch); + return NULL; + } //end if + if (!PC_ExpectAnyToken(source, &token)) + { + FreeSource(source); + BotFreeCharacterStrings(ch); + FreeMemory(ch); + return NULL; + } //end if + if (token.type == TT_NUMBER) + { + if (token.subtype & TT_FLOAT) + { + ch->c[index].value._float = token.floatvalue; + ch->c[index].type = CT_FLOAT; + } //end if + else + { + ch->c[index].value.integer = token.intvalue; + ch->c[index].type = CT_INTEGER; + } //end else + } //end if + else if (token.type == TT_STRING) + { + StripDoubleQuotes(token.string); + ch->c[index].value.string = (char *)GetMemory(strlen(token.string)+1); + strcpy(ch->c[index].value.string, token.string); + ch->c[index].type = CT_STRING; + } //end else if + else + { + SourceError(source, "expected integer, float or string, found %s", token.string); + FreeSource(source); + BotFreeCharacterStrings(ch); + FreeMemory(ch); + return NULL; + } //end else + } //end if + break; + } //end if + else + { + indent = 1; + while(indent) + { + if (!PC_ExpectAnyToken(source, &token)) + { + FreeSource(source); + BotFreeCharacterStrings(ch); + FreeMemory(ch); + return NULL; + } //end if + if (!strcmp(token.string, "{")) indent++; + else if (!strcmp(token.string, "}")) indent--; + } //end while + } //end else + } //end if + else + { + SourceError(source, "unknown definition %s", token.string); + FreeSource(source); + BotFreeCharacterStrings(ch); + FreeMemory(ch); + return NULL; + } //end else + } //end while + FreeSource(source); + // + if (!foundcharacter) + { + BotFreeCharacterStrings(ch); + FreeMemory(ch); + return NULL; + } //end if + return ch; +} //end of the function BotLoadCharacterFromFile +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotFindCachedCharacter(char *charfile, float skill) +{ + int handle; + + for (handle = 1; handle <= MAX_CLIENTS; handle++) + { + if ( !botcharacters[handle] ) continue; + if ( strcmp( botcharacters[handle]->filename, charfile ) == 0 && + (skill < 0 || fabs(botcharacters[handle]->skill - skill) < 0.01) ) + { + return handle; + } //end if + } //end for + return 0; +} //end of the function BotFindCachedCharacter +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotLoadCachedCharacter(char *charfile, float skill, int reload) +{ + int handle, cachedhandle, intskill; + bot_character_t *ch = NULL; +#ifdef DEBUG + int starttime; + + starttime = Sys_MilliSeconds(); +#endif //DEBUG + + //find a free spot for a character + for (handle = 1; handle <= MAX_CLIENTS; handle++) + { + if (!botcharacters[handle]) break; + } //end for + if (handle > MAX_CLIENTS) return 0; + //try to load a cached character with the given skill + if (!reload) + { + cachedhandle = BotFindCachedCharacter(charfile, skill); + if (cachedhandle) + { + botimport.Print(PRT_MESSAGE, "loaded cached skill %f from %s\n", skill, charfile); + return cachedhandle; + } //end if + } //end else + // + intskill = (int) (skill + 0.5); + //try to load the character with the given skill + ch = BotLoadCharacterFromFile(charfile, intskill); + if (ch) + { + botcharacters[handle] = ch; + // + botimport.Print(PRT_MESSAGE, "loaded skill %d from %s\n", intskill, charfile); +#ifdef DEBUG + if (botDeveloper) + { + botimport.Print(PRT_MESSAGE, "skill %d loaded in %d msec from %s\n", intskill, Sys_MilliSeconds() - starttime, charfile); + } //end if +#endif //DEBUG + return handle; + } //end if + // + botimport.Print(PRT_WARNING, "couldn't find skill %d in %s\n", intskill, charfile); + // + if (!reload) + { + //try to load a cached default character with the given skill + cachedhandle = BotFindCachedCharacter(DEFAULT_CHARACTER, skill); + if (cachedhandle) + { + botimport.Print(PRT_MESSAGE, "loaded cached default skill %d from %s\n", intskill, charfile); + return cachedhandle; + } //end if + } //end if + //try to load the default character with the given skill + ch = BotLoadCharacterFromFile(DEFAULT_CHARACTER, intskill); + if (ch) + { + botcharacters[handle] = ch; + botimport.Print(PRT_MESSAGE, "loaded default skill %d from %s\n", intskill, charfile); + return handle; + } //end if + // + if (!reload) + { + //try to load a cached character with any skill + cachedhandle = BotFindCachedCharacter(charfile, -1); + if (cachedhandle) + { + botimport.Print(PRT_MESSAGE, "loaded cached skill %f from %s\n", botcharacters[cachedhandle]->skill, charfile); + return cachedhandle; + } //end if + } //end if + //try to load a character with any skill + ch = BotLoadCharacterFromFile(charfile, -1); + if (ch) + { + botcharacters[handle] = ch; + botimport.Print(PRT_MESSAGE, "loaded skill %f from %s\n", ch->skill, charfile); + return handle; + } //end if + // + if (!reload) + { + //try to load a cached character with any skill + cachedhandle = BotFindCachedCharacter(DEFAULT_CHARACTER, -1); + if (cachedhandle) + { + botimport.Print(PRT_MESSAGE, "loaded cached default skill %f from %s\n", botcharacters[cachedhandle]->skill, charfile); + return cachedhandle; + } //end if + } //end if + //try to load a character with any skill + ch = BotLoadCharacterFromFile(DEFAULT_CHARACTER, -1); + if (ch) + { + botcharacters[handle] = ch; + botimport.Print(PRT_MESSAGE, "loaded default skill %f from %s\n", ch->skill, charfile); + return handle; + } //end if + // + botimport.Print(PRT_WARNING, "couldn't load any skill from %s\n", charfile); + //couldn't load any character + return 0; +} //end of the function BotLoadCachedCharacter +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotLoadCharacterSkill(char *charfile, float skill) +{ + int ch, defaultch; + + defaultch = BotLoadCachedCharacter(DEFAULT_CHARACTER, skill, qfalse); + ch = BotLoadCachedCharacter(charfile, skill, LibVarGetValue("bot_reloadcharacters")); + + if (defaultch && ch) + { + BotDefaultCharacteristics(botcharacters[ch], botcharacters[defaultch]); + } //end if + + return ch; +} //end of the function BotLoadCharacterSkill +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotInterpolateCharacters(int handle1, int handle2, float desiredskill) +{ + bot_character_t *ch1, *ch2, *out; + int i, handle; + float scale; + + ch1 = BotCharacterFromHandle(handle1); + ch2 = BotCharacterFromHandle(handle2); + if (!ch1 || !ch2) + return 0; + //find a free spot for a character + for (handle = 1; handle <= MAX_CLIENTS; handle++) + { + if (!botcharacters[handle]) break; + } //end for + if (handle > MAX_CLIENTS) return 0; + out = (bot_character_t *) GetClearedMemory(sizeof(bot_character_t) + + MAX_CHARACTERISTICS * sizeof(bot_characteristic_t)); + out->skill = desiredskill; + strcpy(out->filename, ch1->filename); + botcharacters[handle] = out; + + scale = (float) (desiredskill - ch1->skill) / (ch2->skill - ch1->skill); + for (i = 0; i < MAX_CHARACTERISTICS; i++) + { + // + if (ch1->c[i].type == CT_FLOAT && ch2->c[i].type == CT_FLOAT) + { + out->c[i].type = CT_FLOAT; + out->c[i].value._float = ch1->c[i].value._float + + (ch2->c[i].value._float - ch1->c[i].value._float) * scale; + } //end if + else if (ch1->c[i].type == CT_INTEGER) + { + out->c[i].type = CT_INTEGER; + out->c[i].value.integer = ch1->c[i].value.integer; + } //end else if + else if (ch1->c[i].type == CT_STRING) + { + out->c[i].type = CT_STRING; + out->c[i].value.string = (char *) GetMemory(strlen(ch1->c[i].value.string)+1); + strcpy(out->c[i].value.string, ch1->c[i].value.string); + } //end else if + } //end for + return handle; +} //end of the function BotInterpolateCharacters +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotLoadCharacter(char *charfile, float skill) +{ + int firstskill, secondskill, handle; + + //make sure the skill is in the valid range + if (skill < 1.0) skill = 1.0; + else if (skill > 5.0) skill = 5.0; + //skill 1, 4 and 5 should be available in the character files + if (skill == 1.0 || skill == 4.0 || skill == 5.0) + { + return BotLoadCharacterSkill(charfile, skill); + } //end if + //check if there's a cached skill + handle = BotFindCachedCharacter(charfile, skill); + if (handle) + { + botimport.Print(PRT_MESSAGE, "loaded cached skill %f from %s\n", skill, charfile); + return handle; + } //end if + if (skill < 4.0) + { + //load skill 1 and 4 + firstskill = BotLoadCharacterSkill(charfile, 1); + if (!firstskill) return 0; + secondskill = BotLoadCharacterSkill(charfile, 4); + if (!secondskill) return firstskill; + } //end if + else + { + //load skill 4 and 5 + firstskill = BotLoadCharacterSkill(charfile, 4); + if (!firstskill) return 0; + secondskill = BotLoadCharacterSkill(charfile, 5); + if (!secondskill) return firstskill; + } //end else + //interpolate between the two skills + handle = BotInterpolateCharacters(firstskill, secondskill, skill); + if (!handle) return 0; + //write the character to the log file + BotDumpCharacter(botcharacters[handle]); + // + return handle; +} //end of the function BotLoadCharacter +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int CheckCharacteristicIndex(int character, int index) +{ + bot_character_t *ch; + + ch = BotCharacterFromHandle(character); + if (!ch) return qfalse; + if (index < 0 || index >= MAX_CHARACTERISTICS) + { + botimport.Print(PRT_ERROR, "characteristic %d does not exist\n", index); + return qfalse; + } //end if + if (!ch->c[index].type) + { + botimport.Print(PRT_ERROR, "characteristic %d is not initialized\n", index); + return qfalse; + } //end if + return qtrue; +} //end of the function CheckCharacteristicIndex +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float Characteristic_Float(int character, int index) +{ + bot_character_t *ch; + + ch = BotCharacterFromHandle(character); + if (!ch) return 0; + //check if the index is in range + if (!CheckCharacteristicIndex(character, index)) return 0; + //an integer will be converted to a float + if (ch->c[index].type == CT_INTEGER) + { + return (float) ch->c[index].value.integer; + } //end if + //floats are just returned + else if (ch->c[index].type == CT_FLOAT) + { + return ch->c[index].value._float; + } //end else if + //cannot convert a string pointer to a float + else + { + botimport.Print(PRT_ERROR, "characteristic %d is not a float\n", index); + return 0; + } //end else if +// return 0; +} //end of the function Characteristic_Float +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float Characteristic_BFloat(int character, int index, float min, float max) +{ + float value; + bot_character_t *ch; + + ch = BotCharacterFromHandle(character); + if (!ch) return 0; + if (min > max) + { + botimport.Print(PRT_ERROR, "cannot bound characteristic %d between %f and %f\n", index, min, max); + return 0; + } //end if + value = Characteristic_Float(character, index); + if (value < min) return min; + if (value > max) return max; + return value; +} //end of the function Characteristic_BFloat +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int Characteristic_Integer(int character, int index) +{ + bot_character_t *ch; + + ch = BotCharacterFromHandle(character); + if (!ch) return 0; + //check if the index is in range + if (!CheckCharacteristicIndex(character, index)) return 0; + //an integer will just be returned + if (ch->c[index].type == CT_INTEGER) + { + return ch->c[index].value.integer; + } //end if + //floats are casted to integers + else if (ch->c[index].type == CT_FLOAT) + { + return (int) ch->c[index].value._float; + } //end else if + else + { + botimport.Print(PRT_ERROR, "characteristic %d is not an integer\n", index); + return 0; + } //end else if +// return 0; +} //end of the function Characteristic_Integer +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int Characteristic_BInteger(int character, int index, int min, int max) +{ + int value; + bot_character_t *ch; + + ch = BotCharacterFromHandle(character); + if (!ch) return 0; + if (min > max) + { + botimport.Print(PRT_ERROR, "cannot bound characteristic %d between %d and %d\n", index, min, max); + return 0; + } //end if + value = Characteristic_Integer(character, index); + if (value < min) return min; + if (value > max) return max; + return value; +} //end of the function Characteristic_BInteger +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void Characteristic_String(int character, int index, char *buf, int size) +{ + bot_character_t *ch; + + ch = BotCharacterFromHandle(character); + if (!ch) return; + //check if the index is in range + if (!CheckCharacteristicIndex(character, index)) return; + //an integer will be converted to a float + if (ch->c[index].type == CT_STRING) + { + strncpy(buf, ch->c[index].value.string, size-1); + buf[size-1] = '\0'; + return; + } //end if + else + { + botimport.Print(PRT_ERROR, "characteristic %d is not a string\n", index); + return; + } //end else if + return; +} //end of the function Characteristic_String +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotShutdownCharacters(void) +{ + int handle; + + for (handle = 1; handle <= MAX_CLIENTS; handle++) + { + if (botcharacters[handle]) + { + BotFreeCharacter2(handle); + } //end if + } //end for +} //end of the function BotShutdownCharacters + diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_char.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_char.h new file mode 100644 index 0000000..4443b9d --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_char.h @@ -0,0 +1,54 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_ai_char.h + * + * desc: bot characters + * + * $Archive: /source/code/botlib/be_ai_char.h $ + * $Author: osman $ + * $Revision: 1.4 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 2003/03/15 23:43:59 $ + * + *****************************************************************************/ + +#pragma once + +//loads a bot character from a file +int BotLoadCharacter(char *charfile, float skill); +//frees a bot character +void BotFreeCharacter(int character); +//returns a float characteristic +float Characteristic_Float(int character, int index); +//returns a bounded float characteristic +float Characteristic_BFloat(int character, int index, float min, float max); +//returns an integer characteristic +int Characteristic_Integer(int character, int index); +//returns a bounded integer characteristic +int Characteristic_BInteger(int character, int index, int min, int max); +//returns a string characteristic +void Characteristic_String(int character, int index, char *buf, int size); +//free cached bot characters +void BotShutdownCharacters(void); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_chat.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_chat.cpp new file mode 100644 index 0000000..fb29c53 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_chat.cpp @@ -0,0 +1,3044 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_ai_chat.c + * + * desc: bot chat AI + * + * $Archive: /MissionPack/code/botlib/be_ai_chat.c $ + * $Author: Ttimo $ + * $Revision: 12 $ + * $Modtime: 4/13/01 4:45p $ + * $Date: 4/13/01 4:45p $ + * + *****************************************************************************/ + +#include "qcommon/q_shared.h" +#include "l_memory.h" +#include "l_libvar.h" +#include "l_script.h" +#include "l_precomp.h" +#include "l_struct.h" +#include "l_utils.h" +#include "l_log.h" +#include "aasfile.h" +#include "botlib.h" +#include "be_aas.h" +#include "be_aas_funcs.h" +#include "be_interface.h" +#include "be_ea.h" +#include "be_ai_chat.h" + + +//escape character +#define ESCAPE_CHAR 0x01 //'_' +// +// "hi ", people, " ", 0, " entered the game" +//becomes: +// "hi _rpeople_ _v0_ entered the game" +// + +//match piece types +#define MT_VARIABLE 1 //variable match piece +#define MT_STRING 2 //string match piece +//reply chat key flags +#define RCKFL_AND 1 //key must be present +#define RCKFL_NOT 2 //key must be absent +#define RCKFL_NAME 4 //name of bot must be present +#define RCKFL_STRING 8 //key is a string +#define RCKFL_VARIABLES 16 //key is a match template +#define RCKFL_BOTNAMES 32 //key is a series of botnames +#define RCKFL_GENDERFEMALE 64 //bot must be female +#define RCKFL_GENDERMALE 128 //bot must be male +#define RCKFL_GENDERLESS 256 //bot must be genderless +//time to ignore a chat message after using it +#define CHATMESSAGE_RECENTTIME 20 + +//the actuall chat messages +typedef struct bot_chatmessage_s +{ + char *chatmessage; //chat message string + float time; //last time used + struct bot_chatmessage_s *next; //next chat message in a list +} bot_chatmessage_t; +//bot chat type with chat lines +typedef struct bot_chattype_s +{ + char name[MAX_CHATTYPE_NAME]; + int numchatmessages; + bot_chatmessage_t *firstchatmessage; + struct bot_chattype_s *next; +} bot_chattype_t; +//bot chat lines +typedef struct bot_chat_s +{ + bot_chattype_t *types; +} bot_chat_t; + +//random string +typedef struct bot_randomstring_s +{ + char *string; + struct bot_randomstring_s *next; +} bot_randomstring_t; +//list with random strings +typedef struct bot_randomlist_s +{ + char *string; + int numstrings; + bot_randomstring_t *firstrandomstring; + struct bot_randomlist_s *next; +} bot_randomlist_t; + +//synonym +typedef struct bot_synonym_s +{ + char *string; + float weight; + struct bot_synonym_s *next; +} bot_synonym_t; +//list with synonyms +typedef struct bot_synonymlist_s +{ + unsigned long int context; + float totalweight; + bot_synonym_t *firstsynonym; + struct bot_synonymlist_s *next; +} bot_synonymlist_t; + +//fixed match string +typedef struct bot_matchstring_s +{ + char *string; + struct bot_matchstring_s *next; +} bot_matchstring_t; + +//piece of a match template +typedef struct bot_matchpiece_s +{ + int type; + bot_matchstring_t *firststring; + int variable; + struct bot_matchpiece_s *next; +} bot_matchpiece_t; +//match template +typedef struct bot_matchtemplate_s +{ + unsigned long int context; + int type; + int subtype; + bot_matchpiece_t *first; + struct bot_matchtemplate_s *next; +} bot_matchtemplate_t; + +//reply chat key +typedef struct bot_replychatkey_s +{ + int flags; + char *string; + bot_matchpiece_t *match; + struct bot_replychatkey_s *next; +} bot_replychatkey_t; +//reply chat +typedef struct bot_replychat_s +{ + bot_replychatkey_t *keys; + float priority; + int numchatmessages; + bot_chatmessage_t *firstchatmessage; + struct bot_replychat_s *next; +} bot_replychat_t; + +//string list +typedef struct bot_stringlist_s +{ + char *string; + struct bot_stringlist_s *next; +} bot_stringlist_t; + +//chat state of a bot +typedef struct bot_chatstate_s +{ + int gender; //0=it, 1=female, 2=male + int client; //client number + char name[32]; //name of the bot + char chatmessage[MAX_MESSAGE_SIZE]; + int handle; + //the console messages visible to the bot + bot_consolemessage_t *firstmessage; //first message is the first typed message + bot_consolemessage_t *lastmessage; //last message is the last typed message, bottom of console + //number of console messages stored in the state + int numconsolemessages; + //the bot chat lines + bot_chat_t *chat; +} bot_chatstate_t; + +typedef struct bot_ichatdata_s { + bot_chat_t *chat; + char filename[MAX_QPATH]; + char chatname[MAX_QPATH]; +} bot_ichatdata_t; + +bot_ichatdata_t *ichatdata[MAX_CLIENTS]; + +bot_chatstate_t *botchatstates[MAX_CLIENTS+1]; +//console message heap +bot_consolemessage_t *consolemessageheap = NULL; +bot_consolemessage_t *freeconsolemessages = NULL; +//list with match strings +bot_matchtemplate_t *matchtemplates = NULL; +//list with synonyms +bot_synonymlist_t *synonyms = NULL; +//list with random strings +bot_randomlist_t *randomstrings = NULL; +//reply chats +bot_replychat_t *replychats = NULL; + +//======================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//======================================================================== +bot_chatstate_t *BotChatStateFromHandle(int handle) +{ + if (handle <= 0 || handle > MAX_CLIENTS) + { + botimport.Print(PRT_FATAL, "chat state handle %d out of range\n", handle); + return NULL; + } //end if + if (!botchatstates[handle]) + { + botimport.Print(PRT_FATAL, "invalid chat state %d\n", handle); + return NULL; + } //end if + return botchatstates[handle]; +} //end of the function BotChatStateFromHandle +//=========================================================================== +// initialize the heap with unused console messages +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void InitConsoleMessageHeap(void) +{ + int i, max_messages; + + if (consolemessageheap) FreeMemory(consolemessageheap); + // + max_messages = (int) LibVarValue("max_messages", "1024"); + consolemessageheap = (bot_consolemessage_t *) GetClearedHunkMemory(max_messages * + sizeof(bot_consolemessage_t)); + consolemessageheap[0].prev = NULL; + consolemessageheap[0].next = &consolemessageheap[1]; + for (i = 1; i < max_messages-1; i++) + { + consolemessageheap[i].prev = &consolemessageheap[i - 1]; + consolemessageheap[i].next = &consolemessageheap[i + 1]; + } //end for + consolemessageheap[max_messages-1].prev = &consolemessageheap[max_messages-2]; + consolemessageheap[max_messages-1].next = NULL; + //pointer to the free console messages + freeconsolemessages = consolemessageheap; +} //end of the function InitConsoleMessageHeap +//=========================================================================== +// allocate one console message from the heap +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_consolemessage_t *AllocConsoleMessage(void) +{ + bot_consolemessage_t *message; + message = freeconsolemessages; + if (freeconsolemessages) freeconsolemessages = freeconsolemessages->next; + if (freeconsolemessages) freeconsolemessages->prev = NULL; + return message; +} //end of the function AllocConsoleMessage +//=========================================================================== +// deallocate one console message from the heap +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void FreeConsoleMessage(bot_consolemessage_t *message) +{ + if (freeconsolemessages) freeconsolemessages->prev = message; + message->prev = NULL; + message->next = freeconsolemessages; + freeconsolemessages = message; +} //end of the function FreeConsoleMessage +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotRemoveConsoleMessage(int chatstate, int handle) +{ + bot_consolemessage_t *m, *nextm; + bot_chatstate_t *cs; + + cs = BotChatStateFromHandle(chatstate); + if (!cs) return; + + for (m = cs->firstmessage; m; m = nextm) + { + nextm = m->next; + if (m->handle == handle) + { + if (m->next) m->next->prev = m->prev; + else cs->lastmessage = m->prev; + if (m->prev) m->prev->next = m->next; + else cs->firstmessage = m->next; + + FreeConsoleMessage(m); + cs->numconsolemessages--; + break; + } //end if + } //end for +} //end of the function BotRemoveConsoleMessage +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotQueueConsoleMessage(int chatstate, int type, char *message) +{ + bot_consolemessage_t *m; + bot_chatstate_t *cs; + + cs = BotChatStateFromHandle(chatstate); + if (!cs) return; + + m = AllocConsoleMessage(); + if (!m) + { + botimport.Print(PRT_ERROR, "empty console message heap\n"); + return; + } //end if + cs->handle++; + if (cs->handle <= 0 || cs->handle > 8192) cs->handle = 1; + m->handle = cs->handle; + m->time = AAS_Time(); + m->type = type; + strncpy(m->message, message, MAX_MESSAGE_SIZE); + m->next = NULL; + if (cs->lastmessage) + { + cs->lastmessage->next = m; + m->prev = cs->lastmessage; + cs->lastmessage = m; + } //end if + else + { + cs->lastmessage = m; + cs->firstmessage = m; + m->prev = NULL; + } //end if + cs->numconsolemessages++; +} //end of the function BotQueueConsoleMessage +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotNextConsoleMessage(int chatstate, bot_consolemessage_t *cm) +{ + bot_chatstate_t *cs; + bot_consolemessage_t *firstmsg; + + cs = BotChatStateFromHandle(chatstate); + if (!cs) return 0; + if ((firstmsg = cs->firstmessage)) + { + cm->handle = firstmsg->handle; + cm->time = firstmsg->time; + cm->type = firstmsg->type; + Q_strncpyz(cm->message, firstmsg->message, + sizeof(cm->message)); + + /* We omit setting the two pointers in cm because pointer + * size in the VM differs between the size in the engine on + * 64 bit machines, which would lead to a buffer overflow if + * this functions is called from the VM. The pointers are + * of no interest to functions calling + * BotNextConsoleMessage anyways. + */ + + return cm->handle; + } //end if + return 0; +} //end of the function BotConsoleMessage +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotNumConsoleMessages(int chatstate) +{ + bot_chatstate_t *cs; + + cs = BotChatStateFromHandle(chatstate); + if (!cs) return 0; + return cs->numconsolemessages; +} //end of the function BotNumConsoleMessages +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int IsWhiteSpace(char c) +{ + if ((c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z') + || (c >= '0' && c <= '9') + || c == '(' || c == ')' + || c == '?' || c == ':' + || c == '\''|| c == '/' + || c == ',' || c == '.' + || c == '[' || c == ']' + || c == '-' || c == '_' + || c == '+' || c == '=') return qfalse; + return qtrue; +} //end of the function IsWhiteSpace +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotRemoveTildes(char *message) +{ + int i; + + //remove all tildes from the chat message + for (i = 0; message[i]; i++) + { + if (message[i] == '~') + { + memmove(&message[i], &message[i+1], strlen(&message[i+1])+1); + } //end if + } //end for +} //end of the function BotRemoveTildes +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void UnifyWhiteSpaces(char *string) +{ + char *ptr, *oldptr; + + for (ptr = oldptr = string; *ptr; oldptr = ptr) + { + while(*ptr && IsWhiteSpace(*ptr)) ptr++; + if (ptr > oldptr) + { + //if not at the start and not at the end of the string + //write only one space + if (oldptr > string && *ptr) *oldptr++ = ' '; + //remove all other white spaces + if (ptr > oldptr) memmove(oldptr, ptr, strlen(ptr)+1); + } //end if + while(*ptr && !IsWhiteSpace(*ptr)) ptr++; + } //end while +} //end of the function UnifyWhiteSpaces +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int StringContains(char *str1, char *str2, int casesensitive) +{ + int len, i, j, index; + + if (str1 == NULL || str2 == NULL) return -1; + + len = strlen(str1) - strlen(str2); + index = 0; + for (i = 0; i <= len; i++, str1++, index++) + { + for (j = 0; str2[j]; j++) + { + if (casesensitive) + { + if (str1[j] != str2[j]) break; + } //end if + else + { + if (toupper(str1[j]) != toupper(str2[j])) break; + } //end else + } //end for + if (!str2[j]) return index; + } //end for + return -1; +} //end of the function StringContains +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +char *StringContainsWord(char *str1, char *str2, int casesensitive) +{ + int len, i, j; + + len = strlen(str1) - strlen(str2); + for (i = 0; i <= len; i++, str1++) + { + //if not at the start of the string + if (i) + { + //skip to the start of the next word + while(*str1 && *str1 != ' ' && *str1 != '.' && *str1 != ',' && *str1 != '!') str1++; + if (!*str1) break; + str1++; + } //end for + //compare the word + for (j = 0; str2[j]; j++) + { + if (casesensitive) + { + if (str1[j] != str2[j]) break; + } //end if + else + { + if (toupper(str1[j]) != toupper(str2[j])) break; + } //end else + } //end for + //if there was a word match + if (!str2[j]) + { + //if the first string has an end of word + if (!str1[j] || str1[j] == ' ' || str1[j] == '.' || str1[j] == ',' || str1[j] == '!') return str1; + } //end if + } //end for + return NULL; +} //end of the function StringContainsWord +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void StringReplaceWords(char *string, char *synonym, char *replacement) +{ + char *str, *str2; + + //find the synonym in the string + str = StringContainsWord(string, synonym, qfalse); + //if the synonym occured in the string + while(str) + { + //if the synonym isn't part of the replacement which is already in the string + //usefull for abreviations + str2 = StringContainsWord(string, replacement, qfalse); + while(str2) + { + if (str2 <= str && str < str2 + strlen(replacement)) break; + str2 = StringContainsWord(str2+1, replacement, qfalse); + } //end while + if (!str2) + { + memmove(str + strlen(replacement), str+strlen(synonym), strlen(str+strlen(synonym))+1); + //append the synonum replacement + Com_Memcpy(str, replacement, strlen(replacement)); + } //end if + //find the next synonym in the string + str = StringContainsWord(str+strlen(replacement), synonym, qfalse); + } //end if +} //end of the function StringReplaceWords +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotDumpSynonymList(bot_synonymlist_t *synlist) +{ + FILE *fp; + bot_synonymlist_t *syn; + bot_synonym_t *synonym; + + fp = Log_FilePointer(); + if (!fp) return; + for (syn = synlist; syn; syn = syn->next) + { + fprintf(fp, "%ld : [", syn->context); + for (synonym = syn->firstsynonym; synonym; synonym = synonym->next) + { + fprintf(fp, "(\"%s\", %1.2f)", synonym->string, synonym->weight); + if (synonym->next) fprintf(fp, ", "); + } //end for + fprintf(fp, "]\n"); + } //end for +} //end of the function BotDumpSynonymList +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_synonymlist_t *BotLoadSynonyms(char *filename) +{ + int pass, size, contextlevel, numsynonyms; + unsigned long int context, contextstack[32]; + char *ptr = NULL; + source_t *source; + token_t token; + bot_synonymlist_t *synlist, *lastsyn, *syn; + bot_synonym_t *synonym, *lastsynonym; + + size = 0; + synlist = NULL; //make compiler happy + syn = NULL; //make compiler happy + synonym = NULL; //make compiler happy + //the synonyms are parsed in two phases + for (pass = 0; pass < 2; pass++) + { + // + if (pass && size) ptr = (char *) GetClearedHunkMemory(size); + // + PC_SetBaseFolder(BOTFILESBASEFOLDER); + source = LoadSourceFile(filename); + if (!source) + { + botimport.Print(PRT_ERROR, "counldn't load %s\n", filename); + return NULL; + } //end if + // + context = 0; + contextlevel = 0; + synlist = NULL; //list synonyms + lastsyn = NULL; //last synonym in the list + // + while(PC_ReadToken(source, &token)) + { + if (token.type == TT_NUMBER) + { + context |= token.intvalue; + contextstack[contextlevel] = token.intvalue; + contextlevel++; + if (contextlevel >= 32) + { + SourceError(source, "more than 32 context levels"); + FreeSource(source); + return NULL; + } //end if + if (!PC_ExpectTokenString(source, "{")) + { + FreeSource(source); + return NULL; + } //end if + } //end if + else if (token.type == TT_PUNCTUATION) + { + if (!strcmp(token.string, "}")) + { + contextlevel--; + if (contextlevel < 0) + { + SourceError(source, "too many }"); + FreeSource(source); + return NULL; + } //end if + context &= ~contextstack[contextlevel]; + } //end if + else if (!strcmp(token.string, "[")) + { + size += sizeof(bot_synonymlist_t); + if (pass) + { + syn = (bot_synonymlist_t *) ptr; + ptr += sizeof(bot_synonymlist_t); + syn->context = context; + syn->firstsynonym = NULL; + syn->next = NULL; + if (lastsyn) lastsyn->next = syn; + else synlist = syn; + lastsyn = syn; + } //end if + numsynonyms = 0; + lastsynonym = NULL; + while(1) + { + size_t len; + if (!PC_ExpectTokenString(source, "(") || + !PC_ExpectTokenType(source, TT_STRING, 0, &token)) + { + FreeSource(source); + return NULL; + } //end if + StripDoubleQuotes(token.string); + if (strlen(token.string) <= 0) + { + SourceError(source, "empty string"); + FreeSource(source); + return NULL; + } //end if + len = strlen(token.string) + 1; + len = PAD(len, sizeof(long)); + size += sizeof(bot_synonym_t) + len; + if (pass) + { + synonym = (bot_synonym_t *) ptr; + ptr += sizeof(bot_synonym_t); + synonym->string = ptr; + ptr += len; + strcpy(synonym->string, token.string); + // + if (lastsynonym) lastsynonym->next = synonym; + else syn->firstsynonym = synonym; + lastsynonym = synonym; + } //end if + numsynonyms++; + if (!PC_ExpectTokenString(source, ",") || + !PC_ExpectTokenType(source, TT_NUMBER, 0, &token) || + !PC_ExpectTokenString(source, ")")) + { + FreeSource(source); + return NULL; + } //end if + if (pass) + { + synonym->weight = token.floatvalue; + syn->totalweight += synonym->weight; + } //end if + if (PC_CheckTokenString(source, "]")) break; + if (!PC_ExpectTokenString(source, ",")) + { + FreeSource(source); + return NULL; + } //end if + } //end while + if (numsynonyms < 2) + { + SourceError(source, "synonym must have at least two entries"); + FreeSource(source); + return NULL; + } //end if + } //end else + else + { + SourceError(source, "unexpected %s", token.string); + FreeSource(source); + return NULL; + } //end if + } //end else if + } //end while + // + FreeSource(source); + // + if (contextlevel > 0) + { + SourceError(source, "missing }"); + return NULL; + } //end if + } //end for + botimport.Print(PRT_MESSAGE, "loaded %s\n", filename); + // + //BotDumpSynonymList(synlist); + // + return synlist; +} //end of the function BotLoadSynonyms +//=========================================================================== +// replace all the synonyms in the string +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotReplaceSynonyms(char *string, unsigned long int context) +{ + bot_synonymlist_t *syn; + bot_synonym_t *synonym; + + for (syn = synonyms; syn; syn = syn->next) + { + if (!(syn->context & context)) continue; + for (synonym = syn->firstsynonym->next; synonym; synonym = synonym->next) + { + StringReplaceWords(string, synonym->string, syn->firstsynonym->string); + } //end for + } //end for +} //end of the function BotReplaceSynonyms +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotReplaceWeightedSynonyms(char *string, unsigned long int context) +{ + bot_synonymlist_t *syn; + bot_synonym_t *synonym, *replacement; + float weight, curweight; + + for (syn = synonyms; syn; syn = syn->next) + { + if (!(syn->context & context)) continue; + //choose a weighted random replacement synonym + weight = Q_flrand(0.0f, 1.0f) * syn->totalweight; + if (!weight) continue; + curweight = 0; + for (replacement = syn->firstsynonym; replacement; replacement = replacement->next) + { + curweight += replacement->weight; + if (weight < curweight) break; + } //end for + if (!replacement) continue; + //replace all synonyms with the replacement + for (synonym = syn->firstsynonym; synonym; synonym = synonym->next) + { + if (synonym == replacement) continue; + StringReplaceWords(string, synonym->string, replacement->string); + } //end for + } //end for +} //end of the function BotReplaceWeightedSynonyms +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotReplaceReplySynonyms(char *string, unsigned long int context) +{ + char *str1, *str2, *replacement; + bot_synonymlist_t *syn; + bot_synonym_t *synonym; + + for (str1 = string; *str1; ) + { + //go to the start of the next word + while(*str1 && *str1 <= ' ') str1++; + if (!*str1) break; + // + for (syn = synonyms; syn; syn = syn->next) + { + if (!(syn->context & context)) continue; + for (synonym = syn->firstsynonym->next; synonym; synonym = synonym->next) + { + //if the synonym is not at the front of the string continue + str2 = StringContainsWord(str1, synonym->string, qfalse); + if (!str2 || str2 != str1) continue; + // + replacement = syn->firstsynonym->string; + //if the replacement IS in front of the string continue + str2 = StringContainsWord(str1, replacement, qfalse); + if (str2 && str2 == str1) continue; + // + memmove(str1 + strlen(replacement), str1+strlen(synonym->string), + strlen(str1+strlen(synonym->string)) + 1); + //append the synonum replacement + Com_Memcpy(str1, replacement, strlen(replacement)); + // + break; + } //end for + //if a synonym has been replaced + if (synonym) break; + } //end for + //skip over this word + while(*str1 && *str1 > ' ') str1++; + if (!*str1) break; + } //end while +} //end of the function BotReplaceReplySynonyms +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotLoadChatMessage(source_t *source, char *chatmessagestring) +{ + char *ptr; + token_t token; + + ptr = chatmessagestring; + *ptr = 0; + // + while(1) + { + if (!PC_ExpectAnyToken(source, &token)) return qfalse; + //fixed string + if (token.type == TT_STRING) + { + StripDoubleQuotes(token.string); + if (strlen(ptr) + strlen(token.string) + 1 > MAX_MESSAGE_SIZE) + { + SourceError(source, "chat message too long"); + return qfalse; + } //end if + strcat(ptr, token.string); + } //end else if + //variable string + else if (token.type == TT_NUMBER && (token.subtype & TT_INTEGER)) + { + if (strlen(ptr) + 7 > MAX_MESSAGE_SIZE) + { + SourceError(source, "chat message too long"); + return qfalse; + } //end if + sprintf(&ptr[strlen(ptr)], "%cv%ld%c", ESCAPE_CHAR, token.intvalue, ESCAPE_CHAR); + } //end if + //random string + else if (token.type == TT_NAME) + { + if (strlen(ptr) + 7 > MAX_MESSAGE_SIZE) + { + SourceError(source, "chat message too long"); + return qfalse; + } //end if + sprintf(&ptr[strlen(ptr)], "%cr%s%c", ESCAPE_CHAR, token.string, ESCAPE_CHAR); + } //end else if + else + { + SourceError(source, "unknown message component %s", token.string); + return qfalse; + } //end else + if (PC_CheckTokenString(source, ";")) break; + if (!PC_ExpectTokenString(source, ",")) return qfalse; + } //end while + // + return qtrue; +} //end of the function BotLoadChatMessage +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotDumpRandomStringList(bot_randomlist_t *randomlist) +{ + FILE *fp; + bot_randomlist_t *random; + bot_randomstring_t *rs; + + fp = Log_FilePointer(); + if (!fp) return; + for (random = randomlist; random; random = random->next) + { + fprintf(fp, "%s = {", random->string); + for (rs = random->firstrandomstring; rs; rs = rs->next) + { + fprintf(fp, "\"%s\"", rs->string); + if (rs->next) fprintf(fp, ", "); + else fprintf(fp, "}\n"); + } //end for + } //end for +} //end of the function BotDumpRandomStringList +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_randomlist_t *BotLoadRandomStrings(char *filename) +{ + int pass, size; + char *ptr = NULL, chatmessagestring[MAX_MESSAGE_SIZE]; + source_t *source; + token_t token; + bot_randomlist_t *randomlist, *lastrandom, *random; + bot_randomstring_t *randomstring; + +#ifdef DEBUG + int starttime = Sys_MilliSeconds(); +#endif //DEBUG + + size = 0; + randomlist = NULL; + random = NULL; + //the synonyms are parsed in two phases + for (pass = 0; pass < 2; pass++) + { + // + if (pass && size) ptr = (char *) GetClearedHunkMemory(size); + // + PC_SetBaseFolder(BOTFILESBASEFOLDER); + source = LoadSourceFile(filename); + if (!source) + { + botimport.Print(PRT_ERROR, "counldn't load %s\n", filename); + return NULL; + } //end if + // + randomlist = NULL; //list + lastrandom = NULL; //last + // + while(PC_ReadToken(source, &token)) + { + size_t len; + if (token.type != TT_NAME) + { + SourceError(source, "unknown random %s", token.string); + FreeSource(source); + return NULL; + } //end if + len = strlen(token.string) + 1; + len = PAD(len, sizeof(long)); + size += sizeof(bot_randomlist_t) + len; + if (pass) + { + random = (bot_randomlist_t *) ptr; + ptr += sizeof(bot_randomlist_t); + random->string = ptr; + ptr += len; + strcpy(random->string, token.string); + random->firstrandomstring = NULL; + random->numstrings = 0; + // + if (lastrandom) lastrandom->next = random; + else randomlist = random; + lastrandom = random; + } //end if + if (!PC_ExpectTokenString(source, "=") || + !PC_ExpectTokenString(source, "{")) + { + FreeSource(source); + return NULL; + } //end if + while(!PC_CheckTokenString(source, "}")) + { + size_t len; + if (!BotLoadChatMessage(source, chatmessagestring)) + { + FreeSource(source); + return NULL; + } //end if + len = strlen(chatmessagestring) + 1; + len = PAD(len, sizeof(long)); + size += sizeof(bot_randomstring_t) + len; + if (pass) + { + randomstring = (bot_randomstring_t *) ptr; + ptr += sizeof(bot_randomstring_t); + randomstring->string = ptr; + ptr += len; + strcpy(randomstring->string, chatmessagestring); + // + random->numstrings++; + randomstring->next = random->firstrandomstring; + random->firstrandomstring = randomstring; + } //end if + } //end while + } //end while + //free the source after one pass + FreeSource(source); + } //end for + botimport.Print(PRT_MESSAGE, "loaded %s\n", filename); + // +#ifdef DEBUG + botimport.Print(PRT_MESSAGE, "random strings %d msec\n", Sys_MilliSeconds() - starttime); + //BotDumpRandomStringList(randomlist); +#endif //DEBUG + // + return randomlist; +} //end of the function BotLoadRandomStrings +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +char *RandomString(char *name) +{ + bot_randomlist_t *random; + bot_randomstring_t *rs; + int i; + + for (random = randomstrings; random; random = random->next) + { + if (!strcmp(random->string, name)) + { + i = Q_flrand(0.0f, 1.0f) * random->numstrings; + for (rs = random->firstrandomstring; rs; rs = rs->next) + { + if (--i < 0) break; + } //end for + if (rs) + { + return rs->string; + } //end if + } //end for + } //end for + return NULL; +} //end of the function RandomString +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotDumpMatchTemplates(bot_matchtemplate_t *matches) +{ + FILE *fp; + bot_matchtemplate_t *mt; + bot_matchpiece_t *mp; + bot_matchstring_t *ms; + + fp = Log_FilePointer(); + if (!fp) return; + for (mt = matches; mt; mt = mt->next) + { + fprintf(fp, "{ " ); + for (mp = mt->first; mp; mp = mp->next) + { + if (mp->type == MT_STRING) + { + for (ms = mp->firststring; ms; ms = ms->next) + { + fprintf(fp, "\"%s\"", ms->string); + if (ms->next) fprintf(fp, "|"); + } //end for + } //end if + else if (mp->type == MT_VARIABLE) + { + fprintf(fp, "%d", mp->variable); + } //end else if + if (mp->next) fprintf(fp, ", "); + } //end for + fprintf(fp, " = (%d, %d);}\n", mt->type, mt->subtype); + } //end for +} //end of the function BotDumpMatchTemplates +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotFreeMatchPieces(bot_matchpiece_t *matchpieces) +{ + bot_matchpiece_t *mp, *nextmp; + bot_matchstring_t *ms, *nextms; + + for (mp = matchpieces; mp; mp = nextmp) + { + nextmp = mp->next; + if (mp->type == MT_STRING) + { + for (ms = mp->firststring; ms; ms = nextms) + { + nextms = ms->next; + FreeMemory(ms); + } //end for + } //end if + FreeMemory(mp); + } //end for +} //end of the function BotFreeMatchPieces +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_matchpiece_t *BotLoadMatchPieces(source_t *source, char *endtoken) +{ + int lastwasvariable, emptystring; + token_t token; + bot_matchpiece_t *matchpiece, *firstpiece, *lastpiece; + bot_matchstring_t *matchstring, *lastmatchstring; + + firstpiece = NULL; + lastpiece = NULL; + // + lastwasvariable = qfalse; + // + while(PC_ReadToken(source, &token)) + { + if (token.type == TT_NUMBER && (token.subtype & TT_INTEGER)) + { + if (token.intvalue >= MAX_MATCHVARIABLES) + { + SourceError(source, "can't have more than %d match variables", MAX_MATCHVARIABLES); + FreeSource(source); + BotFreeMatchPieces(firstpiece); + return NULL; + } //end if + if (lastwasvariable) + { + SourceError(source, "not allowed to have adjacent variables"); + FreeSource(source); + BotFreeMatchPieces(firstpiece); + return NULL; + } //end if + lastwasvariable = qtrue; + // + matchpiece = (bot_matchpiece_t *) GetClearedHunkMemory(sizeof(bot_matchpiece_t)); + matchpiece->type = MT_VARIABLE; + matchpiece->variable = token.intvalue; + matchpiece->next = NULL; + if (lastpiece) lastpiece->next = matchpiece; + else firstpiece = matchpiece; + lastpiece = matchpiece; + } //end if + else if (token.type == TT_STRING) + { + // + matchpiece = (bot_matchpiece_t *) GetClearedHunkMemory(sizeof(bot_matchpiece_t)); + matchpiece->firststring = NULL; + matchpiece->type = MT_STRING; + matchpiece->variable = 0; + matchpiece->next = NULL; + if (lastpiece) lastpiece->next = matchpiece; + else firstpiece = matchpiece; + lastpiece = matchpiece; + // + lastmatchstring = NULL; + emptystring = qfalse; + // + do + { + if (matchpiece->firststring) + { + if (!PC_ExpectTokenType(source, TT_STRING, 0, &token)) + { + FreeSource(source); + BotFreeMatchPieces(firstpiece); + return NULL; + } //end if + } //end if + StripDoubleQuotes(token.string); + matchstring = (bot_matchstring_t *) GetClearedHunkMemory(sizeof(bot_matchstring_t) + strlen(token.string) + 1); + matchstring->string = (char *) matchstring + sizeof(bot_matchstring_t); + strcpy(matchstring->string, token.string); + if (!strlen(token.string)) emptystring = qtrue; + matchstring->next = NULL; + if (lastmatchstring) lastmatchstring->next = matchstring; + else matchpiece->firststring = matchstring; + lastmatchstring = matchstring; + } while(PC_CheckTokenString(source, "|")); + //if there was no empty string found + if (!emptystring) lastwasvariable = qfalse; + } //end if + else + { + SourceError(source, "invalid token %s", token.string); + FreeSource(source); + BotFreeMatchPieces(firstpiece); + return NULL; + } //end else + if (PC_CheckTokenString(source, endtoken)) break; + if (!PC_ExpectTokenString(source, ",")) + { + FreeSource(source); + BotFreeMatchPieces(firstpiece); + return NULL; + } //end if + } //end while + return firstpiece; +} //end of the function BotLoadMatchPieces +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotFreeMatchTemplates(bot_matchtemplate_t *mt) +{ + bot_matchtemplate_t *nextmt; + + for (; mt; mt = nextmt) + { + nextmt = mt->next; + BotFreeMatchPieces(mt->first); + FreeMemory(mt); + } //end for +} //end of the function BotFreeMatchTemplates +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_matchtemplate_t *BotLoadMatchTemplates(char *matchfile) +{ + source_t *source; + token_t token; + bot_matchtemplate_t *matchtemplate, *matches, *lastmatch; + unsigned long int context; + + PC_SetBaseFolder(BOTFILESBASEFOLDER); + source = LoadSourceFile(matchfile); + if (!source) + { + botimport.Print(PRT_ERROR, "counldn't load %s\n", matchfile); + return NULL; + } //end if + // + matches = NULL; //list with matches + lastmatch = NULL; //last match in the list + + while(PC_ReadToken(source, &token)) + { + if (token.type != TT_NUMBER || !(token.subtype & TT_INTEGER)) + { + SourceError(source, "expected integer, found %s", token.string); + BotFreeMatchTemplates(matches); + FreeSource(source); + return NULL; + } //end if + //the context + context = token.intvalue; + // + if (!PC_ExpectTokenString(source, "{")) + { + BotFreeMatchTemplates(matches); + FreeSource(source); + return NULL; + } //end if + // + while(PC_ReadToken(source, &token)) + { + if (!strcmp(token.string, "}")) break; + // + PC_UnreadLastToken(source); + // + matchtemplate = (bot_matchtemplate_t *) GetClearedHunkMemory(sizeof(bot_matchtemplate_t)); + matchtemplate->context = context; + matchtemplate->next = NULL; + //add the match template to the list + if (lastmatch) lastmatch->next = matchtemplate; + else matches = matchtemplate; + lastmatch = matchtemplate; + //load the match template + matchtemplate->first = BotLoadMatchPieces(source, "="); + if (!matchtemplate->first) + { + BotFreeMatchTemplates(matches); + return NULL; + } //end if + //read the match type + if (!PC_ExpectTokenString(source, "(") || + !PC_ExpectTokenType(source, TT_NUMBER, TT_INTEGER, &token)) + { + BotFreeMatchTemplates(matches); + FreeSource(source); + return NULL; + } //end if + matchtemplate->type = token.intvalue; + //read the match subtype + if (!PC_ExpectTokenString(source, ",") || + !PC_ExpectTokenType(source, TT_NUMBER, TT_INTEGER, &token)) + { + BotFreeMatchTemplates(matches); + FreeSource(source); + return NULL; + } //end if + matchtemplate->subtype = token.intvalue; + //read trailing punctuations + if (!PC_ExpectTokenString(source, ")") || + !PC_ExpectTokenString(source, ";")) + { + BotFreeMatchTemplates(matches); + FreeSource(source); + return NULL; + } //end if + } //end while + } //end while + //free the source + FreeSource(source); + botimport.Print(PRT_MESSAGE, "loaded %s\n", matchfile); + // + //BotDumpMatchTemplates(matches); + // + return matches; +} //end of the function BotLoadMatchTemplates +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int StringsMatch(bot_matchpiece_t *pieces, bot_match_t *match) +{ + int lastvariable, index; + char *strptr, *newstrptr; + bot_matchpiece_t *mp; + bot_matchstring_t *ms; + + //no last variable + lastvariable = -1; + //pointer to the string to compare the match string with + strptr = match->string; + //Log_Write("match: %s", strptr); + //compare the string with the current match string + for (mp = pieces; mp; mp = mp->next) + { + //if it is a piece of string + if (mp->type == MT_STRING) + { + newstrptr = NULL; + for (ms = mp->firststring; ms; ms = ms->next) + { + if (!strlen(ms->string)) + { + newstrptr = strptr; + break; + } //end if + //Log_Write("MT_STRING: %s", mp->string); + index = StringContains(strptr, ms->string, qfalse); + if (index >= 0) + { + newstrptr = strptr + index; + if (lastvariable >= 0) + { + match->variables[lastvariable].length = + (newstrptr - match->string) - match->variables[lastvariable].offset; + //newstrptr - match->variables[lastvariable].ptr; + lastvariable = -1; + break; + } //end if + else if (index == 0) + { + break; + } //end else + newstrptr = NULL; + } //end if + } //end for + if (!newstrptr) return qfalse; + strptr = newstrptr + strlen(ms->string); + } //end if + //if it is a variable piece of string + else if (mp->type == MT_VARIABLE) + { + //Log_Write("MT_VARIABLE"); + match->variables[mp->variable].offset = strptr - match->string; + lastvariable = mp->variable; + } //end else if + } //end for + //if a match was found + if (!mp && (lastvariable >= 0 || !strlen(strptr))) + { + //if the last piece was a variable string + if (lastvariable >= 0) + { + assert( match->variables[lastvariable].offset >= 0 ); // bk001204 + match->variables[lastvariable].length = + strlen(&match->string[ (int) match->variables[lastvariable].offset]); + } //end if + return qtrue; + } //end if + return qfalse; +} //end of the function StringsMatch +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotFindMatch(char *str, bot_match_t *match, unsigned long int context) +{ + int i; + bot_matchtemplate_t *ms; + + strncpy(match->string, str, MAX_MESSAGE_SIZE); + //remove any trailing enters + while(strlen(match->string) && + match->string[strlen(match->string)-1] == '\n') + { + match->string[strlen(match->string)-1] = '\0'; + } //end while + //compare the string with all the match strings + for (ms = matchtemplates; ms; ms = ms->next) + { + if (!(ms->context & context)) continue; + //reset the match variable offsets + for (i = 0; i < MAX_MATCHVARIABLES; i++) match->variables[i].offset = -1; + // + if (StringsMatch(ms->first, match)) + { + match->type = ms->type; + match->subtype = ms->subtype; + return qtrue; + } //end if + } //end for + return qfalse; +} //end of the function BotFindMatch +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotMatchVariable(bot_match_t *match, int variable, char *buf, int size) +{ + if (variable < 0 || variable >= MAX_MATCHVARIABLES) + { + botimport.Print(PRT_FATAL, "BotMatchVariable: variable out of range\n"); + strcpy(buf, ""); + return; + } //end if + + if (match->variables[variable].offset >= 0) + { + if (match->variables[variable].length < size) + size = match->variables[variable].length+1; + assert( match->variables[variable].offset >= 0 ); // bk001204 + strncpy(buf, &match->string[ (int) match->variables[variable].offset], size-1); + buf[size-1] = '\0'; + } //end if + else + { + strcpy(buf, ""); + } //end else + return; +} //end of the function BotMatchVariable +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_stringlist_t *BotFindStringInList(bot_stringlist_t *list, char *string) +{ + bot_stringlist_t *s; + + for (s = list; s; s = s->next) + { + if (!strcmp(s->string, string)) return s; + } //end for + return NULL; +} //end of the function BotFindStringInList +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_stringlist_t *BotCheckChatMessageIntegrety(char *message, bot_stringlist_t *stringlist) +{ + int i; + char *msgptr; + char temp[MAX_MESSAGE_SIZE]; + bot_stringlist_t *s; + + msgptr = message; + // + while(*msgptr) + { + if (*msgptr == ESCAPE_CHAR) + { + msgptr++; + switch(*msgptr) + { + case 'v': //variable + { + //step over the 'v' + msgptr++; + while(*msgptr && *msgptr != ESCAPE_CHAR) msgptr++; + //step over the trailing escape char + if (*msgptr) msgptr++; + break; + } //end case + case 'r': //random + { + //step over the 'r' + msgptr++; + for (i = 0; (*msgptr && *msgptr != ESCAPE_CHAR); i++) + { + temp[i] = *msgptr++; + } //end while + temp[i] = '\0'; + //step over the trailing escape char + if (*msgptr) msgptr++; + //find the random keyword + if (!RandomString(temp)) + { + if (!BotFindStringInList(stringlist, temp)) + { + Log_Write("%s = {\"%s\"} //MISSING RANDOM\r\n", temp, temp); + s = (struct bot_stringlist_s *)GetClearedMemory(sizeof(bot_stringlist_t) + strlen(temp) + 1); + s->string = (char *) s + sizeof(bot_stringlist_t); + strcpy(s->string, temp); + s->next = stringlist; + stringlist = s; + } //end if + } //end if + break; + } //end case + default: + { + botimport.Print(PRT_FATAL, "BotCheckChatMessageIntegrety: message \"%s\" invalid escape char\n", message); + break; + } //end default + } //end switch + } //end if + else + { + msgptr++; + } //end else + } //end while + return stringlist; +} //end of the function BotCheckChatMessageIntegrety +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotCheckInitialChatIntegrety(bot_chat_t *chat) +{ + bot_chattype_t *t; + bot_chatmessage_t *cm; + bot_stringlist_t *stringlist, *s, *nexts; + + stringlist = NULL; + for (t = chat->types; t; t = t->next) + { + for (cm = t->firstchatmessage; cm; cm = cm->next) + { + stringlist = BotCheckChatMessageIntegrety(cm->chatmessage, stringlist); + } //end for + } //end for + for (s = stringlist; s; s = nexts) + { + nexts = s->next; + FreeMemory(s); + } //end for +} //end of the function BotCheckInitialChatIntegrety +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotCheckReplyChatIntegrety(bot_replychat_t *replychat) +{ + bot_replychat_t *rp; + bot_chatmessage_t *cm; + bot_stringlist_t *stringlist, *s, *nexts; + + stringlist = NULL; + for (rp = replychat; rp; rp = rp->next) + { + for (cm = rp->firstchatmessage; cm; cm = cm->next) + { + stringlist = BotCheckChatMessageIntegrety(cm->chatmessage, stringlist); + } //end for + } //end for + for (s = stringlist; s; s = nexts) + { + nexts = s->next; + FreeMemory(s); + } //end for +} //end of the function BotCheckReplyChatIntegrety +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotDumpReplyChat(bot_replychat_t *replychat) +{ + FILE *fp; + bot_replychat_t *rp; + bot_replychatkey_t *key; + bot_chatmessage_t *cm; + bot_matchpiece_t *mp; + + fp = Log_FilePointer(); + if (!fp) return; + fprintf(fp, "BotDumpReplyChat:\n"); + for (rp = replychat; rp; rp = rp->next) + { + fprintf(fp, "["); + for (key = rp->keys; key; key = key->next) + { + if (key->flags & RCKFL_AND) fprintf(fp, "&"); + else if (key->flags & RCKFL_NOT) fprintf(fp, "!"); + // + if (key->flags & RCKFL_NAME) fprintf(fp, "name"); + else if (key->flags & RCKFL_GENDERFEMALE) fprintf(fp, "female"); + else if (key->flags & RCKFL_GENDERMALE) fprintf(fp, "male"); + else if (key->flags & RCKFL_GENDERLESS) fprintf(fp, "it"); + else if (key->flags & RCKFL_VARIABLES) + { + fprintf(fp, "("); + for (mp = key->match; mp; mp = mp->next) + { + if (mp->type == MT_STRING) fprintf(fp, "\"%s\"", mp->firststring->string); + else fprintf(fp, "%d", mp->variable); + if (mp->next) fprintf(fp, ", "); + } //end for + fprintf(fp, ")"); + } //end if + else if (key->flags & RCKFL_STRING) + { + fprintf(fp, "\"%s\"", key->string); + } //end if + if (key->next) fprintf(fp, ", "); + else fprintf(fp, "] = %1.0f\n", rp->priority); + } //end for + fprintf(fp, "{\n"); + for (cm = rp->firstchatmessage; cm; cm = cm->next) + { + fprintf(fp, "\t\"%s\";\n", cm->chatmessage); + } //end for + fprintf(fp, "}\n"); + } //end for +} //end of the function BotDumpReplyChat +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotFreeReplyChat(bot_replychat_t *replychat) +{ + bot_replychat_t *rp, *nextrp; + bot_replychatkey_t *key, *nextkey; + bot_chatmessage_t *cm, *nextcm; + + for (rp = replychat; rp; rp = nextrp) + { + nextrp = rp->next; + for (key = rp->keys; key; key = nextkey) + { + nextkey = key->next; + if (key->match) BotFreeMatchPieces(key->match); + if (key->string) FreeMemory(key->string); + FreeMemory(key); + } //end for + for (cm = rp->firstchatmessage; cm; cm = nextcm) + { + nextcm = cm->next; + FreeMemory(cm); + } //end for + FreeMemory(rp); + } //end for +} //end of the function BotFreeReplyChat +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotCheckValidReplyChatKeySet(source_t *source, bot_replychatkey_t *keys) +{ + int allprefixed, hasvariableskey, hasstringkey; + bot_matchpiece_t *m; + bot_matchstring_t *ms; + bot_replychatkey_t *key, *key2; + + // + allprefixed = qtrue; + hasvariableskey = hasstringkey = qfalse; + for (key = keys; key; key = key->next) + { + if (!(key->flags & (RCKFL_AND|RCKFL_NOT))) + { + allprefixed = qfalse; + if (key->flags & RCKFL_VARIABLES) + { + for (m = key->match; m; m = m->next) + { + if (m->type == MT_VARIABLE) hasvariableskey = qtrue; + } //end for + } //end if + else if (key->flags & RCKFL_STRING) + { + hasstringkey = qtrue; + } //end else if + } //end if + else if ((key->flags & RCKFL_AND) && (key->flags & RCKFL_STRING)) + { + for (key2 = keys; key2; key2 = key2->next) + { + if (key2 == key) continue; + if (key2->flags & RCKFL_NOT) continue; + if (key2->flags & RCKFL_VARIABLES) + { + for (m = key2->match; m; m = m->next) + { + if (m->type == MT_STRING) + { + for (ms = m->firststring; ms; ms = ms->next) + { + if (StringContains(ms->string, key->string, qfalse) != -1) + { + break; + } //end if + } //end for + if (ms) break; + } //end if + else if (m->type == MT_VARIABLE) + { + break; + } //end if + } //end for + if (!m) + { + SourceWarning(source, "one of the match templates does not " + "leave space for the key %s with the & prefix", key->string); + } //end if + } //end if + } //end for + } //end else + if ((key->flags & RCKFL_NOT) && (key->flags & RCKFL_STRING)) + { + for (key2 = keys; key2; key2 = key2->next) + { + if (key2 == key) continue; + if (key2->flags & RCKFL_NOT) continue; + if (key2->flags & RCKFL_STRING) + { + if (StringContains(key2->string, key->string, qfalse) != -1) + { + SourceWarning(source, "the key %s with prefix ! is inside the key %s", key->string, key2->string); + } //end if + } //end if + else if (key2->flags & RCKFL_VARIABLES) + { + for (m = key2->match; m; m = m->next) + { + if (m->type == MT_STRING) + { + for (ms = m->firststring; ms; ms = ms->next) + { + if (StringContains(ms->string, key->string, qfalse) != -1) + { + SourceWarning(source, "the key %s with prefix ! is inside " + "the match template string %s", key->string, ms->string); + } //end if + } //end for + } //end if + } //end for + } //end else if + } //end for + } //end if + } //end for + if (allprefixed) SourceWarning(source, "all keys have a & or ! prefix"); + if (hasvariableskey && hasstringkey) + { + SourceWarning(source, "variables from the match template(s) could be " + "invalid when outputting one of the chat messages"); + } //end if +} //end of the function BotCheckValidReplyChatKeySet +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_replychat_t *BotLoadReplyChat(char *filename) +{ + char chatmessagestring[MAX_MESSAGE_SIZE]; + char namebuffer[MAX_MESSAGE_SIZE]; + source_t *source; + token_t token; + bot_chatmessage_t *chatmessage = NULL; + bot_replychat_t *replychat, *replychatlist; + bot_replychatkey_t *key; + + PC_SetBaseFolder(BOTFILESBASEFOLDER); + source = LoadSourceFile(filename); + if (!source) + { + botimport.Print(PRT_ERROR, "counldn't load %s\n", filename); + return NULL; + } //end if + // + replychatlist = NULL; + // + while(PC_ReadToken(source, &token)) + { + if (strcmp(token.string, "[")) + { + SourceError(source, "expected [, found %s", token.string); + BotFreeReplyChat(replychatlist); + FreeSource(source); + return NULL; + } //end if + // + replychat = (struct bot_replychat_s *)GetClearedHunkMemory(sizeof(bot_replychat_t)); + replychat->keys = NULL; + replychat->next = replychatlist; + replychatlist = replychat; + //read the keys, there must be at least one key + do + { + //allocate a key + key = (bot_replychatkey_t *) GetClearedHunkMemory(sizeof(bot_replychatkey_t)); + key->flags = 0; + key->string = NULL; + key->match = NULL; + key->next = replychat->keys; + replychat->keys = key; + //check for MUST BE PRESENT and MUST BE ABSENT keys + if (PC_CheckTokenString(source, "&")) key->flags |= RCKFL_AND; + else if (PC_CheckTokenString(source, "!")) key->flags |= RCKFL_NOT; + //special keys + if (PC_CheckTokenString(source, "name")) key->flags |= RCKFL_NAME; + else if (PC_CheckTokenString(source, "female")) key->flags |= RCKFL_GENDERFEMALE; + else if (PC_CheckTokenString(source, "male")) key->flags |= RCKFL_GENDERMALE; + else if (PC_CheckTokenString(source, "it")) key->flags |= RCKFL_GENDERLESS; + else if (PC_CheckTokenString(source, "(")) //match key + { + key->flags |= RCKFL_VARIABLES; + key->match = BotLoadMatchPieces(source, ")"); + if (!key->match) + { + BotFreeReplyChat(replychatlist); + return NULL; + } //end if + } //end else if + else if (PC_CheckTokenString(source, "<")) //bot names + { + key->flags |= RCKFL_BOTNAMES; + strcpy(namebuffer, ""); + do + { + if (!PC_ExpectTokenType(source, TT_STRING, 0, &token)) + { + BotFreeReplyChat(replychatlist); + FreeSource(source); + return NULL; + } //end if + StripDoubleQuotes(token.string); + if (strlen(namebuffer)) strcat(namebuffer, "\\"); + strcat(namebuffer, token.string); + } while(PC_CheckTokenString(source, ",")); + if (!PC_ExpectTokenString(source, ">")) + { + BotFreeReplyChat(replychatlist); + FreeSource(source); + return NULL; + } //end if + key->string = (char *) GetClearedHunkMemory(strlen(namebuffer) + 1); + strcpy(key->string, namebuffer); + } //end else if + else //normal string key + { + key->flags |= RCKFL_STRING; + if (!PC_ExpectTokenType(source, TT_STRING, 0, &token)) + { + BotFreeReplyChat(replychatlist); + FreeSource(source); + return NULL; + } //end if + StripDoubleQuotes(token.string); + key->string = (char *) GetClearedHunkMemory(strlen(token.string) + 1); + strcpy(key->string, token.string); + } //end else + // + PC_CheckTokenString(source, ","); + } while(!PC_CheckTokenString(source, "]")); + // + BotCheckValidReplyChatKeySet(source, replychat->keys); + //read the = sign and the priority + if (!PC_ExpectTokenString(source, "=") || + !PC_ExpectTokenType(source, TT_NUMBER, 0, &token)) + { + BotFreeReplyChat(replychatlist); + FreeSource(source); + return NULL; + } //end if + replychat->priority = token.floatvalue; + //read the leading { + if (!PC_ExpectTokenString(source, "{")) + { + BotFreeReplyChat(replychatlist); + FreeSource(source); + return NULL; + } //end if + replychat->numchatmessages = 0; + //while the trailing } is not found + while(!PC_CheckTokenString(source, "}")) + { + if (!BotLoadChatMessage(source, chatmessagestring)) + { + BotFreeReplyChat(replychatlist); + FreeSource(source); + return NULL; + } //end if + chatmessage = (bot_chatmessage_t *) GetClearedHunkMemory(sizeof(bot_chatmessage_t) + strlen(chatmessagestring) + 1); + chatmessage->chatmessage = (char *) chatmessage + sizeof(bot_chatmessage_t); + strcpy(chatmessage->chatmessage, chatmessagestring); + chatmessage->time = -2*CHATMESSAGE_RECENTTIME; + chatmessage->next = replychat->firstchatmessage; + //add the chat message to the reply chat + replychat->firstchatmessage = chatmessage; + replychat->numchatmessages++; + } //end while + } //end while + FreeSource(source); + botimport.Print(PRT_MESSAGE, "loaded %s\n", filename); + // + //BotDumpReplyChat(replychatlist); + if (botDeveloper) + { + BotCheckReplyChatIntegrety(replychatlist); + } //end if + // + if (!replychatlist) botimport.Print(PRT_MESSAGE, "no rchats\n"); + // + return replychatlist; +} //end of the function BotLoadReplyChat +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotDumpInitialChat(bot_chat_t *chat) +{ + bot_chattype_t *t; + bot_chatmessage_t *m; + + Log_Write("{"); + for (t = chat->types; t; t = t->next) + { + Log_Write(" type \"%s\"", t->name); + Log_Write(" {"); + Log_Write(" numchatmessages = %d", t->numchatmessages); + for (m = t->firstchatmessage; m; m = m->next) + { + Log_Write(" \"%s\"", m->chatmessage); + } //end for + Log_Write(" }"); + } //end for + Log_Write("}"); +} //end of the function BotDumpInitialChat +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_chat_t *BotLoadInitialChat(char *chatfile, char *chatname) +{ + int pass, foundchat, indent, size; + char *ptr = NULL; + char chatmessagestring[MAX_MESSAGE_SIZE]; + source_t *source; + token_t token; + bot_chat_t *chat = NULL; + bot_chattype_t *chattype = NULL; + bot_chatmessage_t *chatmessage = NULL; +#ifdef DEBUG + int starttime; + + starttime = Sys_MilliSeconds(); +#endif //DEBUG + // + size = 0; + foundchat = qfalse; + //a bot chat is parsed in two phases + for (pass = 0; pass < 2; pass++) + { + //allocate memory + if (pass && size) ptr = (char *) GetClearedMemory(size); + //load the source file + PC_SetBaseFolder(BOTFILESBASEFOLDER); + source = LoadSourceFile(chatfile); + if (!source) + { + botimport.Print(PRT_ERROR, "counldn't load %s\n", chatfile); + return NULL; + } //end if + //chat structure + if (pass) + { + chat = (bot_chat_t *) ptr; + ptr += sizeof(bot_chat_t); + } //end if + size = sizeof(bot_chat_t); + // + while(PC_ReadToken(source, &token)) + { + if (!strcmp(token.string, "chat")) + { + if (!PC_ExpectTokenType(source, TT_STRING, 0, &token)) + { + FreeSource(source); + return NULL; + } //end if + StripDoubleQuotes(token.string); + //after the chat name we expect an opening brace + if (!PC_ExpectTokenString(source, "{")) + { + FreeSource(source); + return NULL; + } //end if + //if the chat name is found + if (!Q_stricmp(token.string, chatname)) + { + foundchat = qtrue; + //read the chat types + while(1) + { + if (!PC_ExpectAnyToken(source, &token)) + { + FreeSource(source); + return NULL; + } //end if + if (!strcmp(token.string, "}")) break; + if (strcmp(token.string, "type")) + { + SourceError(source, "expected type found %s", token.string); + FreeSource(source); + return NULL; + } //end if + //expect the chat type name + if (!PC_ExpectTokenType(source, TT_STRING, 0, &token) || + !PC_ExpectTokenString(source, "{")) + { + FreeSource(source); + return NULL; + } //end if + StripDoubleQuotes(token.string); + if (pass) + { + chattype = (bot_chattype_t *) ptr; + strncpy(chattype->name, token.string, MAX_CHATTYPE_NAME); + chattype->firstchatmessage = NULL; + //add the chat type to the chat + chattype->next = chat->types; + chat->types = chattype; + // + ptr += sizeof(bot_chattype_t); + } //end if + size += sizeof(bot_chattype_t); + //read the chat messages + while(!PC_CheckTokenString(source, "}")) + { + size_t len; + if (!BotLoadChatMessage(source, chatmessagestring)) + { + FreeSource(source); + return NULL; + } //end if + len = strlen(chatmessagestring) + 1; + len = PAD(len, sizeof(long)); + if (pass) + { + chatmessage = (bot_chatmessage_t *) ptr; + chatmessage->time = -2*CHATMESSAGE_RECENTTIME; + //put the chat message in the list + chatmessage->next = chattype->firstchatmessage; + chattype->firstchatmessage = chatmessage; + //store the chat message + ptr += sizeof(bot_chatmessage_t); + chatmessage->chatmessage = ptr; + strcpy(chatmessage->chatmessage, chatmessagestring); + ptr += len; + //the number of chat messages increased + chattype->numchatmessages++; + } //end if + size += sizeof(bot_chatmessage_t) + len; + } //end if + } //end while + } //end if + else //skip the bot chat + { + indent = 1; + while(indent) + { + if (!PC_ExpectAnyToken(source, &token)) + { + FreeSource(source); + return NULL; + } //end if + if (!strcmp(token.string, "{")) indent++; + else if (!strcmp(token.string, "}")) indent--; + } //end while + } //end else + } //end if + else + { + SourceError(source, "unknown definition %s", token.string); + FreeSource(source); + return NULL; + } //end else + } //end while + //free the source + FreeSource(source); + //if the requested character is not found + if (!foundchat) + { + botimport.Print(PRT_ERROR, "couldn't find chat %s in %s\n", chatname, chatfile); + return NULL; + } //end if + } //end for + // + botimport.Print(PRT_MESSAGE, "loaded %s from %s\n", chatname, chatfile); + // + //BotDumpInitialChat(chat); + if (botDeveloper) + { + BotCheckInitialChatIntegrety(chat); + } //end if +#ifdef DEBUG + botimport.Print(PRT_MESSAGE, "initial chats loaded in %d msec\n", Sys_MilliSeconds() - starttime); +#endif //DEBUG + //character was read successfully + return chat; +} //end of the function BotLoadInitialChat +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotFreeChatFile(int chatstate) +{ + bot_chatstate_t *cs; + + cs = BotChatStateFromHandle(chatstate); + if (!cs) return; + if (cs->chat) FreeMemory(cs->chat); + cs->chat = NULL; +} //end of the function BotFreeChatFile +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotLoadChatFile(int chatstate, char *chatfile, char *chatname) +{ + bot_chatstate_t *cs; + int n, avail = 0; + + cs = BotChatStateFromHandle(chatstate); + if (!cs) return BLERR_CANNOTLOADICHAT; + BotFreeChatFile(chatstate); + + if (!LibVarGetValue("bot_reloadcharacters")) + { + avail = -1; + for( n = 0; n < MAX_CLIENTS; n++ ) { + if( !ichatdata[n] ) { + if( avail == -1 ) { + avail = n; + } + continue; + } + if( strcmp( chatfile, ichatdata[n]->filename ) != 0 ) { + continue; + } + if( strcmp( chatname, ichatdata[n]->chatname ) != 0 ) { + continue; + } + cs->chat = ichatdata[n]->chat; + // botimport.Print( PRT_MESSAGE, "retained %s from %s\n", chatname, chatfile ); + return BLERR_NOERROR; + } + + if( avail == -1 ) { + botimport.Print(PRT_FATAL, "ichatdata table full; couldn't load chat %s from %s\n", chatname, chatfile); + return BLERR_CANNOTLOADICHAT; + } + } + + cs->chat = BotLoadInitialChat(chatfile, chatname); + if (!cs->chat) + { + botimport.Print(PRT_FATAL, "couldn't load chat %s from %s\n", chatname, chatfile); + return BLERR_CANNOTLOADICHAT; + } //end if + if (!LibVarGetValue("bot_reloadcharacters")) + { + ichatdata[avail] = (bot_ichatdata_t *)GetClearedMemory( sizeof(bot_ichatdata_t) ); + ichatdata[avail]->chat = cs->chat; + Q_strncpyz( ichatdata[avail]->chatname, chatname, sizeof(ichatdata[avail]->chatname) ); + Q_strncpyz( ichatdata[avail]->filename, chatfile, sizeof(ichatdata[avail]->filename) ); + } //end if + + return BLERR_NOERROR; +} //end of the function BotLoadChatFile +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotExpandChatMessage(char *outmessage, char *message, unsigned long mcontext, + bot_match_t *match, unsigned long vcontext, int reply) +{ + int num, len, i, expansion; + char *outputbuf, *ptr, *msgptr; + char temp[MAX_MESSAGE_SIZE]; + + expansion = qfalse; + msgptr = message; + outputbuf = outmessage; + len = 0; + // + while(*msgptr) + { + if (*msgptr == ESCAPE_CHAR) + { + msgptr++; + switch(*msgptr) + { + case 'v': //variable + { + msgptr++; + num = 0; + while(*msgptr && *msgptr != ESCAPE_CHAR) + { + num = num * 10 + (*msgptr++) - '0'; + } //end while + //step over the trailing escape char + if (*msgptr) msgptr++; + if (num > MAX_MATCHVARIABLES) + { + botimport.Print(PRT_ERROR, "BotConstructChat: message %s variable %d out of range\n", message, num); + return qfalse; + } //end if + if (match->variables[num].offset >= 0) + { + assert( match->variables[num].offset >= 0 ); // bk001204 + ptr = &match->string[ (int) match->variables[num].offset]; + for (i = 0; i < match->variables[num].length; i++) + { + temp[i] = ptr[i]; + } //end for + temp[i] = 0; + //if it's a reply message + if (reply) + { + //replace the reply synonyms in the variables + BotReplaceReplySynonyms(temp, vcontext); + } //end if + else + { + //replace synonyms in the variable context + BotReplaceSynonyms(temp, vcontext); + } //end else + // + if (len + strlen(temp) >= MAX_MESSAGE_SIZE) + { + botimport.Print(PRT_ERROR, "BotConstructChat: message %s too long\n", message); + return qfalse; + } //end if + strcpy(&outputbuf[len], temp); + len += strlen(temp); + } //end if + break; + } //end case + case 'r': //random + { + msgptr++; + for (i = 0; (*msgptr && *msgptr != ESCAPE_CHAR); i++) + { + temp[i] = *msgptr++; + } //end while + temp[i] = '\0'; + //step over the trailing escape char + if (*msgptr) msgptr++; + //find the random keyword + ptr = RandomString(temp); + if (!ptr) + { + botimport.Print(PRT_ERROR, "BotConstructChat: unknown random string %s\n", temp); + return qfalse; + } //end if + if (len + strlen(ptr) >= MAX_MESSAGE_SIZE) + { + botimport.Print(PRT_ERROR, "BotConstructChat: message \"%s\" too long\n", message); + return qfalse; + } //end if + strcpy(&outputbuf[len], ptr); + len += strlen(ptr); + expansion = qtrue; + break; + } //end case + default: + { + botimport.Print(PRT_FATAL, "BotConstructChat: message \"%s\" invalid escape char\n", message); + break; + } //end default + } //end switch + } //end if + else + { + outputbuf[len++] = *msgptr++; + if (len >= MAX_MESSAGE_SIZE) + { + botimport.Print(PRT_ERROR, "BotConstructChat: message \"%s\" too long\n", message); + break; + } //end if + } //end else + } //end while + outputbuf[len] = '\0'; + //replace synonyms weighted in the message context + BotReplaceWeightedSynonyms(outputbuf, mcontext); + //return true if a random was expanded + return expansion; +} //end of the function BotExpandChatMessage +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotConstructChatMessage(bot_chatstate_t *chatstate, char *message, unsigned long mcontext, + bot_match_t *match, unsigned long vcontext, int reply) +{ + int i; + char srcmessage[MAX_MESSAGE_SIZE]; + + strcpy(srcmessage, message); + for (i = 0; i < 10; i++) + { + if (!BotExpandChatMessage(chatstate->chatmessage, srcmessage, mcontext, match, vcontext, reply)) + { + break; + } //end if + strcpy(srcmessage, chatstate->chatmessage); + } //end for + if (i >= 10) + { + botimport.Print(PRT_WARNING, "too many expansions in chat message\n"); + botimport.Print(PRT_WARNING, "%s\n", chatstate->chatmessage); + } //end if +} //end of the function BotConstructChatMessage +//=========================================================================== +// randomly chooses one of the chat message of the given type +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +char *BotChooseInitialChatMessage(bot_chatstate_t *cs, char *type) +{ + int n, numchatmessages; + float besttime; + bot_chattype_t *t; + bot_chatmessage_t *m, *bestchatmessage; + bot_chat_t *chat; + + chat = cs->chat; + for (t = chat->types; t; t = t->next) + { + if (!Q_stricmp(t->name, type)) + { + numchatmessages = 0; + for (m = t->firstchatmessage; m; m = m->next) + { + if (m->time > AAS_Time()) continue; + numchatmessages++; + } //end if + //if all chat messages have been used recently + if (numchatmessages <= 0) + { + besttime = 0; + bestchatmessage = NULL; + for (m = t->firstchatmessage; m; m = m->next) + { + if (!besttime || m->time < besttime) + { + bestchatmessage = m; + besttime = m->time; + } //end if + } //end for + if (bestchatmessage) return bestchatmessage->chatmessage; + } //end if + else //choose a chat message randomly + { + n = Q_flrand(0.0f, 1.0f) * numchatmessages; + for (m = t->firstchatmessage; m; m = m->next) + { + if (m->time > AAS_Time()) continue; + if (--n < 0) + { + m->time = AAS_Time() + CHATMESSAGE_RECENTTIME; + return m->chatmessage; + } //end if + } //end for + } //end else + return NULL; + } //end if + } //end for + return NULL; +} //end of the function BotChooseInitialChatMessage +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotNumInitialChats(int chatstate, char *type) +{ + bot_chatstate_t *cs; + bot_chattype_t *t; + + cs = BotChatStateFromHandle(chatstate); + if (!cs) return 0; + + for (t = cs->chat->types; t; t = t->next) + { + if (!Q_stricmp(t->name, type)) + { + if (LibVarGetValue("bot_testichat")) { + botimport.Print(PRT_MESSAGE, "%s has %d chat lines\n", type, t->numchatmessages); + botimport.Print(PRT_MESSAGE, "-------------------\n"); + } + return t->numchatmessages; + } //end if + } //end for + return 0; +} //end of the function BotNumInitialChats +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotInitialChat(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7) +{ + char *message; + int index; + bot_match_t match; + bot_chatstate_t *cs; + + cs = BotChatStateFromHandle(chatstate); + if (!cs) return; + //if no chat file is loaded + if (!cs->chat) return; + //choose a chat message randomly of the given type + message = BotChooseInitialChatMessage(cs, type); + //if there's no message of the given type + if (!message) + { +#ifdef DEBUG + botimport.Print(PRT_MESSAGE, "no chat messages of type %s\n", type); +#endif //DEBUG + return; + } //end if + // + Com_Memset(&match, 0, sizeof(match)); + index = 0; + if( var0 ) { + strcat(match.string, var0); + match.variables[0].offset = index; + match.variables[0].length = strlen(var0); + index += strlen(var0); + } + if( var1 ) { + strcat(match.string, var1); + match.variables[1].offset = index; + match.variables[1].length = strlen(var1); + index += strlen(var1); + } + if( var2 ) { + strcat(match.string, var2); + match.variables[2].offset = index; + match.variables[2].length = strlen(var2); + index += strlen(var2); + } + if( var3 ) { + strcat(match.string, var3); + match.variables[3].offset = index; + match.variables[3].length = strlen(var3); + index += strlen(var3); + } + if( var4 ) { + strcat(match.string, var4); + match.variables[4].offset = index; + match.variables[4].length = strlen(var4); + index += strlen(var4); + } + if( var5 ) { + strcat(match.string, var5); + match.variables[5].offset = index; + match.variables[5].length = strlen(var5); + index += strlen(var5); + } + if( var6 ) { + strcat(match.string, var6); + match.variables[6].offset = index; + match.variables[6].length = strlen(var6); + index += strlen(var6); + } + if( var7 ) { + strcat(match.string, var7); + match.variables[7].offset = index; + match.variables[7].length = strlen(var7); + index += strlen(var7); + } + // + BotConstructChatMessage(cs, message, mcontext, &match, 0, qfalse); +} //end of the function BotInitialChat +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotPrintReplyChatKeys(bot_replychat_t *replychat) +{ + bot_replychatkey_t *key; + bot_matchpiece_t *mp; + + botimport.Print(PRT_MESSAGE, "["); + for (key = replychat->keys; key; key = key->next) + { + if (key->flags & RCKFL_AND) botimport.Print(PRT_MESSAGE, "&"); + else if (key->flags & RCKFL_NOT) botimport.Print(PRT_MESSAGE, "!"); + // + if (key->flags & RCKFL_NAME) botimport.Print(PRT_MESSAGE, "name"); + else if (key->flags & RCKFL_GENDERFEMALE) botimport.Print(PRT_MESSAGE, "female"); + else if (key->flags & RCKFL_GENDERMALE) botimport.Print(PRT_MESSAGE, "male"); + else if (key->flags & RCKFL_GENDERLESS) botimport.Print(PRT_MESSAGE, "it"); + else if (key->flags & RCKFL_VARIABLES) + { + botimport.Print(PRT_MESSAGE, "("); + for (mp = key->match; mp; mp = mp->next) + { + if (mp->type == MT_STRING) botimport.Print(PRT_MESSAGE, "\"%s\"", mp->firststring->string); + else botimport.Print(PRT_MESSAGE, "%d", mp->variable); + if (mp->next) botimport.Print(PRT_MESSAGE, ", "); + } //end for + botimport.Print(PRT_MESSAGE, ")"); + } //end if + else if (key->flags & RCKFL_STRING) + { + botimport.Print(PRT_MESSAGE, "\"%s\"", key->string); + } //end if + if (key->next) botimport.Print(PRT_MESSAGE, ", "); + else botimport.Print(PRT_MESSAGE, "] = %1.0f\n", replychat->priority); + } //end for + botimport.Print(PRT_MESSAGE, "{\n"); +} //end of the function BotPrintReplyChatKeys +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotReplyChat(int chatstate, char *message, int mcontext, int vcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7) +{ + bot_replychat_t *rchat, *bestrchat; + bot_replychatkey_t *key; + bot_chatmessage_t *m, *bestchatmessage; + bot_match_t match, bestmatch; + int bestpriority, num, found, res, numchatmessages, index; + bot_chatstate_t *cs; + + cs = BotChatStateFromHandle(chatstate); + if (!cs) return qfalse; + Com_Memset(&match, 0, sizeof(bot_match_t)); + strcpy(match.string, message); + bestpriority = -1; + bestchatmessage = NULL; + bestrchat = NULL; + //go through all the reply chats + for (rchat = replychats; rchat; rchat = rchat->next) + { + found = qfalse; + for (key = rchat->keys; key; key = key->next) + { + res = qfalse; + //get the match result + if (key->flags & RCKFL_NAME) res = (StringContains(message, cs->name, qfalse) != -1); + else if (key->flags & RCKFL_BOTNAMES) res = (StringContains(key->string, cs->name, qfalse) != -1); + else if (key->flags & RCKFL_GENDERFEMALE) res = (cs->gender == CHAT_GENDERFEMALE); + else if (key->flags & RCKFL_GENDERMALE) res = (cs->gender == CHAT_GENDERMALE); + else if (key->flags & RCKFL_GENDERLESS) res = (cs->gender == CHAT_GENDERLESS); + else if (key->flags & RCKFL_VARIABLES) res = StringsMatch(key->match, &match); + else if (key->flags & RCKFL_STRING) res = (StringContainsWord(message, key->string, qfalse) != NULL); + //if the key must be present + if (key->flags & RCKFL_AND) + { + if (!res) + { + found = qfalse; + break; + } //end if + } //end else if + //if the key must be absent + else if (key->flags & RCKFL_NOT) + { + if (res) + { + found = qfalse; + break; + } //end if + } //end if + else if (res) + { + found = qtrue; + } //end else + } //end for + // + if (found) + { + if (rchat->priority > bestpriority) + { + numchatmessages = 0; + for (m = rchat->firstchatmessage; m; m = m->next) + { + if (m->time > AAS_Time()) continue; + numchatmessages++; + } //end if + num = Q_flrand(0.0f, 1.0f) * numchatmessages; + for (m = rchat->firstchatmessage; m; m = m->next) + { + if (--num < 0) break; + if (m->time > AAS_Time()) continue; + } //end for + //if the reply chat has a message + if (m) + { + Com_Memcpy(&bestmatch, &match, sizeof(bot_match_t)); + bestchatmessage = m; + bestrchat = rchat; + bestpriority = rchat->priority; + } //end if + } //end if + } //end if + } //end for + if (bestchatmessage) + { + index = strlen(bestmatch.string); + if( var0 ) { + strcat(bestmatch.string, var0); + bestmatch.variables[0].offset = index; + bestmatch.variables[0].length = strlen(var0); + index += strlen(var0); + } + if( var1 ) { + strcat(bestmatch.string, var1); + bestmatch.variables[1].offset = index; + bestmatch.variables[1].length = strlen(var1); + index += strlen(var1); + } + if( var2 ) { + strcat(bestmatch.string, var2); + bestmatch.variables[2].offset = index; + bestmatch.variables[2].length = strlen(var2); + index += strlen(var2); + } + if( var3 ) { + strcat(bestmatch.string, var3); + bestmatch.variables[3].offset = index; + bestmatch.variables[3].length = strlen(var3); + index += strlen(var3); + } + if( var4 ) { + strcat(bestmatch.string, var4); + bestmatch.variables[4].offset = index; + bestmatch.variables[4].length = strlen(var4); + index += strlen(var4); + } + if( var5 ) { + strcat(bestmatch.string, var5); + bestmatch.variables[5].offset = index; + bestmatch.variables[5].length = strlen(var5); + index += strlen(var5); + } + if( var6 ) { + strcat(bestmatch.string, var6); + bestmatch.variables[6].offset = index; + bestmatch.variables[6].length = strlen(var6); + index += strlen(var6); + } + if( var7 ) { + strcat(bestmatch.string, var7); + bestmatch.variables[7].offset = index; + bestmatch.variables[7].length = strlen(var7); + index += strlen(var7); + } + if (LibVarGetValue("bot_testrchat")) + { + for (m = bestrchat->firstchatmessage; m; m = m->next) + { + BotConstructChatMessage(cs, m->chatmessage, mcontext, &bestmatch, vcontext, qtrue); + BotRemoveTildes(cs->chatmessage); + botimport.Print(PRT_MESSAGE, "%s\n", cs->chatmessage); + } //end if + } //end if + else + { + bestchatmessage->time = AAS_Time() + CHATMESSAGE_RECENTTIME; + BotConstructChatMessage(cs, bestchatmessage->chatmessage, mcontext, &bestmatch, vcontext, qtrue); + } //end else + return qtrue; + } //end if + return qfalse; +} //end of the function BotReplyChat +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotChatLength(int chatstate) +{ + bot_chatstate_t *cs; + + cs = BotChatStateFromHandle(chatstate); + if (!cs) return 0; + return strlen(cs->chatmessage); +} //end of the function BotChatLength +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotEnterChat(int chatstate, int clientto, int sendto) +{ + bot_chatstate_t *cs; + + cs = BotChatStateFromHandle(chatstate); + if (!cs) return; + + if (strlen(cs->chatmessage)) + { + BotRemoveTildes(cs->chatmessage); + if (LibVarGetValue("bot_testichat")) { + botimport.Print(PRT_MESSAGE, "%s\n", cs->chatmessage); + } + else { + switch(sendto) { + case CHAT_TEAM: + EA_Command(cs->client, va("say_team %s", cs->chatmessage)); + break; + case CHAT_TELL: + EA_Command(cs->client, va("tell %d %s", clientto, cs->chatmessage)); + break; + default: //CHAT_ALL + EA_Command(cs->client, va("say %s", cs->chatmessage)); + break; + } + } + //clear the chat message from the state + strcpy(cs->chatmessage, ""); + } //end if +} //end of the function BotEnterChat +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotGetChatMessage(int chatstate, char *buf, int size) +{ + bot_chatstate_t *cs; + + cs = BotChatStateFromHandle(chatstate); + if (!cs) return; + + BotRemoveTildes(cs->chatmessage); + strncpy(buf, cs->chatmessage, size-1); + buf[size-1] = '\0'; + //clear the chat message from the state + strcpy(cs->chatmessage, ""); +} //end of the function BotGetChatMessage +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotSetChatGender(int chatstate, int gender) +{ + bot_chatstate_t *cs; + + cs = BotChatStateFromHandle(chatstate); + if (!cs) return; + switch(gender) + { + case CHAT_GENDERFEMALE: cs->gender = CHAT_GENDERFEMALE; break; + case CHAT_GENDERMALE: cs->gender = CHAT_GENDERMALE; break; + default: cs->gender = CHAT_GENDERLESS; break; + } //end switch +} //end of the function BotSetChatGender +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotSetChatName(int chatstate, char *name, int client) +{ + bot_chatstate_t *cs; + + cs = BotChatStateFromHandle(chatstate); + if (!cs) return; + cs->client = client; + Com_Memset(cs->name, 0, sizeof(cs->name)); + strncpy(cs->name, name, sizeof(cs->name)); + cs->name[sizeof(cs->name)-1] = '\0'; +} //end of the function BotSetChatName +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotResetChatAI(void) +{ + bot_replychat_t *rchat; + bot_chatmessage_t *m; + + for (rchat = replychats; rchat; rchat = rchat->next) + { + for (m = rchat->firstchatmessage; m; m = m->next) + { + m->time = 0; + } //end for + } //end for +} //end of the function BotResetChatAI +//======================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//======================================================================== +int BotAllocChatState(void) +{ + int i; + + for (i = 1; i <= MAX_CLIENTS; i++) + { + if (!botchatstates[i]) + { + botchatstates[i] = (struct bot_chatstate_s *)GetClearedMemory(sizeof(bot_chatstate_t)); + return i; + } //end if + } //end for + return 0; +} //end of the function BotAllocChatState +//======================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//======================================================================== +void BotFreeChatState(int handle) +{ + bot_consolemessage_t m; + int h; + + if (handle <= 0 || handle > MAX_CLIENTS) + { + botimport.Print(PRT_FATAL, "chat state handle %d out of range\n", handle); + return; + } //end if + if (!botchatstates[handle]) + { + botimport.Print(PRT_FATAL, "invalid chat state %d\n", handle); + return; + } //end if + if (LibVarGetValue("bot_reloadcharacters")) + { + BotFreeChatFile(handle); + } //end if + //free all the console messages left in the chat state + for (h = BotNextConsoleMessage(handle, &m); h; h = BotNextConsoleMessage(handle, &m)) + { + //remove the console message + BotRemoveConsoleMessage(handle, h); + } //end for + FreeMemory(botchatstates[handle]); + botchatstates[handle] = NULL; +} //end of the function BotFreeChatState +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotSetupChatAI(void) +{ + char *file; + +#ifdef DEBUG + int starttime = Sys_MilliSeconds(); +#endif //DEBUG + + file = LibVarString("synfile", "syn.c"); + synonyms = BotLoadSynonyms(file); + file = LibVarString("rndfile", "rnd.c"); + randomstrings = BotLoadRandomStrings(file); + file = LibVarString("matchfile", "match.c"); + matchtemplates = BotLoadMatchTemplates(file); + // + if (!LibVarValue("nochat", "0")) + { + file = LibVarString("rchatfile", "rchat.c"); + replychats = BotLoadReplyChat(file); + } //end if + + InitConsoleMessageHeap(); + +#ifdef DEBUG + botimport.Print(PRT_MESSAGE, "setup chat AI %d msec\n", Sys_MilliSeconds() - starttime); +#endif //DEBUG + return BLERR_NOERROR; +} //end of the function BotSetupChatAI +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotShutdownChatAI(void) +{ + int i; + + //free all remaining chat states + for(i = 0; i < MAX_CLIENTS; i++) + { + if (botchatstates[i]) + { + BotFreeChatState(i); + } //end if + } //end for + //free all cached chats + for(i = 0; i < MAX_CLIENTS; i++) + { + if (ichatdata[i]) + { + FreeMemory(ichatdata[i]->chat); + FreeMemory(ichatdata[i]); + ichatdata[i] = NULL; + } //end if + } //end for + if (consolemessageheap) FreeMemory(consolemessageheap); + consolemessageheap = NULL; + if (matchtemplates) BotFreeMatchTemplates(matchtemplates); + matchtemplates = NULL; + if (randomstrings) FreeMemory(randomstrings); + randomstrings = NULL; + if (synonyms) FreeMemory(synonyms); + synonyms = NULL; + if (replychats) BotFreeReplyChat(replychats); + replychats = NULL; +} //end of the function BotShutdownChatAI diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_chat.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_chat.h new file mode 100644 index 0000000..b36c9e6 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_chat.h @@ -0,0 +1,119 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_ai_chat.h + * + * desc: char AI + * + * $Archive: /source/code/botlib/be_ai_chat.h $ + * $Author: osman $ + * $Revision: 1.4 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 2003/03/15 23:43:59 $ + * + *****************************************************************************/ + +#pragma once + +#define MAX_MESSAGE_SIZE 256 +#define MAX_CHATTYPE_NAME 32 +#define MAX_MATCHVARIABLES 8 + +#define CHAT_GENDERLESS 0 +#define CHAT_GENDERFEMALE 1 +#define CHAT_GENDERMALE 2 + +#define CHAT_ALL 0 +#define CHAT_TEAM 1 +#define CHAT_TELL 2 + +//a console message +typedef struct bot_consolemessage_s +{ + int handle; + float time; //message time + int type; //message type + char message[MAX_MESSAGE_SIZE]; //message + struct bot_consolemessage_s *prev, *next; //prev and next in list +} bot_consolemessage_t; + +//match variable +typedef struct bot_matchvariable_s +{ + char offset; + int length; +} bot_matchvariable_t; +//returned to AI when a match is found +typedef struct bot_match_s +{ + char string[MAX_MESSAGE_SIZE]; + int type; + int subtype; + bot_matchvariable_t variables[MAX_MATCHVARIABLES]; +} bot_match_t; + +//setup the chat AI +int BotSetupChatAI(void); +//shutdown the chat AI +void BotShutdownChatAI(void); +//returns the handle to a newly allocated chat state +int BotAllocChatState(void); +//frees the chatstate +void BotFreeChatState(int handle); +//adds a console message to the chat state +void BotQueueConsoleMessage(int chatstate, int type, char *message); +//removes the console message from the chat state +void BotRemoveConsoleMessage(int chatstate, int handle); +//returns the next console message from the state +int BotNextConsoleMessage(int chatstate, bot_consolemessage_t *cm); +//returns the number of console messages currently stored in the state +int BotNumConsoleMessages(int chatstate); +//selects a chat message of the given type +void BotInitialChat(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7); +//returns the number of initial chat messages of the given type +int BotNumInitialChats(int chatstate, char *type); +//find and select a reply for the given message +int BotReplyChat(int chatstate, char *message, int mcontext, int vcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7); +//returns the length of the currently selected chat message +int BotChatLength(int chatstate); +//enters the selected chat message +void BotEnterChat(int chatstate, int clientto, int sendto); +//get the chat message ready to be output +void BotGetChatMessage(int chatstate, char *buf, int size); +//checks if the first string contains the second one, returns index into first string or -1 if not found +int StringContains(char *str1, char *str2, int casesensitive); +//finds a match for the given string using the match templates +int BotFindMatch(char *str, bot_match_t *match, unsigned long int context); +//returns a variable from a match +void BotMatchVariable(bot_match_t *match, int variable, char *buf, int size); +//unify all the white spaces in the string +void UnifyWhiteSpaces(char *string); +//replace all the context related synonyms in the string +void BotReplaceSynonyms(char *string, unsigned long int context); +//loads a chat file for the chat state +int BotLoadChatFile(int chatstate, char *chatfile, char *chatname); +//store the gender of the bot in the chat state +void BotSetChatGender(int chatstate, int gender); +//store the bot name in the chat state +void BotSetChatName(int chatstate, char *name, int client); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_gen.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_gen.cpp new file mode 100644 index 0000000..d3871b5 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_gen.cpp @@ -0,0 +1,139 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_ai_gen.c + * + * desc: genetic selection + * + * $Archive: /MissionPack/code/botlib/be_ai_gen.c $ + * $Author: Zaphod $ + * $Revision: 3 $ + * $Modtime: 11/22/00 8:50a $ + * $Date: 11/22/00 8:55a $ + * + *****************************************************************************/ + +#include "qcommon/q_shared.h" +#include "l_memory.h" +#include "l_log.h" +#include "l_utils.h" +#include "l_script.h" +#include "l_precomp.h" +#include "l_struct.h" +#include "aasfile.h" +#include "botlib.h" +#include "be_aas.h" +#include "be_aas_funcs.h" +#include "be_interface.h" +#include "be_ai_gen.h" + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int GeneticSelection(int numranks, float *rankings) +{ + float sum; + int i, index; + + sum = 0; + for (i = 0; i < numranks; i++) + { + if (rankings[i] < 0) continue; + sum += rankings[i]; + } //end for + if (sum > 0) + { + //select a bot where the ones with the higest rankings have + //the highest chance of being selected + //sum *= Q_flrand(0.0f, 1.0f); + for (i = 0; i < numranks; i++) + { + if (rankings[i] < 0) continue; + sum -= rankings[i]; + if (sum <= 0) return i; + } //end for + } //end if + //select a bot randomly + index = Q_flrand(0.0f, 1.0f) * numranks; + for (i = 0; i < numranks; i++) + { + if (rankings[index] >= 0) return index; + index = (index + 1) % numranks; + } //end for + return 0; +} //end of the function GeneticSelection +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int GeneticParentsAndChildSelection(int numranks, float *ranks, int *parent1, int *parent2, int *child) +{ + float rankings[256], max; + int i; + + if (numranks > 256) + { + botimport.Print(PRT_WARNING, "GeneticParentsAndChildSelection: too many bots\n"); + *parent1 = *parent2 = *child = 0; + return qfalse; + } //end if + for (max = 0, i = 0; i < numranks; i++) + { + if (ranks[i] < 0) continue; + max++; + } //end for + if (max < 3) + { + botimport.Print(PRT_WARNING, "GeneticParentsAndChildSelection: too few valid bots\n"); + *parent1 = *parent2 = *child = 0; + return qfalse; + } //end if + Com_Memcpy(rankings, ranks, sizeof(float) * numranks); + //select first parent + *parent1 = GeneticSelection(numranks, rankings); + rankings[*parent1] = -1; + //select second parent + *parent2 = GeneticSelection(numranks, rankings); + rankings[*parent2] = -1; + //reverse the rankings + max = 0; + for (i = 0; i < numranks; i++) + { + if (rankings[i] < 0) continue; + if (rankings[i] > max) max = rankings[i]; + } //end for + for (i = 0; i < numranks; i++) + { + if (rankings[i] < 0) continue; + rankings[i] = max - rankings[i]; + } //end for + //select child + *child = GeneticSelection(numranks, rankings); + return qtrue; +} //end of the function GeneticParentsAndChildSelection diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_gen.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_gen.h new file mode 100644 index 0000000..4186a0b --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_gen.h @@ -0,0 +1,39 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_ai_gen.h + * + * desc: genetic selection + * + * $Archive: /source/code/botlib/be_ai_gen.h $ + * $Author: osman $ + * $Revision: 1.4 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 2003/03/15 23:44:00 $ + * + *****************************************************************************/ + +#pragma once + +int GeneticParentsAndChildSelection(int numranks, float *ranks, int *parent1, int *parent2, int *child); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_goal.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_goal.cpp new file mode 100644 index 0000000..88c882f --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_goal.cpp @@ -0,0 +1,1826 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_ai_goal.c + * + * desc: goal AI + * + * $Archive: /MissionPack/code/botlib/be_ai_goal.c $ + * $Author: Ttimo $ + * $Revision: 14 $ + * $Modtime: 4/13/01 4:45p $ + * $Date: 4/13/01 4:45p $ + * + *****************************************************************************/ + +#include "qcommon/q_shared.h" +#include "l_utils.h" +#include "l_libvar.h" +#include "l_memory.h" +#include "l_log.h" +#include "l_script.h" +#include "l_precomp.h" +#include "l_struct.h" +#include "aasfile.h" +#include "botlib.h" +#include "be_aas.h" +#include "be_aas_funcs.h" +#include "be_interface.h" +#include "be_ai_weight.h" +#include "be_ai_goal.h" +#include "be_ai_move.h" + +//#define DEBUG_AI_GOAL +#ifdef RANDOMIZE +#define UNDECIDEDFUZZY +#endif //RANDOMIZE +#define DROPPEDWEIGHT +//minimum avoid goal time +#define AVOID_MINIMUM_TIME 10 +//default avoid goal time +#define AVOID_DEFAULT_TIME 30 +//avoid dropped goal time +#define AVOID_DROPPED_TIME 10 +// +#define TRAVELTIME_SCALE 0.01 +//item flags +#define IFL_NOTFREE 1 //not in free for all +#define IFL_NOTTEAM 2 //not in team play +#define IFL_NOTSINGLE 4 //not in single player +#define IFL_NOTBOT 8 //bot should never go for this +#define IFL_ROAM 16 //bot roam goal + +//location in the map "target_location" +typedef struct maplocation_s +{ + vec3_t origin; + int areanum; + char name[MAX_EPAIRKEY]; + struct maplocation_s *next; +} maplocation_t; + +//camp spots "info_camp" +typedef struct campspot_s +{ + vec3_t origin; + int areanum; + char name[MAX_EPAIRKEY]; + float range; + float weight; + float wait; + float random; + struct campspot_s *next; +} campspot_t; + +//FIXME: these are game specific +enum { + GT_FFA, // free for all + GT_HOLOCRON, // holocron match + GT_JEDIMASTER, // jedi master + GT_DUEL, // one on one tournament + GT_POWERDUEL, + GT_SINGLE_PLAYER, // single player tournament + + //-- team games go after this -- + + GT_TEAM, // team deathmatch + GT_SIEGE, // siege + GT_CTF, // capture the flag + GT_CTY, + GT_MAX_GAME_TYPE +}; +typedef int gametype_t; + +typedef struct levelitem_s +{ + int number; //number of the level item + int iteminfo; //index into the item info + int flags; //item flags + float weight; //fixed roam weight + vec3_t origin; //origin of the item + int goalareanum; //area the item is in + vec3_t goalorigin; //goal origin within the area + int entitynum; //entity number + float timeout; //item is removed after this time + struct levelitem_s *prev, *next; +} levelitem_t; + +typedef struct iteminfo_s +{ + char classname[32]; //classname of the item + char name[MAX_STRINGFIELD]; //name of the item + char model[MAX_STRINGFIELD]; //model of the item + int modelindex; //model index + int type; //item type + int index; //index in the inventory + float respawntime; //respawn time + vec3_t mins; //mins of the item + vec3_t maxs; //maxs of the item + int number; //number of the item info +} iteminfo_t; + +#define ITEMINFO_OFS(x) offsetof(iteminfo_t, x) + +fielddef_t iteminfo_fields[] = +{ +{"name", ITEMINFO_OFS(name), FT_STRING}, +{"model", ITEMINFO_OFS(model), FT_STRING}, +{"modelindex", ITEMINFO_OFS(modelindex), FT_INT}, +{"type", ITEMINFO_OFS(type), FT_INT}, +{"index", ITEMINFO_OFS(index), FT_INT}, +{"respawntime", ITEMINFO_OFS(respawntime), FT_FLOAT}, +{"mins", ITEMINFO_OFS(mins), FT_FLOAT|FT_ARRAY, 3}, +{"maxs", ITEMINFO_OFS(maxs), FT_FLOAT|FT_ARRAY, 3}, +{NULL, 0, 0} +}; + +structdef_t iteminfo_struct = +{ + sizeof(iteminfo_t), iteminfo_fields +}; + +typedef struct itemconfig_s +{ + int numiteminfo; + iteminfo_t *iteminfo; +} itemconfig_t; + +//goal state +typedef struct bot_goalstate_s +{ + struct weightconfig_s *itemweightconfig; //weight config + int *itemweightindex; //index from item to weight + // + int client; //client using this goal state + int lastreachabilityarea; //last area with reachabilities the bot was in + // + bot_goal_t goalstack[MAX_GOALSTACK]; //goal stack + int goalstacktop; //the top of the goal stack + // + int avoidgoals[MAX_AVOIDGOALS]; //goals to avoid + float avoidgoaltimes[MAX_AVOIDGOALS]; //times to avoid the goals +} bot_goalstate_t; + +bot_goalstate_t *botgoalstates[MAX_CLIENTS + 1]; // bk001206 - FIXME: init? +//item configuration +itemconfig_t *itemconfig = NULL; // bk001206 - init +//level items +levelitem_t *levelitemheap = NULL; // bk001206 - init +levelitem_t *freelevelitems = NULL; // bk001206 - init +levelitem_t *levelitems = NULL; // bk001206 - init +int numlevelitems = 0; +//map locations +maplocation_t *maplocations = NULL; // bk001206 - init +//camp spots +campspot_t *campspots = NULL; // bk001206 - init +//the game type +int g_gametype = 0; // bk001206 - init +//additional dropped item weight +libvar_t *droppedweight = NULL; // bk001206 - init + +//======================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//======================================================================== +bot_goalstate_t *BotGoalStateFromHandle(int handle) +{ + if (handle <= 0 || handle > MAX_CLIENTS) + { + botimport.Print(PRT_FATAL, "goal state handle %d out of range\n", handle); + return NULL; + } //end if + if (!botgoalstates[handle]) + { + botimport.Print(PRT_FATAL, "invalid goal state %d\n", handle); + return NULL; + } //end if + return botgoalstates[handle]; +} //end of the function BotGoalStateFromHandle +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotInterbreedGoalFuzzyLogic(int parent1, int parent2, int child) +{ + bot_goalstate_t *p1, *p2, *c; + + p1 = BotGoalStateFromHandle(parent1); + p2 = BotGoalStateFromHandle(parent2); + c = BotGoalStateFromHandle(child); + + InterbreedWeightConfigs(p1->itemweightconfig, p2->itemweightconfig, + c->itemweightconfig); +} //end of the function BotInterbreedingGoalFuzzyLogic +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotSaveGoalFuzzyLogic(int goalstate, char *filename) +{ + //bot_goalstate_t *gs; + + //gs = BotGoalStateFromHandle(goalstate); + + //WriteWeightConfig(filename, gs->itemweightconfig); +} //end of the function BotSaveGoalFuzzyLogic +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotMutateGoalFuzzyLogic(int goalstate, float range) +{ + bot_goalstate_t *gs; + + gs = BotGoalStateFromHandle(goalstate); + + EvolveWeightConfig(gs->itemweightconfig); +} //end of the function BotMutateGoalFuzzyLogic +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +itemconfig_t *LoadItemConfig(char *filename) +{ + int max_iteminfo; + token_t token; + char path[MAX_PATH]; + source_t *source; + itemconfig_t *ic; + iteminfo_t *ii; + + max_iteminfo = (int) LibVarValue("max_iteminfo", "256"); + if (max_iteminfo < 0) + { + botimport.Print(PRT_ERROR, "max_iteminfo = %d\n", max_iteminfo); + max_iteminfo = 256; + LibVarSet( "max_iteminfo", "256" ); + } + + strncpy( path, filename, MAX_PATH ); + PC_SetBaseFolder(BOTFILESBASEFOLDER); + source = LoadSourceFile( path ); + if( !source ) { + botimport.Print( PRT_ERROR, "counldn't load %s\n", path ); + return NULL; + } //end if + //initialize item config + ic = (itemconfig_t *) GetClearedHunkMemory(sizeof(itemconfig_t) + + max_iteminfo * sizeof(iteminfo_t)); + ic->iteminfo = (iteminfo_t *) ((char *) ic + sizeof(itemconfig_t)); + ic->numiteminfo = 0; + //parse the item config file + while(PC_ReadToken(source, &token)) + { + if (!strcmp(token.string, "iteminfo")) + { + if (ic->numiteminfo >= max_iteminfo) + { + SourceError(source, "more than %d item info defined", max_iteminfo); + FreeMemory(ic); + FreeSource(source); + return NULL; + } //end if + ii = &ic->iteminfo[ic->numiteminfo]; + Com_Memset(ii, 0, sizeof(iteminfo_t)); + if (!PC_ExpectTokenType(source, TT_STRING, 0, &token)) + { + FreeMemory(ic); + FreeSource(source); + return NULL; + } //end if + StripDoubleQuotes(token.string); + strncpy(ii->classname, token.string, sizeof(ii->classname)-1); + if (!ReadStructure(source, &iteminfo_struct, (char *) ii)) + { + FreeMemory(ic); + FreeSource(source); + return NULL; + } //end if + ii->number = ic->numiteminfo; + ic->numiteminfo++; + } //end if + else + { + SourceError(source, "unknown definition %s", token.string); + FreeMemory(ic); + FreeSource(source); + return NULL; + } //end else + } //end while + FreeSource(source); + // + if (!ic->numiteminfo) botimport.Print(PRT_WARNING, "no item info loaded\n"); + botimport.Print(PRT_MESSAGE, "loaded %s\n", path); + return ic; +} //end of the function LoadItemConfig +//=========================================================================== +// index to find the weight function of an iteminfo +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int *ItemWeightIndex(weightconfig_t *iwc, itemconfig_t *ic) +{ + int *index, i; + + //initialize item weight index + index = (int *) GetClearedMemory(sizeof(int) * ic->numiteminfo); + + for (i = 0; i < ic->numiteminfo; i++) + { + index[i] = FindFuzzyWeight(iwc, ic->iteminfo[i].classname); + if (index[i] < 0) + { + Log_Write("item info %d \"%s\" has no fuzzy weight\r\n", i, ic->iteminfo[i].classname); + } //end if + } //end for + return index; +} //end of the function ItemWeightIndex +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void InitLevelItemHeap(void) +{ + int i, max_levelitems; + + if (levelitemheap) FreeMemory(levelitemheap); + + max_levelitems = (int) LibVarValue("max_levelitems", "256"); + levelitemheap = (levelitem_t *) GetClearedMemory(max_levelitems * sizeof(levelitem_t)); + + for (i = 0; i < max_levelitems-1; i++) + { + levelitemheap[i].next = &levelitemheap[i + 1]; + } //end for + levelitemheap[max_levelitems-1].next = NULL; + // + freelevelitems = levelitemheap; +} //end of the function InitLevelItemHeap +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +levelitem_t *AllocLevelItem(void) +{ + levelitem_t *li; + + li = freelevelitems; + if (!li) + { + botimport.Print(PRT_FATAL, "out of level items\n"); + return NULL; + } //end if + // + freelevelitems = freelevelitems->next; + Com_Memset(li, 0, sizeof(levelitem_t)); + return li; +} //end of the function AllocLevelItem +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void FreeLevelItem(levelitem_t *li) +{ + li->next = freelevelitems; + freelevelitems = li; +} //end of the function FreeLevelItem +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AddLevelItemToList(levelitem_t *li) +{ + if (levelitems) levelitems->prev = li; + li->prev = NULL; + li->next = levelitems; + levelitems = li; +} //end of the function AddLevelItemToList +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void RemoveLevelItemFromList(levelitem_t *li) +{ + if (li->prev) li->prev->next = li->next; + else levelitems = li->next; + if (li->next) li->next->prev = li->prev; +} //end of the function RemoveLevelItemFromList +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotFreeInfoEntities(void) +{ + maplocation_t *ml, *nextml; + campspot_t *cs, *nextcs; + + for (ml = maplocations; ml; ml = nextml) + { + nextml = ml->next; + FreeMemory(ml); + } //end for + maplocations = NULL; + for (cs = campspots; cs; cs = nextcs) + { + nextcs = cs->next; + FreeMemory(cs); + } //end for + campspots = NULL; +} //end of the function BotFreeInfoEntities +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotInitInfoEntities(void) +{ + char classname[MAX_EPAIRKEY]; + maplocation_t *ml; + campspot_t *cs; + int ent, numlocations, numcampspots; + + BotFreeInfoEntities(); + // + numlocations = 0; + numcampspots = 0; + for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent)) + { + if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue; + + //map locations + if (!strcmp(classname, "target_location")) + { + ml = (maplocation_t *) GetClearedMemory(sizeof(maplocation_t)); + AAS_VectorForBSPEpairKey(ent, "origin", ml->origin); + AAS_ValueForBSPEpairKey(ent, "message", ml->name, sizeof(ml->name)); + ml->areanum = AAS_PointAreaNum(ml->origin); + ml->next = maplocations; + maplocations = ml; + numlocations++; + } //end if + //camp spots + else if (!strcmp(classname, "info_camp")) + { + cs = (campspot_t *) GetClearedMemory(sizeof(campspot_t)); + AAS_VectorForBSPEpairKey(ent, "origin", cs->origin); + //cs->origin[2] += 16; + AAS_ValueForBSPEpairKey(ent, "message", cs->name, sizeof(cs->name)); + AAS_FloatForBSPEpairKey(ent, "range", &cs->range); + AAS_FloatForBSPEpairKey(ent, "weight", &cs->weight); + AAS_FloatForBSPEpairKey(ent, "wait", &cs->wait); + AAS_FloatForBSPEpairKey(ent, "random", &cs->random); + cs->areanum = AAS_PointAreaNum(cs->origin); + if (!cs->areanum) + { + botimport.Print(PRT_MESSAGE, "camp spot at %1.1f %1.1f %1.1f in solid\n", cs->origin[0], cs->origin[1], cs->origin[2]); + FreeMemory(cs); + continue; + } //end if + cs->next = campspots; + campspots = cs; + //AAS_DrawPermanentCross(cs->origin, 4, LINECOLOR_YELLOW); + numcampspots++; + } //end else if + } //end for + if (botDeveloper) + { + botimport.Print(PRT_MESSAGE, "%d map locations\n", numlocations); + botimport.Print(PRT_MESSAGE, "%d camp spots\n", numcampspots); + } //end if +} //end of the function BotInitInfoEntities +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotInitLevelItems(void) +{ + int i, spawnflags, value; + char classname[MAX_EPAIRKEY]; + vec3_t origin, end; + int ent, goalareanum; + itemconfig_t *ic; + levelitem_t *li; + bsp_trace_t trace; + + //initialize the map locations and camp spots + BotInitInfoEntities(); + + //initialize the level item heap + InitLevelItemHeap(); + levelitems = NULL; + numlevelitems = 0; + // + ic = itemconfig; + if (!ic) return; + + //if there's no AAS file loaded + if (!AAS_Loaded()) return; + + //validate the modelindexes of the item info + for (i = 0; i < ic->numiteminfo; i++) + { + if (!ic->iteminfo[i].modelindex) + { + Log_Write("item %s has modelindex 0", ic->iteminfo[i].classname); + } //end if + } //end for + + for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent)) + { + if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue; + // + spawnflags = 0; + AAS_IntForBSPEpairKey(ent, "spawnflags", &spawnflags); + // + for (i = 0; i < ic->numiteminfo; i++) + { + if (!strcmp(classname, ic->iteminfo[i].classname)) break; + } //end for + if (i >= ic->numiteminfo) + { + Log_Write("entity %s unknown item\r\n", classname); + continue; + } //end if + //get the origin of the item + if (!AAS_VectorForBSPEpairKey(ent, "origin", origin)) + { + botimport.Print(PRT_ERROR, "item %s without origin\n", classname); + continue; + } //end else + // + goalareanum = 0; + //if it is a floating item + if (spawnflags & 1) + { + //if the item is not floating in water + if (!(AAS_PointContents(origin) & CONTENTS_WATER)) + { + VectorCopy(origin, end); + end[2] -= 32; + trace = AAS_Trace(origin, ic->iteminfo[i].mins, ic->iteminfo[i].maxs, end, -1, CONTENTS_SOLID|CONTENTS_PLAYERCLIP); + //if the item not near the ground + if (trace.fraction >= 1) + { + //if the item is not reachable from a jumppad + goalareanum = AAS_BestReachableFromJumpPadArea(origin, ic->iteminfo[i].mins, ic->iteminfo[i].maxs); + Log_Write("item %s reachable from jumppad area %d\r\n", ic->iteminfo[i].classname, goalareanum); + //botimport.Print(PRT_MESSAGE, "item %s reachable from jumppad area %d\r\n", ic->iteminfo[i].classname, goalareanum); + if (!goalareanum) continue; + } //end if + } //end if + } //end if + + li = AllocLevelItem(); + if (!li) return; + // + li->number = ++numlevelitems; + li->timeout = 0; + li->entitynum = 0; + // + li->flags = 0; + AAS_IntForBSPEpairKey(ent, "notfree", &value); + if (value) li->flags |= IFL_NOTFREE; + AAS_IntForBSPEpairKey(ent, "notteam", &value); + if (value) li->flags |= IFL_NOTTEAM; + AAS_IntForBSPEpairKey(ent, "notsingle", &value); + if (value) li->flags |= IFL_NOTSINGLE; + AAS_IntForBSPEpairKey(ent, "notbot", &value); + if (value) li->flags |= IFL_NOTBOT; + if (!strcmp(classname, "item_botroam")) + { + li->flags |= IFL_ROAM; + AAS_FloatForBSPEpairKey(ent, "weight", &li->weight); + } //end if + //if not a stationary item + if (!(spawnflags & 1)) + { + if (!AAS_DropToFloor(origin, ic->iteminfo[i].mins, ic->iteminfo[i].maxs)) + { + botimport.Print(PRT_MESSAGE, "%s in solid at (%1.1f %1.1f %1.1f)\n", + classname, origin[0], origin[1], origin[2]); + } //end if + } //end if + //item info of the level item + li->iteminfo = i; + //origin of the item + VectorCopy(origin, li->origin); + // + if (goalareanum) + { + li->goalareanum = goalareanum; + VectorCopy(origin, li->goalorigin); + } //end if + else + { + //get the item goal area and goal origin + li->goalareanum = AAS_BestReachableArea(origin, + ic->iteminfo[i].mins, ic->iteminfo[i].maxs, + li->goalorigin); + if (!li->goalareanum) + { + botimport.Print(PRT_MESSAGE, "%s not reachable for bots at (%1.1f %1.1f %1.1f)\n", + classname, origin[0], origin[1], origin[2]); + } //end if + } //end else + // + AddLevelItemToList(li); + } //end for + botimport.Print(PRT_MESSAGE, "found %d level items\n", numlevelitems); +} //end of the function BotInitLevelItems +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotGoalName(int number, char *name, int size) +{ + levelitem_t *li; + + if (!itemconfig) return; + // + for (li = levelitems; li; li = li->next) + { + if (li->number == number) + { + strncpy(name, itemconfig->iteminfo[li->iteminfo].name, size-1); + name[size-1] = '\0'; + return; + } //end for + } //end for + strcpy(name, ""); + return; +} //end of the function BotGoalName +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotResetAvoidGoals(int goalstate) +{ + bot_goalstate_t *gs; + + gs = BotGoalStateFromHandle(goalstate); + if (!gs) return; + Com_Memset(gs->avoidgoals, 0, MAX_AVOIDGOALS * sizeof(int)); + Com_Memset(gs->avoidgoaltimes, 0, MAX_AVOIDGOALS * sizeof(float)); +} //end of the function BotResetAvoidGoals +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotDumpAvoidGoals(int goalstate) +{ + int i; + bot_goalstate_t *gs; + char name[32]; + + gs = BotGoalStateFromHandle(goalstate); + if (!gs) return; + for (i = 0; i < MAX_AVOIDGOALS; i++) + { + if (gs->avoidgoaltimes[i] >= AAS_Time()) + { + BotGoalName(gs->avoidgoals[i], name, 32); + Log_Write("avoid goal %s, number %d for %f seconds", name, + gs->avoidgoals[i], gs->avoidgoaltimes[i] - AAS_Time()); + } //end if + } //end for +} //end of the function BotDumpAvoidGoals +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotAddToAvoidGoals(bot_goalstate_t *gs, int number, float avoidtime) +{ + int i; + + for (i = 0; i < MAX_AVOIDGOALS; i++) + { + //if the avoid goal is already stored + if (gs->avoidgoals[i] == number) + { + gs->avoidgoals[i] = number; + gs->avoidgoaltimes[i] = AAS_Time() + avoidtime; + return; + } //end if + } //end for + + for (i = 0; i < MAX_AVOIDGOALS; i++) + { + //if this avoid goal has expired + if (gs->avoidgoaltimes[i] < AAS_Time()) + { + gs->avoidgoals[i] = number; + gs->avoidgoaltimes[i] = AAS_Time() + avoidtime; + return; + } //end if + } //end for +} //end of the function BotAddToAvoidGoals +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotRemoveFromAvoidGoals(int goalstate, int number) +{ + int i; + bot_goalstate_t *gs; + + gs = BotGoalStateFromHandle(goalstate); + if (!gs) return; + //don't use the goals the bot wants to avoid + for (i = 0; i < MAX_AVOIDGOALS; i++) + { + if (gs->avoidgoals[i] == number && gs->avoidgoaltimes[i] >= AAS_Time()) + { + gs->avoidgoaltimes[i] = 0; + return; + } //end if + } //end for +} //end of the function BotRemoveFromAvoidGoals +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float BotAvoidGoalTime(int goalstate, int number) +{ + int i; + bot_goalstate_t *gs; + + gs = BotGoalStateFromHandle(goalstate); + if (!gs) return 0; + //don't use the goals the bot wants to avoid + for (i = 0; i < MAX_AVOIDGOALS; i++) + { + if (gs->avoidgoals[i] == number && gs->avoidgoaltimes[i] >= AAS_Time()) + { + return gs->avoidgoaltimes[i] - AAS_Time(); + } //end if + } //end for + return 0; +} //end of the function BotAvoidGoalTime +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotSetAvoidGoalTime(int goalstate, int number, float avoidtime) +{ + bot_goalstate_t *gs; + levelitem_t *li; + + gs = BotGoalStateFromHandle(goalstate); + if (!gs) + return; + if (avoidtime < 0) + { + if (!itemconfig) + return; + // + for (li = levelitems; li; li = li->next) + { + if (li->number == number) + { + avoidtime = itemconfig->iteminfo[li->iteminfo].respawntime; + if (!avoidtime) + avoidtime = AVOID_DEFAULT_TIME; + if (avoidtime < AVOID_MINIMUM_TIME) + avoidtime = AVOID_MINIMUM_TIME; + BotAddToAvoidGoals(gs, number, avoidtime); + return; + } //end for + } //end for + return; + } //end if + else + { + BotAddToAvoidGoals(gs, number, avoidtime); + } //end else +} //end of the function BotSetAvoidGoalTime +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotGetLevelItemGoal(int index, char *name, bot_goal_t *goal) +{ + levelitem_t *li; + + if (!itemconfig) return -1; + li = levelitems; + if (index >= 0) + { + for (; li; li = li->next) + { + if (li->number == index) + { + li = li->next; + break; + } //end if + } //end for + } //end for + for (; li; li = li->next) + { + // + if (g_gametype == GT_SINGLE_PLAYER) { + if (li->flags & IFL_NOTSINGLE) continue; + } + else if (g_gametype >= GT_TEAM) { + if (li->flags & IFL_NOTTEAM) continue; + } + else { + if (li->flags & IFL_NOTFREE) continue; + } + if (li->flags & IFL_NOTBOT) continue; + // + if (!Q_stricmp(name, itemconfig->iteminfo[li->iteminfo].name)) + { + goal->areanum = li->goalareanum; + VectorCopy(li->goalorigin, goal->origin); + goal->entitynum = li->entitynum; + VectorCopy(itemconfig->iteminfo[li->iteminfo].mins, goal->mins); + VectorCopy(itemconfig->iteminfo[li->iteminfo].maxs, goal->maxs); + goal->number = li->number; + goal->flags = GFL_ITEM; + if (li->timeout) goal->flags |= GFL_DROPPED; + //botimport.Print(PRT_MESSAGE, "found li %s\n", itemconfig->iteminfo[li->iteminfo].name); + return li->number; + } //end if + } //end for + return -1; +} //end of the function BotGetLevelItemGoal +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotGetMapLocationGoal(char *name, bot_goal_t *goal) +{ + maplocation_t *ml; + vec3_t mins = {-8, -8, -8}, maxs = {8, 8, 8}; + + for (ml = maplocations; ml; ml = ml->next) + { + if (!Q_stricmp(ml->name, name)) + { + goal->areanum = ml->areanum; + VectorCopy(ml->origin, goal->origin); + goal->entitynum = 0; + VectorCopy(mins, goal->mins); + VectorCopy(maxs, goal->maxs); + return qtrue; + } //end if + } //end for + return qfalse; +} //end of the function BotGetMapLocationGoal +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotGetNextCampSpotGoal(int num, bot_goal_t *goal) +{ + int i; + campspot_t *cs; + vec3_t mins = {-8, -8, -8}, maxs = {8, 8, 8}; + + if (num < 0) num = 0; + i = num; + for (cs = campspots; cs; cs = cs->next) + { + if (--i < 0) + { + goal->areanum = cs->areanum; + VectorCopy(cs->origin, goal->origin); + goal->entitynum = 0; + VectorCopy(mins, goal->mins); + VectorCopy(maxs, goal->maxs); + return num+1; + } //end if + } //end for + return 0; +} //end of the function BotGetNextCampSpotGoal +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotFindEntityForLevelItem(levelitem_t *li) +{ + int ent, modelindex; + itemconfig_t *ic; + aas_entityinfo_t entinfo; + vec3_t dir; + + ic = itemconfig; + if (!itemconfig) return; + for (ent = AAS_NextEntity(0); ent; ent = AAS_NextEntity(ent)) + { + //get the model index of the entity + modelindex = AAS_EntityModelindex(ent); + // + if (!modelindex) continue; + //get info about the entity + AAS_EntityInfo(ent, &entinfo); + //if the entity is still moving + if (entinfo.origin[0] != entinfo.lastvisorigin[0] || + entinfo.origin[1] != entinfo.lastvisorigin[1] || + entinfo.origin[2] != entinfo.lastvisorigin[2]) continue; + // + if (ic->iteminfo[li->iteminfo].modelindex == modelindex) + { + //check if the entity is very close + VectorSubtract(li->origin, entinfo.origin, dir); + if (VectorLength(dir) < 30) + { + //found an entity for this level item + li->entitynum = ent; + } //end if + } //end if + } //end for +} //end of the function BotFindEntityForLevelItem +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== + +//NOTE: enum entityType_t in bg_public.h +#define ET_ITEM 2 + +void BotUpdateEntityItems(void) +{ + int ent, i, modelindex; + vec3_t dir; + levelitem_t *li, *nextli; + aas_entityinfo_t entinfo; + itemconfig_t *ic; + + //timeout current entity items if necessary + for (li = levelitems; li; li = nextli) + { + nextli = li->next; + //if it is an item that will time out + if (li->timeout) + { + //timeout the item + if (li->timeout < AAS_Time()) + { + RemoveLevelItemFromList(li); + FreeLevelItem(li); + } //end if + } //end if + } //end for + //find new entity items + ic = itemconfig; + if (!itemconfig) return; + // + for (ent = AAS_NextEntity(0); ent; ent = AAS_NextEntity(ent)) + { + if (AAS_EntityType(ent) != ET_ITEM) continue; + //get the model index of the entity + modelindex = AAS_EntityModelindex(ent); + // + if (!modelindex) continue; + //get info about the entity + AAS_EntityInfo(ent, &entinfo); + //FIXME: don't do this + //skip all floating items for now + //if (entinfo.groundent != ENTITYNUM_WORLD) continue; + //if the entity is still moving + if (entinfo.origin[0] != entinfo.lastvisorigin[0] || + entinfo.origin[1] != entinfo.lastvisorigin[1] || + entinfo.origin[2] != entinfo.lastvisorigin[2]) continue; + //check if the entity is already stored as a level item + for (li = levelitems; li; li = li->next) + { + //if the level item is linked to an entity + if (li->entitynum && li->entitynum == ent) + { + //the entity is re-used if the models are different + if (ic->iteminfo[li->iteminfo].modelindex != modelindex) + { + //remove this level item + RemoveLevelItemFromList(li); + FreeLevelItem(li); + li = NULL; + break; + } //end if + else + { + if (entinfo.origin[0] != li->origin[0] || + entinfo.origin[1] != li->origin[1] || + entinfo.origin[2] != li->origin[2]) + { + VectorCopy(entinfo.origin, li->origin); + //also update the goal area number + li->goalareanum = AAS_BestReachableArea(li->origin, + ic->iteminfo[li->iteminfo].mins, ic->iteminfo[li->iteminfo].maxs, + li->goalorigin); + } //end if + break; + } //end else + } //end if + } //end for + if (li) continue; + //try to link the entity to a level item + for (li = levelitems; li; li = li->next) + { + //if this level item is already linked + if (li->entitynum) continue; + // + if (g_gametype == GT_SINGLE_PLAYER) { + if (li->flags & IFL_NOTSINGLE) continue; + } + else if (g_gametype >= GT_TEAM) { + if (li->flags & IFL_NOTTEAM) continue; + } + else { + if (li->flags & IFL_NOTFREE) continue; + } + //if the model of the level item and the entity are the same + if (ic->iteminfo[li->iteminfo].modelindex == modelindex) + { + //check if the entity is very close + VectorSubtract(li->origin, entinfo.origin, dir); + if (VectorLength(dir) < 30) + { + //found an entity for this level item + li->entitynum = ent; + //if the origin is different + if (entinfo.origin[0] != li->origin[0] || + entinfo.origin[1] != li->origin[1] || + entinfo.origin[2] != li->origin[2]) + { + //update the level item origin + VectorCopy(entinfo.origin, li->origin); + //also update the goal area number + li->goalareanum = AAS_BestReachableArea(li->origin, + ic->iteminfo[li->iteminfo].mins, ic->iteminfo[li->iteminfo].maxs, + li->goalorigin); + } //end if +#ifdef DEBUG + Log_Write("linked item %s to an entity", ic->iteminfo[li->iteminfo].classname); +#endif //DEBUG + break; + } //end if + } //end else + } //end for + if (li) continue; + //check if the model is from a known item + for (i = 0; i < ic->numiteminfo; i++) + { + if (ic->iteminfo[i].modelindex == modelindex) + { + break; + } //end if + } //end for + //if the model is not from a known item + if (i >= ic->numiteminfo) continue; + //allocate a new level item + li = AllocLevelItem(); + // + if (!li) continue; + //entity number of the level item + li->entitynum = ent; + //number for the level item + li->number = numlevelitems + ent; + //set the item info index for the level item + li->iteminfo = i; + //origin of the item + VectorCopy(entinfo.origin, li->origin); + //get the item goal area and goal origin + li->goalareanum = AAS_BestReachableArea(li->origin, + ic->iteminfo[i].mins, ic->iteminfo[i].maxs, + li->goalorigin); + //never go for items dropped into jumppads + if (AAS_AreaJumpPad(li->goalareanum)) + { + FreeLevelItem(li); + continue; + } //end if + //time this item out after 30 seconds + //dropped items disappear after 30 seconds + li->timeout = AAS_Time() + 30; + //add the level item to the list + AddLevelItemToList(li); + //botimport.Print(PRT_MESSAGE, "found new level item %s\n", ic->iteminfo[i].classname); + } //end for + /* + for (li = levelitems; li; li = li->next) + { + if (!li->entitynum) + { + BotFindEntityForLevelItem(li); + } //end if + } //end for*/ +} //end of the function BotUpdateEntityItems +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotDumpGoalStack(int goalstate) +{ + int i; + bot_goalstate_t *gs; + char name[32]; + + gs = BotGoalStateFromHandle(goalstate); + if (!gs) return; + for (i = 1; i <= gs->goalstacktop; i++) + { + BotGoalName(gs->goalstack[i].number, name, 32); + Log_Write("%d: %s", i, name); + } //end for +} //end of the function BotDumpGoalStack +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotPushGoal(int goalstate, bot_goal_t *goal) +{ + bot_goalstate_t *gs; + + gs = BotGoalStateFromHandle(goalstate); + if (!gs) return; + if (gs->goalstacktop >= MAX_GOALSTACK-1) + { + botimport.Print(PRT_ERROR, "goal heap overflow\n"); + BotDumpGoalStack(goalstate); + return; + } //end if + gs->goalstacktop++; + Com_Memcpy(&gs->goalstack[gs->goalstacktop], goal, sizeof(bot_goal_t)); +} //end of the function BotPushGoal +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotPopGoal(int goalstate) +{ + bot_goalstate_t *gs; + + gs = BotGoalStateFromHandle(goalstate); + if (!gs) return; + if (gs->goalstacktop > 0) gs->goalstacktop--; +} //end of the function BotPopGoal +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotEmptyGoalStack(int goalstate) +{ + bot_goalstate_t *gs; + + gs = BotGoalStateFromHandle(goalstate); + if (!gs) return; + gs->goalstacktop = 0; +} //end of the function BotEmptyGoalStack +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotGetTopGoal(int goalstate, bot_goal_t *goal) +{ + bot_goalstate_t *gs; + + gs = BotGoalStateFromHandle(goalstate); + if (!gs) return qfalse; + if (!gs->goalstacktop) return qfalse; + Com_Memcpy(goal, &gs->goalstack[gs->goalstacktop], sizeof(bot_goal_t)); + return qtrue; +} //end of the function BotGetTopGoal +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotGetSecondGoal(int goalstate, bot_goal_t *goal) +{ + bot_goalstate_t *gs; + + gs = BotGoalStateFromHandle(goalstate); + if (!gs) return qfalse; + if (gs->goalstacktop <= 1) return qfalse; + Com_Memcpy(goal, &gs->goalstack[gs->goalstacktop-1], sizeof(bot_goal_t)); + return qtrue; +} //end of the function BotGetSecondGoal +//=========================================================================== +// pops a new long term goal on the goal stack in the goalstate +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotChooseLTGItem(int goalstate, vec3_t origin, int *inventory, int travelflags) +{ + int areanum, t, weightnum; + float weight, bestweight, avoidtime; + iteminfo_t *iteminfo; + itemconfig_t *ic; + levelitem_t *li, *bestitem; + bot_goal_t goal; + bot_goalstate_t *gs; + + gs = BotGoalStateFromHandle(goalstate); + if (!gs) + return qfalse; + if (!gs->itemweightconfig) + return qfalse; + //get the area the bot is in + areanum = BotReachabilityArea(origin, gs->client); + //if the bot is in solid or if the area the bot is in has no reachability links + if (!areanum || !AAS_AreaReachability(areanum)) + { + //use the last valid area the bot was in + areanum = gs->lastreachabilityarea; + } //end if + //remember the last area with reachabilities the bot was in + gs->lastreachabilityarea = areanum; + //if still in solid + if (!areanum) + return qfalse; + //the item configuration + ic = itemconfig; + if (!itemconfig) + return qfalse; + //best weight and item so far + bestweight = 0; + bestitem = NULL; + Com_Memset(&goal, 0, sizeof(bot_goal_t)); + //go through the items in the level + for (li = levelitems; li; li = li->next) + { + if (g_gametype == GT_SINGLE_PLAYER) { + if (li->flags & IFL_NOTSINGLE) + continue; + } + else if (g_gametype >= GT_TEAM) { + if (li->flags & IFL_NOTTEAM) + continue; + } + else { + if (li->flags & IFL_NOTFREE) + continue; + } + if (li->flags & IFL_NOTBOT) + continue; + //if the item is not in a possible goal area + if (!li->goalareanum) + continue; + //FIXME: is this a good thing? added this for items that never spawned into the game (f.i. CTF flags in obelisk) + if (!li->entitynum && !(li->flags & IFL_ROAM)) + continue; + //get the fuzzy weight function for this item + iteminfo = &ic->iteminfo[li->iteminfo]; + weightnum = gs->itemweightindex[iteminfo->number]; + if (weightnum < 0) + continue; + +#ifdef UNDECIDEDFUZZY + weight = FuzzyWeightUndecided(inventory, gs->itemweightconfig, weightnum); +#else + weight = FuzzyWeight(inventory, gs->itemweightconfig, weightnum); +#endif //UNDECIDEDFUZZY +#ifdef DROPPEDWEIGHT + //HACK: to make dropped items more attractive + if (li->timeout) + weight += droppedweight->value; +#endif //DROPPEDWEIGHT + //use weight scale for item_botroam + if (li->flags & IFL_ROAM) weight *= li->weight; + // + if (weight > 0) + { + //get the travel time towards the goal area + t = AAS_AreaTravelTimeToGoalArea(areanum, origin, li->goalareanum, travelflags); + //if the goal is reachable + if (t > 0) + { + //if this item won't respawn before we get there + avoidtime = BotAvoidGoalTime(goalstate, li->number); + if (avoidtime - t * 0.009 > 0) + continue; + // + weight /= (float) t * TRAVELTIME_SCALE; + // + if (weight > bestweight) + { + bestweight = weight; + bestitem = li; + } //end if + } //end if + } //end if + } //end for + //if no goal item found + if (!bestitem) + { + /* + //if not in lava or slime + if (!AAS_AreaLava(areanum) && !AAS_AreaSlime(areanum)) + { + if (AAS_RandomGoalArea(areanum, travelflags, &goal.areanum, goal.origin)) + { + VectorSet(goal.mins, -15, -15, -15); + VectorSet(goal.maxs, 15, 15, 15); + goal.entitynum = 0; + goal.number = 0; + goal.flags = GFL_ROAM; + goal.iteminfo = 0; + //push the goal on the stack + BotPushGoal(goalstate, &goal); + // +#ifdef DEBUG + botimport.Print(PRT_MESSAGE, "chosen roam goal area %d\n", goal.areanum); +#endif //DEBUG + return qtrue; + } //end if + } //end if + */ + return qfalse; + } //end if + //create a bot goal for this item + iteminfo = &ic->iteminfo[bestitem->iteminfo]; + VectorCopy(bestitem->goalorigin, goal.origin); + VectorCopy(iteminfo->mins, goal.mins); + VectorCopy(iteminfo->maxs, goal.maxs); + goal.areanum = bestitem->goalareanum; + goal.entitynum = bestitem->entitynum; + goal.number = bestitem->number; + goal.flags = GFL_ITEM; + if (bestitem->timeout) + goal.flags |= GFL_DROPPED; + if (bestitem->flags & IFL_ROAM) + goal.flags |= GFL_ROAM; + goal.iteminfo = bestitem->iteminfo; + //if it's a dropped item + if (bestitem->timeout) + { + avoidtime = AVOID_DROPPED_TIME; + } //end if + else + { + avoidtime = iteminfo->respawntime; + if (!avoidtime) + avoidtime = AVOID_DEFAULT_TIME; + if (avoidtime < AVOID_MINIMUM_TIME) + avoidtime = AVOID_MINIMUM_TIME; + } //end else + //add the chosen goal to the goals to avoid for a while + BotAddToAvoidGoals(gs, bestitem->number, avoidtime); + //push the goal on the stack + BotPushGoal(goalstate, &goal); + // + return qtrue; +} //end of the function BotChooseLTGItem +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotChooseNBGItem(int goalstate, vec3_t origin, int *inventory, int travelflags, + bot_goal_t *ltg, float maxtime) +{ + int areanum, t, weightnum, ltg_time; + float weight, bestweight, avoidtime; + iteminfo_t *iteminfo; + itemconfig_t *ic; + levelitem_t *li, *bestitem; + bot_goal_t goal; + bot_goalstate_t *gs; + + gs = BotGoalStateFromHandle(goalstate); + if (!gs) + return qfalse; + if (!gs->itemweightconfig) + return qfalse; + //get the area the bot is in + areanum = BotReachabilityArea(origin, gs->client); + //if the bot is in solid or if the area the bot is in has no reachability links + if (!areanum || !AAS_AreaReachability(areanum)) + { + //use the last valid area the bot was in + areanum = gs->lastreachabilityarea; + } //end if + //remember the last area with reachabilities the bot was in + gs->lastreachabilityarea = areanum; + //if still in solid + if (!areanum) + return qfalse; + // + if (ltg) ltg_time = AAS_AreaTravelTimeToGoalArea(areanum, origin, ltg->areanum, travelflags); + else ltg_time = 99999; + //the item configuration + ic = itemconfig; + if (!itemconfig) + return qfalse; + //best weight and item so far + bestweight = 0; + bestitem = NULL; + Com_Memset(&goal, 0, sizeof(bot_goal_t)); + //go through the items in the level + for (li = levelitems; li; li = li->next) + { + if (g_gametype == GT_SINGLE_PLAYER) { + if (li->flags & IFL_NOTSINGLE) + continue; + } + else if (g_gametype >= GT_TEAM) { + if (li->flags & IFL_NOTTEAM) + continue; + } + else { + if (li->flags & IFL_NOTFREE) + continue; + } + if (li->flags & IFL_NOTBOT) + continue; + //if the item is in a possible goal area + if (!li->goalareanum) + continue; + //FIXME: is this a good thing? added this for items that never spawned into the game (f.i. CTF flags in obelisk) + if (!li->entitynum && !(li->flags & IFL_ROAM)) + continue; + //get the fuzzy weight function for this item + iteminfo = &ic->iteminfo[li->iteminfo]; + weightnum = gs->itemweightindex[iteminfo->number]; + if (weightnum < 0) + continue; + // +#ifdef UNDECIDEDFUZZY + weight = FuzzyWeightUndecided(inventory, gs->itemweightconfig, weightnum); +#else + weight = FuzzyWeight(inventory, gs->itemweightconfig, weightnum); +#endif //UNDECIDEDFUZZY +#ifdef DROPPEDWEIGHT + //HACK: to make dropped items more attractive + if (li->timeout) + weight += droppedweight->value; +#endif //DROPPEDWEIGHT + //use weight scale for item_botroam + if (li->flags & IFL_ROAM) weight *= li->weight; + // + if (weight > 0) + { + //get the travel time towards the goal area + t = AAS_AreaTravelTimeToGoalArea(areanum, origin, li->goalareanum, travelflags); + //if the goal is reachable + if (t > 0 && t < maxtime) + { + //if this item won't respawn before we get there + avoidtime = BotAvoidGoalTime(goalstate, li->number); + if (avoidtime - t * 0.009 > 0) + continue; + // + weight /= (float) t * TRAVELTIME_SCALE; + // + if (weight > bestweight) + { + t = 0; + if (ltg && !li->timeout) + { + //get the travel time from the goal to the long term goal + t = AAS_AreaTravelTimeToGoalArea(li->goalareanum, li->goalorigin, ltg->areanum, travelflags); + } //end if + //if the travel back is possible and doesn't take too long + if (t <= ltg_time) + { + bestweight = weight; + bestitem = li; + } //end if + } //end if + } //end if + } //end if + } //end for + //if no goal item found + if (!bestitem) + return qfalse; + //create a bot goal for this item + iteminfo = &ic->iteminfo[bestitem->iteminfo]; + VectorCopy(bestitem->goalorigin, goal.origin); + VectorCopy(iteminfo->mins, goal.mins); + VectorCopy(iteminfo->maxs, goal.maxs); + goal.areanum = bestitem->goalareanum; + goal.entitynum = bestitem->entitynum; + goal.number = bestitem->number; + goal.flags = GFL_ITEM; + if (bestitem->timeout) + goal.flags |= GFL_DROPPED; + if (bestitem->flags & IFL_ROAM) + goal.flags |= GFL_ROAM; + goal.iteminfo = bestitem->iteminfo; + //if it's a dropped item + if (bestitem->timeout) + { + avoidtime = AVOID_DROPPED_TIME; + } //end if + else + { + avoidtime = iteminfo->respawntime; + if (!avoidtime) + avoidtime = AVOID_DEFAULT_TIME; + if (avoidtime < AVOID_MINIMUM_TIME) + avoidtime = AVOID_MINIMUM_TIME; + } //end else + //add the chosen goal to the goals to avoid for a while + BotAddToAvoidGoals(gs, bestitem->number, avoidtime); + //push the goal on the stack + BotPushGoal(goalstate, &goal); + // + return qtrue; +} //end of the function BotChooseNBGItem +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotTouchingGoal(vec3_t origin, bot_goal_t *goal) +{ + int i; + vec3_t boxmins, boxmaxs; + vec3_t absmins, absmaxs; + vec3_t safety_maxs = {0, 0, 0}; //{4, 4, 10}; + vec3_t safety_mins = {0, 0, 0}; //{-4, -4, 0}; + + AAS_PresenceTypeBoundingBox(PRESENCE_NORMAL, boxmins, boxmaxs); + VectorSubtract(goal->mins, boxmaxs, absmins); + VectorSubtract(goal->maxs, boxmins, absmaxs); + VectorAdd(absmins, goal->origin, absmins); + VectorAdd(absmaxs, goal->origin, absmaxs); + //make the box a little smaller for safety + VectorSubtract(absmaxs, safety_maxs, absmaxs); + VectorSubtract(absmins, safety_mins, absmins); + + for (i = 0; i < 3; i++) + { + if (origin[i] < absmins[i] || origin[i] > absmaxs[i]) return qfalse; + } //end for + return qtrue; +} //end of the function BotTouchingGoal +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotItemGoalInVisButNotVisible(int viewer, vec3_t eye, vec3_t viewangles, bot_goal_t *goal) +{ + aas_entityinfo_t entinfo; + bsp_trace_t trace; + vec3_t middle; + + if (!(goal->flags & GFL_ITEM)) return qfalse; + // + VectorAdd(goal->mins, goal->mins, middle); + VectorScale(middle, 0.5, middle); + VectorAdd(goal->origin, middle, middle); + // + trace = AAS_Trace(eye, NULL, NULL, middle, viewer, CONTENTS_SOLID); + //if the goal middle point is visible + if (trace.fraction >= 1) + { + //the goal entity number doesn't have to be valid + //just assume it's valid + if (goal->entitynum <= 0) + return qfalse; + // + //if the entity data isn't valid + AAS_EntityInfo(goal->entitynum, &entinfo); + //NOTE: for some wacko reason entities are sometimes + // not updated + //if (!entinfo.valid) return qtrue; + if (entinfo.ltime < AAS_Time() - 0.5) + return qtrue; + } //end if + return qfalse; +} //end of the function BotItemGoalInVisButNotVisible +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotResetGoalState(int goalstate) +{ + bot_goalstate_t *gs; + + gs = BotGoalStateFromHandle(goalstate); + if (!gs) return; + Com_Memset(gs->goalstack, 0, MAX_GOALSTACK * sizeof(bot_goal_t)); + gs->goalstacktop = 0; + BotResetAvoidGoals(goalstate); +} //end of the function BotResetGoalState +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotLoadItemWeights(int goalstate, char *filename) +{ + bot_goalstate_t *gs; + + gs = BotGoalStateFromHandle(goalstate); + if (!gs) return BLERR_CANNOTLOADITEMWEIGHTS; + //load the weight configuration + gs->itemweightconfig = ReadWeightConfig(filename); + if (!gs->itemweightconfig) + { + botimport.Print(PRT_FATAL, "couldn't load weights\n"); + return BLERR_CANNOTLOADITEMWEIGHTS; + } //end if + //if there's no item configuration + if (!itemconfig) return BLERR_CANNOTLOADITEMWEIGHTS; + //create the item weight index + gs->itemweightindex = ItemWeightIndex(gs->itemweightconfig, itemconfig); + //everything went ok + return BLERR_NOERROR; +} //end of the function BotLoadItemWeights +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotFreeItemWeights(int goalstate) +{ + bot_goalstate_t *gs; + + gs = BotGoalStateFromHandle(goalstate); + if (!gs) return; + if (gs->itemweightconfig) FreeWeightConfig(gs->itemweightconfig); + if (gs->itemweightindex) FreeMemory(gs->itemweightindex); +} //end of the function BotFreeItemWeights +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotAllocGoalState(int client) +{ + int i; + + for (i = 1; i <= MAX_CLIENTS; i++) + { + if (!botgoalstates[i]) + { + botgoalstates[i] = (struct bot_goalstate_s *)GetClearedMemory(sizeof(bot_goalstate_t)); + botgoalstates[i]->client = client; + return i; + } //end if + } //end for + return 0; +} //end of the function BotAllocGoalState +//======================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//======================================================================== +void BotFreeGoalState(int handle) +{ + if (handle <= 0 || handle > MAX_CLIENTS) + { + botimport.Print(PRT_FATAL, "goal state handle %d out of range\n", handle); + return; + } //end if + if (!botgoalstates[handle]) + { + botimport.Print(PRT_FATAL, "invalid goal state handle %d\n", handle); + return; + } //end if + BotFreeItemWeights(handle); + FreeMemory(botgoalstates[handle]); + botgoalstates[handle] = NULL; +} //end of the function BotFreeGoalState +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotSetupGoalAI(void) +{ + char *filename; + + //check if teamplay is on + g_gametype = LibVarValue("g_gametype", "0"); + //item configuration file + filename = LibVarString("itemconfig", "items.c"); + //load the item configuration + itemconfig = LoadItemConfig(filename); + if (!itemconfig) + { + botimport.Print(PRT_FATAL, "couldn't load item config\n"); + return BLERR_CANNOTLOADITEMCONFIG; + } //end if + // + droppedweight = LibVar("droppedweight", "1000"); + //everything went ok + return BLERR_NOERROR; +} //end of the function BotSetupGoalAI +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotShutdownGoalAI(void) +{ + int i; + + if (itemconfig) FreeMemory(itemconfig); + itemconfig = NULL; + if (levelitemheap) FreeMemory(levelitemheap); + levelitemheap = NULL; + freelevelitems = NULL; + levelitems = NULL; + numlevelitems = 0; + + BotFreeInfoEntities(); + + for (i = 1; i <= MAX_CLIENTS; i++) + { + if (botgoalstates[i]) + { + BotFreeGoalState(i); + } //end if + } //end for +} //end of the function BotShutdownGoalAI diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_goal.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_goal.h new file mode 100644 index 0000000..524f737 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_goal.h @@ -0,0 +1,125 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_ai_goal.h + * + * desc: goal AI + * + * $Archive: /source/code/botlib/be_ai_goal.h $ + * $Author: osman $ + * $Revision: 1.4 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 2003/03/15 23:44:00 $ + * + *****************************************************************************/ + +#pragma once + +#define MAX_AVOIDGOALS 256 +#define MAX_GOALSTACK 8 + +#define GFL_NONE 0 +#define GFL_ITEM 1 +#define GFL_ROAM 2 +#define GFL_DROPPED 4 + +//a bot goal +typedef struct bot_goal_s +{ + vec3_t origin; //origin of the goal + int areanum; //area number of the goal + vec3_t mins, maxs; //mins and maxs of the goal + int entitynum; //number of the goal entity + int number; //goal number + int flags; //goal flags + int iteminfo; //item information +} bot_goal_t; + +//reset the whole goal state, but keep the item weights +void BotResetGoalState(int goalstate); +//reset avoid goals +void BotResetAvoidGoals(int goalstate); +//remove the goal with the given number from the avoid goals +void BotRemoveFromAvoidGoals(int goalstate, int number); +//push a goal onto the goal stack +void BotPushGoal(int goalstate, bot_goal_t *goal); +//pop a goal from the goal stack +void BotPopGoal(int goalstate); +//empty the bot's goal stack +void BotEmptyGoalStack(int goalstate); +//dump the avoid goals +void BotDumpAvoidGoals(int goalstate); +//dump the goal stack +void BotDumpGoalStack(int goalstate); +//get the name name of the goal with the given number +void BotGoalName(int number, char *name, int size); +//get the top goal from the stack +int BotGetTopGoal(int goalstate, bot_goal_t *goal); +//get the second goal on the stack +int BotGetSecondGoal(int goalstate, bot_goal_t *goal); +//choose the best long term goal item for the bot +int BotChooseLTGItem(int goalstate, vec3_t origin, int *inventory, int travelflags); +//choose the best nearby goal item for the bot +//the item may not be further away from the current bot position than maxtime +//also the travel time from the nearby goal towards the long term goal may not +//be larger than the travel time towards the long term goal from the current bot position +int BotChooseNBGItem(int goalstate, vec3_t origin, int *inventory, int travelflags, + bot_goal_t *ltg, float maxtime); +//returns true if the bot touches the goal +int BotTouchingGoal(vec3_t origin, bot_goal_t *goal); +//returns true if the goal should be visible but isn't +int BotItemGoalInVisButNotVisible(int viewer, vec3_t eye, vec3_t viewangles, bot_goal_t *goal); +//search for a goal for the given classname, the index can be used +//as a start point for the search when multiple goals are available with that same classname +int BotGetLevelItemGoal(int index, char *classname, bot_goal_t *goal); +//get the next camp spot in the map +int BotGetNextCampSpotGoal(int num, bot_goal_t *goal); +//get the map location with the given name +int BotGetMapLocationGoal(char *name, bot_goal_t *goal); +//returns the avoid goal time +float BotAvoidGoalTime(int goalstate, int number); +//set the avoid goal time +void BotSetAvoidGoalTime(int goalstate, int number, float avoidtime); +//initializes the items in the level +void BotInitLevelItems(void); +//regularly update dynamic entity items (dropped weapons, flags etc.) +void BotUpdateEntityItems(void); +//interbreed the goal fuzzy logic +void BotInterbreedGoalFuzzyLogic(int parent1, int parent2, int child); +//save the goal fuzzy logic to disk +void BotSaveGoalFuzzyLogic(int goalstate, char *filename); +//mutate the goal fuzzy logic +void BotMutateGoalFuzzyLogic(int goalstate, float range); +//loads item weights for the bot +int BotLoadItemWeights(int goalstate, char *filename); +//frees the item weights of the bot +void BotFreeItemWeights(int goalstate); +//returns the handle of a newly allocated goal state +int BotAllocGoalState(int client); +//free the given goal state +void BotFreeGoalState(int handle); +//setup the goal AI +int BotSetupGoalAI(void); +//shut down the goal AI +void BotShutdownGoalAI(void); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_move.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_move.cpp new file mode 100644 index 0000000..8f24960 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_move.cpp @@ -0,0 +1,3569 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_ai_move.c + * + * desc: bot movement AI + * + * $Archive: /MissionPack/code/botlib/be_ai_move.c $ + * $Author: Ttimo $ + * $Revision: 14 $ + * $Modtime: 4/22/01 8:52a $ + * $Date: 4/22/01 8:52a $ + * + *****************************************************************************/ + +#include "qcommon/q_shared.h" +#include "l_memory.h" +#include "l_libvar.h" +#include "l_utils.h" +#include "l_script.h" +#include "l_precomp.h" +#include "l_struct.h" +#include "aasfile.h" +#include "botlib.h" +#include "be_aas.h" +#include "be_aas_funcs.h" +#include "be_interface.h" + +#include "be_ea.h" +#include "be_ai_goal.h" +#include "be_ai_move.h" + + +//#define DEBUG_AI_MOVE +//#define DEBUG_ELEVATOR +//#define DEBUG_GRAPPLE + +// bk001204 - redundant bot_avoidspot_t, see ../game/be_ai_move.h + +//movement state +//NOTE: the moveflags MFL_ONGROUND, MFL_TELEPORTED, MFL_WATERJUMP and +// MFL_GRAPPLEPULL must be set outside the movement code +typedef struct bot_movestate_s +{ + //input vars (all set outside the movement code) + vec3_t origin; //origin of the bot + vec3_t velocity; //velocity of the bot + vec3_t viewoffset; //view offset + int entitynum; //entity number of the bot + int client; //client number of the bot + float thinktime; //time the bot thinks + int presencetype; //presencetype of the bot + vec3_t viewangles; //view angles of the bot + //state vars + int areanum; //area the bot is in + int lastareanum; //last area the bot was in + int lastgoalareanum; //last goal area number + int lastreachnum; //last reachability number + vec3_t lastorigin; //origin previous cycle + int reachareanum; //area number of the reachabilty + int moveflags; //movement flags + int jumpreach; //set when jumped + float grapplevisible_time; //last time the grapple was visible + float lastgrappledist; //last distance to the grapple end + float reachability_time; //time to use current reachability + int avoidreach[MAX_AVOIDREACH]; //reachabilities to avoid + float avoidreachtimes[MAX_AVOIDREACH]; //times to avoid the reachabilities + int avoidreachtries[MAX_AVOIDREACH]; //number of tries before avoiding + // + bot_avoidspot_t avoidspots[MAX_AVOIDSPOTS]; //spots to avoid + int numavoidspots; +} bot_movestate_t; + +//used to avoid reachability links for some time after being used +#define AVOIDREACH +#define AVOIDREACH_TIME 6 //avoid links for 6 seconds after use +#define AVOIDREACH_TRIES 4 +//prediction times +#define PREDICTIONTIME_JUMP 3 //in seconds +#define PREDICTIONTIME_MOVE 2 //in seconds +//weapon indexes for weapon jumping +#define WEAPONINDEX_ROCKET_LAUNCHER 5 +#define WEAPONINDEX_BFG 9 + +#define MODELTYPE_FUNC_PLAT 1 +#define MODELTYPE_FUNC_BOB 2 +#define MODELTYPE_FUNC_DOOR 3 +#define MODELTYPE_FUNC_STATIC 4 + +libvar_t *sv_maxstep; +libvar_t *sv_maxbarrier; +libvar_t *sv_gravity; +libvar_t *weapindex_rocketlauncher; +libvar_t *weapindex_bfg10k; +libvar_t *weapindex_grapple; +libvar_t *entitytypemissile; +libvar_t *offhandgrapple; +libvar_t *cmd_grappleoff; +libvar_t *cmd_grappleon; +//type of model, func_plat or func_bobbing +int modeltypes[MAX_MODELS]; + +bot_movestate_t *botmovestates[MAX_CLIENTS+1]; + +//======================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//======================================================================== +int BotAllocMoveState(void) +{ + int i; + + for (i = 1; i <= MAX_CLIENTS; i++) + { + if (!botmovestates[i]) + { + botmovestates[i] = (struct bot_movestate_s *)GetClearedMemory(sizeof(bot_movestate_t)); + return i; + } //end if + } //end for + return 0; +} //end of the function BotAllocMoveState +//======================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//======================================================================== +void BotFreeMoveState(int handle) +{ + if (handle <= 0 || handle > MAX_CLIENTS) + { + botimport.Print(PRT_FATAL, "move state handle %d out of range\n", handle); + return; + } //end if + if (!botmovestates[handle]) + { + botimport.Print(PRT_FATAL, "invalid move state %d\n", handle); + return; + } //end if + FreeMemory(botmovestates[handle]); + botmovestates[handle] = NULL; +} //end of the function BotFreeMoveState +//======================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//======================================================================== +bot_movestate_t *BotMoveStateFromHandle(int handle) +{ + if (handle <= 0 || handle > MAX_CLIENTS) + { + botimport.Print(PRT_FATAL, "move state handle %d out of range\n", handle); + return NULL; + } //end if + if (!botmovestates[handle]) + { + botimport.Print(PRT_FATAL, "invalid move state %d\n", handle); + return NULL; + } //end if + return botmovestates[handle]; +} //end of the function BotMoveStateFromHandle +//======================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//======================================================================== +void BotInitMoveState(int handle, bot_initmove_t *initmove) +{ + bot_movestate_t *ms; + + ms = BotMoveStateFromHandle(handle); + if (!ms) return; + VectorCopy(initmove->origin, ms->origin); + VectorCopy(initmove->velocity, ms->velocity); + VectorCopy(initmove->viewoffset, ms->viewoffset); + ms->entitynum = initmove->entitynum; + ms->client = initmove->client; + ms->thinktime = initmove->thinktime; + ms->presencetype = initmove->presencetype; + VectorCopy(initmove->viewangles, ms->viewangles); + // + ms->moveflags &= ~MFL_ONGROUND; + if (initmove->or_moveflags & MFL_ONGROUND) ms->moveflags |= MFL_ONGROUND; + ms->moveflags &= ~MFL_TELEPORTED; + if (initmove->or_moveflags & MFL_TELEPORTED) ms->moveflags |= MFL_TELEPORTED; + ms->moveflags &= ~MFL_WATERJUMP; + if (initmove->or_moveflags & MFL_WATERJUMP) ms->moveflags |= MFL_WATERJUMP; + ms->moveflags &= ~MFL_WALK; + if (initmove->or_moveflags & MFL_WALK) ms->moveflags |= MFL_WALK; + ms->moveflags &= ~MFL_GRAPPLEPULL; + if (initmove->or_moveflags & MFL_GRAPPLEPULL) ms->moveflags |= MFL_GRAPPLEPULL; +} //end of the function BotInitMoveState +//======================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//======================================================================== +float AngleDiff(float ang1, float ang2) +{ + float diff; + + diff = ang1 - ang2; + if (ang1 > ang2) + { + if (diff > 180.0) diff -= 360.0; + } //end if + else + { + if (diff < -180.0) diff += 360.0; + } //end else + return diff; +} //end of the function AngleDiff +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotFuzzyPointReachabilityArea(vec3_t origin) +{ + int firstareanum, j, x, y, z; + int areas[10], numareas, areanum, bestareanum; + float dist, bestdist; + vec3_t points[10], v, end; + + firstareanum = 0; + areanum = AAS_PointAreaNum(origin); + if (areanum) + { + firstareanum = areanum; + if (AAS_AreaReachability(areanum)) return areanum; + } //end if + VectorCopy(origin, end); + end[2] += 4; + numareas = AAS_TraceAreas(origin, end, areas, points, 10); + for (j = 0; j < numareas; j++) + { + if (AAS_AreaReachability(areas[j])) return areas[j]; + } //end for + bestdist = 999999; + bestareanum = 0; + for (z = 1; z >= -1; z -= 1) + { + for (x = 1; x >= -1; x -= 1) + { + for (y = 1; y >= -1; y -= 1) + { + VectorCopy(origin, end); + end[0] += x * 8; + end[1] += y * 8; + end[2] += z * 12; + numareas = AAS_TraceAreas(origin, end, areas, points, 10); + for (j = 0; j < numareas; j++) + { + if (AAS_AreaReachability(areas[j])) + { + VectorSubtract(points[j], origin, v); + dist = VectorLength(v); + if (dist < bestdist) + { + bestareanum = areas[j]; + bestdist = dist; + } //end if + } //end if + if (!firstareanum) firstareanum = areas[j]; + } //end for + } //end for + } //end for + if (bestareanum) return bestareanum; + } //end for + return firstareanum; +} //end of the function BotFuzzyPointReachabilityArea +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotReachabilityArea(vec3_t origin, int client) +{ + int modelnum, modeltype, reachnum, areanum; + aas_reachability_t reach; + vec3_t org, end, mins, maxs, up = {0, 0, 1}; + bsp_trace_t bsptrace; + aas_trace_t trace; + + //check if the bot is standing on something + AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, mins, maxs); + VectorMA(origin, -3, up, end); + bsptrace = AAS_Trace(origin, mins, maxs, end, client, CONTENTS_SOLID|CONTENTS_PLAYERCLIP); + if (!bsptrace.startsolid && bsptrace.fraction < 1 && bsptrace.ent != ENTITYNUM_NONE) + { + //if standing on the world the bot should be in a valid area + if (bsptrace.ent == ENTITYNUM_WORLD) + { + return BotFuzzyPointReachabilityArea(origin); + } //end if + + modelnum = AAS_EntityModelindex(bsptrace.ent); + modeltype = modeltypes[modelnum]; + + //if standing on a func_plat or func_bobbing then the bot is assumed to be + //in the area the reachability points to + if (modeltype == MODELTYPE_FUNC_PLAT || modeltype == MODELTYPE_FUNC_BOB) + { + reachnum = AAS_NextModelReachability(0, modelnum); + if (reachnum) + { + AAS_ReachabilityFromNum(reachnum, &reach); + return reach.areanum; + } //end if + } //end else if + + //if the bot is swimming the bot should be in a valid area + if (AAS_Swimming(origin)) + { + return BotFuzzyPointReachabilityArea(origin); + } //end if + // + areanum = BotFuzzyPointReachabilityArea(origin); + //if the bot is in an area with reachabilities + if (areanum && AAS_AreaReachability(areanum)) return areanum; + //trace down till the ground is hit because the bot is standing on some other entity + VectorCopy(origin, org); + VectorCopy(org, end); + end[2] -= 800; + trace = AAS_TraceClientBBox(org, end, PRESENCE_CROUCH, -1); + if (!trace.startsolid) + { + VectorCopy(trace.endpos, org); + } //end if + // + return BotFuzzyPointReachabilityArea(org); + } //end if + // + return BotFuzzyPointReachabilityArea(origin); +} //end of the function BotReachabilityArea +//=========================================================================== +// returns the reachability area the bot is in +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +/* +int BotReachabilityArea(vec3_t origin, int testground) +{ + int firstareanum, i, j, x, y, z; + int areas[10], numareas, areanum, bestareanum; + float dist, bestdist; + vec3_t org, end, points[10], v; + aas_trace_t trace; + + firstareanum = 0; + for (i = 0; i < 2; i++) + { + VectorCopy(origin, org); + //if test at the ground (used when bot is standing on an entity) + if (i > 0) + { + VectorCopy(origin, end); + end[2] -= 800; + trace = AAS_TraceClientBBox(origin, end, PRESENCE_CROUCH, -1); + if (!trace.startsolid) + { + VectorCopy(trace.endpos, org); + } //end if + } //end if + + firstareanum = 0; + areanum = AAS_PointAreaNum(org); + if (areanum) + { + firstareanum = areanum; + if (AAS_AreaReachability(areanum)) return areanum; + } //end if + bestdist = 999999; + bestareanum = 0; + for (z = 1; z >= -1; z -= 1) + { + for (x = 1; x >= -1; x -= 1) + { + for (y = 1; y >= -1; y -= 1) + { + VectorCopy(org, end); + end[0] += x * 8; + end[1] += y * 8; + end[2] += z * 12; + numareas = AAS_TraceAreas(org, end, areas, points, 10); + for (j = 0; j < numareas; j++) + { + if (AAS_AreaReachability(areas[j])) + { + VectorSubtract(points[j], org, v); + dist = VectorLength(v); + if (dist < bestdist) + { + bestareanum = areas[j]; + bestdist = dist; + } //end if + } //end if + } //end for + } //end for + } //end for + if (bestareanum) return bestareanum; + } //end for + if (!testground) break; + } //end for +//#ifdef DEBUG + //botimport.Print(PRT_MESSAGE, "no reachability area\n"); +//#endif //DEBUG + return firstareanum; +} //end of the function BotReachabilityArea*/ +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotOnMover(vec3_t origin, int entnum, aas_reachability_t *reach) +{ + int i, modelnum; + vec3_t mins, maxs, modelorigin, org, end; + vec3_t angles = {0, 0, 0}; + vec3_t boxmins = {-16, -16, -8}, boxmaxs = {16, 16, 8}; + bsp_trace_t trace; + + modelnum = reach->facenum & 0x0000FFFF; + //get some bsp model info + AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, NULL); + // + if (!AAS_OriginOfMoverWithModelNum(modelnum, modelorigin)) + { + botimport.Print(PRT_MESSAGE, "no entity with model %d\n", modelnum); + return qfalse; + } //end if + // + for (i = 0; i < 2; i++) + { + if (origin[i] > modelorigin[i] + maxs[i] + 16) return qfalse; + if (origin[i] < modelorigin[i] + mins[i] - 16) return qfalse; + } //end for + // + VectorCopy(origin, org); + org[2] += 24; + VectorCopy(origin, end); + end[2] -= 48; + // + trace = AAS_Trace(org, boxmins, boxmaxs, end, entnum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP); + if (!trace.startsolid && !trace.allsolid) + { + //NOTE: the reachability face number is the model number of the elevator + if (trace.ent != ENTITYNUM_NONE && AAS_EntityModelNum(trace.ent) == modelnum) + { + return qtrue; + } //end if + } //end if + return qfalse; +} //end of the function BotOnMover +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int MoverDown(aas_reachability_t *reach) +{ + int modelnum; + vec3_t mins, maxs, origin; + vec3_t angles = {0, 0, 0}; + + modelnum = reach->facenum & 0x0000FFFF; + //get some bsp model info + AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin); + // + if (!AAS_OriginOfMoverWithModelNum(modelnum, origin)) + { + botimport.Print(PRT_MESSAGE, "no entity with model %d\n", modelnum); + return qfalse; + } //end if + //if the top of the plat is below the reachability start point + if (origin[2] + maxs[2] < reach->start[2]) return qtrue; + return qfalse; +} //end of the function MoverDown +//======================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//======================================================================== +void BotSetBrushModelTypes(void) +{ + int ent, modelnum; + char classname[MAX_EPAIRKEY], model[MAX_EPAIRKEY]; + + Com_Memset(modeltypes, 0, MAX_MODELS * sizeof(int)); + // + for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent)) + { + if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue; + if (!AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY)) continue; + if (model[0]) modelnum = atoi(model+1); + else modelnum = 0; + + if (modelnum < 0 || modelnum >= MAX_MODELS) + { + botimport.Print(PRT_MESSAGE, "entity %s model number out of range\n", classname); + continue; + } //end if + + if (!Q_stricmp(classname, "func_bobbing")) + modeltypes[modelnum] = MODELTYPE_FUNC_BOB; + else if (!Q_stricmp(classname, "func_plat")) + modeltypes[modelnum] = MODELTYPE_FUNC_PLAT; + else if (!Q_stricmp(classname, "func_door")) + modeltypes[modelnum] = MODELTYPE_FUNC_DOOR; + else if (!Q_stricmp(classname, "func_static")) + modeltypes[modelnum] = MODELTYPE_FUNC_STATIC; + } //end for +} //end of the function BotSetBrushModelTypes +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotOnTopOfEntity(bot_movestate_t *ms) +{ + vec3_t mins, maxs, end, up = {0, 0, 1}; + bsp_trace_t trace; + + AAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs); + VectorMA(ms->origin, -3, up, end); + trace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP); + if (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) ) + { + return trace.ent; + } //end if + return -1; +} //end of the function BotOnTopOfEntity +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotValidTravel(vec3_t origin, aas_reachability_t *reach, int travelflags) +{ + //if the reachability uses an unwanted travel type + if (AAS_TravelFlagForType(reach->traveltype) & ~travelflags) return qfalse; + //don't go into areas with bad travel types + if (AAS_AreaContentsTravelFlags(reach->areanum) & ~travelflags) return qfalse; + return qtrue; +} //end of the function BotValidTravel +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotAddToAvoidReach(bot_movestate_t *ms, int number, float avoidtime) +{ + int i; + + for (i = 0; i < MAX_AVOIDREACH; i++) + { + if (ms->avoidreach[i] == number) + { + if (ms->avoidreachtimes[i] > AAS_Time()) ms->avoidreachtries[i]++; + else ms->avoidreachtries[i] = 1; + ms->avoidreachtimes[i] = AAS_Time() + avoidtime; + return; + } //end if + } //end for + //add the reachability to the reachabilities to avoid for a while + for (i = 0; i < MAX_AVOIDREACH; i++) + { + if (ms->avoidreachtimes[i] < AAS_Time()) + { + ms->avoidreach[i] = number; + ms->avoidreachtimes[i] = AAS_Time() + avoidtime; + ms->avoidreachtries[i] = 1; + return; + } //end if + } //end for +} //end of the function BotAddToAvoidReach +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float DistanceFromLineSquared(vec3_t p, vec3_t lp1, vec3_t lp2) +{ + vec3_t proj, dir; + int j; + + AAS_ProjectPointOntoVector(p, lp1, lp2, proj); + for (j = 0; j < 3; j++) + if ((proj[j] > lp1[j] && proj[j] > lp2[j]) || + (proj[j] < lp1[j] && proj[j] < lp2[j])) + break; + if (j < 3) { + if (fabs(proj[j] - lp1[j]) < fabs(proj[j] - lp2[j])) + VectorSubtract(p, lp1, dir); + else + VectorSubtract(p, lp2, dir); + return VectorLengthSquared(dir); + } + VectorSubtract(p, proj, dir); + return VectorLengthSquared(dir); +} //end of the function DistanceFromLineSquared +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float VectorDistanceSquared(vec3_t p1, vec3_t p2) +{ + vec3_t dir; + VectorSubtract(p2, p1, dir); + return VectorLengthSquared(dir); +} //end of the function VectorDistanceSquared +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotAvoidSpots(vec3_t origin, aas_reachability_t *reach, bot_avoidspot_t *avoidspots, int numavoidspots) +{ + int checkbetween, i, type; + float squareddist, squaredradius; + + switch(reach->traveltype & TRAVELTYPE_MASK) + { + case TRAVEL_WALK: checkbetween = qtrue; break; + case TRAVEL_CROUCH: checkbetween = qtrue; break; + case TRAVEL_BARRIERJUMP: checkbetween = qtrue; break; + case TRAVEL_LADDER: checkbetween = qtrue; break; + case TRAVEL_WALKOFFLEDGE: checkbetween = qfalse; break; + case TRAVEL_JUMP: checkbetween = qfalse; break; + case TRAVEL_SWIM: checkbetween = qtrue; break; + case TRAVEL_WATERJUMP: checkbetween = qtrue; break; + case TRAVEL_TELEPORT: checkbetween = qfalse; break; + case TRAVEL_ELEVATOR: checkbetween = qfalse; break; + case TRAVEL_GRAPPLEHOOK: checkbetween = qfalse; break; + case TRAVEL_ROCKETJUMP: checkbetween = qfalse; break; + case TRAVEL_BFGJUMP: checkbetween = qfalse; break; + case TRAVEL_JUMPPAD: checkbetween = qfalse; break; + case TRAVEL_FUNCBOB: checkbetween = qfalse; break; + default: checkbetween = qtrue; break; + } //end switch + + type = AVOID_CLEAR; + for (i = 0; i < numavoidspots; i++) + { + squaredradius = Square(avoidspots[i].radius); + squareddist = DistanceFromLineSquared(avoidspots[i].origin, origin, reach->start); + // if moving towards the avoid spot + if (squareddist < squaredradius && + VectorDistanceSquared(avoidspots[i].origin, origin) > squareddist) + { + type = avoidspots[i].type; + } //end if + else if (checkbetween) { + squareddist = DistanceFromLineSquared(avoidspots[i].origin, reach->start, reach->end); + // if moving towards the avoid spot + if (squareddist < squaredradius && + VectorDistanceSquared(avoidspots[i].origin, reach->start) > squareddist) + { + type = avoidspots[i].type; + } //end if + } //end if + else + { + VectorDistanceSquared(avoidspots[i].origin, reach->end); + // if the reachability leads closer to the avoid spot + if (squareddist < squaredradius && + VectorDistanceSquared(avoidspots[i].origin, reach->start) > squareddist) + { + type = avoidspots[i].type; + } //end if + } //end else + if (type == AVOID_ALWAYS) + return type; + } //end for + return type; +} //end of the function BotAvoidSpots +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotAddAvoidSpot(int movestate, vec3_t origin, float radius, int type) +{ + bot_movestate_t *ms; + + ms = BotMoveStateFromHandle(movestate); + if (!ms) return; + if (type == AVOID_CLEAR) + { + ms->numavoidspots = 0; + return; + } //end if + + if (ms->numavoidspots >= MAX_AVOIDSPOTS) + return; + VectorCopy(origin, ms->avoidspots[ms->numavoidspots].origin); + ms->avoidspots[ms->numavoidspots].radius = radius; + ms->avoidspots[ms->numavoidspots].type = type; + ms->numavoidspots++; +} //end of the function BotAddAvoidSpot +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotGetReachabilityToGoal(vec3_t origin, int areanum, + int lastgoalareanum, int lastareanum, + int *avoidreach, float *avoidreachtimes, int *avoidreachtries, + bot_goal_t *goal, int travelflags, + struct bot_avoidspot_s *avoidspots, int numavoidspots, int *flags) +{ + int i, t, besttime, bestreachnum, reachnum; + aas_reachability_t reach; + + //if not in a valid area + if (!areanum) return 0; + // + if (AAS_AreaDoNotEnter(areanum) || AAS_AreaDoNotEnter(goal->areanum)) + { + travelflags |= TFL_DONOTENTER; + } //end if + //use the routing to find the next area to go to + besttime = 0; + bestreachnum = 0; + // + for (reachnum = AAS_NextAreaReachability(areanum, 0); reachnum; + reachnum = AAS_NextAreaReachability(areanum, reachnum)) + { +#ifdef AVOIDREACH + //check if it isn't a reachability to avoid + for (i = 0; i < MAX_AVOIDREACH; i++) + { + if (avoidreach[i] == reachnum && avoidreachtimes[i] >= AAS_Time()) break; + } //end for + if (i != MAX_AVOIDREACH && avoidreachtries[i] > AVOIDREACH_TRIES) + { +#ifdef DEBUG + if (botDeveloper) + { + botimport.Print(PRT_MESSAGE, "avoiding reachability %d\n", avoidreach[i]); + } //end if +#endif //DEBUG + continue; + } //end if +#endif //AVOIDREACH + //get the reachability from the number + AAS_ReachabilityFromNum(reachnum, &reach); + //NOTE: do not go back to the previous area if the goal didn't change + //NOTE: is this actually avoidance of local routing minima between two areas??? + if (lastgoalareanum == goal->areanum && reach.areanum == lastareanum) continue; + //if (AAS_AreaContentsTravelFlags(reach.areanum) & ~travelflags) continue; + //if the travel isn't valid + if (!BotValidTravel(origin, &reach, travelflags)) continue; + //get the travel time + t = AAS_AreaTravelTimeToGoalArea(reach.areanum, reach.end, goal->areanum, travelflags); + //if the goal area isn't reachable from the reachable area + if (!t) continue; + //if the bot should not use this reachability to avoid bad spots + if (BotAvoidSpots(origin, &reach, avoidspots, numavoidspots)) { + if (flags) { + *flags |= MOVERESULT_BLOCKEDBYAVOIDSPOT; + } + continue; + } + //add the travel time towards the area + t += reach.traveltime;// + AAS_AreaTravelTime(areanum, origin, reach.start); + //if the travel time is better than the ones already found + if (!besttime || t < besttime) + { + besttime = t; + bestreachnum = reachnum; + } //end if + } //end for + // + return bestreachnum; +} //end of the function BotGetReachabilityToGoal +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotAddToTarget(vec3_t start, vec3_t end, float maxdist, float *dist, vec3_t target) +{ + vec3_t dir; + float curdist; + + VectorSubtract(end, start, dir); + curdist = VectorNormalize(dir); + if (*dist + curdist < maxdist) + { + VectorCopy(end, target); + *dist += curdist; + return qfalse; + } //end if + else + { + VectorMA(start, maxdist - *dist, dir, target); + *dist = maxdist; + return qtrue; + } //end else +} //end of the function BotAddToTarget + +int BotMovementViewTarget(int movestate, bot_goal_t *goal, int travelflags, float lookahead, vec3_t target) +{ + aas_reachability_t reach; + int reachnum, lastareanum; + bot_movestate_t *ms; + vec3_t end; + float dist; + + ms = BotMoveStateFromHandle(movestate); + if (!ms) return qfalse; + //if the bot has no goal or no last reachability + if (!ms->lastreachnum || !goal) return qfalse; + + reachnum = ms->lastreachnum; + VectorCopy(ms->origin, end); + lastareanum = ms->lastareanum; + dist = 0; + while(reachnum && dist < lookahead) + { + AAS_ReachabilityFromNum(reachnum, &reach); + if (BotAddToTarget(end, reach.start, lookahead, &dist, target)) return qtrue; + //never look beyond teleporters + if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_TELEPORT) return qtrue; + //never look beyond the weapon jump point + if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_ROCKETJUMP) return qtrue; + if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_BFGJUMP) return qtrue; + //don't add jump pad distances + if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_JUMPPAD && + (reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR && + (reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_FUNCBOB) + { + if (BotAddToTarget(reach.start, reach.end, lookahead, &dist, target)) return qtrue; + } //end if + reachnum = BotGetReachabilityToGoal(reach.end, reach.areanum, + ms->lastgoalareanum, lastareanum, + ms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries, + goal, travelflags, NULL, 0, NULL); + VectorCopy(reach.end, end); + lastareanum = reach.areanum; + if (lastareanum == goal->areanum) + { + BotAddToTarget(reach.end, goal->origin, lookahead, &dist, target); + return qtrue; + } //end if + } //end while + // + return qfalse; +} //end of the function BotMovementViewTarget +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotVisible(int ent, vec3_t eye, vec3_t target) +{ + bsp_trace_t trace; + + trace = AAS_Trace(eye, NULL, NULL, target, ent, CONTENTS_SOLID|CONTENTS_PLAYERCLIP); + if (trace.fraction >= 1) return qtrue; + return qfalse; +} //end of the function BotVisible +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotPredictVisiblePosition(vec3_t origin, int areanum, bot_goal_t *goal, int travelflags, vec3_t target) +{ + aas_reachability_t reach; + int reachnum, lastgoalareanum, lastareanum, i; + int avoidreach[MAX_AVOIDREACH]; + float avoidreachtimes[MAX_AVOIDREACH]; + int avoidreachtries[MAX_AVOIDREACH]; + vec3_t end; + + //if the bot has no goal or no last reachability + if (!goal) return qfalse; + //if the areanum is not valid + if (!areanum) return qfalse; + //if the goal areanum is not valid + if (!goal->areanum) return qfalse; + + Com_Memset(avoidreach, 0, MAX_AVOIDREACH * sizeof(int)); + lastgoalareanum = goal->areanum; + lastareanum = areanum; + VectorCopy(origin, end); + //only do 20 hops + for (i = 0; i < 20 && (areanum != goal->areanum); i++) + { + // + reachnum = BotGetReachabilityToGoal(end, areanum, + lastgoalareanum, lastareanum, + avoidreach, avoidreachtimes, avoidreachtries, + goal, travelflags, NULL, 0, NULL); + if (!reachnum) return qfalse; + AAS_ReachabilityFromNum(reachnum, &reach); + // + if (BotVisible(goal->entitynum, goal->origin, reach.start)) + { + VectorCopy(reach.start, target); + return qtrue; + } //end if + // + if (BotVisible(goal->entitynum, goal->origin, reach.end)) + { + VectorCopy(reach.end, target); + return qtrue; + } //end if + // + if (reach.areanum == goal->areanum) + { + VectorCopy(reach.end, target); + return qtrue; + } //end if + // + lastareanum = areanum; + areanum = reach.areanum; + VectorCopy(reach.end, end); + // + } //end while + // + return qfalse; +} //end of the function BotPredictVisiblePosition +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void MoverBottomCenter(aas_reachability_t *reach, vec3_t bottomcenter) +{ + int modelnum; + vec3_t mins, maxs, origin, mids; + vec3_t angles = {0, 0, 0}; + + modelnum = reach->facenum & 0x0000FFFF; + //get some bsp model info + AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin); + // + if (!AAS_OriginOfMoverWithModelNum(modelnum, origin)) + { + botimport.Print(PRT_MESSAGE, "no entity with model %d\n", modelnum); + } //end if + //get a point just above the plat in the bottom position + VectorAdd(mins, maxs, mids); + VectorMA(origin, 0.5, mids, bottomcenter); + bottomcenter[2] = reach->start[2]; +} //end of the function MoverBottomCenter +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float BotGapDistance(vec3_t origin, vec3_t hordir, int entnum) +{ + int dist; + float startz; + vec3_t start, end; + aas_trace_t trace; + + //do gap checking + //startz = origin[2]; + //this enables walking down stairs more fluidly + { + VectorCopy(origin, start); + VectorCopy(origin, end); + end[2] -= 60; + trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, entnum); + if (trace.fraction >= 1) return 1; + startz = trace.endpos[2] + 1; + } + // + for (dist = 8; dist <= 100; dist += 8) + { + VectorMA(origin, dist, hordir, start); + start[2] = startz + 24; + VectorCopy(start, end); + end[2] -= 48 + sv_maxbarrier->value; + trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, entnum); + //if solid is found the bot can't walk any further and fall into a gap + if (!trace.startsolid) + { + //if it is a gap + if (trace.endpos[2] < startz - sv_maxstep->value - 8) + { + VectorCopy(trace.endpos, end); + end[2] -= 20; + if (AAS_PointContents(end) & CONTENTS_WATER) break; + //if a gap is found slow down + //botimport.Print(PRT_MESSAGE, "gap at %i\n", dist); + return dist; + } //end if + startz = trace.endpos[2]; + } //end if + } //end for + return 0; +} //end of the function BotGapDistance +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotCheckBarrierJump(bot_movestate_t *ms, vec3_t dir, float speed) +{ + vec3_t start, hordir, end; + aas_trace_t trace; + + VectorCopy(ms->origin, end); + end[2] += sv_maxbarrier->value; + //trace right up + trace = AAS_TraceClientBBox(ms->origin, end, PRESENCE_NORMAL, ms->entitynum); + //this shouldn't happen... but we check anyway + if (trace.startsolid) return qfalse; + //if very low ceiling it isn't possible to jump up to a barrier + if (trace.endpos[2] - ms->origin[2] < sv_maxstep->value) return qfalse; + // + hordir[0] = dir[0]; + hordir[1] = dir[1]; + hordir[2] = 0; + VectorNormalize(hordir); + VectorMA(ms->origin, ms->thinktime * speed * 0.5, hordir, end); + VectorCopy(trace.endpos, start); + end[2] = trace.endpos[2]; + //trace from previous trace end pos horizontally in the move direction + trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, ms->entitynum); + //again this shouldn't happen + if (trace.startsolid) return qfalse; + // + VectorCopy(trace.endpos, start); + VectorCopy(trace.endpos, end); + end[2] = ms->origin[2]; + //trace down from the previous trace end pos + trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, ms->entitynum); + //if solid + if (trace.startsolid) return qfalse; + //if no obstacle at all + if (trace.fraction >= 1.0) return qfalse; + //if less than the maximum step height + if (trace.endpos[2] - ms->origin[2] < sv_maxstep->value) return qfalse; + // + EA_Jump(ms->client); + EA_Move(ms->client, hordir, speed); + ms->moveflags |= MFL_BARRIERJUMP; + //there is a barrier + return qtrue; +} //end of the function BotCheckBarrierJump +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotSwimInDirection(bot_movestate_t *ms, vec3_t dir, float speed, int type) +{ + vec3_t normdir; + + VectorCopy(dir, normdir); + VectorNormalize(normdir); + EA_Move(ms->client, normdir, speed); + return qtrue; +} //end of the function BotSwimInDirection +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotWalkInDirection(bot_movestate_t *ms, vec3_t dir, float speed, int type) +{ + vec3_t hordir, cmdmove, velocity, tmpdir, origin; + int presencetype, maxframes, cmdframes, stopevent; + aas_clientmove_t move; + float dist; + + if (AAS_OnGround(ms->origin, ms->presencetype, ms->entitynum)) ms->moveflags |= MFL_ONGROUND; + //if the bot is on the ground + if (ms->moveflags & MFL_ONGROUND) + { + //if there is a barrier the bot can jump on + if (BotCheckBarrierJump(ms, dir, speed)) return qtrue; + //remove barrier jump flag + ms->moveflags &= ~MFL_BARRIERJUMP; + //get the presence type for the movement + if ((type & MOVE_CROUCH) && !(type & MOVE_JUMP)) presencetype = PRESENCE_CROUCH; + else presencetype = PRESENCE_NORMAL; + //horizontal direction + hordir[0] = dir[0]; + hordir[1] = dir[1]; + hordir[2] = 0; + VectorNormalize(hordir); + //if the bot is not supposed to jump + if (!(type & MOVE_JUMP)) + { + //if there is a gap, try to jump over it + if (BotGapDistance(ms->origin, hordir, ms->entitynum) > 0) type |= MOVE_JUMP; + } //end if + //get command movement + VectorScale(hordir, speed, cmdmove); + VectorCopy(ms->velocity, velocity); + // + if (type & MOVE_JUMP) + { + //botimport.Print(PRT_MESSAGE, "trying jump\n"); + cmdmove[2] = 400; + maxframes = PREDICTIONTIME_JUMP / 0.1; + cmdframes = 1; + stopevent = SE_HITGROUND|SE_HITGROUNDDAMAGE| + SE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA; + } //end if + else + { + maxframes = 2; + cmdframes = 2; + stopevent = SE_HITGROUNDDAMAGE| + SE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA; + } //end else + //AAS_ClearShownDebugLines(); + // + VectorCopy(ms->origin, origin); + origin[2] += 0.5; + AAS_PredictClientMovement(&move, ms->entitynum, origin, presencetype, qtrue, + velocity, cmdmove, cmdframes, maxframes, 0.1f, + stopevent, 0, qfalse);//qtrue); + //if prediction time wasn't enough to fully predict the movement + if (move.frames >= maxframes && (type & MOVE_JUMP)) + { + //botimport.Print(PRT_MESSAGE, "client %d: max prediction frames\n", ms->client); + return qfalse; + } //end if + //don't enter slime or lava and don't fall from too high + if (move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE)) + { + //botimport.Print(PRT_MESSAGE, "client %d: would be hurt ", ms->client); + //if (move.stopevent & SE_ENTERSLIME) botimport.Print(PRT_MESSAGE, "slime\n"); + //if (move.stopevent & SE_ENTERLAVA) botimport.Print(PRT_MESSAGE, "lava\n"); + //if (move.stopevent & SE_HITGROUNDDAMAGE) botimport.Print(PRT_MESSAGE, "hitground\n"); + return qfalse; + } //end if + //if ground was hit + if (move.stopevent & SE_HITGROUND) + { + //check for nearby gap + VectorNormalize2(move.velocity, tmpdir); + dist = BotGapDistance(move.endpos, tmpdir, ms->entitynum); + if (dist > 0) return qfalse; + // + dist = BotGapDistance(move.endpos, hordir, ms->entitynum); + if (dist > 0) return qfalse; + } //end if + //get horizontal movement + tmpdir[0] = move.endpos[0] - ms->origin[0]; + tmpdir[1] = move.endpos[1] - ms->origin[1]; + tmpdir[2] = 0; + // + //AAS_DrawCross(move.endpos, 4, LINECOLOR_BLUE); + //the bot is blocked by something + if (VectorLength(tmpdir) < speed * ms->thinktime * 0.5) return qfalse; + //perform the movement + if (type & MOVE_JUMP) EA_Jump(ms->client); + if (type & MOVE_CROUCH) EA_Crouch(ms->client); + EA_Move(ms->client, hordir, speed); + //movement was succesfull + return qtrue; + } //end if + else + { + if (ms->moveflags & MFL_BARRIERJUMP) + { + //if near the top or going down + if (ms->velocity[2] < 50) + { + EA_Move(ms->client, dir, speed); + } //end if + } //end if + //FIXME: do air control to avoid hazards + return qtrue; + } //end else +} //end of the function BotWalkInDirection +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotMoveInDirection(int movestate, vec3_t dir, float speed, int type) +{ + bot_movestate_t *ms; + + ms = BotMoveStateFromHandle(movestate); + if (!ms) return qfalse; + //if swimming + if (AAS_Swimming(ms->origin)) + { + return BotSwimInDirection(ms, dir, speed, type); + } //end if + else + { + return BotWalkInDirection(ms, dir, speed, type); + } //end else +} //end of the function BotMoveInDirection +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int Intersection(vec2_t p1, vec2_t p2, vec2_t p3, vec2_t p4, vec2_t out) +{ + float x1, dx1, dy1, x2, dx2, dy2, d; + + dx1 = p2[0] - p1[0]; + dy1 = p2[1] - p1[1]; + dx2 = p4[0] - p3[0]; + dy2 = p4[1] - p3[1]; + + d = dy1 * dx2 - dx1 * dy2; + if (d != 0) + { + x1 = p1[1] * dx1 - p1[0] * dy1; + x2 = p3[1] * dx2 - p3[0] * dy2; + out[0] = (int) ((dx1 * x2 - dx2 * x1) / d); + out[1] = (int) ((dy1 * x2 - dy2 * x1) / d); + return qtrue; + } //end if + else + { + return qfalse; + } //end else +} //end of the function Intersection +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotCheckBlocked(bot_movestate_t *ms, vec3_t dir, int checkbottom, bot_moveresult_t *result) +{ + vec3_t mins, maxs, end, up = {0, 0, 1}; + bsp_trace_t trace; + + //test for entities obstructing the bot's path + AAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs); + // + if (fabs(DotProduct(dir, up)) < 0.7) + { + mins[2] += sv_maxstep->value; //if the bot can step on + maxs[2] -= 10; //a little lower to avoid low ceiling + } //end if + VectorMA(ms->origin, 3, dir, end); + trace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_BODY); + //if not started in solid and not hitting the world entity + if (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) ) + { + result->blocked = qtrue; + result->blockentity = trace.ent; +#ifdef DEBUG + //botimport.Print(PRT_MESSAGE, "%d: BotCheckBlocked: I'm blocked\n", ms->client); +#endif //DEBUG + } //end if + //if not in an area with reachability + else if (checkbottom && !AAS_AreaReachability(ms->areanum)) + { + //check if the bot is standing on something + AAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs); + VectorMA(ms->origin, -3, up, end); + trace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP); + if (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) ) + { + result->blocked = qtrue; + result->blockentity = trace.ent; + result->flags |= MOVERESULT_ONTOPOFOBSTACLE; +#ifdef DEBUG + //botimport.Print(PRT_MESSAGE, "%d: BotCheckBlocked: I'm blocked\n", ms->client); +#endif //DEBUG + } //end if + } //end else +} //end of the function BotCheckBlocked +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_Walk(bot_movestate_t *ms, aas_reachability_t *reach) +{ + float dist, speed; + vec3_t hordir; + bot_moveresult_t_cleared( result ); + + //first walk straight to the reachability start + hordir[0] = reach->start[0] - ms->origin[0]; + hordir[1] = reach->start[1] - ms->origin[1]; + hordir[2] = 0; + dist = VectorNormalize(hordir); + // + BotCheckBlocked(ms, hordir, qtrue, &result); + // + if (dist < 10) + { + //walk straight to the reachability end + hordir[0] = reach->end[0] - ms->origin[0]; + hordir[1] = reach->end[1] - ms->origin[1]; + hordir[2] = 0; + dist = VectorNormalize(hordir); + } //end if + //if going towards a crouch area + if (!(AAS_AreaPresenceType(reach->areanum) & PRESENCE_NORMAL)) + { + //if pretty close to the reachable area + if (dist < 20) EA_Crouch(ms->client); + } //end if + // + dist = BotGapDistance(ms->origin, hordir, ms->entitynum); + // + if (ms->moveflags & MFL_WALK) + { + if (dist > 0) speed = 200 - (180 - 1 * dist); + else speed = 200; + EA_Walk(ms->client); + } //end if + else + { + if (dist > 0) speed = 400 - (360 - 2 * dist); + else speed = 400; + } //end else + //elemantary action move in direction + EA_Move(ms->client, hordir, speed); + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotTravel_Walk +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotFinishTravel_Walk(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t hordir; + float dist, speed; + bot_moveresult_t_cleared( result ); + //if not on the ground and changed areas... don't walk back!! + //(doesn't seem to help) + /* + ms->areanum = BotFuzzyPointReachabilityArea(ms->origin); + if (ms->areanum == reach->areanum) + { +#ifdef DEBUG + botimport.Print(PRT_MESSAGE, "BotFinishTravel_Walk: already in reach area\n"); +#endif //DEBUG + return result; + } //end if*/ + //go straight to the reachability end + hordir[0] = reach->end[0] - ms->origin[0]; + hordir[1] = reach->end[1] - ms->origin[1]; + hordir[2] = 0; + dist = VectorNormalize(hordir); + // + if (dist > 100) dist = 100; + speed = 400 - (400 - 3 * dist); + // + EA_Move(ms->client, hordir, speed); + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotFinishTravel_Walk +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_Crouch(bot_movestate_t *ms, aas_reachability_t *reach) +{ + float speed; + vec3_t hordir; + bot_moveresult_t_cleared( result ); + + // + speed = 400; + //walk straight to reachability end + hordir[0] = reach->end[0] - ms->origin[0]; + hordir[1] = reach->end[1] - ms->origin[1]; + hordir[2] = 0; + VectorNormalize(hordir); + // + BotCheckBlocked(ms, hordir, qtrue, &result); + //elemantary actions + EA_Crouch(ms->client); + EA_Move(ms->client, hordir, speed); + // + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotTravel_Crouch +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_BarrierJump(bot_movestate_t *ms, aas_reachability_t *reach) +{ + float dist, speed; + vec3_t hordir; + bot_moveresult_t_cleared( result ); + + //walk straight to reachability start + hordir[0] = reach->start[0] - ms->origin[0]; + hordir[1] = reach->start[1] - ms->origin[1]; + hordir[2] = 0; + dist = VectorNormalize(hordir); + // + BotCheckBlocked(ms, hordir, qtrue, &result); + //if pretty close to the barrier + if (dist < 9) + { + EA_Jump(ms->client); + } //end if + else + { + if (dist > 60) dist = 60; + speed = 360 - (360 - 6 * dist); + EA_Move(ms->client, hordir, speed); + } //end else + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotTravel_BarrierJump +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotFinishTravel_BarrierJump(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t hordir; + bot_moveresult_t_cleared( result ); + + //if near the top or going down + if (ms->velocity[2] < 250) + { + hordir[0] = reach->end[0] - ms->origin[0]; + hordir[1] = reach->end[1] - ms->origin[1]; + hordir[2] = 0; + // + BotCheckBlocked(ms, hordir, qtrue, &result); + // + EA_Move(ms->client, hordir, 400); + VectorCopy(hordir, result.movedir); + } //end if + // + return result; +} //end of the function BotFinishTravel_BarrierJump +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_Swim(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t dir; + bot_moveresult_t_cleared( result ); + + //swim straight to reachability end + VectorSubtract(reach->start, ms->origin, dir); + VectorNormalize(dir); + // + BotCheckBlocked(ms, dir, qtrue, &result); + //elemantary actions + EA_Move(ms->client, dir, 400); + // + VectorCopy(dir, result.movedir); + Vector2Angles(dir, result.ideal_viewangles); + result.flags |= MOVERESULT_SWIMVIEW; + // + return result; +} //end of the function BotTravel_Swim +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_WaterJump(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t dir, hordir; + float dist; + bot_moveresult_t_cleared( result ); + + //swim straight to reachability end + VectorSubtract(reach->end, ms->origin, dir); + VectorCopy(dir, hordir); + hordir[2] = 0; + dir[2] += 15 + Q_flrand(-1.0f, 1.0f) * 40; + //botimport.Print(PRT_MESSAGE, "BotTravel_WaterJump: dir[2] = %f\n", dir[2]); + VectorNormalize(dir); + dist = VectorNormalize(hordir); + //elemantary actions + //EA_Move(ms->client, dir, 400); + EA_MoveForward(ms->client); + //move up if close to the actual out of water jump spot + if (dist < 40) EA_MoveUp(ms->client); + //set the ideal view angles + Vector2Angles(dir, result.ideal_viewangles); + result.flags |= MOVERESULT_MOVEMENTVIEW; + // + VectorCopy(dir, result.movedir); + // + return result; +} //end of the function BotTravel_WaterJump +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotFinishTravel_WaterJump(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t dir, pnt; + bot_moveresult_t_cleared( result ); + + //botimport.Print(PRT_MESSAGE, "BotFinishTravel_WaterJump\n"); + //if waterjumping there's nothing to do + if (ms->moveflags & MFL_WATERJUMP) return result; + //if not touching any water anymore don't do anything + //otherwise the bot sometimes keeps jumping? + VectorCopy(ms->origin, pnt); + pnt[2] -= 32; //extra for q2dm4 near red armor/mega health + if (!(AAS_PointContents(pnt) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER))) return result; + //swim straight to reachability end + VectorSubtract(reach->end, ms->origin, dir); + dir[0] += Q_flrand(-1.0f, 1.0f) * 10; + dir[1] += Q_flrand(-1.0f, 1.0f) * 10; + dir[2] += 70 + Q_flrand(-1.0f, 1.0f) * 10; + //elemantary actions + EA_Move(ms->client, dir, 400); + //set the ideal view angles + Vector2Angles(dir, result.ideal_viewangles); + result.flags |= MOVERESULT_MOVEMENTVIEW; + // + VectorCopy(dir, result.movedir); + // + return result; +} //end of the function BotFinishTravel_WaterJump +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_WalkOffLedge(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t hordir, dir; + float dist, speed, reachhordist; + bot_moveresult_t_cleared( result ); + + //check if the bot is blocked by anything + VectorSubtract(reach->start, ms->origin, dir); + VectorNormalize(dir); + BotCheckBlocked(ms, dir, qtrue, &result); + //if the reachability start and end are practially above each other + VectorSubtract(reach->end, reach->start, dir); + dir[2] = 0; + reachhordist = VectorLength(dir); + //walk straight to the reachability start + hordir[0] = reach->start[0] - ms->origin[0]; + hordir[1] = reach->start[1] - ms->origin[1]; + hordir[2] = 0; + dist = VectorNormalize(hordir); + //if pretty close to the start focus on the reachability end + if (dist < 48) + { + hordir[0] = reach->end[0] - ms->origin[0]; + hordir[1] = reach->end[1] - ms->origin[1]; + hordir[2] = 0; + VectorNormalize(hordir); + // + if (reachhordist < 20) + { + speed = 100; + } //end if + else if (!AAS_HorizontalVelocityForJump(0, reach->start, reach->end, &speed)) + { + speed = 400; + } //end if + } //end if + else + { + if (reachhordist < 20) + { + if (dist > 64) dist = 64; + speed = 400 - (256 - 4 * dist); + } //end if + else + { + speed = 400; + } //end else + } //end else + // + BotCheckBlocked(ms, hordir, qtrue, &result); + //elemantary action + EA_Move(ms->client, hordir, speed); + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotTravel_WalkOffLedge +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotAirControl(vec3_t origin, vec3_t velocity, vec3_t goal, vec3_t dir, float *speed) +{ + vec3_t org, vel; + float dist; + int i; + + VectorCopy(origin, org); + VectorScale(velocity, 0.1, vel); + for (i = 0; i < 50; i++) + { + vel[2] -= sv_gravity->value * 0.01; + //if going down and next position would be below the goal + if (vel[2] < 0 && org[2] + vel[2] < goal[2]) + { + VectorScale(vel, (goal[2] - org[2]) / vel[2], vel); + VectorAdd(org, vel, org); + VectorSubtract(goal, org, dir); + dist = VectorNormalize(dir); + if (dist > 32) dist = 32; + *speed = 400 - (400 - 13 * dist); + return qtrue; + } //end if + else + { + VectorAdd(org, vel, org); + } //end else + } //end for + VectorSet(dir, 0, 0, 0); + *speed = 400; + return qfalse; +} //end of the function BotAirControl +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotFinishTravel_WalkOffLedge(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t dir, hordir, end, v; + float dist, speed; + bot_moveresult_t_cleared( result ); + + // + VectorSubtract(reach->end, ms->origin, dir); + BotCheckBlocked(ms, dir, qtrue, &result); + // + VectorSubtract(reach->end, ms->origin, v); + v[2] = 0; + dist = VectorNormalize(v); + if (dist > 16) VectorMA(reach->end, 16, v, end); + else VectorCopy(reach->end, end); + // + if (!BotAirControl(ms->origin, ms->velocity, end, hordir, &speed)) + { + //go straight to the reachability end + VectorCopy(dir, hordir); + hordir[2] = 0; + // + speed = 400; + } //end if + // + EA_Move(ms->client, hordir, speed); + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotFinishTravel_WalkOffLedge +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +/* +bot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t hordir; + float dist, gapdist, speed, horspeed, sv_jumpvel; + bot_moveresult_t_cleared( result ); + + // + sv_jumpvel = botlibglobals.sv_jumpvel->value; + //walk straight to the reachability start + hordir[0] = reach->start[0] - ms->origin[0]; + hordir[1] = reach->start[1] - ms->origin[1]; + hordir[2] = 0; + dist = VectorNormalize(hordir); + // + speed = 350; + // + gapdist = BotGapDistance(ms, hordir, ms->entitynum); + //if pretty close to the start focus on the reachability end + if (dist < 50 || (gapdist && gapdist < 50)) + { + //NOTE: using max speed (400) works best + //if (AAS_HorizontalVelocityForJump(sv_jumpvel, ms->origin, reach->end, &horspeed)) + //{ + // speed = horspeed * 400 / botlibglobals.sv_maxwalkvelocity->value; + //} //end if + hordir[0] = reach->end[0] - ms->origin[0]; + hordir[1] = reach->end[1] - ms->origin[1]; + VectorNormalize(hordir); + //elemantary action jump + EA_Jump(ms->client); + // + ms->jumpreach = ms->lastreachnum; + speed = 600; + } //end if + else + { + if (AAS_HorizontalVelocityForJump(sv_jumpvel, reach->start, reach->end, &horspeed)) + { + speed = horspeed * 400 / botlibglobals.sv_maxwalkvelocity->value; + } //end if + } //end else + //elemantary action + EA_Move(ms->client, hordir, speed); + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotTravel_Jump*/ +/* +bot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t hordir, dir1, dir2, mins, maxs, start, end; + int gapdist; + float dist1, dist2, speed; + bot_moveresult_t_cleared( result ); + bsp_trace_t trace; + + // + hordir[0] = reach->start[0] - reach->end[0]; + hordir[1] = reach->start[1] - reach->end[1]; + hordir[2] = 0; + VectorNormalize(hordir); + // + VectorCopy(reach->start, start); + start[2] += 1; + //minus back the bouding box size plus 16 + VectorMA(reach->start, 80, hordir, end); + // + AAS_PresenceTypeBoundingBox(PRESENCE_NORMAL, mins, maxs); + //check for solids + trace = AAS_Trace(start, mins, maxs, end, ms->entitynum, MASK_PLAYERSOLID); + if (trace.startsolid) VectorCopy(start, trace.endpos); + //check for a gap + for (gapdist = 0; gapdist < 80; gapdist += 10) + { + VectorMA(start, gapdist+10, hordir, end); + end[2] += 1; + if (AAS_PointAreaNum(end) != ms->reachareanum) break; + } //end for + if (gapdist < 80) VectorMA(reach->start, gapdist, hordir, trace.endpos); +// dist1 = BotGapDistance(start, hordir, ms->entitynum); +// if (dist1 && dist1 <= trace.fraction * 80) VectorMA(reach->start, dist1-20, hordir, trace.endpos); + // + VectorSubtract(ms->origin, reach->start, dir1); + dir1[2] = 0; + dist1 = VectorNormalize(dir1); + VectorSubtract(ms->origin, trace.endpos, dir2); + dir2[2] = 0; + dist2 = VectorNormalize(dir2); + //if just before the reachability start + if (DotProduct(dir1, dir2) < -0.8 || dist2 < 5) + { + //botimport.Print(PRT_MESSAGE, "between jump start and run to point\n"); + hordir[0] = reach->end[0] - ms->origin[0]; + hordir[1] = reach->end[1] - ms->origin[1]; + hordir[2] = 0; + VectorNormalize(hordir); + //elemantary action jump + if (dist1 < 24) EA_Jump(ms->client); + else if (dist1 < 32) EA_DelayedJump(ms->client); + EA_Move(ms->client, hordir, 600); + // + ms->jumpreach = ms->lastreachnum; + } //end if + else + { + //botimport.Print(PRT_MESSAGE, "going towards run to point\n"); + hordir[0] = trace.endpos[0] - ms->origin[0]; + hordir[1] = trace.endpos[1] - ms->origin[1]; + hordir[2] = 0; + VectorNormalize(hordir); + // + if (dist2 > 80) dist2 = 80; + speed = 400 - (400 - 5 * dist2); + EA_Move(ms->client, hordir, speed); + } //end else + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotTravel_Jump*/ +//* +bot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t hordir, dir1, dir2, start, end, runstart; +// vec3_t runstart, dir1, dir2, hordir; + int gapdist; + float dist1, dist2, speed; + bot_moveresult_t_cleared( result ); + + // + AAS_JumpReachRunStart(reach, runstart); + //* + hordir[0] = runstart[0] - reach->start[0]; + hordir[1] = runstart[1] - reach->start[1]; + hordir[2] = 0; + VectorNormalize(hordir); + // + VectorCopy(reach->start, start); + start[2] += 1; + VectorMA(reach->start, 80, hordir, runstart); + //check for a gap + for (gapdist = 0; gapdist < 80; gapdist += 10) + { + VectorMA(start, gapdist+10, hordir, end); + end[2] += 1; + if (AAS_PointAreaNum(end) != ms->reachareanum) break; + } //end for + if (gapdist < 80) VectorMA(reach->start, gapdist, hordir, runstart); + // + VectorSubtract(ms->origin, reach->start, dir1); + dir1[2] = 0; + dist1 = VectorNormalize(dir1); + VectorSubtract(ms->origin, runstart, dir2); + dir2[2] = 0; + dist2 = VectorNormalize(dir2); + //if just before the reachability start + if (DotProduct(dir1, dir2) < -0.8 || dist2 < 5) + { +// botimport.Print(PRT_MESSAGE, "between jump start and run start point\n"); + hordir[0] = reach->end[0] - ms->origin[0]; + hordir[1] = reach->end[1] - ms->origin[1]; + hordir[2] = 0; + VectorNormalize(hordir); + //elemantary action jump + if (dist1 < 24) EA_Jump(ms->client); + else if (dist1 < 32) EA_DelayedJump(ms->client); + EA_Move(ms->client, hordir, 600); + // + ms->jumpreach = ms->lastreachnum; + } //end if + else + { +// botimport.Print(PRT_MESSAGE, "going towards run start point\n"); + hordir[0] = runstart[0] - ms->origin[0]; + hordir[1] = runstart[1] - ms->origin[1]; + hordir[2] = 0; + VectorNormalize(hordir); + // + if (dist2 > 80) dist2 = 80; + speed = 400 - (400 - 5 * dist2); + EA_Move(ms->client, hordir, speed); + } //end else + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotTravel_Jump*/ +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotFinishTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t hordir, hordir2; + float speed, dist; + bot_moveresult_t_cleared( result ); + + //if not jumped yet + if (!ms->jumpreach) return result; + //go straight to the reachability end + hordir[0] = reach->end[0] - ms->origin[0]; + hordir[1] = reach->end[1] - ms->origin[1]; + hordir[2] = 0; + dist = VectorNormalize(hordir); + // + hordir2[0] = reach->end[0] - reach->start[0]; + hordir2[1] = reach->end[1] - reach->start[1]; + hordir2[2] = 0; + VectorNormalize(hordir2); + // + if (DotProduct(hordir, hordir2) < -0.5 && dist < 24) return result; + //always use max speed when traveling through the air + speed = 800; + // + EA_Move(ms->client, hordir, speed); + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotFinishTravel_Jump +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_Ladder(bot_movestate_t *ms, aas_reachability_t *reach) +{ + //float dist, speed; + vec3_t dir, viewdir;//, hordir; + vec3_t origin = {0, 0, 0}; +// vec3_t up = {0, 0, 1}; + bot_moveresult_t_cleared( result ); + + // +// if ((ms->moveflags & MFL_AGAINSTLADDER)) + //NOTE: not a good idea for ladders starting in water + // || !(ms->moveflags & MFL_ONGROUND)) + { + //botimport.Print(PRT_MESSAGE, "against ladder or not on ground\n"); + VectorSubtract(reach->end, ms->origin, dir); + VectorNormalize(dir); + //set the ideal view angles, facing the ladder up or down + viewdir[0] = dir[0]; + viewdir[1] = dir[1]; + viewdir[2] = 3 * dir[2]; + Vector2Angles(viewdir, result.ideal_viewangles); + //elemantary action + EA_Move(ms->client, origin, 0); + EA_MoveForward(ms->client); + //set movement view flag so the AI can see the view is focussed + result.flags |= MOVERESULT_MOVEMENTVIEW; + } //end if +/* else + { + //botimport.Print(PRT_MESSAGE, "moving towards ladder\n"); + VectorSubtract(reach->end, ms->origin, dir); + //make sure the horizontal movement is large enough + VectorCopy(dir, hordir); + hordir[2] = 0; + dist = VectorNormalize(hordir); + // + dir[0] = hordir[0]; + dir[1] = hordir[1]; + if (dir[2] > 0) dir[2] = 1; + else dir[2] = -1; + if (dist > 50) dist = 50; + speed = 400 - (200 - 4 * dist); + EA_Move(ms->client, dir, speed); + } //end else*/ + //save the movement direction + VectorCopy(dir, result.movedir); + // + return result; +} //end of the function BotTravel_Ladder +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_Teleport(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t hordir; + float dist; + bot_moveresult_t_cleared( result ); + + //if the bot is being teleported + if (ms->moveflags & MFL_TELEPORTED) return result; + + //walk straight to center of the teleporter + VectorSubtract(reach->start, ms->origin, hordir); + if (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0; + dist = VectorNormalize(hordir); + // + BotCheckBlocked(ms, hordir, qtrue, &result); + + if (dist < 30) EA_Move(ms->client, hordir, 200); + else EA_Move(ms->client, hordir, 400); + + if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; + + VectorCopy(hordir, result.movedir); + return result; +} //end of the function BotTravel_Teleport +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_Elevator(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t dir, dir1, dir2, hordir, bottomcenter; + float dist, dist1, dist2, speed; + bot_moveresult_t_cleared( result ); + + //if standing on the plat + if (BotOnMover(ms->origin, ms->entitynum, reach)) + { +#ifdef DEBUG_ELEVATOR + botimport.Print(PRT_MESSAGE, "bot on elevator\n"); +#endif //DEBUG_ELEVATOR + //if vertically not too far from the end point + if (fabs(ms->origin[2] - reach->end[2]) < sv_maxbarrier->value) + { +#ifdef DEBUG_ELEVATOR + botimport.Print(PRT_MESSAGE, "bot moving to end\n"); +#endif //DEBUG_ELEVATOR + //move to the end point + VectorSubtract(reach->end, ms->origin, hordir); + hordir[2] = 0; + VectorNormalize(hordir); + if (!BotCheckBarrierJump(ms, hordir, 100)) + { + EA_Move(ms->client, hordir, 400); + } //end if + VectorCopy(hordir, result.movedir); + } //end else + //if not really close to the center of the elevator + else + { + MoverBottomCenter(reach, bottomcenter); + VectorSubtract(bottomcenter, ms->origin, hordir); + hordir[2] = 0; + dist = VectorNormalize(hordir); + // + if (dist > 10) + { +#ifdef DEBUG_ELEVATOR + botimport.Print(PRT_MESSAGE, "bot moving to center\n"); +#endif //DEBUG_ELEVATOR + //move to the center of the plat + if (dist > 100) dist = 100; + speed = 400 - (400 - 4 * dist); + // + EA_Move(ms->client, hordir, speed); + VectorCopy(hordir, result.movedir); + } //end if + } //end else + } //end if + else + { +#ifdef DEBUG_ELEVATOR + botimport.Print(PRT_MESSAGE, "bot not on elevator\n"); +#endif //DEBUG_ELEVATOR + //if very near the reachability end + VectorSubtract(reach->end, ms->origin, dir); + dist = VectorLength(dir); + if (dist < 64) + { + if (dist > 60) dist = 60; + speed = 360 - (360 - 6 * dist); + // + if ((ms->moveflags & MFL_SWIMMING) || !BotCheckBarrierJump(ms, dir, 50)) + { + if (speed > 5) EA_Move(ms->client, dir, speed); + } //end if + VectorCopy(dir, result.movedir); + // + if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; + //stop using this reachability + ms->reachability_time = 0; + return result; + } //end if + //get direction and distance to reachability start + VectorSubtract(reach->start, ms->origin, dir1); + if (!(ms->moveflags & MFL_SWIMMING)) dir1[2] = 0; + dist1 = VectorNormalize(dir1); + //if the elevator isn't down + if (!MoverDown(reach)) + { +#ifdef DEBUG_ELEVATOR + botimport.Print(PRT_MESSAGE, "elevator not down\n"); +#endif //DEBUG_ELEVATOR + dist = dist1; + VectorCopy(dir1, dir); + // + BotCheckBlocked(ms, dir, qfalse, &result); + // + if (dist > 60) dist = 60; + speed = 360 - (360 - 6 * dist); + // + if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50)) + { + if (speed > 5) EA_Move(ms->client, dir, speed); + } //end if + VectorCopy(dir, result.movedir); + // + if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; + //this isn't a failure... just wait till the elevator comes down + result.type = RESULTTYPE_ELEVATORUP; + result.flags |= MOVERESULT_WAITING; + return result; + } //end if + //get direction and distance to elevator bottom center + MoverBottomCenter(reach, bottomcenter); + VectorSubtract(bottomcenter, ms->origin, dir2); + if (!(ms->moveflags & MFL_SWIMMING)) dir2[2] = 0; + dist2 = VectorNormalize(dir2); + //if very close to the reachability start or + //closer to the elevator center or + //between reachability start and elevator center + if (dist1 < 20 || dist2 < dist1 || DotProduct(dir1, dir2) < 0) + { +#ifdef DEBUG_ELEVATOR + botimport.Print(PRT_MESSAGE, "bot moving to center\n"); +#endif //DEBUG_ELEVATOR + dist = dist2; + VectorCopy(dir2, dir); + } //end if + else //closer to the reachability start + { +#ifdef DEBUG_ELEVATOR + botimport.Print(PRT_MESSAGE, "bot moving to start\n"); +#endif //DEBUG_ELEVATOR + dist = dist1; + VectorCopy(dir1, dir); + } //end else + // + BotCheckBlocked(ms, dir, qfalse, &result); + // + if (dist > 60) dist = 60; + speed = 400 - (400 - 6 * dist); + // + if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50)) + { + EA_Move(ms->client, dir, speed); + } //end if + VectorCopy(dir, result.movedir); + // + if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; + } //end else + return result; +} //end of the function BotTravel_Elevator +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotFinishTravel_Elevator(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t bottomcenter, bottomdir, topdir; + bot_moveresult_t_cleared( result ); + + // + MoverBottomCenter(reach, bottomcenter); + VectorSubtract(bottomcenter, ms->origin, bottomdir); + // + VectorSubtract(reach->end, ms->origin, topdir); + // + if (fabs(bottomdir[2]) < fabs(topdir[2])) + { + VectorNormalize(bottomdir); + EA_Move(ms->client, bottomdir, 300); + } //end if + else + { + VectorNormalize(topdir); + EA_Move(ms->client, topdir, 300); + } //end else + return result; +} //end of the function BotFinishTravel_Elevator +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotFuncBobStartEnd(aas_reachability_t *reach, vec3_t start, vec3_t end, vec3_t origin) +{ + int spawnflags, modelnum; + vec3_t mins, maxs, mid, angles = {0, 0, 0}; + int num0, num1; + + modelnum = reach->facenum & 0x0000FFFF; + if (!AAS_OriginOfMoverWithModelNum(modelnum, origin)) + { + botimport.Print(PRT_MESSAGE, "BotFuncBobStartEnd: no entity with model %d\n", modelnum); + VectorSet(start, 0, 0, 0); + VectorSet(end, 0, 0, 0); + return; + } //end if + AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, NULL); + VectorAdd(mins, maxs, mid); + VectorScale(mid, 0.5, mid); + VectorCopy(mid, start); + VectorCopy(mid, end); + spawnflags = reach->facenum >> 16; + num0 = reach->edgenum >> 16; + if (num0 > 0x00007FFF) num0 |= 0xFFFF0000; + num1 = reach->edgenum & 0x0000FFFF; + if (num1 > 0x00007FFF) num1 |= 0xFFFF0000; + if (spawnflags & 1) + { + start[0] = num0; + end[0] = num1; + // + origin[0] += mid[0]; + origin[1] = mid[1]; + origin[2] = mid[2]; + } //end if + else if (spawnflags & 2) + { + start[1] = num0; + end[1] = num1; + // + origin[0] = mid[0]; + origin[1] += mid[1]; + origin[2] = mid[2]; + } //end else if + else + { + start[2] = num0; + end[2] = num1; + // + origin[0] = mid[0]; + origin[1] = mid[1]; + origin[2] += mid[2]; + } //end else +} //end of the function BotFuncBobStartEnd +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_FuncBobbing(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t dir, dir1, dir2, hordir, bottomcenter, bob_start, bob_end, bob_origin; + float dist, dist1, dist2, speed; + bot_moveresult_t_cleared( result ); + + // + BotFuncBobStartEnd(reach, bob_start, bob_end, bob_origin); + //if standing ontop of the func_bobbing + if (BotOnMover(ms->origin, ms->entitynum, reach)) + { +#ifdef DEBUG_FUNCBOB + botimport.Print(PRT_MESSAGE, "bot on func_bobbing\n"); +#endif + //if near end point of reachability + VectorSubtract(bob_origin, bob_end, dir); + if (VectorLength(dir) < 24) + { +#ifdef DEBUG_FUNCBOB + botimport.Print(PRT_MESSAGE, "bot moving to reachability end\n"); +#endif + //move to the end point + VectorSubtract(reach->end, ms->origin, hordir); + hordir[2] = 0; + VectorNormalize(hordir); + if (!BotCheckBarrierJump(ms, hordir, 100)) + { + EA_Move(ms->client, hordir, 400); + } //end if + VectorCopy(hordir, result.movedir); + } //end else + //if not really close to the center of the elevator + else + { + MoverBottomCenter(reach, bottomcenter); + VectorSubtract(bottomcenter, ms->origin, hordir); + hordir[2] = 0; + dist = VectorNormalize(hordir); + // + if (dist > 10) + { +#ifdef DEBUG_FUNCBOB + botimport.Print(PRT_MESSAGE, "bot moving to func_bobbing center\n"); +#endif + //move to the center of the plat + if (dist > 100) dist = 100; + speed = 400 - (400 - 4 * dist); + // + EA_Move(ms->client, hordir, speed); + VectorCopy(hordir, result.movedir); + } //end if + } //end else + } //end if + else + { +#ifdef DEBUG_FUNCBOB + botimport.Print(PRT_MESSAGE, "bot not ontop of func_bobbing\n"); +#endif + //if very near the reachability end + VectorSubtract(reach->end, ms->origin, dir); + dist = VectorLength(dir); + if (dist < 64) + { +#ifdef DEBUG_FUNCBOB + botimport.Print(PRT_MESSAGE, "bot moving to end\n"); +#endif + if (dist > 60) dist = 60; + speed = 360 - (360 - 6 * dist); + //if swimming or no barrier jump + if ((ms->moveflags & MFL_SWIMMING) || !BotCheckBarrierJump(ms, dir, 50)) + { + if (speed > 5) EA_Move(ms->client, dir, speed); + } //end if + VectorCopy(dir, result.movedir); + // + if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; + //stop using this reachability + ms->reachability_time = 0; + return result; + } //end if + //get direction and distance to reachability start + VectorSubtract(reach->start, ms->origin, dir1); + if (!(ms->moveflags & MFL_SWIMMING)) dir1[2] = 0; + dist1 = VectorNormalize(dir1); + //if func_bobbing is Not its start position + VectorSubtract(bob_origin, bob_start, dir); + if (VectorLength(dir) > 16) + { +#ifdef DEBUG_FUNCBOB + botimport.Print(PRT_MESSAGE, "func_bobbing not at start\n"); +#endif + dist = dist1; + VectorCopy(dir1, dir); + // + BotCheckBlocked(ms, dir, qfalse, &result); + // + if (dist > 60) dist = 60; + speed = 360 - (360 - 6 * dist); + // + if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50)) + { + if (speed > 5) EA_Move(ms->client, dir, speed); + } //end if + VectorCopy(dir, result.movedir); + // + if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; + //this isn't a failure... just wait till the func_bobbing arrives + result.type = RESULTTYPE_WAITFORFUNCBOBBING; + result.flags |= MOVERESULT_WAITING; + return result; + } //end if + //get direction and distance to func_bob bottom center + MoverBottomCenter(reach, bottomcenter); + VectorSubtract(bottomcenter, ms->origin, dir2); + if (!(ms->moveflags & MFL_SWIMMING)) dir2[2] = 0; + dist2 = VectorNormalize(dir2); + //if very close to the reachability start or + //closer to the elevator center or + //between reachability start and func_bobbing center + if (dist1 < 20 || dist2 < dist1 || DotProduct(dir1, dir2) < 0) + { +#ifdef DEBUG_FUNCBOB + botimport.Print(PRT_MESSAGE, "bot moving to func_bobbing center\n"); +#endif + dist = dist2; + VectorCopy(dir2, dir); + } //end if + else //closer to the reachability start + { +#ifdef DEBUG_FUNCBOB + botimport.Print(PRT_MESSAGE, "bot moving to reachability start\n"); +#endif + dist = dist1; + VectorCopy(dir1, dir); + } //end else + // + BotCheckBlocked(ms, dir, qfalse, &result); + // + if (dist > 60) dist = 60; + speed = 400 - (400 - 6 * dist); + // + if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50)) + { + EA_Move(ms->client, dir, speed); + } //end if + VectorCopy(dir, result.movedir); + // + if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; + } //end else + return result; +} //end of the function BotTravel_FuncBobbing +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotFinishTravel_FuncBobbing(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t bob_origin, bob_start, bob_end, dir, hordir, bottomcenter; + bot_moveresult_t_cleared( result ); + float dist, speed; + + // + BotFuncBobStartEnd(reach, bob_start, bob_end, bob_origin); + // + VectorSubtract(bob_origin, bob_end, dir); + dist = VectorLength(dir); + //if the func_bobbing is near the end + if (dist < 16) + { + VectorSubtract(reach->end, ms->origin, hordir); + if (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0; + dist = VectorNormalize(hordir); + // + if (dist > 60) dist = 60; + speed = 360 - (360 - 6 * dist); + // + if (speed > 5) EA_Move(ms->client, dir, speed); + VectorCopy(dir, result.movedir); + // + if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; + } //end if + else + { + MoverBottomCenter(reach, bottomcenter); + VectorSubtract(bottomcenter, ms->origin, hordir); + if (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0; + dist = VectorNormalize(hordir); + // + if (dist > 5) + { + //move to the center of the plat + if (dist > 100) dist = 100; + speed = 400 - (400 - 4 * dist); + // + EA_Move(ms->client, hordir, speed); + VectorCopy(hordir, result.movedir); + } //end if + } //end else + return result; +} //end of the function BotFinishTravel_FuncBobbing +//=========================================================================== +// 0 no valid grapple hook visible +// 1 the grapple hook is still flying +// 2 the grapple hooked into a wall +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int GrappleState(bot_movestate_t *ms, aas_reachability_t *reach) +{ + int i; + aas_entityinfo_t entinfo; + + //if the grapple hook is pulling + if (ms->moveflags & MFL_GRAPPLEPULL) + return 2; + //check for a visible grapple missile entity + //or visible grapple entity + for (i = AAS_NextEntity(0); i; i = AAS_NextEntity(i)) + { + if (AAS_EntityType(i) == (int) entitytypemissile->value) + { + AAS_EntityInfo(i, &entinfo); + if (entinfo.weapon == (int) weapindex_grapple->value) + { + return 1; + } //end if + } //end if + } //end for + //no valid grapple at all + return 0; +} //end of the function GrappleState +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotResetGrapple(bot_movestate_t *ms) +{ + aas_reachability_t reach; + + AAS_ReachabilityFromNum(ms->lastreachnum, &reach); + //if not using the grapple hook reachability anymore + if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_GRAPPLEHOOK) + { + if ((ms->moveflags & MFL_ACTIVEGRAPPLE) || ms->grapplevisible_time) + { + if (offhandgrapple->value) + EA_Command(ms->client, cmd_grappleoff->string); + ms->moveflags &= ~MFL_ACTIVEGRAPPLE; + ms->grapplevisible_time = 0; +#ifdef DEBUG_GRAPPLE + botimport.Print(PRT_MESSAGE, "reset grapple\n"); +#endif //DEBUG_GRAPPLE + } //end if + } //end if +} //end of the function BotResetGrapple +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_Grapple(bot_movestate_t *ms, aas_reachability_t *reach) +{ + bot_moveresult_t_cleared( result ); + float dist, speed; + vec3_t dir, viewdir, org; + int state, areanum; + bsp_trace_t trace; + +#ifdef DEBUG_GRAPPLE + static int debugline; + if (!debugline) debugline = botimport.DebugLineCreate(); + botimport.DebugLineShow(debugline, reach->start, reach->end, LINECOLOR_BLUE); +#endif //DEBUG_GRAPPLE + + // + if (ms->moveflags & MFL_GRAPPLERESET) + { + if (offhandgrapple->value) + EA_Command(ms->client, cmd_grappleoff->string); + ms->moveflags &= ~MFL_ACTIVEGRAPPLE; + return result; + } //end if + // + if (!(int) offhandgrapple->value) + { + result.weapon = weapindex_grapple->value; + result.flags |= MOVERESULT_MOVEMENTWEAPON; + } //end if + // + if (ms->moveflags & MFL_ACTIVEGRAPPLE) + { +#ifdef DEBUG_GRAPPLE + botimport.Print(PRT_MESSAGE, "BotTravel_Grapple: active grapple\n"); +#endif //DEBUG_GRAPPLE + // + state = GrappleState(ms, reach); + // + VectorSubtract(reach->end, ms->origin, dir); + dir[2] = 0; + dist = VectorLength(dir); + //if very close to the grapple end or the grappled is hooked and + //the bot doesn't get any closer + if (state && dist < 48) + { + if (ms->lastgrappledist - dist < 1) + { +#ifdef DEBUG_GRAPPLE + botimport.Print(PRT_ERROR, "grapple normal end\n"); +#endif //DEBUG_GRAPPLE + if (offhandgrapple->value) + EA_Command(ms->client, cmd_grappleoff->string); + ms->moveflags &= ~MFL_ACTIVEGRAPPLE; + ms->moveflags |= MFL_GRAPPLERESET; + ms->reachability_time = 0; //end the reachability + return result; + } //end if + } //end if + //if no valid grapple at all, or the grapple hooked and the bot + //isn't moving anymore + else if (!state || (state == 2 && dist > ms->lastgrappledist - 2)) + { + if (ms->grapplevisible_time < AAS_Time() - 0.4) + { +#ifdef DEBUG_GRAPPLE + botimport.Print(PRT_ERROR, "grapple not visible\n"); +#endif //DEBUG_GRAPPLE + if (offhandgrapple->value) + EA_Command(ms->client, cmd_grappleoff->string); + ms->moveflags &= ~MFL_ACTIVEGRAPPLE; + ms->moveflags |= MFL_GRAPPLERESET; + ms->reachability_time = 0; //end the reachability + return result; + } //end if + } //end if + else + { + ms->grapplevisible_time = AAS_Time(); + } //end else + // + if (!(int) offhandgrapple->value) + { + EA_Attack(ms->client); + } //end if + //remember the current grapple distance + ms->lastgrappledist = dist; + } //end if + else + { +#ifdef DEBUG_GRAPPLE + botimport.Print(PRT_MESSAGE, "BotTravel_Grapple: inactive grapple\n"); +#endif //DEBUG_GRAPPLE + // + ms->grapplevisible_time = AAS_Time(); + // + VectorSubtract(reach->start, ms->origin, dir); + if (!(ms->moveflags & MFL_SWIMMING)) dir[2] = 0; + VectorAdd(ms->origin, ms->viewoffset, org); + VectorSubtract(reach->end, org, viewdir); + // + dist = VectorNormalize(dir); + Vector2Angles(viewdir, result.ideal_viewangles); + result.flags |= MOVERESULT_MOVEMENTVIEW; + // + if (dist < 5 && + fabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 2 && + fabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 2) + { +#ifdef DEBUG_GRAPPLE + botimport.Print(PRT_MESSAGE, "BotTravel_Grapple: activating grapple\n"); +#endif //DEBUG_GRAPPLE + //check if the grapple missile path is clear + VectorAdd(ms->origin, ms->viewoffset, org); + trace = AAS_Trace(org, NULL, NULL, reach->end, ms->entitynum, CONTENTS_SOLID); + VectorSubtract(reach->end, trace.endpos, dir); + if (VectorLength(dir) > 16) + { + result.failure = qtrue; + return result; + } //end if + //activate the grapple + if (offhandgrapple->value) + { + EA_Command(ms->client, cmd_grappleon->string); + } //end if + else + { + EA_Attack(ms->client); + } //end else + ms->moveflags |= MFL_ACTIVEGRAPPLE; + ms->lastgrappledist = 999999; + } //end if + else + { + if (dist < 70) speed = 300 - (300 - 4 * dist); + else speed = 400; + // + BotCheckBlocked(ms, dir, qtrue, &result); + //elemantary action move in direction + EA_Move(ms->client, dir, speed); + VectorCopy(dir, result.movedir); + } //end else + //if in another area before actually grappling + areanum = AAS_PointAreaNum(ms->origin); + if (areanum && areanum != ms->reachareanum) ms->reachability_time = 0; + } //end else + return result; +} //end of the function BotTravel_Grapple +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_RocketJump(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t hordir; + float dist, speed; + bot_moveresult_t_cleared( result ); + + //botimport.Print(PRT_MESSAGE, "BotTravel_RocketJump: bah\n"); + // + hordir[0] = reach->start[0] - ms->origin[0]; + hordir[1] = reach->start[1] - ms->origin[1]; + hordir[2] = 0; + // + dist = VectorNormalize(hordir); + //look in the movement direction + Vector2Angles(hordir, result.ideal_viewangles); + //look straight down + result.ideal_viewangles[PITCH] = 90; + // + if (dist < 5 && + fabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 5 && + fabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 5) + { + //botimport.Print(PRT_MESSAGE, "between jump start and run start point\n"); + hordir[0] = reach->end[0] - ms->origin[0]; + hordir[1] = reach->end[1] - ms->origin[1]; + hordir[2] = 0; + VectorNormalize(hordir); + //elemantary action jump + EA_Jump(ms->client); + EA_Attack(ms->client); + EA_Move(ms->client, hordir, 800); + // + ms->jumpreach = ms->lastreachnum; + } //end if + else + { + if (dist > 80) dist = 80; + speed = 400 - (400 - 5 * dist); + EA_Move(ms->client, hordir, speed); + } //end else + //look in the movement direction + Vector2Angles(hordir, result.ideal_viewangles); + //look straight down + result.ideal_viewangles[PITCH] = 90; + //set the view angles directly + EA_View(ms->client, result.ideal_viewangles); + //view is important for the movment + result.flags |= MOVERESULT_MOVEMENTVIEWSET; + //select the rocket launcher + EA_SelectWeapon(ms->client, (int) weapindex_rocketlauncher->value); + //weapon is used for movement + result.weapon = (int) weapindex_rocketlauncher->value; + result.flags |= MOVERESULT_MOVEMENTWEAPON; + // + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotTravel_RocketJump +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_BFGJump(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t hordir; + float dist, speed; + bot_moveresult_t_cleared( result ); + + //botimport.Print(PRT_MESSAGE, "BotTravel_BFGJump: bah\n"); + // + hordir[0] = reach->start[0] - ms->origin[0]; + hordir[1] = reach->start[1] - ms->origin[1]; + hordir[2] = 0; + // + dist = VectorNormalize(hordir); + // + if (dist < 5 && + fabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 5 && + fabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 5) + { + //botimport.Print(PRT_MESSAGE, "between jump start and run start point\n"); + hordir[0] = reach->end[0] - ms->origin[0]; + hordir[1] = reach->end[1] - ms->origin[1]; + hordir[2] = 0; + VectorNormalize(hordir); + //elemantary action jump + EA_Jump(ms->client); + EA_Attack(ms->client); + EA_Move(ms->client, hordir, 800); + // + ms->jumpreach = ms->lastreachnum; + } //end if + else + { + if (dist > 80) dist = 80; + speed = 400 - (400 - 5 * dist); + EA_Move(ms->client, hordir, speed); + } //end else + //look in the movement direction + Vector2Angles(hordir, result.ideal_viewangles); + //look straight down + result.ideal_viewangles[PITCH] = 90; + //set the view angles directly + EA_View(ms->client, result.ideal_viewangles); + //view is important for the movment + result.flags |= MOVERESULT_MOVEMENTVIEWSET; + //select the rocket launcher + EA_SelectWeapon(ms->client, (int) weapindex_bfg10k->value); + //weapon is used for movement + result.weapon = (int) weapindex_bfg10k->value; + result.flags |= MOVERESULT_MOVEMENTWEAPON; + // + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotTravel_BFGJump +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotFinishTravel_WeaponJump(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t hordir; + float speed; + bot_moveresult_t_cleared( result ); + + //if not jumped yet + if (!ms->jumpreach) return result; + /* + //go straight to the reachability end + hordir[0] = reach->end[0] - ms->origin[0]; + hordir[1] = reach->end[1] - ms->origin[1]; + hordir[2] = 0; + VectorNormalize(hordir); + //always use max speed when traveling through the air + EA_Move(ms->client, hordir, 800); + VectorCopy(hordir, result.movedir); + */ + // + if (!BotAirControl(ms->origin, ms->velocity, reach->end, hordir, &speed)) + { + //go straight to the reachability end + VectorSubtract(reach->end, ms->origin, hordir); + hordir[2] = 0; + VectorNormalize(hordir); + speed = 400; + } //end if + // + EA_Move(ms->client, hordir, speed); + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotFinishTravel_WeaponJump +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_JumpPad(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t hordir; + bot_moveresult_t_cleared( result ); + + //first walk straight to the reachability start + hordir[0] = reach->start[0] - ms->origin[0]; + hordir[1] = reach->start[1] - ms->origin[1]; + hordir[2] = 0; + // + BotCheckBlocked(ms, hordir, qtrue, &result); + //elemantary action move in direction + EA_Move(ms->client, hordir, 400); + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotTravel_JumpPad +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotFinishTravel_JumpPad(bot_movestate_t *ms, aas_reachability_t *reach) +{ + float speed; + vec3_t hordir; + bot_moveresult_t_cleared( result ); + + if (!BotAirControl(ms->origin, ms->velocity, reach->end, hordir, &speed)) + { + hordir[0] = reach->end[0] - ms->origin[0]; + hordir[1] = reach->end[1] - ms->origin[1]; + hordir[2] = 0; + VectorNormalize(hordir); + speed = 400; + } //end if + BotCheckBlocked(ms, hordir, qtrue, &result); + //elemantary action move in direction + EA_Move(ms->client, hordir, speed); + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotFinishTravel_JumpPad +//=========================================================================== +// time before the reachability times out +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotReachabilityTime(aas_reachability_t *reach) +{ + switch(reach->traveltype & TRAVELTYPE_MASK) + { + case TRAVEL_WALK: return 5; + case TRAVEL_CROUCH: return 5; + case TRAVEL_BARRIERJUMP: return 5; + case TRAVEL_LADDER: return 6; + case TRAVEL_WALKOFFLEDGE: return 5; + case TRAVEL_JUMP: return 5; + case TRAVEL_SWIM: return 5; + case TRAVEL_WATERJUMP: return 5; + case TRAVEL_TELEPORT: return 5; + case TRAVEL_ELEVATOR: return 10; + case TRAVEL_GRAPPLEHOOK: return 8; + case TRAVEL_ROCKETJUMP: return 6; + case TRAVEL_BFGJUMP: return 6; + case TRAVEL_JUMPPAD: return 10; + case TRAVEL_FUNCBOB: return 10; + default: + { + botimport.Print(PRT_ERROR, "travel type %d not implemented yet\n", reach->traveltype); + return 8; + } //end case + } //end switch +} //end of the function BotReachabilityTime +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotMoveInGoalArea(bot_movestate_t *ms, bot_goal_t *goal) +{ + bot_moveresult_t_cleared( result ); + vec3_t dir; + float dist, speed; + +#ifdef DEBUG + //botimport.Print(PRT_MESSAGE, "%s: moving straight to goal\n", ClientName(ms->entitynum-1)); + //AAS_ClearShownDebugLines(); + //AAS_DebugLine(ms->origin, goal->origin, LINECOLOR_RED); +#endif //DEBUG + //walk straight to the goal origin + dir[0] = goal->origin[0] - ms->origin[0]; + dir[1] = goal->origin[1] - ms->origin[1]; + if (ms->moveflags & MFL_SWIMMING) + { + dir[2] = goal->origin[2] - ms->origin[2]; + result.traveltype = TRAVEL_SWIM; + } //end if + else + { + dir[2] = 0; + result.traveltype = TRAVEL_WALK; + } //endif + // + dist = VectorNormalize(dir); + if (dist > 100) dist = 100; + speed = 400 - (400 - 4 * dist); + if (speed < 10) speed = 0; + // + BotCheckBlocked(ms, dir, qtrue, &result); + //elemantary action move in direction + EA_Move(ms->client, dir, speed); + VectorCopy(dir, result.movedir); + // + if (ms->moveflags & MFL_SWIMMING) + { + Vector2Angles(dir, result.ideal_viewangles); + result.flags |= MOVERESULT_SWIMVIEW; + } //end if + //if (!debugline) debugline = botimport.DebugLineCreate(); + //botimport.DebugLineShow(debugline, ms->origin, goal->origin, LINECOLOR_BLUE); + // + ms->lastreachnum = 0; + ms->lastareanum = 0; + ms->lastgoalareanum = goal->areanum; + VectorCopy(ms->origin, ms->lastorigin); + // + return result; +} //end of the function BotMoveInGoalArea +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotMoveToGoal(bot_moveresult_t *result, int movestate, bot_goal_t *goal, int travelflags) +{ + int reachnum, lastreachnum, foundjumppad, ent, resultflags; + aas_reachability_t reach, lastreach; + bot_movestate_t *ms; + //vec3_t mins, maxs, up = {0, 0, 1}; + //bsp_trace_t trace; + //static int debugline; + + result->failure = qfalse; + result->type = 0; + result->blocked = qfalse; + result->blockentity = 0; + result->traveltype = 0; + result->flags = 0; + + // + ms = BotMoveStateFromHandle(movestate); + if (!ms) return; + //reset the grapple before testing if the bot has a valid goal + //because the bot could lose all its goals when stuck to a wall + BotResetGrapple(ms); + // + if (!goal) + { +#ifdef DEBUG + botimport.Print(PRT_MESSAGE, "client %d: movetogoal -> no goal\n", ms->client); +#endif //DEBUG + result->failure = qtrue; + return; + } //end if + //botimport.Print(PRT_MESSAGE, "numavoidreach = %d\n", ms->numavoidreach); + //remove some of the move flags + ms->moveflags &= ~(MFL_SWIMMING|MFL_AGAINSTLADDER); + //set some of the move flags + //NOTE: the MFL_ONGROUND flag is also set in the higher AI + if (AAS_OnGround(ms->origin, ms->presencetype, ms->entitynum)) ms->moveflags |= MFL_ONGROUND; + // + if (ms->moveflags & MFL_ONGROUND) + { + int modeltype, modelnum; + + ent = BotOnTopOfEntity(ms); + + if (ent != -1) + { + modelnum = AAS_EntityModelindex(ent); + if (modelnum >= 0 && modelnum < MAX_MODELS) + { + modeltype = modeltypes[modelnum]; + + if (modeltype == MODELTYPE_FUNC_PLAT) + { + AAS_ReachabilityFromNum(ms->lastreachnum, &reach); + //if the bot is Not using the elevator + if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR || + //NOTE: the face number is the plat model number + (reach.facenum & 0x0000FFFF) != modelnum) + { + reachnum = AAS_NextModelReachability(0, modelnum); + if (reachnum) + { + //botimport.Print(PRT_MESSAGE, "client %d: accidentally ended up on func_plat\n", ms->client); + AAS_ReachabilityFromNum(reachnum, &reach); + ms->lastreachnum = reachnum; + ms->reachability_time = AAS_Time() + BotReachabilityTime(&reach); + } //end if + else + { + if (botDeveloper) + { + botimport.Print(PRT_MESSAGE, "client %d: on func_plat without reachability\n", ms->client); + } //end if + result->blocked = qtrue; + result->blockentity = ent; + result->flags |= MOVERESULT_ONTOPOFOBSTACLE; + return; + } //end else + } //end if + result->flags |= MOVERESULT_ONTOPOF_ELEVATOR; + } //end if + else if (modeltype == MODELTYPE_FUNC_BOB) + { + AAS_ReachabilityFromNum(ms->lastreachnum, &reach); + //if the bot is Not using the func bobbing + if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_FUNCBOB || + //NOTE: the face number is the func_bobbing model number + (reach.facenum & 0x0000FFFF) != modelnum) + { + reachnum = AAS_NextModelReachability(0, modelnum); + if (reachnum) + { + //botimport.Print(PRT_MESSAGE, "client %d: accidentally ended up on func_bobbing\n", ms->client); + AAS_ReachabilityFromNum(reachnum, &reach); + ms->lastreachnum = reachnum; + ms->reachability_time = AAS_Time() + BotReachabilityTime(&reach); + } //end if + else + { + if (botDeveloper) + { + botimport.Print(PRT_MESSAGE, "client %d: on func_bobbing without reachability\n", ms->client); + } //end if + result->blocked = qtrue; + result->blockentity = ent; + result->flags |= MOVERESULT_ONTOPOFOBSTACLE; + return; + } //end else + } //end if + result->flags |= MOVERESULT_ONTOPOF_FUNCBOB; + } //end if + else if (modeltype == MODELTYPE_FUNC_STATIC || modeltype == MODELTYPE_FUNC_DOOR) + { + // check if ontop of a door bridge ? + ms->areanum = BotFuzzyPointReachabilityArea(ms->origin); + // if not in a reachability area + if (!AAS_AreaReachability(ms->areanum)) + { + result->blocked = qtrue; + result->blockentity = ent; + result->flags |= MOVERESULT_ONTOPOFOBSTACLE; + return; + } //end if + } //end else if + else + { + result->blocked = qtrue; + result->blockentity = ent; + result->flags |= MOVERESULT_ONTOPOFOBSTACLE; + return; + } //end else + } //end if + } //end if + } //end if + //if swimming + if (AAS_Swimming(ms->origin)) ms->moveflags |= MFL_SWIMMING; + //if against a ladder + if (AAS_AgainstLadder(ms->origin)) ms->moveflags |= MFL_AGAINSTLADDER; + //if the bot is on the ground, swimming or against a ladder + if (ms->moveflags & (MFL_ONGROUND|MFL_SWIMMING|MFL_AGAINSTLADDER)) + { + //botimport.Print(PRT_MESSAGE, "%s: onground, swimming or against ladder\n", ClientName(ms->entitynum-1)); + // + AAS_ReachabilityFromNum(ms->lastreachnum, &lastreach); + //reachability area the bot is in + //ms->areanum = BotReachabilityArea(ms->origin, ((lastreach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR)); + ms->areanum = BotFuzzyPointReachabilityArea(ms->origin); + // + if ( !ms->areanum ) + { + result->failure = qtrue; + result->blocked = qtrue; + result->blockentity = 0; + result->type = RESULTTYPE_INSOLIDAREA; + return; + } //end if + //if the bot is in the goal area + if (ms->areanum == goal->areanum) + { + *result = BotMoveInGoalArea(ms, goal); + return; + } //end if + //assume we can use the reachability from the last frame + reachnum = ms->lastreachnum; + //if there is a last reachability + if (reachnum) + { + AAS_ReachabilityFromNum(reachnum, &reach); + //check if the reachability is still valid + if (!(AAS_TravelFlagForType(reach.traveltype) & travelflags)) + { + reachnum = 0; + } //end if + //special grapple hook case + else if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_GRAPPLEHOOK) + { + if (ms->reachability_time < AAS_Time() || + (ms->moveflags & MFL_GRAPPLERESET)) + { + reachnum = 0; + } //end if + } //end if + //special elevator case + else if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_ELEVATOR || + (reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_FUNCBOB) + { + if ((result->flags & MOVERESULT_ONTOPOF_ELEVATOR) || + (result->flags & MOVERESULT_ONTOPOF_FUNCBOB)) + { + ms->reachability_time = AAS_Time() + 5; + } //end if + //if the bot was going for an elevator and reached the reachability area + if (ms->areanum == reach.areanum || + ms->reachability_time < AAS_Time()) + { + reachnum = 0; + } //end if + } //end if + else + { +#ifdef DEBUG + if (botDeveloper) + { + if (ms->reachability_time < AAS_Time()) + { + botimport.Print(PRT_MESSAGE, "client %d: reachability timeout in ", ms->client); + AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK); + botimport.Print(PRT_MESSAGE, "\n"); + } //end if + /* + if (ms->lastareanum != ms->areanum) + { + botimport.Print(PRT_MESSAGE, "changed from area %d to %d\n", ms->lastareanum, ms->areanum); + } //end if*/ + } //end if +#endif //DEBUG + //if the goal area changed or the reachability timed out + //or the area changed + if (ms->lastgoalareanum != goal->areanum || + ms->reachability_time < AAS_Time() || + ms->lastareanum != ms->areanum) + { + reachnum = 0; + //botimport.Print(PRT_MESSAGE, "area change or timeout\n"); + } //end else if + } //end else + } //end if + resultflags = 0; + //if the bot needs a new reachability + if (!reachnum) + { + //if the area has no reachability links + if (!AAS_AreaReachability(ms->areanum)) + { +#ifdef DEBUG + if (botDeveloper) + { + botimport.Print(PRT_MESSAGE, "area %d no reachability\n", ms->areanum); + } //end if +#endif //DEBUG + } //end if + //get a new reachability leading towards the goal + reachnum = BotGetReachabilityToGoal(ms->origin, ms->areanum, + ms->lastgoalareanum, ms->lastareanum, + ms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries, + goal, travelflags, + ms->avoidspots, ms->numavoidspots, &resultflags); + //the area number the reachability starts in + ms->reachareanum = ms->areanum; + //reset some state variables + ms->jumpreach = 0; //for TRAVEL_JUMP + ms->moveflags &= ~MFL_GRAPPLERESET; //for TRAVEL_GRAPPLEHOOK + //if there is a reachability to the goal + if (reachnum) + { + AAS_ReachabilityFromNum(reachnum, &reach); + //set a timeout for this reachability + ms->reachability_time = AAS_Time() + BotReachabilityTime(&reach); + // +#ifdef AVOIDREACH + //add the reachability to the reachabilities to avoid for a while + BotAddToAvoidReach(ms, reachnum, AVOIDREACH_TIME); +#endif //AVOIDREACH + } //end if +#ifdef DEBUG + + else if (botDeveloper) + { + botimport.Print(PRT_MESSAGE, "goal not reachable\n"); + Com_Memset(&reach, 0, sizeof(aas_reachability_t)); //make compiler happy + } //end else + if (botDeveloper) + { + //if still going for the same goal + if (ms->lastgoalareanum == goal->areanum) + { + if (ms->lastareanum == reach.areanum) + { + botimport.Print(PRT_MESSAGE, "same goal, going back to previous area\n"); + } //end if + } //end if + } //end if +#endif //DEBUG + } //end else + // + ms->lastreachnum = reachnum; + ms->lastgoalareanum = goal->areanum; + ms->lastareanum = ms->areanum; + //if the bot has a reachability + if (reachnum) + { + //get the reachability from the number + AAS_ReachabilityFromNum(reachnum, &reach); + result->traveltype = reach.traveltype; + // +#ifdef DEBUG_AI_MOVE + AAS_ClearShownDebugLines(); + AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK); + AAS_ShowReachability(&reach); +#endif //DEBUG_AI_MOVE + // +#ifdef DEBUG + //botimport.Print(PRT_MESSAGE, "client %d: ", ms->client); + //AAS_PrintTravelType(reach.traveltype); + //botimport.Print(PRT_MESSAGE, "\n"); +#endif //DEBUG + switch(reach.traveltype & TRAVELTYPE_MASK) + { + case TRAVEL_WALK: *result = BotTravel_Walk(ms, &reach); break; + case TRAVEL_CROUCH: *result = BotTravel_Crouch(ms, &reach); break; + case TRAVEL_BARRIERJUMP: *result = BotTravel_BarrierJump(ms, &reach); break; + case TRAVEL_LADDER: *result = BotTravel_Ladder(ms, &reach); break; + case TRAVEL_WALKOFFLEDGE: *result = BotTravel_WalkOffLedge(ms, &reach); break; + case TRAVEL_JUMP: *result = BotTravel_Jump(ms, &reach); break; + case TRAVEL_SWIM: *result = BotTravel_Swim(ms, &reach); break; + case TRAVEL_WATERJUMP: *result = BotTravel_WaterJump(ms, &reach); break; + case TRAVEL_TELEPORT: *result = BotTravel_Teleport(ms, &reach); break; + case TRAVEL_ELEVATOR: *result = BotTravel_Elevator(ms, &reach); break; + case TRAVEL_GRAPPLEHOOK: *result = BotTravel_Grapple(ms, &reach); break; + case TRAVEL_ROCKETJUMP: *result = BotTravel_RocketJump(ms, &reach); break; + case TRAVEL_BFGJUMP: *result = BotTravel_BFGJump(ms, &reach); break; + case TRAVEL_JUMPPAD: *result = BotTravel_JumpPad(ms, &reach); break; + case TRAVEL_FUNCBOB: *result = BotTravel_FuncBobbing(ms, &reach); break; + default: + { + botimport.Print(PRT_FATAL, "travel type %d not implemented yet\n", (reach.traveltype & TRAVELTYPE_MASK)); + break; + } //end case + } //end switch + result->traveltype = reach.traveltype; + result->flags |= resultflags; + } //end if + else + { + result->failure = qtrue; + result->flags |= resultflags; + Com_Memset(&reach, 0, sizeof(aas_reachability_t)); + } //end else +#ifdef DEBUG + if (botDeveloper) + { + if (result->failure) + { + botimport.Print(PRT_MESSAGE, "client %d: movement failure in ", ms->client); + AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK); + botimport.Print(PRT_MESSAGE, "\n"); + } //end if + } //end if +#endif //DEBUG + } //end if + else + { + int i, numareas, areas[16]; + vec3_t end; + + //special handling of jump pads when the bot uses a jump pad without knowing it + foundjumppad = qfalse; + VectorMA(ms->origin, -2 * ms->thinktime, ms->velocity, end); + numareas = AAS_TraceAreas(ms->origin, end, areas, NULL, 16); + for (i = numareas-1; i >= 0; i--) + { + if (AAS_AreaJumpPad(areas[i])) + { + //botimport.Print(PRT_MESSAGE, "client %d used a jumppad without knowing, area %d\n", ms->client, areas[i]); + foundjumppad = qtrue; + lastreachnum = BotGetReachabilityToGoal(end, areas[i], + ms->lastgoalareanum, ms->lastareanum, + ms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries, + goal, TFL_JUMPPAD, ms->avoidspots, ms->numavoidspots, NULL); + if (lastreachnum) + { + ms->lastreachnum = lastreachnum; + ms->lastareanum = areas[i]; + //botimport.Print(PRT_MESSAGE, "found jumppad reachability\n"); + break; + } //end if + else + { + for (lastreachnum = AAS_NextAreaReachability(areas[i], 0); lastreachnum; + lastreachnum = AAS_NextAreaReachability(areas[i], lastreachnum)) + { + //get the reachability from the number + AAS_ReachabilityFromNum(lastreachnum, &reach); + if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMPPAD) + { + ms->lastreachnum = lastreachnum; + ms->lastareanum = areas[i]; + //botimport.Print(PRT_MESSAGE, "found jumppad reachability hard!!\n"); + } //end if + } //end for + if (lastreachnum) break; + } //end else + } //end if + } //end for + if (botDeveloper) + { + //if a jumppad is found with the trace but no reachability is found + if (foundjumppad && !ms->lastreachnum) + { + botimport.Print(PRT_MESSAGE, "client %d didn't find jumppad reachability\n", ms->client); + } //end if + } //end if + // + if (ms->lastreachnum) + { + //botimport.Print(PRT_MESSAGE, "%s: NOT onground, swimming or against ladder\n", ClientName(ms->entitynum-1)); + AAS_ReachabilityFromNum(ms->lastreachnum, &reach); + result->traveltype = reach.traveltype; +#ifdef DEBUG + //botimport.Print(PRT_MESSAGE, "client %d finish: ", ms->client); + //AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK); + //botimport.Print(PRT_MESSAGE, "\n"); +#endif //DEBUG + // + switch(reach.traveltype & TRAVELTYPE_MASK) + { + case TRAVEL_WALK: *result = BotTravel_Walk(ms, &reach); break;//BotFinishTravel_Walk(ms, &reach); break; + case TRAVEL_CROUCH: /*do nothing*/ break; + case TRAVEL_BARRIERJUMP: *result = BotFinishTravel_BarrierJump(ms, &reach); break; + case TRAVEL_LADDER: *result = BotTravel_Ladder(ms, &reach); break; + case TRAVEL_WALKOFFLEDGE: *result = BotFinishTravel_WalkOffLedge(ms, &reach); break; + case TRAVEL_JUMP: *result = BotFinishTravel_Jump(ms, &reach); break; + case TRAVEL_SWIM: *result = BotTravel_Swim(ms, &reach); break; + case TRAVEL_WATERJUMP: *result = BotFinishTravel_WaterJump(ms, &reach); break; + case TRAVEL_TELEPORT: /*do nothing*/ break; + case TRAVEL_ELEVATOR: *result = BotFinishTravel_Elevator(ms, &reach); break; + case TRAVEL_GRAPPLEHOOK: *result = BotTravel_Grapple(ms, &reach); break; + case TRAVEL_ROCKETJUMP: + case TRAVEL_BFGJUMP: *result = BotFinishTravel_WeaponJump(ms, &reach); break; + case TRAVEL_JUMPPAD: *result = BotFinishTravel_JumpPad(ms, &reach); break; + case TRAVEL_FUNCBOB: *result = BotFinishTravel_FuncBobbing(ms, &reach); break; + default: + { + botimport.Print(PRT_FATAL, "(last) travel type %d not implemented yet\n", (reach.traveltype & TRAVELTYPE_MASK)); + break; + } //end case + } //end switch + result->traveltype = reach.traveltype; +#ifdef DEBUG + if (botDeveloper) + { + if (result->failure) + { + botimport.Print(PRT_MESSAGE, "client %d: movement failure in finish ", ms->client); + AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK); + botimport.Print(PRT_MESSAGE, "\n"); + } //end if + } //end if +#endif //DEBUG + } //end if + } //end else + //FIXME: is it right to do this here? + if (result->blocked) ms->reachability_time -= 10 * ms->thinktime; + //copy the last origin + VectorCopy(ms->origin, ms->lastorigin); + //return the movement result + return; +} //end of the function BotMoveToGoal +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotResetAvoidReach(int movestate) +{ + bot_movestate_t *ms; + + ms = BotMoveStateFromHandle(movestate); + if (!ms) return; + Com_Memset(ms->avoidreach, 0, MAX_AVOIDREACH * sizeof(int)); + Com_Memset(ms->avoidreachtimes, 0, MAX_AVOIDREACH * sizeof(float)); + Com_Memset(ms->avoidreachtries, 0, MAX_AVOIDREACH * sizeof(int)); +} //end of the function BotResetAvoidReach +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotResetLastAvoidReach(int movestate) +{ + int i, latest; + float latesttime; + bot_movestate_t *ms; + + ms = BotMoveStateFromHandle(movestate); + if (!ms) return; + latesttime = 0; + latest = 0; + for (i = 0; i < MAX_AVOIDREACH; i++) + { + if (ms->avoidreachtimes[i] > latesttime) + { + latesttime = ms->avoidreachtimes[i]; + latest = i; + } //end if + } //end for + if (latesttime) + { + ms->avoidreachtimes[latest] = 0; + if (ms->avoidreachtries[latest] > 0) ms->avoidreachtries[latest]--; + } //end if +} //end of the function BotResetLastAvoidReach +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotResetMoveState(int movestate) +{ + bot_movestate_t *ms; + + ms = BotMoveStateFromHandle(movestate); + if (!ms) return; + Com_Memset(ms, 0, sizeof(bot_movestate_t)); +} //end of the function BotResetMoveState +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotSetupMoveAI(void) +{ + BotSetBrushModelTypes(); + sv_maxstep = LibVar("sv_step", "18"); + sv_maxbarrier = LibVar("sv_maxbarrier", "32"); + sv_gravity = LibVar("sv_gravity", "800"); + weapindex_rocketlauncher = LibVar("weapindex_rocketlauncher", "5"); + weapindex_bfg10k = LibVar("weapindex_bfg10k", "9"); + weapindex_grapple = LibVar("weapindex_grapple", "10"); + entitytypemissile = LibVar("entitytypemissile", "3"); + offhandgrapple = LibVar("offhandgrapple", "0"); + cmd_grappleon = LibVar("cmd_grappleon", "grappleon"); + cmd_grappleoff = LibVar("cmd_grappleoff", "grappleoff"); + return BLERR_NOERROR; +} //end of the function BotSetupMoveAI +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotShutdownMoveAI(void) +{ + int i; + + for (i = 1; i <= MAX_CLIENTS; i++) + { + if (botmovestates[i]) + { + FreeMemory(botmovestates[i]); + botmovestates[i] = NULL; + } //end if + } //end for +} //end of the function BotShutdownMoveAI + + diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_move.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_move.h new file mode 100644 index 0000000..1c0cd08 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_move.h @@ -0,0 +1,147 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_ai_move.h + * + * desc: movement AI + * + * $Archive: /source/code/botlib/be_ai_move.h $ + * $Author: osman $ + * $Revision: 1.4 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 2003/03/15 23:44:00 $ + * + *****************************************************************************/ + +#pragma once + +//movement types +#define MOVE_WALK 1 +#define MOVE_CROUCH 2 +#define MOVE_JUMP 4 +#define MOVE_GRAPPLE 8 +#define MOVE_ROCKETJUMP 16 +#define MOVE_BFGJUMP 32 +//move flags +#define MFL_BARRIERJUMP 1 //bot is performing a barrier jump +#define MFL_ONGROUND 2 //bot is in the ground +#define MFL_SWIMMING 4 //bot is swimming +#define MFL_AGAINSTLADDER 8 //bot is against a ladder +#define MFL_WATERJUMP 16 //bot is waterjumping +#define MFL_TELEPORTED 32 //bot is being teleported +#define MFL_GRAPPLEPULL 64 //bot is being pulled by the grapple +#define MFL_ACTIVEGRAPPLE 128 //bot is using the grapple hook +#define MFL_GRAPPLERESET 256 //bot has reset the grapple +#define MFL_WALK 512 //bot should walk slowly +// move result flags +#define MOVERESULT_MOVEMENTVIEW 1 //bot uses view for movement +#define MOVERESULT_SWIMVIEW 2 //bot uses view for swimming +#define MOVERESULT_WAITING 4 //bot is waiting for something +#define MOVERESULT_MOVEMENTVIEWSET 8 //bot has set the view in movement code +#define MOVERESULT_MOVEMENTWEAPON 16 //bot uses weapon for movement +#define MOVERESULT_ONTOPOFOBSTACLE 32 //bot is ontop of obstacle +#define MOVERESULT_ONTOPOF_FUNCBOB 64 //bot is ontop of a func_bobbing +#define MOVERESULT_ONTOPOF_ELEVATOR 128 //bot is ontop of an elevator (func_plat) +#define MOVERESULT_BLOCKEDBYAVOIDSPOT 256 //bot is blocked by an avoid spot +// +#define MAX_AVOIDREACH 1 +#define MAX_AVOIDSPOTS 32 +// avoid spot types +#define AVOID_CLEAR 0 //clear all avoid spots +#define AVOID_ALWAYS 1 //avoid always +#define AVOID_DONTBLOCK 2 //never totally block +// restult types +#define RESULTTYPE_ELEVATORUP 1 //elevator is up +#define RESULTTYPE_WAITFORFUNCBOBBING 2 //waiting for func bobbing to arrive +#define RESULTTYPE_BADGRAPPLEPATH 4 //grapple path is obstructed +#define RESULTTYPE_INSOLIDAREA 8 //stuck in solid area, this is bad + +//structure used to initialize the movement state +//the or_moveflags MFL_ONGROUND, MFL_TELEPORTED and MFL_WATERJUMP come from the playerstate +typedef struct bot_initmove_s +{ + vec3_t origin; //origin of the bot + vec3_t velocity; //velocity of the bot + vec3_t viewoffset; //view offset + int entitynum; //entity number of the bot + int client; //client number of the bot + float thinktime; //time the bot thinks + int presencetype; //presencetype of the bot + vec3_t viewangles; //view angles of the bot + int or_moveflags; //values ored to the movement flags +} bot_initmove_t; + +//NOTE: the ideal_viewangles are only valid if MFL_MOVEMENTVIEW is set +typedef struct bot_moveresult_s +{ + int failure; //true if movement failed all together + int type; //failure or blocked type + int blocked; //true if blocked by an entity + int blockentity; //entity blocking the bot + int traveltype; //last executed travel type + int flags; //result flags + int weapon; //weapon used for movement + vec3_t movedir; //movement direction + vec3_t ideal_viewangles; //ideal viewangles for the movement +} bot_moveresult_t; + +#define bot_moveresult_t_cleared(x) bot_moveresult_t (x) = {0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, {0, 0, 0}} + +typedef struct bot_avoidspot_s +{ + vec3_t origin; + float radius; + int type; +} bot_avoidspot_t; + +//resets the whole move state +void BotResetMoveState(int movestate); +//moves the bot to the given goal +void BotMoveToGoal(bot_moveresult_t *result, int movestate, bot_goal_t *goal, int travelflags); +//moves the bot in the specified direction using the specified type of movement +int BotMoveInDirection(int movestate, vec3_t dir, float speed, int type); +//reset avoid reachability +void BotResetAvoidReach(int movestate); +//resets the last avoid reachability +void BotResetLastAvoidReach(int movestate); +//returns a reachability area if the origin is in one +int BotReachabilityArea(vec3_t origin, int client); +//view target based on movement +int BotMovementViewTarget(int movestate, bot_goal_t *goal, int travelflags, float lookahead, vec3_t target); +//predict the position of a player based on movement towards a goal +int BotPredictVisiblePosition(vec3_t origin, int areanum, bot_goal_t *goal, int travelflags, vec3_t target); +//returns the handle of a newly allocated movestate +int BotAllocMoveState(void); +//frees the movestate with the given handle +void BotFreeMoveState(int handle); +//initialize movement state before performing any movement +void BotInitMoveState(int handle, bot_initmove_t *initmove); +//add a spot to avoid (if type == AVOID_CLEAR all spots are removed) +void BotAddAvoidSpot(int movestate, vec3_t origin, float radius, int type); +//must be called every map change +void BotSetBrushModelTypes(void); +//setup movement AI +int BotSetupMoveAI(void); +//shutdown movement AI +void BotShutdownMoveAI(void); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_weap.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_weap.cpp new file mode 100644 index 0000000..231f722 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_weap.cpp @@ -0,0 +1,548 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_ai_weap.c + * + * desc: weapon AI + * + * $Archive: /MissionPack/code/botlib/be_ai_weap.c $ + * $Author: Ttimo $ + * $Revision: 6 $ + * $Modtime: 4/13/01 4:45p $ + * $Date: 4/13/01 4:45p $ + * + *****************************************************************************/ + +#include "qcommon/q_shared.h" +#include "l_libvar.h" +#include "l_log.h" +#include "l_memory.h" +#include "l_utils.h" +#include "l_script.h" +#include "l_precomp.h" +#include "l_struct.h" +#include "aasfile.h" +#include "botlib.h" +#include "be_aas.h" +#include "be_aas_funcs.h" +#include "be_interface.h" +#include "be_ai_weight.h" //fuzzy weights +#include "be_ai_weap.h" + +//#define DEBUG_AI_WEAP + +//structure field offsets +#define WEAPON_OFS(x) offsetof(weaponinfo_t, x) +#define PROJECTILE_OFS(x) offsetof(projectileinfo_t, x) + +//weapon definition // bk001212 - static +static fielddef_t weaponinfo_fields[] = +{ +{"number", WEAPON_OFS(number), FT_INT}, //weapon number +{"name", WEAPON_OFS(name), FT_STRING}, //name of the weapon +{"level", WEAPON_OFS(level), FT_INT}, +{"model", WEAPON_OFS(model), FT_STRING}, //model of the weapon +{"weaponindex", WEAPON_OFS(weaponindex), FT_INT}, //index of weapon in inventory +{"flags", WEAPON_OFS(flags), FT_INT}, //special flags +{"projectile", WEAPON_OFS(projectile), FT_STRING}, //projectile used by the weapon +{"numprojectiles", WEAPON_OFS(numprojectiles), FT_INT}, //number of projectiles +{"hspread", WEAPON_OFS(hspread), FT_FLOAT}, //horizontal spread of projectiles (degrees from middle) +{"vspread", WEAPON_OFS(vspread), FT_FLOAT}, //vertical spread of projectiles (degrees from middle) +{"speed", WEAPON_OFS(speed), FT_FLOAT}, //speed of the projectile (0 = instant hit) +{"acceleration", WEAPON_OFS(acceleration), FT_FLOAT}, //"acceleration" * time (in seconds) + "speed" = projectile speed +{"recoil", WEAPON_OFS(recoil), FT_FLOAT|FT_ARRAY, 3}, //amount of recoil the player gets from the weapon +{"offset", WEAPON_OFS(offset), FT_FLOAT|FT_ARRAY, 3}, //projectile start offset relative to eye and view angles +{"angleoffset", WEAPON_OFS(angleoffset), FT_FLOAT|FT_ARRAY, 3},//offset of the shoot angles relative to the view angles +{"extrazvelocity", WEAPON_OFS(extrazvelocity), FT_FLOAT},//extra z velocity the projectile gets +{"ammoamount", WEAPON_OFS(ammoamount), FT_INT}, //ammo amount used per shot +{"ammoindex", WEAPON_OFS(ammoindex), FT_INT}, //index of ammo in inventory +{"activate", WEAPON_OFS(activate), FT_FLOAT}, //time it takes to select the weapon +{"reload", WEAPON_OFS(reload), FT_FLOAT}, //time it takes to reload the weapon +{"spinup", WEAPON_OFS(spinup), FT_FLOAT}, //time it takes before first shot +{"spindown", WEAPON_OFS(spindown), FT_FLOAT}, //time it takes before weapon stops firing +{NULL, 0, 0, 0} +}; + +//projectile definition +static fielddef_t projectileinfo_fields[] = +{ +{"name", PROJECTILE_OFS(name), FT_STRING}, //name of the projectile +{"model", PROJECTILE_OFS(model), FT_STRING}, //model of the projectile +{"flags", PROJECTILE_OFS(flags), FT_INT}, //special flags +{"gravity", PROJECTILE_OFS(gravity), FT_FLOAT}, //amount of gravity applied to the projectile [0,1] +{"damage", PROJECTILE_OFS(damage), FT_INT}, //damage of the projectile +{"radius", PROJECTILE_OFS(radius), FT_FLOAT}, //radius of damage +{"visdamage", PROJECTILE_OFS(visdamage), FT_INT}, //damage of the projectile to visible entities +{"damagetype", PROJECTILE_OFS(damagetype), FT_INT}, //type of damage (combination of the DAMAGETYPE_? flags) +{"healthinc", PROJECTILE_OFS(healthinc), FT_INT}, //health increase the owner gets +{"push", PROJECTILE_OFS(push), FT_FLOAT}, //amount a player is pushed away from the projectile impact +{"detonation", PROJECTILE_OFS(detonation), FT_FLOAT}, //time before projectile explodes after fire pressed +{"bounce", PROJECTILE_OFS(bounce), FT_FLOAT}, //amount the projectile bounces +{"bouncefric", PROJECTILE_OFS(bouncefric), FT_FLOAT}, //amount the bounce decreases per bounce +{"bouncestop", PROJECTILE_OFS(bouncestop), FT_FLOAT}, //minimum bounce value before bouncing stops +//recurive projectile definition?? +{NULL, 0, 0, 0} +}; + +static structdef_t weaponinfo_struct = +{ + sizeof(weaponinfo_t), weaponinfo_fields +}; +static structdef_t projectileinfo_struct = +{ + sizeof(projectileinfo_t), projectileinfo_fields +}; + +//weapon configuration: set of weapons with projectiles +typedef struct weaponconfig_s +{ + int numweapons; + int numprojectiles; + projectileinfo_t *projectileinfo; + weaponinfo_t *weaponinfo; +} weaponconfig_t; + +//the bot weapon state +typedef struct bot_weaponstate_s +{ + struct weightconfig_s *weaponweightconfig; //weapon weight configuration + int *weaponweightindex; //weapon weight index +} bot_weaponstate_t; + +static bot_weaponstate_t *botweaponstates[MAX_CLIENTS+1]; +static weaponconfig_t *weaponconfig; + +//======================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//======================================================================== +int BotValidWeaponNumber(int weaponnum) +{ + if (weaponnum <= 0 || weaponnum > weaponconfig->numweapons) + { + botimport.Print(PRT_ERROR, "weapon number out of range\n"); + return qfalse; + } //end if + return qtrue; +} //end of the function BotValidWeaponNumber +//======================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//======================================================================== +bot_weaponstate_t *BotWeaponStateFromHandle(int handle) +{ + if (handle <= 0 || handle > MAX_CLIENTS) + { + botimport.Print(PRT_FATAL, "weapon state handle %d out of range\n", handle); + return NULL; + } //end if + if (!botweaponstates[handle]) + { + botimport.Print(PRT_FATAL, "invalid weapon state %d\n", handle); + return NULL; + } //end if + return botweaponstates[handle]; +} //end of the function BotWeaponStateFromHandle +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +#ifdef DEBUG_AI_WEAP +void DumpWeaponConfig(weaponconfig_t *wc) +{ + FILE *fp; + int i; + + fp = Log_FileStruct(); + if (!fp) return; + for (i = 0; i < wc->numprojectiles; i++) + { + WriteStructure(fp, &projectileinfo_struct, (char *) &wc->projectileinfo[i]); + Log_Flush(); + } //end for + for (i = 0; i < wc->numweapons; i++) + { + WriteStructure(fp, &weaponinfo_struct, (char *) &wc->weaponinfo[i]); + Log_Flush(); + } //end for +} //end of the function DumpWeaponConfig +#endif //DEBUG_AI_WEAP +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +weaponconfig_t *LoadWeaponConfig(char *filename) +{ + int max_weaponinfo, max_projectileinfo; + token_t token; + char path[MAX_PATH]; + int i, j; + source_t *source; + weaponconfig_t *wc; + weaponinfo_t weaponinfo; + + max_weaponinfo = (int) LibVarValue("max_weaponinfo", "32"); + if (max_weaponinfo < 0) + { + botimport.Print(PRT_ERROR, "max_weaponinfo = %d\n", max_weaponinfo); + max_weaponinfo = 32; + LibVarSet("max_weaponinfo", "32"); + } //end if + max_projectileinfo = (int) LibVarValue("max_projectileinfo", "32"); + if (max_projectileinfo < 0) + { + botimport.Print(PRT_ERROR, "max_projectileinfo = %d\n", max_projectileinfo); + max_projectileinfo = 32; + LibVarSet("max_projectileinfo", "32"); + } //end if + strncpy(path, filename, MAX_PATH); + PC_SetBaseFolder(BOTFILESBASEFOLDER); + source = LoadSourceFile(path); + if (!source) + { + botimport.Print(PRT_ERROR, "counldn't load %s\n", path); + return NULL; + } //end if + //initialize weapon config + wc = (weaponconfig_t *) GetClearedHunkMemory(sizeof(weaponconfig_t) + + max_weaponinfo * sizeof(weaponinfo_t) + + max_projectileinfo * sizeof(projectileinfo_t)); + wc->weaponinfo = (weaponinfo_t *) ((char *) wc + sizeof(weaponconfig_t)); + wc->projectileinfo = (projectileinfo_t *) ((char *) wc->weaponinfo + + max_weaponinfo * sizeof(weaponinfo_t)); + wc->numweapons = max_weaponinfo; + wc->numprojectiles = 0; + //parse the source file + while(PC_ReadToken(source, &token)) + { + if (!strcmp(token.string, "weaponinfo")) + { + Com_Memset(&weaponinfo, 0, sizeof(weaponinfo_t)); + if (!ReadStructure(source, &weaponinfo_struct, (char *) &weaponinfo)) + { + FreeMemory(wc); + FreeSource(source); + return NULL; + } //end if + if (weaponinfo.number < 0 || weaponinfo.number >= max_weaponinfo) + { + botimport.Print(PRT_ERROR, "weapon info number %d out of range in %s\n", weaponinfo.number, path); + FreeMemory(wc); + FreeSource(source); + return NULL; + } //end if + Com_Memcpy(&wc->weaponinfo[weaponinfo.number], &weaponinfo, sizeof(weaponinfo_t)); + wc->weaponinfo[weaponinfo.number].valid = qtrue; + } //end if + else if (!strcmp(token.string, "projectileinfo")) + { + if (wc->numprojectiles >= max_projectileinfo) + { + botimport.Print(PRT_ERROR, "more than %d projectiles defined in %s\n", max_projectileinfo, path); + FreeMemory(wc); + FreeSource(source); + return NULL; + } //end if + Com_Memset(&wc->projectileinfo[wc->numprojectiles], 0, sizeof(projectileinfo_t)); + if (!ReadStructure(source, &projectileinfo_struct, (char *) &wc->projectileinfo[wc->numprojectiles])) + { + FreeMemory(wc); + FreeSource(source); + return NULL; + } //end if + wc->numprojectiles++; + } //end if + else + { + botimport.Print(PRT_ERROR, "unknown definition %s in %s\n", token.string, path); + FreeMemory(wc); + FreeSource(source); + return NULL; + } //end else + } //end while + FreeSource(source); + //fix up weapons + for (i = 0; i < wc->numweapons; i++) + { + if (!wc->weaponinfo[i].valid) continue; + if (!wc->weaponinfo[i].name[0]) + { + botimport.Print(PRT_ERROR, "weapon %d has no name in %s\n", i, path); + FreeMemory(wc); + return NULL; + } //end if + if (!wc->weaponinfo[i].projectile[0]) + { + botimport.Print(PRT_ERROR, "weapon %s has no projectile in %s\n", wc->weaponinfo[i].name, path); + FreeMemory(wc); + return NULL; + } //end if + //find the projectile info and copy it to the weapon info + for (j = 0; j < wc->numprojectiles; j++) + { + if (!strcmp(wc->projectileinfo[j].name, wc->weaponinfo[i].projectile)) + { + Com_Memcpy(&wc->weaponinfo[i].proj, &wc->projectileinfo[j], sizeof(projectileinfo_t)); + break; + } //end if + } //end for + if (j == wc->numprojectiles) + { + botimport.Print(PRT_ERROR, "weapon %s uses undefined projectile in %s\n", wc->weaponinfo[i].name, path); + FreeMemory(wc); + return NULL; + } //end if + } //end for + if (!wc->numweapons) botimport.Print(PRT_WARNING, "no weapon info loaded\n"); + botimport.Print(PRT_MESSAGE, "loaded %s\n", path); + return wc; +} //end of the function LoadWeaponConfig +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int *WeaponWeightIndex(weightconfig_t *wwc, weaponconfig_t *wc) +{ + int *index, i; + + //initialize item weight index + index = (int *) GetClearedMemory(sizeof(int) * wc->numweapons); + + for (i = 0; i < wc->numweapons; i++) + { + index[i] = FindFuzzyWeight(wwc, wc->weaponinfo[i].name); + } //end for + return index; +} //end of the function WeaponWeightIndex +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotFreeWeaponWeights(int weaponstate) +{ + bot_weaponstate_t *ws; + + ws = BotWeaponStateFromHandle(weaponstate); + if (!ws) return; + if (ws->weaponweightconfig) FreeWeightConfig(ws->weaponweightconfig); + if (ws->weaponweightindex) FreeMemory(ws->weaponweightindex); +} //end of the function BotFreeWeaponWeights +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotLoadWeaponWeights(int weaponstate, char *filename) +{ + bot_weaponstate_t *ws; + + ws = BotWeaponStateFromHandle(weaponstate); + if (!ws) return BLERR_CANNOTLOADWEAPONWEIGHTS; + BotFreeWeaponWeights(weaponstate); + // + ws->weaponweightconfig = ReadWeightConfig(filename); + if (!ws->weaponweightconfig) + { + botimport.Print(PRT_FATAL, "couldn't load weapon config %s\n", filename); + return BLERR_CANNOTLOADWEAPONWEIGHTS; + } //end if + if (!weaponconfig) return BLERR_CANNOTLOADWEAPONCONFIG; + ws->weaponweightindex = WeaponWeightIndex(ws->weaponweightconfig, weaponconfig); + return BLERR_NOERROR; +} //end of the function BotLoadWeaponWeights +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotGetWeaponInfo(int weaponstate, int weapon, weaponinfo_t *weaponinfo) +{ + bot_weaponstate_t *ws; + + if (!BotValidWeaponNumber(weapon)) return; + ws = BotWeaponStateFromHandle(weaponstate); + if (!ws) return; + if (!weaponconfig) return; + Com_Memcpy(weaponinfo, &weaponconfig->weaponinfo[weapon], sizeof(weaponinfo_t)); +} //end of the function BotGetWeaponInfo +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotChooseBestFightWeapon(int weaponstate, int *inventory) +{ + int i, index, bestweapon; + float weight, bestweight; + weaponconfig_t *wc; + bot_weaponstate_t *ws; + + ws = BotWeaponStateFromHandle(weaponstate); + if (!ws) return 0; + wc = weaponconfig; + if (!weaponconfig) return 0; + + //if the bot has no weapon weight configuration + if (!ws->weaponweightconfig) return 0; + + bestweight = 0; + bestweapon = 0; + for (i = 0; i < wc->numweapons; i++) + { + if (!wc->weaponinfo[i].valid) continue; + index = ws->weaponweightindex[i]; + if (index < 0) continue; + weight = FuzzyWeight(inventory, ws->weaponweightconfig, index); + if (weight > bestweight) + { + bestweight = weight; + bestweapon = i; + } //end if + } //end for + return bestweapon; +} //end of the function BotChooseBestFightWeapon +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotResetWeaponState(int weaponstate) +{ + struct weightconfig_s *weaponweightconfig; + int *weaponweightindex; + bot_weaponstate_t *ws; + + ws = BotWeaponStateFromHandle(weaponstate); + if (!ws) return; + weaponweightconfig = ws->weaponweightconfig; + weaponweightindex = ws->weaponweightindex; + + //Com_Memset(ws, 0, sizeof(bot_weaponstate_t)); + ws->weaponweightconfig = weaponweightconfig; + ws->weaponweightindex = weaponweightindex; +} //end of the function BotResetWeaponState +//======================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//======================================================================== +int BotAllocWeaponState(void) +{ + int i; + + for (i = 1; i <= MAX_CLIENTS; i++) + { + if (!botweaponstates[i]) + { + botweaponstates[i] = (struct bot_weaponstate_s *)GetClearedMemory(sizeof(bot_weaponstate_t)); + return i; + } //end if + } //end for + return 0; +} //end of the function BotAllocWeaponState +//======================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//======================================================================== +void BotFreeWeaponState(int handle) +{ + if (handle <= 0 || handle > MAX_CLIENTS) + { + botimport.Print(PRT_FATAL, "weapon state handle %d out of range\n", handle); + return; + } //end if + if (!botweaponstates[handle]) + { + botimport.Print(PRT_FATAL, "invalid weapon state %d\n", handle); + return; + } //end if + BotFreeWeaponWeights(handle); + FreeMemory(botweaponstates[handle]); + botweaponstates[handle] = NULL; +} //end of the function BotFreeWeaponState +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotSetupWeaponAI(void) +{ + char *file; + + file = LibVarString("weaponconfig", "weapons.c"); + weaponconfig = LoadWeaponConfig(file); + if (!weaponconfig) + { + botimport.Print(PRT_FATAL, "couldn't load the weapon config\n"); + return BLERR_CANNOTLOADWEAPONCONFIG; + } //end if + +#ifdef DEBUG_AI_WEAP + DumpWeaponConfig(weaponconfig); +#endif //DEBUG_AI_WEAP + // + return BLERR_NOERROR; +} //end of the function BotSetupWeaponAI +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotShutdownWeaponAI(void) +{ + int i; + + if (weaponconfig) FreeMemory(weaponconfig); + weaponconfig = NULL; + + for (i = 1; i <= MAX_CLIENTS; i++) + { + if (botweaponstates[i]) + { + BotFreeWeaponState(i); + } //end if + } //end for +} //end of the function BotShutdownWeaponAI + diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_weap.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_weap.h new file mode 100644 index 0000000..34ededb --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_weap.h @@ -0,0 +1,110 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_ai_weap.h + * + * desc: weapon AI + * + * $Archive: /source/code/botlib/be_ai_weap.h $ + * $Author: osman $ + * $Revision: 1.4 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 2003/03/15 23:44:00 $ + * + *****************************************************************************/ + +#pragma once + +//projectile flags +#define PFL_WINDOWDAMAGE 1 //projectile damages through window +#define PFL_RETURN 2 //set when projectile returns to owner +//weapon flags +#define WFL_FIRERELEASED 1 //set when projectile is fired with key-up event +//damage types +#define DAMAGETYPE_IMPACT 1 //damage on impact +#define DAMAGETYPE_RADIAL 2 //radial damage +#define DAMAGETYPE_VISIBLE 4 //damage to all entities visible to the projectile + +typedef struct projectileinfo_s +{ + char name[MAX_STRINGFIELD]; + char model[MAX_STRINGFIELD]; + int flags; + float gravity; + int damage; + float radius; + int visdamage; + int damagetype; + int healthinc; + float push; + float detonation; + float bounce; + float bouncefric; + float bouncestop; +} projectileinfo_t; + +typedef struct weaponinfo_s +{ + int valid; //true if the weapon info is valid + int number; //number of the weapon + char name[MAX_STRINGFIELD]; + char model[MAX_STRINGFIELD]; + int level; + int weaponindex; + int flags; + char projectile[MAX_STRINGFIELD]; + int numprojectiles; + float hspread; + float vspread; + float speed; + float acceleration; + vec3_t recoil; + vec3_t offset; + vec3_t angleoffset; + float extrazvelocity; + int ammoamount; + int ammoindex; + float activate; + float reload; + float spinup; + float spindown; + projectileinfo_t proj; //pointer to the used projectile +} weaponinfo_t; + +//setup the weapon AI +int BotSetupWeaponAI(void); +//shut down the weapon AI +void BotShutdownWeaponAI(void); +//returns the best weapon to fight with +int BotChooseBestFightWeapon(int weaponstate, int *inventory); +//returns the information of the current weapon +void BotGetWeaponInfo(int weaponstate, int weapon, weaponinfo_t *weaponinfo); +//loads the weapon weights +int BotLoadWeaponWeights(int weaponstate, char *filename); +//returns a handle to a newly allocated weapon state +int BotAllocWeaponState(void); +//frees the weapon state +void BotFreeWeaponState(int weaponstate); +//resets the whole weapon state +void BotResetWeaponState(int weaponstate); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_weight.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_weight.cpp new file mode 100644 index 0000000..6f5d74d --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_weight.cpp @@ -0,0 +1,930 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_ai_weight.c + * + * desc: fuzzy logic + * + * $Archive: /MissionPack/code/botlib/be_ai_weight.c $ + * $Author: Mrelusive $ + * $Revision: 3 $ + * $Modtime: 8/06/00 5:25p $ + * $Date: 8/06/00 11:07p $ + * + *****************************************************************************/ + +#include "qcommon/q_shared.h" +#include "l_memory.h" +#include "l_log.h" +#include "l_utils.h" +#include "l_script.h" +#include "l_precomp.h" +#include "l_struct.h" +#include "l_libvar.h" +#include "aasfile.h" +#include "botlib.h" +#include "be_aas.h" +#include "be_aas_funcs.h" +#include "be_interface.h" +#include "be_ai_weight.h" + +#define MAX_INVENTORYVALUE 999999 +#define EVALUATERECURSIVELY + +#define MAX_WEIGHT_FILES 128 +weightconfig_t *weightFileList[MAX_WEIGHT_FILES]; + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int ReadValue(source_t *source, float *value) +{ + token_t token; + + if (!PC_ExpectAnyToken(source, &token)) return qfalse; + if (!strcmp(token.string, "-")) + { + SourceWarning(source, "negative value set to zero"); + + if(!PC_ExpectAnyToken(source, &token)) + { + SourceError(source, "Missing return value"); + return qfalse; + } + } + + if (token.type != TT_NUMBER) + { + SourceError(source, "invalid return value %s", token.string); + return qfalse; + } + + *value = token.floatvalue; + return qtrue; +} //end of the function ReadValue +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int ReadFuzzyWeight(source_t *source, fuzzyseperator_t *fs) +{ + if (PC_CheckTokenString(source, "balance")) + { + fs->type = WT_BALANCE; + if (!PC_ExpectTokenString(source, "(")) return qfalse; + if (!ReadValue(source, &fs->weight)) return qfalse; + if (!PC_ExpectTokenString(source, ",")) return qfalse; + if (!ReadValue(source, &fs->minweight)) return qfalse; + if (!PC_ExpectTokenString(source, ",")) return qfalse; + if (!ReadValue(source, &fs->maxweight)) return qfalse; + if (!PC_ExpectTokenString(source, ")")) return qfalse; + } //end if + else + { + fs->type = 0; + if (!ReadValue(source, &fs->weight)) return qfalse; + fs->minweight = fs->weight; + fs->maxweight = fs->weight; + } //end if + if (!PC_ExpectTokenString(source, ";")) return qfalse; + return qtrue; +} //end of the function ReadFuzzyWeight +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void FreeFuzzySeperators_r(fuzzyseperator_t *fs) +{ + if (!fs) return; + if (fs->child) FreeFuzzySeperators_r(fs->child); + if (fs->next) FreeFuzzySeperators_r(fs->next); + FreeMemory(fs); +} //end of the function FreeFuzzySeperators +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void FreeWeightConfig2(weightconfig_t *config) +{ + int i; + + for (i = 0; i < config->numweights; i++) + { + FreeFuzzySeperators_r(config->weights[i].firstseperator); + if (config->weights[i].name) FreeMemory(config->weights[i].name); + } //end for + FreeMemory(config); +} //end of the function FreeWeightConfig2 +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void FreeWeightConfig(weightconfig_t *config) +{ + if (!LibVarGetValue("bot_reloadcharacters")) return; + FreeWeightConfig2(config); +} //end of the function FreeWeightConfig +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +fuzzyseperator_t *ReadFuzzySeperators_r(source_t *source) +{ + int newindent, index, def, founddefault; + token_t token; + fuzzyseperator_t *fs, *lastfs, *firstfs; + + founddefault = qfalse; + firstfs = NULL; + lastfs = NULL; + if (!PC_ExpectTokenString(source, "(")) return NULL; + if (!PC_ExpectTokenType(source, TT_NUMBER, TT_INTEGER, &token)) return NULL; + index = token.intvalue; + if (!PC_ExpectTokenString(source, ")")) return NULL; + if (!PC_ExpectTokenString(source, "{")) return NULL; + if (!PC_ExpectAnyToken(source, &token)) return NULL; + do + { + def = !strcmp(token.string, "default"); + if (def || !strcmp(token.string, "case")) + { + fs = (fuzzyseperator_t *) GetClearedMemory(sizeof(fuzzyseperator_t)); + fs->index = index; + if (lastfs) lastfs->next = fs; + else firstfs = fs; + lastfs = fs; + if (def) + { + if (founddefault) + { + SourceError(source, "switch already has a default"); + FreeFuzzySeperators_r(firstfs); + return NULL; + } //end if + fs->value = MAX_INVENTORYVALUE; + founddefault = qtrue; + } //end if + else + { + if (!PC_ExpectTokenType(source, TT_NUMBER, TT_INTEGER, &token)) + { + FreeFuzzySeperators_r(firstfs); + return NULL; + } //end if + fs->value = token.intvalue; + } //end else + if (!PC_ExpectTokenString(source, ":") || !PC_ExpectAnyToken(source, &token)) + { + FreeFuzzySeperators_r(firstfs); + return NULL; + } //end if + newindent = qfalse; + if (!strcmp(token.string, "{")) + { + newindent = qtrue; + if (!PC_ExpectAnyToken(source, &token)) + { + FreeFuzzySeperators_r(firstfs); + return NULL; + } //end if + } //end if + if (!strcmp(token.string, "return")) + { + if (!ReadFuzzyWeight(source, fs)) + { + FreeFuzzySeperators_r(firstfs); + return NULL; + } //end if + } //end if + else if (!strcmp(token.string, "switch")) + { + fs->child = ReadFuzzySeperators_r(source); + if (!fs->child) + { + FreeFuzzySeperators_r(firstfs); + return NULL; + } //end if + } //end else if + else + { + SourceError(source, "invalid name %s", token.string); + return NULL; + } //end else + if (newindent) + { + if (!PC_ExpectTokenString(source, "}")) + { + FreeFuzzySeperators_r(firstfs); + return NULL; + } //end if + } //end if + } //end if + else + { + FreeFuzzySeperators_r(firstfs); + SourceError(source, "invalid name %s", token.string); + return NULL; + } //end else + if (!PC_ExpectAnyToken(source, &token)) + { + FreeFuzzySeperators_r(firstfs); + return NULL; + } //end if + } while(strcmp(token.string, "}")); + // + if (!founddefault) + { + SourceWarning(source, "switch without default"); + fs = (fuzzyseperator_t *) GetClearedMemory(sizeof(fuzzyseperator_t)); + fs->index = index; + fs->value = MAX_INVENTORYVALUE; + fs->weight = 0; + fs->next = NULL; + fs->child = NULL; + if (lastfs) lastfs->next = fs; + else firstfs = fs; + lastfs = fs; + } //end if + // + return firstfs; +} //end of the function ReadFuzzySeperators_r +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +weightconfig_t *ReadWeightConfig(char *filename) +{ + int newindent, avail = 0, n; + token_t token; + source_t *source; + fuzzyseperator_t *fs; + weightconfig_t *config = NULL; +#ifdef DEBUG + int starttime; + + starttime = Sys_MilliSeconds(); +#endif //DEBUG + + if (!LibVarGetValue("bot_reloadcharacters")) + { + avail = -1; + for( n = 0; n < MAX_WEIGHT_FILES; n++ ) + { + config = weightFileList[n]; + if( !config ) + { + if( avail == -1 ) + { + avail = n; + } //end if + continue; + } //end if + if( strcmp( filename, config->filename ) == 0 ) + { + //botimport.Print( PRT_MESSAGE, "retained %s\n", filename ); + return config; + } //end if + } //end for + + if( avail == -1 ) + { + botimport.Print( PRT_ERROR, "weightFileList was full trying to load %s\n", filename ); + return NULL; + } //end if + } //end if + + PC_SetBaseFolder(BOTFILESBASEFOLDER); + source = LoadSourceFile(filename); + if (!source) + { + botimport.Print(PRT_ERROR, "counldn't load %s\n", filename); + return NULL; + } //end if + // + config = (weightconfig_t *) GetClearedMemory(sizeof(weightconfig_t)); + config->numweights = 0; + Q_strncpyz( config->filename, filename, sizeof(config->filename) ); + //parse the item config file + while(PC_ReadToken(source, &token)) + { + if (!strcmp(token.string, "weight")) + { + if (config->numweights >= MAX_WEIGHTS) + { + SourceWarning(source, "too many fuzzy weights"); + break; + } //end if + if (!PC_ExpectTokenType(source, TT_STRING, 0, &token)) + { + FreeWeightConfig(config); + FreeSource(source); + return NULL; + } //end if + StripDoubleQuotes(token.string); + config->weights[config->numweights].name = (char *) GetClearedMemory(strlen(token.string) + 1); + strcpy(config->weights[config->numweights].name, token.string); + if (!PC_ExpectAnyToken(source, &token)) + { + FreeWeightConfig(config); + FreeSource(source); + return NULL; + } //end if + newindent = qfalse; + if (!strcmp(token.string, "{")) + { + newindent = qtrue; + if (!PC_ExpectAnyToken(source, &token)) + { + FreeWeightConfig(config); + FreeSource(source); + return NULL; + } //end if + } //end if + if (!strcmp(token.string, "switch")) + { + fs = ReadFuzzySeperators_r(source); + if (!fs) + { + FreeWeightConfig(config); + FreeSource(source); + return NULL; + } //end if + config->weights[config->numweights].firstseperator = fs; + } //end if + else if (!strcmp(token.string, "return")) + { + fs = (fuzzyseperator_t *) GetClearedMemory(sizeof(fuzzyseperator_t)); + fs->index = 0; + fs->value = MAX_INVENTORYVALUE; + fs->next = NULL; + fs->child = NULL; + if (!ReadFuzzyWeight(source, fs)) + { + FreeMemory(fs); + FreeWeightConfig(config); + FreeSource(source); + return NULL; + } //end if + config->weights[config->numweights].firstseperator = fs; + } //end else if + else + { + SourceError(source, "invalid name %s", token.string); + FreeWeightConfig(config); + FreeSource(source); + return NULL; + } //end else + if (newindent) + { + if (!PC_ExpectTokenString(source, "}")) + { + FreeWeightConfig(config); + FreeSource(source); + return NULL; + } //end if + } //end if + config->numweights++; + } //end if + else + { + SourceError(source, "invalid name %s", token.string); + FreeWeightConfig(config); + FreeSource(source); + return NULL; + } //end else + } //end while + //free the source at the end of a pass + FreeSource(source); + //if the file was located in a pak file + botimport.Print(PRT_MESSAGE, "loaded %s\n", filename); +#ifdef DEBUG + if (botDeveloper) + { + botimport.Print(PRT_MESSAGE, "weights loaded in %d msec\n", Sys_MilliSeconds() - starttime); + } //end if +#endif //DEBUG + // + if (!LibVarGetValue("bot_reloadcharacters")) + { + weightFileList[avail] = config; + } //end if + // + return config; +} //end of the function ReadWeightConfig +#if 0 +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +qboolean WriteFuzzyWeight(FILE *fp, fuzzyseperator_t *fs) +{ + if (fs->type == WT_BALANCE) + { + if (fprintf(fp, " return balance(") < 0) return qfalse; + if (!WriteFloat(fp, fs->weight)) return qfalse; + if (fprintf(fp, ",") < 0) return qfalse; + if (!WriteFloat(fp, fs->minweight)) return qfalse; + if (fprintf(fp, ",") < 0) return qfalse; + if (!WriteFloat(fp, fs->maxweight)) return qfalse; + if (fprintf(fp, ");\n") < 0) return qfalse; + } //end if + else + { + if (fprintf(fp, " return ") < 0) return qfalse; + if (!WriteFloat(fp, fs->weight)) return qfalse; + if (fprintf(fp, ";\n") < 0) return qfalse; + } //end else + return qtrue; +} //end of the function WriteFuzzyWeight +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +qboolean WriteFuzzySeperators_r(FILE *fp, fuzzyseperator_t *fs, int indent) +{ + if (!WriteIndent(fp, indent)) return qfalse; + if (fprintf(fp, "switch(%d)\n", fs->index) < 0) return qfalse; + if (!WriteIndent(fp, indent)) return qfalse; + if (fprintf(fp, "{\n") < 0) return qfalse; + indent++; + do + { + if (!WriteIndent(fp, indent)) return qfalse; + if (fs->next) + { + if (fprintf(fp, "case %d:", fs->value) < 0) return qfalse; + } //end if + else + { + if (fprintf(fp, "default:") < 0) return qfalse; + } //end else + if (fs->child) + { + if (fprintf(fp, "\n") < 0) return qfalse; + if (!WriteIndent(fp, indent)) return qfalse; + if (fprintf(fp, "{\n") < 0) return qfalse; + if (!WriteFuzzySeperators_r(fp, fs->child, indent + 1)) return qfalse; + if (!WriteIndent(fp, indent)) return qfalse; + if (fs->next) + { + if (fprintf(fp, "} //end case\n") < 0) return qfalse; + } //end if + else + { + if (fprintf(fp, "} //end default\n") < 0) return qfalse; + } //end else + } //end if + else + { + if (!WriteFuzzyWeight(fp, fs)) return qfalse; + } //end else + fs = fs->next; + } while(fs); + indent--; + if (!WriteIndent(fp, indent)) return qfalse; + if (fprintf(fp, "} //end switch\n") < 0) return qfalse; + return qtrue; +} //end of the function WriteItemFuzzyWeights_r +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +qboolean WriteWeightConfig(char *filename, weightconfig_t *config) +{ + int i; + FILE *fp; + weight_t *ifw; + + fp = fopen(filename, "wb"); + if (!fp) return qfalse; + + for (i = 0; i < config->numweights; i++) + { + ifw = &config->weights[i]; + if (fprintf(fp, "\nweight \"%s\"\n", ifw->name) < 0) return qfalse; + if (fprintf(fp, "{\n") < 0) return qfalse; + if (ifw->firstseperator->index > 0) + { + if (!WriteFuzzySeperators_r(fp, ifw->firstseperator, 1)) return qfalse; + } //end if + else + { + if (!WriteIndent(fp, 1)) return qfalse; + if (!WriteFuzzyWeight(fp, ifw->firstseperator)) return qfalse; + } //end else + if (fprintf(fp, "} //end weight\n") < 0) return qfalse; + } //end for + fclose(fp); + return qtrue; +} //end of the function WriteWeightConfig +#endif +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int FindFuzzyWeight(weightconfig_t *wc, char *name) +{ + int i; + + for (i = 0; i < wc->numweights; i++) + { + if (!strcmp(wc->weights[i].name, name)) + { + return i; + } //end if + } //end if + return -1; +} //end of the function FindFuzzyWeight +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float FuzzyWeight_r(int *inventory, fuzzyseperator_t *fs) +{ + float scale, w1, w2; + + if (inventory[fs->index] < fs->value) + { + if (fs->child) return FuzzyWeight_r(inventory, fs->child); + else return fs->weight; + } //end if + else if (fs->next) + { + if (inventory[fs->index] < fs->next->value) + { + //first weight + if (fs->child) w1 = FuzzyWeight_r(inventory, fs->child); + else w1 = fs->weight; + //second weight + if (fs->next->child) w2 = FuzzyWeight_r(inventory, fs->next->child); + else w2 = fs->next->weight; + //the scale factor + if(fs->next->value == MAX_INVENTORYVALUE) // is fs->next the default case? + return w2; // can't interpolate, return default weight + else + scale = (float) (inventory[fs->index] - fs->value) / (fs->next->value - fs->value); + //scale between the two weights + return (1 - scale) * w1 + scale * w2; + } //end if + return FuzzyWeight_r(inventory, fs->next); + } //end else if + return fs->weight; +} //end of the function FuzzyWeight_r +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float FuzzyWeightUndecided_r(int *inventory, fuzzyseperator_t *fs) +{ + float scale, w1, w2; + + if (inventory[fs->index] < fs->value) + { + if (fs->child) return FuzzyWeightUndecided_r(inventory, fs->child); + else return fs->minweight + Q_flrand(0.0f, 1.0f) * (fs->maxweight - fs->minweight); + } //end if + else if (fs->next) + { + if (inventory[fs->index] < fs->next->value) + { + //first weight + if (fs->child) w1 = FuzzyWeightUndecided_r(inventory, fs->child); + else w1 = fs->minweight + Q_flrand(0.0f, 1.0f) * (fs->maxweight - fs->minweight); + //second weight + if (fs->next->child) w2 = FuzzyWeight_r(inventory, fs->next->child); + else w2 = fs->next->minweight + Q_flrand(0.0f, 1.0f) * (fs->next->maxweight - fs->next->minweight); + //the scale factor + if(fs->next->value == MAX_INVENTORYVALUE) // is fs->next the default case? + return w2; // can't interpolate, return default weight + else + scale = (float) (inventory[fs->index] - fs->value) / (fs->next->value - fs->value); + //scale between the two weights + return (1 - scale) * w1 + scale * w2; + } //end if + return FuzzyWeightUndecided_r(inventory, fs->next); + } //end else if + return fs->weight; +} //end of the function FuzzyWeightUndecided_r +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float FuzzyWeight(int *inventory, weightconfig_t *wc, int weightnum) +{ +#ifdef EVALUATERECURSIVELY + return FuzzyWeight_r(inventory, wc->weights[weightnum].firstseperator); +#else + fuzzyseperator_t *s; + + s = wc->weights[weightnum].firstseperator; + if (!s) return 0; + while(1) + { + if (inventory[s->index] < s->value) + { + if (s->child) s = s->child; + else return s->weight; + } //end if + else + { + if (s->next) s = s->next; + else return s->weight; + } //end else + } //end if + return 0; +#endif +} //end of the function FuzzyWeight +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float FuzzyWeightUndecided(int *inventory, weightconfig_t *wc, int weightnum) +{ +#ifdef EVALUATERECURSIVELY + return FuzzyWeightUndecided_r(inventory, wc->weights[weightnum].firstseperator); +#else + fuzzyseperator_t *s; + + s = wc->weights[weightnum].firstseperator; + if (!s) return 0; + while(1) + { + if (inventory[s->index] < s->value) + { + if (s->child) s = s->child; + else return s->minweight + Q_flrand(0.0f, 1.0f) * (s->maxweight - s->minweight); + } //end if + else + { + if (s->next) s = s->next; + else return s->minweight + Q_flrand(0.0f, 1.0f) * (s->maxweight - s->minweight); + } //end else + } //end if + return 0; +#endif +} //end of the function FuzzyWeightUndecided +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EvolveFuzzySeperator_r(fuzzyseperator_t *fs) +{ + if (fs->child) + { + EvolveFuzzySeperator_r(fs->child); + } //end if + else if (fs->type == WT_BALANCE) + { + //every once in a while an evolution leap occurs, mutation + if (Q_flrand(0.0f, 1.0f) < 0.01) fs->weight += Q_flrand(-1.0f, 1.0f) * (fs->maxweight - fs->minweight); + else fs->weight += Q_flrand(-1.0f, 1.0f) * (fs->maxweight - fs->minweight) * 0.5; + //modify bounds if necesary because of mutation + if (fs->weight < fs->minweight) fs->minweight = fs->weight; + else if (fs->weight > fs->maxweight) fs->maxweight = fs->weight; + } //end else if + if (fs->next) EvolveFuzzySeperator_r(fs->next); +} //end of the function EvolveFuzzySeperator_r +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EvolveWeightConfig(weightconfig_t *config) +{ + int i; + + for (i = 0; i < config->numweights; i++) + { + EvolveFuzzySeperator_r(config->weights[i].firstseperator); + } //end for +} //end of the function EvolveWeightConfig +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void ScaleFuzzySeperator_r(fuzzyseperator_t *fs, float scale) +{ + if (fs->child) + { + ScaleFuzzySeperator_r(fs->child, scale); + } //end if + else if (fs->type == WT_BALANCE) + { + // + fs->weight = (float) (fs->maxweight + fs->minweight) * scale; + //get the weight between bounds + if (fs->weight < fs->minweight) fs->weight = fs->minweight; + else if (fs->weight > fs->maxweight) fs->weight = fs->maxweight; + } //end else if + if (fs->next) ScaleFuzzySeperator_r(fs->next, scale); +} //end of the function ScaleFuzzySeperator_r +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void ScaleWeight(weightconfig_t *config, char *name, float scale) +{ + int i; + + if (scale < 0) scale = 0; + else if (scale > 1) scale = 1; + for (i = 0; i < config->numweights; i++) + { + if (!strcmp(name, config->weights[i].name)) + { + ScaleFuzzySeperator_r(config->weights[i].firstseperator, scale); + break; + } //end if + } //end for +} //end of the function ScaleWeight +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void ScaleFuzzySeperatorBalanceRange_r(fuzzyseperator_t *fs, float scale) +{ + if (fs->child) + { + ScaleFuzzySeperatorBalanceRange_r(fs->child, scale); + } //end if + else if (fs->type == WT_BALANCE) + { + float mid = (fs->minweight + fs->maxweight) * 0.5; + //get the weight between bounds + fs->maxweight = mid + (fs->maxweight - mid) * scale; + fs->minweight = mid + (fs->minweight - mid) * scale; + if (fs->maxweight < fs->minweight) + { + fs->maxweight = fs->minweight; + } //end if + } //end else if + if (fs->next) ScaleFuzzySeperatorBalanceRange_r(fs->next, scale); +} //end of the function ScaleFuzzySeperatorBalanceRange_r +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void ScaleFuzzyBalanceRange(weightconfig_t *config, float scale) +{ + int i; + + if (scale < 0) scale = 0; + else if (scale > 100) scale = 100; + for (i = 0; i < config->numweights; i++) + { + ScaleFuzzySeperatorBalanceRange_r(config->weights[i].firstseperator, scale); + } //end for +} //end of the function ScaleFuzzyBalanceRange +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int InterbreedFuzzySeperator_r(fuzzyseperator_t *fs1, fuzzyseperator_t *fs2, + fuzzyseperator_t *fsout) +{ + if (fs1->child) + { + if (!fs2->child || !fsout->child) + { + botimport.Print(PRT_ERROR, "cannot interbreed weight configs, unequal child\n"); + return qfalse; + } //end if + if (!InterbreedFuzzySeperator_r(fs2->child, fs2->child, fsout->child)) + { + return qfalse; + } //end if + } //end if + else if (fs1->type == WT_BALANCE) + { + if (fs2->type != WT_BALANCE || fsout->type != WT_BALANCE) + { + botimport.Print(PRT_ERROR, "cannot interbreed weight configs, unequal balance\n"); + return qfalse; + } //end if + fsout->weight = (fs1->weight + fs2->weight) / 2; + if (fsout->weight > fsout->maxweight) fsout->maxweight = fsout->weight; + if (fsout->weight > fsout->minweight) fsout->minweight = fsout->weight; + } //end else if + if (fs1->next) + { + if (!fs2->next || !fsout->next) + { + botimport.Print(PRT_ERROR, "cannot interbreed weight configs, unequal next\n"); + return qfalse; + } //end if + if (!InterbreedFuzzySeperator_r(fs1->next, fs2->next, fsout->next)) + { + return qfalse; + } //end if + } //end if + return qtrue; +} //end of the function InterbreedFuzzySeperator_r +//=========================================================================== +// config1 and config2 are interbreeded and stored in configout +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void InterbreedWeightConfigs(weightconfig_t *config1, weightconfig_t *config2, + weightconfig_t *configout) +{ + int i; + + if (config1->numweights != config2->numweights || + config1->numweights != configout->numweights) + { + botimport.Print(PRT_ERROR, "cannot interbreed weight configs, unequal numweights\n"); + return; + } //end if + for (i = 0; i < config1->numweights; i++) + { + InterbreedFuzzySeperator_r(config1->weights[i].firstseperator, + config2->weights[i].firstseperator, + configout->weights[i].firstseperator); + } //end for +} //end of the function InterbreedWeightConfigs +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotShutdownWeights(void) +{ + int i; + + for( i = 0; i < MAX_WEIGHT_FILES; i++ ) + { + if (weightFileList[i]) + { + FreeWeightConfig2(weightFileList[i]); + weightFileList[i] = NULL; + } //end if + } //end for +} //end of the function BotShutdownWeights diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_weight.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_weight.h new file mode 100644 index 0000000..145abf0 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ai_weight.h @@ -0,0 +1,90 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_ai_weight.h + * + * desc: fuzzy weights + * + * $Archive: /source/code/botlib/be_ai_weight.h $ + * $Author: Mrelusive $ + * $Revision: 2 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 10/05/99 3:42p $ + * + *****************************************************************************/ + +#pragma once + +#define WT_BALANCE 1 +#define MAX_WEIGHTS 128 + +//fuzzy seperator +typedef struct fuzzyseperator_s +{ + int index; + int value; + int type; + float weight; + float minweight; + float maxweight; + struct fuzzyseperator_s *child; + struct fuzzyseperator_s *next; +} fuzzyseperator_t; + +//fuzzy weight +typedef struct weight_s +{ + char *name; + struct fuzzyseperator_s *firstseperator; +} weight_t; + +//weight configuration +typedef struct weightconfig_s +{ + int numweights; + weight_t weights[MAX_WEIGHTS]; + char filename[MAX_QPATH]; +} weightconfig_t; + +//reads a weight configuration +weightconfig_t *ReadWeightConfig(char *filename); +//free a weight configuration +void FreeWeightConfig(weightconfig_t *config); +//writes a weight configuration, returns true if successfull +qboolean WriteWeightConfig(char *filename, weightconfig_t *config); +//find the fuzzy weight with the given name +int FindFuzzyWeight(weightconfig_t *wc, char *name); +//returns the fuzzy weight for the given inventory and weight +float FuzzyWeight(int *inventory, weightconfig_t *wc, int weightnum); +float FuzzyWeightUndecided(int *inventory, weightconfig_t *wc, int weightnum); +//scales the weight with the given name +void ScaleWeight(weightconfig_t *config, char *name, float scale); +//scale the balance range +void ScaleBalanceRange(weightconfig_t *config, float scale); +//evolves the weight configuration +void EvolveWeightConfig(weightconfig_t *config); +//interbreed the weight configurations and stores the interbreeded one in configout +void InterbreedWeightConfigs(weightconfig_t *config1, weightconfig_t *config2, weightconfig_t *configout); +//frees cached weight configurations +void BotShutdownWeights(void); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ea.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ea.cpp new file mode 100644 index 0000000..24ea43b --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ea.cpp @@ -0,0 +1,511 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_ea.c + * + * desc: elementary actions + * + * $Archive: /MissionPack/code/botlib/be_ea.c $ + * $Author: Zaphod $ + * $Revision: 5 $ + * $Modtime: 11/22/00 8:50a $ + * $Date: 11/22/00 8:55a $ + * + *****************************************************************************/ + +#include "qcommon/q_shared.h" +#include "l_memory.h" +#include "l_script.h" +#include "l_precomp.h" +#include "l_struct.h" +#include "botlib.h" +#include "be_interface.h" +#include "be_ea.h" + +#define MAX_USERMOVE 400 +#define MAX_COMMANDARGUMENTS 10 +#define ACTION_JUMPEDLASTFRAME 0x0800000//128 + +bot_input_t *botinputs; + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_Say(int client, char *str) +{ + botimport.BotClientCommand(client, va("say %s", str) ); +} //end of the function EA_Say +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_SayTeam(int client, char *str) +{ + botimport.BotClientCommand(client, va("say_team %s", str)); +} //end of the function EA_SayTeam +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_Tell(int client, int clientto, char *str) +{ + botimport.BotClientCommand(client, va("tell %d, %s", clientto, str)); +} //end of the function EA_SayTeam +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_UseItem(int client, char *it) +{ + botimport.BotClientCommand(client, va("use %s", it)); +} //end of the function EA_UseItem +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_DropItem(int client, char *it) +{ + botimport.BotClientCommand(client, va("drop %s", it)); +} //end of the function EA_DropItem +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_UseInv(int client, char *inv) +{ + botimport.BotClientCommand(client, va("invuse %s", inv)); +} //end of the function EA_UseInv +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_DropInv(int client, char *inv) +{ + botimport.BotClientCommand(client, va("invdrop %s", inv)); +} //end of the function EA_DropInv +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_Gesture(int client) +{ + bot_input_t *bi; + + bi = &botinputs[client]; + + bi->actionflags |= ACTION_GESTURE; +} //end of the function EA_Gesture +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_Command(int client, char *command) +{ + botimport.BotClientCommand(client, command); +} //end of the function EA_Command +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_SelectWeapon(int client, int weapon) +{ + bot_input_t *bi; + + bi = &botinputs[client]; + + bi->weapon = weapon; +} //end of the function EA_SelectWeapon +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_Attack(int client) +{ + bot_input_t *bi; + + bi = &botinputs[client]; + + bi->actionflags |= ACTION_ATTACK; +} //end of the function EA_Attack +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_Alt_Attack(int client) +{ + bot_input_t *bi; + + bi = &botinputs[client]; + + bi->actionflags |= ACTION_ALT_ATTACK; +} //end of the function EA_Alt_Attack +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_ForcePower(int client) +{ + bot_input_t *bi; + + bi = &botinputs[client]; + + bi->actionflags |= ACTION_FORCEPOWER; +} //end of the function EA_ForcePower +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_Talk(int client) +{ + bot_input_t *bi; + + bi = &botinputs[client]; + + bi->actionflags |= ACTION_TALK; +} //end of the function EA_Talk +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_Use(int client) +{ + bot_input_t *bi; + + bi = &botinputs[client]; + + bi->actionflags |= ACTION_USE; +} //end of the function EA_Use +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_Respawn(int client) +{ + bot_input_t *bi; + + bi = &botinputs[client]; + + bi->actionflags |= ACTION_RESPAWN; +} //end of the function EA_Respawn +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_Jump(int client) +{ + bot_input_t *bi; + + bi = &botinputs[client]; + + if (bi->actionflags & ACTION_JUMPEDLASTFRAME) + { + bi->actionflags &= ~ACTION_JUMP; + } //end if + else + { + bi->actionflags |= ACTION_JUMP; + } //end if +} //end of the function EA_Jump +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_DelayedJump(int client) +{ + bot_input_t *bi; + + bi = &botinputs[client]; + + if (bi->actionflags & ACTION_JUMPEDLASTFRAME) + { + bi->actionflags &= ~ACTION_DELAYEDJUMP; + } //end if + else + { + bi->actionflags |= ACTION_DELAYEDJUMP; + } //end if +} //end of the function EA_DelayedJump +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_Crouch(int client) +{ + bot_input_t *bi; + + bi = &botinputs[client]; + + bi->actionflags |= ACTION_CROUCH; +} //end of the function EA_Crouch +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_Walk(int client) +{ + bot_input_t *bi; + + bi = &botinputs[client]; + + bi->actionflags |= ACTION_WALK; +} //end of the function EA_Walk +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_Action(int client, int action) +{ + bot_input_t *bi; + + bi = &botinputs[client]; + + bi->actionflags |= action; +} //end of function EA_Action +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_MoveUp(int client) +{ + bot_input_t *bi; + + bi = &botinputs[client]; + + bi->actionflags |= ACTION_MOVEUP; +} //end of the function EA_MoveUp +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_MoveDown(int client) +{ + bot_input_t *bi; + + bi = &botinputs[client]; + + bi->actionflags |= ACTION_MOVEDOWN; +} //end of the function EA_MoveDown +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_MoveForward(int client) +{ + bot_input_t *bi; + + bi = &botinputs[client]; + + bi->actionflags |= ACTION_MOVEFORWARD; +} //end of the function EA_MoveForward +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_MoveBack(int client) +{ + bot_input_t *bi; + + bi = &botinputs[client]; + + bi->actionflags |= ACTION_MOVEBACK; +} //end of the function EA_MoveBack +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_MoveLeft(int client) +{ + bot_input_t *bi; + + bi = &botinputs[client]; + + bi->actionflags |= ACTION_MOVELEFT; +} //end of the function EA_MoveLeft +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_MoveRight(int client) +{ + bot_input_t *bi; + + bi = &botinputs[client]; + + bi->actionflags |= ACTION_MOVERIGHT; +} //end of the function EA_MoveRight +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_Move(int client, vec3_t dir, float speed) +{ + bot_input_t *bi; + + bi = &botinputs[client]; + + VectorCopy(dir, bi->dir); + //cap speed + if (speed > MAX_USERMOVE) speed = MAX_USERMOVE; + else if (speed < -MAX_USERMOVE) speed = -MAX_USERMOVE; + bi->speed = speed; +} //end of the function EA_Move +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_View(int client, vec3_t viewangles) +{ + bot_input_t *bi; + + bi = &botinputs[client]; + + VectorCopy(viewangles, bi->viewangles); +} //end of the function EA_View +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_EndRegular(int client, float thinktime) +{ +} //end of the function EA_EndRegular +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_GetInput(int client, float thinktime, bot_input_t *input) +{ + bot_input_t *bi; + + bi = &botinputs[client]; + bi->thinktime = thinktime; + Com_Memcpy(input, bi, sizeof(bot_input_t)); +} //end of the function EA_GetInput +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_ResetInput(int client) +{ + bot_input_t *bi; + int jumped = qfalse; + + bi = &botinputs[client]; + bi->actionflags &= ~ACTION_JUMPEDLASTFRAME; + + bi->thinktime = 0; + VectorClear(bi->dir); + bi->speed = 0; + jumped = bi->actionflags & ACTION_JUMP; + bi->actionflags = 0; + if (jumped) bi->actionflags |= ACTION_JUMPEDLASTFRAME; +} //end of the function EA_ResetInput +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int EA_Setup(void) +{ + //initialize the bot inputs + botinputs = (bot_input_t *) GetClearedHunkMemory( + botlibglobals.maxclients * sizeof(bot_input_t)); + return BLERR_NOERROR; +} //end of the function EA_Setup +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void EA_Shutdown(void) +{ + FreeMemory(botinputs); + botinputs = NULL; +} //end of the function EA_Shutdown diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ea.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ea.h new file mode 100644 index 0000000..ccacd53 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_ea.h @@ -0,0 +1,74 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_ea.h + * + * desc: elementary actions + * + * $Archive: /source/code/botlib/be_ea.h $ + * $Author: osman $ + * $Revision: 1.4 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 2003/03/15 23:44:00 $ + * + *****************************************************************************/ + +#pragma once + +//ClientCommand elementary actions +void EA_Say(int client, char *str); +void EA_SayTeam(int client, char *str); +void EA_Command(int client, char *command ); + +void EA_Action(int client, int action); +void EA_Crouch(int client); +void EA_Walk(int client); +void EA_MoveUp(int client); +void EA_MoveDown(int client); +void EA_MoveForward(int client); +void EA_MoveBack(int client); +void EA_MoveLeft(int client); +void EA_MoveRight(int client); +void EA_Attack(int client); +void EA_Alt_Attack(int client); +void EA_ForcePower(int client); +void EA_Respawn(int client); +void EA_Talk(int client); +void EA_Gesture(int client); +void EA_Use(int client); + +//regular elementary actions +void EA_SelectWeapon(int client, int weapon); +void EA_Jump(int client); +void EA_DelayedJump(int client); +void EA_Move(int client, vec3_t dir, float speed); +void EA_View(int client, vec3_t viewangles); + +//send regular input to the server +void EA_EndRegular(int client, float thinktime); +void EA_GetInput(int client, float thinktime, bot_input_t *input); +void EA_ResetInput(int client); +//setup and shutdown routines +int EA_Setup(void); +void EA_Shutdown(void); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_interface.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_interface.cpp new file mode 100644 index 0000000..6d61da9 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_interface.cpp @@ -0,0 +1,914 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_interface.c // bk010221 - FIXME - DEAD code elimination + * + * desc: bot library interface + * + * $Archive: /MissionPack/code/botlib/be_interface.c $ + * $Author: Zaphod $ + * $Revision: 16 $ + * $Modtime: 5/16/01 2:36p $ + * $Date: 5/16/01 2:41p $ + * + *****************************************************************************/ + +#include "qcommon/q_shared.h" +#include "l_memory.h" +#include "l_log.h" +#include "l_libvar.h" +#include "l_script.h" +#include "l_precomp.h" +#include "l_struct.h" +#include "aasfile.h" +#include "botlib.h" +#include "be_aas.h" +#include "be_aas_funcs.h" +#include "be_aas_def.h" +#include "be_interface.h" + +#include "be_ea.h" +#include "be_ai_weight.h" +#include "be_ai_goal.h" +#include "be_ai_move.h" +#include "be_ai_weap.h" +#include "be_ai_chat.h" +#include "be_ai_char.h" +#include "be_ai_gen.h" + +//library globals in a structure +botlib_globals_t botlibglobals; + +botlib_export_t be_botlib_export; +botlib_import_t botimport; +// +int botDeveloper; +//true if the library is setup +int botlibsetup = qfalse; + +//=========================================================================== +// +// several functions used by the exported functions +// +//=========================================================================== + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int Sys_MilliSeconds(void) +{ + return clock() * 1000 / CLOCKS_PER_SEC; +} //end of the function Sys_MilliSeconds +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +qboolean ValidClientNumber(int num, char *str) +{ + if (num < 0 || num > botlibglobals.maxclients) + { + //weird: the disabled stuff results in a crash + botimport.Print(PRT_ERROR, "%s: invalid client number %d, [0, %d]\n", + str, num, botlibglobals.maxclients); + return qfalse; + } //end if + return qtrue; +} //end of the function BotValidateClientNumber +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +qboolean ValidEntityNumber(int num, char *str) +{ + if (num < 0 || num > botlibglobals.maxentities) + { + botimport.Print(PRT_ERROR, "%s: invalid entity number %d, [0, %d]\n", + str, num, botlibglobals.maxentities); + return qfalse; + } //end if + return qtrue; +} //end of the function BotValidateClientNumber +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +qboolean BotLibSetup(char *str) +{ + if (!botlibglobals.botlibsetup) + { + botimport.Print(PRT_ERROR, "%s: bot library used before being setup\n", str); + return qfalse; + } //end if + return qtrue; +} //end of the function BotLibSetup + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int Export_BotLibSetup(void) +{ + int errnum; + + botDeveloper = LibVarGetValue("bot_developer"); + memset( &botlibglobals, 0, sizeof(botlibglobals) ); // bk001207 - init + //initialize byte swapping (litte endian etc.) +// Swap_Init(); + + if(botDeveloper) + { + char *homedir, *gamedir, *basedir; + char logfilename[MAX_OSPATH]; + + homedir = LibVarGetString("homedir"); + gamedir = LibVarGetString("gamedir"); + basedir = LibVarGetString("com_basegame"); + + if (*homedir) + { + if(*gamedir) + Com_sprintf(logfilename, sizeof(logfilename), "%s%c%s%cbotlib.log", homedir, PATH_SEP, gamedir, PATH_SEP); + else if(*basedir) + Com_sprintf(logfilename, sizeof(logfilename), "%s%c%s%cbotlib.log", homedir, PATH_SEP, basedir, PATH_SEP); + else + Com_sprintf(logfilename, sizeof(logfilename), "%s%c" "base" "%cbotlib.log", homedir, PATH_SEP, PATH_SEP); //fixme use BASEGAME define + } + else + Com_sprintf(logfilename, sizeof(logfilename), "botlib.log"); + + Log_Open(logfilename); + } + // +// botimport.Print(PRT_MESSAGE, "------- BotLib Initialization -------\n"); + // + botlibglobals.maxclients = (int) LibVarValue("maxclients", "128"); + botlibglobals.maxentities = (int) LibVarValue("maxentities", "1024"); + + errnum = AAS_Setup(); //be_aas_main.c + if (errnum != BLERR_NOERROR) return errnum; + errnum = EA_Setup(); //be_ea.c + if (errnum != BLERR_NOERROR) return errnum; + /* + errnum = BotSetupWeaponAI(); //be_ai_weap.c + if (errnum != BLERR_NOERROR)return errnum; + errnum = BotSetupGoalAI(); //be_ai_goal.c + if (errnum != BLERR_NOERROR) return errnum; + errnum = BotSetupChatAI(); //be_ai_chat.c + if (errnum != BLERR_NOERROR) return errnum; + errnum = BotSetupMoveAI(); //be_ai_move.c + if (errnum != BLERR_NOERROR) return errnum; + */ + botlibsetup = qtrue; + botlibglobals.botlibsetup = qtrue; + + return BLERR_NOERROR; +} //end of the function Export_BotLibSetup +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int Export_BotLibShutdown(void) +{ + if (!BotLibSetup("BotLibShutdown")) return BLERR_LIBRARYNOTSETUP; +#ifndef DEMO + //DumpFileCRCs(); +#endif //DEMO + // + BotShutdownChatAI(); //be_ai_chat.c + BotShutdownMoveAI(); //be_ai_move.c + BotShutdownGoalAI(); //be_ai_goal.c + BotShutdownWeaponAI(); //be_ai_weap.c + BotShutdownWeights(); //be_ai_weight.c + BotShutdownCharacters(); //be_ai_char.c + //shud down aas + AAS_Shutdown(); + //shut down bot elemantary actions + EA_Shutdown(); + //free all libvars + LibVarDeAllocAll(); + //remove all global defines from the pre compiler + PC_RemoveAllGlobalDefines(); + + //dump all allocated memory +// DumpMemory(); +#ifdef DEBUG + PrintMemoryLabels(); +#endif + //shut down library log file + Log_Shutdown(); + // + botlibsetup = qfalse; + botlibglobals.botlibsetup = qfalse; + // print any files still open + PC_CheckOpenSourceHandles(); + // + return BLERR_NOERROR; +} //end of the function Export_BotLibShutdown +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int Export_BotLibVarSet(char *var_name, char *value) +{ + LibVarSet(var_name, value); + return BLERR_NOERROR; +} //end of the function Export_BotLibVarSet +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int Export_BotLibVarGet(char *var_name, char *value, int size) +{ + char *varvalue; + + varvalue = LibVarGetString(var_name); + strncpy(value, varvalue, size-1); + value[size-1] = '\0'; + return BLERR_NOERROR; +} //end of the function Export_BotLibVarGet +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int Export_BotLibStartFrame(float time) +{ + if (!BotLibSetup("BotStartFrame")) return BLERR_LIBRARYNOTSETUP; + return AAS_StartFrame(time); +} //end of the function Export_BotLibStartFrame +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int Export_BotLibLoadMap(const char *mapname) +{ +#ifdef DEBUG + int starttime = Sys_MilliSeconds(); +#endif + int errnum; + + if (!BotLibSetup("BotLoadMap")) return BLERR_LIBRARYNOTSETUP; + // + botimport.Print(PRT_MESSAGE, "------------ Map Loading ------------\n"); + //startup AAS for the current map, model and sound index + errnum = AAS_LoadMap(mapname); + if (errnum != BLERR_NOERROR) return errnum; + //initialize the items in the level + BotInitLevelItems(); //be_ai_goal.h + BotSetBrushModelTypes(); //be_ai_move.h + // + botimport.Print(PRT_MESSAGE, "-------------------------------------\n"); +#ifdef DEBUG + botimport.Print(PRT_MESSAGE, "map loaded in %d msec\n", Sys_MilliSeconds() - starttime); +#endif + // + return BLERR_NOERROR; +} //end of the function Export_BotLibLoadMap +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int Export_BotLibUpdateEntity(int ent, bot_entitystate_t *state) +{ + if (!BotLibSetup("BotUpdateEntity")) return BLERR_LIBRARYNOTSETUP; + if (!ValidEntityNumber(ent, "BotUpdateEntity")) return BLERR_INVALIDENTITYNUMBER; + + return AAS_UpdateEntity(ent, state); +} //end of the function Export_BotLibUpdateEntity +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void AAS_TestMovementPrediction(int entnum, vec3_t origin, vec3_t dir); +void ElevatorBottomCenter(aas_reachability_t *reach, vec3_t bottomcenter); +int BotGetReachabilityToGoal(vec3_t origin, int areanum, + int lastgoalareanum, int lastareanum, + int *avoidreach, float *avoidreachtimes, int *avoidreachtries, + bot_goal_t *goal, int travelflags, + struct bot_avoidspot_s *avoidspots, int numavoidspots, int *flags); + +int AAS_PointLight(vec3_t origin, int *red, int *green, int *blue); + +int AAS_TraceAreas(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas); + +int AAS_Reachability_WeaponJump(int area1num, int area2num); + +int BotFuzzyPointReachabilityArea(vec3_t origin); + +float BotGapDistance(vec3_t origin, vec3_t hordir, int entnum); + +void AAS_FloodAreas(vec3_t origin); + +int BotExportTest(int parm0, char *parm1, vec3_t parm2, vec3_t parm3) +{ + +// return AAS_PointLight(parm2, NULL, NULL, NULL); + +#ifdef DEBUG + static int area = -1; + static int line[2]; + int newarea, i, highlightarea, flood; +// int reachnum; + vec3_t eye, forward, right, end, origin; +// vec3_t bottomcenter; +// aas_trace_t trace; +// aas_face_t *face; +// aas_entity_t *ent; +// bsp_trace_t bsptrace; +// aas_reachability_t reach; +// bot_goal_t goal; + + // clock_t start_time, end_time; + vec3_t mins = {-16, -16, -24}; + vec3_t maxs = {16, 16, 32}; + +// int areas[10], numareas; + + + //return 0; + + if (!aasworld.loaded) return 0; + + /* + if (parm0 & 1) + { + AAS_ClearShownPolygons(); + AAS_FloodAreas(parm2); + } //end if + return 0; + */ + for (i = 0; i < 2; i++) if (!line[i]) line[i] = botimport.DebugLineCreate(); + +// AAS_ClearShownDebugLines(); + + //if (AAS_AgainstLadder(parm2)) botimport.Print(PRT_MESSAGE, "against ladder\n"); + //BotOnGround(parm2, PRESENCE_NORMAL, 1, &newarea, &newarea); + //botimport.Print(PRT_MESSAGE, "%f %f %f\n", parm2[0], parm2[1], parm2[2]); + //* + highlightarea = LibVarGetValue("bot_highlightarea"); + if (highlightarea > 0) + { + newarea = highlightarea; + } //end if + else + { + VectorCopy(parm2, origin); + origin[2] += 0.5; + //newarea = AAS_PointAreaNum(origin); + newarea = BotFuzzyPointReachabilityArea(origin); + } //end else + + botimport.Print(PRT_MESSAGE, "\rtravel time to goal (%d) = %d ", botlibglobals.goalareanum, + AAS_AreaTravelTimeToGoalArea(newarea, origin, botlibglobals.goalareanum, TFL_DEFAULT)); + //newarea = BotReachabilityArea(origin, qtrue); + if (newarea != area) + { + botimport.Print(PRT_MESSAGE, "origin = %f, %f, %f\n", origin[0], origin[1], origin[2]); + area = newarea; + botimport.Print(PRT_MESSAGE, "new area %d, cluster %d, presence type %d\n", + area, AAS_AreaCluster(area), AAS_PointPresenceType(origin)); + botimport.Print(PRT_MESSAGE, "area contents: "); + if (aasworld.areasettings[area].contents & AREACONTENTS_WATER) + { + botimport.Print(PRT_MESSAGE, "water &"); + } //end if + if (aasworld.areasettings[area].contents & AREACONTENTS_LAVA) + { + botimport.Print(PRT_MESSAGE, "lava &"); + } //end if + if (aasworld.areasettings[area].contents & AREACONTENTS_SLIME) + { + botimport.Print(PRT_MESSAGE, "slime &"); + } //end if + if (aasworld.areasettings[area].contents & AREACONTENTS_JUMPPAD) + { + botimport.Print(PRT_MESSAGE, "jump pad &"); + } //end if + if (aasworld.areasettings[area].contents & AREACONTENTS_CLUSTERPORTAL) + { + botimport.Print(PRT_MESSAGE, "cluster portal &"); + } //end if + if (aasworld.areasettings[area].contents & AREACONTENTS_VIEWPORTAL) + { + botimport.Print(PRT_MESSAGE, "view portal &"); + } //end if + if (aasworld.areasettings[area].contents & AREACONTENTS_DONOTENTER) + { + botimport.Print(PRT_MESSAGE, "do not enter &"); + } //end if + if (aasworld.areasettings[area].contents & AREACONTENTS_MOVER) + { + botimport.Print(PRT_MESSAGE, "mover &"); + } //end if + if (!aasworld.areasettings[area].contents) + { + botimport.Print(PRT_MESSAGE, "empty"); + } //end if + botimport.Print(PRT_MESSAGE, "\n"); + botimport.Print(PRT_MESSAGE, "travel time to goal (%d) = %d\n", botlibglobals.goalareanum, + AAS_AreaTravelTimeToGoalArea(newarea, origin, botlibglobals.goalareanum, TFL_DEFAULT|TFL_ROCKETJUMP)); + /* + VectorCopy(origin, end); + end[2] += 5; + numareas = AAS_TraceAreas(origin, end, areas, NULL, 10); + AAS_TraceClientBBox(origin, end, PRESENCE_CROUCH, -1); + botimport.Print(PRT_MESSAGE, "num areas = %d, area = %d\n", numareas, areas[0]); + */ + /* + botlibglobals.goalareanum = newarea; + VectorCopy(parm2, botlibglobals.goalorigin); + botimport.Print(PRT_MESSAGE, "new goal %2.1f %2.1f %2.1f area %d\n", + origin[0], origin[1], origin[2], newarea); + */ + } //end if + //* + flood = LibVarGetValue("bot_flood"); + if (parm0 & 1) + { + if (flood) + { + AAS_ClearShownPolygons(); + AAS_ClearShownDebugLines(); + AAS_FloodAreas(parm2); + } + else + { + botlibglobals.goalareanum = newarea; + VectorCopy(parm2, botlibglobals.goalorigin); + botimport.Print(PRT_MESSAGE, "new goal %2.1f %2.1f %2.1f area %d\n", + origin[0], origin[1], origin[2], newarea); + } + } //end if*/ + if (flood) + return 0; +// if (parm0 & BUTTON_USE) +// { +// botlibglobals.runai = !botlibglobals.runai; +// if (botlibglobals.runai) botimport.Print(PRT_MESSAGE, "started AI\n"); +// else botimport.Print(PRT_MESSAGE, "stopped AI\n"); + //* / + /* + goal.areanum = botlibglobals.goalareanum; + reachnum = BotGetReachabilityToGoal(parm2, newarea, 1, + ms.avoidreach, ms.avoidreachtimes, + &goal, TFL_DEFAULT); + if (!reachnum) + { + botimport.Print(PRT_MESSAGE, "goal not reachable\n"); + } //end if + else + { + AAS_ReachabilityFromNum(reachnum, &reach); + AAS_ClearShownDebugLines(); + AAS_ShowArea(area, qtrue); + AAS_ShowArea(reach.areanum, qtrue); + AAS_DrawCross(reach.start, 6, LINECOLOR_BLUE); + AAS_DrawCross(reach.end, 6, LINECOLOR_RED); + // + if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_ELEVATOR) + { + ElevatorBottomCenter(&reach, bottomcenter); + AAS_DrawCross(bottomcenter, 10, LINECOLOR_GREEN); + } //end if + } //end else*/ +// botimport.Print(PRT_MESSAGE, "travel time to goal = %d\n", +// AAS_AreaTravelTimeToGoalArea(area, origin, botlibglobals.goalareanum, TFL_DEFAULT)); +// botimport.Print(PRT_MESSAGE, "test rj from 703 to 716\n"); +// AAS_Reachability_WeaponJump(703, 716); +// } //end if*/ + +/* face = AAS_AreaGroundFace(newarea, parm2); + if (face) + { + AAS_ShowFace(face - aasworld.faces); + } //end if*/ + /* + AAS_ClearShownDebugLines(); + AAS_ShowArea(newarea, parm0 & BUTTON_USE); + AAS_ShowReachableAreas(area); + */ + AAS_ClearShownPolygons(); + AAS_ClearShownDebugLines(); + AAS_ShowAreaPolygons(newarea, 1, parm0 & 4); + if (parm0 & 2) AAS_ShowReachableAreas(area); + else + { + static int lastgoalareanum, lastareanum; + static int avoidreach[MAX_AVOIDREACH]; + static float avoidreachtimes[MAX_AVOIDREACH]; + static int avoidreachtries[MAX_AVOIDREACH]; + int reachnum, resultFlags; + bot_goal_t goal; + aas_reachability_t reach; + + /* + goal.areanum = botlibglobals.goalareanum; + VectorCopy(botlibglobals.goalorigin, goal.origin); + reachnum = BotGetReachabilityToGoal(origin, newarea, + lastgoalareanum, lastareanum, + avoidreach, avoidreachtimes, avoidreachtries, + &goal, TFL_DEFAULT|TFL_FUNCBOB|TFL_ROCKETJUMP, + NULL, 0, &resultFlags); + AAS_ReachabilityFromNum(reachnum, &reach); + AAS_ShowReachability(&reach); + */ + int curarea; + vec3_t curorigin; + + goal.areanum = botlibglobals.goalareanum; + VectorCopy(botlibglobals.goalorigin, goal.origin); + VectorCopy(origin, curorigin); + curarea = newarea; + for ( i = 0; i < 100; i++ ) { + if ( curarea == goal.areanum ) { + break; + } + reachnum = BotGetReachabilityToGoal(curorigin, curarea, + lastgoalareanum, lastareanum, + avoidreach, avoidreachtimes, avoidreachtries, + &goal, TFL_DEFAULT|TFL_FUNCBOB|TFL_ROCKETJUMP, + NULL, 0, &resultFlags); + AAS_ReachabilityFromNum(reachnum, &reach); + AAS_ShowReachability(&reach); + VectorCopy(reach.end, origin); + lastareanum = curarea; + curarea = reach.areanum; + } + } //end else + VectorClear(forward); + //BotGapDistance(origin, forward, 0); + /* + if (parm0 & BUTTON_USE) + { + botimport.Print(PRT_MESSAGE, "test rj from 703 to 716\n"); + AAS_Reachability_WeaponJump(703, 716); + } //end if*/ + + AngleVectors(parm3, forward, right, NULL); + //get the eye 16 units to the right of the origin + VectorMA(parm2, 8, right, eye); + //get the eye 24 units up + eye[2] += 24; + //get the end point for the line to be traced + VectorMA(eye, 800, forward, end); + +// AAS_TestMovementPrediction(1, parm2, forward); +/* + //trace the line to find the hit point + trace = AAS_TraceClientBBox(eye, end, PRESENCE_NORMAL, 1); + if (!line[0]) line[0] = botimport.DebugLineCreate(); + botimport.DebugLineShow(line[0], eye, trace.endpos, LINECOLOR_BLUE); + // + AAS_ClearShownDebugLines(); + if (trace.ent) + { + ent = &aasworld.entities[trace.ent]; + AAS_ShowBoundingBox(ent->origin, ent->mins, ent->maxs); + } //end if +*/ + +/* + start_time = clock(); + for (i = 0; i < 2000; i++) + { + AAS_Trace2(eye, mins, maxs, end, 1, MASK_PLAYERSOLID); +// AAS_TraceClientBBox(eye, end, PRESENCE_NORMAL, 1); + } //end for + end_time = clock(); + botimport.Print(PRT_MESSAGE, "me %lu clocks, %lu CLOCKS_PER_SEC\n", end_time - start_time, CLOCKS_PER_SEC); + start_time = clock(); + for (i = 0; i < 2000; i++) + { + AAS_Trace(eye, mins, maxs, end, 1, MASK_PLAYERSOLID); + } //end for + end_time = clock(); + botimport.Print(PRT_MESSAGE, "id %lu clocks, %lu CLOCKS_PER_SEC\n", end_time - start_time, CLOCKS_PER_SEC); +*/ + + // TTimo: nested comments are BAD for gcc -Werror, use #if 0 instead.. +#if 0 + AAS_ClearShownDebugLines(); + //bsptrace = AAS_Trace(eye, NULL, NULL, end, 1, MASK_PLAYERSOLID); + bsptrace = AAS_Trace(eye, mins, maxs, end, 1, MASK_PLAYERSOLID); + if (!line[0]) line[0] = botimport.DebugLineCreate(); + botimport.DebugLineShow(line[0], eye, bsptrace.endpos, LINECOLOR_YELLOW); + if (bsptrace.fraction < 1.0) + { + face = AAS_TraceEndFace(&trace); + if (face) + { + AAS_ShowFace(face - aasworld.faces); + } //end if + + AAS_DrawPlaneCross(bsptrace.endpos, + bsptrace.plane.normal, + bsptrace.plane.dist + bsptrace.exp_dist, + bsptrace.plane.type, LINECOLOR_GREEN); + if (trace.ent) + { + ent = &aasworld.entities[trace.ent]; + AAS_ShowBoundingBox(ent->origin, ent->mins, ent->maxs); + } //end if + } //end if + //bsptrace = AAS_Trace2(eye, NULL, NULL, end, 1, MASK_PLAYERSOLID); + bsptrace = AAS_Trace2(eye, mins, maxs, end, 1, MASK_PLAYERSOLID); + botimport.DebugLineShow(line[1], eye, bsptrace.endpos, LINECOLOR_BLUE); + if (bsptrace.fraction < 1.0) + { + AAS_DrawPlaneCross(bsptrace.endpos, + bsptrace.plane.normal, + bsptrace.plane.dist,// + bsptrace.exp_dist, + bsptrace.plane.type, LINECOLOR_RED); + if (bsptrace.ent) + { + ent = &aasworld.entities[bsptrace.ent]; + AAS_ShowBoundingBox(ent->origin, ent->mins, ent->maxs); + } //end if + } //end if +#endif +#endif + return 0; +} //end of the function BotExportTest + + +/* +============ +Init_AAS_Export +============ +*/ +static void Init_AAS_Export( aas_export_t *aas ) { + //-------------------------------------------- + // be_aas_entity.c + //-------------------------------------------- + aas->AAS_EntityInfo = AAS_EntityInfo; + //-------------------------------------------- + // be_aas_main.c + //-------------------------------------------- + aas->AAS_Initialized = AAS_Initialized; + aas->AAS_PresenceTypeBoundingBox = AAS_PresenceTypeBoundingBox; + aas->AAS_Time = AAS_Time; + //-------------------------------------------- + // be_aas_sample.c + //-------------------------------------------- + aas->AAS_PointAreaNum = AAS_PointAreaNum; + aas->AAS_PointReachabilityAreaIndex = AAS_PointReachabilityAreaIndex; + aas->AAS_TraceAreas = AAS_TraceAreas; + aas->AAS_BBoxAreas = AAS_BBoxAreas; + aas->AAS_AreaInfo = AAS_AreaInfo; + //-------------------------------------------- + // be_aas_bspq3.c + //-------------------------------------------- + aas->AAS_PointContents = AAS_PointContents; + aas->AAS_NextBSPEntity = AAS_NextBSPEntity; + aas->AAS_ValueForBSPEpairKey = AAS_ValueForBSPEpairKey; + aas->AAS_VectorForBSPEpairKey = AAS_VectorForBSPEpairKey; + aas->AAS_FloatForBSPEpairKey = AAS_FloatForBSPEpairKey; + aas->AAS_IntForBSPEpairKey = AAS_IntForBSPEpairKey; + //-------------------------------------------- + // be_aas_reach.c + //-------------------------------------------- + aas->AAS_AreaReachability = AAS_AreaReachability; + //-------------------------------------------- + // be_aas_route.c + //-------------------------------------------- + aas->AAS_AreaTravelTimeToGoalArea = AAS_AreaTravelTimeToGoalArea; + aas->AAS_EnableRoutingArea = AAS_EnableRoutingArea; + aas->AAS_PredictRoute = AAS_PredictRoute; + //-------------------------------------------- + // be_aas_altroute.c + //-------------------------------------------- + aas->AAS_AlternativeRouteGoals = AAS_AlternativeRouteGoals; + //-------------------------------------------- + // be_aas_move.c + //-------------------------------------------- + aas->AAS_Swimming = AAS_Swimming; + aas->AAS_PredictClientMovement = AAS_PredictClientMovement; +} + + +/* +============ +Init_EA_Export +============ +*/ +static void Init_EA_Export( ea_export_t *ea ) { + //ClientCommand elementary actions + ea->EA_Command = EA_Command; + ea->EA_Say = EA_Say; + ea->EA_SayTeam = EA_SayTeam; + + ea->EA_Action = EA_Action; + ea->EA_Gesture = EA_Gesture; + ea->EA_Talk = EA_Talk; + ea->EA_Attack = EA_Attack; + ea->EA_Alt_Attack = EA_Alt_Attack; + ea->EA_ForcePower = EA_ForcePower; + ea->EA_Use = EA_Use; + ea->EA_Respawn = EA_Respawn; + ea->EA_Crouch = EA_Crouch; + ea->EA_MoveUp = EA_MoveUp; + ea->EA_MoveDown = EA_MoveDown; + ea->EA_MoveForward = EA_MoveForward; + ea->EA_MoveBack = EA_MoveBack; + ea->EA_MoveLeft = EA_MoveLeft; + ea->EA_MoveRight = EA_MoveRight; + + ea->EA_SelectWeapon = EA_SelectWeapon; + ea->EA_Jump = EA_Jump; + ea->EA_DelayedJump = EA_DelayedJump; + ea->EA_Move = EA_Move; + ea->EA_View = EA_View; + ea->EA_GetInput = EA_GetInput; + ea->EA_EndRegular = EA_EndRegular; + ea->EA_ResetInput = EA_ResetInput; +} + + +/* +============ +Init_AI_Export +============ +*/ +static void Init_AI_Export( ai_export_t *ai ) { + //----------------------------------- + // be_ai_char.h + //----------------------------------- + ai->BotLoadCharacter = BotLoadCharacter; + ai->BotFreeCharacter = BotFreeCharacter; + ai->Characteristic_Float = Characteristic_Float; + ai->Characteristic_BFloat = Characteristic_BFloat; + ai->Characteristic_Integer = Characteristic_Integer; + ai->Characteristic_BInteger = Characteristic_BInteger; + ai->Characteristic_String = Characteristic_String; + //----------------------------------- + // be_ai_chat.h + //----------------------------------- + ai->BotAllocChatState = BotAllocChatState; + ai->BotFreeChatState = BotFreeChatState; + ai->BotQueueConsoleMessage = BotQueueConsoleMessage; + ai->BotRemoveConsoleMessage = BotRemoveConsoleMessage; + ai->BotNextConsoleMessage = BotNextConsoleMessage; + ai->BotNumConsoleMessages = BotNumConsoleMessages; + ai->BotInitialChat = BotInitialChat; + ai->BotNumInitialChats = BotNumInitialChats; + ai->BotReplyChat = BotReplyChat; + ai->BotChatLength = BotChatLength; + ai->BotEnterChat = BotEnterChat; + ai->BotGetChatMessage = BotGetChatMessage; + ai->StringContains = StringContains; + ai->BotFindMatch = BotFindMatch; + ai->BotMatchVariable = BotMatchVariable; + ai->UnifyWhiteSpaces = UnifyWhiteSpaces; + ai->BotReplaceSynonyms = BotReplaceSynonyms; + ai->BotLoadChatFile = BotLoadChatFile; + ai->BotSetChatGender = BotSetChatGender; + ai->BotSetChatName = BotSetChatName; + //----------------------------------- + // be_ai_goal.h + //----------------------------------- + ai->BotResetGoalState = BotResetGoalState; + ai->BotResetAvoidGoals = BotResetAvoidGoals; + ai->BotRemoveFromAvoidGoals = BotRemoveFromAvoidGoals; + ai->BotPushGoal = BotPushGoal; + ai->BotPopGoal = BotPopGoal; + ai->BotEmptyGoalStack = BotEmptyGoalStack; + ai->BotDumpAvoidGoals = BotDumpAvoidGoals; + ai->BotDumpGoalStack = BotDumpGoalStack; + ai->BotGoalName = BotGoalName; + ai->BotGetTopGoal = BotGetTopGoal; + ai->BotGetSecondGoal = BotGetSecondGoal; + ai->BotChooseLTGItem = BotChooseLTGItem; + ai->BotChooseNBGItem = BotChooseNBGItem; + ai->BotTouchingGoal = BotTouchingGoal; + ai->BotItemGoalInVisButNotVisible = BotItemGoalInVisButNotVisible; + ai->BotGetLevelItemGoal = BotGetLevelItemGoal; + ai->BotGetNextCampSpotGoal = BotGetNextCampSpotGoal; + ai->BotGetMapLocationGoal = BotGetMapLocationGoal; + ai->BotAvoidGoalTime = BotAvoidGoalTime; + ai->BotSetAvoidGoalTime = BotSetAvoidGoalTime; + ai->BotInitLevelItems = BotInitLevelItems; + ai->BotUpdateEntityItems = BotUpdateEntityItems; + ai->BotLoadItemWeights = BotLoadItemWeights; + ai->BotFreeItemWeights = BotFreeItemWeights; + ai->BotInterbreedGoalFuzzyLogic = BotInterbreedGoalFuzzyLogic; + ai->BotSaveGoalFuzzyLogic = BotSaveGoalFuzzyLogic; + ai->BotMutateGoalFuzzyLogic = BotMutateGoalFuzzyLogic; + ai->BotAllocGoalState = BotAllocGoalState; + ai->BotFreeGoalState = BotFreeGoalState; + //----------------------------------- + // be_ai_move.h + //----------------------------------- + ai->BotResetMoveState = BotResetMoveState; + ai->BotMoveToGoal = BotMoveToGoal; + ai->BotMoveInDirection = BotMoveInDirection; + ai->BotResetAvoidReach = BotResetAvoidReach; + ai->BotResetLastAvoidReach = BotResetLastAvoidReach; + ai->BotReachabilityArea = BotReachabilityArea; + ai->BotMovementViewTarget = BotMovementViewTarget; + ai->BotPredictVisiblePosition = BotPredictVisiblePosition; + ai->BotAllocMoveState = BotAllocMoveState; + ai->BotFreeMoveState = BotFreeMoveState; + ai->BotInitMoveState = BotInitMoveState; + ai->BotAddAvoidSpot = BotAddAvoidSpot; + //----------------------------------- + // be_ai_weap.h + //----------------------------------- + ai->BotChooseBestFightWeapon = BotChooseBestFightWeapon; + ai->BotGetWeaponInfo = BotGetWeaponInfo; + ai->BotLoadWeaponWeights = BotLoadWeaponWeights; + ai->BotAllocWeaponState = BotAllocWeaponState; + ai->BotFreeWeaponState = BotFreeWeaponState; + ai->BotResetWeaponState = BotResetWeaponState; + //----------------------------------- + // be_ai_gen.h + //----------------------------------- + ai->GeneticParentsAndChildSelection = GeneticParentsAndChildSelection; +} + + +/* +============ +GetBotLibAPI +============ +*/ +botlib_export_t *GetBotLibAPI(int apiVersion, botlib_import_t *import) { + assert(import); // bk001129 - this wasn't set for base/ + botimport = *import; + assert(botimport.Print); // bk001129 - pars pro toto + + Com_Memset( &be_botlib_export, 0, sizeof( be_botlib_export ) ); + + if ( apiVersion != BOTLIB_API_VERSION ) { + botimport.Print( PRT_ERROR, "Mismatched BOTLIB_API_VERSION: expected %i, got %i\n", BOTLIB_API_VERSION, apiVersion ); + return NULL; + } + + Init_AAS_Export(&be_botlib_export.aas); + Init_EA_Export(&be_botlib_export.ea); + Init_AI_Export(&be_botlib_export.ai); + + be_botlib_export.BotLibSetup = Export_BotLibSetup; + be_botlib_export.BotLibShutdown = Export_BotLibShutdown; + be_botlib_export.BotLibVarSet = Export_BotLibVarSet; + be_botlib_export.BotLibVarGet = Export_BotLibVarGet; + + be_botlib_export.PC_AddGlobalDefine = PC_AddGlobalDefine; + be_botlib_export.PC_LoadSourceHandle = PC_LoadSourceHandle; + be_botlib_export.PC_FreeSourceHandle = PC_FreeSourceHandle; + be_botlib_export.PC_ReadTokenHandle = PC_ReadTokenHandle; + be_botlib_export.PC_SourceFileAndLine = PC_SourceFileAndLine; + be_botlib_export.PC_LoadGlobalDefines = PC_LoadGlobalDefines; + be_botlib_export.PC_RemoveAllGlobalDefines = PC_RemoveAllGlobalDefines; + + be_botlib_export.BotLibStartFrame = Export_BotLibStartFrame; + be_botlib_export.BotLibLoadMap = Export_BotLibLoadMap; + be_botlib_export.BotLibUpdateEntity = Export_BotLibUpdateEntity; + be_botlib_export.Test = BotExportTest; + + return &be_botlib_export; +} diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_interface.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_interface.h new file mode 100644 index 0000000..caa376a --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/be_interface.h @@ -0,0 +1,63 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: be_interface.h + * + * desc: botlib interface + * + * $Archive: /source/code/botlib/be_interface.h $ + * $Author: Mrelusive $ + * $Revision: 2 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 10/05/99 3:42p $ + * + *****************************************************************************/ + +#pragma once + +//#define DEBUG //debug code +#define RANDOMIZE //randomize bot behaviour + +//FIXME: get rid of this global structure +typedef struct botlib_globals_s +{ + int botlibsetup; //true when the bot library has been setup + int maxentities; //maximum number of entities + int maxclients; //maximum number of clients + float time; //the global time +#ifdef DEBUG + qboolean debug; //true if debug is on + int goalareanum; + vec3_t goalorigin; + int runai; +#endif +} botlib_globals_t; + + +extern botlib_globals_t botlibglobals; +extern botlib_import_t botimport; +extern int botDeveloper; //true if developer is on + +// +int Sys_MilliSeconds(void); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/botlib.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/botlib.h new file mode 100644 index 0000000..0345e75 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/botlib.h @@ -0,0 +1,530 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#pragma once + +/***************************************************************************** + * name: botlib.h + * + * desc: bot AI library + * + * $Archive: /source/code/game/botai.h $ + * $Author: osman $ + * $Revision: 1.4 $ + * $Modtime: 03/01/00 3:32p $ + * $Date: 2003/03/15 23:44:00 $ + * + *****************************************************************************/ + +#define BOTLIB_API_VERSION 2 + +struct aas_clientmove_s; +struct aas_entityinfo_s; +struct aas_areainfo_s; +struct aas_altroutegoal_s; +struct aas_predictroute_s; +struct bot_consolemessage_s; +struct bot_match_s; +struct bot_goal_s; +struct bot_moveresult_s; +struct bot_initmove_s; +struct weaponinfo_s; + +#define BOTFILESBASEFOLDER "botfiles" +//debug line colors +#define LINECOLOR_NONE -1 +#define LINECOLOR_RED 1//0xf2f2f0f0L +#define LINECOLOR_GREEN 2//0xd0d1d2d3L +#define LINECOLOR_BLUE 3//0xf3f3f1f1L +#define LINECOLOR_YELLOW 4//0xdcdddedfL +#define LINECOLOR_ORANGE 5//0xe0e1e2e3L + +//Print types +#define PRT_MESSAGE 1 +#define PRT_WARNING 2 +#define PRT_ERROR 3 +#define PRT_FATAL 4 +#define PRT_EXIT 5 + +//console message types +#define CMS_NORMAL 0 +#define CMS_CHAT 1 + +//botlib error codes +#define BLERR_NOERROR 0 //no error +#define BLERR_LIBRARYNOTSETUP 1 //library not setup +#define BLERR_INVALIDENTITYNUMBER 2 //invalid entity number +#define BLERR_NOAASFILE 3 //no AAS file available +#define BLERR_CANNOTOPENAASFILE 4 //cannot open AAS file +#define BLERR_WRONGAASFILEID 5 //incorrect AAS file id +#define BLERR_WRONGAASFILEVERSION 6 //incorrect AAS file version +#define BLERR_CANNOTREADAASLUMP 7 //cannot read AAS file lump +#define BLERR_CANNOTLOADICHAT 8 //cannot load initial chats +#define BLERR_CANNOTLOADITEMWEIGHTS 9 //cannot load item weights +#define BLERR_CANNOTLOADITEMCONFIG 10 //cannot load item config +#define BLERR_CANNOTLOADWEAPONWEIGHTS 11 //cannot load weapon weights +#define BLERR_CANNOTLOADWEAPONCONFIG 12 //cannot load weapon config + +//action flags +#define ACTION_ATTACK 0x0000001 +#define ACTION_USE 0x0000002 +#define ACTION_RESPAWN 0x0000008 +#define ACTION_JUMP 0x0000010 +#define ACTION_MOVEUP 0x0000020 +#define ACTION_CROUCH 0x0000080 +#define ACTION_MOVEDOWN 0x0000100 +#define ACTION_MOVEFORWARD 0x0000200 +#define ACTION_MOVEBACK 0x0000800 +#define ACTION_MOVELEFT 0x0001000 +#define ACTION_MOVERIGHT 0x0002000 +#define ACTION_DELAYEDJUMP 0x0008000 +#define ACTION_TALK 0x0010000 +#define ACTION_GESTURE 0x0020000 +#define ACTION_WALK 0x0080000 +#define ACTION_FORCEPOWER 0x0100000 +#define ACTION_ALT_ATTACK 0x0200000 +/* +#define ACTION_AFFIRMATIVE 0x0100000 +#define ACTION_NEGATIVE 0x0200000 +#define ACTION_GETFLAG 0x0800000 +#define ACTION_GUARDBASE 0x1000000 +#define ACTION_PATROL 0x2000000 +#define ACTION_FOLLOWME 0x8000000 +*/ + +//the bot input, will be converted to a usercmd_t +typedef struct bot_input_s +{ + float thinktime; //time since last output (in seconds) + vec3_t dir; //movement direction + float speed; //speed in the range [0, 400] + vec3_t viewangles; //the view angles + int actionflags; //one of the ACTION_? flags + int weapon; //weapon to use +} bot_input_t; + +#ifndef BSPTRACE + +#define BSPTRACE + +//bsp_trace_t hit surface +typedef struct bsp_surface_s +{ + char name[16]; + int flags; + int value; +} bsp_surface_t; + +//remove the bsp_trace_s structure definition l8r on +//a trace is returned when a box is swept through the world +typedef struct bsp_trace_s +{ + qboolean allsolid; // if true, plane is not valid + qboolean startsolid; // if true, the initial point was in a solid area + float fraction; // time completed, 1.0 = didn't hit anything + vec3_t endpos; // final position + cplane_t plane; // surface normal at impact + float exp_dist; // expanded plane distance + int sidenum; // number of the brush side hit + bsp_surface_t surface; // the hit point surface + int contents; // contents on other side of surface hit + int ent; // number of entity hit +} bsp_trace_t; + +#endif // BSPTRACE + +//entity state +typedef struct bot_entitystate_s +{ + int type; // entity type + int flags; // entity flags + vec3_t origin; // origin of the entity + vec3_t angles; // angles of the model + vec3_t old_origin; // for lerping + vec3_t mins; // bounding box minimums + vec3_t maxs; // bounding box maximums + int groundent; // ground entity + int solid; // solid type + int modelindex; // model used + int modelindex2; // weapons, CTF flags, etc + int frame; // model frame number + int event; // impulse events -- muzzle flashes, footsteps, etc + int eventParm; // even parameter + int powerups; // bit flags + int weapon; // determines weapon and flash model, etc + int legsAnim; + int torsoAnim; +} bot_entitystate_t; + +//bot AI library exported functions +typedef struct botlib_import_s +{ + //print messages from the bot library + void (QDECL *Print)(int type, char *fmt, ...) __attribute__ ((format (printf, 2, 3))); + //trace a bbox through the world + void (*Trace)(bsp_trace_t *trace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask); + //trace a bbox against a specific entity + void (*EntityTrace)(bsp_trace_t *trace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int entnum, int contentmask); + //retrieve the contents at the given point + int (*PointContents)(vec3_t point); + //check if the point is in potential visible sight + int (*inPVS)(vec3_t p1, vec3_t p2); + //retrieve the BSP entity data lump + char *(*BSPEntityData)(void); + // + void (*BSPModelMinsMaxsOrigin)(int modelnum, vec3_t angles, vec3_t mins, vec3_t maxs, vec3_t origin); + //send a bot client command + void (*BotClientCommand)(int client, char *command); + //memory allocation + void *(*GetMemory)(int size); // allocate from Zone + void (*FreeMemory)(void *ptr); // free memory from Zone + int (*AvailableMemory)(void); // available Zone memory + void *(*HunkAlloc)(int size); // allocate from hunk + //file system access + int (*FS_FOpenFile)( const char *qpath, fileHandle_t *file, fsMode_t mode ); + int (*FS_Read)( void *buffer, int len, fileHandle_t f ); + int (*FS_Write)( const void *buffer, int len, fileHandle_t f ); + void (*FS_FCloseFile)( fileHandle_t f ); + int (*FS_Seek)( fileHandle_t f, long offset, int origin ); + //debug visualisation stuff + int (*DebugLineCreate)(void); + void (*DebugLineDelete)(int line); + void (*DebugLineShow)(int line, vec3_t start, vec3_t end, int color); + // + int (*DebugPolygonCreate)(int color, int numPoints, vec3_t *points); + void (*DebugPolygonDelete)(int id); +} botlib_import_t; + +typedef struct aas_export_s +{ + //----------------------------------- + // be_aas_entity.h + //----------------------------------- + void (*AAS_EntityInfo)(int entnum, struct aas_entityinfo_s *info); + //----------------------------------- + // be_aas_main.h + //----------------------------------- + int (*AAS_Initialized)(void); + void (*AAS_PresenceTypeBoundingBox)(int presencetype, vec3_t mins, vec3_t maxs); + float (*AAS_Time)(void); + //-------------------------------------------- + // be_aas_sample.c + //-------------------------------------------- + int (*AAS_PointAreaNum)(vec3_t point); + int (*AAS_PointReachabilityAreaIndex)( vec3_t point ); + int (*AAS_TraceAreas)(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas); + int (*AAS_BBoxAreas)(vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas); + int (*AAS_AreaInfo)( int areanum, struct aas_areainfo_s *info ); + //-------------------------------------------- + // be_aas_bspq3.c + //-------------------------------------------- + int (*AAS_PointContents)(vec3_t point); + int (*AAS_NextBSPEntity)(int ent); + int (*AAS_ValueForBSPEpairKey)(int ent, char *key, char *value, int size); + int (*AAS_VectorForBSPEpairKey)(int ent, char *key, vec3_t v); + int (*AAS_FloatForBSPEpairKey)(int ent, char *key, float *value); + int (*AAS_IntForBSPEpairKey)(int ent, char *key, int *value); + //-------------------------------------------- + // be_aas_reach.c + //-------------------------------------------- + int (*AAS_AreaReachability)(int areanum); + //-------------------------------------------- + // be_aas_route.c + //-------------------------------------------- + int (*AAS_AreaTravelTimeToGoalArea)(int areanum, vec3_t origin, int goalareanum, int travelflags); + int (*AAS_EnableRoutingArea)(int areanum, int enable); + int (*AAS_PredictRoute)(struct aas_predictroute_s *route, int areanum, vec3_t origin, + int goalareanum, int travelflags, int maxareas, int maxtime, + int stopevent, int stopcontents, int stoptfl, int stopareanum); + //-------------------------------------------- + // be_aas_altroute.c + //-------------------------------------------- + int (*AAS_AlternativeRouteGoals)(vec3_t start, int startareanum, vec3_t goal, int goalareanum, int travelflags, + struct aas_altroutegoal_s *altroutegoals, int maxaltroutegoals, + int type); + //-------------------------------------------- + // be_aas_move.c + //-------------------------------------------- + int (*AAS_Swimming)(vec3_t origin); + int (*AAS_PredictClientMovement)(struct aas_clientmove_s *move, + int entnum, vec3_t origin, + int presencetype, int onground, + vec3_t velocity, vec3_t cmdmove, + int cmdframes, + int maxframes, float frametime, + int stopevent, int stopareanum, int visualize); +} aas_export_t; + +typedef struct ea_export_s +{ + //ClientCommand elementary actions + void (*EA_Command)(int client, char *command ); + void (*EA_Say)(int client, char *str); + void (*EA_SayTeam)(int client, char *str); + // + void (*EA_Action)(int client, int action); + void (*EA_Gesture)(int client); + void (*EA_Talk)(int client); + void (*EA_Attack)(int client); + void (*EA_Use)(int client); + void (*EA_Respawn)(int client); + void (*EA_MoveUp)(int client); + void (*EA_MoveDown)(int client); + void (*EA_MoveForward)(int client); + void (*EA_MoveBack)(int client); + void (*EA_MoveLeft)(int client); + void (*EA_MoveRight)(int client); + void (*EA_Crouch)(int client); + void (*EA_Alt_Attack)(int client); + void (*EA_ForcePower)(int client); + + void (*EA_SelectWeapon)(int client, int weapon); + void (*EA_Jump)(int client); + void (*EA_DelayedJump)(int client); + void (*EA_Move)(int client, vec3_t dir, float speed); + void (*EA_View)(int client, vec3_t viewangles); + //send regular input to the server + void (*EA_EndRegular)(int client, float thinktime); + void (*EA_GetInput)(int client, float thinktime, bot_input_t *input); + void (*EA_ResetInput)(int client); +} ea_export_t; + +typedef struct ai_export_s +{ + //----------------------------------- + // be_ai_char.h + //----------------------------------- + int (*BotLoadCharacter)(char *charfile, float skill); + void (*BotFreeCharacter)(int character); + float (*Characteristic_Float)(int character, int index); + float (*Characteristic_BFloat)(int character, int index, float min, float max); + int (*Characteristic_Integer)(int character, int index); + int (*Characteristic_BInteger)(int character, int index, int min, int max); + void (*Characteristic_String)(int character, int index, char *buf, int size); + //----------------------------------- + // be_ai_chat.h + //----------------------------------- + int (*BotAllocChatState)(void); + void (*BotFreeChatState)(int handle); + void (*BotQueueConsoleMessage)(int chatstate, int type, char *message); + void (*BotRemoveConsoleMessage)(int chatstate, int handle); + int (*BotNextConsoleMessage)(int chatstate, struct bot_consolemessage_s *cm); + int (*BotNumConsoleMessages)(int chatstate); + void (*BotInitialChat)(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7); + int (*BotNumInitialChats)(int chatstate, char *type); + int (*BotReplyChat)(int chatstate, char *message, int mcontext, int vcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7); + int (*BotChatLength)(int chatstate); + void (*BotEnterChat)(int chatstate, int client, int sendto); + void (*BotGetChatMessage)(int chatstate, char *buf, int size); + int (*StringContains)(char *str1, char *str2, int casesensitive); + int (*BotFindMatch)(char *str, struct bot_match_s *match, unsigned long int context); + void (*BotMatchVariable)(struct bot_match_s *match, int variable, char *buf, int size); + void (*UnifyWhiteSpaces)(char *string); + void (*BotReplaceSynonyms)(char *string, unsigned long int context); + int (*BotLoadChatFile)(int chatstate, char *chatfile, char *chatname); + void (*BotSetChatGender)(int chatstate, int gender); + void (*BotSetChatName)(int chatstate, char *name, int client); + //----------------------------------- + // be_ai_goal.h + //----------------------------------- + void (*BotResetGoalState)(int goalstate); + void (*BotResetAvoidGoals)(int goalstate); + void (*BotRemoveFromAvoidGoals)(int goalstate, int number); + void (*BotPushGoal)(int goalstate, struct bot_goal_s *goal); + void (*BotPopGoal)(int goalstate); + void (*BotEmptyGoalStack)(int goalstate); + void (*BotDumpAvoidGoals)(int goalstate); + void (*BotDumpGoalStack)(int goalstate); + void (*BotGoalName)(int number, char *name, int size); + int (*BotGetTopGoal)(int goalstate, struct bot_goal_s *goal); + int (*BotGetSecondGoal)(int goalstate, struct bot_goal_s *goal); + int (*BotChooseLTGItem)(int goalstate, vec3_t origin, int *inventory, int travelflags); + int (*BotChooseNBGItem)(int goalstate, vec3_t origin, int *inventory, int travelflags, + struct bot_goal_s *ltg, float maxtime); + int (*BotTouchingGoal)(vec3_t origin, struct bot_goal_s *goal); + int (*BotItemGoalInVisButNotVisible)(int viewer, vec3_t eye, vec3_t viewangles, struct bot_goal_s *goal); + int (*BotGetLevelItemGoal)(int index, char *classname, struct bot_goal_s *goal); + int (*BotGetNextCampSpotGoal)(int num, struct bot_goal_s *goal); + int (*BotGetMapLocationGoal)(char *name, struct bot_goal_s *goal); + float (*BotAvoidGoalTime)(int goalstate, int number); + void (*BotSetAvoidGoalTime)(int goalstate, int number, float avoidtime); + void (*BotInitLevelItems)(void); + void (*BotUpdateEntityItems)(void); + int (*BotLoadItemWeights)(int goalstate, char *filename); + void (*BotFreeItemWeights)(int goalstate); + void (*BotInterbreedGoalFuzzyLogic)(int parent1, int parent2, int child); + void (*BotSaveGoalFuzzyLogic)(int goalstate, char *filename); + void (*BotMutateGoalFuzzyLogic)(int goalstate, float range); + int (*BotAllocGoalState)(int client); + void (*BotFreeGoalState)(int handle); + //----------------------------------- + // be_ai_move.h + //----------------------------------- + void (*BotResetMoveState)(int movestate); + void (*BotMoveToGoal)(struct bot_moveresult_s *result, int movestate, struct bot_goal_s *goal, int travelflags); + int (*BotMoveInDirection)(int movestate, vec3_t dir, float speed, int type); + void (*BotResetAvoidReach)(int movestate); + void (*BotResetLastAvoidReach)(int movestate); + int (*BotReachabilityArea)(vec3_t origin, int testground); + int (*BotMovementViewTarget)(int movestate, struct bot_goal_s *goal, int travelflags, float lookahead, vec3_t target); + int (*BotPredictVisiblePosition)(vec3_t origin, int areanum, struct bot_goal_s *goal, int travelflags, vec3_t target); + int (*BotAllocMoveState)(void); + void (*BotFreeMoveState)(int handle); + void (*BotInitMoveState)(int handle, struct bot_initmove_s *initmove); + void (*BotAddAvoidSpot)(int movestate, vec3_t origin, float radius, int type); + //----------------------------------- + // be_ai_weap.h + //----------------------------------- + int (*BotChooseBestFightWeapon)(int weaponstate, int *inventory); + void (*BotGetWeaponInfo)(int weaponstate, int weapon, struct weaponinfo_s *weaponinfo); + int (*BotLoadWeaponWeights)(int weaponstate, char *filename); + int (*BotAllocWeaponState)(void); + void (*BotFreeWeaponState)(int weaponstate); + void (*BotResetWeaponState)(int weaponstate); + //----------------------------------- + // be_ai_gen.h + //----------------------------------- + int (*GeneticParentsAndChildSelection)(int numranks, float *ranks, int *parent1, int *parent2, int *child); +} ai_export_t; + +//bot AI library imported functions +typedef struct botlib_export_s +{ + //Area Awareness System functions + aas_export_t aas; + //Elementary Action functions + ea_export_t ea; + //AI functions + ai_export_t ai; + //setup the bot library, returns BLERR_ + int (*BotLibSetup)(void); + //shutdown the bot library, returns BLERR_ + int (*BotLibShutdown)(void); + //sets a library variable returns BLERR_ + int (*BotLibVarSet)(char *var_name, char *value); + //gets a library variable returns BLERR_ + int (*BotLibVarGet)(char *var_name, char *value, int size); + + //sets a C-like define returns BLERR_ + int (*PC_AddGlobalDefine)(char *string); + int (*PC_LoadSourceHandle)(const char *filename); + int (*PC_FreeSourceHandle)(int handle); + int (*PC_ReadTokenHandle)(int handle, pc_token_t *pc_token); + int (*PC_SourceFileAndLine)(int handle, char *filename, int *line); + int (*PC_LoadGlobalDefines)(const char* filename ); + void (*PC_RemoveAllGlobalDefines) ( void ); + + //start a frame in the bot library + int (*BotLibStartFrame)(float time); + //load a new map in the bot library + int (*BotLibLoadMap)(const char *mapname); + //entity updates + int (*BotLibUpdateEntity)(int ent, bot_entitystate_t *state); + //just for testing + int (*Test)(int parm0, char *parm1, vec3_t parm2, vec3_t parm3); +} botlib_export_t; + +//linking of bot library +botlib_export_t *GetBotLibAPI( int apiVersion, botlib_import_t *import ); + +/* Library variables: + +name: default: module(s): description: + +"basedir" "" l_utils.c base directory +"gamedir" "" l_utils.c game directory +"cddir" "" l_utils.c CD directory + +"log" "0" l_log.c enable/disable creating a log file +"maxclients" "4" be_interface.c maximum number of clients +"maxentities" "1024" be_interface.c maximum number of entities +"bot_developer" "0" be_interface.c bot developer mode (it's "botDeveloper" in C to prevent symbol clash). + +"phys_friction" "6" be_aas_move.c ground friction +"phys_stopspeed" "100" be_aas_move.c stop speed +"phys_gravity" "800" be_aas_move.c gravity value +"phys_waterfriction" "1" be_aas_move.c water friction +"phys_watergravity" "400" be_aas_move.c gravity in water +"phys_maxvelocity" "320" be_aas_move.c maximum velocity +"phys_maxwalkvelocity" "320" be_aas_move.c maximum walk velocity +"phys_maxcrouchvelocity" "100" be_aas_move.c maximum crouch velocity +"phys_maxswimvelocity" "150" be_aas_move.c maximum swim velocity +"phys_walkaccelerate" "10" be_aas_move.c walk acceleration +"phys_airaccelerate" "1" be_aas_move.c air acceleration +"phys_swimaccelerate" "4" be_aas_move.c swim acceleration +"phys_maxstep" "18" be_aas_move.c maximum step height +"phys_maxsteepness" "0.7" be_aas_move.c maximum floor steepness +"phys_maxbarrier" "32" be_aas_move.c maximum barrier height +"phys_maxwaterjump" "19" be_aas_move.c maximum waterjump height +"phys_jumpvel" "270" be_aas_move.c jump z velocity +"phys_falldelta5" "40" be_aas_move.c +"phys_falldelta10" "60" be_aas_move.c +"rs_waterjump" "400" be_aas_move.c +"rs_teleport" "50" be_aas_move.c +"rs_barrierjump" "100" be_aas_move.c +"rs_startcrouch" "300" be_aas_move.c +"rs_startgrapple" "500" be_aas_move.c +"rs_startwalkoffledge" "70" be_aas_move.c +"rs_startjump" "300" be_aas_move.c +"rs_rocketjump" "500" be_aas_move.c +"rs_bfgjump" "500" be_aas_move.c +"rs_jumppad" "250" be_aas_move.c +"rs_aircontrolledjumppad" "300" be_aas_move.c +"rs_funcbob" "300" be_aas_move.c +"rs_startelevator" "50" be_aas_move.c +"rs_falldamage5" "300" be_aas_move.c +"rs_falldamage10" "500" be_aas_move.c +"rs_maxjumpfallheight" "450" be_aas_move.c + +"max_aaslinks" "4096" be_aas_sample.c maximum links in the AAS +"max_routingcache" "4096" be_aas_route.c maximum routing cache size in KB +"forceclustering" "0" be_aas_main.c force recalculation of clusters +"forcereachability" "0" be_aas_main.c force recalculation of reachabilities +"forcewrite" "0" be_aas_main.c force writing of aas file +"aasoptimize" "0" be_aas_main.c enable aas optimization +"sv_mapChecksum" "0" be_aas_main.c BSP file checksum +"bot_visualizejumppads" "0" be_aas_reach.c visualize jump pads + +"bot_reloadcharacters" "0" - reload bot character files +"ai_gametype" "0" be_ai_goal.c game type +"droppedweight" "1000" be_ai_goal.c additional dropped item weight +"weapindex_rocketlauncher" "5" be_ai_move.c rl weapon index for rocket jumping +"weapindex_bfg10k" "9" be_ai_move.c bfg weapon index for bfg jumping +"weapindex_grapple" "10" be_ai_move.c grapple weapon index for grappling +"entitytypemissile" "3" be_ai_move.c ET_MISSILE +"offhandgrapple" "0" be_ai_move.c enable off hand grapple hook +"cmd_grappleon" "grappleon" be_ai_move.c command to activate off hand grapple +"cmd_grappleoff" "grappleoff" be_ai_move.c command to deactivate off hand grapple +"itemconfig" "items.c" be_ai_goal.c item configuration file +"weaponconfig" "weapons.c" be_ai_weap.c weapon configuration file +"synfile" "syn.c" be_ai_chat.c file with synonyms +"rndfile" "rnd.c" be_ai_chat.c file with random strings +"matchfile" "match.c" be_ai_chat.c file with match strings +"nochat" "0" be_ai_chat.c disable chats +"max_messages" "1024" be_ai_chat.c console message heap size +"max_weaponinfo" "32" be_ai_weap.c maximum number of weapon info +"max_projectileinfo" "32" be_ai_weap.c maximum number of projectile info +"max_iteminfo" "256" be_ai_goal.c maximum number of item info +"max_levelitems" "256" be_ai_goal.c maximum number of level items + +*/ diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_crc.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_crc.cpp new file mode 100644 index 0000000..d542eea --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_crc.cpp @@ -0,0 +1,157 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: l_crc.c + * + * desc: CRC calculation + * + * $Archive: /MissionPack/CODE/botlib/l_crc.c $ + * $Author: Raduffy $ + * $Revision: 1 $ + * $Modtime: 12/20/99 8:42p $ + * $Date: 3/08/00 11:28a $ + * + *****************************************************************************/ + +#include +#include +#include + +#include "qcommon/q_shared.h" +#include "botlib.h" +#include "be_interface.h" //for botimport.Print +#include "l_crc.h" + + +// FIXME: byte swap? + +// this is a 16 bit, non-reflected CRC using the polynomial 0x1021 +// and the initial and final xor values shown below... in other words, the +// CCITT standard CRC used by XMODEM + +#define CRC_INIT_VALUE 0xffff +#define CRC_XOR_VALUE 0x0000 + +unsigned short crctable[257] = +{ + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void CRC_Init(unsigned short *crcvalue) +{ + *crcvalue = CRC_INIT_VALUE; +} //end of the function CRC_Init +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void CRC_ProcessByte(unsigned short *crcvalue, byte data) +{ + *crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data]; +} //end of the function CRC_ProcessByte +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +unsigned short CRC_Value(unsigned short crcvalue) +{ + return crcvalue ^ CRC_XOR_VALUE; +} //end of the function CRC_Value +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +unsigned short CRC_ProcessString(unsigned char *data, int length) +{ + unsigned short crcvalue; + int i, ind; + + CRC_Init(&crcvalue); + + for (i = 0; i < length; i++) + { + ind = (crcvalue >> 8) ^ data[i]; + if (ind < 0 || ind > 256) ind = 0; + crcvalue = (crcvalue << 8) ^ crctable[ind]; + } //end for + return CRC_Value(crcvalue); +} //end of the function CRC_ProcessString +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void CRC_ContinueProcessString(unsigned short *crc, char *data, int length) +{ + int i; + + for (i = 0; i < length; i++) + { + *crc = (*crc << 8) ^ crctable[(*crc >> 8) ^ data[i]]; + } //end for +} //end of the function CRC_ProcessString diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_crc.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_crc.h new file mode 100644 index 0000000..709cf6f --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_crc.h @@ -0,0 +1,41 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +//=========================================================================== +// +// Name: l_crc.h +// Function: for CRC checks +// Programmer: Mr Elusive (MrElusive@demigod.demon.nl) +// Last update: 1997-12-31 +// Tab Size: 3 +//=========================================================================== + +#pragma once + +typedef unsigned short crc_t; + +void CRC_Init(unsigned short *crcvalue); +void CRC_ProcessByte(unsigned short *crcvalue, byte data); +unsigned short CRC_Value(unsigned short crcvalue); +unsigned short CRC_ProcessString(unsigned char *data, int length); +void CRC_ContinueProcessString(unsigned short *crc, char *data, int length); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_libvar.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_libvar.cpp new file mode 100644 index 0000000..a27e93a --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_libvar.cpp @@ -0,0 +1,300 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: l_libvar.c + * + * desc: bot library variables + * + * $Archive: /MissionPack/code/botlib/l_libvar.c $ + * $Author: Zaphod $ + * $Revision: 2 $ + * $Modtime: 11/21/00 11:33a $ + * $Date: 11/21/00 11:49a $ + * + *****************************************************************************/ + +#include "qcommon/q_shared.h" +#include "l_memory.h" +#include "l_libvar.h" + +//list with library variables +libvar_t *libvarlist = NULL; + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float LibVarStringValue(char *string) +{ + int dotfound = 0; + float value = 0; + + while(*string) + { + if (*string < '0' || *string > '9') + { + if (dotfound || *string != '.') + { + return 0; + } //end if + else + { + dotfound = 10; + string++; + } //end if + } //end if + if (dotfound) + { + value = value + (float) (*string - '0') / (float) dotfound; + dotfound *= 10; + } //end if + else + { + value = value * 10.0 + (float) (*string - '0'); + } //end else + string++; + } //end while + return value; +} //end of the function LibVarStringValue +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +libvar_t *LibVarAlloc(char *var_name) +{ + libvar_t *v; + + v = (libvar_t *) GetMemory(sizeof(libvar_t)); + Com_Memset(v, 0, sizeof(libvar_t)); + v->name = (char *) GetMemory(strlen(var_name)+1); + strcpy(v->name, var_name); + //add the variable in the list + v->next = libvarlist; + libvarlist = v; + return v; +} //end of the function LibVarAlloc +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void LibVarDeAlloc(libvar_t *v) +{ + if (v->string) FreeMemory(v->string); + FreeMemory(v->name); + FreeMemory(v); +} //end of the function LibVarDeAlloc +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void LibVarDeAllocAll(void) +{ + libvar_t *v; + + for (v = libvarlist; v; v = libvarlist) + { + libvarlist = libvarlist->next; + LibVarDeAlloc(v); + } //end for + libvarlist = NULL; +} //end of the function LibVarDeAllocAll +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +libvar_t *LibVarGet(char *var_name) +{ + libvar_t *v; + + for (v = libvarlist; v; v = v->next) + { + if (!Q_stricmp(v->name, var_name)) + { + return v; + } //end if + } //end for + return NULL; +} //end of the function LibVarGet +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +char *LibVarGetString(char *var_name) +{ + libvar_t *v; + + v = LibVarGet(var_name); + if (v) + { + return v->string; + } //end if + else + { + return ""; + } //end else +} //end of the function LibVarGetString +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float LibVarGetValue(char *var_name) +{ + libvar_t *v; + + v = LibVarGet(var_name); + if (v) + { + return v->value; + } //end if + else + { + return 0; + } //end else +} //end of the function LibVarGetValue +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +libvar_t *LibVar(char *var_name, char *value) +{ + libvar_t *v; + v = LibVarGet(var_name); + if (v) return v; + //create new variable + v = LibVarAlloc(var_name); + //variable string + v->string = (char *) GetMemory(strlen(value) + 1); + strcpy(v->string, value); + //the value + v->value = LibVarStringValue(v->string); + //variable is modified + v->modified = qtrue; + // + return v; +} //end of the function LibVar +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +char *LibVarString(char *var_name, char *value) +{ + libvar_t *v; + + v = LibVar(var_name, value); + return v->string; +} //end of the function LibVarString +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float LibVarValue(char *var_name, char *value) +{ + libvar_t *v; + + v = LibVar(var_name, value); + return v->value; +} //end of the function LibVarValue +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void LibVarSet(char *var_name, char *value) +{ + libvar_t *v; + + v = LibVarGet(var_name); + if (v) + { + FreeMemory(v->string); + } //end if + else + { + v = LibVarAlloc(var_name); + } //end else + //variable string + v->string = (char *) GetMemory(strlen(value) + 1); + strcpy(v->string, value); + //the value + v->value = LibVarStringValue(v->string); + //variable is modified + v->modified = qtrue; +} //end of the function LibVarSet +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +qboolean LibVarChanged(char *var_name) +{ + libvar_t *v; + + v = LibVarGet(var_name); + if (v) + { + return v->modified; + } //end if + else + { + return qfalse; + } //end else +} //end of the function LibVarChanged +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void LibVarSetNotModified(char *var_name) +{ + libvar_t *v; + + v = LibVarGet(var_name); + if (v) + { + v->modified = qfalse; + } //end if +} //end of the function LibVarSetNotModified diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_libvar.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_libvar.h new file mode 100644 index 0000000..a41871a --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_libvar.h @@ -0,0 +1,69 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: l_libvar.h + * + * desc: botlib vars + * + * $Archive: /source/code/botlib/l_libvar.h $ + * $Author: Mrelusive $ + * $Revision: 2 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 10/05/99 3:42p $ + * + *****************************************************************************/ + +#pragma once + +//library variable +typedef struct libvar_s +{ + char *name; + char *string; + int flags; + qboolean modified; // set each time the cvar is changed + float value; + struct libvar_s *next; +} libvar_t; + +//removes all library variables +void LibVarDeAllocAll(void); +//gets the library variable with the given name +libvar_t *LibVarGet(char *var_name); +//gets the string of the library variable with the given name +char *LibVarGetString(char *var_name); +//gets the value of the library variable with the given name +float LibVarGetValue(char *var_name); +//creates the library variable if not existing already and returns it +libvar_t *LibVar(char *var_name, char *value); +//creates the library variable if not existing already and returns the value +float LibVarValue(char *var_name, char *value); +//creates the library variable if not existing already and returns the value string +char *LibVarString(char *var_name, char *value); +//sets the library variable +void LibVarSet(char *var_name, char *value); +//returns true if the library variable has been modified +qboolean LibVarChanged(char *var_name); +//sets the library variable to unmodified +void LibVarSetNotModified(char *var_name); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_log.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_log.cpp new file mode 100644 index 0000000..0a977ee --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_log.cpp @@ -0,0 +1,175 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: l_log.c + * + * desc: log file + * + * $Archive: /MissionPack/CODE/botlib/l_log.c $ + * $Author: Raduffy $ + * $Revision: 1 $ + * $Modtime: 12/20/99 8:43p $ + * $Date: 3/08/00 11:28a $ + * + *****************************************************************************/ + +#include +#include +#include + +#include "qcommon/q_shared.h" +#include "botlib.h" +#include "be_interface.h" //for botimport.Print +#include "l_libvar.h" +#include "l_log.h" + +#define MAX_LOGFILENAMESIZE 1024 + +typedef struct logfile_s +{ + char filename[MAX_LOGFILENAMESIZE]; + FILE *fp; + int numwrites; +} logfile_t; + +static logfile_t logfile; + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void Log_Open(char *filename) +{ + if (!LibVarValue("log", "0")) return; + if (!filename || !strlen(filename)) + { + botimport.Print(PRT_MESSAGE, "openlog \n"); + return; + } //end if + if (logfile.fp) + { + botimport.Print(PRT_ERROR, "log file %s is already opened\n", logfile.filename); + return; + } //end if + logfile.fp = fopen(filename, "wb"); + if (!logfile.fp) + { + botimport.Print(PRT_ERROR, "can't open the log file %s\n", filename); + return; + } //end if + strncpy(logfile.filename, filename, MAX_LOGFILENAMESIZE); + botimport.Print(PRT_MESSAGE, "Opened log %s\n", logfile.filename); +} //end of the function Log_Create +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void Log_Close(void) +{ + if (!logfile.fp) return; + if (fclose(logfile.fp)) + { + botimport.Print(PRT_ERROR, "can't close log file %s\n", logfile.filename); + return; + } //end if + logfile.fp = NULL; + botimport.Print(PRT_MESSAGE, "Closed log %s\n", logfile.filename); +} //end of the function Log_Close +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void Log_Shutdown(void) +{ + if (logfile.fp) Log_Close(); +} //end of the function Log_Shutdown +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void QDECL Log_Write(char *fmt, ...) +{ + va_list ap; + + if (!logfile.fp) return; + va_start(ap, fmt); + vfprintf(logfile.fp, fmt, ap); + va_end(ap); + //fprintf(logfile.fp, "\r\n"); + fflush(logfile.fp); +} //end of the function Log_Write +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void QDECL Log_WriteTimeStamped(char *fmt, ...) +{ + va_list ap; + + if (!logfile.fp) return; + fprintf(logfile.fp, "%d %02d:%02d:%02d:%02d ", + logfile.numwrites, + (int) (botlibglobals.time / 60 / 60), + (int) (botlibglobals.time / 60), + (int) (botlibglobals.time), + (int) ((int) (botlibglobals.time * 100)) - + ((int) botlibglobals.time) * 100); + va_start(ap, fmt); + vfprintf(logfile.fp, fmt, ap); + va_end(ap); + fprintf(logfile.fp, "\r\n"); + logfile.numwrites++; + fflush(logfile.fp); +} //end of the function Log_Write +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +FILE *Log_FilePointer(void) +{ + return logfile.fp; +} //end of the function Log_FilePointer +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void Log_Flush(void) +{ + if (logfile.fp) fflush(logfile.fp); +} //end of the function Log_Flush + diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_log.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_log.h new file mode 100644 index 0000000..142c703 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_log.h @@ -0,0 +1,52 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: l_log.h + * + * desc: log file + * + * $Archive: /source/code/botlib/l_log.h $ + * $Author: Mrelusive $ + * $Revision: 2 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 10/05/99 3:42p $ + * + *****************************************************************************/ + +#pragma once + +//open a log file +void Log_Open(char *filename); +//close the current log file +void Log_Close(void); +//close log file if present +void Log_Shutdown(void); +//write to the current opened log file +void QDECL Log_Write(char *fmt, ...); +//write to the current opened log file with a time stamp +void QDECL Log_WriteTimeStamped(char *fmt, ...); +//returns a pointer to the log file +FILE *Log_FilePointer(void); +//flush log file +void Log_Flush(void); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_memory.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_memory.cpp new file mode 100644 index 0000000..569d398 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_memory.cpp @@ -0,0 +1,470 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: l_memory.c + * + * desc: memory allocation + * + * $Archive: /MissionPack/code/botlib/l_memory.c $ + * $Author: Ttimo $ + * $Revision: 6 $ + * $Modtime: 4/22/01 8:52a $ + * $Date: 4/22/01 8:52a $ + * + *****************************************************************************/ + +#include "qcommon/q_shared.h" +#include "botlib.h" +#include "l_log.h" +#include "l_memory.h" +#include "be_interface.h" +#include + +//#define MEMDEBUG +//#define MEMORYMANEGER + +#define MEM_ID 0x12345678l +#define HUNK_ID 0x87654321l + +int allocatedmemory; +int totalmemorysize; +int numblocks; + +#ifdef MEMORYMANEGER + +typedef struct memoryblock_s +{ + unsigned long int id; + void *ptr; + int size; +#ifdef MEMDEBUG + char *label; + char *file; + int line; +#endif //MEMDEBUG + struct memoryblock_s *prev, *next; +} memoryblock_t; + +memoryblock_t *memory; + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void LinkMemoryBlock(memoryblock_t *block) +{ + block->prev = NULL; + block->next = memory; + if (memory) memory->prev = block; + memory = block; +} //end of the function LinkMemoryBlock +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void UnlinkMemoryBlock(memoryblock_t *block) +{ + if (block->prev) block->prev->next = block->next; + else memory = block->next; + if (block->next) block->next->prev = block->prev; +} //end of the function UnlinkMemoryBlock +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +#ifdef MEMDEBUG +void *GetMemoryDebug(unsigned long size, char *label, char *file, int line) +#else +void *GetMemory(unsigned long size) +#endif //MEMDEBUG +{ + void *ptr; + memoryblock_t *block; + assert(botimport.GetMemory); // bk001129 - was NULL'ed + ptr = botimport.GetMemory(size + sizeof(memoryblock_t)); + block = (memoryblock_t *) ptr; + block->id = MEM_ID; + block->ptr = (char *) ptr + sizeof(memoryblock_t); + block->size = size + sizeof(memoryblock_t); +#ifdef MEMDEBUG + block->label = label; + block->file = file; + block->line = line; +#endif //MEMDEBUG + LinkMemoryBlock(block); + allocatedmemory += block->size; + totalmemorysize += block->size + sizeof(memoryblock_t); + numblocks++; + return block->ptr; +} //end of the function GetMemoryDebug +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +#ifdef MEMDEBUG +void *GetClearedMemoryDebug(unsigned long size, char *label, char *file, int line) +#else +void *GetClearedMemory(unsigned long size) +#endif //MEMDEBUG +{ + void *ptr; +#ifdef MEMDEBUG + ptr = GetMemoryDebug(size, label, file, line); +#else + ptr = GetMemory(size); +#endif //MEMDEBUG + Com_Memset(ptr, 0, size); + return ptr; +} //end of the function GetClearedMemory +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +#ifdef MEMDEBUG +void *GetHunkMemoryDebug(unsigned long size, char *label, char *file, int line) +#else +void *GetHunkMemory(unsigned long size) +#endif //MEMDEBUG +{ + void *ptr; + memoryblock_t *block; + + ptr = botimport.HunkAlloc(size + sizeof(memoryblock_t)); + block = (memoryblock_t *) ptr; + block->id = HUNK_ID; + block->ptr = (char *) ptr + sizeof(memoryblock_t); + block->size = size + sizeof(memoryblock_t); +#ifdef MEMDEBUG + block->label = label; + block->file = file; + block->line = line; +#endif //MEMDEBUG + LinkMemoryBlock(block); + allocatedmemory += block->size; + totalmemorysize += block->size + sizeof(memoryblock_t); + numblocks++; + return block->ptr; +} //end of the function GetHunkMemoryDebug +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +#ifdef MEMDEBUG +void *GetClearedHunkMemoryDebug(unsigned long size, char *label, char *file, int line) +#else +void *GetClearedHunkMemory(unsigned long size) +#endif //MEMDEBUG +{ + void *ptr; +#ifdef MEMDEBUG + ptr = GetHunkMemoryDebug(size, label, file, line); +#else + ptr = GetHunkMemory(size); +#endif //MEMDEBUG + Com_Memset(ptr, 0, size); + return ptr; +} //end of the function GetClearedHunkMemory +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +memoryblock_t *BlockFromPointer(void *ptr, char *str) +{ + memoryblock_t *block; + + if (!ptr) + { +#ifdef MEMDEBUG + //char *crash = (char *) NULL; + //crash[0] = 1; + botimport.Print(PRT_FATAL, "%s: NULL pointer\n", str); +#endif // MEMDEBUG + return NULL; + } //end if + block = (memoryblock_t *) ((char *) ptr - sizeof(memoryblock_t)); + if (block->id != MEM_ID && block->id != HUNK_ID) + { + botimport.Print(PRT_FATAL, "%s: invalid memory block\n", str); + return NULL; + } //end if + if (block->ptr != ptr) + { + botimport.Print(PRT_FATAL, "%s: memory block pointer invalid\n", str); + return NULL; + } //end if + return block; +} //end of the function BlockFromPointer +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void FreeMemory(void *ptr) +{ + memoryblock_t *block; + + block = BlockFromPointer(ptr, "FreeMemory"); + if (!block) return; + UnlinkMemoryBlock(block); + allocatedmemory -= block->size; + totalmemorysize -= block->size + sizeof(memoryblock_t); + numblocks--; + // + if (block->id == MEM_ID) + { + botimport.FreeMemory(block); + } //end if +} //end of the function FreeMemory +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AvailableMemory(void) +{ + return botimport.AvailableMemory(); +} //end of the function AvailableMemory +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int MemoryByteSize(void *ptr) +{ + memoryblock_t *block; + + block = BlockFromPointer(ptr, "MemoryByteSize"); + if (!block) return 0; + return block->size; +} //end of the function MemoryByteSize +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void PrintUsedMemorySize(void) +{ + botimport.Print(PRT_MESSAGE, "total allocated memory: %d KB\n", allocatedmemory >> 10); + botimport.Print(PRT_MESSAGE, "total botlib memory: %d KB\n", totalmemorysize >> 10); + botimport.Print(PRT_MESSAGE, "total memory blocks: %d\n", numblocks); +} //end of the function PrintUsedMemorySize +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void PrintMemoryLabels(void) +{ + memoryblock_t *block; + int i; + + PrintUsedMemorySize(); + i = 0; + Log_Write("============= Botlib memory log ==============\r\n"); + Log_Write("\r\n"); + for (block = memory; block; block = block->next) + { +#ifdef MEMDEBUG + if (block->id == HUNK_ID) + { + Log_Write("%6d, hunk %p, %8d: %24s line %6d: %s\r\n", i, block->ptr, block->size, block->file, block->line, block->label); + } //end if + else + { + Log_Write("%6d, %p, %8d: %24s line %6d: %s\r\n", i, block->ptr, block->size, block->file, block->line, block->label); + } //end else +#endif //MEMDEBUG + i++; + } //end for +} //end of the function PrintMemoryLabels +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void DumpMemory(void) +{ + memoryblock_t *block; + + for (block = memory; block; block = memory) + { + FreeMemory(block->ptr); + } //end for + totalmemorysize = 0; + allocatedmemory = 0; +} //end of the function DumpMemory + +#else + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +#ifdef MEMDEBUG +void *GetMemoryDebug(unsigned long size, char *label, char *file, int line) +#else +void *GetMemory(unsigned long size) +#endif //MEMDEBUG +{ + void *ptr; + unsigned long int *memid; + + ptr = botimport.GetMemory(size + sizeof(qmax_align_t)); + if (!ptr) return NULL; + memid = (unsigned long int *) ptr; + *memid = MEM_ID; + return (unsigned long int *) ((char *) ptr + sizeof(qmax_align_t)); +} //end of the function GetMemory +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +#ifdef MEMDEBUG +void *GetClearedMemoryDebug(unsigned long size, char *label, char *file, int line) +#else +void *GetClearedMemory(unsigned long size) +#endif //MEMDEBUG +{ + void *ptr; +#ifdef MEMDEBUG + ptr = GetMemoryDebug(size, label, file, line); +#else + ptr = GetMemory(size); +#endif //MEMDEBUG + Com_Memset(ptr, 0, size); + return ptr; +} //end of the function GetClearedMemory +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +#ifdef MEMDEBUG +void *GetHunkMemoryDebug(unsigned long size, char *label, char *file, int line) +#else +void *GetHunkMemory(unsigned long size) +#endif //MEMDEBUG +{ + void *ptr; + unsigned long int *memid; + + ptr = botimport.HunkAlloc(size + sizeof(qmax_align_t)); + if (!ptr) return NULL; + memid = (unsigned long int *) ptr; + *memid = HUNK_ID; + return (unsigned long int *) ((char *) ptr + sizeof(qmax_align_t)); +} //end of the function GetHunkMemory +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +#ifdef MEMDEBUG +void *GetClearedHunkMemoryDebug(unsigned long size, char *label, char *file, int line) +#else +void *GetClearedHunkMemory(unsigned long size) +#endif //MEMDEBUG +{ + void *ptr; +#ifdef MEMDEBUG + ptr = GetHunkMemoryDebug(size, label, file, line); +#else + ptr = GetHunkMemory(size); +#endif //MEMDEBUG + Com_Memset(ptr, 0, size); + return ptr; +} //end of the function GetClearedHunkMemory +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void FreeMemory(void *ptr) +{ + unsigned long int *memid; + + memid = (unsigned long int *) ((char *) ptr - sizeof(qmax_align_t)); + + if (*memid == MEM_ID) + { + botimport.FreeMemory(memid); + } //end if +} //end of the function FreeMemory +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int AvailableMemory(void) +{ + return botimport.AvailableMemory(); +} //end of the function AvailableMemory +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void PrintUsedMemorySize(void) +{ +} //end of the function PrintUsedMemorySize +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void PrintMemoryLabels(void) +{ +} //end of the function PrintMemoryLabels + +#endif diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_memory.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_memory.h new file mode 100644 index 0000000..e85b919 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_memory.h @@ -0,0 +1,83 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: l_memory.h + * + * desc: memory management + * + * $Archive: /source/code/botlib/l_memory.h $ + * $Author: Mrelusive $ + * $Revision: 2 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 10/05/99 3:42p $ + * + *****************************************************************************/ + +#pragma once + +//#define MEMDEBUG + +#ifdef MEMDEBUG +#define GetMemory(size) GetMemoryDebug(size, #size, __FILE__, __LINE__); +#define GetClearedMemory(size) GetClearedMemoryDebug(size, #size, __FILE__, __LINE__); +//allocate a memory block of the given size +void *GetMemoryDebug(unsigned long size, char *label, char *file, int line); +//allocate a memory block of the given size and clear it +void *GetClearedMemoryDebug(unsigned long size, char *label, char *file, int line); +// +#define GetHunkMemory(size) GetHunkMemoryDebug(size, #size, __FILE__, __LINE__); +#define GetClearedHunkMemory(size) GetClearedHunkMemoryDebug(size, #size, __FILE__, __LINE__); +//allocate a memory block of the given size +void *GetHunkMemoryDebug(unsigned long size, char *label, char *file, int line); +//allocate a memory block of the given size and clear it +void *GetClearedHunkMemoryDebug(unsigned long size, char *label, char *file, int line); +#else +//allocate a memory block of the given size +void *GetMemory(unsigned long size); +//allocate a memory block of the given size and clear it +void *GetClearedMemory(unsigned long size); +// +#ifdef BSPC +#define GetHunkMemory GetMemory +#define GetClearedHunkMemory GetClearedMemory +#else +//allocate a memory block of the given size +void *GetHunkMemory(unsigned long size); +//allocate a memory block of the given size and clear it +void *GetClearedHunkMemory(unsigned long size); +#endif +#endif + +//free the given memory block +void FreeMemory(void *ptr); +//returns the amount available memory +int AvailableMemory(void); +//prints the total used memory size +void PrintUsedMemorySize(void); +//print all memory blocks with label +void PrintMemoryLabels(void); +//returns the size of the memory block in bytes +int MemoryByteSize(void *ptr); +//free all allocated memory +void DumpMemory(void); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_precomp.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_precomp.cpp new file mode 100644 index 0000000..8089a56 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_precomp.cpp @@ -0,0 +1,3351 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: l_precomp.c + * + * desc: pre compiler + * + * $Archive: /MissionPack/code/botlib/l_precomp.c $ + * $Author: Ttimo $ + * $Revision: 20 $ + * $Modtime: 5/15/01 4:10a $ + * $Date: 5/15/01 4:10a $ + * + *****************************************************************************/ + +//Notes: fix: PC_StringizeTokens + +//#define SCREWUP +//#define BOTLIB +//#define QUAKE +//#define QUAKEC +//#define MEQCC + +#ifdef SCREWUP +#include +#include +#include +#include +#include +#include +#include "l_memory.h" +#include "l_script.h" +#include "l_precomp.h" + +typedef enum {qfalse, qtrue} qboolean; +#endif //SCREWUP + +#ifdef BOTLIB +#include "qcommon/q_shared.h" +#include "botlib.h" +#include "be_interface.h" +#include "l_memory.h" +#include "l_script.h" +#include "l_precomp.h" +#include "l_log.h" +#endif //BOTLIB + +#ifdef MEQCC +#include "qcc.h" +#include "time.h" //time & ctime +#include "math.h" //fabs +#include "l_memory.h" +#include "l_script.h" +#include "l_precomp.h" +#include "l_log.h" + +#define qtrue true +#define qfalse false +#endif //MEQCC + +#ifdef BSPC +//include files for usage in the BSP Converter +#include "../bspc/qbsp.h" +#include "../bspc/l_log.h" +#include "../bspc/l_mem.h" +#include "l_precomp.h" + +#define qtrue true +#define qfalse false +#define Q_stricmp stricmp + +#endif //BSPC + +#if defined(QUAKE) && !defined(BSPC) +#include "l_utils.h" +#endif //QUAKE + +//#define DEBUG_EVAL + +#define MAX_DEFINEPARMS 128 + +#define DEFINEHASHING 1 + +//directive name with parse function +typedef struct directive_s +{ + char *name; + int (*func)(source_t *source); +} directive_t; + +#define DEFINEHASHSIZE 1024 + +#define TOKEN_HEAP_SIZE 4096 + +int numtokens; +/* +int tokenheapinitialized; //true when the token heap is initialized +token_t token_heap[TOKEN_HEAP_SIZE]; //heap with tokens +token_t *freetokens; //free tokens from the heap +*/ + +//list with global defines added to every source loaded +#if DEFINEHASHING +define_t **globaldefines = NULL; +#else +define_t *globaldefines = NULL; +#endif +qboolean addGlobalDefine = qfalse; + +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void QDECL SourceError(source_t *source, char *str, ...) +{ + char text[1024]; + va_list ap; + + va_start(ap, str); + Q_vsnprintf(text, sizeof(text), str, ap); + va_end(ap); +#ifdef BOTLIB + botimport.Print(PRT_ERROR, "file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); +#endif //BOTLIB +#ifdef MEQCC + printf("error: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); +#endif //MEQCC +#ifdef BSPC + Log_Print("error: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); +#endif //BSPC +} //end of the function SourceError +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void QDECL SourceWarning(source_t *source, char *str, ...) +{ + char text[1024]; + va_list ap; + + va_start(ap, str); + Q_vsnprintf(text, sizeof(text), str, ap); + va_end(ap); +#ifdef BOTLIB + botimport.Print(PRT_WARNING, "file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); +#endif //BOTLIB +#ifdef MEQCC + printf("warning: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); +#endif //MEQCC +#ifdef BSPC + Log_Print("warning: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); +#endif //BSPC +} //end of the function ScriptWarning +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_PushIndent(source_t *source, int type, int skip) +{ + indent_t *indent; + + indent = (indent_t *) GetMemory(sizeof(indent_t)); + indent->type = type; + indent->script = source->scriptstack; + indent->skip = (skip != 0); + source->skip += indent->skip; + indent->next = source->indentstack; + source->indentstack = indent; +} //end of the function PC_PushIndent +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_PopIndent(source_t *source, int *type, int *skip) +{ + indent_t *indent; + + *type = 0; + *skip = 0; + + indent = source->indentstack; + if (!indent) return; + + //must be an indent from the current script + if (source->indentstack->script != source->scriptstack) return; + + *type = indent->type; + *skip = indent->skip; + source->indentstack = source->indentstack->next; + source->skip -= indent->skip; + FreeMemory(indent); +} //end of the function PC_PopIndent +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_PushScript(source_t *source, script_t *script) +{ + script_t *s; + + for (s = source->scriptstack; s; s = s->next) + { + if (!Q_stricmp(s->filename, script->filename)) + { + SourceError(source, "%s recursively included", script->filename); + return; + } //end if + } //end for + //push the script on the script stack + script->next = source->scriptstack; + source->scriptstack = script; +} //end of the function PC_PushScript +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_InitTokenHeap(void) +{ + /* + int i; + + if (tokenheapinitialized) return; + freetokens = NULL; + for (i = 0; i < TOKEN_HEAP_SIZE; i++) + { + token_heap[i].next = freetokens; + freetokens = &token_heap[i]; + } //end for + tokenheapinitialized = qtrue; + */ +} //end of the function PC_InitTokenHeap +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +token_t *PC_CopyToken(token_t *token) +{ + token_t *t; + +// t = (token_t *) malloc(sizeof(token_t)); + t = (token_t *) GetMemory(sizeof(token_t)); +// t = freetokens; + if (!t) + { +#ifdef BSPC + Error("out of token space"); +#else + Com_Error(ERR_FATAL, "out of token space"); +#endif + return NULL; + } //end if +// freetokens = freetokens->next; + Com_Memcpy(t, token, sizeof(token_t)); + t->next = NULL; + numtokens++; + return t; +} //end of the function PC_CopyToken +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_FreeToken(token_t *token) +{ + //free(token); + FreeMemory(token); +// token->next = freetokens; +// freetokens = token; + numtokens--; +} //end of the function PC_FreeToken +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_ReadSourceToken(source_t *source, token_t *token) +{ + token_t *t; + script_t *script; + int type, skip; + + //if there's no token already available + while(!source->tokens) + { + //if there's a token to read from the script + if (PS_ReadToken(source->scriptstack, token)) return qtrue; + //if at the end of the script + if (EndOfScript(source->scriptstack)) + { + //remove all indents of the script + while(source->indentstack && + source->indentstack->script == source->scriptstack) + { + SourceWarning(source, "missing #endif"); + PC_PopIndent(source, &type, &skip); + } //end if + } //end if + //if this was the initial script + if (!source->scriptstack->next) return qfalse; + //remove the script and return to the last one + script = source->scriptstack; + source->scriptstack = source->scriptstack->next; + FreeScript(script); + } //end while + //copy the already available token + Com_Memcpy(token, source->tokens, sizeof(token_t)); + //free the read token + t = source->tokens; + source->tokens = source->tokens->next; + PC_FreeToken(t); + return qtrue; +} //end of the function PC_ReadSourceToken +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_UnreadSourceToken(source_t *source, token_t *token) +{ + token_t *t; + + t = PC_CopyToken(token); + t->next = source->tokens; + source->tokens = t; + return qtrue; +} //end of the function PC_UnreadSourceToken +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_ReadDefineParms(source_t *source, define_t *define, token_t **parms, int maxparms) +{ + token_t token, *t, *last; + int i, done, lastcomma, numparms, indent; + + if (!PC_ReadSourceToken(source, &token)) + { + SourceError(source, "define %s missing parms", define->name); + return qfalse; + } //end if + // + if (define->numparms > maxparms) + { + SourceError(source, "define with more than %d parameters", maxparms); + return qfalse; + } //end if + // + for (i = 0; i < define->numparms; i++) parms[i] = NULL; + //if no leading "(" + if (strcmp(token.string, "(")) + { + PC_UnreadSourceToken(source, &token); + SourceError(source, "define %s missing parms", define->name); + return qfalse; + } //end if + //read the define parameters + for (done = 0, numparms = 0, indent = 0; !done;) + { + if (numparms >= maxparms) + { + SourceError(source, "define %s with too many parms", define->name); + return qfalse; + } //end if + if (numparms >= define->numparms) + { + SourceWarning(source, "define %s has too many parms", define->name); + return qfalse; + } //end if + parms[numparms] = NULL; + lastcomma = 1; + last = NULL; + while(!done) + { + // + if (!PC_ReadSourceToken(source, &token)) + { + SourceError(source, "define %s incomplete", define->name); + return qfalse; + } //end if + // + if (!strcmp(token.string, ",")) + { + if (indent <= 0) + { + if (lastcomma) SourceWarning(source, "too many comma's"); + lastcomma = 1; + break; + } //end if + } //end if + lastcomma = 0; + // + if (!strcmp(token.string, "(")) + { + indent++; + continue; + } //end if + else if (!strcmp(token.string, ")")) + { + if (--indent <= 0) + { + if (!parms[define->numparms-1]) + { + SourceWarning(source, "too few define parms"); + } //end if + done = 1; + break; + } //end if + } //end if + // + if (numparms < define->numparms) + { + // + t = PC_CopyToken(&token); + t->next = NULL; + if (last) last->next = t; + else parms[numparms] = t; + last = t; + } //end if + } //end while + numparms++; + } //end for + return qtrue; +} //end of the function PC_ReadDefineParms +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_StringizeTokens(token_t *tokens, token_t *token) +{ + token_t *t; + + token->type = TT_STRING; + token->whitespace_p = NULL; + token->endwhitespace_p = NULL; + token->string[0] = '\0'; + strcat(token->string, "\""); + for (t = tokens; t; t = t->next) + { + strncat(token->string, t->string, MAX_TOKEN - strlen(token->string) - 1); + } //end for + strncat(token->string, "\"", MAX_TOKEN - strlen(token->string) - 1); + return qtrue; +} //end of the function PC_StringizeTokens +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_MergeTokens(token_t *t1, token_t *t2) +{ + //merging of a name with a name or number + if (t1->type == TT_NAME && (t2->type == TT_NAME || t2->type == TT_NUMBER)) + { + strcat(t1->string, t2->string); + return qtrue; + } //end if + //merging of two strings + if (t1->type == TT_STRING && t2->type == TT_STRING) + { + //remove trailing double quote + t1->string[strlen(t1->string)-1] = '\0'; + //concat without leading double quote + strcat(t1->string, &t2->string[1]); + return qtrue; + } //end if + //FIXME: merging of two number of the same sub type + return qfalse; +} //end of the function PC_MergeTokens +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +/* +void PC_PrintDefine(define_t *define) +{ + printf("define->name = %s\n", define->name); + printf("define->flags = %d\n", define->flags); + printf("define->builtin = %d\n", define->builtin); + printf("define->numparms = %d\n", define->numparms); +// token_t *parms; //define parameters +// token_t *tokens; //macro tokens (possibly containing parm tokens) +// struct define_s *next; //next defined macro in a list +} //end of the function PC_PrintDefine*/ +#if DEFINEHASHING +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_PrintDefineHashTable(define_t **definehash) +{ + int i; + define_t *d; + + for (i = 0; i < DEFINEHASHSIZE; i++) + { + Log_Write("%4d:", i); + for (d = definehash[i]; d; d = d->hashnext) + { + Log_Write(" %s", d->name); + } //end for + Log_Write("\n"); + } //end for +} //end of the function PC_PrintDefineHashTable +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +//char primes[16] = {1, 3, 5, 7, 11, 13, 17, 19, 23, 27, 29, 31, 37, 41, 43, 47}; + +int PC_NameHash(char *name) +{ + int hash, i; + + hash = 0; + for (i = 0; name[i] != '\0'; i++) + { + hash += name[i] * (119 + i); + //hash += (name[i] << 7) + i; + //hash += (name[i] << (i&15)); + } //end while + hash = (hash ^ (hash >> 10) ^ (hash >> 20)) & (DEFINEHASHSIZE-1); + return hash; +} //end of the function PC_NameHash +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_AddDefineToHash(define_t *define, define_t **definehash) +{ + int hash; + + + if ( addGlobalDefine ) + { + definehash = globaldefines; + define->flags |= DEFINE_GLOBAL; + } + + hash = PC_NameHash(define->name); + define->hashnext = definehash[hash]; + definehash[hash] = define; + + if ( addGlobalDefine ) + { + define->globalnext = define->hashnext; + } +} //end of the function PC_AddDefineToHash +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +define_t *PC_FindHashedDefine(define_t **definehash, char *name) +{ + define_t *d; + int hash; + + hash = PC_NameHash(name); + for (d = definehash[hash]; d; d = d->hashnext) + { + if (!strcmp(d->name, name)) return d; + } //end for + return NULL; +} //end of the function PC_FindHashedDefine +#endif //DEFINEHASHING +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +define_t *PC_FindDefine(define_t *defines, char *name) +{ + define_t *d; + + for (d = defines; d; d = d->next) + { + if (!strcmp(d->name, name)) return d; + } //end for + return NULL; +} //end of the function PC_FindDefine +//============================================================================ +// +// Parameter: - +// Returns: number of the parm +// if no parm found with the given name -1 is returned +// Changes Globals: - +//============================================================================ +int PC_FindDefineParm(define_t *define, char *name) +{ + token_t *p; + int i; + + i = 0; + for (p = define->parms; p; p = p->next) + { + if (!strcmp(p->string, name)) return i; + i++; + } //end for + return -1; +} //end of the function PC_FindDefineParm +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_FreeDefine(define_t *define) +{ + token_t *t, *next; + + //free the define parameters + for (t = define->parms; t; t = next) + { + next = t->next; + PC_FreeToken(t); + } //end for + //free the define tokens + for (t = define->tokens; t; t = next) + { + next = t->next; + PC_FreeToken(t); + } //end for + //free the define + FreeMemory(define->name); + FreeMemory(define); +} //end of the function PC_FreeDefine +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_AddBuiltinDefines(source_t *source) +{ + int i; + define_t *define; + struct builtin + { + char *string; + int mBuiltin; + } builtin[] = { // bk001204 - brackets + { "__LINE__", BUILTIN_LINE }, + { "__FILE__", BUILTIN_FILE }, + { "__DATE__", BUILTIN_DATE }, + { "__TIME__", BUILTIN_TIME }, +// { "__STDC__", BUILTIN_STDC }, + { NULL, 0 } + }; + + for (i = 0; builtin[i].string; i++) + { + define = (define_t *) GetMemory(sizeof(define_t)); + Com_Memset(define, 0, sizeof(define_t)); + define->name = (char *) GetMemory(strlen(builtin[i].string) + 1); + strcpy(define->name, builtin[i].string); + define->flags |= DEFINE_FIXED; + define->builtin = builtin[i].mBuiltin; + //add the define to the source +#if DEFINEHASHING + PC_AddDefineToHash(define, source->definehash); +#else + define->next = source->defines; + source->defines = define; +#endif //DEFINEHASHING + } //end for +} //end of the function PC_AddBuiltinDefines +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_ExpandBuiltinDefine(source_t *source, token_t *deftoken, define_t *define, + token_t **firsttoken, token_t **lasttoken) +{ + token_t *token; + time_t t; + char *curtime; + + token = PC_CopyToken(deftoken); + switch(define->builtin) + { + case BUILTIN_LINE: + { + sprintf(token->string, "%d", deftoken->line); +#ifdef NUMBERVALUE + token->intvalue = deftoken->line; + token->floatvalue = deftoken->line; +#endif //NUMBERVALUE + token->type = TT_NUMBER; + token->subtype = TT_DECIMAL | TT_INTEGER; + *firsttoken = token; + *lasttoken = token; + break; + } //end case + case BUILTIN_FILE: + { + strcpy(token->string, source->scriptstack->filename); + token->type = TT_NAME; + token->subtype = strlen(token->string); + *firsttoken = token; + *lasttoken = token; + break; + } //end case + case BUILTIN_DATE: + { + t = time(NULL); + curtime = ctime(&t); + strcpy(token->string, "\""); + strncat(token->string, curtime+4, 7); + strncat(token->string+7, curtime+20, 4); + strcat(token->string, "\""); + free(curtime); + token->type = TT_NAME; + token->subtype = strlen(token->string); + *firsttoken = token; + *lasttoken = token; + break; + } //end case + case BUILTIN_TIME: + { + t = time(NULL); + curtime = ctime(&t); + strcpy(token->string, "\""); + strncat(token->string, curtime+11, 8); + strcat(token->string, "\""); + free(curtime); + token->type = TT_NAME; + token->subtype = strlen(token->string); + *firsttoken = token; + *lasttoken = token; + break; + } //end case + case BUILTIN_STDC: + default: + { + *firsttoken = NULL; + *lasttoken = NULL; + break; + } //end case + } //end switch + return qtrue; +} //end of the function PC_ExpandBuiltinDefine +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_ExpandDefine(source_t *source, token_t *deftoken, define_t *define, + token_t **firsttoken, token_t **lasttoken) +{ + token_t *parms[MAX_DEFINEPARMS], *dt, *pt, *t; + token_t *t1, *t2, *first, *last, *nextpt, token; + int parmnum, i; + + //if it is a builtin define + if (define->builtin) + { + return PC_ExpandBuiltinDefine(source, deftoken, define, firsttoken, lasttoken); + } //end if + //if the define has parameters + if (define->numparms) + { + if (!PC_ReadDefineParms(source, define, parms, MAX_DEFINEPARMS)) return qfalse; +#ifdef DEBUG_EVAL + for (i = 0; i < define->numparms; i++) + { + Log_Write("define parms %d:", i); + for (pt = parms[i]; pt; pt = pt->next) + { + Log_Write("%s", pt->string); + } //end for + } //end for +#endif //DEBUG_EVAL + } //end if + //empty list at first + first = NULL; + last = NULL; + //create a list with tokens of the expanded define + for (dt = define->tokens; dt; dt = dt->next) + { + parmnum = -1; + //if the token is a name, it could be a define parameter + if (dt->type == TT_NAME) + { + parmnum = PC_FindDefineParm(define, dt->string); + } //end if + //if it is a define parameter + if (parmnum >= 0) + { + for (pt = parms[parmnum]; pt; pt = pt->next) + { + t = PC_CopyToken(pt); + //add the token to the list + t->next = NULL; + if (last) last->next = t; + else first = t; + last = t; + } //end for + } //end if + else + { + //if stringizing operator + if (dt->string[0] == '#' && dt->string[1] == '\0') + { + //the stringizing operator must be followed by a define parameter + if (dt->next) parmnum = PC_FindDefineParm(define, dt->next->string); + else parmnum = -1; + // + if (parmnum >= 0) + { + //step over the stringizing operator + dt = dt->next; + //stringize the define parameter tokens + if (!PC_StringizeTokens(parms[parmnum], &token)) + { + SourceError(source, "can't stringize tokens"); + return qfalse; + } //end if + t = PC_CopyToken(&token); + } //end if + else + { + SourceWarning(source, "stringizing operator without define parameter"); + continue; + } //end if + } //end if + else + { + t = PC_CopyToken(dt); + } //end else + //add the token to the list + t->next = NULL; + if (last) last->next = t; + else first = t; + last = t; + } //end else + } //end for + //check for the merging operator + for (t = first; t; ) + { + if (t->next) + { + //if the merging operator + if (t->next->string[0] == '#' && t->next->string[1] == '#') + { + t1 = t; + t2 = t->next->next; + if (t2) + { + if (!PC_MergeTokens(t1, t2)) + { + SourceError(source, "can't merge %s with %s", t1->string, t2->string); + return qfalse; + } //end if + PC_FreeToken(t1->next); + t1->next = t2->next; + if (t2 == last) last = t1; + PC_FreeToken(t2); + continue; + } //end if + } //end if + } //end if + t = t->next; + } //end for + //store the first and last token of the list + *firsttoken = first; + *lasttoken = last; + //free all the parameter tokens + for (i = 0; i < define->numparms; i++) + { + for (pt = parms[i]; pt; pt = nextpt) + { + nextpt = pt->next; + PC_FreeToken(pt); + } //end for + } //end for + // + return qtrue; +} //end of the function PC_ExpandDefine +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_ExpandDefineIntoSource(source_t *source, token_t *deftoken, define_t *define) +{ + token_t *firsttoken, *lasttoken; + + if (!PC_ExpandDefine(source, deftoken, define, &firsttoken, &lasttoken)) return qfalse; + + if (firsttoken && lasttoken) + { + lasttoken->next = source->tokens; + source->tokens = firsttoken; + return qtrue; + } //end if + return qfalse; +} //end of the function PC_ExpandDefineIntoSource +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_ConvertPath(char *path) +{ + char *ptr; + + //remove double path seperators + for (ptr = path; *ptr;) + { + if ((*ptr == '\\' || *ptr == '/') && + (*(ptr+1) == '\\' || *(ptr+1) == '/')) + { + memmove(ptr, ptr+1, strlen(ptr)); + } //end if + else + { + ptr++; + } //end else + } //end while + //set OS dependent path seperators + for (ptr = path; *ptr;) + { + if (*ptr == '/' || *ptr == '\\') *ptr = PATHSEPERATOR_CHAR; + ptr++; + } //end while +} //end of the function PC_ConvertPath +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_include(source_t *source) +{ + script_t *script; + token_t token; + char path[MAX_PATH]; +#ifdef QUAKE + foundfile_t file; +#endif //QUAKE + + if (source->skip > 0) return qtrue; + // + if (!PC_ReadSourceToken(source, &token)) + { + SourceError(source, "#include without file name"); + return qfalse; + } //end if + if (token.linescrossed > 0) + { + SourceError(source, "#include without file name"); + return qfalse; + } //end if + if (token.type == TT_STRING) + { + StripDoubleQuotes(token.string); + PC_ConvertPath(token.string); + script = LoadScriptFile(token.string); + if (!script) + { + Q_strncpyz(path, source->includepath, sizeof(path)); + Q_strcat(path, sizeof(path), token.string); + script = LoadScriptFile(path); + } //end if + } //end if + else if (token.type == TT_PUNCTUATION && *token.string == '<') + { + Q_strncpyz(path, source->includepath, sizeof(path)); + while(PC_ReadSourceToken(source, &token)) + { + if (token.linescrossed > 0) + { + PC_UnreadSourceToken(source, &token); + break; + } //end if + if (token.type == TT_PUNCTUATION && *token.string == '>') break; + Q_strcat(path, sizeof(path), token.string); + } //end while + if (*token.string != '>') + { + SourceWarning(source, "#include missing trailing >"); + } //end if + if (!strlen(path)) + { + SourceError(source, "#include without file name between < >"); + return qfalse; + } //end if + PC_ConvertPath(path); + script = LoadScriptFile(path); + } //end if + else + { + SourceError(source, "#include without file name"); + return qfalse; + } //end else +#ifdef QUAKE + if (!script) + { + Com_Memset(&file, 0, sizeof(foundfile_t)); + script = LoadScriptFile(path); + if (script) strncpy(script->filename, path, MAX_PATH); + } //end if +#endif //QUAKE + if (!script) + { +#ifdef SCREWUP + SourceWarning(source, "file %s not found", path); + return qtrue; +#else + SourceError(source, "file %s not found", path); + return qfalse; +#endif //SCREWUP + } //end if + PC_PushScript(source, script); + return qtrue; +} //end of the function PC_Directive_include +//============================================================================ +// reads a token from the current line, continues reading on the next +// line only if a backslash '\' is encountered. +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_ReadLine(source_t *source, token_t *token) +{ + int crossline; + + crossline = 0; + do + { + if (!PC_ReadSourceToken(source, token)) return qfalse; + + if (token->linescrossed > crossline) + { + PC_UnreadSourceToken(source, token); + return qfalse; + } //end if + crossline = 1; + } while(!strcmp(token->string, "\\")); + return qtrue; +} //end of the function PC_ReadLine +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_WhiteSpaceBeforeToken(token_t *token) +{ + return token->endwhitespace_p - token->whitespace_p > 0; +} //end of the function PC_WhiteSpaceBeforeToken +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_ClearTokenWhiteSpace(token_t *token) +{ + token->whitespace_p = NULL; + token->endwhitespace_p = NULL; + token->linescrossed = 0; +} //end of the function PC_ClearTokenWhiteSpace +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_undef(source_t *source) +{ + token_t token; + define_t *define, *lastdefine; + int hash; + + if (source->skip > 0) return qtrue; + // + if (!PC_ReadLine(source, &token)) + { + SourceError(source, "undef without name"); + return qfalse; + } //end if + if (token.type != TT_NAME) + { + PC_UnreadSourceToken(source, &token); + SourceError(source, "expected name, found %s", token.string); + return qfalse; + } //end if +#if DEFINEHASHING + + hash = PC_NameHash(token.string); + for (lastdefine = NULL, define = source->definehash[hash]; define; define = define->hashnext) + { + if (!strcmp(define->name, token.string)) + { + if (define->flags & DEFINE_FIXED) + { + SourceWarning(source, "can't undef %s", token.string); + } //end if + else + { + if (lastdefine) lastdefine->hashnext = define->hashnext; + else source->definehash[hash] = define->hashnext; + + if ( !(define->flags & DEFINE_GLOBAL ) ) + { + PC_FreeDefine(define); + } + } //end else + break; + } //end if + lastdefine = define; + } //end for +#else //DEFINEHASHING + for (lastdefine = NULL, define = source->defines; define; define = define->next) + { + if (!strcmp(define->name, token.string)) + { + if (define->flags & DEFINE_FIXED) + { + SourceWarning(source, "can't undef %s", token.string); + } //end if + else + { + if (lastdefine) lastdefine->next = define->next; + else source->defines = define->next; + PC_FreeDefine(define); + } //end else + break; + } //end if + lastdefine = define; + } //end for +#endif //DEFINEHASHING + return qtrue; +} //end of the function PC_Directive_undef +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_define(source_t *source) +{ + token_t token, *t, *last; + define_t *define; + + if (source->skip > 0) return qtrue; + // + if (!PC_ReadLine(source, &token)) + { + SourceError(source, "#define without name"); + return qfalse; + } //end if + if (token.type != TT_NAME) + { + PC_UnreadSourceToken(source, &token); + SourceError(source, "expected name after #define, found %s", token.string); + return qfalse; + } //end if + //check if the define already exists +#if DEFINEHASHING + define = PC_FindHashedDefine(source->definehash, token.string); +#else + define = PC_FindDefine(source->defines, token.string); +#endif //DEFINEHASHING + if (define) + { + if (define->flags & DEFINE_FIXED) + { + SourceError(source, "can't redefine %s", token.string); + return qfalse; + } //end if + SourceWarning(source, "redefinition of %s", token.string); + //unread the define name before executing the #undef directive + PC_UnreadSourceToken(source, &token); + if (!PC_Directive_undef(source)) return qfalse; + //if the define was not removed (define->flags & DEFINE_FIXED) +#if DEFINEHASHING + define = PC_FindHashedDefine(source->definehash, token.string); +#else + define = PC_FindDefine(source->defines, token.string); +#endif //DEFINEHASHING + } //end if + //allocate define + define = (define_t *) GetMemory(sizeof(define_t)); + Com_Memset(define, 0, sizeof(define_t)); + define->name = (char *) GetMemory(strlen(token.string) + 1); + strcpy(define->name, token.string); + //add the define to the source +#if DEFINEHASHING + PC_AddDefineToHash(define, source->definehash); +#else //DEFINEHASHING + define->next = source->defines; + source->defines = define; +#endif //DEFINEHASHING + //if nothing is defined, just return + if (!PC_ReadLine(source, &token)) return qtrue; + //if it is a define with parameters + if (!PC_WhiteSpaceBeforeToken(&token) && !strcmp(token.string, "(")) + { + //read the define parameters + last = NULL; + if (!PC_CheckTokenString(source, ")")) + { + while(1) + { + if (!PC_ReadLine(source, &token)) + { + SourceError(source, "expected define parameter"); + return qfalse; + } //end if + //if it isn't a name + if (token.type != TT_NAME) + { + SourceError(source, "invalid define parameter"); + return qfalse; + } //end if + // + if (PC_FindDefineParm(define, token.string) >= 0) + { + SourceError(source, "two the same define parameters"); + return qfalse; + } //end if + //add the define parm + t = PC_CopyToken(&token); + PC_ClearTokenWhiteSpace(t); + t->next = NULL; + if (last) last->next = t; + else define->parms = t; + last = t; + define->numparms++; + //read next token + if (!PC_ReadLine(source, &token)) + { + SourceError(source, "define parameters not terminated"); + return qfalse; + } //end if + // + if (!strcmp(token.string, ")")) break; + //then it must be a comma + if (strcmp(token.string, ",")) + { + SourceError(source, "define not terminated"); + return qfalse; + } //end if + } //end while + } //end if + if (!PC_ReadLine(source, &token)) return qtrue; + } //end if + //read the defined stuff + last = NULL; + do + { + t = PC_CopyToken(&token); + if (t->type == TT_NAME && !strcmp(t->string, define->name)) + { + SourceError(source, "recursive define (removed recursion)"); + continue; + } //end if + PC_ClearTokenWhiteSpace(t); + t->next = NULL; + if (last) last->next = t; + else define->tokens = t; + last = t; + } while(PC_ReadLine(source, &token)); + // + if (last) + { + //check for merge operators at the beginning or end + if (!strcmp(define->tokens->string, "##") || + !strcmp(last->string, "##")) + { + SourceError(source, "define with misplaced ##"); + return qfalse; + } //end if + } //end if + return qtrue; +} //end of the function PC_Directive_define +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +define_t *PC_DefineFromString(char *string) +{ + script_t *script; + source_t src; + token_t *t; + int res, i; + define_t *def; + + PC_InitTokenHeap(); + + script = LoadScriptMemory(string, strlen(string), "*extern"); + //create a new source + Com_Memset(&src, 0, sizeof(source_t)); + strncpy(src.filename, "*extern", MAX_PATH); + src.scriptstack = script; +#if DEFINEHASHING + src.definehash = (struct define_s **)GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *)); +#endif //DEFINEHASHING + //create a define from the source + res = PC_Directive_define(&src); + //free any tokens if left + for (t = src.tokens; t; t = src.tokens) + { + src.tokens = src.tokens->next; + PC_FreeToken(t); + } //end for +#ifdef DEFINEHASHING + def = NULL; + for (i = 0; i < DEFINEHASHSIZE; i++) + { + if (src.definehash[i]) + { + def = src.definehash[i]; + break; + } //end if + } //end for +#else + def = src.defines; +#endif //DEFINEHASHING + // +#if DEFINEHASHING + FreeMemory(src.definehash); +#endif //DEFINEHASHING + // + FreeScript(script); + //if the define was created successfully + if (res > 0) return def; + //free the define is created + if (src.defines) PC_FreeDefine(def); + // + return NULL; +} //end of the function PC_DefineFromString +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_AddDefine(source_t *source, char *string) +{ + define_t *define; + + if ( addGlobalDefine ) + { + return PC_AddGlobalDefine ( string ); + } + + define = PC_DefineFromString(string); + if (!define) return qfalse; +#if DEFINEHASHING + PC_AddDefineToHash(define, source->definehash); +#else //DEFINEHASHING + define->next = source->defines; + source->defines = define; +#endif //DEFINEHASHING + return qtrue; +} //end of the function PC_AddDefine +//============================================================================ +// add a globals define that will be added to all opened sources +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_AddGlobalDefine(char *string) +{ +#if !DEFINEHASHING + define_t *define; + + define = PC_DefineFromString(string); + if (!define) return qfalse; + define->next = globaldefines; + globaldefines = define; +#endif + return qtrue; +} //end of the function PC_AddGlobalDefine +//============================================================================ +// remove the given global define +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_RemoveGlobalDefine(char *name) +{ +#if !DEFINEHASHING + define_t *define; + + define = PC_FindDefine(globaldefines, name); + if (define) + { + PC_FreeDefine(define); + return qtrue; + } //end if +#endif + return qfalse; +} //end of the function PC_RemoveGlobalDefine +//============================================================================ +// remove all globals defines +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_RemoveAllGlobalDefines(void) +{ + define_t *define; + +#if DEFINEHASHING + int i; + if ( globaldefines ) + { + for (i = 0; i < DEFINEHASHSIZE; i++) + { + while(globaldefines[i]) + { + define = globaldefines[i]; + globaldefines[i] = globaldefines[i]->globalnext; + PC_FreeDefine(define); + } + } + } +#else //DEFINEHASHING + for (define = globaldefines; define; define = globaldefines) + { + globaldefines = globaldefines->next; + PC_FreeDefine(define); + } //end for +#endif +} //end of the function PC_RemoveAllGlobalDefines +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +define_t *PC_CopyDefine(source_t *source, define_t *define) +{ + define_t *newdefine; + token_t *token, *newtoken, *lasttoken; + + newdefine = (define_t *) GetMemory(sizeof(define_t)); + //copy the define name + newdefine->name = (char *) GetMemory(strlen(define->name) + 1); + strcpy(newdefine->name, define->name); + newdefine->flags = define->flags; + newdefine->builtin = define->builtin; + newdefine->numparms = define->numparms; + //the define is not linked + newdefine->next = NULL; + newdefine->hashnext = NULL; + //copy the define tokens + newdefine->tokens = NULL; + for (lasttoken = NULL, token = define->tokens; token; token = token->next) + { + newtoken = PC_CopyToken(token); + newtoken->next = NULL; + if (lasttoken) lasttoken->next = newtoken; + else newdefine->tokens = newtoken; + lasttoken = newtoken; + } //end for + //copy the define parameters + newdefine->parms = NULL; + for (lasttoken = NULL, token = define->parms; token; token = token->next) + { + newtoken = PC_CopyToken(token); + newtoken->next = NULL; + if (lasttoken) lasttoken->next = newtoken; + else newdefine->parms = newtoken; + lasttoken = newtoken; + } //end for + return newdefine; +} //end of the function PC_CopyDefine +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_AddGlobalDefinesToSource(source_t *source) +{ + define_t *define; + +#if DEFINEHASHING + int i; + for (i = 0; i < DEFINEHASHSIZE; i++) + { + define = globaldefines[i]; + while(define) + { + define->hashnext = NULL; + PC_AddDefineToHash(define, source->definehash); + + define = define->globalnext; + } + } +#else //DEFINEHASHING + define_t* newdefine; + for (define = globaldefines; define; define = define->next) + { + newdefine = PC_CopyDefine(source, define); + + + + newdefine->next = source->defines; + source->defines = newdefine; + } +#endif +} //end of the function PC_AddGlobalDefinesToSource +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_if_def(source_t *source, int type) +{ + token_t token; + define_t *d; + int skip; + + if (!PC_ReadLine(source, &token)) + { + SourceError(source, "#ifdef without name"); + return qfalse; + } //end if + if (token.type != TT_NAME) + { + PC_UnreadSourceToken(source, &token); + SourceError(source, "expected name after #ifdef, found %s", token.string); + return qfalse; + } //end if +#if DEFINEHASHING + d = PC_FindHashedDefine(source->definehash, token.string); +#else + d = PC_FindDefine(source->defines, token.string); +#endif //DEFINEHASHING + skip = (type == INDENT_IFDEF) == (d == NULL); + PC_PushIndent(source, type, skip); + return qtrue; +} //end of the function PC_Directiveif_def +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_ifdef(source_t *source) +{ + return PC_Directive_if_def(source, INDENT_IFDEF); +} //end of the function PC_Directive_ifdef +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_ifndef(source_t *source) +{ + return PC_Directive_if_def(source, INDENT_IFNDEF); +} //end of the function PC_Directive_ifndef +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_else(source_t *source) +{ + int type, skip; + + PC_PopIndent(source, &type, &skip); + if (!type) + { + SourceError(source, "misplaced #else"); + return qfalse; + } //end if + if (type == INDENT_ELSE) + { + SourceError(source, "#else after #else"); + return qfalse; + } //end if + PC_PushIndent(source, INDENT_ELSE, !skip); + return qtrue; +} //end of the function PC_Directive_else +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_endif(source_t *source) +{ + int type, skip; + + PC_PopIndent(source, &type, &skip); + if (!type) + { + SourceError(source, "misplaced #endif"); + return qfalse; + } //end if + return qtrue; +} //end of the function PC_Directive_endif +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +typedef struct operator_s +{ + int mOperator; + int priority; + int parentheses; + struct operator_s *prev, *next; +} operator_t; + +typedef struct value_s +{ + signed long int intvalue; + double floatvalue; + int parentheses; + struct value_s *prev, *next; +} value_t; + +int PC_OperatorPriority(int op) +{ + switch(op) + { + case P_MUL: return 15; + case P_DIV: return 15; + case P_MOD: return 15; + case P_ADD: return 14; + case P_SUB: return 14; + + case P_LOGIC_AND: return 7; + case P_LOGIC_OR: return 6; + case P_LOGIC_GEQ: return 12; + case P_LOGIC_LEQ: return 12; + case P_LOGIC_EQ: return 11; + case P_LOGIC_UNEQ: return 11; + + case P_LOGIC_NOT: return 16; + case P_LOGIC_GREATER: return 12; + case P_LOGIC_LESS: return 12; + + case P_RSHIFT: return 13; + case P_LSHIFT: return 13; + + case P_BIN_AND: return 10; + case P_BIN_OR: return 8; + case P_BIN_XOR: return 9; + case P_BIN_NOT: return 16; + + case P_COLON: return 5; + case P_QUESTIONMARK: return 5; + } //end switch + return qfalse; +} //end of the function PC_OperatorPriority + +#define MAX_VALUES 64 +#define MAX_OPERATORS 64 +#define AllocValue(val) \ + if (numvalues >= MAX_VALUES) { \ + SourceError(source, "out of value space"); \ + error = 1; \ + break; \ + } \ + else \ + val = &value_heap[numvalues++]; +#define FreeValue(val) +// +#define AllocOperator(op) \ + if (numoperators >= MAX_OPERATORS) { \ + SourceError(source, "out of operator space"); \ + error = 1; \ + break; \ + } \ + else \ + op = &operator_heap[numoperators++]; +#define FreeOperator(op) + +int PC_EvaluateTokens(source_t *source, token_t *tokens, signed long int *intvalue, + double *floatvalue, int integer) +{ + operator_t *o, *firstoperator, *lastoperator; + value_t *v, *firstvalue, *lastvalue, *v1, *v2; + token_t *t; + int brace = 0; + int parentheses = 0; + int error = 0; + int lastwasvalue = 0; + int negativevalue = 0; + int questmarkintvalue = 0; + double questmarkfloatvalue = 0; + int gotquestmarkvalue = qfalse; + // + operator_t operator_heap[MAX_OPERATORS]; + int numoperators = 0; + value_t value_heap[MAX_VALUES]; + int numvalues = 0; + + firstoperator = lastoperator = NULL; + firstvalue = lastvalue = NULL; + if (intvalue) *intvalue = 0; + if (floatvalue) *floatvalue = 0; + for (t = tokens; t; t = t->next) + { + switch(t->type) + { + case TT_NAME: + { + if (lastwasvalue || negativevalue) + { + SourceError(source, "syntax error in #if/#elif"); + error = 1; + break; + } //end if + if (strcmp(t->string, "defined")) + { + SourceError(source, "undefined name %s in #if/#elif", t->string); + error = 1; + break; + } //end if + t = t->next; + if (!strcmp(t->string, "(")) + { + brace = qtrue; + t = t->next; + } //end if + if (!t || t->type != TT_NAME) + { + SourceError(source, "defined without name in #if/#elif"); + error = 1; + break; + } //end if + //v = (value_t *) GetClearedMemory(sizeof(value_t)); + AllocValue(v); +#if DEFINEHASHING + if (PC_FindHashedDefine(source->definehash, t->string)) +#else + if (PC_FindDefine(source->defines, t->string)) +#endif //DEFINEHASHING + { + v->intvalue = 1; + v->floatvalue = 1; + } //end if + else + { + v->intvalue = 0; + v->floatvalue = 0; + } //end else + v->parentheses = parentheses; + v->next = NULL; + v->prev = lastvalue; + if (lastvalue) lastvalue->next = v; + else firstvalue = v; + lastvalue = v; + if (brace) + { + t = t->next; + if (!t || strcmp(t->string, ")")) + { + SourceError(source, "defined without ) in #if/#elif"); + error = 1; + break; + } //end if + } //end if + brace = qfalse; + // defined() creates a value + lastwasvalue = 1; + break; + } //end case + case TT_NUMBER: + { + if (lastwasvalue) + { + SourceError(source, "syntax error in #if/#elif"); + error = 1; + break; + } //end if + //v = (value_t *) GetClearedMemory(sizeof(value_t)); + AllocValue(v); + if (negativevalue) + { + v->intvalue = - (signed int) t->intvalue; + v->floatvalue = - t->floatvalue; + } //end if + else + { + v->intvalue = t->intvalue; + v->floatvalue = t->floatvalue; + } //end else + v->parentheses = parentheses; + v->next = NULL; + v->prev = lastvalue; + if (lastvalue) lastvalue->next = v; + else firstvalue = v; + lastvalue = v; + //last token was a value + lastwasvalue = 1; + // + negativevalue = 0; + break; + } //end case + case TT_PUNCTUATION: + { + if (negativevalue) + { + SourceError(source, "misplaced minus sign in #if/#elif"); + error = 1; + break; + } //end if + if (t->subtype == P_PARENTHESESOPEN) + { + parentheses++; + break; + } //end if + else if (t->subtype == P_PARENTHESESCLOSE) + { + parentheses--; + if (parentheses < 0) + { + SourceError(source, "too many ) in #if/#elsif"); + error = 1; + } //end if + break; + } //end else if + //check for invalid operators on floating point values + if (!integer) + { + if (t->subtype == P_BIN_NOT || t->subtype == P_MOD || + t->subtype == P_RSHIFT || t->subtype == P_LSHIFT || + t->subtype == P_BIN_AND || t->subtype == P_BIN_OR || + t->subtype == P_BIN_XOR) + { + SourceError(source, "illigal operator %s on floating point operands", t->string); + error = 1; + break; + } //end if + } //end if + switch(t->subtype) + { + case P_LOGIC_NOT: + case P_BIN_NOT: + { + if (lastwasvalue) + { + SourceError(source, "! or ~ after value in #if/#elif"); + error = 1; + break; + } //end if + break; + } //end case + case P_INC: + case P_DEC: + { + SourceError(source, "++ or -- used in #if/#elif"); + break; + } //end case + case P_SUB: + { + if (!lastwasvalue) + { + negativevalue = 1; + break; + } //end if + } //end case + + case P_MUL: + case P_DIV: + case P_MOD: + case P_ADD: + + case P_LOGIC_AND: + case P_LOGIC_OR: + case P_LOGIC_GEQ: + case P_LOGIC_LEQ: + case P_LOGIC_EQ: + case P_LOGIC_UNEQ: + + case P_LOGIC_GREATER: + case P_LOGIC_LESS: + + case P_RSHIFT: + case P_LSHIFT: + + case P_BIN_AND: + case P_BIN_OR: + case P_BIN_XOR: + + case P_COLON: + case P_QUESTIONMARK: + { + if (!lastwasvalue) + { + SourceError(source, "operator %s after operator in #if/#elif", t->string); + error = 1; + break; + } //end if + break; + } //end case + default: + { + SourceError(source, "invalid operator %s in #if/#elif", t->string); + error = 1; + break; + } //end default + } //end switch + if (!error && !negativevalue) + { + //o = (operator_t *) GetClearedMemory(sizeof(operator_t)); + AllocOperator(o); + o->mOperator = t->subtype; + o->priority = PC_OperatorPriority(t->subtype); + o->parentheses = parentheses; + o->next = NULL; + o->prev = lastoperator; + if (lastoperator) lastoperator->next = o; + else firstoperator = o; + lastoperator = o; + lastwasvalue = 0; + } //end if + break; + } //end case + default: + { + SourceError(source, "unknown %s in #if/#elif", t->string); + error = 1; + break; + } //end default + } //end switch + if (error) break; + } //end for + if (!error) + { + if (!lastwasvalue) + { + SourceError(source, "trailing operator in #if/#elif"); + error = 1; + } //end if + else if (parentheses) + { + SourceError(source, "too many ( in #if/#elif"); + error = 1; + } //end else if + } //end if + // + gotquestmarkvalue = qfalse; + questmarkintvalue = 0; + questmarkfloatvalue = 0; + //while there are operators + while(!error && firstoperator) + { + v = firstvalue; + for (o = firstoperator; o->next; o = o->next) + { + //if the current operator is nested deeper in parentheses + //than the next operator + if (o->parentheses > o->next->parentheses) break; + //if the current and next operator are nested equally deep in parentheses + if (o->parentheses == o->next->parentheses) + { + //if the priority of the current operator is equal or higher + //than the priority of the next operator + if (o->priority >= o->next->priority) break; + } //end if + //if the arity of the operator isn't equal to 1 + if (o->mOperator != P_LOGIC_NOT + && o->mOperator != P_BIN_NOT) v = v->next; + //if there's no value or no next value + if (!v) + { + SourceError(source, "mising values in #if/#elif"); + error = 1; + break; + } //end if + } //end for + if (error) break; + v1 = v; + v2 = v->next; +#ifdef DEBUG_EVAL + if (integer) + { + Log_Write("operator %s, value1 = %d", PunctuationFromNum(source->scriptstack, o->mOperator), v1->intvalue); + if (v2) Log_Write("value2 = %d", v2->intvalue); + } //end if + else + { + Log_Write("operator %s, value1 = %f", PunctuationFromNum(source->scriptstack, o->mOperator), v1->floatvalue); + if (v2) Log_Write("value2 = %f", v2->floatvalue); + } //end else +#endif //DEBUG_EVAL + switch(o->mOperator) + { + case P_LOGIC_NOT: v1->intvalue = !v1->intvalue; + v1->floatvalue = !v1->floatvalue; break; + case P_BIN_NOT: v1->intvalue = ~v1->intvalue; + break; + case P_MUL: v1->intvalue *= v2->intvalue; + v1->floatvalue *= v2->floatvalue; break; + case P_DIV: if (!v2->intvalue || !v2->floatvalue) + { + SourceError(source, "divide by zero in #if/#elif"); + error = 1; + break; + } + v1->intvalue /= v2->intvalue; + v1->floatvalue /= v2->floatvalue; break; + case P_MOD: if (!v2->intvalue) + { + SourceError(source, "divide by zero in #if/#elif"); + error = 1; + break; + } + v1->intvalue %= v2->intvalue; break; + case P_ADD: v1->intvalue += v2->intvalue; + v1->floatvalue += v2->floatvalue; break; + case P_SUB: v1->intvalue -= v2->intvalue; + v1->floatvalue -= v2->floatvalue; break; + case P_LOGIC_AND: v1->intvalue = v1->intvalue && v2->intvalue; + v1->floatvalue = v1->floatvalue && v2->floatvalue; break; + case P_LOGIC_OR: v1->intvalue = v1->intvalue || v2->intvalue; + v1->floatvalue = v1->floatvalue || v2->floatvalue; break; + case P_LOGIC_GEQ: v1->intvalue = v1->intvalue >= v2->intvalue; + v1->floatvalue = v1->floatvalue >= v2->floatvalue; break; + case P_LOGIC_LEQ: v1->intvalue = v1->intvalue <= v2->intvalue; + v1->floatvalue = v1->floatvalue <= v2->floatvalue; break; + case P_LOGIC_EQ: v1->intvalue = v1->intvalue == v2->intvalue; + v1->floatvalue = v1->floatvalue == v2->floatvalue; break; + case P_LOGIC_UNEQ: v1->intvalue = v1->intvalue != v2->intvalue; + v1->floatvalue = v1->floatvalue != v2->floatvalue; break; + case P_LOGIC_GREATER: v1->intvalue = v1->intvalue > v2->intvalue; + v1->floatvalue = v1->floatvalue > v2->floatvalue; break; + case P_LOGIC_LESS: v1->intvalue = v1->intvalue < v2->intvalue; + v1->floatvalue = v1->floatvalue < v2->floatvalue; break; + case P_RSHIFT: v1->intvalue >>= v2->intvalue; + break; + case P_LSHIFT: v1->intvalue <<= v2->intvalue; + break; + case P_BIN_AND: v1->intvalue &= v2->intvalue; + break; + case P_BIN_OR: v1->intvalue |= v2->intvalue; + break; + case P_BIN_XOR: v1->intvalue ^= v2->intvalue; + break; + case P_COLON: + { + if (!gotquestmarkvalue) + { + SourceError(source, ": without ? in #if/#elif"); + error = 1; + break; + } //end if + if (integer) + { + if (!questmarkintvalue) v1->intvalue = v2->intvalue; + } //end if + else + { + if (!questmarkfloatvalue) v1->floatvalue = v2->floatvalue; + } //end else + gotquestmarkvalue = qfalse; + break; + } //end case + case P_QUESTIONMARK: + { + if (gotquestmarkvalue) + { + SourceError(source, "? after ? in #if/#elif"); + error = 1; + break; + } //end if + questmarkintvalue = v1->intvalue; + questmarkfloatvalue = v1->floatvalue; + gotquestmarkvalue = qtrue; + break; + } //end if + } //end switch +#ifdef DEBUG_EVAL + if (integer) Log_Write("result value = %d", v1->intvalue); + else Log_Write("result value = %f", v1->floatvalue); +#endif //DEBUG_EVAL + if (error) break; + //if not an operator with arity 1 + if (o->mOperator != P_LOGIC_NOT + && o->mOperator != P_BIN_NOT) + { + //remove the second value if not question mark operator + if (o->mOperator != P_QUESTIONMARK) v = v->next; + // + if (v->prev) v->prev->next = v->next; + else firstvalue = v->next; + if (v->next) v->next->prev = v->prev; + else lastvalue = v->prev; + //FreeMemory(v); + FreeValue(v); + } //end if + //remove the operator + if (o->prev) o->prev->next = o->next; + else firstoperator = o->next; + if (o->next) o->next->prev = o->prev; + else lastoperator = o->prev; + //FreeMemory(o); + FreeOperator(o); + } //end while + if (firstvalue) + { + if (intvalue) *intvalue = firstvalue->intvalue; + if (floatvalue) *floatvalue = firstvalue->floatvalue; + } //end if + for (o = firstoperator; o; o = lastoperator) + { + lastoperator = o->next; + //FreeMemory(o); + FreeOperator(o); + } //end for + for (v = firstvalue; v; v = lastvalue) + { + lastvalue = v->next; + //FreeMemory(v); + FreeValue(v); + } //end for + if (!error) return qtrue; + if (intvalue) *intvalue = 0; + if (floatvalue) *floatvalue = 0; + return qfalse; +} //end of the function PC_EvaluateTokens +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Evaluate(source_t *source, signed long int *intvalue, + double *floatvalue, int integer) +{ + token_t token, *firsttoken, *lasttoken; + token_t *t, *nexttoken; + define_t *define; + int defined = qfalse; + + if (intvalue) *intvalue = 0; + if (floatvalue) *floatvalue = 0; + // + if (!PC_ReadLine(source, &token)) + { + SourceError(source, "no value after #if/#elif"); + return qfalse; + } //end if + firsttoken = NULL; + lasttoken = NULL; + do + { + //if the token is a name + if (token.type == TT_NAME) + { + if (defined) + { + defined = qfalse; + t = PC_CopyToken(&token); + t->next = NULL; + if (lasttoken) lasttoken->next = t; + else firsttoken = t; + lasttoken = t; + } //end if + else if (!strcmp(token.string, "defined")) + { + defined = qtrue; + t = PC_CopyToken(&token); + t->next = NULL; + if (lasttoken) lasttoken->next = t; + else firsttoken = t; + lasttoken = t; + } //end if + else + { + //then it must be a define +#if DEFINEHASHING + define = PC_FindHashedDefine(source->definehash, token.string); +#else + define = PC_FindDefine(source->defines, token.string); +#endif //DEFINEHASHING + if (!define) + { + SourceError(source, "can't evaluate %s, not defined", token.string); + return qfalse; + } //end if + if (!PC_ExpandDefineIntoSource(source, &token, define)) return qfalse; + } //end else + } //end if + //if the token is a number or a punctuation + else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION) + { + t = PC_CopyToken(&token); + t->next = NULL; + if (lasttoken) lasttoken->next = t; + else firsttoken = t; + lasttoken = t; + } //end else + else //can't evaluate the token + { + SourceError(source, "can't evaluate %s", token.string); + return qfalse; + } //end else + } while(PC_ReadLine(source, &token)); + // + if (!PC_EvaluateTokens(source, firsttoken, intvalue, floatvalue, integer)) return qfalse; + // +#ifdef DEBUG_EVAL + Log_Write("eval:"); +#endif //DEBUG_EVAL + for (t = firsttoken; t; t = nexttoken) + { +#ifdef DEBUG_EVAL + Log_Write(" %s", t->string); +#endif //DEBUG_EVAL + nexttoken = t->next; + PC_FreeToken(t); + } //end for +#ifdef DEBUG_EVAL + if (integer) Log_Write("eval result: %d", *intvalue); + else Log_Write("eval result: %f", *floatvalue); +#endif //DEBUG_EVAL + // + return qtrue; +} //end of the function PC_Evaluate +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_DollarEvaluate(source_t *source, signed long int *intvalue, + double *floatvalue, int integer) +{ + int indent, defined = qfalse; + token_t token, *firsttoken, *lasttoken; + token_t *t, *nexttoken; + define_t *define; + + if (intvalue) *intvalue = 0; + if (floatvalue) *floatvalue = 0; + // + if (!PC_ReadSourceToken(source, &token)) + { + SourceError(source, "no leading ( after $evalint/$evalfloat"); + return qfalse; + } //end if + if (!PC_ReadSourceToken(source, &token)) + { + SourceError(source, "nothing to evaluate"); + return qfalse; + } //end if + indent = 1; + firsttoken = NULL; + lasttoken = NULL; + do + { + //if the token is a name + if (token.type == TT_NAME) + { + if (defined) + { + defined = qfalse; + t = PC_CopyToken(&token); + t->next = NULL; + if (lasttoken) lasttoken->next = t; + else firsttoken = t; + lasttoken = t; + } //end if + else if (!strcmp(token.string, "defined")) + { + defined = qtrue; + t = PC_CopyToken(&token); + t->next = NULL; + if (lasttoken) lasttoken->next = t; + else firsttoken = t; + lasttoken = t; + } //end if + else + { + //then it must be a define +#if DEFINEHASHING + define = PC_FindHashedDefine(source->definehash, token.string); +#else + define = PC_FindDefine(source->defines, token.string); +#endif //DEFINEHASHING + if (!define) + { + SourceError(source, "can't evaluate %s, not defined", token.string); + return qfalse; + } //end if + if (!PC_ExpandDefineIntoSource(source, &token, define)) return qfalse; + } //end else + } //end if + //if the token is a number or a punctuation + else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION) + { + if (*token.string == '(') indent++; + else if (*token.string == ')') indent--; + if (indent <= 0) break; + t = PC_CopyToken(&token); + t->next = NULL; + if (lasttoken) lasttoken->next = t; + else firsttoken = t; + lasttoken = t; + } //end else + else //can't evaluate the token + { + SourceError(source, "can't evaluate %s", token.string); + return qfalse; + } //end else + } while(PC_ReadSourceToken(source, &token)); + // + if (!PC_EvaluateTokens(source, firsttoken, intvalue, floatvalue, integer)) return qfalse; + // +#ifdef DEBUG_EVAL + Log_Write("$eval:"); +#endif //DEBUG_EVAL + for (t = firsttoken; t; t = nexttoken) + { +#ifdef DEBUG_EVAL + Log_Write(" %s", t->string); +#endif //DEBUG_EVAL + nexttoken = t->next; + PC_FreeToken(t); + } //end for +#ifdef DEBUG_EVAL + if (integer) Log_Write("$eval result: %d", *intvalue); + else Log_Write("$eval result: %f", *floatvalue); +#endif //DEBUG_EVAL + // + return qtrue; +} //end of the function PC_DollarEvaluate +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_elif(source_t *source) +{ + signed long int value; + int type, skip; + + PC_PopIndent(source, &type, &skip); + if (!type || type == INDENT_ELSE) + { + SourceError(source, "misplaced #elif"); + return qfalse; + } //end if + if (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse; + skip = (value == 0); + PC_PushIndent(source, INDENT_ELIF, skip); + return qtrue; +} //end of the function PC_Directive_elif +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_if(source_t *source) +{ + signed long int value; + int skip; + + if (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse; + skip = (value == 0); + PC_PushIndent(source, INDENT_IF, skip); + return qtrue; +} //end of the function PC_Directive +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_line(source_t *source) +{ + SourceError(source, "#line directive not supported"); + return qfalse; +} //end of the function PC_Directive_line +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_error(source_t *source) +{ + token_t token; + + strcpy(token.string, ""); + PC_ReadSourceToken(source, &token); + SourceError(source, "#error directive: %s", token.string); + return qfalse; +} //end of the function PC_Directive_error +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_pragma(source_t *source) +{ + token_t token; + + SourceWarning(source, "#pragma directive not supported"); + while(PC_ReadLine(source, &token)) ; + return qtrue; +} //end of the function PC_Directive_pragma +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void UnreadSignToken(source_t *source) +{ + token_t token; + + token.line = source->scriptstack->line; + token.whitespace_p = source->scriptstack->script_p; + token.endwhitespace_p = source->scriptstack->script_p; + token.linescrossed = 0; + strcpy(token.string, "-"); + token.type = TT_PUNCTUATION; + token.subtype = P_SUB; + PC_UnreadSourceToken(source, &token); +} //end of the function UnreadSignToken +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_eval(source_t *source) +{ + signed long int value; + token_t token; + + if (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse; + // + token.line = source->scriptstack->line; + token.whitespace_p = source->scriptstack->script_p; + token.endwhitespace_p = source->scriptstack->script_p; + token.linescrossed = 0; + sprintf(token.string, "%ld", labs(value)); + token.type = TT_NUMBER; + token.subtype = TT_INTEGER|TT_LONG|TT_DECIMAL; + PC_UnreadSourceToken(source, &token); + if (value < 0) UnreadSignToken(source); + return qtrue; +} //end of the function PC_Directive_eval +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_Directive_evalfloat(source_t *source) +{ + double value; + token_t token; + + if (!PC_Evaluate(source, NULL, &value, qfalse)) return qfalse; + token.line = source->scriptstack->line; + token.whitespace_p = source->scriptstack->script_p; + token.endwhitespace_p = source->scriptstack->script_p; + token.linescrossed = 0; + sprintf(token.string, "%1.2f", fabs(value)); + token.type = TT_NUMBER; + token.subtype = TT_FLOAT|TT_LONG|TT_DECIMAL; + PC_UnreadSourceToken(source, &token); + if (value < 0) UnreadSignToken(source); + return qtrue; +} //end of the function PC_Directive_evalfloat +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +directive_t directives[20] = +{ + {"if", PC_Directive_if}, + {"ifdef", PC_Directive_ifdef}, + {"ifndef", PC_Directive_ifndef}, + {"elif", PC_Directive_elif}, + {"else", PC_Directive_else}, + {"endif", PC_Directive_endif}, + {"include", PC_Directive_include}, + {"define", PC_Directive_define}, + {"undef", PC_Directive_undef}, + {"line", PC_Directive_line}, + {"error", PC_Directive_error}, + {"pragma", PC_Directive_pragma}, + {"eval", PC_Directive_eval}, + {"evalfloat", PC_Directive_evalfloat}, + {NULL, NULL} +}; + +int PC_ReadDirective(source_t *source) +{ + token_t token; + int i; + + //read the directive name + if (!PC_ReadSourceToken(source, &token)) + { + SourceError(source, "found # without name"); + return qfalse; + } //end if + //directive name must be on the same line + if (token.linescrossed > 0) + { + PC_UnreadSourceToken(source, &token); + SourceError(source, "found # at end of line"); + return qfalse; + } //end if + //if if is a name + if (token.type == TT_NAME) + { + //find the precompiler directive + for (i = 0; directives[i].name; i++) + { + if (!strcmp(directives[i].name, token.string)) + { + return directives[i].func(source); + } //end if + } //end for + } //end if + SourceError(source, "unknown precompiler directive %s", token.string); + return qfalse; +} //end of the function PC_ReadDirective +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_DollarDirective_evalint(source_t *source) +{ + signed long int value; + token_t token; + + if (!PC_DollarEvaluate(source, &value, NULL, qtrue)) return qfalse; + // + token.line = source->scriptstack->line; + token.whitespace_p = source->scriptstack->script_p; + token.endwhitespace_p = source->scriptstack->script_p; + token.linescrossed = 0; + sprintf(token.string, "%ld", labs(value)); + token.type = TT_NUMBER; + token.subtype = TT_INTEGER|TT_LONG|TT_DECIMAL; + +#ifdef NUMBERVALUE + token.intvalue = labs(value); + token.floatvalue = token.intvalue; +#endif //NUMBERVALUE + + PC_UnreadSourceToken(source, &token); + if (value < 0) + UnreadSignToken(source); + + return qtrue; +} //end of the function PC_DollarDirective_evalint +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_DollarDirective_evalfloat(source_t *source) +{ + double value; + token_t token; + + if (!PC_DollarEvaluate(source, NULL, &value, qfalse)) return qfalse; + token.line = source->scriptstack->line; + token.whitespace_p = source->scriptstack->script_p; + token.endwhitespace_p = source->scriptstack->script_p; + token.linescrossed = 0; + sprintf(token.string, "%1.2f", fabs(value)); + token.type = TT_NUMBER; + token.subtype = TT_FLOAT|TT_LONG|TT_DECIMAL; + +#ifdef NUMBERVALUE + token.floatvalue = fabs(value); + token.intvalue = (unsigned long) token.floatvalue; +#endif //NUMBERVALUE + + PC_UnreadSourceToken(source, &token); + if (value < 0) + UnreadSignToken(source); + + return qtrue; +} //end of the function PC_DollarDirective_evalfloat +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +directive_t dollardirectives[20] = +{ + {"evalint", PC_DollarDirective_evalint}, + {"evalfloat", PC_DollarDirective_evalfloat}, + {NULL, NULL} +}; + +int PC_ReadDollarDirective(source_t *source) +{ + token_t token; + int i; + + //read the directive name + if (!PC_ReadSourceToken(source, &token)) + { + SourceError(source, "found $ without name"); + return qfalse; + } //end if + //directive name must be on the same line + if (token.linescrossed > 0) + { + PC_UnreadSourceToken(source, &token); + SourceError(source, "found $ at end of line"); + return qfalse; + } //end if + //if if is a name + if (token.type == TT_NAME) + { + //find the precompiler directive + for (i = 0; dollardirectives[i].name; i++) + { + if (!strcmp(dollardirectives[i].name, token.string)) + { + return dollardirectives[i].func(source); + } //end if + } //end for + } //end if + PC_UnreadSourceToken(source, &token); + SourceError(source, "unknown precompiler directive %s", token.string); + return qfalse; +} //end of the function PC_ReadDirective + +#ifdef QUAKEC +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int BuiltinFunction(source_t *source) +{ + token_t token; + + if (!PC_ReadSourceToken(source, &token)) return qfalse; + if (token.type == TT_NUMBER) + { + PC_UnreadSourceToken(source, &token); + return qtrue; + } //end if + else + { + PC_UnreadSourceToken(source, &token); + return qfalse; + } //end else +} //end of the function BuiltinFunction +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int QuakeCMacro(source_t *source) +{ + int i; + token_t token; + + if (!PC_ReadSourceToken(source, &token)) return qtrue; + if (token.type != TT_NAME) + { + PC_UnreadSourceToken(source, &token); + return qtrue; + } //end if + //find the precompiler directive + for (i = 0; dollardirectives[i].name; i++) + { + if (!strcmp(dollardirectives[i].name, token.string)) + { + PC_UnreadSourceToken(source, &token); + return qfalse; + } //end if + } //end for + PC_UnreadSourceToken(source, &token); + return qtrue; +} //end of the function QuakeCMacro +#endif //QUAKEC +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_ReadToken(source_t *source, token_t *token) +{ + define_t *define; + + while(1) + { + if (!PC_ReadSourceToken(source, token)) return qfalse; + //check for precompiler directives + if (token->type == TT_PUNCTUATION && *token->string == '@') // It is a StringEd key + { + char *holdString,holdString2[MAX_TOKEN]; + + PC_ReadSourceToken(source, token); + holdString = &token->string[1]; + Com_Memcpy( holdString2, token->string, sizeof(token->string)); + Com_Memcpy( holdString, holdString2, sizeof(token->string)); + token->string[0] = '@'; + return qtrue; + } + + if (token->type == TT_PUNCTUATION && *token->string == '#') + { +#ifdef QUAKEC + if (!BuiltinFunction(source)) +#endif //QUAKC + { + //read the precompiler directive + if (!PC_ReadDirective(source)) return qfalse; + continue; + } //end if + } //end if + if (token->type == TT_PUNCTUATION && *token->string == '$') + { +#ifdef QUAKEC + if (!QuakeCMacro(source)) +#endif //QUAKEC + { + //read the precompiler directive + if (!PC_ReadDollarDirective(source)) return qfalse; + continue; + } //end if + } //end if + // recursively concatenate strings that are behind each other still resolving defines + if (token->type == TT_STRING) + { + token_t newtoken; + if (PC_ReadToken(source, &newtoken)) + { + if (newtoken.type == TT_STRING) + { + token->string[strlen(token->string)-1] = '\0'; + if (strlen(token->string) + strlen(newtoken.string+1) + 1 >= MAX_TOKEN) + { + SourceError(source, "string longer than MAX_TOKEN %d", MAX_TOKEN); + return qfalse; + } + strcat(token->string, newtoken.string+1); + } + else + { + PC_UnreadToken(source, &newtoken); + } + } + } //end if + //if skipping source because of conditional compilation + if (source->skip) continue; + //if the token is a name + if (token->type == TT_NAME) + { + //check if the name is a define macro +#if DEFINEHASHING + define = PC_FindHashedDefine(source->definehash, token->string); +#else + define = PC_FindDefine(source->defines, token->string); +#endif //DEFINEHASHING + //if it is a define macro + if (define) + { + //expand the defined macro + if (!PC_ExpandDefineIntoSource(source, token, define)) return qfalse; + continue; + } //end if + } //end if + //copy token for unreading + Com_Memcpy(&source->token, token, sizeof(token_t)); + //found a token + return qtrue; + } //end while +} //end of the function PC_ReadToken +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_ExpectTokenString(source_t *source, char *string) +{ + token_t token; + + if (!PC_ReadToken(source, &token)) + { + SourceError(source, "couldn't find expected %s", string); + return qfalse; + } //end if + + if (strcmp(token.string, string)) + { + SourceError(source, "expected %s, found %s", string, token.string); + return qfalse; + } //end if + return qtrue; +} //end of the function PC_ExpectTokenString +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_ExpectTokenType(source_t *source, int type, int subtype, token_t *token) +{ + char str[MAX_TOKEN]; + + if (!PC_ReadToken(source, token)) + { + SourceError(source, "couldn't read expected token"); + return qfalse; + } //end if + + if (token->type != type) + { + strcpy(str, ""); + if (type == TT_STRING) strcpy(str, "string"); + if (type == TT_LITERAL) strcpy(str, "literal"); + if (type == TT_NUMBER) strcpy(str, "number"); + if (type == TT_NAME) strcpy(str, "name"); + if (type == TT_PUNCTUATION) strcpy(str, "punctuation"); + SourceError(source, "expected a %s, found %s", str, token->string); + return qfalse; + } //end if + if (token->type == TT_NUMBER) + { + if ((token->subtype & subtype) != subtype) + { + strcpy(str, ""); + if (subtype & TT_DECIMAL) strcpy(str, "decimal"); + if (subtype & TT_HEX) strcpy(str, "hex"); + if (subtype & TT_OCTAL) strcpy(str, "octal"); + if (subtype & TT_BINARY) strcpy(str, "binary"); + if (subtype & TT_LONG) strcat(str, " long"); + if (subtype & TT_UNSIGNED) strcat(str, " unsigned"); + if (subtype & TT_FLOAT) strcat(str, " float"); + if (subtype & TT_INTEGER) strcat(str, " integer"); + SourceError(source, "expected %s, found %s", str, token->string); + return qfalse; + } //end if + } //end if + else if (token->type == TT_PUNCTUATION) + { + if (token->subtype != subtype) + { + SourceError(source, "found %s", token->string); + return qfalse; + } //end if + } //end else if + return qtrue; +} //end of the function PC_ExpectTokenType +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_ExpectAnyToken(source_t *source, token_t *token) +{ + if (!PC_ReadToken(source, token)) + { + SourceError(source, "couldn't read expected token"); + return qfalse; + } //end if + else + { + return qtrue; + } //end else +} //end of the function PC_ExpectAnyToken +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_CheckTokenString(source_t *source, char *string) +{ + token_t tok; + + if (!PC_ReadToken(source, &tok)) return qfalse; + //if the token is available + if (!strcmp(tok.string, string)) return qtrue; + // + PC_UnreadSourceToken(source, &tok); + return qfalse; +} //end of the function PC_CheckTokenString +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_CheckTokenType(source_t *source, int type, int subtype, token_t *token) +{ + token_t tok; + + if (!PC_ReadToken(source, &tok)) return qfalse; + //if the type matches + if (tok.type == type && + (tok.subtype & subtype) == subtype) + { + Com_Memcpy(token, &tok, sizeof(token_t)); + return qtrue; + } //end if + // + PC_UnreadSourceToken(source, &tok); + return qfalse; +} //end of the function PC_CheckTokenType +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_SkipUntilString(source_t *source, char *string) +{ + token_t token; + + while(PC_ReadToken(source, &token)) + { + if (!strcmp(token.string, string)) return qtrue; + } //end while + return qfalse; +} //end of the function PC_SkipUntilString +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_UnreadLastToken(source_t *source) +{ + PC_UnreadSourceToken(source, &source->token); +} //end of the function PC_UnreadLastToken +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_UnreadToken(source_t *source, token_t *token) +{ + PC_UnreadSourceToken(source, token); +} //end of the function PC_UnreadToken +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_SetIncludePath(source_t *source, char *path) +{ + size_t len; + + Q_strncpyz(source->includepath, path, MAX_PATH-1); + + len = strlen(source->includepath); + //add trailing path seperator + if (len > 0 && source->includepath[len-1] != '\\' && + source->includepath[len-1] != '/') + { + strcat(source->includepath, PATHSEPERATOR_STR); + } //end if +} //end of the function PC_SetIncludePath +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_SetPunctuations(source_t *source, punctuation_t *p) +{ + source->punctuations = p; +} //end of the function PC_SetPunctuations +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +source_t *LoadSourceFile(const char *filename) +{ + source_t *source; + script_t *script; + + PC_InitTokenHeap(); + +#if DEFINEHASHING + if ( !globaldefines ) + { + globaldefines = (struct define_s **)GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *)); + } +#endif + + script = LoadScriptFile(filename); + if (!script) return NULL; + + script->next = NULL; + + source = (source_t *) GetMemory(sizeof(source_t)); + Com_Memset(source, 0, sizeof(source_t)); + + strncpy(source->filename, filename, MAX_PATH); + source->scriptstack = script; + source->tokens = NULL; + source->defines = NULL; + source->indentstack = NULL; + source->skip = 0; + +#if DEFINEHASHING + source->definehash = (struct define_s **)GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *)); +#endif //DEFINEHASHING + PC_AddGlobalDefinesToSource(source); + return source; +} //end of the function LoadSourceFile +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +source_t *LoadSourceMemory(char *ptr, int length, char *name) +{ + source_t *source; + script_t *script; + + PC_InitTokenHeap(); + + script = LoadScriptMemory(ptr, length, name); + if (!script) return NULL; + script->next = NULL; + + source = (source_t *) GetMemory(sizeof(source_t)); + Com_Memset(source, 0, sizeof(source_t)); + + strncpy(source->filename, name, MAX_PATH); + source->scriptstack = script; + source->tokens = NULL; + source->defines = NULL; + source->indentstack = NULL; + source->skip = 0; + +#if DEFINEHASHING + source->definehash = (struct define_s **)GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *)); +#endif //DEFINEHASHING + PC_AddGlobalDefinesToSource(source); + return source; +} //end of the function LoadSourceMemory +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void FreeSource(source_t *source) +{ + script_t *script; + token_t *token; + define_t *define; + indent_t *indent; + define_t *nextdefine; + int i; + + //PC_PrintDefineHashTable(source->definehash); + //free all the scripts + while(source->scriptstack) + { + script = source->scriptstack; + source->scriptstack = source->scriptstack->next; + FreeScript(script); + } //end for + //free all the tokens + while(source->tokens) + { + token = source->tokens; + source->tokens = source->tokens->next; + PC_FreeToken(token); + } //end for +#if DEFINEHASHING + for (i = 0; i < DEFINEHASHSIZE; i++) + { + define = source->definehash[i]; + while(define) + { + nextdefine = define->hashnext; + + if ( !(define->flags & DEFINE_GLOBAL) ) + { + PC_FreeDefine(define); + } + + define = nextdefine; + } //end while + + source->definehash[i] = NULL; + } //end for +#else //DEFINEHASHING + //free all defines + while(source->defines) + { + define = source->defines; + source->defines = source->defines->next; + PC_FreeDefine(define); + } //end for +#endif //DEFINEHASHING + //free all indents + while(source->indentstack) + { + indent = source->indentstack; + source->indentstack = source->indentstack->next; + FreeMemory(indent); + } //end for +#if DEFINEHASHING + // + if (source->definehash) FreeMemory(source->definehash); +#endif //DEFINEHASHING + //free the source itself + FreeMemory(source); +} //end of the function FreeSource +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ + +#define MAX_SOURCEFILES 64 + +source_t *sourceFiles[MAX_SOURCEFILES]; + +int PC_LoadSourceHandle(const char *filename) +{ + source_t *source; + int i; + + for (i = 1; i < MAX_SOURCEFILES; i++) + { + if (!sourceFiles[i]) + break; + } //end for + if (i >= MAX_SOURCEFILES) + return 0; + PS_SetBaseFolder(""); + source = LoadSourceFile(filename); + if (!source) + return 0; + sourceFiles[i] = source; + return i; +} //end of the function PC_LoadSourceHandle +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_FreeSourceHandle(int handle) +{ + if (handle < 1 || handle >= MAX_SOURCEFILES) + return qfalse; + if (!sourceFiles[handle]) + return qfalse; + + FreeSource(sourceFiles[handle]); + sourceFiles[handle] = NULL; + return qtrue; +} //end of the function PC_FreeSourceHandle + +int PC_LoadGlobalDefines ( const char* filename ) +{ + int handle; + token_t token; + + handle = PC_LoadSourceHandle ( filename ); + if ( handle < 1 ) + return qfalse; + + addGlobalDefine = qtrue; + + // Read all the token files which will add the defines globally + while ( PC_ReadToken(sourceFiles[handle], &token) ); + + addGlobalDefine = qfalse; + + PC_FreeSourceHandle ( handle ); + + return qtrue; +} + +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_ReadTokenHandle(int handle, pc_token_t *pc_token) +{ + token_t token; + int ret; + + if (handle < 1 || handle >= MAX_SOURCEFILES) + return 0; + if (!sourceFiles[handle]) + return 0; + + ret = PC_ReadToken(sourceFiles[handle], &token); + strcpy(pc_token->string, token.string); + pc_token->type = token.type; + pc_token->subtype = token.subtype; + pc_token->intvalue = token.intvalue; + pc_token->floatvalue = token.floatvalue; + if ((pc_token->type == TT_STRING) && (pc_token->string[0]!='@')) + StripDoubleQuotes(pc_token->string); + + return ret; +} //end of the function PC_ReadTokenHandle +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PC_SourceFileAndLine(int handle, char *filename, int *line) +{ + if (handle < 1 || handle >= MAX_SOURCEFILES) + return qfalse; + if (!sourceFiles[handle]) + return qfalse; + + strcpy(filename, sourceFiles[handle]->filename); + if (sourceFiles[handle]->scriptstack) + *line = sourceFiles[handle]->scriptstack->line; + else + *line = 0; + return qtrue; +} //end of the function PC_SourceFileAndLine +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_SetBaseFolder(char *path) +{ + PS_SetBaseFolder(path); +} //end of the function PC_SetBaseFolder +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PC_CheckOpenSourceHandles(void) +{ + int i; + + for (i = 1; i < MAX_SOURCEFILES; i++) + { + if (sourceFiles[i]) + { +#ifdef BOTLIB + botimport.Print(PRT_ERROR, "file %s still open in precompiler\n", sourceFiles[i]->scriptstack->filename); +#endif //BOTLIB + } //end if + } //end for +} //end of the function PC_CheckOpenSourceHandles + diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_precomp.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_precomp.h new file mode 100644 index 0000000..b1731c1 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_precomp.h @@ -0,0 +1,191 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: l_precomp.h + * + * desc: pre compiler + * + * $Archive: /source/code/botlib/l_precomp.h $ + * $Author: Mrelusive $ + * $Revision: 2 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 10/05/99 3:42p $ + * + *****************************************************************************/ + +#pragma once + +#ifndef MAX_PATH + #define MAX_PATH MAX_QPATH +#endif + +#ifndef PATH_SEPERATORSTR + #ifdef _WIN32 + #define PATHSEPERATOR_STR "\\" + #else + #define PATHSEPERATOR_STR "/" + #endif +#endif +#ifndef PATH_SEPERATORCHAR + #ifdef _WIN32 + #define PATHSEPERATOR_CHAR '\\' + #else + #define PATHSEPERATOR_CHAR '/' + #endif +#endif + +#if defined(BSPC) && !defined(QDECL) +#define QDECL +#endif + + +#define DEFINE_FIXED 0x0001 +#define DEFINE_GLOBAL 0x0002 + +#define BUILTIN_LINE 1 +#define BUILTIN_FILE 2 +#define BUILTIN_DATE 3 +#define BUILTIN_TIME 4 +#define BUILTIN_STDC 5 + +#define INDENT_IF 0x0001 +#define INDENT_ELSE 0x0002 +#define INDENT_ELIF 0x0004 +#define INDENT_IFDEF 0x0008 +#define INDENT_IFNDEF 0x0010 + +//macro definitions +typedef struct define_s +{ + char *name; //define name + int flags; //define flags + int builtin; // > 0 if builtin define + int numparms; //number of define parameters + token_t *parms; //define parameters + token_t *tokens; //macro tokens (possibly containing parm tokens) + struct define_s *next; //next defined macro in a list + struct define_s *hashnext; //next define in the hash chain + struct define_s *globalnext; //used to link up the globald defines +} define_t; + +//indents +//used for conditional compilation directives: +//#if, #else, #elif, #ifdef, #ifndef +typedef struct indent_s +{ + int type; //indent type + int skip; //true if skipping current indent + script_t *script; //script the indent was in + struct indent_s *next; //next indent on the indent stack +} indent_t; + +//source file +typedef struct source_s +{ + char filename[1024]; //file name of the script + char includepath[1024]; //path to include files + punctuation_t *punctuations; //punctuations to use + script_t *scriptstack; //stack with scripts of the source + token_t *tokens; //tokens to read first + define_t *defines; //list with macro definitions + define_t **definehash; //hash chain with defines + indent_t *indentstack; //stack with indents + int skip; // > 0 if skipping conditional code + token_t token; //last read token +} source_t; + + +//read a token from the source +int PC_ReadToken(source_t *source, token_t *token); +//expect a certain token +int PC_ExpectTokenString(source_t *source, char *string); +//expect a certain token type +int PC_ExpectTokenType(source_t *source, int type, int subtype, token_t *token); +//expect a token +int PC_ExpectAnyToken(source_t *source, token_t *token); +//returns true when the token is available +int PC_CheckTokenString(source_t *source, char *string); +//returns true and reads the token when a token with the given type is available +int PC_CheckTokenType(source_t *source, int type, int subtype, token_t *token); +//skip tokens until the given token string is read +int PC_SkipUntilString(source_t *source, char *string); +//unread the last token read from the script +void PC_UnreadLastToken(source_t *source); +//unread the given token +void PC_UnreadToken(source_t *source, token_t *token); +//read a token only if on the same line, lines are concatenated with a slash +int PC_ReadLine(source_t *source, token_t *token); +//returns true if there was a white space in front of the token +int PC_WhiteSpaceBeforeToken(token_t *token); +//add a define to the source +int PC_AddDefine(source_t *source, char *string); +//add a globals define that will be added to all opened sources +int PC_AddGlobalDefine(char *string); +//remove the given global define +int PC_RemoveGlobalDefine(char *name); +//remove all globals defines +void PC_RemoveAllGlobalDefines(void); +//add builtin defines +void PC_AddBuiltinDefines(source_t *source); +//set the source include path +void PC_SetIncludePath(source_t *source, char *path); +//set the punction set +void PC_SetPunctuations(source_t *source, punctuation_t *p); +//set the base folder to load files from +void PC_SetBaseFolder(char *path); +//load a source file +source_t *LoadSourceFile(const char *filename); +//load a source from memory +source_t *LoadSourceMemory(char *ptr, int length, char *name); +//free the given source +void FreeSource(source_t *source); +//print a source error +void QDECL SourceError(source_t *source, char *str, ...); +//print a source warning +void QDECL SourceWarning(source_t *source, char *str, ...); + +#ifdef BSPC +// some of BSPC source does include qcommon/q_shared.h and some does not +// we define pc_token_s pc_token_t if needed (yes, it's ugly) +#ifndef __Q_SHARED_H +#define MAX_TOKENLENGTH 1024 +typedef struct pc_token_s +{ + int type; + int subtype; + int intvalue; + float floatvalue; + char string[MAX_TOKENLENGTH]; +} pc_token_t; +#endif //!_Q_SHARED_H +#endif //BSPC + +// +int PC_LoadSourceHandle(const char *filename); +int PC_FreeSourceHandle(int handle); +int PC_ReadTokenHandle(int handle, pc_token_t *pc_token); +int PC_SourceFileAndLine(int handle, char *filename, int *line); +void PC_CheckOpenSourceHandles(void); +int PC_LoadGlobalDefines ( const char* filename ); +void PC_RemoveAllGlobalDefines ( void ); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_script.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_script.cpp new file mode 100644 index 0000000..8be425b --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_script.cpp @@ -0,0 +1,1458 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: l_script.c + * + * desc: lexicographical parser + * + * $Archive: /MissionPack/code/botlib/l_script.c $ + * $Author: Ttimo $ + * $Revision: 9 $ + * $Modtime: 4/13/01 4:45p $ + * $Date: 4/13/01 4:45p $ + * + *****************************************************************************/ + +//#define SCREWUP +//#define BOTLIB +//#define MEQCC +//#define BSPC + +#ifdef SCREWUP +#include +#include +#include +#include +#include +#include "l_memory.h" +#include "l_script.h" + +typedef enum {qfalse, qtrue} qboolean; + +#endif //SCREWUP + +#ifdef BOTLIB +//include files for usage in the bot library +#include "qcommon/q_shared.h" +#include "botlib.h" +#include "be_interface.h" +#include "l_script.h" +#include "l_memory.h" +#include "l_log.h" +#include "l_libvar.h" +#endif //BOTLIB + +#ifdef MEQCC +//include files for usage in MrElusive's QuakeC Compiler +#include "qcc.h" +#include "l_script.h" +#include "l_memory.h" +#include "l_log.h" + +#define qtrue true +#define qfalse false +#endif //MEQCC + +#ifdef BSPC +//include files for usage in the BSP Converter +#include "../bspc/qbsp.h" +#include "../bspc/l_log.h" +#include "../bspc/l_mem.h" + +#define qtrue true +#define qfalse false +#endif //BSPC + + +#define PUNCTABLE + +//longer punctuations first +punctuation_t default_punctuations[] = +{ + //binary operators + {">>=",P_RSHIFT_ASSIGN, NULL}, + {"<<=",P_LSHIFT_ASSIGN, NULL}, + // + {"...",P_PARMS, NULL}, + //define merge operator + {"##",P_PRECOMPMERGE, NULL}, + //logic operators + {"&&",P_LOGIC_AND, NULL}, + {"||",P_LOGIC_OR, NULL}, + {">=",P_LOGIC_GEQ, NULL}, + {"<=",P_LOGIC_LEQ, NULL}, + {"==",P_LOGIC_EQ, NULL}, + {"!=",P_LOGIC_UNEQ, NULL}, + //arithmatic operators + {"*=",P_MUL_ASSIGN, NULL}, + {"/=",P_DIV_ASSIGN, NULL}, + {"%=",P_MOD_ASSIGN, NULL}, + {"+=",P_ADD_ASSIGN, NULL}, + {"-=",P_SUB_ASSIGN, NULL}, + {"++",P_INC, NULL}, + {"--",P_DEC, NULL}, + //binary operators + {"&=",P_BIN_AND_ASSIGN, NULL}, + {"|=",P_BIN_OR_ASSIGN, NULL}, + {"^=",P_BIN_XOR_ASSIGN, NULL}, + {">>",P_RSHIFT, NULL}, + {"<<",P_LSHIFT, NULL}, + //reference operators + {"->",P_POINTERREF, NULL}, + //C++ + {"::",P_CPP1, NULL}, + {".*",P_CPP2, NULL}, + //arithmatic operators + {"*",P_MUL, NULL}, + {"/",P_DIV, NULL}, + {"%",P_MOD, NULL}, + {"+",P_ADD, NULL}, + {"-",P_SUB, NULL}, + {"=",P_ASSIGN, NULL}, + //binary operators + {"&",P_BIN_AND, NULL}, + {"|",P_BIN_OR, NULL}, + {"^",P_BIN_XOR, NULL}, + {"~",P_BIN_NOT, NULL}, + //logic operators + {"!",P_LOGIC_NOT, NULL}, + {">",P_LOGIC_GREATER, NULL}, + {"<",P_LOGIC_LESS, NULL}, + //reference operator + {".",P_REF, NULL}, + //seperators + {",",P_COMMA, NULL}, + {";",P_SEMICOLON, NULL}, + //label indication + {":",P_COLON, NULL}, + //if statement + {"?",P_QUESTIONMARK, NULL}, + //embracements + {"(",P_PARENTHESESOPEN, NULL}, + {")",P_PARENTHESESCLOSE, NULL}, + {"{",P_BRACEOPEN, NULL}, + {"}",P_BRACECLOSE, NULL}, + {"[",P_SQBRACKETOPEN, NULL}, + {"]",P_SQBRACKETCLOSE, NULL}, + // + {"\\",P_BACKSLASH, NULL}, + //precompiler operator + {"#",P_PRECOMP, NULL}, +#ifdef DOLLAR + {"$",P_DOLLAR, NULL}, +#endif //DOLLAR + // StringEd key + {"@",P_ATSIGN, NULL}, + {NULL, 0} +}; + +#ifdef BSPC +char basefolder[MAX_PATH]; +#else +char basefolder[MAX_QPATH]; +#endif + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void PS_CreatePunctuationTable(script_t *script, punctuation_t *punctuations) +{ + int i; + punctuation_t *p, *lastp, *newp; + + //get memory for the table + if (!script->punctuationtable) script->punctuationtable = (punctuation_t **) + GetMemory(256 * sizeof(punctuation_t *)); + Com_Memset(script->punctuationtable, 0, 256 * sizeof(punctuation_t *)); + //add the punctuations in the list to the punctuation table + for (i = 0; punctuations[i].p; i++) + { + newp = &punctuations[i]; + lastp = NULL; + //sort the punctuations in this table entry on length (longer punctuations first) + for (p = script->punctuationtable[(unsigned int) newp->p[0]]; p; p = p->next) + { + if (strlen(p->p) < strlen(newp->p)) + { + newp->next = p; + if (lastp) lastp->next = newp; + else script->punctuationtable[(unsigned int) newp->p[0]] = newp; + break; + } //end if + lastp = p; + } //end for + if (!p) + { + newp->next = NULL; + if (lastp) lastp->next = newp; + else script->punctuationtable[(unsigned int) newp->p[0]] = newp; + } //end if + } //end for +} //end of the function PS_CreatePunctuationTable +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +const char *PunctuationFromNum(script_t *script, int num) +{ + int i; + + for (i = 0; script->punctuations[i].p; i++) + { + if (script->punctuations[i].n == num) return script->punctuations[i].p; + } //end for + return "unkown punctuation"; +} //end of the function PunctuationFromNum +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void QDECL ScriptError(script_t *script, char *str, ...) +{ + char text[1024]; + va_list ap; + + if (script->flags & SCFL_NOERRORS) return; + + va_start(ap, str); + Q_vsnprintf(text, sizeof(text), str, ap); + va_end(ap); +#ifdef BOTLIB + botimport.Print(PRT_ERROR, "file %s, line %d: %s\n", script->filename, script->line, text); +#endif //BOTLIB +#ifdef MEQCC + printf("error: file %s, line %d: %s\n", script->filename, script->line, text); +#endif //MEQCC +#ifdef BSPC + Log_Print("error: file %s, line %d: %s\n", script->filename, script->line, text); +#endif //BSPC +} //end of the function ScriptError +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void QDECL ScriptWarning(script_t *script, char *str, ...) +{ + char text[1024]; + va_list ap; + + if (script->flags & SCFL_NOWARNINGS) return; + + va_start(ap, str); + Q_vsnprintf(text, sizeof(text), str, ap); + va_end(ap); +#ifdef BOTLIB + botimport.Print(PRT_WARNING, "file %s, line %d: %s\n", script->filename, script->line, text); +#endif //BOTLIB +#ifdef MEQCC + printf("warning: file %s, line %d: %s\n", script->filename, script->line, text); +#endif //MEQCC +#ifdef BSPC + Log_Print("warning: file %s, line %d: %s\n", script->filename, script->line, text); +#endif //BSPC +} //end of the function ScriptWarning +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void SetScriptPunctuations(script_t *script, punctuation_t *p) +{ +#ifdef PUNCTABLE + if (p) PS_CreatePunctuationTable(script, p); + else PS_CreatePunctuationTable(script, default_punctuations); +#endif //PUNCTABLE + if (p) script->punctuations = p; + else script->punctuations = default_punctuations; +} //end of the function SetScriptPunctuations +//============================================================================ +// Reads spaces, tabs, C-like comments etc. +// When a newline character is found the scripts line counter is increased. +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PS_ReadWhiteSpace(script_t *script) +{ + while(1) + { + //skip white space + while(*script->script_p <= ' ') + { + if (!*script->script_p) return 0; + if (*script->script_p == '\n') script->line++; + script->script_p++; + } //end while + //skip comments + if (*script->script_p == '/') + { + //comments // + if (*(script->script_p+1) == '/') + { + script->script_p++; + do + { + script->script_p++; + if (!*script->script_p) return 0; + } //end do + while(*script->script_p != '\n'); + script->line++; + script->script_p++; + if (!*script->script_p) return 0; + continue; + } //end if + //comments /* */ + else if (*(script->script_p+1) == '*') + { + script->script_p++; + do + { + script->script_p++; + if (!*script->script_p) return 0; + if (*script->script_p == '\n') script->line++; + } //end do + while(!(*script->script_p == '*' && *(script->script_p+1) == '/')); + script->script_p++; + if (!*script->script_p) return 0; + script->script_p++; + if (!*script->script_p) return 0; + continue; + } //end if + } //end if + break; + } //end while + return 1; +} //end of the function PS_ReadWhiteSpace +//============================================================================ +// Reads an escape character. +// +// Parameter: script : script to read from +// ch : place to store the read escape character +// Returns: - +// Changes Globals: - +//============================================================================ +int PS_ReadEscapeCharacter(script_t *script, char *ch) +{ + int c, val, i; + + //step over the leading '\\' + script->script_p++; + //determine the escape character + switch(*script->script_p) + { + case '\\': c = '\\'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'v': c = '\v'; break; + case 'b': c = '\b'; break; + case 'f': c = '\f'; break; + case 'a': c = '\a'; break; + case '\'': c = '\''; break; + case '\"': c = '\"'; break; + case '\?': c = '\?'; break; + case 'x': + { + script->script_p++; + for (i = 0, val = 0; ; i++, script->script_p++) + { + c = *script->script_p; + if (c >= '0' && c <= '9') c = c - '0'; + else if (c >= 'A' && c <= 'Z') c = c - 'A' + 10; + else if (c >= 'a' && c <= 'z') c = c - 'a' + 10; + else break; + val = (val << 4) + c; + } //end for + script->script_p--; + if (val > 0xFF) + { + ScriptWarning(script, "too large value in escape character"); + val = 0xFF; + } //end if + c = val; + break; + } //end case + default: //NOTE: decimal ASCII code, NOT octal + { + if (*script->script_p < '0' || *script->script_p > '9') ScriptError(script, "unknown escape char"); + for (i = 0, val = 0; ; i++, script->script_p++) + { + c = *script->script_p; + if (c >= '0' && c <= '9') c = c - '0'; + else break; + val = val * 10 + c; + } //end for + script->script_p--; + if (val > 0xFF) + { + ScriptWarning(script, "too large value in escape character"); + val = 0xFF; + } //end if + c = val; + break; + } //end default + } //end switch + //step over the escape character or the last digit of the number + script->script_p++; + //store the escape character + *ch = c; + //successfully read escape character + return 1; +} //end of the function PS_ReadEscapeCharacter +//============================================================================ +// Reads C-like string. Escape characters are interpretted. +// Quotes are included with the string. +// Reads two strings with a white space between them as one string. +// +// Parameter: script : script to read from +// token : buffer to store the string +// Returns: qtrue when a string was read succesfully +// Changes Globals: - +//============================================================================ +int PS_ReadString(script_t *script, token_t *token, int quote) +{ + int len, tmpline; + char *tmpscript_p; + + if (quote == '\"') token->type = TT_STRING; + else token->type = TT_LITERAL; + + len = 0; + //leading quote + token->string[len++] = *script->script_p++; + // + while(1) + { + //minus 2 because trailing double quote and zero have to be appended + if (len >= MAX_TOKEN - 2) + { + ScriptError(script, "string longer than MAX_TOKEN = %d", MAX_TOKEN); + return 0; + } //end if + //if there is an escape character and + //if escape characters inside a string are allowed + if (*script->script_p == '\\' && !(script->flags & SCFL_NOSTRINGESCAPECHARS)) + { + if (!PS_ReadEscapeCharacter(script, &token->string[len])) + { + token->string[len] = 0; + return 0; + } //end if + len++; + } //end if + //if a trailing quote + else if (*script->script_p == quote) + { + //step over the double quote + script->script_p++; + //if white spaces in a string are not allowed + if (script->flags & SCFL_NOSTRINGWHITESPACES) break; + // + tmpscript_p = script->script_p; + tmpline = script->line; + //read unusefull stuff between possible two following strings + if (!PS_ReadWhiteSpace(script)) + { + script->script_p = tmpscript_p; + script->line = tmpline; + break; + } //end if + //if there's no leading double qoute + if (*script->script_p != quote) + { + script->script_p = tmpscript_p; + script->line = tmpline; + break; + } //end if + //step over the new leading double quote + script->script_p++; + } //end if + else + { + if (*script->script_p == '\0') + { + token->string[len] = 0; + ScriptError(script, "missing trailing quote"); + return 0; + } //end if + if (*script->script_p == '\n') + { + token->string[len] = 0; + ScriptError(script, "newline inside string %s", token->string); + return 0; + } //end if + token->string[len++] = *script->script_p++; + } //end else + } //end while + //trailing quote + token->string[len++] = quote; + //end string with a zero + token->string[len] = '\0'; + //the sub type is the length of the string + token->subtype = len; + return 1; +} //end of the function PS_ReadString +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PS_ReadName(script_t *script, token_t *token) +{ + int len = 0; + char c; + + token->type = TT_NAME; + do + { + token->string[len++] = *script->script_p++; + if (len >= MAX_TOKEN) + { + ScriptError(script, "name longer than MAX_TOKEN = %d", MAX_TOKEN); + return 0; + } //end if + c = *script->script_p; + } while ((c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || + c == '_'); + token->string[len] = '\0'; + //the sub type is the length of the name + token->subtype = len; + return 1; +} //end of the function PS_ReadName +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void NumberValue(char *string, int subtype, unsigned long int *intvalue, + long double *floatvalue) +{ + unsigned long int dotfound = 0; + + *intvalue = 0; + *floatvalue = 0; + //floating point number + if (subtype & TT_FLOAT) + { + while(*string) + { + if (*string == '.') + { + if (dotfound) return; + dotfound = 10; + string++; + } //end if + if (dotfound) + { + *floatvalue = *floatvalue + (long double) (*string - '0') / + (long double) dotfound; + dotfound *= 10; + } //end if + else + { + *floatvalue = *floatvalue * 10.0 + (long double) (*string - '0'); + } //end else + string++; + } //end while + *intvalue = (unsigned long) *floatvalue; + } //end if + else if (subtype & TT_DECIMAL) + { + while(*string) *intvalue = *intvalue * 10 + (*string++ - '0'); + *floatvalue = *intvalue; + } //end else if + else if (subtype & TT_HEX) + { + //step over the leading 0x or 0X + string += 2; + while(*string) + { + *intvalue <<= 4; + if (*string >= 'a' && *string <= 'f') *intvalue += *string - 'a' + 10; + else if (*string >= 'A' && *string <= 'F') *intvalue += *string - 'A' + 10; + else *intvalue += *string - '0'; + string++; + } //end while + *floatvalue = *intvalue; + } //end else if + else if (subtype & TT_OCTAL) + { + //step over the first zero + string += 1; + while(*string) *intvalue = (*intvalue << 3) + (*string++ - '0'); + *floatvalue = *intvalue; + } //end else if + else if (subtype & TT_BINARY) + { + //step over the leading 0b or 0B + string += 2; + while(*string) *intvalue = (*intvalue << 1) + (*string++ - '0'); + *floatvalue = *intvalue; + } //end else if +} //end of the function NumberValue +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PS_ReadNumber(script_t *script, token_t *token) +{ + int len = 0, i; + int octal, dot; + char c; +// unsigned long int intvalue = 0; +// long double floatvalue = 0; + + token->type = TT_NUMBER; + //check for a hexadecimal number + if (*script->script_p == '0' && + (*(script->script_p + 1) == 'x' || + *(script->script_p + 1) == 'X')) + { + token->string[len++] = *script->script_p++; + token->string[len++] = *script->script_p++; + c = *script->script_p; + //hexadecimal + while((c >= '0' && c <= '9') || + (c >= 'a' && c <= 'f') || + (c >= 'A' && c <= 'A')) + { + token->string[len++] = *script->script_p++; + if (len >= MAX_TOKEN) + { + ScriptError(script, "hexadecimal number longer than MAX_TOKEN = %d", MAX_TOKEN); + return 0; + } //end if + c = *script->script_p; + } //end while + token->subtype |= TT_HEX; + } //end if +#ifdef BINARYNUMBERS + //check for a binary number + else if (*script->script_p == '0' && + (*(script->script_p + 1) == 'b' || + *(script->script_p + 1) == 'B')) + { + token->string[len++] = *script->script_p++; + token->string[len++] = *script->script_p++; + c = *script->script_p; + //binary + while(c == '0' || c == '1') + { + token->string[len++] = *script->script_p++; + if (len >= MAX_TOKEN) + { + ScriptError(script, "binary number longer than MAX_TOKEN = %d", MAX_TOKEN); + return 0; + } //end if + c = *script->script_p; + } //end while + token->subtype |= TT_BINARY; + } //end if +#endif //BINARYNUMBERS + else //decimal or octal integer or floating point number + { + octal = qfalse; + dot = qfalse; + if (*script->script_p == '0') octal = qtrue; + while(1) + { + c = *script->script_p; + if (c == '.') dot = qtrue; + else if (c == '8' || c == '9') octal = qfalse; + else if (c < '0' || c > '9') break; + token->string[len++] = *script->script_p++; + if (len >= MAX_TOKEN - 1) + { + ScriptError(script, "number longer than MAX_TOKEN = %d", MAX_TOKEN); + return 0; + } //end if + } //end while + if (octal) token->subtype |= TT_OCTAL; + else token->subtype |= TT_DECIMAL; + if (dot) token->subtype |= TT_FLOAT; + } //end else + for (i = 0; i < 2; i++) + { + c = *script->script_p; + //check for a LONG number + if ( (c == 'l' || c == 'L') // bk001204 - brackets + && !(token->subtype & TT_LONG)) + { + script->script_p++; + token->subtype |= TT_LONG; + } //end if + //check for an UNSIGNED number + else if ( (c == 'u' || c == 'U') // bk001204 - brackets + && !(token->subtype & (TT_UNSIGNED | TT_FLOAT))) + { + script->script_p++; + token->subtype |= TT_UNSIGNED; + } //end if + } //end for + token->string[len] = '\0'; +#ifdef NUMBERVALUE + NumberValue(token->string, token->subtype, &token->intvalue, &token->floatvalue); +#endif //NUMBERVALUE + if (!(token->subtype & TT_FLOAT)) token->subtype |= TT_INTEGER; + return 1; +} //end of the function PS_ReadNumber +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PS_ReadLiteral(script_t *script, token_t *token) +{ + token->type = TT_LITERAL; + //first quote + token->string[0] = *script->script_p++; + //check for end of file + if (!*script->script_p) + { + ScriptError(script, "end of file before trailing \'"); + return 0; + } //end if + //if it is an escape character + if (*script->script_p == '\\') + { + if (!PS_ReadEscapeCharacter(script, &token->string[1])) return 0; + } //end if + else + { + token->string[1] = *script->script_p++; + } //end else + //check for trailing quote + if (*script->script_p != '\'') + { + ScriptWarning(script, "too many characters in literal, ignored"); + while(*script->script_p && + *script->script_p != '\'' && + *script->script_p != '\n') + { + script->script_p++; + } //end while + if (*script->script_p == '\'') script->script_p++; + } //end if + //store the trailing quote + token->string[2] = *script->script_p++; + //store trailing zero to end the string + token->string[3] = '\0'; + //the sub type is the integer literal value + token->subtype = token->string[1]; + // + return 1; +} //end of the function PS_ReadLiteral +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PS_ReadPunctuation(script_t *script, token_t *token) +{ + int len; + const char *p; + punctuation_t *punc; + +#ifdef PUNCTABLE + for (punc = script->punctuationtable[(unsigned int)*script->script_p]; punc; punc = punc->next) + { +#else + int i; + + for (i = 0; script->punctuations[i].p; i++) + { + punc = &script->punctuations[i]; +#endif //PUNCTABLE + p = punc->p; + len = strlen(p); + //if the script contains at least as much characters as the punctuation + if (script->script_p + len <= script->end_p) + { + //if the script contains the punctuation + if (!Q_strncmp(script->script_p, p, len)) + { + strncpy(token->string, p, MAX_TOKEN); + script->script_p += len; + token->type = TT_PUNCTUATION; + //sub type is the number of the punctuation + token->subtype = punc->n; + return 1; + } //end if + } //end if + } //end for + return 0; +} //end of the function PS_ReadPunctuation +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PS_ReadPrimitive(script_t *script, token_t *token) +{ + int len; + + len = 0; + while(*script->script_p > ' ' && *script->script_p != ';') + { + if (len >= MAX_TOKEN - 1) + { + ScriptError(script, "primitive token longer than MAX_TOKEN = %d", MAX_TOKEN); + return 0; + } //end if + token->string[len++] = *script->script_p++; + } //end while + token->string[len] = 0; + //copy the token into the script structure + Com_Memcpy(&script->token, token, sizeof(token_t)); + //primitive reading successfull + return 1; +} //end of the function PS_ReadPrimitive +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PS_ReadToken(script_t *script, token_t *token) +{ + //if there is a token available (from UnreadToken) + if (script->tokenavailable) + { + script->tokenavailable = 0; + Com_Memcpy(token, &script->token, sizeof(token_t)); + return 1; + } //end if + //save script pointer + script->lastscript_p = script->script_p; + //save line counter + script->lastline = script->line; + //clear the token stuff + Com_Memset(token, 0, sizeof(token_t)); + //start of the white space + script->whitespace_p = script->script_p; + token->whitespace_p = script->script_p; + //read unusefull stuff + if (!PS_ReadWhiteSpace(script)) return 0; + //end of the white space + script->endwhitespace_p = script->script_p; + token->endwhitespace_p = script->script_p; + //line the token is on + token->line = script->line; + //number of lines crossed before token + token->linescrossed = script->line - script->lastline; + //if there is a leading double quote + if (*script->script_p == '\"') + { + if (!PS_ReadString(script, token, '\"')) return 0; + } //end if + //if an literal + else if (*script->script_p == '\'') + { + //if (!PS_ReadLiteral(script, token)) return 0; + if (!PS_ReadString(script, token, '\'')) return 0; + } //end if + //if there is a number + else if ((*script->script_p >= '0' && *script->script_p <= '9') || + (*script->script_p == '.' && + (*(script->script_p + 1) >= '0' && *(script->script_p + 1) <= '9'))) + { + if (!PS_ReadNumber(script, token)) return 0; + } //end if + //if this is a primitive script + else if (script->flags & SCFL_PRIMITIVE) + { + return PS_ReadPrimitive(script, token); + } //end else if + //if there is a name + else if ((*script->script_p >= 'a' && *script->script_p <= 'z') || + (*script->script_p >= 'A' && *script->script_p <= 'Z') || + *script->script_p == '_' || *script->script_p == '@') + { + if (!PS_ReadName(script, token)) return 0; + } //end if + //check for punctuations + else if (!PS_ReadPunctuation(script, token)) + { + ScriptError(script, "can't read token"); + return 0; + } //end if + //copy the token into the script structure + Com_Memcpy(&script->token, token, sizeof(token_t)); + //successfully read a token + return 1; +} //end of the function PS_ReadToken +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PS_ExpectTokenString(script_t *script, char *string) +{ + token_t token; + + if (!PS_ReadToken(script, &token)) + { + ScriptError(script, "couldn't find expected %s", string); + return 0; + } //end if + + if (strcmp(token.string, string)) + { + ScriptError(script, "expected %s, found %s", string, token.string); + return 0; + } //end if + return 1; +} //end of the function PS_ExpectToken +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PS_ExpectTokenType(script_t *script, int type, int subtype, token_t *token) +{ + char str[MAX_TOKEN]; + + if (!PS_ReadToken(script, token)) + { + ScriptError(script, "couldn't read expected token"); + return 0; + } //end if + + if (token->type != type) + { + strcpy(str, ""); + if (type == TT_STRING) strcpy(str, "string"); + if (type == TT_LITERAL) strcpy(str, "literal"); + if (type == TT_NUMBER) strcpy(str, "number"); + if (type == TT_NAME) strcpy(str, "name"); + if (type == TT_PUNCTUATION) strcpy(str, "punctuation"); + ScriptError(script, "expected a %s, found %s", str, token->string); + return 0; + } //end if + if (token->type == TT_NUMBER) + { + if ((token->subtype & subtype) != subtype) + { + strcpy(str, ""); + if (subtype & TT_DECIMAL) strcpy(str, "decimal"); + if (subtype & TT_HEX) strcpy(str, "hex"); + if (subtype & TT_OCTAL) strcpy(str, "octal"); + if (subtype & TT_BINARY) strcpy(str, "binary"); + if (subtype & TT_LONG) strcat(str, " long"); + if (subtype & TT_UNSIGNED) strcat(str, " unsigned"); + if (subtype & TT_FLOAT) strcat(str, " float"); + if (subtype & TT_INTEGER) strcat(str, " integer"); + ScriptError(script, "expected %s, found %s", str, token->string); + return 0; + } //end if + } //end if + else if (token->type == TT_PUNCTUATION) + { + if (subtype < 0) + { + ScriptError(script, "BUG: wrong punctuation subtype"); + return 0; + } //end if + if (token->subtype != subtype) + { + ScriptError(script, "expected %s, found %s", + script->punctuations[subtype].p, token->string); + return 0; + } //end if + } //end else if + return 1; +} //end of the function PS_ExpectTokenType +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PS_ExpectAnyToken(script_t *script, token_t *token) +{ + if (!PS_ReadToken(script, token)) + { + ScriptError(script, "couldn't read expected token"); + return 0; + } //end if + else + { + return 1; + } //end else +} //end of the function PS_ExpectAnyToken +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PS_CheckTokenString(script_t *script, char *string) +{ + token_t tok; + + if (!PS_ReadToken(script, &tok)) return 0; + //if the token is available + if (!strcmp(tok.string, string)) return 1; + //token not available + script->script_p = script->lastscript_p; + return 0; +} //end of the function PS_CheckTokenString +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PS_CheckTokenType(script_t *script, int type, int subtype, token_t *token) +{ + token_t tok; + + if (!PS_ReadToken(script, &tok)) return 0; + //if the type matches + if (tok.type == type && + (tok.subtype & subtype) == subtype) + { + Com_Memcpy(token, &tok, sizeof(token_t)); + return 1; + } //end if + //token is not available + script->script_p = script->lastscript_p; + return 0; +} //end of the function PS_CheckTokenType +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int PS_SkipUntilString(script_t *script, char *string) +{ + token_t token; + + while(PS_ReadToken(script, &token)) + { + if (!strcmp(token.string, string)) return 1; + } //end while + return 0; +} //end of the function PS_SkipUntilString +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PS_UnreadLastToken(script_t *script) +{ + script->tokenavailable = 1; +} //end of the function UnreadLastToken +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PS_UnreadToken(script_t *script, token_t *token) +{ + Com_Memcpy(&script->token, token, sizeof(token_t)); + script->tokenavailable = 1; +} //end of the function UnreadToken +//============================================================================ +// returns the next character of the read white space, returns NULL if none +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +char PS_NextWhiteSpaceChar(script_t *script) +{ + if (script->whitespace_p != script->endwhitespace_p) + { + return *script->whitespace_p++; + } //end if + else + { + return 0; + } //end else +} //end of the function PS_NextWhiteSpaceChar +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void StripDoubleQuotes(char *string) +{ + if (*string == '\"') + { + memmove(string, string+1, strlen(string)); + } //end if + if (string[strlen(string)-1] == '\"') + { + string[strlen(string)-1] = '\0'; + } //end if +} //end of the function StripDoubleQuotes +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void StripSingleQuotes(char *string) +{ + if (*string == '\'') + { + memmove(string, string+1, strlen(string)); + } //end if + if (string[strlen(string)-1] == '\'') + { + string[strlen(string)-1] = '\0'; + } //end if +} //end of the function StripSingleQuotes +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +long double ReadSignedFloat(script_t *script) +{ + token_t token; + long double sign = 1; + + PS_ExpectAnyToken(script, &token); + if (!strcmp(token.string, "-")) + { + if(!PS_ExpectAnyToken(script, &token)) + { + ScriptError(script, "Missing float value"); + return 0; + } + + sign = -1; + } + + if (token.type != TT_NUMBER) + { + ScriptError(script, "expected float value, found %s", token.string); + return 0; + } + + return sign * token.floatvalue; +} //end of the function ReadSignedFloat +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +signed long int ReadSignedInt(script_t *script) +{ + token_t token; + signed long int sign = 1; + + PS_ExpectAnyToken(script, &token); + if (!strcmp(token.string, "-")) + { + if(!PS_ExpectAnyToken(script, &token)) + { + ScriptError(script, "Missing integer value"); + return 0; + } + + sign = -1; + } + + if (token.type != TT_NUMBER || token.subtype == TT_FLOAT) + { + ScriptError(script, "expected integer value, found %s", token.string); + return 0; + } + + return sign * token.intvalue; +} //end of the function ReadSignedInt +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void SetScriptFlags(script_t *script, int flags) +{ + script->flags = flags; +} //end of the function SetScriptFlags +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int GetScriptFlags(script_t *script) +{ + return script->flags; +} //end of the function GetScriptFlags +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void ResetScript(script_t *script) +{ + //pointer in script buffer + script->script_p = script->buffer; + //pointer in script buffer before reading token + script->lastscript_p = script->buffer; + //begin of white space + script->whitespace_p = NULL; + //end of white space + script->endwhitespace_p = NULL; + //set if there's a token available in script->token + script->tokenavailable = 0; + // + script->line = 1; + script->lastline = 1; + //clear the saved token + Com_Memset(&script->token, 0, sizeof(token_t)); +} //end of the function ResetScript +//============================================================================ +// returns true if at the end of the script +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int EndOfScript(script_t *script) +{ + return script->script_p >= script->end_p; +} //end of the function EndOfScript +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int NumLinesCrossed(script_t *script) +{ + return script->line - script->lastline; +} //end of the function NumLinesCrossed +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int ScriptSkipTo(script_t *script, char *value) +{ + int len; + char firstchar; + + firstchar = *value; + len = strlen(value); + do + { + if (!PS_ReadWhiteSpace(script)) return 0; + if (*script->script_p == firstchar) + { + if (!Q_strncmp(script->script_p, value, len)) + { + return 1; + } //end if + } //end if + script->script_p++; + } while(1); +} //end of the function ScriptSkipTo +#ifndef BOTLIB +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +int FileLength(FILE *fp) +{ + int pos; + int end; + + pos = ftell(fp); + fseek(fp, 0, SEEK_END); + end = ftell(fp); + fseek(fp, pos, SEEK_SET); + + return end; +} //end of the function FileLength +#endif +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +script_t *LoadScriptFile(const char *filename) +{ +#ifdef BOTLIB + fileHandle_t fp; + char pathname[MAX_QPATH]; +#else + FILE *fp; +#endif + int length; + void *buffer; + script_t *script; + +#ifdef BOTLIB + if (strlen(basefolder)) + Com_sprintf(pathname, sizeof(pathname), "%s/%s", basefolder, filename); + else + Com_sprintf(pathname, sizeof(pathname), "%s", filename); + length = botimport.FS_FOpenFile( pathname, &fp, FS_READ ); + if (!fp) return NULL; +#else + fp = fopen(filename, "rb"); + if (!fp) return NULL; + + length = FileLength(fp); +#endif + + buffer = GetClearedMemory(sizeof(script_t) + length + 1); + script = (script_t *) buffer; + Com_Memset(script, 0, sizeof(script_t)); + Q_strncpyz(script->filename, filename, sizeof(script->filename)); + script->buffer = (char *) buffer + sizeof(script_t); + script->buffer[length] = 0; + script->length = length; + //pointer in script buffer + script->script_p = script->buffer; + //pointer in script buffer before reading token + script->lastscript_p = script->buffer; + //pointer to end of script buffer + script->end_p = &script->buffer[length]; + //set if there's a token available in script->token + script->tokenavailable = 0; + // + script->line = 1; + script->lastline = 1; + // + SetScriptPunctuations(script, NULL); + // +#ifdef BOTLIB + botimport.FS_Read(script->buffer, length, fp); + botimport.FS_FCloseFile(fp); +#else + if (fread(script->buffer, length, 1, fp) != 1) + { + FreeMemory(buffer); + script = NULL; + } //end if + fclose(fp); +#endif + // + script->length = COM_Compress(script->buffer); + + return script; +} //end of the function LoadScriptFile +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +script_t *LoadScriptMemory(char *ptr, int length, char *name) +{ + void *buffer; + script_t *script; + + buffer = GetClearedMemory(sizeof(script_t) + length + 1); + script = (script_t *) buffer; + Com_Memset(script, 0, sizeof(script_t)); + Q_strncpyz(script->filename, name, sizeof(script->filename)); + script->buffer = (char *) buffer + sizeof(script_t); + script->buffer[length] = 0; + script->length = length; + //pointer in script buffer + script->script_p = script->buffer; + //pointer in script buffer before reading token + script->lastscript_p = script->buffer; + //pointer to end of script buffer + script->end_p = &script->buffer[length]; + //set if there's a token available in script->token + script->tokenavailable = 0; + // + script->line = 1; + script->lastline = 1; + // + SetScriptPunctuations(script, NULL); + // + Com_Memcpy(script->buffer, ptr, length); + // + return script; +} //end of the function LoadScriptMemory +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void FreeScript(script_t *script) +{ +#ifdef PUNCTABLE + if (script->punctuationtable) FreeMemory(script->punctuationtable); +#endif //PUNCTABLE + FreeMemory(script); +} //end of the function FreeScript +//============================================================================ +// +// Parameter: - +// Returns: - +// Changes Globals: - +//============================================================================ +void PS_SetBaseFolder(char *path) +{ +#ifdef BSPC + sprintf(basefolder, path); +#else + Com_sprintf(basefolder, sizeof(basefolder), "%s", path); +#endif +} //end of the function PS_SetBaseFolder diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_script.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_script.h new file mode 100644 index 0000000..574732a --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_script.h @@ -0,0 +1,253 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: l_script.h + * + * desc: lexicographical parser + * + * $Archive: /source/code/botlib/l_script.h $ + * $Author: Mrelusive $ + * $Revision: 2 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 10/05/99 3:42p $ + * + *****************************************************************************/ + +#pragma once + +//undef if binary numbers of the form 0b... or 0B... are not allowed +#define BINARYNUMBERS +//undef if not using the token.intvalue and token.floatvalue +#define NUMBERVALUE +//use dollar sign also as punctuation +#define DOLLAR + +//maximum token length +#define MAX_TOKEN 1024 + +#if defined(BSPC) && !defined(QDECL) +#define QDECL +#endif + + +//script flags +#define SCFL_NOERRORS 0x0001 +#define SCFL_NOWARNINGS 0x0002 +#define SCFL_NOSTRINGWHITESPACES 0x0004 +#define SCFL_NOSTRINGESCAPECHARS 0x0008 +#define SCFL_PRIMITIVE 0x0010 +#define SCFL_NOBINARYNUMBERS 0x0020 +#define SCFL_NONUMBERVALUES 0x0040 + +//token types +#define TT_STRING 1 // string +#define TT_LITERAL 2 // literal +#define TT_NUMBER 3 // number +#define TT_NAME 4 // name +#define TT_PUNCTUATION 5 // punctuation + +//string sub type +//--------------- +// the length of the string +//literal sub type +//---------------- +// the ASCII code of the literal +//number sub type +//--------------- +#define TT_DECIMAL 0x0008 // decimal number +#define TT_HEX 0x0100 // hexadecimal number +#define TT_OCTAL 0x0200 // octal number +#ifdef BINARYNUMBERS +#define TT_BINARY 0x0400 // binary number +#endif //BINARYNUMBERS +#define TT_FLOAT 0x0800 // floating point number +#define TT_INTEGER 0x1000 // integer number +#define TT_LONG 0x2000 // long number +#define TT_UNSIGNED 0x4000 // unsigned number +//punctuation sub type +//-------------------- +#define P_RSHIFT_ASSIGN 1 +#define P_LSHIFT_ASSIGN 2 +#define P_PARMS 3 +#define P_PRECOMPMERGE 4 + +#define P_LOGIC_AND 5 +#define P_LOGIC_OR 6 +#define P_LOGIC_GEQ 7 +#define P_LOGIC_LEQ 8 +#define P_LOGIC_EQ 9 +#define P_LOGIC_UNEQ 10 + +#define P_MUL_ASSIGN 11 +#define P_DIV_ASSIGN 12 +#define P_MOD_ASSIGN 13 +#define P_ADD_ASSIGN 14 +#define P_SUB_ASSIGN 15 +#define P_INC 16 +#define P_DEC 17 + +#define P_BIN_AND_ASSIGN 18 +#define P_BIN_OR_ASSIGN 19 +#define P_BIN_XOR_ASSIGN 20 +#define P_RSHIFT 21 +#define P_LSHIFT 22 + +#define P_POINTERREF 23 +#define P_CPP1 24 +#define P_CPP2 25 +#define P_MUL 26 +#define P_DIV 27 +#define P_MOD 28 +#define P_ADD 29 +#define P_SUB 30 +#define P_ASSIGN 31 + +#define P_BIN_AND 32 +#define P_BIN_OR 33 +#define P_BIN_XOR 34 +#define P_BIN_NOT 35 + +#define P_LOGIC_NOT 36 +#define P_LOGIC_GREATER 37 +#define P_LOGIC_LESS 38 + +#define P_REF 39 +#define P_COMMA 40 +#define P_SEMICOLON 41 +#define P_COLON 42 +#define P_QUESTIONMARK 43 + +#define P_PARENTHESESOPEN 44 +#define P_PARENTHESESCLOSE 45 +#define P_BRACEOPEN 46 +#define P_BRACECLOSE 47 +#define P_SQBRACKETOPEN 48 +#define P_SQBRACKETCLOSE 49 +#define P_BACKSLASH 50 + +#define P_PRECOMP 51 +#define P_DOLLAR 52 +#define P_ATSIGN 53 +//name sub type +//------------- +// the length of the name + +//punctuation +typedef struct punctuation_s +{ + const char *p; //punctuation character(s) + int n; //punctuation indication + struct punctuation_s *next; //next punctuation +} punctuation_t; + +//token +typedef struct token_s +{ + char string[MAX_TOKEN]; //available token + int type; //last read token type + int subtype; //last read token sub type +#ifdef NUMBERVALUE + unsigned long int intvalue; //integer value + long double floatvalue; //floating point value +#endif //NUMBERVALUE + char *whitespace_p; //start of white space before token + char *endwhitespace_p; //start of white space before token + int line; //line the token was on + int linescrossed; //lines crossed in white space + struct token_s *next; //next token in chain +} token_t; + +//script file +typedef struct script_s +{ + char filename[1024]; //file name of the script + char *buffer; //buffer containing the script + char *script_p; //current pointer in the script + char *end_p; //pointer to the end of the script + char *lastscript_p; //script pointer before reading token + char *whitespace_p; //begin of the white space + char *endwhitespace_p; //end of the white space + int length; //length of the script in bytes + int line; //current line in script + int lastline; //line before reading token + int tokenavailable; //set by UnreadLastToken + int flags; //several script flags + punctuation_t *punctuations; //the punctuations used in the script + punctuation_t **punctuationtable; + token_t token; //available token + struct script_s *next; //next script in a chain +} script_t; + +//read a token from the script +int PS_ReadToken(script_t *script, token_t *token); +//expect a certain token +int PS_ExpectTokenString(script_t *script, char *string); +//expect a certain token type +int PS_ExpectTokenType(script_t *script, int type, int subtype, token_t *token); +//expect a token +int PS_ExpectAnyToken(script_t *script, token_t *token); +//returns true when the token is available +int PS_CheckTokenString(script_t *script, char *string); +//returns true and reads the token when a token with the given type is available +int PS_CheckTokenType(script_t *script, int type, int subtype, token_t *token); +//skip tokens until the given token string is read +int PS_SkipUntilString(script_t *script, char *string); +//unread the last token read from the script +void PS_UnreadLastToken(script_t *script); +//unread the given token +void PS_UnreadToken(script_t *script, token_t *token); +//returns the next character of the read white space, returns NULL if none +char PS_NextWhiteSpaceChar(script_t *script); +//remove any leading and trailing double quotes from the token +void StripDoubleQuotes(char *string); +//remove any leading and trailing single quotes from the token +void StripSingleQuotes(char *string); +//read a possible signed integer +signed long int ReadSignedInt(script_t *script); +//read a possible signed floating point number +long double ReadSignedFloat(script_t *script); +//set an array with punctuations, NULL restores default C/C++ set +void SetScriptPunctuations(script_t *script, punctuation_t *p); +//set script flags +void SetScriptFlags(script_t *script, int flags); +//get script flags +int GetScriptFlags(script_t *script); +//reset a script +void ResetScript(script_t *script); +//returns true if at the end of the script +int EndOfScript(script_t *script); +//returns a pointer to the punctuation with the given number +const char *PunctuationFromNum(script_t *script, int num); +//load a script from the given file at the given offset with the given length +script_t *LoadScriptFile(const char *filename); +//load a script from the given memory with the given length +script_t *LoadScriptMemory(char *ptr, int length, char *name); +//free a script +void FreeScript(script_t *script); +//set the base folder to load files from +void PS_SetBaseFolder(char *path); +//print a script error with filename and line number +void QDECL ScriptError(script_t *script, char *str, ...) __attribute__ ((format (printf, 2, 3))); +//print a script warning with filename and line number +void QDECL ScriptWarning(script_t *script, char *str, ...) __attribute__ ((format (printf, 2, 3))); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_struct.cpp b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_struct.cpp new file mode 100644 index 0000000..bd8e0bf --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_struct.cpp @@ -0,0 +1,467 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: l_struct.c + * + * desc: structure reading / writing + * + * $Archive: /MissionPack/CODE/botlib/l_struct.c $ + * $Author: Raduffy $ + * $Revision: 1 $ + * $Modtime: 12/20/99 8:43p $ + * $Date: 3/08/00 11:28a $ + * + *****************************************************************************/ + +#ifdef BOTLIB +#include "qcommon/q_shared.h" +#include "botlib.h" //for the include of be_interface.h +#include "l_script.h" +#include "l_precomp.h" +#include "l_struct.h" +#include "l_utils.h" +#include "be_interface.h" +#endif //BOTLIB + +#ifdef BSPC +//include files for usage in the BSP Converter +#include "../bspc/qbsp.h" +#include "../bspc/l_log.h" +#include "../bspc/l_mem.h" +#include "l_precomp.h" +#include "l_struct.h" + +#define qtrue true +#define qfalse false +#endif //BSPC + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +fielddef_t *FindField(fielddef_t *defs, char *name) +{ + int i; + + for (i = 0; defs[i].name; i++) + { + if (!strcmp(defs[i].name, name)) return &defs[i]; + } //end for + return NULL; +} //end of the function FindField +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +qboolean ReadNumber(source_t *source, fielddef_t *fd, void *p) +{ + token_t token; + int negative = qfalse; + long int intval, intmin = 0, intmax = 0; + double floatval; + + if (!PC_ExpectAnyToken(source, &token)) return (qboolean)0; + + //check for minus sign + if (token.type == TT_PUNCTUATION) + { + if (fd->type & FT_UNSIGNED) + { + SourceError(source, "expected unsigned value, found %s", token.string); + return (qboolean)0; + } //end if + //if not a minus sign + if (strcmp(token.string, "-")) + { + SourceError(source, "unexpected punctuation %s", token.string); + return (qboolean)0; + } //end if + negative = qtrue; + //read the number + if (!PC_ExpectAnyToken(source, &token)) return (qboolean)0; + } //end if + //check if it is a number + if (token.type != TT_NUMBER) + { + SourceError(source, "expected number, found %s", token.string); + return (qboolean)0; + } //end if + //check for a float value + if (token.subtype & TT_FLOAT) + { + if ((fd->type & FT_TYPE) != FT_FLOAT) + { + SourceError(source, "unexpected float"); + return (qboolean)0; + } //end if + floatval = token.floatvalue; + if (negative) floatval = -floatval; + if (fd->type & FT_BOUNDED) + { + if (floatval < fd->floatmin || floatval > fd->floatmax) + { + SourceError(source, "float out of range [%f, %f]", fd->floatmin, fd->floatmax); + return (qboolean)0; + } //end if + } //end if + *(float *) p = (float) floatval; + return (qboolean)1; + } //end if + // + intval = token.intvalue; + if (negative) intval = -intval; + //check bounds + if ((fd->type & FT_TYPE) == FT_CHAR) + { + if (fd->type & FT_UNSIGNED) {intmin = 0; intmax = 255;} + else {intmin = -128; intmax = 127;} + } //end if + if ((fd->type & FT_TYPE) == FT_INT) + { + if (fd->type & FT_UNSIGNED) {intmin = 0; intmax = 65535;} + else {intmin = -32768; intmax = 32767;} + } //end else if + if ((fd->type & FT_TYPE) == FT_CHAR || (fd->type & FT_TYPE) == FT_INT) + { + if (fd->type & FT_BOUNDED) + { + intmin = Maximum(intmin, fd->floatmin); + intmax = Minimum(intmax, fd->floatmax); + } //end if + if (intval < intmin || intval > intmax) + { + SourceError(source, "value %ld out of range [%ld, %ld]", intval, intmin, intmax); + return (qboolean)0; + } //end if + } //end if + else if ((fd->type & FT_TYPE) == FT_FLOAT) + { + if (fd->type & FT_BOUNDED) + { + if (intval < fd->floatmin || intval > fd->floatmax) + { + SourceError(source, "value %ld out of range [%f, %f]", intval, fd->floatmin, fd->floatmax); + return (qboolean)0; + } //end if + } //end if + } //end else if + //store the value + if ((fd->type & FT_TYPE) == FT_CHAR) + { + if (fd->type & FT_UNSIGNED) *(unsigned char *) p = (unsigned char) intval; + else *(char *) p = (char) intval; + } //end if + else if ((fd->type & FT_TYPE) == FT_INT) + { + if (fd->type & FT_UNSIGNED) *(unsigned int *) p = (unsigned int) intval; + else *(int *) p = (int) intval; + } //end else + else if ((fd->type & FT_TYPE) == FT_FLOAT) + { + *(float *) p = (float) intval; + } //end else + return (qboolean)1; +} //end of the function ReadNumber +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +qboolean ReadChar(source_t *source, fielddef_t *fd, void *p) +{ + token_t token; + + if (!PC_ExpectAnyToken(source, &token)) return (qboolean)0; + + //take literals into account + if (token.type == TT_LITERAL) + { + StripSingleQuotes(token.string); + *(char *) p = token.string[0]; + } //end if + else + { + PC_UnreadLastToken(source); + if (!ReadNumber(source, fd, p)) return (qboolean)0; + } //end if + return (qboolean)1; +} //end of the function ReadChar +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int ReadString(source_t *source, fielddef_t *fd, void *p) +{ + token_t token; + + if (!PC_ExpectTokenType(source, TT_STRING, 0, &token)) return 0; + //remove the double quotes + StripDoubleQuotes(token.string); + //copy the string + strncpy((char *) p, token.string, MAX_STRINGFIELD); + //make sure the string is closed with a zero + ((char *)p)[MAX_STRINGFIELD-1] = '\0'; + // + return 1; +} //end of the function ReadString +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int ReadStructure(source_t *source, structdef_t *def, char *structure) +{ + token_t token; + fielddef_t *fd; + void *p; + int num; + + if (!PC_ExpectTokenString(source, "{")) return 0; + while(1) + { + if (!PC_ExpectAnyToken(source, &token)) return qfalse; + //if end of structure + if (!strcmp(token.string, "}")) break; + //find the field with the name + fd = FindField(def->fields, token.string); + if (!fd) + { + SourceError(source, "unknown structure field %s", token.string); + return qfalse; + } //end if + if (fd->type & FT_ARRAY) + { + num = fd->maxarray; + if (!PC_ExpectTokenString(source, "{")) return qfalse; + } //end if + else + { + num = 1; + } //end else + p = (void *)(structure + fd->offset); + while (num-- > 0) + { + if (fd->type & FT_ARRAY) + { + if (PC_CheckTokenString(source, "}")) break; + } //end if + switch(fd->type & FT_TYPE) + { + case FT_CHAR: + { + if (!ReadChar(source, fd, p)) return qfalse; + p = (char *) p + sizeof(char); + break; + } //end case + case FT_INT: + { + if (!ReadNumber(source, fd, p)) return qfalse; + p = (char *) p + sizeof(int); + break; + } //end case + case FT_FLOAT: + { + if (!ReadNumber(source, fd, p)) return qfalse; + p = (char *) p + sizeof(float); + break; + } //end case + case FT_STRING: + { + if (!ReadString(source, fd, p)) return qfalse; + p = (char *) p + MAX_STRINGFIELD; + break; + } //end case + case FT_STRUCT: + { + if (!fd->substruct) + { + SourceError(source, "BUG: no sub structure defined"); + return qfalse; + } //end if + ReadStructure(source, fd->substruct, (char *) p); + p = (char *) p + fd->substruct->size; + break; + } //end case + } //end switch + if (fd->type & FT_ARRAY) + { + if (!PC_ExpectAnyToken(source, &token)) return qfalse; + if (!strcmp(token.string, "}")) break; + if (strcmp(token.string, ",")) + { + SourceError(source, "expected a comma, found %s", token.string); + return qfalse; + } //end if + } //end if + } //end while + } //end while + return qtrue; +} //end of the function ReadStructure +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WriteIndent(FILE *fp, int indent) +{ + while(indent-- > 0) + { + if (fprintf(fp, "\t") < 0) return qfalse; + } //end while + return qtrue; +} //end of the function WriteIndent +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WriteFloat(FILE *fp, float value) +{ + char buf[128]; + int l; + + Com_sprintf(buf, sizeof(buf), "%f", value); + l = strlen(buf); + //strip any trailing zeros + while(l-- > 1) + { + if (buf[l] != '0' && buf[l] != '.') break; + if (buf[l] == '.') + { + buf[l] = 0; + break; + } //end if + buf[l] = 0; + } //end while + //write the float to file + if (fprintf(fp, "%s", buf) < 0) return 0; + return 1; +} //end of the function WriteFloat +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WriteStructWithIndent(FILE *fp, structdef_t *def, char *structure, int indent) +{ + int i, num; + void *p; + fielddef_t *fd; + + if (!WriteIndent(fp, indent)) return qfalse; + if (fprintf(fp, "{\r\n") < 0) return qfalse; + + indent++; + for (i = 0; def->fields[i].name; i++) + { + fd = &def->fields[i]; + if (!WriteIndent(fp, indent)) return qfalse; + if (fprintf(fp, "%s\t", fd->name) < 0) return qfalse; + p = (void *)(structure + fd->offset); + if (fd->type & FT_ARRAY) + { + num = fd->maxarray; + if (fprintf(fp, "{") < 0) return qfalse; + } //end if + else + { + num = 1; + } //end else + while(num-- > 0) + { + switch(fd->type & FT_TYPE) + { + case FT_CHAR: + { + if (fprintf(fp, "%d", *(char *) p) < 0) return qfalse; + p = (char *) p + sizeof(char); + break; + } //end case + case FT_INT: + { + if (fprintf(fp, "%d", *(int *) p) < 0) return qfalse; + p = (char *) p + sizeof(int); + break; + } //end case + case FT_FLOAT: + { + if (!WriteFloat(fp, *(float *)p)) return qfalse; + p = (char *) p + sizeof(float); + break; + } //end case + case FT_STRING: + { + if (fprintf(fp, "\"%s\"", (char *) p) < 0) return qfalse; + p = (char *) p + MAX_STRINGFIELD; + break; + } //end case + case FT_STRUCT: + { + if (!WriteStructWithIndent(fp, fd->substruct, structure, indent)) return qfalse; + p = (char *) p + fd->substruct->size; + break; + } //end case + } //end switch + if (fd->type & FT_ARRAY) + { + if (num > 0) + { + if (fprintf(fp, ",") < 0) return qfalse; + } //end if + else + { + if (fprintf(fp, "}") < 0) return qfalse; + } //end else + } //end if + } //end while + if (fprintf(fp, "\r\n") < 0) return qfalse; + } //end for + indent--; + + if (!WriteIndent(fp, indent)) return qfalse; + if (fprintf(fp, "}\r\n") < 0) return qfalse; + return qtrue; +} //end of the function WriteStructWithIndent +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WriteStructure(FILE *fp, structdef_t *def, char *structure) +{ + return WriteStructWithIndent(fp, def, structure, 0); +} //end of the function WriteStructure + diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_struct.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_struct.h new file mode 100644 index 0000000..62b6d2e --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_struct.h @@ -0,0 +1,79 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: l_struct.h + * + * desc: structure reading/writing + * + * $Archive: /source/code/botlib/l_struct.h $ + * $Author: Mrelusive $ + * $Revision: 2 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 10/05/99 3:42p $ + * + *****************************************************************************/ + +#pragma once + +#define MAX_STRINGFIELD 80 +//field types +#define FT_CHAR 1 // char +#define FT_INT 2 // int +#define FT_FLOAT 3 // float +#define FT_STRING 4 // char [MAX_STRINGFIELD] +#define FT_STRUCT 6 // struct (sub structure) +//type only mask +#define FT_TYPE 0x00FF // only type, clear subtype +//sub types +#define FT_ARRAY 0x0100 // array of type +#define FT_BOUNDED 0x0200 // bounded value +#define FT_UNSIGNED 0x0400 + +//structure field definition +typedef struct fielddef_s +{ + char *name; //name of the field + int offset; //offset in the structure + int type; //type of the field + //type specific fields + int maxarray; //maximum array size + float floatmin, floatmax; //float min and max + struct structdef_s *substruct; //sub structure +} fielddef_t; + +//structure definition +typedef struct structdef_s +{ + int size; + fielddef_t *fields; +} structdef_t; + +//read a structure from a script +int ReadStructure(source_t *source, structdef_t *def, char *structure); +//write a structure to a file +int WriteStructure(FILE *fp, structdef_t *def, char *structure); +//writes indents +int WriteIndent(FILE *fp, int indent); +//writes a float without traling zeros +int WriteFloat(FILE *fp, float value); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_utils.h b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_utils.h new file mode 100644 index 0000000..955323c --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/botlib/l_utils.h @@ -0,0 +1,45 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/***************************************************************************** + * name: l_util.h + * + * desc: utils + * + * $Archive: /source/code/botlib/l_util.h $ + * $Author: Mrelusive $ + * $Revision: 2 $ + * $Modtime: 10/05/99 3:32p $ + * $Date: 10/05/99 3:42p $ + * + *****************************************************************************/ + +#pragma once + +#define Vector2Angles(v,a) vectoangles(v,a) +#ifdef MAX_PATH + #undef MAX_PATH +#endif +#define MAX_PATH MAX_QPATH +#define Maximum(x,y) (x > y ? x : y) +#define Minimum(x,y) (x < y ? x : y) diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/CMakeLists.txt b/Projects/Android/jni/OpenJK/codemp_delete/cgame/CMakeLists.txt similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/CMakeLists.txt rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/CMakeLists.txt diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/animtable.h b/Projects/Android/jni/OpenJK/codemp_delete/cgame/animtable.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/animtable.h rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/animtable.h diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_consolecmds.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_consolecmds.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_consolecmds.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_consolecmds.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_cvar.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_cvar.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_cvar.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_cvar.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_draw.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_draw.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_draw.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_draw.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_drawtools.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_drawtools.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_drawtools.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_drawtools.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_effects.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_effects.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_effects.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_effects.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_ents.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_ents.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_ents.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_ents.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_event.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_event.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_event.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_event.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_info.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_info.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_info.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_info.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_light.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_light.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_light.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_light.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_local.h b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_local.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_local.h rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_local.h diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_localents.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_localents.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_localents.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_localents.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_main.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_main.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_main.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_main.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_marks.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_marks.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_marks.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_marks.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_newDraw.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_newDraw.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_newDraw.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_newDraw.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_players.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_players.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_players.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_players.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_playerstate.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_playerstate.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_playerstate.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_playerstate.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_predict.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_predict.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_predict.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_predict.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_public.h b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_public.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_public.h rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_public.h diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_saga.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_saga.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_saga.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_saga.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_scoreboard.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_scoreboard.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_scoreboard.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_scoreboard.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_servercmds.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_servercmds.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_servercmds.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_servercmds.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_snapshot.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_snapshot.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_snapshot.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_snapshot.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_spawn.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_spawn.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_spawn.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_spawn.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_syscalls.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_syscalls.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_syscalls.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_syscalls.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_turret.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_turret.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_turret.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_turret.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_view.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_view.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_view.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_view.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_weaponinit.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_weaponinit.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_weaponinit.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_weaponinit.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_weapons.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_weapons.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_weapons.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_weapons.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/cg_xcvar.h b/Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_xcvar.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/cg_xcvar.h rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/cg_xcvar.h diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/fx_blaster.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/fx_blaster.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/fx_blaster.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/fx_blaster.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/fx_bowcaster.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/fx_bowcaster.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/fx_bowcaster.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/fx_bowcaster.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/fx_bryarpistol.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/fx_bryarpistol.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/fx_bryarpistol.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/fx_bryarpistol.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/fx_demp2.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/fx_demp2.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/fx_demp2.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/fx_demp2.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/fx_disruptor.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/fx_disruptor.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/fx_disruptor.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/fx_disruptor.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/fx_flechette.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/fx_flechette.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/fx_flechette.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/fx_flechette.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/fx_force.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/fx_force.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/fx_force.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/fx_force.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/fx_heavyrepeater.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/fx_heavyrepeater.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/fx_heavyrepeater.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/fx_heavyrepeater.c diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/fx_local.h b/Projects/Android/jni/OpenJK/codemp_delete/cgame/fx_local.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/fx_local.h rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/fx_local.h diff --git a/Projects/Android/jni/OpenJK/codemp/cgame/fx_rocketlauncher.c b/Projects/Android/jni/OpenJK/codemp_delete/cgame/fx_rocketlauncher.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/cgame/fx_rocketlauncher.c rename to Projects/Android/jni/OpenJK/codemp_delete/cgame/fx_rocketlauncher.c diff --git a/Projects/Android/jni/OpenJK/codemp_delete/client/FXExport.cpp b/Projects/Android/jni/OpenJK/codemp_delete/client/FXExport.cpp new file mode 100644 index 0000000..ecd0c6f --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/client/FXExport.cpp @@ -0,0 +1,124 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#include "client.h" +#include "FxScheduler.h" + +//#define __FXCHECKER + +#ifdef __FXCHECKER + #include +#endif // __FXCHECKER + +int FX_RegisterEffect(const char *file) +{ + return theFxScheduler.RegisterEffect(file, true); +} + +void FX_PlayEffect( const char *file, vec3_t org, vec3_t fwd, int vol, int rad ) +{ +#ifdef __FXCHECKER + if (_isnan(org[0]) || _isnan(org[1]) || _isnan(org[2])) + { + assert(0); + } + if (_isnan(fwd[0]) || _isnan(fwd[1]) || _isnan(fwd[2])) + { + assert(0); + } + if (fabs(fwd[0]) < 0.1 && fabs(fwd[1]) < 0.1 && fabs(fwd[2]) < 0.1) + { + assert(0); + } +#endif // __FXCHECKER + + theFxScheduler.PlayEffect(file, org, fwd, vol, rad); +} + +void FX_PlayEffectID( int id, vec3_t org, vec3_t fwd, int vol, int rad, qboolean isPortal ) +{ +#ifdef __FXCHECKER + if (_isnan(org[0]) || _isnan(org[1]) || _isnan(org[2])) + { + assert(0); + } + if (_isnan(fwd[0]) || _isnan(fwd[1]) || _isnan(fwd[2])) + { + assert(0); + } + if (fabs(fwd[0]) < 0.1 && fabs(fwd[1]) < 0.1 && fabs(fwd[2]) < 0.1) + { + assert(0); + } +#endif // __FXCHECKER + + theFxScheduler.PlayEffect(id, org, fwd, vol, rad, !!isPortal ); +} + +void FX_PlayBoltedEffectID( int id, vec3_t org, + const int boltInfo, CGhoul2Info_v *ghoul2, int iLooptime, qboolean isRelative ) +{ + theFxScheduler.PlayEffect(id, org, 0, boltInfo, ghoul2, -1, -1, -1, qfalse, iLooptime, !!isRelative ); +} + +void FX_PlayEntityEffectID( int id, vec3_t org, + matrix3_t axis, const int boltInfo, const int entNum, int vol, int rad ) +{ +#ifdef __FXCHECKER + if (_isnan(org[0]) || _isnan(org[1]) || _isnan(org[2])) + { + assert(0); + } +#endif // __FXCHECKER + + theFxScheduler.PlayEffect(id, org, axis, boltInfo, 0, -1, vol, rad ); +} + +void FX_AddScheduledEffects( qboolean portal ) +{ + theFxScheduler.AddScheduledEffects(!!portal); +} + +void FX_Draw2DEffects( float screenXScale, float screenYScale ) +{ + theFxScheduler.Draw2DEffects( screenXScale, screenYScale ); +} + +int FX_InitSystem( refdef_t* refdef ) +{ + return FX_Init( refdef ); +} + +void FX_SetRefDefFromCGame( refdef_t* refdef ) +{ + FX_SetRefDef( refdef ); +} + +qboolean FX_FreeSystem( void ) +{ + return (qboolean)FX_Free( true ); +} + +void FX_AdjustTime( int time ) +{ + theFxHelper.AdjustTime(time); +} diff --git a/Projects/Android/jni/OpenJK/codemp_delete/client/FXExport.h b/Projects/Android/jni/OpenJK/codemp_delete/client/FXExport.h new file mode 100644 index 0000000..b2a53a6 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/client/FXExport.h @@ -0,0 +1,39 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#pragma once + +int FX_RegisterEffect(const char *file); + +void FX_PlayEffect( const char *file, vec3_t org, vec3_t fwd, int vol, int rad ); // builds arbitrary perp. right vector, does a cross product to define up + +void FX_PlayEffectID( int id, vec3_t org, vec3_t fwd, int vol, int rad, qboolean isPortal = qfalse ); // builds arbitrary perp. right vector, does a cross product to define up +void FX_PlayEntityEffectID( int id, vec3_t org, matrix3_t axis, const int boltInfo, const int entNum, int vol, int rad ); +void FX_PlayBoltedEffectID( int id, vec3_t org, const int boltInfo, CGhoul2Info_v *ghoul2, int iLooptime, qboolean isRelative ); + +void FX_AddScheduledEffects( qboolean portal ); +void FX_Draw2DEffects ( float screenXScale, float screenYScale ); + +int FX_InitSystem( refdef_t* refdef ); // called in CG_Init to purge the fx system. +void FX_SetRefDefFromCGame( refdef_t* refdef ); +qboolean FX_FreeSystem( void ); // ditches all active effects; +void FX_AdjustTime( int time ); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/client/FxPrimitives.cpp b/Projects/Android/jni/OpenJK/codemp_delete/client/FxPrimitives.cpp new file mode 100644 index 0000000..1497924 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/client/FxPrimitives.cpp @@ -0,0 +1,2311 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#include "client.h" +#include "cl_cgameapi.h" +#include "FxScheduler.h" + +extern int drawnFx; + +//-------------------------- +// +// Base Effect Class +// +//-------------------------- +CEffect::CEffect(void) : + mFlags(0), + mMatImpactFX(MATIMPACTFX_NONE), + mMatImpactParm(-1), + mSoundRadius(-1), + mSoundVolume(-1) +{ + memset( &mRefEnt, 0, sizeof( mRefEnt )); +} + +//-------------------------- +// +// Derived Particle Class +// +//-------------------------- + +//---------------------------- +void CParticle::Init(void) +{ + mRefEnt.radius = 0.0f; + if (mFlags & FX_PLAYER_VIEW) + { + mOrigin1[0] = irand(0, 639); + mOrigin1[1] = irand(0, 479); + } +} + +//---------------------------- +void CParticle::Die(void) +{ + if ( mFlags & FX_DEATH_RUNS_FX && !(mFlags & FX_KILL_ON_IMPACT) ) + { + vec3_t norm; + + // Man, this just seems so, like, uncool and stuff... + VectorSet( norm, flrand(-1.0f, 1.0f), flrand(-1.0f, 1.0f), flrand(-1.0f, 1.0f)); + VectorNormalize( norm ); + + theFxScheduler.PlayEffect( mDeathFxID, mOrigin1, norm ); + } +} + +//---------------------------- +bool CParticle::Cull(void) +{ + vec3_t dir; + + if (mFlags & FX_PLAYER_VIEW) + { + // this will be drawn as a 2D effect so don't cull it + return false; + } + + // Get the direction to the view + VectorSubtract( mOrigin1, theFxHelper.refdef->vieworg, dir ); + + // Check if it's behind the viewer + if ( (DotProduct( theFxHelper.refdef->viewaxis[0], dir )) < 0) // cg.cosHalfFOV * (len - mRadius) ) + { + return true; + } + + // don't cull if this is hacked to show up close to the inview wpn + if (mFlags & FX_DEPTH_HACK) + { + return false; + } + // Can't be too close + float len = VectorLengthSquared( dir ); + if ( len < fx_nearCull->value ) + { + return true; + } + + return false; +} + +//---------------------------- +void CParticle::Draw(void) +{ + if ( mFlags & FX_DEPTH_HACK ) + { + // Not sure if first person needs to be set, but it can't hurt? + mRefEnt.renderfx |= RF_DEPTHHACK; + } + + if (mFlags & FX_PLAYER_VIEW) + { + vec4_t color; + + color[0] = mRefEnt.shaderRGBA[0] / 255.0; + color[1] = mRefEnt.shaderRGBA[1] / 255.0; + color[2] = mRefEnt.shaderRGBA[2] / 255.0; + color[3] = mRefEnt.shaderRGBA[3] / 255.0; + + // add this 2D effect to the proper list. it will get drawn after the trap->RenderScene call + theFxScheduler.Add2DEffect(mOrigin1[0], mOrigin1[1], mRefEnt.radius, mRefEnt.radius, color, mRefEnt.customShader); + } + else + { + // Add our refEntity to the scene + VectorCopy( mOrigin1, mRefEnt.origin ); + + theFxHelper.AddFxToScene(&mRefEnt); + } + drawnFx++; +} + +//---------------------------- +// Update +//---------------------------- +bool CParticle::Update(void) +{ + // Game pausing can cause dumb time things to happen, so kill the effect in this instance + if ( mTimeStart > theFxHelper.mTime ) + { + return false; + } + + if ( mFlags & FX_RELATIVE ) + { + if ( !re->G2API_IsGhoul2InfovValid (*mGhoul2)) + { // the thing we are bolted to is no longer valid, so we may as well just die. + return false; + } + + vec3_t org; + matrix3_t ax; + + // Get our current position and direction + if (!theFxHelper.GetOriginAxisFromBolt(mGhoul2, mEntNum, mModelNum, mBoltNum, org, ax)) + { //could not get bolt + return false; + } + vec3_t realVel, realAccel; + + VectorMA( org, mOrgOffset[0], ax[0], org ); + VectorMA( org, mOrgOffset[1], ax[1], org ); + VectorMA( org, mOrgOffset[2], ax[2], org ); + + const float time = (theFxHelper.mTime - mTimeStart) * 0.001f; + // calc the real velocity and accel vectors + VectorScale( ax[0], mVel[0], realVel ); + VectorMA( realVel, mVel[1], ax[1], realVel ); + VectorMA( realVel, mVel[2], ax[2], realVel ); + //realVel[2] += 0.5f * mGravity * time; + + VectorScale( ax[0], mAccel[0], realAccel ); + VectorMA( realAccel, mAccel[1], ax[1], realAccel ); + VectorMA( realAccel, mAccel[2], ax[2], realAccel ); + + // Get our real velocity at the current time, taking into account the effects of acceleartion. NOTE: not sure if this is even 100% correct math-wise + VectorMA( realVel, time, realAccel, realVel ); + + // Now move us to where we should be at the given time + VectorMA( org, time, realVel, mOrigin1 ); + + } + else if (( mTimeStart < theFxHelper.mTime ) && UpdateOrigin() == false ) + { + // we are marked for death + return false; + } + + + if ( !Cull() ) + { + // Only update these if the thing is visible. + UpdateSize(); + UpdateRGB(); + UpdateAlpha(); + UpdateRotation(); + + Draw(); + } + + return true; +} + +//---------------------------- +// Update Origin +//---------------------------- +bool CParticle::UpdateOrigin(void) +{ + vec3_t new_origin; + + VectorMA( mVel, theFxHelper.mRealTime, mAccel, mVel ); + + // Predict the new position + new_origin[0] = mOrigin1[0] + (theFxHelper.mRealTime * mVel[0]);// + (theFxHelper.mHalfRealTimeSq * mVel[0]); + new_origin[1] = mOrigin1[1] + (theFxHelper.mRealTime * mVel[1]);// + (theFxHelper.mHalfRealTimeSq * mVel[1]); + new_origin[2] = mOrigin1[2] + (theFxHelper.mRealTime * mVel[2]);// + (theFxHelper.mHalfRealTimeSq * mVel[2]); + + // Only perform physics if this object is tagged to do so + if ( (mFlags & FX_APPLY_PHYSICS) && !(mFlags & FX_PLAYER_VIEW) ) + { + if ( mFlags & FX_EXPENSIVE_PHYSICS ) + { + trace_t trace; + float dot; + + if ( mFlags & FX_USE_BBOX ) + { + if (mFlags & FX_GHOUL2_TRACE) + { + theFxHelper.G2Trace( trace, mOrigin1, mMin, mMax, new_origin, -1, MASK_SOLID ); + } + else + { + theFxHelper.Trace( trace, mOrigin1, mMin, mMax, new_origin, -1, MASK_SOLID ); + } + } + else + { + if (mFlags & FX_GHOUL2_TRACE) + { + theFxHelper.G2Trace( trace, mOrigin1, NULL, NULL, new_origin, -1, MASK_PLAYERSOLID ); + } + else + { + theFxHelper.Trace( trace, mOrigin1, NULL, NULL, new_origin, -1, MASK_SOLID ); + } + } + + // Hit something + if (trace.startsolid || trace.allsolid) + { + VectorClear( mVel ); + VectorClear( mAccel ); + + if ((mFlags & FX_GHOUL2_TRACE) && (mFlags & FX_IMPACT_RUNS_FX)) + { + static vec3_t bsNormal = {0, 1, 0}; + + theFxScheduler.PlayEffect( mImpactFxID, trace.endpos, bsNormal ); + } + + mFlags &= ~(FX_APPLY_PHYSICS | FX_IMPACT_RUNS_FX); + + return true; + } + else if ( trace.fraction < 1.0f )//&& !trace.startsolid && !trace.allsolid ) + { + if ( mFlags & FX_IMPACT_RUNS_FX && !(trace.surfaceFlags & SURF_NOIMPACT )) + { + theFxScheduler.PlayEffect( mImpactFxID, trace.endpos, trace.plane.normal ); + } + + // may need to interact with the material type we hit + theFxScheduler.MaterialImpact(&trace, (CEffect*)this); + + if ( mFlags & FX_KILL_ON_IMPACT ) + { + // time to die + return false; + } + + VectorMA( mVel, theFxHelper.mRealTime * trace.fraction, mAccel, mVel ); + + dot = DotProduct( mVel, trace.plane.normal ); + + VectorMA( mVel, -2.0f * dot, trace.plane.normal, mVel ); + + VectorScale( mVel, mElasticity, mVel ); + mElasticity *= 0.5f; + + // If the velocity is too low, make it stop moving, rotating, and turn off physics to avoid + // doing expensive operations when they aren't needed + //if ( trace.plane.normal[2] > 0.33f && mVel[2] < 10.0f ) + if (VectorLengthSquared(mVel) < 100.0f) + { + VectorClear( mVel ); + VectorClear( mAccel ); + + mFlags &= ~(FX_APPLY_PHYSICS | FX_IMPACT_RUNS_FX); + } + + // Set the origin to the exact impact point + VectorMA( trace.endpos, 1.0f, trace.plane.normal, mOrigin1 ); + return true; + } + } + } + + // No physics were done to this object, move it + VectorCopy( new_origin, mOrigin1 ); + + if (mFlags & FX_PLAYER_VIEW) + { + if (mOrigin1[0] < 0 || mOrigin1[0] > 639 || mOrigin1[1] < 0 || mOrigin1[1] > 479) + { + return false; + } + } + + return true; +} + +//---------------------------- +// Update Size +//---------------------------- +void CParticle::UpdateSize(void) +{ + // completely biased towards start if it doesn't get overridden + float perc1 = 1.0f, perc2 = 1.0f; + + if ( (mFlags & FX_SIZE_LINEAR) ) + { + // calculate element biasing + perc1 = 1.0f - (float)(theFxHelper.mTime - mTimeStart) / (float)(mTimeEnd - mTimeStart); + } + + // We can combine FX_LINEAR with _either_ FX_NONLINEAR, FX_WAVE, or FX_CLAMP + if (( mFlags & FX_SIZE_PARM_MASK ) == FX_SIZE_NONLINEAR ) + { + if ( theFxHelper.mTime > mSizeParm ) + { + // get percent done, using parm as the start of the non-linear fade + perc2 = 1.0f - (float)(theFxHelper.mTime - mSizeParm) / (float)(mTimeEnd - mSizeParm); + } + + if ( mFlags & FX_SIZE_LINEAR ) + { + // do an even blend + perc1 = perc1 * 0.5f + perc2 * 0.5f; + } + else + { + // just copy it over...sigh + perc1 = perc2; + } + } + else if (( mFlags & FX_SIZE_PARM_MASK ) == FX_SIZE_WAVE ) + { + // wave gen, with parm being the frequency multiplier + perc1 = perc1 * cosf( (theFxHelper.mTime - mTimeStart) * mSizeParm ); + } + else if (( mFlags & FX_SIZE_PARM_MASK ) == FX_SIZE_CLAMP ) + { + if ( theFxHelper.mTime < mSizeParm ) + { + // get percent done, using parm as the start of the non-linear fade + perc2 = (float)(mSizeParm - theFxHelper.mTime) / (float)(mSizeParm - mTimeStart); + } + else + { + perc2 = 0.0f; // make it full size?? + } + + if ( (mFlags & FX_SIZE_LINEAR) ) + { + // do an even blend + perc1 = perc1 * 0.5f + perc2 * 0.5f; + } + else + { + // just copy it over...sigh + perc1 = perc2; + } + } + + // If needed, RAND can coexist with linear and either non-linear or wave. + if ( mFlags & FX_SIZE_RAND ) + { + // Random simply modulates the existing value + perc1 = flrand(0.0f, perc1); + } + + mRefEnt.radius = (mSizeStart * perc1) + (mSizeEnd * (1.0f - perc1)); +} + +void ClampRGB( const vec3_t in, byte *out ) +{ + int r; + + for ( int i=0; i<3; i++ ) { + r = Q_ftol(in[i] * 255.0f); + + if ( r < 0 ) + r = 0; + else if ( r > 255 ) + r = 255; + + out[i] = (byte)r; + } +} + +//---------------------------- +// Update RGB +//---------------------------- +void CParticle::UpdateRGB(void) +{ + // completely biased towards start if it doesn't get overridden + float perc1 = 1.0f, perc2 = 1.0f; + vec3_t res; + + if ( (mFlags & FX_RGB_LINEAR) ) + { + // calculate element biasing + perc1 = 1.0f - (float)( theFxHelper.mTime - mTimeStart ) / (float)( mTimeEnd - mTimeStart ); + } + + // We can combine FX_LINEAR with _either_ FX_NONLINEAR, FX_WAVE, or FX_CLAMP + if (( mFlags & FX_RGB_PARM_MASK ) == FX_RGB_NONLINEAR ) + { + if ( theFxHelper.mTime > mRGBParm ) + { + // get percent done, using parm as the start of the non-linear fade + perc2 = 1.0f - (float)( theFxHelper.mTime - mRGBParm ) / (float)( mTimeEnd - mRGBParm ); + } + + if ( (mFlags & FX_RGB_LINEAR) ) + { + // do an even blend + perc1 = perc1 * 0.5f + perc2 * 0.5f; + } + else + { + // just copy it over...sigh + perc1 = perc2; + } + } + else if (( mFlags & FX_RGB_PARM_MASK ) == FX_RGB_WAVE ) + { + // wave gen, with parm being the frequency multiplier + perc1 = perc1 * cosf(( theFxHelper.mTime - mTimeStart ) * mRGBParm ); + } + else if (( mFlags & FX_RGB_PARM_MASK ) == FX_RGB_CLAMP ) + { + if ( theFxHelper.mTime < mRGBParm ) + { + // get percent done, using parm as the start of the non-linear fade + perc2 = (float)(mRGBParm - theFxHelper.mTime) / (float)(mRGBParm - mTimeStart); + } + else + { + perc2 = 0.0f; // make it full size?? + } + + if (( mFlags & FX_RGB_LINEAR )) + { + // do an even blend + perc1 = perc1 * 0.5f + perc2 * 0.5f; + } + else + { + // just copy it over...sigh + perc1 = perc2; + } + } + + // If needed, RAND can coexist with linear and either non-linear or wave. + if ( mFlags & FX_RGB_RAND ) + { + // Random simply modulates the existing value + perc1 = flrand(0.0f, perc1); + } + + // Now get the correct color + VectorScale( mRGBStart, perc1, res ); + VectorMA( res, 1.0f - perc1, mRGBEnd, res ); + + ClampRGB( res, (byte*)(&mRefEnt.shaderRGBA) ); +} + +//---------------------------- +// Update Alpha +//---------------------------- +void CParticle::UpdateAlpha(void) +{ + int alpha; + + // completely biased towards start if it doesn't get overridden + float perc1 = 1.0f, perc2 = 1.0f; + + if ( (mFlags & FX_ALPHA_LINEAR) ) + { + // calculate element biasing + perc1 = 1.0f - (float)(theFxHelper.mTime - mTimeStart) / (float)(mTimeEnd - mTimeStart); + } + + // We can combine FX_LINEAR with _either_ FX_NONLINEAR, FX_WAVE, or FX_CLAMP + if (( mFlags & FX_ALPHA_PARM_MASK ) == FX_ALPHA_NONLINEAR ) + { + if ( theFxHelper.mTime > mAlphaParm ) + { + // get percent done, using parm as the start of the non-linear fade + perc2 = 1.0f - (float)(theFxHelper.mTime - mAlphaParm) / (float)(mTimeEnd - mAlphaParm); + } + + if (( mFlags & FX_ALPHA_LINEAR )) + { + // do an even blend + perc1 = perc1 * 0.5f + perc2 * 0.5f; + } + else + { + // just copy it over...sigh + perc1 = perc2; + } + } + else if (( mFlags & FX_ALPHA_PARM_MASK ) == FX_ALPHA_WAVE ) + { + // wave gen, with parm being the frequency multiplier + perc1 = perc1 * cosf( (theFxHelper.mTime - mTimeStart) * mAlphaParm ); + } + else if (( mFlags & FX_ALPHA_PARM_MASK ) == FX_ALPHA_CLAMP ) + { + if ( theFxHelper.mTime < mAlphaParm ) + { + // get percent done, using parm as the start of the non-linear fade + perc2 = (float)(mAlphaParm - theFxHelper.mTime) / (float)(mAlphaParm - mTimeStart); + } + else + { + perc2 = 0.0f; // make it full size?? + } + + if (( mFlags & FX_ALPHA_LINEAR )) + { + // do an even blend + perc1 = perc1 * 0.5f + perc2 * 0.5f; + } + else + { + // just copy it over...sigh + perc1 = perc2; + } + } + + perc1 = (mAlphaStart * perc1) + (mAlphaEnd * (1.0f - perc1)); + + // We should be in the right range, but clamp to ensure + perc1 = Com_Clamp(0.0f, 1.0f, perc1); + + // If needed, RAND can coexist with linear and either non-linear or wave. + if ( mFlags & FX_ALPHA_RAND ) + { + // Random simply modulates the existing value + perc1 = flrand(0.0f, perc1); + } + + alpha = Com_Clamp(0, 255, perc1 * 255.0f); + if ( mFlags & FX_USE_ALPHA ) + { + // should use this when using art that has an alpha channel + mRefEnt.shaderRGBA[3] = (byte)alpha; + } + else + { + // Modulate the rgb fields by the alpha value to do the fade, works fine for additive blending + mRefEnt.shaderRGBA[0] = ((int)mRefEnt.shaderRGBA[0] * alpha) >> 8; + mRefEnt.shaderRGBA[1] = ((int)mRefEnt.shaderRGBA[1] * alpha) >> 8; + mRefEnt.shaderRGBA[2] = ((int)mRefEnt.shaderRGBA[2] * alpha) >> 8; + } +} + +//-------------------------- +void CParticle::UpdateRotation(void) +{ + mRefEnt.rotation += theFxHelper.mFrameTime * 0.01f * mRotationDelta; + mRotationDelta *= ( 1.0f - ( theFxHelper.mFrameTime * 0.0007f )); // decay rotationDelta +} + + +//-------------------------------- +// +// Derived Oriented Particle Class +// +//-------------------------------- +COrientedParticle::COrientedParticle(void) +{ + mRefEnt.reType = RT_ORIENTED_QUAD; +} + +//---------------------------- +bool COrientedParticle::Cull(void) +{ + vec3_t dir; +// float len; + + // Get the direction to the view + VectorSubtract( mOrigin1, theFxHelper.refdef->vieworg, dir ); + + // Check if it's behind the viewer + if ( (DotProduct( theFxHelper.refdef->viewaxis[0], dir )) < 0 ) + { + return true; + } + +// len = VectorLengthSquared( dir ); + + // don't cull stuff that's associated with inview wpns + if ( mFlags & FX_DEPTH_HACK ) + { + return false; + } + // Can't be too close +// if ( len < fx_nearCull->value * fx_nearCull->value) +// { +// return true; +// } + + return false; +} + +//---------------------------- +void COrientedParticle::Draw(void) +{ + if ( mFlags & FX_DEPTH_HACK ) + { + // Not sure if first person needs to be set + mRefEnt.renderfx |= RF_DEPTHHACK; + } + + // Add our refEntity to the scene + VectorCopy( mOrigin1, mRefEnt.origin ); + if ( !(mFlags&FX_RELATIVE) ) + { + VectorCopy( mNormal, mRefEnt.axis[0] ); + MakeNormalVectors( mRefEnt.axis[0], mRefEnt.axis[1], mRefEnt.axis[2] ); + } + + theFxHelper.AddFxToScene( &mRefEnt ); + drawnFx++; +} + +//---------------------------- +// Update +//---------------------------- +bool COrientedParticle::Update(void) +{ + // Game pausing can cause dumb time things to happen, so kill the effect in this instance + if ( mTimeStart > theFxHelper.mTime ) + { + return false; + } + + if ( mFlags & FX_RELATIVE ) + { + if ( !re->G2API_IsGhoul2InfovValid (*mGhoul2)) + { // the thing we are bolted to is no longer valid, so we may as well just die. + return false; + } + vec3_t org; + matrix3_t ax; + + // Get our current position and direction + if (!theFxHelper.GetOriginAxisFromBolt(mGhoul2, mEntNum, mModelNum, mBoltNum, org, ax)) + { //could not get bolt + return false; + } + vec3_t realVel, realAccel; + + VectorMA( org, mOrgOffset[0], ax[0], org ); + VectorMA( org, mOrgOffset[1], ax[1], org ); + VectorMA( org, mOrgOffset[2], ax[2], org ); + + const float time = (theFxHelper.mTime - mTimeStart) * 0.001f; + // calc the real velocity and accel vectors + VectorScale( ax[0], mVel[0], realVel ); + VectorMA( realVel, mVel[1], ax[1], realVel ); + VectorMA( realVel, mVel[2], ax[2], realVel ); +// realVel[2] += 0.5f * mGravity * time; + + VectorScale( ax[0], mAccel[0], realAccel ); + VectorMA( realAccel, mAccel[1], ax[1], realAccel ); + VectorMA( realAccel, mAccel[2], ax[2], realAccel ); + + // Get our real velocity at the current time, taking into account the effects of acceleartion. NOTE: not sure if this is even 100% correct math-wise + VectorMA( realVel, time, realAccel, realVel ); + + // Now move us to where we should be at the given time + VectorMA( org, time, realVel, mOrigin1 ); + + //use the normalOffset and add that to the actual normal of the bolt + //NOTE: not tested!!! + VectorCopy( ax[0], mRefEnt.axis[0] ); + VectorCopy( ax[1], mRefEnt.axis[1] ); + VectorCopy( ax[2], mRefEnt.axis[2] ); + + //vec3_t offsetAngles; + //VectorSet( offsetAngles, 0, 90, 90 ); + + matrix3_t offsetAxis; + //NOTE: mNormal is actually PITCH YAW and ROLL offsets + AnglesToAxis( mNormal, offsetAxis ); + MatrixMultiply( offsetAxis, ax, mRefEnt.axis ); + } + else if (( mTimeStart < theFxHelper.mTime ) && UpdateOrigin() == false ) + { + // we are marked for death + return false; + } + + if ( !Cull() ) + { // Only update these if the thing is visible. + UpdateSize(); + UpdateRGB(); + UpdateAlpha(); + UpdateRotation(); + + Draw(); + } + + return true; +} + + +//---------------------------- +// +// Derived Line Class +// +//---------------------------- +CLine::CLine(void) +{ + mRefEnt.reType = RT_LINE; +} + +//---------------------------- +void CLine::Draw(void) +{ + if ( mFlags & FX_DEPTH_HACK ) + { + // Not sure if first person needs to be set, but it can't hurt? + mRefEnt.renderfx |= RF_DEPTHHACK; + } + + VectorCopy( mOrigin1, mRefEnt.origin ); + VectorCopy( mOrigin2, mRefEnt.oldorigin ); + + theFxHelper.AddFxToScene(&mRefEnt); + drawnFx++; +} + +//---------------------------- +bool CLine::Update(void) +{ + // Game pausing can cause dumb time things to happen, so kill the effect in this instance + if ( mTimeStart > theFxHelper.mTime ) + { + return false; + } + + if ( mFlags & FX_RELATIVE ) + { + if ( !re->G2API_IsGhoul2InfovValid (*mGhoul2)) + { // the thing we are bolted to is no longer valid, so we may as well just die. + return false; + } + + matrix3_t ax; + // Get our current position and direction + if (!theFxHelper.GetOriginAxisFromBolt(mGhoul2, mEntNum, mModelNum, mBoltNum, mOrigin1, ax)) + { //could not get bolt + return false; + } + + VectorAdd(mOrigin1, mOrgOffset, mOrigin1); //add the offset to the bolt point + + VectorMA( mOrigin1, mVel[0], ax[0], mOrigin2 ); + VectorMA( mOrigin2, mVel[1], ax[1], mOrigin2 ); + VectorMA( mOrigin2, mVel[2], ax[2], mOrigin2 ); + } + + if ( !Cull()) + { + // Only update these if the thing is visible. + UpdateSize(); + UpdateRGB(); + UpdateAlpha(); + + Draw(); + } + + return true; +} + +//---------------------------- +// +// Derived Electricity Class +// +//---------------------------- +CElectricity::CElectricity(void) +{ + mRefEnt.reType = RT_ELECTRICITY; +} + +//---------------------------- +void CElectricity::Initialize(void) +{ + mRefEnt.frame = flrand(0.0f, 1.0f) * 1265536.0f; + mRefEnt.axis[0][2] = theFxHelper.mTime + (mTimeEnd - mTimeStart); // endtime + + if ( mFlags & FX_DEPTH_HACK ) + { + mRefEnt.renderfx |= RF_DEPTHHACK; + } + + if ( mFlags & FX_BRANCH ) + { + mRefEnt.renderfx |= RF_FORKED; + } + + if ( mFlags & FX_TAPER ) + { + mRefEnt.renderfx |= RF_TAPERED; + } + + if ( mFlags & FX_GROW ) + { + mRefEnt.renderfx |= RF_GROW; + } +} + +//---------------------------- +void CElectricity::Draw(void) +{ + VectorCopy( mOrigin1, mRefEnt.origin ); + VectorCopy( mOrigin2, mRefEnt.oldorigin ); + mRefEnt.axis[0][0] = mChaos; + mRefEnt.axis[0][1] = mTimeEnd - mTimeStart; + + theFxHelper.AddFxToScene( &mRefEnt ); + drawnFx++; +} + +//---------------------------- +bool CElectricity::Update(void) +{ + // Game pausing can cause dumb time things to happen, so kill the effect in this instance + if ( mTimeStart > theFxHelper.mTime ) + { + return false; + } + + if ( mFlags & FX_RELATIVE ) + { + if ( !re->G2API_IsGhoul2InfovValid (*mGhoul2)) + { // the thing we are bolted to is no longer valid, so we may as well just die. + return false; + } + + matrix3_t ax; + // Get our current position and direction + if (!theFxHelper.GetOriginAxisFromBolt(mGhoul2, mEntNum, mModelNum, mBoltNum, mOrigin1, ax)) + { //could not get bolt + return false; + } + + VectorAdd(mOrigin1, mOrgOffset, mOrigin1); //add the offset to the bolt point + + VectorMA( mOrigin1, mVel[0], ax[0], mOrigin2 ); + VectorMA( mOrigin2, mVel[1], ax[1], mOrigin2 ); + VectorMA( mOrigin2, mVel[2], ax[2], mOrigin2 ); + } + + if ( !Cull()) + { + // Only update these if the thing is visible. + UpdateSize(); + UpdateRGB(); + UpdateAlpha(); + + Draw(); + } + + return true; +} + +//---------------------------- +// +// Derived Tail Class +// +//---------------------------- +CTail::CTail(void) +{ + mRefEnt.reType = RT_LINE; +} + +//---------------------------- +void CTail::Draw(void) +{ + if ( mFlags & FX_DEPTH_HACK ) + { + // Not sure if first person needs to be set + mRefEnt.renderfx |= RF_DEPTHHACK; + } + + VectorCopy( mOrigin1, mRefEnt.origin ); + + theFxHelper.AddFxToScene(&mRefEnt); + drawnFx++; +} + +//---------------------------- +bool CTail::Update(void) +{ + // Game pausing can cause dumb time things to happen, so kill the effect in this instance + if ( mTimeStart > theFxHelper.mTime ) + { + return false; + } + + if ( mFlags & FX_RELATIVE ) + { + if ( !re->G2API_IsGhoul2InfovValid (*mGhoul2)) + { // the thing we are bolted to is no longer valid, so we may as well just die. + return false; + } + vec3_t org; + matrix3_t ax; + if (mModelNum>=0 && mBoltNum>=0) //bolt style + { + if (!theFxHelper.GetOriginAxisFromBolt(mGhoul2, mEntNum, mModelNum, mBoltNum, org, ax)) + { //could not get bolt + return false; + } + } + + vec3_t realVel, realAccel; + + VectorMA( org, mOrgOffset[0], ax[0], org ); + VectorMA( org, mOrgOffset[1], ax[1], org ); + VectorMA( org, mOrgOffset[2], ax[2], org ); + + // calc the real velocity and accel vectors + // FIXME: if you want right and up movement in addition to the forward movement, you'll have to convert dir into a set of perp. axes and do some extra work + VectorScale( ax[0], mVel[0], realVel ); + VectorMA( realVel, mVel[1], ax[1], realVel ); + VectorMA( realVel, mVel[2], ax[2], realVel ); + + VectorScale( ax[0], mAccel[0], realAccel ); + VectorMA( realAccel, mAccel[1], ax[1], realAccel ); + VectorMA( realAccel, mAccel[2], ax[2], realAccel ); + + const float time = (theFxHelper.mTime - mTimeStart) * 0.001f; + + // Get our real velocity at the current time, taking into account the effects of acceleration. NOTE: not sure if this is even 100% correct math-wise + VectorMA( realVel, time, realAccel, realVel ); + + // Now move us to where we should be at the given time + VectorMA( org, time, realVel, mOrigin1 ); + + // Just calc an old point some time in the past, doesn't really matter when + VectorMA( org, (time - 0.003f), realVel, mOldOrigin ); + } +#ifdef _DEBUG + else if ( !fx_freeze->integer ) +#else + else +#endif + { + VectorCopy( mOrigin1, mOldOrigin ); + } + + if (( mTimeStart < theFxHelper.mTime ) && UpdateOrigin() == false ) + { + // we are marked for death + return false; + } + + if ( !Cull() ) + { + // Only update these if the thing is visible. + UpdateSize(); + UpdateLength(); + UpdateRGB(); + UpdateAlpha(); + + CalcNewEndpoint(); + Draw(); + } + + return true; +} + +//---------------------------- +void CTail::UpdateLength(void) +{ + // completely biased towards start if it doesn't get overridden + float perc1 = 1.0f, perc2 = 1.0f; + + if ( mFlags & FX_LENGTH_LINEAR ) + { + // calculate element biasing + perc1 = 1.0f - (float)(theFxHelper.mTime - mTimeStart) / (float)(mTimeEnd - mTimeStart); + } + + // We can combine FX_LINEAR with _either_ FX_NONLINEAR or FX_WAVE + if (( mFlags & FX_LENGTH_PARM_MASK ) == FX_LENGTH_NONLINEAR ) + { + if ( theFxHelper.mTime > mLengthParm ) + { + // get percent done, using parm as the start of the non-linear fade + perc2 = 1.0f - (float)(theFxHelper.mTime - mLengthParm) / (float)(mTimeEnd - mLengthParm); + } + + if ( mFlags & FX_LENGTH_LINEAR ) + { + // do an even blend + perc1 = perc1 * 0.5f + perc2 * 0.5f; + } + else + { + // just copy it over...sigh + perc1 = perc2; + } + } + else if (( mFlags & FX_LENGTH_PARM_MASK ) == FX_LENGTH_WAVE ) + { + // wave gen, with parm being the frequency multiplier + perc1 = perc1 * cosf( (theFxHelper.mTime - mTimeStart) * mLengthParm ); + } + else if (( mFlags & FX_LENGTH_PARM_MASK ) == FX_LENGTH_CLAMP ) + { + if ( theFxHelper.mTime < mLengthParm ) + { + // get percent done, using parm as the start of the non-linear fade + perc2 = (float)(mLengthParm - theFxHelper.mTime) / (float)(mLengthParm - mTimeStart); + } + else + { + perc2 = 0.0f; // make it full size?? + } + + if ( mFlags & FX_LENGTH_LINEAR ) + { + // do an even blend + perc1 = perc1 * 0.5f + perc2 * 0.5f; + } + else + { + // just copy it over...sigh + perc1 = perc2; + } + } + + // If needed, RAND can coexist with linear and either non-linear or wave. + if ( mFlags & FX_LENGTH_RAND ) + { + // Random simply modulates the existing value + perc1 = flrand(0.0f, perc1); + } + + mLength = (mLengthStart * perc1) + (mLengthEnd * (1.0f - perc1)); +} + + +//---------------------------- +void CTail::CalcNewEndpoint(void) +{ + vec3_t temp; + + // FIXME: Hmmm, this looks dumb when physics are on and a bounce happens + VectorSubtract( mOldOrigin, mOrigin1, temp ); + + // I wish we didn't have to do a VectorNormalize every frame..... + VectorNormalize( temp ); + + VectorMA( mOrigin1, mLength, temp, mRefEnt.oldorigin ); +} + + +//---------------------------- +// +// Derived Cylinder Class +// +//---------------------------- +CCylinder::CCylinder(void) +{ + mRefEnt.reType = RT_CYLINDER; + mTraceEnd = qfalse; +} + +bool CCylinder::Cull(void) +{ + if (mTraceEnd) + { //eh, don't cull variable-length cylinders + return false; + } + + return CTail::Cull(); +} + +void CCylinder::UpdateLength(void) +{ + if (mTraceEnd) + { + vec3_t temp; + trace_t tr; + + VectorMA( mOrigin1, FX_MAX_TRACE_DIST, mRefEnt.axis[0], temp ); + theFxHelper.Trace( tr, mOrigin1, NULL, NULL, temp, -1, MASK_SOLID ); + VectorSubtract( tr.endpos, mOrigin1, temp ); + mLength = VectorLength(temp); + } + else + { + CTail::UpdateLength(); + } +} + +//---------------------------- +void CCylinder::Draw(void) +{ + if ( mFlags & FX_DEPTH_HACK ) + { + // Not sure if first person needs to be set, but it can't hurt? + mRefEnt.renderfx |= RF_DEPTHHACK; + } + + VectorCopy( mOrigin1, mRefEnt.origin ); + VectorMA( mOrigin1, mLength, mRefEnt.axis[0], mRefEnt.oldorigin ); + + theFxHelper.AddFxToScene(&mRefEnt); + drawnFx++; +} + +//---------------------------- +// Update Size2 +//---------------------------- +void CCylinder::UpdateSize2(void) +{ + // completely biased towards start if it doesn't get overridden + float perc1 = 1.0f, perc2 = 1.0f; + + if ( mFlags & FX_SIZE2_LINEAR ) + { + // calculate element biasing + perc1 = 1.0f - (float)(theFxHelper.mTime - mTimeStart) / (float)(mTimeEnd - mTimeStart); + } + + // We can combine FX_LINEAR with _either_ FX_NONLINEAR or FX_WAVE + if (( mFlags & FX_SIZE2_PARM_MASK ) == FX_SIZE2_NONLINEAR ) + { + if ( theFxHelper.mTime > mSize2Parm ) + { + // get percent done, using parm as the start of the non-linear fade + perc2 = 1.0f - (float)(theFxHelper.mTime - mSize2Parm) / (float)(mTimeEnd - mSize2Parm); + } + + if ( (mFlags & FX_SIZE2_LINEAR) ) + { + // do an even blend + perc1 = perc1 * 0.5f + perc2 * 0.5f; + } + else + { + // just copy it over...sigh + perc1 = perc2; + } + } + else if (( mFlags & FX_SIZE2_PARM_MASK ) == FX_SIZE2_WAVE ) + { + // wave gen, with parm being the frequency multiplier + perc1 = perc1 * cosf( (theFxHelper.mTime - mTimeStart) * mSize2Parm ); + } + else if (( mFlags & FX_SIZE2_PARM_MASK ) == FX_SIZE2_CLAMP ) + { + if ( theFxHelper.mTime < mSize2Parm ) + { + // get percent done, using parm as the start of the non-linear fade + perc2 = (float)(mSize2Parm - theFxHelper.mTime) / (float)(mSize2Parm - mTimeStart); + } + else + { + perc2 = 0.0f; // make it full size?? + } + + if ( mFlags & FX_SIZE2_LINEAR ) + { + // do an even blend + perc1 = perc1 * 0.5f + perc2 * 0.5f; + } + else + { + // just copy it over...sigh + perc1 = perc2; + } + } + + // If needed, RAND can coexist with linear and either non-linear or wave. + if ( mFlags & FX_SIZE2_RAND ) + { + // Random simply modulates the existing value + perc1 = flrand(0.0f, perc1); + } + + mRefEnt.rotation = (mSize2Start * perc1) + (mSize2End * (1.0f - perc1)); +} + +//---------------------------- +bool CCylinder::Update(void) +{ + // Game pausing can cause dumb time things to happen, so kill the effect in this instance + if ( mTimeStart > theFxHelper.mTime ) + { + return false; + } + + if ( mFlags & FX_RELATIVE ) + { + if ( !re->G2API_IsGhoul2InfovValid (*mGhoul2)) + { // the thing we are bolted to is no longer valid, so we may as well just die. + return false; + } + + matrix3_t ax; + // Get our current position and direction + if (!theFxHelper.GetOriginAxisFromBolt(mGhoul2, mEntNum, mModelNum, mBoltNum, mOrigin1, ax)) + { //could not get bolt + return false; + } + + VectorAdd(mOrigin1, mOrgOffset, mOrigin1); //add the offset to the bolt point + + VectorCopy( ax[0], mRefEnt.axis[0] ); + //FIXME: should mNormal be a modifier on the forward axis? + /* + VectorMA( mOrigin1, mNormal[0], ax[0], mOrigin2 ); + VectorMA( mOrigin2, mNormal[1], ax[1], mOrigin2 ); + VectorMA( mOrigin2, mNormal[2], ax[2], mOrigin2 ); + */ + } + + if ( !Cull() ) + { + // Only update these if the thing is visible. + UpdateSize(); + UpdateSize2(); + UpdateLength(); + UpdateRGB(); + UpdateAlpha(); + + Draw(); + } + + return true; +} + + +//---------------------------- +// +// Derived Emitter Class +// +//---------------------------- +CEmitter::CEmitter(void) +{ + // There may or may not be a model, but if there isn't one, + // we just won't bother adding the refEnt in our Draw func + mRefEnt.reType = RT_MODEL; +} + +//---------------------------- +CEmitter::~CEmitter(void) +{ +} + +//---------------------------- +// Draw +//---------------------------- +void CEmitter::Draw(void) +{ + // Emitters don't draw themselves, but they may need to add an attached model + if ( mFlags & FX_ATTACHED_MODEL ) + { + mRefEnt.nonNormalizedAxes = qtrue; + + VectorCopy( mOrigin1, mRefEnt.origin ); + + VectorScale( mRefEnt.axis[0], mRefEnt.radius, mRefEnt.axis[0] ); + VectorScale( mRefEnt.axis[1], mRefEnt.radius, mRefEnt.axis[1] ); + VectorScale( mRefEnt.axis[2], mRefEnt.radius, mRefEnt.axis[2] ); + + theFxHelper.AddFxToScene((miniRefEntity_t*)0);// I hate having to do this, but this needs to get added as a regular refEntity + theFxHelper.AddFxToScene(&mRefEnt); + } + + // If we are emitting effects, we had better be careful because just calling it every cgame frame could + // either choke up the effects system on a fast machine, or look really nasty on a low end one. + if ( mFlags & FX_EMIT_FX ) + { + vec3_t org, v; + float ftime, time2, step; + int t, dif; + +#define TRAIL_RATE 12 // we "think" at about a 60hz rate + + // Pick a target step distance and square it + step = mDensity + flrand(-mVariance, mVariance); + step *= step; + + dif = 0; + + for ( t = mOldTime; t <= theFxHelper.mTime; t += TRAIL_RATE ) + { + dif += TRAIL_RATE; + + // ?Not sure if it's better to update this before or after updating the origin + VectorMA( mOldVelocity, dif * 0.001f, mAccel, v ); + + // Calc the time differences + ftime = dif * 0.001f; + time2 = ftime * ftime * 0.5f; + + // Predict the new position + org[0] = mOldOrigin[0] + (ftime * v[0]) + (time2 * v[0]); + org[1] = mOldOrigin[1] + (ftime * v[1]) + (time2 * v[1]); + org[2] = mOldOrigin[2] + (ftime * v[2]) + (time2 * v[2]); + + // Is it time to draw an effect? + if ( DistanceSquared( org, mOldOrigin ) >= step ) + { + // Pick a new target step distance and square it + step = mDensity + flrand(-mVariance, mVariance); + step *= step; + + // We met the step criteria so, we should add in the effect + theFxScheduler.PlayEffect( mEmitterFxID, org, mRefEnt.axis ); + + VectorCopy( org, mOldOrigin ); + VectorCopy( v, mOldVelocity ); + dif = 0; + mOldTime = t; + } + } + } + drawnFx++; +} + +//---------------------------- +bool CEmitter::Update(void) +{ + // Game pausing can cause dumb time things to happen, so kill the effect in this instance + if ( mTimeStart > theFxHelper.mTime ) + { + return false; + } + + // Use this to track if we've stopped moving + VectorCopy( mOrigin1, mOldOrigin ); + VectorCopy( mVel, mOldVelocity ); + + if ( mFlags & FX_RELATIVE ) + { + if ( !re->G2API_IsGhoul2InfovValid (*mGhoul2)) + { // the thing we are bolted to is no longer valid, so we may as well just die. + return false; + } + assert(0);//need this? + + } + if (( mTimeStart < theFxHelper.mTime ) && UpdateOrigin() == false ) + { + // we are marked for death + return false; + } + + bool moving = false; + + // If the thing is no longer moving, kill the angle delta, but don't do it too quickly or it will + // look very artificial. Don't do it too slowly or it will look like there is no friction. + if ( VectorCompare( mOldOrigin, mOrigin1 )) + { + VectorScale( mAngleDelta, 0.7f, mAngleDelta ); + } + else + { + moving = true; + } + + if ( mFlags & FX_PAPER_PHYSICS ) + { + // do this in a more framerate independent manner + float sc = ( 20.0f / theFxHelper.mFrameTime); + + // bah, evil clamping + if ( sc >= 1.0f ) + { + sc = 1.0f; + } + + if ( moving ) + { + // scale the velocity down, basically inducing drag. Acceleration ( gravity ) should keep it pulling down, which is what we want. + VectorScale( mVel, (sc * 0.8f + 0.2f ) * 0.92f, mVel ); + + // add some chaotic motion based on the way we are oriented + VectorMA( mVel, (1.5f - sc) * 4.0f, mRefEnt.axis[0], mVel ); + VectorMA( mVel, (1.5f - sc) * 4.0f, mRefEnt.axis[1], mVel ); + } + + // make us settle so we can lay flat + mAngles[0] *= (0.97f * (sc * 0.4f + 0.6f )); + mAngles[2] *= (0.97f * (sc * 0.4f + 0.6f )); + + // decay our angle delta so we don't rotate as quickly + VectorScale( mAngleDelta, (0.96f * (sc * 0.1f + 0.9f )), mAngleDelta ); + } + + UpdateAngles(); + UpdateSize(); + + Draw(); + + return true; +} + +//---------------------------- +void CEmitter::UpdateAngles(void) +{ + VectorMA( mAngles, theFxHelper.mFrameTime * 0.01f, mAngleDelta, mAngles ); // was 0.001f, but then you really have to jack up the delta to even notice anything + AnglesToAxis( mAngles, mRefEnt.axis ); +} + + +//-------------------------- +// +// Derived Light Class +// +//-------------------------- + +//---------------------------- +void CLight::Draw(void) +{ + theFxHelper.AddLightToScene( mOrigin1, mRefEnt.radius, mRefEnt.origin[0], mRefEnt.origin[1], mRefEnt.origin[2] ); + drawnFx++; +} + +//---------------------------- +// Update +//---------------------------- +bool CLight::Update(void) +{ + // Game pausing can cause dumb time things to happen, so kill the effect in this instance + if ( mTimeStart > theFxHelper.mTime ) + { + return false; + } + + if ( mFlags & FX_RELATIVE ) + { + if ( !re->G2API_IsGhoul2InfovValid (*mGhoul2)) + { // the thing we are bolted to is no longer valid, so we may as well just die. + return false; + } + + matrix3_t ax; + // Get our current position and direction + if (!theFxHelper.GetOriginAxisFromBolt(mGhoul2, mEntNum, mModelNum, mBoltNum, mOrigin1, ax)) + { //could not get bolt + return false; + } + + VectorMA( mOrigin1, mOrgOffset[0], ax[0], mOrigin1 ); + VectorMA( mOrigin1, mOrgOffset[1], ax[1], mOrigin1 ); + VectorMA( mOrigin1, mOrgOffset[2], ax[2], mOrigin1 ); + } + + UpdateSize(); + UpdateRGB(); + + Draw(); + + return true; +} + +//---------------------------- +// Update Size +//---------------------------- +void CLight::UpdateSize(void) +{ + // completely biased towards start if it doesn't get overridden + float perc1 = 1.0f, perc2 = 1.0f; + + if ( mFlags & FX_SIZE_LINEAR ) + { + // calculate element biasing + perc1 = 1.0f - (float)(theFxHelper.mTime - mTimeStart) / (float)(mTimeEnd - mTimeStart); + } + + // We can combine FX_LINEAR with _either_ FX_NONLINEAR or FX_WAVE + if (( mFlags & FX_SIZE_PARM_MASK ) == FX_SIZE_NONLINEAR ) + { + if ( theFxHelper.mTime > mSizeParm ) + { + // get percent done, using parm as the start of the non-linear fade + perc2 = 1.0f - (float)(theFxHelper.mTime - mSizeParm) / (float)(mTimeEnd - mSizeParm); + } + + if ( (mFlags & FX_SIZE_LINEAR) ) + { + // do an even blend + perc1 = perc1 * 0.5f + perc2 * 0.5f; + } + else + { + // just copy it over...sigh + perc1 = perc2; + } + } + else if (( mFlags & FX_SIZE_PARM_MASK ) == FX_SIZE_WAVE ) + { + // wave gen, with parm being the frequency multiplier + perc1 = perc1 * cosf( (theFxHelper.mTime - mTimeStart) * mSizeParm ); + } + else if (( mFlags & FX_SIZE_PARM_MASK ) == FX_SIZE_CLAMP ) + { + if ( theFxHelper.mTime < mSizeParm ) + { + // get percent done, using parm as the start of the non-linear fade + perc2 = (float)(mSizeParm - theFxHelper.mTime) / (float)(mSizeParm - mTimeStart); + } + else + { + perc2 = 0.0f; // make it full size?? + } + + if ( mFlags & FX_SIZE_LINEAR ) + { + // do an even blend + perc1 = perc1 * 0.5f + perc2 * 0.5f; + } + else + { + // just copy it over...sigh + perc1 = perc2; + } + } + + // If needed, RAND can coexist with linear and either non-linear or wave. + if ( mFlags & FX_SIZE_RAND ) + { + // Random simply modulates the existing value + perc1 = flrand(0.0f, perc1); + } + + mRefEnt.radius = (mSizeStart * perc1) + (mSizeEnd * (1.0f - perc1)); +} + +//---------------------------- +// Update RGB +//---------------------------- +void CLight::UpdateRGB(void) +{ + // completely biased towards start if it doesn't get overridden + float perc1 = 1.0f, perc2 = 1.0f; + vec3_t res; + + if ( mFlags & FX_RGB_LINEAR ) + { + // calculate element biasing + perc1 = 1.0f - (float)( theFxHelper.mTime - mTimeStart ) / (float)( mTimeEnd - mTimeStart ); + } + + // We can combine FX_LINEAR with _either_ FX_NONLINEAR or FX_WAVE + if (( mFlags & FX_RGB_PARM_MASK ) == FX_RGB_NONLINEAR ) + { + if ( theFxHelper.mTime > mRGBParm ) + { + // get percent done, using parm as the start of the non-linear fade + perc2 = 1.0f - (float)( theFxHelper.mTime - mRGBParm ) / (float)( mTimeEnd - mRGBParm ); + } + + if ( mFlags & FX_RGB_LINEAR ) + { + // do an even blend + perc1 = perc1 * 0.5f + perc2 * 0.5f; + } + else + { + // just copy it over...sigh + perc1 = perc2; + } + } + else if (( mFlags & FX_RGB_PARM_MASK ) == FX_RGB_WAVE ) + { + // wave gen, with parm being the frequency multiplier + perc1 = perc1 * cosf(( theFxHelper.mTime - mTimeStart ) * mRGBParm ); + } + else if (( mFlags & FX_RGB_PARM_MASK ) == FX_RGB_CLAMP ) + { + if ( theFxHelper.mTime < mRGBParm ) + { + // get percent done, using parm as the start of the non-linear fade + perc2 = (float)(mRGBParm - theFxHelper.mTime) / (float)(mRGBParm - mTimeStart); + } + else + { + perc2 = 0.0f; // make it full size?? + } + + if ( mFlags & FX_RGB_LINEAR ) + { + // do an even blend + perc1 = perc1 * 0.5f + perc2 * 0.5f; + } + else + { + // just copy it over...sigh + perc1 = perc2; + } + } + + // If needed, RAND can coexist with linear and either non-linear or wave. + if ( mFlags & FX_RGB_RAND ) + { + // Random simply modulates the existing value + perc1 = flrand(0.0f, perc1); + } + + // Now get the correct color + VectorScale( mRGBStart, perc1, res ); + VectorMA(res, ( 1.0f - perc1 ), mRGBEnd, mRefEnt.origin); +} + +//-------------------------- +// +// Derived Trail Class +// +//-------------------------- +#define NEW_MUZZLE 0 +#define NEW_TIP 1 +#define OLD_TIP 2 +#define OLD_MUZZLE 3 + +//---------------------------- +void CTrail::Draw() +{ + polyVert_t verts[3]; +// vec3_t color; + + // build the first tri out of the new muzzle...new tip...old muzzle + VectorCopy( mVerts[NEW_MUZZLE].origin, verts[0].xyz ); + VectorCopy( mVerts[NEW_TIP].origin, verts[1].xyz ); + VectorCopy( mVerts[OLD_MUZZLE].origin, verts[2].xyz ); + +// VectorScale( mVerts[NEW_MUZZLE].curRGB, mVerts[NEW_MUZZLE].curAlpha, color ); + verts[0].modulate[0] = mVerts[NEW_MUZZLE].rgb[0]; + verts[0].modulate[1] = mVerts[NEW_MUZZLE].rgb[1]; + verts[0].modulate[2] = mVerts[NEW_MUZZLE].rgb[2]; + verts[0].modulate[3] = mVerts[NEW_MUZZLE].alpha; + +// VectorScale( mVerts[NEW_TIP].curRGB, mVerts[NEW_TIP].curAlpha, color ); + verts[1].modulate[0] = mVerts[NEW_TIP].rgb[0]; + verts[1].modulate[1] = mVerts[NEW_TIP].rgb[1]; + verts[1].modulate[2] = mVerts[NEW_TIP].rgb[2]; + verts[1].modulate[3] = mVerts[NEW_TIP].alpha; + +// VectorScale( mVerts[OLD_MUZZLE].curRGB, mVerts[OLD_MUZZLE].curAlpha, color ); + verts[2].modulate[0] = mVerts[OLD_MUZZLE].rgb[0]; + verts[2].modulate[1] = mVerts[OLD_MUZZLE].rgb[1]; + verts[2].modulate[2] = mVerts[OLD_MUZZLE].rgb[2]; + verts[2].modulate[3] = mVerts[OLD_MUZZLE].alpha; + + verts[0].st[0] = mVerts[NEW_MUZZLE].curST[0]; + verts[0].st[1] = mVerts[NEW_MUZZLE].curST[1]; + verts[1].st[0] = mVerts[NEW_TIP].curST[0]; + verts[1].st[1] = mVerts[NEW_TIP].curST[1]; + verts[2].st[0] = mVerts[OLD_MUZZLE].curST[0]; + verts[2].st[1] = mVerts[OLD_MUZZLE].curST[1]; + + // Add this tri + theFxHelper.AddPolyToScene( mShader, 3, verts ); + + // build the second tri out of the old muzzle...old tip...new tip + VectorCopy( mVerts[OLD_MUZZLE].origin, verts[0].xyz ); + VectorCopy( mVerts[OLD_TIP].origin, verts[1].xyz ); + VectorCopy( mVerts[NEW_TIP].origin, verts[2].xyz ); + +// VectorScale( mVerts[OLD_MUZZLE].curRGB, mVerts[OLD_MUZZLE].curAlpha, color ); + verts[0].modulate[0] = mVerts[OLD_MUZZLE].rgb[0]; + verts[0].modulate[1] = mVerts[OLD_MUZZLE].rgb[1]; + verts[0].modulate[2] = mVerts[OLD_MUZZLE].rgb[2]; + verts[0].modulate[3] = mVerts[OLD_MUZZLE].alpha; + +// VectorScale( mVerts[OLD_TIP].curRGB, mVerts[OLD_TIP].curAlpha, color ); + verts[1].modulate[0] = mVerts[OLD_TIP].rgb[0]; + verts[1].modulate[1] = mVerts[OLD_TIP].rgb[1]; + verts[1].modulate[2] = mVerts[OLD_TIP].rgb[2]; + verts[0].modulate[3] = mVerts[OLD_TIP].alpha; + +// VectorScale( mVerts[NEW_TIP].curRGB, mVerts[NEW_TIP].curAlpha, color ); + verts[2].modulate[0] = mVerts[NEW_TIP].rgb[0]; + verts[2].modulate[1] = mVerts[NEW_TIP].rgb[1]; + verts[2].modulate[2] = mVerts[NEW_TIP].rgb[2]; + verts[0].modulate[3] = mVerts[NEW_TIP].alpha; + + verts[0].st[0] = mVerts[OLD_MUZZLE].curST[0]; + verts[0].st[1] = mVerts[OLD_MUZZLE].curST[1]; + verts[1].st[0] = mVerts[OLD_TIP].curST[0]; + verts[1].st[1] = mVerts[OLD_TIP].curST[1]; + verts[2].st[0] = mVerts[NEW_TIP].curST[0]; + verts[2].st[1] = mVerts[NEW_TIP].curST[1]; + + // Add this tri + theFxHelper.AddPolyToScene( mShader, 3, verts ); + + drawnFx++; +} + +//---------------------------- +// Update +//---------------------------- +bool CTrail::Update() +{ + // Game pausing can cause dumb time things to happen, so kill the effect in this instance + if ( mTimeStart > theFxHelper.mTime ) + { + return false; + } + + float perc = (float)(mTimeEnd - theFxHelper.mTime) / (float)(mTimeEnd - mTimeStart); + + for ( int t = 0; t < 4; t++ ) + { +// mVerts[t].curAlpha = mVerts[t].alpha * perc + mVerts[t].destAlpha * ( 1.0f - perc ); +// if ( mVerts[t].curAlpha < 0.0f ) +// { +// mVerts[t].curAlpha = 0.0f; +// } + +// VectorScale( mVerts[t].rgb, perc, mVerts[t].curRGB ); +// VectorMA( mVerts[t].curRGB, ( 1.0f - perc ), mVerts[t].destrgb, mVerts[t].curRGB ); + mVerts[t].curST[0] = mVerts[t].ST[0] * perc + mVerts[t].destST[0] * ( 1.0f - perc ); + if ( mVerts[t].curST[0] > 1.0f ) + { + mVerts[t].curST[0] = 1.0f; + } + mVerts[t].curST[1] = mVerts[t].ST[1] * perc + mVerts[t].destST[1] * ( 1.0f - perc ); + } + + Draw(); + + return true; +} + +//-------------------------- +// +// Derived Poly Class +// +//-------------------------- + +//---------------------------- +bool CPoly::Cull(void) +{ + vec3_t dir; + + // Get the direction to the view + VectorSubtract( mOrigin1, theFxHelper.refdef->vieworg, dir ); + + // Check if it's behind the viewer + if ( (DotProduct( theFxHelper.refdef->viewaxis[0], dir )) < 0 ) + { + return true; + } + + float len = VectorLengthSquared( dir ); + + // Can't be too close + if ( len < fx_nearCull->value * fx_nearCull->value) + { + return true; + } + + return false; +} + +//---------------------------- +void CPoly::Draw(void) +{ + polyVert_t verts[MAX_CPOLY_VERTS]; + + for ( int i = 0; i < mCount; i++ ) + { + // Add our midpoint and vert offset to get the actual vertex + VectorAdd( mOrigin1, mOrg[i], verts[i].xyz ); + + // Assign the same color to each vert + for ( int k=0; k<4; k++ ) + verts[i].modulate[k] = mRefEnt.shaderRGBA[k]; + + // Copy the ST coords + VectorCopy2( mST[i], verts[i].st ); + } + + // Add this poly + theFxHelper.AddPolyToScene( mRefEnt.customShader, mCount, verts ); + drawnFx++; +} + +//---------------------------- +void CPoly::CalcRotateMatrix(void) +{ + float cosX, cosZ; + float sinX, sinZ; + float rad; + + // rotate around Z + rad = DEG2RAD( mRotDelta[YAW] * theFxHelper.mFrameTime * 0.01f ); + cosZ = cosf( rad ); + sinZ = sinf( rad ); + // rotate around X + rad = DEG2RAD( mRotDelta[PITCH] * theFxHelper.mFrameTime * 0.01f ); + cosX = cosf( rad ); + sinX = sinf( rad ); + +/*Pitch - aroundx Yaw - around z +1 0 0 c -s 0 +0 c -s s c 0 +0 s c 0 0 1 +*/ + mRot[0][0] = cosZ; + mRot[1][0] = -sinZ; + mRot[2][0] = 0; + mRot[0][1] = cosX * sinZ; + mRot[1][1] = cosX * cosZ; + mRot[2][1] = -sinX; + mRot[0][2] = sinX * sinZ; + mRot[1][2] = sinX * cosZ; + mRot[2][2] = cosX; +/* +// ROLL is not supported unless anyone complains, if it needs to be added, use this format +Roll + + c 0 s + 0 1 0 +-s 0 c +*/ + mLastFrameTime = theFxHelper.mFrameTime; +} + +//-------------------------------- +void CPoly::Rotate(void) +{ + vec3_t temp[MAX_CPOLY_VERTS]; + float dif = fabs( (float)(mLastFrameTime - theFxHelper.mFrameTime) ); + + if ( dif > 0.1f * mLastFrameTime ) + { + CalcRotateMatrix(); + } + + // Multiply our rotation matrix by each of the offset verts to get their new position + for ( int i = 0; i < mCount; i++ ) + { + VectorRotate( mOrg[i], mRot, temp[i] ); + VectorCopy( temp[i], mOrg[i] ); + } +} + +//---------------------------- +// Update +//---------------------------- +bool CPoly::Update(void) +{ + // Game pausing can cause dumb time things to happen, so kill the effect in this instance + if ( mTimeStart > theFxHelper.mTime ) + { + return false; + } + + // If our timestamp hasn't exired yet, we won't even consider doing any kind of motion + if ( theFxHelper.mTime > mTimeStamp ) + { + vec3_t mOldOrigin; + + VectorCopy( mOrigin1, mOldOrigin ); + + if (( mTimeStart < theFxHelper.mTime ) && UpdateOrigin() == false ) + { + // we are marked for death + return false; + } + + // Only rotate whilst moving + if ( !VectorCompare( mOldOrigin, mOrigin1 )) + { + Rotate(); + } + } + + if ( !Cull()) + { + // Only update these if the thing is visible. + UpdateRGB(); + UpdateAlpha(); + + Draw(); + } + + return true; +} + +//---------------------------- +void CPoly::PolyInit(void) +{ + if ( mCount < 3 ) + { + return; + } + + int i; + vec3_t org = {0.0f, 0.0f ,0.0f}; + + // Find our midpoint + for ( i = 0; i < mCount; i++ ) + { + VectorAdd( org, mOrg[i], org ); + } + + VectorScale( org, (float)(1.0f / mCount), org ); + + // now store our midpoint for physics purposes + VectorCopy( org, mOrigin1 ); + + // Now we process the passed in points and make it so that they aren't actually the point... + // rather, they are the offset from mOrigin1. + for ( i = 0; i < mCount; i++ ) + { + VectorSubtract( mOrg[i], mOrigin1, mOrg[i] ); + } + + CalcRotateMatrix(); +} + +/* +------------------------- +CBezier + +Bezier curve line +------------------------- +*/ +bool CBezier::Cull( void ) +{ + vec3_t dir; + + VectorSubtract( mOrigin1, theFxHelper.refdef->vieworg, dir ); + + //Check if it's in front of the viewer + if ( (DotProduct( theFxHelper.refdef->viewaxis[0], dir )) >= 0 ) + { + return false; //don't cull + } + + VectorSubtract( mOrigin2, theFxHelper.refdef->vieworg, dir ); + + //Check if it's in front of the viewer + if ( (DotProduct( theFxHelper.refdef->viewaxis[0], dir )) >= 0 ) + { + return false; + } + + VectorSubtract( mControl1, theFxHelper.refdef->vieworg, dir ); + + //Check if it's in front of the viewer + if ( (DotProduct( theFxHelper.refdef->viewaxis[0], dir )) >= 0 ) + { + return false; + } + + return true; //all points behind viewer +} + +//---------------------------- +bool CBezier::Update( void ) +{ + float ftime, time2; + + ftime = theFxHelper.mFrameTime * 0.001f; + time2 = ftime * ftime * 0.5f; + + mControl1[0] = mControl1[0] + (ftime * mControl1Vel[0]) + (time2 * mControl1Vel[0]); + mControl2[0] = mControl2[0] + (ftime * mControl2Vel[0]) + (time2 * mControl2Vel[0]); + mControl1[1] = mControl1[1] + (ftime * mControl1Vel[1]) + (time2 * mControl1Vel[1]); + mControl2[1] = mControl2[1] + (ftime * mControl2Vel[1]) + (time2 * mControl2Vel[1]); + mControl1[2] = mControl1[2] + (ftime * mControl1Vel[2]) + (time2 * mControl1Vel[2]); + mControl2[2] = mControl2[2] + (ftime * mControl2Vel[2]) + (time2 * mControl2Vel[2]); + + if ( Cull() == false ) + { + // Only update these if the thing is visible. + UpdateSize(); + UpdateRGB(); + UpdateAlpha(); + + Draw(); + } + return true; +} + +//---------------------------- +inline void CBezier::DrawSegment( vec3_t start, vec3_t end, float texcoord1, float texcoord2, float segPercent, float lastSegPercent ) +{ + vec3_t lineDir, cross, viewDir; + static vec3_t lastEnd[2]; + polyVert_t verts[4]; + float scaleBottom = 0.0f, scaleTop = 0.0f; + + VectorSubtract( end, start, lineDir ); + VectorSubtract( end, theFxHelper.refdef->vieworg, viewDir ); + CrossProduct( lineDir, viewDir, cross ); + VectorNormalize( cross ); + + // scaleBottom is the width of the bottom edge of the quad, scaleTop is the width of the top edge + scaleBottom = (mSizeStart + ((mSizeEnd - mSizeStart) * lastSegPercent)) * 0.5f; + scaleTop = (mSizeStart + ((mSizeEnd - mSizeStart) * segPercent)) * 0.5f; + + //Construct the oriented quad + if ( mInit ) + { + VectorCopy( lastEnd[0], verts[0].xyz ); + VectorCopy( lastEnd[1], verts[1].xyz ); + } + else + { + VectorMA( start, -scaleBottom, cross, verts[0].xyz ); + VectorMA( start, scaleBottom, cross, verts[1].xyz ); + } + + verts[0].st[0] = 0.0f; + verts[0].st[1] = texcoord1; + + verts[0].modulate[0] = mRefEnt.shaderRGBA[0] * ( 1.0f - texcoord1 ); + verts[0].modulate[1] = mRefEnt.shaderRGBA[1] * ( 1.0f - texcoord1 ); + verts[0].modulate[2] = mRefEnt.shaderRGBA[2] * ( 1.0f - texcoord1 ); + verts[0].modulate[3] = mRefEnt.shaderRGBA[3]; + + verts[1].st[0] = 1.0f; + verts[1].st[1] = texcoord1; + + verts[1].modulate[0] = mRefEnt.shaderRGBA[0] * ( 1.0f - texcoord1 ); + verts[1].modulate[1] = mRefEnt.shaderRGBA[1] * ( 1.0f - texcoord1 ); + verts[1].modulate[2] = mRefEnt.shaderRGBA[2] * ( 1.0f - texcoord1 ); + verts[1].modulate[3] = mRefEnt.shaderRGBA[3]; + + if ( texcoord1 == 0.0f ) + { + for ( int k=0; k<4; k++ ) { + verts[0].modulate[k] = verts[1].modulate[k] = 0; + } + } + + VectorMA( end, scaleTop, cross, verts[2].xyz ); + verts[2].st[0] = 1.0f; + verts[2].st[1] = texcoord2; + + verts[2].modulate[0] = mRefEnt.shaderRGBA[0] * ( 1.0f - texcoord2 ); + verts[2].modulate[1] = mRefEnt.shaderRGBA[1] * ( 1.0f - texcoord2 ); + verts[2].modulate[2] = mRefEnt.shaderRGBA[2] * ( 1.0f - texcoord2 ); + verts[2].modulate[3] = mRefEnt.shaderRGBA[3]; + + VectorMA( end, -scaleTop, cross, verts[3].xyz ); + verts[3].st[0] = 0.0f; + verts[3].st[1] = texcoord2; + + verts[3].modulate[0] = mRefEnt.shaderRGBA[0] * ( 1.0f - texcoord2 ); + verts[3].modulate[1] = mRefEnt.shaderRGBA[1] * ( 1.0f - texcoord2 ); + verts[3].modulate[2] = mRefEnt.shaderRGBA[2] * ( 1.0f - texcoord2 ); + verts[3].modulate[3] = mRefEnt.shaderRGBA[3]; + + theFxHelper.AddPolyToScene( mRefEnt.customShader, 4, verts ); + + VectorCopy( verts[2].xyz, lastEnd[1] ); + VectorCopy( verts[3].xyz, lastEnd[0] ); + + mInit = true; +} + +const float BEZIER_RESOLUTION = 16.0f; + +//---------------------------- +void CBezier::Draw( void ) +{ + vec3_t pos, old_pos; + float mu, mum1; + float incr = 1.0f / BEZIER_RESOLUTION, tex = 1.0f, tc1, tc2; + int i = 0; + + VectorCopy( mOrigin1, old_pos ); + + mInit = false; //Signify a new batch for vert gluing + + float mum13, mu3, group1, group2; + + tc1 = 0.0f; + + for ( mu = incr; mu <= 1.0f; mu += incr) + { + //Four point curve + mum1 = 1 - mu; + mum13 = mum1 * mum1 * mum1; + mu3 = mu * mu * mu; + group1 = 3 * mu * mum1 * mum1; + group2 = 3 * mu * mu *mum1; + + for ( i = 0; i < 3; i++ ) + { + pos[i] = mum13 * mOrigin1[i] + group1 * mControl1[i] + group2 * mControl2[i] + mu3 * mOrigin2[i]; + } + + tc2 = mu * tex; + + //Draw it + DrawSegment( old_pos, pos, tc1, tc2, mu, mu - incr ); + + VectorCopy( pos, old_pos ); + tc1 = tc2; + } + drawnFx++; +} + +/* +------------------------- +CFlash + +Full screen flash +------------------------- +*/ + +//---------------------------- +bool CFlash::Update( void ) +{ + if ( UpdateOrigin() == false ) + { + // we are marked for death + return false; + } + + UpdateSize(); + mRefEnt.radius *= mRadiusModifier; + UpdateRGB(); + UpdateAlpha(); + + Draw(); + return true; +} + +bool FX_WorldToScreen(vec3_t worldCoord, float *x, float *y) +{ + int xcenter, ycenter; + vec3_t local, transformed; + vec3_t vfwd, vright, vup; + + //NOTE: did it this way because most draw functions expect virtual 640x480 coords + // and adjust them for current resolution + xcenter = 640 / 2;//gives screen coords in virtual 640x480, to be adjusted when drawn + ycenter = 480 / 2;//gives screen coords in virtual 640x480, to be adjusted when drawn + + VectorSubtract (worldCoord, theFxHelper.refdef->vieworg, local); + + AngleVectors (theFxHelper.refdef->viewangles, vfwd, vright, vup); + + 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.01) + { + return false; + } + // Simple convert to screen coords. + float xzi = xcenter / transformed[2] * (90.0/theFxHelper.refdef->fov_x); + float yzi = ycenter / transformed[2] * (90.0/theFxHelper.refdef->fov_y); + + *x = (xcenter + xzi * transformed[0]); + *y = (ycenter - yzi * transformed[1]); + + return true; +} + +//---------------------------- +void CFlash::Init( void ) +{ + // 10/19/01 kef -- maybe we want to do something different here for localized flashes, but right + //now I want to be sure that whatever RGB changes occur to a non-localized flash will also occur + //to a localized flash (so I'll have the same initial RGBA values for both...I need them sync'd for an effect) + + vec3_t dif; + float mod = 1.0f, dis = 0.0f, maxRange = 900; + + VectorSubtract( mOrigin1, theFxHelper.refdef->vieworg, dif ); + dis = VectorNormalize( dif ); + + mod = DotProduct( dif, theFxHelper.refdef->viewaxis[0] ); + + if ( dis > maxRange || ( mod < 0.5f && dis > 100 )) + { + mod = 0.0f; + } + else if ( mod < 0.5f && dis <= 100 ) + { + mod += 1.1f; + } + + mod *= (1.0f - ((dis * dis) / (maxRange * maxRange))); + + VectorScale( mRGBStart, mod, mRGBStart ); + VectorScale( mRGBEnd, mod, mRGBEnd ); + + if ( mFlags & FX_LOCALIZED_FLASH ) + { + FX_WorldToScreen(mOrigin1, &mScreenX, &mScreenY); + + // modify size of localized flash based on distance to effect (but not orientation) + if (dis > 100 && dis < maxRange) + { + mRadiusModifier = (1.0f - ((dis * dis) / (maxRange * maxRange))); + } + } +} + +//---------------------------- +void CFlash::Draw( void ) +{ + // Interestingly, if znear is set > than this, then the flash + // doesn't appear at all. + const float FLASH_DISTANCE_FROM_VIEWER = 12.0f; + mRefEnt.reType = RT_SPRITE; + + if ( mFlags & FX_LOCALIZED_FLASH ) + { + vec4_t color; + + color[0] = mRefEnt.shaderRGBA[0] / 255.0; + color[1] = mRefEnt.shaderRGBA[1] / 255.0; + color[2] = mRefEnt.shaderRGBA[2] / 255.0; + color[3] = mRefEnt.shaderRGBA[3] / 255.0; + + // add this 2D effect to the proper list. it will get drawn after the trap->RenderScene call + theFxScheduler.Add2DEffect(mScreenX, mScreenY, mRefEnt.radius, mRefEnt.radius, color, mRefEnt.customShader); + } + else + { + VectorCopy( theFxHelper.refdef->vieworg, mRefEnt.origin ); + VectorMA( mRefEnt.origin, FLASH_DISTANCE_FROM_VIEWER, theFxHelper.refdef->viewaxis[0], mRefEnt.origin ); + + // This is assuming that the screen is wider than it is tall. + mRefEnt.radius = FLASH_DISTANCE_FROM_VIEWER * tan (DEG2RAD (theFxHelper.refdef->fov_x * 0.5f)); + + theFxHelper.AddFxToScene( &mRefEnt ); + } + drawnFx++; +} + +void FX_AddPrimitive( CEffect **pEffect, int killTime ); +void FX_FeedTrail(effectTrailArgStruct_t *a) +{ + CTrail *fx = new CTrail; + int i = 0; + + while (i < 4) + { + VectorCopy(a->mVerts[i].origin, fx->mVerts[i].origin); + VectorCopy(a->mVerts[i].rgb, fx->mVerts[i].rgb); + VectorCopy(a->mVerts[i].destrgb, fx->mVerts[i].destrgb); + VectorCopy(a->mVerts[i].curRGB, fx->mVerts[i].curRGB); + fx->mVerts[i].alpha = a->mVerts[i].alpha; + fx->mVerts[i].destAlpha = a->mVerts[i].destAlpha; + fx->mVerts[i].curAlpha = a->mVerts[i].curAlpha; + fx->mVerts[i].ST[0] = a->mVerts[i].ST[0]; + fx->mVerts[i].ST[1] = a->mVerts[i].ST[1]; + fx->mVerts[i].destST[0] = a->mVerts[i].destST[0]; + fx->mVerts[i].destST[1] = a->mVerts[i].destST[1]; + fx->mVerts[i].curST[0] = a->mVerts[i].curST[0]; + fx->mVerts[i].curST[1] = a->mVerts[i].curST[1]; + i++; + } + + fx->SetFlags(a->mSetFlags); + + fx->mShader = a->mShader; + + FX_AddPrimitive((CEffect **)&fx, a->mKillTime); +} +// end diff --git a/Projects/Android/jni/OpenJK/codemp_delete/client/FxPrimitives.h b/Projects/Android/jni/OpenJK/codemp_delete/client/FxPrimitives.h new file mode 100644 index 0000000..b04ccf5 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/client/FxPrimitives.h @@ -0,0 +1,620 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#pragma once + +#include "FxSystem.h" + +#define MAX_EFFECTS 1800 + +// Generic group flags, used by parser, then get converted to the appropriate specific flags +#define FX_PARM_MASK 0xC // use this to mask off any transition types that use a parm +#define FX_GENERIC_MASK 0xF +#define FX_LINEAR 0x1 +#define FX_RAND 0x2 +#define FX_NONLINEAR 0x4 +#define FX_WAVE 0x8 +#define FX_CLAMP 0xC + +// Group flags +#define FX_ALPHA_SHIFT 0 +#define FX_ALPHA_PARM_MASK 0x0000000C +#define FX_ALPHA_LINEAR 0x00000001 +#define FX_ALPHA_RAND 0x00000002 +#define FX_ALPHA_NONLINEAR 0x00000004 +#define FX_ALPHA_WAVE 0x00000008 +#define FX_ALPHA_CLAMP 0x0000000C + +#define FX_RGB_SHIFT 4 +#define FX_RGB_PARM_MASK 0x000000C0 +#define FX_RGB_LINEAR 0x00000010 +#define FX_RGB_RAND 0x00000020 +#define FX_RGB_NONLINEAR 0x00000040 +#define FX_RGB_WAVE 0x00000080 +#define FX_RGB_CLAMP 0x000000C0 + +#define FX_SIZE_SHIFT 8 +#define FX_SIZE_PARM_MASK 0x00000C00 +#define FX_SIZE_LINEAR 0x00000100 +#define FX_SIZE_RAND 0x00000200 +#define FX_SIZE_NONLINEAR 0x00000400 +#define FX_SIZE_WAVE 0x00000800 +#define FX_SIZE_CLAMP 0x00000C00 + +#define FX_LENGTH_SHIFT 12 +#define FX_LENGTH_PARM_MASK 0x0000C000 +#define FX_LENGTH_LINEAR 0x00001000 +#define FX_LENGTH_RAND 0x00002000 +#define FX_LENGTH_NONLINEAR 0x00004000 +#define FX_LENGTH_WAVE 0x00008000 +#define FX_LENGTH_CLAMP 0x0000C000 + +#define FX_SIZE2_SHIFT 16 +#define FX_SIZE2_PARM_MASK 0x000C0000 +#define FX_SIZE2_LINEAR 0x00010000 +#define FX_SIZE2_RAND 0x00020000 +#define FX_SIZE2_NONLINEAR 0x00040000 +#define FX_SIZE2_WAVE 0x00080000 +#define FX_SIZE2_CLAMP 0x000C0000 + +// Shared flag--these flags, at first glance would appear to be shared, but are safe. I'd rather not do this, but as you can see, features flags are currently all accounted for +#define FX_PAPER_PHYSICS 0x00010000 // emitters ONLY. shared with FX_SIZE_2_LINEAR +#define FX_LOCALIZED_FLASH 0x00010000 // full screen flashes ONLY. shared with FX_SIZE_2_LINEAR +#define FX_PLAYER_VIEW 0x00010000 // player view effects ONLY. shared with FX_SIZE_2_LINEAR + +// Feature flags +#define FX_DEPTH_HACK 0x00100000 +#define FX_RELATIVE 0x00200000 +#define FX_SET_SHADER_TIME 0x00400000 +#define FX_EXPENSIVE_PHYSICS 0x00800000 + +//rww - g2-related flags (these can slow things down significantly, use sparingly) +//These should be used only with particles/decals as they steal flags used by cylinders. +#define FX_GHOUL2_TRACE 0x00020000 //use in conjunction with particles - actually do full ghoul2 traces for physics collision against entities with a ghoul2 instance + //shared FX_SIZE2_RAND (used only with cylinders) +#define FX_GHOUL2_DECALS 0x00040000 //use in conjunction with decals - can project decal as a ghoul2 gore skin object onto ghoul2 models + //shared FX_SIZE2_NONLINEAR (used only with cylinders) + +#define FX_ATTACHED_MODEL 0x01000000 + +#define FX_APPLY_PHYSICS 0x02000000 +#define FX_USE_BBOX 0x04000000 // can make physics more accurate at the expense of speed + +#define FX_USE_ALPHA 0x08000000 // the FX system actually uses RGB to do fades, but this will override that + // and cause it to fill in the alpha. + +#define FX_EMIT_FX 0x10000000 // emitters technically don't have to emit stuff, but when they do + // this flag needs to be set +#define FX_DEATH_RUNS_FX 0x20000000 // Normal death triggers effect, but not kill_on_impact +#define FX_KILL_ON_IMPACT 0x40000000 // works just like it says, but only when physics are on. +#define FX_IMPACT_RUNS_FX 0x80000000 // an effect can call another effect when it hits something. + +// Lightning flags, duplicates of existing flags, but lightning doesn't use those flags in that context...and nothing will ever use these in this context..so we are safe. +#define FX_TAPER 0x01000000 // tapers as it moves towards its endpoint +#define FX_BRANCH 0x02000000 // enables lightning branching +#define FX_GROW 0x04000000 // lightning grows from start point to end point over the course of its life + + +// stuff that can occur when an effect is flagged with "materialImpact" and it hits something +enum EMatImpactEffect +{ + MATIMPACTFX_NONE = 0, + MATIMPACTFX_SHELLSOUND +}; + +//------------------------------ +class CEffect +{ +protected: + + CEffect *mNext; + vec3_t mOrigin1; + + int mTimeStart; + int mTimeEnd; + + unsigned int mFlags; + + EMatImpactEffect mMatImpactFX; + int mMatImpactParm; + + // Size of our object, useful for things that have physics + vec3_t mMin; + vec3_t mMax; + + int mImpactFxID; // if we have an impact event, we may have to call an effect + int mDeathFxID; // if we have a death event, we may have to call an effect + + miniRefEntity_t mRefEnt; + + int mSoundRadius; + int mSoundVolume; + +public: + + CEffect(); + virtual ~CEffect() {} + + virtual void Die() {} + virtual bool Update() { return true; } + virtual void Draw(void) {} + + inline miniRefEntity_t &GetRefEnt(void) { return mRefEnt; } + + inline void SetNext(CEffect *Next) { mNext = Next; } + inline CEffect *GetNext(void) { return mNext; } + inline void GetOrigin(vec3_t dest) {VectorCopy( mOrigin1, dest); } + + inline void SetSTScale(float s,float t) { mRefEnt.shaderTexCoord[0]=s;mRefEnt.shaderTexCoord[1]=t;} + + inline void SetSound ( int vol, int rad) { mSoundRadius = rad; mSoundVolume = vol; } + inline void SetMin( vec3_t min ) { if(min){VectorCopy(min,mMin);}else{VectorClear(mMin);} } + inline void SetMax( vec3_t max ) { if(max){VectorCopy(max,mMax);}else{VectorClear(mMax);} } + inline void SetFlags( int flags ) { mFlags = flags; } + inline void AddFlags( int flags ) { mFlags |= flags; } + inline void ClearFlags( int flags ) { mFlags &= ~flags; } + inline void SetOrigin1( vec3_t org ) { if(org){VectorCopy(org,mOrigin1);}else{VectorClear(mOrigin1);} } + inline void SetTimeStart( int time ) { mTimeStart = time; if (mFlags&FX_SET_SHADER_TIME) { mRefEnt.shaderTime = time * 0.001f; }} + inline void SetTimeEnd( int time ) { mTimeEnd = time; } + inline void SetImpactFxID( int id ) { mImpactFxID = id; } + inline void SetDeathFxID( int id ) { mDeathFxID = id; } + inline EMatImpactEffect GetMatImpactFX() { return mMatImpactFX; } + inline int GetMatImpactParm() { return mMatImpactParm; } + inline void SetMatImpactFX(EMatImpactEffect matFX) { mMatImpactFX = matFX; } + inline void SetMatImpactParm(int matParm) { mMatImpactParm = matParm; } +}; + +//--------------------------------------------------- +// This class is kind of an exception to the "rule". +// For now it exists only for allowing an easy way +// to get the saber slash trails rendered. +//--------------------------------------------------- +class CTrail : public CEffect +{ +// This is such a specific case thing, just grant public access to the goods. +protected: + + void Draw(); + +public: + + typedef struct + { + vec3_t origin; + + // very specifc case, we can modulate the color and the alpha + vec3_t rgb; + vec3_t destrgb; + vec3_t curRGB; + + float alpha; + float destAlpha; + float curAlpha; + + // this is a very specific case thing...allow interpolating the st coords so we can map the texture + // properly as this segement progresses through it's life + float ST[2]; + float destST[2]; + float curST[2]; + + } TVert; + + TVert mVerts[4]; + qhandle_t mShader; + + + CTrail() {}; + virtual ~CTrail() {}; + + virtual bool Update(); +}; + +//------------------------------ +class CLight : public CEffect +{ +protected: + + float mSizeStart; + float mSizeEnd; + float mSizeParm; + + vec3_t mOrgOffset; + vec3_t mRGBStart; + vec3_t mRGBEnd; + float mRGBParm; + + CGhoul2Info_v *mGhoul2; + short mEntNum; + char mModelNum; + char mBoltNum; + + void UpdateSize(); + void UpdateRGB(); + + virtual void Draw(void); +public: + + inline CLight(void) + { + mEntNum = -1; mModelNum = -1; mBoltNum = -1; + } + + inline void SetBoltinfo( CGhoul2Info_v *ghoul2, int entNum, int modelNum = -1, int boltNum = -1 ) + { + mGhoul2 = ghoul2; + mEntNum = entNum; + mModelNum = modelNum; + mBoltNum = boltNum; + } + + virtual bool Update(); + + inline void SetSizeStart( float sz ) { mSizeStart = sz; } + inline void SetSizeEnd( float sz ) { mSizeEnd = sz; } + inline void SetSizeParm( float parm ) { mSizeParm = parm; } + + inline void SetOrgOffset( const vec3_t o ) { if(o){VectorCopy(o,mOrgOffset);}else{VectorClear(mOrgOffset);}} + inline void SetRGBStart( vec3_t rgb ) { if(rgb){VectorCopy(rgb,mRGBStart);}else{VectorClear(mRGBStart);} } + inline void SetRGBEnd( vec3_t rgb ) { if(rgb){VectorCopy(rgb,mRGBEnd);}else{VectorClear(mRGBEnd);} } + inline void SetRGBParm( float parm ) { mRGBParm = parm; } +}; + +//------------------------------ +class CParticle : public CEffect +{ +protected: + + vec3_t mOrgOffset; + + vec3_t mVel; + vec3_t mAccel; + + float mSizeStart; + float mSizeEnd; + float mSizeParm; + + vec3_t mRGBStart; + vec3_t mRGBEnd; + float mRGBParm; + + float mAlphaStart; + float mAlphaEnd; + float mAlphaParm; + + float mRotationDelta; + float mElasticity; + + CGhoul2Info_v *mGhoul2; + short mEntNum; + char mModelNum; + char mBoltNum; + + bool UpdateOrigin(); + void UpdateSize(); + void UpdateRGB(); + void UpdateAlpha(); + void UpdateRotation(); + + +public: + + inline void SetBoltinfo( CGhoul2Info_v *ghoul2, int entNum, int modelNum = -1, int boltNum = -1 ) + { + mGhoul2 = ghoul2; + mEntNum = entNum; + mModelNum = modelNum; + mBoltNum = boltNum; + } + + inline CParticle(void) + { + mRefEnt.reType = RT_SPRITE; mEntNum = -1; mModelNum = -1; mBoltNum = -1; + } + + virtual void Init(); + virtual void Die(); + virtual bool Update(); + virtual bool Cull(void); + virtual void Draw(void); + + inline void SetShader( qhandle_t sh ) { mRefEnt.customShader = sh; } + + inline void SetOrgOffset( const vec3_t o ) { if(o){VectorCopy(o,mOrgOffset);}else{VectorClear(mOrgOffset);}} + inline void SetVel( vec3_t vel ) { if(vel){VectorCopy(vel,mVel);}else{VectorClear(mVel);} } + inline void SetAccel( vec3_t ac ) { if(ac){VectorCopy(ac,mAccel);}else{VectorClear(mAccel);} } + + inline void SetSizeStart( float sz ) { mSizeStart = sz; mRefEnt.radius = sz; } + inline void SetSizeEnd( float sz ) { mSizeEnd = sz; } + inline void SetSizeParm( float parm ) { mSizeParm = parm; } + + inline void SetRGBStart( vec3_t rgb ) { if(rgb){VectorCopy(rgb,mRGBStart);}else{VectorClear(mRGBStart);} } + inline void SetRGBEnd( vec3_t rgb ) { if(rgb){VectorCopy(rgb,mRGBEnd);}else{VectorClear(mRGBEnd);} } + inline void SetRGBParm( float parm ) { mRGBParm = parm; } + + inline void SetAlphaStart( float al ) { mAlphaStart = al; } + inline void SetAlphaEnd( float al ) { mAlphaEnd = al; } + inline void SetAlphaParm( float parm ) { mAlphaParm = parm; } + + inline void SetRotation( float rot ) { mRefEnt.rotation = rot; } + inline void SetRotationDelta( float rot ) { mRotationDelta = rot; } + inline void SetElasticity( float el ) { mElasticity = el; } +}; + +//------------------------------ +class CFlash : public CParticle +{ +public: + + CFlash(): + mScreenX(0), + mScreenY(0), + mRadiusModifier(1) + {} + + virtual ~CFlash() {} + + virtual bool Update(); + virtual void Draw(void); + virtual bool Cull(void) { return false; } + + void Init( void ); + +protected: + // kef -- mScreenX and mScreenY are used for flashes that are FX_LOCALIZED_FLASH + float mScreenX; + float mScreenY; + float mRadiusModifier; +}; + +//------------------------------ +class CLine : public CParticle +{ +protected: + + vec3_t mOrigin2; + + virtual void Draw(void); +public: + + CLine(); + virtual ~CLine() {} + + virtual void Die() {} + + virtual bool Update(); + + inline void SetOrigin2( vec3_t org2 ) { VectorCopy( org2, mOrigin2 ); } +}; + +//------------------------------ +class CBezier : public CLine +{ +protected: + + vec3_t mControl1; + vec3_t mControl1Vel; + + vec3_t mControl2; + vec3_t mControl2Vel; + + bool mInit; + +public: + + CBezier(){ mInit = false; } + virtual ~CBezier() {} + + virtual void Die() {} + virtual bool Update(); + virtual bool Cull(void); + virtual void Draw(void); + + void DrawSegment( vec3_t start, vec3_t end, float texcoord1, float texcoord2, float segPercent, float lastSegPercent ); + + inline void SetControlPoints( vec3_t ctrl1, vec3_t ctrl2 ) { VectorCopy( ctrl1, mControl1 ); VectorCopy( ctrl2, mControl2 ); } + inline void SetControlVel( vec3_t ctrl1v, vec3_t ctrl2v ) { VectorCopy( ctrl1v, mControl1Vel ); VectorCopy( ctrl2v, mControl2Vel ); } +}; + +//------------------------------ +class CElectricity : public CLine +{ +protected: + + float mChaos; + + virtual void Draw(void); +public: + + CElectricity(); + virtual ~CElectricity() {} + + virtual void Die() {} + + virtual bool Update(); + + void Initialize(); + + inline void SetChaos( float chaos ) { mChaos = chaos; } +}; + + +// Oriented quad +//------------------------------ +class COrientedParticle : public CParticle +{ +protected: + + vec3_t mNormal; + +public: + + COrientedParticle(); + virtual ~COrientedParticle() {} + + virtual bool Update(); + virtual bool Cull(void); + virtual void Draw(void); + + inline void SetNormal( vec3_t norm ) { VectorCopy( norm, mNormal ); } +}; + +//------------------------------ +class CTail : public CParticle +{ +protected: + + vec3_t mOldOrigin; + + float mLengthStart; + float mLengthEnd; + float mLengthParm; + + float mLength; + + void UpdateLength(); + void CalcNewEndpoint(); + + virtual void Draw(void); +public: + + CTail(); + virtual ~CTail() {} + + virtual bool Update(); + + inline void SetLengthStart( float len ) { mLengthStart = len; } + inline void SetLengthEnd( float len ) { mLengthEnd = len; } + inline void SetLengthParm( float len ) { mLengthParm = len; } +}; + + +//------------------------------ +class CCylinder : public CTail +{ +protected: + + float mSize2Start; + float mSize2End; + float mSize2Parm; + qboolean mTraceEnd; + + void UpdateSize2(); + + virtual void Draw(void); +public: + + CCylinder(); + virtual ~CCylinder() {} + + virtual bool Cull(void); + virtual void UpdateLength(void); + virtual bool Update(); + + inline void SetSize2Start( float sz ) { mSize2Start = sz; } + inline void SetSize2End( float sz ) { mSize2End = sz; } + inline void SetSize2Parm( float parm ) { mSize2Parm = parm; } + inline void SetTraceEnd(qboolean traceEnd) { mTraceEnd = traceEnd; } + + inline void SetNormal( vec3_t norm ) { VectorCopy( norm, mRefEnt.axis[0] ); } +}; + + +//------------------------------ +// Emitters are derived from particles because, although they don't draw, any effect called +// from them can borrow an initial or ending value from the emitters current alpha, rgb, etc.. +class CEmitter : public CParticle +{ +protected: + + vec3_t mOldOrigin; // we use these to do some nice + vec3_t mLastOrigin; // tricks... + vec3_t mOldVelocity; // + int mOldTime; + + vec3_t mAngles; // for a rotating thing, using a delta + vec3_t mAngleDelta; // as opposed to an end angle is probably much easier + + int mEmitterFxID; // if we have emitter fx, this is our id + + float mDensity; // controls how often emitter chucks an effect + float mVariance; // density sloppiness + + void UpdateAngles(); + + virtual void Draw(void); +public: + + CEmitter(); + virtual ~CEmitter(); + + virtual bool Cull(void) {return false;} + virtual bool Update(); + + inline void SetModel( qhandle_t model ) { mRefEnt.hModel = model; } + inline void SetAngles( vec3_t ang ) { if(ang){VectorCopy(ang,mAngles);}else{VectorClear(mAngles);} } + inline void SetAngleDelta( vec3_t ang ) { if(ang){VectorCopy(ang,mAngleDelta);}else{VectorClear(mAngleDelta);} } + inline void SetEmitterFxID( int id ) { mEmitterFxID = id; } + inline void SetDensity( float density ) { mDensity = density; } + inline void SetVariance( float var ) { mVariance = var; } + inline void SetOldTime( int time ) { mOldTime = time; } + inline void SetLastOrg( vec3_t org ) { if(org){VectorCopy(org,mLastOrigin);}else{VectorClear(mLastOrigin);} } + inline void SetLastVel( vec3_t vel ) { if(vel){VectorCopy(vel,mOldVelocity);}else{VectorClear(mOldVelocity);} } +}; + +// We're getting pretty low level here, not the kind of thing to abuse considering how much overhead this +// adds to a SINGLE triangle or quad.... +//------------------------------ +#define MAX_CPOLY_VERTS 5 + +class CPoly : public CParticle +{ +protected: + + int mCount; + vec3_t mRotDelta; + int mTimeStamp; + +public: + + vec3_t mOrg[MAX_CPOLY_VERTS]; + vec2_t mST[MAX_CPOLY_VERTS]; + + float mRot[3][3]; + int mLastFrameTime; + + + CPoly() {} + virtual ~CPoly() {} + + virtual bool Update(); + virtual bool Cull(void); + virtual void Draw(void); + + void PolyInit(); + void CalcRotateMatrix(); + void Rotate(); + + inline void SetNumVerts( int c ) { mCount = c; } + inline void SetRot( vec3_t r ) { if(r){VectorCopy(r,mRotDelta);}else{VectorClear(mRotDelta);}} + inline void SetMotionTimeStamp( int t ) { mTimeStamp = theFxHelper.GetTime() + t; } + inline int GetMotionTimeStamp() { return mTimeStamp; } +}; diff --git a/Projects/Android/jni/OpenJK/codemp_delete/client/FxScheduler.cpp b/Projects/Android/jni/OpenJK/codemp_delete/client/FxScheduler.cpp new file mode 100644 index 0000000..15a3ecc --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/client/FxScheduler.cpp @@ -0,0 +1,1734 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#include "client.h" +#include "cl_cgameapi.h" +#include "FxScheduler.h" +#include "qcommon/q_shared.h" + +#include +#include +#include + +CFxScheduler theFxScheduler; + +//----------------------------------------------------------- +CMediaHandles &CMediaHandles::operator=(const CMediaHandles &that ) +{ + mMediaList.clear(); + + for ( size_t i = 0; i < that.mMediaList.size(); i++ ) + { + mMediaList.push_back( that.mMediaList[i] ); + } + return *this; +} + +//------------------------------------------------------ +CFxScheduler::CFxScheduler() +{ + mNextFree2DEffect = 0; + memset( &mEffectTemplates, 0, sizeof( mEffectTemplates )); + memset( &mLoopedEffectArray, 0, sizeof( mLoopedEffectArray )); +} + +int CFxScheduler::ScheduleLoopedEffect( int id, int boltInfo, CGhoul2Info_v *ghoul2, bool isPortal, int iLoopTime, bool isRelative ) +{ + int i; + + assert(id); + assert(boltInfo!=-1); + + for (i=0;i> ENTITY_SHIFT ) & ENTITY_AND; + // Find out where the entity currently is + TCGVectorData *data = (TCGVectorData*)cl.mSharedMemory; + + data->mEntityNum = entNum; + CGVM_GetLerpOrigin(); + + PlayEffect( mLoopedEffectArray[i].mId, data->mPoint, 0, mLoopedEffectArray[i].mBoltInfo, mLoopedEffectArray[i].mGhoul2, -1, mLoopedEffectArray[i].mPortalEffect, false, mLoopedEffectArray[i].mIsRelative ); //very important to send FALSE to not recursively add me! + mLoopedEffectArray[i].mNextTime = theFxHelper.mTime + mEffectTemplates[mLoopedEffectArray[i].mId].mRepeatDelay; + if (mLoopedEffectArray[i].mLoopStopTime && mLoopedEffectArray[i].mLoopStopTime < theFxHelper.mTime) //time's up + {//kill this entry + memset( &mLoopedEffectArray[i], 0, sizeof(mLoopedEffectArray[i]) ); + } + } + } + +} + +//----------------------------------------------------------- +SEffectTemplate &SEffectTemplate::operator=(const SEffectTemplate &that) +{ + mCopy = true; + + strcpy( mEffectName, that.mEffectName ); + + mPrimitiveCount = that.mPrimitiveCount; + + for( int i = 0; i < mPrimitiveCount; i++ ) + { + mPrimitives[i] = new CPrimitiveTemplate; + *(mPrimitives[i]) = *(that.mPrimitives[i]); + // Mark use as a copy so that we know that we should be chucked when used up + mPrimitives[i]->mCopy = true; + } + return *this; +} + +//------------------------------------------------------ +// Clean +// Free up any memory we've allocated so we aren't leaking memory +// +// Input: +// Whether to clean everything or just stop the playing (active) effects +// +// Return: +// None +// +//------------------------------------------------------ +void CFxScheduler::Clean(bool bRemoveTemplates /*= true*/, int idToPreserve /*= 0*/) +{ + int i, j; + TScheduledEffect::iterator itr, next; + + // Ditch any scheduled effects + itr = mFxSchedule.begin(); + + while ( itr != mFxSchedule.end() ) + { + next = itr; + ++next; + + mScheduledEffectsPool.Free (*itr); + mFxSchedule.erase(itr); + + itr = next; + } + + if (bRemoveTemplates) + { + // Ditch any effect templates + for ( i = 1; i < FX_MAX_EFFECTS; i++ ) + { + if ( i == idToPreserve) + { + continue; + } + + if ( mEffectTemplates[i].mInUse ) + { + // Ditch the primitives + for (j = 0; j < mEffectTemplates[i].mPrimitiveCount; j++) + { + delete mEffectTemplates[i].mPrimitives[j]; + } + } + + mEffectTemplates[i].mInUse = false; + } + + if (idToPreserve == 0) + { + mEffectIDs.clear(); + } + else + { + // Clear the effect names, but first get the name of the effect to preserve, + // and restore it after clearing. + std::string str; + TEffectID::iterator iter; + + for (iter = mEffectIDs.begin(); iter != mEffectIDs.end(); ++iter) + { + if ((*iter).second == idToPreserve) + { + str = (*iter).first; + break; + } + } + + mEffectIDs.clear(); + + mEffectIDs[str] = idToPreserve; + } + } +} + +//------------------------------------------------------ +// RegisterEffect +// Attempt to open the specified effect file, if +// file read succeeds, parse the file. +// +// Input: +// path or filename to open +// +// Return: +// int handle to the effect +//------------------------------------------------------ +int CFxScheduler::RegisterEffect( const char *file, bool bHasCorrectPath /*= false*/ ) +{ + // Dealing with file names: + // File names can come from two places - the editor, in which case we should use the given + // path as is, and the effect file, in which case we should add the correct path and extension. + // In either case we create a stripped file name to use for naming effects. + // + + char sfile[MAX_QPATH]; + + COM_StripExtension( file, sfile, sizeof( sfile ) ); + + std::string s = sfile; + std::transform(s.begin(), s.end(), s.begin(), ::tolower); + + Com_DPrintf("Registering effect : %s\n", sfile); + + // see if the specified file is already registered. If it is, just return the id of that file + TEffectID::iterator itr; + + itr = mEffectIDs.find( sfile ); + + if ( itr != mEffectIDs.end() ) + { + return (*itr).second; + } + + CGenericParser2 parser; + int len = 0; + fileHandle_t fh; + char data[65536]; + char *bufParse = 0; + + // if our file doesn't have an extension, add one + std::string finalFilename = file; + std::string effectsSubstr = finalFilename.substr(0, 7); + + if (finalFilename.find('.') == std::string::npos) + { + // didn't find an extension so add one + finalFilename += ".efx"; + } + + // kef - grr. this angers me. every filename everywhere should start from the base dir + if (effectsSubstr.compare("effects") != 0) + { + //theFxHelper.Print("Hey!!! '%s' should be pathed from the base directory!!!\n", finalFilename.c_str()); + std::string strTemp = finalFilename; + finalFilename = "effects/"; + finalFilename += strTemp; + } + + len = theFxHelper.OpenFile( finalFilename.c_str(), &fh, FS_READ ); + + /* + if (bHasCorrectPath) + { + pfile = file; + } + else + { + // Add on our extension and prepend the file with the default path + sprintf( temp, "%s/%s.efx", FX_FILE_PATH, sfile ); + pfile = temp; + } + len = theFxHelper.OpenFile( pfile, &fh, FS_READ ); + */ + + + if ( len < 0 ) + { + theFxHelper.Print( "Effect file load failed: %s\n", finalFilename.c_str() ); + return 0; + } + + if (len == 0) + { + theFxHelper.Print( "INVALID Effect file: %s\n", finalFilename.c_str() ); + theFxHelper.CloseFile( fh ); + return 0; + } + + // If we'll overflow our buffer, bail out--not a particularly elegant solution + if ((unsigned)len >= sizeof(data) - 1 ) + { + theFxHelper.CloseFile( fh ); + return 0; + } + + // Get the goods and ensure Null termination + theFxHelper.ReadFile( data, len, fh ); + data[len] = '\0'; + bufParse = data; + + // Let the generic parser process the whole file + parser.Parse( &bufParse ); + + theFxHelper.CloseFile( fh ); + + // Lets convert the effect file into something that we can work with + return ParseEffect( sfile, parser.GetBaseParseGroup() ); +} + + +//------------------------------------------------------ +// ParseEffect +// Starts at ground zero, using each group header to +// determine which kind of effect we are working with. +// Then we call the appropriate function to parse the +// specified effect group. +// +// Input: +// base group, essentially the whole files contents +// +// Return: +// int handle of the effect +//------------------------------------------------------ + +struct primitiveType_s { const char *name; EPrimType type; } primitiveTypes[] = { + { "particle", Particle }, + { "line", Line }, + { "tail", Tail }, + { "sound", Sound }, + { "cylinder", Cylinder }, + { "electricity", Electricity }, + { "emitter", Emitter }, + { "decal", Decal }, + { "orientedparticle", OrientedParticle }, + { "fxrunner", FxRunner }, + { "light", Light }, + { "cameraShake", CameraShake }, + { "flash", ScreenFlash }, +}; +static const size_t numPrimitiveTypes = ARRAY_LEN( primitiveTypes ); + +int CFxScheduler::ParseEffect( const char *file, CGPGroup *base ) +{ + CGPGroup *primitiveGroup; + CPrimitiveTemplate *prim; + const char *grpName; + SEffectTemplate *effect = 0; + EPrimType type; + int handle; + CGPValue *pair; + + effect = GetNewEffectTemplate( &handle, file ); + + if ( !handle || !effect ) + { + // failure + return 0; + } + if ((pair = base->GetPairs())!=0) + { + grpName = pair->GetName(); + if ( !Q_stricmp( grpName, "repeatDelay" )) + { + effect->mRepeatDelay = atoi(pair->GetTopValue()); + } + else + {//unknown + + } + } + + primitiveGroup = base->GetSubGroups(); + + while ( primitiveGroup ) + { + grpName = primitiveGroup->GetName(); + + type = None; + for ( size_t i=0; imType = type; + prim->ParsePrimitive( primitiveGroup ); + + // Add our primitive template to the effect list + AddPrimitiveToEffect( effect, prim ); + } + + primitiveGroup = (CGPGroup *)primitiveGroup->GetNext(); + } + + return handle; +} + + +//------------------------------------------------------ +// AddPrimitiveToEffect +// Takes a primitive and attaches it to the effect. +// +// Input: +// Effect template that we tack the primitive on to +// Primitive to add to the effect template +// +// Return: +// None +//------------------------------------------------------ +void CFxScheduler::AddPrimitiveToEffect( SEffectTemplate *fx, CPrimitiveTemplate *prim ) +{ + int ct = fx->mPrimitiveCount; + + if ( ct >= FX_MAX_EFFECT_COMPONENTS ) + { + theFxHelper.Print( "FxScheduler: Error--too many primitives in an effect\n" ); + } + else + { + fx->mPrimitives[ct] = prim; + fx->mPrimitiveCount++; + } +} + +//------------------------------------------------------ +// GetNewEffectTemplate +// Finds an unused effect template and returns it to the +// caller. +// +// Input: +// pointer to an id that will be filled in, +// file name-- should be NULL when requesting a copy +// +// Return: +// the id of the added effect template +//------------------------------------------------------ +SEffectTemplate *CFxScheduler::GetNewEffectTemplate( int *id, const char *file ) +{ + SEffectTemplate *effect; + + // wanted zero to be a bogus effect ID, so we just skip it. + for ( int i = 1; i < FX_MAX_EFFECTS; i++ ) + { + effect = &mEffectTemplates[i]; + + if ( !effect->mInUse ) + { + *id = i; + memset( effect, 0, sizeof( SEffectTemplate )); + + // If we are a copy, we really won't have a name that we care about saving for later + if ( file ) + { + mEffectIDs[file] = i; + strcpy( effect->mEffectName, file ); + } + + effect->mInUse = true; + effect->mRepeatDelay = 300; + return effect; + } + } + + theFxHelper.Print( "FxScheduler: Error--reached max effects\n" ); + *id = 0; + return 0; +} + +//------------------------------------------------------ +// GetEffectCopy +// Returns a copy of the desired effect so that it can +// easily be modified run-time. +// +// Input: +// file-- the name of the effect file that you want a copy of +// newHandle-- will actually be the returned handle to the new effect +// you have to hold onto this if you intend to call it again +// +// Return: +// the pointer to the copy +//------------------------------------------------------ +SEffectTemplate *CFxScheduler::GetEffectCopy( const char *file, int *newHandle ) +{ + return ( GetEffectCopy( mEffectIDs[file], newHandle ) ); +} + +//------------------------------------------------------ +// GetEffectCopy +// Returns a copy of the desired effect so that it can +// easily be modified run-time. +// +// Input: +// fxHandle-- the handle to the effect that you want a copy of +// newHandle-- will actually be the returned handle to the new effect +// you have to hold onto this if you intend to call it again +// +// Return: +// the pointer to the copy +//------------------------------------------------------ +SEffectTemplate *CFxScheduler::GetEffectCopy( int fxHandle, int *newHandle ) +{ + if ( fxHandle < 1 || fxHandle >= FX_MAX_EFFECTS) + { + // Didn't even request a valid effect to copy!!! + theFxHelper.Print( "FxScheduler: Bad effect file copy request: id = %d\n", fxHandle ); + + *newHandle = 0; + return 0; + } + + if (!mEffectTemplates[fxHandle].mInUse ) + { + // Didn't even request a valid effect to copy!!! + theFxHelper.Print( "FxScheduler: Bad effect file copy request: id %d not inuse\n", fxHandle ); + + *newHandle = 0; + return 0; + } + +#ifdef _DEBUG + // never get a copy when time is frozen + if ( fx_freeze->integer ) + { + return 0; + } +#endif + + // Copies shouldn't have names, otherwise they could trash our stl map used for getting ID from name + SEffectTemplate *copy = GetNewEffectTemplate( newHandle, NULL ); + + if ( copy && *newHandle ) + { + // do the effect copy and mark us as what we are + *copy = mEffectTemplates[fxHandle]; + copy->mCopy = true; + + // the user had better hold onto this handle if they ever hope to call this effect. + return copy; + } + + // No space left to return an effect + *newHandle = 0; + return 0; +} + +//------------------------------------------------------ +// GetPrimitiveCopy +// Helper function that returns a copy of the desired primitive +// +// Input: +// fxHandle - the pointer to the effect copy you want to override +// componentName - name of the component to find +// +// Return: +// the pointer to the desired primitive +//------------------------------------------------------ +CPrimitiveTemplate *CFxScheduler::GetPrimitiveCopy( SEffectTemplate *effectCopy, const char *componentName ) +{ + if ( !effectCopy || !effectCopy->mInUse ) + { + return NULL; + } + + for ( int i = 0; i < effectCopy->mPrimitiveCount; i++ ) + { + if ( !Q_stricmp( effectCopy->mPrimitives[i]->mName, componentName )) + { + // we found a match, so return it + return effectCopy->mPrimitives[i]; + } + } + + // bah, no good. + return NULL; +} + + +void CFxScheduler::MaterialImpact(trace_t *tr, CEffect *effect) +{ +/* EMatImpactEffect matImpactEffect = effect->GetMatImpactFX(); + int impactParm = effect->GetMatImpactParm(); + + if (matImpactEffect == MATIMPACTFX_NONE) + { + return; + } + else if (matImpactEffect == MATIMPACTFX_SHELLSOUND) + { + // only want to play this for the first impact + effect->SetMatImpactFX(MATIMPACTFX_NONE); + + int material = tr->surfaceFlags & MATERIAL_MASK; + const char *ammoName = CWeaponSystem::GetAmmoName(impactParm); + + if(ammoName && materials[material].HasShellSound(ammoName)) + { + theFxHelper.PlaySound( tr->endpos, ENTITYNUM_NONE, CHAN_AUTO, materials[material].GetShellSoundHandle(ammoName) ); + } + }*/ +} + + +//------------------------------------------------------ +static void ReportPlayEffectError(int id) +{ + theFxHelper.Print( "CFxScheduler::PlayEffect called with invalid effect ID: %i\n", id ); +} + + +//------------------------------------------------------ +// PlayEffect +// Handles scheduling an effect so all the components +// happen at the specified time. Applies a default up +// axis. +// +// Input: +// Effect file id and the origin +// +// Return: +// none +//------------------------------------------------------ +/*void CFxScheduler::PlayEffect( int id, vec3_t origin, int vol, int rad ) +{ + matrix3_t axis; + + VectorSet( axis[0], 0, 0, 1 ); + VectorSet( axis[1], 1, 0, 0 ); + VectorSet( axis[2], 0, 1, 0 ); + + PlayEffect( id, origin, axis, vol, rad ); +} +*/ +//------------------------------------------------------ +// PlayEffect +// Handles scheduling an effect so all the components +// happen at the specified time. Takes a fwd vector +// and builds a right and up vector +// +// Input: +// Effect file id, the origin, and a fwd vector +// +// Return: +// none +//------------------------------------------------------ +void CFxScheduler::PlayEffect( int id, vec3_t origin, vec3_t forward, int vol, int rad, bool isPortal ) +{ + matrix3_t axis; + + // Take the forward vector and create two arbitrary but perpendicular vectors + VectorCopy( forward, axis[0] ); + MakeNormalVectors( forward, axis[1], axis[2] ); + + PlayEffect( id, origin, axis, -1, 0, -1, vol, rad, isPortal ); +} + + +//------------------------------------------------------ +// PlayEffect +// Handles scheduling an effect so all the components +// happen at the specified time. Uses the specified axis +// +// Input: +// Effect file name, the origin, and axis. +// Optional boltInfo (defaults to -1) +// and iGhoul2 used by boltInfo +// +// Return: +// none +//------------------------------------------------------ +void CFxScheduler::PlayEffect( const char *file, vec3_t origin, matrix3_t axis, const int boltInfo, CGhoul2Info_v *ghoul2, + int fxParm /*-1*/, int vol, int rad, int iLoopTime, bool isRelative ) +{ + char sfile[MAX_QPATH]; + + // Get an extenstion stripped version of the file + COM_StripExtension( file, sfile, sizeof( sfile ) ); + +#ifndef FINAL_BUILD + if ( mEffectIDs[sfile] == 0 ) + { + theFxHelper.Print( "CFxScheduler::PlayEffect unregistered/non-existent effect: %s\n", sfile ); + return; + } +#endif + + PlayEffect( mEffectIDs[sfile], origin, axis, boltInfo, ghoul2, fxParm, vol, rad, qfalse, iLoopTime, isRelative ); +} + +int totalPrimitives = 0; +int totalEffects = 0; + +void GetRGB_Colors( CPrimitiveTemplate *fx, vec3_t outStartRGB, vec3_t outEndRGB ) +{ + float percent; + + if ( fx->mSpawnFlags & FX_RGB_COMPONENT_INTERP ) + { + percent = flrand(0.0f, 1.0f); + + VectorSet( outStartRGB, fx->mRedStart.GetVal(percent), fx->mGreenStart.GetVal(percent), fx->mBlueStart.GetVal(percent) ); + VectorSet( outEndRGB, fx->mRedEnd.GetVal(percent), fx->mGreenEnd.GetVal(percent), fx->mBlueEnd.GetVal(percent) ); + } + else + { + VectorSet( outStartRGB, fx->mRedStart.GetVal(), fx->mGreenStart.GetVal(), fx->mBlueStart.GetVal() ); + VectorSet( outEndRGB, fx->mRedEnd.GetVal(), fx->mGreenEnd.GetVal(), fx->mBlueEnd.GetVal() ); + } +} + +//------------------------------------------------------ +// PlayEffect +// Handles scheduling an effect so all the components +// happen at the specified time. Uses the specified axis +// +// Input: +// Effect id, the origin, and axis. +// Optional boltInfo (defaults to -1) +// Optional entity number to be used by a cheap entity origin bolt (defaults to -1) +// +// Return: +// none +//------------------------------------------------------ +void CFxScheduler::PlayEffect( int id, vec3_t origin, matrix3_t axis, const int boltInfo, CGhoul2Info_v *ghoul2, int fxParm /*-1*/, int vol, int rad, bool isPortal/*false*/, int iLoopTime/*0*/, bool isRelative ) +{ + SEffectTemplate *fx; + CPrimitiveTemplate *prim; + int i = 0; + int count = 0, delay = 0; + float factor = 0.0f, fxscale; + bool forceScheduling = false; + + if ( id < 1 || id >= FX_MAX_EFFECTS || !mEffectTemplates[id].mInUse ) + { + // Now you've done it! + ReportPlayEffectError(id); + return; + } + +#ifdef _DEBUG + // Don't bother scheduling the effect if the system is currently frozen + if ( fx_freeze->integer ) + { + return; + } +#endif + + int modelNum = 0, boltNum = -1; + int entityNum = -1; + + if ( boltInfo > 0 ) + { + // extract the wraith ID from the bolt info + modelNum = ( boltInfo >> MODEL_SHIFT ) & MODEL_AND; + boltNum = ( boltInfo >> BOLT_SHIFT ) & BOLT_AND; + entityNum = ( boltInfo >> ENTITY_SHIFT ) & ENTITY_AND; + + // We always force ghoul bolted objects to be scheduled so that they don't play right away. + forceScheduling = true; + + if (iLoopTime)//0 = not looping, 1 for infinite, else duration + {//store off the id to reschedule every frame + ScheduleLoopedEffect(id, boltInfo, ghoul2, !!isPortal, iLoopTime, isRelative); + } + } + + // Get the effect. + fx = &mEffectTemplates[id]; + +#ifndef FINAL_BUILD + if ( fx_debug->integer == 2 ) + { + Com_Printf( "> %s\n", fx->mEffectName); + } +#endif + + // Loop through the primitives and schedule each bit + for ( i = 0; i < fx->mPrimitiveCount; i++ ) + { + totalPrimitives++; + prim = fx->mPrimitives[i]; + + prim->mSoundRadius = rad; + prim->mSoundVolume = vol; + + if ( prim->mCullRange ) + { + if ( DistanceSquared( origin, theFxHelper.refdef->vieworg ) > prim->mCullRange ) // cullrange gets squared on load + { + // is too far away + continue; + } + } + + // Scale the particles based on the countscale factor. Never, ever scale the particles upwards, however. + fxscale = fx_countScale->value; + if (fxscale > 1.0) + { + fxscale = 1.0; + } + // Only use scalability if there is a range + // Temp fix until I have time to reweight all the scalability files + if(fabsf(prim->mSpawnCount.GetMax() - prim->mSpawnCount.GetMin()) > 1.0f) + { + count = Round(prim->mSpawnCount.GetVal() * fxscale); + } + else + { + count = Round(prim->mSpawnCount.GetVal()); + } + // Make sure we have at least one particle after scaling + if(prim->mSpawnCount.GetMin() >= 1.0f && count < 1) + { + count = 1; + } + + if ( prim->mCopy ) + { + // If we are a copy, we need to store a "how many references count" so that we + // can keep the primitive template around for the correct amount of time. + prim->mRefCount = count; + } + + if ( prim->mSpawnFlags & FX_EVEN_DISTRIBUTION ) + { + factor = abs(prim->mSpawnDelay.GetMax() - prim->mSpawnDelay.GetMin()) / (float)count; + } + + // Schedule the random number of bits + for ( int t = 0; t < count; t++ ) + { + totalEffects++; + if ( prim->mSpawnFlags & FX_EVEN_DISTRIBUTION ) + { + delay = t * factor; + } + else + { + delay = prim->mSpawnDelay.GetVal(); + } + + // if the delay is so small, we may as well just create this bit right now + if ( delay < 1 && !forceScheduling && !isPortal ) + { + if ( boltInfo == -1 && entityNum != -1 ) + { + // Find out where the entity currently is + TCGVectorData *data = (TCGVectorData*)cl.mSharedMemory; + + data->mEntityNum = entityNum; + CGVM_GetLerpOrigin(); + CreateEffect( prim, data->mPoint, axis, -delay, fxParm ); + } + else + { + CreateEffect( prim, origin, axis, -delay, fxParm ); + } + } + else + { + SScheduledEffect *sfx = mScheduledEffectsPool.Alloc(); + + if ( sfx == NULL ) + { + Com_Error (ERR_DROP, "ERROR: Failed to allocate EFX from memory pool."); + return; + } + + sfx->mStartTime = theFxHelper.mTime + delay; + sfx->mpTemplate = prim; + sfx->mIsRelative = isRelative; + sfx->mPortalEffect = isPortal; + + if ( boltInfo == -1 ) + { + sfx->ghoul2 = NULL; + if ( entityNum == -1 ) + { + // we aren't bolting, so make sure the spawn system knows this by putting -1's in these fields + sfx->mBoltNum = -1; + sfx->mEntNum = ENTITYNUM_NONE; + sfx->mModelNum = 0; + + if ( origin ) + { + VectorCopy( origin, sfx->mOrigin ); + } + else + { + VectorClear( sfx->mOrigin ); + } + + AxisCopy( axis, sfx->mAxis ); + } + else + { + // we are doing bolting onto the origin of the entity, so use a cheaper method + sfx->mBoltNum = -1; + sfx->mEntNum = entityNum; + sfx->mModelNum = 0; + + AxisCopy( axis, sfx->mAxis ); + } + } + else + { + // we are bolting, so store the extra info + sfx->mBoltNum = boltNum; + sfx->mEntNum = entityNum; + sfx->mModelNum = modelNum; + sfx->ghoul2 = ghoul2; + + // Also, the ghoul bolt may not be around yet, so delay the creation one frame + sfx->mStartTime++; + } + + mFxSchedule.push_front( sfx ); + } + } + } + + // We track effect templates and primitive templates separately. + if ( fx->mCopy ) + { + // We don't use dynamic memory allocation, so just mark us as dead + fx->mInUse = false; + } +} + +//------------------------------------------------------ +// PlayEffect +// Handles scheduling an effect so all the components +// happen at the specified time. Applies a default up +// axis. +// +// Input: +// Effect file name and the origin +// +// Return: +// none +//------------------------------------------------------ +/* +void CFxScheduler::PlayEffect( const char *file, vec3_t origin, int vol, int rad ) +{ + char sfile[MAX_QPATH]; + + // Get an extenstion stripped version of the file + COM_StripExtension( file, sfile, sizeof(sfile) ); + + PlayEffect( mEffectIDs[sfile], origin, vol, rad ); +} +*/ +//------------------------------------------------------ +// PlayEffect +// Handles scheduling an effect so all the components +// happen at the specified time. Takes a forward vector +// and uses this to complete the axis field. +// +// Input: +// Effect file name, the origin, and a forward vector +// +// Return: +// none +//------------------------------------------------------ +void CFxScheduler::PlayEffect( const char *file, vec3_t origin, vec3_t forward, int vol, int rad ) +{ + char sfile[MAX_QPATH]; + + // Get an extenstion stripped version of the file + COM_StripExtension( file, sfile, sizeof( sfile ) ); + + PlayEffect( mEffectIDs[sfile], origin, forward, vol, rad ); +} + +//------------------------------------------------------ +// AddScheduledEffects +// Handles determining if a scheduled effect should +// be created or not. If it should it handles converting +// the template effect into a real one. +// +// Input: +// none +// +// Return: +// none +//------------------------------------------------------ +bool gEffectsInPortal = qfalse; //this is just because I don't want to have to add an mPortalEffect field to every actual effect. + +void CFxScheduler::AddScheduledEffects( bool portal ) +{ + TScheduledEffect::iterator itr, next; + vec3_t origin; + matrix3_t axis; + int oldEntNum = -1, oldBoltIndex = -1, oldModelNum = -1; + qboolean doesBoltExist = qfalse; + + if (portal) + { + gEffectsInPortal = true; + } + else + { + AddLoopedEffects(); + } + + for ( itr = mFxSchedule.begin(); itr != mFxSchedule.end(); /* do nothing */ ) + { + SScheduledEffect *effect = *itr; + + if (portal == effect->mPortalEffect && effect->mStartTime <= theFxHelper.mTime ) + { //only render portal fx on the skyportal pass and vice versa + if (effect->mBoltNum == -1) + {// ok, are we spawning a bolt on effect or a normal one? + if ( effect->mEntNum != ENTITYNUM_NONE ) + { + // Find out where the entity currently is + TCGVectorData *data = (TCGVectorData*)cl.mSharedMemory; + + data->mEntityNum = effect->mEntNum; + CGVM_GetLerpOrigin(); + CreateEffect( effect->mpTemplate, + data->mPoint, effect->mAxis, + theFxHelper.mTime - effect->mStartTime ); + } + else + { + CreateEffect( effect->mpTemplate, + effect->mOrigin, effect->mAxis, + theFxHelper.mTime - effect->mStartTime ); + } + } + else + { //bolted on effect + // do we need to go and re-get the bolt matrix again? Since it takes time lets try to do it only once + if ((effect->mModelNum != oldModelNum) || + (effect->mEntNum != oldEntNum) || + (effect->mBoltNum != oldBoltIndex)) + { + oldModelNum = effect->mModelNum; + oldEntNum = effect->mEntNum; + oldBoltIndex = effect->mBoltNum; + + doesBoltExist = theFxHelper.GetOriginAxisFromBolt(effect->ghoul2, effect->mEntNum, effect->mModelNum, effect->mBoltNum, origin, axis); + } + + // only do this if we found the bolt + if (doesBoltExist) + { + if (effect->mIsRelative ) + { + CreateEffect( effect->mpTemplate, + origin, axis, 0, -1, + effect->ghoul2, effect->mEntNum, effect->mModelNum, effect->mBoltNum ); + } + else + { + CreateEffect( effect->mpTemplate, + origin, axis, + theFxHelper.mTime - effect->mStartTime ); + } + } + } + + mScheduledEffectsPool.Free (effect); + itr = mFxSchedule.erase(itr); + } + else + { + ++itr; + } + } + + // Add all active effects into the scene + FX_Add( !!portal ); + + gEffectsInPortal = false; +} + +bool CFxScheduler::Add2DEffect(float x, float y, float w, float h, vec4_t color, qhandle_t shaderHandle) +{ + // need some sort of scale here because the effect was created using world units, not pixels + float fxScale2D = 10.0f; + + if (mNextFree2DEffect < FX_MAX_2DEFFECTS) + { + m2DEffects[mNextFree2DEffect].mScreenX = x; + m2DEffects[mNextFree2DEffect].mScreenY = y; + m2DEffects[mNextFree2DEffect].mWidth = w*fxScale2D; + m2DEffects[mNextFree2DEffect].mHeight = h*fxScale2D; + VectorCopy4(color, m2DEffects[mNextFree2DEffect].mColor); + m2DEffects[mNextFree2DEffect].mShaderHandle = shaderHandle; + + mNextFree2DEffect++; + return true; + } + return false; +} + +void CFxScheduler::Draw2DEffects(float screenXScale, float screenYScale) +{ + float x = 0, y = 0, w = 0, h = 0; + + for (int i = 0; i < mNextFree2DEffect; i++) + { + x = m2DEffects[i].mScreenX; + y = m2DEffects[i].mScreenY; + w = m2DEffects[i].mWidth; + h = m2DEffects[i].mHeight; + + x *= screenXScale; + w *= screenXScale; + y *= screenYScale; + h *= screenYScale; + + //allow 2d effect coloring? + re->DrawStretchPic(x - (w*0.5f), y - (h*0.5f), w, h, 0, 0, 1, 1, /*m2DEffects[i].mColor,*/ m2DEffects[i].mShaderHandle); + } + // now that all 2D effects have been drawn we can consider the entire array to be free + mNextFree2DEffect = 0; +} + +//------------------------------------------------------ +// CreateEffect +// Creates the specified fx taking into account the +// multitude of different ways it could be spawned. +// +// Input: +// template used to build the effect, desired effect origin, +// desired orientation and how late the effect is so that +// it can be moved to the correct spot +// +// Return: +// none +//------------------------------------------------------ +void CFxScheduler::CreateEffect( CPrimitiveTemplate *fx, const vec3_t origin, matrix3_t axis, int lateTime, int fxParm /*-1*/, CGhoul2Info_v *ghoul2, int entNum, int modelNum, int boltNum ) +{ + vec3_t org, org2, temp, + vel, accel, + sRGB, eRGB, + ang, angDelta, + ax[3]; + trace_t tr; + int emitterModel; + + // We may modify the axis, so make a work copy + AxisCopy( axis, ax ); + + int flags = fx->mFlags; + if (ghoul2 != NULL && modelNum>=0 && boltNum>=0) + {//since you passed in these values, mark as relative to use them if it is supported + switch( fx->mType ) + { + case Particle: + case Line: + case Tail: + case Electricity: + case Cylinder: + case Emitter: + case OrientedParticle: + case Light: + flags |= FX_RELATIVE; + break; + case Decal: + case FxRunner: + case ScreenFlash: + //not supported yet + case Sound: + case CameraShake: + //does not work bolted + break; + default: + break; + } + } + + if( fx->mSpawnFlags & FX_RAND_ROT_AROUND_FWD ) + { + RotatePointAroundVector( ax[1], ax[0], axis[1], flrand(0.0f, 360.0f) ); + CrossProduct( ax[0], ax[1], ax[2] ); + } + + // Origin calculations + //------------------------------------- + if ( fx->mSpawnFlags & FX_CHEAP_ORG_CALC || flags & FX_RELATIVE ) + { // let's take the easy way out + VectorSet( org, fx->mOrigin1X.GetVal(), fx->mOrigin1Y.GetVal(), fx->mOrigin1Z.GetVal() ); + } + else + { // time for some extra work + VectorScale( ax[0], fx->mOrigin1X.GetVal(), org ); + VectorMA( org, fx->mOrigin1Y.GetVal(), ax[1], org ); + VectorMA( org, fx->mOrigin1Z.GetVal(), ax[2], org ); + } + + // We always add our calculated offset to the passed in origin, unless relative! + if( !(flags & FX_RELATIVE) ) + { + VectorAdd( org, origin, org ); + } + // Now, we may need to calc a point on a sphere/ellipsoid/cylinder/disk and add that to it + //---------------------------------------------------------------- + if ( fx->mSpawnFlags & FX_ORG_ON_SPHERE ) + { + float x, y; + float width, height; + + x = DEG2RAD( flrand(0.0f, 360.0f) ); + y = DEG2RAD( flrand(0.0f, 180.0f) ); + + width = fx->mRadius.GetVal(); + height = fx->mHeight.GetVal(); + + // calculate point on ellipse + VectorSet( temp, sin(x) * width * sin(y), cos(x) * width * sin(y), cos(y) * height ); // sinx * siny, cosx * siny, cosy + VectorAdd( org, temp, org ); + + if ( fx->mSpawnFlags & FX_AXIS_FROM_SPHERE ) + { + // well, we will now override the axis at the users request + VectorNormalize2( temp, ax[0] ); + MakeNormalVectors( ax[0], ax[1], ax[2] ); + } + } + else if ( fx->mSpawnFlags & FX_ORG_ON_CYLINDER ) + { + vec3_t pt; + + // set up our point, then rotate around the current direction to. Make unrotated cylinder centered around 0,0,0 + VectorScale( ax[1], fx->mRadius.GetVal(), pt ); + VectorMA( pt, flrand(-1.0f, 1.0f) * 0.5f * fx->mHeight.GetVal(), ax[0], pt ); + RotatePointAroundVector( temp, ax[0], pt, flrand(0.0f, 360.0f) ); + + VectorAdd( org, temp, org ); + + if ( fx->mSpawnFlags & FX_AXIS_FROM_SPHERE ) + { + vec3_t up={0,0,1}; + + // well, we will now override the axis at the users request + VectorNormalize2( temp, ax[0] ); + + if ( ax[0][2] == 1.0f ) + { + // readjust up + VectorSet( up, 0, 1, 0 ); + } + + CrossProduct( up, ax[0], ax[1] ); + CrossProduct( ax[0], ax[1], ax[2] ); + } + } + + if ( fx->mType == OrientedParticle ) + {//bolted oriented particles use origin2 as an angular rotation offset... + if ( flags & FX_RELATIVE ) + { + VectorSet( ax[0], fx->mOrigin2X.GetVal(), fx->mOrigin2Y.GetVal(), fx->mOrigin2Z.GetVal() ); + } + } + + // There are only a few types that really use velocity and acceleration, so do extra work for those types + //-------------------------------------------------------------------------------------------------------- + if ( fx->mType == Particle || fx->mType == OrientedParticle || fx->mType == Tail || fx->mType == Emitter ) + { + // Velocity calculations + //------------------------------------- + if ( fx->mSpawnFlags & FX_VEL_IS_ABSOLUTE || flags & FX_RELATIVE ) + { + VectorSet( vel, fx->mVelX.GetVal(), fx->mVelY.GetVal(), fx->mVelZ.GetVal() ); + } + else + { // bah, do some extra work to coerce it + VectorScale( ax[0], fx->mVelX.GetVal(), vel ); + VectorMA( vel, fx->mVelY.GetVal(), ax[1], vel ); + VectorMA( vel, fx->mVelZ.GetVal(), ax[2], vel ); + } + + //------------------------------------- + if ( fx->mSpawnFlags & FX_AFFECTED_BY_WIND ) + { +/*rjr vec3_t wind; + + // wind is affecting us, so modify our initial velocity. ideally, we would update throughout our lives, but this is easier + CL_GetWindVector( wind ); + VectorMA( vel, fx->mWindModifier.GetVal() * 0.01f, wind, vel ); + */ + } + + // Acceleration calculations + //------------------------------------- + if ( fx->mSpawnFlags & FX_ACCEL_IS_ABSOLUTE || flags & FX_RELATIVE ) + { + VectorSet( accel, fx->mAccelX.GetVal(), fx->mAccelY.GetVal(), fx->mAccelZ.GetVal() ); + } + else + { + VectorScale( ax[0], fx->mAccelX.GetVal(), accel ); + VectorMA( accel, fx->mAccelY.GetVal(), ax[1], accel ); + VectorMA( accel, fx->mAccelZ.GetVal(), ax[2], accel ); + } + + // Gravity is completely decoupled from acceleration since it is __always__ absolute + // NOTE: I only effect Z ( up/down in the Quake world ) + accel[2] += fx->mGravity.GetVal(); + + // There may be a lag between when the effect should be created and when it actually gets created. + // Since we know what the discrepancy is, we can attempt to compensate... + if ( lateTime > 0 ) + { + // Calc the time differences + float ftime = lateTime * 0.001f; + float time2 = ftime * ftime * 0.5f; + + VectorMA( vel, ftime, accel, vel ); + + // Predict the new position + for ( int i = 0 ; i < 3 ; i++ ) + { + org[i] = org[i] + ftime * vel[i] + time2 * vel[i]; + } + } + } // end moving types + + // Line type primitives work with an origin2, so do the extra work for them + //-------------------------------------------------------------------------- + if ( fx->mType == Line || fx->mType == Electricity ) + { + // We may have to do a trace to find our endpoint + if ( fx->mSpawnFlags & FX_ORG2_FROM_TRACE ) + { + VectorMA( org, FX_MAX_TRACE_DIST, ax[0], temp ); + + if ( fx->mSpawnFlags & FX_ORG2_IS_OFFSET ) + { // add a random flair to the endpoint...note: org2 will have to be pretty large to affect this much + // we also do this pre-trace as opposed to post trace since we may have to render an impact effect + // and we will want the normal at the exact endpos... + if ( fx->mSpawnFlags & FX_CHEAP_ORG2_CALC || flags & FX_RELATIVE ) + { + VectorSet( org2, fx->mOrigin2X.GetVal(), fx->mOrigin2Y.GetVal(), fx->mOrigin2Z.GetVal() ); + VectorAdd( org2, temp, temp ); + } + else + { // I can only imagine a few cases where you might want to do this... + VectorMA( temp, fx->mOrigin2X.GetVal(), ax[0], temp ); + VectorMA( temp, fx->mOrigin2Y.GetVal(), ax[1], temp ); + VectorMA( temp, fx->mOrigin2Z.GetVal(), ax[2], temp ); + } + } + + theFxHelper.Trace( tr, org, NULL, NULL, temp, -1, MASK_SOLID ); + + VectorCopy( tr.endpos, org2 ); + + if ( fx->mSpawnFlags & FX_TRACE_IMPACT_FX ) + { + PlayEffect( fx->mImpactFxHandles.GetHandle(), org2, tr.plane.normal ); + } + } + else + { + if ( fx->mSpawnFlags & FX_CHEAP_ORG2_CALC || flags & FX_RELATIVE ) + { + VectorSet( org2, fx->mOrigin2X.GetVal(), fx->mOrigin2Y.GetVal(), fx->mOrigin2Z.GetVal() ); + } + else + { + VectorScale( ax[0], fx->mOrigin2X.GetVal(), org2 ); + VectorMA( org2, fx->mOrigin2Y.GetVal(), ax[1], org2 ); + VectorMA( org2, fx->mOrigin2Z.GetVal(), ax[2], org2 ); + } + if( !(flags & FX_RELATIVE) ) + { + VectorAdd( org2, origin, org2 ); + } + } + } // end special org2 types + + // handle RGB color, but only for types that will use it + //--------------------------------------------------------------------------- + if ( fx->mType != Sound && fx->mType != FxRunner && fx->mType != CameraShake ) + { + GetRGB_Colors( fx, sRGB, eRGB ); + } + + // Now create the appropriate effect entity + //------------------------ + switch( fx->mType ) + { + //--------- + case Particle: + //--------- + + FX_AddParticle( org, vel, accel, + fx->mSizeStart.GetVal(), fx->mSizeEnd.GetVal(), fx->mSizeParm.GetVal(), + fx->mAlphaStart.GetVal(), fx->mAlphaEnd.GetVal(), fx->mAlphaParm.GetVal(), + sRGB, eRGB, fx->mRGBParm.GetVal(), + fx->mRotation.GetVal(), fx->mRotationDelta.GetVal(), + fx->mMin, fx->mMax, fx->mElasticity.GetVal(), + fx->mDeathFxHandles.GetHandle(), fx->mImpactFxHandles.GetHandle(), + fx->mLife.GetVal(), fx->mMediaHandles.GetHandle(), flags, fx->mMatImpactFX, fxParm, + ghoul2, entNum, modelNum, boltNum ); + break; + + //--------- + case Line: + //--------- + + FX_AddLine( org, org2, + fx->mSizeStart.GetVal(), fx->mSizeEnd.GetVal(), fx->mSizeParm.GetVal(), + fx->mAlphaStart.GetVal(), fx->mAlphaEnd.GetVal(), fx->mAlphaParm.GetVal(), + sRGB, eRGB, fx->mRGBParm.GetVal(), + fx->mLife.GetVal(), fx->mMediaHandles.GetHandle(), flags, fx->mMatImpactFX, fxParm, + ghoul2, entNum, modelNum, boltNum); + break; + + //--------- + case Tail: + //--------- + + FX_AddTail( org, vel, accel, + fx->mSizeStart.GetVal(), fx->mSizeEnd.GetVal(), fx->mSizeParm.GetVal(), + fx->mLengthStart.GetVal(), fx->mLengthEnd.GetVal(), fx->mLengthParm.GetVal(), + fx->mAlphaStart.GetVal(), fx->mAlphaEnd.GetVal(), fx->mAlphaParm.GetVal(), + sRGB, eRGB, fx->mRGBParm.GetVal(), + fx->mMin, fx->mMax, fx->mElasticity.GetVal(), + fx->mDeathFxHandles.GetHandle(), fx->mImpactFxHandles.GetHandle(), + fx->mLife.GetVal(), fx->mMediaHandles.GetHandle(), flags, fx->mMatImpactFX, fxParm, + ghoul2, entNum, modelNum, boltNum); + break; + + //---------------- + case Electricity: + //---------------- + + FX_AddElectricity( org, org2, + fx->mSizeStart.GetVal(), fx->mSizeEnd.GetVal(), fx->mSizeParm.GetVal(), + fx->mAlphaStart.GetVal(), fx->mAlphaEnd.GetVal(), fx->mAlphaParm.GetVal(), + sRGB, eRGB, fx->mRGBParm.GetVal(), + fx->mElasticity.GetVal(), fx->mLife.GetVal(), fx->mMediaHandles.GetHandle(), flags, + fx->mMatImpactFX, fxParm, + ghoul2, entNum, modelNum, boltNum); + break; + + //--------- + case Cylinder: + //--------- + + FX_AddCylinder( org, ax[0], + fx->mSizeStart.GetVal(), fx->mSizeEnd.GetVal(), fx->mSizeParm.GetVal(), + fx->mSize2Start.GetVal(), fx->mSize2End.GetVal(), fx->mSize2Parm.GetVal(), + fx->mLengthStart.GetVal(), fx->mLengthEnd.GetVal(), fx->mLengthParm.GetVal(), + fx->mAlphaStart.GetVal(), fx->mAlphaEnd.GetVal(), fx->mAlphaParm.GetVal(), + sRGB, eRGB, fx->mRGBParm.GetVal(), + fx->mLife.GetVal(), fx->mMediaHandles.GetHandle(), flags, fx->mMatImpactFX, fxParm, + ghoul2, entNum, modelNum, boltNum, + (qboolean)( fx->mSpawnFlags & FX_ORG2_FROM_TRACE )); + break; + + //--------- + case Emitter: + //--------- + + // for chunk angles, you don't really need much control over the end result...you just want variation.. + VectorSet( ang, + fx->mAngle1.GetVal(), + fx->mAngle2.GetVal(), + fx->mAngle3.GetVal() ); + + vectoangles( ax[0], temp ); + VectorAdd( ang, temp, ang ); + + VectorSet( angDelta, + fx->mAngle1Delta.GetVal(), + fx->mAngle2Delta.GetVal(), + fx->mAngle3Delta.GetVal() ); + + emitterModel = fx->mMediaHandles.GetHandle(); + + FX_AddEmitter( org, vel, accel, + fx->mSizeStart.GetVal(), fx->mSizeEnd.GetVal(), fx->mSizeParm.GetVal(), + fx->mAlphaStart.GetVal(), fx->mAlphaEnd.GetVal(), fx->mAlphaParm.GetVal(), + sRGB, eRGB, fx->mRGBParm.GetVal(), + ang, angDelta, + fx->mMin, fx->mMax, fx->mElasticity.GetVal(), + fx->mDeathFxHandles.GetHandle(), fx->mImpactFxHandles.GetHandle(), + fx->mEmitterFxHandles.GetHandle(), + fx->mDensity.GetVal(), fx->mVariance.GetVal(), + fx->mLife.GetVal(), emitterModel, flags, fx->mMatImpactFX, fxParm ); + break; + + //--------- + case Decal: + //--------- + +/* rjr + // This function is a somewhat higher-cost function for projecting a decal mark onto a surface. + // We shouldn't always need this, only for big hits or when a decal is very close-up. + + // If the impact size is greater than 6, don't even try to use cheap sprites. Big marks need real decals. + if (fx->mSizeStart.GetVal()<6) + { + vec3_t dest, normal; + int findmarkret; + + findmarkret = CG_FindMark(org, ax[0], dest, normal); + + if (findmarkret) + { // Legal to put down a mark. + + if ( findmarkret == FINDMARK_CHEAP || // If we can't put down a decal OR if and distance > 200 + DistanceSquared( dest, cg.refdef.vieworg ) > 40000) + { // Use cheap oriented particle decals. + vec3_t zerovec={0,0,0}; + + FX_AddOrientedParticle( effectCloud, org, ax[0], + zerovec, // velocity + zerovec, // acceleration + fx->mSizeStart.GetVal(), fx->mSizeStart.GetVal(), 0, // size params + fx->mAlphaStart.GetVal(), 0, 0.75, // alpha params (start fading at 75% life) + sRGB, sRGB, 0, // rgb params + fx->mRotation.GetVal(), 0, // rotation delta + zerovec, // min + zerovec, // max + 0, // bounce + 0, // deathID + 0, // impactID + 20000, // lifetime + fx->mMediaHandles.GetHandle(), + (fx->mFlags&~FX_ALPHA_PARM_MASK)|FX_ALPHA_NONLINEAR, + MATIMPACTFX_NONE, -1); + } + else + { // Use the expensive kind. + color.rgba.r = sRGB[0] * 0xff; + color.rgba.g = sRGB[1] * 0xff; + color.rgba.b = sRGB[2] * 0xff; + color.rgba.a = fx->mAlphaStart.GetVal() * 0xff; + + CG_ImpactMark( fx->mMediaHandles.GetHandle(), org, ax[0], + fx->mRotation.GetVal(), color.c, 12000, 8000, + true, fx->mSizeStart.GetVal(), false ); + } + } + } + else + { // Use the expensive kind. + color.rgba.r = sRGB[0] * 0xff; + color.rgba.g = sRGB[1] * 0xff; + color.rgba.b = sRGB[2] * 0xff; + color.rgba.a = fx->mAlphaStart.GetVal() * 0xff; + + CG_ImpactMark( fx->mMediaHandles.GetHandle(), org, ax[0], + fx->mRotation.GetVal(), color.c, 12000, 8000, + true, fx->mSizeStart.GetVal(), false ); + } */ + + theFxHelper.AddDecalToScene ( fx->mMediaHandles.GetHandle(), org, ax[0], fx->mRotation.GetVal(), sRGB[0], sRGB[1], sRGB[2], fx->mAlphaStart.GetVal(), qtrue, fx->mSizeStart.GetVal(), qfalse ); + + if (fx->mFlags & FX_GHOUL2_DECALS) + { + theFxHelper.AddGhoul2Decal(fx->mMediaHandles.GetHandle(), org, ax[0], fx->mSizeStart.GetVal()); + } + + break; + + //------------------- + case OrientedParticle: + //------------------- + + FX_AddOrientedParticle( org, ax[0], vel, accel, + fx->mSizeStart.GetVal(), fx->mSizeEnd.GetVal(), fx->mSizeParm.GetVal(), + fx->mAlphaStart.GetVal(), fx->mAlphaEnd.GetVal(), fx->mAlphaParm.GetVal(), + sRGB, eRGB, fx->mRGBParm.GetVal(), + fx->mRotation.GetVal(), fx->mRotationDelta.GetVal(), + fx->mMin, fx->mMax, fx->mElasticity.GetVal(), + fx->mDeathFxHandles.GetHandle(), fx->mImpactFxHandles.GetHandle(), + fx->mLife.GetVal(), fx->mMediaHandles.GetHandle(), flags, fx->mMatImpactFX, fxParm, + ghoul2, entNum, modelNum, boltNum); + break; + + //--------- + case Sound: + //--------- + if (gEffectsInPortal) + { //could orient this anyway for panning, but eh. It's going to appear to the player in the sky the same place no matter what, so just make it a local sound. + theFxHelper.PlayLocalSound( fx->mMediaHandles.GetHandle(), CHAN_AUTO ); + } + else + { + theFxHelper.PlaySound( org, ENTITYNUM_NONE, CHAN_AUTO, fx->mMediaHandles.GetHandle(), fx->mSoundVolume, fx->mSoundRadius ); + } + break; + + //--------- + case FxRunner: + //--------- + + PlayEffect( fx->mPlayFxHandles.GetHandle(), org, ax ); + break; + + //--------- + case Light: + //--------- + + FX_AddLight( org, fx->mSizeStart.GetVal(), fx->mSizeEnd.GetVal(), fx->mSizeParm.GetVal(), + sRGB, eRGB, fx->mRGBParm.GetVal(), + fx->mLife.GetVal(), flags, fx->mMatImpactFX, fxParm, + ghoul2, entNum, modelNum, boltNum); + break; + + //--------- + case CameraShake: + //--------- + // It calculates how intense the shake should be based on how close you are to the origin you pass in here + // elasticity is actually the intensity...radius is the distance in which the shake will have some effect + // life is how long the effect lasts. + theFxHelper.CameraShake( org, fx->mElasticity.GetVal(), fx->mRadius.GetVal(), fx->mLife.GetVal() ); + break; + + //-------------- + case ScreenFlash: + //-------------- + + FX_AddFlash( org, fx->mSizeStart.GetVal(), fx->mSizeEnd.GetVal(), fx->mSizeParm.GetVal(), + fx->mAlphaStart.GetVal(), fx->mAlphaEnd.GetVal(), fx->mAlphaParm.GetVal(), + sRGB, eRGB, fx->mRGBParm.GetVal(), + fx->mLife.GetVal(), fx->mMediaHandles.GetHandle(), flags, fx->mMatImpactFX, fxParm ); + break; + + default: + assert(0); + break; + } + + // Track when we need to clean ourselves up if we are a copy + if ( fx->mCopy ) + { + fx->mRefCount--; + + if ( fx->mRefCount <= 0 ) + { + delete fx; + } + } +} + +//------------------------------------------------------ +// CreateEffect +// Creates the fx_runner +// +// Input: +// template used to build the effect, and the scheduled effect we are based off of +// +// Return: +// none +//------------------------------------------------------ +void CFxScheduler::CreateEffect( CPrimitiveTemplate *fx, SScheduledEffect *scheduledFx ) +{ + int boltInfo; + + // annoying bit....we have to pack the values back into an int before calling playEffect since there isn't the ideal overload we can already use. + boltInfo = (( scheduledFx->mModelNum & MODEL_AND ) << MODEL_SHIFT ); + boltInfo |= (( scheduledFx->mBoltNum & BOLT_AND ) << BOLT_SHIFT ); + boltInfo |= (( scheduledFx->mEntNum & ENTITY_AND ) << ENTITY_SHIFT ); + + PlayEffect( fx->mPlayFxHandles.GetHandle(), scheduledFx->mOrigin, scheduledFx->mAxis, boltInfo ); +} + diff --git a/Projects/Android/jni/OpenJK/codemp_delete/client/FxScheduler.h b/Projects/Android/jni/OpenJK/codemp_delete/client/FxScheduler.h new file mode 100644 index 0000000..73b23e8 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/client/FxScheduler.h @@ -0,0 +1,684 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#pragma once + +#include "FxUtil.h" +#include "qcommon/GenericParser2.h" + +#include +#include +#include +#include +#include + +#define FX_FILE_PATH "effects" + +#define FX_MAX_TRACE_DIST 16384 // SOF2 uses a larger scale +#define FX_MAX_EFFECTS 256 // how many effects the system can store +#define FX_MAX_2DEFFECTS 64 // how many 2d effects the system can store +#define FX_MAX_EFFECT_COMPONENTS 24 // how many primitives an effect can hold, this should be plenty +#define FX_MAX_PRIM_NAME 32 + +//----------------------------------------------- +// These are spawn flags for primitiveTemplates +//----------------------------------------------- + +#define FX_ORG_ON_SPHERE 0x00001 // Pretty dang expensive, calculates a point on a sphere/ellipsoid +#define FX_AXIS_FROM_SPHERE 0x00002 // Can be used in conjunction with org_on_sphere to cause particles to move out + // from the center of the sphere +#define FX_ORG_ON_CYLINDER 0x00004 // calculate point on cylinder/disk + +#define FX_ORG2_FROM_TRACE 0x00010 +#define FX_TRACE_IMPACT_FX 0x00020 // if trace impacts, we should play one of the specified impact fx files +#define FX_ORG2_IS_OFFSET 0x00040 // template specified org2 should be the offset from a trace endpos or + // passed in org2. You might use this to lend a random flair to the endpos. + // Note: this is done pre-trace, so you may have to specify large numbers for this + +#define FX_CHEAP_ORG_CALC 0x00100 // Origin is calculated relative to passed in axis unless this is on. +#define FX_CHEAP_ORG2_CALC 0x00200 // Origin2 is calculated relative to passed in axis unless this is on. +#define FX_VEL_IS_ABSOLUTE 0x00400 // Velocity isn't relative to passed in axis with this flag on. +#define FX_ACCEL_IS_ABSOLUTE 0x00800 // Acceleration isn't relative to passed in axis with this flag on. + +#define FX_RAND_ROT_AROUND_FWD 0x01000 // Randomly rotates up and right around forward vector +#define FX_EVEN_DISTRIBUTION 0x02000 // When you have a delay, it normally picks a random time to play. When + // this flag is on, it generates an even time distribution +#define FX_RGB_COMPONENT_INTERP 0x04000 // Picks a color on the line defined by RGB min & max, default is to pick color in cube defined by min & max + +#define FX_AFFECTED_BY_WIND 0x10000 // this effect primitive needs to query wind + +//----------------------------------------------------------------- +// +// CMediaHandles +// +// Primitive templates might want to use a list of sounds, shaders +// or models to get a bit more variation in their effects. +// +//----------------------------------------------------------------- +class CMediaHandles +{ +private: + + std::vector mMediaList; + +public: + + void AddHandle( int item ) { mMediaList.push_back( item ); } + int GetHandle() { if (mMediaList.size()==0) {return 0;} + else {return mMediaList[irand(0,(int)mMediaList.size()-1)];} } + + CMediaHandles &operator=(const CMediaHandles &that ); +}; + + +//----------------------------------------------------------------- +// +// CFxRange +// +// Primitive templates typically use this class to define each of +// its members. This is done to make it easier to create effects +// with a desired range of characteristics. +// +//----------------------------------------------------------------- +class CFxRange +{ +private: + + float mMin; + float mMax; + +public: + + CFxRange(void) { mMin = 0.0f; mMax = 0.0f; } + + inline void SetRange(float min,float max) { mMin = min; mMax = max; } + + inline float GetMax(void) const { return mMax; } + inline float GetMin(void) const { return mMin; } + inline float GetVal(float fraction) const { if(mMin != mMax) { return mMin + fraction * (mMax - mMin); } else { return mMin; } } + inline float GetVal(void) const { if(mMin != mMax) { return flrand(mMin,mMax); } else { return mMin; } } + + inline int GetRoundedVal() const {if(mMin == mMax){return (int)mMin;} + return (int)(flrand(mMin, mMax) + 0.5f);} + + bool operator==(const CFxRange &rhs) const { return ((mMin == rhs.mMin) && (mMax == rhs.mMax)); } +}; + + +//---------------------------- +// Supported primitive types +//---------------------------- + +enum EPrimType +{ + None = 0, + Particle, // sprite + Line, + Tail, // comet-like tail thing + Cylinder, + Emitter, // emits effects as it moves, can also attach a chunk + Sound, + Decal, // projected onto architecture + OrientedParticle, + Electricity, + FxRunner, + Light, + CameraShake, + ScreenFlash +}; + + +//----------------------------------------------------------------- +// +// CPrimitiveTemplate +// +// The primitive template is used to spawn 1 or more fx primitives +// with the range of characteristics defined by the template. +// +// As such, I just made this one huge shared class knowing that +// there won't be many of them in memory at once, and we won't +// be dynamically creating and deleting them mid-game. Also, +// note that not every primitive type will use all of these fields. +// +//----------------------------------------------------------------- +class CPrimitiveTemplate +{ + +public: + + // These kinds of things should not even be allowed to be accessed publicly + bool mCopy; + int mRefCount; // For a copy of a primitive...when we figure out how many items we want to spawn, + // we'll store that here and then decrement us for each we actually spawn. When we + // hit zero, we are no longer used and so we can just free ourselves + + char mName[FX_MAX_PRIM_NAME]; + + EPrimType mType; + + CFxRange mSpawnDelay; + CFxRange mSpawnCount; + CFxRange mLife; + int mCullRange; + + CMediaHandles mMediaHandles; + CMediaHandles mImpactFxHandles; + CMediaHandles mDeathFxHandles; + CMediaHandles mEmitterFxHandles; + CMediaHandles mPlayFxHandles; + + int mFlags; // These need to get passed on to the primitive + int mSpawnFlags; // These are only used to control spawning, but never get passed to prims. + + EMatImpactEffect mMatImpactFX; + + vec3_t mMin; + vec3_t mMax; + + CFxRange mOrigin1X; + CFxRange mOrigin1Y; + CFxRange mOrigin1Z; + + CFxRange mOrigin2X; + CFxRange mOrigin2Y; + CFxRange mOrigin2Z; + + CFxRange mRadius; // spawn on sphere/ellipse/disk stuff. + CFxRange mHeight; + CFxRange mWindModifier; + + CFxRange mRotation; + CFxRange mRotationDelta; + + CFxRange mAngle1; + CFxRange mAngle2; + CFxRange mAngle3; + + CFxRange mAngle1Delta; + CFxRange mAngle2Delta; + CFxRange mAngle3Delta; + + CFxRange mVelX; + CFxRange mVelY; + CFxRange mVelZ; + + CFxRange mAccelX; + CFxRange mAccelY; + CFxRange mAccelZ; + + CFxRange mGravity; + + CFxRange mDensity; + CFxRange mVariance; + + CFxRange mRedStart; + CFxRange mGreenStart; + CFxRange mBlueStart; + + CFxRange mRedEnd; + CFxRange mGreenEnd; + CFxRange mBlueEnd; + + CFxRange mRGBParm; + + CFxRange mAlphaStart; + CFxRange mAlphaEnd; + CFxRange mAlphaParm; + + CFxRange mSizeStart; + CFxRange mSizeEnd; + CFxRange mSizeParm; + + CFxRange mSize2Start; + CFxRange mSize2End; + CFxRange mSize2Parm; + + CFxRange mLengthStart; + CFxRange mLengthEnd; + CFxRange mLengthParm; + + CFxRange mTexCoordS; + CFxRange mTexCoordT; + + CFxRange mElasticity; + + int mSoundRadius; + int mSoundVolume; + + // Lower level parsing utilities + bool ParseVector( const char *val, vec3_t min, vec3_t max ); + bool ParseFloat( const char *val, float *min, float *max ); + bool ParseGroupFlags( const char *val, int *flags ); + + // Base key processing + // Note that these all have their own parse functions in case it becomes important to do certain kinds + // of validation specific to that type. + bool ParseMin( const char *val ); + bool ParseMax( const char *val ); + bool ParseDelay( const char *val ); + bool ParseCount( const char *val ); + bool ParseLife( const char *val ); + bool ParseElasticity( const char *val ); + bool ParseFlags( const char *val ); + bool ParseSpawnFlags( const char *val ); + + bool ParseOrigin1( const char *val ); + bool ParseOrigin2( const char *val ); + bool ParseRadius( const char *val ); + bool ParseHeight( const char *val ); + bool ParseWindModifier( const char *val ); + bool ParseRotation( const char *val ); + bool ParseRotationDelta( const char *val ); + bool ParseAngle( const char *val ); + bool ParseAngleDelta( const char *val ); + bool ParseVelocity( const char *val ); + bool ParseAcceleration( const char *val ); + bool ParseGravity( const char *val ); + bool ParseDensity( const char *val ); + bool ParseVariance( const char *val ); + + // Group type processing + bool ParseRGB( CGPGroup *grp ); + bool ParseAlpha( CGPGroup *grp ); + bool ParseSize( CGPGroup *grp ); + bool ParseSize2( CGPGroup *grp ); + bool ParseLength( CGPGroup *grp ); + + bool ParseModels( CGPValue *grp ); + bool ParseShaders( CGPValue *grp ); + bool ParseSounds( CGPValue *grp ); + + bool ParseImpactFxStrings( CGPValue *grp ); + bool ParseDeathFxStrings( CGPValue *grp ); + bool ParseEmitterFxStrings( CGPValue *grp ); + bool ParsePlayFxStrings( CGPValue *grp ); + + // Group keys + bool ParseRGBStart( const char *val ); + bool ParseRGBEnd( const char *val ); + bool ParseRGBParm( const char *val ); + bool ParseRGBFlags( const char *val ); + + bool ParseAlphaStart( const char *val ); + bool ParseAlphaEnd( const char *val ); + bool ParseAlphaParm( const char *val ); + bool ParseAlphaFlags( const char *val ); + + bool ParseSizeStart( const char *val ); + bool ParseSizeEnd( const char *val ); + bool ParseSizeParm( const char *val ); + bool ParseSizeFlags( const char *val ); + + bool ParseSize2Start( const char *val ); + bool ParseSize2End( const char *val ); + bool ParseSize2Parm( const char *val ); + bool ParseSize2Flags( const char *val ); + + bool ParseLengthStart( const char *val ); + bool ParseLengthEnd( const char *val ); + bool ParseLengthParm( const char *val ); + bool ParseLengthFlags( const char *val ); + + bool ParseMaterialImpact(const char *val); + +public: + + CPrimitiveTemplate(); + ~CPrimitiveTemplate() {}; + + bool ParsePrimitive( CGPGroup *grp ); + + CPrimitiveTemplate &operator=(const CPrimitiveTemplate &that); +}; + +// forward declaration +struct SEffectTemplate; + +// Effects are built of one or more primitives +struct SEffectTemplate +{ + bool mInUse; + bool mCopy; + char mEffectName[MAX_QPATH]; // is this extraneous?? + int mPrimitiveCount; + int mRepeatDelay; + CPrimitiveTemplate *mPrimitives[FX_MAX_EFFECT_COMPONENTS]; + + bool operator == (const char * name) const + { + return !Q_stricmp( mEffectName, name ); + } + SEffectTemplate &operator=(const SEffectTemplate &that); +}; + +template +class PoolAllocator +{ +public: + PoolAllocator() + : pool (new T[N]) + , freeAndAllocated (new int[N]) + , numFree (N) + , highWatermark (0) + { + for ( int i = 0; i < N; i++ ) + { + freeAndAllocated[i] = i; + } + } + + T *Alloc() + { + if ( numFree == 0 ) + { + return NULL; + } + + T *ptr = new (&pool[freeAndAllocated[0]]) T; + + std::rotate (freeAndAllocated, freeAndAllocated + 1, freeAndAllocated + N); + numFree--; + + highWatermark = Q_max(highWatermark, N - numFree); + + return ptr; + } + + void TransferTo ( PoolAllocator& allocator ) + { + allocator.freeAndAllocated = freeAndAllocated; + allocator.highWatermark = highWatermark; + allocator.numFree = numFree; + allocator.pool = pool; + + highWatermark = 0; + numFree = N; + freeAndAllocated = NULL; + pool = NULL; + } + + bool OwnsPtr ( const T *ptr ) const + { + return ptr >= pool && ptr < (pool + N); + } + + void Free ( T *ptr ) + { + for ( int i = numFree; i < N; i++ ) + { + T *p = &pool[freeAndAllocated[i]]; + + if ( p == ptr ) + { + if ( i > numFree ) + { + std::rotate (freeAndAllocated + numFree, freeAndAllocated + i, freeAndAllocated + i + 1); + } + + p->~T(); + numFree++; + + break; + } + } + } + + int GetHighWatermark() const { return highWatermark; } + + ~PoolAllocator() + { + for ( int i = numFree; i < N; i++ ) + { + T *p = &pool[freeAndAllocated[i]]; + + p->~T(); + } + + delete [] freeAndAllocated; + delete [] pool; + } + +private: + PoolAllocator ( const PoolAllocator& ); + PoolAllocator& operator = ( const PoolAllocator& ); + + T *pool; + + // The first 'numFree' elements are the indexes of the free slots. + // The remaining elements are the indexes of the allocated slots. + int *freeAndAllocated; + int numFree; + + int highWatermark; +}; + +template +class PagedPoolAllocator +{ + public: + PagedPoolAllocator () + : numPages (1) + , pages (new PoolAllocator[1]()) + { + } + + T *Alloc () + { + T *ptr = NULL; + for ( int i = 0; i < numPages && ptr == NULL; i++ ) + { + ptr = pages[i].Alloc (); + } + + if ( ptr == NULL ) + { + PoolAllocator *newPages = new PoolAllocator[numPages + 1] (); + for ( int i = 0; i < numPages; i++ ) + { + pages[i].TransferTo (newPages[i]); + } + + delete[] pages; + pages = newPages; + + ptr = pages[numPages].Alloc (); + if ( ptr == NULL ) + { + return NULL; + } + + numPages++; + } + + return ptr; + } + + void Free ( T *ptr ) + { + for ( int i = 0; i < numPages; i++ ) + { + if ( pages[i].OwnsPtr (ptr) ) + { + pages[i].Free (ptr); + break; + } + } + } + + int GetHighWatermark () const + { + int total = 0; + for ( int i = 0; i < numPages; i++ ) + { + total += pages[i].GetHighWatermark (); + } + + return total; + } + + ~PagedPoolAllocator () + { + delete[] pages; + } + + private: + int numPages; + PoolAllocator *pages; +}; + +//----------------------------------------------------------------- +// +// CFxScheduler +// +// The scheduler not only handles requests to play an effect, it +// tracks the request throughout its life if necessary, creating +// any of the delayed components as needed. +// +//----------------------------------------------------------------- +class CFxScheduler +{ +private: + + // We hold a scheduled effect here + struct SScheduledEffect + { + CPrimitiveTemplate *mpTemplate; // primitive template + int mStartTime; + char mModelNum; // uset to determine which ghoul2 model we want to bolt this effect to + char mBoltNum; // used to determine which bolt on the ghoul2 model we should be attaching this effect to + short mEntNum; // used to determine which entity this ghoul model is attached to. + bool mPortalEffect; // rww - render this before skyportals, and not in the normal world view. + bool mIsRelative; // bolt this puppy on keep it updated + CGhoul2Info_v *ghoul2; + vec3_t mOrigin; + matrix3_t mAxis; + }; + +/* Looped Effects get stored and reschedule at mRepeatRate */ + #define MAX_LOOPED_FX 32 + // We hold a looped effect here + struct SLoopedEffect + { + int mId; // effect id + int mBoltInfo; // used to determine which bolt on the ghoul2 model we should be attaching this effect to + CGhoul2Info_v *mGhoul2; + int mNextTime; //time to render again + int mLoopStopTime; //time to die + bool mPortalEffect; // rww - render this before skyportals, and not in the normal world view. + bool mIsRelative; // bolt this puppy on keep it updated + }; + + SLoopedEffect mLoopedEffectArray[MAX_LOOPED_FX]; + + int ScheduleLoopedEffect( int id, int boltInfo, CGhoul2Info_v *ghoul2, bool isPortal, int iLoopTime, bool isRelative ); + void AddLoopedEffects( ); + + + class CScheduled2DEffect + { + public: + CScheduled2DEffect(): + mScreenX(0), + mScreenY(0), + mWidth(0), + mHeight(0), + mShaderHandle(0) + {mColor[0]=mColor[1]=mColor[2]=mColor[3]=1.0f;} + + public: + float mScreenX; + float mScreenY; + float mWidth; + float mHeight; + vec4_t mColor; // bytes A, G, B, R -- see class paletteRGBA_c + qhandle_t mShaderHandle; + }; + + // this makes looking up the index based on the string name much easier + typedef std::map TEffectID; + + typedef std::list TScheduledEffect; + + // Effects + SEffectTemplate mEffectTemplates[FX_MAX_EFFECTS]; + TEffectID mEffectIDs; // if you only have the unique effect name, you'll have to use this to get the ID. + + // 2D effects + CScheduled2DEffect m2DEffects[FX_MAX_2DEFFECTS]; + int mNextFree2DEffect; + + // List of scheduled effects that will need to be created at the correct time. + TScheduledEffect mFxSchedule; + + PagedPoolAllocator mScheduledEffectsPool; + + // Private function prototypes + SEffectTemplate *GetNewEffectTemplate( int *id, const char *file ); + + void AddPrimitiveToEffect( SEffectTemplate *fx, CPrimitiveTemplate *prim ); + int ParseEffect( const char *file, CGPGroup *base ); + + void CreateEffect( CPrimitiveTemplate *fx, const vec3_t origin, matrix3_t axis, int lateTime, int fxParm = -1, CGhoul2Info_v *ghoul2 = NULL, int entNum = -1, int modelNum = -1, int boltNum = -1); + void CreateEffect( CPrimitiveTemplate *fx, SScheduledEffect *schedFx ); + +public: + + CFxScheduler(); + + int RegisterEffect( const char *file, bool bHasCorrectPath = false ); // handles pre-caching + + // Nasty overloaded madness + //rww - maybe this should be done differently.. it's more than a bit confusing. + //Remind me when I don't have 50 files checked out. + void PlayEffect( int id, vec3_t org, vec3_t fwd, int vol = -1, int rad = -1, bool isPortal = false ); // builds arbitrary perp. right vector, does a cross product to define up + void PlayEffect( int id, vec3_t origin, matrix3_t axis, const int boltInfo=-1, CGhoul2Info_v *ghoul2 = NULL, + int fxParm = -1, int vol = -1, int rad = -1, bool isPortal = false, int iLoopTime = false, bool isRelative = false ); + void PlayEffect( const char *file, vec3_t org, int vol = -1, int rad = -1 ); // uses a default up axis + void PlayEffect( const char *file, vec3_t org, vec3_t fwd, int vol = -1, int rad = -1 ); // builds arbitrary perp. right vector, does a cross product to define up + void PlayEffect( const char *file, vec3_t origin, + matrix3_t axis, const int boltInfo = -1, CGhoul2Info_v *ghoul2 = NULL, int fxParm = -1, int vol = -1, int rad = -1, int iLoopTime = false, bool isRelative = false ); + + void StopEffect( const char *file, const int boltInfo, bool isPortal = false ); //find a scheduled Looping effect with these parms and kill it + void AddScheduledEffects( bool portal ); // call once per CGame frame + + // kef -- called for a 2D effect instead of addRefToScene + bool Add2DEffect(float x, float y, float w, float h, vec4_t color, qhandle_t shaderHandle); + // kef -- called once per cgame frame AFTER trap->RenderScene + void Draw2DEffects(float screenXScale, float screenYScale); + + int GetHighWatermark() const { return mScheduledEffectsPool.GetHighWatermark(); } + int NumScheduledFx() { return (int)mFxSchedule.size(); } + void Clean(bool bRemoveTemplates = true, int idToPreserve = 0); // clean out the system + + // FX Override functions + SEffectTemplate *GetEffectCopy( int fxHandle, int *newHandle ); + SEffectTemplate *GetEffectCopy( const char *file, int *newHandle ); + + CPrimitiveTemplate *GetPrimitiveCopy( SEffectTemplate *effectCopy, const char *componentName ); + + void MaterialImpact(trace_t *tr, CEffect *effect); +}; + +//------------------- +// The one and only +//------------------- +extern CFxScheduler theFxScheduler; diff --git a/Projects/Android/jni/OpenJK/codemp_delete/client/FxSystem.cpp b/Projects/Android/jni/OpenJK/codemp_delete/client/FxSystem.cpp new file mode 100644 index 0000000..f54d991 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/client/FxSystem.cpp @@ -0,0 +1,147 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#include "client.h" +#include "cl_cgameapi.h" +#include "FxScheduler.h" +#include "ghoul2/G2.h" + +cvar_t *fx_debug; +#ifdef _DEBUG +cvar_t *fx_freeze; +#endif +cvar_t *fx_countScale; +cvar_t *fx_nearCull; + +#define DEFAULT_EXPLOSION_RADIUS 512 + +// Stuff for the FxHelper +//------------------------------------------------------ +SFxHelper::SFxHelper() : + mTime(0), + mOldTime(0), + mFrameTime(0), + mTimeFrozen(false), + refdef(0) +{ +} + +void SFxHelper::ReInit(refdef_t* pRefdef) +{ + mTime = 0; + mOldTime = 0; + mFrameTime = 0; + mTimeFrozen = false; + refdef = pRefdef; +} + +//------------------------------------------------------ +void SFxHelper::Print( const char *msg, ... ) +{ + va_list argptr; + char text[1024]; + + va_start( argptr, msg ); + Q_vsnprintf(text, sizeof(text), msg, argptr); + va_end( argptr ); + + Com_DPrintf( text ); +} + +//------------------------------------------------------ +void SFxHelper::AdjustTime( int frametime ) +{ +#ifdef _DEBUG + if ( fx_freeze->integer || ( frametime <= 0 )) +#else + if ( frametime <= 0 ) +#endif + { + // Allow no time progression when we are paused. + mFrameTime = 0; + mRealTime = 0.0f; + } + else + { + mOldTime = mTime; + mTime = frametime; + mFrameTime = mTime - mOldTime; + + mRealTime = mFrameTime * 0.001f; + + +/* mFrameTime = frametime; + mTime += mFrameTime; + mRealTime = mFrameTime * 0.001f;*/ + +// mHalfRealTimeSq = mRealTime * mRealTime * 0.5f; + } +} + +//------------------------------------------------------ +void SFxHelper::CameraShake( vec3_t origin, float intensity, int radius, int time ) +{ + TCGCameraShake *data = (TCGCameraShake *)cl.mSharedMemory; + + VectorCopy(origin, data->mOrigin); + data->mIntensity = intensity; + data->mRadius = radius; + data->mTime = time; + + CGVM_CameraShake(); +} + +//------------------------------------------------------ +qboolean SFxHelper::GetOriginAxisFromBolt(CGhoul2Info_v *pGhoul2, int mEntNum, int modelNum, int boltNum, vec3_t /*out*/origin, vec3_t /*out*/axis[3]) +{ + qboolean doesBoltExist; + mdxaBone_t boltMatrix; + TCGGetBoltData *data = (TCGGetBoltData*)cl.mSharedMemory; + data->mEntityNum = mEntNum; + CGVM_GetLerpData();//this func will zero out pitch and roll for players, and ridable vehicles + + //Fixme: optimize these VM calls away by storing + + // go away and get me the bolt position for this frame please + doesBoltExist = re->G2API_GetBoltMatrix(*pGhoul2, modelNum, boltNum, + &boltMatrix, data->mAngles, data->mOrigin, theFxHelper.mOldTime, 0, data->mScale); + + if (doesBoltExist) + { // set up the axis and origin we need for the actual effect spawning + origin[0] = boltMatrix.matrix[0][3]; + origin[1] = boltMatrix.matrix[1][3]; + origin[2] = boltMatrix.matrix[2][3]; + + axis[1][0] = boltMatrix.matrix[0][0]; + axis[1][1] = boltMatrix.matrix[1][0]; + axis[1][2] = boltMatrix.matrix[2][0]; + + axis[0][0] = boltMatrix.matrix[0][1]; + axis[0][1] = boltMatrix.matrix[1][1]; + axis[0][2] = boltMatrix.matrix[2][1]; + + axis[2][0] = boltMatrix.matrix[0][2]; + axis[2][1] = boltMatrix.matrix[1][2]; + axis[2][2] = boltMatrix.matrix[2][2]; + } + return doesBoltExist; +} diff --git a/Projects/Android/jni/OpenJK/codemp_delete/client/FxSystem.h b/Projects/Android/jni/OpenJK/codemp_delete/client/FxSystem.h new file mode 100644 index 0000000..d42750f --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/client/FxSystem.h @@ -0,0 +1,207 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#pragma once + +#include "client/cl_cgameapi.h" +#include "ghoul2/G2.h" + +extern cvar_t *fx_debug; + +#ifdef _DEBUG +extern cvar_t *fx_freeze; +#endif + +extern cvar_t *fx_countScale; +extern cvar_t *fx_nearCull; + +class SFxHelper +{ +public: + int mTime; + int mOldTime; + int mFrameTime; + bool mTimeFrozen; + float mRealTime; + refdef_t* refdef; +#ifdef _DEBUG + int mMainRefs; + int mMiniRefs; +#endif + +public: + SFxHelper(); + + inline int GetTime(void) { return mTime; } + inline int GetFrameTime(void) { return mFrameTime; } + + void ReInit(refdef_t* pRefdef); + void AdjustTime( int time ); + + // These functions are wrapped and used by the fx system in case it makes things a bit more portable + void Print( const char *msg, ... ); + + // File handling + inline int OpenFile( const char *path, fileHandle_t *fh, int mode ) + { + return FS_FOpenFileByMode( path, fh, FS_READ ); + } + inline int ReadFile( void *data, int len, fileHandle_t fh ) + { + FS_Read( data, len, fh ); + return 1; + } + inline void CloseFile( fileHandle_t fh ) + { + FS_FCloseFile( fh ); + } + + // Sound + inline void PlaySound( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfxHandle, int volume, int radius ) + { + //S_StartSound( origin, ENTITYNUM_NONE, CHAN_AUTO, sfxHandle, volume, radius ); + S_StartSound( origin, ENTITYNUM_NONE, CHAN_AUTO, sfxHandle ); + } + inline void PlayLocalSound(sfxHandle_t sfxHandle, int entchannel) + { + //S_StartSound( origin, ENTITYNUM_NONE, CHAN_AUTO, sfxHandle, volume, radius ); + S_StartLocalSound(sfxHandle, entchannel); + } + inline int RegisterSound( const char *sound ) + { + return S_RegisterSound( sound ); + } + + // Physics/collision + inline void Trace( trace_t &tr, vec3_t start, vec3_t min, vec3_t max, vec3_t end, int skipEntNum, int flags ) + { + TCGTrace *td = (TCGTrace *)cl.mSharedMemory; + + if ( !min ) + { + min = vec3_origin; + } + + if ( !max ) + { + max = vec3_origin; + } + + memset(td, 0, sizeof(*td)); + VectorCopy(start, td->mStart); + VectorCopy(min, td->mMins); + VectorCopy(max, td->mMaxs); + VectorCopy(end, td->mEnd); + td->mSkipNumber = skipEntNum; + td->mMask = flags; + + CGVM_Trace(); + + tr = td->mResult; + } + + inline void G2Trace( trace_t &tr, vec3_t start, vec3_t min, vec3_t max, vec3_t end, int skipEntNum, int flags ) + { + TCGTrace *td = (TCGTrace *)cl.mSharedMemory; + + if ( !min ) + { + min = vec3_origin; + } + + if ( !max ) + { + max = vec3_origin; + } + + memset(td, 0, sizeof(*td)); + VectorCopy(start, td->mStart); + VectorCopy(min, td->mMins); + VectorCopy(max, td->mMaxs); + VectorCopy(end, td->mEnd); + td->mSkipNumber = skipEntNum; + td->mMask = flags; + + CGVM_G2Trace(); + + tr = td->mResult; + } + + inline void AddGhoul2Decal(int shader, vec3_t start, vec3_t dir, float size) + { + TCGG2Mark *td = (TCGG2Mark *)cl.mSharedMemory; + + td->size = size; + td->shader = shader; + VectorCopy(start, td->start); + VectorCopy(dir, td->dir); + + CGVM_G2Mark(); + } + + inline void AddFxToScene( refEntity_t *ent ) + { +#ifdef _DEBUG + mMainRefs++; + + assert(!ent || ent->renderfx >= 0); +#endif + re->AddRefEntityToScene( ent ); + } + inline void AddFxToScene( miniRefEntity_t *ent ) + { +#ifdef _DEBUG + mMiniRefs++; + + assert(!ent || ent->renderfx >= 0); +#endif + re->AddMiniRefEntityToScene( ent ); + } + inline void AddLightToScene( vec3_t org, float radius, float red, float green, float blue ) + { + re->AddLightToScene( org, radius, red, green, blue ); + } + + inline int RegisterShader( const char *shader ) + { + return re->RegisterShader( shader ); + } + inline int RegisterModel( const char *model ) + { + return re->RegisterModel( model ); + } + + inline void AddPolyToScene( int shader, int count, polyVert_t *verts ) + { + re->AddPolyToScene( shader, count, verts, 1 ); + } + + inline void AddDecalToScene ( qhandle_t shader, const vec3_t origin, const vec3_t dir, float orientation, float r, float g, float b, float a, qboolean alphaFade, float radius, qboolean temporary ) + { + re->AddDecalToScene ( shader, origin, dir, orientation, r, g, b, a, alphaFade, radius, temporary ); + } + + void CameraShake( vec3_t origin, float intensity, int radius, int time ); + qboolean GetOriginAxisFromBolt(CGhoul2Info_v *pGhoul2, int mEntNum, int modelNum, int boltNum, vec3_t /*out*/origin, vec3_t /*out*/axis[3]); +}; + +extern SFxHelper theFxHelper; diff --git a/Projects/Android/jni/OpenJK/codemp_delete/client/FxTemplate.cpp b/Projects/Android/jni/OpenJK/codemp_delete/client/FxTemplate.cpp new file mode 100644 index 0000000..83f404c --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/client/FxTemplate.cpp @@ -0,0 +1,2205 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#include "client.h" +#include "FxScheduler.h" + +//------------------------------------------------------ +// CPrimitiveTemplate +// Set up our minimal default values +// +// Input: +// none +// +// Return: +// none +//------------------------------------------------------ +CPrimitiveTemplate::CPrimitiveTemplate() +{ + // We never start out as a copy or with a name + mCopy = false; + mName[0] = 0; + mCullRange = 0; // no distance culling + + mFlags = mSpawnFlags = 0; + mElasticity.SetRange(0.1f, 0.1f); + + mSoundVolume = -1; + mSoundRadius = -1; + + mMatImpactFX = MATIMPACTFX_NONE; + + mLife.SetRange( 50.0f, 50.0f ); + mSpawnCount.SetRange( 1.0f, 1.0f ); + mRadius.SetRange( 10.0f, 10.0f ); + mHeight.SetRange( 10.0f, 10.0f ); + mWindModifier.SetRange( 1.0f, 1.0f ); + + VectorSet( mMin, 0.0f, 0.0f, 0.0f ); + VectorSet( mMax, 0.0f, 0.0f, 0.0f ); + + mRedStart.SetRange( 1.0f, 1.0f ); + mGreenStart.SetRange( 1.0f, 1.0f ); + mBlueStart.SetRange( 1.0f, 1.0f ); + + mRedEnd.SetRange( 1.0f, 1.0f ); + mGreenEnd.SetRange( 1.0f, 1.0f ); + mBlueEnd.SetRange( 1.0f, 1.0f ); + + mAlphaStart.SetRange( 1.0f, 1.0f ); + mAlphaEnd.SetRange( 1.0f, 1.0f ); + + mSizeStart.SetRange( 1.0f, 1.0f ); + mSizeEnd.SetRange( 1.0f, 1.0f ); + + mSize2Start.SetRange( 1.0f, 1.0f ); + mSize2End.SetRange( 1.0f, 1.0f ); + + mLengthStart.SetRange( 1.0f, 1.0f ); + mLengthEnd.SetRange( 1.0f, 1.0f ); + + mTexCoordS.SetRange( 1.0f, 1.0f ); + mTexCoordT.SetRange( 1.0f, 1.0f ); + + mVariance.SetRange( 1.0f, 1.0f ); + mDensity.SetRange( 10.0f, 10.0f );// default this high so it doesn't do bad things +} + +//----------------------------------------------------------- +CPrimitiveTemplate &CPrimitiveTemplate::operator=(const CPrimitiveTemplate &that) +{ + // I'm assuming that doing a memcpy wouldn't work here + // If you are looking at this and know a better way to do this, please tell me. + strcpy( mName, that.mName ); + + mType = that.mType; + + mSpawnDelay = that.mSpawnDelay; + mSpawnCount = that.mSpawnCount; + mLife = that.mLife; + mCullRange = that.mCullRange; + + mMediaHandles = that.mMediaHandles; + mImpactFxHandles = that.mImpactFxHandles; + mDeathFxHandles = that.mDeathFxHandles; + mEmitterFxHandles = that.mEmitterFxHandles; + mPlayFxHandles = that.mPlayFxHandles; + + mFlags = that.mFlags; + mSpawnFlags = that.mSpawnFlags; + + VectorCopy( that.mMin, mMin ); + VectorCopy( that.mMax, mMax ); + + mOrigin1X = that.mOrigin1X; + mOrigin1Y = that.mOrigin1Y; + mOrigin1Z = that.mOrigin1Z; + + mOrigin2X = that.mOrigin2X; + mOrigin2Y = that.mOrigin2Y; + mOrigin2Z = that.mOrigin2Z; + + mRadius = that.mRadius; + mHeight = that.mHeight; + mWindModifier = that.mWindModifier; + + mRotation = that.mRotation; + mRotationDelta = that.mRotationDelta; + + mAngle1 = that.mAngle1; + mAngle2 = that.mAngle2; + mAngle3 = that.mAngle3; + + mAngle1Delta = that.mAngle1Delta; + mAngle2Delta = that.mAngle2Delta; + mAngle3Delta = that.mAngle3Delta; + + mVelX = that.mVelX; + mVelY = that.mVelY; + mVelZ = that.mVelZ; + + mAccelX = that.mAccelX; + mAccelY = that.mAccelY; + mAccelZ = that.mAccelZ; + + mGravity = that.mGravity; + + mDensity = that.mDensity; + mVariance = that.mVariance; + + mRedStart = that.mRedStart; + mGreenStart = that.mGreenStart; + mBlueStart = that.mBlueStart; + + mRedEnd = that.mRedEnd; + mGreenEnd = that.mGreenEnd; + mBlueEnd = that.mBlueEnd; + + mRGBParm = that.mRGBParm; + + mAlphaStart = that.mAlphaStart; + mAlphaEnd = that.mAlphaEnd; + mAlphaParm = that.mAlphaParm; + + mSizeStart = that.mSizeStart; + mSizeEnd = that.mSizeEnd; + mSizeParm = that.mSizeParm; + + mSize2Start = that.mSize2Start; + mSize2End = that.mSize2End; + mSize2Parm = that.mSize2Parm; + + mLengthStart = that.mLengthStart; + mLengthEnd = that.mLengthEnd; + mLengthParm = that.mLengthParm; + + mTexCoordS = that.mTexCoordS; + mTexCoordT = that.mTexCoordT; + + mElasticity = that.mElasticity; + + mSoundRadius = that.mSoundRadius; + mSoundVolume = that.mSoundVolume; + + return *this; +} + +//------------------------------------------------------ +// ParseFloat +// Removes up to two values from a passed in string and +// sets these values into the passed in min and max +// fields. if no max is present, min is copied into it. +// +// input: +// string that contains up to two float values +// min & max are used to return the parse values +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseFloat( const char *val, float *min, float *max ) +{ + // We don't allow passing in a null for either of the fields + if ( min == 0 || max == 0 ) + { // failue + return false; + } + + // attempt to read out the values + int v = sscanf( val, "%f %f", min, max ); + + if ( v == 0 ) + { // nothing was there, failure + return false; + } + else if ( v == 1 ) + { // only one field entered, this is ok, but we should copy min into max + *max = *min; + } + + return true; +} + + +//------------------------------------------------------ +// ParseVector +// Removes up to six values from a passed in string and +// sets these values into the passed in min and max vector +// fields. if no max is present, min is copied into it. +// +// input: +// string that contains up to six float values +// min & max are used to return the parse values +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseVector( const char *val, vec3_t min, vec3_t max ) +{ + // we don't allow passing in a null + if ( min == 0 || max == 0 ) + { + return false; + } + + // attempt to read out our values + int v = sscanf( val, "%f %f %f %f %f %f", &min[0], &min[1], &min[2], &max[0], &max[1], &max[2] ); + + // Check for completeness + if ( v < 3 || v == 4 || v == 5 ) + { // not a complete value + return false; + } + else if ( v == 3 ) + { // only a min was entered, so copy the result into max + VectorCopy( min, max ); + } + + return true; +} + +//------------------------------------------------------ +// ParseGroupFlags +// Group flags are generic in nature, so we can easily +// use a generic function to parse them in, then the +// caller can shift them into the appropriate range. +// +// input: +// string that contains the flag strings +// *flags returns the set bit flags +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseGroupFlags( const char *val, int *flags ) +{ + // Must pass in a non-null pointer + if ( flags == 0 ) + { + return false; + } + + char flag[][32] = {"\0","\0","\0","0"}; + bool ok = true; + + // For a sub group, really you probably only have one or two flags set + int v = sscanf( val, "%s %s %s %s", flag[0], flag[1], flag[2], flag[3] ); + + // Clear out the flags field, then convert the flag string to an actual value ( use generic flags ) + *flags = 0; + + for ( int i = 0; i < 4; i++ ) + { + if ( i + 1 > v ) + { + return true; + } + + if ( !Q_stricmp( flag[i], "linear" ) ) + *flags |= FX_LINEAR; + else if ( !Q_stricmp( flag[i], "nonlinear" ) ) + *flags |= FX_NONLINEAR; + else if ( !Q_stricmp( flag[i], "wave" ) ) + *flags |= FX_WAVE; + else if ( !Q_stricmp( flag[i], "random" ) ) + *flags |= FX_RAND; + else if ( !Q_stricmp( flag[i], "clamp" ) ) + *flags |= FX_CLAMP; + + else + { // we have badness going on, but continue on in case there are any valid fields in here + ok = false; + } + } + + return ok; +} + +//------------------------------------------------------ +// ParseMin +// Reads in a min bounding box field in vector format +// +// input: +// string that contains three float values +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseMin( const char *val ) +{ + vec3_t min; + + if ( ParseVector( val, min, min ) == true ) + { + VectorCopy( min, mMin ); + + // We assume that if a min is being set that we are using physics and a bounding box + mFlags |= (FX_USE_BBOX | FX_APPLY_PHYSICS); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseMax +// Reads in a max bounding box field in vector format +// +// input: +// string that contains three float values +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseMax( const char *val ) +{ + vec3_t max; + + if ( ParseVector( val, max, max ) == true ) + { + VectorCopy( max, mMax ); + + // We assume that if a max is being set that we are using physics and a bounding box + mFlags |= (FX_USE_BBOX | FX_APPLY_PHYSICS); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseLife +// Reads in a ranged life value +// +// input: +// string that contains a float range ( two vals ) +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseLife( const char *val ) +{ + float min, max; + + if ( ParseFloat( val, &min, &max ) == true ) + { + mLife.SetRange( min, max ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseDelay +// Reads in a ranged delay value +// +// input: +// string that contains a float range ( two vals ) +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseDelay( const char *val ) +{ + float min, max; + + if ( ParseFloat( val, &min, &max ) == true ) + { + mSpawnDelay.SetRange( min, max ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseCount +// Reads in a ranged count value +// +// input: +// string that contains a float range ( two vals ) +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseCount( const char *val ) +{ + float min, max; + + if ( ParseFloat( val, &min, &max ) == true ) + { + mSpawnCount.SetRange( min, max ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseElasticity +// Reads in a ranged elasticity value +// +// input: +// string that contains a float range ( two vals ) +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseElasticity( const char *val ) +{ + float min, max; + + if ( ParseFloat( val, &min, &max ) == true ) + { + mElasticity.SetRange( min, max ); + + // We assume that if elasticity is set that we are using physics, but don't assume we are + // using a bounding box unless a min/max are explicitly set + mFlags |= FX_APPLY_PHYSICS; + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseOrigin1 +// Reads in an origin field in vector format +// +// input: +// string that contains three float values +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseOrigin1( const char *val ) +{ + vec3_t min, max; + + if ( ParseVector( val, min, max ) == true ) + { + mOrigin1X.SetRange( min[0], max[0] ); + mOrigin1Y.SetRange( min[1], max[1] ); + mOrigin1Z.SetRange( min[2], max[2] ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseOrigin2 +// Reads in an origin field in vector format +// +// input: +// string that contains three float values +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseOrigin2( const char *val ) +{ + vec3_t min, max; + + if ( ParseVector( val, min, max ) == true ) + { + mOrigin2X.SetRange( min[0], max[0] ); + mOrigin2Y.SetRange( min[1], max[1] ); + mOrigin2Z.SetRange( min[2], max[2] ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseRadius +// Reads in a ranged radius value +// +// input: +// string that contains one or two floats +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseRadius( const char *val ) +{ + float min, max; + + if ( ParseFloat( val, &min, &max ) == true ) + { + mRadius.SetRange( min, max ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseHeight +// Reads in a ranged height value +// +// input: +// string that contains one or two floats +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseHeight( const char *val ) +{ + float min, max; + + if ( ParseFloat( val, &min, &max ) == true ) + { + mHeight.SetRange( min, max ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseWindModifier +// Reads in a ranged wind modifier value +// +// input: +// string that contains one or two floats +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseWindModifier( const char *val ) +{ + float min, max; + + if ( ParseFloat( val, &min, &max ) == true ) + { + mWindModifier.SetRange( min, max ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseRotation +// Reads in a ranged rotation value +// +// input: +// string that contains one or two floats +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseRotation( const char *val ) +{ + float min, max; + + if ( ParseFloat( val, &min, &max ) == qtrue ) + { + mRotation.SetRange( min, max ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseRotationDelta +// Reads in a ranged rotationDelta value +// +// input: +// string that contains one or two floats +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseRotationDelta( const char *val ) +{ + float min, max; + + if ( ParseFloat( val, &min, &max ) == qtrue ) + { + mRotationDelta.SetRange( min, max ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseAngle +// Reads in a ranged angle field in vector format +// +// input: +// string that contains one or two vectors +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseAngle( const char *val ) +{ + vec3_t min, max; + + if ( ParseVector( val, min, max ) == true ) + { + mAngle1.SetRange( min[0], max[0] ); + mAngle2.SetRange( min[1], max[1] ); + mAngle3.SetRange( min[2], max[2] ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseAngleDelta +// Reads in a ranged angleDelta field in vector format +// +// input: +// string that contains one or two vectors +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseAngleDelta( const char *val ) +{ + vec3_t min, max; + + if ( ParseVector( val, min, max ) == true ) + { + mAngle1Delta.SetRange( min[0], max[0] ); + mAngle2Delta.SetRange( min[1], max[1] ); + mAngle3Delta.SetRange( min[2], max[2] ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseVelocity +// Reads in a ranged velocity field in vector format +// +// input: +// string that contains one or two vectors +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseVelocity( const char *val ) +{ + vec3_t min, max; + + if ( ParseVector( val, min, max ) == true ) + { + mVelX.SetRange( min[0], max[0] ); + mVelY.SetRange( min[1], max[1] ); + mVelZ.SetRange( min[2], max[2] ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseFlags +// These are flags that are not specific to a group, +// rather, they are specific to the whole primitive. +// +// input: +// string that contains the flag strings +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseFlags( const char *val ) +{ + char flag[][32] = {"\0","\0","\0","\0","\0","\0","\0"}; + bool ok = true; + + // For a primitive, really you probably only have two or less flags set + int v = sscanf( val, "%s %s %s %s %s %s %s", flag[0], flag[1], flag[2], flag[3], flag[4], flag[5], flag[6] ); + + for ( int i = 0; i < 7; i++ ) + { + if ( i + 1 > v ) + { + return true; + } + + if ( !Q_stricmp( flag[i], "useModel" )) + mFlags |= FX_ATTACHED_MODEL; + else if ( !Q_stricmp( flag[i], "useBBox" )) + mFlags |= FX_USE_BBOX; + else if ( !Q_stricmp( flag[i], "usePhysics" )) + mFlags |= FX_APPLY_PHYSICS; + else if ( !Q_stricmp( flag[i], "expensivePhysics" )) + mFlags |= FX_EXPENSIVE_PHYSICS; + //rww - begin g2 stuff + else if ( !Q_stricmp( flag[i], "ghoul2Collision" )) + mFlags |= (FX_GHOUL2_TRACE|FX_APPLY_PHYSICS|FX_EXPENSIVE_PHYSICS); + else if ( !Q_stricmp( flag[i], "ghoul2Decals" )) + mFlags |= FX_GHOUL2_DECALS; + //rww - end + else if ( !Q_stricmp( flag[i], "impactKills" )) + mFlags |= FX_KILL_ON_IMPACT; + else if ( !Q_stricmp( flag[i], "impactFx" )) + mFlags |= FX_IMPACT_RUNS_FX; + else if ( !Q_stricmp( flag[i], "deathFx" )) + mFlags |= FX_DEATH_RUNS_FX; + else if ( !Q_stricmp( flag[i], "useAlpha" )) + mFlags |= FX_USE_ALPHA; + else if ( !Q_stricmp( flag[i], "emitFx" )) + mFlags |= FX_EMIT_FX; + else if ( !Q_stricmp( flag[i], "depthHack" )) + mFlags |= FX_DEPTH_HACK; + else if ( !Q_stricmp( flag[i], "relative" )) + mFlags |= FX_RELATIVE; + else if ( !Q_stricmp( flag[i], "setShaderTime" )) + mFlags |= FX_SET_SHADER_TIME; + else if ( !Q_stricmp( flag[i], "paperPhysics" )) + mFlags |= FX_PAPER_PHYSICS; //warning! shared flag. You use this with a cylinder and you can expect evilness to ensue + else if ( !Q_stricmp( flag[i], "localizedFlash" )) + mFlags |= FX_LOCALIZED_FLASH; //warning! shared flag. You use this with a cylinder and you can expect evilness to ensue + else if ( !Q_stricmp( flag[i], "playerView" )) + mFlags |= FX_PLAYER_VIEW; //warning! shared flag. You use this with a cylinder and you can expect evilness to ensue + else + { // we have badness going on, but continue on in case there are any valid fields in here + ok = false; + } + } + + return ok; +} + +//------------------------------------------------------ +// ParseSpawnFlags +// These kinds of flags control how things spawn. They +// never get passed on to a primitive. +// +// input: +// string that contains the flag strings +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseSpawnFlags( const char *val ) +{ + char flag[][32] = {"\0","\0","\0","\0","\0","\0","\0"}; + bool ok = true; + + // For a primitive, really you probably only have two or less flags set + int v = sscanf( val, "%s %s %s %s %s %s %s", flag[0], flag[1], flag[2], flag[3], flag[4], flag[5], flag[6] ); + + for ( int i = 0; i < 7; i++ ) + { + if ( i + 1 > v ) + { + return true; + } + + if ( !Q_stricmp( flag[i], "org2fromTrace" ) ) + mSpawnFlags |= FX_ORG2_FROM_TRACE; + else if ( !Q_stricmp( flag[i], "traceImpactFx" ) ) + mSpawnFlags |= FX_TRACE_IMPACT_FX; + else if ( !Q_stricmp( flag[i], "org2isOffset" ) ) + mSpawnFlags |= FX_ORG2_IS_OFFSET; + else if ( !Q_stricmp( flag[i], "cheapOrgCalc" ) ) + mSpawnFlags |= FX_CHEAP_ORG_CALC; + else if ( !Q_stricmp( flag[i], "cheapOrg2Calc" ) ) + mSpawnFlags |= FX_CHEAP_ORG2_CALC; + else if ( !Q_stricmp( flag[i], "absoluteVel" ) ) + mSpawnFlags |= FX_VEL_IS_ABSOLUTE; + else if ( !Q_stricmp( flag[i], "absoluteAccel" ) ) + mSpawnFlags |= FX_ACCEL_IS_ABSOLUTE; + else if ( !Q_stricmp( flag[i], "orgOnSphere" ) ) // sphere/ellipsoid + mSpawnFlags |= FX_ORG_ON_SPHERE; + else if ( !Q_stricmp( flag[i], "orgOnCylinder" ) ) // cylinder/disk + mSpawnFlags |= FX_ORG_ON_CYLINDER; + else if ( !Q_stricmp( flag[i], "axisFromSphere" ) ) + mSpawnFlags |= FX_AXIS_FROM_SPHERE; + else if ( !Q_stricmp( flag[i], "randrotaroundfwd" ) ) + mSpawnFlags |= FX_RAND_ROT_AROUND_FWD; + else if ( !Q_stricmp( flag[i], "evenDistribution" ) ) + mSpawnFlags |= FX_EVEN_DISTRIBUTION; + else if ( !Q_stricmp( flag[i], "rgbComponentInterpolation" ) ) + mSpawnFlags |= FX_RGB_COMPONENT_INTERP; + else if ( !Q_stricmp( flag[i], "affectedByWind" ) ) + mSpawnFlags |= FX_AFFECTED_BY_WIND; + else + { // we have badness going on, but continue on in case there are any valid fields in here + ok = false; + } + } + + return ok; +} + + + +bool CPrimitiveTemplate::ParseMaterialImpact(const char *val) +{ + if (!Q_stricmp(val, "shellsound")) + { + mMatImpactFX = MATIMPACTFX_SHELLSOUND; + } + else + { + mMatImpactFX = MATIMPACTFX_NONE; + theFxHelper.Print( "CPrimitiveTemplate::ParseMaterialImpact -- unknown materialImpact type!\n" ); + return false; + } + return true; +} + + +//------------------------------------------------------ +// ParseAcceleration +// Reads in a ranged acceleration field in vector format +// +// input: +// string that contains one or two vectors +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseAcceleration( const char *val ) +{ + vec3_t min, max; + + if ( ParseVector( val, min, max ) == true ) + { + mAccelX.SetRange( min[0], max[0] ); + mAccelY.SetRange( min[1], max[1] ); + mAccelZ.SetRange( min[2], max[2] ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseGravity +// Reads in a ranged gravity value +// +// input: +// string that contains one or two floats +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseGravity( const char *val ) +{ + float min, max; + + if ( ParseFloat( val, &min, &max ) == true ) + { + mGravity.SetRange( min, max ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseDensity +// Reads in a ranged density value. Density is only +// for emitters that are calling effects...it basically +// specifies how often the emitter should emit fx. +// +// input: +// string that contains one or two floats +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseDensity( const char *val ) +{ + float min, max; + + if ( ParseFloat( val, &min, &max ) == true ) + { + mDensity.SetRange( min, max ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseVariance +// Reads in a ranged variance value. Variance is only +// valid for emitters that are calling effects... +// it basically determines the amount of slop in the +// density calculations +// +// input: +// string that contains one or two floats +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseVariance( const char *val ) +{ + float min, max; + + if ( ParseFloat( val, &min, &max ) == true ) + { + mVariance.SetRange( min, max ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseRGBStart +// Reads in a ranged rgbStart field in vector format +// +// input: +// string that contains one or two vectors +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseRGBStart( const char *val ) +{ + vec3_t min, max; + + if ( ParseVector( val, min, max ) == true ) + { + mRedStart.SetRange( min[0], max[0] ); + mGreenStart.SetRange( min[1], max[1] ); + mBlueStart.SetRange( min[2], max[2] ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseRGBEnd +// Reads in a ranged rgbEnd field in vector format +// +// input: +// string that contains one or two vectors +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseRGBEnd( const char *val ) +{ + vec3_t min, max; + + if ( ParseVector( val, min, max ) == true ) + { + mRedEnd.SetRange( min[0], max[0] ); + mGreenEnd.SetRange( min[1], max[1] ); + mBlueEnd.SetRange( min[2], max[2] ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseRGBParm +// Reads in a ranged rgbParm field in float format +// +// input: +// string that contains one or two floats +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseRGBParm( const char *val ) +{ + float min, max; + + if ( ParseFloat( val, &min, &max ) == true ) + { + mRGBParm.SetRange( min, max ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseRGBFlags +// Reads in a set of rgbFlags in string format +// +// input: +// string that contains the flag strings +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseRGBFlags( const char *val ) +{ + int flags; + + if ( ParseGroupFlags( val, &flags ) == true ) + { + // Convert our generic flag values into type specific ones + mFlags |= ( flags << FX_RGB_SHIFT ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseAlphaStart +// Reads in a ranged alphaStart field in float format +// +// input: +// string that contains one or two floats +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseAlphaStart( const char *val ) +{ + float min, max; + + if ( ParseFloat( val, &min, &max ) == true ) + { + mAlphaStart.SetRange( min, max ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseAlphaEnd +// Reads in a ranged alphaEnd field in float format +// +// input: +// string that contains one or two floats +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseAlphaEnd( const char *val ) +{ + float min, max; + + if ( ParseFloat( val, &min, &max ) == true ) + { + mAlphaEnd.SetRange( min, max ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseAlphaParm +// Reads in a ranged alphaParm field in float format +// +// input: +// string that contains one or two floats +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseAlphaParm( const char *val ) +{ + float min, max; + + if ( ParseFloat( val, &min, &max ) == true ) + { + mAlphaParm.SetRange( min, max ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseAlphaFlags +// Reads in a set of alphaFlags in string format +// +// input: +// string that contains the flag strings +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseAlphaFlags( const char *val ) +{ + int flags; + + if ( ParseGroupFlags( val, &flags ) == true ) + { + // Convert our generic flag values into type specific ones + mFlags |= ( flags << FX_ALPHA_SHIFT ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseSizeStart +// Reads in a ranged sizeStart field in float format +// +// input: +// string that contains one or two floats +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseSizeStart( const char *val ) +{ + float min, max; + + if ( ParseFloat( val, &min, &max ) == true ) + { + mSizeStart.SetRange( min, max ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseSizeEnd +// Reads in a ranged sizeEnd field in float format +// +// input: +// string that contains one or two floats +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseSizeEnd( const char *val ) +{ + float min, max; + + if ( ParseFloat( val, &min, &max ) == true ) + { + mSizeEnd.SetRange( min, max ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseSizeParm +// Reads in a ranged sizeParm field in float format +// +// input: +// string that contains one or two floats +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseSizeParm( const char *val ) +{ + float min, max; + + if ( ParseFloat( val, &min, &max ) == true ) + { + mSizeParm.SetRange( min, max ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseSizeFlags +// Reads in a set of sizeFlags in string format +// +// input: +// string that contains the flag strings +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseSizeFlags( const char *val ) +{ + int flags; + + if ( ParseGroupFlags( val, &flags ) == true ) + { + // Convert our generic flag values into type specific ones + mFlags |= ( flags << FX_SIZE_SHIFT ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseSize2Start +// Reads in a ranged Size2Start field in float format +// +// input: +// string that contains one or two floats +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseSize2Start( const char *val ) +{ + float min, max; + + if ( ParseFloat( val, &min, &max ) == true ) + { + mSize2Start.SetRange( min, max ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseSize2End +// Reads in a ranged Size2End field in float format +// +// input: +// string that contains one or two floats +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseSize2End( const char *val ) +{ + float min, max; + + if ( ParseFloat( val, &min, &max ) == true ) + { + mSize2End.SetRange( min, max ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseSize2Parm +// Reads in a ranged Size2Parm field in float format +// +// input: +// string that contains one or two floats +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseSize2Parm( const char *val ) +{ + float min, max; + + if ( ParseFloat( val, &min, &max ) == true ) + { + mSize2Parm.SetRange( min, max ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseSize2Flags +// Reads in a set of Size2Flags in string format +// +// input: +// string that contains the flag strings +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseSize2Flags( const char *val ) +{ + int flags; + + if ( ParseGroupFlags( val, &flags ) == true ) + { + // Convert our generic flag values into type specific ones + mFlags |= ( flags << FX_SIZE2_SHIFT ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseLengthStart +// Reads in a ranged lengthStart field in float format +// +// input: +// string that contains one or two floats +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseLengthStart( const char *val ) +{ + float min, max; + + if ( ParseFloat( val, &min, &max ) == true ) + { + mLengthStart.SetRange( min, max ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseLengthEnd +// Reads in a ranged lengthEnd field in float format +// +// input: +// string that contains one or two floats +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseLengthEnd( const char *val ) +{ + float min, max; + + if ( ParseFloat( val, &min, &max ) == true ) + { + mLengthEnd.SetRange( min, max ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseLengthParm +// Reads in a ranged lengthParm field in float format +// +// input: +// string that contains one or two floats +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseLengthParm( const char *val ) +{ + float min, max; + + if ( ParseFloat( val, &min, &max ) == true ) + { + mLengthParm.SetRange( min, max ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseLengthFlags +// Reads in a set of lengthFlags in string format +// +// input: +// string that contains the flag strings +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseLengthFlags( const char *val ) +{ + int flags; + + if ( ParseGroupFlags( val, &flags ) == true ) + { + // Convert our generic flag values into type specific ones + mFlags |= ( flags << FX_LENGTH_SHIFT ); + return true; + } + + return false; +} + +//------------------------------------------------------ +// ParseShaders +// Reads in a group of shaders and registers them +// +// input: +// Parse group that contains the list of shaders to parse +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseShaders( CGPValue *grp ) +{ + const char *val; + int handle; + + if ( grp->IsList() ) + { + // If we are a list we have to do separate processing + CGPObject *list = grp->GetList(); + + while ( list ) + { + // name is actually the value contained in the list + val = list->GetName(); + + handle = theFxHelper.RegisterShader( val ); + mMediaHandles.AddHandle( handle ); + + list = (CGPValue *)list->GetNext(); + } + } + else + { + // Let's get a value + val = grp->GetTopValue(); + + if ( val ) + { + handle = theFxHelper.RegisterShader( val ); + mMediaHandles.AddHandle( handle ); + } + else + { + // empty "list" + theFxHelper.Print( "CPrimitiveTemplate::ParseShaders called with an empty list!\n" ); + return false; + } + } + + return true; +} + +//------------------------------------------------------ +// ParseSounds +// Reads in a group of sounds and registers them +// +// input: +// Parse group that contains the list of sounds to parse +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseSounds( CGPValue *grp ) +{ + const char *val; + int handle; + + if ( grp->IsList() ) + { + // If we are a list we have to do separate processing + CGPObject *list = grp->GetList(); + + while ( list ) + { + // name is actually the value contained in the list + val = list->GetName(); + + handle = theFxHelper.RegisterSound( val ); + mMediaHandles.AddHandle( handle ); + + list = (CGPValue *)list->GetNext(); + } + } + else + { + // Let's get a value + val = grp->GetTopValue(); + + if ( val ) + { + handle = theFxHelper.RegisterSound( val ); + mMediaHandles.AddHandle( handle ); + } + else + { + // empty "list" + theFxHelper.Print( "CPrimitiveTemplate::ParseSounds called with an empty list!\n" ); + return false; + } + } + + return true; +} + +//------------------------------------------------------ +// ParseModels +// Reads in a group of models and registers them +// +// input: +// Parse group that contains the list of models to parse +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseModels( CGPValue *grp ) +{ + const char *val; + int handle; + + if ( grp->IsList() ) + { + // If we are a list we have to do separate processing + CGPObject *list = grp->GetList(); + + while ( list ) + { + // name is actually the value contained in the list + val = list->GetName(); + + handle = theFxHelper.RegisterModel( val ); + mMediaHandles.AddHandle( handle ); + + list = (CGPValue *)list->GetNext(); + } + } + else + { + // Let's get a value + val = grp->GetTopValue(); + + if ( val ) + { + handle = theFxHelper.RegisterModel( val ); + mMediaHandles.AddHandle( handle ); + } + else + { + // empty "list" + theFxHelper.Print( "CPrimitiveTemplate::ParseModels called with an empty list!\n" ); + return false; + } + } + + mFlags |= FX_ATTACHED_MODEL; + + return true; +} + +//------------------------------------------------------ +// ParseImpactFxStrings +// Reads in a group of fx file names and registers them +// +// input: +// Parse group that contains the list of fx to parse +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseImpactFxStrings( CGPValue *grp ) +{ + const char *val; + int handle; + + if ( grp->IsList() ) + { + // If we are a list we have to do separate processing + CGPObject *list = grp->GetList(); + + while ( list ) + { + // name is actually the value contained in the list + val = list->GetName(); + handle = theFxScheduler.RegisterEffect( val ); + + if ( handle ) + { + mImpactFxHandles.AddHandle( handle ); + } + else + { + theFxHelper.Print( "FxTemplate: Impact effect file not found.\n" ); + return false; + } + + list = (CGPValue *)list->GetNext(); + } + } + else + { + // Let's get a value + val = grp->GetTopValue(); + + if ( val ) + { + handle = theFxScheduler.RegisterEffect( val ); + + if ( handle ) + { + mImpactFxHandles.AddHandle( handle ); + } + else + { + theFxHelper.Print( "FxTemplate: Impact effect file not found.\n" ); + return false; + } + } + else + { + // empty "list" + theFxHelper.Print( "CPrimitiveTemplate::ParseImpactFxStrings called with an empty list!\n" ); + return false; + } + } + + mFlags |= FX_IMPACT_RUNS_FX | FX_APPLY_PHYSICS; + + return true; +} + +//------------------------------------------------------ +// ParseDeathFxStrings +// Reads in a group of fx file names and registers them +// +// input: +// Parse group that contains the list of fx to parse +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseDeathFxStrings( CGPValue *grp ) +{ + const char *val; + int handle; + + if ( grp->IsList() ) + { + // If we are a list we have to do separate processing + CGPObject *list = grp->GetList(); + + while ( list ) + { + // name is actually the value contained in the list + val = list->GetName(); + handle = theFxScheduler.RegisterEffect( val ); + + if ( handle ) + { + mDeathFxHandles.AddHandle( handle ); + } + else + { + theFxHelper.Print( "FxTemplate: Death effect file not found.\n" ); + return false; + } + + list = (CGPValue *)list->GetNext(); + } + } + else + { + // Let's get a value + val = grp->GetTopValue(); + + if ( val ) + { + handle = theFxScheduler.RegisterEffect( val ); + + if ( handle ) + { + mDeathFxHandles.AddHandle( handle ); + } + else + { + theFxHelper.Print( "FxTemplate: Death effect file not found.\n" ); + return false; + } + } + else + { + // empty "list" + theFxHelper.Print( "CPrimitiveTemplate::ParseDeathFxStrings called with an empty list!\n" ); + return false; + } + } + + mFlags |= FX_DEATH_RUNS_FX; + + return true; +} + +//------------------------------------------------------ +// ParseEmitterFxStrings +// Reads in a group of fx file names and registers them +// +// input: +// Parse group that contains the list of fx to parse +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseEmitterFxStrings( CGPValue *grp ) +{ + const char *val; + int handle; + + if ( grp->IsList() ) + { + // If we are a list we have to do separate processing + CGPObject *list = grp->GetList(); + + while ( list ) + { + // name is actually the value contained in the list + val = list->GetName(); + handle = theFxScheduler.RegisterEffect( val ); + + if ( handle ) + { + mEmitterFxHandles.AddHandle( handle ); + } + else + { + theFxHelper.Print( "FxTemplate: Emitter effect file not found.\n" ); + return false; + } + + list = (CGPValue *)list->GetNext(); + } + } + else + { + // Let's get a value + val = grp->GetTopValue(); + + if ( val ) + { + handle = theFxScheduler.RegisterEffect( val ); + + if ( handle ) + { + mEmitterFxHandles.AddHandle( handle ); + } + else + { + theFxHelper.Print( "FxTemplate: Emitter effect file not found.\n" ); + return false; + } + } + else + { + // empty "list" + theFxHelper.Print( "CPrimitiveTemplate::ParseEmitterFxStrings called with an empty list!\n" ); + return false; + } + } + + mFlags |= FX_EMIT_FX; + + return true; +} + +//------------------------------------------------------ +// ParsePlayFxStrings +// Reads in a group of fx file names and registers them +// +// input: +// Parse group that contains the list of fx to parse +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParsePlayFxStrings( CGPValue *grp ) +{ + const char *val; + int handle; + + if ( grp->IsList() ) + { + // If we are a list we have to do separate processing + CGPObject *list = grp->GetList(); + + while ( list ) + { + // name is actually the value contained in the list + val = list->GetName(); + handle = theFxScheduler.RegisterEffect( val ); + + if ( handle ) + { + mPlayFxHandles.AddHandle( handle ); + } + else + { + theFxHelper.Print( "FxTemplate: Effect file not found.\n" ); + return false; + } + + list = (CGPValue *)list->GetNext(); + } + } + else + { + // Let's get a value + val = grp->GetTopValue(); + + if ( val ) + { + handle = theFxScheduler.RegisterEffect( val ); + + if ( handle ) + { + mPlayFxHandles.AddHandle( handle ); + } + else + { + theFxHelper.Print( "FxTemplate: Effect file not found.\n" ); + return false; + } + } + else + { + // empty "list" + theFxHelper.Print( "CPrimitiveTemplate::ParsePlayFxStrings called with an empty list!\n" ); + return false; + } + } + + return true; +} + +//------------------------------------------------------ +// ParseRGB +// Takes an RGB group and chomps out any pairs contained +// in it. +// +// input: +// the parse group to process +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseRGB( CGPGroup *grp ) +{ + CGPValue *pairs; + const char *key; + const char *val; + + // Inside of the group, we should have a series of pairs + pairs = grp->GetPairs(); + + while( pairs ) + { + // Let's get the key field + key = pairs->GetName(); + val = pairs->GetTopValue(); + + // Huge Q_stricmp lists suxor + if ( !Q_stricmp( key, "start" ) ) + ParseRGBStart( val ); + else if ( !Q_stricmp( key, "end" ) ) + ParseRGBEnd( val ); + else if ( !Q_stricmp( key, "parm" ) || !Q_stricmp( key, "parms" ) ) + ParseRGBParm( val ); + else if ( !Q_stricmp( key, "flags" ) || !Q_stricmp( key, "flag" ) ) + ParseRGBFlags( val ); + else + theFxHelper.Print( "Unknown key parsing an RGB group: %s\n", key ); + + pairs = (CGPValue *)pairs->GetNext(); + } + + return true; +} + +//------------------------------------------------------ +// ParseAlpha +// Takes an alpha group and chomps out any pairs contained +// in it. +// +// input: +// the parse group to process +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseAlpha( CGPGroup *grp ) +{ + CGPValue *pairs; + const char *key; + const char *val; + + // Inside of the group, we should have a series of pairs + pairs = grp->GetPairs(); + + while( pairs ) + { + // Let's get the key field + key = pairs->GetName(); + val = pairs->GetTopValue(); + + // Huge Q_stricmp lists suxor + if ( !Q_stricmp( key, "start" ) ) + ParseAlphaStart( val ); + else if ( !Q_stricmp( key, "end" ) ) + ParseAlphaEnd( val ); + else if ( !Q_stricmp( key, "parm" ) || !Q_stricmp( key, "parms" ) ) + ParseAlphaParm( val ); + else if ( !Q_stricmp( key, "flags" ) || !Q_stricmp( key, "flag" ) ) + ParseAlphaFlags( val ); + else + theFxHelper.Print( "Unknown key parsing an Alpha group: %s\n", key ); + + pairs = (CGPValue *)pairs->GetNext(); + } + + return true; +} + +//------------------------------------------------------ +// ParseSize +// Takes a size group and chomps out any pairs contained +// in it. +// +// input: +// the parse group to process +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseSize( CGPGroup *grp ) +{ + CGPValue *pairs; + const char *key; + const char *val; + + // Inside of the group, we should have a series of pairs + pairs = grp->GetPairs(); + + while( pairs ) + { + // Let's get the key field + key = pairs->GetName(); + val = pairs->GetTopValue(); + + // Huge Q_stricmp lists suxor + if ( !Q_stricmp( key, "start" ) ) + ParseSizeStart( val ); + else if ( !Q_stricmp( key, "end" ) ) + ParseSizeEnd( val ); + else if ( !Q_stricmp( key, "parm" ) || !Q_stricmp( key, "parms" ) ) + ParseSizeParm( val ); + else if ( !Q_stricmp( key, "flags" ) || !Q_stricmp( key, "flag" ) ) + ParseSizeFlags( val ); + else + theFxHelper.Print( "Unknown key parsing a Size group: %s\n", key ); + + pairs = (CGPValue *)pairs->GetNext(); + } + + return true; +} + +//------------------------------------------------------ +// ParseSize2 +// Takes a Size2 group and chomps out any pairs contained +// in it. +// +// input: +// the parse group to process +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseSize2( CGPGroup *grp ) +{ + CGPValue *pairs; + const char *key; + const char *val; + + // Inside of the group, we should have a series of pairs + pairs = grp->GetPairs(); + + while( pairs ) + { + // Let's get the key field + key = pairs->GetName(); + val = pairs->GetTopValue(); + + // Huge Q_stricmp lists suxor + if ( !Q_stricmp( key, "start" ) ) + ParseSize2Start( val ); + else if ( !Q_stricmp( key, "end" ) ) + ParseSize2End( val ); + else if ( !Q_stricmp( key, "parm" ) || !Q_stricmp( key, "parms" ) ) + ParseSize2Parm( val ); + else if ( !Q_stricmp( key, "flags" ) || !Q_stricmp( key, "flag" ) ) + ParseSize2Flags( val ); + else + theFxHelper.Print( "Unknown key parsing a Size2 group: %s\n", key ); + + pairs = (CGPValue *)pairs->GetNext(); + } + + return true; +} + +//------------------------------------------------------ +// ParseLength +// Takes a length group and chomps out any pairs contained +// in it. +// +// input: +// the parse group to process +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseLength( CGPGroup *grp ) +{ + CGPValue *pairs; + const char *key; + const char *val; + + // Inside of the group, we should have a series of pairs + pairs = grp->GetPairs(); + + while( pairs ) + { + // Let's get the key field + key = pairs->GetName(); + val = pairs->GetTopValue(); + + // Huge Q_stricmp lists suxor + if ( !Q_stricmp( key, "start" )) + ParseLengthStart( val ); + else if ( !Q_stricmp( key, "end" )) + ParseLengthEnd( val ); + else if ( !Q_stricmp( key, "parm" ) || !Q_stricmp( key, "parms" )) + ParseLengthParm( val ); + else if ( !Q_stricmp( key, "flags" ) || !Q_stricmp( key, "flag" )) + ParseLengthFlags( val ); + else + theFxHelper.Print( "Unknown key parsing a Length group: %s\n", key ); + + pairs = (CGPValue *)pairs->GetNext(); + } + + return true; +} + +// Parse a primitive, apply defaults first, grab any base level +// key pairs, then process any sub groups we may contain. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParsePrimitive( CGPGroup *grp ) +{ + CGPGroup *subGrp; + CGPValue *pairs; + const char *key; + const char *val; + + // Lets work with the pairs first + pairs = grp->GetPairs(); + + while( pairs ) + { + // the fields + key = pairs->GetName(); + val = pairs->GetTopValue(); + + // Huge Q_stricmp lists suxor + if ( !Q_stricmp( key, "count" ) ) + ParseCount( val ); + else if ( !Q_stricmp( key, "shaders" ) || !Q_stricmp( key, "shader" ) ) + ParseShaders( pairs ); + else if ( !Q_stricmp( key, "models" ) || !Q_stricmp( key, "model" ) ) + ParseModels( pairs ); + else if ( !Q_stricmp( key, "sounds" ) || !Q_stricmp( key, "sound" ) ) + ParseSounds( pairs ); + else if ( !Q_stricmp( key, "impactfx" ) ) + ParseImpactFxStrings( pairs ); + else if ( !Q_stricmp( key, "deathfx" ) ) + ParseDeathFxStrings( pairs ); + else if ( !Q_stricmp( key, "emitfx" ) ) + ParseEmitterFxStrings( pairs ); + else if ( !Q_stricmp( key, "playfx" ) ) + ParsePlayFxStrings( pairs ); + else if ( !Q_stricmp( key, "life" ) ) + ParseLife( val ); + else if ( !Q_stricmp( key, "delay" ) ) + ParseDelay( val ); + else if ( !Q_stricmp( key, "cullrange" ) ) { +// mCullRange = atoi( val ); +// mCullRange *= mCullRange; // square it now so we don't have to square every time we compare + } + else if ( !Q_stricmp( key, "bounce" ) || !Q_stricmp( key, "intensity" ) ) // me==bad for reusing this...but it shouldn't hurt anything) + ParseElasticity( val ); + else if ( !Q_stricmp( key, "min" ) ) + ParseMin( val ); + else if ( !Q_stricmp( key, "max" ) ) + ParseMax( val ); + else if ( !Q_stricmp( key, "angle" ) || !Q_stricmp( key, "angles" ) ) + ParseAngle( val ); + else if ( !Q_stricmp( key, "angleDelta" ) ) + ParseAngleDelta( val ); + else if ( !Q_stricmp( key, "velocity" ) || !Q_stricmp( key, "vel" ) ) + ParseVelocity( val ); + else if ( !Q_stricmp( key, "acceleration" ) || !Q_stricmp( key, "accel" ) ) + ParseAcceleration( val ); + else if ( !Q_stricmp( key, "gravity" ) ) + ParseGravity( val ); + else if ( !Q_stricmp( key, "density" ) ) + ParseDensity( val ); + else if ( !Q_stricmp( key, "variance" ) ) + ParseVariance( val ); + else if ( !Q_stricmp( key, "origin" ) ) + ParseOrigin1( val ); + else if ( !Q_stricmp( key, "origin2" ) ) + ParseOrigin2( val ); + else if ( !Q_stricmp( key, "radius" ) ) // part of ellipse/cylinder calcs. + ParseRadius( val ); + else if ( !Q_stricmp( key, "height" ) ) // part of ellipse/cylinder calcs. + ParseHeight( val ); + else if ( !Q_stricmp( key, "wind" ) ) + ParseWindModifier( val ); + else if ( !Q_stricmp( key, "rotation" ) ) + ParseRotation( val ); + else if ( !Q_stricmp( key, "rotationDelta" ) ) + ParseRotationDelta( val ); + // these need to get passed on to the primitive + else if ( !Q_stricmp( key, "flags" ) || !Q_stricmp( key, "flag" ) ) + ParseFlags( val ); + // these are used to spawn things in cool ways, but don't ever get passed on to prims. + else if ( !Q_stricmp( key, "spawnFlags" ) || !Q_stricmp( key, "spawnFlag" ) ) + ParseSpawnFlags( val ); + else if ( !Q_stricmp( key, "name" ) ) { + if ( val ) // just stash the descriptive name of the primitive + strcpy( mName, val ); + } + else if ( !Q_stricmp( key, "materialImpact" ) ) + ParseMaterialImpact( val ); + else + theFxHelper.Print( "Unknown key parsing an effect primitive: %s\n", key ); + + pairs = (CGPValue *)pairs->GetNext(); + } + + subGrp = grp->GetSubGroups(); + + // Lets chomp on the groups now + while ( subGrp ) + { + key = subGrp->GetName(); + + if ( !Q_stricmp( key, "rgb" ) ) + ParseRGB( subGrp ); + else if ( !Q_stricmp( key, "alpha" ) ) + ParseAlpha( subGrp ); + else if ( !Q_stricmp( key, "size" ) || !Q_stricmp( key, "width" ) ) + ParseSize( subGrp ); + else if ( !Q_stricmp( key, "size2" ) || !Q_stricmp( key, "width2" ) ) + ParseSize2( subGrp ); + else if ( !Q_stricmp( key, "length" ) || !Q_stricmp( key, "height" ) ) + ParseLength( subGrp ); + else + theFxHelper.Print( "Unknown group key parsing a particle: %s\n", key ); + + subGrp = (CGPGroup *)subGrp->GetNext(); + } + + return true; +} diff --git a/Projects/Android/jni/OpenJK/codemp_delete/client/FxUtil.cpp b/Projects/Android/jni/OpenJK/codemp_delete/client/FxUtil.cpp new file mode 100644 index 0000000..aaf29fd --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/client/FxUtil.cpp @@ -0,0 +1,1247 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#include "client.h" +#include "FxScheduler.h" + +vec3_t WHITE = {1.0f, 1.0f, 1.0f}; + +struct SEffectList +{ + CEffect *mEffect; + int mKillTime; + bool mPortal; +}; + +#define PI 3.14159f + +SEffectList effectList[MAX_EFFECTS]; +SEffectList *nextValidEffect; +SFxHelper theFxHelper; + +int activeFx = 0; +int drawnFx; +qboolean fxInitialized = qfalse; + +//------------------------- +// FX_Free +// +// Frees all FX +//------------------------- +bool FX_Free( bool templates ) +{ + for ( int i = 0; i < MAX_EFFECTS; i++ ) + { + if ( effectList[i].mEffect ) + { + delete effectList[i].mEffect; + } + + effectList[i].mEffect = 0; + } + + activeFx = 0; + + theFxScheduler.Clean( templates ); + return true; +} + +//------------------------- +// FX_Stop +// +// Frees all active FX but leaves the templates +//------------------------- +void FX_Stop( void ) +{ + for ( int i = 0; i < MAX_EFFECTS; i++ ) + { + if ( effectList[i].mEffect ) + { + delete effectList[i].mEffect; + } + + effectList[i].mEffect = 0; + } + + activeFx = 0; + + theFxScheduler.Clean(false); +} + +//------------------------- +// FX_Init +// +// Preps system for use +//------------------------- +int FX_Init( refdef_t* refdef ) +{ +// FX_Free( true ); + if ( fxInitialized == qfalse ) + { + fxInitialized = qtrue; + + for ( int i = 0; i < MAX_EFFECTS; i++ ) + { + effectList[i].mEffect = 0; + } + } + nextValidEffect = &effectList[0]; + +#ifdef _DEBUG + fx_freeze = Cvar_Get("fx_freeze", "0", CVAR_CHEAT); +#endif + fx_debug = Cvar_Get("fx_debug", "0", CVAR_TEMP); + fx_countScale = Cvar_Get("fx_countScale", "1", CVAR_ARCHIVE_ND); + fx_nearCull = Cvar_Get("fx_nearCull", "16", CVAR_ARCHIVE_ND); + + theFxHelper.ReInit(refdef); + + return true; +} + +void FX_SetRefDef(refdef_t *refdef) +{ + theFxHelper.refdef = refdef; +} + +//------------------------- +// FX_FreeMember +//------------------------- +static void FX_FreeMember( SEffectList *obj ) +{ + obj->mEffect->Die(); + delete obj->mEffect; + obj->mEffect = 0; + + // May as well mark this to be used next + nextValidEffect = obj; + + activeFx--; +} + + +//------------------------- +// FX_GetValidEffect +// +// Finds an unused effect slot +// +// Note - in the editor, this function may return NULL, indicating that all +// effects are being stopped. +//------------------------- +static SEffectList *FX_GetValidEffect() +{ + if ( nextValidEffect->mEffect == 0 ) + { + return nextValidEffect; + } + + int i; + SEffectList *ef; + + // Blah..plow through the list till we find something that is currently untainted + for ( i = 0, ef = effectList; i < MAX_EFFECTS; i++, ef++ ) + { + if ( ef->mEffect == 0 ) + { + return ef; + } + } + + // report the error. +#ifndef FINAL_BUILD + theFxHelper.Print( "FX system out of effects\n" ); +#endif + + // Hmmm.. just trashing the first effect in the list is a poor approach + FX_FreeMember( &effectList[0] ); + + // Recursive call + return nextValidEffect; +} + +//------------------------- +// FX_Add +// +// Adds all fx to the view +//------------------------- +void FX_Add( bool portal ) +{ + int i; + SEffectList *ef; + + drawnFx = 0; + + int numFx = activeFx; //but stop when there can't be any more left! + for ( i = 0, ef = effectList; i < MAX_EFFECTS && numFx; i++, ef++ ) + { + if ( ef->mEffect != 0) + { + --numFx; + if (portal != ef->mPortal) + { + continue; //this one does not render in this scene + } + // Effect is active + if ( theFxHelper.mTime > ef->mKillTime ) + { + // Clean up old effects, calling any death effects as needed + // this flag just has to be cleared otherwise death effects might not happen correctly + ef->mEffect->ClearFlags( FX_KILL_ON_IMPACT ); + FX_FreeMember( ef ); + } + else + { + if ( ef->mEffect->Update() == false ) + { + // We've been marked for death + FX_FreeMember( ef ); + continue; + } + } + } + } + + + if ( fx_debug->integer && !portal) + { + theFxHelper.Print( "Active FX: %i\n", activeFx ); + theFxHelper.Print( "Drawn FX: %i\n", drawnFx ); + theFxHelper.Print( "Scheduled FX: %i High: %i\n", theFxScheduler.NumScheduledFx(), theFxScheduler.GetHighWatermark() ); + } +} + + + +//------------------------- +// FX_AddPrimitive +// +// Note - in the editor, this function may change *pEffect to NULL, indicating that +// all effects are being stopped. +//------------------------- +extern bool gEffectsInPortal; //from FXScheduler.cpp so i don't have to pass it in on EVERY FX_ADD* +void FX_AddPrimitive( CEffect **pEffect, int killTime ) +{ + SEffectList *item = FX_GetValidEffect(); + + item->mEffect = *pEffect; + item->mKillTime = theFxHelper.mTime + killTime; + item->mPortal = gEffectsInPortal; //global set in AddScheduledEffects + + activeFx++; + + // Stash these in the primitive so it has easy access to the vals + (*pEffect)->SetTimeStart( theFxHelper.mTime ); + (*pEffect)->SetTimeEnd( theFxHelper.mTime + killTime ); +} + +//------------------------- +// FX_AddParticle +//------------------------- +CParticle *FX_AddParticle( vec3_t org, vec3_t vel, vec3_t accel, float size1, float size2, float sizeParm, + float alpha1, float alpha2, float alphaParm, + vec3_t sRGB, vec3_t eRGB, float rgbParm, + float rotation, float rotationDelta, + vec3_t min, vec3_t max, float elasticity, + int deathID, int impactID, + int killTime, qhandle_t shader, int flags = 0, + EMatImpactEffect matImpactFX /*MATIMPACTFX_NONE*/, int fxParm /*-1*/, + CGhoul2Info_v *ghoul2/*0*/, int entNum/*-1*/, int modelNum/*-1*/, int boltNum/*-1*/ ) +{ + if ( theFxHelper.mFrameTime < 1 ) + { // disallow adding effects when the system is paused + return 0; + } + + CParticle *fx = new CParticle; + + if ( fx ) + { + if (flags&FX_RELATIVE && ghoul2 != NULL) + { + fx->SetOrigin1( NULL ); + fx->SetOrgOffset( org ); + fx->SetBoltinfo( ghoul2, entNum, modelNum, boltNum ); + } + else + { + fx->SetOrigin1( org ); + } + fx->SetOrigin1( org ); + fx->SetMatImpactFX(matImpactFX); + fx->SetMatImpactParm(fxParm); + fx->SetVel( vel ); + fx->SetAccel( accel ); + + // RGB---------------- + fx->SetRGBStart( sRGB ); + fx->SetRGBEnd( eRGB ); + + if (( flags & FX_RGB_PARM_MASK ) == FX_RGB_WAVE ) + { + fx->SetRGBParm( rgbParm * PI * 0.001f ); + } + else if ( flags & FX_RGB_PARM_MASK ) + { + // rgbParm should be a value from 0-100.. + fx->SetRGBParm( rgbParm * 0.01f * killTime + theFxHelper.mTime ); + } + + // Alpha---------------- + fx->SetAlphaStart( alpha1 ); + fx->SetAlphaEnd( alpha2 ); + + if (( flags & FX_ALPHA_PARM_MASK ) == FX_ALPHA_WAVE ) + { + fx->SetAlphaParm( alphaParm * PI * 0.001f ); + } + else if ( flags & FX_ALPHA_PARM_MASK ) + { + fx->SetAlphaParm( alphaParm * 0.01f * killTime + theFxHelper.mTime ); + } + + // Size---------------- + fx->SetSizeStart( size1 ); + fx->SetSizeEnd( size2 ); + + if (( flags & FX_SIZE_PARM_MASK ) == FX_SIZE_WAVE ) + { + fx->SetSizeParm( sizeParm * PI * 0.001f ); + } + else if ( flags & FX_SIZE_PARM_MASK ) + { + fx->SetSizeParm( sizeParm * 0.01f * killTime + theFxHelper.mTime ); + } + + fx->SetFlags( flags ); + fx->SetShader( shader ); + fx->SetRotation( rotation ); + fx->SetRotationDelta( rotationDelta ); + fx->SetElasticity( elasticity ); + fx->SetMin( min ); + fx->SetMax( max ); + fx->SetDeathFxID( deathID ); + fx->SetImpactFxID( impactID ); + + fx->Init(); + + FX_AddPrimitive( (CEffect**)&fx, killTime ); + } + + return fx; +} + + + +//------------------------- +// FX_AddLine +//------------------------- +CLine *FX_AddLine( vec3_t start, vec3_t end, float size1, float size2, float sizeParm, + float alpha1, float alpha2, float alphaParm, + vec3_t sRGB, vec3_t eRGB, float rgbParm, + int killTime, qhandle_t shader, int flags = 0, + EMatImpactEffect matImpactFX /*MATIMPACTFX_NONE*/, int fxParm /*-1*/, + CGhoul2Info_v *ghoul2/*0*/, int entNum/*-1*/, int modelNum/*-1*/, int boltNum/*-1*/) +{ + if ( theFxHelper.mFrameTime < 1 ) + { // disallow adding new effects when the system is paused + return 0; + } + + CLine *fx = new CLine; + + if ( fx ) + { + if (flags&FX_RELATIVE && ghoul2 != NULL) + { + fx->SetOrigin1( NULL ); + fx->SetOrgOffset( start ); //offset from bolt pos + fx->SetVel( end ); //vel is the vector offset from bolt+orgOffset + fx->SetBoltinfo( ghoul2, entNum, modelNum, boltNum ); + } + else + { + fx->SetOrigin1( start ); + fx->SetOrigin2( end ); + } + fx->SetMatImpactFX(matImpactFX); + fx->SetMatImpactParm(fxParm); + + // RGB---------------- + fx->SetRGBStart( sRGB ); + fx->SetRGBEnd( eRGB ); + + if (( flags & FX_RGB_PARM_MASK ) == FX_RGB_WAVE ) + { + fx->SetRGBParm( rgbParm * PI * 0.001f ); + } + else if ( flags & FX_RGB_PARM_MASK ) + { + // rgbParm should be a value from 0-100.. + fx->SetRGBParm( rgbParm * 0.01f * killTime + theFxHelper.mTime ); + } + + // Alpha---------------- + fx->SetAlphaStart( alpha1 ); + fx->SetAlphaEnd( alpha2 ); + + if (( flags & FX_ALPHA_PARM_MASK ) == FX_ALPHA_WAVE ) + { + fx->SetAlphaParm( alphaParm * PI * 0.001f ); + } + else if ( flags & FX_ALPHA_PARM_MASK ) + { + fx->SetAlphaParm( alphaParm * 0.01f * killTime + theFxHelper.mTime ); + } + + // Size---------------- + fx->SetSizeStart( size1 ); + fx->SetSizeEnd( size2 ); + + if (( flags & FX_SIZE_PARM_MASK ) == FX_SIZE_WAVE ) + { + fx->SetSizeParm( sizeParm * PI * 0.001f ); + } + else if ( flags & FX_SIZE_PARM_MASK ) + { + fx->SetSizeParm( sizeParm * 0.01f * killTime + theFxHelper.mTime ); + } + + fx->SetShader( shader ); + fx->SetFlags( flags ); + + fx->SetSTScale( 1.0f, 1.0f ); + + FX_AddPrimitive( (CEffect**)&fx, killTime ); + } + + return fx; +} + + +//------------------------- +// FX_AddElectricity +//------------------------- +CElectricity *FX_AddElectricity( vec3_t start, vec3_t end, float size1, float size2, float sizeParm, + float alpha1, float alpha2, float alphaParm, + vec3_t sRGB, vec3_t eRGB, float rgbParm, + float chaos, int killTime, qhandle_t shader, int flags = 0, + EMatImpactEffect matImpactFX /*MATIMPACTFX_NONE*/, int fxParm /*-1*/, + CGhoul2Info_v *ghoul2/*0*/, int entNum/*-1*/, int modelNum/*-1*/, int boltNum/*-1*/ ) +{ + if ( theFxHelper.mFrameTime < 1 ) + { // disallow adding new effects when the system is paused + return 0; + } + + CElectricity *fx = new CElectricity; + + if ( fx ) + { + if (flags&FX_RELATIVE && ghoul2 != NULL) + { + fx->SetOrigin1( NULL ); + fx->SetOrgOffset( start );//offset + fx->SetVel( end ); //vel is the vector offset from bolt+orgOffset + fx->SetBoltinfo( ghoul2, entNum, modelNum, boltNum ); + } + else + { + fx->SetOrigin1( start ); + fx->SetOrigin2( end ); + } + fx->SetMatImpactFX(matImpactFX); + fx->SetMatImpactParm(fxParm); + + // RGB---------------- + fx->SetRGBStart( sRGB ); + fx->SetRGBEnd( eRGB ); + + if (( flags & FX_RGB_PARM_MASK ) == FX_RGB_WAVE ) + { + fx->SetRGBParm( rgbParm * PI * 0.001f ); + } + else if ( flags & FX_RGB_PARM_MASK ) + { + // rgbParm should be a value from 0-100.. + fx->SetRGBParm( rgbParm * 0.01f * killTime + theFxHelper.mTime ); + } + + // Alpha---------------- + fx->SetAlphaStart( alpha1 ); + fx->SetAlphaEnd( alpha2 ); + + if (( flags & FX_ALPHA_PARM_MASK ) == FX_ALPHA_WAVE ) + { + fx->SetAlphaParm( alphaParm * PI * 0.001f ); + } + else if ( flags & FX_ALPHA_PARM_MASK ) + { + fx->SetAlphaParm( alphaParm * 0.01f * killTime + theFxHelper.mTime ); + } + + // Size---------------- + fx->SetSizeStart( size1 ); + fx->SetSizeEnd( size2 ); + + if (( flags & FX_SIZE_PARM_MASK ) == FX_SIZE_WAVE ) + { + fx->SetSizeParm( sizeParm * PI * 0.001f ); + } + else if ( flags & FX_SIZE_PARM_MASK ) + { + fx->SetSizeParm( sizeParm * 0.01f * killTime + theFxHelper.mTime ); + } + + fx->SetShader( shader ); + fx->SetFlags( flags ); + fx->SetChaos( chaos ); + + fx->SetSTScale( 1.0f, 1.0f ); + + FX_AddPrimitive( (CEffect**)&fx, killTime ); + // in the editor, fx may now be NULL? + if ( fx ) + { + fx->Initialize(); + } + } + + return fx; +} + + +//------------------------- +// FX_AddTail +//------------------------- +CTail *FX_AddTail( vec3_t org, vec3_t vel, vec3_t accel, + float size1, float size2, float sizeParm, + float length1, float length2, float lengthParm, + float alpha1, float alpha2, float alphaParm, + vec3_t sRGB, vec3_t eRGB, float rgbParm, + vec3_t min, vec3_t max, float elasticity, + int deathID, int impactID, + int killTime, qhandle_t shader, int flags = 0, + EMatImpactEffect matImpactFX /*MATIMPACTFX_NONE*/, int fxParm /*-1*/, + CGhoul2Info_v *ghoul2/*0*/, int entNum/*-1*/, int modelNum/*-1*/, int boltNum/*-1*/ ) +{ + if ( theFxHelper.mFrameTime < 1 ) + { // disallow adding effects when the system is paused + return 0; + } + + CTail *fx = new CTail; + + if ( fx ) + { + if (flags&FX_RELATIVE && ghoul2 != NULL) + { + fx->SetOrigin1( NULL ); + fx->SetOrgOffset( org ); + fx->SetBoltinfo( ghoul2, entNum, modelNum, boltNum ); + } + else + { + fx->SetOrigin1( org ); + } + fx->SetMatImpactFX(matImpactFX); + fx->SetMatImpactParm(fxParm); + fx->SetVel( vel ); + fx->SetAccel( accel ); + + // RGB---------------- + fx->SetRGBStart( sRGB ); + fx->SetRGBEnd( eRGB ); + + if (( flags & FX_RGB_PARM_MASK ) == FX_RGB_WAVE ) + { + fx->SetRGBParm( rgbParm * PI * 0.001f ); + } + else if ( flags & FX_RGB_PARM_MASK ) + { + // rgbParm should be a value from 0-100.. + fx->SetRGBParm( rgbParm * 0.01f * killTime + theFxHelper.mTime ); + } + + // Alpha---------------- + fx->SetAlphaStart( alpha1 ); + fx->SetAlphaEnd( alpha2 ); + + if (( flags & FX_ALPHA_PARM_MASK ) == FX_ALPHA_WAVE ) + { + fx->SetAlphaParm( alphaParm * PI * 0.001f ); + } + else if ( flags & FX_ALPHA_PARM_MASK ) + { + fx->SetAlphaParm( alphaParm * 0.01f * killTime + theFxHelper.mTime ); + } + + // Size---------------- + fx->SetSizeStart( size1 ); + fx->SetSizeEnd( size2 ); + + if (( flags & FX_SIZE_PARM_MASK ) == FX_SIZE_WAVE ) + { + fx->SetSizeParm( sizeParm * PI * 0.001f ); + } + else if ( flags & FX_SIZE_PARM_MASK ) + { + fx->SetSizeParm( sizeParm * 0.01f * killTime + theFxHelper.mTime ); + } + + // Length---------------- + fx->SetLengthStart( length1 ); + fx->SetLengthEnd( length2 ); + + if (( flags & FX_LENGTH_PARM_MASK ) == FX_LENGTH_WAVE ) + { + fx->SetLengthParm( lengthParm * PI * 0.001f ); + } + else if ( flags & FX_LENGTH_PARM_MASK ) + { + fx->SetLengthParm( lengthParm * 0.01f * killTime + theFxHelper.mTime ); + } + + fx->SetFlags( flags ); + fx->SetShader( shader ); + fx->SetElasticity( elasticity ); + fx->SetMin( min ); + fx->SetMax( max ); + fx->SetSTScale( 1.0f, 1.0f ); + fx->SetDeathFxID( deathID ); + fx->SetImpactFxID( impactID ); + + FX_AddPrimitive( (CEffect**)&fx, killTime ); + } + + return fx; +} + + +//------------------------- +// FX_AddCylinder +//------------------------- +CCylinder *FX_AddCylinder( vec3_t start, vec3_t normal, + float size1s, float size1e, float size1Parm, + float size2s, float size2e, float size2Parm, + float length1, float length2, float lengthParm, + float alpha1, float alpha2, float alphaParm, + vec3_t rgb1, vec3_t rgb2, float rgbParm, + int killTime, qhandle_t shader, int flags, + EMatImpactEffect matImpactFX /*MATIMPACTFX_NONE*/, int fxParm /*-1*/, + CGhoul2Info_v *ghoul2/*0*/, int entNum/*-1*/, int modelNum/*-1*/, int boltNum/*-1*/, + qboolean traceEnd) +{ + if ( theFxHelper.mFrameTime < 1 ) + { // disallow adding new effects when the system is paused + return 0; + } + + CCylinder *fx = new CCylinder; + + if ( fx ) + { + if (flags&FX_RELATIVE && ghoul2 != NULL) + { + fx->SetOrigin1( NULL ); + fx->SetOrgOffset( start );//offset + fx->SetBoltinfo( ghoul2, entNum, modelNum, boltNum ); + } + else + { + fx->SetOrigin1( start ); + } + fx->SetTraceEnd(traceEnd); + + fx->SetMatImpactFX(matImpactFX); + fx->SetMatImpactParm(fxParm); + fx->SetOrigin1( start ); + fx->SetNormal( normal ); + + // RGB---------------- + fx->SetRGBStart( rgb1 ); + fx->SetRGBEnd( rgb2 ); + + if (( flags & FX_RGB_PARM_MASK ) == FX_RGB_WAVE ) + { + fx->SetRGBParm( rgbParm * PI * 0.001f ); + } + else if ( flags & FX_RGB_PARM_MASK ) + { + // rgbParm should be a value from 0-100.. + fx->SetRGBParm( rgbParm * 0.01f * killTime + theFxHelper.mTime ); + } + + // Size1---------------- + fx->SetSizeStart( size1s ); + fx->SetSizeEnd( size1e ); + + if (( flags & FX_SIZE_PARM_MASK ) == FX_SIZE_WAVE ) + { + fx->SetSizeParm( size1Parm * PI * 0.001f ); + } + else if ( flags & FX_SIZE_PARM_MASK ) + { + fx->SetSizeParm( size1Parm * 0.01f * killTime + theFxHelper.mTime ); + } + + // Size2---------------- + fx->SetSize2Start( size2s ); + fx->SetSize2End( size2e ); + + if (( flags & FX_SIZE2_PARM_MASK ) == FX_SIZE2_WAVE ) + { + fx->SetSize2Parm( size2Parm * PI * 0.001f ); + } + else if ( flags & FX_SIZE2_PARM_MASK ) + { + fx->SetSize2Parm( size2Parm * 0.01f * killTime + theFxHelper.mTime ); + } + + // Length1--------------- + fx->SetLengthStart( length1 ); + fx->SetLengthEnd( length2 ); + + if (( flags & FX_LENGTH_PARM_MASK ) == FX_LENGTH_WAVE ) + { + fx->SetLengthParm( lengthParm * PI * 0.001f ); + } + else if ( flags & FX_LENGTH_PARM_MASK ) + { + fx->SetLengthParm( lengthParm * 0.01f * killTime + theFxHelper.mTime ); + } + + // Alpha---------------- + fx->SetAlphaStart( alpha1 ); + fx->SetAlphaEnd( alpha2 ); + + if (( flags & FX_ALPHA_PARM_MASK ) == FX_ALPHA_WAVE ) + { + fx->SetAlphaParm( alphaParm * PI * 0.001f ); + } + else if ( flags & FX_ALPHA_PARM_MASK ) + { + fx->SetAlphaParm( alphaParm * 0.01f * killTime + theFxHelper.mTime ); + } + + fx->SetShader( shader ); + fx->SetFlags( flags ); + + FX_AddPrimitive( (CEffect**)&fx, killTime ); + } + + return fx; +} + +//------------------------- +// FX_AddEmitter +//------------------------- +CEmitter *FX_AddEmitter( vec3_t org, vec3_t vel, vec3_t accel, + float size1, float size2, float sizeParm, + float alpha1, float alpha2, float alphaParm, + vec3_t rgb1, vec3_t rgb2, float rgbParm, + vec3_t angs, vec3_t deltaAngs, + vec3_t min, vec3_t max, float elasticity, + int deathID, int impactID, int emitterID, + float density, float variance, + int killTime, qhandle_t model, int flags = 0, + EMatImpactEffect matImpactFX /*MATIMPACTFX_NONE*/, int fxParm /*-1*/, + CGhoul2Info_v *ghoul2/*0*/, int entNum/*-1*/, int modelNum/*-1*/, int boltNum/*-1*/ ) +{ + if ( theFxHelper.mFrameTime < 1 ) + { // disallow adding effects when the system is paused + return 0; + } + + CEmitter *fx = new CEmitter; + + if ( fx ) + { + if (flags&FX_RELATIVE && ghoul2 != NULL) + { + assert(0);//not done +// fx->SetBoltinfo( ghoul2, entNum, modelNum, boltNum ); + } + fx->SetMatImpactFX(matImpactFX); + fx->SetMatImpactParm(fxParm); + fx->SetOrigin1( org ); + fx->SetVel( vel ); + fx->SetAccel( accel ); + + // RGB---------------- + fx->SetRGBStart( rgb1 ); + fx->SetRGBEnd( rgb2 ); + + if (( flags & FX_RGB_PARM_MASK ) == FX_RGB_WAVE ) + { + fx->SetRGBParm( rgbParm * PI * 0.001f ); + } + else if ( flags & FX_RGB_PARM_MASK ) + { + // rgbParm should be a value from 0-100.. + fx->SetRGBParm( rgbParm * 0.01f * killTime + theFxHelper.mTime ); + } + + // Size---------------- + fx->SetSizeStart( size1 ); + fx->SetSizeEnd( size2 ); + + if (( flags & FX_SIZE_PARM_MASK ) == FX_SIZE_WAVE ) + { + fx->SetSizeParm( sizeParm * PI * 0.001f ); + } + else if ( flags & FX_SIZE_PARM_MASK ) + { + fx->SetSizeParm( sizeParm * 0.01f * killTime + theFxHelper.mTime ); + } + + // Alpha---------------- + fx->SetAlphaStart( alpha1 ); + fx->SetAlphaEnd( alpha2 ); + + if (( flags & FX_ALPHA_PARM_MASK ) == FX_ALPHA_WAVE ) + { + fx->SetAlphaParm( alphaParm * PI * 0.001f ); + } + else if ( flags & FX_ALPHA_PARM_MASK ) + { + fx->SetAlphaParm( alphaParm * 0.01f * killTime + theFxHelper.mTime ); + } + + fx->SetAngles( angs ); + fx->SetAngleDelta( deltaAngs ); + fx->SetFlags( flags ); + fx->SetModel( model ); + fx->SetElasticity( elasticity ); + fx->SetMin( min ); + fx->SetMax( max ); + fx->SetDeathFxID( deathID ); + fx->SetImpactFxID( impactID ); + fx->SetEmitterFxID( emitterID ); + fx->SetDensity( density ); + fx->SetVariance( variance ); + fx->SetOldTime( theFxHelper.mTime ); + + fx->SetLastOrg( org ); + fx->SetLastVel( vel ); + + FX_AddPrimitive( (CEffect**)&fx, killTime ); + } + + return fx; +} + +//------------------------- +// FX_AddLight +//------------------------- +CLight *FX_AddLight( vec3_t org, float size1, float size2, float sizeParm, + vec3_t rgb1, vec3_t rgb2, float rgbParm, + int killTime, int flags = 0, + EMatImpactEffect matImpactFX /*MATIMPACTFX_NONE*/, int fxParm /*-1*/, + CGhoul2Info_v *ghoul2/*0*/, int entNum/*-1*/, int modelNum/*-1*/, int boltNum/*-1*/) +{ + if ( theFxHelper.mFrameTime < 1 ) + { // disallow adding effects when the system is paused + return 0; + } + + CLight *fx = new CLight; + + if ( fx ) + { + if (flags&FX_RELATIVE && ghoul2 != NULL) + { + fx->SetOrigin1( NULL ); + fx->SetOrgOffset( org );//offset + fx->SetBoltinfo( ghoul2, entNum, modelNum, boltNum ); + } + else + { + fx->SetOrigin1( org ); + } + fx->SetMatImpactFX(matImpactFX); + fx->SetMatImpactParm(fxParm); + + // RGB---------------- + fx->SetRGBStart( rgb1 ); + fx->SetRGBEnd( rgb2 ); + + if (( flags & FX_RGB_PARM_MASK ) == FX_RGB_WAVE ) + { + fx->SetRGBParm( rgbParm * PI * 0.001f ); + } + else if ( flags & FX_RGB_PARM_MASK ) + { + // rgbParm should be a value from 0-100.. + fx->SetRGBParm( rgbParm * 0.01f * killTime + theFxHelper.mTime ); + } + + // Size---------------- + fx->SetSizeStart( size1 ); + fx->SetSizeEnd( size2 ); + + if (( flags & FX_SIZE_PARM_MASK ) == FX_SIZE_WAVE ) + { + fx->SetSizeParm( sizeParm * PI * 0.001f ); + } + else if ( flags & FX_SIZE_PARM_MASK ) + { + fx->SetSizeParm( sizeParm * 0.01f * killTime + theFxHelper.mTime ); + } + + fx->SetFlags( flags ); + + FX_AddPrimitive( (CEffect**)&fx, killTime ); + } + + return fx; + +} + + +//------------------------- +// FX_AddOrientedParticle +//------------------------- +COrientedParticle *FX_AddOrientedParticle( vec3_t org, vec3_t norm, vec3_t vel, vec3_t accel, + float size1, float size2, float sizeParm, + float alpha1, float alpha2, float alphaParm, + vec3_t rgb1, vec3_t rgb2, float rgbParm, + float rotation, float rotationDelta, + vec3_t min, vec3_t max, float bounce, + int deathID, int impactID, + int killTime, qhandle_t shader, int flags = 0, + EMatImpactEffect matImpactFX /*MATIMPACTFX_NONE*/, int fxParm /*-1*/, + CGhoul2Info_v *ghoul2/*0*/, int entNum/*-1*/, int modelNum/*-1*/, int boltNum/*-1*/ ) +{ + if ( theFxHelper.mFrameTime < 1 ) + { // disallow adding effects when the system is paused + return 0; + } + + COrientedParticle *fx = new COrientedParticle; + + if ( fx ) + { + if (flags&FX_RELATIVE && ghoul2 != NULL) + { + fx->SetOrigin1( NULL ); + fx->SetOrgOffset( org );//offset + fx->SetBoltinfo( ghoul2, entNum, modelNum, boltNum ); + } + else + { + fx->SetOrigin1( org ); + } + fx->SetMatImpactFX(matImpactFX); + fx->SetMatImpactParm(fxParm); + fx->SetOrigin1( org ); + fx->SetNormal( norm ); + fx->SetVel( vel ); + fx->SetAccel( accel ); + + // RGB---------------- + fx->SetRGBStart( rgb1 ); + fx->SetRGBEnd( rgb2 ); + + if (( flags & FX_RGB_PARM_MASK ) == FX_RGB_WAVE ) + { + fx->SetRGBParm( rgbParm * PI * 0.001f ); + } + else if ( flags & FX_RGB_PARM_MASK ) + { + // rgbParm should be a value from 0-100.. + fx->SetRGBParm( rgbParm * 0.01f * killTime + theFxHelper.mTime ); + } + + // Alpha---------------- + fx->SetAlphaStart( alpha1 ); + fx->SetAlphaEnd( alpha2 ); + + if (( flags & FX_ALPHA_PARM_MASK ) == FX_ALPHA_WAVE ) + { + fx->SetAlphaParm( alphaParm * PI * 0.001f ); + } + else if ( flags & FX_ALPHA_PARM_MASK ) + { + fx->SetAlphaParm( alphaParm * 0.01f * killTime + theFxHelper.mTime ); + } + + // Size---------------- + fx->SetSizeStart( size1 ); + fx->SetSizeEnd( size2 ); + + if (( flags & FX_SIZE_PARM_MASK ) == FX_SIZE_WAVE ) + { + fx->SetSizeParm( sizeParm * PI * 0.001f ); + } + else if ( flags & FX_SIZE_PARM_MASK ) + { + fx->SetSizeParm( sizeParm * 0.01f * killTime + theFxHelper.mTime ); + } + + fx->SetFlags( flags ); + fx->SetShader( shader ); + fx->SetRotation( rotation ); + fx->SetRotationDelta( rotationDelta ); + fx->SetElasticity( bounce ); + fx->SetMin( min ); + fx->SetMax( max ); + fx->SetDeathFxID( deathID ); + fx->SetImpactFxID( impactID ); + + FX_AddPrimitive( (CEffect**)&fx, killTime ); + } + + return fx; +} + + +//------------------------- +// FX_AddPoly +//------------------------- +CPoly *FX_AddPoly( vec3_t *verts, vec2_t *st, int numVerts, + vec3_t vel, vec3_t accel, + float alpha1, float alpha2, float alphaParm, + vec3_t rgb1, vec3_t rgb2, float rgbParm, + vec3_t rotationDelta, float bounce, int motionDelay, + int killTime, qhandle_t shader, int flags ) +{ + if ( theFxHelper.mFrameTime < 1 || !verts ) + { // disallow adding effects when the system is paused or the user doesn't pass in a vert array + return 0; + } + + CPoly *fx = new CPoly; + + if ( fx ) + { + // Do a cheesy copy of the verts and texture coords into our own structure + for ( int i = 0; i < numVerts; i++ ) + { + VectorCopy( verts[i], fx->mOrg[i] ); + VectorCopy2( st[i], fx->mST[i] ); + } + + fx->SetVel( vel ); + fx->SetAccel( accel ); + + // RGB---------------- + fx->SetRGBStart( rgb1 ); + fx->SetRGBEnd( rgb2 ); + + if (( flags & FX_RGB_PARM_MASK ) == FX_RGB_WAVE ) + { + fx->SetRGBParm( rgbParm * PI * 0.001f ); + } + else if ( flags & FX_RGB_PARM_MASK ) + { + // rgbParm should be a value from 0-100.. + fx->SetRGBParm( rgbParm * 0.01f * killTime + theFxHelper.mTime ); + } + + // Alpha---------------- + fx->SetAlphaStart( alpha1 ); + fx->SetAlphaEnd( alpha2 ); + + if (( flags & FX_ALPHA_PARM_MASK ) == FX_ALPHA_WAVE ) + { + fx->SetAlphaParm( alphaParm * PI * 0.001f ); + } + else if ( flags & FX_ALPHA_PARM_MASK ) + { + fx->SetAlphaParm( alphaParm * 0.01f * killTime + theFxHelper.mTime ); + } + + fx->SetFlags( flags ); + fx->SetShader( shader ); + fx->SetRot( rotationDelta ); + fx->SetElasticity( bounce ); + fx->SetMotionTimeStamp( motionDelay ); + fx->SetNumVerts( numVerts ); + + // Now that we've set our data up, let's process it into a useful format + fx->PolyInit(); + + FX_AddPrimitive( (CEffect**)&fx, killTime ); + } + + return fx; +} + + +//------------------------- +// FX_AddFlash +//------------------------- +CFlash *FX_AddFlash( vec3_t origin, + float size1, float size2, float sizeParm, + float alpha1, float alpha2, float alphaParm, + vec3_t sRGB, vec3_t eRGB, float rgbParm, + int killTime, qhandle_t shader, int flags, + EMatImpactEffect matImpactFX /*MATIMPACTFX_NONE*/, int fxParm /*-1*/ ) +{ + if ( theFxHelper.mFrameTime < 1 ) + { // disallow adding new effects when the system is paused + return 0; + } + + if (!shader) + { //yeah..this is bad, I guess, but SP seems to handle it by not drawing the flash, so I will too. + assert(shader); + return 0; + } + + CFlash *fx = new CFlash; + + if ( fx ) + { + fx->SetMatImpactFX(matImpactFX); + fx->SetMatImpactParm(fxParm); + fx->SetOrigin1( origin ); + + // RGB---------------- + fx->SetRGBStart( sRGB ); + fx->SetRGBEnd( eRGB ); + + if (( flags & FX_RGB_PARM_MASK ) == FX_RGB_WAVE ) + { + fx->SetRGBParm( rgbParm * PI * 0.001f ); + } + else if ( flags & FX_RGB_PARM_MASK ) + { + // rgbParm should be a value from 0-100.. + fx->SetRGBParm( rgbParm * 0.01f * killTime + theFxHelper.mTime ); + } + + // Alpha---------------- + fx->SetAlphaStart( alpha1 ); + fx->SetAlphaEnd( alpha2 ); + + if (( flags & FX_ALPHA_PARM_MASK ) == FX_ALPHA_WAVE ) + { + fx->SetAlphaParm( alphaParm * PI * 0.001f ); + } + else if ( flags & FX_ALPHA_PARM_MASK ) + { + fx->SetAlphaParm( alphaParm * 0.01f * killTime + theFxHelper.mTime ); + } + + // Size---------------- + fx->SetSizeStart( size1 ); + fx->SetSizeEnd( size2 ); + + if (( flags & FX_SIZE_PARM_MASK ) == FX_SIZE_WAVE ) + { + fx->SetSizeParm( sizeParm * PI * 0.001f ); + } + else if ( flags & FX_SIZE_PARM_MASK ) + { + fx->SetSizeParm( sizeParm * 0.01f * killTime + theFxHelper.mTime ); + } + + fx->SetShader( shader ); + fx->SetFlags( flags ); + +// fx->SetSTScale( 1.0f, 1.0f ); + + fx->Init(); + + FX_AddPrimitive( (CEffect**)&fx, killTime ); + } + + return fx; +} + +//------------------------- +// FX_AddBezier +//------------------------- +CBezier *FX_AddBezier( vec3_t start, vec3_t end, + vec3_t control1, vec3_t control1Vel, + vec3_t control2, vec3_t control2Vel, + float size1, float size2, float sizeParm, + float alpha1, float alpha2, float alphaParm, + vec3_t sRGB, vec3_t eRGB, float rgbParm, + int killTime, qhandle_t shader, int flags ) +{ + if ( theFxHelper.mFrameTime < 1 ) + { // disallow adding new effects when the system is paused + return 0; + } + + CBezier *fx = new CBezier; + + if ( fx ) + { + fx->SetOrigin1( start ); + fx->SetOrigin2( end ); + + fx->SetControlPoints( control1, control2 ); + fx->SetControlVel( control1Vel, control2Vel ); + + // RGB---------------- + fx->SetRGBStart( sRGB ); + fx->SetRGBEnd( eRGB ); + + if (( flags & FX_RGB_PARM_MASK ) == FX_RGB_WAVE ) + { + fx->SetRGBParm( rgbParm * PI * 0.001f ); + } + else if ( flags & FX_RGB_PARM_MASK ) + { + // rgbParm should be a value from 0-100.. + fx->SetRGBParm( rgbParm * 0.01f * killTime + theFxHelper.mTime ); + } + + // Alpha---------------- + fx->SetAlphaStart( alpha1 ); + fx->SetAlphaEnd( alpha2 ); + + if (( flags & FX_ALPHA_PARM_MASK ) == FX_ALPHA_WAVE ) + { + fx->SetAlphaParm( alphaParm * PI * 0.001f ); + } + else if ( flags & FX_ALPHA_PARM_MASK ) + { + fx->SetAlphaParm( alphaParm * 0.01f * killTime + theFxHelper.mTime ); + } + + // Size---------------- + fx->SetSizeStart( size1 ); + fx->SetSizeEnd( size2 ); + + if (( flags & FX_SIZE_PARM_MASK ) == FX_SIZE_WAVE ) + { + fx->SetSizeParm( sizeParm * PI * 0.001f ); + } + else if ( flags & FX_SIZE_PARM_MASK ) + { + fx->SetSizeParm( sizeParm * 0.01f * killTime + theFxHelper.mTime ); + } + + fx->SetShader( shader ); + fx->SetFlags( flags ); + + fx->SetSTScale( 1.0f, 1.0f ); + + FX_AddPrimitive( (CEffect**)&fx, killTime ); + } + + return fx; +} diff --git a/Projects/Android/jni/OpenJK/codemp_delete/client/FxUtil.h b/Projects/Android/jni/OpenJK/codemp_delete/client/FxUtil.h new file mode 100644 index 0000000..54d0155 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/client/FxUtil.h @@ -0,0 +1,131 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#pragma once + +#include "FxPrimitives.h" + +bool FX_Free( bool templates ); // ditches all active effects; +int FX_Init( refdef_t* refdef ); // called in CG_Init to purge the fx system. +void FX_SetRefDef(refdef_t *refdef); +void FX_Add( bool portal ); // called every cgame frame to add all fx into the scene. +void FX_Stop( void ); // ditches all active effects without touching the templates. + + +CParticle *FX_AddParticle( vec3_t org, vec3_t vel, vec3_t accel, + float size1, float size2, float sizeParm, + float alpha1, float alpha2, float alphaParm, + vec3_t rgb1, vec3_t rgb2, float rgbParm, + float rotation, float rotationDelta, + vec3_t min, vec3_t max, float elasticity, + int deathID, int impactID, + int killTime, qhandle_t shader, int flags, + EMatImpactEffect matImpactFX = MATIMPACTFX_NONE, int fxParm = -1, + CGhoul2Info_v *ghoul2 = NULL, int entNum=-1, int modelNum=-1, int boltNum=-1); + +CLine *FX_AddLine( vec3_t start, vec3_t end, + float size1, float size2, float sizeParm, + float alpha1, float alpha2, float alphaParm, + vec3_t rgb1, vec3_t rgb2, float rgbParm, + int killTime, qhandle_t shader, int flags, + EMatImpactEffect matImpactFX = MATIMPACTFX_NONE, int fxParm = -1, + CGhoul2Info_v *ghoul2 = NULL, int entNum=-1, int modelNum=-1, int boltNum=-1); + +CElectricity *FX_AddElectricity( vec3_t start, vec3_t end, float size1, float size2, float sizeParm, + float alpha1, float alpha2, float alphaParm, + vec3_t sRGB, vec3_t eRGB, float rgbParm, + float chaos, int killTime, qhandle_t shader, int flags, + EMatImpactEffect matImpactFX = MATIMPACTFX_NONE, int fxParm = -1, + CGhoul2Info_v *ghoul2 = NULL, int entNum=-1, int modelNum=-1, int boltNum=-1); + +CTail *FX_AddTail( vec3_t org, vec3_t vel, vec3_t accel, + float size1, float size2, float sizeParm, + float length1, float length2, float lengthParm, + float alpha1, float alpha2, float alphaParm, + vec3_t rgb1, vec3_t rgb2, float rgbParm, + vec3_t min, vec3_t max, float elasticity, + int deathID, int impactID, + int killTime, qhandle_t shader, int flags, + EMatImpactEffect matImpactFX = MATIMPACTFX_NONE, int fxParm = -1, + CGhoul2Info_v *ghoul2 = NULL, int entNum=-1, int modelNum=-1, int boltNum=-1); + +CCylinder *FX_AddCylinder( vec3_t start, vec3_t normal, + float size1s, float size1e, float size1Parm, + float size2s, float size2e, float size2Parm, + float length1, float length2, float lengthParm, + float alpha1, float alpha2, float alphaParm, + vec3_t rgb1, vec3_t rgb2, float rgbParm, + int killTime, qhandle_t shader, int flags, + EMatImpactEffect matImpactFX = MATIMPACTFX_NONE, int fxParm = -1, + CGhoul2Info_v *ghoul2 = NULL, int entNum=-1, int modelNum=-1, int boltNum=-1, + qboolean traceEnd = qfalse); + +CEmitter *FX_AddEmitter( vec3_t org, vec3_t vel, vec3_t accel, + float size1, float size2, float sizeParm, + float alpha1, float alpha2, float alphaParm, + vec3_t rgb1, vec3_t rgb2, float rgbParm, + vec3_t angs, vec3_t deltaAngs, + vec3_t min, vec3_t max, float elasticity, + int deathID, int impactID, int emitterID, + float density, float variance, + int killTime, qhandle_t model, int flags, + EMatImpactEffect matImpactFX = MATIMPACTFX_NONE, int fxParm = -1, + CGhoul2Info_v *ghoul2 = NULL, int entNum=-1, int modelNum=-1, int boltNum=-1); + +CLight *FX_AddLight( vec3_t org, float size1, float size2, float sizeParm, + vec3_t rgb1, vec3_t rgb2, float rgbParm, + int killTime, int flags, + EMatImpactEffect matImpactFX = MATIMPACTFX_NONE, int fxParm = -1, + CGhoul2Info_v *ghoul2 = NULL, int entNum=-1, int modelNum=-1, int boltNum=-1); + +COrientedParticle *FX_AddOrientedParticle( vec3_t org, vec3_t norm, vec3_t vel, vec3_t accel, + float size1, float size2, float sizeParm, + float alpha1, float alpha2, float alphaParm, + vec3_t rgb1, vec3_t rgb2, float rgbParm, + float rotation, float rotationDelta, + vec3_t min, vec3_t max, float bounce, + int deathID, int impactID, + int killTime, qhandle_t shader, int flags, + EMatImpactEffect matImpactFX = MATIMPACTFX_NONE, int fxParm = -1, + CGhoul2Info_v *ghoul2 = NULL, int entNum=-1, int modelNum=-1, int boltNum=-1); + +CPoly *FX_AddPoly( vec3_t *verts, vec2_t *st, int numVerts, + vec3_t vel, vec3_t accel, + float alpha1, float alpha2, float alphaParm, + vec3_t rgb1, vec3_t rgb2, float rgbParm, + vec3_t rotationDelta, float bounce, int motionDelay, + int killTime, qhandle_t shader, int flags ); + +CFlash *FX_AddFlash( vec3_t origin, + float size1, float size2, float sizeParm, + float alpha1, float alpha2, float alphaParm, + vec3_t sRGB, vec3_t eRGB, float rgbParm, + int killTime, qhandle_t shader, int flags = 0, + EMatImpactEffect matImpactFX = MATIMPACTFX_NONE, int fxParm = -1); + +CBezier *FX_AddBezier( vec3_t start, vec3_t end, + vec3_t control1, vec3_t control1Vel, + vec3_t control2, vec3_t control2Vel, + float size1, float size2, float sizeParm, + float alpha1, float alpha2, float alphaParm, + vec3_t sRGB, vec3_t eRGB, float rgbParm, + int killTime, qhandle_t shader, int flags = 0 ); diff --git a/Projects/Android/jni/OpenJK/codemp/client/OpenAL/al.h b/Projects/Android/jni/OpenJK/codemp_delete/client/OpenAL/al.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/OpenAL/al.h rename to Projects/Android/jni/OpenJK/codemp_delete/client/OpenAL/al.h diff --git a/Projects/Android/jni/OpenJK/codemp/client/OpenAL/alc.h b/Projects/Android/jni/OpenJK/codemp_delete/client/OpenAL/alc.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/OpenAL/alc.h rename to Projects/Android/jni/OpenJK/codemp_delete/client/OpenAL/alc.h diff --git a/Projects/Android/jni/OpenJK/codemp/client/OpenAL/alctypes.h b/Projects/Android/jni/OpenJK/codemp_delete/client/OpenAL/alctypes.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/OpenAL/alctypes.h rename to Projects/Android/jni/OpenJK/codemp_delete/client/OpenAL/alctypes.h diff --git a/Projects/Android/jni/OpenJK/codemp/client/OpenAL/altypes.h b/Projects/Android/jni/OpenJK/codemp_delete/client/OpenAL/altypes.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/OpenAL/altypes.h rename to Projects/Android/jni/OpenJK/codemp_delete/client/OpenAL/altypes.h diff --git a/Projects/Android/jni/OpenJK/codemp/client/OpenAL/alu.h b/Projects/Android/jni/OpenJK/codemp_delete/client/OpenAL/alu.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/OpenAL/alu.h rename to Projects/Android/jni/OpenJK/codemp_delete/client/OpenAL/alu.h diff --git a/Projects/Android/jni/OpenJK/codemp/client/OpenAL/alut.h b/Projects/Android/jni/OpenJK/codemp_delete/client/OpenAL/alut.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/OpenAL/alut.h rename to Projects/Android/jni/OpenJK/codemp_delete/client/OpenAL/alut.h diff --git a/Projects/Android/jni/OpenJK/codemp_delete/client/cl_avi.cpp b/Projects/Android/jni/OpenJK/codemp_delete/client/cl_avi.cpp new file mode 100644 index 0000000..2a8c268 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/client/cl_avi.cpp @@ -0,0 +1,680 @@ +/* +=========================================================================== +Copyright (C) 2005-2006 Tim Angus + +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 +=========================================================================== +*/ + +#include "client.h" +#include "snd_local.h" + +#define INDEX_FILE_EXTENSION ".index.dat" + +#define MAX_RIFF_CHUNKS 16 + +typedef struct audioFormat_s +{ + int rate; + int format; + int channels; + int bits; + + int sampleSize; + int totalBytes; +} audioFormat_t; + +typedef struct aviFileData_s +{ + qboolean fileOpen; + fileHandle_t f; + char fileName[ MAX_QPATH ]; + int fileSize; + int moviOffset; + int moviSize; + + fileHandle_t idxF; + int numIndices; + + int frameRate; + int framePeriod; + int width, height; + int numVideoFrames; + int maxRecordSize; + qboolean motionJpeg; + + qboolean audio; + audioFormat_t a; + int numAudioFrames; + + int chunkStack[ MAX_RIFF_CHUNKS ]; + int chunkStackTop; + + byte *cBuffer, *eBuffer; +} aviFileData_t; + +static aviFileData_t afd; + +#define MAX_AVI_BUFFER 2048 + +static byte buffer[ MAX_AVI_BUFFER ]; +static int bufIndex; + +/* +=============== +SafeFS_Write +=============== +*/ +static QINLINE void SafeFS_Write( const void *buffer, int len, fileHandle_t f ) +{ + if( FS_Write( buffer, len, f ) < len ) + Com_Error( ERR_DROP, "Failed to write avi file" ); +} + +/* +=============== +WRITE_STRING +=============== +*/ +static QINLINE void WRITE_STRING( const char *s ) +{ + Com_Memcpy( &buffer[ bufIndex ], s, strlen( s ) ); + bufIndex += strlen( s ); +} + +/* +=============== +WRITE_4BYTES +=============== +*/ +static QINLINE void WRITE_4BYTES( int x ) +{ + buffer[ bufIndex + 0 ] = (byte)( ( x >> 0 ) & 0xFF ); + buffer[ bufIndex + 1 ] = (byte)( ( x >> 8 ) & 0xFF ); + buffer[ bufIndex + 2 ] = (byte)( ( x >> 16 ) & 0xFF ); + buffer[ bufIndex + 3 ] = (byte)( ( x >> 24 ) & 0xFF ); + bufIndex += 4; +} + +/* +=============== +WRITE_2BYTES +=============== +*/ +static QINLINE void WRITE_2BYTES( int x ) +{ + buffer[ bufIndex + 0 ] = (byte)( ( x >> 0 ) & 0xFF ); + buffer[ bufIndex + 1 ] = (byte)( ( x >> 8 ) & 0xFF ); + bufIndex += 2; +} + +/* +=============== +WRITE_1BYTES +=============== +*/ +/*static QINLINE void WRITE_1BYTES( int x ) +{ + buffer[ bufIndex ] = x; + bufIndex += 1; +}*/ + +/* +=============== +START_CHUNK +=============== +*/ +static QINLINE void START_CHUNK( const char *s ) +{ + if( afd.chunkStackTop == MAX_RIFF_CHUNKS ) + { + Com_Error( ERR_DROP, "ERROR: Top of chunkstack breached" ); + } + + afd.chunkStack[ afd.chunkStackTop ] = bufIndex; + afd.chunkStackTop++; + WRITE_STRING( s ); + WRITE_4BYTES( 0 ); +} + +/* +=============== +END_CHUNK +=============== +*/ +static QINLINE void END_CHUNK( void ) +{ + int endIndex = bufIndex; + + if( afd.chunkStackTop <= 0 ) + { + Com_Error( ERR_DROP, "ERROR: Bottom of chunkstack breached" ); + } + + afd.chunkStackTop--; + bufIndex = afd.chunkStack[ afd.chunkStackTop ]; + bufIndex += 4; + WRITE_4BYTES( endIndex - bufIndex - 4 ); + bufIndex = endIndex; + bufIndex = PAD( bufIndex, 2 ); +} + +/* +=============== +CL_WriteAVIHeader +=============== +*/ +void CL_WriteAVIHeader( void ) +{ + bufIndex = 0; + afd.chunkStackTop = 0; + + START_CHUNK( "RIFF" ); + { + WRITE_STRING( "AVI " ); + { + START_CHUNK( "LIST" ); + { + WRITE_STRING( "hdrl" ); + WRITE_STRING( "avih" ); + WRITE_4BYTES( 56 ); //"avih" "chunk" size + WRITE_4BYTES( afd.framePeriod ); //dwMicroSecPerFrame + WRITE_4BYTES( afd.maxRecordSize * + afd.frameRate ); //dwMaxBytesPerSec + WRITE_4BYTES( 0 ); //dwReserved1 + WRITE_4BYTES( 0x110 ); //dwFlags bits HAS_INDEX and IS_INTERLEAVED + WRITE_4BYTES( afd.numVideoFrames ); //dwTotalFrames + WRITE_4BYTES( 0 ); //dwInitialFrame + + if( afd.audio ) //dwStreams + WRITE_4BYTES( 2 ); + else + WRITE_4BYTES( 1 ); + + WRITE_4BYTES( afd.maxRecordSize ); //dwSuggestedBufferSize + WRITE_4BYTES( afd.width ); //dwWidth + WRITE_4BYTES( afd.height ); //dwHeight + WRITE_4BYTES( 0 ); //dwReserved[ 0 ] + WRITE_4BYTES( 0 ); //dwReserved[ 1 ] + WRITE_4BYTES( 0 ); //dwReserved[ 2 ] + WRITE_4BYTES( 0 ); //dwReserved[ 3 ] + + START_CHUNK( "LIST" ); + { + WRITE_STRING( "strl" ); + WRITE_STRING( "strh" ); + WRITE_4BYTES( 56 ); //"strh" "chunk" size + WRITE_STRING( "vids" ); + + if( afd.motionJpeg ) + WRITE_STRING( "MJPG" ); + else + WRITE_4BYTES( 0 ); // BI_RGB + + WRITE_4BYTES( 0 ); //dwFlags + WRITE_4BYTES( 0 ); //dwPriority + WRITE_4BYTES( 0 ); //dwInitialFrame + + WRITE_4BYTES( 1 ); //dwTimescale + WRITE_4BYTES( afd.frameRate ); //dwDataRate + WRITE_4BYTES( 0 ); //dwStartTime + WRITE_4BYTES( afd.numVideoFrames ); //dwDataLength + + WRITE_4BYTES( afd.maxRecordSize ); //dwSuggestedBufferSize + WRITE_4BYTES( -1 ); //dwQuality + WRITE_4BYTES( 0 ); //dwSampleSize + WRITE_2BYTES( 0 ); //rcFrame + WRITE_2BYTES( 0 ); //rcFrame + WRITE_2BYTES( afd.width ); //rcFrame + WRITE_2BYTES( afd.height ); //rcFrame + + WRITE_STRING( "strf" ); + WRITE_4BYTES( 40 ); //"strf" "chunk" size + WRITE_4BYTES( 40 ); //biSize + WRITE_4BYTES( afd.width ); //biWidth + WRITE_4BYTES( afd.height ); //biHeight + WRITE_2BYTES( 1 ); //biPlanes + WRITE_2BYTES( 24 ); //biBitCount + + if( afd.motionJpeg ) //biCompression + { + WRITE_STRING( "MJPG" ); + WRITE_4BYTES( afd.width * + afd.height ); //biSizeImage + } + else + { + WRITE_4BYTES( 0 ); // BI_RGB + WRITE_4BYTES( afd.width * + afd.height * 3 ); //biSizeImage + } + + WRITE_4BYTES( 0 ); //biXPelsPetMeter + WRITE_4BYTES( 0 ); //biYPelsPetMeter + WRITE_4BYTES( 0 ); //biClrUsed + WRITE_4BYTES( 0 ); //biClrImportant + } + END_CHUNK( ); + + if( afd.audio ) + { + START_CHUNK( "LIST" ); + { + WRITE_STRING( "strl" ); + WRITE_STRING( "strh" ); + WRITE_4BYTES( 56 ); //"strh" "chunk" size + WRITE_STRING( "auds" ); + WRITE_4BYTES( 0 ); //FCC + WRITE_4BYTES( 0 ); //dwFlags + WRITE_4BYTES( 0 ); //dwPriority + WRITE_4BYTES( 0 ); //dwInitialFrame + + WRITE_4BYTES( afd.a.sampleSize ); //dwTimescale + WRITE_4BYTES( afd.a.sampleSize * + afd.a.rate ); //dwDataRate + WRITE_4BYTES( 0 ); //dwStartTime + WRITE_4BYTES( afd.a.totalBytes / + afd.a.sampleSize ); //dwDataLength + + WRITE_4BYTES( 0 ); //dwSuggestedBufferSize + WRITE_4BYTES( -1 ); //dwQuality + WRITE_4BYTES( afd.a.sampleSize ); //dwSampleSize + WRITE_2BYTES( 0 ); //rcFrame + WRITE_2BYTES( 0 ); //rcFrame + WRITE_2BYTES( 0 ); //rcFrame + WRITE_2BYTES( 0 ); //rcFrame + + WRITE_STRING( "strf" ); + WRITE_4BYTES( 18 ); //"strf" "chunk" size + WRITE_2BYTES( afd.a.format ); //wFormatTag + WRITE_2BYTES( afd.a.channels ); //nChannels + WRITE_4BYTES( afd.a.rate ); //nSamplesPerSec + WRITE_4BYTES( afd.a.sampleSize * + afd.a.rate ); //nAvgBytesPerSec + WRITE_2BYTES( afd.a.sampleSize ); //nBlockAlign + WRITE_2BYTES( afd.a.bits ); //wBitsPerSample + WRITE_2BYTES( 0 ); //cbSize + } + END_CHUNK( ); + } + } + END_CHUNK( ); + + afd.moviOffset = bufIndex; + + START_CHUNK( "LIST" ); + { + WRITE_STRING( "movi" ); + } + } + } +} + +/* +=============== +CL_OpenAVIForWriting + +Creates an AVI file and gets it into a state where +writing the actual data can begin +=============== +*/ +qboolean CL_OpenAVIForWriting( const char *fileName ) +{ + if( afd.fileOpen ) + return qfalse; + + Com_Memset( &afd, 0, sizeof( aviFileData_t ) ); + + // Don't start if a framerate has not been chosen + if( cl_aviFrameRate->integer <= 0 ) + { + Com_Printf( S_COLOR_RED "cl_aviFrameRate must be >= 1\n" ); + return qfalse; + } + + if( ( afd.f = FS_FOpenFileWrite( fileName ) ) <= 0 ) + return qfalse; + + if( ( afd.idxF = FS_FOpenFileWrite( + va( "%s" INDEX_FILE_EXTENSION, fileName ) ) ) <= 0 ) + { + FS_FCloseFile( afd.f ); + return qfalse; + } + + Q_strncpyz( afd.fileName, fileName, MAX_QPATH ); + + afd.frameRate = cl_aviFrameRate->integer; + afd.framePeriod = (int)( 1000000.0f / afd.frameRate ); + afd.width = cls.glconfig.vidWidth; + afd.height = cls.glconfig.vidHeight; + + if( cl_aviMotionJpeg->integer ) + afd.motionJpeg = qtrue; + else + afd.motionJpeg = qfalse; + + // Buffers only need to store RGB pixels. + // Allocate a bit more space for the capture buffer to account for possible + // padding at the end of pixel lines, and padding for alignment + #define MAX_PACK_LEN 16 + afd.cBuffer = (byte *)Z_Malloc((afd.width * 3 + MAX_PACK_LEN - 1) * afd.height + MAX_PACK_LEN - 1, TAG_AVI, qtrue); + // raw avi files have pixel lines start on 4-byte boundaries + afd.eBuffer = (byte *)Z_Malloc(PAD(afd.width * 3, AVI_LINE_PADDING) * afd.height, TAG_AVI, qtrue); + + afd.a.rate = dma.speed; + afd.a.format = WAV_FORMAT_PCM; + afd.a.channels = dma.channels; + afd.a.bits = dma.samplebits; + afd.a.sampleSize = ( afd.a.bits / 8 ) * afd.a.channels; + + if( afd.a.rate % afd.frameRate ) + { + int suggestRate = afd.frameRate; + + while( ( afd.a.rate % suggestRate ) && suggestRate >= 1 ) + suggestRate--; + + Com_Printf( S_COLOR_YELLOW "WARNING: cl_aviFrameRate is not a divisor " + "of the audio rate, suggest %d\n", suggestRate ); + } + + if( !Cvar_VariableIntegerValue( "s_initsound" ) ) + { + afd.audio = qfalse; + } + else if( Cvar_VariableIntegerValue( "s_UseOpenAL" ) == 0 ) + //else if( Q_stricmp( Cvar_VariableString( "s_backend" ), "OpenAL" ) ) + { + if( afd.a.bits != 16 || afd.a.channels != 2 ) + { + Com_Printf( S_COLOR_YELLOW "WARNING: Audio format of %d bit/%d channels not supported", + afd.a.bits, afd.a.channels ); + afd.audio = qfalse; + } + else + afd.audio = qtrue; + } + else + { + afd.audio = qfalse; + Com_Printf( S_COLOR_YELLOW "WARNING: Audio capture is not supported " + "with OpenAL. Set s_UseOpenAL to 0 for audio capture\n" ); + } + + // This doesn't write a real header, but allocates the + // correct amount of space at the beginning of the file + CL_WriteAVIHeader( ); + + SafeFS_Write( buffer, bufIndex, afd.f ); + afd.fileSize = bufIndex; + + bufIndex = 0; + START_CHUNK( "idx1" ); + SafeFS_Write( buffer, bufIndex, afd.idxF ); + + afd.moviSize = 4; // For the "movi" + afd.fileOpen = qtrue; + + return qtrue; +} + +/* +=============== +CL_CheckFileSize +=============== +*/ +static qboolean CL_CheckFileSize( int bytesToAdd ) +{ + unsigned int newFileSize; + + newFileSize = + afd.fileSize + // Current file size + bytesToAdd + // What we want to add + ( afd.numIndices * 16 ) + // The index + 4; // The index size + + if ( cl_avi2GBLimit->integer ) + { + // I assume all the operating systems + // we target can handle a 2Gb file + if ( newFileSize > INT_MAX ) + { + // Close the current file... + CL_CloseAVI(); + + // ...And open a new one + CL_OpenAVIForWriting( va( "%s_", afd.fileName ) ); + + return qtrue; + } + } + + return qfalse; +} + +/* +=============== +CL_WriteAVIVideoFrame +=============== +*/ +void CL_WriteAVIVideoFrame( const byte *imageBuffer, int size ) +{ + int chunkOffset = afd.fileSize - afd.moviOffset - 8; + int chunkSize = 8 + size; + int paddingSize = PADLEN(size, 2); + byte padding[ 4 ] = { 0 }; + + if( !afd.fileOpen ) + return; + + // Chunk header + contents + padding + if( CL_CheckFileSize( 8 + size + 2 ) ) + return; + + bufIndex = 0; + WRITE_STRING( "00dc" ); + WRITE_4BYTES( size ); + + SafeFS_Write( buffer, 8, afd.f ); + SafeFS_Write( imageBuffer, size, afd.f ); + SafeFS_Write( padding, paddingSize, afd.f ); + afd.fileSize += ( chunkSize + paddingSize ); + + afd.numVideoFrames++; + afd.moviSize += ( chunkSize + paddingSize ); + + if( size > afd.maxRecordSize ) + afd.maxRecordSize = size; + + // Index + bufIndex = 0; + WRITE_STRING( "00dc" ); //dwIdentifier + WRITE_4BYTES( 0x00000010 ); //dwFlags (all frames are KeyFrames) + WRITE_4BYTES( chunkOffset ); //dwOffset + WRITE_4BYTES( size ); //dwLength + SafeFS_Write( buffer, 16, afd.idxF ); + + afd.numIndices++; +} + +#define PCM_BUFFER_SIZE 44100 + +/* +=============== +CL_WriteAVIAudioFrame +=============== +*/ +void CL_WriteAVIAudioFrame( const byte *pcmBuffer, int size ) +{ + static byte pcmCaptureBuffer[ PCM_BUFFER_SIZE ] = { 0 }; + static int bytesInBuffer = 0; + + if( !afd.audio ) + return; + + if( !afd.fileOpen ) + return; + + // Chunk header + contents + padding + if( CL_CheckFileSize( 8 + bytesInBuffer + size + 2 ) ) + return; + + if( bytesInBuffer + size > PCM_BUFFER_SIZE ) + { + Com_Printf( S_COLOR_YELLOW + "WARNING: Audio capture buffer overflow -- truncating\n" ); + size = PCM_BUFFER_SIZE - bytesInBuffer; + } + + Com_Memcpy( &pcmCaptureBuffer[ bytesInBuffer ], pcmBuffer, size ); + bytesInBuffer += size; + + // Only write if we have a frame's worth of audio + if( bytesInBuffer >= (int)ceil( (float)afd.a.rate / (float)afd.frameRate ) * + afd.a.sampleSize ) + { + int chunkOffset = afd.fileSize - afd.moviOffset - 8; + int chunkSize = 8 + bytesInBuffer; + int paddingSize = PADLEN(bytesInBuffer, 2); + byte padding[ 4 ] = { 0 }; + + bufIndex = 0; + WRITE_STRING( "01wb" ); + WRITE_4BYTES( bytesInBuffer ); + + SafeFS_Write( buffer, 8, afd.f ); + SafeFS_Write( pcmCaptureBuffer, bytesInBuffer, afd.f ); + SafeFS_Write( padding, paddingSize, afd.f ); + afd.fileSize += ( chunkSize + paddingSize ); + + afd.numAudioFrames++; + afd.moviSize += ( chunkSize + paddingSize ); + afd.a.totalBytes += bytesInBuffer; + + // Index + bufIndex = 0; + WRITE_STRING( "01wb" ); //dwIdentifier + WRITE_4BYTES( 0 ); //dwFlags + WRITE_4BYTES( chunkOffset ); //dwOffset + WRITE_4BYTES( bytesInBuffer ); //dwLength + SafeFS_Write( buffer, 16, afd.idxF ); + + afd.numIndices++; + + bytesInBuffer = 0; + } +} + +/* +=============== +CL_TakeVideoFrame +=============== +*/ +void CL_TakeVideoFrame( void ) +{ + // AVI file isn't open + if( !afd.fileOpen ) + return; + + re->TakeVideoFrame( afd.width, afd.height, + afd.cBuffer, afd.eBuffer, afd.motionJpeg ); +} + +/* +=============== +CL_CloseAVI + +Closes the AVI file and writes an index chunk +=============== +*/ +qboolean CL_CloseAVI( void ) +{ + int indexRemainder; + int indexSize = afd.numIndices * 16; + const char *idxFileName = va( "%s" INDEX_FILE_EXTENSION, afd.fileName ); + + // AVI file isn't open + if( !afd.fileOpen ) + return qfalse; + + afd.fileOpen = qfalse; + + FS_Seek( afd.idxF, 4, FS_SEEK_SET ); + bufIndex = 0; + WRITE_4BYTES( indexSize ); + SafeFS_Write( buffer, bufIndex, afd.idxF ); + FS_FCloseFile( afd.idxF ); + + // Write index + + // Open the temp index file + if( ( indexSize = FS_FOpenFileRead( idxFileName, + &afd.idxF, qtrue ) ) <= 0 ) + { + FS_FCloseFile( afd.f ); + return qfalse; + } + + indexRemainder = indexSize; + + // Append index to end of avi file + while( indexRemainder > MAX_AVI_BUFFER ) + { + FS_Read( buffer, MAX_AVI_BUFFER, afd.idxF ); + SafeFS_Write( buffer, MAX_AVI_BUFFER, afd.f ); + afd.fileSize += MAX_AVI_BUFFER; + indexRemainder -= MAX_AVI_BUFFER; + } + FS_Read( buffer, indexRemainder, afd.idxF ); + SafeFS_Write( buffer, indexRemainder, afd.f ); + afd.fileSize += indexRemainder; + FS_FCloseFile( afd.idxF ); + + // Remove temp index file + FS_HomeRemove( idxFileName ); + + // Write the real header + FS_Seek( afd.f, 0, FS_SEEK_SET ); + CL_WriteAVIHeader( ); + + bufIndex = 4; + WRITE_4BYTES( afd.fileSize - 8 ); // "RIFF" size + + bufIndex = afd.moviOffset + 4; // Skip "LIST" + WRITE_4BYTES( afd.moviSize ); + + SafeFS_Write( buffer, bufIndex, afd.f ); + + Z_Free( afd.cBuffer ); + Z_Free( afd.eBuffer ); + FS_FCloseFile( afd.f ); + + Com_Printf( "Wrote %d:%d frames to %s\n", afd.numVideoFrames, afd.numAudioFrames, afd.fileName ); + + return qtrue; +} + +/* +=============== +CL_VideoRecording +=============== +*/ +qboolean CL_VideoRecording( void ) +{ + return afd.fileOpen; +} diff --git a/Projects/Android/jni/OpenJK/codemp/client/cl_cgame.cpp b/Projects/Android/jni/OpenJK/codemp_delete/client/cl_cgame.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/cl_cgame.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/client/cl_cgame.cpp diff --git a/Projects/Android/jni/OpenJK/codemp_delete/client/cl_cgameapi.cpp b/Projects/Android/jni/OpenJK/codemp_delete/client/cl_cgameapi.cpp new file mode 100644 index 0000000..1526744 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/client/cl_cgameapi.cpp @@ -0,0 +1,1939 @@ +/* +=========================================================================== +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +// cl_cgameapi.cpp -- client system interaction with client game +#include "qcommon/cm_public.h" +#include "qcommon/RoffSystem.h" +#include "qcommon/stringed_ingame.h" +#include "qcommon/timing.h" +#include "client.h" +#include "cl_uiapi.h" +#include "botlib/botlib.h" +#include "snd_ambient.h" +#include "FXExport.h" +#include "FxUtil.h" + +extern IHeapAllocator *G2VertSpaceClient; +extern botlib_export_t *botlib_export; + +// cgame interface +static cgameExport_t *cge; // cgame export table +static vm_t *cgvm; // cgame vm, valid for legacy and new api + +// +// cgame vmMain calls +// +void CGVM_Init( int serverMessageNum, int serverCommandSequence, int clientNum ) { + if ( cgvm->isLegacy ) { + VM_Call( cgvm, CG_INIT, serverMessageNum, serverCommandSequence, clientNum ); + return; + } + VMSwap v( cgvm ); + + cge->Init( serverMessageNum, serverCommandSequence, clientNum ); +} + +void CGVM_Shutdown( void ) { + if ( cgvm->isLegacy ) { + VM_Call( cgvm, CG_SHUTDOWN ); + return; + } + VMSwap v( cgvm ); + + cge->Shutdown(); +} + +qboolean CGVM_ConsoleCommand( void ) { + if ( cgvm->isLegacy ) { + return (qboolean)VM_Call( cgvm, CG_CONSOLE_COMMAND ); + } + VMSwap v( cgvm ); + + return cge->ConsoleCommand(); +} + +void CGVM_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback ) { + if ( cgvm->isLegacy ) { + VM_Call( cgvm, CG_DRAW_ACTIVE_FRAME, serverTime, stereoView, demoPlayback ); + return; + } + VMSwap v( cgvm ); + + cge->DrawActiveFrame( serverTime, stereoView, demoPlayback ); +} + +int CGVM_CrosshairPlayer( void ) { + if ( cgvm->isLegacy ) { + return VM_Call( cgvm, CG_CROSSHAIR_PLAYER ); + } + VMSwap v( cgvm ); + + return cge->CrosshairPlayer(); +} + +int CGVM_LastAttacker( void ) { + if ( cgvm->isLegacy ) { + return VM_Call( cgvm, CG_LAST_ATTACKER ); + } + VMSwap v( cgvm ); + + return cge->LastAttacker(); +} + +void CGVM_KeyEvent( int key, qboolean down ) { + if ( cgvm->isLegacy ) { + VM_Call( cgvm, CG_KEY_EVENT, key, down ); + return; + } + VMSwap v( cgvm ); + + cge->KeyEvent( key, down ); +} + +void CGVM_MouseEvent( int x, int y ) { + if ( cgvm->isLegacy ) { + VM_Call( cgvm, CG_MOUSE_EVENT, x, y ); + return; + } + VMSwap v( cgvm ); + + cge->MouseEvent( x, y ); +} + +void CGVM_EventHandling( int type ) { + if ( cgvm->isLegacy ) { + VM_Call( cgvm, CG_EVENT_HANDLING, type ); + return; + } + VMSwap v( cgvm ); + + cge->EventHandling( type ); +} + +int CGVM_PointContents( void ) { + if ( cgvm->isLegacy ) { + return VM_Call( cgvm, CG_POINT_CONTENTS ); + } + VMSwap v( cgvm ); + + return cge->PointContents(); +} + +void CGVM_GetLerpOrigin( void ) { + if ( cgvm->isLegacy ) { + VM_Call( cgvm, CG_GET_LERP_ORIGIN ); + return; + } + VMSwap v( cgvm ); + + cge->GetLerpOrigin(); +} + +void CGVM_GetLerpData( void ) { + if ( cgvm->isLegacy ) { + VM_Call( cgvm, CG_GET_LERP_DATA ); + return; + } + VMSwap v( cgvm ); + + cge->GetLerpData(); +} + +void CGVM_Trace( void ) { + if ( cgvm->isLegacy ) { + VM_Call( cgvm, CG_TRACE ); + return; + } + VMSwap v( cgvm ); + + cge->Trace(); +} + +void CGVM_G2Trace( void ) { + if ( cgvm->isLegacy ) { + VM_Call( cgvm, CG_G2TRACE ); + return; + } + VMSwap v( cgvm ); + + cge->G2Trace(); +} + +void CGVM_G2Mark( void ) { + if ( cgvm->isLegacy ) { + VM_Call( cgvm, CG_G2MARK ); + return; + } + VMSwap v( cgvm ); + + cge->G2Mark(); +} + +int CGVM_RagCallback( int callType ) { + if ( cgvm->isLegacy ) { + return VM_Call( cgvm, CG_RAG_CALLBACK, callType ); + } + VMSwap v( cgvm ); + + return cge->RagCallback( callType ); +} + +qboolean CGVM_IncomingConsoleCommand( void ) { + if ( cgvm->isLegacy ) { + return (qboolean)VM_Call( cgvm, CG_INCOMING_CONSOLE_COMMAND ); + } + VMSwap v( cgvm ); + + return cge->IncomingConsoleCommand(); +} + +qboolean CGVM_NoUseableForce( void ) { + if ( cgvm->isLegacy ) { + return (qboolean)VM_Call( cgvm, CG_GET_USEABLE_FORCE ); + } + VMSwap v( cgvm ); + + return cge->NoUseableForce(); +} + +void CGVM_GetOrigin( int entID, vec3_t out ) { + if ( cgvm->isLegacy ) { + VM_Call( cgvm, CG_GET_ORIGIN, entID, reinterpret_cast< intptr_t >( out ) ); + return; + } + VMSwap v( cgvm ); + + cge->GetOrigin( entID, out ); +} + +void CGVM_GetAngles( int entID, vec3_t out ) { + if ( cgvm->isLegacy ) { + VM_Call( cgvm, CG_GET_ANGLES, entID, reinterpret_cast< intptr_t >( out ) ); + return; + } + VMSwap v( cgvm ); + + cge->GetAngles( entID, out ); +} + +trajectory_t *CGVM_GetOriginTrajectory( int entID ) { + if ( cgvm->isLegacy ) { + return (trajectory_t *)VM_Call( cgvm, CG_GET_ORIGIN_TRAJECTORY, entID ); + } + VMSwap v( cgvm ); + + return cge->GetOriginTrajectory( entID ); +} + +trajectory_t *CGVM_GetAngleTrajectory( int entID ) { + if ( cgvm->isLegacy ) { + return (trajectory_t *)VM_Call( cgvm, CG_GET_ANGLE_TRAJECTORY, entID ); + } + VMSwap v( cgvm ); + + return cge->GetAngleTrajectory( entID ); +} + +void CGVM_ROFF_NotetrackCallback( int entID, const char *notetrack ) { + if ( cgvm->isLegacy ) { + VM_Call( cgvm, CG_ROFF_NOTETRACK_CALLBACK, entID, reinterpret_cast< intptr_t >( notetrack ) ); + return; + } + VMSwap v( cgvm ); + + cge->ROFF_NotetrackCallback( entID, notetrack ); +} + +void CGVM_MapChange( void ) { + if ( cgvm->isLegacy ) { + VM_Call( cgvm, CG_MAP_CHANGE ); + return; + } + VMSwap v( cgvm ); + + cge->MapChange(); +} + +void CGVM_AutomapInput( void ) { + if ( cgvm->isLegacy ) { + VM_Call( cgvm, CG_AUTOMAP_INPUT ); + return; + } + VMSwap v( cgvm ); + + cge->AutomapInput(); +} + +void CGVM_MiscEnt( void ) { + if ( cgvm->isLegacy ) { + VM_Call( cgvm, CG_MISC_ENT ); + return; + } + VMSwap v( cgvm ); + + cge->MiscEnt(); +} + +void CGVM_CameraShake( void ) { + if ( cgvm->isLegacy ) { + VM_Call( cgvm, CG_FX_CAMERASHAKE ); + return; + } + VMSwap v( cgvm ); + + cge->CameraShake(); +} + + +// +// cgame syscalls +// only used by legacy mods! +// + +extern int CL_GetValueForHidden( const char *s ); //cl_parse.cpp +extern qboolean cl_bUseFighterPitch; //cl_input.cpp +int CM_LoadSubBSP( const char *name, qboolean clientload ); //cm_load.cpp +void FX_FeedTrail( effectTrailArgStruct_t *a ); //FxPrimitives.cpp + +// wrappers and such + +static void CL_AddCgameCommand( const char *cmdName ) { + Cmd_AddCommand( cmdName, NULL ); +} + +static void CL_CM_LoadMap( const char *mapname, qboolean subBSP ) { + if ( subBSP ) CM_LoadSubBSP( va( "maps/%s.bsp", mapname+1 ), qfalse ); + else CM_LoadMap( mapname, qtrue, NULL ); +} + +static void CL_GetGlconfig( glconfig_t *glconfig ) { + *glconfig = cls.glconfig; +} + +static void CL_GetGameState( gameState_t *gs ) { + *gs = cl.gameState; +} + +static void RegisterSharedMemory( char *memory ) { + cl.mSharedMemory = memory; +} + +static int CL_Milliseconds( void ) { + return Sys_Milliseconds(); +} + +static void CL_AddReliableCommand2( const char *cmd ) { + CL_AddReliableCommand( cmd, qfalse ); +} + +static int CL_CM_RegisterTerrain( const char *config ) { + return 0; +} + +extern int s_entityWavVol[MAX_GENTITIES]; +static int CL_S_GetVoiceVolume( int entID ) { + return s_entityWavVol[entID]; +} + +static void CL_S_Shutup( qboolean shutup ) { + s_shutUp = shutup; +} + +static int CL_GetCurrentCmdNumber( void ) { + return cl.cmdNumber; +} + +static void _CL_SetUserCmdValue( int stateValue, float sensitivityScale, float mPitchOverride, float mYawOverride, float mSensitivityOverride, int fpSel, int invenSel, qboolean fighterControls ) { + cl_bUseFighterPitch = fighterControls; + CL_SetUserCmdValue( stateValue, sensitivityScale, mPitchOverride, mYawOverride, mSensitivityOverride, fpSel, invenSel ); +} + +static void CL_OpenUIMenu( int menuID ) { + UIVM_SetActiveMenu( (uiMenuCommand_t)menuID ); +} + +static void CGFX_AddLine( vec3_t start, vec3_t end, float size1, float size2, float sizeParm, float alpha1, float alpha2, float alphaParm, vec3_t sRGB, vec3_t eRGB, float rgbParm, int killTime, qhandle_t shader, int flags ) { + FX_AddLine( start, end, size1, size2, sizeParm, alpha1, alpha2, alphaParm, sRGB, eRGB, rgbParm, killTime, shader, flags ); +} + +static void CGFX_AddPoly( addpolyArgStruct_t *p ) { + FX_AddPoly( p->p, p->ev, p->numVerts, p->vel, p->accel, p->alpha1, p->alpha2, p->alphaParm, p->rgb1, p->rgb2, p->rgbParm, p->rotationDelta, p->bounce, p->motionDelay, p->killTime, p->shader, p->flags ); +} + +static void CGFX_AddBezier( addbezierArgStruct_t *b ) { + FX_AddBezier( b->start, b->end, b->control1, b->control1Vel, b->control2, b->control2Vel, b->size1, b->size2, b->sizeParm, b->alpha1, b->alpha2, b->alphaParm, b->sRGB, b->eRGB, b->rgbParm, b->killTime, b->shader, b->flags ); +} + +static void CGFX_AddPrimitive( effectTrailArgStruct_t *e ) { + FX_FeedTrail( e ); +} + +static void CGFX_AddSprite( addspriteArgStruct_t *s ) { + vec3_t rgb = { 1.0f, 1.0f, 1.0f }; + FX_AddParticle( s->origin, s->vel, s->accel, s->scale, s->dscale, 0, s->sAlpha, s->eAlpha, 0, rgb, rgb, 0, s->rotation, 0, vec3_origin, vec3_origin, s->bounce, 0, 0, s->life, s->shader, s->flags ); +} + +static void CGFX_AddElectricity( addElectricityArgStruct_t *p ) { + FX_AddElectricity( p->start, p->end, p->size1, p->size2, p->sizeParm, p->alpha1, p->alpha2, p->alphaParm, p->sRGB, p->eRGB, p->rgbParm, p->chaos, p->killTime, p->shader, p->flags ); +} + +static qboolean CL_ROFF_Clean( void ) { + return theROFFSystem.Clean( qtrue ); +} + +static void CL_ROFF_UpdateEntities( void ) { + theROFFSystem.UpdateEntities( qtrue ); +} + +static int CL_ROFF_Cache( char *file ) { + return theROFFSystem.Cache( file, qtrue ); +} + +static qboolean CL_ROFF_Play( int entID, int roffID, qboolean doTranslation ) { + return theROFFSystem.Play( entID, roffID, doTranslation, qtrue ); +} + +static qboolean CL_ROFF_Purge_Ent( int entID ) { + return theROFFSystem.PurgeEnt( entID, qtrue ); +} + +static void CL_GetCurrentSnapshotNumber( int *snapshotNumber, int *serverTime ) { + *snapshotNumber = cl.snap.messageNum; + *serverTime = cl.snap.serverTime; +} + +static void CL_SetClientForceAngle( int time, vec3_t angle ) { + cl.cgameViewAngleForceTime = time; + VectorCopy(angle, cl.cgameViewAngleForce); +} + +static void CL_PrecisionTimerStart( void **p ) { + timing_c *newTimer = new timing_c; //create the new timer + *p = newTimer; //assign the pointer within the pointer to point at the mem addr of our new timer + newTimer->Start(); //start the timer +} + +static int CL_PrecisionTimerEnd( void *p ) { + int r = 0; + timing_c *timer = (timing_c *)p; //this is the pointer we assigned in start, so we can directly cast it back + r = timer->End(); //get the result + delete timer; //delete the timer since we're done with it + return r; //return the result +} + +static void CL_RMG_Init( int /* terrainID */, const char * /* terrainInfo */ ) { } + +static qboolean CGFX_PlayBoltedEffectID( int id, vec3_t org, void *ghoul2, const int boltNum, const int entNum, const int modelNum, int iLooptime, qboolean isRelative ) { + if ( !ghoul2 ) return qfalse; + + CGhoul2Info_v &g2 = *((CGhoul2Info_v *)ghoul2); + int boltInfo=0; + if ( re->G2API_AttachEnt( &boltInfo, g2, modelNum, boltNum, entNum, modelNum ) ) + { + FX_PlayBoltedEffectID(id, org, boltInfo, &g2, iLooptime, isRelative ); + return qtrue; + } + return qfalse; +} + +static qboolean CL_SE_GetStringTextString( const char *text, char *buffer, int bufferLength ) { + const char *str; + + assert( text && buffer ); + + str = SE_GetString( text ); + + if ( str[0] ) { + Q_strncpyz( buffer, str, bufferLength ); + return qtrue; + } + + Com_sprintf( buffer, bufferLength, "??%s", str ); + return qfalse; +} + +static void CL_G2API_ListModelSurfaces( void *ghlInfo ) { + re->G2API_ListSurfaces( (CGhoul2Info *)ghlInfo ); +} + +static void CL_G2API_ListModelBones( void *ghlInfo, int frame ) { + re->G2API_ListBones( (CGhoul2Info *)ghlInfo, frame ); +} + +static void CL_G2API_SetGhoul2ModelIndexes( void *ghoul2, qhandle_t *modelList, qhandle_t *skinList ) { + if ( !ghoul2 ) return; + re->G2API_SetGhoul2ModelIndexes( *((CGhoul2Info_v *)ghoul2), modelList, skinList ); +} + +static qboolean CL_G2API_HaveWeGhoul2Models( void *ghoul2) { + if ( !ghoul2 ) return qfalse; + return re->G2API_HaveWeGhoul2Models( *((CGhoul2Info_v *)ghoul2) ); +} + +static qboolean CL_G2API_GetBoltMatrix( void *ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale ) { + if ( !ghoul2 ) return qfalse; + return re->G2API_GetBoltMatrix( *((CGhoul2Info_v *)ghoul2), modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale ); +} + +static qboolean CL_G2API_GetBoltMatrix_NoReconstruct( void *ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale ) { + if ( !ghoul2 ) return qfalse; + re->G2API_BoltMatrixReconstruction( qfalse ); + return re->G2API_GetBoltMatrix( *((CGhoul2Info_v *)ghoul2), modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale ); +} + +static qboolean CL_G2API_GetBoltMatrix_NoRecNoRot( void *ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale ) { + if ( !ghoul2 ) return qfalse; + // Intentionally not setting bolt matrix reconstruction state per original code comments + re->G2API_BoltMatrixSPMethod( qtrue ); + return re->G2API_GetBoltMatrix( *((CGhoul2Info_v *)ghoul2), modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale ); +} + +static int CL_G2API_InitGhoul2Model( void **ghoul2Ptr, const char *fileName, int modelIndex, qhandle_t customSkin, qhandle_t customShader, int modelFlags, int lodBias ) { +#ifdef _FULL_G2_LEAK_CHECKING + g_G2AllocServer = 0; +#endif + return re->G2API_InitGhoul2Model( (CGhoul2Info_v **)ghoul2Ptr, fileName, modelIndex, customSkin, customShader, modelFlags, lodBias ); +} + +static qboolean CL_G2API_SetSkin( void *ghoul2, int modelIndex, qhandle_t customSkin, qhandle_t renderSkin ) { + if ( !ghoul2 ) return qfalse; + CGhoul2Info_v &g2 = *((CGhoul2Info_v *)ghoul2); + return re->G2API_SetSkin( g2, modelIndex, customSkin, renderSkin ); +} + +static void CL_G2API_CollisionDetect( CollisionRecord_t *collRecMap, void* ghoul2, const vec3_t angles, const vec3_t position, int frameNumber, int entNum, vec3_t rayStart, vec3_t rayEnd, vec3_t scale, int traceFlags, int useLod, float fRadius ) { + if ( !ghoul2 ) return; + re->G2API_CollisionDetect( collRecMap, *((CGhoul2Info_v *)ghoul2), angles, position, frameNumber, entNum, rayStart, rayEnd, scale, G2VertSpaceClient, traceFlags, useLod, fRadius ); +} + +static void CL_G2API_CollisionDetectCache( CollisionRecord_t *collRecMap, void* ghoul2, const vec3_t angles, const vec3_t position, int frameNumber, int entNum, vec3_t rayStart, vec3_t rayEnd, vec3_t scale, int traceFlags, int useLod, float fRadius ) { + if ( !ghoul2 ) return; + re->G2API_CollisionDetectCache( collRecMap, *((CGhoul2Info_v *)ghoul2), angles, position, frameNumber, entNum, rayStart, rayEnd, scale, G2VertSpaceClient, traceFlags, useLod, fRadius ); +} + +static void CL_G2API_CleanGhoul2Models( void **ghoul2Ptr ) { +#ifdef _FULL_G2_LEAK_CHECKING + g_G2AllocServer = 0; +#endif + re->G2API_CleanGhoul2Models( (CGhoul2Info_v **)ghoul2Ptr ); +} + +static qboolean CL_G2API_SetBoneAngles( void *ghoul2, int modelIndex, const char *boneName, const vec3_t angles, const int flags, const int up, const int right, const int forward, qhandle_t *modelList, int blendTime , int currentTime ) { + if ( !ghoul2 ) return qfalse; + return re->G2API_SetBoneAngles( *((CGhoul2Info_v *)ghoul2), modelIndex, boneName, angles, flags, (const Eorientations)up, (const Eorientations)right, (const Eorientations)forward, modelList, blendTime , currentTime ); +} + +static qboolean CL_G2API_SetBoneAnim( void *ghoul2, const int modelIndex, const char *boneName, const int startFrame, const int endFrame, const int flags, const float animSpeed, const int currentTime, const float setFrame, const int blendTime ) { + if ( !ghoul2 ) return qfalse; + return re->G2API_SetBoneAnim( *((CGhoul2Info_v *)ghoul2), modelIndex, boneName, startFrame, endFrame, flags, animSpeed, currentTime, setFrame, blendTime ); +} + +static qboolean CL_G2API_GetBoneAnim( void *ghoul2, const char *boneName, const int currentTime, float *currentFrame, int *startFrame, int *endFrame, int *flags, float *animSpeed, int *modelList, const int modelIndex ) { + if ( !ghoul2 ) return qfalse; + CGhoul2Info_v &g2 = *((CGhoul2Info_v *)ghoul2); + return re->G2API_GetBoneAnim( g2, modelIndex, boneName, currentTime, currentFrame, startFrame, endFrame, flags, animSpeed, modelList ); +} + +static qboolean CL_G2API_GetBoneFrame( void *ghoul2, const char *boneName, const int currentTime, float *currentFrame, int *modelList, const int modelIndex ) { + if ( !ghoul2 ) return qfalse; + CGhoul2Info_v &g2 = *((CGhoul2Info_v *)ghoul2); + int iDontCare1 = 0, iDontCare2 = 0, iDontCare3 = 0; + float fDontCare1 = 0; + + return re->G2API_GetBoneAnim(g2, modelIndex, boneName, currentTime, currentFrame, &iDontCare1, &iDontCare2, &iDontCare3, &fDontCare1, modelList); +} + +static void CL_G2API_GetGLAName( void *ghoul2, int modelIndex, char *fillBuf ) { + if ( !ghoul2 ) + { + fillBuf[0] = '\0'; + return; + } + + char *tmp = re->G2API_GetGLAName( *((CGhoul2Info_v *)ghoul2), modelIndex ); + if ( tmp ) + strcpy( fillBuf, tmp ); + else + fillBuf[0] = '\0'; +} + +static int CL_G2API_CopyGhoul2Instance( void *g2From, void *g2To, int modelIndex ) { + if ( !g2From || !g2To ) return 0; + + return re->G2API_CopyGhoul2Instance( *((CGhoul2Info_v *)g2From), *((CGhoul2Info_v *)g2To), modelIndex ); +} + +static void CL_G2API_CopySpecificGhoul2Model( void *g2From, int modelFrom, void *g2To, int modelTo ) { + if ( !g2From || !g2To) return; + re->G2API_CopySpecificG2Model( *((CGhoul2Info_v *)g2From), modelFrom, *((CGhoul2Info_v *)g2To), modelTo ); +} + +static void CL_G2API_DuplicateGhoul2Instance( void *g2From, void **g2To ) { +#ifdef _FULL_G2_LEAK_CHECKING + g_G2AllocServer = 0; +#endif + if ( !g2From || !g2To ) return; + re->G2API_DuplicateGhoul2Instance( *((CGhoul2Info_v *)g2From), (CGhoul2Info_v **)g2To ); +} + +static qboolean CL_G2API_HasGhoul2ModelOnIndex( void *ghlInfo, int modelIndex ) { + return re->G2API_HasGhoul2ModelOnIndex( (CGhoul2Info_v **)ghlInfo, modelIndex ); +} + +static qboolean CL_G2API_RemoveGhoul2Model( void *ghlInfo, int modelIndex ) { +#ifdef _FULL_G2_LEAK_CHECKING + g_G2AllocServer = 0; +#endif + return re->G2API_RemoveGhoul2Model( (CGhoul2Info_v **)ghlInfo, modelIndex ); +} + +static qboolean CL_G2API_SkinlessModel( void *ghlInfo, int modelIndex ) { + if ( !ghlInfo ) return qfalse; + + CGhoul2Info_v &g2 = *((CGhoul2Info_v *)ghlInfo); + return re->G2API_SkinlessModel( g2, modelIndex ); +} + +static int CL_G2API_GetNumGoreMarks( void *ghlInfo, int modelIndex ) { +#ifdef _G2_GORE + if ( !ghlInfo ) return 0; + CGhoul2Info_v &g2 = *((CGhoul2Info_v *)ghlInfo); + return re->G2API_GetNumGoreMarks( g2, modelIndex ); +#else + return 0; +#endif +} + +static void CL_G2API_AddSkinGore( void *ghlInfo, SSkinGoreData *gore ) { +#ifdef _G2_GORE + if ( !ghlInfo ) return; + re->G2API_AddSkinGore( *((CGhoul2Info_v *)ghlInfo), *(SSkinGoreData *)gore ); +#endif +} + +static void CL_G2API_ClearSkinGore( void *ghlInfo ) { +#ifdef _G2_GORE + if ( !ghlInfo ) return; + re->G2API_ClearSkinGore( *((CGhoul2Info_v *)ghlInfo) ); +#endif +} + +static int CL_G2API_Ghoul2Size( void *ghlInfo ) { + if ( !ghlInfo ) return 0; + return re->G2API_Ghoul2Size( *((CGhoul2Info_v *)ghlInfo) ); +} + +static int CL_G2API_AddBolt( void *ghoul2, int modelIndex, const char *boneName ) { + if ( !ghoul2 ) return -1; + return re->G2API_AddBolt( *((CGhoul2Info_v *)ghoul2), modelIndex, boneName ); +} + +static qboolean CL_G2API_AttachEnt( int *boltInfo, void *ghlInfoTo, int toBoltIndex, int entNum, int toModelNum ) { + if ( !ghlInfoTo ) return qfalse; + CGhoul2Info_v &g2 = *((CGhoul2Info_v *)ghlInfoTo); + return re->G2API_AttachEnt( boltInfo, g2, 0, toBoltIndex, entNum, toModelNum ); +} + +static void CL_G2API_SetBoltInfo( void *ghoul2, int modelIndex, int boltInfo ) { + if ( !ghoul2 ) return; + re->G2API_SetBoltInfo( *((CGhoul2Info_v *)ghoul2), modelIndex, boltInfo ); +} + +static qboolean CL_G2API_SetRootSurface( void *ghoul2, const int modelIndex, const char *surfaceName ) { + if ( !ghoul2 ) return qfalse; + return re->G2API_SetRootSurface( *((CGhoul2Info_v *)ghoul2), modelIndex, surfaceName ); +} + +static qboolean CL_G2API_SetSurfaceOnOff( void *ghoul2, const char *surfaceName, const int flags ) { + if ( !ghoul2 ) return qfalse; + return re->G2API_SetSurfaceOnOff( *((CGhoul2Info_v *)ghoul2), surfaceName, flags ); +} + +static qboolean CL_G2API_SetNewOrigin( void *ghoul2, const int boltIndex ) { + if ( !ghoul2 ) return qfalse; + return re->G2API_SetNewOrigin( *((CGhoul2Info_v *)ghoul2), boltIndex ); +} + +static qboolean CL_G2API_DoesBoneExist( void *ghoul2, int modelIndex, const char *boneName ) { + if ( !ghoul2 ) return qfalse; + CGhoul2Info_v &g2 = *((CGhoul2Info_v *)ghoul2); + return re->G2API_DoesBoneExist( g2, modelIndex, boneName ); +} + +static int CL_G2API_GetSurfaceRenderStatus( void *ghoul2, const int modelIndex, const char *surfaceName ) { + if ( !ghoul2 ) return -1; + CGhoul2Info_v &g2 = *((CGhoul2Info_v *)ghoul2); + return re->G2API_GetSurfaceRenderStatus( g2, modelIndex, surfaceName ); +} + +static int CL_G2API_GetTime( void ) { + return re->G2API_GetTime( 0 ); +} + +static void CL_G2API_SetTime( int time, int clock ) { + re->G2API_SetTime( time, clock ); +} + +static void CL_G2API_AbsurdSmoothing( void *ghoul2, qboolean status ) { + if ( !ghoul2 ) return; + CGhoul2Info_v &g2 = *((CGhoul2Info_v *)ghoul2); + re->G2API_AbsurdSmoothing( g2, status ); +} + +static void CL_G2API_SetRagDoll( void *ghoul2, sharedRagDollParams_t *params ) { + if ( !ghoul2 ) return; + + CRagDollParams rdParams; + if ( !params ) { + re->G2API_ResetRagDoll( *((CGhoul2Info_v *)ghoul2) ); + return; + } + + VectorCopy( params->angles, rdParams.angles ); + VectorCopy( params->position, rdParams.position ); + VectorCopy( params->scale, rdParams.scale ); + VectorCopy( params->pelvisAnglesOffset, rdParams.pelvisAnglesOffset ); + VectorCopy( params->pelvisPositionOffset, rdParams.pelvisPositionOffset ); + + rdParams.fImpactStrength = params->fImpactStrength; + rdParams.fShotStrength = params->fShotStrength; + rdParams.me = params->me; + + rdParams.startFrame = params->startFrame; + rdParams.endFrame = params->endFrame; + + rdParams.collisionType = params->collisionType; + rdParams.CallRagDollBegin = params->CallRagDollBegin; + + rdParams.RagPhase = (CRagDollParams::ERagPhase)params->RagPhase; + rdParams.effectorsToTurnOff = (CRagDollParams::ERagEffector)params->effectorsToTurnOff; + + re->G2API_SetRagDoll( *((CGhoul2Info_v *)ghoul2), &rdParams ); +} + +static void CL_G2API_AnimateG2Models( void *ghoul2, int time, sharedRagDollUpdateParams_t *params ) { + if ( !ghoul2 ) return; + if ( !params ) return; + + CRagDollUpdateParams rduParams; + VectorCopy( params->angles, rduParams.angles ); + VectorCopy( params->position, rduParams.position ); + VectorCopy( params->scale, rduParams.scale ); + VectorCopy( params->velocity, rduParams.velocity ); + + rduParams.me = params->me; + rduParams.settleFrame = params->settleFrame; + + re->G2API_AnimateG2ModelsRag( *((CGhoul2Info_v *)ghoul2), time, &rduParams ); +} + +static qboolean CL_G2API_RagPCJConstraint( void *ghoul2, const char *boneName, vec3_t min, vec3_t max ) { + if ( !ghoul2 ) return qfalse; + return re->G2API_RagPCJConstraint( *((CGhoul2Info_v *)ghoul2), boneName, min, max ); +} + +static qboolean CL_G2API_RagPCJGradientSpeed( void *ghoul2, const char *boneName, const float speed ) { + if ( !ghoul2 ) return qfalse; + return re->G2API_RagPCJGradientSpeed( *((CGhoul2Info_v *)ghoul2), boneName, speed ); +} + +static qboolean CL_G2API_RagEffectorGoal( void *ghoul2, const char *boneName, vec3_t pos ) { + if ( !ghoul2 ) return qfalse; + return re->G2API_RagEffectorGoal( *((CGhoul2Info_v *)ghoul2), boneName, pos ); +} + +static qboolean CL_G2API_GetRagBonePos( void *ghoul2, const char *boneName, vec3_t pos, vec3_t entAngles, vec3_t entPos, vec3_t entScale ) { + if ( !ghoul2 ) return qfalse; + return re->G2API_GetRagBonePos( *((CGhoul2Info_v *)ghoul2), boneName, pos, entAngles, entPos, entScale ); +} + +static qboolean CL_G2API_RagEffectorKick( void *ghoul2, const char *boneName, vec3_t velocity ) { + if ( !ghoul2 ) return qfalse; + return re->G2API_RagEffectorKick( *((CGhoul2Info_v *)ghoul2), boneName, velocity ); +} + +static qboolean CL_G2API_RagForceSolve( void *ghoul2, qboolean force ) { + if ( !ghoul2 ) return qfalse; + return re->G2API_RagForceSolve( *((CGhoul2Info_v *)ghoul2), force ); +} + +static qboolean CL_G2API_SetBoneIKState( void *ghoul2, int time, const char *boneName, int ikState, sharedSetBoneIKStateParams_t *params ) { + if ( !ghoul2 ) return qfalse; + return re->G2API_SetBoneIKState( *((CGhoul2Info_v *)ghoul2), time, boneName, ikState, params ); +} + +static qboolean CL_G2API_IKMove( void *ghoul2, int time, sharedIKMoveParams_t *params ) { + if ( !ghoul2 ) return qfalse; + return re->G2API_IKMove( *((CGhoul2Info_v *)ghoul2), time, params ); +} + +static qboolean CL_G2API_RemoveBone( void *ghoul2, const char *boneName, int modelIndex ) { + if ( !ghoul2 ) return qfalse; + CGhoul2Info_v &g2 = *((CGhoul2Info_v *)ghoul2); + return re->G2API_RemoveBone( g2, modelIndex, boneName ); +} + +static void CL_G2API_AttachInstanceToEntNum( void *ghoul2, int entityNum, qboolean server ) { + if ( !ghoul2 ) return; + re->G2API_AttachInstanceToEntNum( *((CGhoul2Info_v *)ghoul2), entityNum, server ); +} + +static void CL_G2API_ClearAttachedInstance( int entityNum ) { + re->G2API_ClearAttachedInstance( entityNum ); +} + +static void CL_G2API_CleanEntAttachments( void ) { + re->G2API_CleanEntAttachments(); +} + +static qboolean CL_G2API_OverrideServer( void *serverInstance ) { + if ( !serverInstance ) return qfalse; + CGhoul2Info_v &g2 = *((CGhoul2Info_v *)serverInstance); + return re->G2API_OverrideServerWithClientData( g2, 0 ); +} + +static void CL_G2API_GetSurfaceName( void *ghoul2, int surfNumber, int modelIndex, char *fillBuf ) { + if ( !ghoul2 ) return; + CGhoul2Info_v &g2 = *((CGhoul2Info_v *)ghoul2); + char *tmp = re->G2API_GetSurfaceName( g2, modelIndex, surfNumber ); + strcpy( fillBuf, tmp ); +} + +static void CL_Key_SetCatcher( int catcher ) { + // Don't allow the cgame module to close the console + Key_SetCatcher( catcher | ( Key_GetCatcher( ) & KEYCATCH_CONSOLE ) ); +} + +static void CGVM_Cvar_Set( const char *var_name, const char *value ) { + Cvar_VM_Set( var_name, value, VM_CGAME ); +} + +static void CGVM_Cmd_RemoveCommand( const char *cmd_name ) { + Cmd_VM_RemoveCommand( cmd_name, VM_CGAME ); +} + +// legacy syscall + +intptr_t CL_CgameSystemCalls( intptr_t *args ) { + switch ( args[0] ) { + //rww - alright, DO NOT EVER add a GAME/CGAME/UI generic call without adding a trap to match, and + //all of these traps must be shared and have cases in sv_game, cl_cgame, and cl_ui. They must also + //all be in the same order, and start at 100. + case TRAP_MEMSET: + Com_Memset( VMA(1), args[2], args[3] ); + return 0; + + case TRAP_MEMCPY: + Com_Memcpy( VMA(1), VMA(2), args[3] ); + return 0; + + case TRAP_STRNCPY: + strncpy( (char *)VMA(1), (const char *)VMA(2), args[3] ); + return args[1]; + + case TRAP_SIN: + return FloatAsInt( sin( VMF(1) ) ); + + case TRAP_COS: + return FloatAsInt( cos( VMF(1) ) ); + + case TRAP_ATAN2: + return FloatAsInt( atan2( VMF(1), VMF(2) ) ); + + case TRAP_SQRT: + return FloatAsInt( sqrt( VMF(1) ) ); + + case TRAP_MATRIXMULTIPLY: + MatrixMultiply( (vec3_t *)VMA(1), (vec3_t *)VMA(2), (vec3_t *)VMA(3) ); + return 0; + + case TRAP_ANGLEVECTORS: + AngleVectors( (const float *)VMA(1), (float *)VMA(2), (float *)VMA(3), (float *)VMA(4) ); + return 0; + + case TRAP_PERPENDICULARVECTOR: + PerpendicularVector( (float *)VMA(1), (const float *)VMA(2) ); + return 0; + + case TRAP_FLOOR: + return FloatAsInt( floor( VMF(1) ) ); + + case TRAP_CEIL: + return FloatAsInt( ceil( VMF(1) ) ); + + case TRAP_TESTPRINTINT: + return 0; + + case TRAP_TESTPRINTFLOAT: + return 0; + + case TRAP_ACOS: + return FloatAsInt( Q_acos( VMF(1) ) ); + + case TRAP_ASIN: + return FloatAsInt( Q_asin( VMF(1) ) ); + + case CG_PRINT: + Com_Printf( "%s", (const char*)VMA(1) ); + return 0; + + case CG_ERROR: + Com_Error( ERR_DROP, "%s", (const char*)VMA(1) ); + return 0; + + case CG_MILLISECONDS: + return CL_Milliseconds(); + + //rww - precision timer funcs... -ALWAYS- call end after start with supplied ptr, or you'll get a nasty memory leak. + //not that you should be using these outside of debug anyway.. because you shouldn't be. So don't. + case CG_PRECISIONTIMER_START: + CL_PrecisionTimerStart( (void **)VMA(1) ); + return 0; + + case CG_PRECISIONTIMER_END: + return CL_PrecisionTimerEnd( (void *)args[1] ); + + case CG_CVAR_REGISTER: + Cvar_Register( (vmCvar_t *)VMA(1), (const char *)VMA(2), (const char *)VMA(3), args[4] ); + return 0; + + case CG_CVAR_UPDATE: + Cvar_Update( (vmCvar_t *)VMA(1) ); + return 0; + + case CG_CVAR_SET: + Cvar_VM_Set( (const char *)VMA(1), (const char *)VMA(2), VM_CGAME ); + return 0; + + case CG_CVAR_VARIABLESTRINGBUFFER: + Cvar_VariableStringBuffer( (const char *)VMA(1), (char *)VMA(2), args[3] ); + return 0; + + case CG_CVAR_GETHIDDENVALUE: + return CL_GetValueForHidden((const char *)VMA(1)); + + case CG_ARGC: + return Cmd_Argc(); + + case CG_ARGV: + Cmd_ArgvBuffer( args[1], (char *)VMA(2), args[3] ); + return 0; + + case CG_ARGS: + Cmd_ArgsBuffer( (char *)VMA(1), args[2] ); + return 0; + + case CG_FS_FOPENFILE: + return FS_FOpenFileByMode( (const char *)VMA(1), (int *)VMA(2), (fsMode_t)args[3] ); + + case CG_FS_READ: + FS_Read( VMA(1), args[2], args[3] ); + return 0; + + case CG_FS_WRITE: + FS_Write( VMA(1), args[2], args[3] ); + return 0; + + case CG_FS_FCLOSEFILE: + FS_FCloseFile( args[1] ); + return 0; + + case CG_FS_GETFILELIST: + return FS_GetFileList( (const char *)VMA(1), (const char *)VMA(2), (char *)VMA(3), args[4] ); + + case CG_SENDCONSOLECOMMAND: + Cbuf_AddText( (const char *)VMA(1) ); + return 0; + + case CG_ADDCOMMAND: + CL_AddCgameCommand( (const char *)VMA(1) ); + return 0; + + case CG_REMOVECOMMAND: + Cmd_VM_RemoveCommand( (const char *)VMA(1), VM_CGAME ); + return 0; + + case CG_SENDCLIENTCOMMAND: + CL_AddReliableCommand2( (const char *)VMA(1) ); + return 0; + + case CG_UPDATESCREEN: + // this is used during lengthy level loading, so pump message loop + // Com_EventLoop(); // FIXME: if a server restarts here, BAD THINGS HAPPEN! + // We can't call Com_EventLoop here, a restart will crash and this _does_ happen + // if there is a map change while we are downloading at pk3. + // ZOID + SCR_UpdateScreen(); + return 0; + + case CG_CM_LOADMAP: + CL_CM_LoadMap( (const char *)VMA(1), (qboolean)args[2] ); + return 0; + + case CG_CM_NUMINLINEMODELS: + return CM_NumInlineModels(); + + case CG_CM_INLINEMODEL: + return CM_InlineModel( args[1] ); + + case CG_CM_TEMPBOXMODEL: + return CM_TempBoxModel( (const float *)VMA(1), (const float *)VMA(2), /*int capsule*/ qfalse ); + + case CG_CM_TEMPCAPSULEMODEL: + return CM_TempBoxModel( (const float *)VMA(1), (const float *)VMA(2), /*int capsule*/ qtrue ); + + case CG_CM_POINTCONTENTS: + return CM_PointContents( (const float *)VMA(1), args[2] ); + + case CG_CM_TRANSFORMEDPOINTCONTENTS: + return CM_TransformedPointContents( (const float *)VMA(1), args[2], (const float *)VMA(3), (const float *)VMA(4) ); + + case CG_CM_BOXTRACE: + CM_BoxTrace( (trace_t *)VMA(1), (const float *)VMA(2), (const float *)VMA(3), (const float *)VMA(4), (const float *)VMA(5), args[6], args[7], /*int capsule*/ qfalse ); + return 0; + + case CG_CM_CAPSULETRACE: + CM_BoxTrace( (trace_t *)VMA(1), (const float *)VMA(2), (const float *)VMA(3), (const float *)VMA(4), (const float *)VMA(5), args[6], args[7], /*int capsule*/ qtrue ); + return 0; + + case CG_CM_TRANSFORMEDBOXTRACE: + CM_TransformedBoxTrace( (trace_t *)VMA(1), (const float *)VMA(2), (const float *)VMA(3), (const float *)VMA(4), (const float *)VMA(5), args[6], args[7], (const float *)VMA(8), (const float *)VMA(9), /*int capsule*/ qfalse ); + return 0; + + case CG_CM_TRANSFORMEDCAPSULETRACE: + CM_TransformedBoxTrace( (trace_t *)VMA(1), (const float *)VMA(2), (const float *)VMA(3), (const float *)VMA(4), (const float *)VMA(5), args[6], args[7], (const float *)VMA(8), (const float *)VMA(9), /*int capsule*/ qtrue ); + return 0; + + case CG_CM_MARKFRAGMENTS: + return re->MarkFragments( args[1], (const vec3_t *)VMA(2), (const float *)VMA(3), args[4], (float *)VMA(5), args[6], (markFragment_t *)VMA(7) ); + + case CG_S_GETVOICEVOLUME: + return CL_S_GetVoiceVolume( args[1] ); + + case CG_S_MUTESOUND: + S_MuteSound( args[1], args[2] ); + return 0; + + case CG_S_STARTSOUND: + S_StartSound( (float *)VMA(1), args[2], args[3], args[4] ); + return 0; + + case CG_S_STARTLOCALSOUND: + S_StartLocalSound( args[1], args[2] ); + return 0; + + case CG_S_CLEARLOOPINGSOUNDS: + S_ClearLoopingSounds(); + return 0; + + case CG_S_ADDLOOPINGSOUND: + S_AddLoopingSound( args[1], (const float *)VMA(2), (const float *)VMA(3), args[4] ); + return 0; + + case CG_S_ADDREALLOOPINGSOUND: + /*S_AddRealLoopingSound*/S_AddLoopingSound( args[1], (const float *)VMA(2), (const float *)VMA(3), args[4] ); + return 0; + + case CG_S_STOPLOOPINGSOUND: + S_StopLoopingSound( args[1] ); + return 0; + + case CG_S_UPDATEENTITYPOSITION: + S_UpdateEntityPosition( args[1], (const float *)VMA(2) ); + return 0; + + case CG_S_RESPATIALIZE: + S_Respatialize( args[1], (const float *)VMA(2), (vec3_t *)VMA(3), args[4] ); + return 0; + + case CG_S_SHUTUP: + CL_S_Shutup( (qboolean)args[1] ); + return 0; + + case CG_S_REGISTERSOUND: + return S_RegisterSound( (const char *)VMA(1) ); + + case CG_S_STARTBACKGROUNDTRACK: + S_StartBackgroundTrack( (const char *)VMA(1), (const char *)VMA(2), args[3]?qtrue:qfalse ); + return 0; + + case CG_S_UPDATEAMBIENTSET: + S_UpdateAmbientSet((const char *)VMA(1), (float *)VMA(2)); + return 0; + + case CG_AS_PARSESETS: + AS_ParseSets(); + return 0; + + case CG_AS_ADDPRECACHEENTRY: + AS_AddPrecacheEntry((const char *)VMA(1)); + return 0; + + case CG_S_ADDLOCALSET: + return S_AddLocalSet((const char *)VMA(1), (float *)VMA(2), (float *)VMA(3), args[4], args[5]); + + case CG_AS_GETBMODELSOUND: + return AS_GetBModelSound((const char *)VMA(1), args[2]); + + case CG_R_LOADWORLDMAP: + re->LoadWorld( (const char *)VMA(1) ); + return 0; + + case CG_R_REGISTERMODEL: + return re->RegisterModel( (const char *)VMA(1) ); + + case CG_R_REGISTERSKIN: + return re->RegisterSkin( (const char *)VMA(1) ); + + case CG_R_REGISTERSHADER: + return re->RegisterShader( (const char *)VMA(1) ); + + case CG_R_REGISTERSHADERNOMIP: + return re->RegisterShaderNoMip( (const char *)VMA(1) ); + + case CG_R_REGISTERFONT: + return re->RegisterFont( (const char *)VMA(1) ); + + case CG_R_FONT_STRLENPIXELS: + return re->Font_StrLenPixels( (const char *)VMA(1), args[2], VMF(3) ); + + case CG_R_FONT_STRLENCHARS: + return re->Font_StrLenChars( (const char *)VMA(1) ); + + case CG_R_FONT_STRHEIGHTPIXELS: + return re->Font_HeightPixels( args[1], VMF(2) ); + + case CG_R_FONT_DRAWSTRING: + re->Font_DrawString( args[1], args[2], (const char *)VMA(3), (const float *) VMA(4), args[5], args[6], VMF(7) ); + return 0; + + case CG_LANGUAGE_ISASIAN: + return re->Language_IsAsian(); + + case CG_LANGUAGE_USESSPACES: + return re->Language_UsesSpaces(); + + case CG_ANYLANGUAGE_READCHARFROMSTRING: + return re->AnyLanguage_ReadCharFromString( (const char *) VMA(1), (int *) VMA(2), (qboolean *) VMA(3) ); + + case CG_R_CLEARSCENE: + re->ClearScene(); + return 0; + + case CG_R_CLEARDECALS: + re->ClearDecals(); + return 0; + + case CG_R_ADDREFENTITYTOSCENE: + re->AddRefEntityToScene( (const refEntity_t *)VMA(1) ); + return 0; + + case CG_R_ADDPOLYTOSCENE: + re->AddPolyToScene( args[1], args[2], (const polyVert_t *)VMA(3), 1 ); + return 0; + + case CG_R_ADDPOLYSTOSCENE: + re->AddPolyToScene( args[1], args[2], (const polyVert_t *)VMA(3), args[4] ); + return 0; + + case CG_R_ADDDECALTOSCENE: + re->AddDecalToScene( (qhandle_t)args[1], (const float*)VMA(2), (const float*)VMA(3), VMF(4), VMF(5), VMF(6), VMF(7), VMF(8), (qboolean)args[9], VMF(10), (qboolean)args[11] ); + return 0; + + case CG_R_LIGHTFORPOINT: + return re->LightForPoint( (float *)VMA(1), (float *)VMA(2), (float *)VMA(3), (float *)VMA(4) ); + + case CG_R_ADDLIGHTTOSCENE: + re->AddLightToScene( (const float *)VMA(1), VMF(2), VMF(3), VMF(4), VMF(5) ); + return 0; + + case CG_R_ADDADDITIVELIGHTTOSCENE: + re->AddAdditiveLightToScene( (const float *)VMA(1), VMF(2), VMF(3), VMF(4), VMF(5) ); + return 0; + + case CG_R_RENDERSCENE: + re->RenderScene( (const refdef_t *)VMA(1) ); + return 0; + + case CG_R_SETCOLOR: + re->SetColor( (const float *)VMA(1) ); + return 0; + + case CG_R_DRAWSTRETCHPIC: + re->DrawStretchPic( VMF(1), VMF(2), VMF(3), VMF(4), VMF(5), VMF(6), VMF(7), VMF(8), args[9] ); + return 0; + + case CG_R_MODELBOUNDS: + re->ModelBounds( args[1], (float *)VMA(2), (float *)VMA(3) ); + return 0; + + case CG_R_LERPTAG: + return re->LerpTag( (orientation_t *)VMA(1), args[2], args[3], args[4], VMF(5), (const char *)VMA(6) ); + + case CG_R_DRAWROTATEPIC: + re->DrawRotatePic( VMF(1), VMF(2), VMF(3), VMF(4), VMF(5), VMF(6), VMF(7), VMF(8), VMF(9), args[10] ); + return 0; + + case CG_R_DRAWROTATEPIC2: + re->DrawRotatePic2( VMF(1), VMF(2), VMF(3), VMF(4), VMF(5), VMF(6), VMF(7), VMF(8), VMF(9), args[10] ); + return 0; + + case CG_R_SETRANGEFOG: + re->SetRangedFog( VMF(1) ); + return 0; + + case CG_R_SETREFRACTIONPROP: + re->SetRefractionProperties( VMF(1), VMF(2), (qboolean)args[3], (qboolean)args[4] ); + return 0; + + case CG_GETGLCONFIG: + CL_GetGlconfig( (glconfig_t *)VMA(1) ); + return 0; + + case CG_GETGAMESTATE: + CL_GetGameState( (gameState_t *)VMA(1) ); + return 0; + + case CG_GETCURRENTSNAPSHOTNUMBER: + CL_GetCurrentSnapshotNumber( (int *)VMA(1), (int *)VMA(2) ); + return 0; + + case CG_GETSNAPSHOT: + return CL_GetSnapshot( args[1], (snapshot_t *)VMA(2) ); + + case CG_GETDEFAULTSTATE: + return CL_GetDefaultState(args[1], (entityState_t *)VMA(2)); + + case CG_GETSERVERCOMMAND: + return CL_GetServerCommand( args[1] ); + + case CG_GETCURRENTCMDNUMBER: + return CL_GetCurrentCmdNumber(); + + case CG_GETUSERCMD: + return CL_GetUserCmd( args[1], (struct usercmd_s *)VMA(2) ); + + case CG_SETUSERCMDVALUE: + _CL_SetUserCmdValue( args[1], VMF(2), VMF(3), VMF(4), VMF(5), args[6], args[7], (qboolean)args[8] ); + return 0; + + case CG_SETCLIENTFORCEANGLE: + CL_SetClientForceAngle(args[1], (float *)VMA(2)); + return 0; + + case CG_SETCLIENTTURNEXTENT: + return 0; + + case CG_OPENUIMENU: + CL_OpenUIMenu( args[1] ); + return 0; + + case CG_MEMORY_REMAINING: + return Hunk_MemoryRemaining(); + + case CG_KEY_ISDOWN: + return Key_IsDown( args[1] ); + + case CG_KEY_GETCATCHER: + return Key_GetCatcher(); + + case CG_KEY_SETCATCHER: + CL_Key_SetCatcher( args[1] ); + return 0; + + case CG_KEY_GETKEY: + return Key_GetKey( (const char *)VMA(1) ); + + case CG_PC_ADD_GLOBAL_DEFINE: + return botlib_export->PC_AddGlobalDefine( (char *)VMA(1) ); + + case CG_PC_LOAD_SOURCE: + return botlib_export->PC_LoadSourceHandle( (const char *)VMA(1) ); + + case CG_PC_FREE_SOURCE: + return botlib_export->PC_FreeSourceHandle( args[1] ); + + case CG_PC_READ_TOKEN: + return botlib_export->PC_ReadTokenHandle( args[1], (struct pc_token_s *)VMA(2) ); + + case CG_PC_SOURCE_FILE_AND_LINE: + return botlib_export->PC_SourceFileAndLine( args[1], (char *)VMA(2), (int *)VMA(3) ); + + case CG_PC_LOAD_GLOBAL_DEFINES: + return botlib_export->PC_LoadGlobalDefines ( (char *)VMA(1) ); + + case CG_PC_REMOVE_ALL_GLOBAL_DEFINES: + botlib_export->PC_RemoveAllGlobalDefines ( ); + return 0; + + case CG_S_STOPBACKGROUNDTRACK: + S_StopBackgroundTrack(); + return 0; + + case CG_REAL_TIME: + return Com_RealTime( (struct qtime_s *)VMA(1) ); + + case CG_SNAPVECTOR: + Sys_SnapVector( (float *)VMA(1) ); + return 0; + + case CG_CIN_PLAYCINEMATIC: + return CIN_PlayCinematic((const char *)VMA(1), args[2], args[3], args[4], args[5], args[6]); + + case CG_CIN_STOPCINEMATIC: + return CIN_StopCinematic(args[1]); + + case CG_CIN_RUNCINEMATIC: + return CIN_RunCinematic(args[1]); + + case CG_CIN_DRAWCINEMATIC: + CIN_DrawCinematic(args[1]); + return 0; + + case CG_CIN_SETEXTENTS: + CIN_SetExtents(args[1], args[2], args[3], args[4], args[5]); + return 0; + + case CG_R_REMAP_SHADER: + re->RemapShader( (const char *)VMA(1), (const char *)VMA(2), (const char *)VMA(3) ); + return 0; + + case CG_R_GET_LIGHT_STYLE: + re->GetLightStyle(args[1], (unsigned char *)VMA(2)); + return 0; + + case CG_R_SET_LIGHT_STYLE: + re->SetLightStyle(args[1], args[2]); + return 0; + + case CG_R_GET_BMODEL_VERTS: + re->GetBModelVerts( args[1], (float (*)[3])VMA(2), (float *)VMA(3) ); + return 0; + + case CG_R_GETDISTANCECULL: + { + float *f = (float *)VMA(1); + *f = re->GetDistanceCull(); + } + return 0; + + case CG_R_GETREALRES: + { + int *w = (int *)VMA(1); + int *h = (int *)VMA(2); + re->GetRealRes( w, h ); + } + return 0; + + case CG_R_AUTOMAPELEVADJ: + re->AutomapElevationAdjustment(VMF(1)); + return 0; + + case CG_R_INITWIREFRAMEAUTO: + return re->InitializeWireframeAutomap(); + + case CG_GET_ENTITY_TOKEN: + return re->GetEntityToken( (char *)VMA(1), args[2] ); + + case CG_R_INPVS: + return re->inPVS( (const float *)VMA(1), (const float *)VMA(2), (byte *)VMA(3) ); + +#ifndef DEBUG_DISABLEFXCALLS + case CG_FX_ADDLINE: + CGFX_AddLine( (float *)VMA(1), (float *)VMA(2), VMF(3), VMF(4), VMF(5), + VMF(6), VMF(7), VMF(8), + (float *)VMA(9), (float *)VMA(10), VMF(11), + args[12], args[13], args[14]); + return 0; + case CG_FX_REGISTER_EFFECT: + return FX_RegisterEffect((const char *)VMA(1)); + + case CG_FX_PLAY_EFFECT: + FX_PlayEffect((const char *)VMA(1), (float *)VMA(2), (float *)VMA(3), args[4], args[5] ); + return 0; + + case CG_FX_PLAY_ENTITY_EFFECT: + assert(0); + return 0; + + case CG_FX_PLAY_EFFECT_ID: + FX_PlayEffectID(args[1], (float *)VMA(2), (float *)VMA(3), args[4], args[5] ); + return 0; + + case CG_FX_PLAY_PORTAL_EFFECT_ID: + FX_PlayEffectID(args[1], (float *)VMA(2), (float *)VMA(3), args[4], args[5], qtrue ); + return 0; + + case CG_FX_PLAY_ENTITY_EFFECT_ID: + FX_PlayEntityEffectID(args[1], (float *)VMA(2), (vec3_t *)VMA(3), args[4], args[5], args[6], args[7] ); + return 0; + + case CG_FX_PLAY_BOLTED_EFFECT_ID: + return CGFX_PlayBoltedEffectID( args[1], (float *)VMA(2), (void *)args[3], args[4], args[5], args[6], args[7], (qboolean)args[8] ); + + case CG_FX_ADD_SCHEDULED_EFFECTS: + FX_AddScheduledEffects((qboolean)args[1]); + return 0; + + case CG_FX_DRAW_2D_EFFECTS: + FX_Draw2DEffects ( VMF(1), VMF(2) ); + return 0; + + case CG_FX_INIT_SYSTEM: + return FX_InitSystem( (refdef_t*)VMA(1) ); + + case CG_FX_SET_REFDEF: + FX_SetRefDefFromCGame( (refdef_t*)VMA(1) ); + return 0; + + case CG_FX_FREE_SYSTEM: + return FX_FreeSystem(); + + case CG_FX_ADJUST_TIME: + FX_AdjustTime(args[1]); + return 0; + + case CG_FX_RESET: + FX_Free ( false ); + return 0; + + case CG_FX_ADDPOLY: + CGFX_AddPoly( (addpolyArgStruct_t *)VMA(1) ); + return 0; + case CG_FX_ADDBEZIER: + CGFX_AddBezier( (addbezierArgStruct_t *)VMA(1) ); + return 0; + case CG_FX_ADDPRIMITIVE: + CGFX_AddPrimitive( (effectTrailArgStruct_t *)VMA(1) ); + return 0; + case CG_FX_ADDSPRITE: + CGFX_AddSprite( (addspriteArgStruct_t *)VMA(1) ); + return 0; + case CG_FX_ADDELECTRICITY: + CGFX_AddElectricity( (addElectricityArgStruct_t *)VMA(1) ); + return 0; +#else + case CG_FX_REGISTER_EFFECT: + case CG_FX_PLAY_EFFECT: + case CG_FX_PLAY_ENTITY_EFFECT: + case CG_FX_PLAY_EFFECT_ID: + case CG_FX_PLAY_PORTAL_EFFECT_ID: + case CG_FX_PLAY_ENTITY_EFFECT_ID: + case CG_FX_PLAY_BOLTED_EFFECT_ID: + case CG_FX_ADD_SCHEDULED_EFFECTS: + case CG_FX_INIT_SYSTEM: + case CG_FX_FREE_SYSTEM: + case CG_FX_ADJUST_TIME: + case CG_FX_ADDPOLY: + case CG_FX_ADDBEZIER: + case CG_FX_ADDPRIMITIVE: + case CG_FX_ADDSPRITE: + case CG_FX_ADDELECTRICITY: + return 0; +#endif + + case CG_ROFF_CLEAN: + return CL_ROFF_Clean(); + + case CG_ROFF_UPDATE_ENTITIES: + CL_ROFF_UpdateEntities(); + return 0; + + case CG_ROFF_CACHE: + return CL_ROFF_Cache( (char *)VMA(1) ); + + case CG_ROFF_PLAY: + return CL_ROFF_Play( args[1], args[2], (qboolean)args[3] ); + + case CG_ROFF_PURGE_ENT: + return CL_ROFF_Purge_Ent( args[1] ); + + case CG_TRUEMALLOC: + VM_Shifted_Alloc((void **)VMA(1), args[2]); + return 0; + + case CG_TRUEFREE: + VM_Shifted_Free((void **)VMA(1)); + return 0; + + case CG_G2_LISTSURFACES: + CL_G2API_ListModelSurfaces( VMA(1) ); + return 0; + + case CG_G2_LISTBONES: + CL_G2API_ListModelBones( VMA(1), args[2]); + return 0; + + case CG_G2_HAVEWEGHOULMODELS: + return CL_G2API_HaveWeGhoul2Models( VMA(1) ); + + case CG_G2_SETMODELS: + CL_G2API_SetGhoul2ModelIndexes( VMA(1), (qhandle_t *)VMA(2), (qhandle_t *)VMA(3) ); + return 0; + + case CG_G2_GETBOLT: + return CL_G2API_GetBoltMatrix(VMA(1), args[2], args[3], (mdxaBone_t *)VMA(4), (const float *)VMA(5),(const float *)VMA(6), args[7], (qhandle_t *)VMA(8), (float *)VMA(9)); + + case CG_G2_GETBOLT_NOREC: + return CL_G2API_GetBoltMatrix_NoReconstruct(VMA(1), args[2], args[3], (mdxaBone_t *)VMA(4), (const float *)VMA(5),(const float *)VMA(6), args[7], (qhandle_t *)VMA(8), (float *)VMA(9)); + + case CG_G2_GETBOLT_NOREC_NOROT: + return CL_G2API_GetBoltMatrix_NoRecNoRot(VMA(1), args[2], args[3], (mdxaBone_t *)VMA(4), (const float *)VMA(5),(const float *)VMA(6), args[7], (qhandle_t *)VMA(8), (float *)VMA(9)); + + case CG_G2_INITGHOUL2MODEL: + return CL_G2API_InitGhoul2Model((void **)VMA(1), (const char *)VMA(2), args[3], (qhandle_t) args[4], (qhandle_t) args[5], args[6], args[7]); + + case CG_G2_SETSKIN: + return CL_G2API_SetSkin( VMA(1), args[2], args[3], args[4] ); + + case CG_G2_COLLISIONDETECT: + CL_G2API_CollisionDetect ( (CollisionRecord_t*)VMA(1), VMA(2), (const float*)VMA(3), (const float*)VMA(4), args[5], args[6], (float*)VMA(7), (float*)VMA(8), (float*)VMA(9), args[10], args[11], VMF(12) ); + return 0; + + case CG_G2_COLLISIONDETECTCACHE: + CL_G2API_CollisionDetectCache ( (CollisionRecord_t*)VMA(1), VMA(2), (const float*)VMA(3), (const float*)VMA(4), args[5], args[6], (float*)VMA(7), (float*)VMA(8), (float*)VMA(9), args[10], args[11], VMF(12) ); + return 0; + + case CG_G2_ANGLEOVERRIDE: + return CL_G2API_SetBoneAngles( VMA(1), args[2], (const char *)VMA(3), (float *)VMA(4), args[5], args[6], args[7], args[8], (qhandle_t *)VMA(9), args[10], args[11] ); + + case CG_G2_CLEANMODELS: + CL_G2API_CleanGhoul2Models( (void **)VMA(1) ); + return 0; + + case CG_G2_PLAYANIM: + return CL_G2API_SetBoneAnim( VMA(1), args[2], (const char *)VMA(3), args[4], args[5], args[6], VMF(7), args[8], VMF(9), args[10] ); + + case CG_G2_GETBONEANIM: + return CL_G2API_GetBoneAnim( VMA(1), (const char *)VMA(2), args[3], (float *)VMA(4), (int *)VMA(5), (int *)VMA(6), (int *)VMA(7), (float *)VMA(8), (int *)VMA(9), args[10] ); + + case CG_G2_GETBONEFRAME: + return CL_G2API_GetBoneFrame( VMA(1), (const char*)VMA(2), args[3], (float *)VMA(4), (int *)VMA(5), args[6] ); + + case CG_G2_GETGLANAME: + CL_G2API_GetGLAName( VMA(1), args[2], (char *)VMA(3) ); + return 0; + + case CG_G2_COPYGHOUL2INSTANCE: + return CL_G2API_CopyGhoul2Instance( VMA(1), VMA(2), args[3] ); + + case CG_G2_COPYSPECIFICGHOUL2MODEL: + CL_G2API_CopySpecificGhoul2Model( VMA(1), args[2], VMA(3), args[4] ); + return 0; + + case CG_G2_DUPLICATEGHOUL2INSTANCE: + CL_G2API_DuplicateGhoul2Instance( VMA(1), (void **)VMA(2) ); + return 0; + + case CG_G2_HASGHOUL2MODELONINDEX: + return CL_G2API_HasGhoul2ModelOnIndex( VMA(1), args[2]); + + case CG_G2_REMOVEGHOUL2MODEL: + return CL_G2API_RemoveGhoul2Model( VMA(1), args[2]); + + case CG_G2_SKINLESSMODEL: + return CL_G2API_SkinlessModel( VMA(1), args[2] ); + + case CG_G2_GETNUMGOREMARKS: + return CL_G2API_GetNumGoreMarks( VMA(1), args[2] ); + + case CG_G2_ADDSKINGORE: + CL_G2API_AddSkinGore( VMA(1), (SSkinGoreData *)VMA(2)); + return 0; + + case CG_G2_CLEARSKINGORE: + CL_G2API_ClearSkinGore ( VMA(1) ); + return 0; + + case CG_G2_SIZE: + return CL_G2API_Ghoul2Size ( VMA(1) ); + + case CG_G2_ADDBOLT: + return CL_G2API_AddBolt( VMA(1), args[2], (const char *)VMA(3)); + + case CG_G2_ATTACHENT: + return CL_G2API_AttachEnt( (int*)VMA(1), VMA(2), args[3], args[4], args[5] ); + + case CG_G2_SETBOLTON: + CL_G2API_SetBoltInfo( VMA(1), args[2], args[3] ); + return 0; + + case CG_G2_SETROOTSURFACE: + return CL_G2API_SetRootSurface( VMA(1), args[2], (const char *)VMA(3)); + + case CG_G2_SETSURFACEONOFF: + return CL_G2API_SetSurfaceOnOff( VMA(1), (const char *)VMA(2), args[3]); + + case CG_G2_SETNEWORIGIN: + return CL_G2API_SetNewOrigin( VMA(1), args[2]); + + case CG_G2_DOESBONEEXIST: + return CL_G2API_DoesBoneExist( VMA(1), args[2], (const char *)VMA(3)); + + case CG_G2_GETSURFACERENDERSTATUS: + return CL_G2API_GetSurfaceRenderStatus( VMA(1), args[2], (const char *)VMA(3)); + + case CG_G2_GETTIME: + return CL_G2API_GetTime(); + + case CG_G2_SETTIME: + CL_G2API_SetTime(args[1], args[2]); + return 0; + + case CG_G2_ABSURDSMOOTHING: + CL_G2API_AbsurdSmoothing( VMA(1), (qboolean)args[2]); + return 0; + + + case CG_G2_SETRAGDOLL: + CL_G2API_SetRagDoll( VMA(1), (sharedRagDollParams_t *)VMA(2) ); + return 0; + + case CG_G2_ANIMATEG2MODELS: + CL_G2API_AnimateG2Models( VMA(1), args[2], (sharedRagDollUpdateParams_t *)VMA(3) ); + return 0; + + //additional ragdoll options -rww + case CG_G2_RAGPCJCONSTRAINT: + return CL_G2API_RagPCJConstraint( VMA(1), (const char *)VMA(2), (float *)VMA(3), (float *)VMA(4)); + + case CG_G2_RAGPCJGRADIENTSPEED: + return CL_G2API_RagPCJGradientSpeed( VMA(1), (const char *)VMA(2), VMF(3)); + + case CG_G2_RAGEFFECTORGOAL: + return CL_G2API_RagEffectorGoal( VMA(1), (const char *)VMA(2), (float *)VMA(3)); + + case CG_G2_GETRAGBONEPOS: + return CL_G2API_GetRagBonePos( VMA(1), (const char *)VMA(2), (float *)VMA(3), (float *)VMA(4), (float *)VMA(5), (float *)VMA(6)); + + case CG_G2_RAGEFFECTORKICK: + return CL_G2API_RagEffectorKick( VMA(1), (const char *)VMA(2), (float *)VMA(3)); + + case CG_G2_RAGFORCESOLVE: + return CL_G2API_RagForceSolve( VMA(1), (qboolean)args[2]); + + case CG_G2_SETBONEIKSTATE: + return CL_G2API_SetBoneIKState( VMA(1), args[2], (const char *)VMA(3), args[4], (sharedSetBoneIKStateParams_t *)VMA(5)); + + case CG_G2_IKMOVE: + return CL_G2API_IKMove( VMA(1), args[2], (sharedIKMoveParams_t *)VMA(3)); + + case CG_G2_REMOVEBONE: + return CL_G2API_RemoveBone( VMA(1), (const char *)VMA(2), args[3] ); + + case CG_G2_ATTACHINSTANCETOENTNUM: + CL_G2API_AttachInstanceToEntNum( VMA(1), args[2], (qboolean)args[3]); + return 0; + + case CG_G2_CLEARATTACHEDINSTANCE: + CL_G2API_ClearAttachedInstance(args[1]); + return 0; + + case CG_G2_CLEANENTATTACHMENTS: + CL_G2API_CleanEntAttachments(); + return 0; + + case CG_G2_OVERRIDESERVER: + return CL_G2API_OverrideServer( VMA(1) ); + + case CG_G2_GETSURFACENAME: + CL_G2API_GetSurfaceName( VMA(1), args[2], args[3], (char *)VMA(4) ); + return 0; + + case CG_SP_GETSTRINGTEXTSTRING: + return CL_SE_GetStringTextString( (const char *)VMA(1), (char *)VMA(2), args[3] ); + + case CG_SET_SHARED_BUFFER: + RegisterSharedMemory( (char *)VMA(1) ); + return 0; + + case CG_CM_REGISTER_TERRAIN: + return 0; + + case CG_RMG_INIT: + return 0; + + case CG_RE_INIT_RENDERER_TERRAIN: + return 0; + + case CG_R_WEATHER_CONTENTS_OVERRIDE: + //contentOverride = args[1]; + return 0; + + case CG_R_WORLDEFFECTCOMMAND: + re->WorldEffectCommand((const char *)VMA(1)); + return 0; + + case CG_WE_ADDWEATHERZONE: + re->AddWeatherZone( (float *)VMA(1), (float *)VMA(2) ); + return 0; + + default: + assert(0); // bk010102 + Com_Error( ERR_DROP, "Bad cgame system trap: %ld", (long int) args[0] ); + } + return 0; +} + +// Stub function for old RMG system. +static void RE_InitRendererTerrain ( const char * /*info*/ ) {} + +void CL_BindCGame( void ) { + static cgameImport_t cgi; + cgameExport_t *ret; + GetCGameAPI_t GetCGameAPI; + char dllName[MAX_OSPATH] = "cgame" ARCH_STRING DLL_EXT; + + memset( &cgi, 0, sizeof( cgi ) ); + + cgvm = VM_Create( VM_CGAME ); + if ( cgvm && !cgvm->isLegacy ) { + cgi.Print = Com_Printf; + cgi.Error = Com_Error; + cgi.SnapVector = Sys_SnapVector; + cgi.MemoryRemaining = Hunk_MemoryRemaining; + cgi.RegisterSharedMemory = RegisterSharedMemory; + cgi.TrueMalloc = VM_Shifted_Alloc; + cgi.TrueFree = VM_Shifted_Free; + cgi.Milliseconds = CL_Milliseconds; + cgi.RealTime = Com_RealTime; + cgi.PrecisionTimerStart = CL_PrecisionTimerStart; + cgi.PrecisionTimerEnd = CL_PrecisionTimerEnd; + cgi.Cvar_Register = Cvar_Register; + cgi.Cvar_Set = CGVM_Cvar_Set; + cgi.Cvar_Update = Cvar_Update; + cgi.Cvar_VariableStringBuffer = Cvar_VariableStringBuffer; + cgi.AddCommand = CL_AddCgameCommand; + cgi.Cmd_Argc = Cmd_Argc; + cgi.Cmd_Args = Cmd_ArgsBuffer; + cgi.Cmd_Argv = Cmd_ArgvBuffer; + cgi.RemoveCommand = CGVM_Cmd_RemoveCommand; + cgi.SendClientCommand = CL_AddReliableCommand2; + cgi.SendConsoleCommand = Cbuf_AddText; + cgi.FS_Close = FS_FCloseFile; + cgi.FS_GetFileList = FS_GetFileList; + cgi.FS_Open = FS_FOpenFileByMode; + cgi.FS_Read = FS_Read; + cgi.FS_Write = FS_Write; + cgi.UpdateScreen = SCR_UpdateScreen; + cgi.CM_InlineModel = CM_InlineModel; + cgi.CM_LoadMap = CL_CM_LoadMap; + cgi.CM_NumInlineModels = CM_NumInlineModels; + cgi.CM_PointContents = CM_PointContents; + cgi.CM_RegisterTerrain = CL_CM_RegisterTerrain; + cgi.CM_TempModel = CM_TempBoxModel; + cgi.CM_Trace = CM_BoxTrace; + cgi.CM_TransformedPointContents = CM_TransformedPointContents; + cgi.CM_TransformedTrace = CM_TransformedBoxTrace; + cgi.RMG_Init = CL_RMG_Init; + cgi.S_AddLocalSet = S_AddLocalSet; + cgi.S_AddLoopingSound = S_AddLoopingSound; + cgi.S_ClearLoopingSounds = S_ClearLoopingSounds; + cgi.S_GetVoiceVolume = CL_S_GetVoiceVolume; + cgi.S_MuteSound = S_MuteSound; + cgi.S_RegisterSound = S_RegisterSound; + cgi.S_Respatialize = S_Respatialize; + cgi.S_Shutup = CL_S_Shutup; + cgi.S_StartBackgroundTrack = S_StartBackgroundTrack; + cgi.S_StartLocalSound = S_StartLocalSound; + cgi.S_StartSound = S_StartSound; + cgi.S_StopBackgroundTrack = S_StopBackgroundTrack; + cgi.S_StopLoopingSound = S_StopLoopingSound; + cgi.S_UpdateEntityPosition = S_UpdateEntityPosition; + cgi.S_UpdateAmbientSet = S_UpdateAmbientSet; + cgi.AS_AddPrecacheEntry = AS_AddPrecacheEntry; + cgi.AS_GetBModelSound = AS_GetBModelSound; + cgi.AS_ParseSets = AS_ParseSets; + cgi.R_AddAdditiveLightToScene = re->AddAdditiveLightToScene; + cgi.R_AddDecalToScene = re->AddDecalToScene; + cgi.R_AddLightToScene = re->AddLightToScene; + cgi.R_AddPolysToScene = re->AddPolyToScene; + cgi.R_AddRefEntityToScene = re->AddRefEntityToScene; + cgi.R_AnyLanguage_ReadCharFromString = re->AnyLanguage_ReadCharFromString; + cgi.R_AutomapElevationAdjustment = re->AutomapElevationAdjustment; + cgi.R_ClearDecals = re->ClearDecals; + cgi.R_ClearScene = re->ClearScene; + cgi.R_DrawStretchPic = re->DrawStretchPic; + cgi.R_DrawRotatePic = re->DrawRotatePic; + cgi.R_DrawRotatePic2 = re->DrawRotatePic2; + cgi.R_Font_DrawString = re->Font_DrawString; + cgi.R_Font_HeightPixels = re->Font_HeightPixels; + cgi.R_Font_StrLenChars = re->Font_StrLenChars; + cgi.R_Font_StrLenPixels = re->Font_StrLenPixels; + cgi.R_GetBModelVerts = re->GetBModelVerts; + cgi.R_GetDistanceCull = re->GetDistanceCull; + cgi.R_GetEntityToken = re->GetEntityToken; + cgi.R_GetLightStyle = re->GetLightStyle; + cgi.R_GetRealRes = re->GetRealRes; + cgi.R_InitializeWireframeAutomap = re->InitializeWireframeAutomap; + cgi.R_InPVS = re->inPVS; + cgi.R_Language_IsAsian = re->Language_IsAsian; + cgi.R_Language_UsesSpaces = re->Language_UsesSpaces; + cgi.R_LerpTag = re->LerpTag; + cgi.R_LightForPoint = re->LightForPoint; + cgi.R_LoadWorld = re->LoadWorld; + cgi.R_MarkFragments = re->MarkFragments; + cgi.R_ModelBounds = re->ModelBounds; + cgi.R_RegisterFont = re->RegisterFont; + cgi.R_RegisterModel = re->RegisterModel; + cgi.R_RegisterShader = re->RegisterShader; + cgi.R_RegisterShaderNoMip = re->RegisterShaderNoMip; + cgi.R_RegisterSkin = re->RegisterSkin; + cgi.R_RemapShader = re->RemapShader; + cgi.R_RenderScene = re->RenderScene; + cgi.R_SetColor = re->SetColor; + cgi.R_SetLightStyle = re->SetLightStyle; + cgi.R_SetRangedFog = re->SetRangedFog; + cgi.R_SetRefractionProperties = re->SetRefractionProperties; + cgi.R_WorldEffectCommand = re->WorldEffectCommand; + cgi.RE_InitRendererTerrain = RE_InitRendererTerrain; + cgi.WE_AddWeatherZone = re->AddWeatherZone; + cgi.GetCurrentSnapshotNumber = CL_GetCurrentSnapshotNumber; + cgi.GetCurrentCmdNumber = CL_GetCurrentCmdNumber; + cgi.GetDefaultState = CL_GetDefaultState; + cgi.GetGameState = CL_GetGameState; + cgi.GetGlconfig = CL_GetGlconfig; + cgi.GetServerCommand = CL_GetServerCommand; + cgi.GetSnapshot = CL_GetSnapshot; + cgi.GetUserCmd = CL_GetUserCmd; + cgi.OpenUIMenu = CL_OpenUIMenu; + cgi.SetClientForceAngle = CL_SetClientForceAngle; + cgi.SetUserCmdValue = _CL_SetUserCmdValue; + cgi.Key_GetCatcher = Key_GetCatcher; + cgi.Key_GetKey = Key_GetKey; + cgi.Key_IsDown = Key_IsDown; + cgi.Key_SetCatcher = CL_Key_SetCatcher; + cgi.PC_AddGlobalDefine = botlib_export->PC_AddGlobalDefine; + cgi.PC_FreeSource = botlib_export->PC_FreeSourceHandle; + cgi.PC_LoadGlobalDefines = botlib_export->PC_LoadGlobalDefines; + cgi.PC_LoadSource = botlib_export->PC_LoadSourceHandle; + cgi.PC_ReadToken = botlib_export->PC_ReadTokenHandle; + cgi.PC_RemoveAllGlobalDefines = botlib_export->PC_RemoveAllGlobalDefines; + cgi.PC_SourceFileAndLine = botlib_export->PC_SourceFileAndLine; + cgi.CIN_DrawCinematic = CIN_DrawCinematic; + cgi.CIN_PlayCinematic = CIN_PlayCinematic; + cgi.CIN_RunCinematic = CIN_RunCinematic; + cgi.CIN_SetExtents = CIN_SetExtents; + cgi.CIN_StopCinematic = CIN_StopCinematic; + cgi.FX_AddLine = CGFX_AddLine; + cgi.FX_RegisterEffect = FX_RegisterEffect; + cgi.FX_PlayEffect = FX_PlayEffect; + cgi.FX_PlayEffectID = FX_PlayEffectID; + cgi.FX_PlayEntityEffectID = FX_PlayEntityEffectID; + cgi.FX_PlayBoltedEffectID = CGFX_PlayBoltedEffectID; + cgi.FX_AddScheduledEffects = FX_AddScheduledEffects; + cgi.FX_InitSystem = FX_InitSystem; + cgi.FX_SetRefDef = FX_SetRefDef; + cgi.FX_FreeSystem = FX_FreeSystem; + cgi.FX_AdjustTime = FX_AdjustTime; + cgi.FX_Draw2DEffects = FX_Draw2DEffects; + cgi.FX_AddPoly = CGFX_AddPoly; + cgi.FX_AddBezier = CGFX_AddBezier; + cgi.FX_AddPrimitive = CGFX_AddPrimitive; + cgi.FX_AddSprite = CGFX_AddSprite; + cgi.FX_AddElectricity = CGFX_AddElectricity; + cgi.SE_GetStringTextString = CL_SE_GetStringTextString; + cgi.ROFF_Clean = CL_ROFF_Clean; + cgi.ROFF_UpdateEntities = CL_ROFF_UpdateEntities; + cgi.ROFF_Cache = CL_ROFF_Cache; + cgi.ROFF_Play = CL_ROFF_Play; + cgi.ROFF_Purge_Ent = CL_ROFF_Purge_Ent; + cgi.G2_ListModelSurfaces = CL_G2API_ListModelSurfaces; + cgi.G2_ListModelBones = CL_G2API_ListModelBones; + cgi.G2_SetGhoul2ModelIndexes = CL_G2API_SetGhoul2ModelIndexes; + cgi.G2_HaveWeGhoul2Models = CL_G2API_HaveWeGhoul2Models; + cgi.G2API_GetBoltMatrix = CL_G2API_GetBoltMatrix; + cgi.G2API_GetBoltMatrix_NoReconstruct = CL_G2API_GetBoltMatrix_NoReconstruct; + cgi.G2API_GetBoltMatrix_NoRecNoRot = CL_G2API_GetBoltMatrix_NoRecNoRot; + cgi.G2API_InitGhoul2Model = CL_G2API_InitGhoul2Model; + cgi.G2API_SetSkin = CL_G2API_SetSkin; + cgi.G2API_CollisionDetect = CL_G2API_CollisionDetect; + cgi.G2API_CollisionDetectCache = CL_G2API_CollisionDetectCache; + cgi.G2API_CleanGhoul2Models = CL_G2API_CleanGhoul2Models; + cgi.G2API_SetBoneAngles = CL_G2API_SetBoneAngles; + cgi.G2API_SetBoneAnim = CL_G2API_SetBoneAnim; + cgi.G2API_GetBoneAnim = CL_G2API_GetBoneAnim; + cgi.G2API_GetBoneFrame = CL_G2API_GetBoneFrame; + cgi.G2API_GetGLAName = CL_G2API_GetGLAName; + cgi.G2API_CopyGhoul2Instance = CL_G2API_CopyGhoul2Instance; + cgi.G2API_CopySpecificGhoul2Model = CL_G2API_CopySpecificGhoul2Model; + cgi.G2API_DuplicateGhoul2Instance = CL_G2API_DuplicateGhoul2Instance; + cgi.G2API_HasGhoul2ModelOnIndex = CL_G2API_HasGhoul2ModelOnIndex; + cgi.G2API_RemoveGhoul2Model = CL_G2API_RemoveGhoul2Model; + cgi.G2API_SkinlessModel = CL_G2API_SkinlessModel; + cgi.G2API_GetNumGoreMarks = CL_G2API_GetNumGoreMarks; + cgi.G2API_AddSkinGore = CL_G2API_AddSkinGore; + cgi.G2API_ClearSkinGore = CL_G2API_ClearSkinGore; + cgi.G2API_Ghoul2Size = CL_G2API_Ghoul2Size; + cgi.G2API_AddBolt = CL_G2API_AddBolt; + cgi.G2API_AttachEnt = CL_G2API_AttachEnt; + cgi.G2API_SetBoltInfo = CL_G2API_SetBoltInfo; + cgi.G2API_SetRootSurface = CL_G2API_SetRootSurface; + cgi.G2API_SetSurfaceOnOff = CL_G2API_SetSurfaceOnOff; + cgi.G2API_SetNewOrigin = CL_G2API_SetNewOrigin; + cgi.G2API_DoesBoneExist = CL_G2API_DoesBoneExist; + cgi.G2API_GetSurfaceRenderStatus = CL_G2API_GetSurfaceRenderStatus; + cgi.G2API_GetTime = CL_G2API_GetTime; + cgi.G2API_SetTime = CL_G2API_SetTime; + cgi.G2API_AbsurdSmoothing = CL_G2API_AbsurdSmoothing; + cgi.G2API_SetRagDoll = CL_G2API_SetRagDoll; + cgi.G2API_AnimateG2Models = CL_G2API_AnimateG2Models; + cgi.G2API_RagPCJConstraint = CL_G2API_RagPCJConstraint; + cgi.G2API_RagPCJGradientSpeed = CL_G2API_RagPCJGradientSpeed; + cgi.G2API_RagEffectorGoal = CL_G2API_RagEffectorGoal; + cgi.G2API_GetRagBonePos = CL_G2API_GetRagBonePos; + cgi.G2API_RagEffectorKick = CL_G2API_RagEffectorKick; + cgi.G2API_RagForceSolve = CL_G2API_RagForceSolve; + cgi.G2API_SetBoneIKState = CL_G2API_SetBoneIKState; + cgi.G2API_IKMove = CL_G2API_IKMove; + cgi.G2API_RemoveBone = CL_G2API_RemoveBone; + cgi.G2API_AttachInstanceToEntNum = CL_G2API_AttachInstanceToEntNum; + cgi.G2API_ClearAttachedInstance = CL_G2API_ClearAttachedInstance; + cgi.G2API_CleanEntAttachments = CL_G2API_CleanEntAttachments; + cgi.G2API_OverrideServer = CL_G2API_OverrideServer; + cgi.G2API_GetSurfaceName = CL_G2API_GetSurfaceName; + + cgi.ext.R_Font_StrLenPixels = re->ext.Font_StrLenPixels; + + GetCGameAPI = (GetCGameAPI_t)cgvm->GetModuleAPI; + ret = GetCGameAPI( CGAME_API_VERSION, &cgi ); + if ( !ret ) { + //free VM? + cls.cgameStarted = qfalse; + Com_Error( ERR_FATAL, "GetGameAPI failed on %s", dllName ); + } + cge = ret; + + return; + } + + // fall back to legacy syscall/vm_call api + cgvm = VM_CreateLegacy( VM_CGAME, CL_CgameSystemCalls ); + if ( !cgvm ) { + cls.cgameStarted = qfalse; + Com_Error( ERR_DROP, "VM_CreateLegacy on cgame failed" ); + } +} + +void CL_UnbindCGame( void ) { + CGVM_Shutdown(); + VM_Free( cgvm ); + cgvm = NULL; +} diff --git a/Projects/Android/jni/OpenJK/codemp_delete/client/cl_cgameapi.h b/Projects/Android/jni/OpenJK/codemp_delete/client/cl_cgameapi.h new file mode 100644 index 0000000..b4f9933 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/client/cl_cgameapi.h @@ -0,0 +1,52 @@ +/* +=========================================================================== +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#pragma once + +void CGVM_Init ( int serverMessageNum, int serverCommandSequence, int clientNum ); +void CGVM_Shutdown ( void ); +qboolean CGVM_ConsoleCommand ( void ); +void CGVM_DrawActiveFrame ( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback ); +int CGVM_CrosshairPlayer ( void ); +int CGVM_LastAttacker ( void ); +void CGVM_KeyEvent ( int key, qboolean down ); +void CGVM_MouseEvent ( int x, int y ); +void CGVM_EventHandling ( int type ); +int CGVM_PointContents ( void ); +void CGVM_GetLerpOrigin ( void ); +void CGVM_GetLerpData ( void ); +void CGVM_Trace ( void ); +void CGVM_G2Trace ( void ); +void CGVM_G2Mark ( void ); +int CGVM_RagCallback ( int callType ); +qboolean CGVM_IncomingConsoleCommand ( void ); +qboolean CGVM_NoUseableForce ( void ); +void CGVM_GetOrigin ( int entID, vec3_t out ); +void CGVM_GetAngles ( int entID, vec3_t out ); +trajectory_t * CGVM_GetOriginTrajectory ( int entID ); +trajectory_t * CGVM_GetAngleTrajectory ( int entID ); +void CGVM_ROFF_NotetrackCallback ( int entID, const char *notetrack ); +void CGVM_MapChange ( void ); +void CGVM_AutomapInput ( void ); +void CGVM_MiscEnt ( void ); +void CGVM_CameraShake ( void ); + +void CL_BindCGame( void ); +void CL_UnbindCGame( void ); diff --git a/Projects/Android/jni/OpenJK/codemp/client/cl_cin.cpp b/Projects/Android/jni/OpenJK/codemp_delete/client/cl_cin.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/cl_cin.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/client/cl_cin.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/client/cl_console.cpp b/Projects/Android/jni/OpenJK/codemp_delete/client/cl_console.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/cl_console.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/client/cl_console.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/client/cl_input.cpp b/Projects/Android/jni/OpenJK/codemp_delete/client/cl_input.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/cl_input.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/client/cl_input.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/client/cl_keys.cpp b/Projects/Android/jni/OpenJK/codemp_delete/client/cl_keys.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/cl_keys.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/client/cl_keys.cpp diff --git a/Projects/Android/jni/OpenJK/codemp_delete/client/cl_lan.cpp b/Projects/Android/jni/OpenJK/codemp_delete/client/cl_lan.cpp new file mode 100644 index 0000000..b530cb1 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/client/cl_lan.cpp @@ -0,0 +1,588 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#include "client.h" + +// This is for compatibility of old servercache only +// Remove when 64-bit +int cls_nummplayerservers; +serverInfo_t cls_mplayerServers[MAX_OTHER_SERVERS]; + +/* +==================== +LAN_LoadCachedServers +==================== +*/ +void LAN_LoadCachedServers( ) { + int size; + fileHandle_t fileIn; + cls.numglobalservers = cls_nummplayerservers = cls.numfavoriteservers = 0; + cls.numGlobalServerAddresses = 0; + if (FS_SV_FOpenFileRead("servercache.dat", &fileIn)) { + FS_Read(&cls.numglobalservers, sizeof(int), fileIn); + FS_Read(&cls_nummplayerservers, sizeof(int), fileIn); + FS_Read(&cls.numfavoriteservers, sizeof(int), fileIn); + FS_Read(&size, sizeof(int), fileIn); + if (size == sizeof(cls.globalServers) + sizeof(cls.favoriteServers) + sizeof(cls_mplayerServers)) { + FS_Read(&cls.globalServers, sizeof(cls.globalServers), fileIn); + FS_Read(&cls_mplayerServers, sizeof(cls_mplayerServers), fileIn); + FS_Read(&cls.favoriteServers, sizeof(cls.favoriteServers), fileIn); + } else { + cls.numglobalservers = cls_nummplayerservers = cls.numfavoriteservers = 0; + cls.numGlobalServerAddresses = 0; + } + FS_FCloseFile(fileIn); + } +} + +/* +==================== +LAN_SaveServersToCache +==================== +*/ +void LAN_SaveServersToCache( ) { + int size; + fileHandle_t fileOut = FS_SV_FOpenFileWrite("servercache.dat"); + FS_Write(&cls.numglobalservers, sizeof(int), fileOut); + FS_Write(&cls_nummplayerservers, sizeof(int), fileOut); + FS_Write(&cls.numfavoriteservers, sizeof(int), fileOut); + size = sizeof(cls.globalServers) + sizeof(cls.favoriteServers) + sizeof(cls_mplayerServers); + FS_Write(&size, sizeof(int), fileOut); + FS_Write(&cls.globalServers, sizeof(cls.globalServers), fileOut); + FS_Write(&cls_mplayerServers, sizeof(cls_mplayerServers), fileOut); + FS_Write(&cls.favoriteServers, sizeof(cls.favoriteServers), fileOut); + FS_FCloseFile(fileOut); +} + +/* +==================== +LAN_ResetPings +==================== +*/ +void LAN_ResetPings(int source) { + int count,i; + serverInfo_t *servers = NULL; + count = 0; + + switch (source) { + case AS_LOCAL : + servers = &cls.localServers[0]; + count = MAX_OTHER_SERVERS; + break; + case AS_MPLAYER: + case AS_GLOBAL : + servers = &cls.globalServers[0]; + count = MAX_GLOBAL_SERVERS; + break; + case AS_FAVORITES : + servers = &cls.favoriteServers[0]; + count = MAX_OTHER_SERVERS; + break; + } + if (servers) { + for (i = 0; i < count; i++) { + servers[i].ping = -1; + } + } +} + +/* +==================== +LAN_AddServer +==================== +*/ +int LAN_AddServer(int source, const char *name, const char *address) { + int max, *count, i; + netadr_t adr; + serverInfo_t *servers = NULL; + max = MAX_OTHER_SERVERS; + count = NULL; + + switch (source) { + case AS_LOCAL : + count = &cls.numlocalservers; + servers = &cls.localServers[0]; + break; + case AS_MPLAYER: + case AS_GLOBAL : + max = MAX_GLOBAL_SERVERS; + count = &cls.numglobalservers; + servers = &cls.globalServers[0]; + break; + case AS_FAVORITES : + count = &cls.numfavoriteservers; + servers = &cls.favoriteServers[0]; + break; + } + if (servers && *count < max) { + NET_StringToAdr( address, &adr ); + for ( i = 0; i < *count; i++ ) { + if (NET_CompareAdr(servers[i].adr, adr)) { + break; + } + } + if (i >= *count) { + servers[*count].adr = adr; + Q_strncpyz(servers[*count].hostName, name, sizeof(servers[*count].hostName)); + servers[*count].visible = qtrue; + (*count)++; + return 1; + } + return 0; + } + return -1; +} + +int LAN_AddFavAddr( const char *address ) { + if ( cls.numfavoriteservers < MAX_OTHER_SERVERS ) { + netadr_t adr; + if ( !NET_StringToAdr( address, &adr ) ) { + return 2; + } + if ( adr.type == NA_BAD ) { + return 3; + } + + for ( int i = 0; i < cls.numfavoriteservers; i++ ) { + if ( NET_CompareAdr( cls.favoriteServers[i].adr, adr ) ) { + return 0; + } + } + cls.favoriteServers[cls.numfavoriteservers].adr = adr; + Q_strncpyz( cls.favoriteServers[cls.numfavoriteservers].hostName, address, + sizeof(cls.favoriteServers[cls.numfavoriteservers].hostName) ); + cls.favoriteServers[cls.numfavoriteservers].visible = qtrue; + cls.numfavoriteservers++; + return 1; + } + + return -1; +} + +/* +==================== +LAN_RemoveServer +==================== +*/ +void LAN_RemoveServer(int source, const char *addr) { + int *count, i; + serverInfo_t *servers = NULL; + count = NULL; + switch (source) { + case AS_LOCAL : + count = &cls.numlocalservers; + servers = &cls.localServers[0]; + break; + case AS_MPLAYER: + case AS_GLOBAL : + count = &cls.numglobalservers; + servers = &cls.globalServers[0]; + break; + case AS_FAVORITES : + count = &cls.numfavoriteservers; + servers = &cls.favoriteServers[0]; + break; + } + if (servers) { + netadr_t comp; + NET_StringToAdr( addr, &comp ); + for (i = 0; i < *count; i++) { + if (NET_CompareAdr( comp, servers[i].adr)) { + int j = i; + while (j < *count - 1) { + Com_Memcpy(&servers[j], &servers[j+1], sizeof(servers[j])); + j++; + } + (*count)--; + break; + } + } + } +} + + +/* +==================== +LAN_GetServerCount +==================== +*/ +int LAN_GetServerCount( int source ) { + switch (source) { + case AS_LOCAL : + return cls.numlocalservers; + break; + case AS_MPLAYER: + case AS_GLOBAL : + return cls.numglobalservers; + break; + case AS_FAVORITES : + return cls.numfavoriteservers; + break; + } + return 0; +} + +/* +==================== +LAN_GetLocalServerAddressString +==================== +*/ +void LAN_GetServerAddressString( int source, int n, char *buf, int buflen ) { + switch (source) { + case AS_LOCAL : + if (n >= 0 && n < MAX_OTHER_SERVERS) { + Q_strncpyz(buf, NET_AdrToString( cls.localServers[n].adr) , buflen ); + return; + } + break; + case AS_MPLAYER: + case AS_GLOBAL : + if (n >= 0 && n < MAX_GLOBAL_SERVERS) { + Q_strncpyz(buf, NET_AdrToString( cls.globalServers[n].adr) , buflen ); + return; + } + break; + case AS_FAVORITES : + if (n >= 0 && n < MAX_OTHER_SERVERS) { + Q_strncpyz(buf, NET_AdrToString( cls.favoriteServers[n].adr) , buflen ); + return; + } + break; + } + buf[0] = '\0'; +} + +/* +==================== +LAN_GetServerInfo +==================== +*/ +void LAN_GetServerInfo( int source, int n, char *buf, int buflen ) { + char info[MAX_STRING_CHARS]; + serverInfo_t *server = NULL; + info[0] = '\0'; + switch (source) { + case AS_LOCAL : + if (n >= 0 && n < MAX_OTHER_SERVERS) { + server = &cls.localServers[n]; + } + break; + case AS_MPLAYER: + case AS_GLOBAL : + if (n >= 0 && n < MAX_GLOBAL_SERVERS) { + server = &cls.globalServers[n]; + } + break; + case AS_FAVORITES : + if (n >= 0 && n < MAX_OTHER_SERVERS) { + server = &cls.favoriteServers[n]; + } + break; + } + if (server && buf) { + buf[0] = '\0'; + Info_SetValueForKey( info, "hostname", server->hostName); + Info_SetValueForKey( info, "mapname", server->mapName); + Info_SetValueForKey( info, "clients", va("%i",server->clients)); + Info_SetValueForKey( info, "sv_maxclients", va("%i",server->maxClients)); + Info_SetValueForKey( info, "ping", va("%i",server->ping)); + Info_SetValueForKey( info, "minping", va("%i",server->minPing)); + Info_SetValueForKey( info, "maxping", va("%i",server->maxPing)); + Info_SetValueForKey( info, "nettype", va("%i",server->netType)); + Info_SetValueForKey( info, "needpass", va("%i", server->needPassword ) ); + Info_SetValueForKey( info, "truejedi", va("%i", server->trueJedi ) ); + Info_SetValueForKey( info, "wdisable", va("%i", server->weaponDisable ) ); + Info_SetValueForKey( info, "fdisable", va("%i", server->forceDisable ) ); + Info_SetValueForKey( info, "game", server->game); + Info_SetValueForKey( info, "gametype", va("%i",server->gameType)); + Info_SetValueForKey( info, "addr", NET_AdrToString(server->adr)); + Info_SetValueForKey( info, "g_humanplayers", va( "%i", server->humans ) ); + Info_SetValueForKey( info, "bots", va( "%i", server->bots ) ); +// Info_SetValueForKey( info, "sv_allowAnonymous", va("%i", server->allowAnonymous)); +// Info_SetValueForKey( info, "pure", va("%i", server->pure ) ); + Q_strncpyz(buf, info, buflen); + } else { + if (buf) { + buf[0] = '\0'; + } + } +} + +/* +==================== +LAN_GetServerPing +==================== +*/ +int LAN_GetServerPing( int source, int n ) { + serverInfo_t *server = NULL; + switch (source) { + case AS_LOCAL : + if (n >= 0 && n < MAX_OTHER_SERVERS) { + server = &cls.localServers[n]; + } + break; + case AS_MPLAYER: + case AS_GLOBAL : + if (n >= 0 && n < MAX_GLOBAL_SERVERS) { + server = &cls.globalServers[n]; + } + break; + case AS_FAVORITES : + if (n >= 0 && n < MAX_OTHER_SERVERS) { + server = &cls.favoriteServers[n]; + } + break; + } + if (server) { + return server->ping; + } + return -1; +} + +/* +==================== +LAN_GetServerPtr +==================== +*/ +static serverInfo_t *LAN_GetServerPtr( int source, int n ) { + switch (source) { + case AS_LOCAL : + if (n >= 0 && n < MAX_OTHER_SERVERS) { + return &cls.localServers[n]; + } + break; + case AS_MPLAYER: + case AS_GLOBAL : + if (n >= 0 && n < MAX_GLOBAL_SERVERS) { + return &cls.globalServers[n]; + } + break; + case AS_FAVORITES : + if (n >= 0 && n < MAX_OTHER_SERVERS) { + return &cls.favoriteServers[n]; + } + break; + } + return NULL; +} + +/* +==================== +LAN_CompareServers +==================== +*/ +int LAN_CompareServers( int source, int sortKey, int sortDir, int s1, int s2 ) { + int res; + serverInfo_t *server1, *server2; + + server1 = LAN_GetServerPtr(source, s1); + server2 = LAN_GetServerPtr(source, s2); + if (!server1 || !server2) { + return 0; + } + + res = 0; + switch( sortKey ) { + case SORT_HOST: + res = Q_stricmp( server1->hostName, server2->hostName ); + break; + + case SORT_MAP: + res = Q_stricmp( server1->mapName, server2->mapName ); + break; + case SORT_CLIENTS: + if (server1->clients < server2->clients) { + res = -1; + } + else if (server1->clients > server2->clients) { + res = 1; + } + else { + res = 0; + } + break; + case SORT_GAME: + if (server1->gameType < server2->gameType) { + res = -1; + } + else if (server1->gameType > server2->gameType) { + res = 1; + } + else { + res = 0; + } + break; + case SORT_PING: + if (server1->ping < server2->ping) { + res = -1; + } + else if (server1->ping > server2->ping) { + res = 1; + } + else { + res = 0; + } + break; + } + + if (sortDir) { + if (res < 0) + return 1; + if (res > 0) + return -1; + return 0; + } + return res; +} + +/* +==================== +LAN_GetPingQueueCount +==================== +*/ +int LAN_GetPingQueueCount( void ) { + return (CL_GetPingQueueCount()); +} + +/* +==================== +LAN_ClearPing +==================== +*/ +void LAN_ClearPing( int n ) { + CL_ClearPing( n ); +} + +/* +==================== +LAN_GetPing +==================== +*/ +void LAN_GetPing( int n, char *buf, int buflen, int *pingtime ) { + CL_GetPing( n, buf, buflen, pingtime ); +} + +/* +==================== +LAN_GetPingInfo +==================== +*/ +void LAN_GetPingInfo( int n, char *buf, int buflen ) { + CL_GetPingInfo( n, buf, buflen ); +} + +/* +==================== +LAN_MarkServerVisible +==================== +*/ +void LAN_MarkServerVisible(int source, int n, qboolean visible ) { + if (n == -1) { + int count = MAX_OTHER_SERVERS; + serverInfo_t *server = NULL; + switch (source) { + case AS_LOCAL : + server = &cls.localServers[0]; + break; + case AS_MPLAYER: + case AS_GLOBAL : + server = &cls.globalServers[0]; + count = MAX_GLOBAL_SERVERS; + break; + case AS_FAVORITES : + server = &cls.favoriteServers[0]; + break; + } + if (server) { + for (n = 0; n < count; n++) { + server[n].visible = visible; + } + } + + } else { + switch (source) { + case AS_LOCAL : + if (n >= 0 && n < MAX_OTHER_SERVERS) { + cls.localServers[n].visible = visible; + } + break; + case AS_MPLAYER: + case AS_GLOBAL : + if (n >= 0 && n < MAX_GLOBAL_SERVERS) { + cls.globalServers[n].visible = visible; + } + break; + case AS_FAVORITES : + if (n >= 0 && n < MAX_OTHER_SERVERS) { + cls.favoriteServers[n].visible = visible; + } + break; + } + } +} + + +/* +======================= +LAN_ServerIsVisible +======================= +*/ +int LAN_ServerIsVisible(int source, int n ) { + switch (source) { + case AS_LOCAL : + if (n >= 0 && n < MAX_OTHER_SERVERS) { + return cls.localServers[n].visible; + } + break; + case AS_MPLAYER: + case AS_GLOBAL : + if (n >= 0 && n < MAX_GLOBAL_SERVERS) { + return cls.globalServers[n].visible; + } + break; + case AS_FAVORITES : + if (n >= 0 && n < MAX_OTHER_SERVERS) { + return cls.favoriteServers[n].visible; + } + break; + } + return qfalse; +} + +/* +======================= +LAN_UpdateVisiblePings +======================= +*/ +qboolean LAN_UpdateVisiblePings(int source ) { + return CL_UpdateVisiblePings_f(source); +} + +/* +==================== +LAN_GetServerStatus +==================== +*/ +int LAN_GetServerStatus( const char *serverAddress, char *serverStatus, int maxLen ) { + return CL_ServerStatus( serverAddress, serverStatus, maxLen ); +} diff --git a/Projects/Android/jni/OpenJK/codemp_delete/client/cl_lan.h b/Projects/Android/jni/OpenJK/codemp_delete/client/cl_lan.h new file mode 100644 index 0000000..3579e1b --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/client/cl_lan.h @@ -0,0 +1,44 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#pragma once + +void LAN_LoadCachedServers( ); +void LAN_SaveServersToCache( ); +void LAN_ResetPings(int source); +int LAN_AddServer(int source, const char *name, const char *address); +int LAN_AddFavAddr( const char *address ); +void LAN_RemoveServer(int source, const char *addr); +int LAN_GetServerCount( int source ); +void LAN_GetServerAddressString( int source, int n, char *buf, int buflen ); +void LAN_GetServerInfo( int source, int n, char *buf, int buflen ); +int LAN_GetServerPing( int source, int n ); +int LAN_CompareServers( int source, int sortKey, int sortDir, int s1, int s2 ); +int LAN_GetPingQueueCount( void ); +void LAN_ClearPing( int n ); +void LAN_GetPing( int n, char *buf, int buflen, int *pingtime ); +void LAN_GetPingInfo( int n, char *buf, int buflen ); +void LAN_MarkServerVisible(int source, int n, qboolean visible ); +int LAN_ServerIsVisible(int source, int n ); +qboolean LAN_UpdateVisiblePings(int source ); +int LAN_GetServerStatus( const char *serverAddress, char *serverStatus, int maxLen ); diff --git a/Projects/Android/jni/OpenJK/codemp/client/cl_main.cpp b/Projects/Android/jni/OpenJK/codemp_delete/client/cl_main.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/cl_main.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/client/cl_main.cpp diff --git a/Projects/Android/jni/OpenJK/codemp_delete/client/cl_net_chan.cpp b/Projects/Android/jni/OpenJK/codemp_delete/client/cl_net_chan.cpp new file mode 100644 index 0000000..d34317b --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/client/cl_net_chan.cpp @@ -0,0 +1,189 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#include "client.h" + +// TTimo: unused, commenting out to make gcc happy +#if 1 +/* +============== +CL_Netchan_Encode + + // first 12 bytes of the data are always: + long serverId; + long messageAcknowledge; + long reliableAcknowledge; + +============== +*/ +static void CL_Netchan_Encode( msg_t *msg ) { + int serverId, messageAcknowledge, reliableAcknowledge; + int i, index, srdc, sbit, soob; + byte key, *string; + + if ( msg->cursize <= CL_ENCODE_START ) { + return; + } + + srdc = msg->readcount; + sbit = msg->bit; + soob = msg->oob; + + msg->bit = 0; + msg->readcount = 0; + msg->oob = (qboolean)0; + + serverId = MSG_ReadLong(msg); + messageAcknowledge = MSG_ReadLong(msg); + reliableAcknowledge = MSG_ReadLong(msg); + + msg->oob = (qboolean)soob; + msg->bit = sbit; + msg->readcount = srdc; + + string = (byte *)clc.serverCommands[ reliableAcknowledge & (MAX_RELIABLE_COMMANDS-1) ]; + index = 0; + // + key = clc.challenge ^ serverId ^ messageAcknowledge; + for (i = CL_ENCODE_START; i < msg->cursize; i++) { + // modify the key with the last received now acknowledged server command + if (!string[index]) + index = 0; + if (/*string[index] > 127 || */ // eurofix: remove this so we can chat in european languages... -ste + string[index] == '%') + { + key ^= '.' << (i & 1); + } + else { + key ^= string[index] << (i & 1); + } + index++; + // encode the data with this key + *(msg->data + i) = (*(msg->data + i)) ^ key; + } +} + +/* +============== +CL_Netchan_Decode + + // first four bytes of the data are always: + long reliableAcknowledge; + +============== +*/ +static void CL_Netchan_Decode( msg_t *msg ) { + long reliableAcknowledge, i, index; + byte key, *string; + int srdc, sbit, soob; + + srdc = msg->readcount; + sbit = msg->bit; + soob = msg->oob; + + msg->oob = (qboolean)0; + + reliableAcknowledge = MSG_ReadLong(msg); + + msg->oob = (qboolean)soob; + msg->bit = sbit; + msg->readcount = srdc; + + string = (unsigned char *)clc.reliableCommands[ reliableAcknowledge & (MAX_RELIABLE_COMMANDS-1) ]; + index = 0; + // xor the client challenge with the netchan sequence number (need something that changes every message) + key = clc.challenge ^ LittleLong( *(unsigned *)msg->data ); + for (i = msg->readcount + CL_DECODE_START; i < msg->cursize; i++) { + // modify the key with the last sent and with this message acknowledged client command + if (!string[index]) + index = 0; + if (/*string[index] > 127 || */ // eurofix: remove this so we can chat in european languages... -ste + string[index] == '%') + { + key ^= '.' << (i & 1); + } + else { + key ^= string[index] << (i & 1); + } + index++; + // decode the data with this key + *(msg->data + i) = *(msg->data + i) ^ key; + } +} +#endif + +/* +================= +CL_Netchan_TransmitNextFragment +================= +*/ +void CL_Netchan_TransmitNextFragment( netchan_t *chan ) { + Netchan_TransmitNextFragment( chan ); +} + +//byte chksum[65536]; + +/* +=============== +CL_Netchan_Transmit +================ +*/ +void CL_Netchan_Transmit( netchan_t *chan, msg_t* msg ) { +// int i; + MSG_WriteByte( msg, clc_EOF ); +// for(i=CL_ENCODE_START;icursize;i++) { +// chksum[i-CL_ENCODE_START] = msg->data[i]; +// } + +// Huff_Compress( msg, CL_ENCODE_START ); + CL_Netchan_Encode( msg ); + Netchan_Transmit( chan, msg->cursize, msg->data ); +} + +extern int oldsize; +int newsize = 0; + +/* +================= +CL_Netchan_Process +================= +*/ +qboolean CL_Netchan_Process( netchan_t *chan, msg_t *msg ) { + int ret; +// int i; +// static int newsize = 0; + + ret = Netchan_Process( chan, msg ); + if (!ret) + return qfalse; + CL_Netchan_Decode( msg ); +// Huff_Decompress( msg, CL_DECODE_START ); +// for(i=CL_DECODE_START+msg->readcount;icursize;i++) { +// if (msg->data[i] != chksum[i-(CL_DECODE_START+msg->readcount)]) { +// Com_Error(ERR_DROP,"bad %d v %d\n", msg->data[i], chksum[i-(CL_DECODE_START+msg->readcount)]); +// } +// } + newsize += msg->cursize; +// Com_Printf("saved %d to %d (%d%%)\n", (oldsize>>3), newsize, 100-(newsize*100/(oldsize>>3))); + return qtrue; +} diff --git a/Projects/Android/jni/OpenJK/codemp/client/cl_parse.cpp b/Projects/Android/jni/OpenJK/codemp_delete/client/cl_parse.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/cl_parse.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/client/cl_parse.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/client/cl_scrn.cpp b/Projects/Android/jni/OpenJK/codemp_delete/client/cl_scrn.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/cl_scrn.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/client/cl_scrn.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/client/cl_ui.cpp b/Projects/Android/jni/OpenJK/codemp_delete/client/cl_ui.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/cl_ui.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/client/cl_ui.cpp diff --git a/Projects/Android/jni/OpenJK/codemp_delete/client/cl_uiapi.cpp b/Projects/Android/jni/OpenJK/codemp_delete/client/cl_uiapi.cpp new file mode 100644 index 0000000..29cf09b --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/client/cl_uiapi.cpp @@ -0,0 +1,1455 @@ +/* +=========================================================================== +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +// cl_uiapi.c -- client system interaction with client game +#include "qcommon/RoffSystem.h" +#include "qcommon/stringed_ingame.h" +#include "qcommon/timing.h" +#include "client.h" +#include "cl_lan.h" +#include "botlib/botlib.h" +#include "snd_ambient.h" +#include "FXExport.h" +#include "FxUtil.h" + +extern IHeapAllocator *G2VertSpaceClient; +extern botlib_export_t *botlib_export; + +// ui interface +static uiExport_t *uie; // ui export table +static vm_t *uivm; // ui vm, valid for legacy and new api + +// +// ui vmMain calls +// + +void UIVM_Init( qboolean inGameLoad ) { + if ( uivm->isLegacy ) { + VM_Call( uivm, UI_INIT, inGameLoad ); + return; + } + VMSwap v( uivm ); + + uie->Init( inGameLoad ); +} + +void UIVM_Shutdown( void ) { + if ( uivm->isLegacy ) { + VM_Call( uivm, UI_SHUTDOWN ); + VM_Call( uivm, UI_MENU_RESET ); + return; + } + VMSwap v( uivm ); + + uie->Shutdown(); + uie->MenuReset(); +} + +void UIVM_KeyEvent( int key, qboolean down ) { + if ( uivm->isLegacy ) { + VM_Call( uivm, UI_KEY_EVENT, key, down ); + return; + } + VMSwap v( uivm ); + + uie->KeyEvent( key, down ); +} + +void UIVM_MouseEvent( int dx, int dy ) { + if ( uivm->isLegacy ) { + VM_Call( uivm, UI_MOUSE_EVENT, dx, dy ); + return; + } + VMSwap v( uivm ); + + uie->MouseEvent( dx, dy ); +} + +void UIVM_Refresh( int realtime ) { + if ( uivm->isLegacy ) { + VM_Call( uivm, UI_REFRESH, realtime ); + return; + } + VMSwap v( uivm ); + + uie->Refresh( realtime ); +} + +qboolean UIVM_IsFullscreen( void ) { + if ( uivm->isLegacy ) { + return (qboolean)VM_Call( uivm, UI_IS_FULLSCREEN ); + } + VMSwap v( uivm ); + + return uie->IsFullscreen(); +} + +void UIVM_SetActiveMenu( uiMenuCommand_t menu ) { + if ( uivm->isLegacy ) { + VM_Call( uivm, UI_SET_ACTIVE_MENU, menu ); + return; + } + VMSwap v( uivm ); + + uie->SetActiveMenu( menu ); +} + +qboolean UIVM_ConsoleCommand( int realTime ) { + if ( uivm->isLegacy ) { + return (qboolean)VM_Call( uivm, UI_CONSOLE_COMMAND, realTime ); + } + VMSwap v( uivm ); + + return uie->ConsoleCommand( realTime ); +} +void UIVM_DrawConnectScreen( qboolean overlay ) { + if ( uivm->isLegacy ) { + VM_Call( uivm, UI_DRAW_CONNECT_SCREEN, overlay ); + return; + } + VMSwap v( uivm ); + + uie->DrawConnectScreen( overlay ); +} + +// +// ui syscalls +// only used by legacy mods! +// + +// wrappers and such + +static int CL_Milliseconds( void ) { + return Sys_Milliseconds(); +} + +static void CL_Cvar_Get( const char *var_name, const char *value, uint32_t flags ) { + Cvar_Register( NULL, var_name, value, flags ); +} + +static void CL_GetClientState( uiClientState_t *state ) { + state->connectPacketCount = clc.connectPacketCount; + state->connState = cls.state; + Q_strncpyz( state->servername, cls.servername, sizeof( state->servername ) ); + Q_strncpyz( state->updateInfoString, cls.updateInfoString, sizeof( state->updateInfoString ) ); + Q_strncpyz( state->messageString, clc.serverMessage, sizeof( state->messageString ) ); + state->clientNum = cl.snap.ps.clientNum; +} + +static void CL_GetGlconfig( glconfig_t *config ) { + *config = cls.glconfig; +} + +static void GetClipboardData( char *buf, int buflen ) { + char *cbd, *c; + + c = cbd = Sys_GetClipboardData(); + if ( !cbd ) { + *buf = 0; + return; + } + + for ( int i = 0, end = buflen - 1; *c && i < end; i++ ) + { + uint32_t utf32 = ConvertUTF8ToUTF32( c, &c ); + buf[i] = ConvertUTF32ToExpectedCharset( utf32 ); + } + + Z_Free( cbd ); +} + +static int GetConfigString(int index, char *buf, int size) +{ + int offset; + + if (index < 0 || index >= MAX_CONFIGSTRINGS) + return qfalse; + + offset = cl.gameState.stringOffsets[index]; + if (!offset) { + if( size ) { + buf[0] = 0; + } + return qfalse; + } + + Q_strncpyz( buf, cl.gameState.stringData+offset, size); + + return qtrue; +} + +static void Key_GetBindingBuf( int keynum, char *buf, int buflen ) { + char *value; + + value = Key_GetBinding( keynum ); + if ( value ) { + Q_strncpyz( buf, value, buflen ); + } + else { + *buf = 0; + } +} + +static void Key_KeynumToStringBuf( int keynum, char *buf, int buflen ) +{ + const char *psKeyName = Key_KeynumToString( keynum/*, qtrue */); + + // see if there's a more friendly (or localised) name... + // + const char *psKeyNameFriendly = SE_GetString( va("KEYNAMES_KEYNAME_%s",psKeyName) ); + + Q_strncpyz( buf, (psKeyNameFriendly && psKeyNameFriendly[0]) ? psKeyNameFriendly : psKeyName, buflen ); +} + +static void CL_SE_GetLanguageName( const int languageIndex, char *buffer ) { + Q_strncpyz( buffer, SE_GetLanguageName( languageIndex ), 128 ); +} + +static qboolean CL_SE_GetStringTextString( const char *text, char *buffer, int bufferLength ) { + assert( text && buffer ); + Q_strncpyz( buffer, SE_GetString( text ), bufferLength ); + return qtrue; +} + +static void CL_R_ShaderNameFromIndex( char *name, int index ) { + const char *retMem = re->ShaderNameFromIndex( index ); + if ( retMem ) + strcpy( name, retMem ); + else + name[0] = '\0'; +} + +static void CL_G2API_ListModelSurfaces( void *ghlInfo ) { + if ( !ghlInfo ) { + return; + } + + re->G2API_ListSurfaces( (CGhoul2Info *)ghlInfo ); +} + +static void CL_G2API_ListModelBones( void *ghlInfo, int frame ) { + if ( !ghlInfo ) { + return; + } + + re->G2API_ListBones( (CGhoul2Info *)ghlInfo, frame ); +} + +static void CL_G2API_SetGhoul2ModelIndexes( void *ghoul2, qhandle_t *modelList, qhandle_t *skinList ) { + if ( !ghoul2 ) { + return; + } + + re->G2API_SetGhoul2ModelIndexes( *((CGhoul2Info_v *)ghoul2), modelList, skinList ); +} + +static qboolean CL_G2API_HaveWeGhoul2Models( void *ghoul2) { + if ( !ghoul2 ) { + return qfalse; + } + + return re->G2API_HaveWeGhoul2Models( *((CGhoul2Info_v *)ghoul2) ); +} + +static qboolean CL_G2API_GetBoltMatrix( void *ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale ) { + if ( !ghoul2 ) { + return qfalse; + + } + return re->G2API_GetBoltMatrix( *((CGhoul2Info_v *)ghoul2), modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale ); +} + +static qboolean CL_G2API_GetBoltMatrix_NoReconstruct( void *ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale ) { + if ( !ghoul2 ) { + return qfalse; + } + + re->G2API_BoltMatrixReconstruction( qfalse ); + return re->G2API_GetBoltMatrix( *((CGhoul2Info_v *)ghoul2), modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale ); +} + +static qboolean CL_G2API_GetBoltMatrix_NoRecNoRot( void *ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale ) { + if ( !ghoul2 ) { + return qfalse; + } + + re->G2API_BoltMatrixReconstruction( qfalse ); + re->G2API_BoltMatrixSPMethod( qtrue ); + return re->G2API_GetBoltMatrix( *((CGhoul2Info_v *)ghoul2), modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale ); +} + +static int CL_G2API_InitGhoul2Model( void **ghoul2Ptr, const char *fileName, int modelIndex, qhandle_t customSkin, qhandle_t customShader, int modelFlags, int lodBias ) { + if ( !ghoul2Ptr ) { + return 0; + } + +#ifdef _FULL_G2_LEAK_CHECKING + g_G2AllocServer = 0; +#endif + return re->G2API_InitGhoul2Model( (CGhoul2Info_v **)ghoul2Ptr, fileName, modelIndex, customSkin, customShader, modelFlags, lodBias ); +} + +static qboolean CL_G2API_SetSkin( void *ghoul2, int modelIndex, qhandle_t customSkin, qhandle_t renderSkin ) { + if ( !ghoul2 ) { + return qfalse; + } + + CGhoul2Info_v &g2 = *((CGhoul2Info_v *)ghoul2); + return re->G2API_SetSkin( g2, modelIndex, customSkin, renderSkin ); +} + +static void CL_G2API_CollisionDetect( + CollisionRecord_t *collRecMap, + void* ghoul2, + const vec3_t angles, + const vec3_t position, + int frameNumber, + int entNum, + vec3_t rayStart, + vec3_t rayEnd, + vec3_t scale, + int traceFlags, + int useLod, + float fRadius ) +{ + if ( !ghoul2 ) { + return; + } + + re->G2API_CollisionDetect( + collRecMap, + *((CGhoul2Info_v *)ghoul2), + angles, + position, + frameNumber, + entNum, + rayStart, + rayEnd, + scale, + G2VertSpaceClient, + traceFlags, + useLod, + fRadius); +} + +static void CL_G2API_CollisionDetectCache( + CollisionRecord_t *collRecMap, + void* ghoul2, + const vec3_t angles, + const vec3_t position, + int frameNumber, + int entNum, + vec3_t rayStart, + vec3_t rayEnd, + vec3_t scale, + int traceFlags, + int useLod, + float fRadius) +{ + if ( !ghoul2 ) { + return; + } + + re->G2API_CollisionDetectCache( + collRecMap, + *((CGhoul2Info_v *)ghoul2), + angles, + position, + frameNumber, + entNum, + rayStart, + rayEnd, + scale, + G2VertSpaceClient, + traceFlags, + useLod, + fRadius); +} + +static void CL_G2API_CleanGhoul2Models( void **ghoul2Ptr ) { + if ( !ghoul2Ptr ) { + return; + } + +#ifdef _FULL_G2_LEAK_CHECKING + g_G2AllocServer = 0; +#endif + re->G2API_CleanGhoul2Models( (CGhoul2Info_v **)ghoul2Ptr ); +} + +static qboolean CL_G2API_SetBoneAngles( + void *ghoul2, + int modelIndex, + const char *boneName, + const vec3_t angles, + const int flags, + const int up, + const int right, + const int forward, + qhandle_t *modelList, + int blendTime , + int currentTime) +{ + if ( !ghoul2 ) { + return qfalse; + } + + return re->G2API_SetBoneAngles( + *((CGhoul2Info_v *)ghoul2), + modelIndex, + boneName, + angles, + flags, + (const Eorientations)up, + (const Eorientations)right, + (const Eorientations)forward, + modelList, + blendTime, + currentTime); +} + +static qboolean CL_G2API_SetBoneAnim( + void *ghoul2, + const int modelIndex, + const char *boneName, + const int startFrame, + const int endFrame, + const int flags, + const float animSpeed, + const int currentTime, + const float setFrame, + const int blendTime) +{ + if ( !ghoul2 ) { + return qfalse; + } + + return re->G2API_SetBoneAnim( + *((CGhoul2Info_v *)ghoul2), + modelIndex, + boneName, + startFrame, + endFrame, + flags, + animSpeed, + currentTime, + setFrame, + blendTime); +} + +static qboolean CL_G2API_GetBoneAnim( + void *ghoul2, + const char *boneName, + const int currentTime, + float *currentFrame, + int *startFrame, + int *endFrame, + int *flags, + float *animSpeed, + int *modelList, + const int modelIndex) +{ + if ( !ghoul2 ) { + return qfalse; + } + + CGhoul2Info_v &g2 = *((CGhoul2Info_v *)ghoul2); + return re->G2API_GetBoneAnim( + g2, + modelIndex, + boneName, + currentTime, + currentFrame, + startFrame, + endFrame, + flags, + animSpeed, + modelList); +} + +static qboolean CL_G2API_GetBoneFrame( + void *ghoul2, + const char *boneName, + const int currentTime, + float *currentFrame, + int *modelList, + const int modelIndex) +{ + if ( !ghoul2 ) { + return qfalse; + } + + CGhoul2Info_v &g2 = *((CGhoul2Info_v *)ghoul2); + int iDontCare1 = 0, iDontCare2 = 0, iDontCare3 = 0; + float fDontCare1 = 0; + + return re->G2API_GetBoneAnim( + g2, + modelIndex, + boneName, + currentTime, + currentFrame, + &iDontCare1, + &iDontCare2, + &iDontCare3, + &fDontCare1, + modelList); +} + +static void CL_G2API_GetGLAName( void *ghoul2, int modelIndex, char *fillBuf ) { + if ( !ghoul2 ) + { + fillBuf[0] = '\0'; + return; + } + + char *tmp = re->G2API_GetGLAName( *((CGhoul2Info_v *)ghoul2), modelIndex ); + if ( tmp ) + strcpy( fillBuf, tmp ); + else + fillBuf[0] = '\0'; +} + +static int CL_G2API_CopyGhoul2Instance( void *g2From, void *g2To, int modelIndex ) { + if ( !g2From || !g2To ) { + return 0; + } + + return re->G2API_CopyGhoul2Instance( *((CGhoul2Info_v *)g2From), *((CGhoul2Info_v *)g2To), modelIndex ); +} + +static void CL_G2API_CopySpecificGhoul2Model( void *g2From, int modelFrom, void *g2To, int modelTo ) { + if ( !g2From || !g2To ) { + return; + } + + re->G2API_CopySpecificG2Model( *((CGhoul2Info_v *)g2From), modelFrom, *((CGhoul2Info_v *)g2To), modelTo ); +} + +static void CL_G2API_DuplicateGhoul2Instance( void *g2From, void **g2To ) { + if ( !g2From || !g2To ) { + return; + } + +#ifdef _FULL_G2_LEAK_CHECKING + g_G2AllocServer = 0; +#endif + re->G2API_DuplicateGhoul2Instance( *((CGhoul2Info_v *)g2From), (CGhoul2Info_v **)g2To ); +} + +static qboolean CL_G2API_HasGhoul2ModelOnIndex( void *ghlInfo, int modelIndex ) { + if ( !ghlInfo ) { + return qfalse; + } + + return re->G2API_HasGhoul2ModelOnIndex( (CGhoul2Info_v **)ghlInfo, modelIndex ); +} + +static qboolean CL_G2API_RemoveGhoul2Model( void *ghlInfo, int modelIndex ) { + if ( !ghlInfo ) { + return qfalse; + } + +#ifdef _FULL_G2_LEAK_CHECKING + g_G2AllocServer = 0; +#endif + return re->G2API_RemoveGhoul2Model( (CGhoul2Info_v **)ghlInfo, modelIndex ); +} + +static int CL_G2API_AddBolt( void *ghoul2, int modelIndex, const char *boneName ) { + if ( !ghoul2 ) { + return -1; + } + + return re->G2API_AddBolt( *((CGhoul2Info_v *)ghoul2), modelIndex, boneName ); +} + +static void CL_G2API_SetBoltInfo( void *ghoul2, int modelIndex, int boltInfo ) { + if ( !ghoul2 ) { + return; + } + + re->G2API_SetBoltInfo( *((CGhoul2Info_v *)ghoul2), modelIndex, boltInfo ); +} + +static qboolean CL_G2API_SetRootSurface( void *ghoul2, const int modelIndex, const char *surfaceName ) { + if ( !ghoul2 ) { + return qfalse; + } + + return re->G2API_SetRootSurface( *((CGhoul2Info_v *)ghoul2), modelIndex, surfaceName ); +} + +static qboolean CL_G2API_SetSurfaceOnOff( void *ghoul2, const char *surfaceName, const int flags ) { + if ( !ghoul2 ) { + return qfalse; + } + + return re->G2API_SetSurfaceOnOff( *((CGhoul2Info_v *)ghoul2), surfaceName, flags ); +} + +static qboolean CL_G2API_SetNewOrigin( void *ghoul2, const int boltIndex ) { + if ( !ghoul2 ) { + return qfalse; + } + + return re->G2API_SetNewOrigin( *((CGhoul2Info_v *)ghoul2), boltIndex ); +} + +static int CL_G2API_GetTime( void ) { + return re->G2API_GetTime( 0 ); +} + +static void CL_G2API_SetTime( int time, int clock ) { + re->G2API_SetTime( time, clock ); +} + +static void CL_G2API_SetRagDoll( void *ghoul2, sharedRagDollParams_t *params ) { + if ( !ghoul2 ) { + return; + } + + CRagDollParams rdParams; + + if ( !params ) { + re->G2API_ResetRagDoll( *((CGhoul2Info_v *)ghoul2) ); + return; + } + + VectorCopy( params->angles, rdParams.angles ); + VectorCopy( params->position, rdParams.position ); + VectorCopy( params->scale, rdParams.scale ); + VectorCopy( params->pelvisAnglesOffset, rdParams.pelvisAnglesOffset ); + VectorCopy( params->pelvisPositionOffset, rdParams.pelvisPositionOffset ); + + rdParams.fImpactStrength = params->fImpactStrength; + rdParams.fShotStrength = params->fShotStrength; + rdParams.me = params->me; + + rdParams.startFrame = params->startFrame; + rdParams.endFrame = params->endFrame; + + rdParams.collisionType = params->collisionType; + rdParams.CallRagDollBegin = params->CallRagDollBegin; + + rdParams.RagPhase = (CRagDollParams::ERagPhase)params->RagPhase; + rdParams.effectorsToTurnOff = (CRagDollParams::ERagEffector)params->effectorsToTurnOff; + + re->G2API_SetRagDoll( *((CGhoul2Info_v *)ghoul2), &rdParams ); +} + +static void CL_G2API_AnimateG2Models( void *ghoul2, int time, sharedRagDollUpdateParams_t *params ) { + if ( !ghoul2 ) { + return; + } + + CRagDollUpdateParams rduParams; + + if ( !params ) + return; + + VectorCopy( params->angles, rduParams.angles ); + VectorCopy( params->position, rduParams.position ); + VectorCopy( params->scale, rduParams.scale ); + VectorCopy( params->velocity, rduParams.velocity ); + + rduParams.me = params->me; + rduParams.settleFrame = params->settleFrame; + + re->G2API_AnimateG2ModelsRag( *((CGhoul2Info_v *)ghoul2), time, &rduParams ); +} + +static qboolean CL_G2API_SetBoneIKState( void *ghoul2, int time, const char *boneName, int ikState, sharedSetBoneIKStateParams_t *params ) { + if ( !ghoul2 ) { + return qfalse; + } + + return re->G2API_SetBoneIKState( *((CGhoul2Info_v *)ghoul2), time, boneName, ikState, params ); +} + +static qboolean CL_G2API_IKMove( void *ghoul2, int time, sharedIKMoveParams_t *params ) { + if ( !ghoul2 ) { + return qfalse; + } + + return re->G2API_IKMove( *((CGhoul2Info_v *)ghoul2), time, params ); +} + +static void CL_G2API_GetSurfaceName( void *ghoul2, int surfNumber, int modelIndex, char *fillBuf ) { + if ( !ghoul2 ) { + return; + } + + CGhoul2Info_v &g2 = *((CGhoul2Info_v *)ghoul2); + char *tmp = re->G2API_GetSurfaceName( g2, modelIndex, surfNumber ); + strcpy( fillBuf, tmp ); +} + +static qboolean CL_G2API_AttachG2Model( void *ghoul2From, int modelIndexFrom, void *ghoul2To, int toBoltIndex, int toModel ) { + if ( !ghoul2From || !ghoul2To ) { + return qfalse; + } + + CGhoul2Info_v *g2From = ((CGhoul2Info_v *)ghoul2From); + CGhoul2Info_v *g2To = ((CGhoul2Info_v *)ghoul2To); + + return re->G2API_AttachG2Model(*g2From, modelIndexFrom, *g2To, toBoltIndex, toModel); +} + +static void CL_Key_SetCatcher( int catcher ) { + // Don't allow the ui module to close the console + Key_SetCatcher( catcher | ( Key_GetCatcher( ) & KEYCATCH_CONSOLE ) ); +} + +static void UIVM_Cvar_Set( const char *var_name, const char *value ) { + Cvar_VM_Set( var_name, value, VM_UI ); +} + +static void UIVM_Cvar_SetValue( const char *var_name, float value ) { + Cvar_VM_SetValue( var_name, value, VM_UI ); +} + +static void CL_AddUICommand( const char *cmdName ) { + Cmd_AddCommand( cmdName, NULL ); +} + +static void UIVM_Cmd_RemoveCommand( const char *cmd_name ) { + Cmd_VM_RemoveCommand( cmd_name, VM_UI ); +} + +// legacy syscall + +intptr_t CL_UISystemCalls( intptr_t *args ) { + switch ( args[0] ) { + //rww - alright, DO NOT EVER add a GAME/CGAME/UI generic call without adding a trap to match, and + //all of these traps must be shared and have cases in sv_game, cl_cgame, and cl_ui. They must also + //all be in the same order, and start at 100. + case TRAP_MEMSET: + Com_Memset( VMA(1), args[2], args[3] ); + return 0; + + case TRAP_MEMCPY: + Com_Memcpy( VMA(1), VMA(2), args[3] ); + return 0; + + case TRAP_STRNCPY: + strncpy( (char *)VMA(1), (const char *)VMA(2), args[3] ); + return args[1]; + + case TRAP_SIN: + return FloatAsInt( sin( VMF(1) ) ); + + case TRAP_COS: + return FloatAsInt( cos( VMF(1) ) ); + + case TRAP_ATAN2: + return FloatAsInt( atan2( VMF(1), VMF(2) ) ); + + case TRAP_SQRT: + return FloatAsInt( sqrt( VMF(1) ) ); + + case TRAP_MATRIXMULTIPLY: + MatrixMultiply( (vec3_t *)VMA(1), (vec3_t *)VMA(2), (vec3_t *)VMA(3) ); + return 0; + + case TRAP_ANGLEVECTORS: + AngleVectors( (const float *)VMA(1), (float *)VMA(2), (float *)VMA(3), (float *)VMA(4) ); + return 0; + + case TRAP_PERPENDICULARVECTOR: + PerpendicularVector( (float *)VMA(1), (const float *)VMA(2) ); + return 0; + + case TRAP_FLOOR: + return FloatAsInt( floor( VMF(1) ) ); + + case TRAP_CEIL: + return FloatAsInt( ceil( VMF(1) ) ); + + case TRAP_TESTPRINTINT: + return 0; + + case TRAP_TESTPRINTFLOAT: + return 0; + + case TRAP_ACOS: + return FloatAsInt( Q_acos( VMF(1) ) ); + + case TRAP_ASIN: + return FloatAsInt( Q_asin( VMF(1) ) ); + + case UI_ERROR: + Com_Error( ERR_DROP, "%s", VMA(1) ); + return 0; + + case UI_PRINT: + Com_Printf( "%s", VMA(1) ); + return 0; + + case UI_MILLISECONDS: + return Sys_Milliseconds(); + + case UI_CVAR_REGISTER: + Cvar_Register( (vmCvar_t *)VMA(1), (const char *)VMA(2), (const char *)VMA(3), args[4] ); + return 0; + + case UI_CVAR_UPDATE: + Cvar_Update( (vmCvar_t *)VMA(1) ); + return 0; + + case UI_CVAR_SET: + Cvar_VM_Set( (const char *)VMA(1), (const char *)VMA(2), VM_UI ); + return 0; + + case UI_CVAR_VARIABLEVALUE: + return FloatAsInt( Cvar_VariableValue( (const char *)VMA(1) ) ); + + case UI_CVAR_VARIABLESTRINGBUFFER: + Cvar_VariableStringBuffer( (const char *)VMA(1), (char *)VMA(2), args[3] ); + return 0; + + case UI_CVAR_SETVALUE: + Cvar_VM_SetValue( (const char *)VMA(1), VMF(2), VM_UI ); + return 0; + + case UI_CVAR_RESET: + Cvar_Reset( (const char *)VMA(1) ); + return 0; + + case UI_CVAR_CREATE: + Cvar_Get( (const char *)VMA(1), (const char *)VMA(2), args[3] ); + return 0; + + case UI_CVAR_INFOSTRINGBUFFER: + Cvar_InfoStringBuffer( args[1], (char *)VMA(2), args[3] ); + return 0; + + case UI_ARGC: + return Cmd_Argc(); + + case UI_ARGV: + Cmd_ArgvBuffer( args[1], (char *)VMA(2), args[3] ); + return 0; + + case UI_CMD_EXECUTETEXT: + Cbuf_ExecuteText( args[1], (const char *)VMA(2) ); + return 0; + + case UI_FS_FOPENFILE: + return FS_FOpenFileByMode( (const char *)VMA(1), (int *)VMA(2), (fsMode_t)args[3] ); + + case UI_FS_READ: + FS_Read( VMA(1), args[2], args[3] ); + return 0; + + case UI_FS_WRITE: + FS_Write( VMA(1), args[2], args[3] ); + return 0; + + case UI_FS_FCLOSEFILE: + FS_FCloseFile( args[1] ); + return 0; + + case UI_FS_GETFILELIST: + return FS_GetFileList( (const char *)VMA(1), (const char *)VMA(2), (char *)VMA(3), args[4] ); + + case UI_R_REGISTERMODEL: + return re->RegisterModel( (const char *)VMA(1) ); + + case UI_R_REGISTERSKIN: + return re->RegisterSkin( (const char *)VMA(1) ); + + case UI_R_REGISTERSHADERNOMIP: + return re->RegisterShaderNoMip( (const char *)VMA(1) ); + + case UI_R_SHADERNAMEFROMINDEX: + CL_R_ShaderNameFromIndex( (char *)VMA(1), args[2] ); + return 0; + + case UI_R_CLEARSCENE: + re->ClearScene(); + return 0; + + case UI_R_ADDREFENTITYTOSCENE: + re->AddRefEntityToScene( (const refEntity_t *)VMA(1) ); + return 0; + + case UI_R_ADDPOLYTOSCENE: + re->AddPolyToScene( args[1], args[2], (const polyVert_t *)VMA(3), 1 ); + return 0; + + case UI_R_ADDLIGHTTOSCENE: + re->AddLightToScene( (const float *)VMA(1), VMF(2), VMF(3), VMF(4), VMF(5) ); + return 0; + + case UI_R_RENDERSCENE: + re->RenderScene( (const refdef_t *)VMA(1) ); + return 0; + + case UI_R_SETCOLOR: + re->SetColor( (const float *)VMA(1) ); + return 0; + + case UI_R_DRAWSTRETCHPIC: + re->DrawStretchPic( VMF(1), VMF(2), VMF(3), VMF(4), VMF(5), VMF(6), VMF(7), VMF(8), args[9] ); + return 0; + + case UI_R_MODELBOUNDS: + re->ModelBounds( args[1], (float *)VMA(2), (float *)VMA(3) ); + return 0; + + case UI_UPDATESCREEN: + SCR_UpdateScreen(); + return 0; + + case UI_CM_LERPTAG: + re->LerpTag( (orientation_t *)VMA(1), args[2], args[3], args[4], VMF(5), (const char *)VMA(6) ); + return 0; + + case UI_S_REGISTERSOUND: + return S_RegisterSound( (const char *)VMA(1) ); + + case UI_S_STARTLOCALSOUND: + S_StartLocalSound( args[1], args[2] ); + return 0; + + case UI_KEY_KEYNUMTOSTRINGBUF: + Key_KeynumToStringBuf( args[1], (char *)VMA(2), args[3] ); + return 0; + + case UI_KEY_GETBINDINGBUF: + Key_GetBindingBuf( args[1], (char *)VMA(2), args[3] ); + return 0; + + case UI_KEY_SETBINDING: + Key_SetBinding( args[1], (const char *)VMA(2) ); + return 0; + + case UI_KEY_ISDOWN: + return Key_IsDown( args[1] ); + + case UI_KEY_GETOVERSTRIKEMODE: + return Key_GetOverstrikeMode(); + + case UI_KEY_SETOVERSTRIKEMODE: + Key_SetOverstrikeMode( (qboolean)args[1] ); + return 0; + + case UI_KEY_CLEARSTATES: + Key_ClearStates(); + return 0; + + case UI_KEY_GETCATCHER: + return Key_GetCatcher(); + + case UI_KEY_SETCATCHER: + CL_Key_SetCatcher( args[1] ); + return 0; + + case UI_GETCLIPBOARDDATA: + GetClipboardData( (char *)VMA(1), args[2] ); + return 0; + + case UI_GETCLIENTSTATE: + CL_GetClientState( (uiClientState_t *)VMA(1) ); + return 0; + + case UI_GETGLCONFIG: + CL_GetGlconfig( (glconfig_t *)VMA(1) ); + return 0; + + case UI_GETCONFIGSTRING: + return GetConfigString( args[1], (char *)VMA(2), args[3] ); + + case UI_LAN_LOADCACHEDSERVERS: + LAN_LoadCachedServers(); + return 0; + + case UI_LAN_SAVECACHEDSERVERS: + LAN_SaveServersToCache(); + return 0; + + case UI_LAN_ADDSERVER: + return LAN_AddServer(args[1], (const char *)VMA(2), (const char *)VMA(3)); + + case UI_LAN_REMOVESERVER: + LAN_RemoveServer(args[1], (const char *)VMA(2)); + return 0; + + case UI_LAN_GETPINGQUEUECOUNT: + return LAN_GetPingQueueCount(); + + case UI_LAN_CLEARPING: + LAN_ClearPing( args[1] ); + return 0; + + case UI_LAN_GETPING: + LAN_GetPing( args[1], (char *)VMA(2), args[3], (int *)VMA(4) ); + return 0; + + case UI_LAN_GETPINGINFO: + LAN_GetPingInfo( args[1], (char *)VMA(2), args[3] ); + return 0; + + case UI_LAN_GETSERVERCOUNT: + return LAN_GetServerCount(args[1]); + + case UI_LAN_GETSERVERADDRESSSTRING: + LAN_GetServerAddressString( args[1], args[2], (char *)VMA(3), args[4] ); + return 0; + + case UI_LAN_GETSERVERINFO: + LAN_GetServerInfo( args[1], args[2], (char *)VMA(3), args[4] ); + return 0; + + case UI_LAN_GETSERVERPING: + return LAN_GetServerPing( args[1], args[2] ); + + case UI_LAN_MARKSERVERVISIBLE: + LAN_MarkServerVisible( args[1], args[2], (qboolean)args[3] ); + return 0; + + case UI_LAN_SERVERISVISIBLE: + return LAN_ServerIsVisible( args[1], args[2] ); + + case UI_LAN_UPDATEVISIBLEPINGS: + return LAN_UpdateVisiblePings( args[1] ); + + case UI_LAN_RESETPINGS: + LAN_ResetPings( args[1] ); + return 0; + + case UI_LAN_SERVERSTATUS: + return LAN_GetServerStatus( (char *)VMA(1), (char *)VMA(2), args[3] ); + + case UI_LAN_COMPARESERVERS: + return LAN_CompareServers( args[1], args[2], args[3], args[4], args[5] ); + + case UI_MEMORY_REMAINING: + return Hunk_MemoryRemaining(); + + case UI_R_REGISTERFONT: + return re->RegisterFont( (const char *)VMA(1) ); + + case UI_R_FONT_STRLENPIXELS: + return re->Font_StrLenPixels( (const char *)VMA(1), args[2], VMF(3) ); + + case UI_R_FONT_STRLENCHARS: + return re->Font_StrLenChars( (const char *)VMA(1) ); + + case UI_R_FONT_STRHEIGHTPIXELS: + return re->Font_HeightPixels( args[1], VMF(2) ); + + case UI_R_FONT_DRAWSTRING: + re->Font_DrawString( args[1], args[2], (const char *)VMA(3), (const float *) VMA(4), args[5], args[6], VMF(7) ); + return 0; + + case UI_LANGUAGE_ISASIAN: + return re->Language_IsAsian(); + + case UI_LANGUAGE_USESSPACES: + return re->Language_UsesSpaces(); + + case UI_ANYLANGUAGE_READCHARFROMSTRING: + return re->AnyLanguage_ReadCharFromString( (const char *)VMA(1), (int *) VMA(2), (qboolean *) VMA(3) ); + + case UI_PC_ADD_GLOBAL_DEFINE: + return botlib_export->PC_AddGlobalDefine( (char *)VMA(1) ); + + case UI_PC_LOAD_SOURCE: + return botlib_export->PC_LoadSourceHandle( (const char *)VMA(1) ); + + case UI_PC_FREE_SOURCE: + return botlib_export->PC_FreeSourceHandle( args[1] ); + + case UI_PC_READ_TOKEN: + return botlib_export->PC_ReadTokenHandle( args[1], (struct pc_token_s *)VMA(2) ); + + case UI_PC_SOURCE_FILE_AND_LINE: + return botlib_export->PC_SourceFileAndLine( args[1], (char *)VMA(2), (int *)VMA(3) ); + + case UI_PC_LOAD_GLOBAL_DEFINES: + return botlib_export->PC_LoadGlobalDefines ( (char *)VMA(1) ); + + case UI_PC_REMOVE_ALL_GLOBAL_DEFINES: + botlib_export->PC_RemoveAllGlobalDefines ( ); + return 0; + + case UI_S_STOPBACKGROUNDTRACK: + S_StopBackgroundTrack(); + return 0; + + case UI_S_STARTBACKGROUNDTRACK: + S_StartBackgroundTrack( (const char *)VMA(1), (const char *)VMA(2), qfalse ); + return 0; + + case UI_REAL_TIME: + return Com_RealTime( (struct qtime_s *)VMA(1) ); + + case UI_CIN_PLAYCINEMATIC: + Com_DPrintf("UI_CIN_PlayCinematic\n"); + return CIN_PlayCinematic((const char *)VMA(1), args[2], args[3], args[4], args[5], args[6]); + + case UI_CIN_STOPCINEMATIC: + return CIN_StopCinematic(args[1]); + + case UI_CIN_RUNCINEMATIC: + return CIN_RunCinematic(args[1]); + + case UI_CIN_DRAWCINEMATIC: + CIN_DrawCinematic(args[1]); + return 0; + + case UI_CIN_SETEXTENTS: + CIN_SetExtents(args[1], args[2], args[3], args[4], args[5]); + return 0; + + case UI_R_REMAP_SHADER: + re->RemapShader( (const char *)VMA(1), (const char *)VMA(2), (const char *)VMA(3) ); + return 0; + + case UI_SP_GETNUMLANGUAGES: + return SE_GetNumLanguages(); + + case UI_SP_GETLANGUAGENAME: + CL_SE_GetLanguageName( args[1], (char *)VMA(2) ); + return 0; + + case UI_SP_GETSTRINGTEXTSTRING: + return CL_SE_GetStringTextString( (const char *)VMA(1), (char *)VMA(2), args[3] ); + + case UI_G2_LISTSURFACES: + CL_G2API_ListModelSurfaces( VMA(1) ); + return 0; + + case UI_G2_LISTBONES: + CL_G2API_ListModelBones( VMA(1), args[2]); + return 0; + + case UI_G2_HAVEWEGHOULMODELS: + return CL_G2API_HaveWeGhoul2Models( VMA(1) ); + + case UI_G2_SETMODELS: + CL_G2API_SetGhoul2ModelIndexes( VMA(1),(qhandle_t *)VMA(2),(qhandle_t *)VMA(3)); + return 0; + + case UI_G2_GETBOLT: + return CL_G2API_GetBoltMatrix(VMA(1), args[2], args[3], (mdxaBone_t *)VMA(4), (const float *)VMA(5),(const float *)VMA(6), args[7], (qhandle_t *)VMA(8), (float *)VMA(9)); + + case UI_G2_GETBOLT_NOREC: + return CL_G2API_GetBoltMatrix_NoReconstruct(VMA(1), args[2], args[3], (mdxaBone_t *)VMA(4), (const float *)VMA(5),(const float *)VMA(6), args[7], (qhandle_t *)VMA(8), (float *)VMA(9)); + + case UI_G2_GETBOLT_NOREC_NOROT: + return CL_G2API_GetBoltMatrix_NoRecNoRot(VMA(1), args[2], args[3], (mdxaBone_t *)VMA(4), (const float *)VMA(5),(const float *)VMA(6), args[7], (qhandle_t *)VMA(8), (float *)VMA(9)); + + case UI_G2_INITGHOUL2MODEL: +#ifdef _FULL_G2_LEAK_CHECKING + g_G2AllocServer = 0; +#endif + return CL_G2API_InitGhoul2Model((void **)VMA(1), (const char *)VMA(2), args[3], (qhandle_t) args[4], (qhandle_t) args[5], args[6], args[7]); + + case UI_G2_COLLISIONDETECT: + case UI_G2_COLLISIONDETECTCACHE: + return 0; //not supported for ui + + case UI_G2_ANGLEOVERRIDE: + return CL_G2API_SetBoneAngles(VMA(1), args[2], (const char *)VMA(3), (float *)VMA(4), args[5], (const Eorientations) args[6], (const Eorientations) args[7], (const Eorientations) args[8], (qhandle_t *)VMA(9), args[10], args[11] ); + + case UI_G2_CLEANMODELS: +#ifdef _FULL_G2_LEAK_CHECKING + g_G2AllocServer = 0; +#endif + CL_G2API_CleanGhoul2Models((void **)VMA(1)); + return 0; + + case UI_G2_PLAYANIM: + return CL_G2API_SetBoneAnim(VMA(1), args[2], (const char *)VMA(3), args[4], args[5], args[6], VMF(7), args[8], VMF(9), args[10]); + + case UI_G2_GETBONEANIM: + return CL_G2API_GetBoneAnim(VMA(1), (const char*)VMA(2), args[3], (float *)VMA(4), (int *)VMA(5), (int *)VMA(6), (int *)VMA(7), (float *)VMA(8), (int *)VMA(9), args[10]); + + case UI_G2_GETBONEFRAME: + return CL_G2API_GetBoneFrame(VMA(1), (const char*)VMA(2), args[3], (float *)VMA(4), (int *)VMA(5), args[6]); + + case UI_G2_GETGLANAME: + CL_G2API_GetGLAName( VMA(1), args[2], (char *)VMA(3) ); + return 0; + + case UI_G2_COPYGHOUL2INSTANCE: + return (int)CL_G2API_CopyGhoul2Instance(VMA(1), VMA(2), args[3]); + + case UI_G2_COPYSPECIFICGHOUL2MODEL: + CL_G2API_CopySpecificGhoul2Model(VMA(1), args[2], VMA(3), args[4]); + return 0; + + case UI_G2_DUPLICATEGHOUL2INSTANCE: +#ifdef _FULL_G2_LEAK_CHECKING + g_G2AllocServer = 0; +#endif + CL_G2API_DuplicateGhoul2Instance(VMA(1), (void **)VMA(2)); + return 0; + + case UI_G2_HASGHOUL2MODELONINDEX: + return (int)CL_G2API_HasGhoul2ModelOnIndex(VMA(1), args[2]); + + case UI_G2_REMOVEGHOUL2MODEL: +#ifdef _FULL_G2_LEAK_CHECKING + g_G2AllocServer = 0; +#endif + return (int)CL_G2API_RemoveGhoul2Model(VMA(1), args[2]); + + case UI_G2_ADDBOLT: + return CL_G2API_AddBolt(VMA(1), args[2], (const char *)VMA(3)); + + case UI_G2_SETBOLTON: + CL_G2API_SetBoltInfo(VMA(1), args[2], args[3]); + return 0; + + case UI_G2_SETROOTSURFACE: + return CL_G2API_SetRootSurface(VMA(1), args[2], (const char *)VMA(3)); + + case UI_G2_SETSURFACEONOFF: + return CL_G2API_SetSurfaceOnOff(VMA(1), (const char *)VMA(2), args[3]); + + case UI_G2_SETNEWORIGIN: + return CL_G2API_SetNewOrigin(VMA(1), args[2]); + + case UI_G2_GETTIME: + return CL_G2API_GetTime(); + + case UI_G2_SETTIME: + CL_G2API_SetTime(args[1], args[2]); + return 0; + + case UI_G2_SETRAGDOLL: + return 0; //not supported for ui + break; + + case UI_G2_ANIMATEG2MODELS: + return 0; //not supported for ui + break; + + case UI_G2_SETBONEIKSTATE: + return CL_G2API_SetBoneIKState(VMA(1), args[2], (const char *)VMA(3), args[4], (sharedSetBoneIKStateParams_t *)VMA(5)); + + case UI_G2_IKMOVE: + return CL_G2API_IKMove(VMA(1), args[2], (sharedIKMoveParams_t *)VMA(3)); + + case UI_G2_GETSURFACENAME: + CL_G2API_GetSurfaceName( (void *)args[1], args[2], args[3], (char *)VMA( 4 ) ); + return 0; + + case UI_G2_SETSKIN: + return CL_G2API_SetSkin(VMA(1), args[2], args[3], args[4]); + + case UI_G2_ATTACHG2MODEL: + return CL_G2API_AttachG2Model(VMA(1), args[2], VMA(3), args[4], args[5]); + + default: + Com_Error( ERR_DROP, "Bad UI system trap: %ld", (long int) args[0] ); + + } + + return 0; +} + +void CL_BindUI( void ) { + static uiImport_t uii; + uiExport_t *ret; + GetUIAPI_t GetUIAPI; + char dllName[MAX_OSPATH] = "ui" ARCH_STRING DLL_EXT; + + memset( &uii, 0, sizeof( uii ) ); + + uivm = VM_Create( VM_UI ); + if ( uivm && !uivm->isLegacy ) { + uii.Print = Com_Printf; + uii.Error = Com_Error; + uii.Milliseconds = CL_Milliseconds; + uii.RealTime = Com_RealTime; + uii.MemoryRemaining = Hunk_MemoryRemaining; + + uii.Cvar_Create = CL_Cvar_Get; + uii.Cvar_InfoStringBuffer = Cvar_InfoStringBuffer; + uii.Cvar_Register = Cvar_Register; + uii.Cvar_Reset = Cvar_Reset; + uii.Cvar_Set = UIVM_Cvar_Set; + uii.Cvar_SetValue = UIVM_Cvar_SetValue; + uii.Cvar_Update = Cvar_Update; + uii.Cvar_VariableStringBuffer = Cvar_VariableStringBuffer; + uii.Cvar_VariableValue = Cvar_VariableValue; + + uii.Cmd_Argc = Cmd_Argc; + uii.Cmd_Argv = Cmd_ArgvBuffer; + uii.Cmd_ExecuteText = Cbuf_ExecuteText; + + uii.FS_Close = FS_FCloseFile; + uii.FS_GetFileList = FS_GetFileList; + uii.FS_Open = FS_FOpenFileByMode; + uii.FS_Read = FS_Read; + uii.FS_Write = FS_Write; + + uii.GetClientState = CL_GetClientState; + uii.GetClipboardData = GetClipboardData; + uii.GetConfigString = GetConfigString; + uii.GetGlconfig = CL_GetGlconfig; + uii.UpdateScreen = SCR_UpdateScreen; + + uii.Key_ClearStates = Key_ClearStates; + uii.Key_GetBindingBuf = Key_GetBindingBuf; + uii.Key_IsDown = Key_IsDown; + uii.Key_KeynumToStringBuf = Key_KeynumToStringBuf; + uii.Key_SetBinding = Key_SetBinding; + uii.Key_GetCatcher = Key_GetCatcher; + uii.Key_GetOverstrikeMode = Key_GetOverstrikeMode; + uii.Key_SetCatcher = CL_Key_SetCatcher; + uii.Key_SetOverstrikeMode = Key_SetOverstrikeMode; + + uii.PC_AddGlobalDefine = botlib_export->PC_AddGlobalDefine; + uii.PC_FreeSource = botlib_export->PC_FreeSourceHandle; + uii.PC_LoadGlobalDefines = botlib_export->PC_LoadGlobalDefines; + uii.PC_LoadSource = botlib_export->PC_LoadSourceHandle; + uii.PC_ReadToken = botlib_export->PC_ReadTokenHandle; + uii.PC_RemoveAllGlobalDefines = botlib_export->PC_RemoveAllGlobalDefines; + uii.PC_SourceFileAndLine = botlib_export->PC_SourceFileAndLine; + + uii.CIN_DrawCinematic = CIN_DrawCinematic; + uii.CIN_PlayCinematic = CIN_PlayCinematic; + uii.CIN_RunCinematic = CIN_RunCinematic; + uii.CIN_SetExtents = CIN_SetExtents; + uii.CIN_StopCinematic = CIN_StopCinematic; + + uii.LAN_AddServer = LAN_AddServer; + uii.LAN_ClearPing = LAN_ClearPing; + uii.LAN_CompareServers = LAN_CompareServers; + uii.LAN_GetPing = LAN_GetPing; + uii.LAN_GetPingInfo = LAN_GetPingInfo; + uii.LAN_GetPingQueueCount = LAN_GetPingQueueCount; + uii.LAN_GetServerAddressString = LAN_GetServerAddressString; + uii.LAN_GetServerCount = LAN_GetServerCount; + uii.LAN_GetServerInfo = LAN_GetServerInfo; + uii.LAN_GetServerPing = LAN_GetServerPing; + uii.LAN_LoadCachedServers = LAN_LoadCachedServers; + uii.LAN_MarkServerVisible = LAN_MarkServerVisible; + uii.LAN_RemoveServer = LAN_RemoveServer; + uii.LAN_ResetPings = LAN_ResetPings; + uii.LAN_SaveCachedServers = LAN_SaveServersToCache; + uii.LAN_ServerIsVisible = LAN_ServerIsVisible; + uii.LAN_ServerStatus = LAN_GetServerStatus; + uii.LAN_UpdateVisiblePings = LAN_UpdateVisiblePings; + + uii.S_StartBackgroundTrack = S_StartBackgroundTrack; + uii.S_StartLocalSound = S_StartLocalSound; + uii.S_StopBackgroundTrack = S_StopBackgroundTrack; + uii.S_RegisterSound = S_RegisterSound; + + uii.SE_GetLanguageName = CL_SE_GetLanguageName; + uii.SE_GetNumLanguages = SE_GetNumLanguages; + uii.SE_GetStringTextString = CL_SE_GetStringTextString; + + uii.R_Language_IsAsian = re->Language_IsAsian; + uii.R_Language_UsesSpaces = re->Language_UsesSpaces; + uii.R_AnyLanguage_ReadCharFromString = re->AnyLanguage_ReadCharFromString; + + uii.R_AddLightToScene = re->AddLightToScene; + uii.R_AddPolysToScene = re->AddPolyToScene; + uii.R_AddRefEntityToScene = re->AddRefEntityToScene; + uii.R_ClearScene = re->ClearScene; + uii.R_DrawStretchPic = re->DrawStretchPic; + uii.R_Font_DrawString = re->Font_DrawString; + uii.R_Font_HeightPixels = re->Font_HeightPixels; + uii.R_Font_StrLenChars = re->Font_StrLenChars; + uii.R_Font_StrLenPixels = re->Font_StrLenPixels; + uii.R_LerpTag = re->LerpTag; + uii.R_ModelBounds = re->ModelBounds; + uii.R_RegisterFont = re->RegisterFont; + uii.R_RegisterModel = re->RegisterModel; + uii.R_RegisterShaderNoMip = re->RegisterShaderNoMip; + uii.R_RegisterSkin = re->RegisterSkin; + uii.R_RemapShader = re->RemapShader; + uii.R_RenderScene = re->RenderScene; + uii.R_SetColor = re->SetColor; + uii.R_ShaderNameFromIndex = CL_R_ShaderNameFromIndex; + + uii.G2_ListModelSurfaces = CL_G2API_ListModelSurfaces; + uii.G2_ListModelBones = CL_G2API_ListModelBones; + uii.G2_SetGhoul2ModelIndexes = CL_G2API_SetGhoul2ModelIndexes; + uii.G2_HaveWeGhoul2Models = CL_G2API_HaveWeGhoul2Models; + uii.G2API_GetBoltMatrix = CL_G2API_GetBoltMatrix; + uii.G2API_GetBoltMatrix_NoReconstruct = CL_G2API_GetBoltMatrix_NoReconstruct; + uii.G2API_GetBoltMatrix_NoRecNoRot = CL_G2API_GetBoltMatrix_NoRecNoRot; + uii.G2API_InitGhoul2Model = CL_G2API_InitGhoul2Model; + uii.G2API_SetSkin = CL_G2API_SetSkin; + uii.G2API_CollisionDetect = CL_G2API_CollisionDetect; + uii.G2API_CollisionDetectCache = CL_G2API_CollisionDetectCache; + uii.G2API_CleanGhoul2Models = CL_G2API_CleanGhoul2Models; + uii.G2API_SetBoneAngles = CL_G2API_SetBoneAngles; + uii.G2API_SetBoneAnim = CL_G2API_SetBoneAnim; + uii.G2API_GetBoneAnim = CL_G2API_GetBoneAnim; + uii.G2API_GetBoneFrame = CL_G2API_GetBoneFrame; + uii.G2API_GetGLAName = CL_G2API_GetGLAName; + uii.G2API_CopyGhoul2Instance = CL_G2API_CopyGhoul2Instance; + uii.G2API_CopySpecificGhoul2Model = CL_G2API_CopySpecificGhoul2Model; + uii.G2API_DuplicateGhoul2Instance = CL_G2API_DuplicateGhoul2Instance; + uii.G2API_HasGhoul2ModelOnIndex = CL_G2API_HasGhoul2ModelOnIndex; + uii.G2API_RemoveGhoul2Model = CL_G2API_RemoveGhoul2Model; + uii.G2API_AddBolt = CL_G2API_AddBolt; + uii.G2API_SetBoltInfo = CL_G2API_SetBoltInfo; + uii.G2API_SetRootSurface = CL_G2API_SetRootSurface; + uii.G2API_SetSurfaceOnOff = CL_G2API_SetSurfaceOnOff; + uii.G2API_SetNewOrigin = CL_G2API_SetNewOrigin; + uii.G2API_GetTime = CL_G2API_GetTime; + uii.G2API_SetTime = CL_G2API_SetTime; + uii.G2API_SetRagDoll = CL_G2API_SetRagDoll; + uii.G2API_AnimateG2Models = CL_G2API_AnimateG2Models; + uii.G2API_SetBoneIKState = CL_G2API_SetBoneIKState; + uii.G2API_IKMove = CL_G2API_IKMove; + uii.G2API_GetSurfaceName = CL_G2API_GetSurfaceName; + uii.G2API_AttachG2Model = CL_G2API_AttachG2Model; + + uii.ext.R_Font_StrLenPixels = re->ext.Font_StrLenPixels; + uii.ext.AddCommand = CL_AddUICommand; + uii.ext.RemoveCommand = UIVM_Cmd_RemoveCommand; + + GetUIAPI = (GetUIAPI_t)uivm->GetModuleAPI; + ret = GetUIAPI( UI_API_VERSION, &uii ); + if ( !ret ) { + //free VM? + cls.uiStarted = qfalse; + Com_Error( ERR_FATAL, "GetGameAPI failed on %s", dllName ); + } + uie = ret; + + return; + } + + // fall back to legacy syscall/vm_call api + uivm = VM_CreateLegacy( VM_UI, CL_UISystemCalls ); + if ( !uivm ) { + cls.uiStarted = qfalse; + Com_Error( ERR_DROP, "VM_CreateLegacy on ui failed" ); + } +} + +void CL_UnbindUI( void ) { + UIVM_Shutdown(); + VM_Free( uivm ); + uivm = NULL; +} diff --git a/Projects/Android/jni/OpenJK/codemp_delete/client/cl_uiapi.h b/Projects/Android/jni/OpenJK/codemp_delete/client/cl_uiapi.h new file mode 100644 index 0000000..21760dd --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/client/cl_uiapi.h @@ -0,0 +1,34 @@ +/* +=========================================================================== +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#pragma once + +void UIVM_Init ( qboolean inGameLoad ); +void UIVM_Shutdown ( void ); +void UIVM_KeyEvent ( int key, qboolean down ); +void UIVM_MouseEvent ( int dx, int dy ); +void UIVM_Refresh ( int realtime ); +qboolean UIVM_IsFullscreen ( void ); +void UIVM_SetActiveMenu ( uiMenuCommand_t menu ); +qboolean UIVM_ConsoleCommand ( int realTime ); +void UIVM_DrawConnectScreen ( qboolean overlay ); + +void CL_BindUI( void ); +void CL_UnbindUI( void ); diff --git a/Projects/Android/jni/OpenJK/codemp/client/client.h b/Projects/Android/jni/OpenJK/codemp_delete/client/client.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/client.h rename to Projects/Android/jni/OpenJK/codemp_delete/client/client.h diff --git a/Projects/Android/jni/OpenJK/codemp/client/eax/EaxMan.h b/Projects/Android/jni/OpenJK/codemp_delete/client/eax/EaxMan.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/eax/EaxMan.h rename to Projects/Android/jni/OpenJK/codemp_delete/client/eax/EaxMan.h diff --git a/Projects/Android/jni/OpenJK/codemp/client/eax/eax.h b/Projects/Android/jni/OpenJK/codemp_delete/client/eax/eax.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/eax/eax.h rename to Projects/Android/jni/OpenJK/codemp_delete/client/eax/eax.h diff --git a/Projects/Android/jni/OpenJK/codemp/client/keycodes.h b/Projects/Android/jni/OpenJK/codemp_delete/client/keycodes.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/keycodes.h rename to Projects/Android/jni/OpenJK/codemp_delete/client/keycodes.h diff --git a/Projects/Android/jni/OpenJK/codemp/client/keys.h b/Projects/Android/jni/OpenJK/codemp_delete/client/keys.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/keys.h rename to Projects/Android/jni/OpenJK/codemp_delete/client/keys.h diff --git a/Projects/Android/jni/OpenJK/codemp/client/snd_ambient.cpp b/Projects/Android/jni/OpenJK/codemp_delete/client/snd_ambient.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/snd_ambient.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/client/snd_ambient.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/client/snd_ambient.h b/Projects/Android/jni/OpenJK/codemp_delete/client/snd_ambient.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/snd_ambient.h rename to Projects/Android/jni/OpenJK/codemp_delete/client/snd_ambient.h diff --git a/Projects/Android/jni/OpenJK/codemp/client/snd_dma.cpp b/Projects/Android/jni/OpenJK/codemp_delete/client/snd_dma.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/snd_dma.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/client/snd_dma.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/client/snd_local.h b/Projects/Android/jni/OpenJK/codemp_delete/client/snd_local.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/snd_local.h rename to Projects/Android/jni/OpenJK/codemp_delete/client/snd_local.h diff --git a/Projects/Android/jni/OpenJK/codemp/client/snd_mem.cpp b/Projects/Android/jni/OpenJK/codemp_delete/client/snd_mem.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/snd_mem.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/client/snd_mem.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/client/snd_mix.cpp b/Projects/Android/jni/OpenJK/codemp_delete/client/snd_mix.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/snd_mix.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/client/snd_mix.cpp diff --git a/Projects/Android/jni/OpenJK/codemp_delete/client/snd_mp3.cpp b/Projects/Android/jni/OpenJK/codemp_delete/client/snd_mp3.cpp new file mode 100644 index 0000000..452d210 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/client/snd_mp3.cpp @@ -0,0 +1,572 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +// Filename:- cl_mp3.cpp +// +// (The interface module between all the MP3 stuff and the game) + + +#include "client.h" +#include "snd_mp3.h" // only included directly by a few snd_xxxx.cpp files plus this one +#include "mp3code/mp3struct.h" // keep this rather awful file secret from the rest of the program + +// expects data already loaded, filename arg is for error printing only +// +// returns success/fail +// +qboolean MP3_IsValid( const char *psLocalFilename, void *pvData, int iDataLen, qboolean bStereoDesired /* = qfalse */) +{ + char *psError = C_MP3_IsValid(pvData, iDataLen, bStereoDesired); + + if (psError) + { + Com_Printf(va(S_COLOR_RED"%s(%s)\n",psError, psLocalFilename)); + } + + return (qboolean)!psError; +} + + + +// expects data already loaded, filename arg is for error printing only +// +// returns unpacked length, or 0 for errors (which will be printed internally) +// +int MP3_GetUnpackedSize( const char *psLocalFilename, void *pvData, int iDataLen, qboolean qbIgnoreID3Tag /* = qfalse */ + , qboolean bStereoDesired /* = qfalse */ + ) +{ + int iUnpackedSize = 0; + + // always do this now that we have fast-unpack code for measuring output size... (much safer than relying on tags that may have been edited, or if MP3 has been re-saved with same tag) + // + if (1)//qbIgnoreID3Tag || !MP3_ReadSpecialTagInfo((byte *)pvData, iDataLen, NULL, &iUnpackedSize)) + { + char *psError = C_MP3_GetUnpackedSize( pvData, iDataLen, &iUnpackedSize, bStereoDesired); + + if (psError) + { + Com_Printf(va(S_COLOR_RED"%s\n(File: %s)\n",psError, psLocalFilename)); + return 0; + } + } + + return iUnpackedSize; +} + + + +// expects data already loaded, filename arg is for error printing only +// +// returns byte count of unpacked data (effectively a success/fail bool) +// +int MP3_UnpackRawPCM( const char *psLocalFilename, void *pvData, int iDataLen, byte *pbUnpackBuffer, qboolean bStereoDesired /* = qfalse */) +{ + int iUnpackedSize; + char *psError = C_MP3_UnpackRawPCM( pvData, iDataLen, &iUnpackedSize, pbUnpackBuffer, bStereoDesired); + + if (psError) + { + Com_Printf(va(S_COLOR_RED"%s\n(File: %s)\n",psError, psLocalFilename)); + return 0; + } + + return iUnpackedSize; +} + + +// psLocalFilename is just for error reporting (if any)... +// +qboolean MP3Stream_InitPlayingTimeFields( LP_MP3STREAM lpMP3Stream, const char *psLocalFilename, void *pvData, int iDataLen, qboolean bStereoDesired /* = qfalse */) +{ + qboolean bRetval = qfalse; + + int iRate, iWidth, iChannels; + + char *psError = C_MP3_GetHeaderData(pvData, iDataLen, &iRate, &iWidth, &iChannels, bStereoDesired ); + if (psError) + { + Com_Printf(va(S_COLOR_RED"MP3Stream_InitPlayingTimeFields(): %s\n(File: %s)\n",psError, psLocalFilename)); + } + else + { + int iUnpackLength = MP3_GetUnpackedSize( psLocalFilename, pvData, iDataLen, qfalse, // qboolean qbIgnoreID3Tag + bStereoDesired); + if (iUnpackLength) + { + lpMP3Stream->iTimeQuery_UnpackedLength = iUnpackLength; + lpMP3Stream->iTimeQuery_SampleRate = iRate; + lpMP3Stream->iTimeQuery_Channels = iChannels; + lpMP3Stream->iTimeQuery_Width = iWidth; + + bRetval = qtrue; + } + } + + return bRetval; +} + +float MP3Stream_GetPlayingTimeInSeconds( LP_MP3STREAM lpMP3Stream ) +{ + if (lpMP3Stream->iTimeQuery_UnpackedLength) // fields initialised? + return (float)((((double)lpMP3Stream->iTimeQuery_UnpackedLength / (double)lpMP3Stream->iTimeQuery_SampleRate) / (double)lpMP3Stream->iTimeQuery_Channels) / (double)lpMP3Stream->iTimeQuery_Width); + + return 0.0f; +} + +float MP3Stream_GetRemainingTimeInSeconds( LP_MP3STREAM lpMP3Stream ) +{ + if (lpMP3Stream->iTimeQuery_UnpackedLength) // fields initialised? + return (float)(((((double)(lpMP3Stream->iTimeQuery_UnpackedLength - (lpMP3Stream->iBytesDecodedTotal * (lpMP3Stream->iTimeQuery_SampleRate / dma.speed)))) / (double)lpMP3Stream->iTimeQuery_SampleRate) / (double)lpMP3Stream->iTimeQuery_Channels) / (double)lpMP3Stream->iTimeQuery_Width); + + return 0.0f; +} + + + + +// expects data already loaded, filename arg is for error printing only +// +qboolean MP3_FakeUpWAVInfo( const char *psLocalFilename, void *pvData, int iDataLen, int iUnpackedDataLength, + int &format, int &rate, int &width, int &channels, int &samples, int &dataofs, + qboolean bStereoDesired /* = qfalse */ + ) +{ + // some things can be done instantly... + // + format = 1; // 1 for MS format + dataofs= 0; // will be 0 for me (since there's no header in the unpacked data) + + // some things need to be read... (though the whole stereo flag thing is crap) + // + char *psError = C_MP3_GetHeaderData(pvData, iDataLen, &rate, &width, &channels, bStereoDesired ); + if (psError) + { + Com_Printf(va(S_COLOR_RED"%s\n(File: %s)\n",psError, psLocalFilename)); + } + + // and some stuff needs calculating... + // + samples = iUnpackedDataLength / width; + + return (qboolean)!psError; +} + + + +const char sKEY_MAXVOL[]="#MAXVOL"; // formerly #defines +const char sKEY_UNCOMP[]="#UNCOMP"; // " " + +// returns qtrue for success... +// +qboolean MP3_ReadSpecialTagInfo(byte *pbLoadedFile, int iLoadedFileLen, + id3v1_1** ppTAG /* = NULL */, + int *piUncompressedSize /* = NULL */, + float *pfMaxVol /* = NULL */ + ) +{ + qboolean qbError = qfalse; + + id3v1_1* pTAG = (id3v1_1*) ((pbLoadedFile+iLoadedFileLen)-sizeof(id3v1_1)); // sizeof = 128 + + if (!Q_strncmp(pTAG->id, "TAG", 3)) + { + // TAG found... + // + + // read MAXVOL key... + // + if (Q_strncmp(pTAG->comment, sKEY_MAXVOL, strlen(sKEY_MAXVOL))) + { + qbError = qtrue; + } + else + { + if ( pfMaxVol) + { + *pfMaxVol = atof(pTAG->comment + strlen(sKEY_MAXVOL)); + } + } + + // + // read UNCOMP key... + // + if (Q_strncmp(pTAG->album, sKEY_UNCOMP, strlen(sKEY_UNCOMP))) + { + qbError = qtrue; + } + else + { + if ( piUncompressedSize) + { + *piUncompressedSize = atoi(pTAG->album + strlen(sKEY_UNCOMP)); + } + } + } + else + { + pTAG = NULL; + } + + if (ppTAG) + { + *ppTAG = pTAG; + } + + return (qboolean)(pTAG && !qbError); +} + + + +#define FUZZY_AMOUNT (5*1024) // so it has to be significantly over, not just break even, because of + // the xtra CPU time versus memory saving + +cvar_t* cv_MP3overhead = NULL; +void MP3_InitCvars(void) +{ + cv_MP3overhead = Cvar_Get("s_mp3overhead", va("%d", sizeof(MP3STREAM) + FUZZY_AMOUNT), CVAR_ARCHIVE ); +} + + +// a file has been loaded in memory, see if we want to keep it as MP3, else as normal WAV... +// +// return = qtrue if keeping as MP3 +// +// (note: the reason I pass in the unpacked size rather than working it out here is simply because I already have it) +// +qboolean MP3Stream_InitFromFile( sfx_t* sfx, byte *pbSrcData, int iSrcDatalen, const char *psSrcDataFilename, + int iMP3UnPackedSize, qboolean bStereoDesired /* = qfalse */ + ) +{ + // first, make a decision based on size here as to whether or not it's worth it because of MP3 buffer space + // making small files much bigger (and therefore best left as WAV)... + // + + if (cv_MP3overhead && + ( + //iSrcDatalen + sizeof(MP3STREAM) + FUZZY_AMOUNT < iMP3UnPackedSize + iSrcDatalen + cv_MP3overhead->integer < iMP3UnPackedSize + ) + ) + { + // ok, let's keep it as MP3 then... + // + float fMaxVol = 128; // seems to be a reasonable typical default for maxvol (for lip synch). Naturally there's no #define I can use instead... + + MP3_ReadSpecialTagInfo(pbSrcData, iSrcDatalen, NULL, NULL, &fMaxVol ); // try and read a read maxvol from MP3 header + + // fill in some sfx_t fields... + // +// Q_strncpyz( sfx->name, psSrcDataFilename, sizeof(sfx->name) ); + sfx->eSoundCompressionMethod = ct_MP3; + sfx->fVolRange = fMaxVol; + //sfx->width = 2; + sfx->iSoundLengthInSamples = ((iMP3UnPackedSize / 2/*sfx->width*/) / (44100 / dma.speed)) / (bStereoDesired?2:1); + // + // alloc mem for data and store it (raw MP3 in this case)... + // + sfx->pSoundData = (short *) SND_malloc( iSrcDatalen, sfx ); + memcpy( sfx->pSoundData, pbSrcData, iSrcDatalen ); + + // now init the low-level MP3 stuff... + // + MP3STREAM SFX_MP3Stream = {}; // important to init to all zeroes! + char *psError = C_MP3Stream_DecodeInit( &SFX_MP3Stream, /*sfx->data*/ /*sfx->soundData*/ pbSrcData, iSrcDatalen, + dma.speed,//(s_khz->value == 44)?44100:(s_khz->value == 22)?22050:11025, + 2/*sfx->width*/ * 8, + bStereoDesired + ); + SFX_MP3Stream.pbSourceData = (byte *) sfx->pSoundData; + if (psError) + { + // This should never happen, since any errors or problems with the MP3 file would have stopped us getting + // to this whole function, but just in case... + // + Com_Printf(va(S_COLOR_YELLOW"File \"%s\": %s\n",psSrcDataFilename,psError)); + + // This will leave iSrcDatalen bytes on the hunk stack (since you can't dealloc that), but MP3 files are + // usually small, and like I say, it should never happen. + // + // Strictly speaking, I should do a Z_Malloc above, then I could do a Z_Free if failed, else do a Hunk_Alloc + // to copy the Z_Malloc data into, then Z_Free, but for something that shouldn't happen it seemed bad to + // penalise the rest of the game with extra alloc demands. + // + return qfalse; + } + + // success ( ...on a plate). + // + // make a copy of the filled-in stream struct and attach to the sfx_t struct... + // + sfx->pMP3StreamHeader = (MP3STREAM *) Z_Malloc( sizeof(MP3STREAM), TAG_SND_MP3STREAMHDR, qfalse ); + memcpy( sfx->pMP3StreamHeader, &SFX_MP3Stream, sizeof(MP3STREAM) ); + // + return qtrue; + } + + return qfalse; +} + + + +// decode one packet of MP3 data only (typical output size is 2304, or 2304*2 for stereo, so input size is less +// +// return is decoded byte count, else 0 for finished +// +int MP3Stream_Decode( LP_MP3STREAM lpMP3Stream, qboolean bDoingMusic ) +{ + lpMP3Stream->iCopyOffset = 0; + + if (0)//!bDoingMusic) + { + /* + // SOF2: need to make a local buffer up so we can decode the piece we want from a contiguous bitstream rather than + // this linklist junk... + // + // since MP3 packets are generally 416 or 417 bytes in length it seems reasonable to just find which linked-chunk + // the current read offset lies within then grab the next one as well (since they're 2048 bytes) and make one + // buffer with just the two concat'd together. Shouldn't be much of a processor hit. + // + sndBuffer *pChunk = (sndBuffer *) lpMP3Stream->pbSourceData; + // + // may as well make this static to avoid cut down on stack-validation run-time... + // + static byte byRawBuffer[SND_CHUNK_SIZE_BYTE*2]; // *2 for byte->short // easily enough to decode one frame of MP3 data, most are 416 or 417 bytes + + // fast-forward to the correct chunk... + // + int iBytesToSkipPast = lpMP3Stream->iSourceReadIndex; + + while (iBytesToSkipPast >= SND_CHUNK_SIZE_BYTE) + { + pChunk = pChunk->next; + if (!pChunk) + { + // err.... reading off the end of the data stream guys... + // + // pChunk = (sndBuffer *) lpMP3Stream->pbSourceData; // restart + return 0; // ... 0 bytes decoded, so will just stop caller-decoder all nice and legal as EOS + } + iBytesToSkipPast -= SND_CHUNK_SIZE_BYTE; + } + + { + // ok, pChunk is now the 2k or so chunk we're in the middle of... + // + int iChunk1BytesToCopy = SND_CHUNK_SIZE_BYTE - iBytesToSkipPast; + memcpy(byRawBuffer,((byte *)pChunk->sndChunk) + iBytesToSkipPast, iChunk1BytesToCopy); + // + // concat next chunk on to this as well... + // + pChunk = pChunk->next; + if (pChunk) + { + memcpy(byRawBuffer + iChunk1BytesToCopy, pChunk->sndChunk, SND_CHUNK_SIZE_BYTE); + } + else + { + memset(byRawBuffer + iChunk1BytesToCopy, 0, SND_CHUNK_SIZE_BYTE); + } + } + + + { + // now we need to backup some struct fields, fake 'em, do the lo-level call, then restore 'em... + // + byte *pbSourceData_Old = lpMP3Stream->pbSourceData; + int iSourceReadIndex_Old= lpMP3Stream->iSourceReadIndex; + + lpMP3Stream->pbSourceData = &byRawBuffer[0]; + lpMP3Stream->iSourceReadIndex= 0; // since this is zero, not the buffer offset within a chunk, we can play tricks further down when restoring + + { + unsigned int uiBytesDecoded = C_MP3Stream_Decode( lpMP3Stream, qfalse ); + + lpMP3Stream->iSourceReadIndex += iSourceReadIndex_Old; // note '+=' rather than '=', to take account of movement. + lpMP3Stream->pbSourceData = pbSourceData_Old; + + return uiBytesDecoded; + } + } + */ + } + else + { + // SOF2 music, or EF1 anything... + // + return C_MP3Stream_Decode( lpMP3Stream, qfalse ); // bFastForwarding + } +} + + +qboolean MP3Stream_SeekTo( channel_t *ch, float fTimeToSeekTo ) +{ + const float fEpsilon = 0.05f; // accurate to 1/50 of a second, but plus or minus this gives 1/10 of second + + MP3Stream_Rewind( ch ); + // + // sanity... :-) + // + const float fTrackLengthInSeconds = MP3Stream_GetPlayingTimeInSeconds( &ch->MP3StreamHeader ); + if (fTimeToSeekTo > fTrackLengthInSeconds) + { + fTimeToSeekTo = fTrackLengthInSeconds; + } + + // now do the seek... + // + while (1) + { + float fPlayingTimeElapsed = MP3Stream_GetPlayingTimeInSeconds( &ch->MP3StreamHeader ) - MP3Stream_GetRemainingTimeInSeconds( &ch->MP3StreamHeader ); + float fAbsTimeDiff = fabs(fTimeToSeekTo - fPlayingTimeElapsed); + + if ( fAbsTimeDiff <= fEpsilon) + return qtrue; + + // when decoding, use fast-forward until within 3 seconds, then slow-decode (which should init stuff properly?)... + // + int iBytesDecodedThisPacket = C_MP3Stream_Decode( &ch->MP3StreamHeader, (fAbsTimeDiff > 3.0f) ); // bFastForwarding + if (iBytesDecodedThisPacket == 0) + break; // EOS + } + + return qfalse; +} + + +// returns qtrue for all ok +// +qboolean MP3Stream_Rewind( channel_t *ch ) +{ + ch->iMP3SlidingDecodeWritePos = 0; + ch->iMP3SlidingDecodeWindowPos= 0; + +/* + char *psError = C_MP3Stream_Rewind( &ch->MP3StreamHeader ); + + if (psError) + { + Com_Printf(S_COLOR_YELLOW"%s\n",psError); + return qfalse; + } + + return qtrue; +*/ + + // speed opt, since I know I already have the right data setup here... + // + memcpy(&ch->MP3StreamHeader, ch->thesfx->pMP3StreamHeader, sizeof(ch->MP3StreamHeader)); + return qtrue; + +} + + +// returns qtrue while still playing normally, else qfalse for either finished or request-offset-error +// +qboolean MP3Stream_GetSamples( channel_t *ch, int startingSampleNum, int count, short *buf, qboolean bStereo ) +{ + qboolean qbStreamStillGoing = qtrue; + + const int iQuarterOfSlidingBuffer = sizeof(ch->MP3SlidingDecodeBuffer)/4; + const int iThreeQuartersOfSlidingBuffer = (sizeof(ch->MP3SlidingDecodeBuffer)*3)/4; + +// Com_Printf("startingSampleNum %d\n",startingSampleNum); + + count *= 2/* <- = SOF2; ch->sfx->width*/; // count arg was for words, so double it for bytes; + + // convert sample number into a byte offset... (make new variable for clarity?) + // + startingSampleNum *= 2 /* <- = SOF2; ch->sfx->width*/ * (bStereo?2:1); + + if ( startingSampleNum < ch->iMP3SlidingDecodeWindowPos) + { + // what?!?!?! smegging time travel needed or something?, forget it + memset(buf,0,count); + return qfalse; + } + +// Com_OPrintf("\nRequest: startingSampleNum %d, count %d\n",startingSampleNum,count); +// Com_OPrintf("WindowPos %d, WindowWritePos %d\n",ch->iMP3SlidingDecodeWindowPos,ch->iMP3SlidingDecodeWritePos); + +// qboolean _bDecoded = qfalse; + + while (! + ( + (startingSampleNum >= ch->iMP3SlidingDecodeWindowPos) + && + (startingSampleNum + count < ch->iMP3SlidingDecodeWindowPos + ch->iMP3SlidingDecodeWritePos) + ) + ) + { +// if (!_bDecoded) +// { +// Com_Printf(S_COLOR_YELLOW"Decode needed!\n"); +// } +// _bDecoded = qtrue; +// Com_OPrintf("Scrolling..."); + + int _iBytesDecoded = MP3Stream_Decode( (LP_MP3STREAM) &ch->MP3StreamHeader, bStereo ); // stereo only for music, so this is safe +// Com_OPrintf("%d bytes decoded\n",_iBytesDecoded); + if (_iBytesDecoded == 0) + { + // no more source data left so clear the remainder of the buffer... + // + memset(ch->MP3SlidingDecodeBuffer + ch->iMP3SlidingDecodeWritePos, 0, sizeof(ch->MP3SlidingDecodeBuffer)-ch->iMP3SlidingDecodeWritePos); +// Com_OPrintf("Finished\n"); + qbStreamStillGoing = qfalse; + break; + } + else + { + memcpy(ch->MP3SlidingDecodeBuffer + ch->iMP3SlidingDecodeWritePos,ch->MP3StreamHeader.bDecodeBuffer,_iBytesDecoded); + + ch->iMP3SlidingDecodeWritePos += _iBytesDecoded; + + // if reached 3/4 of buffer pos, backscroll the decode window by one quarter... + // + if (ch->iMP3SlidingDecodeWritePos > iThreeQuartersOfSlidingBuffer) + { + memmove(ch->MP3SlidingDecodeBuffer, ((byte *)ch->MP3SlidingDecodeBuffer + iQuarterOfSlidingBuffer), iThreeQuartersOfSlidingBuffer); + ch->iMP3SlidingDecodeWritePos -= iQuarterOfSlidingBuffer; + ch->iMP3SlidingDecodeWindowPos+= iQuarterOfSlidingBuffer; + } + } +// Com_OPrintf("WindowPos %d, WindowWritePos %d\n",ch->iMP3SlidingDecodeWindowPos,ch->iMP3SlidingDecodeWritePos); + } + +// if (!_bDecoded) +// { +// Com_Printf(S_COLOR_YELLOW"No decode needed\n"); +// } + + assert(startingSampleNum >= ch->iMP3SlidingDecodeWindowPos); + memcpy( buf, ch->MP3SlidingDecodeBuffer + (startingSampleNum-ch->iMP3SlidingDecodeWindowPos), count); + +// Com_OPrintf("OK\n\n"); + + return qbStreamStillGoing; +} + + +///////////// eof ///////////// + diff --git a/Projects/Android/jni/OpenJK/codemp_delete/client/snd_mp3.h b/Projects/Android/jni/OpenJK/codemp_delete/client/snd_mp3.h new file mode 100644 index 0000000..20abb91 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/client/snd_mp3.h @@ -0,0 +1,98 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#pragma once + +// Filename:- cl_mp3.h +// +// (Interface to the rest of the game for the MP3 functions) +// + +#include "snd_local.h" + +typedef struct id3v1_1 { + char id[3]; + char title[30]; // + char artist[30]; // "Raven Software" + char album[30]; // "#UNCOMP %d" // needed + char year[4]; // "2000" + char comment[28]; // "#MAXVOL %g" // needed + char zero; + char track; + char genre; +} id3v1_1; // 128 bytes in size + +extern const char sKEY_MAXVOL[]; +extern const char sKEY_UNCOMP[]; + +// (so far, all these functions are only called from one place in snd_mem.cpp) +// +// (filenames are used purely for error reporting, all files should already be loaded before you get here) +// +void MP3_InitCvars ( void ); +qboolean MP3_IsValid ( const char *psLocalFilename, void *pvData, int iDataLen, qboolean bStereoDesired = qfalse ); +int MP3_GetUnpackedSize ( const char *psLocalFilename, void *pvData, int iDataLen, qboolean qbIgnoreID3Tag = qfalse, qboolean bStereoDesired = qfalse ); +int MP3_UnpackRawPCM ( const char *psLocalFilename, void *pvData, int iDataLen, byte *pbUnpackBuffer, qboolean bStereoDesired = qfalse ); +qboolean MP3Stream_InitPlayingTimeFields( LP_MP3STREAM lpMP3Stream, const char *psLocalFilename, void *pvData, int iDataLen, qboolean bStereoDesired = qfalse); +float MP3Stream_GetPlayingTimeInSeconds( LP_MP3STREAM lpMP3Stream ); +float MP3Stream_GetRemainingTimeInSeconds( LP_MP3STREAM lpMP3Stream ); +qboolean MP3_FakeUpWAVInfo ( const char *psLocalFilename, void *pvData, int iDataLen, int iUnpackedDataLength, int &format, int &rate, int &width, int &channels, int &samples, int &dataofs, qboolean bStereoDesired = qfalse ); +qboolean MP3_ReadSpecialTagInfo ( byte *pbLoadedFile, int iLoadedFileLen, + id3v1_1** ppTAG = NULL, int *piUncompressedSize = NULL, float *pfMaxVol = NULL); +qboolean MP3Stream_InitFromFile ( sfx_t* sfx, byte *pbSrcData, int iSrcDatalen, const char *psSrcDataFilename, int iMP3UnPackedSize, qboolean bStereoDesired = qfalse ); +int MP3Stream_Decode ( LP_MP3STREAM lpMP3Stream, qboolean bDoingMusic ); +qboolean MP3Stream_SeekTo ( channel_t *ch, float fTimeToSeekTo ); +qboolean MP3Stream_Rewind ( channel_t *ch ); +qboolean MP3Stream_GetSamples ( channel_t *ch, int startingSampleNum, int count, short *buf, qboolean bStereo ); + + + + + +/////////////////////////////////////// +// +// the real worker code deep down in the MP3 C code... (now externalised here so the music streamer can access one) +// +#ifdef __cplusplus +extern "C" +{ +#endif + + +char* C_MP3_IsValid (void *pvData, int iDataLen, int bStereoDesired); +char* C_MP3_GetUnpackedSize (void *pvData, int iDataLen, int *piUnpackedSize, int bStereoDesired); +char* C_MP3_UnpackRawPCM (void *pvData, int iDataLen, int *piUnpackedSize, void *pbUnpackBuffer, int bStereoDesired); +char* C_MP3_GetHeaderData (void *pvData, int iDataLen, int *piRate, int *piWidth, int *piChannels, int bStereoDesired); +char* C_MP3Stream_DecodeInit (LP_MP3STREAM pSFX_MP3Stream, void *pvSourceData, int iSourceBytesRemaining, + int iGameAudioSampleRate, int iGameAudioSampleBits, int bStereoDesired); +unsigned int C_MP3Stream_Decode( LP_MP3STREAM pSFX_MP3Stream, int bFastForwarding ); +char* C_MP3Stream_Rewind (LP_MP3STREAM pSFX_MP3Stream); + + +#ifdef __cplusplus +} +#endif +// +/////////////////////////////////////// + + +///////////////// eof ///////////////////// diff --git a/Projects/Android/jni/OpenJK/codemp/client/snd_music.cpp b/Projects/Android/jni/OpenJK/codemp_delete/client/snd_music.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/snd_music.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/client/snd_music.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/client/snd_music.h b/Projects/Android/jni/OpenJK/codemp_delete/client/snd_music.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/snd_music.h rename to Projects/Android/jni/OpenJK/codemp_delete/client/snd_music.h diff --git a/Projects/Android/jni/OpenJK/codemp/client/snd_public.h b/Projects/Android/jni/OpenJK/codemp_delete/client/snd_public.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/client/snd_public.h rename to Projects/Android/jni/OpenJK/codemp_delete/client/snd_public.h diff --git a/Projects/Android/jni/OpenJK/codemp/game/AnimalNPC.c b/Projects/Android/jni/OpenJK/codemp_delete/game/AnimalNPC.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/AnimalNPC.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/AnimalNPC.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/CMakeLists.txt b/Projects/Android/jni/OpenJK/codemp_delete/game/CMakeLists.txt similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/CMakeLists.txt rename to Projects/Android/jni/OpenJK/codemp_delete/game/CMakeLists.txt diff --git a/Projects/Android/jni/OpenJK/codemp/game/FighterNPC.c b/Projects/Android/jni/OpenJK/codemp_delete/game/FighterNPC.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/FighterNPC.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/FighterNPC.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Atst.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Atst.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Atst.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Atst.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Default.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Default.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Default.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Default.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Droid.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Droid.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Droid.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Droid.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_AI_GalakMech.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_GalakMech.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_AI_GalakMech.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_GalakMech.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Grenadier.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Grenadier.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Grenadier.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Grenadier.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Howler.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Howler.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Howler.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Howler.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_AI_ImperialProbe.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_ImperialProbe.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_AI_ImperialProbe.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_ImperialProbe.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Interrogator.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Interrogator.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Interrogator.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Interrogator.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Jedi.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Jedi.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Jedi.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Jedi.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Mark1.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Mark1.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Mark1.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Mark1.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Mark2.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Mark2.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Mark2.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Mark2.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_AI_MineMonster.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_MineMonster.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_AI_MineMonster.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_MineMonster.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Rancor.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Rancor.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Rancor.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Rancor.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Remote.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Remote.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Remote.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Remote.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Seeker.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Seeker.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Seeker.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Seeker.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Sentry.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Sentry.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Sentry.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Sentry.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Sniper.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Sniper.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Sniper.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Sniper.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Stormtrooper.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Stormtrooper.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Stormtrooper.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Stormtrooper.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Utils.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Utils.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Utils.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Utils.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Wampa.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Wampa.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_AI_Wampa.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_AI_Wampa.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_behavior.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_behavior.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_behavior.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_behavior.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_combat.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_combat.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_combat.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_combat.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_goal.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_goal.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_goal.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_goal.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_misc.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_misc.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_misc.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_misc.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_move.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_move.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_move.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_move.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_reactions.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_reactions.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_reactions.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_reactions.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_senses.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_senses.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_senses.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_senses.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_sounds.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_sounds.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_sounds.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_sounds.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_spawn.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_spawn.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_spawn.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_spawn.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_stats.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_stats.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_stats.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_stats.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/NPC_utils.c b/Projects/Android/jni/OpenJK/codemp_delete/game/NPC_utils.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/NPC_utils.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/NPC_utils.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/SpeederNPC.c b/Projects/Android/jni/OpenJK/codemp_delete/game/SpeederNPC.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/SpeederNPC.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/SpeederNPC.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/WalkerNPC.c b/Projects/Android/jni/OpenJK/codemp_delete/game/WalkerNPC.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/WalkerNPC.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/WalkerNPC.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/ai.h b/Projects/Android/jni/OpenJK/codemp_delete/game/ai.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/ai.h rename to Projects/Android/jni/OpenJK/codemp_delete/game/ai.h diff --git a/Projects/Android/jni/OpenJK/codemp/game/ai_main.c b/Projects/Android/jni/OpenJK/codemp_delete/game/ai_main.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/ai_main.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/ai_main.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/ai_main.h b/Projects/Android/jni/OpenJK/codemp_delete/game/ai_main.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/ai_main.h rename to Projects/Android/jni/OpenJK/codemp_delete/game/ai_main.h diff --git a/Projects/Android/jni/OpenJK/codemp/game/ai_util.c b/Projects/Android/jni/OpenJK/codemp_delete/game/ai_util.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/ai_util.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/ai_util.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/ai_wpnav.c b/Projects/Android/jni/OpenJK/codemp_delete/game/ai_wpnav.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/ai_wpnav.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/ai_wpnav.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/anims.h b/Projects/Android/jni/OpenJK/codemp_delete/game/anims.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/anims.h rename to Projects/Android/jni/OpenJK/codemp_delete/game/anims.h diff --git a/Projects/Android/jni/OpenJK/codemp/game/b_local.h b/Projects/Android/jni/OpenJK/codemp_delete/game/b_local.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/b_local.h rename to Projects/Android/jni/OpenJK/codemp_delete/game/b_local.h diff --git a/Projects/Android/jni/OpenJK/codemp/game/b_public.h b/Projects/Android/jni/OpenJK/codemp_delete/game/b_public.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/b_public.h rename to Projects/Android/jni/OpenJK/codemp_delete/game/b_public.h diff --git a/Projects/Android/jni/OpenJK/codemp/game/bg_g2_utils.c b/Projects/Android/jni/OpenJK/codemp_delete/game/bg_g2_utils.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/bg_g2_utils.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/bg_g2_utils.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/bg_local.h b/Projects/Android/jni/OpenJK/codemp_delete/game/bg_local.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/bg_local.h rename to Projects/Android/jni/OpenJK/codemp_delete/game/bg_local.h diff --git a/Projects/Android/jni/OpenJK/codemp/game/bg_misc.c b/Projects/Android/jni/OpenJK/codemp_delete/game/bg_misc.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/bg_misc.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/bg_misc.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/bg_panimate.c b/Projects/Android/jni/OpenJK/codemp_delete/game/bg_panimate.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/bg_panimate.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/bg_panimate.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/bg_pmove.c b/Projects/Android/jni/OpenJK/codemp_delete/game/bg_pmove.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/bg_pmove.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/bg_pmove.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/bg_public.h b/Projects/Android/jni/OpenJK/codemp_delete/game/bg_public.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/bg_public.h rename to Projects/Android/jni/OpenJK/codemp_delete/game/bg_public.h diff --git a/Projects/Android/jni/OpenJK/codemp/game/bg_saber.c b/Projects/Android/jni/OpenJK/codemp_delete/game/bg_saber.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/bg_saber.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/bg_saber.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/bg_saberLoad.c b/Projects/Android/jni/OpenJK/codemp_delete/game/bg_saberLoad.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/bg_saberLoad.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/bg_saberLoad.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/bg_saga.c b/Projects/Android/jni/OpenJK/codemp_delete/game/bg_saga.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/bg_saga.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/bg_saga.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/bg_saga.h b/Projects/Android/jni/OpenJK/codemp_delete/game/bg_saga.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/bg_saga.h rename to Projects/Android/jni/OpenJK/codemp_delete/game/bg_saga.h diff --git a/Projects/Android/jni/OpenJK/codemp/game/bg_slidemove.c b/Projects/Android/jni/OpenJK/codemp_delete/game/bg_slidemove.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/bg_slidemove.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/bg_slidemove.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/bg_vehicleLoad.c b/Projects/Android/jni/OpenJK/codemp_delete/game/bg_vehicleLoad.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/bg_vehicleLoad.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/bg_vehicleLoad.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/bg_vehicles.h b/Projects/Android/jni/OpenJK/codemp_delete/game/bg_vehicles.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/bg_vehicles.h rename to Projects/Android/jni/OpenJK/codemp_delete/game/bg_vehicles.h diff --git a/Projects/Android/jni/OpenJK/codemp/game/bg_weapons.c b/Projects/Android/jni/OpenJK/codemp_delete/game/bg_weapons.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/bg_weapons.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/bg_weapons.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/bg_weapons.h b/Projects/Android/jni/OpenJK/codemp_delete/game/bg_weapons.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/bg_weapons.h rename to Projects/Android/jni/OpenJK/codemp_delete/game/bg_weapons.h diff --git a/Projects/Android/jni/OpenJK/codemp/game/chars.h b/Projects/Android/jni/OpenJK/codemp_delete/game/chars.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/chars.h rename to Projects/Android/jni/OpenJK/codemp_delete/game/chars.h diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_ICARUScb.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_ICARUScb.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_ICARUScb.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_ICARUScb.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_ICARUScb.h b/Projects/Android/jni/OpenJK/codemp_delete/game/g_ICARUScb.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_ICARUScb.h rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_ICARUScb.h diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_active.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_active.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_active.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_active.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_bot.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_bot.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_bot.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_bot.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_client.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_client.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_client.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_client.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_cmds.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_cmds.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_cmds.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_cmds.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_combat.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_combat.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_combat.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_combat.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_cvar.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_cvar.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_cvar.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_cvar.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_exphysics.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_exphysics.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_exphysics.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_exphysics.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_items.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_items.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_items.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_items.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_local.h b/Projects/Android/jni/OpenJK/codemp_delete/game/g_local.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_local.h rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_local.h diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_log.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_log.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_log.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_log.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_main.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_main.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_main.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_main.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_mem.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_mem.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_mem.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_mem.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_misc.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_misc.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_misc.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_misc.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_missile.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_missile.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_missile.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_missile.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_mover.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_mover.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_mover.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_mover.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_nav.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_nav.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_nav.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_nav.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_nav.h b/Projects/Android/jni/OpenJK/codemp_delete/game/g_nav.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_nav.h rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_nav.h diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_navnew.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_navnew.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_navnew.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_navnew.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_object.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_object.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_object.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_object.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_public.h b/Projects/Android/jni/OpenJK/codemp_delete/game/g_public.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_public.h rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_public.h diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_saga.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_saga.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_saga.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_saga.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_session.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_session.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_session.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_session.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_spawn.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_spawn.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_spawn.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_spawn.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_svcmds.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_svcmds.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_svcmds.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_svcmds.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_syscalls.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_syscalls.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_syscalls.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_syscalls.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_target.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_target.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_target.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_target.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_team.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_team.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_team.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_team.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_team.h b/Projects/Android/jni/OpenJK/codemp_delete/game/g_team.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_team.h rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_team.h diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_timer.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_timer.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_timer.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_timer.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_trigger.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_trigger.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_trigger.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_trigger.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_turret.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_turret.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_turret.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_turret.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_turret_G2.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_turret_G2.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_turret_G2.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_turret_G2.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_utils.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_utils.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_utils.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_utils.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_vehicleTurret.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_vehicleTurret.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_vehicleTurret.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_vehicleTurret.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_vehicles.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_vehicles.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_vehicles.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_vehicles.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_weapon.c b/Projects/Android/jni/OpenJK/codemp_delete/game/g_weapon.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_weapon.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_weapon.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/g_xcvar.h b/Projects/Android/jni/OpenJK/codemp_delete/game/g_xcvar.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/g_xcvar.h rename to Projects/Android/jni/OpenJK/codemp_delete/game/g_xcvar.h diff --git a/Projects/Android/jni/OpenJK/codemp/game/inv.h b/Projects/Android/jni/OpenJK/codemp_delete/game/inv.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/inv.h rename to Projects/Android/jni/OpenJK/codemp_delete/game/inv.h diff --git a/Projects/Android/jni/OpenJK/codemp/game/match.h b/Projects/Android/jni/OpenJK/codemp_delete/game/match.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/match.h rename to Projects/Android/jni/OpenJK/codemp_delete/game/match.h diff --git a/Projects/Android/jni/OpenJK/codemp/game/npc_headers.h b/Projects/Android/jni/OpenJK/codemp_delete/game/npc_headers.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/npc_headers.h rename to Projects/Android/jni/OpenJK/codemp_delete/game/npc_headers.h diff --git a/Projects/Android/jni/OpenJK/codemp/game/say.h b/Projects/Android/jni/OpenJK/codemp_delete/game/say.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/say.h rename to Projects/Android/jni/OpenJK/codemp_delete/game/say.h diff --git a/Projects/Android/jni/OpenJK/codemp/game/surfaceflags.h b/Projects/Android/jni/OpenJK/codemp_delete/game/surfaceflags.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/surfaceflags.h rename to Projects/Android/jni/OpenJK/codemp_delete/game/surfaceflags.h diff --git a/Projects/Android/jni/OpenJK/codemp/game/teams.h b/Projects/Android/jni/OpenJK/codemp_delete/game/teams.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/teams.h rename to Projects/Android/jni/OpenJK/codemp_delete/game/teams.h diff --git a/Projects/Android/jni/OpenJK/codemp/game/tri_coll_test.c b/Projects/Android/jni/OpenJK/codemp_delete/game/tri_coll_test.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/tri_coll_test.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/tri_coll_test.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/w_force.c b/Projects/Android/jni/OpenJK/codemp_delete/game/w_force.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/w_force.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/w_force.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/w_saber.c b/Projects/Android/jni/OpenJK/codemp_delete/game/w_saber.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/w_saber.c rename to Projects/Android/jni/OpenJK/codemp_delete/game/w_saber.c diff --git a/Projects/Android/jni/OpenJK/codemp/game/w_saber.h b/Projects/Android/jni/OpenJK/codemp_delete/game/w_saber.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/game/w_saber.h rename to Projects/Android/jni/OpenJK/codemp_delete/game/w_saber.h diff --git a/Projects/Android/jni/OpenJK/codemp/ghoul2/G2.h b/Projects/Android/jni/OpenJK/codemp_delete/ghoul2/G2.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/ghoul2/G2.h rename to Projects/Android/jni/OpenJK/codemp_delete/ghoul2/G2.h diff --git a/Projects/Android/jni/OpenJK/codemp_delete/ghoul2/G2_gore.cpp b/Projects/Android/jni/OpenJK/codemp_delete/ghoul2/G2_gore.cpp new file mode 100644 index 0000000..f821093 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/ghoul2/G2_gore.cpp @@ -0,0 +1,41 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#include "G2_gore.h" +#include "../rd-common/tr_common.h" + +GoreTextureCoordinates::GoreTextureCoordinates() +{ + Com_Memset (tex, 0, sizeof (tex)); +} + +GoreTextureCoordinates::~GoreTextureCoordinates() +{ + for ( int i = 0; i < MAX_LODS; i++ ) + { + if ( tex[i] ) + { + ri.Z_Free(tex[i]); + tex[i] = NULL; + } + } +} diff --git a/Projects/Android/jni/OpenJK/codemp_delete/ghoul2/G2_gore.h b/Projects/Android/jni/OpenJK/codemp_delete/ghoul2/G2_gore.h new file mode 100644 index 0000000..613ed0a --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/ghoul2/G2_gore.h @@ -0,0 +1,196 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#pragma once + +#include "../ghoul2/ghoul2_shared.h" +#include "../qcommon/q_shared.h" + +#ifdef _G2_GORE + +#define MAX_LODS (8) +struct GoreTextureCoordinates +{ + float *tex[MAX_LODS]; + + GoreTextureCoordinates(); + ~GoreTextureCoordinates(); +}; + +int AllocGoreRecord(); +GoreTextureCoordinates *FindGoreRecord(int tag); +void DeleteGoreRecord(int tag); + +struct SGoreSurface +{ + int shader; + int mGoreTag; + int mDeleteTime; + int mFadeTime; + bool mFadeRGB; + + int mGoreGrowStartTime; + int mGoreGrowEndTime; // set this to -1 to disable growing + //curscale = (curtime-mGoreGrowStartTime)*mGoreGrowFactor + mGoreGrowOffset; + float mGoreGrowFactor; + float mGoreGrowOffset; +}; + +class CGoreSet +{ +public: + int mMyGoreSetTag; + unsigned char mRefCount; + std::multimap mGoreRecords; // a map from surface index + CGoreSet(int tag) : mMyGoreSetTag(tag), mRefCount(0) {} + ~CGoreSet(); +}; + +CGoreSet *FindGoreSet(int goreSetTag); +CGoreSet *NewGoreSet(); +void DeleteGoreSet(int goreSetTag); + +#endif // _G2_GORE + +//rww - RAGDOLL_BEGIN + +/// ragdoll stuff +struct SRagDollEffectorCollision +{ + vec3_t effectorPosition; + const trace_t &tr; + bool useTracePlane; + SRagDollEffectorCollision(const vec3_t effectorPos,const trace_t &t) : + tr(t), + useTracePlane(false) + { + VectorCopy(effectorPos,effectorPosition); + } +}; + +class CRagDollUpdateParams +{ +public: + vec3_t angles; + vec3_t position; + vec3_t scale; + vec3_t velocity; + //CServerEntity *me; + int me; //index! + int settleFrame; + + //at some point I'll want to make VM callbacks in here. For now I am just doing nothing. + virtual void EffectorCollision(const SRagDollEffectorCollision &data) + { + // assert(0); // you probably meant to override this + } + virtual void RagDollBegin() + { + // assert(0); // you probably meant to override this + } + virtual void RagDollSettled() + { + // assert(0); // you probably meant to override this + } + + virtual void Collision() + { + // assert(0); // you probably meant to override this + // we had a collision, uhh I guess call SetRagDoll RP_DEATH_COLLISION + } + +#ifdef _DEBUG + virtual void DebugLine(const vec3_t p1,const vec3_t p2,bool bbox) {assert(0);} +#endif +}; + + +class CRagDollParams +{ +public: + + enum ERagPhase + { + RP_START_DEATH_ANIM, + RP_END_DEATH_ANIM, + RP_DEATH_COLLISION, + RP_CORPSE_SHOT, + RP_GET_PELVIS_OFFSET, // this actually does nothing but set the pelvisAnglesOffset, and pelvisPositionOffset + RP_SET_PELVIS_OFFSET, // this actually does nothing but set the pelvisAnglesOffset, and pelvisPositionOffset + RP_DISABLE_EFFECTORS // this removes effectors given by the effectorsToTurnOff member + }; + vec3_t angles; + vec3_t position; + vec3_t scale; + vec3_t pelvisAnglesOffset; // always set on return, an argument for RP_SET_PELVIS_OFFSET + vec3_t pelvisPositionOffset; // always set on return, an argument for RP_SET_PELVIS_OFFSET + + float fImpactStrength; //should be applicable when RagPhase is RP_DEATH_COLLISION + float fShotStrength; //should be applicable for setting velocity of corpse on shot (probably only on RP_CORPSE_SHOT) + //CServerEntity *me; + int me; + + //rww - we have convenient animation/frame access in the game, so just send this info over from there. + int startFrame; + int endFrame; + + int collisionType; // 1 = from a fall, 0 from effectors, this will be going away soon, hence no enum + + qboolean CallRagDollBegin; // a return value, means that we are now begininng ragdoll and the NPC stuff needs to happen + + ERagPhase RagPhase; + +// effector control, used for RP_DISABLE_EFFECTORS call + + enum ERagEffector + { + RE_MODEL_ROOT= 0x00000001, //"model_root" + RE_PELVIS= 0x00000002, //"pelvis" + RE_LOWER_LUMBAR= 0x00000004, //"lower_lumbar" + RE_UPPER_LUMBAR= 0x00000008, //"upper_lumbar" + RE_THORACIC= 0x00000010, //"thoracic" + RE_CRANIUM= 0x00000020, //"cranium" + RE_RHUMEROUS= 0x00000040, //"rhumerus" + RE_LHUMEROUS= 0x00000080, //"lhumerus" + RE_RRADIUS= 0x00000100, //"rradius" + RE_LRADIUS= 0x00000200, //"lradius" + RE_RFEMURYZ= 0x00000400, //"rfemurYZ" + RE_LFEMURYZ= 0x00000800, //"lfemurYZ" + RE_RTIBIA= 0x00001000, //"rtibia" + RE_LTIBIA= 0x00002000, //"ltibia" + RE_RHAND= 0x00004000, //"rhand" + RE_LHAND= 0x00008000, //"lhand" + RE_RTARSAL= 0x00010000, //"rtarsal" + RE_LTARSAL= 0x00020000, //"ltarsal" + RE_RTALUS= 0x00040000, //"rtalus" + RE_LTALUS= 0x00080000, //"ltalus" + RE_RRADIUSX= 0x00100000, //"rradiusX" + RE_LRADIUSX= 0x00200000, //"lradiusX" + RE_RFEMURX= 0x00400000, //"rfemurX" + RE_LFEMURX= 0x00800000, //"lfemurX" + RE_CEYEBROW= 0x01000000 //"ceyebrow" + }; + + ERagEffector effectorsToTurnOff; // set this to an | of the above flags for a RP_DISABLE_EFFECTORS + +}; +//rww - RAGDOLL_END diff --git a/Projects/Android/jni/OpenJK/codemp_delete/ghoul2/g2_local.h b/Projects/Android/jni/OpenJK/codemp_delete/ghoul2/g2_local.h new file mode 100644 index 0000000..ac8e675 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/ghoul2/g2_local.h @@ -0,0 +1,380 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#pragma once + +// defines to setup the + +#include "ghoul2/ghoul2_shared.h" + +//rww - RAGDOLL_BEGIN +class CRagDollUpdateParams; +//rww - RAGDOLL_END + +class IHeapAllocator; + +#define GHOUL2_CRAZY_SMOOTH 0x2000 //hack for smoothing during ugly situations. forgive me. + +class IGhoul2InfoArray +{ +public: + virtual ~IGhoul2InfoArray() {} + + virtual int New()=0; + virtual void Delete(int handle)=0; + virtual bool IsValid(int handle) const=0; + virtual std::vector &Get(int handle)=0; + virtual const std::vector &Get(int handle) const=0; +}; + +IGhoul2InfoArray &TheGhoul2InfoArray(); +class CGhoul2Info_v +{ + IGhoul2InfoArray &InfoArray() const + { + return TheGhoul2InfoArray(); + } + + void Alloc() + { + assert(!mItem); //already alloced + mItem=InfoArray().New(); + assert(!Array().size()); + } + void Free() + { + if (mItem) + { + assert(InfoArray().IsValid(mItem)); + InfoArray().Delete(mItem); + mItem=0; + } + } + std::vector &Array() + { + assert(InfoArray().IsValid(mItem)); + return InfoArray().Get(mItem); + } + const std::vector &Array() const + { + assert(InfoArray().IsValid(mItem)); + return InfoArray().Get(mItem); + } +public: + int mItem; //dont' be bad and muck with this + CGhoul2Info_v() + { + mItem=0; + } + CGhoul2Info_v(const int item) + { //be VERY carefull with what you pass in here + mItem=item; + } + ~CGhoul2Info_v() + { + Free(); //this had better be taken care of via the clean ghoul2 models call + } + void operator=(const CGhoul2Info_v &other) + { + mItem=other.mItem; + } + void operator=(const int otherItem) //assigning one from the VM side item number + { + mItem=otherItem; + } + void DeepCopy(const CGhoul2Info_v &other) + { + Free(); + if (other.mItem) + { + Alloc(); + Array()=other.Array(); + int i; + for (i=0;i= 0 && idx < size()); + + return Array()[idx]; + } + const CGhoul2Info &operator[](int idx) const + { + assert (mItem); + assert (idx >= 0 && idx < size()); + + return Array()[idx]; + } + void resize(int num) + { + assert(num>=0); + if (num) + { + if (!mItem) + { + Alloc(); + } + } + if (mItem||num) + { + Array().resize(num); + } + } + void clear() + { + Free(); + } + void push_back(const CGhoul2Info &model) + { + if (!mItem) + { + Alloc(); + } + Array().push_back(model); + } + int size() const + { + if (!IsValid()) + { + return 0; + } + return Array().size(); + } + bool IsValid() const + { + return InfoArray().IsValid(mItem); + } + void kill() + { + // this scary method zeros the infovector handle without actually freeing it + // it is used for some places where a copy is made, but we don't want to go through the trouble + // of making a deep copy + mItem=0; + } +}; + +void Create_Matrix(const float *angle, mdxaBone_t *matrix); + +extern mdxaBone_t worldMatrix; +extern mdxaBone_t worldMatrixInv; + +// internal surface calls G2_surfaces.cpp +qboolean G2_SetSurfaceOnOff (CGhoul2Info *ghlInfo, surfaceInfo_v &slist, const char *surfaceName, const int offFlags); +int G2_IsSurfaceOff (CGhoul2Info *ghlInfo, surfaceInfo_v &slist, const char *surfaceName); +qboolean G2_SetRootSurface( CGhoul2Info_v &ghoul2, const int modelIndex, const char *surfaceName); +int G2_AddSurface(CGhoul2Info *ghoul2, int surfaceNumber, int polyNumber, float BarycentricI, float BarycentricJ, int lod ); +qboolean G2_RemoveSurface(surfaceInfo_v &slist, const int index); +surfaceInfo_t *G2_FindOverrideSurface(int surfaceNum, surfaceInfo_v &surfaceList); +int G2_IsSurfaceLegal(void *mod, const char *surfaceName, int *flags); +int G2_GetParentSurface(CGhoul2Info *ghlInfo, const int index); +int G2_GetSurfaceIndex(CGhoul2Info *ghlInfo, const char *surfaceName); +int G2_IsSurfaceRendered(CGhoul2Info *ghlInfo, const char *surfaceName, surfaceInfo_v &slist); + +// internal bone calls - G2_Bones.cpp +qboolean G2_Set_Bone_Angles(CGhoul2Info *ghlInfo, boneInfo_v &blist, const char *boneName, const float *angles, const int flags, const Eorientations up, const Eorientations left, const Eorientations forward, qhandle_t *modelList, const int modelIndex, const int blendTime, const int currentTime); +qboolean G2_Remove_Bone (CGhoul2Info *ghlInfo, boneInfo_v &blist, const char *boneName); +qboolean G2_Set_Bone_Anim(CGhoul2Info *ghlInfo, boneInfo_v &blist, const char *boneName, const int startFrame, const int endFrame, const int flags, const float animSpeed, const int currentTime, const float setFrame, const int blendTime); +qboolean G2_Get_Bone_Anim(CGhoul2Info *ghlInfo, boneInfo_v &blist, const char *boneName, const int currentTime, float *currentFrame, int *startFrame, int *endFrame, int *flags, float *retAnimSpeed, qhandle_t *modelList, int modelIndex); +qboolean G2_Get_Bone_Anim_Range(CGhoul2Info *ghlInfo, boneInfo_v &blist, const char *boneName, int *startFrame, int *endFrame); +qboolean G2_Pause_Bone_Anim(CGhoul2Info *ghlInfo, boneInfo_v &blist, const char *boneName, const int currentTime ); +qboolean G2_IsPaused(const char *fileName, boneInfo_v &blist, const char *boneName); +qboolean G2_Stop_Bone_Anim(const char *fileName, boneInfo_v &blist, const char *boneName); +qboolean G2_Stop_Bone_Angles(const char *fileName, boneInfo_v &blist, const char *boneName); +//rww - RAGDOLL_BEGIN +void G2_Animate_Bone_List(CGhoul2Info_v &ghoul2, const int currentTime, const int index,CRagDollUpdateParams *params); +//rww - RAGDOLL_END +void G2_Init_Bone_List(boneInfo_v &blist, int numBones); +int G2_Find_Bone_In_List(boneInfo_v &blist, const int boneNum); +void G2_RemoveRedundantBoneOverrides(boneInfo_v &blist, int *activeBones); +qboolean G2_Set_Bone_Angles_Matrix(const char *fileName, boneInfo_v &blist, const char *boneName, const mdxaBone_t &matrix, const int flags, qhandle_t *modelList, const int modelIndex, const int blendTime, const int currentTime); +int G2_Get_Bone_Index(CGhoul2Info *ghoul2, const char *boneName); +qboolean G2_Set_Bone_Angles_Index(boneInfo_v &blist, const int index, const float *angles, const int flags, const Eorientations yaw, const Eorientations pitch, const Eorientations roll, qhandle_t *modelList, const int modelIndex, const int blendTime, const int currentTime); +qboolean G2_Set_Bone_Angles_Matrix_Index(boneInfo_v &blist, const int index, const mdxaBone_t &matrix, const int flags, qhandle_t *modelList, const int modelIndex, const int blendTime, const int currentTime); +qboolean G2_Stop_Bone_Anim_Index(boneInfo_v &blist, const int index); +qboolean G2_Stop_Bone_Angles_Index(boneInfo_v &blist, const int index); +qboolean G2_Set_Bone_Anim_Index(boneInfo_v &blist, const int index, const int startFrame, const int endFrame, const int flags, const float animSpeed, const int currentTime, const float setFrame, const int blendTime, const int numFrames); +qboolean G2_Get_Bone_Anim_Index( boneInfo_v &blist, const int index, const int currentTime, float *currentFrame, int *startFrame, int *endFrame, int *flags, float *retAnimSpeed, qhandle_t *modelList, int modelIndex); + +// misc functions G2_misc.cpp +void G2_List_Model_Surfaces(const char *fileName); +void G2_List_Model_Bones(const char *fileName, int frame); +qboolean G2_GetAnimFileName(const char *fileName, char **filename); +#ifdef _G2_GORE +void G2_TraceModels(CGhoul2Info_v &ghoul2, vec3_t rayStart, vec3_t rayEnd, CollisionRecord_t *collRecMap, int entNum, int traceFlags, int useLod, float fRadius, float ssize,float tsize,float theta,int shader, SSkinGoreData *gore, qboolean skipIfLODNotMatch); +#else +void G2_TraceModels(CGhoul2Info_v &ghoul2, vec3_t rayStart, vec3_t rayEnd, CollisionRecord_t *collRecMap, int entNum, int traceFlags, int useLod, float fRadius); +#endif +void TransformAndTranslatePoint (const vec3_t in, vec3_t out, mdxaBone_t *mat); +#ifdef _G2_GORE +void G2_TransformModel(CGhoul2Info_v &ghoul2, const int frameNum, vec3_t scale, IHeapAllocator *G2VertSpace, int useLod, bool ApplyGore); +#else +void G2_TransformModel(CGhoul2Info_v &ghoul2, const int frameNum, vec3_t scale, IHeapAllocator *G2VertSpace, int useLod); +#endif +void G2_GenerateWorldMatrix(const vec3_t angles, const vec3_t origin); +void TransformPoint (const vec3_t in, vec3_t out, mdxaBone_t *mat); +void Inverse_Matrix(mdxaBone_t *src, mdxaBone_t *dest); +void *G2_FindSurface(void *mod, int index, int lod); +qboolean G2_SaveGhoul2Models(CGhoul2Info_v &ghoul2, char **buffer, int *size); +void G2_LoadGhoul2Model(CGhoul2Info_v &ghoul2, char *buffer); + +// internal bolt calls. G2_bolts.cpp +int G2_Add_Bolt(CGhoul2Info *ghlInfo, boltInfo_v &bltlist, surfaceInfo_v &slist, const char *boneName); +qboolean G2_Remove_Bolt (boltInfo_v &bltlist, int index); +void G2_Init_Bolt_List(boltInfo_v &bltlist); +int G2_Find_Bolt_Bone_Num(boltInfo_v &bltlist, const int boneNum); +int G2_Find_Bolt_Surface_Num(boltInfo_v &bltlist, const int surfaceNum, const int flags); +int G2_Add_Bolt_Surf_Num(CGhoul2Info *ghlInfo, boltInfo_v &bltlist, surfaceInfo_v &slist, const int surfNum); +void G2_RemoveRedundantBolts(boltInfo_v &bltlist, surfaceInfo_v &slist, int *activeSurfaces, int *activeBones); + + +// API calls - G2_API.cpp +void RestoreGhoul2InfoArray(); +void SaveGhoul2InfoArray(); + +void G2API_SetTime(int currentTime, int clock); +int G2API_GetTime(int argTime); + +qhandle_t G2API_PrecacheGhoul2Model(const char *fileName); + +qboolean G2API_IsGhoul2InfovValid (CGhoul2Info_v& ghoul2); +int G2API_InitGhoul2Model(CGhoul2Info_v **ghoul2Ptr, const char *fileName, int modelIndex, qhandle_t customSkin = NULL_HANDLE, qhandle_t customShader = NULL_HANDLE, int modelFlags = 0, int lodBias = 0); +qboolean G2API_SetLodBias(CGhoul2Info *ghlInfo, int lodBias); +qboolean G2API_SetSkin(CGhoul2Info_v& ghoul2, int modelIndex, qhandle_t customSkin, qhandle_t renderSkin); +qboolean G2API_SetShader(CGhoul2Info *ghlInfo, qhandle_t customShader); +qboolean G2API_HasGhoul2ModelOnIndex(CGhoul2Info_v **ghlRemove, const int modelIndex); +qboolean G2API_RemoveGhoul2Model(CGhoul2Info_v **ghlRemove, const int modelIndex); +qboolean G2API_RemoveGhoul2Models(CGhoul2Info_v **ghlRemove); +qboolean G2API_SetSurfaceOnOff(CGhoul2Info_v &ghoul2, const char *surfaceName, const int flags); +int G2API_GetSurfaceOnOff(CGhoul2Info *ghlInfo, const char *surfaceName); +qboolean G2API_SetRootSurface(CGhoul2Info_v &ghoul2, const int modelIndex, const char *surfaceName); +qboolean G2API_RemoveSurface(CGhoul2Info *ghlInfo, const int index); +int G2API_AddSurface(CGhoul2Info *ghlInfo, int surfaceNumber, int polyNumber, float BarycentricI, float BarycentricJ, int lod ); +qboolean G2API_SetBoneAnim(CGhoul2Info_v &ghoul2, const int modelIndex, const char *boneName, const int startFrame, const int endFrame, const int flags, const float animSpeed, const int currentTime, const float setFrame = -1, const int blendTime = -1); +qboolean G2API_GetBoneAnim(CGhoul2Info_v& ghoul2, int modelIndex, const char *boneName, const int currentTime, float *currentFrame, int *startFrame, int *endFrame, int *flags, float *animSpeed, qhandle_t *modelList); +qboolean G2API_GetAnimRange(CGhoul2Info *ghlInfo, const char *boneName, int *startFrame, int *endFrame); +qboolean G2API_PauseBoneAnim(CGhoul2Info *ghlInfo, const char *boneName, const int currentTime); +qboolean G2API_IsPaused(CGhoul2Info *ghlInfo, const char *boneName); +qboolean G2API_StopBoneAnim(CGhoul2Info *ghlInfo, const char *boneName); + + +qboolean G2API_SetBoneAngles(CGhoul2Info_v &ghoul2, const int modelIndex, const char *boneName, const vec3_t angles, const int flags, const Eorientations up, const Eorientations left, const Eorientations forward, qhandle_t *modelList, int blendTime, int currentTime ); + +qboolean G2API_StopBoneAngles(CGhoul2Info *ghlInfo, const char *boneName); +qboolean G2API_RemoveBone(CGhoul2Info_v& ghoul2, int modelIndex, const char *boneName); +void G2API_AnimateG2Models(CGhoul2Info_v &ghoul2, float speedVar); +qboolean G2API_RemoveBolt(CGhoul2Info *ghlInfo, const int index); +int G2API_AddBolt(CGhoul2Info_v &ghoul2, const int modelIndex, const char *boneName); +int G2API_AddBoltSurfNum(CGhoul2Info *ghlInfo, const int surfIndex); +void G2API_SetBoltInfo(CGhoul2Info_v &ghoul2, int modelIndex, int boltInfo); +qboolean G2API_AttachG2Model(CGhoul2Info_v &ghoul2From, int modelFrom, CGhoul2Info_v &ghoul2To, int toBoltIndex, int toModel); +qboolean G2API_DetachG2Model(CGhoul2Info *ghlInfo); +qboolean G2API_AttachEnt(int *boltInfo, CGhoul2Info_v& ghoul2, int modelIndex, int toBoltIndex, int entNum, int toModelNum); +void G2API_DetachEnt(int *boltInfo); + +qboolean G2API_GetBoltMatrix(CGhoul2Info_v &ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale); + +void G2API_ListSurfaces(CGhoul2Info *ghlInfo); +void G2API_ListBones(CGhoul2Info *ghlInfo, int frame); +qboolean G2API_HaveWeGhoul2Models(CGhoul2Info_v &ghoul2); +void G2API_SetGhoul2ModelIndexes(CGhoul2Info_v &ghoul2, qhandle_t *modelList, qhandle_t *skinList); +qboolean G2API_SetGhoul2ModelFlags(CGhoul2Info *ghlInfo, const int flags); +int G2API_GetGhoul2ModelFlags(CGhoul2Info *ghlInfo); + +qboolean G2API_GetAnimFileName(CGhoul2Info *ghlInfo, char **filename); +void G2API_CollisionDetect(CollisionRecord_t *collRecMap, CGhoul2Info_v &ghoul2, const vec3_t angles, const vec3_t position, int frameNumber, int entNum, vec3_t rayStart, vec3_t rayEnd, vec3_t scale, IHeapAllocator *G2VertSpace, int traceFlags, int useLod, float fRadius); +void G2API_CollisionDetectCache(CollisionRecord_t *collRecMap, CGhoul2Info_v &ghoul2, const vec3_t angles, const vec3_t position, int frameNumber, int entNum, vec3_t rayStart, vec3_t rayEnd, vec3_t scale, IHeapAllocator *G2VertSpace, int traceFlags, int useLod, float fRadius); + +void G2API_GiveMeVectorFromMatrix(mdxaBone_t *boltMatrix, Eorientations flags, vec3_t vec); +int G2API_CopyGhoul2Instance(CGhoul2Info_v &g2From, CGhoul2Info_v &g2To, int modelIndex); +void G2API_CleanGhoul2Models(CGhoul2Info_v **ghoul2Ptr); +int G2API_GetParentSurface(CGhoul2Info *ghlInfo, const int index); +int G2API_GetSurfaceIndex(CGhoul2Info *ghlInfo, const char *surfaceName); +char *G2API_GetSurfaceName(CGhoul2Info_v& ghoul2, int modelIndex, int surfNumber); +char *G2API_GetGLAName(CGhoul2Info_v &ghoul2, int modelIndex); +qboolean G2API_SetBoneAnglesMatrix(CGhoul2Info *ghlInfo, const char *boneName, const mdxaBone_t &matrix, const int flags, qhandle_t *modelList, int blendTime = 0, int currentTime = 0); +qboolean G2API_SetNewOrigin(CGhoul2Info_v &ghoul2, const int boltIndex); +int G2API_GetBoneIndex(CGhoul2Info *ghlInfo, const char *boneName); +qboolean G2API_StopBoneAnglesIndex(CGhoul2Info *ghlInfo, const int index); +qboolean G2API_StopBoneAnimIndex(CGhoul2Info *ghlInfo, const int index); +qboolean G2API_SetBoneAnglesIndex( CGhoul2Info *ghlInfo, const int index, const vec3_t angles, const int flags, const Eorientations yaw, const Eorientations pitch, const Eorientations roll, qhandle_t *modelList, int blendTime, int currentTime ); +qboolean G2API_SetBoneAnglesMatrixIndex(CGhoul2Info *ghlInfo, const int index, const mdxaBone_t &matrix, const int flags, qhandle_t *modelList, int blendTime, int currentTime); +qboolean G2API_DoesBoneExist(CGhoul2Info_v& ghoul2, int modelIndex, const char *boneName); +qboolean G2API_SetBoneAnimIndex(CGhoul2Info *ghlInfo, const int index, const int startFrame, const int endFrame, const int flags, const float animSpeed, const int currentTime, const float setFrame, const int blendTime); +qboolean G2API_SaveGhoul2Models(CGhoul2Info_v &ghoul2, char **buffer, int *size); +void G2API_LoadGhoul2Models(CGhoul2Info_v &ghoul2, char *buffer); +void G2API_LoadSaveCodeDestructGhoul2Info(CGhoul2Info_v &ghoul2); +void G2API_FreeSaveBuffer(char *buffer); +char *G2API_GetAnimFileNameIndex(qhandle_t modelIndex); +int G2API_GetSurfaceRenderStatus(CGhoul2Info_v& ghoul2, int modelIndex, const char *surfaceName); +void G2API_CopySpecificG2Model(CGhoul2Info_v &ghoul2From, int modelFrom, CGhoul2Info_v &ghoul2To, int modelTo); +void G2API_DuplicateGhoul2Instance(CGhoul2Info_v &g2From, CGhoul2Info_v **g2To); +void G2API_SetBoltInfo(CGhoul2Info_v &ghoul2, int modelIndex, int boltInfo); + +class CRagDollUpdateParams; +class CRagDollParams; + +void G2API_AbsurdSmoothing(CGhoul2Info_v &ghoul2, qboolean status); + +void G2API_SetRagDoll(CGhoul2Info_v &ghoul2,CRagDollParams *parms); +void G2API_ResetRagDoll(CGhoul2Info_v &ghoul2); +void G2API_AnimateG2ModelsRag(CGhoul2Info_v &ghoul2, int AcurrentTime,CRagDollUpdateParams *params); + +qboolean G2API_RagPCJConstraint(CGhoul2Info_v &ghoul2, const char *boneName, vec3_t min, vec3_t max); +qboolean G2API_RagPCJGradientSpeed(CGhoul2Info_v &ghoul2, const char *boneName, const float speed); +qboolean G2API_RagEffectorGoal(CGhoul2Info_v &ghoul2, const char *boneName, vec3_t pos); +qboolean G2API_GetRagBonePos(CGhoul2Info_v &ghoul2, const char *boneName, vec3_t pos, vec3_t entAngles, vec3_t entPos, vec3_t entScale); +qboolean G2API_RagEffectorKick(CGhoul2Info_v &ghoul2, const char *boneName, vec3_t velocity); +qboolean G2API_RagForceSolve(CGhoul2Info_v &ghoul2, qboolean force); + +qboolean G2API_SetBoneIKState(CGhoul2Info_v &ghoul2, int time, const char *boneName, int ikState, sharedSetBoneIKStateParams_t *params); +qboolean G2API_IKMove(CGhoul2Info_v &ghoul2, int time, sharedIKMoveParams_t *params); + +void G2API_AttachInstanceToEntNum(CGhoul2Info_v &ghoul2, int entityNum, qboolean server); +void G2API_ClearAttachedInstance(int entityNum); +void G2API_CleanEntAttachments(void); +qboolean G2API_OverrideServerWithClientData(CGhoul2Info_v& ghoul2, int modelIndex); + +extern qboolean gG2_GBMNoReconstruct; +extern qboolean gG2_GBMUseSPMethod; +// From tr_ghoul2.cpp +void G2_ConstructGhoulSkeleton( CGhoul2Info_v &ghoul2,const int frameNum,bool checkForNewOrigin,const vec3_t scale); + +qboolean G2API_SkinlessModel(CGhoul2Info_v& ghoul2, int modelIndex); + +#ifdef _G2_GORE +int G2API_GetNumGoreMarks(CGhoul2Info_v& ghoul2, int modelIndex); +void G2API_AddSkinGore(CGhoul2Info_v &ghoul2,SSkinGoreData &gore); +void G2API_ClearSkinGore ( CGhoul2Info_v &ghoul2 ); +#endif // _SOF2 + +int G2API_Ghoul2Size ( CGhoul2Info_v &ghoul2 ); +void RemoveBoneCache( CBoneCache *boneCache ); + +const char *G2API_GetModelName ( CGhoul2Info_v& ghoul2, int modelIndex ); diff --git a/Projects/Android/jni/OpenJK/codemp_delete/ghoul2/ghoul2_shared.h b/Projects/Android/jni/OpenJK/codemp_delete/ghoul2/ghoul2_shared.h new file mode 100644 index 0000000..f20fa75 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/ghoul2/ghoul2_shared.h @@ -0,0 +1,340 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#pragma once + +#include +#include + +#define MDXABONEDEF +#include "rd-common/mdx_format.h" +#include "rd-common/tr_types.h" +#include "qcommon/matcomp.h" +#include "ghoul2/G2_gore.h" + +struct model_s; + +//rww - RAGDOLL_BEGIN +#define G2T_SV_TIME (0) +#define G2T_CG_TIME (1) +#define NUM_G2T_TIME (2) + +//rww - RAGDOLL_END + +//=================================================================== +// +// G H O U L I I D E F I N E S +// +// we save the whole surfaceInfo_t struct +struct surfaceInfo_t +{ + int offFlags; // what the flags are for this model + int surface; // index into array held inside the model definition of pointers to the actual surface data loaded in - used by both client and game + float genBarycentricJ; // point 0 barycentric coors + float genBarycentricI; // point 1 barycentric coors - point 2 is 1 - point0 - point1 + int genPolySurfaceIndex; // used to point back to the original surface and poly if this is a generated surface + int genLod; // used to determine original lod of original surface and poly hit location + +surfaceInfo_t(): + offFlags(0), + surface(0), + genBarycentricJ(0), + genBarycentricI(0), + genPolySurfaceIndex(0), + genLod(0) + {} + +}; + + + +#define MDXABONEDEF // used in the mdxformat.h file to stop redefinitions of the bone struct. + +// we save the whole structure here. +struct boneInfo_t +{ + int boneNumber; // what bone are we overriding? + mdxaBone_t matrix; // details of bone angle overrides - some are pre-done on the server, some in ghoul2 + int flags; // flags for override + int startFrame; // start frame for animation + int endFrame; // end frame for animation NOTE anim actually ends on endFrame+1 + int startTime; // time we started this animation + int pauseTime; // time we paused this animation - 0 if not paused + float animSpeed; // speed at which this anim runs. 1.0f means full speed of animation incoming - ie if anim is 20hrtz, we run at 20hrts. If 5hrts, we run at 5 hrts + float blendFrame; // frame PLUS LERP value to blend from + int blendLerpFrame; // frame to lerp the blend frame with. + int blendTime; // Duration time for blending - used to calc amount each frame of new anim is blended with last frame of the last anim + int blendStart; // Time when blending starts - not necessarily the same as startTime since we might start half way through an anim + int boneBlendTime; // time for duration of bone angle blend with normal animation + int boneBlendStart; // time bone angle blend with normal animation began + int lastTime; // this does not go across the network + mdxaBone_t newMatrix; // This is the lerped matrix that Ghoul2 uses on the client side - does not go across the network + + //rww - RAGDOLL_BEGIN + int lastTimeUpdated; // if non-zero this is all intialized + int lastContents; + vec3_t lastPosition; + vec3_t velocityEffector; + vec3_t lastAngles; + vec3_t minAngles; + vec3_t maxAngles; + vec3_t currentAngles; + vec3_t anglesOffset; + vec3_t positionOffset; + float radius; + float weight; // current radius cubed + int ragIndex; + vec3_t velocityRoot; // I am really tired of recomiling the whole game to add a param here + int ragStartTime; + int firstTime; + int firstCollisionTime; + int restTime; + int RagFlags; + int DependentRagIndexMask; + mdxaBone_t originalTrueBoneMatrix; + mdxaBone_t parentTrueBoneMatrix; // figure I will need this sooner or later + mdxaBone_t parentOriginalTrueBoneMatrix; // figure I will need this sooner or later + vec3_t originalOrigin; + vec3_t originalAngles; + vec3_t lastShotDir; + mdxaBone_t *basepose; + mdxaBone_t *baseposeInv; + mdxaBone_t *baseposeParent; + mdxaBone_t *baseposeInvParent; + int parentRawBoneIndex; + mdxaBone_t ragOverrideMatrix; // figure I will need this sooner or later + + mdxaBone_t extraMatrix; // figure I will need this sooner or later + vec3_t extraVec1; // I am really tired of recomiling the whole game to add a param here + float extraFloat1; + int extraInt1; + + vec3_t ikPosition; + float ikSpeed; + + vec3_t epVelocity; //velocity factor, can be set, and is also maintained by physics based on gravity, mass, etc. + float epGravFactor; //gravity factor maintained by bone physics + int solidCount; //incremented every time we try to move and are in solid - if we get out of solid, it is reset to 0 + bool physicsSettled; //true when the bone is on ground and finished bouncing, etc. but may still be pushed into solid by other bones + bool snapped; //the bone is broken out of standard constraints + + int parentBoneIndex; + + float offsetRotation; + + //user api overrides + float overGradSpeed; + + vec3_t overGoalSpot; + bool hasOverGoal; + + mdxaBone_t animFrameMatrix; //matrix for the bone in the desired settling pose -rww + int hasAnimFrameMatrix; + + int airTime; //base is in air, be more quick and sensitive about collisions + //rww - RAGDOLL_END + +boneInfo_t(): + boneNumber(-1), + flags(0), + startFrame(0), + endFrame(0), + startTime(0), + pauseTime(0), + animSpeed(0), + blendFrame(0), + blendLerpFrame(0), + blendTime(0), + blendStart(0), + boneBlendTime(0), + boneBlendStart(0), + lastTime(0), + RagFlags(0) + { + matrix.matrix[0][0] = matrix.matrix[0][1] = matrix.matrix[0][2] = matrix.matrix[0][3] = + matrix.matrix[1][0] = matrix.matrix[1][1] = matrix.matrix[1][2] = matrix.matrix[1][3] = + matrix.matrix[2][0] = matrix.matrix[2][1] = matrix.matrix[2][2] = matrix.matrix[2][3] = 0.0f; + } + +}; +//we save from top to boltUsed here. Don't bother saving the position, it gets rebuilt every frame anyway +struct boltInfo_t{ + int boneNumber; // bone number bolt attaches to + int surfaceNumber; // surface number bolt attaches to + int surfaceType; // if we attach to a surface, this tells us if it is an original surface or a generated one - doesn't go across the network + int boltUsed; // nor does this + mdxaBone_t position; // this does not go across the network + boltInfo_t(): + boneNumber(-1), + surfaceNumber(-1), + surfaceType(0), + boltUsed(0) + {} +}; + +#ifdef _SOF2 +typedef enum +{ + PGORE_NONE, + PGORE_ARMOR, + PGORE_BULLETSMALL, + PGORE_BULLETMED, + PGORE_BULLETBIG, + PGORE_HEGRENADE, + PGORE_COUNT +} goreEnum_t; + +struct goreEnumShader_t +{ + goreEnum_t shaderEnum; + char shaderName[MAX_QPATH]; +}; + +struct SSkinGoreData +{ + vec3_t angles; + vec3_t position; + int currentTime; + int entNum; + vec3_t rayDirection; // in world space + vec3_t hitLocation; // in world space + vec3_t scale; + float SSize; // size of splotch in the S texture direction in world units + float TSize; // size of splotch in the T texture direction in world units + float theta; // angle to rotate the splotch + +// qhandle_t shader; // handle to shader for gore, this better be rendered after the shader of the underlying surface + // this shader should also have "clamp" mode, not tiled. + goreEnum_t shaderEnum; // enum that'll get switched over to the shader's actual handle +}; +#endif // _SOF2 + +#define MAX_GHOUL_COUNT_BITS 8 // bits required to send across the MAX_G2_MODELS inside of the networking - this is the only restriction on ghoul models possible per entity + +typedef std::vector surfaceInfo_v; +typedef std::vector boneInfo_v; +typedef std::vector boltInfo_v; +typedef std::vector > mdxaBone_v; + +// defines for stuff to go into the mflags +#define GHOUL2_NOCOLLIDE 0x001 +#define GHOUL2_NORENDER 0x002 +#define GHOUL2_NOMODEL 0x004 +#define GHOUL2_NEWORIGIN 0x008 + +//for transform optimization -rww +#define GHOUL2_ZONETRANSALLOC 0x2000 + +class CBoneCache; + +// NOTE order in here matters. We save out from mModelindex to mFlags, but not the STL vectors that are at the top or the bottom. +class CGhoul2Info +{ +public: + surfaceInfo_v mSlist; + boltInfo_v mBltlist; + boneInfo_v mBlist; +// save from here + int mModelindex; + qhandle_t mCustomShader; + qhandle_t mCustomSkin; + int mModelBoltLink; + int mSurfaceRoot; + int mLodBias; + int mNewOrigin; // this contains the bolt index of the new origin for this model +#ifdef _G2_GORE + int mGoreSetTag; +#endif + qhandle_t mModel; // this and the next entries do NOT go across the network. They are for gameside access ONLY + char mFileName[MAX_QPATH]; + int mAnimFrameDefault; + int mSkelFrameNum; + int mMeshFrameNum; + int mFlags; // used for determining whether to do full collision detection against this object +// to here + size_t *mTransformedVertsArray; // used to create an array of pointers to transformed verts per surface for collision detection + CBoneCache *mBoneCache; + int mSkin; + + // these occasionally are not valid (like after a vid_restart) + // call the questionably efficient G2_SetupModelPointers(this) to insure validity + bool mValid; // all the below are proper and valid + const model_s *currentModel; + int currentModelSize; + const model_s *animModel; + int currentAnimModelSize; + const mdxaHeader_t *aHeader; + +#ifdef _G2_LISTEN_SERVER_OPT + int entityNum; +#endif + + CGhoul2Info(): + mModelindex(-1), + mCustomShader(0), + mCustomSkin(0), + mModelBoltLink(0), + mSurfaceRoot(0), + mLodBias(0), + mNewOrigin(-1), +#ifdef _G2_GORE + mGoreSetTag(0), +#endif + mModel(0), + mAnimFrameDefault(0), + mSkelFrameNum(-1), + mMeshFrameNum(-1), + mFlags(0), + mTransformedVertsArray(0), + mBoneCache(0), + mSkin(0), + mValid(false), + currentModel(0), + currentModelSize(0), + animModel(0), + currentAnimModelSize(0), + aHeader(0) +#ifdef _G2_LISTEN_SERVER_OPT + , entityNum(ENTITYNUM_NONE) +#endif + { + mFileName[0] = 0; + } +}; + +class CGhoul2Info_v; + +// collision detection stuff +#define G2_FRONTFACE 1 +#define G2_BACKFACE 0 + + +// calling defines for the trace function +enum EG2_Collision +{ + G2_NOCOLLIDE, + G2_COLLIDE, + G2_RETURNONHIT +}; + + +//==================================================================== diff --git a/Projects/Android/jni/OpenJK/codemp/icarus/BlockStream.cpp b/Projects/Android/jni/OpenJK/codemp_delete/icarus/BlockStream.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/icarus/BlockStream.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/icarus/BlockStream.cpp diff --git a/Projects/Android/jni/OpenJK/codemp_delete/icarus/GameInterface.cpp b/Projects/Android/jni/OpenJK/codemp_delete/icarus/GameInterface.cpp new file mode 100644 index 0000000..d32b2bb --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/icarus/GameInterface.cpp @@ -0,0 +1,747 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +// ICARUS Utility functions +//rww - mangled to work in server exe setting. + +#include "game/g_public.h" +#include "server/server.h" +#include "interface.h" +#include "GameInterface.h" +#include "qcommon/RoffSystem.h" +#include "Q3_Interface.h" +#include "server/sv_gameapi.h" + +ICARUS_Instance *iICARUS; +bufferlist_t ICARUS_BufferList; +entlist_t ICARUS_EntList; + +extern uint32_t Com_BlockChecksum (const void *buffer, int length); +extern void Q3_DebugPrint( int level, const char *format, ... ); + +int ICARUS_entFilter = -1; + +/* +============= +ICARUS_GetScript + +gets the named script from the cache or disk if not already loaded +============= +*/ + +int ICARUS_GetScript( const char *name, char **buf ) +{ + bufferlist_t::iterator ei; + //Make sure the caller is valid + + //Attempt to retrieve a precached script + ei = ICARUS_BufferList.find( (char *) name ); + + //Not found, check the disk + if ( ei == ICARUS_BufferList.end() ) + { + if ( ICARUS_RegisterScript( name ) == false ) + return 0; + + //Script is now inserted, retrieve it and pass through + ei = ICARUS_BufferList.find( (char *) name ); + + if ( ei == ICARUS_BufferList.end() ) + { + //NOTENOTE: This is an internal error in STL if this happens... + assert(0); + return 0; + } + } + + *buf = (*ei).second->buffer; + return (*ei).second->length; +} + +/* +============= +ICARUS_RunScript + +Runs the script by the given name +============= +*/ +int ICARUS_RunScript( sharedEntity_t *ent, const char *name ) +{ + char *buf; + int len; + + //Make sure the caller is valid + if ( gSequencers[ent->s.number] == NULL ) + { + //Com_Printf( "%s : entity is not a valid script user\n", ent->classname ); + return false; + } +#ifdef _HACK_FOR_TESTING_ONLY_1 + char namex[1024]; + char *blah = strstr(name, "stu/"); + int r = blah - name; + if (blah) + { + int i = 0; + while (i < r) + { + namex[i] = name[i]; + i++; + } + namex[i] = 0; + strcat(namex, "ignorethisfolder/"); + i = strlen(namex); + while (name[r] != '/') + { + r++; + } + r++; + + while (name[r]) + { + namex[i] = name[r]; + r++; + i++; + } + namex[i] = 0; + } + else + { + strcpy(namex, name); + } + + len = ICARUS_GetScript (namex, &buf); +#else + len = ICARUS_GetScript (name, &buf); +#endif + if (len == 0) + { + return false; + } + + //Attempt to run the script + if S_FAILED(gSequencers[ent->s.number]->Run( buf, len )) + return false; + + if ( ( ICARUS_entFilter == -1 ) || ( ICARUS_entFilter == ent->s.number ) ) + { + Q3_DebugPrint( WL_VERBOSE, "%d Script %s executed by %s %s\n", svs.time, (char *) name, ent->classname, ent->targetname ); + } + + return true; +} + +/* +================= +ICARUS_Init + +Allocates a new ICARUS instance +================= +*/ + +void ICARUS_Init( void ) +{ + //Link all interface functions + Interface_Init( &interface_export ); + + //Create the ICARUS instance for this session + iICARUS = ICARUS_Instance::Create( &interface_export ); + + if ( iICARUS == NULL ) + { + Com_Error( ERR_DROP, "Unable to initialize ICARUS instance\n" ); + return; + } +} + +/* +================= +ICARUS_Shutdown + +Frees up ICARUS resources from all entities +================= +*/ + +void ICARUS_Shutdown( void ) +{ + bufferlist_t::iterator ei; + sharedEntity_t *ent = SV_GentityNum(0); + + //Release all ICARUS resources from the entities + for ( int i = 0; i < /*globals.num_entities*/MAX_GENTITIES; i++ ) + { + ent = SV_GentityNum(i); + + if (gSequencers[i]) + { + if (ent->s.number >= MAX_GENTITIES || + ent->s.number < 0) + { + ent->s.number = i; + assert(0); + } + ICARUS_FreeEnt( ent ); + } + } + + //Clear out all precached scripts + for ( ei = ICARUS_BufferList.begin(); ei != ICARUS_BufferList.end(); ++ei ) + { + //gi.Free( (*ei).second->buffer ); + ICARUS_Free((*ei).second->buffer); + delete (*ei).second; + } + + ICARUS_BufferList.clear(); + + //Clear the name map + ICARUS_EntList.clear(); + + //Free this instance + if ( iICARUS ) + { + iICARUS->Delete(); + iICARUS = NULL; + } +} + +/* +============== +ICARUS_FreeEnt + +Frees all ICARUS resources on an entity + +WARNING!!! DO NOT DO THIS WHILE RUNNING A SCRIPT, ICARUS WILL CRASH!!! +FIXME: shouldn't ICARUS handle this internally? + +============== +*/ +void ICARUS_FreeEnt( sharedEntity_t *ent ) +{ + assert( iICARUS ); + + if (ent->s.number >= MAX_GENTITIES || + ent->s.number < 0) + { + assert(0); + return; + } + + //Make sure the ent is valid + if ( gSequencers[ent->s.number] == NULL ) + return; + + //Remove them from the ICARUSE_EntList list so that when their g_entity index is reused, ICARUS doesn't try to affect the new (incorrect) ent. + if VALIDSTRING( ent->script_targetname ) + { + char temp[1024]; + + strncpy( (char *) temp, ent->script_targetname, 1023 ); + temp[ 1023 ] = 0; + + entlist_t::iterator it = ICARUS_EntList.find( Q_strupr(temp) ); + + if (it != ICARUS_EntList.end()) + { + ICARUS_EntList.erase(it); + } + } + + //Delete the sequencer and the task manager + iICARUS->DeleteSequencer( gSequencers[ent->s.number] ); + + //Clean up the pointers + gSequencers[ent->s.number] = NULL; + gTaskManagers[ent->s.number] = NULL; +} + + +/* +============== +ICARUS_ValidEnt + +Determines whether or not an entity needs ICARUS information +============== +*/ + +bool ICARUS_ValidEnt( sharedEntity_t *ent ) +{ + int i; + + //Targeted by a script + if VALIDSTRING( ent->script_targetname ) + return true; + + //Potentially able to call a script + for ( i = 0; i < NUM_BSETS; i++ ) + { + if VALIDSTRING( ent->behaviorSet[i] ) + { + //Com_Printf( "WARNING: Entity %d (%s) has behaviorSet but no script_targetname -- using targetname\n", ent->s.number, ent->targetname ); + + //ent->script_targetname = ent->targetname; + //rww - You CANNOT do things like this now. We're switching memory around to be able to read this memory from vm land, + //and while this allows us to read it on our "fake" entity here, we can't modify pointers like this. We can however do + //something completely hackish such as the following. + assert(ent->s.number >= 0 && ent->s.number < MAX_GENTITIES); + sharedEntity_t *trueEntity = SV_GentityNum(ent->s.number); + //This works because we're modifying the actual shared game vm data and turning one pointer into another. + //While these pointers both look like garbage to us in here, they are not. + trueEntity->script_targetname = trueEntity->targetname; + return true; + } + } + + return false; +} + +/* +============== +ICARUS_AssociateEnt + +Associate the entity's id and name so that it can be referenced later +============== +*/ + +void ICARUS_AssociateEnt( sharedEntity_t *ent ) +{ + char temp[1024]; + + if ( VALIDSTRING( ent->script_targetname ) == false ) + return; + + strncpy( (char *) temp, ent->script_targetname, 1023 ); + temp[ 1023 ] = 0; + + ICARUS_EntList[ Q_strupr( (char *) temp ) ] = ent->s.number; +} + +/* +============== +ICARUS_RegisterScript + +Loads and caches a script +============== +*/ + +bool ICARUS_RegisterScript( const char *name, qboolean bCalledDuringInterrogate /* = false */ ) +{ + bufferlist_t::iterator ei; + pscript_t *pscript; + char newname[MAX_FILENAME_LENGTH]; + char *buffer = NULL; // lose compiler warning about uninitialised vars + long length; + + //Make sure this isn't already cached + ei = ICARUS_BufferList.find( (char *) name ); + + // note special return condition here, if doing interrogate and we already have this file then we MUST return + // false (which stops the interrogator proceeding), this not only saves some time, but stops a potential + // script recursion bug which could lock the program in an infinite loop... Return TRUE for normal though! + // + if ( ei != ICARUS_BufferList.end() ) + return (bCalledDuringInterrogate)?false:true; + + Com_sprintf( newname, sizeof(newname), "%s%s", name, IBI_EXT ); + + + // small update here, if called during interrogate, don't let gi.FS_ReadFile() complain because it can't + // find stuff like BS_RUN_AND_SHOOT as scriptname... During FINALBUILD the message won't appear anyway, hence + // the ifndef, this just cuts down on internal error reports while testing release mode... + // + qboolean qbIgnoreFileRead = qfalse; + // + // NOTENOTE: For the moment I've taken this back out, to avoid doubling the number of fopen()'s per file. +#if 0//#ifndef FINAL_BUILD + if (bCalledDuringInterrogate) + { + fileHandle_t file; + + gi.FS_Open( newname, &file, FS_READ ); + + if ( file == NULL ) + { + qbIgnoreFileRead = qtrue; // warn disk code further down not to try FS_ReadFile() + } + else + { + gi.FS_Close( file ); + } + } +#endif + + length = qbIgnoreFileRead ? -1 : FS_ReadFile( newname, (void **) &buffer ); + + if ( length <= 0 ) + { + // File not found, but keep quiet during interrogate stage, because of stuff like BS_RUN_AND_SHOOT as scriptname + // + if (!bCalledDuringInterrogate) + { + Com_Printf(S_COLOR_RED"Could not open file '%s'\n", newname ); + } + return false; + } + + pscript = new pscript_t; + + pscript->buffer = (char *) ICARUS_Malloc(length);//gi.Malloc(length, TAG_ICARUS, qfalse); + memcpy (pscript->buffer, buffer, length); + pscript->length = length; + + FS_FreeFile( buffer ); + + ICARUS_BufferList[ name ] = pscript; + + return true; +} + +void ICARUS_SoundPrecache(const char *filename) +{ + T_G_ICARUS_SOUNDINDEX *sharedMem = (T_G_ICARUS_SOUNDINDEX *)sv.mSharedMemory; + + strcpy( sharedMem->filename, filename ); + + GVM_ICARUS_SoundIndex(); +} + +int ICARUS_GetIDForString( const char *string ) +{ + T_G_ICARUS_GETSETIDFORSTRING *sharedMem = (T_G_ICARUS_GETSETIDFORSTRING *)sv.mSharedMemory; + + strcpy(sharedMem->string, string); + + return GVM_ICARUS_GetSetIDForString(); +} + +/* +------------------------- +ICARUS_InterrogateScript +------------------------- +*/ + +// at this point the filename should have had the "scripts" (Q3_SCRIPT_DIR) added to it (but not the IBI extension) +// +void ICARUS_InterrogateScript( const char *filename ) +{ + CBlockStream stream; + CBlockMember *blockMember; + CBlock block; + + if (!Q_stricmp(filename,"NULL") || !Q_stricmp(filename,"default")) + return; + + ////////////////////////////////// + // + // ensure "scripts" (Q3_SCRIPT_DIR), which will be missing if this was called recursively... + // + char sFilename[MAX_FILENAME_LENGTH]; // should really be MAX_QPATH (and 64 bytes instead of 1024), but this fits the rest of the code + + if (!Q_stricmpn(filename,Q3_SCRIPT_DIR,strlen(Q3_SCRIPT_DIR))) + { + Q_strncpyz(sFilename,filename,sizeof(sFilename)); + } + else + { + Q_strncpyz(sFilename,va("%s/%s",Q3_SCRIPT_DIR,filename),sizeof(sFilename)); + } + // + ////////////////////////////////// + + + //Attempt to register this script + if ( ICARUS_RegisterScript( sFilename, qtrue ) == false ) // true = bCalledDuringInterrogate + return; + + char *buf; + long len; + + //Attempt to retrieve the new script data + if ( ( len = ICARUS_GetScript ( sFilename, &buf ) ) == 0 ) + return; + + //Open the stream + if ( stream.Open( buf, len ) == qfalse ) + return; + + const char *sVal1, *sVal2; + char temp[1024]; + int setID; + + //Now iterate through all blocks of the script, searching for keywords + while ( stream.BlockAvailable() ) + { + //Get a block + if ( stream.ReadBlock( &block ) == qfalse ) + return; + + //Determine what type of block this is + switch( block.GetBlockID() ) + { + case ID_CAMERA: // to cache ROFF files + { + float f = *(float *) block.GetMemberData( 0 ); + + if (f == TYPE_PATH) + { + sVal1 = (const char *) block.GetMemberData( 1 ); + + //we can do this I guess since the roff is loaded on the server. + theROFFSystem.Cache((char *)sVal1, qfalse); + } + } + break; + + case ID_PLAY: // to cache ROFF files + + sVal1 = (const char *) block.GetMemberData( 0 ); + + if (!Q_stricmp(sVal1,"PLAY_ROFF")) + { + sVal1 = (const char *) block.GetMemberData( 1 ); + + //we can do this I guess since the roff is loaded on the server. + theROFFSystem.Cache((char *)sVal1, qfalse); + } + break; + + //Run commands + case ID_RUN: + + sVal1 = (const char *) block.GetMemberData( 0 ); + + COM_StripExtension( sVal1, (char *) temp, sizeof( temp ) ); + ICARUS_InterrogateScript( (const char *) &temp ); + + break; + + case ID_SOUND: + //We can't just call over to S_RegisterSound or whatever because this is on the server. + sVal1 = (const char *) block.GetMemberData( 1 ); //0 is channel, 1 is filename + ICARUS_SoundPrecache(sVal1); + break; + + case ID_SET: + blockMember = block.GetMember( 0 ); + + //NOTENOTE: This will not catch special case get() inlines! (There's not really a good way to do that) + + //Make sure we're testing against strings + if ( blockMember->GetID() == TK_STRING ) + { + sVal1 = (const char *) block.GetMemberData( 0 ); + sVal2 = (const char *) block.GetMemberData( 1 ); + + //Get the id for this set identifier + setID = ICARUS_GetIDForString( sVal1 ); + + //Check against valid types + switch ( setID ) + { + case SET_SPAWNSCRIPT: + case SET_USESCRIPT: + case SET_AWAKESCRIPT: + case SET_ANGERSCRIPT: + case SET_ATTACKSCRIPT: + case SET_VICTORYSCRIPT: + case SET_LOSTENEMYSCRIPT: + case SET_PAINSCRIPT: + case SET_FLEESCRIPT: + case SET_DEATHSCRIPT: + case SET_DELAYEDSCRIPT: + case SET_BLOCKEDSCRIPT: + case SET_FFIRESCRIPT: + case SET_FFDEATHSCRIPT: + case SET_MINDTRICKSCRIPT: + case SET_CINEMATIC_SKIPSCRIPT: + //Recursively obtain all embedded scripts + ICARUS_InterrogateScript( sVal2 ); + break; + case SET_LOOPSOUND: //like ID_SOUND, but set's looping + ICARUS_SoundPrecache(sVal2); + break; + case SET_VIDEO_PLAY: //in game cinematic + //do nothing for MP. + break; + case SET_ADDRHANDBOLT_MODEL: + case SET_ADDLHANDBOLT_MODEL: + //do nothing for MP + break; + default: + break; + } + } + break; + + default: + break; + } + + //Clean out the block for the next pass + block.Free(); + } + + //All done + stream.Free(); +} + +stringID_table_t BSTable[] = +{ + ENUM2STRING(BS_DEFAULT),//# default behavior for that NPC + ENUM2STRING(BS_ADVANCE_FIGHT),//# Advance to captureGoal and shoot enemies if you can + ENUM2STRING(BS_SLEEP),//# Play awake script when startled by sound + ENUM2STRING(BS_FOLLOW_LEADER),//# Follow your leader and shoot any enemies you come across + ENUM2STRING(BS_JUMP),//# Face navgoal and jump to it. + ENUM2STRING(BS_SEARCH),//# Using current waypoint as a base), search the immediate branches of waypoints for enemies + ENUM2STRING(BS_WANDER),//# Wander down random waypoint paths + ENUM2STRING(BS_NOCLIP),//# Moves through walls), etc. + ENUM2STRING(BS_REMOVE),//# Waits for player to leave PVS then removes itself + ENUM2STRING(BS_CINEMATIC),//# Does nothing but face it's angles and move to a goal if it has one + //the rest are internal only + { "", -1 } +}; + +/* +============== +ICARUS_PrecacheEnt + +Precache all scripts being used by the entity +============== +*/ + +void ICARUS_PrecacheEnt( sharedEntity_t *ent ) +{ + char newname[MAX_FILENAME_LENGTH]; + int i; + + for ( i = 0; i < NUM_BSETS; i++ ) + { + if ( ent->behaviorSet[i] == NULL ) + continue; + + if ( GetIDForString( BSTable, ent->behaviorSet[i] ) == -1 ) + {//not a behavior set + Com_sprintf( newname, sizeof(newname), "%s/%s", Q3_SCRIPT_DIR, ent->behaviorSet[i] ); + + //Precache this, and all internally referenced scripts + ICARUS_InterrogateScript( newname ); + } + } +} + +/* +============== +ICARUS_InitEnt + +Allocates a sequencer and task manager only if an entity is a potential script user +============== +*/ + +void Q3_TaskIDClear( int *taskID ); +void ICARUS_InitEnt( sharedEntity_t *ent ) +{ + //Make sure this is a fresh ent + assert( iICARUS ); + assert( gTaskManagers[ent->s.number] == NULL ); + assert( gSequencers[ent->s.number] == NULL ); + + if ( gSequencers[ent->s.number] != NULL ) + return; + + if ( gTaskManagers[ent->s.number] != NULL ) + return; + + //Create the sequencer and setup the task manager + gSequencers[ent->s.number] = iICARUS->GetSequencer( ent->s.number ); + gTaskManagers[ent->s.number] = gSequencers[ent->s.number]->GetTaskManager(); + + //Initialize all taskIDs to -1 + memset( &ent->taskID, -1, sizeof( ent->taskID ) ); + + //Add this entity to a map of valid associated ents for quick retrieval later + ICARUS_AssociateEnt( ent ); + + //Precache all the entity's scripts + ICARUS_PrecacheEnt( ent ); +} + +/* +------------------------- +ICARUS_LinkEntity +------------------------- +*/ + +int ICARUS_LinkEntity( int entID, CSequencer *sequencer, CTaskManager *taskManager ) +{ + sharedEntity_t *ent = SV_GentityNum(entID); + + if ( ent == NULL ) + return false; + + gSequencers[ent->s.number] = sequencer; + gTaskManagers[ent->s.number] = taskManager; + + ICARUS_AssociateEnt( ent ); + + return true; +} + +/* +------------------------- +Svcmd_ICARUS_f +------------------------- +*/ + +void Svcmd_ICARUS_f( void ) +{ + //rwwFIXMEFIXME: Do something with this for debugging purposes at some point. + /* + char *cmd = Cmd_Argv( 1 ); + + if ( Q_stricmp( cmd, "log" ) == 0 ) + { + //g_ICARUSDebug->integer = WL_DEBUG; + if ( VALIDSTRING( Cmd_Argv( 2 ) ) ) + { + sharedEntity_t *ent = G_Find( NULL, FOFS( script_targetname ), gi.argv(2) ); + + if ( ent == NULL ) + { + Com_Printf( "Entity \"%s\" not found!\n", gi.argv(2) ); + return; + } + + //Start logging + Com_Printf("Logging ICARUS info for entity %s\n", gi.argv(2) ); + + ICARUS_entFilter = ( ent->s.number == ICARUS_entFilter ) ? -1 : ent->s.number; + + return; + } + + Com_Printf("Logging ICARUS info for all entities\n"); + + return; + } + */ + return; +} diff --git a/Projects/Android/jni/OpenJK/codemp_delete/icarus/GameInterface.h b/Projects/Android/jni/OpenJK/codemp_delete/icarus/GameInterface.h new file mode 100644 index 0000000..666fd6c --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/icarus/GameInterface.h @@ -0,0 +1,58 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#pragma once + +#include +#include + +typedef struct pscript_s +{ + char *buffer; + long length; +} pscript_t; + +typedef std::map < std::string, int > entlist_t; +typedef std::map < std::string, pscript_t* > bufferlist_t; + +//ICARUS includes +extern interface_export_t interface_export; + +extern void Interface_Init( interface_export_t *pe ); +extern int ICARUS_RunScript( sharedEntity_t *ent, const char *name ); +extern bool ICARUS_RegisterScript( const char *name, qboolean bCalledDuringInterrogate = qfalse); +extern ICARUS_Instance *iICARUS; +extern bufferlist_t ICARUS_BufferList; +extern entlist_t ICARUS_EntList; + +// +// g_ICARUS.cpp +// +void ICARUS_Init( void ); +bool ICARUS_ValidEnt( sharedEntity_t *ent ); +void ICARUS_InitEnt( sharedEntity_t *ent ); +void ICARUS_FreeEnt( sharedEntity_t *ent ); +void ICARUS_AssociateEnt( sharedEntity_t *ent ); +void ICARUS_Shutdown( void ); +void Svcmd_ICARUS_f( void ); + +extern int ICARUS_entFilter; diff --git a/Projects/Android/jni/OpenJK/codemp_delete/icarus/Instance.cpp b/Projects/Android/jni/OpenJK/codemp_delete/icarus/Instance.cpp new file mode 100644 index 0000000..58b3261 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/icarus/Instance.cpp @@ -0,0 +1,664 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +// ICARUS Instance +// +// -- jweier + +// this include must remain at the top of every Icarus CPP file +#include "icarus.h" + +#include + +class CSequencer; +class CTaskManager; + +//We can't put these on entity fields since all that stuff is in C +//which can't be changed due to VMs. So we'll use a global array +//and access by the entity index given. +CSequencer *gSequencers[MAX_GENTITIES]; +CTaskManager *gTaskManagers[MAX_GENTITIES]; + +// Instance + +ICARUS_Instance::ICARUS_Instance( void ) +{ + m_GUID = 0; + + //to be safe + memset(gSequencers,0, sizeof(gSequencers)); + memset(gTaskManagers,0, sizeof(gTaskManagers)); + +#ifdef _DEBUG + + m_DEBUG_NumSequencerAlloc = 0; + m_DEBUG_NumSequencerFreed = 0; + m_DEBUG_NumSequencerResidual = 0; + + m_DEBUG_NumSequenceAlloc = 0; + m_DEBUG_NumSequenceFreed = 0; + m_DEBUG_NumSequenceResidual = 0; + +#endif + +} + +ICARUS_Instance::~ICARUS_Instance( void ) +{ +} + +/* +------------------------- +Create +------------------------- +*/ + +ICARUS_Instance *ICARUS_Instance::Create( interface_export_t *ie ) +{ + ICARUS_Instance *instance = new ICARUS_Instance; + instance->m_interface = ie; + Com_OPrintf( "ICARUS Instance successfully created\n" ); + return instance; +} + +/* +------------------------- +Free +------------------------- +*/ + +int ICARUS_Instance::Free( void ) +{ + sequencer_l::iterator sri; + + //Delete any residual sequencers + STL_ITERATE( sri, m_sequencers ) + { + delete (*sri); + +#ifdef _DEBUG + + m_DEBUG_NumSequencerResidual++; + +#endif + + } + + m_sequencers.clear(); + //all these are deleted now so clear the global map. + memset(gSequencers,0, sizeof(gSequencers)); + memset(gTaskManagers,0, sizeof(gTaskManagers)); + m_signals.clear(); + + sequence_l::iterator si; + + //Delete any residual sequences + STL_ITERATE( si, m_sequences ) + { + delete (*si); + +#ifdef _DEBUG + + m_DEBUG_NumSequenceResidual++; + +#endif + + } + + m_sequences.clear(); + + return true; +} + +/* +------------------------- +Delete +------------------------- +*/ + +int ICARUS_Instance::Delete( void ) +{ + + Free(); + +#ifdef _DEBUG + + Com_OPrintf( "\nICARUS Instance Debug Info:\n---------------------------\n" ); + + Com_OPrintf( "Sequencers Allocated:\t%d\n", m_DEBUG_NumSequencerAlloc ); + + Com_OPrintf( "Sequencers Freed:\t\t%d\n", m_DEBUG_NumSequencerFreed ); + + Com_OPrintf( "Sequencers Residual:\t%d\n\n", m_DEBUG_NumSequencerResidual ); + + Com_OPrintf( "Sequences Allocated:\t%d\n", m_DEBUG_NumSequenceAlloc ); + + Com_OPrintf( "Sequences Freed:\t\t%d\n", m_DEBUG_NumSequenceFreed ); + + Com_OPrintf( "Sequences Residual:\t\t%d\n\n", m_DEBUG_NumSequenceResidual ); + + Com_OPrintf( "\n" ); + +#endif + + delete this; + + return true; +} + +/* +------------------------- +GetSequencer +------------------------- +*/ + +CSequencer *ICARUS_Instance::GetSequencer( int ownerID ) +{ + CSequencer *sequencer = CSequencer::Create(); + CTaskManager *taskManager = CTaskManager::Create(); + + sequencer->Init( ownerID, m_interface, taskManager, this ); + + taskManager->Init( sequencer ); + + STL_INSERT( m_sequencers, sequencer ); + +#ifdef _DEBUG + + m_DEBUG_NumSequencerAlloc++; + +#endif + + return sequencer; +} + +/* +------------------------- +DeleteSequencer +------------------------- +*/ + +void ICARUS_Instance::DeleteSequencer( CSequencer *sequencer ) +{ + // added 2/12/2 to properly delete blocks that were passed to the task manager + sequencer->Recall(); + + CTaskManager *taskManager = sequencer->GetTaskManager(); + + if ( taskManager ) + { + taskManager->Free(); + delete taskManager; + } + + m_sequencers.remove( sequencer ); + + sequencer->Free(); + delete sequencer; + +#ifdef _DEBUG + + m_DEBUG_NumSequencerFreed++; + +#endif + +} + +/* +------------------------- +GetSequence +------------------------- +*/ + +CSequence *ICARUS_Instance::GetSequence( void ) +{ + CSequence *sequence = CSequence::Create(); + + //Assign the GUID + sequence->SetID( m_GUID++ ); + sequence->SetOwner( this ); + + STL_INSERT( m_sequences, sequence ); + +#ifdef _DEBUG + + m_DEBUG_NumSequenceAlloc++; + +#endif + + return sequence; +} + +/* +------------------------- +GetSequence +------------------------- +*/ + +CSequence *ICARUS_Instance::GetSequence( int id ) +{ + sequence_l::iterator si; + STL_ITERATE( si, m_sequences ) + { + if ( (*si)->GetID() == id ) + return (*si); + } + + return NULL; +} + +/* +------------------------- +DeleteSequence +------------------------- +*/ + +void ICARUS_Instance::DeleteSequence( CSequence *sequence ) +{ + m_sequences.remove( sequence ); + + delete sequence; + +#ifdef _DEBUG + + m_DEBUG_NumSequenceFreed++; + +#endif +} + +/* +------------------------- +AllocateSequences +------------------------- +*/ + +int ICARUS_Instance::AllocateSequences( int numSequences, int *idTable ) +{ + CSequence *sequence; + + for ( int i = 0; i < numSequences; i++ ) + { + //If the GUID of this sequence is higher than the current, take this a the "current" GUID + if ( idTable[i] > m_GUID ) + m_GUID = idTable[i]; + + //Allocate the container sequence + if ( ( sequence = GetSequence() ) == NULL ) + return false; + + //Override the given GUID with the real one + sequence->SetID( idTable[i] ); + } + + return true; +} + +/* +------------------------- +SaveSequenceIDTable +------------------------- +*/ + +int ICARUS_Instance::SaveSequenceIDTable( void ) +{ + //Save out the number of sequences to follow + int numSequences = m_sequences.size(); + m_interface->I_WriteSaveData( INT_ID('#','S','E','Q'), &numSequences, sizeof( numSequences ) ); + + //Sequences are saved first, by ID and information + sequence_l::iterator sqi; + + //First pass, save all sequences ID for reconstruction + int *idTable = new int[ numSequences ]; + int itr = 0; + + if ( idTable == NULL ) + return false; + + STL_ITERATE( sqi, m_sequences ) + { + idTable[itr++] = (*sqi)->GetID(); + } + + m_interface->I_WriteSaveData( INT_ID('S','Q','T','B'), idTable, sizeof( int ) * numSequences ); + + delete[] idTable; + + return true; +} + +/* +------------------------- +SaveSequences +------------------------- +*/ + +int ICARUS_Instance::SaveSequences( void ) +{ + //Save out a listing of all the used sequences by ID + SaveSequenceIDTable(); + + //Save all the information in order + sequence_l::iterator sqi; + STL_ITERATE( sqi, m_sequences ) + { + (*sqi)->Save(); + } + + return true; +} + +/* +------------------------- +SaveSequencers +------------------------- +*/ + +int ICARUS_Instance::SaveSequencers( void ) +{ + //Save out the number of sequences to follow + int numSequencers = m_sequencers.size(); + m_interface->I_WriteSaveData( INT_ID('#','S','Q','R'), &numSequencers, sizeof( numSequencers ) ); + + //The sequencers are then saved + sequencer_l::iterator si; + STL_ITERATE( si, m_sequencers ) + { + (*si)->Save(); + } + + return true; +} + +/* +------------------------- +SaveSignals +------------------------- +*/ + +int ICARUS_Instance::SaveSignals( void ) +{ + int numSignals = m_signals.size(); + + m_interface->I_WriteSaveData( INT_ID('I','S','I','G'), &numSignals, sizeof( numSignals ) ); + + signal_m::iterator si; + STL_ITERATE( si, m_signals ) + { + //m_interface->I_WriteSaveData( 'ISIG', &numSignals, sizeof( numSignals ) ); + const char *name = ((*si).first).c_str(); + + //Make sure this is a valid string + assert( ( name != NULL ) && ( name[0] != '\0' ) ); + + int length = strlen( name ) + 1; + + //Save out the string size + m_interface->I_WriteSaveData( INT_ID('S','I','G','#'), &length, sizeof ( length ) ); + + //Write out the string + m_interface->I_WriteSaveData( INT_ID('S','I','G','N'), (void *) name, length ); + } + + return true; +} + +/* +------------------------- +Save +------------------------- +*/ + +int ICARUS_Instance::Save( void ) +{ + //Save out a ICARUS save block header with the ICARUS version + double version = ICARUS_VERSION; + m_interface->I_WriteSaveData( INT_ID('I','C','A','R'), &version, sizeof( version ) ); + + //Save out the signals + if ( SaveSignals() == false ) + return false; + + //Save out the sequences + if ( SaveSequences() == false ) + return false; + + //Save out the sequencers + if ( SaveSequencers() == false ) + return false; + + m_interface->I_WriteSaveData( INT_ID('I','E','N','D'), &version, sizeof( version ) ); + + return true; +} + +/* +------------------------- +LoadSignals +------------------------- +*/ + +int ICARUS_Instance::LoadSignals( void ) +{ + int numSignals; + + m_interface->I_ReadSaveData( INT_ID('I','S','I','G'), &numSignals, sizeof( numSignals ) ); + + for ( int i = 0; i < numSignals; i++ ) + { + char buffer[1024]; + int length; + + //Get the size of the string + m_interface->I_ReadSaveData( INT_ID('S','I','G','#'), &length, sizeof( length ) ); + + assert( length < (int)sizeof( buffer ) ); + + //Get the string + m_interface->I_ReadSaveData( INT_ID('S','I','G','N'), &buffer, length ); + + //Turn it on and add it to the system + Signal( (const char *) &buffer ); + } + + return true; +} + +/* +------------------------- +LoadSequence +------------------------- +*/ + +int ICARUS_Instance::LoadSequence( void ) +{ + CSequence *sequence = GetSequence(); + + //Load the sequence back in + sequence->Load(); + + //If this sequence had a higher GUID than the current, save it + if ( sequence->GetID() > m_GUID ) + m_GUID = sequence->GetID(); + + return true; +} + +/* +------------------------- +LoadSequence +------------------------- +*/ + +int ICARUS_Instance::LoadSequences( void ) +{ + CSequence *sequence; + int numSequences; + + //Get the number of sequences to read in + m_interface->I_ReadSaveData( INT_ID('#','S','E','Q'), &numSequences, sizeof( numSequences ) ); + + int *idTable = new int[ numSequences ]; + + if ( idTable == NULL ) + return false; + + //Load the sequencer ID table + m_interface->I_ReadSaveData( INT_ID('S','Q','T','B'), idTable, sizeof( int ) * numSequences ); + + //First pass, allocate all container sequences and give them their proper IDs + if ( AllocateSequences( numSequences, idTable ) == false ) + return false; + + //Second pass, load all sequences + for ( int i = 0; i < numSequences; i++ ) + { + //Get the proper sequence for this load + if ( ( sequence = GetSequence( idTable[i] ) ) == NULL ) + return false; + + //Load the sequence + if ( ( sequence->Load() ) == false ) + return false; + } + + //Free the idTable + delete[] idTable; + + return true; +} + +/* +------------------------- +LoadSequencers +------------------------- +*/ + +int ICARUS_Instance::LoadSequencers( void ) +{ + CSequencer *sequencer; + int numSequencers; + + //Get the number of sequencers to load + m_interface->I_ReadSaveData( INT_ID('#','S','Q','R'), &numSequencers, sizeof( numSequencers ) ); + + //Load all sequencers + for ( int i = 0; i < numSequencers; i++ ) + { + //NOTENOTE: The ownerID will be replaced in the loading process + if ( ( sequencer = GetSequencer( -1 ) ) == NULL ) + return false; + + if ( sequencer->Load() == false ) + return false; + } + + return true; +} + +/* +------------------------- +Load +------------------------- +*/ + +int ICARUS_Instance::Load( void ) +{ + //Clear out any old information + Free(); + + //Check to make sure we're at the ICARUS save block + double version; + m_interface->I_ReadSaveData( INT_ID('I','C','A','R'), &version, sizeof( version ) ); + + //Versions must match! + if ( version != ICARUS_VERSION ) + { + m_interface->I_DPrintf( WL_ERROR, "save game data contains outdated ICARUS version information!\n"); + return false; + } + + //Load all signals + if ( LoadSignals() == false ) + { + m_interface->I_DPrintf( WL_ERROR, "failed to load signals from save game!\n"); + return false; + } + + //Load in all sequences + if ( LoadSequences() == false ) + { + m_interface->I_DPrintf( WL_ERROR, "failed to load sequences from save game!\n"); + return false; + } + + //Load in all sequencers + if ( LoadSequencers() == false ) + { + m_interface->I_DPrintf( WL_ERROR, "failed to load sequencers from save game!\n"); + return false; + } + + m_interface->I_ReadSaveData( INT_ID('I','E','N','D'), &version, sizeof( version ) ); + + return true; +} + +/* +------------------------- +Signal +------------------------- +*/ + +void ICARUS_Instance::Signal( const char *identifier ) +{ + m_signals[ identifier ] = 1; +} + +/* +------------------------- +CheckSignal +------------------------- +*/ + +bool ICARUS_Instance::CheckSignal( const char *identifier ) +{ + signal_m::iterator smi; + + smi = m_signals.find( identifier ); + + if ( smi == m_signals.end() ) + return false; + + return true; +} + +/* +------------------------- +ClearSignal +------------------------- +*/ + +void ICARUS_Instance::ClearSignal( const char *identifier ) +{ + m_signals.erase( identifier ); +} diff --git a/Projects/Android/jni/OpenJK/codemp_delete/icarus/Interface.cpp b/Projects/Android/jni/OpenJK/codemp_delete/icarus/Interface.cpp new file mode 100644 index 0000000..fa64e91 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/icarus/Interface.cpp @@ -0,0 +1,43 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +// ICARUS Engine Interface File +// +// This file is the only section of the ICARUS systems that +// is not directly portable from engine to engine. +// +// -- jweier + +#include "game/g_public.h" + +#include "interface.h" +/* +void Interface_Init( interface_export_t *pe ) +{ + + //TODO: This is where you link up all your functions to the engine + + //Example: + // + // pe->I_GetEntityByName = ENGINE_GetEntityByName; +} +*/ diff --git a/Projects/Android/jni/OpenJK/codemp_delete/icarus/Interpreter.cpp b/Projects/Android/jni/OpenJK/codemp_delete/icarus/Interpreter.cpp new file mode 100644 index 0000000..53a29dc --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/icarus/Interpreter.cpp @@ -0,0 +1,2513 @@ +// Token Interpreter +// +// -- jweier + +#ifdef _WIN32 +#include //For getcwd() +#include //For getch() +#else +#include +#include +extern void *ICARUS_Malloc(int iSize); +extern void ICARUS_Free(void *pMem); +#endif +#include + +#include "tokenizer.h" +#include "blockstream.h" +#include "interpreter.h" + +/* +=================================================================================================== + + Table Definitions + +=================================================================================================== +*/ + +//FIXME: The following tables should be passed in to the interpreter for flexibility + +//Symbol Table + +keywordArray_t CInterpreter::m_symbolKeywords[] = +{ + //Blocks + "{", TK_BLOCK_START, + "}", TK_BLOCK_END, + + //Vectors + "<", TK_VECTOR_START, + ">", TK_VECTOR_END, + + //Groups + "(", TK_OPEN_PARENTHESIS, + ")", TK_CLOSED_PARENTHESIS, + + "=", TK_EQUALS, + "!", TK_NOT, + + //End + "", TK_EOF, +}; + +keywordArray_t CInterpreter::m_conditionalKeywords[] = +{ + "", TK_EOF, +}; + +//ID Table + +keywordArray_t CInterpreter::m_IDKeywords[] = +{ + "AFFECT", ID_AFFECT, + "SOUND", ID_SOUND, + "MOVE", ID_MOVE, + "ROTATE", ID_ROTATE, + "WAIT", ID_WAIT, + "SET", ID_SET, + "LOOP", ID_LOOP, + "PRINT", ID_PRINT, + "TAG", ID_TAG, + "USE", ID_USE, + "FLUSH", ID_FLUSH, + "RUN", ID_RUN, + "KILL", ID_KILL, + "REMOVE", ID_REMOVE, + "CAMERA", ID_CAMERA, + "GET", ID_GET, + "RANDOM", ID_RANDOM, + "IF", ID_IF, + "ELSE", ID_ELSE, + "REM", ID_REM, + "FLOAT", TK_FLOAT, + "VECTOR", TK_VECTOR, + "STRING", TK_STRING, + "TASK", ID_TASK, + "DO", ID_DO, + "DECLARE", ID_DECLARE, + "FREE", ID_FREE, + "DOWAIT", ID_DOWAIT, + "SIGNAL", ID_SIGNAL, + "WAITSIGNAL", ID_WAITSIGNAL, + "PLAY", ID_PLAY, + + "", ID_EOF, +}; + +//Type Table + +keywordArray_t CInterpreter::m_typeKeywords[] = +{ + //Set types + "ANGLES", TYPE_ANGLES, + "ORIGIN", TYPE_ORIGIN, + + //Affect types + "INSERT", TYPE_INSERT, + "FLUSH", TYPE_FLUSH, + + //Get types + "FLOAT", TK_FLOAT, + "INT", TK_INT, + "VECTOR", TK_VECTOR, + "STRING", TK_STRING, + + "PAN", TYPE_PAN, + "ZOOM", TYPE_ZOOM, + "MOVE", TYPE_MOVE, + "FADE", TYPE_FADE, + "PATH", TYPE_PATH, + "ENABLE", TYPE_ENABLE, + "DISABLE", TYPE_DISABLE, + "SHAKE", TYPE_SHAKE, + "ROLL", TYPE_ROLL, + "TRACK", TYPE_TRACK, + "FOLLOW", TYPE_FOLLOW, + "DISTANCE", TYPE_DISTANCE, + + //End + "", TYPE_EOF, +}; + + +/* +=================================================================================================== + + Constructor / Destructor + +=================================================================================================== +*/ + +CInterpreter::CInterpreter() +{ +} + +CInterpreter::~CInterpreter() +{ +} + +/* +=================================================================================================== + + Error Handling + +=================================================================================================== +*/ + +int CInterpreter::Error( char *format, ... ) +{ + va_list argptr; + char *error_file, error_msg[1024]="", work_dir[1024]="", out_msg[1024]=""; + int error_line = m_iCurrentLine; // m_tokenizer->GetCurLine(); + + m_tokenizer->GetCurFilename( &error_file ); + if (!error_file) + { + // 99% of the time we'll get here now, because of pushed parse streams + // + error_file = (char *)m_sCurrentFile.c_str(); + } + + va_start (argptr, format); + vsprintf (error_msg, format, argptr); + va_end (argptr); + + strcpy((char *) work_dir, getcwd( (char *) &work_dir, 1024 ) ); + + if (error_file[1] == ':') + { + sprintf((char *) out_msg, "%s (%d) : error: %s\n", error_file, error_line, error_msg); + } + else + { + sprintf((char *) out_msg, "%s\\%s (%d) : error: %s\n", work_dir, error_file, error_line, error_msg); + } + + if (m_sCurrentLine.length()) + { + strcat(out_msg, "\nLine:\n\n"); + strcat(out_msg, m_sCurrentLine.c_str()); + strcat(out_msg, "\n"); + } + +#ifdef __POP_UPS__ + + MessageBox( NULL, out_msg, "Error", MB_OK ); + +#else + + printf(out_msg); + +#endif + + // A bit of kludge code that takes care of the case where there's some garbage at the beginning of the file + // before any blocks are read as valid. This is needed because ints are incapable of containing 0 + // + // This'll mean that technically it's saying block 1 is wrong, rather than the one in between them, but I can + // live with that. + // + if (m_iBadCBlockNumber == 0) + { + m_iBadCBlockNumber = 1; + } + return false; +} + +/* +=================================================================================================== + + Local Variable Functions + +=================================================================================================== +*/ + +/* +------------------------- +InitVars +------------------------- +*/ + +void CInterpreter::InitVars( void ) +{ + m_vars.clear(); + m_varMap.clear(); +} + +/* +------------------------- +FreeVars +------------------------- +*/ + +void CInterpreter::FreeVars( void ) +{ + variable_v::iterator vi; + + for ( vi = m_vars.begin(); vi != m_vars.end(); ++vi ) + { + delete (*vi); + } + + InitVars(); +} + +/* +------------------------- +AddVar +------------------------- +*/ + +variable_t *CInterpreter::AddVar( const char *name, int type ) +{ + variable_t *var; + + var = new variable_t; + + if ( var == NULL ) + return NULL; + + //Specify the type + var->type = type; + + //Retain the name internally + strncpy( (char *) var->name, name, MAX_VAR_NAME ); + + //Associate it + m_varMap[ name ] = var; + + return var; +} + +/* +------------------------- +FindVar +------------------------- +*/ + +variable_t *CInterpreter::FindVar( const char *name ) +{ + variable_m::iterator vmi; + + vmi = m_varMap.find( name ); + + if ( vmi == m_varMap.end() ) + return NULL; + + return (*vmi).second; +} + +/* +------------------------- +GetVariable +------------------------- +*/ + +int CInterpreter::GetVariable( int type ) +{ + const char *varName; + variable_t *var; + CToken *token; + + //Get the variable's name + token = m_tokenizer->GetToken( 0, 0 ); + varName = token->GetStringValue(); + + //See if we already have a variable by this name + var = FindVar( varName ); + + //Variable names must be unique on creation + if ( var ) + return Error( "\"%s\" : already exists\n", varName ); + + //Add the variable + AddVar( varName, type ); + + //Insert the variable into the stream + + CBlock block; + + block.Create( TYPE_VARIABLE ); + block.Write( TK_FLOAT, (float) type ); + block.Write( TK_STRING, varName ); + + m_blockStream->WriteBlock( &block ); + + token->Delete(); + + return true; +} + +/* +=================================================================================================== + + ID Table Functions + +=================================================================================================== +*/ + +int CInterpreter::GetVector( CBlock *block ) +{ + //Look for a tag + if ( MatchTag() ) + { + return GetTag( block ); + } + + //Look for a get + if ( MatchGet() ) + { + return GetGet( block ); + } + + if ( Match( TK_VECTOR_START ) ) + { + //Get the vector + block->Write( TK_VECTOR, (float) TK_VECTOR ); + + for (int i=0; i<3; i++) + GetFloat( block ); + + if (!Match( TK_VECTOR_END )) + { + return Error("syntax error : expected end of vector"); + } + + return true; + } + + return false; +} + +/* +=================================================================================================== + + MatchTag() + + Attempts to match to a tag identifier. + +=================================================================================================== +*/ + +int CInterpreter::MatchTag( void ) +{ + CToken *token; + const char *idName; + int id; + + token = m_tokenizer->GetToken( 0, 0 ); + idName = token->GetStringValue(); + id = FindSymbol( idName, m_IDKeywords ); + + if ( id != ID_TAG ) + { + //Return the token + m_tokenizer->PutBackToken( token ); + return false; + } + + token->Delete(); + return true; +} + +/* +=================================================================================================== + + MatchGet() + + Attempts to match to a get identifier. + +=================================================================================================== +*/ + +int CInterpreter::MatchGet( void ) +{ + CToken *token; + const char *idName; + int id; + + token = m_tokenizer->GetToken( 0, 0 ); + idName = token->GetStringValue(); + id = FindSymbol( idName, m_IDKeywords ); + + if ( id != ID_GET ) + { + //Return the token + m_tokenizer->PutBackToken( token ); + return false; + } + + token->Delete(); + return true; +} + +/* +=================================================================================================== + + MatchRandom() + + Attempts to match to a random identifier. + +=================================================================================================== +*/ + +int CInterpreter::MatchRandom( void ) +{ + CToken *token; + const char *idName; + int id; + + token = m_tokenizer->GetToken( 0, 0 ); + idName = token->GetStringValue(); + id = FindSymbol( idName, m_IDKeywords ); + + if ( id != ID_RANDOM ) + { + //Return the token + m_tokenizer->PutBackToken( token ); + return false; + } + + token->Delete(); + return true; +} + +/* +=================================================================================================== + + FindSymbol() + + Searches the symbol table for the given name. Returns the ID if found. + +=================================================================================================== +*/ + +int CInterpreter::FindSymbol( const char *name, keywordArray_t *table) +{ + keywordArray_t *ids; + + for (ids = table; (strcmp(ids->m_keyword, "")); ids++) + { + if (!stricmp(name, ids->m_keyword)) + return ids->m_tokenvalue; + } + + return -1; +} + + +/* +=================================================================================================== + + Match() + + Looks ahead to the next token to try and match it to the passed token, consumes token on success. + +=================================================================================================== +*/ + +//NOTENOTE: LookAhead() was separated from Match() for clarity + +int CInterpreter::Match( int token_id ) +{ + CToken *token; + + token = m_tokenizer->GetToken( 0, 0 ); + + if ( token->GetType() != token_id ) + { + //This may have been a check, so don't loose the token + m_tokenizer->PutBackToken( token ); + + return false; + } + + return true; +} + +/* +------------------------- +GetNextType +------------------------- +*/ + +int CInterpreter::GetNextType( void ) +{ + CToken *token = m_tokenizer->GetToken( 0, 0 ); + int id = token->GetType(); + + m_tokenizer->PutBackToken( token ); + + return id; +} + +/* +=================================================================================================== + + LookAhead() + + Looks ahead without consuming on success. + +=================================================================================================== +*/ + +int CInterpreter::LookAhead( int token_id ) +{ + CToken *token; + + token = m_tokenizer->GetToken( 0, 0 ); + + if ( token->GetType() != token_id ) + { + m_tokenizer->PutBackToken( token ); + + return false; + } + + m_tokenizer->PutBackToken( token ); + + return true; +} + +/* +=================================================================================================== + + GetTokenName() + + Returns the name of a token. + +=================================================================================================== +*/ + +const char *CInterpreter::GetTokenName( int token_id ) +{ + switch ( token_id ) + { + case TK_STRING: + return "STRING"; + break; + + case TK_CHAR: + return "CHARACTER"; + break; + + case TK_IDENTIFIER: + return "IDENTIFIER"; + break; + + case TK_FLOAT: + return "FLOAT"; + break; + + case TK_INTEGER: + return "INTEGER"; + break; + + default: + return "UNKNOWN"; + break; + } +} + +/* +=================================================================================================== + + Token Value Functions + +=================================================================================================== +*/ + +/* +=================================================================================================== + + GetFloat() + + Attempts to match and retrieve the value of a float token. + +=================================================================================================== +*/ + +int CInterpreter::GetFloat( CBlock *block ) +{ + CToken *token; + int type; + + //Look for a get + if ( MatchGet() ) + { + return GetGet( block ); + } + + //Look for a random + if ( MatchRandom() ) + { + return GetRandom( block ); + } + + token = m_tokenizer->GetToken(0,0); + type = token->GetType(); + + //Floats can accept either int or float values + if ( ( type != TK_FLOAT ) && ( type != TK_INT ) ) + { + return Error("syntax error : expected float; found %s", GetTokenName(type) ); + } + + if (type == TK_FLOAT) + { + block->Write( TK_FLOAT, (float) token->GetFloatValue() ); + } + else + { + block->Write( TK_FLOAT, (float) token->GetIntValue() ); + } + + token->Delete(); + + return true; +} + +/* +=================================================================================================== + + GetInteger() + + Attempts to match and retrieve the value of an integer token. + +=================================================================================================== +*/ + +int CInterpreter::GetInteger( CBlock *block ) +{ + return GetFloat( block ); +} + +/* +=================================================================================================== + + GetString() + + Attempts to match and retrieve the value of a string token. + +=================================================================================================== +*/ + +int CInterpreter::GetString( CBlock *block ) +{ + CToken *token; + int type; + + //Look for a get + if ( MatchGet() ) + { + return GetGet( block ); + } + + //Look for a random + if ( MatchRandom() ) + { + return GetRandom( block ); + } + + token = m_tokenizer->GetToken(0, 0); + type = token->GetType(); + + if ( (type != TK_STRING) && (type != TK_CHAR) ) + { + return Error("syntax error : expected string; found %s", GetTokenName(type)); + } + +//UGLY HACK!!! + + const char *temptr; + char temp[1024]; + + temptr = token->GetStringValue(); + + if ( strlen(temptr)+1 > sizeof( temp ) ) + { + return false; + } + + for ( int i = 0; i < (int)strlen( temptr ); i++ ) + { + if ( temptr[i] == '#' ) + temp[i] = '\n'; + else + temp[i] = temptr[i]; + } + + temp[ strlen( temptr ) ] = 0; + +//UGLY HACK END!!! + + block->Write( TK_STRING, (const char *) &temp ); + + token->Delete(); + + return true; +} + +/* +=================================================================================================== + + GetIdentifier() + + Attempts to match and retrieve the value of an indentifier token. + +=================================================================================================== +*/ + +int CInterpreter::GetIdentifier( CBlock *block ) +{ + CToken *token; + int type; + + //FIXME: Should identifiers do this? + if ( MatchGet() ) + { + if ( GetGet( block ) == false ) + return false; + + return true; + } + + token = m_tokenizer->GetToken(0, 0); + type = token->GetType(); + + if ( type != TK_IDENTIFIER ) + { + return Error("syntax error : expected indentifier; found %s", GetTokenName(type)); + } + + block->Write( TK_IDENTIFIER, (const char *) token->GetStringValue() ); + + token->Delete(); + + return true; +} + +/* +=================================================================================================== + + GetEvaluator() + + Attempts to match and retrieve the value of an evaluator token. + +=================================================================================================== +*/ + +int CInterpreter::GetEvaluator( CBlock *block ) +{ + CToken *token; + int type; + + if ( MatchGet() ) + return false; + + if ( MatchRandom() ) + return false; + + token = m_tokenizer->GetToken(0, 0); + type = token->GetType(); + token->Delete(); + + switch ( type ) + { + case TK_GREATER_THAN: + case TK_LESS_THAN: + case TK_EQUALS: + case TK_NOT: + break; + + case TK_VECTOR_START: + type = TK_LESS_THAN; + break; + + case TK_VECTOR_END: + type = TK_GREATER_THAN; + break; + + default: + return Error("syntax error : expected operator type, found %s", GetTokenName( type ) ); + } + + block->Write( type, 0 ); + + return true; +} + +/* +=================================================================================================== + + GetAny() + + Attempts to match and retrieve any valid data type. + +=================================================================================================== +*/ + +int CInterpreter::GetAny( CBlock *block ) +{ + CToken *token; + int type; + + if ( MatchGet() ) + { + if ( GetGet( block ) == false ) + return false; + + return true; + } + + if ( MatchRandom() ) + { + if ( GetRandom( block ) == false ) + return false; + + return true; + } + + if ( MatchTag() ) + { + if ( GetTag( block ) == false ) + return false; + + return true; + } + + token = m_tokenizer->GetToken(0, 0); + type = token->GetType(); + + switch ( type ) + { + case TK_FLOAT: + m_tokenizer->PutBackToken( token ); + if ( GetFloat( block ) == false ) + return false; + + break; + + case TK_INT: + m_tokenizer->PutBackToken( token ); + if ( GetInteger( block ) == false ) + return false; + + break; + + case TK_VECTOR_START: + m_tokenizer->PutBackToken( token ); + if ( GetVector( block ) == false ) + return false; + + break; + + case TK_STRING: + case TK_CHAR: + m_tokenizer->PutBackToken( token ); + if ( GetString( block ) == false ) + return false; + + break; + + case TK_IDENTIFIER: + m_tokenizer->PutBackToken( token ); + if ( GetIdentifier( block ) == false ) + return false; + + break; + + default: + return false; + } + + return true; +} + +/* +=================================================================================================== + + GetType() + + Attempts to match and retrieve the value of a type token. + +=================================================================================================== +*/ + +int CInterpreter::GetType( char *get ) +{ + CToken *token; + char *string; + int type; + + token = m_tokenizer->GetToken(0, 0); + type = token->GetType(); + + if ( type != TK_IDENTIFIER ) + { + return Error("syntax error : expected identifier; found %s", GetTokenName(type)); + } + + string = (char *) token->GetStringValue(); + + if ( (strlen(string) + 1) > MAX_STRING_LENGTH) + { + Error("string exceeds 256 character limit"); + return false; + } + + strcpy(get, string); + + return true; +} + +/* +=================================================================================================== + + GetID() + + Attempts to match and interpret an identifier. + +=================================================================================================== +*/ + +//FIXME: This should use an externally defined table to match ID and functions + +int CInterpreter::GetID( char *id_name ) +{ + int id; + + id = FindSymbol( id_name, m_IDKeywords ); + + if ( id == -1 ) + return Error("'%s' : unknown identifier", id_name); + + //FIXME: Function pointers would be awfully nice.. but not inside a class! Weee!! + + switch (id) + { + + //Affect takes control of an entity + + case ID_AFFECT: + return GetAffect(); + break; + + //Wait for a specified amount of time + + case ID_WAIT: + return GetWait(); + break; + + //Generic set call + + case ID_SET: + return GetSet(); + break; + + case ID_LOOP: + return GetLoop(); + break; + + case ID_PRINT: + return GetPrint(); + break; + + case ID_USE: + return GetUse(); + break; + + case ID_FLUSH: + return GetFlush(); + break; + + case ID_RUN: + return GetRun(); + break; + + case ID_KILL: + return GetKill(); + break; + + case ID_REMOVE: + return GetRemove(); + break; + + case ID_CAMERA: + return GetCamera(); + break; + + case ID_SOUND: + return GetSound(); + break; + + case ID_MOVE: + return GetMove(); + break; + + case ID_ROTATE: + return GetRotate(); + break; + + case ID_IF: + return GetIf(); + break; + + case ID_ELSE: + //return Error("syntax error : else without matching if"); + return GetElse(); //FIXME: Protect this call so that floating else's aren't allowed + break; + + case ID_GET: + return Error("syntax error : illegal use of \"get\""); + break; + + case ID_TAG: + return Error("syntax error : illegal use of \"tag\""); + break; + + case ID_TASK: + return GetTask(); + break; + + case ID_DO: + return GetDo(); + break; + + case ID_DECLARE: + return GetDeclare(); + break; + + case ID_FREE: + return GetFree(); + break; + + case ID_REM: + GetRem(); + break; + + case ID_DOWAIT: + GetDoWait(); + break; + + case ID_SIGNAL: + GetSignal(); + break; + + case ID_WAITSIGNAL: + GetWaitSignal(); + break; + + case ID_PLAY: + GetPlay(); //Bad eighties slang joke... yeah, it's not really funny, I know... + break; + + //Local variable types + case TK_FLOAT: + case TK_INT: + case TK_STRING: + case TK_VECTOR: + GetVariable( id ); + break; + + //Unknown ID + + default: + case -1: + return Error("'%s' : unknown identifier", id_name); + break; + } + + return true; +} + +/* +=================================================================================================== + + ID Interpreting Functions + +=================================================================================================== +*/ + +/* +------------------------- +GetDeclare +------------------------- +*/ + +int CInterpreter::GetDeclare( void ) +{ + CBlock block; + char typeName[MAX_STRING_LENGTH]; + int type; + + block.Create( ID_DECLARE ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetType( (char *) typeName ) == false ) + return false; + + type = FindSymbol( typeName, m_typeKeywords); + + switch ( type ) + { + case TK_FLOAT: + case TK_VECTOR: + case TK_STRING: + block.Write( TK_FLOAT, (float) type ); + break; + + default: + return Error("unknown identifier %s", typeName ); + break; + } + + if ( GetString( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("declare : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + + +/* +------------------------- +GetFree +------------------------- +*/ + +int CInterpreter::GetFree( void ) +{ + CBlock block; + + block.Create( ID_FREE ); + + if ( Match( TK_OPEN_PARENTHESIS ) == false ) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + if ( Match( TK_CLOSED_PARENTHESIS ) == false ) + return Error("free : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetIf() + + Handles the if() conditional statement. + +=================================================================================================== +*/ + +// if ( STRING ? STRING ) + +int CInterpreter::GetIf( void ) +{ + CBlock block; + + block.Create( ID_IF ); + + if ( Match( TK_OPEN_PARENTHESIS ) == false ) + return Error("syntax error : '(' not found"); + + if ( GetAny( &block ) == false ) + return false; + + if ( GetEvaluator( &block ) == false ) + return false; + + if ( GetAny( &block ) == false ) + return false; + + if ( Match( TK_CLOSED_PARENTHESIS ) == false ) + return Error("if : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetElse() + + Handles the else() conditional statement. + +=================================================================================================== +*/ + +// else + +int CInterpreter::GetElse( void ) +{ + CBlock block; + + block.Create( ID_ELSE ); + + /* + if ( Match( TK_OPEN_PARENTHESIS ) == false ) + return Error("syntax error : '(' not found"); + */ + + /* + if ( GetAny( &block ) == false ) + return false; + + if ( GetEvaluator( &block ) == false ) + return false; + + if ( GetAny( &block ) == false ) + return false; + */ + + /* + if ( Match( TK_CLOSED_PARENTHESIS ) == false ) + return Error("sound : too many parameters"); + */ + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetTask() + + Handles the task() sequence specifier. + +=================================================================================================== +*/ + +//task ( name ) { } + +int CInterpreter::GetTask( void ) +{ + CBlock block; + + block.Create( ID_TASK ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("GetTask: too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; + +} + +/* +=================================================================================================== + + GetDo() + + Handles the do() function. + +=================================================================================================== +*/ + +//do ( taskName ) + +int CInterpreter::GetDo( void ) +{ + CBlock block; + + block.Create( ID_DO ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("do : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetGet() + + Handles the get() function. + +=================================================================================================== +*/ + +// get( TYPE, NAME ); + +int CInterpreter::GetGet( CBlock *block ) +{ + char typeName[MAX_STRING_LENGTH]; + int type; + + block->Write( ID_GET, (float) ID_GET ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetType( (char *) typeName ) == false ) + return false; + + type = FindSymbol( typeName, m_typeKeywords); + + switch ( type ) + { + case TK_FLOAT: + case TK_INT: + case TK_VECTOR: + case TK_STRING: + block->Write( TK_FLOAT, (float) type ); + break; + + default: + return Error("unknown identifier %s", typeName ); + break; + } + + if ( GetString( block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("affect : too many parameters"); + + return true; +} + +/* +=================================================================================================== + + GetRandom() + + Handles the random() function. + +=================================================================================================== +*/ + +// random( low, high ); + +int CInterpreter::GetRandom( CBlock *block ) +{ + block->Write( ID_RANDOM, (float) ID_RANDOM ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetFloat( block ) == false ) + return false; + + if ( GetFloat( block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("affect : too many parameters"); + + return true; +} + +/* +=================================================================================================== + + GetSound() + + Handles the sound() function. + +=================================================================================================== +*/ + +// sound( NAME ); + +int CInterpreter::GetSound( void ) +{ + CBlock block; + + block.Create( ID_SOUND ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetIdentifier( &block ) == false ) + return false; + + if ( GetString( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("sound : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetMove() + + Handles the move() function. + +=================================================================================================== +*/ + +// move( ORIGIN, ANGLES, DURATION ); + +int CInterpreter::GetMove( void ) +{ + CBlock block; + + block.Create( ID_MOVE ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetVector( &block ) == false ) + return false; + + //Angles are optional + if ( LookAhead( TK_VECTOR_START ) || LookAhead( TK_IDENTIFIER ) ) + { + if ( GetVector( &block ) == false ) + return false; + } + + if ( GetFloat( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("move : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetRotate() + + Handles the rotate() function. + +=================================================================================================== +*/ + +// move( ANGLES, DURATION ); + +int CInterpreter::GetRotate( void ) +{ + CBlock block; + + block.Create( ID_ROTATE ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetVector( &block ) == false ) + return false; + + if ( GetFloat( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("move : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetAffect() + + Handles the affect() function. + +=================================================================================================== +*/ + +//FIXME: This should be externally defined + +int CInterpreter::GetAffect( void ) +{ + CBlock block; + char typeName[MAX_STRING_SIZE]; + int type; + + block.Create( ID_AFFECT ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + if (!LookAhead( TK_IDENTIFIER )) + return Error("syntax error : identifier not found"); + + if ( MatchGet() ) + return Error("syntax error : illegal use of \"get\""); + + if ( GetType( (char *) typeName ) == false ) + return false; + + type = FindSymbol( typeName, m_typeKeywords); + + switch ( type ) + { + case TYPE_INSERT: + case TYPE_FLUSH: + + block.Write( TK_FLOAT, (float) type ); + break; + + default: + return Error("'%s': unknown affect type", typeName ); + break; + + } + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("affect : too many parameters"); + + if (!LookAhead( TK_BLOCK_START )) + return Error("syntax error : '{' not found"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetWait() + + Handles the wait() function. + +=================================================================================================== +*/ + +//FIXME: This should be externally defined + +int CInterpreter::GetWait( void ) +{ + CBlock block; + + block.Create( ID_WAIT ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( LookAhead( TK_STRING ) ) + { + if ( GetString( &block ) == false ) + return false; + } + else + { + if ( GetFloat( &block ) == false ) + return false; + } + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("wait : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetSet() + + Handles the set() function. + +=================================================================================================== +*/ + +//FIXME: This should be externally defined + +int CInterpreter::GetSet( void ) +{ + CBlock block; + + block.Create( ID_SET ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + //Check for get placement + if ( MatchGet() ) + { + if ( GetGet( &block ) == false ) + return false; + } + else + { + switch( GetNextType() ) + { + case TK_INT: + + if ( GetInteger( &block ) == false ) + return false; + + break; + + case TK_FLOAT: + + if ( GetFloat( &block ) == false ) + return false; + + break; + + case TK_STRING: + + if ( GetString( &block ) == false ) + return false; + + break; + + case TK_VECTOR_START: + + if ( GetVector( &block ) == false ) + return false; + + break; + + default: + + if ( MatchTag() ) + { + GetTag( &block ); + break; + } + + if ( MatchRandom() ) + { + GetRandom( &block ); + break; + } + + return Error("unknown parameter type"); + break; + } + } + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("set : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetLoop() + + Handles the loop() function. + +=================================================================================================== +*/ + +int CInterpreter::GetLoop( void ) +{ + CBlock block; + + block.Create( ID_LOOP ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( LookAhead( TK_CLOSED_PARENTHESIS ) ) + { + //-1 denotes an infinite loop + block.Write( TK_FLOAT, (float) -1); + } + else + { + if ( GetInteger( &block ) == false ) + return false; + } + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("GetLoop : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetPrint() + + Handles the print() function. + +=================================================================================================== +*/ + +int CInterpreter::GetPrint( void ) +{ + CBlock block; + + block.Create( ID_PRINT ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("print : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetUse() + + Handles the use() function. + +=================================================================================================== +*/ + +int CInterpreter::GetUse( void ) +{ + CBlock block; + + block.Create( ID_USE ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("use : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetFlush() + + Handles the flush() function. + +=================================================================================================== +*/ + +int CInterpreter::GetFlush( void ) +{ + CBlock block; + + block.Create( ID_FLUSH ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("flush : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetRun() + + Handles the run() function. + +=================================================================================================== +*/ + +int CInterpreter::GetRun( void ) +{ + CBlock block; + + block.Create( ID_RUN ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("run : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetKill() + + Handles the kill() function. + +=================================================================================================== +*/ + +int CInterpreter::GetKill( void ) +{ + CBlock block; + + block.Create( ID_KILL ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("kill : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetRemove() + + Handles the remove() function. + +=================================================================================================== +*/ + +int CInterpreter::GetRemove( void ) +{ + CBlock block; + + block.Create( ID_REMOVE ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("remove : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetRem() + + Handles the rem() function. + +=================================================================================================== +*/ + +// this is just so people can put comments in scripts in BehavEd and not have them lost as normal comments would be. +// +int CInterpreter::GetRem( void ) +{ + CBlock block; + + block.Create( ID_REM ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + // optional string? + + if (Match( TK_CLOSED_PARENTHESIS )) + return true; + + GetString( &block ); + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("rem : function only takes 1 optional parameter"); + + return true; +} + + +/* +=================================================================================================== + + GetCamera() + + Handles the camera() function. + +=================================================================================================== +*/ + +int CInterpreter::GetCamera( void ) +{ + CBlock block; + char typeName[MAX_STRING_SIZE]; + int type; + + block.Create( ID_CAMERA ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetType( (char *) typeName ) == false ) + return false; + + type = FindSymbol( typeName, m_typeKeywords); + + switch ( type ) + { + case TYPE_PAN: //PAN ( ANGLES, DURATION ) + + block.Write( TK_FLOAT, (float) type ); + + if ( GetVector( &block ) == false ) + return false; + + if ( GetVector( &block ) == false ) + return false; + + if ( GetFloat( &block ) == false ) + return false; + + break; + + case TYPE_ZOOM: //ZOOM ( FOV, DURATION ) + + block.Write( TK_FLOAT, (float) type ); + + if ( GetFloat( &block ) == false ) + return false; + + if ( GetFloat( &block ) == false ) + return false; + + break; + + case TYPE_MOVE: //MOVE ( ORIGIN, DURATION ) + + block.Write( TK_FLOAT, (float) type ); + + if ( GetVector( &block ) == false ) + return false; + + if ( GetFloat( &block ) == false ) + return false; + + break; + + case TYPE_FADE: //FADE ( SOURCE(R,G,B,A), DEST(R,G,B,A), DURATION ) + + block.Write( TK_FLOAT, (float) type ); + + //Source color + if ( GetVector( &block ) == false ) + return false; + if ( GetFloat( &block ) == false ) + return false; + + //Dest color + if ( GetVector( &block ) == false ) + return false; + if ( GetFloat( &block ) == false ) + return false; + + //Duration + if ( GetFloat( &block ) == false ) + return false; + + break; + + case TYPE_PATH: //PATH ( FILENAME ) + + block.Write( TK_FLOAT, (float) type ); + + //Filename + if ( GetString( &block ) == false ) + return false; + + break; + + case TYPE_ENABLE: + case TYPE_DISABLE: + + block.Write( TK_FLOAT, (float) type ); + break; + + case TYPE_SHAKE: //SHAKE ( INTENSITY, DURATION ) + + block.Write( TK_FLOAT, (float) type ); + + //Intensity + if ( GetFloat( &block ) == false ) + return false; + + //Duration + if ( GetFloat( &block ) == false ) + return false; + + break; + + case TYPE_ROLL: //ROLL ( ANGLE, TIME ) + + block.Write( TK_FLOAT, (float) type ); + + //Angle + if ( GetFloat( &block ) == false ) + return false; + + //Time + if ( GetFloat( &block ) == false ) + return false; + + break; + + case TYPE_TRACK: //TRACK ( TARGETNAME, SPEED, INITLERP ) + + block.Write( TK_FLOAT, (float) type ); + + //Target name + if ( GetString( &block ) == false ) + return false; + + //Speed + if ( GetFloat( &block ) == false ) + return false; + + //Init lerp + if ( GetFloat( &block ) == false ) + return false; + + break; + + case TYPE_FOLLOW: //FOLLOW ( CAMERAGROUP, SPEED, INITLERP ) + + block.Write( TK_FLOAT, (float) type ); + + //Camera group + if ( GetString( &block ) == false ) + return false; + + //Speed + if ( GetFloat( &block ) == false ) + return false; + + //Init lerp + if ( GetFloat( &block ) == false ) + return false; + + break; + + case TYPE_DISTANCE: //DISTANCE ( DISTANCE, INITLERP ) + + block.Write( TK_FLOAT, (float) type ); + + //Distance + if ( GetFloat( &block ) == false ) + return false; + + //Init lerp + if ( GetFloat( &block ) == false ) + return false; + + break; + } + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("camera : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +------------------------- +GetDoWait +------------------------- +*/ + +int CInterpreter::GetDoWait( void ) +{ + CBlock block; + + //Write out the "do" portion + block.Create( ID_DO ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("do : too many parameters"); + + //Write out the accompanying "wait" + char *str = (char *) block.GetMemberData( 0 ); + + CBlock block2; + + block2.Create( ID_WAIT ); + + block2.Write( TK_STRING, (char *) str ); + + m_blockStream->WriteBlock( &block ); + m_blockStream->WriteBlock( &block2 ); + + return true; +} + +/* +------------------------- +GetSignal +------------------------- +*/ + +int CInterpreter::GetSignal( void ) +{ + CBlock block; + + block.Create( ID_SIGNAL ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("signal : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +------------------------- +GetSignal +------------------------- +*/ + +int CInterpreter::GetWaitSignal( void ) +{ + CBlock block; + + block.Create( ID_WAITSIGNAL ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("waitsignal : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +------------------------- +GetPlay +------------------------- +*/ + +int CInterpreter::GetPlay( void ) +{ + CBlock block; + + block.Create( ID_PLAY ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + if ( GetString( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("waitsignal : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetTag() + + Handles the tag() identifier. + +=================================================================================================== +*/ + +//NOTENOTE: The tag's information is included as block members, not as a separate block. + +int CInterpreter::GetTag( CBlock *block ) +{ + char typeName[MAX_STRING_SIZE]; + int typeID; + + //Mark as a tag + block->Write( ID_TAG, (float) ID_TAG ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + //Get the tag name + if ( GetString( block ) == false ) + return false; + + //Get the lookup ID + GetType( (char *) typeName ); + + typeID = FindSymbol( (char *) typeName, m_typeKeywords); + + //Tags only contain origin and angles lookups + if ( (typeID != TYPE_ORIGIN) && (typeID != TYPE_ANGLES) ) + { + return Error("syntax error : 'tag' : %s is not a valid look up identifier", typeName ); + } + + block->Write( TK_FLOAT, (float) typeID ); + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("tag : too many parameters"); + + return true; +} + +/* +=================================================================================================== + + Interpret function + +=================================================================================================== +*/ + +// note new return type, this now returns the bad block number, else 0 for success. +// +// I also return -ve block numbers for errors between blocks. Eg if you read 3 good blocks, then find an unexpected +// float in the script between blocks 3 & 4 then I return -3 to indicate the error is after that, but not block 4 +// +int CInterpreter::Interpret( CTokenizer *Tokenizer, CBlockStream *BlockStream, char *filename ) +{ + CBlock block; + CToken *token; + int type, blockLevel = 0, parenthesisLevel = 0; + + m_sCurrentFile = filename; // used during error reporting because you can't ask tokenizer for pushed streams + + m_tokenizer = Tokenizer; + m_blockStream = BlockStream; + + m_iCurrentLine = m_tokenizer->GetCurLine(); + token = m_tokenizer->GetToEndOfLine(TK_STRING); + m_sCurrentLine = token->GetStringValue(); + m_tokenizer->PutBackToken(token, false, NULL, true); + + m_iBadCBlockNumber = 0; + + while (m_tokenizer->GetRemainingSize() > 0) + { + token = m_tokenizer->GetToken( TKF_USES_EOL, 0 ); + type = token->GetType(); + + switch ( type ) + { + case TK_UNDEFINED: + token->Delete(); + m_iBadCBlockNumber = -m_iBadCBlockNumber; + Error("%d : undefined token", type); + return m_iBadCBlockNumber; + break; + + case TK_EOF: + break; + + case TK_EOL: + // read the next line, then put it back + token->Delete(); + m_iCurrentLine = m_tokenizer->GetCurLine(); + token = m_tokenizer->GetToEndOfLine(TK_STRING); + m_sCurrentLine = token->GetStringValue(); + m_tokenizer->PutBackToken(token, false, NULL, true); + break; + + case TK_CHAR: + case TK_STRING: + token->Delete(); + m_iBadCBlockNumber = -m_iBadCBlockNumber; + Error("syntax error : unexpected string"); + return m_iBadCBlockNumber; + break; + + case TK_INT: + token->Delete(); + m_iBadCBlockNumber = -m_iBadCBlockNumber; + Error("syntax error : unexpected integer"); + return m_iBadCBlockNumber; + break; + + case TK_FLOAT: + token->Delete(); + m_iBadCBlockNumber = -m_iBadCBlockNumber; + Error("syntax error : unexpected float"); + return m_iBadCBlockNumber; + break; + + case TK_IDENTIFIER: + m_iBadCBlockNumber++; + if (!GetID( (char *) token->GetStringValue() )) + { + token->Delete(); + return m_iBadCBlockNumber; + } + token->Delete(); + break; + + case TK_BLOCK_START: + token->Delete(); + if (parenthesisLevel) + { + m_iBadCBlockNumber = -m_iBadCBlockNumber; + Error("syntax error : brace inside parenthesis"); + return m_iBadCBlockNumber; + } + + blockLevel++; + break; + + case TK_BLOCK_END: + token->Delete(); + if (parenthesisLevel) + { + m_iBadCBlockNumber = -m_iBadCBlockNumber; + Error("syntax error : brace inside parenthesis"); + return m_iBadCBlockNumber; + } + + block.Create( ID_BLOCK_END ); + m_blockStream->WriteBlock( &block ); + block.Free(); + + blockLevel--; + break; + + case TK_OPEN_PARENTHESIS: + token->Delete(); + blockLevel++; + parenthesisLevel++; + break; + + case TK_CLOSED_PARENTHESIS: + token->Delete(); + blockLevel--; + parenthesisLevel--; + + if (parenthesisLevel<0) + { + m_iBadCBlockNumber = -m_iBadCBlockNumber; + Error("syntax error : closed parenthesis with no opening match"); + return m_iBadCBlockNumber; + } + break; + + case TK_VECTOR_START: + token->Delete(); + m_iBadCBlockNumber = -m_iBadCBlockNumber; + Error("syntax error : unexpected vector"); + return m_iBadCBlockNumber; + break; + + case TK_VECTOR_END: + token->Delete(); + m_iBadCBlockNumber = -m_iBadCBlockNumber; + Error("syntax error : unexpected vector"); + return m_iBadCBlockNumber; + break; + } + } + + if ( blockLevel ) + { + m_iBadCBlockNumber = -m_iBadCBlockNumber; + Error("error : open brace was not closed"); + return m_iBadCBlockNumber; + } + + if ( parenthesisLevel ) + { + m_iBadCBlockNumber = -m_iBadCBlockNumber; + Error("error: open parenthesis"); + return m_iBadCBlockNumber; + } + + //Release all the variable information, because it's already been written out + FreeVars(); + + m_iBadCBlockNumber = 0; + return m_iBadCBlockNumber; //true; +} + diff --git a/Projects/Android/jni/OpenJK/codemp_delete/icarus/Memory.cpp b/Projects/Android/jni/OpenJK/codemp_delete/icarus/Memory.cpp new file mode 100644 index 0000000..d9d907c --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/icarus/Memory.cpp @@ -0,0 +1,39 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#include "icarus.h" + +// leave these two as standard mallocs for the moment, there's something weird happening in ICARUS... +// +void *ICARUS_Malloc(int iSize) +{ + //return gi.Malloc(iSize, TAG_ICARUS); + //return malloc(iSize); + return Z_Malloc(iSize, TAG_ICARUS5, qfalse); +} + +void ICARUS_Free(void *pMem) +{ + //gi.Free(pMem); + //free(pMem); + Z_Free(pMem); +} diff --git a/Projects/Android/jni/OpenJK/codemp_delete/icarus/Q3_Interface.cpp b/Projects/Android/jni/OpenJK/codemp_delete/icarus/Q3_Interface.cpp new file mode 100644 index 0000000..059d65d --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/icarus/Q3_Interface.cpp @@ -0,0 +1,1023 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +// ICARUS Engine Interface File +// +// This file is the only section of the ICARUS systems that +// is not directly portable from engine to engine. +// +// -- jweier + +#include "game/g_public.h" +#include "server/server.h" +#include "interface.h" +#include "GameInterface.h" +#include "Q3_Interface.h" +#include "Q3_Registers.h" +#include "server/sv_gameapi.h" + +#define stringIDExpand(str, strEnum) str, strEnum, ENUM2STRING(strEnum) +//#define stringIDExpand(str, strEnum) str,strEnum + +/* +stringID_table_t tagsTable [] = +{ +} +*/ + +extern float Q_flrand(float min, float max); +extern qboolean COM_ParseString( char **data, char **s ); + +//======================================================================= + +interface_export_t interface_export; + + +/* +============ +Q3_ReadScript + Description : Reads in a file and attaches the script directory properly + Return type : static int + Argument : const char *name + Argument : void **buf +============ +*/ +extern int ICARUS_GetScript( const char *name, char **buf ); //g_icarus.cpp +static int Q3_ReadScript( const char *name, void **buf ) +{ + return ICARUS_GetScript( va( "%s/%s", Q3_SCRIPT_DIR, name ), (char**)buf ); //get a (hopefully) cached file +} + +/* +============ +Q3_CenterPrint + Description : Prints a message in the center of the screen + Return type : static void + Argument : const char *format + Argument : ... +============ +*/ +static void Q3_CenterPrint ( const char *format, ... ) +{ + + va_list argptr; + char text[1024]; + + va_start (argptr, format); + Q_vsnprintf(text, sizeof(text), format, argptr); + va_end (argptr); + + // FIXME: added '!' so you can print something that's hasn't been precached, '@' searches only for precache text + // this is just a TEMPORARY placeholder until objectives are in!!! -- dmv 11/26/01 + + if ((text[0] == '@') || text[0] == '!') // It's a key + { + if( text[0] == '!') + { + SV_SendServerCommand( NULL, "cp \"%s\"", (text+1) ); + return; + } + + SV_SendServerCommand( NULL, "cp \"%s\"", text ); + } + + Q3_DebugPrint( WL_VERBOSE, "%s\n", text); // Just a developers note + + return; +} + + +/* +------------------------- +void Q3_ClearTaskID( int *taskID ) + +WARNING: Clearing a taskID will make that task never finish unless you intend to + return the same taskID from somewhere else. +------------------------- +*/ +void Q3_TaskIDClear( int *taskID ) +{ + *taskID = -1; +} + +/* +------------------------- +qboolean Q3_TaskIDPending( sharedEntity_t *ent, taskID_t taskType ) +------------------------- +*/ +qboolean Q3_TaskIDPending( sharedEntity_t *ent, taskID_t taskType ) +{ + if ( !gSequencers[ent->s.number] || !gTaskManagers[ent->s.number] ) + { + return qfalse; + } + + if ( taskType < TID_CHAN_VOICE || taskType >= NUM_TIDS ) + { + return qfalse; + } + + if ( ent->taskID[taskType] >= 0 )//-1 is none + { + return qtrue; + } + + return qfalse; +} + +/* +------------------------- +void Q3_TaskIDComplete( sharedEntity_t *ent, taskID_t taskType ) +------------------------- +*/ +void Q3_TaskIDComplete( sharedEntity_t *ent, taskID_t taskType ) +{ + if ( taskType < TID_CHAN_VOICE || taskType >= NUM_TIDS ) + { + return; + } + + if ( gTaskManagers[ent->s.number] && Q3_TaskIDPending( ent, taskType ) ) + {//Complete it + gTaskManagers[ent->s.number]->Completed( ent->taskID[taskType] ); + + //See if any other tasks have the name number and clear them so we don't complete more than once + int clearTask = ent->taskID[taskType]; + for ( int tid = 0; tid < NUM_TIDS; tid++ ) + { + if ( ent->taskID[tid] == clearTask ) + { + Q3_TaskIDClear( &ent->taskID[tid] ); + } + } + + //clear it - should be cleared in for loop above + //Q3_TaskIDClear( &ent->taskID[taskType] ); + } + //otherwise, wasn't waiting for a task to complete anyway +} + +/* +------------------------- +void Q3_SetTaskID( sharedEntity_t *ent, taskID_t taskType, int taskID ) +------------------------- +*/ + +void Q3_TaskIDSet( sharedEntity_t *ent, taskID_t taskType, int taskID ) +{ + if ( taskType < TID_CHAN_VOICE || taskType >= NUM_TIDS ) + { + return; + } + + //Might be stomping an old task, so complete and clear previous task if there was one + Q3_TaskIDComplete( ent, taskType ); + + ent->taskID[taskType] = taskID; +} + + +/* +============ +Q3_CheckStringCounterIncrement + Description : + Return type : static float + Argument : const char *string +============ +*/ +static float Q3_CheckStringCounterIncrement( const char *string ) +{ + char *numString; + float val = 0.0f; + + if ( string[0] == '+' ) + {//We want to increment whatever the value is by whatever follows the + + if ( string[1] ) + { + numString = (char *)&string[1]; + val = atof( numString ); + } + } + else if ( string[0] == '-' ) + {//we want to decrement + if ( string[1] ) + { + numString = (char *)&string[1]; + val = atof( numString ) * -1; + } + } + + return val; +} + +/* +============= +Q3_GetEntityByName + +Returns the sequencer of the entity by the given name +============= +*/ +static sharedEntity_t *Q3_GetEntityByName( const char *name ) +{ + sharedEntity_t *ent; + entlist_t::iterator ei; + char temp[1024]; + + if ( name == NULL || name[0] == '\0' ) + return NULL; + + strncpy( (char *) temp, name, sizeof(temp) ); + temp[sizeof(temp)-1] = 0; + + ei = ICARUS_EntList.find( Q_strupr( (char *) temp ) ); + + if ( ei == ICARUS_EntList.end() ) + return NULL; + + ent = SV_GentityNum((*ei).second); + + return ent; + // this now returns the ent instead of the sequencer -- dmv 06/27/01 +// if (ent == NULL) +// return NULL; +// return gSequencers[ent->s.number]; +} + +/* +============= +Q3_GetTime + +Get the current game time +============= +*/ +static unsigned int Q3_GetTime( void ) +{ + return svs.time; +} + +/* +============= +G_AddSexToMunroString + +Take any string, look for "kyle/" replace with "kyla/" based on "sex" +And: Take any string, look for "/mr_" replace with "/ms_" based on "sex" +returns qtrue if changed to ms +============= +*/ +/* +static qboolean G_AddSexToMunroString ( char *string, qboolean qDoBoth ) +{ + char *start; + + if VALIDSTRING( string ) { + if ( g_sex->string[0] == 'f' ) { + start = strstr( string, "kyle/" ); + if ( start != NULL ) { + strncpy( start, "kyla", 5 ); + return qtrue; + } else { + start = strrchr( string, '/' ); //get the last slash before the wav + if (start != NULL) { + if (!Q_strncmp( start, "/mr_", 4) ) { + if (qDoBoth) { //we want to change mr to ms + start[2] = 's'; //change mr to ms + return qtrue; + } else { //IF qDoBoth + return qfalse; //don't want this one + } + } + } //IF found slash + } + } //IF Female + else { //i'm male + start = strrchr( string, '/' ); //get the last slash before the wav + if (start != NULL) { + if (!Q_strncmp( start, "/ms_", 4) ) { + return qfalse; //don't want this one + } + } //IF found slash + } + } //if VALIDSTRING + return qtrue; +} +*/ + +/* +============= +Q3_PlaySound + +Plays a sound from an entity +============= +*/ +static int Q3_PlaySound( int taskID, int entID, const char *name, const char *channel ) +{ + T_G_ICARUS_PLAYSOUND *sharedMem = (T_G_ICARUS_PLAYSOUND *)sv.mSharedMemory; + + sharedMem->taskID = taskID; + sharedMem->entID = entID; + strcpy(sharedMem->name, name); + strcpy(sharedMem->channel, channel); + + return GVM_ICARUS_PlaySound(); +} + + +/* +============ +Q3_SetVar + Description : + Return type : static void + Argument : int taskID + Argument : int entID + Argument : const char *type_name + Argument : const char *data +============ +*/ +void Q3_SetVar( int taskID, int entID, const char *type_name, const char *data ) +{ + int vret = Q3_VariableDeclared( type_name ) ; + float float_data; + float val = 0.0f; + + + if ( vret != VTYPE_NONE ) + { + switch ( vret ) + { + case VTYPE_FLOAT: + //Check to see if increment command + if ( (val = Q3_CheckStringCounterIncrement( data )) ) + { + Q3_GetFloatVariable( type_name, &float_data ); + float_data += val; + } + else + { + float_data = atof((char *) data); + } + Q3_SetFloatVariable( type_name, float_data ); + break; + + case VTYPE_STRING: + Q3_SetStringVariable( type_name, data ); + break; + + case VTYPE_VECTOR: + Q3_SetVectorVariable( type_name, (char *) data ); + break; + } + + return; + } + + Q3_DebugPrint( WL_ERROR, "%s variable or field not found!\n", type_name ); +} + +/* +============ +Q3_Set + Description : + Return type : void + Argument : int taskID + Argument : int entID + Argument : const char *type_name + Argument : const char *data +============ +*/ +static void Q3_Set( int taskID, int entID, const char *type_name, const char *data ) +{ + T_G_ICARUS_SET *sharedMem = (T_G_ICARUS_SET *)sv.mSharedMemory; + + sharedMem->taskID = taskID; + sharedMem->entID = entID; + strcpy(sharedMem->type_name, type_name); + strcpy(sharedMem->data, data); + + if ( GVM_ICARUS_Set() ) + { + gTaskManagers[entID]->Completed( taskID ); + } +} + + +/* +============ +Q3_Evaluate + Description : + Return type : int + Argument : int p1Type + Argument : const char *p1 + Argument : int p2Type + Argument : const char *p2 + Argument : int operatorType +============ +*/ +static int Q3_Evaluate( int p1Type, const char *p1, int p2Type, const char *p2, int operatorType ) +{ + float f1=0, f2=0; + vec3_t v1, v2; + char *c1=0, *c2=0; + int i1=0, i2=0; + + //Always demote to int on float to integer comparisons + if ( ( ( p1Type == TK_FLOAT ) && ( p2Type == TK_INT ) ) || ( ( p1Type == TK_INT ) && ( p2Type == TK_FLOAT ) ) ) + { + p1Type = TK_INT; + p2Type = TK_INT; + } + + //Cannot compare two disimilar types + if ( p1Type != p2Type ) + { + Q3_DebugPrint( WL_ERROR, "Q3_Evaluate comparing two disimilar types!\n"); + return false; + } + + //Format the parameters + switch ( p1Type ) + { + case TK_FLOAT: + sscanf( p1, "%f", &f1 ); + sscanf( p2, "%f", &f2 ); + break; + + case TK_INT: + sscanf( p1, "%d", &i1 ); + sscanf( p2, "%d", &i2 ); + break; + + case TK_VECTOR: + sscanf( p1, "%f %f %f", &v1[0], &v1[1], &v1[2] ); + sscanf( p2, "%f %f %f", &v2[0], &v2[1], &v2[2] ); + break; + + case TK_STRING: + case TK_IDENTIFIER: + c1 = (char *) p1; + c2 = (char *) p2; + break; + + default: + Q3_DebugPrint( WL_WARNING, "Q3_Evaluate unknown type used!\n"); + return false; + } + + //Compare them and return the result + + //FIXME: YUCK!!! Better way to do this? + + switch ( operatorType ) + { + + // + // EQUAL TO + // + + case TK_EQUALS: + + switch ( p1Type ) + { + case TK_FLOAT: + return (int) ( f1 == f2 ); + break; + + case TK_INT: + return (int) ( i1 == i2 ); + break; + + case TK_VECTOR: + return (int) VectorCompare( v1, v2 ); + break; + + case TK_STRING: + case TK_IDENTIFIER: + return (int) !Q_stricmp( c1, c2 ); //NOTENOTE: The script uses proper string comparison logic (ex. ( a == a ) == true ) + break; + + default: + Q3_DebugPrint( WL_ERROR, "Q3_Evaluate unknown type used!\n"); + return false; + } + + break; + + // + // GREATER THAN + // + + case TK_GREATER_THAN: + + switch ( p1Type ) + { + case TK_FLOAT: + return (int) ( f1 > f2 ); + break; + + case TK_INT: + return (int) ( i1 > i2 ); + break; + + case TK_VECTOR: + Q3_DebugPrint( WL_ERROR, "Q3_Evaluate vector comparisons of type GREATER THAN cannot be performed!"); + return false; + break; + + case TK_STRING: + case TK_IDENTIFIER: + Q3_DebugPrint( WL_ERROR, "Q3_Evaluate string comparisons of type GREATER THAN cannot be performed!"); + return false; + break; + + default: + Q3_DebugPrint( WL_ERROR, "Q3_Evaluate unknown type used!\n"); + return false; + } + + break; + + // + // LESS THAN + // + + case TK_LESS_THAN: + + switch ( p1Type ) + { + case TK_FLOAT: + return (int) ( f1 < f2 ); + break; + + case TK_INT: + return (int) ( i1 < i2 ); + break; + + case TK_VECTOR: + Q3_DebugPrint( WL_ERROR, "Q3_Evaluate vector comparisons of type LESS THAN cannot be performed!"); + return false; + break; + + case TK_STRING: + case TK_IDENTIFIER: + Q3_DebugPrint( WL_ERROR, "Q3_Evaluate string comparisons of type LESS THAN cannot be performed!"); + return false; + break; + + default: + Q3_DebugPrint( WL_ERROR, "Q3_Evaluate unknown type used!\n"); + return false; + } + + break; + + // + // NOT + // + + case TK_NOT: //NOTENOTE: Implied "NOT EQUAL TO" + + switch ( p1Type ) + { + case TK_FLOAT: + return (int) ( f1 != f2 ); + break; + + case TK_INT: + return (int) ( i1 != i2 ); + break; + + case TK_VECTOR: + return (int) !VectorCompare( v1, v2 ); + break; + + case TK_STRING: + case TK_IDENTIFIER: + return (int) Q_stricmp( c1, c2 ); + break; + + default: + Q3_DebugPrint( WL_ERROR, "Q3_Evaluate unknown type used!\n"); + return false; + } + + break; + + default: + Q3_DebugPrint( WL_ERROR, "Q3_Evaluate unknown operator used!\n"); + break; + } + + return false; +} + +/* +------------------------- +Q3_CameraFade +------------------------- +*/ +static void Q3_CameraFade( float sr, float sg, float sb, float sa, float dr, float dg, float db, float da, float duration ) +{ + Q3_DebugPrint( WL_WARNING, "Q3_CameraFade: NOT SUPPORTED IN MP\n"); +} + +/* +------------------------- +Q3_CameraPath +------------------------- +*/ +static void Q3_CameraPath( const char *name ) +{ + Q3_DebugPrint( WL_WARNING, "Q3_CameraPath: NOT SUPPORTED IN MP\n"); +} + +/* +------------------------- +Q3_DebugPrint +------------------------- +*/ +void Q3_DebugPrint( int level, const char *format, ... ) +{ + //Don't print messages they don't want to see + //if ( g_ICARUSDebug->integer < level ) + if (!com_developer || !com_developer->integer) + return; + + va_list argptr; + char text[1024]; + + va_start (argptr, format); + Q_vsnprintf(text, sizeof(text), format, argptr); + va_end (argptr); + + //Add the color formatting + switch ( level ) + { + case WL_ERROR: + Com_Printf ( S_COLOR_RED"ERROR: %s", text ); + break; + + case WL_WARNING: + Com_Printf ( S_COLOR_YELLOW"WARNING: %s", text ); + break; + + case WL_DEBUG: + { + int entNum; + char *buffer; + + sscanf( text, "%d", &entNum ); + + if ( ( ICARUS_entFilter >= 0 ) && ( ICARUS_entFilter != entNum ) ) + return; + + buffer = (char *) text; + buffer += 5; + + if ( ( entNum < 0 ) || ( entNum >= MAX_GENTITIES ) ) + entNum = 0; + + Com_Printf ( S_COLOR_BLUE"DEBUG: %s(%d): %s\n", SV_GentityNum(entNum)->script_targetname, entNum, buffer ); + break; + } + default: + case WL_VERBOSE: + Com_Printf ( S_COLOR_GREEN"INFO: %s", text ); + break; + } +} + +void CGCam_Anything( void ) +{ + Q3_DebugPrint( WL_WARNING, "Camera functions NOT SUPPORTED IN MP\n"); +} + +//These are useless for MP. Just taking it for now since I don't want to remove all calls to this in ICARUS. +int AppendToSaveGame(unsigned long chid, const void *data, int length) +{ + return 1; +} + +// Changed by BTO (VV) - Visual C++ 7.1 doesn't allow default args on funcion pointers +int ReadFromSaveGame(unsigned long chid, void *pvAddress, int iLength /* , void **ppvAddressPtr = NULL */ ) +{ + return 1; +} + +void CGCam_Enable( void ) +{ + CGCam_Anything(); +} + +void CGCam_Disable( void ) +{ + CGCam_Anything(); +} + +void CGCam_Zoom( float FOV, float duration ) +{ + CGCam_Anything(); +} + +void CGCam_Pan( vec3_t dest, vec3_t panDirection, float duration ) +{ + CGCam_Anything(); +} + +void CGCam_Move( vec3_t dest, float duration ) +{ + CGCam_Anything(); +} + +void CGCam_Shake( float intensity, int duration ) +{ + CGCam_Anything(); +} + +void CGCam_Follow( const char *cameraGroup, float speed, float initLerp ) +{ + CGCam_Anything(); +} + +void CGCam_Track( const char *trackName, float speed, float initLerp ) +{ + CGCam_Anything(); +} + +void CGCam_Distance( float distance, float initLerp ) +{ + CGCam_Anything(); +} + +void CGCam_Roll( float dest, float duration ) +{ + CGCam_Anything(); +} + +int ICARUS_LinkEntity( int entID, CSequencer *sequencer, CTaskManager *taskManager ); + +static unsigned int Q3_GetTimeScale( void ) +{ + return com_timescale->value; +} + +static void Q3_Lerp2Pos( int taskID, int entID, vec3_t origin, vec3_t angles, float duration ) +{ + T_G_ICARUS_LERP2POS *sharedMem = (T_G_ICARUS_LERP2POS *)sv.mSharedMemory; + + sharedMem->taskID = taskID; + sharedMem->entID = entID; + VectorCopy(origin, sharedMem->origin); + + if (angles) + { + VectorCopy(angles, sharedMem->angles); + sharedMem->nullAngles = qfalse; + } + else + { + sharedMem->nullAngles = qtrue; + } + sharedMem->duration = duration; + + GVM_ICARUS_Lerp2Pos(); + //We do this in case the values are modified in the game. It would be expected by icarus that + //the values passed in here are modified equally. + VectorCopy(sharedMem->origin, origin); + + if (angles) + { + VectorCopy(sharedMem->angles, angles); + } +} + +static void Q3_Lerp2Origin( int taskID, int entID, vec3_t origin, float duration ) +{ + T_G_ICARUS_LERP2ORIGIN *sharedMem = (T_G_ICARUS_LERP2ORIGIN *)sv.mSharedMemory; + + sharedMem->taskID = taskID; + sharedMem->entID = entID; + VectorCopy(origin, sharedMem->origin); + sharedMem->duration = duration; + + GVM_ICARUS_Lerp2Origin(); + VectorCopy(sharedMem->origin, origin); +} + +static void Q3_Lerp2Angles( int taskID, int entID, vec3_t angles, float duration ) +{ + T_G_ICARUS_LERP2ANGLES *sharedMem = (T_G_ICARUS_LERP2ANGLES *)sv.mSharedMemory; + + sharedMem->taskID = taskID; + sharedMem->entID = entID; + VectorCopy(angles, sharedMem->angles); + sharedMem->duration = duration; + + GVM_ICARUS_Lerp2Angles(); + VectorCopy(sharedMem->angles, angles); +} + +static int Q3_GetTag( int entID, const char *name, int lookup, vec3_t info ) +{ + int r; + T_G_ICARUS_GETTAG *sharedMem = (T_G_ICARUS_GETTAG *)sv.mSharedMemory; + + sharedMem->entID = entID; + strcpy(sharedMem->name, name); + sharedMem->lookup = lookup; + VectorCopy(info, sharedMem->info); + + r = GVM_ICARUS_GetTag(); + VectorCopy(sharedMem->info, info); + return r; +} + +static void Q3_Lerp2Start( int entID, int taskID, float duration ) +{ + T_G_ICARUS_LERP2START *sharedMem = (T_G_ICARUS_LERP2START *)sv.mSharedMemory; + + sharedMem->taskID = taskID; + sharedMem->entID = entID; + sharedMem->duration = duration; + + GVM_ICARUS_Lerp2Start(); +} + +static void Q3_Lerp2End( int entID, int taskID, float duration ) +{ + T_G_ICARUS_LERP2END *sharedMem = (T_G_ICARUS_LERP2END *)sv.mSharedMemory; + + sharedMem->taskID = taskID; + sharedMem->entID = entID; + sharedMem->duration = duration; + + GVM_ICARUS_Lerp2End(); +} + +static void Q3_Use( int entID, const char *target ) +{ + T_G_ICARUS_USE *sharedMem = (T_G_ICARUS_USE *)sv.mSharedMemory; + + sharedMem->entID = entID; + strcpy(sharedMem->target, target); + + GVM_ICARUS_Use(); +} + +static void Q3_Kill( int entID, const char *name ) +{ + T_G_ICARUS_KILL *sharedMem = (T_G_ICARUS_KILL *)sv.mSharedMemory; + + sharedMem->entID = entID; + strcpy(sharedMem->name, name); + + GVM_ICARUS_Kill(); +} + +static void Q3_Remove( int entID, const char *name ) +{ + T_G_ICARUS_REMOVE *sharedMem = (T_G_ICARUS_REMOVE *)sv.mSharedMemory; + + sharedMem->entID = entID; + strcpy(sharedMem->name, name); + + GVM_ICARUS_Remove(); +} + +static void Q3_Play( int taskID, int entID, const char *type, const char *name ) +{ + T_G_ICARUS_PLAY *sharedMem = (T_G_ICARUS_PLAY *)sv.mSharedMemory; + + sharedMem->taskID = taskID; + sharedMem->entID = entID; + strcpy(sharedMem->type, type); + strcpy(sharedMem->name, name); + + GVM_ICARUS_Play(); +} + +static int Q3_GetFloat( int entID, int type, const char *name, float *value ) +{ + int r; + T_G_ICARUS_GETFLOAT *sharedMem = (T_G_ICARUS_GETFLOAT *)sv.mSharedMemory; + + sharedMem->entID = entID; + sharedMem->type = type; + strcpy(sharedMem->name, name); + sharedMem->value = 0;//*value; + + r = GVM_ICARUS_GetFloat(); + *value = sharedMem->value; + return r; +} + +static int Q3_GetVector( int entID, int type, const char *name, vec3_t value ) +{ + int r; + T_G_ICARUS_GETVECTOR *sharedMem = (T_G_ICARUS_GETVECTOR *)sv.mSharedMemory; + + sharedMem->entID = entID; + sharedMem->type = type; + strcpy(sharedMem->name, name); + VectorCopy(value, sharedMem->value); + + r = GVM_ICARUS_GetVector(); + VectorCopy(sharedMem->value, value); + return r; +} + +static int Q3_GetString( int entID, int type, const char *name, char **value ) +{ + int r; + T_G_ICARUS_GETSTRING *sharedMem = (T_G_ICARUS_GETSTRING *)sv.mSharedMemory; + + sharedMem->entID = entID; + sharedMem->type = type; + strcpy(sharedMem->name, name); + + r = GVM_ICARUS_GetString(); + //rww - careful with this, next time shared memory is altered this will get stomped + *value = &sharedMem->value[0]; + return r; +} + + +/* +============ +Interface_Init + Description : Inits the interface for the game + Return type : void + Argument : interface_export_t *pe +============ +*/ +void Interface_Init( interface_export_t *pe ) +{ + //TODO: This is where you link up all your functions to the engine + + //General + pe->I_LoadFile = Q3_ReadScript; + pe->I_CenterPrint = Q3_CenterPrint; + pe->I_DPrintf = Q3_DebugPrint; + pe->I_GetEntityByName = Q3_GetEntityByName; + pe->I_GetTime = Q3_GetTime; + pe->I_GetTimeScale = Q3_GetTimeScale; + pe->I_PlaySound = Q3_PlaySound; + pe->I_Lerp2Pos = Q3_Lerp2Pos; + pe->I_Lerp2Origin = Q3_Lerp2Origin; + pe->I_Lerp2Angles = Q3_Lerp2Angles; + pe->I_GetTag = Q3_GetTag; + pe->I_Lerp2Start = Q3_Lerp2Start; + pe->I_Lerp2End = Q3_Lerp2End; + pe->I_Use = Q3_Use; + pe->I_Kill = Q3_Kill; + pe->I_Remove = Q3_Remove; + pe->I_Set = Q3_Set; + pe->I_Random = Q_flrand; + pe->I_Play = Q3_Play; + + //Camera functions + pe->I_CameraEnable = CGCam_Enable; + pe->I_CameraDisable = CGCam_Disable; + pe->I_CameraZoom = CGCam_Zoom; + pe->I_CameraMove = CGCam_Move; + pe->I_CameraPan = CGCam_Pan; + pe->I_CameraRoll = CGCam_Roll; + pe->I_CameraTrack = CGCam_Track; + pe->I_CameraFollow = CGCam_Follow; + pe->I_CameraDistance = CGCam_Distance; + pe->I_CameraShake = CGCam_Shake; + pe->I_CameraFade = Q3_CameraFade; + pe->I_CameraPath = Q3_CameraPath; + + //Variable information + pe->I_GetFloat = Q3_GetFloat; + pe->I_GetVector = Q3_GetVector; + pe->I_GetString = Q3_GetString; + + pe->I_Evaluate = Q3_Evaluate; + + pe->I_DeclareVariable = Q3_DeclareVariable; + pe->I_FreeVariable = Q3_FreeVariable; + + //Save / Load functions + pe->I_WriteSaveData = AppendToSaveGame; + pe->I_ReadSaveData = ReadFromSaveGame; + pe->I_LinkEntity = ICARUS_LinkEntity; +} diff --git a/Projects/Android/jni/OpenJK/codemp_delete/icarus/Q3_Interface.h b/Projects/Android/jni/OpenJK/codemp_delete/icarus/Q3_Interface.h new file mode 100644 index 0000000..a8df673 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/icarus/Q3_Interface.h @@ -0,0 +1,316 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#pragma once + +//NOTENOTE: The enums and tables in this file will obviously bitch if they are included multiple times, don't do that + +typedef enum //# setType_e +{ + //# #sep Parm strings + SET_PARM1 = 0,//## %s="" # Set entity parm1 + SET_PARM2,//## %s="" # Set entity parm2 + SET_PARM3,//## %s="" # Set entity parm3 + SET_PARM4,//## %s="" # Set entity parm4 + SET_PARM5,//## %s="" # Set entity parm5 + SET_PARM6,//## %s="" # Set entity parm6 + SET_PARM7,//## %s="" # Set entity parm7 + SET_PARM8,//## %s="" # Set entity parm8 + SET_PARM9,//## %s="" # Set entity parm9 + SET_PARM10,//## %s="" # Set entity parm10 + SET_PARM11,//## %s="" # Set entity parm11 + SET_PARM12,//## %s="" # Set entity parm12 + SET_PARM13,//## %s="" # Set entity parm13 + SET_PARM14,//## %s="" # Set entity parm14 + SET_PARM15,//## %s="" # Set entity parm15 + SET_PARM16,//## %s="" # Set entity parm16 + + // NOTE!!! If you add any other SET_xxxxxxSCRIPT types, make sure you update the 'case' statements in + // ICARUS_InterrogateScript() (game/g_ICARUS.cpp), or the script-precacher won't find them. + + //# #sep Scripts and other file paths + SET_SPAWNSCRIPT,//## %s="NULL" !!"W:\game\base\scripts\!!#*.txt" # Script to run when spawned //0 - do not change these, these are equal to BSET_SPAWN, etc + SET_USESCRIPT,//## %s="NULL" !!"W:\game\base\scripts\!!#*.txt" # Script to run when used + SET_AWAKESCRIPT,//## %s="NULL" !!"W:\game\base\scripts\!!#*.txt" # Script to run when startled + SET_ANGERSCRIPT,//## %s="NULL" !!"W:\game\base\scripts\!!#*.txt" # Script run when find an enemy for the first time + SET_ATTACKSCRIPT,//## %s="NULL" !!"W:\game\base\scripts\!!#*.txt" # Script to run when you shoot + SET_VICTORYSCRIPT,//## %s="NULL" !!"W:\game\base\scripts\!!#*.txt" # Script to run when killed someone + SET_LOSTENEMYSCRIPT,//## %s="NULL" !!"W:\game\base\scripts\!!#*.txt" # Script to run when you can't find your enemy + SET_PAINSCRIPT,//## %s="NULL" !!"W:\game\base\scripts\!!#*.txt" # Script to run when hit + SET_FLEESCRIPT,//## %s="NULL" !!"W:\game\base\scripts\!!#*.txt" # Script to run when hit and low health + SET_DEATHSCRIPT,//## %s="NULL" !!"W:\game\base\scripts\!!#*.txt" # Script to run when killed + SET_DELAYEDSCRIPT,//## %s="NULL" !!"W:\game\base\scripts\!!#*.txt" # Script to run after a delay + SET_BLOCKEDSCRIPT,//## %s="NULL" !!"W:\game\base\scripts\!!#*.txt" # Script to run when blocked by teammate + SET_FFIRESCRIPT,//## %s="NULL" !!"W:\game\base\scripts\!!#*.txt" # Script to run when player has shot own team repeatedly + SET_FFDEATHSCRIPT,//## %s="NULL" !!"W:\game\base\scripts\!!#*.txt" # Script to run when player kills a teammate + SET_MINDTRICKSCRIPT,//## %s="NULL" !!"W:\game\base\scripts\!!#*.txt" # Script to run when player kills a teammate + SET_VIDEO_PLAY,//## %s="filename" !!"W:\game\base\video\!!#*.roq" # Play a video (inGame) + SET_CINEMATIC_SKIPSCRIPT, //## %s="filename" !!"W:\game\base\scripts\!!#*.txt" # Script to run when skipping the running cinematic + + //# #sep Standard strings + SET_ENEMY,//## %s="NULL" # Set enemy by targetname + SET_LEADER,//## %s="NULL" # Set for BS_FOLLOW_LEADER + SET_NAVGOAL,//## %s="NULL" # *Move to this navgoal then continue script + SET_CAPTURE,//## %s="NULL" # Set captureGoal by targetname + SET_VIEWTARGET,//## %s="NULL" # Set angles toward ent by targetname + SET_WATCHTARGET,//## %s="NULL" # Set angles toward ent by targetname, will *continue* to face them... only in BS_CINEMATIC + SET_TARGETNAME,//## %s="NULL" # Set/change your targetname + SET_PAINTARGET,//## %s="NULL" # Set/change what to use when hit + SET_CAMERA_GROUP,//## %s="NULL" # all ents with this cameraGroup will be focused on + SET_CAMERA_GROUP_TAG,//## %s="NULL" # What tag on all clients to try to track + SET_LOOK_TARGET,//## %s="NULL" # object for NPC to look at + SET_ADDRHANDBOLT_MODEL, //## %s="NULL" # object to place on NPC right hand bolt + SET_REMOVERHANDBOLT_MODEL, //## %s="NULL" # object to remove from NPC right hand bolt + SET_ADDLHANDBOLT_MODEL, //## %s="NULL" # object to place on NPC left hand bolt + SET_REMOVELHANDBOLT_MODEL, //## %s="NULL" # object to remove from NPC left hand bolt + SET_CAPTIONTEXTCOLOR, //## %s="" # Color of text RED,WHITE,BLUE, YELLOW + SET_CENTERTEXTCOLOR, //## %s="" # Color of text RED,WHITE,BLUE, YELLOW + SET_SCROLLTEXTCOLOR, //## %s="" # Color of text RED,WHITE,BLUE, YELLOW + SET_COPY_ORIGIN,//## %s="targetname" # Copy the origin of the ent with targetname to your origin + SET_DEFEND_TARGET,//## %s="targetname" # This NPC will attack the target NPC's enemies + SET_TARGET,//## %s="NULL" # Set/change your target + SET_TARGET2,//## %s="NULL" # Set/change your target2, on NPC's, this fires when they're knocked out by the red hypo + SET_LOCATION,//## %s="INVALID" # What trigger_location you're in - Can only be gotten, not set! + SET_REMOVE_TARGET,//## %s="NULL" # Target that is fired when someone completes the BS_REMOVE behaviorState + SET_LOADGAME,//## %s="exitholodeck" # Load the savegame that was auto-saved when you started the holodeck + SET_LOCKYAW,//## %s="off" # Lock legs to a certain yaw angle (or "off" or "auto" uses current) + SET_FULLNAME,//## %s="NULL" # This name will appear when ent is scanned by tricorder + SET_VIEWENTITY,//## %s="NULL" # Make the player look through this ent's eyes - also shunts player movement control to this ent + SET_LOOPSOUND,//## %s="FILENAME" !!"W:\game\base\!!#sound\*.*" # Looping sound to play on entity + SET_ICARUS_FREEZE,//## %s="NULL" # Specify name of entity to freeze - !!!NOTE!!! since the ent is frozen, it cannot unfreeze itself, you must have some other entity unfreeze a frozen ent!!! + SET_ICARUS_UNFREEZE,//## %s="NULL" # Specify name of entity to unfreeze - !!!NOTE!!! since the ent is frozen, it cannot unfreeze itself, you must have some other entity unfreeze a frozen ent!!! + + SET_SCROLLTEXT, //## %s="" # key of text string to print + SET_LCARSTEXT, //## %s="" # key of text string to print in LCARS frame + + //# #sep vectors + SET_ORIGIN,//## %v="0.0 0.0 0.0" # Set origin explicitly or with TAG + SET_ANGLES,//## %v="0.0 0.0 0.0" # Set angles explicitly or with TAG + SET_TELEPORT_DEST,//## %v="0.0 0.0 0.0" # Set origin here as soon as the area is clear + + //# #sep floats + SET_XVELOCITY,//## %f="0.0" # Velocity along X axis + SET_YVELOCITY,//## %f="0.0" # Velocity along Y axis + SET_ZVELOCITY,//## %f="0.0" # Velocity along Z axis + SET_Z_OFFSET,//## %f="0.0" # Vertical offset from original origin... offset/ent's speed * 1000ms is duration + SET_DPITCH,//## %f="0.0" # Pitch for NPC to turn to + SET_DYAW,//## %f="0.0" # Yaw for NPC to turn to + SET_TIMESCALE,//## %f="0.0" # Speed-up slow down game (0 - 1.0) + SET_CAMERA_GROUP_Z_OFS,//## %s="NULL" # when following an ent with the camera, apply this z ofs + SET_VISRANGE,//## %f="0.0" # How far away NPC can see + SET_EARSHOT,//## %f="0.0" # How far an NPC can hear + SET_VIGILANCE,//## %f="0.0" # How often to look for enemies (0 - 1.0) + SET_GRAVITY,//## %f="0.0" # Change this ent's gravity - 800 default + SET_FACEAUX, //## %f="0.0" # Set face to Aux expression for number of seconds + SET_FACEBLINK, //## %f="0.0" # Set face to Blink expression for number of seconds + SET_FACEBLINKFROWN, //## %f="0.0" # Set face to Blinkfrown expression for number of seconds + SET_FACEFROWN, //## %f="0.0" # Set face to Frown expression for number of seconds + SET_FACENORMAL, //## %f="0.0" # Set face to Normal expression for number of seconds + SET_FACEEYESCLOSED, //## %f="0.0" # Set face to Eyes closed + SET_FACEEYESOPENED, //## %f="0.0" # Set face to Eyes open + SET_WAIT, //## %f="0.0" # Change an entity's wait field + SET_FOLLOWDIST, //## %f="0.0" # How far away to stay from leader in BS_FOLLOW_LEADER + SET_SCALE, //## %f="0.0" # Scale the entity model + + //# #sep ints + SET_ANIM_HOLDTIME_LOWER,//## %d="0" # Hold lower anim for number of milliseconds + SET_ANIM_HOLDTIME_UPPER,//## %d="0" # Hold upper anim for number of milliseconds + SET_ANIM_HOLDTIME_BOTH,//## %d="0" # Hold lower and upper anims for number of milliseconds + SET_HEALTH,//## %d="0" # Change health + SET_ARMOR,//## %d="0" # Change armor + SET_WALKSPEED,//## %d="0" # Change walkSpeed + SET_RUNSPEED,//## %d="0" # Change runSpeed + SET_YAWSPEED,//## %d="0" # Change yawSpeed + SET_AGGRESSION,//## %d="0" # Change aggression 1-5 + SET_AIM,//## %d="0" # Change aim 1-5 + SET_FRICTION,//## %d="0" # Change ent's friction - 6 default + SET_SHOOTDIST,//## %d="0" # How far the ent can shoot - 0 uses weapon + SET_HFOV,//## %d="0" # Horizontal field of view + SET_VFOV,//## %d="0" # Vertical field of view + SET_DELAYSCRIPTTIME,//## %d="0" # How many milliseconds to wait before running delayscript + SET_FORWARDMOVE,//## %d="0" # NPC move forward -127(back) to 127 + SET_RIGHTMOVE,//## %d="0" # NPC move right -127(left) to 127 + SET_STARTFRAME, //## %d="0" # frame to start animation sequence on + SET_ENDFRAME, //## %d="0" # frame to end animation sequence on + SET_ANIMFRAME, //## %d="0" # frame to set animation sequence to + SET_COUNT, //## %d="0" # Change an entity's count field + SET_SHOT_SPACING,//## %d="1000" # Time between shots for an NPC - reset to defaults when changes weapon + SET_MISSIONSTATUSTIME,//## %d="0" # Amount of time until Mission Status should be shown after death + SET_WIDTH,//## %d="0.0" # Width of NPC bounding box. + + //# #sep booleans + SET_IGNOREPAIN,//## %t="BOOL_TYPES" # Do not react to pain + SET_IGNOREENEMIES,//## %t="BOOL_TYPES" # Do not acquire enemies + SET_IGNOREALERTS,//## %t="BOOL_TYPES" # Do not get enemy set by allies in area(ambush) + SET_DONTSHOOT,//## %t="BOOL_TYPES" # Others won't shoot you + SET_NOTARGET,//## %t="BOOL_TYPES" # Others won't pick you as enemy + SET_DONTFIRE,//## %t="BOOL_TYPES" # Don't fire your weapon + SET_LOCKED_ENEMY,//## %t="BOOL_TYPES" # Keep current enemy until dead + SET_CROUCHED,//## %t="BOOL_TYPES" # Force NPC to crouch + SET_WALKING,//## %t="BOOL_TYPES" # Force NPC to move at walkSpeed + SET_RUNNING,//## %t="BOOL_TYPES" # Force NPC to move at runSpeed + SET_CHASE_ENEMIES,//## %t="BOOL_TYPES" # NPC will chase after enemies + SET_LOOK_FOR_ENEMIES,//## %t="BOOL_TYPES" # NPC will be on the lookout for enemies + SET_FACE_MOVE_DIR,//## %t="BOOL_TYPES" # NPC will face in the direction it's moving + SET_DONT_FLEE,//## %t="BOOL_TYPES" # NPC will not run from danger + SET_FORCED_MARCH,//## %t="BOOL_TYPES" # NPC will not move unless you aim at him + SET_UNDYING,//## %t="BOOL_TYPES" # Can take damage down to 1 but not die + SET_NOAVOID,//## %t="BOOL_TYPES" # Will not avoid other NPCs or architecture + SET_SOLID,//## %t="BOOL_TYPES" # Make yourself notsolid or solid + SET_PLAYER_USABLE,//## %t="BOOL_TYPES" # Can be activateby the player's "use" button + SET_LOOP_ANIM,//## %t="BOOL_TYPES" # For non-NPCs, loop your animation sequence + SET_INTERFACE,//## %t="BOOL_TYPES" # Player interface on/off + SET_SHIELDS,//## %t="BOOL_TYPES" # NPC has no shields (Borg do not adapt) + SET_INVISIBLE,//## %t="BOOL_TYPES" # Makes an NPC not solid and not visible + SET_VAMPIRE,//## %t="BOOL_TYPES" # Draws only in mirrors/portals + SET_FORCE_INVINCIBLE,//## %t="BOOL_TYPES" # Force Invincibility effect, also godmode + SET_GREET_ALLIES,//## %t="BOOL_TYPES" # Makes an NPC greet teammates + SET_VIDEO_FADE_IN,//## %t="BOOL_TYPES" # Makes video playback fade in + SET_VIDEO_FADE_OUT,//## %t="BOOL_TYPES" # Makes video playback fade out + SET_PLAYER_LOCKED,//## %t="BOOL_TYPES" # Makes it so player cannot move + SET_LOCK_PLAYER_WEAPONS,//## %t="BOOL_TYPES" # Makes it so player cannot switch weapons + SET_NO_IMPACT_DAMAGE,//## %t="BOOL_TYPES" # Stops this ent from taking impact damage + SET_NO_KNOCKBACK,//## %t="BOOL_TYPES" # Stops this ent from taking knockback from weapons + SET_ALT_FIRE,//## %t="BOOL_TYPES" # Force NPC to use altfire when shooting + SET_NO_RESPONSE,//## %t="BOOL_TYPES" # NPCs will do generic responses when this is on (usescripts override generic responses as well) + SET_INVINCIBLE,//## %t="BOOL_TYPES" # Completely unkillable + SET_MISSIONSTATUSACTIVE, //# Turns on Mission Status Screen + SET_NO_COMBAT_TALK,//## %t="BOOL_TYPES" # NPCs will not do their combat talking noises when this is on + SET_NO_ALERT_TALK,//## %t="BOOL_TYPES" # NPCs will not do their combat talking noises when this is on + SET_TREASONED,//## %t="BOOL_TYPES" # Player has turned on his own- scripts will stop, NPCs will turn on him and level changes load the brig + SET_DISABLE_SHADER_ANIM,//## %t="BOOL_TYPES" # Allows turning off an animating shader in a script + SET_SHADER_ANIM,//## %t="BOOL_TYPES" # Sets a shader with an image map to be under frame control + SET_SABERACTIVE,//## %t="BOOL_TYPES" # Turns saber on/off + SET_ADJUST_AREA_PORTALS,//## %t="BOOL_TYPES" # Only set this on things you move with script commands that you *want* to open/close area portals. Default is off. + SET_DMG_BY_HEAVY_WEAP_ONLY,//## %t="BOOL_TYPES" # When true, only a heavy weapon class missile/laser can damage this ent. + SET_SHIELDED,//## %t="BOOL_TYPES" # When true, ion_cannon is shielded from any kind of damage. + SET_NO_GROUPS,//## %t="BOOL_TYPES" # This NPC cannot alert groups or be part of a group + SET_FIRE_WEAPON,//## %t="BOOL_TYPES" # Makes NPC will hold down the fire button, until this is set to false + SET_NO_MINDTRICK,//## %t="BOOL_TYPES" # Makes NPC immune to jedi mind-trick + SET_INACTIVE,//## %t="BOOL_TYPES" # in lieu of using a target_activate or target_deactivate + SET_FUNC_USABLE_VISIBLE,//## %t="BOOL_TYPES" # provides an alternate way of changing func_usable to be visible or not, DOES NOT AFFECT SOLID + SET_SECRET_AREA_FOUND,//## %t="BOOL_TYPES" # Increment secret areas found counter + SET_MISSION_STATUS_SCREEN,//## %t="BOOL_TYPES" # Display Mission Status screen before advancing to next level + SET_END_SCREENDISSOLVE,//## %t="BOOL_TYPES" # End of game dissolve into star background and credits + SET_USE_CP_NEAREST,//## %t="BOOL_TYPES" # NPCs will use their closest combat points, not try and find ones next to the player, or flank player + SET_MORELIGHT,//## %t="BOOL_TYPES" # NPC will have a minlight of 96 + SET_NO_FORCE,//## %t="BOOL_TYPES" # NPC will not be affected by force powers + SET_NO_FALLTODEATH,//## %t="BOOL_TYPES" # NPC will not scream and tumble and fall to hit death over large drops + SET_DISMEMBERABLE,//## %t="BOOL_TYPES" # NPC will not be dismemberable if you set this to false (default is true) + SET_NO_ACROBATICS,//## %t="BOOL_TYPES" # Jedi won't jump, roll or cartwheel + SET_USE_SUBTITLES,//## %t="BOOL_TYPES" # When true NPC will always display subtitle regardless of subtitle setting + SET_CLEAN_DAMAGING_ENTS,//## %t="BOOL_TYPES" # Removes entities that could muck up cinematics, explosives, turrets, seekers. + SET_HUD,//## %t="BOOL_TYPES" # Turns on/off HUD + + //# #sep calls + SET_SKILL,//## %r%d="0" # Cannot set this, only get it - valid values are 0 through 3 + + //# #sep Special tables + SET_ANIM_UPPER,//## %t="ANIM_NAMES" # Torso and head anim + SET_ANIM_LOWER,//## %t="ANIM_NAMES" # Legs anim + SET_ANIM_BOTH,//## %t="ANIM_NAMES" # Set same anim on torso and legs + SET_PLAYER_TEAM,//## %t="TEAM_NAMES" # Your team + SET_ENEMY_TEAM,//## %t="TEAM_NAMES" # Team in which to look for enemies + SET_BEHAVIOR_STATE,//## %t="BSTATE_STRINGS" # Change current bState + SET_DEFAULT_BSTATE,//## %t="BSTATE_STRINGS" # Change fallback bState + SET_TEMP_BSTATE,//## %t="BSTATE_STRINGS" # Set/Chang a temp bState + SET_EVENT,//## %t="EVENT_NAMES" # Events you can initiate + SET_WEAPON,//## %t="WEAPON_NAMES" # Change/Stow/Drop weapon + SET_ITEM,//## %t="ITEM_NAMES" # Give items + SET_MUSIC_STATE,//## %t="MUSIC_STATES" # Set the state of the dynamic music + + SET_FORCE_HEAL_LEVEL,//## %t="FORCE_LEVELS" # Change force power level + SET_FORCE_JUMP_LEVEL,//## %t="FORCE_LEVELS" # Change force power level + SET_FORCE_SPEED_LEVEL,//## %t="FORCE_LEVELS" # Change force power level + SET_FORCE_PUSH_LEVEL,//## %t="FORCE_LEVELS" # Change force power level + SET_FORCE_PULL_LEVEL,//## %t="FORCE_LEVELS" # Change force power level + SET_FORCE_MINDTRICK_LEVEL,//## %t="FORCE_LEVELS" # Change force power level + SET_FORCE_GRIP_LEVEL,//## %t="FORCE_LEVELS" # Change force power level + SET_FORCE_LIGHTNING_LEVEL,//## %t="FORCE_LEVELS" # Change force power level + SET_SABER_THROW,//## %t="FORCE_LEVELS" # Change force power level + SET_SABER_DEFENSE,//## %t="FORCE_LEVELS" # Change force power level + SET_SABER_OFFENSE,//## %t="FORCE_LEVELS" # Change force power level + + SET_OBJECTIVE_SHOW, //## %t="OBJECTIVES" # Show objective on mission screen + SET_OBJECTIVE_HIDE, //## %t="OBJECTIVES" # Hide objective from mission screen + SET_OBJECTIVE_SUCCEEDED,//## %t="OBJECTIVES" # Mark objective as completed + SET_OBJECTIVE_FAILED, //## %t="OBJECTIVES" # Mark objective as failed + + SET_MISSIONFAILED, //## %t="MISSIONFAILED" # Mission failed screen activates + + SET_TACTICAL_SHOW, //## %t="TACTICAL" # Show tactical info on mission objectives screen + SET_TACTICAL_HIDE, //## %t="TACTICAL" # Hide tactical info on mission objectives screen + SET_OBJECTIVE_CLEARALL, //## # Force all objectives to be hidden +/* + SET_OBJECTIVEFOSTER, +*/ + SET_MISSIONSTATUSTEXT, //## %t="STATUSTEXT" # Text to appear in mission status screen + SET_MENU_SCREEN,//## %t="MENUSCREENS" # Brings up specified menu screen + + SET_CLOSINGCREDITS, //## # Show closing credits + + //in-bhc tables + SET_LEAN,//## %t="LEAN_TYPES" # Lean left, right or stop leaning + + //# #eol + SET_ +} setType_t; + +#ifdef __cplusplus + +// this enum isn't used directly by the game, it's mainly for BehavEd to scan for... +// +typedef enum //# playType_e +{ + //# #sep Types of file to play + PLAY_ROFF = 0,//## %s="filename" !!"W:\game\base\scripts\!!#*.rof" # Play a ROFF file + + //# #eol + PLAY_NUMBEROF + +} playType_t; + + +const int Q3_TIME_SCALE = 1; //MILLISECONDS + +extern char cinematicSkipScript[1024]; + +//General +extern void Q3_TaskIDClear( int *taskID ); +extern qboolean Q3_TaskIDPending( sharedEntity_t *ent, taskID_t taskType ); +extern void Q3_TaskIDComplete( sharedEntity_t *ent, taskID_t taskType ); +extern void Q3_DPrintf( const char *, ... ); + +extern void Q3_CameraRoll( float angle, float duration ); +extern void Q3_CameraFollow( const char *name, float speed, float initLerp ); +extern void Q3_CameraTrack( const char *name, float speed, float initLerp ); +extern void Q3_CameraDistance( float distance, float initLerp ); + +//Not referenced directly as script function - all are called through Q3_Set +extern void Q3_SetAnimBoth( int entID, const char *anim_name ); +extern void Q3_SetVelocity( int entID, vec3_t angles ); + +extern void Q3_DeclareVariable ( int type, const char *name ); +extern void Q3_FreeVariable( const char *name ); + +extern void Q3_DebugPrint( int level, const char *format, ... ); +#endif //__cplusplus diff --git a/Projects/Android/jni/OpenJK/codemp_delete/icarus/Q3_Registers.cpp b/Projects/Android/jni/OpenJK/codemp_delete/icarus/Q3_Registers.cpp new file mode 100644 index 0000000..53fd3b0 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/icarus/Q3_Registers.cpp @@ -0,0 +1,448 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#include "game/g_public.h" +#include "Q3_Registers.h" + +extern void Q3_DebugPrint( int level, const char *format, ... ); + +varString_m varStrings; +varFloat_m varFloats; +varString_m varVectors; //Work around for vector types + +int numVariables = 0; + +/* +------------------------- +Q3_VariableDeclared +------------------------- +*/ + +int Q3_VariableDeclared( const char *name ) +{ + //Check the strings + varString_m::iterator vsi = varStrings.find( name ); + + if ( vsi != varStrings.end() ) + return VTYPE_STRING; + + //Check the floats + varFloat_m::iterator vfi = varFloats.find( name ); + + if ( vfi != varFloats.end() ) + return VTYPE_FLOAT; + + //Check the vectors + varString_m::iterator vvi = varVectors.find( name ); + + if ( vvi != varVectors.end() ) + return VTYPE_VECTOR; + + return VTYPE_NONE; +} + +/* +------------------------- +Q3_DeclareVariable +------------------------- +*/ + +void Q3_DeclareVariable( int type, const char *name ) +{ + //Cannot declare the same variable twice + if ( Q3_VariableDeclared( name ) != VTYPE_NONE ) + return; + + if ( numVariables > MAX_VARIABLES ) + { + Q3_DebugPrint( WL_ERROR, "too many variables already declared, maximum is %d\n", MAX_VARIABLES ); + return; + } + + switch( type ) + { + case TK_FLOAT: + varFloats[ name ] = 0.0f; + break; + + case TK_STRING: + varStrings[ name ] = "NULL"; + break; + + case TK_VECTOR: + varVectors[ name ] = "0.0 0.0 0.0"; + break; + + default: + Q3_DebugPrint( WL_ERROR, "unknown 'type' for declare() function!\n" ); + return; + break; + } + + numVariables++; +} + +/* +------------------------- +Q3_FreeVariable +------------------------- +*/ + +void Q3_FreeVariable( const char *name ) +{ + //Check the strings + varString_m::iterator vsi = varStrings.find( name ); + + if ( vsi != varStrings.end() ) + { + varStrings.erase( vsi ); + numVariables--; + return; + } + + //Check the floats + varFloat_m::iterator vfi = varFloats.find( name ); + + if ( vfi != varFloats.end() ) + { + varFloats.erase( vfi ); + numVariables--; + return; + } + + //Check the strings + varString_m::iterator vvi = varVectors.find( name ); + + if ( vvi != varVectors.end() ) + { + varVectors.erase( vvi ); + numVariables--; + return; + } +} + +/* +------------------------- +Q3_GetFloatVariable +------------------------- +*/ + +int Q3_GetFloatVariable( const char *name, float *value ) +{ + //Check the floats + varFloat_m::iterator vfi = varFloats.find( name ); + + if ( vfi != varFloats.end() ) + { + *value = (*vfi).second; + return true; + } + + return false; +} + +/* +------------------------- +Q3_GetStringVariable +------------------------- +*/ + +int Q3_GetStringVariable( const char *name, const char **value ) +{ + //Check the strings + varString_m::iterator vsi = varStrings.find( name ); + + if ( vsi != varStrings.end() ) + { + *value = (const char *) ((*vsi).second).c_str(); + return true; + } + + return false; +} + +/* +------------------------- +Q3_GetVectorVariable +------------------------- +*/ + +int Q3_GetVectorVariable( const char *name, vec3_t value ) +{ + //Check the strings + varString_m::iterator vvi = varVectors.find( name ); + + if ( vvi != varVectors.end() ) + { + const char *str = ((*vvi).second).c_str(); + + sscanf( str, "%f %f %f", &value[0], &value[1], &value[2] ); + return true; + } + + return false; +} + +/* +------------------------- +Q3_InitVariables +------------------------- +*/ + +void Q3_InitVariables( void ) +{ + varStrings.clear(); + varFloats.clear(); + varVectors.clear(); + + if ( numVariables > 0 ) + Q3_DebugPrint( WL_WARNING, "%d residual variables found!\n", numVariables ); + + numVariables = 0; +} + +/* +------------------------- +Q3_SetVariable_Float +------------------------- +*/ + +int Q3_SetFloatVariable( const char *name, float value ) +{ + //Check the floats + varFloat_m::iterator vfi = varFloats.find( name ); + + if ( vfi == varFloats.end() ) + return VTYPE_FLOAT; + + (*vfi).second = value; + + return true; +} + +/* +------------------------- +Q3_SetVariable_String +------------------------- +*/ + +int Q3_SetStringVariable( const char *name, const char *value ) +{ + //Check the strings + varString_m::iterator vsi = varStrings.find( name ); + + if ( vsi == varStrings.end() ) + return false; + + (*vsi).second = value; + + return true; +} + +/* +------------------------- +Q3_SetVariable_Vector +------------------------- +*/ + +int Q3_SetVectorVariable( const char *name, const char *value ) +{ + //Check the strings + varString_m::iterator vvi = varVectors.find( name ); + + if ( vvi == varVectors.end() ) + return false; + + (*vvi).second = value; + + return true; +} + +/* +------------------------- +Q3_VariableSaveFloats +------------------------- +*/ + +void Q3_VariableSaveFloats( varFloat_m &fmap ) +{ + return; + /* + int numFloats = fmap.size(); + gi.AppendToSaveGame( 'FVAR', &numFloats, sizeof( numFloats ) ); + + varFloat_m::iterator vfi; + STL_ITERATE( vfi, fmap ) + { + //Save out the map id + int idSize = strlen( ((*vfi).first).c_str() ); + + //Save out the real data + gi.AppendToSaveGame( 'FIDL', &idSize, sizeof( idSize ) ); + gi.AppendToSaveGame( 'FIDS', (void *) ((*vfi).first).c_str(), idSize ); + + //Save out the float value + gi.AppendToSaveGame( 'FVAL', &((*vfi).second), sizeof( float ) ); + } + */ +} + +/* +------------------------- +Q3_VariableSaveStrings +------------------------- +*/ + +void Q3_VariableSaveStrings( varString_m &smap ) +{ + return; + /* + int numStrings = smap.size(); + gi.AppendToSaveGame( 'SVAR', &numStrings, sizeof( numStrings ) ); + + varString_m::iterator vsi; + STL_ITERATE( vsi, smap ) + { + //Save out the map id + int idSize = strlen( ((*vsi).first).c_str() ); + + //Save out the real data + gi.AppendToSaveGame( 'SIDL', &idSize, sizeof( idSize ) ); + gi.AppendToSaveGame( 'SIDS', (void *) ((*vsi).first).c_str(), idSize ); + + //Save out the string value + idSize = strlen( ((*vsi).second).c_str() ); + + gi.AppendToSaveGame( 'SVSZ', &idSize, sizeof( idSize ) ); + gi.AppendToSaveGame( 'SVAL', (void *) ((*vsi).second).c_str(), idSize ); + } + */ +} + +/* +------------------------- +Q3_VariableSave +------------------------- +*/ + +int Q3_VariableSave( void ) +{ + Q3_VariableSaveFloats( varFloats ); + Q3_VariableSaveStrings( varStrings ); + Q3_VariableSaveStrings( varVectors); + + return qtrue; +} + +/* +------------------------- +Q3_VariableLoadFloats +------------------------- +*/ + +void Q3_VariableLoadFloats( varFloat_m &fmap ) +{ + return; + /* + int numFloats; + char tempBuffer[1024]; + + gi.ReadFromSaveGame( 'FVAR', &numFloats, sizeof( numFloats ) ); + + for ( int i = 0; i < numFloats; i++ ) + { + int idSize; + + gi.ReadFromSaveGame( 'FIDL', &idSize, sizeof( idSize ) ); + gi.ReadFromSaveGame( 'FIDS', &tempBuffer, idSize ); + tempBuffer[ idSize ] = 0; + + float val; + + gi.ReadFromSaveGame( 'FVAL', &val, sizeof( float ) ); + + Q3_DeclareVariable( TK_FLOAT, (const char *) &tempBuffer ); + Q3_SetFloatVariable( (const char *) &tempBuffer, val ); + } + */ +} + +/* +------------------------- +Q3_VariableLoadStrings +------------------------- +*/ + +void Q3_VariableLoadStrings( int type, varString_m &fmap ) +{ + return; + /* + int numFloats; + char tempBuffer[1024]; + char tempBuffer2[1024]; + + gi.ReadFromSaveGame( 'SVAR', &numFloats, sizeof( numFloats ) ); + + for ( int i = 0; i < numFloats; i++ ) + { + int idSize; + + gi.ReadFromSaveGame( 'SIDL', &idSize, sizeof( idSize ) ); + gi.ReadFromSaveGame( 'SIDS', &tempBuffer, idSize ); + tempBuffer[ idSize ] = 0; + + gi.ReadFromSaveGame( 'SVSZ', &idSize, sizeof( idSize ) ); + gi.ReadFromSaveGame( 'SVAL', &tempBuffer2, idSize ); + tempBuffer2[ idSize ] = 0; + + switch ( type ) + { + case TK_STRING: + Q3_DeclareVariable( TK_STRING, (const char *) &tempBuffer ); + Q3_SetStringVariable( (const char *) &tempBuffer, (const char *) &tempBuffer2 ); + break; + + case TK_VECTOR: + Q3_DeclareVariable( TK_VECTOR, (const char *) &tempBuffer ); + Q3_SetVectorVariable( (const char *) &tempBuffer, (const char *) &tempBuffer2 ); + break; + } + } + */ +} + +/* +------------------------- +Q3_VariableLoad +------------------------- +*/ + +int Q3_VariableLoad( void ) +{ + Q3_InitVariables(); + + Q3_VariableLoadFloats( varFloats ); + Q3_VariableLoadStrings( TK_STRING, varStrings ); + Q3_VariableLoadStrings( TK_VECTOR, varVectors); + + return qfalse; +} diff --git a/Projects/Android/jni/OpenJK/codemp_delete/icarus/Q3_Registers.h b/Projects/Android/jni/OpenJK/codemp_delete/icarus/Q3_Registers.h new file mode 100644 index 0000000..abed6c4 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/icarus/Q3_Registers.h @@ -0,0 +1,55 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#pragma once + +enum +{ + VTYPE_NONE = 0, + VTYPE_FLOAT, + VTYPE_STRING, + VTYPE_VECTOR, +}; + +#ifdef __cplusplus + +#define MAX_VARIABLES 32 + +typedef std::map < std::string, std::string > varString_m; +typedef std::map < std::string, float > varFloat_m; + +extern varString_m varStrings; +extern varFloat_m varFloats; +extern varString_m varVectors; + +extern void Q3_InitVariables( void ); +extern void Q3_DeclareVariable( int type, const char *name ); +extern void Q3_FreeVariable( const char *name ); +extern int Q3_GetStringVariable( const char *name, const char **value ); +extern int Q3_GetFloatVariable( const char *name, float *value ); +extern int Q3_GetVectorVariable( const char *name, vec3_t value ); +extern int Q3_VariableDeclared( const char *name ); +extern int Q3_SetFloatVariable( const char *name, float value ); +extern int Q3_SetStringVariable( const char *name, const char *value ); +extern int Q3_SetVectorVariable( const char *name, const char *value ); + +#endif //__cplusplus diff --git a/Projects/Android/jni/OpenJK/codemp/icarus/Sequence.cpp b/Projects/Android/jni/OpenJK/codemp_delete/icarus/Sequence.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/icarus/Sequence.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/icarus/Sequence.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/icarus/Sequencer.cpp b/Projects/Android/jni/OpenJK/codemp_delete/icarus/Sequencer.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/icarus/Sequencer.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/icarus/Sequencer.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/icarus/TaskManager.cpp b/Projects/Android/jni/OpenJK/codemp_delete/icarus/TaskManager.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/icarus/TaskManager.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/icarus/TaskManager.cpp diff --git a/Projects/Android/jni/OpenJK/codemp_delete/icarus/Tokenizer.cpp b/Projects/Android/jni/OpenJK/codemp_delete/icarus/Tokenizer.cpp new file mode 100644 index 0000000..83248b7 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/icarus/Tokenizer.cpp @@ -0,0 +1,2868 @@ +// Tokenizer.cpp +#ifndef NOT_USING_MODULES +// !!! if you are not using modules, read BELOW !!! +#include "module.h" // if you are not using modules, + // create an empty Module.h in your + // project -- use of modules allows + // the error handler to be overridden + // with a custom CErrHandler +#endif +#include "tokenizer.h" + +#pragma warning(disable : 4100) //unreferenced formal parameter +#pragma warning(disable : 4127) //conditional expression is constant +#pragma warning(disable : 4189) //local variable is initialized but not referenced +#pragma warning(disable : 4244) //conversion from x to x, possible loss of data + +#ifndef _WIN32 +#include +#include +#endif + +enum +{ + DIR_INCLUDE = TK_USERDEF, + DIR_IFDEF, + DIR_IFNDEF, + DIR_ENDIF, + DIR_ELSE, + DIR_DEFINE, + DIR_UNDEFINE, +}; + +keywordArray_t CTokenizer::directiveKeywords[] = +{ + "include", DIR_INCLUDE, + "ifdef", DIR_IFDEF, + "ifndef", DIR_IFNDEF, + "endif", DIR_ENDIF, + "else", DIR_ELSE, + "define", DIR_DEFINE, + "undefine", DIR_UNDEFINE, + "", TK_EOF, +}; + +keywordArray_t CTokenizer::errorMessages[] = +{ + "No Error", TKERR_NONE, + "Unknown Error", TKERR_UNKNOWN, + "Buffer creation failed", TKERR_BUFFERCREATE, + "Unrecognized symbol", TKERR_UNRECOGNIZEDSYMBOL, + "Duplicate symbol", TKERR_DUPLICATESYMBOL, + "String length exceeded", TKERR_STRINGLENGTHEXCEEDED, + "Identifier length exceeded", TKERR_IDENTIFIERLENGTHEXCEEDED, + "Expected integer", TKERR_EXPECTED_INTEGER, + "Expected identifier", TKERR_EXPECTED_IDENTIFIER, + "Expected string", TKERR_EXPECTED_STRING, + "Expected char", TKERR_EXPECTED_CHAR, + "Expected float", TKERR_EXPECTED_FLOAT, + "Unexpected token", TKERR_UNEXPECTED_TOKEN, + "Invalid directive", TKERR_INVALID_DIRECTIVE, + "Include file not found", TKERR_INCLUDE_FILE_NOTFOUND, + "Unmatched directive", TKERR_UNMATCHED_DIRECTIVE, + "", TKERR_USERERROR, +}; + +// +// CSymbol +// + +CSymbol::CSymbol() +{ +} + +CSymbol::~CSymbol() +{ +} + +CSymbol* CSymbol::Create(LPCTSTR symbolName) +{ + CSymbol* retval = new CSymbol(); + retval->Init(symbolName); + return retval; +} + +LPCTSTR CSymbol::GetName() +{ + if (m_symbolName == NULL) + { + return ""; + } + return m_symbolName; +} + +void CSymbol::InitBaseSymbol(LPCTSTR symbolName) +{ + m_symbolName = (char*)malloc(strlen(symbolName) + 1); +// ASSERT(m_symbolName); + strcpy(m_symbolName, symbolName); +} + +void CSymbol::Delete() +{ + if (m_symbolName != NULL) + { + free(m_symbolName); + m_symbolName = NULL; + } + delete this; +} + +// +// CDirectiveSymbol +// + +CDirectiveSymbol::CDirectiveSymbol() +{ +} + +CDirectiveSymbol::~CDirectiveSymbol() +{ +} + +CDirectiveSymbol* CDirectiveSymbol::Create(LPCTSTR symbolName) +{ + CDirectiveSymbol* retval = new CDirectiveSymbol(); + retval->Init(symbolName); + return retval; +} + +void CDirectiveSymbol::Init(LPCTSTR symbolName) +{ + CSymbol::InitBaseSymbol(symbolName); + m_value = NULL; +} + +void CDirectiveSymbol::Delete() +{ + if (m_value != NULL) + { + free(m_value); + m_value = NULL; + } + CSymbol::Delete(); +} + +void CDirectiveSymbol::SetValue(LPCTSTR value) +{ + if (m_value != NULL) + { + free(m_value); + } + m_value = (char*)malloc(strlen(value) + 1); + strcpy(m_value, value); +} + +LPCTSTR CDirectiveSymbol::GetValue() +{ + return m_value; +} + +// +// CIntSymbol +// + +CIntSymbol::CIntSymbol() +{ +} + +CIntSymbol* CIntSymbol::Create(LPCTSTR symbolName, int value) +{ + CIntSymbol* retval = new CIntSymbol(); + retval->Init(symbolName, value); + return retval; +} + +void CIntSymbol::Delete() +{ + CSymbol::Delete(); +} + +void CIntSymbol::Init(LPCTSTR symbolName, int value) +{ + CSymbol::InitBaseSymbol(symbolName); + m_value = value; +} + +int CIntSymbol::GetValue() +{ + return m_value; +} + +// +// CSymbolTable +// + +CSymbolTable::CSymbolTable() +{ + Init(); +} + +CSymbolTable::~CSymbolTable() +{ +} + +CSymbolTable* CSymbolTable::Create() +{ + CSymbolTable* retval = new CSymbolTable(); + retval->Init(); + return retval; +} + +void CSymbolTable::Init() +{ +} + +void CSymbolTable::DiscardSymbols() +{ + for (symbolmap_t::iterator isymbol = m_symbols.begin(); isymbol != m_symbols.end(); ++isymbol) + { + (*isymbol).second->Delete(); + } + m_symbols.erase(m_symbols.begin(), m_symbols.end()); +} + +void CSymbolTable::Delete() +{ + DiscardSymbols(); + delete this; +} + +bool CSymbolTable::AddSymbol(CSymbol* theSymbol) +{ + LPCTSTR name = theSymbol->GetName(); + + symbolmap_t::iterator iter = m_symbols.find(name); + if (iter != m_symbols.end()) + { + return false; + } + m_symbols.insert(symbolmap_t::value_type(name, theSymbol)); + return true; +} + +CSymbol* CSymbolTable::FindSymbol(LPCTSTR symbolName) +{ + symbolmap_t::iterator iter = m_symbols.find(symbolName); + if (iter != m_symbols.end()) + { + return (*iter).second; + } + return NULL; +} + +CSymbol* CSymbolTable::ExtractSymbol(LPCTSTR symbolName) +{ + symbolmap_t::iterator iter = m_symbols.find(symbolName); + if (iter != m_symbols.end()) + { + CSymbol* retval = (*iter).second; + m_symbols.erase(iter); + } + return NULL; +} + +void CSymbolTable::RemoveSymbol(LPCTSTR symbolName) +{ + m_symbols.erase(symbolName); +} + +// +// CParseStream +// + +CParseStream::CParseStream() +{ +} + +CParseStream::~CParseStream() +{ +} + +CParseStream* CParseStream::Create() +{ + return NULL; +} + +void CParseStream::Delete() +{ + delete this; +} + +bool CParseStream::InitBaseStream() +{ + m_next = NULL; + + return true; +} + +bool CParseStream::NextChar(byte& theByte) +{ + return false; +} + +long CParseStream::GetRemainingSize() +{ + return 0; +} + +CParseStream* CParseStream::GetNext() +{ + return m_next; +} + +void CParseStream::SetNext(CParseStream* next) +{ + m_next = next; +} + +int CParseStream::GetCurLine() +{ + return 0; +} + +void CParseStream::GetCurFilename(char** theBuff) +{ + *theBuff = NULL; +} + +bool CParseStream::IsThisDefinition(void* theDefinition) +{ + return false; +} + +// +// CParsePutBack +// + +CParsePutBack::CParsePutBack() +{ +} + +CParsePutBack::~CParsePutBack() +{ +} + +CParsePutBack* CParsePutBack::Create(byte theByte, int curLine, LPCTSTR filename) +{ + CParsePutBack* curParsePutBack = new CParsePutBack(); + curParsePutBack->Init(theByte, curLine, filename); + return curParsePutBack; +} + +void CParsePutBack::Delete() +{ + if (m_curFile != NULL) + { + free(m_curFile); + m_curFile = NULL; + } + delete this; +} + +bool CParsePutBack::NextChar(byte& theByte) +{ + if (m_consumed) + { + return false; + } + theByte = m_byte; + m_consumed = true; + return true; +} + +void CParsePutBack::Init(byte theByte, int curLine, LPCTSTR filename) +{ + CParseStream::InitBaseStream(); + m_consumed = false; + m_byte = theByte; + m_curLine = curLine; + if (filename != NULL) + { + m_curFile = (char*)malloc(strlen(filename) + 1); + strcpy(m_curFile, filename); + } + else + { + m_curFile = NULL; + } +} + +long CParsePutBack::GetRemainingSize() +{ + if (m_consumed) + { + return 0; + } + else + { + return 1; + } +} + +int CParsePutBack::GetCurLine() +{ + return m_curLine; +} + +void CParsePutBack::GetCurFilename(char** theBuff) +{ + if (m_curFile == NULL) + { + *theBuff = NULL; + return; + } + *theBuff = (char*)malloc(strlen(m_curFile) + 1); + strcpy(*theBuff, m_curFile); +} + +// +// CParseFile +// + +CParseFile::CParseFile() +{ +} + +CParseFile::~CParseFile() +{ +} + +CParseFile* CParseFile::Create() +{ + CParseFile* theParseFile = new CParseFile(); + + if ( !theParseFile->Init() ) + { + delete theParseFile; + return NULL; + } + + return theParseFile; +} + +CParseFile* CParseFile::Create(LPCTSTR filename, CTokenizer* tokenizer) +{ + CParseFile* theParseFile = new CParseFile(); + + if ( theParseFile->Init(filename, tokenizer) ) + return theParseFile; + + return NULL; +} + +void CParseFile::Delete() +{ + if (m_buff != NULL) + { + free(m_buff); + m_buff = NULL; + } + if (m_ownsFile && (m_fileHandle != NULL)) + { +#ifdef _WIN32 + CloseHandle(m_fileHandle); +#else + fclose(m_fileHandle); +#endif + m_fileHandle = NULL; + } + if (m_fileName != NULL) + { + free(m_fileName); + m_fileName = NULL; + } + delete this; +} + +bool CParseFile::Init() +{ + m_fileHandle = NULL; + m_buff = NULL; + m_ownsFile = false; + m_curByte = NULL; + m_curLine = 1; + m_fileName = NULL; + return CParseStream::InitBaseStream(); +} + +unsigned int CParseFile::GetFileSize() +{ +#ifdef _WIN32 + unsigned int dwCur = SetFilePointer(m_fileHandle, 0L, NULL, FILE_CURRENT); + unsigned int dwLen = SetFilePointer(m_fileHandle, 0, NULL, FILE_END); + SetFilePointer(m_fileHandle, dwCur, NULL, FILE_BEGIN); +#else + fseek(m_fileHandle, 0L, SEEK_END); + unsigned int dwLen = ftell(m_fileHandle); + fseek(m_fileHandle, 0L, SEEK_SET); +#endif + return dwLen; +} + +void CParseFile::Read(void* buff, UINT buffsize) +{ + unsigned int bytesRead; +#ifdef _WIN32 + ReadFile(m_fileHandle, buff, buffsize, &bytesRead, NULL); +#else + fread(buff, buffsize, 1, m_fileHandle); +#endif +} + +bool CParseFile::Init(LPCTSTR filename, CTokenizer* tokenizer) +{ + CParseStream::InitBaseStream(); + m_fileName = (char*)malloc(strlen(filename) + 1); + strcpy(m_fileName, filename); + +#ifdef _WIN32 + unsigned int dwAccess = GENERIC_READ; + unsigned int dwShareMode = FILE_SHARE_WRITE | FILE_SHARE_READ; + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = 0; + unsigned int dwCreateFlag = OPEN_EXISTING; + + m_fileHandle = CreateFile(filename, dwAccess, dwShareMode, &sa, dwCreateFlag, FILE_ATTRIBUTE_NORMAL, NULL); + + if (m_fileHandle == (HANDLE)-1) + { + tokenizer->Error(TKERR_INCLUDE_FILE_NOTFOUND); + Init(); + + return false; + } +#else + m_fileHandle = fopen(filename, "r+"); + + if (m_fileHandle == NULL) + { + tokenizer->Error(TKERR_INCLUDE_FILE_NOTFOUND); + Init(); + + return false; + } +#endif + m_filesize = GetFileSize(); + m_buff = (byte*)malloc(m_filesize); + if (m_buff == NULL) + { + tokenizer->Error(TKERR_BUFFERCREATE); + Init(); + return false; + } + Read(m_buff, m_filesize); + m_curByte = 0; + m_curPos = 1; + m_ownsFile = true; + m_curLine = 1; + + return true; +} + +long CParseFile::GetRemainingSize() +{ + return m_filesize - m_curByte; +} + +bool CParseFile::NextChar(byte& theByte) +{ + if (m_curByte < m_filesize) + { + if (m_buff[m_curByte] == '\n') + { + m_curLine += 1; + m_curPos = 1; + } + else + { + m_curPos++; + } + theByte = m_buff[m_curByte++]; + return true; + } + else + { + return false; + } +} + +int CParseFile::GetCurLine() +{ + return m_curLine; +} + +void CParseFile::GetCurFilename(char** theBuff) +{ + *theBuff = NULL; + if (m_fileName != NULL) + { + *theBuff = (char*)malloc(strlen(m_fileName) + 1); + strcpy(*theBuff, m_fileName); + } +} + +// +// CParseMemory +// + +CParseMemory::CParseMemory() +{ +} + +CParseMemory::~CParseMemory() +{ +} + +CParseMemory* CParseMemory::Create(byte* data, long datasize) +{ + CParseMemory* curParse = new CParseMemory(); + curParse->Init(data, datasize); + return curParse; +} + +void CParseMemory::Delete() +{ + delete this; +} + +bool CParseMemory::NextChar(byte& theByte) +{ + if (m_offset < m_datasize) + { + if (m_data[m_offset] == '\n') + { + m_curLine += 1; + m_curPos = 1; + } + else + { + m_curPos++; + } + theByte = m_data[m_offset++]; + return true; + } + else + { + return false; + } +} + +void CParseMemory::Init(byte* data, long datasize) +{ + m_data = data; + m_curLine = 1; + m_curPos = 1; + m_offset = 0; + m_datasize = datasize; +} + +long CParseMemory::GetRemainingSize() +{ + return m_datasize - m_offset; +} + +int CParseMemory::GetCurLine() +{ + return m_curLine; +} + +void CParseMemory::GetCurFilename(char** theBuff) +{ + *theBuff = NULL; +} + +// +// CParseBlock +// + +CParseBlock::CParseBlock() +{ +} + +CParseBlock::~CParseBlock() +{ +} + +CParseBlock* CParseBlock::Create(byte* data, long datasize) +{ + CParseBlock* curParse = new CParseBlock(); + curParse->Init(data, datasize); + return curParse; +} + +void CParseBlock::Delete() +{ + if (m_data != NULL) + { + free(m_data); + m_data = NULL; + } + delete this; +} + +void CParseBlock::Init(byte* data, long datasize) +{ + m_data = (byte*)malloc(datasize); + memcpy(m_data, data, datasize); + m_curLine = 1; + m_curPos = 1; + m_offset = 0; + m_datasize = datasize; +} + +// +// CParseToken +// + +CParseToken::CParseToken() +{ +} + +CParseToken::~CParseToken() +{ +} + +CParseToken* CParseToken::Create(CToken* token) +{ + CParseToken* curParse = new CParseToken(); + curParse->Init(token); + return curParse; +} + +void CParseToken::Delete() +{ + if (m_data != NULL) + { + free(m_data); + m_data = NULL; + } + delete this; +} + +bool CParseToken::NextChar(byte& theByte) +{ + if (m_offset < m_datasize) + { + if (m_data[m_offset] == '\n') + { + m_curLine += 1; + m_curPos = 1; + } + else + { + m_curPos++; + } + theByte = m_data[m_offset++]; + return true; + } + else + { + return false; + } +} + +void CParseToken::Init(CToken* token) +{ + LPCTSTR tokenString = token->GetStringValue(); + m_datasize = strlen(tokenString); + if (m_datasize > 0) + { + m_data = (byte*) malloc(m_datasize); + memcpy(m_data, tokenString, m_datasize); + } + else + { + m_data = NULL; + } + m_curLine = 1; + m_curPos = 1; + m_offset = 0; + token->Delete(); +} + +long CParseToken::GetRemainingSize() +{ + return m_datasize - m_offset; +} + +int CParseToken::GetCurLine() +{ + return m_curLine; +} + +void CParseToken::GetCurFilename(char** theBuff) +{ + *theBuff = NULL; +} + +// +// CParseDefine +// + +CParseDefine::CParseDefine() +{ +} + +CParseDefine::~CParseDefine() +{ +} + +CParseDefine* CParseDefine::Create(CDirectiveSymbol* definesymbol) +{ + CParseDefine* retval = new CParseDefine(); + retval->Init(definesymbol); + return retval; +} + +void CParseDefine::Delete() +{ + CParseMemory::Delete(); +} + +void CParseDefine::Init(CDirectiveSymbol* definesymbol) +{ + CParseMemory::Init((byte*)definesymbol->GetValue(), strlen(definesymbol->GetValue())); + m_defineSymbol = definesymbol; +} + +bool CParseDefine::IsThisDefinition(void* theDefinition) +{ + return (CDirectiveSymbol*)theDefinition == m_defineSymbol; +} + +// +// CToken +// + +CToken::CToken() +{ +} + +CToken::~CToken() +{ +} + +CToken* CToken::Create() +{ + CToken* theToken = new CToken(); + theToken->InitBaseToken(); + return theToken; +} + +void CToken::Delete() +{ + if (m_string != NULL) + { + free(m_string); + m_string = NULL; + } + delete this; +} + +void CToken::InitBaseToken() +{ + m_next = NULL; + m_string = NULL; +} + +void CToken::SetNext(CToken* theToken) +{ + m_next = theToken; +} + +CToken* CToken::GetNext() +{ + return m_next; +} + +int CToken::GetType() +{ + return TK_EOF; +} + +int CToken::GetIntValue() +{ + return 0; +} + +LPCTSTR CToken::GetStringValue() +{ + if (m_string == NULL) + { + return ""; + } + return m_string; +} + +float CToken::GetFloatValue() +{ + return 0.0; +} + +// +// CCharToken +// + +CCharToken::CCharToken() +{ +} + +CCharToken::~CCharToken() +{ +} + +CCharToken* CCharToken::Create(byte theByte) +{ + CCharToken* theToken = new CCharToken(); + theToken->Init(theByte); + return theToken; +} + +void CCharToken::Delete() +{ + CToken::Delete(); +} + +void CCharToken::Init(byte theByte) +{ + CToken::InitBaseToken(); + char charString[10]; + switch(theByte) + { + case '\0': + strcpy(charString, "\\0"); + break; + case '\n': + strcpy(charString, "\\n"); + break; + case '\\': + strcpy(charString, "\\\\"); + break; + case '\'': + strcpy(charString, "\\'"); + break; + case '\?': + strcpy(charString, "\\?"); + break; + case '\a': + strcpy(charString, "\\a"); + break; + case '\b': + strcpy(charString, "\\b"); + break; + case '\f': + strcpy(charString, "\\f"); + break; + case '\r': + strcpy(charString, "\\r"); + break; + case '\t': + strcpy(charString, "\\t"); + break; + case '\v': + strcpy(charString, "\\v"); + break; + default: + charString[0] = (char)theByte; + charString[1] = '\0'; + break; + } + m_string = (char*)malloc(strlen(charString) + 1); + strcpy(m_string, charString); +} + +int CCharToken::GetType() +{ + return TK_CHAR; +} + +// +// CStringToken +// + +CStringToken::CStringToken() +{ +} + +CStringToken::~CStringToken() +{ +} + +CStringToken* CStringToken::Create(LPCTSTR theString) +{ + CStringToken* theToken = new CStringToken(); + theToken->Init(theString); + return theToken; +} + +void CStringToken::Delete() +{ + CToken::Delete(); +} + +void CStringToken::Init(LPCTSTR theString) +{ + CToken::InitBaseToken(); + m_string = (char*)malloc(strlen(theString) + 1); +// ASSERT(m_string); + strcpy(m_string, theString); +} + +int CStringToken::GetType() +{ + return TK_STRING; +} + +// +// CIntToken +// + +CIntToken::CIntToken() +{ +} + +CIntToken::~CIntToken() +{ +} + +CIntToken* CIntToken::Create(long value) +{ + CIntToken* theToken = new CIntToken(); + theToken->Init(value); + return theToken; +} + +void CIntToken::Delete() +{ + CToken::Delete(); +} + +void CIntToken::Init(long value) +{ + CToken::InitBaseToken(); + m_value = value; +} + +int CIntToken::GetType() +{ + return TK_INT; +} + +int CIntToken::GetIntValue() +{ + return m_value; +} + +float CIntToken::GetFloatValue() +{ + return (float)m_value; +} + +LPCTSTR CIntToken::GetStringValue() +{ + if (m_string != NULL) + { + free(m_string); + m_string = NULL; + } + char temp[128]; + sprintf(temp, "%d", m_value); + m_string = (char*)malloc(strlen(temp) + 1); + strcpy(m_string, temp); + return m_string; +} + +// +// CFloatToken +// + +CFloatToken::CFloatToken() +{ +} + +CFloatToken::~CFloatToken() +{ +} + +CFloatToken* CFloatToken::Create(float value) +{ + CFloatToken* theToken = new CFloatToken(); + theToken->Init(value); + return theToken; +} + +void CFloatToken::Delete() +{ + CToken::Delete(); +} + +void CFloatToken::Init(float value) +{ + CToken::InitBaseToken(); + m_value = value; +} + +int CFloatToken::GetType() +{ + return TK_FLOAT; +} + +float CFloatToken::GetFloatValue() +{ + return m_value; +} + +LPCTSTR CFloatToken::GetStringValue() +{ + if (m_string != NULL) + { + free(m_string); + m_string = NULL; + } + char temp[128]; + sprintf(temp, "%g", m_value); + m_string = (char*)malloc(strlen(temp) + 1); + strcpy(m_string, temp); + return m_string; +} + +// +// CIdentifierToken +// + +CIdentifierToken::CIdentifierToken() +{ +} + +CIdentifierToken::~CIdentifierToken() +{ +} + +CIdentifierToken* CIdentifierToken::Create(LPCTSTR name) +{ + CIdentifierToken* theToken = new CIdentifierToken(); + theToken->Init(name); + return theToken; +} + +void CIdentifierToken::Delete() +{ + CToken::Delete(); +} + +void CIdentifierToken::Init(LPCTSTR name) +{ + CToken::InitBaseToken(); + m_string = (char*)malloc(strlen(name) + 1); +// ASSERT(m_string); + strcpy(m_string, name); +} + +int CIdentifierToken::GetType() +{ + return TK_IDENTIFIER; +} + +// +// CCommentToken +// + +CCommentToken::CCommentToken() +{ +} + +CCommentToken::~CCommentToken() +{ +} + +CCommentToken* CCommentToken::Create(LPCTSTR name) +{ + CCommentToken* theToken = new CCommentToken(); + theToken->Init(name); + return theToken; +} + +void CCommentToken::Delete() +{ + CToken::Delete(); +} + +void CCommentToken::Init(LPCTSTR name) +{ + CToken::InitBaseToken(); + m_string = (char*)malloc(strlen(name) + 1); +// ASSERT(m_string); + strcpy(m_string, name); +} + +int CCommentToken::GetType() +{ + return TK_COMMENT; +} + +// +// CUserToken +// + +CUserToken::CUserToken() +{ +} + +CUserToken::~CUserToken() +{ +} + +CUserToken* CUserToken::Create(int value, LPCTSTR string) +{ + CUserToken* theToken = new CUserToken(); + theToken->Init(value, string); + return theToken; +} + +void CUserToken::Delete() +{ + CToken::Delete(); +} + +void CUserToken::Init(int value, LPCTSTR string) +{ + CToken::InitBaseToken(); + m_value = value; + m_string = (char*)malloc(strlen(string) + 1); + strcpy(m_string, string); +} + +int CUserToken::GetType() +{ + return m_value; +} + +// +// CUndefinedToken +// + +CUndefinedToken::CUndefinedToken() +{ +} + +CUndefinedToken::~CUndefinedToken() +{ +} + +CUndefinedToken* CUndefinedToken::Create(LPCTSTR string) +{ + CUndefinedToken* theToken = new CUndefinedToken(); + theToken->Init(string); + return theToken; +} + +void CUndefinedToken::Delete() +{ + CToken::Delete(); +} + +void CUndefinedToken::Init(LPCTSTR string) +{ + CToken::InitBaseToken(); + m_string = (char*)malloc(strlen(string) + 1); + strcpy(m_string, string); +} + +int CUndefinedToken::GetType() +{ + return TK_UNDEFINED; +} + +// +// CTokenizerState +// + +CTokenizerState::CTokenizerState() +{ +} + +CTokenizerState::~CTokenizerState() +{ +} + +CTokenizerState* CTokenizerState::Create(bool skip) +{ + CTokenizerState* retval = new CTokenizerState(); + retval->Init(skip); + return retval; +} + +void CTokenizerState::Init(bool skip) +{ + m_next = NULL; + m_skip = skip; + m_elseHit = false; +} + +void CTokenizerState::Delete() +{ + delete this; +} + +CTokenizerState* CTokenizerState::GetNext() +{ + return m_next; +} + +bool CTokenizerState::ProcessElse() +{ + if (!m_elseHit) + { + m_elseHit = true; + m_skip = !m_skip; + } + return m_elseHit; +} + +void CTokenizerState::SetNext(CTokenizerState* next) +{ + m_next = next; +} + +bool CTokenizerState::Skipping() +{ + return m_skip; +} + +// +// CTokenizerHolderState +// + +CTokenizerHolderState::CTokenizerHolderState() +{ +} + +CTokenizerHolderState::~CTokenizerHolderState() +{ +} + +CTokenizerHolderState* CTokenizerHolderState::Create() +{ + CTokenizerHolderState* retval = new CTokenizerHolderState(); + retval->Init(); + return retval; +} + +void CTokenizerHolderState::Init() +{ + CTokenizerState::Init(true); +} + +void CTokenizerHolderState::Delete() +{ + delete this; +} + +bool CTokenizerHolderState::ProcessElse() +{ + if (!m_elseHit) + { + m_elseHit = true; + } + return m_elseHit; +} + +// +// CKeywordTable +// + +CKeywordTable::CKeywordTable(CTokenizer* tokenizer, keywordArray_t* keywords) +{ + m_tokenizer = tokenizer; + m_holdKeywords = tokenizer->SetKeywords(keywords); +} + +CKeywordTable::~CKeywordTable() +{ + m_tokenizer->SetKeywords(m_holdKeywords); +} + +// +// CTokenizer +// + +CTokenizer::CTokenizer() +{ +} + +CTokenizer::~CTokenizer() +{ +} + +CTokenizer* CTokenizer::Create(UINT dwFlags) +{ + CTokenizer* theTokenizer = new CTokenizer(); + theTokenizer->Init(dwFlags); + return theTokenizer; +} + +void CTokenizer::Delete() +{ + while (m_curParseStream != NULL) + { + CParseStream* curStream = m_curParseStream; + m_curParseStream = curStream->GetNext(); + curStream->Delete(); + } + if (m_symbolLookup != NULL) + { + m_symbolLookup->Delete(); + m_symbolLookup = NULL; + } + while (m_nextToken != NULL) + { + CToken* curToken = m_nextToken; + m_nextToken = curToken->GetNext(); + curToken->Delete(); + } + while (m_state != NULL) + { + Error(TKERR_UNMATCHED_DIRECTIVE); + CTokenizerState* curState = m_state; + m_state = curState->GetNext(); + curState->Delete(); + } + +/* if (m_lastErrMsg != NULL) + { + free(m_lastErrMsg); + m_lastErrMsg = NULL; + }*/ + delete this; +} + +void CTokenizer::Error(int theError) +{ + char errString[128]; + char lookupstring[128]; + int i = 0; + while ((errorMessages[i].m_tokenvalue != TKERR_USERERROR) && (errorMessages[i].m_tokenvalue != theError)) + { + i++; + } + if ((errorMessages[i].m_tokenvalue == TKERR_USERERROR) && (m_errors != NULL)) + { + i = 0; + while ((m_errors[i].m_tokenvalue != TK_EOF) && (m_errors[i].m_tokenvalue != theError)) + { + i++; + } + strcpy(lookupstring, m_errors[i].m_keyword); + } + else + { + strcpy(lookupstring, errorMessages[i].m_keyword); + } + sprintf(errString, "Error -- %d, %s", theError, lookupstring); + Error(errString, theError); +} + +void CTokenizer::Error(int theError, LPCTSTR errString) +{ + char errstring[128]; + char lookupstring[128]; + int i = 0; + while ((errorMessages[i].m_tokenvalue != TKERR_USERERROR) && (errorMessages[i].m_tokenvalue != theError)) + { + i++; + } + if ((errorMessages[i].m_tokenvalue == TKERR_USERERROR) && (m_errors != NULL)) + { + i = 0; + while ((m_errors[i].m_tokenvalue != TK_EOF) && (m_errors[i].m_tokenvalue != theError)) + { + i++; + } + strcpy(lookupstring, m_errors[i].m_keyword); + } + else + { + strcpy(lookupstring, errorMessages[i].m_keyword); + } + sprintf(errstring, "Error -- %d, %s - %s", theError, lookupstring, errString); + Error(errstring, theError); +} + +void CTokenizer::Error(LPCTSTR errString, int theError) +{ + if (m_errorProc != NULL) + { + m_errorProc(errString); + } +#ifdef USES_MODULES + else + { + ReportError(theError, errString); + } +#endif +} + +bool CTokenizer::AddParseFile(LPCTSTR filename) +{ + CParseStream* newStream = CParseFile::Create(filename, this); + + if ( newStream != NULL ) + { + newStream->SetNext(m_curParseStream); + m_curParseStream = newStream; + return true; + } + + return false; +} + +void CTokenizer::AddParseStream(byte* data, long datasize) +{ + CParseStream* newStream = CParseMemory::Create(data, datasize); + newStream->SetNext(m_curParseStream); + m_curParseStream = newStream; +} + +long CTokenizer::GetRemainingSize() +{ + long retval = 0; + CParseStream* curStream = m_curParseStream; + while (curStream != NULL) + { + retval += curStream->GetRemainingSize(); + curStream = curStream->GetNext(); + } + return retval; +} + +LPCTSTR CTokenizer::LookupToken(int tokenID, keywordArray_t* theTable) +{ + if (theTable == NULL) + { + theTable = m_keywords; + } + if (theTable == NULL) + { + return NULL; + } + + int i = 0; + while (theTable[i].m_tokenvalue != TK_EOF) + { + if (theTable[i].m_tokenvalue == tokenID) + { + return theTable[i].m_keyword; + } + i++; + } + return NULL; +} + +void CTokenizer::PutBackToken(CToken* theToken, bool commented, LPCTSTR addedChars, bool bIgnoreThisTokenType) +{ + if (commented) + { + CParseToken* newStream = CParseToken::Create(theToken); + newStream->SetNext(m_curParseStream); + m_curParseStream = newStream; + + if (addedChars != NULL) + { + CParsePutBack* spacer = CParsePutBack::Create(' ', 0, NULL); + spacer->SetNext(m_curParseStream); + m_curParseStream = spacer; + + CParseBlock* newBlock = CParseBlock::Create((byte*)addedChars, strlen(addedChars)); + newBlock->SetNext(m_curParseStream); + m_curParseStream = newBlock; + } + + char temp[] = "// * "; + CParseBlock* newBlock = CParseBlock::Create((byte*)temp, strlen(temp)); + newBlock->SetNext(m_curParseStream); + m_curParseStream = newBlock; + return; + } + + switch(theToken->GetType()) + { + case TK_INT: + case TK_EOF: + case TK_UNDEFINED: + case TK_FLOAT: + case TK_CHAR: + case TK_STRING: + case TK_EOL: + case TK_COMMENT: + if (!bIgnoreThisTokenType) + { + theToken->SetNext(m_nextToken); + m_nextToken = theToken; + break; + } + default: + CParseToken* newStream = CParseToken::Create(theToken); + newStream->SetNext(m_curParseStream); + m_curParseStream = newStream; + break; + } + + if (addedChars != NULL) + { + CParseBlock* newBlock = CParseBlock::Create((byte*)addedChars, strlen(addedChars)); + newBlock->SetNext(m_curParseStream); + m_curParseStream = newBlock; + } +} + +CToken* CTokenizer::GetToken(keywordArray_t* keywords, UINT onFlags, UINT offFlags) +{ + keywordArray_t* holdKeywords = SetKeywords(keywords); + CToken* retval = GetToken(onFlags, offFlags); + SetKeywords(holdKeywords); + return retval; +} + +CToken* CTokenizer::GetToken(UINT onFlags, UINT offFlags) +{ + UINT holdFlags = m_flags; + + m_flags |= onFlags; + m_flags &= (~offFlags); + CToken* theToken = NULL; + while (theToken == NULL) + { + theToken = FetchToken(); + if (theToken == NULL) + { + continue; + } + if (theToken->GetType() == TK_EOF) + { + break; + } + if (m_state != NULL) + { + if (m_state->Skipping()) + { + theToken->Delete(); + theToken = NULL; + } + } + } + + m_flags = holdFlags; + return theToken; +} + +CToken* CTokenizer::GetToEndOfLine(int tokenType) +{ + // update, if you just want the whole line returned as a string, then allow a much bigger size than + // the default string size of only 128 chars... + // + if (tokenType == TK_STRING) + { + #define iRETURN_STRING_SIZE 2048 + char theString[iRETURN_STRING_SIZE]; + theString[0] = ' '; + + for (int i = 1; i < iRETURN_STRING_SIZE; i++) + { + if (NextChar((byte&)theString[i])) + { + if (theString[i] != '\n') + { + continue; + } + PutBackChar(theString[i]); + } + theString[i] = '\0'; + + return CStringToken::Create(theString); + } + + // line would maks a string too big to fit in buffer... + // + Error(TKERR_STRINGLENGTHEXCEEDED); + } + else + { + char theString[MAX_IDENTIFIER_LENGTH]; + theString[0] = ' '; + while (theString[0] == ' ') + { + if (!NextChar((byte&)theString[0])) + { + return NULL; + } + } + for (int i = 1; i < MAX_IDENTIFIER_LENGTH; i++) + { + if (NextChar((byte&)theString[i])) + { + if (theString[i] != '\n') + { + continue; + } + PutBackChar(theString[i]); + } + theString[i] = '\0'; + switch(tokenType) + { + case TK_COMMENT: + return CCommentToken::Create(theString); + case TK_IDENTIFIER: + default: + return CIdentifierToken::Create(theString); + } + } + Error(TKERR_IDENTIFIERLENGTHEXCEEDED); + } + return NULL; +} + +void CTokenizer::SkipToLineEnd() +{ + byte theByte; + while(NextChar(theByte)) + { + if (theByte == '\n') + { + break; + } + } +} + +CToken* CTokenizer::FetchToken() +{ + if (m_nextToken != NULL) + { + CToken* curToken = m_nextToken; + m_nextToken = curToken->GetNext(); + curToken->SetNext(NULL); + return curToken; + } + byte theByte; + CToken* theToken = NULL; + + while (true) + { + if (!NextChar(theByte)) + { + return CToken::Create(); + } + if (theByte <= ' ') + { + if ((theByte == '\n') && ((TKF_USES_EOL & m_flags) != 0)) + { + return CUserToken::Create(TK_EOL, "-EOLN-"); + } + continue; + } + switch(theByte) + { + case '#': + if ((m_flags & TKF_IGNOREDIRECTIVES) == 0) + { + theToken = HandleDirective(); + } + else + { + if ((m_flags & TKF_NODIRECTIVES) != 0) + { + return HandleSymbol('#'); + } + SkipToLineEnd(); + } + break; + case '/': + theToken = HandleSlash(); + break; + case '"': + theToken = HandleString(); + break; + case '\'': + theToken = HandleQuote(); + break; + default: + if (((theByte >= 'a') && (theByte <= 'z')) + || ((theByte >= 'A') && (theByte <= 'Z')) + || ((theByte == '_') && ((m_flags & TKF_NOUNDERSCOREINIDENTIFIER) == 0))) + { + theToken = HandleIdentifier(theByte); + } + else if (((m_flags & TKF_NUMERICIDENTIFIERSTART) != 0) && (theByte >= '0') && (theByte <= '9')) + { + theToken = HandleIdentifier(theByte); + } + else if (((theByte >= '0') && (theByte <= '9')) || (theByte == '-')) + { + theToken = HandleNumeric(theByte); + } + else if (theByte == '.') + { + theToken = HandleDecimal(); + } + else if (theByte <= ' ') + { + break; + } + else + { + theToken = HandleSymbol(theByte); + } + } + if (theToken != NULL) + { + return theToken; + } + } +} + +bool CTokenizer::NextChar(byte& theByte) +{ + while (m_curParseStream != NULL) + { + if (m_curParseStream->NextChar(theByte)) + { + return true; + } + CParseStream* curParseStream = m_curParseStream; + m_curParseStream = curParseStream->GetNext(); + curParseStream->Delete(); + } + return false; +} + +bool CTokenizer::RequireToken(int tokenType) +{ + CToken* theToken = GetToken(); + bool retValue = theToken->GetType() == tokenType; + theToken->Delete(); + return retValue; +} + +void CTokenizer::ScanUntilToken(int tokenType) +{ + CToken* curToken; + int tokenValue = TK_UNDEFINED; + while (tokenValue != tokenType) + { + curToken = GetToken(); + tokenValue = curToken->GetType(); + if (tokenValue == TK_EOF) + { + PutBackToken(curToken); + break; + } + if (tokenValue == tokenType) + { + PutBackToken(curToken); + } + else + { + curToken->Delete(); + } + } +} + +void CTokenizer::Init(UINT dwFlags) +{ + m_symbolLookup = NULL; + m_nextToken = NULL; + m_curParseStream = NULL; + m_keywords = NULL; + m_symbols = NULL; + m_errors = NULL; + m_state = NULL; + m_flags = dwFlags; + m_errorProc = NULL; +} + +void CTokenizer::SetErrorProc(LPTokenizerErrorProc errorProc) +{ + m_errorProc = errorProc; +} + +void CTokenizer::SetAdditionalErrors(keywordArray_t* theErrors) +{ + m_errors = theErrors; +} + +keywordArray_t* CTokenizer::SetKeywords(keywordArray_t* theKeywords) +{ + keywordArray_t* retval = m_keywords; + m_keywords = theKeywords; + return retval; +} + +void CTokenizer::SetSymbols(keywordArray_t* theSymbols) +{ + m_symbols = theSymbols; + if (m_symbolLookup != NULL) + { + m_symbolLookup->Delete(); + m_symbolLookup = NULL; + } + int i = 0; + if (theSymbols == NULL) + { + return; + } + while(theSymbols[i].m_tokenvalue != TK_EOF) + { + InsertSymbol(theSymbols[i].m_keyword, theSymbols[i].m_tokenvalue); + i++; + } +} + +void CTokenizer::InsertSymbol(LPCTSTR theSymbol, int theValue) +{ + CSymbolLookup** curHead = &m_symbolLookup; + CSymbolLookup* curParent = NULL; + CSymbolLookup* curLookup = NULL; + + for (UINT i = 0; i < strlen(theSymbol); i++) + { + bool found = false; + curLookup = *curHead; + while (curLookup != NULL) + { + if (curLookup->GetByte() == theSymbol[i]) + { + found = true; + break; + } + curLookup = curLookup->GetNext(); + } + if (!found) + { + curLookup = CSymbolLookup::Create(theSymbol[i]); + curLookup->SetParent(curParent); + curLookup->SetNext(*curHead); + *curHead = curLookup; + } + curHead = curLookup->GetChildAddress(); + curParent = curLookup; + } + if (curLookup->GetValue() != -1) + { + Error(TKERR_DUPLICATESYMBOL); + } + curLookup->SetValue(theValue); +} + +CToken* CTokenizer::HandleString() +{ + char theString[MAX_STRING_LENGTH]; + for (int i = 0; i < MAX_STRING_LENGTH; i++) + { + if (!NextChar((byte&)theString[i])) + { + return NULL; + } + if (theString[i] == '"') + { + theString[i] = '\0'; + return CStringToken::Create(theString); + } + if (theString[i] == '\\') + { + theString[i] = Escapement(); + } + } + Error(TKERR_STRINGLENGTHEXCEEDED); + return NULL; +} + +void CTokenizer::GetCurFilename(char** filename) +{ + if (m_curParseStream == NULL) + { + *filename = (char*)malloc(1); + *filename[0] = '\0'; + return; + } + m_curParseStream->GetCurFilename(filename); +} + +int CTokenizer::GetCurLine() +{ + if (m_curParseStream == NULL) + { + return 0; + } + return m_curParseStream->GetCurLine(); +} + +void CTokenizer::PutBackChar(byte theByte, int curLine, LPCTSTR filename) +{ + CParseStream* newStream; + if (filename == NULL) + { + curLine = m_curParseStream->GetCurLine(); + char* theFile = NULL; + m_curParseStream->GetCurFilename(&theFile); + newStream = CParsePutBack::Create(theByte, curLine, theFile); + if (theFile != NULL) + { + free(theFile); + } + } + else + { + newStream = CParsePutBack::Create(theByte, curLine, filename); + } + newStream->SetNext(m_curParseStream); + m_curParseStream = newStream; +} + +byte CTokenizer::Escapement() +{ + byte theByte; + if (NextChar(theByte)) + { + switch(theByte) + { + case 'n': + return '\n'; + case '\\': + return '\\'; + case '\'': + return '\''; + case '?': + return '\?'; + case 'a': + return '\a'; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'r': + return '\r'; + case 't': + return '\t'; + case 'v': + return '\v'; + case '0': + return '\0'; + // support for octal or hex sequences?? \000 or \xhhh + default: + PutBackChar(theByte); + } + } + return '\\'; +} + +bool CTokenizer::AddDefineSymbol(CDirectiveSymbol* definesymbol) +{ + CParseStream* curStream = m_curParseStream; + while(curStream != NULL) + { + if (curStream->IsThisDefinition(definesymbol)) + { + return false; + } + curStream = curStream->GetNext(); + } + CParseStream* newStream = CParseDefine::Create(definesymbol); + newStream->SetNext(m_curParseStream); + m_curParseStream = newStream; + return true; +} + +CToken* CTokenizer::TokenFromName(LPCTSTR name) +{ + CDirectiveSymbol* defineSymbol = (CDirectiveSymbol*)m_defines.FindSymbol(name); + if (defineSymbol != NULL) + { + if (AddDefineSymbol(defineSymbol)) + { + return FetchToken(); + } + } + if ((m_keywords != NULL) && ((m_flags & TKF_IGNOREKEYWORDS) == 0)) + { + int i = 0; + if ((m_flags & TKF_NOCASEKEYWORDS) == 0) + { + while (m_keywords[i].m_tokenvalue != TK_EOF) + { + if (strcmp(m_keywords[i].m_keyword, name) == 0) + { + return CUserToken::Create(m_keywords[i].m_tokenvalue, name); + } + i++; + } + } + else + { + while (m_keywords[i].m_tokenvalue != TK_EOF) + { + if (stricmp(m_keywords[i].m_keyword, name) == 0) + { + return CUserToken::Create(m_keywords[i].m_tokenvalue, name); + } + i++; + } + } + } + return CIdentifierToken::Create(name); +} + +int CTokenizer::DirectiveFromName(LPCTSTR name) +{ + if (directiveKeywords != NULL) + { + int i = 0; + while (directiveKeywords[i].m_tokenvalue != TK_EOF) + { + if (strcmp(directiveKeywords[i].m_keyword, name) == 0) + { + return directiveKeywords[i].m_tokenvalue; + } + i++; + } + } + return -1; +} + +CToken* CTokenizer::HandleIdentifier(byte theByte) +{ + char theString[MAX_IDENTIFIER_LENGTH]; + theString[0] = theByte; + for (int i = 1; i < MAX_IDENTIFIER_LENGTH; i++) + { + if (NextChar((byte&)theString[i])) + { + if (((theString[i] != '_') || ((m_flags & TKF_NOUNDERSCOREINIDENTIFIER) == 0)) && + ((theString[i] != '-') || ((m_flags & TKF_NODASHINIDENTIFIER) == 0))) + { + if (((theString[i] >= 'A') && (theString[i] <= 'Z')) + || ((theString[i] >= 'a') && (theString[i] <= 'z')) + || ((theString[i] >= '0') && (theString[i] <= '9')) + || (theString[i] == '_') || (theString[i] == '-')) + { + continue; + } + } + PutBackChar(theString[i]); + } + theString[i] = '\0'; + return TokenFromName(theString); + } + Error(TKERR_IDENTIFIERLENGTHEXCEEDED); + return NULL; +} + +CToken* CTokenizer::HandleSlash() +{ + byte theByte; + if (!NextChar(theByte)) + { + return NULL; + } + if (theByte == '/') + { + if (m_flags & TKF_COMMENTTOKENS) + { + return GetToEndOfLine(TK_COMMENT); + } + SkipToLineEnd(); + return NULL; + } + if (theByte == '*') + { + if (m_flags & TKF_COMMENTTOKENS) + { + char theString[MAX_IDENTIFIER_LENGTH + 1]; + theString[0] = ' '; + while (theString[0] == ' ') + { + if (!NextChar((byte&)theString[0])) + { + return NULL; + } + } + for (int i = 1; i < MAX_IDENTIFIER_LENGTH; i++) + { + if (NextChar((byte&)theString[i])) + { + if (theString[i] != '*') + { + continue; + } + i++; + if (NextChar((byte&)theString[i])) + { + if (theString[i] == '/') + { + i--; + theString[i] = '\0'; + return CCommentToken::Create(theString); + } + } + } + } + Error(TKERR_IDENTIFIERLENGTHEXCEEDED); + return NULL; + } + while(NextChar(theByte)) + { + while(theByte == '*') + { + if (!NextChar(theByte)) + { + break; + } + if (theByte == '/') + { + return NULL; + } + } + } + return NULL; + } + PutBackChar(theByte); + return HandleSymbol('/'); +} + +CToken* CTokenizer::HandleNumeric(byte theByte) +{ + bool thesign = theByte == '-'; + if (thesign) + { + if (!NextChar(theByte)) + { + return HandleSymbol('-'); + } + if (theByte == '.') + { + return HandleDecimal(thesign); + } + if ((theByte < '0') || (theByte > '9')) + { + PutBackChar(theByte); + return HandleSymbol('-'); + } + } + if (theByte == '0') + { + return HandleOctal(thesign); + } + long value = 0; + bool digithit = false; + while((theByte >= '0') && (theByte <= '9')) + { + value = (value * 10) + (theByte - '0'); + if (!NextChar(theByte)) + { + if (thesign) + { + value = -value; + } + return CIntToken::Create(value); + } + digithit = true; + } + if (theByte == '.') + { + if (digithit) + { + return HandleFloat(thesign, value); + } + if (thesign) + { + PutBackChar(theByte); + theByte = '-'; + } + return HandleSymbol(theByte); + } + PutBackChar(theByte); + if (thesign) + { + value = -value; + } + return CIntToken::Create(value); +} + +CToken* CTokenizer::HandleOctal(bool thesign) +{ + byte theByte; + int value = 0; + + if (!NextChar(theByte)) + { + return CIntToken::Create(value); + } + if (theByte == '.') + { + return HandleDecimal(thesign); + } + if ((theByte == 'x') || (theByte == 'X')) + { + return HandleHex(thesign); + } + while(true) + { + if((theByte >= '0') && (theByte <='7')) + { + value = (value * 8) + (theByte - '0'); + } + else + { + PutBackChar(theByte); + if (thesign) + { + value = -value; + } + return CIntToken::Create(value); + } + if (!NextChar(theByte)) + { + if (thesign) + { + value = -value; + } + return CIntToken::Create(value); + } + } +} + +CToken* CTokenizer::HandleHex(bool thesign) +{ + int value = 0; + + while (true) + { + byte theByte; + if (!NextChar(theByte)) + { + if (thesign) + { + value = -value; + } + return CIntToken::Create(value); + } + switch (theByte) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + theByte = theByte - '0'; + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + theByte = theByte - 'A' + 10; + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + theByte = theByte - 'a' + 10; + break; + default: + PutBackChar(theByte); + if (thesign) + { + value = -value; + } + return CIntToken::Create(value); + } + value = (value * 16) + theByte; + } +} + +CToken* CTokenizer::HandleDecimal(bool thesign) +{ + byte theByte; + if (!NextChar(theByte)) + { + if (thesign) + { + PutBackChar('.'); + return HandleSymbol('-'); + } + HandleSymbol('.'); + } + PutBackChar(theByte); + if ((theByte <= '9') && (theByte >= '0')) + { + return HandleFloat(thesign); + } + if (thesign) + { + PutBackChar('.'); + theByte = '-'; + } + else + { + theByte = '.'; + } + return HandleSymbol(theByte); +} + +CToken* CTokenizer::HandleFloat(bool thesign, long value) +{ + float lower = 1.0; + float newValue = (float)value; + byte theByte; + while(NextChar(theByte)) + { + if ((theByte >= '0') && (theByte <= '9')) + { + lower = lower / 10; + newValue = newValue + ((theByte - '0') * lower); + continue; + } + PutBackChar(theByte); + break; + } + if (thesign) + { + newValue = -newValue; + } + return CFloatToken::Create(newValue); +} + +CToken* CTokenizer::HandleQuote() +{ + byte theByte; + if (!NextChar(theByte)) + { + Error(TKERR_EXPECTED_CHAR); + return NULL; + } + if (theByte == '\\') + { + theByte = Escapement(); + } + byte dummy; + if (!NextChar(dummy)) + { + Error(TKERR_EXPECTED_CHAR); + return NULL; + } + if (dummy != '\'') + { + PutBackChar(dummy); + PutBackChar(theByte); + Error(TKERR_EXPECTED_CHAR); + return NULL; + } + return CCharToken::Create(theByte); +} + +void CTokenizer::SetFlags(UINT flags) +{ + m_flags = flags; +} + +UINT CTokenizer::GetFlags() +{ + return m_flags; +} + +CToken* CTokenizer::HandleSymbol(byte theByte) +{ + char symbolString[128]; + int curStrLen = 0; + symbolString[0] = '\0'; + bool consumed = false; + + CSymbolLookup* curLookup; + if ((m_flags & TKF_RAWSYMBOLSONLY) == 0) + { + curLookup = m_symbolLookup; + } + else + { + curLookup = NULL; + } + CSymbolLookup* lastLookup = NULL; + while(curLookup != NULL) + { + if (curLookup->GetByte() == theByte) + { + symbolString[curStrLen++] = theByte; + symbolString[curStrLen] = '\0'; + lastLookup = curLookup; + consumed = true; + if (curLookup->GetChild() == NULL) + { + break; + } + if (!NextChar(theByte)) + { + PutBackToken(CToken::Create()); + break; + } + consumed = false; + curLookup = curLookup->GetChild(); + continue; + } + curLookup = curLookup->GetNext(); + } + if ((!consumed) && (lastLookup != NULL)) + { + PutBackChar(theByte); + } + while ((lastLookup != NULL) && (lastLookup->GetValue() == -1)) + { + curStrLen--; + symbolString[curStrLen] = '\0'; + // symbolString = symbolString.Left(symbolString.GetLength() - 1); + if (lastLookup->GetParent() == NULL) + { + if ((m_flags & TKF_WANTUNDEFINED) == 0) + { + Error(TKERR_UNRECOGNIZEDSYMBOL); + } + } + else + { + PutBackChar(lastLookup->GetByte()); + } + lastLookup = lastLookup->GetParent(); + } + if (lastLookup == NULL) + { + if ((m_flags & TKF_WANTUNDEFINED) == 0) + { + return NULL; + } + curStrLen = 0; + symbolString[curStrLen++] = char(theByte); + symbolString[curStrLen] = '\0'; + if ((m_flags & TKF_WIDEUNDEFINEDSYMBOLS) != 0) + { + while (true) + { + if (!NextChar(theByte)) + { + PutBackToken(CToken::Create()); + break; + } + if (theByte == ' ') + { + break; + } + if (((theByte >= 'a') && (theByte <= 'z')) || ((theByte >= 'A') && (theByte <= 'Z')) || + ((theByte >= '0') && (theByte <= '9'))) + { + PutBackChar(theByte); + break; + } + if (theByte < ' ') + { + if ((theByte == '\n') && ((TKF_USES_EOL & m_flags) != 0)) + { + PutBackToken(CUserToken::Create(TK_EOL, "-EOLN-")); + break; + } + continue; + } + symbolString[curStrLen++] = theByte; + symbolString[curStrLen] = '\0'; + } + } + return CUndefinedToken::Create(symbolString); + } + return CUserToken::Create(lastLookup->GetValue(), symbolString); +} + +CToken* CTokenizer::HandleDirective() +{ + int tokenValue = 0; + CToken* theToken = FetchToken(); + if (theToken->GetType() == TK_EOF) + { + return theToken; + } + if (theToken->GetType() != TK_IDENTIFIER) + { + Error(TKERR_INVALID_DIRECTIVE); + theToken->Delete(); + SkipToLineEnd(); + return NULL; + } + + CDirectiveSymbol* curSymbol; + CTokenizerState* state; + int theDirective = DirectiveFromName(theToken->GetStringValue()); + theToken->Delete(); + byte theByte; + switch(theDirective) + { + case DIR_INCLUDE: + if ((m_state != NULL) && (m_state->Skipping())) + { + break; + } + theToken = GetToken(); + if (theToken->GetType() != TK_STRING) + { + Error(TKERR_INCLUDE_FILE_NOTFOUND); + theToken->Delete(); + SkipToLineEnd(); + break; + } + AddParseFile(theToken->GetStringValue()); + theToken->Delete(); + break; + case DIR_IFDEF: + if ((m_state != NULL) && (m_state->Skipping())) + { + state = CTokenizerHolderState::Create(); + state->SetNext(m_state); + m_state = state; + break; + } + theToken = GetToken(); + if (theToken->GetType() != TK_IDENTIFIER) + { + Error(TKERR_EXPECTED_IDENTIFIER); + theToken->Delete(); + SkipToLineEnd(); + break; + } + state = CTokenizerState::Create(m_defines.FindSymbol(theToken->GetStringValue()) == NULL); + theToken->Delete(); + state->SetNext(m_state); + m_state = state; + break; + case DIR_IFNDEF: + if ((m_state != NULL) && (m_state->Skipping())) + { + state = CTokenizerHolderState::Create(); + state->SetNext(m_state); + m_state = state; + break; + } + theToken = GetToken(); + if (theToken->GetType() != TK_IDENTIFIER) + { + Error(TKERR_EXPECTED_IDENTIFIER); + theToken->Delete(); + SkipToLineEnd(); + break; + } + state = CTokenizerState::Create(m_defines.FindSymbol(theToken->GetStringValue()) != NULL); + theToken->Delete(); + state->SetNext(m_state); + m_state = state; + break; + case DIR_ENDIF: + if (m_state == NULL) + { + Error(TKERR_UNMATCHED_DIRECTIVE); + break; + } + state = m_state; + m_state = state->GetNext(); + state->Delete(); + break; + case DIR_ELSE: + if (m_state == NULL) + { + Error(TKERR_UNMATCHED_DIRECTIVE); + break; + } + if (!m_state->ProcessElse()) + { + Error(TKERR_UNMATCHED_DIRECTIVE); + break; + } + break; + case DIR_DEFINE: + if ((m_state != NULL) && (m_state->Skipping())) + { + break; + } + theToken = GetToken(); + if (theToken->GetType() != TK_IDENTIFIER) + { + Error(TKERR_EXPECTED_IDENTIFIER); + theToken->Delete(); + SkipToLineEnd(); + break; + } + // blind add - should check first for value changes + { + curSymbol = CDirectiveSymbol::Create(theToken->GetStringValue()); + char temp[128]; + int tempsize = 0; + while(NextChar(theByte)) + { + if (theByte == '\n') + { + break; + } + temp[tempsize++] = char(theByte); + } + temp[tempsize] = '\0'; + curSymbol->SetValue(temp); + if (!m_defines.AddSymbol(curSymbol)) + { + curSymbol->Delete(); + } + } + break; + case DIR_UNDEFINE: + if ((m_state != NULL) && (m_state->Skipping())) + { + break; + } + theToken = GetToken(); + if (theToken->GetType() != TK_IDENTIFIER) + { + Error(TKERR_EXPECTED_IDENTIFIER); + theToken->Delete(); + SkipToLineEnd(); + break; + } + m_defines.RemoveSymbol(theToken->GetStringValue()); + break; + default: + Error(TKERR_INVALID_DIRECTIVE); + SkipToLineEnd(); + break; + } + return NULL; +} + +COLORREF CTokenizer::ParseRGB() +{ + CToken* theToken = GetToken(); + if (theToken->GetType() != TK_INT) + { + Error(TKERR_EXPECTED_INTEGER); + theToken->Delete(); + return RGB(0, 0, 0); + } + int red = theToken->GetIntValue(); + theToken->Delete(); + theToken = GetToken(); + if (theToken->GetType() != TK_INT) + { + Error(TKERR_EXPECTED_INTEGER); + theToken->Delete(); + return RGB(0, 0, 0); + } + int green = theToken->GetIntValue(); + theToken->Delete(); + theToken = GetToken(); + if (theToken->GetType() != TK_INT) + { + Error(TKERR_EXPECTED_INTEGER); + theToken->Delete(); + return RGB(0, 0, 0); + } + int blue = theToken->GetIntValue(); + theToken->Delete(); + return RGB(red, green, blue); +} + +// +// CSymbolLookup +// + +CSymbolLookup::CSymbolLookup() +{ +} + +CSymbolLookup::~CSymbolLookup() +{ +} + +CSymbolLookup* CSymbolLookup::Create(byte theByte) +{ + CSymbolLookup* curLookup = new CSymbolLookup(); + curLookup->Init(theByte); + return curLookup; +} + +void CSymbolLookup::Delete() +{ + if (m_sibling != NULL) + { + m_sibling->Delete(); + m_sibling = NULL; + } + if (m_child != NULL) + { + m_child->Delete(); + m_child = NULL; + } + delete this; +} + +void CSymbolLookup::Init(byte theByte) +{ + m_parent = NULL; + m_child = NULL; + m_sibling = NULL; + m_value = -1; + m_byte = theByte; +} + +CSymbolLookup* CSymbolLookup::GetNext() +{ + return m_sibling; +} + +void CSymbolLookup::SetNext(CSymbolLookup* next) +{ + m_sibling = next; +} + +void CSymbolLookup::SetParent(CSymbolLookup* parent) +{ + m_parent = parent; +} + +void CSymbolLookup::SetValue(int value) +{ + m_value = value; +} + +int CSymbolLookup::GetValue() +{ + return m_value; +} + +byte CSymbolLookup::GetByte() +{ + return m_byte; +} + +CSymbolLookup** CSymbolLookup::GetChildAddress() +{ + return &m_child; +} + +CSymbolLookup* CSymbolLookup::GetChild() +{ + return m_child; +} + +CSymbolLookup* CSymbolLookup::GetParent() +{ + return m_parent; +} diff --git a/Projects/Android/jni/OpenJK/codemp/icarus/blockstream.h b/Projects/Android/jni/OpenJK/codemp_delete/icarus/blockstream.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/icarus/blockstream.h rename to Projects/Android/jni/OpenJK/codemp_delete/icarus/blockstream.h diff --git a/Projects/Android/jni/OpenJK/codemp_delete/icarus/icarus.h b/Projects/Android/jni/OpenJK/codemp_delete/icarus/icarus.h new file mode 100644 index 0000000..e8803ad --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/icarus/icarus.h @@ -0,0 +1,38 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#pragma once + +// ICARUS Public Header File +extern void *ICARUS_Malloc(int iSize); +extern void ICARUS_Free(void *pMem); + +#include "game/g_public.h" +#define STL_ITERATE( a, b ) for ( a = b.begin(); a != b.end(); ++a ) +#define STL_INSERT( a, b ) a.insert( a.end(), b ); + +#include "tokenizer.h" +#include "blockstream.h" +#include "interpreter.h" +#include "sequencer.h" +#include "taskmanager.h" +#include "instance.h" diff --git a/Projects/Android/jni/OpenJK/codemp_delete/icarus/instance.h b/Projects/Android/jni/OpenJK/codemp_delete/icarus/instance.h new file mode 100644 index 0000000..954766b --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/icarus/instance.h @@ -0,0 +1,100 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#pragma once + +// ICARUS Intance header + +#include "blockstream.h" +#include "interface.h" +#include "taskmanager.h" +#include "sequence.h" +#include "sequencer.h" + +class ICARUS_Instance +{ +public: + + typedef std::list< CSequence * > sequence_l; + typedef std::list< CSequencer * > sequencer_l; + typedef std::map < std::string, unsigned char > signal_m; + + ICARUS_Instance( void ); + virtual ~ICARUS_Instance( void ); + + static ICARUS_Instance *Create( interface_export_t * ); + int Delete( void ); + + CSequencer *GetSequencer( int ); + void DeleteSequencer( CSequencer * ); + + CSequence *GetSequence( void ); + CSequence *GetSequence( int id ); + void DeleteSequence( CSequence * ); + + interface_export_t *GetInterface( void ) const { return m_interface; } + + //These are overriddable for "worst-case" save / loads + virtual int Save( void /*FIXME*/ ); + virtual int Load( void /*FIXME*/ ); + + void Signal( const char *identifier ); + bool CheckSignal( const char *identifier ); + void ClearSignal( const char *identifier ); + +protected: + + virtual int SaveSignals( void ); + virtual int SaveSequences( void ); + virtual int SaveSequenceIDTable( void ); + virtual int SaveSequencers( void ); + + int AllocateSequences( int numSequences, int *idTable ); + + virtual int LoadSignals( void ); + virtual int LoadSequencers( void ); + virtual int LoadSequences( void ); + virtual int LoadSequence( void ); + + int Free( void ); + + interface_export_t *m_interface; + int m_GUID; + + sequence_l m_sequences; + sequencer_l m_sequencers; + + signal_m m_signals; + +#ifdef _DEBUG + + int m_DEBUG_NumSequencerAlloc; + int m_DEBUG_NumSequencerFreed; + int m_DEBUG_NumSequencerResidual; + + int m_DEBUG_NumSequenceAlloc; + int m_DEBUG_NumSequenceFreed; + int m_DEBUG_NumSequenceResidual; + +#endif + +}; diff --git a/Projects/Android/jni/OpenJK/codemp_delete/icarus/interface.h b/Projects/Android/jni/OpenJK/codemp_delete/icarus/interface.h new file mode 100644 index 0000000..4bfbba5 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/icarus/interface.h @@ -0,0 +1,85 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#pragma once + +// ICARUS Interface header file + +typedef float vec3_t[3]; + +class CSequencer; +class CTaskManager; + +typedef struct interface_export_s +{ + //General + int (*I_LoadFile)( const char *name, void **buf ); + void (*I_CenterPrint)( const char *format, ... ); + void (*I_DPrintf)( int, const char *, ... ); + sharedEntity_t *(*I_GetEntityByName)( const char *name ); //Polls the engine for the sequencer of the entity matching the name passed + unsigned int (*I_GetTime)( void ); //Gets the current time + unsigned int (*I_GetTimeScale)(void ); + int (*I_PlaySound)( int taskID, int entID, const char *name, const char *channel ); + void (*I_Lerp2Pos)( int taskID, int entID, vec3_t origin, vec3_t angles, float duration ); + void (*I_Lerp2Origin)( int taskID, int entID, vec3_t origin, float duration ); + void (*I_Lerp2Angles)( int taskID, int entID, vec3_t angles, float duration ); + int (*I_GetTag)( int entID, const char *name, int lookup, vec3_t info ); + void (*I_Lerp2Start)( int taskID, int entID, float duration ); + void (*I_Lerp2End)( int taskID, int entID, float duration ); + void (*I_Set)( int taskID, int entID, const char *type_name, const char *data ); + void (*I_Use)( int entID, const char *name ); + void (*I_Kill)( int entID, const char *name ); + void (*I_Remove)( int entID, const char *name ); + float (*I_Random)( float min, float max ); + void (*I_Play)( int taskID, int entID, const char *type, const char *name ); + + //Camera functions + void (*I_CameraPan)( vec3_t angles, vec3_t dir, float duration ); + void (*I_CameraMove)( vec3_t origin, float duration ); + void (*I_CameraZoom)( float fov, float duration ); + void (*I_CameraRoll)( float angle, float duration ); + void (*I_CameraFollow)( const char *name, float speed, float initLerp ); + void (*I_CameraTrack)( const char *name, float speed, float initLerp ); + void (*I_CameraDistance)( float dist, float initLerp ); + void (*I_CameraFade)( float sr, float sg, float sb, float sa, float dr, float dg, float db, float da, float duration ); + void (*I_CameraPath)( const char *name ); + void (*I_CameraEnable)( void ); + void (*I_CameraDisable)( void ); + void (*I_CameraShake)( float intensity, int duration ); + + int (*I_GetFloat)( int entID, int type, const char *name, float *value ); + int (*I_GetVector)( int entID, int type, const char *name, vec3_t value ); + int (*I_GetString)( int entID, int type, const char *name, char **value ); + + int (*I_Evaluate)( int p1Type, const char *p1, int p2Type, const char *p2, int operatorType ); + + void (*I_DeclareVariable)( int type, const char *name ); + void (*I_FreeVariable)( const char *name ); + + //Save / Load functions + + int (*I_WriteSaveData)( unsigned long chid, const void *data, int length ); + // Below changed by BTO (VV). Visual C++ 7.1 compiler no longer allows default args on function pointers. Ack. + int (*I_ReadSaveData)( unsigned long chid, void *address, int length /* , void **addressptr = NULL */ ); + int (*I_LinkEntity)( int entID, CSequencer *sequencer, CTaskManager *taskManager ); + +} interface_export_t; diff --git a/Projects/Android/jni/OpenJK/codemp_delete/icarus/interpreter.h b/Projects/Android/jni/OpenJK/codemp_delete/icarus/interpreter.h new file mode 100644 index 0000000..ca87f7b --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/icarus/interpreter.h @@ -0,0 +1,245 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#pragma once + +// Interpreter.h + +#define ICARUS_VERSION 1.33 + +#define MAX_STRING_SIZE 256 +#define MAX_VAR_NAME 64 + +typedef float vector_t[3]; + +//If you modify this, you MUST modify in g_ICARUScb.c as well. +//Token defines +enum +{ + TK_BLOCK_START = TK_USERDEF, + TK_BLOCK_END, + TK_VECTOR_START, + TK_VECTOR_END, + TK_OPEN_PARENTHESIS, + TK_CLOSED_PARENTHESIS, + TK_VECTOR, + TK_GREATER_THAN, + TK_LESS_THAN, + TK_EQUALS, + TK_NOT, + + NUM_USER_TOKENS +}; + +//ID defines +enum +{ + ID_AFFECT = NUM_USER_TOKENS, + ID_SOUND, + ID_MOVE, + ID_ROTATE, + ID_WAIT, + ID_BLOCK_START, + ID_BLOCK_END, + ID_SET, + ID_LOOP, + ID_LOOPEND, + ID_PRINT, + ID_USE, + ID_FLUSH, + ID_RUN, + ID_KILL, + ID_REMOVE, + ID_CAMERA, + ID_GET, + ID_RANDOM, + ID_IF, + ID_ELSE, + ID_REM, + ID_TASK, + ID_DO, + ID_DECLARE, + ID_FREE, + ID_DOWAIT, + ID_SIGNAL, + ID_WAITSIGNAL, + ID_PLAY, + + ID_TAG, + ID_EOF, + NUM_IDS +}; + +//Type defines +enum +{ + //Wait types + TYPE_WAIT_COMPLETE = NUM_IDS, + TYPE_WAIT_TRIGGERED, + + //Set types + TYPE_ANGLES, + TYPE_ORIGIN, + + //Affect types + TYPE_INSERT, + TYPE_FLUSH, + + //Camera types + TYPE_PAN, + TYPE_ZOOM, + TYPE_MOVE, + TYPE_FADE, + TYPE_PATH, + TYPE_ENABLE, + TYPE_DISABLE, + TYPE_SHAKE, + TYPE_ROLL, + TYPE_TRACK, + TYPE_DISTANCE, + TYPE_FOLLOW, + + //Variable type + TYPE_VARIABLE, + + TYPE_EOF, + NUM_TYPES +}; + +enum +{ + MSG_COMPLETED, + MSG_EOF, + NUM_MESSAGES, +}; + +#ifdef __cplusplus + +typedef struct variable_s +{ + char name[MAX_VAR_NAME]; + int type; + void *data; +} variable_t; + +typedef std::map< std::string, variable_t * > variable_m; +typedef std::vector < variable_t * > variable_v; + +//CInterpreter + +class CInterpreter +{ +public: + + CInterpreter(); + ~CInterpreter(); + + int Interpret( CTokenizer *, CBlockStream *, char *filename=NULL ); //Main interpretation function + + int Match( int ); //Looks ahead to the next token to try and match it to the passed token, consumes token on success + int LookAhead( int ); //Looks ahead without consuming on success + + int FindSymbol( const char *, keywordArray_t * ); //Searches the symbol table for the given name. Returns the ID if found + + int GetAffect( void ); //Handles the affect() function + int GetWait( void ); //Handles the wait() function + int GetSet( void ); //Handles the set() function + int GetBroadcast( void ); //Handles the broadcast() function + int GetLoop( void ); //Handles the loop() function + int GetPrint( void ); //Handles the print() function + int GetUse( void ); //Handles the use() function + int GetFlush( void ); //Handles the flush() function + int GetRun( void ); //Handles the run() function + int GetKill( void ); //Handles the kill() function + int GetRemove( void ); //Handles the remove() function + int GetCamera( void ); //Handles the camera() function + int GetIf( void ); //Handles the if() conditional statement + int GetSound( void ); //Handles the sound() function + int GetMove( void ); //Handles the move() function + int GetRotate( void ); //Handles the rotate() function + int GetRem( void ); //Handles the rem() function + int GetTask( void ); + int GetDo( void ); + int GetElse( void ); + int GetDeclare( void ); + int GetFree( void ); + int GetDoWait( void ); + int GetSignal( void ); + int GetWaitSignal( void ); + int GetPlay( void ); + + int GetRandom( CBlock *block ); + int GetGet( CBlock *block ); //Heh + int GetTag( CBlock *block ); //Handles the tag() identifier + int GetVector( CBlock *block ); + + int GetNextType( void ); + + int GetType( char *get ); + + int GetAny( CBlock *block ); + int GetEvaluator( CBlock *block ); + int GetString( CBlock *); //Attempts to match and retrieve the value of a string token + int GetIdentifier( CBlock *get ); //Attempts to match and retrieve the value of an identifier token + int GetInteger( CBlock * ); //Attempts to match and retrieve the value of a int token + int GetFloat( CBlock * ); //Attempts to match and retrieve the value of a float token + int GetVariable( int type ); + + int GetID ( char * ); //Attempts to match and interpret an identifier + + keywordArray_t *GetSymbols( void ) { return (keywordArray_t *) &m_symbolKeywords; } //Returns the interpreter's symbol table + keywordArray_t *GetIDs( void ) { return (keywordArray_t *) &m_IDKeywords; } //Returns the interpreter's ID table + keywordArray_t *GetTypes( void ) { return (keywordArray_t *) &m_typeKeywords; } //Returns the interpreter's type table + +protected: + + void InitVars( void ); + void FreeVars( void ); + + variable_t *AddVar( const char *name, int type ); + variable_t *FindVar( const char *name ); + + const char *GetTokenName( int ); //Returns the name of a token + int Error( char *, ... ); //Prints an error message + + int MatchTag( void ); //Attempts to match to a tag identifier + int MatchGet( void ); //Attempts to match to a get identifier + int MatchRandom( void ); //Attempts to match to a random identifier + + CTokenizer *m_tokenizer; //Pointer to the tokenizer + CBlockStream *m_blockStream; //Pointer to the block stream + + variable_v m_vars; + variable_m m_varMap; + + std::string m_sCurrentLine; // used in IBIze error reporting for more clarity + std::string m_sCurrentFile; // full-pathed name of .TXT file (needed because of above, which affects parsestreams) + int m_iCurrentLine; // also needed now because of 'm_sCurrentLine' + int m_iBadCBlockNumber; // used for final app return code (NZ = err) + + static keywordArray_t m_symbolKeywords[]; //Symbols + static keywordArray_t m_IDKeywords[]; //Identifiers + static keywordArray_t m_typeKeywords[]; //Types + static keywordArray_t m_conditionalKeywords[]; //Conditional +}; + +#endif //__cplusplus diff --git a/Projects/Android/jni/OpenJK/codemp/icarus/sequence.h b/Projects/Android/jni/OpenJK/codemp_delete/icarus/sequence.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/icarus/sequence.h rename to Projects/Android/jni/OpenJK/codemp_delete/icarus/sequence.h diff --git a/Projects/Android/jni/OpenJK/codemp/icarus/sequencer.h b/Projects/Android/jni/OpenJK/codemp_delete/icarus/sequencer.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/icarus/sequencer.h rename to Projects/Android/jni/OpenJK/codemp_delete/icarus/sequencer.h diff --git a/Projects/Android/jni/OpenJK/codemp/icarus/taskmanager.h b/Projects/Android/jni/OpenJK/codemp_delete/icarus/taskmanager.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/icarus/taskmanager.h rename to Projects/Android/jni/OpenJK/codemp_delete/icarus/taskmanager.h diff --git a/Projects/Android/jni/OpenJK/codemp_delete/icarus/tokenizer.h b/Projects/Android/jni/OpenJK/codemp_delete/icarus/tokenizer.h new file mode 100644 index 0000000..7a71acc --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/icarus/tokenizer.h @@ -0,0 +1,575 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#pragma once + +// Tokenizer.h +// + +#include +#include +#include + +#include "qcommon/q_shared.h" + +#define MAX_STRING_LENGTH 256 +#define MAX_IDENTIFIER_LENGTH 128 + +#define TKF_IGNOREDIRECTIVES 0x00000001 // skip over lines starting with # +#define TKF_USES_EOL 0x00000002 // generate end of line tokens +#define TKF_NODIRECTIVES 0x00000004 // don't treat # in any special way +#define TKF_WANTUNDEFINED 0x00000008 // if token not found in symbols create undefined token +#define TKF_WIDEUNDEFINEDSYMBOLS 0x00000010 // when undefined token encountered, accumulate until space +#define TKF_RAWSYMBOLSONLY 0x00000020 +#define TKF_NUMERICIDENTIFIERSTART 0x00000040 +#define TKF_IGNOREKEYWORDS 0x00000080 +#define TKF_NOCASEKEYWORDS 0x00000100 +#define TKF_NOUNDERSCOREINIDENTIFIER 0x00000200 +#define TKF_NODASHINIDENTIFIER 0x00000400 +#define TKF_COMMENTTOKENS 0x00000800 + +enum +{ + TKERR_NONE, + TKERR_UNKNOWN, + TKERR_BUFFERCREATE, + TKERR_UNRECOGNIZEDSYMBOL, + TKERR_DUPLICATESYMBOL, + TKERR_STRINGLENGTHEXCEEDED, + TKERR_IDENTIFIERLENGTHEXCEEDED, + TKERR_EXPECTED_INTEGER, + TKERR_EXPECTED_IDENTIFIER, + TKERR_EXPECTED_STRING, + TKERR_EXPECTED_CHAR, + TKERR_EXPECTED_FLOAT, + TKERR_UNEXPECTED_TOKEN, + TKERR_INVALID_DIRECTIVE, + TKERR_INCLUDE_FILE_NOTFOUND, + TKERR_UNMATCHED_DIRECTIVE, + TKERR_USERERROR, +}; + +enum +{ + TK_EOF = -1, + TK_UNDEFINED, + TK_COMMENT, + TK_EOL, + TK_CHAR, + TK_STRING, + TK_INT, + TK_INTEGER = TK_INT, + TK_FLOAT, + TK_IDENTIFIER, + TK_USERDEF, +}; + +typedef struct keywordArray_s { + char* m_keyword; + int m_tokenvalue; +} keywordArray_t; + +class lessstr +{ +public: + bool operator()(const char *str1, const char *str2) const {return (strcmp(str1, str2) < 0);}; +}; + +class CParseStream +{ +public: + CParseStream(); + ~CParseStream(); + static CParseStream* Create(); + virtual void Delete(); + virtual bool NextChar(byte& theByte); + virtual int GetCurLine(); + virtual void GetCurFilename(char** theBuff); + virtual long GetRemainingSize(); + + CParseStream* GetNext(); + void SetNext(CParseStream* next); + + virtual bool IsThisDefinition(void* theDefinition); + +protected: + bool InitBaseStream(); + + CParseStream* m_next; +}; + +class CToken +{ +public: + CToken(); + ~CToken(); + static CToken* Create(); + virtual void Delete(); + + virtual int GetType(); + CToken* GetNext(); + void SetNext(CToken* theToken); + virtual int GetIntValue(); + virtual const char *GetStringValue(); + virtual float GetFloatValue(); + +protected: + virtual void InitBaseToken(); + + char* m_string; + CToken* m_next; +}; + +class CCharToken : public CToken +{ +public: + CCharToken(); + ~CCharToken(); + static CCharToken* Create(byte theByte); + virtual void Delete(); + + virtual int GetType(); + +protected: + void Init(byte theByte); +}; + +class CStringToken : public CToken +{ +public: + CStringToken(); + ~CStringToken(); + static CStringToken* Create(const char *theString); + virtual void Delete(); + + virtual int GetType(); + +protected: + void Init(const char *theString); +}; + +class CIntToken : public CToken +{ +public: + CIntToken(); + ~CIntToken(); + static CIntToken* Create(long value); + virtual void Delete(); + + virtual int GetType(); + virtual float GetFloatValue(); + virtual int GetIntValue(); + virtual const char *GetStringValue(); + +protected: + void Init(long value); + + long m_value; +}; + +class CFloatToken : public CToken +{ +public: + CFloatToken(); + ~CFloatToken(); + static CFloatToken* Create(float value); + virtual void Delete(); + + virtual int GetType(); + virtual float GetFloatValue(); + virtual const char *GetStringValue(); + +protected: + void Init(float value); + + float m_value; +}; + +class CIdentifierToken : public CToken +{ +public: + CIdentifierToken(); + ~CIdentifierToken(); + static CIdentifierToken* Create(const char *name); + virtual void Delete(); + + virtual int GetType(); + +protected: + void Init(const char *name); +}; + +class CCommentToken : public CToken +{ +public: + CCommentToken(); + ~CCommentToken(); + static CCommentToken* Create(const char *name); + virtual void Delete(); + + virtual int GetType(); + +protected: + void Init(const char *name); +}; + +class CUserToken : public CToken +{ +public: + CUserToken(); + ~CUserToken(); + static CUserToken* Create(int value, const char *string); + virtual void Delete(); + + virtual int GetType(); + +protected: + void Init(int value, const char *string); + + int m_value; +}; + +class CUndefinedToken : public CToken +{ +public: + CUndefinedToken(); + ~CUndefinedToken(); + static CUndefinedToken* Create(const char *string); + virtual void Delete(); + + virtual int GetType(); + +protected: + void Init(const char *string); +}; + +class CSymbol +{ +public: + CSymbol(); + virtual ~CSymbol(); + static CSymbol* Create(const char *symbolName); + virtual void Delete(); + + const char *GetName(); + +protected: + void InitBaseSymbol(const char *symbolName); + + char* m_symbolName; +}; + +typedef std::map symbolmap_t; + +class CDirectiveSymbol : public CSymbol +{ +public: + CDirectiveSymbol(); + ~CDirectiveSymbol(); + static CDirectiveSymbol* Create(const char *symbolName); + virtual void Delete(); + + void SetValue(const char *value); + const char *GetValue(); + +protected: + void Init(const char *symbolName); + + char* m_value; +}; + +class CIntSymbol : public CSymbol +{ +public: + CIntSymbol(); + static CIntSymbol* Create(const char *symbolName, int value); + virtual void Delete(); + + int GetValue(); + +protected: + void Init(const char *symbolName, int value); + + int m_value; +}; + +class CSymbolTable +{ +public: + CSymbolTable(); + ~CSymbolTable(); + static CSymbolTable* Create(); + void Delete(); + + bool AddSymbol(CSymbol* theSymbol); + CSymbol* FindSymbol(const char *symbolName); + CSymbol* ExtractSymbol(const char *symbolName); + void RemoveSymbol(const char *symbolName); + void DiscardSymbols(); + +protected: + void Init(); + symbolmap_t m_symbols; +}; + +class CSymbolLookup +{ +public: + CSymbolLookup(); + ~CSymbolLookup(); + static CSymbolLookup* Create(byte theByte); + virtual void Delete(); + CSymbolLookup* GetNext(); + void SetNext(CSymbolLookup* next); + void SetParent(CSymbolLookup* parent); + CSymbolLookup* GetParent(); + void SetValue(int value); + int GetValue(); + byte GetByte(); + CSymbolLookup** GetChildAddress(); + CSymbolLookup* GetChild(); + +protected: + void Init(byte theByte); + + CSymbolLookup* m_child; + CSymbolLookup* m_sibling; + CSymbolLookup* m_parent; + int m_value; + byte m_byte; +}; + +class CTokenizerState +{ +public: + CTokenizerState(); + ~CTokenizerState(); + static CTokenizerState* Create(bool skip); + virtual void Delete(); + CTokenizerState* GetNext(); + void SetNext(CTokenizerState* next); + virtual bool ProcessElse(); + bool Skipping(); + +protected: + void Init(bool skip); + + bool m_skip; + bool m_elseHit; + CTokenizerState* m_next; +}; + +class CTokenizerHolderState : public CTokenizerState +{ +public: + CTokenizerHolderState(); + ~CTokenizerHolderState(); + static CTokenizerHolderState* Create(); + virtual void Delete(); + virtual bool ProcessElse(); + +protected: + void Init(); +}; + +typedef void (*LPTokenizerErrorProc)(const char *errString); + +#ifdef USES_MODULES +class CTokenizer : public CModule +#else +class CTokenizer +#endif +{ +public: + CTokenizer(); + ~CTokenizer(); + static CTokenizer* Create(unsigned dwFlags = 0); + virtual void Delete(); + virtual void Error(int theError); + virtual void Error(int theError, const char *errString); + virtual void Error(const char *errString, int theError = TKERR_UNKNOWN); + + CToken* GetToken(unsigned onFlags = 0, unsigned offFlags = 0); + CToken* GetToken(keywordArray_t* keywords, unsigned onFlags, unsigned offFlags); + void PutBackToken(CToken* theToken, bool commented = false, const char *addedChars = NULL, bool bIgnoreThisTokenType = false); + bool RequireToken(int tokenType); + void ScanUntilToken(int tokenType); + void SkipToLineEnd(); + CToken* GetToEndOfLine(int tokenType = TK_IDENTIFIER); + + keywordArray_t* SetKeywords(keywordArray_t* theKeywords); + void SetSymbols(keywordArray_t* theSymbols); + void SetAdditionalErrors(keywordArray_t* theErrors); + void SetErrorProc(LPTokenizerErrorProc errorProc); + void AddParseStream(byte* data, long datasize); + bool AddParseFile(const char *filename); + unsigned int ParseRGB(); + long GetRemainingSize(); + + unsigned GetFlags(); + void SetFlags(unsigned flags); + + void GetCurFilename(char** filename); + int GetCurLine(); + + const char *LookupToken(int tokenID, keywordArray_t* theTable = NULL); + +protected: + void SetError(int theError, const char *errString); + virtual void Init(unsigned dwFlags = 0); + CToken* FetchToken(); + bool AddDefineSymbol(CDirectiveSymbol* definesymbol); + bool NextChar(byte& theByte); + byte Escapement(); + void InsertSymbol(const char *theSymbol, int theValue); + void PutBackChar(byte theByte, int curLine = 0, const char *filename = NULL); + CToken* TokenFromName(const char *name); + CToken* HandleDirective(); + CToken* HandleSlash(); + CToken* HandleString(); + CToken* HandleQuote(); + CToken* HandleIdentifier(byte theByte); + CToken* HandleNumeric(byte theByte); + CToken* HandleFloat(bool thesign = false, long value = 0); + CToken* HandleDecimal(bool thesign = false); + CToken* HandleSymbol(byte theByte); + CToken* HandleHex(bool thesize); + CToken* HandleOctal(bool thesize); + int DirectiveFromName(const char *name); + + CParseStream* m_curParseStream; + keywordArray_t* m_keywords; + keywordArray_t* m_symbols; + keywordArray_t* m_errors; + CSymbolLookup* m_symbolLookup; + CToken* m_nextToken; + CSymbolTable m_defines; + CTokenizerState* m_state; + unsigned m_flags; + LPTokenizerErrorProc m_errorProc; + + static keywordArray_t errorMessages[]; + static keywordArray_t directiveKeywords[]; +}; + +class CKeywordTable +{ +public: + CKeywordTable(CTokenizer* tokenizer, keywordArray_t* keywords); + ~CKeywordTable(); + +protected: + CTokenizer* m_tokenizer; + keywordArray_t* m_holdKeywords; +}; + +class CParsePutBack : public CParseStream +{ +public: + CParsePutBack(); + ~CParsePutBack(); + static CParsePutBack* Create(byte theByte, int curLine, const char *filename); + virtual void Delete(); + virtual bool NextChar(byte& theByte); + virtual int GetCurLine(); + virtual void GetCurFilename(char** theBuff); + virtual long GetRemainingSize(); + +protected: + void Init(byte theByte, int curLine, const char *filename); + + byte m_byte; + bool m_consumed; + int m_curLine; + char* m_curFile; +}; + +class CParseMemory : public CParseStream +{ +public: + CParseMemory(); + ~CParseMemory(); + static CParseMemory* Create(byte* data, long datasize); + virtual void Delete(); + virtual bool NextChar(byte& theByte); + virtual int GetCurLine(); + virtual void GetCurFilename(char** theBuff); + virtual long GetRemainingSize(); + +protected: + void Init(byte* data, long datasize); + + byte* m_data; + int m_curLine; + long m_curPos; + long m_datasize; + long m_offset; +}; + +class CParseBlock : public CParseMemory +{ +public: + CParseBlock(); + ~CParseBlock(); + static CParseBlock* Create(byte* data, long datasize); + virtual void Delete(); + +protected: + virtual void Init(byte* data, long datasize); +}; + +class CParseToken : public CParseStream +{ +public: + CParseToken(); + ~CParseToken(); + static CParseToken* Create(CToken* token); + virtual void Delete(); + virtual bool NextChar(byte& theByte); + virtual int GetCurLine(); + virtual void GetCurFilename(char** theBuff); + virtual long GetRemainingSize(); + +protected: + void Init(CToken* token); + + byte* m_data; + int m_curLine; + long m_curPos; + long m_datasize; + long m_offset; +}; + +class CParseDefine : public CParseMemory +{ +public: + CParseDefine(); + ~CParseDefine(); + static CParseDefine* Create(CDirectiveSymbol* definesymbol); + virtual void Delete(); + virtual bool IsThisDefinition(void* theDefinition); + +protected: + virtual void Init(CDirectiveSymbol* definesymbol); + + CDirectiveSymbol* m_defineSymbol; +}; diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/cdct.c b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/cdct.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/cdct.c rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/cdct.c diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/config.h b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/config.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/config.h rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/config.h diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/csbt.c b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/csbt.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/csbt.c rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/csbt.c diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/csbtb.c b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/csbtb.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/csbtb.c rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/csbtb.c diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/csbtl3.c b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/csbtl3.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/csbtl3.c rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/csbtl3.c diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/cup.c b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/cup.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/cup.c rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/cup.c diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/cupini.c b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/cupini.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/cupini.c rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/cupini.c diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/cupl1.c b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/cupl1.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/cupl1.c rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/cupl1.c diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/cupl3.c b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/cupl3.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/cupl3.c rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/cupl3.c diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/cwin.c b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/cwin.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/cwin.c rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/cwin.c diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/cwinb.c b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/cwinb.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/cwinb.c rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/cwinb.c diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/cwinm.c b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/cwinm.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/cwinm.c rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/cwinm.c diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/htable.h b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/htable.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/htable.h rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/htable.h diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/hwin.c b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/hwin.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/hwin.c rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/hwin.c diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/jdw.h b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/jdw.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/jdw.h rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/jdw.h diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/l3.h b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/l3.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/l3.h rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/l3.h diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/l3dq.c b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/l3dq.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/l3dq.c rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/l3dq.c diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/l3init.c b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/l3init.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/l3init.c rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/l3init.c diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/mdct.c b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/mdct.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/mdct.c rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/mdct.c diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/mhead.c b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/mhead.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/mhead.c rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/mhead.c diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/mhead.h b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/mhead.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/mhead.h rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/mhead.h diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/mp3struct.h b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/mp3struct.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/mp3struct.h rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/mp3struct.h diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/msis.c b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/msis.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/msis.c rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/msis.c diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/port.h b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/port.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/port.h rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/port.h diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/small_header.h b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/small_header.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/small_header.h rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/small_header.h diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/tableawd.h b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/tableawd.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/tableawd.h rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/tableawd.h diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/towave.c b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/towave.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/towave.c rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/towave.c diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/uph.c b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/uph.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/uph.c rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/uph.c diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/upsf.c b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/upsf.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/upsf.c rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/upsf.c diff --git a/Projects/Android/jni/OpenJK/codemp/mp3code/wavep.c b/Projects/Android/jni/OpenJK/codemp_delete/mp3code/wavep.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/mp3code/wavep.c rename to Projects/Android/jni/OpenJK/codemp_delete/mp3code/wavep.c diff --git a/Projects/Android/jni/OpenJK/codemp/null/null_client.cpp b/Projects/Android/jni/OpenJK/codemp_delete/null/null_client.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/null/null_client.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/null/null_client.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/null/null_input.cpp b/Projects/Android/jni/OpenJK/codemp_delete/null/null_input.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/null/null_input.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/null/null_input.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/null/null_renderer.cpp b/Projects/Android/jni/OpenJK/codemp_delete/null/null_renderer.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/null/null_renderer.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/null/null_renderer.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/null/null_snddma.cpp b/Projects/Android/jni/OpenJK/codemp_delete/null/null_snddma.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/null/null_snddma.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/null/null_snddma.cpp diff --git a/Projects/Android/jni/OpenJK/codemp_delete/qcommon/GenericParser2.cpp b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/GenericParser2.cpp new file mode 100644 index 0000000..37f7916 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/GenericParser2.cpp @@ -0,0 +1,1198 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#include "GenericParser2.h" + +#include +#include "qcommon/qcommon.h" + +#define MAX_TOKEN_SIZE 1024 +static char token[MAX_TOKEN_SIZE]; + +static char *GetToken(char **text, bool allowLineBreaks, bool readUntilEOL = false) +{ + char *pointer = *text; + int length = 0; + int c = 0; + bool foundLineBreak; + + token[0] = 0; + if (!pointer) + { + return token; + } + + while(1) + { + foundLineBreak = false; + while(1) + { + c = *pointer; + if (c > ' ') + { + break; + } + if (!c) + { + *text = 0; + return token; + } + if (c == '\n') + { + foundLineBreak = true; + } + pointer++; + } + if (foundLineBreak && !allowLineBreaks) + { + *text = pointer; + return token; + } + + c = *pointer; + + // skip single line comment + if (c == '/' && pointer[1] == '/') + { + pointer += 2; + while (*pointer && *pointer != '\n') + { + pointer++; + } + } + // skip multi line comments + else if (c == '/' && pointer[1] == '*') + { + pointer += 2; + while (*pointer && (*pointer != '*' || pointer[1] != '/')) + { + pointer++; + } + if (*pointer) + { + pointer += 2; + } + } + else + { // found the start of a token + break; + } + } + + if (c == '\"') + { // handle a string + pointer++; + while (1) + { + c = *pointer++; + if (c == '\"') + { +// token[length++] = c; + break; + } + else if (!c) + { + break; + } + else if (length < MAX_TOKEN_SIZE) + { + token[length++] = c; + } + } + } + else if (readUntilEOL) + { + // absorb all characters until EOL + while(c != '\n' && c != '\r') + { + if (c == '/' && ((*(pointer+1)) == '/' || (*(pointer+1)) == '*')) + { + break; + } + + if (length < MAX_TOKEN_SIZE) + { + token[length++] = c; + } + pointer++; + c = *pointer; + } + // remove trailing white space + while(length && token[length-1] < ' ') + { + length--; + } + } + else + { + while(c > ' ') + { + if (length < MAX_TOKEN_SIZE) + { + token[length++] = c; + } + pointer++; + c = *pointer; + } + } + + if (token[0] == '\"') + { // remove start quote + length--; + memmove(token, token+1, length); + + if (length && token[length-1] == '\"') + { // remove end quote + length--; + } + } + + if (length >= MAX_TOKEN_SIZE) + { + length = 0; + } + token[length] = 0; + *text = (char *)pointer; + + return token; +} + +CTextPool::CTextPool(int initSize) : + mNext(0), + mSize(initSize), + mUsed(0) +{ +// mPool = (char *)Z_Malloc(mSize, TAG_GP2); + mPool = (char *)Z_Malloc(mSize, TAG_TEXTPOOL, qtrue); +} + +CTextPool::~CTextPool(void) +{ + Z_Free(mPool); +} + +char *CTextPool::AllocText(char *text, bool addNULL, CTextPool **poolPtr) +{ + int length = strlen(text) + (addNULL ? 1 : 0); + + if (mUsed + length + 1> mSize) + { // extra 1 to put a null on the end + if (poolPtr) + { + (*poolPtr)->SetNext(new CTextPool(mSize)); + *poolPtr = (*poolPtr)->GetNext(); + + return (*poolPtr)->AllocText(text, addNULL); + } + + return 0; + } + + strcpy(mPool + mUsed, text); + mUsed += length; + mPool[mUsed] = 0; + + return mPool + mUsed - length; +} + +void CleanTextPool(CTextPool *pool) +{ + CTextPool *next; + + while(pool) + { + next = pool->GetNext(); + delete pool; + pool = next; + } +} + + + + + + + +CGPObject::CGPObject(const char *initName) : + mName(initName), + mNext(0), + mInOrderNext(0), + mInOrderPrevious(0) +{ +} + +bool CGPObject::WriteText(CTextPool **textPool, const char *text) +{ + if (strchr(text, ' ') || !text[0]) + { + (*textPool)->AllocText("\"", false, textPool); + (*textPool)->AllocText((char *)text, false, textPool); + (*textPool)->AllocText("\"", false, textPool); + } + else + { + (*textPool)->AllocText((char *)text, false, textPool); + } + + return true; +} + + + + + + + + + + + + + + +CGPValue::CGPValue(const char *initName, const char *initValue) : + CGPObject(initName), + mList(0) +{ + if (initValue) + { + AddValue(initValue); + } +} + +CGPValue::~CGPValue(void) +{ + CGPObject *next; + + while(mList) + { + next = mList->GetNext(); + delete mList; + mList = next; + } +} + +CGPValue *CGPValue::Duplicate(CTextPool **textPool) +{ + CGPValue *newValue; + CGPObject *iterator; + char *name; + + if (textPool) + { + name = (*textPool)->AllocText((char *)mName, true, textPool); + } + else + { + name = (char *)mName; + } + + newValue = new CGPValue(name); + iterator = mList; + while(iterator) + { + if (textPool) + { + name = (*textPool)->AllocText((char *)iterator->GetName(), true, textPool); + } + else + { + name = (char *)iterator->GetName(); + } + newValue->AddValue(name); + iterator = iterator->GetNext(); + } + + return newValue; +} + +bool CGPValue::IsList(void) +{ + if (!mList || !mList->GetNext()) + { + return false; + } + + return true; +} + +const char *CGPValue::GetTopValue(void) +{ + if (mList) + { + return mList->GetName(); + } + + return 0; +} + +void CGPValue::AddValue(const char *newValue, CTextPool **textPool) +{ + if (textPool) + { + newValue = (*textPool)->AllocText((char *)newValue, true, textPool); + } + + if (mList == 0) + { + mList = new CGPObject(newValue); + mList->SetInOrderNext(mList); + } + else + { + mList->GetInOrderNext()->SetNext(new CGPObject(newValue)); + mList->SetInOrderNext(mList->GetInOrderNext()->GetNext()); + } +} + +bool CGPValue::Parse(char **dataPtr, CTextPool **textPool) +{ + char *token; + char *value; + + while(1) + { + token = GetToken(dataPtr, true, true); + + if (!token[0]) + { // end of data - error! + return false; + } + else if (Q_stricmp(token, "]") == 0) + { // ending brace for this list + break; + } + + value = (*textPool)->AllocText(token, true, textPool); + AddValue(value); + } + + return true; +} + +bool CGPValue::Write(CTextPool **textPool, int depth) +{ + int i; + CGPObject *next; + + if (!mList) + { + return true; + } + + for(i=0;iAllocText("\t", false, textPool); + } + + WriteText(textPool, mName); + + if (!mList->GetNext()) + { + (*textPool)->AllocText("\t\t", false, textPool); + mList->WriteText(textPool, mList->GetName()); + (*textPool)->AllocText("\r\n", false, textPool); + } + else + { + (*textPool)->AllocText("\r\n", false, textPool); + + for(i=0;iAllocText("\t", false, textPool); + } + (*textPool)->AllocText("[\r\n", false, textPool); + + next = mList; + while(next) + { + for(i=0;iAllocText("\t", false, textPool); + } + mList->WriteText(textPool, next->GetName()); + (*textPool)->AllocText("\r\n", false, textPool); + + next = next->GetNext(); + } + + for(i=0;iAllocText("\t", false, textPool); + } + (*textPool)->AllocText("]\r\n", false, textPool); + } + + return true; +} + + + + + + + + + + + + + + + + +CGPGroup::CGPGroup(const char *initName, CGPGroup *initParent) : + CGPObject(initName), + mPairs(0), + mInOrderPairs(0), + mCurrentPair(0), + mSubGroups(0), + mInOrderSubGroups(0), + mCurrentSubGroup(0), + mParent(initParent), + mWriteable(false) +{ +} + +CGPGroup::~CGPGroup(void) +{ + Clean(); +} + +int CGPGroup::GetNumSubGroups(void) +{ + int count; + CGPGroup *group; + + count = 0; + group = mSubGroups; + do + { + count++; + group = (CGPGroup *)group->GetNext(); + } + while(group); + + return(count); +} + +int CGPGroup::GetNumPairs(void) +{ + int count; + CGPValue *pair; + + count = 0; + pair = mPairs; + do + { + count++; + pair = (CGPValue *)pair->GetNext(); + } + while(pair); + + return(count); +} + +void CGPGroup::Clean(void) +{ + while(mPairs) + { + mCurrentPair = (CGPValue *)mPairs->GetNext(); + delete mPairs; + mPairs = mCurrentPair; + } + + while(mSubGroups) + { + mCurrentSubGroup = (CGPGroup *)mSubGroups->GetNext(); + delete mSubGroups; + mSubGroups = mCurrentSubGroup; + } + + mPairs = mInOrderPairs = mCurrentPair = 0; + mSubGroups = mInOrderSubGroups = mCurrentSubGroup = 0; + mParent = 0; + mWriteable = false; +} + +CGPGroup *CGPGroup::Duplicate(CTextPool **textPool, CGPGroup *initParent) +{ + CGPGroup *newGroup, *subSub, *newSub; + CGPValue *newPair, *subPair; + char *name; + + if (textPool) + { + name = (*textPool)->AllocText((char *)mName, true, textPool); + } + else + { + name = (char *)mName; + } + + newGroup = new CGPGroup(name); + + subSub = mSubGroups; + while(subSub) + { + newSub = subSub->Duplicate(textPool, newGroup); + newGroup->AddGroup(newSub); + + subSub = (CGPGroup *)subSub->GetNext(); + } + + subPair = mPairs; + while(subPair) + { + newPair = subPair->Duplicate(textPool); + newGroup->AddPair(newPair); + + subPair = (CGPValue *)subPair->GetNext(); + } + + return newGroup; +} + +void CGPGroup::SortObject(CGPObject *object, CGPObject **unsortedList, CGPObject **sortedList, + CGPObject **lastObject) +{ + CGPObject *test, *last; + + if (!*unsortedList) + { + *unsortedList = *sortedList = object; + } + else + { + (*lastObject)->SetNext(object); + + test = *sortedList; + last = 0; + while(test) + { + if (Q_stricmp(object->GetName(), test->GetName()) < 0) + { + break; + } + + last = test; + test = test->GetInOrderNext(); + } + + if (test) + { + test->SetInOrderPrevious(object); + object->SetInOrderNext(test); + } + if (last) + { + last->SetInOrderNext(object); + object->SetInOrderPrevious(last); + } + else + { + *sortedList = object; + } + } + + *lastObject = object; +} + +CGPValue *CGPGroup::AddPair(const char *name, const char *value, CTextPool **textPool) +{ + CGPValue *newPair; + + if (textPool) + { + name = (*textPool)->AllocText((char *)name, true, textPool); + if (value) + { + value = (*textPool)->AllocText((char *)value, true, textPool); + } + } + + newPair = new CGPValue(name, value); + + AddPair(newPair); + + return newPair; +} + +void CGPGroup::AddPair(CGPValue *NewPair) +{ + SortObject(NewPair, (CGPObject **)&mPairs, (CGPObject **)&mInOrderPairs, + (CGPObject **)&mCurrentPair); +} + +CGPGroup *CGPGroup::AddGroup(const char *name, CTextPool **textPool) +{ + CGPGroup *newGroup; + + if (textPool) + { + name = (*textPool)->AllocText((char *)name, true, textPool); + } + + newGroup = new CGPGroup(name, this); + + AddGroup(newGroup); + + return newGroup; +} + +void CGPGroup::AddGroup(CGPGroup *NewGroup) +{ + SortObject(NewGroup, (CGPObject **)&mSubGroups, (CGPObject **)&mInOrderSubGroups, + (CGPObject **)&mCurrentSubGroup); +} + +CGPGroup *CGPGroup::FindSubGroup(const char *name) +{ + CGPGroup *group; + + group = mSubGroups; + while(group) + { + if(!Q_stricmp(name, group->GetName())) + { + return(group); + } + group = (CGPGroup *)group->GetNext(); + } + return(NULL); +} + +bool CGPGroup::Parse(char **dataPtr, CTextPool **textPool) +{ + char *token; + char lastToken[MAX_TOKEN_SIZE]; + CGPGroup *newSubGroup; + CGPValue *newPair; + + while(1) + { + token = GetToken(dataPtr, true); + + if (!token[0]) + { // end of data - error! + if (mParent) + { + return false; + } + else + { + break; + } + } + else if (Q_stricmp(token, "}") == 0) + { // ending brace for this group + break; + } + + strcpy(lastToken, token); + + // read ahead to see what we are doing + token = GetToken(dataPtr, true, true); + if (Q_stricmp(token, "{") == 0) + { // new sub group + newSubGroup = AddGroup(lastToken, textPool); + newSubGroup->SetWriteable(mWriteable); + if (!newSubGroup->Parse(dataPtr, textPool)) + { + return false; + } + } + else if (Q_stricmp(token, "[") == 0) + { // new pair list + newPair = AddPair(lastToken, 0, textPool); + if (!newPair->Parse(dataPtr, textPool)) + { + return false; + } + } + else + { // new pair + AddPair(lastToken, token, textPool); + } + } + + return true; +} + +bool CGPGroup::Write(CTextPool **textPool, int depth) +{ + int i; + CGPValue *mPair = mPairs; + CGPGroup *mSubGroup = mSubGroups; + + if (depth >= 0) + { + for(i=0;iAllocText("\t", false, textPool); + } + WriteText(textPool, mName); + (*textPool)->AllocText("\r\n", false, textPool); + + for(i=0;iAllocText("\t", false, textPool); + } + (*textPool)->AllocText("{\r\n", false, textPool); + } + + while(mPair) + { + mPair->Write(textPool, depth+1); + mPair = (CGPValue *)mPair->GetNext(); + } + + while(mSubGroup) + { + mSubGroup->Write(textPool, depth+1); + mSubGroup = (CGPGroup *)mSubGroup->GetNext(); + } + + if (depth >= 0) + { + for(i=0;iAllocText("\t", false, textPool); + } + (*textPool)->AllocText("}\r\n", false, textPool); + } + + return true; +} + +/************************************************************************************************ + * CGPGroup::FindPair + * This function will search for the pair with the specified key name. Multiple keys may be + * searched if you specify "||" inbetween each key name in the string. The first key to be + * found (from left to right) will be returned. + * + * Input + * key: the name of the key(s) to be searched for. + * + * Output / Return + * the group belonging to the first key found or 0 if no group was found. + * + ************************************************************************************************/ +CGPValue *CGPGroup::FindPair(const char *key) +{ + CGPValue *pair; + size_t length; + const char *pos, *separator, *next; + + pos = key; + while(pos[0]) + { + separator = strstr(pos, "||"); + if (separator) + { + length = separator - pos; + next = separator + 2; + } + else + { + length = strlen(pos); + next = pos + length; + } + + pair = mPairs; + while(pair) + { + if (strlen(pair->GetName()) == length && + Q_stricmpn(pair->GetName(), pos, length) == 0) + { + return pair; + } + + pair = pair->GetNext(); + } + + pos = next; + } + + return 0; +} + +const char *CGPGroup::FindPairValue(const char *key, const char *defaultVal) +{ + CGPValue *pair = FindPair(key); + + if (pair) + { + return pair->GetTopValue(); + } + + return defaultVal; +} + + + + + + + + + + + + + + + +CGenericParser2::CGenericParser2(void) : + mTextPool(0), + mWriteable(false) +{ +} + +CGenericParser2::~CGenericParser2(void) +{ + Clean(); +} + +bool CGenericParser2::Parse(char **dataPtr, bool cleanFirst, bool writeable) +{ + CTextPool *topPool; + + if (cleanFirst) + { + Clean(); + } + + if (!mTextPool) + { + mTextPool = new CTextPool; + } + + SetWriteable(writeable); + mTopLevel.SetWriteable(writeable); + topPool = mTextPool; + bool ret = mTopLevel.Parse(dataPtr, &topPool); + + return ret; +} + +void CGenericParser2::Clean(void) +{ + mTopLevel.Clean(); + + CleanTextPool(mTextPool); + mTextPool = 0; +} + +bool CGenericParser2::Write(CTextPool *textPool) +{ + return mTopLevel.Write(&textPool, -1); +} + + + + + + + + + +// The following groups of routines are used for a C interface into GP2. +// C++ users should just use the objects as normally and not call these routines below +// +// CGenericParser2 (void *) routines +TGenericParser2 GP_Parse(char **dataPtr, bool cleanFirst, bool writeable) +{ + CGenericParser2 *parse; + + parse = new CGenericParser2; + if (parse->Parse(dataPtr, cleanFirst, writeable)) + { + return parse; + } + + delete parse; + return 0; +} + +void GP_Clean(TGenericParser2 GP2) +{ + if (!GP2) + { + return; + } + + ((CGenericParser2 *)GP2)->Clean(); +} + +void GP_Delete(TGenericParser2 *GP2) +{ + if (!GP2 || !(*GP2)) + { + return; + } + + delete ((CGenericParser2 *)(*GP2)); + (*GP2) = 0; +} + +TGPGroup GP_GetBaseParseGroup(TGenericParser2 GP2) +{ + if (!GP2) + { + return 0; + } + + return ((CGenericParser2 *)GP2)->GetBaseParseGroup(); +} + + + + +// CGPGroup (void *) routines +const char *GPG_GetName(TGPGroup GPG) +{ + if (!GPG) + { + return ""; + } + + return ((CGPGroup *)GPG)->GetName(); +} + +bool GPG_GetName(TGPGroup GPG, char *Value) +{ + if (!GPG) + { + Value[0] = 0; + return false; + } + + strcpy(Value, ((CGPGroup *)GPG)->GetName()); + return true; +} + +TGPGroup GPG_GetNext(TGPGroup GPG) +{ + if (!GPG) + { + return 0; + } + + return ((CGPGroup *)GPG)->GetNext(); +} + +TGPGroup GPG_GetInOrderNext(TGPGroup GPG) +{ + if (!GPG) + { + return 0; + } + + return ((CGPGroup *)GPG)->GetInOrderNext(); +} + +TGPGroup GPG_GetInOrderPrevious(TGPGroup GPG) +{ + if (!GPG) + { + return 0; + } + + return ((CGPGroup *)GPG)->GetInOrderPrevious(); +} + +TGPGroup GPG_GetPairs(TGPGroup GPG) +{ + if (!GPG) + { + return 0; + } + + return ((CGPGroup *)GPG)->GetPairs(); +} + +TGPGroup GPG_GetInOrderPairs(TGPGroup GPG) +{ + if (!GPG) + { + return 0; + } + + return ((CGPGroup *)GPG)->GetInOrderPairs(); +} + +TGPGroup GPG_GetSubGroups(TGPGroup GPG) +{ + if (!GPG) + { + return 0; + } + + return ((CGPGroup *)GPG)->GetSubGroups(); +} + +TGPGroup GPG_GetInOrderSubGroups(TGPGroup GPG) +{ + if (!GPG) + { + return 0; + } + + return ((CGPGroup *)GPG)->GetInOrderSubGroups(); +} + +TGPGroup GPG_FindSubGroup(TGPGroup GPG, const char *name) +{ + if (!GPG) + { + return 0; + } + + return ((CGPGroup *)GPG)->FindSubGroup(name); +} + +TGPValue GPG_FindPair(TGPGroup GPG, const char *key) +{ + if (!GPG) + { + return 0; + } + + return ((CGPGroup *)GPG)->FindPair(key); +} + +const char *GPG_FindPairValue(TGPGroup GPG, const char *key, const char *defaultVal) +{ + if (!GPG) + { + return defaultVal; + } + + return ((CGPGroup *)GPG)->FindPairValue(key, defaultVal); +} + +bool GPG_FindPairValue(TGPGroup GPG, const char *key, const char *defaultVal, char *Value) +{ + strcpy(Value, GPG_FindPairValue(GPG, key, defaultVal)); + + return true; +} + + + + +// CGPValue (void *) routines +const char *GPV_GetName(TGPValue GPV) +{ + if (!GPV) + { + return ""; + } + + return ((CGPValue *)GPV)->GetName(); +} + +bool GPV_GetName(TGPValue GPV, char *Value) +{ + if (!GPV) + { + Value[0] = 0; + return false; + } + + strcpy(Value, ((CGPValue *)GPV)->GetName()); + return true; +} + +TGPValue GPV_GetNext(TGPValue GPV) +{ + if (!GPV) + { + return 0; + } + + return ((CGPValue *)GPV)->GetNext(); +} + +TGPValue GPV_GetInOrderNext(TGPValue GPV) +{ + if (!GPV) + { + return 0; + } + + return ((CGPValue *)GPV)->GetInOrderNext(); +} + +TGPValue GPV_GetInOrderPrevious(TGPValue GPV) +{ + if (!GPV) + { + return 0; + } + + return ((CGPValue *)GPV)->GetInOrderPrevious(); +} + +bool GPV_IsList(TGPValue GPV) +{ + if (!GPV) + { + return 0; + } + + return ((CGPValue *)GPV)->IsList(); +} + +const char *GPV_GetTopValue(TGPValue GPV) +{ + if (!GPV) + { + return ""; + } + + return ((CGPValue *)GPV)->GetTopValue(); +} + +bool GPV_GetTopValue(TGPValue GPV, char *Value) +{ + if (!GPV) + { + Value[0] = 0; + return false; + } + + strcpy(Value, ((CGPValue *)GPV)->GetTopValue()); + + return true; +} + +TGPValue GPV_GetList(TGPValue GPV) +{ + if (!GPV) + { + return 0; + } + + return ((CGPValue *)GPV)->GetList(); +} diff --git a/Projects/Android/jni/OpenJK/codemp_delete/qcommon/GenericParser2.h b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/GenericParser2.h new file mode 100644 index 0000000..250f866 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/GenericParser2.h @@ -0,0 +1,221 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#pragma once + +#ifdef DEBUG_LINKING + #pragma message("...including GenericParser2.h") +#endif + +#include "disablewarnings.h" + +#ifdef USE_LOCAL_GENERICPARSER +#include +#include +#include + +#define trap_Z_Malloc(x, y) malloc(x) +#define trap_Z_Free(x) free(x) + +#endif + +class CTextPool; +class CGPObject; + +class CTextPool +{ +private: + char *mPool; + CTextPool *mNext; + int mSize, mUsed; + +public: + CTextPool(int initSize = 10240); + ~CTextPool(void); + + CTextPool *GetNext(void) { return mNext; } + void SetNext(CTextPool *which) { mNext = which; } + char *GetPool(void) { return mPool; } + int GetUsed(void) { return mUsed; } + + char *AllocText(char *text, bool addNULL = true, CTextPool **poolPtr = 0); +}; + +void CleanTextPool(CTextPool *pool); + +class CGPObject +{ +protected: + const char *mName; + CGPObject *mNext, *mInOrderNext, *mInOrderPrevious; + +public: + CGPObject(const char *initName); + virtual ~CGPObject( void ) {} + + const char *GetName(void) { return mName; } + + CGPObject *GetNext(void) { return mNext; } + void SetNext(CGPObject *which) { mNext = which; } + CGPObject *GetInOrderNext(void) { return mInOrderNext; } + void SetInOrderNext(CGPObject *which) { mInOrderNext = which; } + CGPObject *GetInOrderPrevious(void) { return mInOrderPrevious; } + void SetInOrderPrevious(CGPObject *which) { mInOrderPrevious = which; } + + bool WriteText(CTextPool **textPool, const char *text); +}; + + + +class CGPValue : public CGPObject +{ +private: + CGPObject *mList; + +public: + CGPValue(const char *initName, const char *initValue = 0); + ~CGPValue(void); + + CGPValue *GetNext(void) { return (CGPValue *)mNext; } + + CGPValue *Duplicate(CTextPool **textPool = 0); + + bool IsList(void); + const char *GetTopValue(void); + CGPObject *GetList(void) { return mList; } + void AddValue(const char *newValue, CTextPool **textPool = 0); + + bool Parse(char **dataPtr, CTextPool **textPool); + + bool Write(CTextPool **textPool, int depth); +}; + + + +class CGPGroup : public CGPObject +{ +private: + CGPValue *mPairs, *mInOrderPairs; + CGPValue *mCurrentPair; + CGPGroup *mSubGroups, *mInOrderSubGroups; + CGPGroup *mCurrentSubGroup; + CGPGroup *mParent; + bool mWriteable; + + void SortObject(CGPObject *object, CGPObject **unsortedList, CGPObject **sortedList, + CGPObject **lastObject); + +public: + CGPGroup(const char *initName = "Top Level", CGPGroup *initParent = 0); + ~CGPGroup(void); + + CGPGroup *GetParent(void) { return mParent; } + CGPGroup *GetNext(void) { return (CGPGroup *)mNext; } + int GetNumSubGroups(void); + int GetNumPairs(void); + + void Clean(void); + CGPGroup *Duplicate(CTextPool **textPool = 0, CGPGroup *initParent = 0); + + void SetWriteable(const bool writeable) { mWriteable = writeable; } + CGPValue *GetPairs(void) { return mPairs; } + CGPValue *GetInOrderPairs(void) { return mInOrderPairs; } + CGPGroup *GetSubGroups(void) { return mSubGroups; } + CGPGroup *GetInOrderSubGroups(void) { return mInOrderSubGroups; } + + CGPValue *AddPair(const char *name, const char *value, CTextPool **textPool = 0); + void AddPair(CGPValue *NewPair); + CGPGroup *AddGroup(const char *name, CTextPool **textPool = 0); + void AddGroup(CGPGroup *NewGroup); + CGPGroup *FindSubGroup(const char *name); + bool Parse(char **dataPtr, CTextPool **textPool); + bool Write(CTextPool **textPool, int depth); + + CGPValue *FindPair(const char *key); + const char *FindPairValue(const char *key, const char *defaultVal = 0); +}; + +class CGenericParser2 +{ +private: + CGPGroup mTopLevel; + CTextPool *mTextPool; + bool mWriteable; + +public: + CGenericParser2(void); + ~CGenericParser2(void); + + void SetWriteable(const bool writeable) { mWriteable = writeable; } + CGPGroup *GetBaseParseGroup(void) { return &mTopLevel; } + + bool Parse(char **dataPtr, bool cleanFirst = true, bool writeable = false); + bool Parse(char *dataPtr, bool cleanFirst = true, bool writeable = false) + { + return Parse(&dataPtr, cleanFirst, writeable); + } + void Clean(void); + + bool Write(CTextPool *textPool); +}; + + + +// The following groups of routines are used for a C interface into GP2. +// C++ users should just use the objects as normally and not call these routines below +// + +typedef void *TGenericParser2; +typedef void *TGPGroup; +typedef void *TGPValue; + +// CGenericParser2 (void *) routines +TGenericParser2 GP_Parse(char **dataPtr, bool cleanFirst, bool writeable); +void GP_Clean(TGenericParser2 GP2); +void GP_Delete(TGenericParser2 *GP2); +TGPGroup GP_GetBaseParseGroup(TGenericParser2 GP2); + +// CGPGroup (void *) routines +const char *GPG_GetName(TGPGroup GPG); +bool GPG_GetName(TGPGroup GPG, char *Value); +TGPGroup GPG_GetNext(TGPGroup GPG); +TGPGroup GPG_GetInOrderNext(TGPGroup GPG); +TGPGroup GPG_GetInOrderPrevious(TGPGroup GPG); +TGPGroup GPG_GetPairs(TGPGroup GPG); +TGPGroup GPG_GetInOrderPairs(TGPGroup GPG); +TGPGroup GPG_GetSubGroups(TGPGroup GPG); +TGPGroup GPG_GetInOrderSubGroups(TGPGroup GPG); +TGPGroup GPG_FindSubGroup(TGPGroup GPG, const char *name); +TGPValue GPG_FindPair(TGPGroup GPG, const char *key); +const char *GPG_FindPairValue(TGPGroup GPG, const char *key, const char *defaultVal); +bool GPG_FindPairValue(TGPGroup GPG, const char *key, const char *defaultVal, char *Value); + +// CGPValue (void *) routines +const char *GPV_GetName(TGPValue GPV); +bool GPV_GetName(TGPValue GPV, char *Value); +TGPValue GPV_GetNext(TGPValue GPV); +TGPValue GPV_GetInOrderNext(TGPValue GPV); +TGPValue GPV_GetInOrderPrevious(TGPValue GPV); +bool GPV_IsList(TGPValue GPV); +const char *GPV_GetTopValue(TGPValue GPV); +bool GPV_GetTopValue(TGPValue GPV, char *Value); +TGPValue GPV_GetList(TGPValue GPV); diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/MiniHeap.h b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/MiniHeap.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/MiniHeap.h rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/MiniHeap.h diff --git a/Projects/Android/jni/OpenJK/codemp_delete/qcommon/RoffSystem.cpp b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/RoffSystem.cpp new file mode 100644 index 0000000..a61e0e3 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/RoffSystem.cpp @@ -0,0 +1,1080 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#include "RoffSystem.h" + +#ifndef DEDICATED +#include "client/cl_cgameapi.h" +#endif +#include "server/sv_gameapi.h" + +// The one and only instance... +CROFFSystem theROFFSystem; + +//--------------------------------------------------------------------------- +// CROFFSystem::CROFF::CROFF +// Simple constructor for CROFF object +// +// INPUTS: +// pass in the filepath and the id of the roff object to create +// +// RETURN: +// none +//--------------------------------------------------------------------------- +CROFFSystem::CROFF::CROFF( const char *file, int id ) +{ + strcpy( mROFFFilePath, file ); + + mID = id; + mMoveRotateList = NULL; + mNoteTrackIndexes = 0; + mUsedByClient = mUsedByServer = qfalse; +} + + +//--------------------------------------------------------------------------- +// CROFFSystem::CROFF::~CROFF() +// Frees any resources when the CROFF object dies +// +// INPUTS: +// none +// +// RETURN: +// none +//--------------------------------------------------------------------------- +CROFFSystem::CROFF::~CROFF() +{ + if ( mMoveRotateList ) + { + delete [] mMoveRotateList; + } + + if (mNoteTrackIndexes) + { + delete mNoteTrackIndexes[0]; + delete [] mNoteTrackIndexes; + } +} + + +//--------------------------------------------------------------------------- +// CROFFSystem::Restart +// Cleans up the roff system, not sure how useful this really is +// +// INPUTS: +// none +// +// RETURN: +// success or failure +//--------------------------------------------------------------------------- +qboolean CROFFSystem::Restart() +{ + TROFFList::iterator itr = mROFFList.begin(); + + // remove everything from the list + while( itr != mROFFList.end() ) + { + delete ((CROFF *)(*itr).second); + + mROFFList.erase( itr ); + itr = mROFFList.begin(); + } + + // clear CROFFSystem unique ID counter + mID = 0; + + return qtrue; +} + + +//--------------------------------------------------------------------------- +// CROFFSystem::IsROFF +// Makes sure that the requested file is actually a ROFF +// +// INPUTS: +// pass in the file data +// +// RETURN: +// returns test success or failure +//--------------------------------------------------------------------------- +qboolean CROFFSystem::IsROFF( unsigned char *data ) +{ + TROFFHeader *hdr = (TROFFHeader *)data; + TROFF2Header *hdr2 = (TROFF2Header *)data; + + if ( !strcmp( hdr->mHeader, ROFF_STRING )) + { // bad header + return qfalse; + } + + if (LittleLong(hdr->mVersion) != ROFF_VERSION && LittleLong(hdr->mVersion) != ROFF_NEW_VERSION) + { // bad version + return qfalse; + } + + if (LittleLong(hdr->mVersion) == ROFF_VERSION && LittleFloat(hdr->mCount) <= 0.0) + { // bad count + return qfalse; + } + + if (LittleLong(hdr->mVersion) == ROFF_NEW_VERSION && LittleLong(hdr2->mCount) <= 0) + { // bad count + return qfalse; + } + + return qtrue; +} + + +//--------------------------------------------------------------------------- +// CROFFSystem::InitROFF +// Handles stuffing the roff data in the CROFF object +// +// INPUTS: +// pass in the file data and the object to stuff the data into. +// +// RETURN: +// returns initialization success or failure +//--------------------------------------------------------------------------- +qboolean CROFFSystem::InitROFF( unsigned char *data, CROFF *obj ) +{ + int i; + + TROFFHeader *hdr = (TROFFHeader *)data; + + if (LittleLong(hdr->mVersion) == ROFF_NEW_VERSION) + { + return InitROFF2(data, obj); + } + + obj->mROFFEntries = LittleLong(hdr->mCount); + obj->mMoveRotateList = new TROFF2Entry[((int)LittleFloat(hdr->mCount))]; + obj->mFrameTime = 1000 / ROFF_SAMPLE_RATE; // default 10 hz + obj->mLerp = ROFF_SAMPLE_RATE; + obj->mNumNoteTracks = 0; + obj->mNoteTrackIndexes = 0; + + if ( obj->mMoveRotateList != 0 ) + { // Step past the header to get to the goods + TROFFEntry *roff_data = ( TROFFEntry *)&hdr[1]; + + // Copy all of the goods into our ROFF cache + for ( i = 0; i < LittleLong(hdr->mCount); i++ ) + { +#ifdef Q3_BIG_ENDIAN + obj->mMoveRotateList[i].mOriginOffset[0] = LittleFloat(roff_data[i].mOriginOffset[0]); + obj->mMoveRotateList[i].mOriginOffset[1] = LittleFloat(roff_data[i].mOriginOffset[1]); + obj->mMoveRotateList[i].mOriginOffset[2] = LittleFloat(roff_data[i].mOriginOffset[2]); + obj->mMoveRotateList[i].mRotateOffset[0] = LittleFloat(roff_data[i].mRotateOffset[0]); + obj->mMoveRotateList[i].mRotateOffset[1] = LittleFloat(roff_data[i].mRotateOffset[1]); + obj->mMoveRotateList[i].mRotateOffset[2] = LittleFloat(roff_data[i].mRotateOffset[2]); +#else + VectorCopy( roff_data[i].mOriginOffset, obj->mMoveRotateList[i].mOriginOffset ); + VectorCopy( roff_data[i].mRotateOffset, obj->mMoveRotateList[i].mRotateOffset ); +#endif + obj->mMoveRotateList[i].mStartNote = -1; + obj->mMoveRotateList[i].mNumNotes = 0; + } + + FixBadAngles(obj); + } + else + { + return qfalse; + } + + return qtrue; +} + + +//--------------------------------------------------------------------------- +// CROFFSystem::InitROFF2 +// Handles stuffing the roff data in the CROFF object for version 2 +// +// INPUTS: +// pass in the file data and the object to stuff the data into. +// +// RETURN: +// returns initialization success or failure +//--------------------------------------------------------------------------- +qboolean CROFFSystem::InitROFF2( unsigned char *data, CROFF *obj ) +{ + int i; + + TROFF2Header *hdr = (TROFF2Header *)data; + + obj->mROFFEntries = LittleLong(hdr->mCount); + obj->mMoveRotateList = new TROFF2Entry[LittleLong(hdr->mCount)]; + obj->mFrameTime = LittleLong(hdr->mFrameRate); + obj->mLerp = 1000 / LittleLong(hdr->mFrameRate); + obj->mNumNoteTracks = LittleLong(hdr->mNumNotes); + + if ( obj->mMoveRotateList != 0 ) + { // Step past the header to get to the goods + TROFF2Entry *roff_data = ( TROFF2Entry *)&hdr[1]; + + // Copy all of the goods into our ROFF cache + for ( i = 0; i < LittleLong(hdr->mCount); i++ ) + { +#ifdef Q3_BIG_ENDIAN + obj->mMoveRotateList[i].mOriginOffset[0] = LittleFloat(roff_data[i].mOriginOffset[0]); + obj->mMoveRotateList[i].mOriginOffset[1] = LittleFloat(roff_data[i].mOriginOffset[1]); + obj->mMoveRotateList[i].mOriginOffset[2] = LittleFloat(roff_data[i].mOriginOffset[2]); + obj->mMoveRotateList[i].mRotateOffset[0] = LittleFloat(roff_data[i].mRotateOffset[0]); + obj->mMoveRotateList[i].mRotateOffset[1] = LittleFloat(roff_data[i].mRotateOffset[1]); + obj->mMoveRotateList[i].mRotateOffset[2] = LittleFloat(roff_data[i].mRotateOffset[2]); +#else + VectorCopy( roff_data[i].mOriginOffset, obj->mMoveRotateList[i].mOriginOffset ); + VectorCopy( roff_data[i].mRotateOffset, obj->mMoveRotateList[i].mRotateOffset ); +#endif + obj->mMoveRotateList[i].mStartNote = LittleLong(roff_data[i].mStartNote); + obj->mMoveRotateList[i].mNumNotes = LittleLong(roff_data[i].mNumNotes); + } + + FixBadAngles(obj); + + if (obj->mNumNoteTracks) + { + size_t size = 0; + char *ptr, *start; + + ptr = start = (char *)&roff_data[i]; + + for(i=0;imNumNoteTracks;i++) + { + size += strlen(ptr) + 1; + ptr += strlen(ptr) + 1; + } + + obj->mNoteTrackIndexes = new char *[obj->mNumNoteTracks]; + ptr = obj->mNoteTrackIndexes[0] = new char[size]; + memcpy(obj->mNoteTrackIndexes[0], start, size); + + for(i=1;imNumNoteTracks;i++) + { + ptr += strlen(ptr) + 1; + obj->mNoteTrackIndexes[i] = ptr; + } + } + } + else + { + return qfalse; + } + + return qtrue; +} + +/************************************************************************************************ + * CROFFSystem::FixBadAngles * + * This function will attempt to fix bad angles (large) that come in from the exporter. * + * * + * Input * + * obj: the ROFF object * + * * + * Output / Return * + * none * + * * + ************************************************************************************************/ +void CROFFSystem::FixBadAngles(CROFF *obj) +{ +// Ideally we would fix the ROFF exporter, if that doesn't happen, this may be an adequate solution +#ifdef ROFF_AUTO_FIX_BAD_ANGLES + int index, t; + + // Attempt to fix bad angles + + for(index=0;indexmROFFEntries;index++) + { + for ( t = 0; t < 3; t++ ) + { + if ( obj->mMoveRotateList[index].mRotateOffset[t] > 180.0f ) + { // found a bad angle + // Com_Printf( S_COLOR_YELLOW"Fixing bad roff angle\n <%6.2f> changed to <%6.2f>.\n", + // roff_data[i].mRotateOffset[t], roff_data[i].mRotateOffset[t] - 360.0f ); + obj->mMoveRotateList[index].mRotateOffset[t] -= 360.0f; + } + else if ( obj->mMoveRotateList[index].mRotateOffset[t] < -180.0f ) + { // found a bad angle + // Com_Printf( S_COLOR_YELLOW"Fixing bad roff angle\n <%6.2f> changed to <%6.2f>.\n", + // roff_data[i].mRotateOffset[t], roff_data[i].mRotateOffset[t] + 360.0f ); + obj->mMoveRotateList[index].mRotateOffset[t] += 360.0f; + } + } + } +#endif // ROFF_AUTO_FIX_BAD_ANGLES +} + +//--------------------------------------------------------------------------- +// CROFFSystem::Cache +// Pre-caches roff data to avoid file hits during gameplay. Disallows +// repeated caches of existing roffs. +// +// INPUTS: +// pass in the filepath of the roff to cache +// +// RETURN: +// returns ID of the roff, whether its an existing one or new one. +//--------------------------------------------------------------------------- +int CROFFSystem::Cache( const char *file, qboolean isClient ) +{ + // See if this item is already cached + int len; + int id = GetID( file ); + unsigned char *data; + CROFF *cROFF; + + if ( id ) + { +#ifdef _DEBUG + Com_Printf( S_COLOR_YELLOW"Ignoring. File '%s' already cached.\n", file ); +#endif + } + else + { // Read the file in one fell swoop + len = FS_ReadFile( file, (void**) &data); + + if ( len <= 0 ) + { + char otherPath[1024]; + COM_StripExtension(file, otherPath, sizeof( otherPath )); + len = FS_ReadFile( va("scripts/%s.rof", otherPath), (void**) &data); + if (len <= 0) + { + Com_Printf( S_COLOR_RED"Could not open .ROF file '%s'\n", file ); + return 0; + } + } + + // Make sure that the file is roff + if ( !IsROFF( data ) ) + { + Com_Printf( S_COLOR_RED"cache failed: roff <%s> does not exist or is not a valid roff\n", file ); + FS_FreeFile( data ); + + return 0; + } + + // Things are looking good so far, so create a new CROFF object + id = NewID(); + + cROFF = new CROFF( file, id ); + + mROFFList[id] = cROFF; + + if ( !InitROFF( data, cROFF ) ) + { // something failed, so get rid of the object + Unload( id ); + id = 0; + } + + FS_FreeFile( data ); + } + + cROFF = (*mROFFList.find( id )).second; + if (isClient) + { + cROFF->mUsedByClient = qtrue; + } + else + { + cROFF->mUsedByServer = qtrue; + } + + // If we haven't requested a new ID, we'll just be returning the ID of the existing roff + return id; +} + + +//--------------------------------------------------------------------------- +// CROFFSystem::GetID +// Finds the associated (internal) ID of the specified roff file +// +// INPUTS: +// pass in the roff file path +// +// RETURN: +// returns ID if there is one, zero if nothing was found +//--------------------------------------------------------------------------- +int CROFFSystem::GetID( const char *file ) +{ + TROFFList::iterator itr; + + // Attempt to find the requested roff + for ( itr = mROFFList.begin(); itr != mROFFList.end(); ++itr ) + { + if ( !strcmp( ((CROFF *)((*itr).second))->mROFFFilePath, file ) ) + { // return the ID to this roff + return (*itr).first; + } + } + + // Not found + return 0; +} + + +//--------------------------------------------------------------------------- +// CROFFSystem::Unload +// Removes the roff from the list, deleting it to free up any used resources +// +// INPUTS: +// pass in the id of the roff to delete, use GetID if you only know the roff +// filepath +// +// RETURN: +// qtrue if item was in the list, qfalse otherwise +//--------------------------------------------------------------------------- +qboolean CROFFSystem::Unload( int id ) +{ + TROFFList::iterator itr; + + itr = mROFFList.find( id ); + + if ( itr != mROFFList.end() ) + { // requested item found in the list, free mem, then remove from list + delete itr->second; + + mROFFList.erase( itr++ ); + +#ifdef _DEBUG + Com_Printf( S_COLOR_GREEN "roff unloaded\n" ); +#endif + + return qtrue; + } + else + { // not found + +#ifdef _DEBUG + Com_Printf( S_COLOR_RED "unload failed: roff <%i> does not exist\n", id ); +#endif + return qfalse; + } +} + +//--------------------------------------------------------------------------- +// CROFFSystem::Clean +// Cleans out all Roffs, freeing up any used resources +// +// INPUTS: +// none +// +// RETURN: +// success of operation +//--------------------------------------------------------------------------- +qboolean CROFFSystem::Clean(qboolean isClient) +{ +#if 0 + TROFFList::iterator itr, next; + TROFFEntList::iterator entI, nextEnt; + itr = mROFFList.begin(); + while ( itr != mROFFList.end() ) + { + next = itr; + ++next; + + if (isClient) + { + (*itr).second->mUsedByClient = qfalse; + } + else + { + (*itr).second->mUsedByServer = qfalse; + } + if ((*itr).second->mUsedByClient == qfalse && (*itr).second->mUsedByServer == qfalse) + { // we are not used on both client and server, so unload + Unload( (*itr).first ); + } + + itr = next; + } + + entI = mROFFEntList.begin(); + while ( entI != mROFFEntList.end() ) + { + nextEnt = entI; + ++nextEnt; + + if ((*entI)->mIsClient == isClient) + { + delete (*entI); + mROFFEntList.erase( entI ); + } + + entI = nextEnt; + } + mROFFEntList.clear(); + + return qtrue; +#else + TROFFList::iterator itr; + + itr = mROFFList.begin(); + + while ( itr != mROFFList.end() ) + { + Unload( (*itr).first ); + + itr = mROFFList.begin(); + } + return qtrue; +#endif +} + +//--------------------------------------------------------------------------- +// CROFFSystem::List +// Dumps the file path to the current set of cached roffs, for debug purposes +// +// INPUTS: +// none +// +// RETURN: +// none +//--------------------------------------------------------------------------- +void CROFFSystem::List() +{ + TROFFList::iterator itr; + + Com_Printf( S_COLOR_GREEN"\n--Cached ROFF files--\n" ); + Com_Printf( S_COLOR_GREEN"ID FILE\n" ); + + for ( itr = mROFFList.begin(); itr != mROFFList.end(); ++itr ) + { + Com_Printf( S_COLOR_GREEN"%2i - %s\n", (*itr).first, ((CROFF *)((*itr).second))->mROFFFilePath ); + } + + Com_Printf( S_COLOR_GREEN"\nFiles: %i\n", mROFFList.size() ); +} + + +//--------------------------------------------------------------------------- +// CROFFSystem::List +// Overloaded version of List, dumps the specified roff data to the console +// +// INPUTS: +// id of roff to display +// +// RETURN: +// success or failure of operation +//--------------------------------------------------------------------------- +qboolean CROFFSystem::List( int id ) +{ + TROFFList::iterator itr; + + itr = mROFFList.find( id ); + + if ( itr != mROFFList.end() ) + { // requested item found in the list + CROFF *obj = ((CROFF *)((*itr).second)); + TROFF2Entry *dat = obj->mMoveRotateList; + + Com_Printf( S_COLOR_GREEN"File: %s\n", obj->mROFFFilePath ); + Com_Printf( S_COLOR_GREEN"ID: %i\n", id ); + Com_Printf( S_COLOR_GREEN"Entries: %i\n\n", obj->mROFFEntries ); + + Com_Printf( S_COLOR_GREEN"MOVE ROTATE\n" ); + + for ( int i = 0; i < obj->mROFFEntries; i++ ) + { + Com_Printf( S_COLOR_GREEN"%6.2f %6.2f %6.2f %6.2f %6.2f %6.2f\n", + dat[i].mOriginOffset[0], dat[i].mOriginOffset[1], dat[i].mOriginOffset[2], + dat[i].mRotateOffset[0], dat[i].mRotateOffset[1], dat[i].mRotateOffset[2] ); + } + + return qtrue; + } + + Com_Printf( S_COLOR_YELLOW"ROFF not found: id <%d>\n", id ); + + return qfalse; +} + + +//--------------------------------------------------------------------------- +// CROFFSystem::Play +// Start roff playback on an entity +// +// INPUTS: +// the id of the entity that will be roffed +// the id of the roff to play +// +// RETURN: +// success or failure of add operation +//--------------------------------------------------------------------------- +qboolean CROFFSystem::Play( int entID, int id, qboolean doTranslation, qboolean isClient ) +{ + sharedEntity_t *ent = NULL; + + if ( !isClient ) + { + ent = SV_GentityNum( entID ); + + if ( ent == NULL ) + { // shame on you.. + return qfalse; + } + ent->r.mIsRoffing = qtrue; + + /*rjr if(ent->GetPhysics() == PHYSICS_TYPE_NONE) + { + ent->SetPhysics(PHYSICS_TYPE_BRUSHMODEL); + }*/ + //bjg TODO: reset this latter? + } + + SROFFEntity *roffing_ent = new SROFFEntity; + + roffing_ent->mEntID = entID; + roffing_ent->mROFFID = id; + roffing_ent->mNextROFFTime = svs.time; + roffing_ent->mROFFFrame = 0; + roffing_ent->mKill = qfalse; + roffing_ent->mSignal = qtrue; // TODO: hook up the real signal code + roffing_ent->mTranslated = doTranslation; + roffing_ent->mIsClient = isClient; + + if ( !isClient ) + VectorCopy(ent->s.apos.trBase, roffing_ent->mStartAngles); + + mROFFEntList.push_back( roffing_ent ); + + return qtrue; +} + + +//--------------------------------------------------------------------------- +// CROFFSystem::ListEnts +// List all of the ents in the roff system +// +// INPUTS: +// none +// +// RETURN: +// none +//--------------------------------------------------------------------------- +void CROFFSystem::ListEnts() +{ +/* char *name, *file; + int id; + + TROFFEntList::iterator itr = mROFFEntList.begin(); + TROFFList::iterator itrRoff; + + Com_Printf( S_COLOR_GREEN"\n--ROFFing Entities--\n" ); + Com_Printf( S_COLOR_GREEN"EntID EntName RoffFile\n" ); + + // display everything in the end list + for ( itr = mROFFEntList.begin(); itr != mROFFEntList.end(); ++itr ) + { + // Entity ID + id = ((SROFFEntity *)(*itr))->mEntID; + // Entity Name + name = entitySystem->GetEntityFromID( id )->GetName(); + // ROFF object that will contain the roff file name + itrRoff = mROFFList.find( ((SROFFEntity *)(*itr))->mROFFID ); + + if ( itrRoff != mROFFList.end() ) + { // grab our filename + file = ((CROFF *)((*itrRoff).second ))->mROFFFilePath; + } + else + { // roff filename not found == bad + file = "Error: Unknown"; + } + + Com_Printf( S_COLOR_GREEN"%3i %s %s\n", id, name, file ); + } + + Com_Printf( S_COLOR_GREEN"\nEntities: %i\n", mROFFEntList.size() );*/ +} + + +//--------------------------------------------------------------------------- +// CROFFSystem::PurgeEnt +// Prematurely purge an entity from the roff system +// +// INPUTS: +// the id of the entity to purge +// +// RETURN: +// success or failure of purge operation +//--------------------------------------------------------------------------- +qboolean CROFFSystem::PurgeEnt( int entID, qboolean isClient ) +{ + TROFFEntList::iterator itr = mROFFEntList.begin(); + + for ( itr = mROFFEntList.begin(); itr != mROFFEntList.end(); ++itr ) + { + if ( (*itr)->mIsClient == isClient && (*itr)->mEntID == entID) + { + // Make sure it won't stay lerping + ClearLerp( (*itr) ); + + delete (*itr); + + mROFFEntList.erase( itr ); + return qtrue; + } + } + + Com_Printf( S_COLOR_RED"Purge failed: Entity <%i> not found\n", entID ); + + return qfalse; +} + + + +//--------------------------------------------------------------------------- +// CROFFSystem::PurgeEnt +// Prematurely purge an entity from the roff system +// +// INPUTS: +// the name fo the entity to purge +// +// RETURN: +// success or failure of purge operation +//--------------------------------------------------------------------------- +qboolean CROFFSystem::PurgeEnt( char *name ) +{ +/* rjr CEntity *ent = entitySystem->GetEntityFromName( NULL, name ); + + if ( ent && ent->GetInUse() == qtrue ) + { + return PurgeEnt( ent->GetID() ); + } + else + { + Com_Printf( S_COLOR_RED"Entity <%s> not found or not in use\n", name ); + return qfalse; + }*/ + + return qfalse; +} + +//--------------------------------------------------------------------------- +// CROFFSystem::UpdateEntities +// Update all of the entities in the system +// +// INPUTS: +// none +// +// RETURN: +// none +//--------------------------------------------------------------------------- +void CROFFSystem::UpdateEntities(qboolean isClient) +{ + TROFFEntList::iterator itr = mROFFEntList.begin(); + TROFFList::iterator itrRoff; + + // display everything in the entity list + for ( itr = mROFFEntList.begin(); itr != mROFFEntList.end(); ++itr ) + { + if ((*itr)->mIsClient != isClient) + { + continue; + } + + // Get this entities ROFF object + itrRoff = mROFFList.find( ((SROFFEntity *)(*itr))->mROFFID ); + + if ( itrRoff != mROFFList.end() ) + { // roff that baby! + if ( !ApplyROFF( ((SROFFEntity *)(*itr)), ((CROFF *)((*itrRoff).second )))) + { // done roffing, mark for death + ((SROFFEntity *)(*itr))->mKill = qtrue; + } + } + else + { // roff not found == bad, dump an error message and purge this ent + Com_Printf( S_COLOR_RED"ROFF System Error:\n" ); +// Com_Printf( S_COLOR_RED" -ROFF not found for entity <%s>\n", +// entitySystem->GetEntityFromID(((SROFFEntity *)(*itr))->mEntID)->GetName() ); + + ((SROFFEntity *)(*itr))->mKill = qtrue; + + ClearLerp( (*itr) ); + } + } + + itr = mROFFEntList.begin(); + + // Delete killed ROFFers from the list + // Man, there just has to be a better way to do this + while ( itr != mROFFEntList.end() ) + { + if ((*itr)->mIsClient != isClient) + { + itr++; + continue; + } + + if ( ((SROFFEntity *)(*itr))->mKill == qtrue ) + { + //make sure ICARUS knows ROFF is stopped +// CICARUSGameInterface::TaskIDComplete( +// entitySystem->GetEntityFromID(((SROFFEntity *)(*itr))->mEntID), TID_MOVE); + // trash this guy from the list + delete (*itr); + mROFFEntList.erase( itr ); + itr = mROFFEntList.begin(); + } + else + { + itr++; + } + } +} + +//--------------------------------------------------------------------------- +// CROFFSystem::ApplyROFF +// Does the dirty work of applying the raw ROFF data +// +// INPUTS: +// The the roff_entity struct and the raw roff data +// +// RETURN: +// True == success; False == roff playback complete or failure +//--------------------------------------------------------------------------- +qboolean CROFFSystem::ApplyROFF( SROFFEntity *roff_ent, CROFFSystem::CROFF *roff ) +{ + vec3_t f, r, u, result; + sharedEntity_t *ent = NULL; + trajectory_t *originTrajectory = NULL, *angleTrajectory = NULL; + float *origin = NULL, *angle = NULL; + + + if ( svs.time < roff_ent->mNextROFFTime ) + { // Not time to roff yet + return qtrue; + } + + if (roff_ent->mIsClient) + { +#ifndef DEDICATED + vec3_t originTemp, angleTemp; + originTrajectory = CGVM_GetOriginTrajectory( roff_ent->mEntID ); + angleTrajectory = CGVM_GetAngleTrajectory( roff_ent->mEntID ); + CGVM_GetOrigin( roff_ent->mEntID, originTemp ); + origin = originTemp; + CGVM_GetAngles( roff_ent->mEntID, angleTemp ); + angle = angleTemp; +#endif + } + else + { + // Find the entity to apply the roff to + ent = SV_GentityNum( roff_ent->mEntID ); + + if ( ent == 0 ) + { // bad stuff + return qfalse; + } + + originTrajectory = &ent->s.pos; + angleTrajectory = &ent->s.apos; + origin = ent->r.currentOrigin; + angle = ent->r.currentAngles; + } + + + if ( roff_ent->mROFFFrame >= roff->mROFFEntries ) + { // we are done roffing, so stop moving and flag this ent to be removed + SetLerp( originTrajectory, TR_STATIONARY, origin, NULL, svs.time, roff->mLerp ); + SetLerp( angleTrajectory, TR_STATIONARY, angle, NULL, svs.time, roff->mLerp ); + if (!roff_ent->mIsClient) + { + ent->r.mIsRoffing = qfalse; + } + return qfalse; + } + + if (roff_ent->mTranslated) + { + AngleVectors(roff_ent->mStartAngles, f, r, u ); + VectorScale(f, roff->mMoveRotateList[roff_ent->mROFFFrame].mOriginOffset[0], result); + VectorMA(result, -roff->mMoveRotateList[roff_ent->mROFFFrame].mOriginOffset[1], r, result); + VectorMA(result, roff->mMoveRotateList[roff_ent->mROFFFrame].mOriginOffset[2], u, result); + } + else + { + VectorCopy(roff->mMoveRotateList[roff_ent->mROFFFrame].mOriginOffset, result); + } + + // Set up our origin interpolation + SetLerp( originTrajectory, TR_LINEAR, origin, result, svs.time, roff->mLerp ); + + // Set up our angle interpolation + SetLerp( angleTrajectory, TR_LINEAR, angle, + roff->mMoveRotateList[roff_ent->mROFFFrame].mRotateOffset, svs.time, roff->mLerp ); + + if (roff->mMoveRotateList[roff_ent->mROFFFrame].mStartNote >= 0) + { + int i; + + for(i=0;imMoveRotateList[roff_ent->mROFFFrame].mNumNotes;i++) + { + ProcessNote(roff_ent, roff->mNoteTrackIndexes[roff->mMoveRotateList[roff_ent->mROFFFrame].mStartNote + i]); + } + } + + // Advance ROFF frames and lock to a 10hz cycle + roff_ent->mROFFFrame++; + roff_ent->mNextROFFTime = svs.time + roff->mFrameTime; + + //rww - npcs need to know when they're getting roff'd + if ( !roff_ent->mIsClient ) + ent->next_roff_time = roff_ent->mNextROFFTime; + + + return qtrue; +} + + +/************************************************************************************************ + * CROFFSystem::ProcessNote * + * This function will send the note to the client. It will parse through the note for * + * leading or trailing white space (thus making each line feed a separate function call). * + * * + * Input * + * ent: the entity for which the roff is being played * + * note: the note that should be passed on * + * * + * Output / Return * + * none * + * * + ************************************************************************************************/ +void CROFFSystem::ProcessNote(SROFFEntity *roff_ent, char *note) +{ + char temp[1024]; + int pos, size; + + pos = 0; + while(note[pos]) + { + size = 0; + while(note[pos] && note[pos] < ' ') + { + pos++; + } + + while(note[pos] && note[pos] >= ' ') + { + temp[size++] = note[pos++]; + } + temp[size] = 0; + + if (size) + { + if (roff_ent->mIsClient) + { +#ifndef DEDICATED + CGVM_ROFF_NotetrackCallback( roff_ent->mEntID, temp ); +#endif + } + else + { + GVM_ROFF_NotetrackCallback( roff_ent->mEntID, temp ); + } + } + } +} + +//--------------------------------------------------------------------------- +// CROFFSystem::ClearLerp +// Helper function to clear a given entities lerp fields +// +// INPUTS: +// The ID of the entity to clear +// +// RETURN: +// success or failure of the operation +//--------------------------------------------------------------------------- +qboolean CROFFSystem::ClearLerp( SROFFEntity *roff_ent ) +{ + sharedEntity_t *ent = NULL; + trajectory_t *originTrajectory = NULL, *angleTrajectory = NULL; + float *origin = NULL, *angle = NULL; + + if (roff_ent->mIsClient) + { +#ifndef DEDICATED + vec3_t originTemp, angleTemp; + originTrajectory = CGVM_GetOriginTrajectory( roff_ent->mEntID ); + angleTrajectory = CGVM_GetAngleTrajectory( roff_ent->mEntID ); + CGVM_GetOrigin( roff_ent->mEntID, originTemp ); + origin = originTemp; + CGVM_GetAngles( roff_ent->mEntID, angleTemp ); + angle = angleTemp; +#endif + } + else + { + // Find the entity to apply the roff to + ent = SV_GentityNum( roff_ent->mEntID ); + + if ( ent == 0 ) + { // bad stuff + return qfalse; + } + + originTrajectory = &ent->s.pos; + angleTrajectory = &ent->s.apos; + origin = ent->r.currentOrigin; + angle = ent->r.currentAngles; + } + + SetLerp( originTrajectory, TR_STATIONARY, origin, NULL, svs.time, ROFF_SAMPLE_RATE ); + SetLerp( angleTrajectory, TR_STATIONARY, angle, NULL, svs.time, ROFF_SAMPLE_RATE ); + + return qtrue; +} + +//--------------------------------------------------------------------------- +// CROFFSystem::SetLerp +// Helper function to set up a positional or angular interpolation +// +// INPUTS: +// The entity trajectory field to modify, the interpolation type, the base origin, +// and the interpolation start time +// +// RETURN: +// none +//--------------------------------------------------------------------------- +void CROFFSystem::SetLerp( trajectory_t *tr, trType_t type, vec3_t origin, vec3_t delta, int time, int rate) +{ + tr->trType = type; + tr->trTime = time; + VectorCopy( origin, tr->trBase ); + + // Check for a NULL delta + if ( delta ) + { + VectorScale( delta, rate, tr->trDelta ); + } + else + { + VectorClear( tr->trDelta ); + } +} + diff --git a/Projects/Android/jni/OpenJK/codemp_delete/qcommon/RoffSystem.h b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/RoffSystem.h new file mode 100644 index 0000000..23c1dd2 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/RoffSystem.h @@ -0,0 +1,192 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#pragma once + +#include "qcommon/q_shared.h" //needs to be in here for entityState_t +#include "server/server.h" + +#include +#include + +// ROFF Defines +//------------------- +#define ROFF_VERSION 1 +#define ROFF_NEW_VERSION 2 +#define ROFF_STRING "ROFF" +#define ROFF_SAMPLE_RATE 10 // 10hz +#define ROFF_AUTO_FIX_BAD_ANGLES // exporter can mess up angles, + // defining this attempts to detect and fix these problems + + +// The CROFFSystem object provides all of the functionality of ROFF +// caching, playback, and clean-up, plus some useful debug features. +//-------------------------------------- +class CROFFSystem +//-------------------------------------- +{ +private: +//------ + + // forward declarations + class CROFF; + struct SROFFEntity; + + typedef std::map TROFFList; + typedef std::vector TROFFEntList; + + TROFFList mROFFList; // List of cached roffs + int mID; // unique ID generator for new roff objects + + TROFFEntList mROFFEntList; // List of roffing entities + + // ROFF Header file definition, nothing else needs to see this + typedef struct tROFFHeader + //------------------------------- + { + char mHeader[4]; // should match roff_string defined above + long mVersion; // version num, supported version defined above + float mCount; // I think this is a float because of a limitation of the roff exporter + + } TROFFHeader; + + // ROFF Entry, nothing else needs to see this + typedef struct tROFFEntry + //------------------------------- + { + float mOriginOffset[3]; + float mRotateOffset[3]; + } TROFFEntry; + + typedef struct tROFF2Header + //------------------------------- + { + char mHeader[4]; // should match roff_string defined above + long mVersion; // version num, supported version defined above + int mCount; // I think this is a float because of a limitation of the roff exporter + int mFrameRate; // Frame rate the roff should be played at + int mNumNotes; // number of notes (null terminated strings) after the roff data + + } TROFF2Header; + + // ROFF Entry, nothing else needs to see this + typedef struct tROFF2Entry + //------------------------------- + { + float mOriginOffset[3]; + float mRotateOffset[3]; + int mStartNote, mNumNotes; // note track info + } TROFF2Entry; + + // An individual ROFF object, + // contains actual rotation/offset information + //-------------------------------------- + class CROFF + //-------------------------------------- + { + public: + //------ + + int mID; // id for this roff file + char mROFFFilePath[MAX_QPATH]; // roff file path + int mROFFEntries; // count of move/rotate commands + int mFrameTime; // frame rate + int mLerp; // Lerp rate (FPS) + TROFF2Entry *mMoveRotateList; // move rotate/command list + int mNumNoteTracks; + char **mNoteTrackIndexes; + qboolean mUsedByClient; + qboolean mUsedByServer; + + CROFF() + { + mUsedByClient = mUsedByServer = qfalse; + } + CROFF( const char *file, int id ); + ~CROFF(); + + }; // class CROFF + + + // The roff system tracks entities that are + // roffing, so this is the internal structure + // that represents these objects. + //-------------------------------------- + struct SROFFEntity + //-------------------------------------- + { + int mEntID; // the entity that is currently roffing + + int mROFFID; // the roff to be applied to that entity + int mNextROFFTime; // next time we should roff + int mROFFFrame; // current roff frame we are applying + + qboolean mKill; // flag to kill a roffing ent + qboolean mSignal; // TODO: Need to implement some sort of signal to Icarus when roff is done. + qboolean mTranslated; // should this roff be "rotated" to fit the entity's initial position? + qboolean mIsClient; + vec3_t mStartAngles; // initial angle of the entity + }; // struct SROFFEntity + + + qboolean IsROFF( byte *file ); // Makes sure the file is a valid roff file + qboolean InitROFF( byte *file, CROFF *obj ); // Handles stashing raw roff data into the roff object + qboolean InitROFF2( byte *file, CROFF *obj ); // Handles stashing raw roff data into the roff object + void FixBadAngles(CROFF *obj); + int NewID() { return ++mID; } // Increment before return so we can use zero as failed return val + qboolean ApplyROFF( SROFFEntity *roff_ent, + CROFFSystem::CROFF *roff ); // True = success; False = roff complete + + void ProcessNote(SROFFEntity *roff_ent, char *note); + + void SetLerp( trajectory_t *tr, + trType_t, vec3_t origin, + vec3_t delta, int time, int rate ); + + qboolean ClearLerp( SROFFEntity *roff_ent ); // Clears out the angular and position lerp fields + +public: +//------ + + CROFFSystem() { mID = 0; mROFFEntList.clear(); } + ~CROFFSystem() { Restart(); } + + + qboolean Restart(); // Free up all system resources and reset the ID counter + + int Cache( const char *file, qboolean isClient ); // roffs should be precached at the start of each level + int GetID( const char *file ); // find the roff id by filename + qboolean Unload( int id ); // when a roff is done, it can be removed to free up resources + qboolean Clean(qboolean isClient); // should be called when level is done, frees all roff resources + void List(void); // dumps a list of all cached roff files to the console + qboolean List( int id ); // dumps the contents of the specified roff to the console + + qboolean Play( int entID, int roffID, qboolean doTranslation, qboolean isClient); // TODO: implement signal on playback completion. + void ListEnts(); // List the entities that are currently roffing + qboolean PurgeEnt( int entID, qboolean isClient ); // Purge the specified entity from the entity list by id + qboolean PurgeEnt( char *file ); // Purge the specified entity from the entity list by name + void UpdateEntities(qboolean isClient); // applys roff data to roffing entities. + +}; // class CROFFSystem + + +extern CROFFSystem theROFFSystem; diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/cm_load.cpp b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/cm_load.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/cm_load.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/cm_load.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/cm_local.h b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/cm_local.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/cm_local.h rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/cm_local.h diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/cm_patch.cpp b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/cm_patch.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/cm_patch.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/cm_patch.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/cm_patch.h b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/cm_patch.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/cm_patch.h rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/cm_patch.h diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/cm_polylib.cpp b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/cm_polylib.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/cm_polylib.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/cm_polylib.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/cm_polylib.h b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/cm_polylib.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/cm_polylib.h rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/cm_polylib.h diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/cm_public.h b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/cm_public.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/cm_public.h rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/cm_public.h diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/cm_test.cpp b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/cm_test.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/cm_test.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/cm_test.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/cm_trace.cpp b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/cm_trace.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/cm_trace.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/cm_trace.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/cmd.cpp b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/cmd.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/cmd.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/cmd.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/common.cpp b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/common.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/common.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/common.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/cvar.cpp b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/cvar.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/cvar.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/cvar.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/disablewarnings.h b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/disablewarnings.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/disablewarnings.h rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/disablewarnings.h diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/files.cpp b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/files.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/files.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/files.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/game_version.h b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/game_version.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/game_version.h rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/game_version.h diff --git a/Projects/Android/jni/OpenJK/codemp_delete/qcommon/huffman.cpp b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/huffman.cpp new file mode 100644 index 0000000..a08e5fa --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/huffman.cpp @@ -0,0 +1,437 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +/* This is based on the Adaptive Huffman algorithm described in Sayood's Data + * Compression book. The ranks are not actually stored, but implicitly defined + * by the location of a node within a doubly-linked list */ + +#include "qcommon/qcommon.h" + +static int bloc = 0; + +void Huff_putBit( int bit, byte *fout, int *offset) { + bloc = *offset; + if ((bloc&7) == 0) { + fout[(bloc>>3)] = 0; + } + fout[(bloc>>3)] |= bit << (bloc&7); + bloc++; + *offset = bloc; +} + +int Huff_getBit( byte *fin, int *offset) { + int t; + bloc = *offset; + t = (fin[(bloc>>3)] >> (bloc&7)) & 0x1; + bloc++; + *offset = bloc; + return t; +} + +/* Add a bit to the output file (buffered) */ +static void add_bit (char bit, byte *fout) { + if ((bloc&7) == 0) { + fout[(bloc>>3)] = 0; + } + fout[(bloc>>3)] |= bit << (bloc&7); + bloc++; +} + +/* Receive one bit from the input file (buffered) */ +static int get_bit (byte *fin) { + int t; + t = (fin[(bloc>>3)] >> (bloc&7)) & 0x1; + bloc++; + return t; +} + +static node_t **get_ppnode(huff_t* huff) { + node_t **tppnode; + if (!huff->freelist) { + return &(huff->nodePtrs[huff->blocPtrs++]); + } else { + tppnode = huff->freelist; + huff->freelist = (node_t **)*tppnode; + return tppnode; + } +} + +static void free_ppnode(huff_t* huff, node_t **ppnode) { + *ppnode = (node_t *)huff->freelist; + huff->freelist = ppnode; +} + +/* Swap the location of these two nodes in the tree */ +static void swap (huff_t* huff, node_t *node1, node_t *node2) { + node_t *par1, *par2; + + par1 = node1->parent; + par2 = node2->parent; + + if (par1) { + if (par1->left == node1) { + par1->left = node2; + } else { + par1->right = node2; + } + } else { + huff->tree = node2; + } + + if (par2) { + if (par2->left == node2) { + par2->left = node1; + } else { + par2->right = node1; + } + } else { + huff->tree = node1; + } + + node1->parent = par2; + node2->parent = par1; +} + +/* Swap these two nodes in the linked list (update ranks) */ +static void swaplist(node_t *node1, node_t *node2) { + node_t *par1; + + par1 = node1->next; + node1->next = node2->next; + node2->next = par1; + + par1 = node1->prev; + node1->prev = node2->prev; + node2->prev = par1; + + if (node1->next == node1) { + node1->next = node2; + } + if (node2->next == node2) { + node2->next = node1; + } + if (node1->next) { + node1->next->prev = node1; + } + if (node2->next) { + node2->next->prev = node2; + } + if (node1->prev) { + node1->prev->next = node1; + } + if (node2->prev) { + node2->prev->next = node2; + } +} + +/* Do the increments */ +static void increment(huff_t* huff, node_t *node) { + node_t *lnode; + + if (!node) { + return; + } + + if (node->next != NULL && node->next->weight == node->weight) { + lnode = *node->head; + if (lnode != node->parent) { + swap(huff, lnode, node); + } + swaplist(lnode, node); + } + if (node->prev && node->prev->weight == node->weight) { + *node->head = node->prev; + } else { + *node->head = NULL; + free_ppnode(huff, node->head); + } + node->weight++; + if (node->next && node->next->weight == node->weight) { + node->head = node->next->head; + } else { + node->head = get_ppnode(huff); + *node->head = node; + } + if (node->parent) { + increment(huff, node->parent); + if (node->prev == node->parent) { + swaplist(node, node->parent); + if (*node->head == node) { + *node->head = node->parent; + } + } + } +} + +void Huff_addRef(huff_t* huff, byte ch) { + node_t *tnode, *tnode2; + if (huff->loc[ch] == NULL) { /* if this is the first transmission of this node */ + tnode = &(huff->nodeList[huff->blocNode++]); + tnode2 = &(huff->nodeList[huff->blocNode++]); + + tnode2->symbol = INTERNAL_NODE; + tnode2->weight = 1; + tnode2->next = huff->lhead->next; + if (huff->lhead->next) { + huff->lhead->next->prev = tnode2; + if (huff->lhead->next->weight == 1) { + tnode2->head = huff->lhead->next->head; + } else { + tnode2->head = get_ppnode(huff); + *tnode2->head = tnode2; + } + } else { + tnode2->head = get_ppnode(huff); + *tnode2->head = tnode2; + } + huff->lhead->next = tnode2; + tnode2->prev = huff->lhead; + + tnode->symbol = ch; + tnode->weight = 1; + tnode->next = huff->lhead->next; + if (huff->lhead->next) { + huff->lhead->next->prev = tnode; + if (huff->lhead->next->weight == 1) { + tnode->head = huff->lhead->next->head; + } else { + /* this should never happen */ + tnode->head = get_ppnode(huff); + *tnode->head = tnode2; + } + } else { + /* this should never happen */ + tnode->head = get_ppnode(huff); + *tnode->head = tnode; + } + huff->lhead->next = tnode; + tnode->prev = huff->lhead; + tnode->left = tnode->right = NULL; + + if (huff->lhead->parent) { + if (huff->lhead->parent->left == huff->lhead) { /* lhead is guaranteed to by the NYT */ + huff->lhead->parent->left = tnode2; + } else { + huff->lhead->parent->right = tnode2; + } + } else { + huff->tree = tnode2; + } + + tnode2->right = tnode; + tnode2->left = huff->lhead; + + tnode2->parent = huff->lhead->parent; + huff->lhead->parent = tnode->parent = tnode2; + + huff->loc[ch] = tnode; + + increment(huff, tnode2->parent); + } else { + increment(huff, huff->loc[ch]); + } +} + +/* Get a symbol */ +int Huff_Receive (node_t *node, int *ch, byte *fin) { + while (node && node->symbol == INTERNAL_NODE) { + if (get_bit(fin)) { + node = node->right; + } else { + node = node->left; + } + } + if (!node) { + return 0; +// Com_Error(ERR_DROP, "Illegal tree!\n"); + } + return (*ch = node->symbol); +} + +/* Get a symbol */ +void Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset) { + bloc = *offset; + while (node && node->symbol == INTERNAL_NODE) { + if (get_bit(fin)) { + node = node->right; + } else { + node = node->left; + } + } + if (!node) { + *ch = 0; + return; +// Com_Error(ERR_DROP, "Illegal tree!\n"); + } + *ch = node->symbol; + *offset = bloc; +} + +/* Send the prefix code for this node */ +static void send(node_t *node, node_t *child, byte *fout) { + if (node->parent) { + send(node->parent, node, fout); + } + if (child) { + if (node->right == child) { + add_bit(1, fout); + } else { + add_bit(0, fout); + } + } +} + +/* Send a symbol */ +void Huff_transmit (huff_t *huff, int ch, byte *fout) { + int i; + if (huff->loc[ch] == NULL) { + /* node_t hasn't been transmitted, send a NYT, then the symbol */ + Huff_transmit(huff, NYT, fout); + for (i = 7; i >= 0; i--) { + add_bit((char)((ch >> i) & 0x1), fout); + } + } else { + send(huff->loc[ch], NULL, fout); + } +} + +void Huff_offsetTransmit (huff_t *huff, int ch, byte *fout, int *offset) { + bloc = *offset; + send(huff->loc[ch], NULL, fout); + *offset = bloc; +} + +void Huff_Decompress(msg_t *mbuf, int offset) { + int ch, cch, i, j, size; + byte seq[65536]; + byte* buffer; + huff_t huff; + + size = mbuf->cursize - offset; + buffer = mbuf->data + offset; + + if ( size <= 0 ) { + return; + } + + Com_Memset(&huff, 0, sizeof(huff_t)); + // Initialize the tree & list with the NYT node + huff.tree = huff.lhead = huff.ltail = huff.loc[NYT] = &(huff.nodeList[huff.blocNode++]); + huff.tree->symbol = NYT; + huff.tree->weight = 0; + huff.lhead->next = huff.lhead->prev = NULL; + huff.tree->parent = huff.tree->left = huff.tree->right = NULL; + + cch = buffer[0]*256 + buffer[1]; + // don't overflow with bad messages + if ( cch > mbuf->maxsize - offset ) { + cch = mbuf->maxsize - offset; + } + bloc = 16; + + for ( j = 0; j < cch; j++ ) { + ch = 0; + // don't overflow reading from the messages + // FIXME: would it be better to have a overflow check in get_bit ? + if ( (bloc >> 3) > size ) { + seq[j] = 0; + break; + } + Huff_Receive(huff.tree, &ch, buffer); /* Get a character */ + if ( ch == NYT ) { /* We got a NYT, get the symbol associated with it */ + ch = 0; + for ( i = 0; i < 8; i++ ) { + ch = (ch<<1) + get_bit(buffer); + } + } + + seq[j] = ch; /* Write symbol */ + + Huff_addRef(&huff, (byte)ch); /* Increment node */ + } + mbuf->cursize = cch + offset; + Com_Memcpy(mbuf->data + offset, seq, cch); +} + +extern int oldsize; + +void Huff_Compress(msg_t *mbuf, int offset) { + int i, ch, size; + byte seq[65536]; + byte* buffer; + huff_t huff; + + size = mbuf->cursize - offset; + buffer = mbuf->data+ + offset; + + if (size<=0) { + return; + } + + Com_Memset(&huff, 0, sizeof(huff_t)); + // Add the NYT (not yet transmitted) node into the tree/list */ + huff.tree = huff.lhead = huff.loc[NYT] = &(huff.nodeList[huff.blocNode++]); + huff.tree->symbol = NYT; + huff.tree->weight = 0; + huff.lhead->next = huff.lhead->prev = NULL; + huff.tree->parent = huff.tree->left = huff.tree->right = NULL; + huff.loc[NYT] = huff.tree; + + seq[0] = (size>>8); + seq[1] = size&0xff; + + bloc = 16; + + for (i=0; icursize = (bloc>>3) + offset; + Com_Memcpy(mbuf->data+offset, seq, (bloc>>3)); +} + +void Huff_Init(huffman_t *huff) { + + Com_Memset(&huff->compressor, 0, sizeof(huff_t)); + Com_Memset(&huff->decompressor, 0, sizeof(huff_t)); + + // Initialize the tree & list with the NYT node + huff->decompressor.tree = huff->decompressor.lhead = huff->decompressor.ltail = huff->decompressor.loc[NYT] = &(huff->decompressor.nodeList[huff->decompressor.blocNode++]); + huff->decompressor.tree->symbol = NYT; + huff->decompressor.tree->weight = 0; + huff->decompressor.lhead->next = huff->decompressor.lhead->prev = NULL; + huff->decompressor.tree->parent = huff->decompressor.tree->left = huff->decompressor.tree->right = NULL; + + // Add the NYT (not yet transmitted) node into the tree/list */ + huff->compressor.tree = huff->compressor.lhead = huff->compressor.loc[NYT] = &(huff->compressor.nodeList[huff->compressor.blocNode++]); + huff->compressor.tree->symbol = NYT; + huff->compressor.tree->weight = 0; + huff->compressor.lhead->next = huff->compressor.lhead->prev = NULL; + huff->compressor.tree->parent = huff->compressor.tree->left = huff->compressor.tree->right = NULL; + huff->compressor.loc[NYT] = huff->compressor.tree; +} + diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/matcomp.cpp b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/matcomp.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/matcomp.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/matcomp.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/matcomp.h b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/matcomp.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/matcomp.h rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/matcomp.h diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/md4.cpp b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/md4.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/md4.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/md4.cpp diff --git a/Projects/Android/jni/OpenJK/codemp_delete/qcommon/md5.cpp b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/md5.cpp new file mode 100644 index 0000000..8bb307d --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/md5.cpp @@ -0,0 +1,354 @@ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * An implementation of HMAC-MD5 (originally for OpenJK) is also + * provided, and also released into the public domain. + */ + +#include "md5.h" +#include "qcommon.h" + +#ifndef Q3_BIG_ENDIAN + #define byteReverse(buf, len) /* Nothing */ +#else + static void byteReverse(unsigned char *buf, unsigned longs); + + /* + * Note: this code is harmless on little-endian machines. + */ + static void byteReverse(unsigned char *buf, unsigned longs) + { + uint32_t t; + do { + t = (uint32_t) + ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(uint32_t *) buf = t; + buf += 4; + } while (--longs); + } +#endif // Q3_BIG_ENDIAN + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) +{ + uint32_t a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len) +{ + uint32_t t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32_t *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32_t *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void MD5Final(struct MD5Context *ctx, unsigned char *digest) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32_t *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((uint32_t *) ctx->in)[14] = ctx->bits[0]; + ((uint32_t *) ctx->in)[15] = ctx->bits[1]; + + MD5Transform(ctx->buf, (uint32_t *) ctx->in); + byteReverse((unsigned char *) ctx->buf, 4); + + if (digest!=NULL) + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ +} + +char *Com_MD5File( const char *fn, int length, const char *prefix, int prefix_len ) +{ + static char final[33] = {""}; + unsigned char digest[16] = {""}; + fileHandle_t f; + MD5_CTX md5; + byte buffer[2048]; + int i; + int filelen = 0; + int r = 0; + int total = 0; + + Q_strncpyz( final, "", sizeof( final ) ); + + filelen = FS_SV_FOpenFileRead( fn, &f ); + + if( !f ) { + return final; + } + if( filelen < 1 ) { + FS_FCloseFile( f ); + return final; + } + if(filelen < length || !length) { + length = filelen; + } + + MD5Init(&md5); + + if( prefix_len && *prefix ) + MD5Update(&md5 , (unsigned char *)prefix, prefix_len); + + for(;;) { + r = FS_Read(buffer, sizeof(buffer), f); + if(r < 1) + break; + if(r + total > length) + r = length - total; + total += r; + MD5Update(&md5 , buffer, r); + if(r < (int)sizeof(buffer) || total >= length) + break; + } + FS_FCloseFile(f); + MD5Final(&md5, digest); + final[0] = '\0'; + for(i = 0; i < 16; i++) { + Q_strcat(final, sizeof(final), va("%02X", digest[i])); + } + return final; +} + +/* + * The following code implements HMAC-MD5 using the public domain MD5 implementation above. + * This code (originally for OpenJK) is also released into the public domain. + */ + +void HMAC_MD5_Init(hmacMD5Context_t *ctx, unsigned char const *key, unsigned int keylen) +{ + unsigned char shortenedKey[MD5_DIGEST_SIZE]; + if (keylen > MD5_BLOCK_SIZE) { + MD5Init(&ctx->md5Context); + MD5Update(&ctx->md5Context, key, keylen); + MD5Final(&ctx->md5Context, shortenedKey); + key = shortenedKey; + keylen = MD5_DIGEST_SIZE; + } + + for (unsigned int i = 0; i < keylen; i++) { + ctx->iKeyPad[i] = 0x36 ^ key[i]; + ctx->oKeyPad[i] = 0x5C ^ key[i]; + } + memset(&ctx->iKeyPad[keylen], 0x36, sizeof(ctx->iKeyPad) - keylen); + memset(&ctx->oKeyPad[keylen], 0x5C, sizeof(ctx->oKeyPad) - keylen); + + MD5Init(&ctx->md5Context); + MD5Update(&ctx->md5Context, ctx->iKeyPad, sizeof(ctx->iKeyPad)); +} + +void HMAC_MD5_Update(hmacMD5Context_t *ctx, unsigned char const *buf, unsigned int len) +{ + MD5Update(&ctx->md5Context, buf, len); +} + +void HMAC_MD5_Final(hmacMD5Context_t *ctx, unsigned char *digest) +{ + unsigned char hashSum1[MD5_DIGEST_SIZE]; + MD5Final(&ctx->md5Context, hashSum1); + + MD5Init(&ctx->md5Context); + MD5Update(&ctx->md5Context, ctx->oKeyPad, sizeof(ctx->oKeyPad)); + MD5Update(&ctx->md5Context, hashSum1, sizeof(hashSum1)); + MD5Final(&ctx->md5Context, digest); +} + +void HMAC_MD5_Reset(hmacMD5Context_t *ctx) +{ + MD5Init(&ctx->md5Context); + MD5Update(&ctx->md5Context, ctx->iKeyPad, sizeof(ctx->iKeyPad)); +} \ No newline at end of file diff --git a/Projects/Android/jni/OpenJK/codemp_delete/qcommon/md5.h b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/md5.h new file mode 100644 index 0000000..ff2a84c --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/md5.h @@ -0,0 +1,54 @@ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * An implementation of HMAC-MD5 (originally for OpenJK) is also + * provided, and also released into the public domain. + */ + +#pragma once + +#include "q_shared.h" + +typedef struct MD5Context { + uint32_t buf[4]; + uint32_t bits[2]; + unsigned char in[64]; +} MD5_CTX; + +void MD5Init(struct MD5Context *ctx); +void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len); +void MD5Final(struct MD5Context *ctx, unsigned char *digest); + +const size_t MD5_BLOCK_SIZE = 64; +const size_t MD5_DIGEST_SIZE = 16; +typedef struct { + struct MD5Context md5Context; + unsigned char iKeyPad[MD5_BLOCK_SIZE]; + unsigned char oKeyPad[MD5_BLOCK_SIZE]; +} hmacMD5Context_t; + +// Initialize a new HMAC-MD5 construct using the specified secret key. +void HMAC_MD5_Init(hmacMD5Context_t *ctx, unsigned char const *key, unsigned int keylen); + +// Update the HMAC message with len number of bytes from the given buffer. +void HMAC_MD5_Update(hmacMD5Context_t *ctx, unsigned char const *buf, unsigned int len); + +// Finalize the HMAC calculation and fill the given buffer with the digest bytes. +// 'digest' must point to a buffer that can hold MD5_DIGEST_SIZE bytes! +void HMAC_MD5_Final(hmacMD5Context_t *ctx, unsigned char *digest); + +// Reset the context to begin working on a new message, using the same secret key as previously initialised. +void HMAC_MD5_Reset(hmacMD5Context_t *ctx); \ No newline at end of file diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/msg.cpp b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/msg.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/msg.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/msg.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/net_chan.cpp b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/net_chan.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/net_chan.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/net_chan.cpp diff --git a/Projects/Android/jni/OpenJK/codemp_delete/qcommon/net_ip.cpp b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/net_ip.cpp new file mode 100644 index 0000000..bf72ebc --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/net_ip.cpp @@ -0,0 +1,1085 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2005 - 2015, ioquake3 contributors +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#include "qcommon/qcommon.h" + +#ifdef _WIN32 + #include + + typedef int socklen_t; + + #undef EAGAIN + #undef EADDRNOTAVAIL + #undef EAFNOSUPPORT + #undef ECONNRESET + + #define EAGAIN WSAEWOULDBLOCK + #define EADDRNOTAVAIL WSAEADDRNOTAVAIL + #define EAFNOSUPPORT WSAEAFNOSUPPORT + #define ECONNRESET WSAECONNRESET + + #define socketError WSAGetLastError( ) + + static WSADATA winsockdata; + static qboolean winsockInitialized = qfalse; +#else + +#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020 + // needed for socklen_t on OSX 10.2 +# define _BSD_SOCKLEN_T_ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef MACOS_X +#include +#include +#include +#include // for 'struct sockaddr_dl' +#endif + +#ifdef __sun +#include +#endif + +typedef int SOCKET; +#define INVALID_SOCKET -1 +#define SOCKET_ERROR -1 +#define closesocket close +#define ioctlsocket ioctl +#define socketError errno + +#endif + +static qboolean usingSocks = qfalse; +static qboolean networkingEnabled = qfalse; + +static cvar_t *net_enabled; +static cvar_t *net_forcenonlocal; + +static cvar_t *net_socksEnabled; +static cvar_t *net_socksServer; +static cvar_t *net_socksPort; +static cvar_t *net_socksUsername; +static cvar_t *net_socksPassword; + +static cvar_t *net_ip; +static cvar_t *net_port; + +static cvar_t *net_dropsim; + +static struct sockaddr_in socksRelayAddr; + +static SOCKET ip_socket = INVALID_SOCKET; +static SOCKET socks_socket = INVALID_SOCKET; + +#define MAX_IPS 16 +static int numIP; +static byte localIP[MAX_IPS][4]; + +//============================================================================= + +/* +==================== +NET_ErrorString +==================== +*/ +char *NET_ErrorString( void ) { +#ifdef _WIN32 + switch( socketError ) { + case WSAEINTR: return "WSAEINTR"; + case WSAEBADF: return "WSAEBADF"; + case WSAEACCES: return "WSAEACCES"; + case WSAEDISCON: return "WSAEDISCON"; + case WSAEFAULT: return "WSAEFAULT"; + case WSAEINVAL: return "WSAEINVAL"; + case WSAEMFILE: return "WSAEMFILE"; + case WSAEWOULDBLOCK: return "WSAEWOULDBLOCK"; + case WSAEINPROGRESS: return "WSAEINPROGRESS"; + case WSAEALREADY: return "WSAEALREADY"; + case WSAENOTSOCK: return "WSAENOTSOCK"; + case WSAEDESTADDRREQ: return "WSAEDESTADDRREQ"; + case WSAEMSGSIZE: return "WSAEMSGSIZE"; + case WSAEPROTOTYPE: return "WSAEPROTOTYPE"; + case WSAENOPROTOOPT: return "WSAENOPROTOOPT"; + case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT"; + case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT"; + case WSAEOPNOTSUPP: return "WSAEOPNOTSUPP"; + case WSAEPFNOSUPPORT: return "WSAEPFNOSUPPORT"; + case WSAEAFNOSUPPORT: return "WSAEAFNOSUPPORT"; + case WSAEADDRINUSE: return "WSAEADDRINUSE"; + case WSAEADDRNOTAVAIL: return "WSAEADDRNOTAVAIL"; + case WSAENETDOWN: return "WSAENETDOWN"; + case WSAENETUNREACH: return "WSAENETUNREACH"; + case WSAENETRESET: return "WSAENETRESET"; + case WSAECONNABORTED: return "WSWSAECONNABORTEDAEINTR"; + case WSAECONNRESET: return "WSAECONNRESET"; + case WSAENOBUFS: return "WSAENOBUFS"; + case WSAEISCONN: return "WSAEISCONN"; + case WSAENOTCONN: return "WSAENOTCONN"; + case WSAESHUTDOWN: return "WSAESHUTDOWN"; + case WSAETOOMANYREFS: return "WSAETOOMANYREFS"; + case WSAETIMEDOUT: return "WSAETIMEDOUT"; + case WSAECONNREFUSED: return "WSAECONNREFUSED"; + case WSAELOOP: return "WSAELOOP"; + case WSAENAMETOOLONG: return "WSAENAMETOOLONG"; + case WSAEHOSTDOWN: return "WSAEHOSTDOWN"; + case WSASYSNOTREADY: return "WSASYSNOTREADY"; + case WSAVERNOTSUPPORTED: return "WSAVERNOTSUPPORTED"; + case WSANOTINITIALISED: return "WSANOTINITIALISED"; + case WSAHOST_NOT_FOUND: return "WSAHOST_NOT_FOUND"; + case WSATRY_AGAIN: return "WSATRY_AGAIN"; + case WSANO_RECOVERY: return "WSANO_RECOVERY"; + case WSANO_DATA: return "WSANO_DATA"; + case WSAEHOSTUNREACH: return "WSAEHOSTUNREACH"; + default: return "NO ERROR"; + } +#else + return strerror ( socketError ); +#endif +} + +static void NetadrToSockadr( netadr_t *a, struct sockaddr_in *s ) { + memset( s, 0, sizeof(*s) ); + + if( a->type == NA_BROADCAST ) { + s->sin_family = AF_INET; + s->sin_port = a->port; + s->sin_addr.s_addr = INADDR_BROADCAST; + } + else if( a->type == NA_IP ) { + s->sin_family = AF_INET; + memcpy( &s->sin_addr, a->ip, sizeof(s->sin_addr) ); + s->sin_port = a->port; + } +} + +static void SockadrToNetadr( struct sockaddr_in *s, netadr_t *a ) { + assert(s->sin_family == AF_INET); + a->type = NA_IP; + memcpy( a->ip, &s->sin_addr, sizeof(a->ip) ); + a->port = s->sin_port; +} + +/* +============= +Sys_StringToSockaddr +============= +*/ +static qboolean Sys_StringToSockaddr( const char *s, struct sockaddr_in *sadr ) +{ + struct hostent *h; + + memset( sadr, 0, sizeof( *sadr ) ); + + sadr->sin_family = AF_INET; + sadr->sin_port = 0; + + if( s[0] >= '0' && s[0] <= '9' ) + { + sadr->sin_addr.s_addr = inet_addr(s); + } + else + { + if( ( h = gethostbyname( s ) ) == 0 ) + return qfalse; + sadr->sin_addr.s_addr = *(uint32_t *)h->h_addr_list[0]; + } + + return qtrue; +} + +/* +============= +Sys_StringToAdr +============= +*/ +qboolean Sys_StringToAdr( const char *s, netadr_t *a ) { + struct sockaddr_in sadr; + + if ( !Sys_StringToSockaddr( s, &sadr ) ) { + return qfalse; + } + + SockadrToNetadr( &sadr, a ); + return qtrue; +} + +//============================================================================= + +/* +================== +NET_GetPacket + +Receive one packet +================== +*/ +#ifdef _DEBUG +int recvfromCount; +#endif + +qboolean NET_GetPacket( netadr_t *net_from, msg_t *net_message, fd_set *fdr ) { + int ret, err; + socklen_t fromlen; + struct sockaddr_in from; + + if ( ip_socket == INVALID_SOCKET || !FD_ISSET(ip_socket, fdr) ) { + return qfalse; + } + + fromlen = sizeof( from ); +#ifdef _DEBUG + recvfromCount++; // performance check +#endif + ret = recvfrom( ip_socket, (char *)net_message->data, net_message->maxsize, 0, (struct sockaddr *)&from, &fromlen ); + + if ( ret == SOCKET_ERROR ) { + err = socketError; + + if( err == EAGAIN || err == ECONNRESET ) + return qfalse; + + Com_Printf( "NET_GetPacket: %s\n", NET_ErrorString() ); + return qfalse; + } + + memset( from.sin_zero, 0, 8 ); + + if ( usingSocks && memcmp( &from, &socksRelayAddr, fromlen ) == 0 ) { + if ( ret < 10 || net_message->data[0] != 0 || net_message->data[1] != 0 || net_message->data[2] != 0 || net_message->data[3] != 1 ) { + return qfalse; + } + net_from->type = NA_IP; + net_from->ip[0] = net_message->data[4]; + net_from->ip[1] = net_message->data[5]; + net_from->ip[2] = net_message->data[6]; + net_from->ip[3] = net_message->data[7]; + memcpy( &net_from->port, &net_message->data[8], 2 ); + net_message->readcount = 10; + } + else { + SockadrToNetadr( &from, net_from ); + net_message->readcount = 0; + } + + if( ret >= net_message->maxsize ) { + Com_Printf( "Oversize packet from %s\n", NET_AdrToString (*net_from) ); + return qfalse; + } + + net_message->cursize = ret; + return qtrue; +} + +//============================================================================= + +static char socksBuf[4096]; + +/* +================== +Sys_SendPacket +================== +*/ +void Sys_SendPacket( int length, const void *data, netadr_t to ) { + int ret; + struct sockaddr_in addr; + + if ( to.type != NA_BROADCAST && to.type != NA_IP ) { + Com_Error( ERR_FATAL, "Sys_SendPacket: bad address type" ); + return; + } + + if ( ip_socket == INVALID_SOCKET ) { + return; + } + + NetadrToSockadr( &to, &addr ); + + if( usingSocks && to.type == NA_IP ) { + socksBuf[0] = 0; // reserved + socksBuf[1] = 0; + socksBuf[2] = 0; // fragment (not fragmented) + socksBuf[3] = 1; // address type: IPV4 + memcpy( &socksBuf[4], &addr.sin_addr, 4 ); + memcpy( &socksBuf[8], &addr.sin_port, 2 ); + memcpy( &socksBuf[10], data, length ); + ret = sendto( ip_socket, socksBuf, length+10, 0, (sockaddr *)&socksRelayAddr, sizeof(socksRelayAddr) ); + } + else { + ret = sendto( ip_socket, (const char *)data, length, 0, (sockaddr *)&addr, sizeof(addr) ); + } + if( ret == SOCKET_ERROR ) { + int err = socketError; + + // wouldblock is silent + if( err == EAGAIN ) { + return; + } + + // some PPP links do not allow broadcasts and return an error + if( err == EADDRNOTAVAIL && to.type == NA_BROADCAST ) { + return; + } + + Com_Printf( "NET_SendPacket: %s\n", NET_ErrorString() ); + } +} + +//============================================================================= + +/* +================== +Sys_IsLANAddress + +LAN clients will have their rate var ignored +================== +*/ +qboolean Sys_IsLANAddress( netadr_t adr ) { + if ( !net_forcenonlocal ) + net_forcenonlocal = Cvar_Get( "net_forcenonlocal", "0", 0 ); + + if ( net_forcenonlocal && net_forcenonlocal->integer ) + return qfalse; + + if( adr.type == NA_LOOPBACK ) + return qtrue; + + if( adr.type != NA_IP ) + return qfalse; + + // RFC1918: + // 10.0.0.0 - 10.255.255.255 (10/8 prefix) + // 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) + // 192.168.0.0 - 192.168.255.255 (192.168/16 prefix) + if ( adr.ip[0] == 10 ) + return qtrue; + if ( adr.ip[0] == 172 && (adr.ip[1]&0xf0) == 16 ) + return qtrue; + if ( adr.ip[0] == 192 && adr.ip[1] == 168 ) + return qtrue; + + if ( adr.ip[0] == 127 ) + return qtrue; + + // choose which comparison to use based on the class of the address being tested + // any local adresses of a different class than the address being tested will fail based on the first byte + + // Class C + for ( int i=0; istring ); + if ( h == NULL ) { + Com_Printf( "WARNING: NET_OpenSocks: gethostbyname: %s\n", NET_ErrorString() ); + return; + } + if ( h->h_addrtype != AF_INET ) { + Com_Printf( "WARNING: NET_OpenSocks: gethostbyname: address type was not AF_INET\n" ); + return; + } + memset( &address, 0, sizeof( address ) ); + address.sin_family = AF_INET; + address.sin_addr.s_addr = *(uint32_t *)h->h_addr_list[0]; + address.sin_port = htons( net_socksPort->integer ); + + if ( connect( socks_socket, (struct sockaddr *)&address, sizeof( address ) ) == SOCKET_ERROR ) { + Com_Printf( "NET_OpenSocks: connect: %s\n", NET_ErrorString() ); + return; + } + + // send socks authentication handshake + if ( *net_socksUsername->string || *net_socksPassword->string ) { + rfc1929 = qtrue; + } + else { + rfc1929 = qfalse; + } + + buf[0] = 5; // SOCKS version + // method count + if ( rfc1929 ) { + buf[1] = 2; + len = 4; + } + else { + buf[1] = 1; + len = 3; + } + buf[2] = 0; // method #1 - method id #00: no authentication + if ( rfc1929 ) { + buf[2] = 2; // method #2 - method id #02: username/password + } + if ( send( socks_socket, (const char *)buf, len, 0 ) == SOCKET_ERROR ) { + Com_Printf( "NET_OpenSocks: send: %s\n", NET_ErrorString() ); + return; + } + + // get the response + len = recv( socks_socket, (char *)buf, 64, 0 ); + if ( len == SOCKET_ERROR ) { + Com_Printf( "NET_OpenSocks: recv: %s\n", NET_ErrorString() ); + return; + } + if ( len != 2 || buf[0] != 5 ) { + Com_Printf( "NET_OpenSocks: bad response\n" ); + return; + } + switch( buf[1] ) { + case 0: // no authentication + break; + case 2: // username/password authentication + break; + default: + Com_Printf( "NET_OpenSocks: request denied\n" ); + return; + } + + // do username/password authentication if needed + if ( buf[1] == 2 ) { + int ulen; + int plen; + + // build the request + ulen = strlen( net_socksUsername->string ); + plen = strlen( net_socksPassword->string ); + + buf[0] = 1; // username/password authentication version + buf[1] = ulen; + if ( ulen ) { + memcpy( &buf[2], net_socksUsername->string, ulen ); + } + buf[2 + ulen] = plen; + if ( plen ) { + memcpy( &buf[3 + ulen], net_socksPassword->string, plen ); + } + + // send it + if ( send( socks_socket, (const char *)buf, 3 + ulen + plen, 0 ) == SOCKET_ERROR ) { + Com_Printf( "NET_OpenSocks: send: %s\n", NET_ErrorString() ); + return; + } + + // get the response + len = recv( socks_socket, (char *)buf, 64, 0 ); + if ( len == SOCKET_ERROR ) { + Com_Printf( "NET_OpenSocks: recv: %s\n", NET_ErrorString() ); + return; + } + if ( len != 2 || buf[0] != 1 ) { + Com_Printf( "NET_OpenSocks: bad response\n" ); + return; + } + if ( buf[1] != 0 ) { + Com_Printf( "NET_OpenSocks: authentication failed\n" ); + return; + } + } + + // send the UDP associate request + buf[0] = 5; // SOCKS version + buf[1] = 3; // command: UDP associate + buf[2] = 0; // reserved + buf[3] = 1; // address type: IPV4 + const uint32_t innadr = INADDR_ANY; // 0.0.0.0 + memcpy( &buf[4], &innadr, 4 ); + uint16_t networkOrderPort = htons( port ); // port + memcpy( &buf[8], &networkOrderPort, 2 ); + if ( send( socks_socket, (const char *)buf, 10, 0 ) == SOCKET_ERROR ) { + Com_Printf( "NET_OpenSocks: send: %s\n", NET_ErrorString() ); + return; + } + + // get the response + len = recv( socks_socket, (char *)buf, 64, 0 ); + if( len == SOCKET_ERROR ) { + Com_Printf( "NET_OpenSocks: recv: %s\n", NET_ErrorString() ); + return; + } + if( len < 2 || buf[0] != 5 ) { + Com_Printf( "NET_OpenSocks: bad response\n" ); + return; + } + // check completion code + if( buf[1] != 0 ) { + Com_Printf( "NET_OpenSocks: request denied: %i\n", buf[1] ); + return; + } + if( buf[3] != 1 ) { + Com_Printf( "NET_OpenSocks: relay address is not IPV4: %i\n", buf[3] ); + return; + } + socksRelayAddr.sin_family = AF_INET; + memcpy( &socksRelayAddr.sin_addr, &buf[4], 4 ); + memcpy( &socksRelayAddr.sin_port, &buf[8], 2 ); + memset( &socksRelayAddr.sin_zero, 0, 8 ); + + usingSocks = qtrue; +} + +/* +===================== +NET_GetLocalAddress +===================== +*/ +#ifdef MACOS_X +// Don't do a forward mapping from the hostname of the machine to the IP. The reason is that we might have obtained an IP address from DHCP and there might not be any name registered for the machine. On Mac OS X, the machine name defaults to 'localhost' and NetInfo has 127.0.0.1 listed for this name. Instead, we want to get a list of all the IP network interfaces on the machine. +// This code adapted from OmniNetworking. + +#ifdef _SIZEOF_ADDR_IFREQ + // tjw: OSX 10.4 does not have sa_len + #define IFR_NEXT(ifr) \ + ((struct ifreq *) ((char *) ifr + _SIZEOF_ADDR_IFREQ(*ifr))) +#else + // tjw: assume that once upon a time some version did have sa_len + #define IFR_NEXT(ifr) \ + ((struct ifreq *) ((char *) (ifr) + sizeof(*(ifr)) + \ + Q_max(0, (int) (ifr)->ifr_addr.sa_len - (int) sizeof((ifr)->ifr_addr)))) +#endif + + +void NET_GetLocalAddress( void ) { + struct ifreq requestBuffer[MAX_IPS], *linkInterface, *inetInterface; + struct ifconf ifc; + struct ifreq ifr; + struct sockaddr_dl *sdl; + int interfaceSocket; + int family; + + // Set this early so we can just return if there is an error + numIP = 0; + + ifc.ifc_len = sizeof(requestBuffer); + ifc.ifc_buf = (caddr_t)requestBuffer; + + // Since we get at this info via an ioctl, we need a temporary little socket. + // This will only get AF_INET interfaces, but we probably don't care about + // anything else. If we do end up caring later, we should add a + // ONAddressFamily and at a -interfaces method to it. + family = AF_INET; + if ((interfaceSocket = socket(family, SOCK_DGRAM, 0)) < 0) { + Com_Printf("NET_GetLocalAddress: Unable to create temporary socket, errno = %d\n", errno); + return; + } + + if (ioctl(interfaceSocket, SIOCGIFCONF, &ifc) != 0) { + Com_Printf("NET_GetLocalAddress: Unable to get list of network interfaces, errno = %d\n", errno); + return; + } + + linkInterface = (struct ifreq *) ifc.ifc_buf; + while ((char *) linkInterface < &ifc.ifc_buf[ifc.ifc_len]) { + unsigned int nameLength; + + // The ioctl returns both the entries having the address (AF_INET) + // and the link layer entries (AF_LINK). The AF_LINK entry has the + // link layer address which contains the interface type. This is the + // only way I can see to get this information. We cannot assume that + // we will get bot an AF_LINK and AF_INET entry since the interface + // may not be configured. For example, if you have a 10Mb port on + // the motherboard and a 100Mb card, you may not configure the + // motherboard port. + + // For each AF_LINK entry... + if (linkInterface->ifr_addr.sa_family == AF_LINK) { + // if there is a matching AF_INET entry + inetInterface = (struct ifreq *) ifc.ifc_buf; + while ((char *) inetInterface < &ifc.ifc_buf[ifc.ifc_len]) { + if (inetInterface->ifr_addr.sa_family == AF_INET && + !strncmp(inetInterface->ifr_name, linkInterface->ifr_name, + sizeof(linkInterface->ifr_name))) { + + for (nameLength = 0; nameLength < IFNAMSIZ; nameLength++) + if (!linkInterface->ifr_name[nameLength]) + break; + + sdl = (struct sockaddr_dl *)&linkInterface->ifr_addr; + // Skip loopback interfaces + if (sdl->sdl_type != IFT_LOOP) { + // Get the local interface address + strncpy(ifr.ifr_name, inetInterface->ifr_name, sizeof(ifr.ifr_name)); + if (ioctl(interfaceSocket, SIOCGIFADDR, (caddr_t)&ifr) < 0) { + Com_Printf("NET_GetLocalAddress: Unable to get local address " + "for interface '%s', errno = %d\n", inetInterface->ifr_name, errno); + } else { + struct sockaddr_in *sin; + int ip; + + sin = (struct sockaddr_in *)&ifr.ifr_addr; + + ip = ntohl(sin->sin_addr.s_addr); + localIP[ numIP ][0] = (ip >> 24) & 0xff; + localIP[ numIP ][1] = (ip >> 16) & 0xff; + localIP[ numIP ][2] = (ip >> 8) & 0xff; + localIP[ numIP ][3] = (ip >> 0) & 0xff; + Com_Printf( "IP: %i.%i.%i.%i (%s)\n", + localIP[ numIP ][0], localIP[ numIP ][1], + localIP[ numIP ][2], localIP[ numIP ][3], + inetInterface->ifr_name); + numIP++; + } + } + + // We will assume that there is only one AF_INET entry per AF_LINK entry. + // What happens when we have an interface that has multiple IP addresses, or + // can that even happen? + // break; + } + inetInterface = IFR_NEXT(inetInterface); + } + } + linkInterface = IFR_NEXT(linkInterface); + } + + close(interfaceSocket); +} +#else +void NET_GetLocalAddress( void ) +{ + char hostname[256]; + struct hostent *hostInfo; + char *p; + int ip; + int n; + + // Set this early so we can just return if there is an error + numIP = 0; + + if( gethostname( hostname, 256 ) == SOCKET_ERROR ) { + return; + } + + hostInfo = gethostbyname( hostname ); + if( !hostInfo ) { + return; + } + + Com_Printf( "Hostname: %s\n", hostInfo->h_name ); + n = 0; + while( ( p = hostInfo->h_aliases[n++] ) != NULL ) { + Com_Printf( "Alias: %s\n", p ); + } + + if ( hostInfo->h_addrtype != AF_INET ) { + return; + } + + while( ( p = hostInfo->h_addr_list[numIP] ) != NULL && numIP < MAX_IPS ) { + ip = ntohl( *(uint32_t *)p ); + localIP[ numIP ][0] = p[0]; + localIP[ numIP ][1] = p[1]; + localIP[ numIP ][2] = p[2]; + localIP[ numIP ][3] = p[3]; + Com_Printf( "IP: %i.%i.%i.%i\n", ( ip >> 24 ) & 0xff, ( ip >> 16 ) & 0xff, ( ip >> 8 ) & 0xff, ip & 0xff ); + numIP++; + } +} +#endif + +/* +==================== +NET_OpenIP +==================== +*/ +void NET_OpenIP( void ) +{ + int port = net_port->integer; + int err; + + NET_GetLocalAddress(); + + // automatically scan for a valid port, so multiple + // dedicated servers can be started without requiring + // a different net_port for each one + + if ( net_enabled->integer & NET_ENABLEV4 ) { + for ( int i=0 ; i < 10 ; i++ ) { + ip_socket = NET_IPSocket( net_ip->string, port + i, &err ); + if ( ip_socket != INVALID_SOCKET ) { + Cvar_SetValue( "net_port", port + i ); + + if ( net_socksEnabled->integer ) + NET_OpenSocks( port + i ); + break; + } + else { + if ( err == EAFNOSUPPORT ) + break; + } + } + if ( ip_socket == INVALID_SOCKET ) + Com_Printf( "WARNING: Couldn't bind to a v4 ip address.\n"); + } +} + +//=================================================================== + +/* +==================== +NET_GetCvars +==================== +*/ +static qboolean NET_GetCvars( void ) { + int modified = 0; + + net_enabled = Cvar_Get( "net_enabled", "1", CVAR_LATCH | CVAR_ARCHIVE_ND ); + modified = net_enabled->modified; + net_enabled->modified = qfalse; + + net_forcenonlocal = Cvar_Get( "net_forcenonlocal", "0", CVAR_LATCH | CVAR_ARCHIVE_ND ); + modified += net_forcenonlocal->modified; + net_forcenonlocal->modified = qfalse; + + net_ip = Cvar_Get( "net_ip", "localhost", CVAR_LATCH ); + modified += net_ip->modified; + net_ip->modified = qfalse; + + net_port = Cvar_Get( "net_port", XSTRING( PORT_SERVER ), CVAR_LATCH ); + modified += net_port->modified; + net_port->modified = qfalse; + + net_socksEnabled = Cvar_Get( "net_socksEnabled", "0", CVAR_LATCH | CVAR_ARCHIVE_ND ); + modified += net_socksEnabled->modified; + net_socksEnabled->modified = qfalse; + + net_socksServer = Cvar_Get( "net_socksServer", "", CVAR_LATCH | CVAR_ARCHIVE_ND ); + modified += net_socksServer->modified; + net_socksServer->modified = qfalse; + + net_socksPort = Cvar_Get( "net_socksPort", "1080", CVAR_LATCH | CVAR_ARCHIVE_ND ); + modified += net_socksPort->modified; + net_socksPort->modified = qfalse; + + net_socksUsername = Cvar_Get( "net_socksUsername", "", CVAR_LATCH | CVAR_ARCHIVE_ND ); + modified += net_socksUsername->modified; + net_socksUsername->modified = qfalse; + + net_socksPassword = Cvar_Get( "net_socksPassword", "", CVAR_LATCH | CVAR_ARCHIVE_ND ); + modified += net_socksPassword->modified; + net_socksPassword->modified = qfalse; + + net_dropsim = Cvar_Get( "net_dropsim", "", CVAR_TEMP); + + return modified ? qtrue : qfalse; +} + +/* +==================== +NET_Config +==================== +*/ +void NET_Config( qboolean enableNetworking ) { + qboolean modified; + qboolean stop; + qboolean start; + + // get any latched changes to cvars + modified = NET_GetCvars(); + + if ( !net_enabled->integer ) + enableNetworking = qfalse; + + // if enable state is the same and no cvars were modified, we have nothing to do + if ( enableNetworking == networkingEnabled && !modified ) + return; + + if ( enableNetworking == networkingEnabled ) { + if ( enableNetworking ) { + stop = qtrue; + start = qtrue; + } + else { + stop = qfalse; + start = qfalse; + } + } + else { + if ( enableNetworking ) { + stop = qfalse; + start = qtrue; + } + else { + stop = qtrue; + start = qfalse; + } + networkingEnabled = enableNetworking; + } + + if ( stop ) { + if ( ip_socket != INVALID_SOCKET ) { + closesocket( ip_socket ); + ip_socket = INVALID_SOCKET; + } + + if ( socks_socket != INVALID_SOCKET ) { + closesocket( socks_socket ); + socks_socket = INVALID_SOCKET; + } + } + + if ( start ) { + if ( net_enabled->integer ) + NET_OpenIP(); + } +} + +/* +==================== +NET_Init +==================== +*/ +void NET_Init( void ) { +#ifdef _WIN32 + int r = WSAStartup( MAKEWORD( 1, 1 ), &winsockdata ); + if( r ) { + Com_Printf( "WARNING: Winsock initialization failed, returned %d\n", r ); + return; + } + + winsockInitialized = qtrue; + Com_Printf( "Winsock Initialized\n" ); +#endif + + NET_Config( qtrue ); + + Cmd_AddCommand ("net_restart", NET_Restart_f, "Restart the networking sub-system" ); +} + +/* +==================== +NET_Shutdown +==================== +*/ +void NET_Shutdown( void ) { + if ( !networkingEnabled ) { + return; + } + + NET_Config( qfalse ); +#ifdef _WIN32 + WSACleanup(); + winsockInitialized = qfalse; +#endif +} + +/* +==================== +NET_Event + +Called from NET_Sleep which uses select() to determine which sockets have seen action. +==================== +*/ + +void NET_Event(fd_set *fdr) +{ + byte bufData[MAX_MSGLEN + 1]; + netadr_t from; + msg_t netmsg; + + while(1) + { + MSG_Init(&netmsg, bufData, sizeof(bufData)); + + if(NET_GetPacket(&from, &netmsg, fdr)) + { + if(net_dropsim->value > 0.0f && net_dropsim->value <= 100.0f) + { + // com_dropsim->value percent of incoming packets get dropped. + if(rand() < (int) (((double) RAND_MAX) / 100.0 * (double) net_dropsim->value)) + continue; // drop this packet + } + + if(com_sv_running->integer) + Com_RunAndTimeServerPacket(&from, &netmsg); + else + CL_PacketEvent(from, &netmsg); + } + else + break; + } +} + +/* +==================== +NET_Sleep + +sleeps msec or until net socket is ready +==================== +*/ +void NET_Sleep( int msec ) { + struct timeval timeout; + fd_set fdset; + int retval; + SOCKET highestfd = INVALID_SOCKET; + + if (msec < 0) + msec = 0; + + FD_ZERO(&fdset); + if (ip_socket != INVALID_SOCKET) { + FD_SET(ip_socket, &fdset); // network socket + highestfd = ip_socket; + } + +#ifdef _WIN32 + if(highestfd == INVALID_SOCKET) + { + // windows ain't happy when select is called without valid FDs + + SleepEx(msec, 0); + return; + } +#endif + + timeout.tv_sec = msec/1000; + timeout.tv_usec = (msec%1000)*1000; + + retval = select(highestfd + 1, &fdset, NULL, NULL, &timeout); + + if(retval == SOCKET_ERROR) + Com_Printf("Warning: select() syscall failed: %s\n", NET_ErrorString()); + else if(retval > 0) + NET_Event(&fdset); +} + +/* +==================== +NET_Restart_f +==================== +*/ +void NET_Restart_f( void ) { + NET_Config( qtrue ); +} diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/persistence.cpp b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/persistence.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/persistence.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/persistence.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/q_shared.c b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/q_shared.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/q_shared.c rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/q_shared.c diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/q_shared.cpp b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/q_shared.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/q_shared.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/q_shared.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/q_shared.h b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/q_shared.h similarity index 99% rename from Projects/Android/jni/OpenJK/codemp/qcommon/q_shared.h rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/q_shared.h index cea7b5c..16b8ed9 100644 --- a/Projects/Android/jni/OpenJK/codemp/qcommon/q_shared.h +++ b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/q_shared.h @@ -51,6 +51,7 @@ along with this program; if not, see . #include "qcommon/q_math.h" #include "qcommon/q_color.h" #include "qcommon/q_string.h" +#include "qcommon/q_platform.h" #include "qcommon/disablewarnings.h" #include "game/teams.h" //npc team stuff diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/qcommon.h b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/qcommon.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/qcommon.h rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/qcommon.h diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/qfiles.h b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/qfiles.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/qfiles.h rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/qfiles.h diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/sstring.h b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/sstring.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/sstring.h rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/sstring.h diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/stringed_ingame.cpp b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/stringed_ingame.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/stringed_ingame.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/stringed_ingame.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/stringed_ingame.h b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/stringed_ingame.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/stringed_ingame.h rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/stringed_ingame.h diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/stringed_interface.cpp b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/stringed_interface.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/stringed_interface.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/stringed_interface.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/stringed_interface.h b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/stringed_interface.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/stringed_interface.h rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/stringed_interface.h diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/tags.h b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/tags.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/tags.h rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/tags.h diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/timing.h b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/timing.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/timing.h rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/timing.h diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/vm.cpp b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/vm.cpp similarity index 99% rename from Projects/Android/jni/OpenJK/codemp/qcommon/vm.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/vm.cpp index 11aa3ee..7aa7d19 100644 --- a/Projects/Android/jni/OpenJK/codemp/qcommon/vm.cpp +++ b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/vm.cpp @@ -26,6 +26,7 @@ along with this program; if not, see . #include #include "qcommon/qcommon.h" +#include "qcommon/q_platform.h" vm_t *currentVM = NULL; diff --git a/Projects/Android/jni/OpenJK/codemp/qcommon/z_memman_pc.cpp b/Projects/Android/jni/OpenJK/codemp_delete/qcommon/z_memman_pc.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/qcommon/z_memman_pc.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/qcommon/z_memman_pc.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-common/mdx_format.h b/Projects/Android/jni/OpenJK/codemp_delete/rd-common/mdx_format.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-common/mdx_format.h rename to Projects/Android/jni/OpenJK/codemp_delete/rd-common/mdx_format.h diff --git a/Projects/Android/jni/OpenJK/codemp/rd-common/tr_common.h b/Projects/Android/jni/OpenJK/codemp_delete/rd-common/tr_common.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-common/tr_common.h rename to Projects/Android/jni/OpenJK/codemp_delete/rd-common/tr_common.h diff --git a/Projects/Android/jni/OpenJK/codemp/rd-common/tr_font.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-common/tr_font.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-common/tr_font.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-common/tr_font.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-common/tr_font.h b/Projects/Android/jni/OpenJK/codemp_delete/rd-common/tr_font.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-common/tr_font.h rename to Projects/Android/jni/OpenJK/codemp_delete/rd-common/tr_font.h diff --git a/Projects/Android/jni/OpenJK/codemp/rd-common/tr_image_jpg.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-common/tr_image_jpg.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-common/tr_image_jpg.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-common/tr_image_jpg.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-common/tr_image_load.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-common/tr_image_load.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-common/tr_image_load.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-common/tr_image_load.cpp diff --git a/Projects/Android/jni/OpenJK/codemp_delete/rd-common/tr_image_manipulation.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-common/tr_image_manipulation.cpp new file mode 100644 index 0000000..7f92db4 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/rd-common/tr_image_manipulation.cpp @@ -0,0 +1,212 @@ +#include "tr_common.h" + +void R_InvertImage(byte *data, int width, int height, int depth) +{ + byte *newData; + byte *oldData; + byte *saveData; + int y, stride; + + stride = width * depth; + + oldData = data + ((height - 1) * stride); + newData = (byte *)ri->Z_Malloc(height * stride, TAG_TEMP_IMAGE, qfalse, 4 ); + saveData = newData; + + for(y = 0; y < height; y++) + { + memcpy(newData, oldData, stride); + newData += stride; + oldData -= stride; + } + memcpy(data, saveData, height * stride); + ri->Z_Free(saveData); +} + +// Lanczos3 image resampling. Better than bicubic, based on sin(x)/x algorithm + +#define LANCZOS3 (3.0f) +#define M_PI_OVER_3 (M_PI / 3.0f) + +typedef struct contrib_s { + int pixel; + float weight; +} contrib_t; + +typedef struct contrib_list_s { + int n; // number of contributors + contrib_t *p; // pointer to list of contributions +} contrib_list_t; + +// sin(x)/x * sin(x/3)/(x/3) + +float Lanczos3(float t) +{ + if(!t) + { + return(1.0f); + } + t = (float)fabs(t); + if(t < 3.0f) + { + return(sinf(t * M_PI) * sinf(t * M_PI_OVER_3) / (t * M_PI * t * M_PI_OVER_3)); + } + return(0.0f); +} + +void R_Resample(byte *source, int swidth, int sheight, byte *dest, int dwidth, int dheight, int components) +{ + int i, j, k, l, count, left, right, num; + int pixel; + byte *raster; + float center, weight, scale, width, height; + contrib_list_t *contributors; + +// MD_PushTag(TAG_RESAMPLE); + + byte *work = (byte *)ri->Z_Malloc(dwidth * sheight * components, TAG_RESAMPLE, qfalse, 4); + + // Pre calculate filter contributions for rows + contributors = (contrib_list_t *)ri->Z_Malloc(sizeof(contrib_list_t) * dwidth, TAG_RESAMPLE, qfalse, 4); + + float xscale = (float)dwidth / (float)swidth; + + if(xscale < 1.0f) + { + width = ceilf(LANCZOS3 / xscale); + scale = xscale; + } + else + { + width = LANCZOS3; + scale = 1.0f; + } + num = ((int)width * 2) + 1; + + for(i = 0; i < dwidth; i++) + { + contributors[i].n = 0; + contributors[i].p = (contrib_t *)ri->Z_Malloc(num * sizeof(contrib_t), TAG_RESAMPLE, qfalse, 4); + + center = (float)i / xscale; + left = (int)ceilf(center - width); + right = (int)floorf(center + width); + + for(j = left; j <= right; j++) + { + weight = Lanczos3((center - (float)j) * scale) * scale; + if(j < 0) + { + pixel = -j; + } + else if(j >= swidth) + { + pixel = (swidth - j) + swidth - 1; + } + else + { + pixel = j; + } + count = contributors[i].n++; + contributors[i].p[count].pixel = pixel; + contributors[i].p[count].weight = weight; + } + } + // Apply filters to zoom horizontally from source to work + for(k = 0; k < sheight; k++) + { + raster = source + (k * swidth * components); + for(i = 0; i < dwidth; i++) + { + for(l = 0; l < components; l++) + { + weight = 0.0f; + for(j = 0; j < contributors[i].n; j++) + { + weight += raster[(contributors[i].p[j].pixel * components) + l] * contributors[i].p[j].weight; + } + pixel = (byte)Com_Clamp(0.0f, 255.0f, weight); + work[(k * dwidth * components) + (i * components) + l] = pixel; + } + } + } + // Clean up + for(i = 0; i < dwidth; i++) + { + ri->Z_Free(contributors[i].p); + } + ri->Z_Free(contributors); + + // Columns + contributors = (contrib_list_t *)ri->Z_Malloc(sizeof(contrib_list_t) * dheight, TAG_RESAMPLE, qfalse, 4); + + float yscale = (float)dheight / (float)sheight; + if(yscale < 1.0f) + { + height = ceilf(LANCZOS3 / yscale); + scale = yscale; + } + else + { + height = LANCZOS3; + scale = 1.0f; + } + num = ((int)height * 2) + 1; + + for(i = 0; i < dheight; i++) + { + contributors[i].n = 0; + contributors[i].p = (contrib_t *)ri->Z_Malloc(num * sizeof(contrib_t), TAG_RESAMPLE, qfalse, 4); + + center = (float)i / yscale; + left = (int)ceilf(center - height); + right = (int)floorf(center + height); + + for(j = left; j <= right; j++) + { + weight = Lanczos3((center - (float)j) * scale) * scale; + if(j < 0) + { + pixel = -j; + } + else if(j >= sheight) + { + pixel = (sheight - j) + sheight - 1; + } + else + { + pixel = j; + } + count = contributors[i].n++; + contributors[i].p[count].pixel = pixel; + contributors[i].p[count].weight = weight; + } + } + // Apply filter to columns + for(k = 0; k < dwidth; k++) + { + for(l = 0; l < components; l++) + { + for(i = 0; i < dheight; i++) + { + weight = 0.0f; + for(j = 0; j < contributors[i].n; j++) + { + weight += work[(contributors[i].p[j].pixel * dwidth * components) + (k * components) + l] * contributors[i].p[j].weight; + } + pixel = (byte)Com_Clamp(0.0f, 255.0f, weight); + dest[(i * dwidth * components) + (k * components) + l] = pixel; + } + } + } + // Clean up + for(i = 0; i < dheight; i++) + { + ri->Z_Free(contributors[i].p); + } + ri->Z_Free(contributors); + ri->Z_Free(work); + +// MD_PopTag(); +} + diff --git a/Projects/Android/jni/OpenJK/codemp/rd-common/tr_image_png.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-common/tr_image_png.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-common/tr_image_png.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-common/tr_image_png.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-common/tr_image_tga.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-common/tr_image_tga.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-common/tr_image_tga.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-common/tr_image_tga.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-common/tr_noise.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-common/tr_noise.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-common/tr_noise.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-common/tr_noise.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-common/tr_public.h b/Projects/Android/jni/OpenJK/codemp_delete/rd-common/tr_public.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-common/tr_public.h rename to Projects/Android/jni/OpenJK/codemp_delete/rd-common/tr_public.h diff --git a/Projects/Android/jni/OpenJK/codemp/rd-common/tr_types.h b/Projects/Android/jni/OpenJK/codemp_delete/rd-common/tr_types.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-common/tr_types.h rename to Projects/Android/jni/OpenJK/codemp_delete/rd-common/tr_types.h diff --git a/Projects/Android/jni/OpenJK/codemp/rd-dedicated/G2_API.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/G2_API.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-dedicated/G2_API.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/G2_API.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-dedicated/G2_bolts.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/G2_bolts.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-dedicated/G2_bolts.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/G2_bolts.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-dedicated/G2_bones.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/G2_bones.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-dedicated/G2_bones.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/G2_bones.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-dedicated/G2_misc.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/G2_misc.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-dedicated/G2_misc.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/G2_misc.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-dedicated/G2_surfaces.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/G2_surfaces.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-dedicated/G2_surfaces.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/G2_surfaces.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-dedicated/qgl.h b/Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/qgl.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-dedicated/qgl.h rename to Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/qgl.h diff --git a/Projects/Android/jni/OpenJK/codemp/rd-dedicated/tr_WorldEffects.h b/Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/tr_WorldEffects.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-dedicated/tr_WorldEffects.h rename to Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/tr_WorldEffects.h diff --git a/Projects/Android/jni/OpenJK/codemp/rd-dedicated/tr_backend.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/tr_backend.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-dedicated/tr_backend.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/tr_backend.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-dedicated/tr_font.h b/Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/tr_font.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-dedicated/tr_font.h rename to Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/tr_font.h diff --git a/Projects/Android/jni/OpenJK/codemp/rd-dedicated/tr_ghoul2.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/tr_ghoul2.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-dedicated/tr_ghoul2.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/tr_ghoul2.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-dedicated/tr_init.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/tr_init.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-dedicated/tr_init.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/tr_init.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-dedicated/tr_local.h b/Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/tr_local.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-dedicated/tr_local.h rename to Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/tr_local.h diff --git a/Projects/Android/jni/OpenJK/codemp/rd-dedicated/tr_main.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/tr_main.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-dedicated/tr_main.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/tr_main.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-dedicated/tr_mesh.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/tr_mesh.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-dedicated/tr_mesh.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/tr_mesh.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-dedicated/tr_model.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/tr_model.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-dedicated/tr_model.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/tr_model.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-dedicated/tr_quicksprite.h b/Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/tr_quicksprite.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-dedicated/tr_quicksprite.h rename to Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/tr_quicksprite.h diff --git a/Projects/Android/jni/OpenJK/codemp/rd-dedicated/tr_shader.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/tr_shader.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-dedicated/tr_shader.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/tr_shader.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-dedicated/tr_skin.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/tr_skin.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-dedicated/tr_skin.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-dedicated/tr_skin.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/CMakeLists.txt b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/CMakeLists.txt similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/CMakeLists.txt rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/CMakeLists.txt diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/G2_API.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/G2_API.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/G2_API.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/G2_API.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/G2_bolts.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/G2_bolts.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/G2_bolts.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/G2_bolts.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/G2_bones.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/G2_bones.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/G2_bones.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/G2_bones.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/G2_misc.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/G2_misc.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/G2_misc.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/G2_misc.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/G2_surfaces.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/G2_surfaces.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/G2_surfaces.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/G2_surfaces.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/glext.h b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/glext.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/glext.h rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/glext.h diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/qgl.h b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/qgl.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/qgl.h rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/qgl.h diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_WorldEffects.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_WorldEffects.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_WorldEffects.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_WorldEffects.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_WorldEffects.h b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_WorldEffects.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_WorldEffects.h rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_WorldEffects.h diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_arb.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_arb.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_arb.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_arb.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_backend.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_backend.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_backend.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_backend.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_bsp.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_bsp.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_bsp.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_bsp.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_cmds.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_cmds.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_cmds.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_cmds.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_curve.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_curve.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_curve.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_curve.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_decals.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_decals.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_decals.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_decals.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_ghoul2.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_ghoul2.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_ghoul2.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_ghoul2.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_image.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_image.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_image.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_image.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_init.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_init.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_init.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_init.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_light.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_light.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_light.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_light.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_local.h b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_local.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_local.h rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_local.h diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_main.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_main.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_main.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_main.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_marks.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_marks.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_marks.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_marks.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_mesh.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_mesh.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_mesh.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_mesh.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_model.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_model.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_model.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_model.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_quicksprite.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_quicksprite.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_quicksprite.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_quicksprite.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_quicksprite.h b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_quicksprite.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_quicksprite.h rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_quicksprite.h diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_scene.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_scene.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_scene.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_scene.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_shade.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_shade.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_shade.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_shade.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_shade_calc.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_shade_calc.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_shade_calc.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_shade_calc.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_shader.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_shader.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_shader.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_shader.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_shadows.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_shadows.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_shadows.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_shadows.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_skin.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_skin.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_skin.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_skin.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_sky.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_sky.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_sky.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_sky.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_subs.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_subs.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_subs.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_subs.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_surface.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_surface.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_surface.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_surface.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_surfacesprites.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_surfacesprites.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_surfacesprites.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_surfacesprites.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_terrain.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_terrain.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_terrain.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_terrain.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_world.cpp b/Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_world.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/rd-vanilla/tr_world.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/rd-vanilla/tr_world.cpp diff --git a/Projects/Android/jni/OpenJK/codemp_delete/server/NPCNav/navigator.cpp b/Projects/Android/jni/OpenJK/codemp_delete/server/NPCNav/navigator.cpp new file mode 100644 index 0000000..3331687 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/server/NPCNav/navigator.cpp @@ -0,0 +1,2792 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#include "qcommon/q_shared.h" + +#include + +#include "navigator.h" +#include "game/g_nav.h" +#include +#ifdef __linux__ +unsigned int timeGetTime(void); +#endif + +#include "../sv_gameapi.h" + +//Global navigator +CNavigator navigator; +//this was in the game before. But now it's all handled in the engine, and we make navigator. calls +//via traps. + +cvar_t *d_altRoutes; +cvar_t *d_patched; + +void NAV_CvarInit() +{ + d_altRoutes = Cvar_Get("d_altRoutes", "0", CVAR_CHEAT); + d_patched = Cvar_Get("d_patched", "0", CVAR_CHEAT); +} + +void NAV_Free() +{ + navigator.Free(); +} + +static vec3_t wpMaxs = { 16, 16, 32 }; +static vec3_t wpMins = { -16, -16, -24+STEPSIZE };//WTF: was 16??!!! + + +static byte CHECKED_NO = 0; +static byte CHECKED_FAILED = 1; +static byte CHECKED_PASSED = 2; + + +#if AI_TIMERS +int GetTime ( int lastTime ) +{ + int curtime; + static int timeBase = 0; + static qboolean initialized = qfalse; + + if (!initialized) { + timeBase = timeGetTime(); + initialized = qtrue; + } + curtime = timeGetTime() - timeBase - lastTime; + + return curtime; +} +#endif + +/* +------------------------- +CEdge +------------------------- +*/ + +CEdge::CEdge( int first, int second, int cost ) +{ + m_first = first; + m_second = second; + m_cost = cost; +} + +CEdge::~CEdge( void ) +{ +} + +/* +------------------------- +CNode +------------------------- +*/ + +CNode::CNode( void ) +{ + m_numEdges = 0; + m_radius = 0; + m_ranks = NULL; +} + +CNode::~CNode( void ) +{ + m_edges.clear(); + + if ( m_ranks ) + delete [] m_ranks; +} + +/* +------------------------- +Create +------------------------- +*/ + +CNode *CNode::Create( vec3_t position, int flags, int radius, int ID ) +{ + CNode *node = new CNode; + + VectorCopy( position, node->m_position ); + + node->m_flags = flags; + node->m_ID = ID; + node->m_radius = radius; + + return node; +} + +/* +------------------------- +Create +------------------------- +*/ + +CNode *CNode::Create( void ) +{ + return new CNode; +} + +/* +------------------------- +AddEdge +------------------------- +*/ + +void CNode::AddEdge( int ID, int cost, int flags ) +{ + if ( m_numEdges ) + {//already have at least 1 + //see if it exists already + edge_v::iterator ei; + STL_ITERATE( ei, m_edges ) + { + if ( (*ei).ID == ID ) + {//found it + (*ei).cost = cost; + (*ei).flags = flags; + return; + } + } + } + + edge_t edge; + + edge.ID = ID; + edge.cost = cost; + edge.flags = flags; + + STL_INSERT( m_edges, edge ); + + m_numEdges++; + + assert( m_numEdges < 9 );//8 is the max +} + +/* +------------------------- +GetEdge +------------------------- +*/ + +int CNode::GetEdgeNumToNode( int ID ) +{ + int count = 0; + + edge_v::iterator ei; + STL_ITERATE( ei, m_edges ) + { + if ( (*ei).ID == ID ) + { + return count; + } + + count++; + } + return -1; +} + +/* +------------------------- +AddRank +------------------------- +*/ + +void CNode::AddRank( int ID, int rank ) +{ + assert( m_ranks ); + + m_ranks[ ID ] = rank; +} + +/* +------------------------- +Draw +------------------------- +*/ + +void CNode::Draw( qboolean showRadius ) +{ //rwwFIXMEFIXME: ... + /* + CG_DrawNode( m_position, NODE_NORMAL ); + if( showRadius ) + { + CG_DrawRadius( m_position, m_radius, NODE_NORMAL ); + } + */ +} + +/* +------------------------- +GetEdge +------------------------- +*/ + +int CNode::GetEdge( int edgeNum ) +{ + if ( edgeNum > m_numEdges ) + return -1; + + int count = 0; + + edge_v::iterator ei; + STL_ITERATE( ei, m_edges ) + { + if ( count == edgeNum ) + { + return (*ei).ID; + } + + count++; + } + + return -1; +} + +/* +------------------------- +GetEdgeCost +------------------------- +*/ + +int CNode::GetEdgeCost( int edgeNum ) +{ + if ( edgeNum > m_numEdges ) + return Q3_INFINITE; // return -1; + + int count = 0; + + edge_v::iterator ei; + STL_ITERATE( ei, m_edges ) + { + if ( count == edgeNum ) + { + return (*ei).cost; + } + + count++; + } + + return Q3_INFINITE; // return -1; +} + +/* +------------------------- +GetEdgeFlags +------------------------- +*/ + +byte CNode::GetEdgeFlags( int edgeNum ) +{ + if ( edgeNum > m_numEdges ) + return 0; + + int count = 0; + + edge_v::iterator ei; + STL_ITERATE( ei, m_edges ) + { + if ( count == edgeNum ) + { + return (*ei).flags; + } + + count++; + } + + return 0; +} + +/* +------------------------- +SetEdgeFlags +------------------------- +*/ + +void CNode::SetEdgeFlags( int edgeNum, int newFlags ) +{ + if ( edgeNum > m_numEdges ) + return; + + int count = 0; + + edge_v::iterator ei; + STL_ITERATE( ei, m_edges ) + { + if ( count == edgeNum ) + { + (*ei).flags = newFlags; + return; + } + + count++; + } + +} +/* +------------------------- +InitRanks +------------------------- +*/ + +void CNode::InitRanks( int size ) +{ + //Clear it if it's already allocated + if ( m_ranks != NULL ) + { + delete [] m_ranks; + m_ranks = NULL; + } + + m_ranks = new int[size]; + + memset( m_ranks, -1, sizeof(int)*size ); +} + +/* +------------------------- +GetRank +------------------------- +*/ + +int CNode::GetRank( int ID ) +{ + assert( m_ranks ); + + return m_ranks[ ID ]; +} + + +/* +------------------------- +Save +------------------------- +*/ + +int CNode::Save( int numNodes, fileHandle_t file ) +{ + //Write out the header + unsigned int header = NODE_HEADER_ID; + FS_Write( &header, sizeof( header ), file ); + + //Write out the basic information + int i; + for ( i = 0; i < 3; i++ ) + FS_Write( &m_position[i], sizeof( float ), file ); + + FS_Write( &m_flags, sizeof( m_flags ), file ); + FS_Write( &m_ID, sizeof( m_ID ), file ); + FS_Write( &m_radius, sizeof( m_radius ), file ); + + //Write out the edge information + FS_Write( &m_numEdges, sizeof( m_numEdges ), file ); + + edge_v::iterator ei; + STL_ITERATE( ei, m_edges ) + { + FS_Write( &(*ei), sizeof( edge_t ), file ); + } + + //Write out the node ranks + FS_Write( &numNodes, sizeof( numNodes ), file ); + + for ( i = 0; i < numNodes; i++ ) + { + FS_Write( &m_ranks[i], sizeof( int ), file ); + } + + return true; +} + +/* +------------------------- +Load +------------------------- +*/ + +int CNode::Load( int numNodes, fileHandle_t file ) +{ + unsigned int header; + FS_Read( &header, sizeof(header), file ); + + //Validate the header + if ( header != NODE_HEADER_ID ) + return false; + + //Get the basic information + int i; + for ( i = 0; i < 3; i++ ) + FS_Read( &m_position[i], sizeof( float ), file ); + + FS_Read( &m_flags, sizeof( m_flags ), file ); + FS_Read( &m_ID, sizeof( m_ID ), file ); + FS_Read( &m_radius, sizeof( m_radius ), file ); + + //Get the edge information + FS_Read( &m_numEdges, sizeof( m_numEdges ), file ); + + for ( i = 0; i < m_numEdges; i++ ) + { + edge_t edge; + + FS_Read( &edge, sizeof( edge_t ), file ); + + STL_INSERT( m_edges, edge ); + } + + //Read the node ranks + int numRanks; + + FS_Read( &numRanks, sizeof( numRanks ), file ); + + //Allocate the memory + InitRanks( numRanks ); + + for ( i = 0; i < numRanks; i++ ) + { + FS_Read( &m_ranks[i], sizeof( int ), file ); + } + + return true; +} + +/* +------------------------- +CNavigator +------------------------- +*/ + +CNavigator::CNavigator( void ) +{ +#if 0 // RAVEN... why u make it so hard to double link list cvars + if (!d_altRoutes || !d_patched) + { + NAV_CvarInit(); + } +#endif +} + +CNavigator::~CNavigator( void ) +{ +} + +/* +------------------------- +FlagAllNodes +------------------------- +*/ + +void CNavigator::FlagAllNodes( int newFlag ) +{ + node_v::iterator ni; + + STL_ITERATE( ni, m_nodes ) + { + (*ni)->AddFlag( newFlag ); + } +} + +/* +------------------------- +GetChar +------------------------- +*/ + +char CNavigator::GetChar( fileHandle_t file ) +{ + char value; + + FS_Read( &value, sizeof( value ), file ); + + return value; +} + +/* +------------------------- +GetInt +------------------------- +*/ + +int CNavigator::GetInt( fileHandle_t file ) +{ + int value; + + FS_Read( &value, sizeof( value ), file ); + + return value; +} + +/* +------------------------- +GetFloat +------------------------- +*/ + +float CNavigator::GetFloat( fileHandle_t file ) +{ + float value; + + FS_Read( &value, sizeof( value ), file ); + + return value; +} + +/* +------------------------- +GetLong +------------------------- +*/ + +long CNavigator::GetLong( fileHandle_t file ) +{ + int value; + + FS_Read( &value, sizeof( value ), file ); + + return value; +} + +/* +------------------------- +Init +------------------------- +*/ + +void CNavigator::Init( void ) +{ + if (!d_altRoutes || !d_patched) + { + NAV_CvarInit(); + } + + Free(); +} + +/* +------------------------- +Free +------------------------- +*/ + +void CNavigator::Free( void ) +{ + node_v::iterator ni; + + STL_ITERATE( ni, m_nodes ) + { + delete (*ni); + } + + m_nodes.clear(); + m_edgeLookupMap.clear(); +} + +/* +------------------------- +Load +------------------------- +*/ + +bool CNavigator::Load( const char *filename, int checksum ) +{ + fileHandle_t file; + + // Free previous map just in case. jampgame doesn't do this by default... + Free(); + + //Attempt to load the file + FS_FOpenFileByMode( va( "maps/%s.nav", filename ), &file, FS_READ ); + + //See if we succeeded + if ( file == 0 ) + return false; + + //Check the header id + int navID = GetLong( file ); + + if ( navID != NAV_HEADER_ID ) + { + FS_FCloseFile( file ); + return false; + } + + //Check the checksum to see if this file is out of date + int check = GetInt( file ); + + if ( check != checksum ) + { + FS_FCloseFile( file ); + return false; + } + + int numNodes = GetInt( file ); + + for ( int i = 0; i < numNodes; i++ ) + { + CNode *node = CNode::Create(); + + if ( node->Load( numNodes, file ) == false ) + { + FS_FCloseFile( file ); + return false; + } + + STL_INSERT( m_nodes, node ); + } + + //read in the failed edges + FS_Read( &failedEdges, sizeof( failedEdges ), file ); + for ( int j = 0; j < MAX_FAILED_EDGES; j++ ) + { + m_edgeLookupMap.insert(std::pair(failedEdges[j].startID, j)); + } + + + FS_FCloseFile( file ); + + return true; +} + +/* +------------------------- +Save +------------------------- +*/ + +bool CNavigator::Save( const char *filename, int checksum ) +{ + fileHandle_t file; + + //Attempt to load the file + FS_FOpenFileByMode( va( "maps/%s.nav", filename ), &file, FS_WRITE ); + + if ( file == 0 ) + return false; + + //Write out the header id + unsigned int id = NAV_HEADER_ID; + + FS_Write( &id, sizeof (id), file ); + + //Write out the checksum + FS_Write( &checksum, sizeof( checksum ), file ); + + int numNodes = m_nodes.size(); + + //Write out the number of nodes to follow + FS_Write( &numNodes, sizeof(numNodes), file ); + + //Write out all the nodes + node_v::iterator ni; + + STL_ITERATE( ni, m_nodes ) + { + (*ni)->Save( numNodes, file ); + } + + //write out failed edges + FS_Write( &failedEdges, sizeof( failedEdges ), file ); + + FS_FCloseFile( file ); + + return true; +} + +/* +------------------------- +AddRawPoint +------------------------- +*/ + +int CNavigator::AddRawPoint( vec3_t point, int flags, int radius ) +{ + CNode *node = CNode::Create( point, flags, radius, m_nodes.size() ); + + if ( node == NULL ) + { + Com_Error( ERR_DROP, "Error adding node!\n" ); + return -1; + } + + //TODO: Validate the position + //TODO: Correct stuck waypoints + + STL_INSERT( m_nodes, node ); + + return node->GetID(); +} + +/* +------------------------- +GetEdgeCost +------------------------- +*/ + +int CNavigator::GetEdgeCost( CNode *first, CNode *second ) +{ + trace_t trace; + vec3_t start, end; + vec3_t mins, maxs; + + //Setup the player size + VectorSet( mins, -8, -8, -8 ); + VectorSet( maxs, 8, 8, 8 ); + + //Setup the points + first->GetPosition( start ); + second->GetPosition( end ); + + SV_Trace( &trace, start, mins, maxs, end, ENTITYNUM_NONE, MASK_SOLID, qfalse, 0, 10 ); + + if ( trace.fraction < 1.0f || trace.allsolid || trace.startsolid ) + return Q3_INFINITE; // return -1; + + //Connection successful, return the cost + return Distance( start, end ); +} + +void CNavigator::SetEdgeCost( int ID1, int ID2, int cost ) +{ + if( (ID1 == -1) || (ID2 == -1) ) + {//not valid nodes, must have come from the ClearAllFailedEdges initization-type calls + return; + } + + CNode *node1 = m_nodes[ID1]; + CNode *node2 = m_nodes[ID2]; + + if ( cost == -1 ) + {//they want us to calc it + //FIXME: can we just remember this instead of recalcing every time? + vec3_t pos1, pos2; + + node1->GetPosition( pos1 ); + node2->GetPosition( pos2 ); + cost = Distance( pos1, pos2 ); + } + + //set it + node1->AddEdge( ID2, cost ); + node2->AddEdge( ID1, cost ); +} + +/* +------------------------- +AddNodeEdges +------------------------- +*/ + +void CNavigator::AddNodeEdges( CNode *node, int addDist, edge_l &edgeList, bool *checkedNodes ) +{ + //Add all edge + for ( int i = 0; i < node->GetNumEdges(); i++ ) + { + //Make sure we don't add an old edge twice + if ( checkedNodes[ node->GetEdge( i ) ] == true ) + continue; + + //Get the node + CNode *nextNode = m_nodes[ node->GetEdge( i ) ]; + + //This node has now been checked + checkedNodes[ nextNode->GetID() ] = true; + + //Add it to the list + STL_INSERT( edgeList, CEdge( nextNode->GetID(), node->GetID(), addDist + ( node->GetEdgeCost( i ) ) ) ); + } +} + +/* +------------------------- +CalculatePath +------------------------- +*/ + +void CNavigator::CalculatePath( CNode *node ) +{ + int curRank = 0; + + CPriorityQueue *pathList = new CPriorityQueue(); + byte *checked; + + //Init the completion table + checked = new byte[ m_nodes.size() ]; + memset( checked, 0, m_nodes.size() ); + + //Mark this node as checked + checked[ node->GetID() ] = true; + node->AddRank( node->GetID(), curRank++ ); + + //Add all initial nodes + int i; + for ( i = 0; i < node->GetNumEdges(); i++ ) + { + CNode *nextNode = m_nodes[ node->GetEdge(i) ]; + assert(nextNode); + + checked[ nextNode->GetID() ] = true; + + pathList->Push( new CEdge( nextNode->GetID(), nextNode->GetID(), node->GetEdgeCost(i) ) ); + } + + //float minDist; + CEdge *test; + + //Now flood fill all the others + while ( !pathList->Empty() ) + { + //minDist = Q3_INFINITE; + test = pathList->Pop(); + + CNode *testNode = m_nodes[ (*test).m_first ]; + assert( testNode ); + + node->AddRank( testNode->GetID(), curRank++ ); + + //Add in all the new edges + for ( i = 0; i < testNode->GetNumEdges(); i++ ) + { + CNode *addNode = m_nodes[ testNode->GetEdge(i) ]; + assert( addNode ); + + if ( checked[ addNode->GetID() ] ) + continue; + + int newDist = (*test).m_cost + testNode->GetEdgeCost(i); + pathList->Push( new CEdge( addNode->GetID(), (*test).m_second, newDist ) ); + + checked[ addNode->GetID() ] = true; + } + delete test; + + } + + node->RemoveFlag( NF_RECALC ); + + delete pathList; + delete [] checked; +} + +/* +------------------------- +CalculatePaths +------------------------- +*/ +void CNavigator::CalculatePaths( qboolean recalc ) +{ +#if _HARD_CONNECT +#else +#endif + + for ( size_t i = 0; i < m_nodes.size(); i++ ) + { + //Allocate the needed memory + m_nodes[i]->InitRanks( m_nodes.size() ); + } + + for ( size_t i = 0; i < m_nodes.size(); i++ ) + { + CalculatePath( m_nodes[i] ); + } + + if(!recalc) //Mike says doesn't need to happen on recalc + { + GVM_NAV_FindCombatPointWaypoints(); + } + + pathsCalculated = qtrue; +} + +/* +------------------------- +ShowNodes +------------------------- +*/ + +void CNavigator::ShowNodes( void ) +{ + node_v::iterator ni; + + vec3_t position; + qboolean showRadius; + float dist, + radius; + + STL_ITERATE( ni, m_nodes ) + { + (*ni)->GetPosition( position ); + + showRadius = qfalse; + //if( NAVDEBUG_showRadius ) + if (0) + { + dist = DistanceSquared( SV_GentityNum(0)->r.currentOrigin, position ); + radius = (*ni)->GetRadius(); + // if player within node radius or 256, draw radius (sometimes the radius is really small, so we check for 256 to catch everything) + if( (dist <= radius*radius) || dist <= 65536 ) + { + showRadius = qtrue; + } + } + else + { + dist = DistanceSquared( SV_GentityNum(0)->r.currentOrigin, position ); + } + if ( dist < 1048576 ) + { + if ( SV_inPVS( SV_GentityNum(0)->r.currentOrigin, position ) ) + { + (*ni)->Draw(showRadius); + } + } + } +} + +/* +------------------------- +ShowEdges +------------------------- +*/ + +typedef std::map < int, bool > drawMap_m; + +void CNavigator::ShowEdges( void ) +{ + node_v::iterator ni; + vec3_t start, end; + + drawMap_m *drawMap; + + drawMap = new drawMap_m[ m_nodes.size() ]; + + STL_ITERATE( ni, m_nodes ) + { + (*ni)->GetPosition( start ); + if ( DistanceSquared( SV_GentityNum(0)->r.currentOrigin, start ) >= 1048576 ) + { + continue; + } + + if (!SV_inPVS(SV_GentityNum(0)->r.currentOrigin, start)) + { + continue; + } + + //Attempt to draw each connection + for ( int i = 0; i < (*ni)->GetNumEdges(); i++ ) + { + int id = (*ni)->GetEdge( i ); + + if ( id == -1 ) + continue; + + //Already drawn? + if ( drawMap[(*ni)->GetID()].find( id ) != drawMap[(*ni)->GetID()].end() ) + continue; + + //BYTE flags = (*ni)->GetEdgeFlags( i ); + + CNode *node = m_nodes[id]; + + node->GetPosition( end ); + + //Set this as drawn + drawMap[id][(*ni)->GetID()] = true; + + if ( DistanceSquared( SV_GentityNum(0)->r.currentOrigin, end ) >= 1048576 ) + { + continue; + } + + if ( !SV_inPVS( SV_GentityNum(0)->r.currentOrigin, end ) ) + continue; + + /* + if ( EdgeFailed( id, (*ni)->GetID() ) != -1 )//flags & EFLAG_FAILED ) + CG_DrawEdge( start, end, EDGE_FAILED ); + else if ( flags & EFLAG_BLOCKED ) + CG_DrawEdge( start, end, EDGE_BLOCKED ); + else + CG_DrawEdge( start, end, EDGE_NORMAL ); + */ + //rwwFIXMEFIXME: ... + } + } + + delete [] drawMap; +} + +int CNavigator::GetNodeRadius( int nodeID ) +{ + if ( m_nodes.size() == 0 ) + return 0; + return m_nodes[nodeID]->GetRadius(); +} + +void CNavigator::CheckBlockedEdges( void ) +{ + CNode *start, *end; + vec3_t p1, p2; + int flags, first, second; + trace_t trace; + qboolean failed; + int edgeNum; + node_v::iterator ni; + + //Go through all edges and test the ones that were blocked + STL_ITERATE( ni, m_nodes ) + { + //Attempt to draw each connection + for ( edgeNum = 0; edgeNum < (*ni)->GetNumEdges(); edgeNum++ ) + { + flags = (*ni)->GetEdgeFlags( edgeNum ); + if ( (flags&EFLAG_BLOCKED) ) + { + first = (*ni)->GetID(); + second = (*ni)->GetEdge( edgeNum ); + start = m_nodes[first]; + end = m_nodes[second]; + failed = qfalse; + + start->GetPosition( p1 ); + end->GetPosition( p2 ); + + //FIXME: can't we just store the trace.entityNum from the HardConnect trace? So we don't have to do another trace here... + SV_Trace( &trace, p1, wpMins, wpMaxs, p2, ENTITYNUM_NONE, MASK_SOLID|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP, qfalse, 0, 10 ); + + if ( trace.entityNum < ENTITYNUM_WORLD && (trace.fraction < 1.0f || trace.startsolid == qtrue || trace.allsolid == qtrue) ) + {//could be assumed, since failed before + if ( GVM_NAV_EntIsDoor( trace.entityNum ) ) + {//door + if ( !GVM_NAV_EntIsUnlockedDoor( trace.entityNum ) ) + {//locked door + failed = qtrue; + } + } + else + { + if ( GVM_NAV_EntIsBreakable( trace.entityNum ) ) + {//do same for breakable brushes/models/glass? + failed = qtrue; + } + else if ( GVM_NAV_EntIsRemovableUsable( trace.entityNum ) ) + { + failed = qtrue; + } + else if ( trace.allsolid || trace.startsolid ) + {//FIXME: the entitynum would be none here, so how do we know if this is stuck inside an ent or the world? + } + else + {//FIXME: what about func_plats and scripted movers? + } + } + } + + if ( failed ) + { + //could add the EFLAG_FAILED to the two edges, but we stopped doing that since it was pointless + AddFailedEdge( ENTITYNUM_NONE, first, second ); + } + } + } + } +} + +#if _HARD_CONNECT + +/* +------------------------- +HardConnect +------------------------- +*/ + +void CNavigator::HardConnect( int first, int second ) +{ + CNode *start, *end; + + start = m_nodes[first]; + end = m_nodes[second]; + + vec3_t p1, p2; + + start->GetPosition( p1 ); + end->GetPosition( p2 ); + + trace_t trace; + + int flags = EFLAG_NONE; + + SV_Trace( &trace, p1, wpMins, wpMaxs, p2, ENTITYNUM_NONE, MASK_SOLID|CONTENTS_BOTCLIP|CONTENTS_MONSTERCLIP, qfalse, 0, 10 ); + + int cost = Distance( p1, p2 ); + + if ( trace.fraction != 1.0f || trace.startsolid == qtrue || trace.allsolid == qtrue ) + { + flags |= EFLAG_BLOCKED; + } + + start->AddEdge( second, cost, flags ); + end->AddEdge( first, cost, flags ); +} + +#endif + +/* +------------------------- +TestNodePath +------------------------- +*/ + +int CNavigator::TestNodePath( sharedEntity_t *ent, int okToHitEntNum, vec3_t position, qboolean includeEnts ) +{ //rwwFIXMEFIXME: Share clipmask? + int clipmask = MASK_SOLID;//ent->clipmask; + + if ( !includeEnts ) + { + clipmask &= ~CONTENTS_BODY; + } + //Check the path + if ( GVM_NAV_ClearPathToPoint( ent->s.number, ent->r.mins, ent->r.maxs, position, clipmask, okToHitEntNum ) == false ) + return false; + + return true; +} + +/* +------------------------- +TestNodeLOS +------------------------- +*/ + +int CNavigator::TestNodeLOS( sharedEntity_t *ent, vec3_t position ) +{ + return GVM_NPC_ClearLOS2( ent->s.number, position ); +} + +/* +------------------------- +TestBestFirst +------------------------- +*/ + +int CNavigator::TestBestFirst( sharedEntity_t *ent, int lastID, int flags ) +{ + //Must be a valid one to begin with + if ( lastID == NODE_NONE ) + return NODE_NONE; + + if ( lastID >= (int)m_nodes.size() ) + return NODE_NONE; + + //Get the info + vec3_t nodePos; + CNode *node = m_nodes[ lastID ]; + CNode *testNode; + int numEdges = node->GetNumEdges(); + float dist; + + node->GetPosition( nodePos ); + + //Setup our last node as our root, and search for a closer one according to its edges + int bestNode = ( TestNodePath( ent, ENTITYNUM_NONE, nodePos, qtrue ) ) ? lastID : NODE_NONE; + float bestDist = ( bestNode == NODE_NONE ) ? Q3_INFINITE : DistanceSquared( ent->r.currentOrigin, nodePos ); + + //Test all these edges first + for ( int i = 0; i < numEdges; i++ ) + { + //Get this node and its distance + testNode = m_nodes[ node->GetEdge(i) ]; + + if ( NodeFailed( ent, testNode->GetID() ) ) + { + continue; + } + + testNode->GetPosition( nodePos ); + + dist = DistanceSquared( ent->r.currentOrigin, nodePos ); + + //Test against current best + if ( dist < bestDist ) + { + //See if this node is valid + if ( CheckedNode(testNode->GetID(),ent->s.number) == CHECKED_PASSED || TestNodePath( ent, ENTITYNUM_NONE, nodePos, qtrue ) ) + { + bestDist = dist; + bestNode = testNode->GetID(); + SetCheckedNode(testNode->GetID(),ent->s.number,CHECKED_PASSED); + } + else + { + SetCheckedNode(testNode->GetID(),ent->s.number,CHECKED_FAILED); + } + } + } + + return bestNode; +} + +/* +------------------------- +CollectNearestNodes +------------------------- +*/ + +#define NODE_COLLECT_MAX 16 //Maximum # of nodes collected at any time +#define NODE_COLLECT_RADIUS 512 //Default radius to search for nodes in +#define NODE_COLLECT_RADIUS_SQR ( NODE_COLLECT_RADIUS * NODE_COLLECT_RADIUS ) + +int CNavigator::CollectNearestNodes( vec3_t origin, int radius, int maxCollect, nodeChain_l &nodeChain ) +{ + node_v::iterator ni; + float dist; + vec3_t position; + int collected = 0; + bool added = false; + + //Get a distance rating for each node in the system + STL_ITERATE( ni, m_nodes ) + { + //If we've got our quota, then stop looking + //Get the distance to the node + (*ni)->GetPosition( position ); + dist = DistanceSquared( position, origin ); + + //Must be within our radius range + if ( dist > (float) ( radius * radius ) ) + continue; + + nodeList_t nChain; + nodeChain_l::iterator nci; + + //Always add the first node + if ( nodeChain.size() == 0 ) + { + nChain.nodeID = (*ni)->GetID(); + nChain.distance = dist; + + nodeChain.insert( nodeChain.begin(), nChain ); + continue; + } + + added = false; + + //Compare it to what we already have + STL_ITERATE( nci, nodeChain ) + { + //If we're less, than this entry, then insert before it + if ( dist < (*nci).distance ) + { + nChain.nodeID = (*ni)->GetID(); + nChain.distance = dist; + + nodeChain.insert( nci, nChain ); + collected = nodeChain.size(); + added = true; + + //If we've hit our collection limit, throw off the oldest one + if ( (int)nodeChain.size() > maxCollect ) + { + nodeChain.pop_back(); + } + + break; + } + } + + //Otherwise, always pad out the collection if possible so we don't miss anything + if ( ( added == false ) && ( (int)nodeChain.size() < maxCollect ) ) + { + nChain.nodeID = (*ni)->GetID(); + nChain.distance = dist; + + nodeChain.insert( nodeChain.end(), nChain ); + } + } + + return collected; +} + +int CNavigator::GetBestPathBetweenEnts( sharedEntity_t *ent, sharedEntity_t *goal, int flags ) +{ + //Must have nodes + if ( m_nodes.size() == 0 ) + return NODE_NONE; + +#define MAX_Z_DELTA 18 + + nodeChain_l nodeChain; + nodeChain_l::iterator nci; + nodeChain_l nodeChain2; + nodeChain_l::iterator nci2; + + //Collect all nodes within a certain radius + CollectNearestNodes( ent->r.currentOrigin, NODE_COLLECT_RADIUS, NODE_COLLECT_MAX, nodeChain ); + CollectNearestNodes( goal->r.currentOrigin, NODE_COLLECT_RADIUS, NODE_COLLECT_MAX, nodeChain2 ); + + vec3_t position; + vec3_t position2; + int radius; + int cost, pathCost, bestCost = Q3_INFINITE; + CNode *node, *node2; + int nodeNum, nodeNum2; + int nextNode = NODE_NONE, bestNode = NODE_NONE; + int nodeFlags = 0; +// bool recalc = false; + + ent->waypoint = NODE_NONE; + goal->waypoint = NODE_NONE; + + //Look through all nodes + STL_ITERATE( nci, nodeChain ) + { + node = m_nodes[(*nci).nodeID]; + nodeNum = (*nci).nodeID; + + node->GetPosition( position ); + + if ( CheckedNode(nodeNum,ent->s.number) == CHECKED_FAILED ) + {//already checked this node against ent and it failed + continue; + } + if ( CheckedNode(nodeNum,ent->s.number) == CHECKED_PASSED ) + {//already checked this node against ent and it passed + } + else + {//haven't checked this node against ent yet + if ( NodeFailed( ent, nodeNum ) ) + { + SetCheckedNode( nodeNum, ent->s.number, CHECKED_FAILED ); + continue; + } + //okay, since we only have to do this once, let's check to see if this node is even usable (could help us short-circuit a whole loop of the dest nodes) + radius = node->GetRadius(); + + //If we're not within the known clear radius of this node OR out of Z height range... + if ( (int)(*nci).distance >= (radius*radius) || ( fabs( position[2] - ent->r.currentOrigin[2] ) >= MAX_Z_DELTA ) ) + { + //We're not *within* this node, so check clear path, etc. + + //FIXME: any way to call G_FindClosestPointOnLineSegment and see if I can at least get to the waypoint's path + if ( flags & NF_CLEAR_PATH )//|| flags & NF_CLEAR_LOS ) + {//need a clear path or LOS + if ( !SV_inPVS( ent->r.currentOrigin, position ) ) + {//not even potentially clear + SetCheckedNode( nodeNum, ent->s.number, CHECKED_FAILED ); + continue; + } + } + + //Do we need a clear path? + if ( flags & NF_CLEAR_PATH ) + { + if ( TestNodePath( ent, goal->s.number, position, qtrue ) == false ) + { + SetCheckedNode( nodeNum, ent->s.number, CHECKED_FAILED ); + continue; + } + } + }//otherwise, inside the node so it must be clear (?) + SetCheckedNode( nodeNum, ent->s.number, CHECKED_PASSED ); + } + + if ( d_altRoutes->integer ) + { + //calc the paths for this node if they're out of date + nodeFlags = node->GetFlags(); + if ( (nodeFlags&NF_RECALC) ) + { + //Com_Printf( S_COLOR_CYAN"%d recalcing paths from node %d\n", svs.time, nodeNum ); + CalculatePath( node ); + } + } + + STL_ITERATE( nci2, nodeChain2 ) + { + node2 = m_nodes[(*nci2).nodeID]; + nodeNum2 = (*nci2).nodeID; + if ( d_altRoutes->integer ) + { + //calc the paths for this node if they're out of date + nodeFlags = node2->GetFlags(); + if ( (nodeFlags&NF_RECALC) ) + { + //Com_Printf( S_COLOR_CYAN"%d recalcing paths from node %d\n", svs.time, nodeNum2 ); + CalculatePath( node2 ); + } + } + + node2->GetPosition( position2 ); + //Okay, first get the entire path cost, including distance to first node from ents' positions + cost = floor(Distance( ent->r.currentOrigin, position ) + Distance( goal->r.currentOrigin, position2 )); + + if ( d_altRoutes->integer ) + { + nextNode = GetBestNodeAltRoute( (*nci).nodeID, (*nci2).nodeID, &pathCost, bestNode ); + cost += pathCost; + } + else + { + cost += GetPathCost( (*nci).nodeID, (*nci2).nodeID ); + } + + if ( cost >= bestCost ) + { + continue; + } + + //okay, this is the shortest path we've found yet, check clear path, etc. + if ( CheckedNode( nodeNum2, goal->s.number ) == CHECKED_FAILED ) + {//already checked this node against goal and it failed + continue; + } + if ( CheckedNode( nodeNum2, goal->s.number ) == CHECKED_PASSED ) + {//already checked this node against goal and it passed + } + else + {//haven't checked this node against goal yet + if ( NodeFailed( goal, nodeNum2 ) ) + { + SetCheckedNode( nodeNum2, goal->s.number, CHECKED_FAILED ); + continue; + } + radius = node2->GetRadius(); + + //If we're not within the known clear radius of this node OR out of Z height range... + if ( (int)(*nci2).distance >= (radius*radius) || ( fabs( position2[2] - goal->r.currentOrigin[2] ) >= MAX_Z_DELTA ) ) + { + //We're not *within* this node, so check clear path, etc. + + if ( flags & NF_CLEAR_PATH )//|| flags & NF_CLEAR_LOS ) + {//need a clear path or LOS + if ( !SV_inPVS( goal->r.currentOrigin, position2 ) ) + {//not even potentially clear + SetCheckedNode( nodeNum2, goal->s.number, CHECKED_FAILED ); + continue; + } + } + //Do we need a clear path? + if ( flags & NF_CLEAR_PATH ) + { + if ( TestNodePath( goal, ent->s.number, position2, qfalse ) == false )//qtrue? + { + SetCheckedNode( nodeNum2, goal->s.number, CHECKED_FAILED ); + continue; + } + } + }//otherwise, inside the node so it must be clear (?) + SetCheckedNode( nodeNum2, goal->s.number, CHECKED_PASSED ); + } + + bestCost = cost; + bestNode = nextNode; + ent->waypoint = (*nci).nodeID; + goal->waypoint = (*nci2).nodeID; + } + } + + if ( !d_altRoutes->integer ) + {//bestNode would not have been set by GetBestNodeAltRoute above, so get it here + if ( ent->waypoint != NODE_NONE && goal->waypoint != NODE_NONE ) + {//have 2 valid waypoints which means a valid path + bestNode = GetBestNodeAltRoute( ent->waypoint, goal->waypoint, &bestCost, NODE_NONE ); + } + } + return bestNode; +} + +/* +------------------------- +GetNearestWaypoint +------------------------- +*/ + +int CNavigator::GetNearestNode( sharedEntity_t *ent, int lastID, int flags, int targetID ) +{ + int bestNode = NODE_NONE; + //Must have nodes + if ( m_nodes.size() == 0 ) + return NODE_NONE; + + if ( targetID == NODE_NONE ) + { + //Try and find an early match using our last node + bestNode = TestBestFirst( ent, lastID, flags ); + + if ( bestNode != NODE_NONE ) + return bestNode; + }//else can't rely on testing last, we want best to targetID + +///////////////////////////////////////////////// + +#define MAX_Z_DELTA 18 + +///////////////////////////////////////////////// + + nodeChain_l nodeChain; + nodeChain_l::iterator nci; + + //Collect all nodes within a certain radius + CollectNearestNodes( ent->r.currentOrigin, NODE_COLLECT_RADIUS, NODE_COLLECT_MAX, nodeChain ); + + vec3_t position; + int radius; + int dist, bestDist = Q3_INFINITE; + CNode *node; + + //Look through all nodes + STL_ITERATE( nci, nodeChain ) + { + node = m_nodes[(*nci).nodeID]; + + node->GetPosition( position ); + + radius = node->GetRadius(); + + if ( NodeFailed( ent, (*nci).nodeID ) ) + { + continue; + } + //Are we within the known clear radius of this node? + if ( (int)(*nci).distance < (radius*radius) ) + { + //Do a z-difference sanity check + if ( fabs( position[2] - ent->r.currentOrigin[2] ) < MAX_Z_DELTA ) + { + //Found one + return (*nci).nodeID; + } + } + + //We're not *within* this node, so... + if ( CheckedNode((*nci).nodeID,ent->s.number) == CHECKED_FAILED ) + { + continue; + } + else if ( CheckedNode((*nci).nodeID,ent->s.number) == CHECKED_FAILED ) + { + continue; + } + else + { + //Do we need a clear path? + if ( flags & NF_CLEAR_PATH ) + { + if ( TestNodePath( ent, ENTITYNUM_NONE, position, qfalse ) == false )//qtrue? + { + SetCheckedNode((*nci).nodeID,ent->s.number,CHECKED_FAILED); + continue; + } + } + + //Do we need a clear line of sight? + /* + if ( flags & NF_CLEAR_LOS ) + { + if ( TestNodeLOS( ent, position ) == false ) + { + nodeChecked[(*nci).nodeID][ent->s.number] = CHECKED_FAILED; + continue; + } + } + */ + SetCheckedNode((*nci).nodeID,ent->s.number,CHECKED_PASSED); + } + + if ( targetID != WAYPOINT_NONE ) + {//we want to find the one with the shortest route here + dist = GetPathCost( (*nci).nodeID, targetID ); + if ( dist < bestDist ) + { + bestDist = dist; + bestNode = (*nci).nodeID; + } + } + else + {//first one we find is fine + bestNode = (*nci).nodeID; + break; + } + } + + //Found one, we're done + return bestNode; +} + +/* +------------------------- +ShowPath +------------------------- +*/ + +void CNavigator::ShowPath( int start, int end ) +{ + //Validate the start position + if ( ( start < 0 ) || ( start >= (int)m_nodes.size() ) ) + return; + + //Validate the end position + if ( ( end < 0 ) || ( end >= (int)m_nodes.size() ) ) + return; + + CNode *startNode = m_nodes[ start ]; + CNode *endNode = m_nodes[ end ]; + + CNode *moveNode = startNode; + CNode *testNode = NULL; + + int bestNode; + vec3_t startPos, endPos; + + int runAway = 0; + + //Draw out our path + while ( moveNode != endNode ) + { + bestNode = GetBestNode( moveNode->GetID(), end ); + + //Some nodes may be fragmented + if ( bestNode == -1 ) + { + Com_Printf("No connection possible between node %d and %d\n", start, end ); + return; + } + + //This is our next node on the path + testNode = m_nodes[ bestNode ]; + + //Get their origins + moveNode->GetPosition( startPos ); + testNode->GetPosition( endPos ); + + //Draw the edge + //rwwFIXMEFIXME: ... + //CG_DrawEdge( startPos, endPos, EDGE_PATH ); + + //Take a new best node + moveNode = testNode; + + if ( runAway++ > 64 ) + { + Com_Printf("Potential Run-away path!\n"); + return; + } + } +} + +static std::map CheckedNodes; +void CNavigator::ClearCheckedNodes( void ) +{ + CheckedNodes.clear(); +} + +byte CNavigator::CheckedNode(int wayPoint,int ent) +{ + //assert(wayPoint>=0&&wayPoint= MAX_STORED_WAYPOINTS) + { + return CHECKED_NO; + } + assert(ent>=0&&ent::iterator f=CheckedNodes.find(wayPoint*MAX_GENTITIES+ent); + if (f!=CheckedNodes.end()) + { + return (*f).second; + } + return CHECKED_NO; +} + +void CNavigator::SetCheckedNode(int wayPoint,int ent,byte value) +{ + //assert(wayPoint>=0&&wayPoint= MAX_STORED_WAYPOINTS) + { + return; + } + assert(ent>=0&&entfailedWaypointCheckTime && ent->failedWaypointCheckTime < svs.time ) + { + int failed = 0; + //do this only once every 1 second + for ( j = 0; j < MAX_FAILED_NODES; j++ ) + { + if ( ent->failedWaypoints[j] != 0 ) + { + failed++; + //-1 because 0 is a valid node but also the default, so we add one when we add one + m_nodes[ent->failedWaypoints[j]-1]->GetPosition( nodePos ); + if ( !GVM_NAV_ClearPathToPoint( ent->s.number, ent->r.mins, ent->r.maxs, nodePos, (CONTENTS_SOLID|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP), ENTITYNUM_NONE ) ) + {//no path clear of architecture, so clear this since we can't check against entities + ent->failedWaypoints[j] = 0; + failed--; + } + //have clear architectural path, now check against ents only + else if ( GVM_NAV_ClearPathToPoint( ent->s.number, ent->r.mins, ent->r.maxs, nodePos, CONTENTS_BODY, ENTITYNUM_NONE ) ) + {//clear of ents, too, so all clear, clear this one out + ent->failedWaypoints[j] = 0; + failed--; + } + } + } + if ( !failed ) + { + ent->failedWaypointCheckTime = 0; + } + else + { + ent->failedWaypointCheckTime = svs.time + CHECK_FAILED_EDGE_INTERVAL + Q_irand( 0, 1000 ); + } + } +} + +void CNavigator::AddFailedNode( sharedEntity_t *ent, int nodeID ) +{ + int j; + for ( j = 0; j < MAX_FAILED_NODES; j++ ) + { + if ( ent->failedWaypoints[j] == 0 ) + { + ent->failedWaypoints[j] = nodeID+1;//+1 because 0 is the default value and that's a valid node, so we take the +1 out when we check the node above + if ( !ent->failedWaypointCheckTime ) + { + ent->failedWaypointCheckTime = svs.time + CHECK_FAILED_EDGE_INTITIAL; + } + return; + } + if ( ent->failedWaypoints[j] == nodeID+1 ) + {//already have this one marked as failed + return; + } + } + if ( j == MAX_FAILED_NODES )//check not needed, but... + {//ran out of failed nodes, get rid of first one, shift rest up + for ( j = 0; j < MAX_FAILED_NODES-1; j++ ) + { + ent->failedWaypoints[j] = ent->failedWaypoints[j+1]; + } + } + ent->failedWaypoints[MAX_FAILED_NODES-1] = nodeID+1; + if ( !ent->failedWaypointCheckTime ) + { + ent->failedWaypointCheckTime = svs.time + CHECK_FAILED_EDGE_INTITIAL; + } +} + +qboolean CNavigator::NodeFailed( sharedEntity_t *ent, int nodeID ) +{ + for ( int j = 0; j < MAX_FAILED_NODES; j++ ) + { + if ( (ent->failedWaypoints[j]-1) == nodeID ) + { + return qtrue; + } + } + return qfalse; +} + +qboolean CNavigator::NodesAreNeighbors( int startID, int endID ) +{//See if these 2 are neighbors + if ( startID == endID ) + { + return qfalse; + } + + CNode *start = m_nodes[startID]; + int nextID = -1; + //NOTE: we only check start because we assume all connections are 2-way + for ( int i = 0; i < start->GetNumEdges(); i++ ) + { + nextID = start->GetEdge(i); + if ( nextID == endID ) + { + return qtrue; + } + } + //not neighbors + return qfalse; +} + +void CNavigator::ClearFailedEdge( failedEdge_t *failedEdge ) +{ + if ( !failedEdge ) + { + return; + } + + //clear the edge failed flags + /* + CNode *node = m_nodes[failedEdge->startID]; + int edgeNum = node->GetEdgeNumToNode( failedEdge->endID ); + int flags; + if ( edgeNum != -1 ) + { + flags = node->GetEdgeFlags( edgeNum )&~EFLAG_FAILED; + node->SetEdgeFlags( edgeNum, flags ); + } + node = m_nodes[failedEdge->endID]; + edgeNum = node->GetEdgeNumToNode( failedEdge->startID ); + if ( edgeNum != -1 ) + { + flags = node->GetEdgeFlags( edgeNum )&~EFLAG_FAILED; + node->SetEdgeFlags( edgeNum, flags ); + } + */ + //clear failedEdge info + SetEdgeCost( failedEdge->startID, failedEdge->endID, -1 ); + failedEdge->startID = failedEdge->endID = WAYPOINT_NONE; + failedEdge->entID = ENTITYNUM_NONE; + failedEdge->checkTime = 0; +} + +void CNavigator::ClearAllFailedEdges( void ) +{ + memset( &failedEdges, WAYPOINT_NONE, sizeof( failedEdges ) ); + for ( int j = 0; j < MAX_FAILED_EDGES; j++ ) + { + ClearFailedEdge( &failedEdges[j] ); + } +} + +int CNavigator::EdgeFailed( int startID, int endID ) +{ + //OPTIMIZED WAY (bjg 01/02) + //find in lookup map + std::pair findValue; + findValue = m_edgeLookupMap.equal_range(startID); + while ( findValue.first != findValue.second ) + { + if( failedEdges[findValue.first->second].endID == endID) + { + return findValue.first->second; + } + ++findValue.first; + } + findValue = m_edgeLookupMap.equal_range(endID); + while ( findValue.first != findValue.second ) + { + if( failedEdges[findValue.first->second].endID == startID) + { + return findValue.first->second; + } + ++findValue.first; + } + + return -1; + + //Old way (linear search) + /* + for ( int j = 0; j < MAX_FAILED_EDGES; j++ ) + { + if ( failedEdges[j].startID == startID ) + { + if ( failedEdges[j].endID == endID ) + { + return j; + } + } + else if ( failedEdges[j].startID == endID ) + { + if ( failedEdges[j].endID == startID ) + { + return j; + } + } + } + return -1; + */ +} + +void CNavigator::AddFailedEdge( int entID, int startID, int endID ) +{ + int j;//, nextID; + + //Must have nodes + if ( m_nodes.size() == 0 ) + return; + + if ( d_patched->integer ) + {//use patch-style navigation + if ( startID == endID ) + {//not an edge! + return; + } + } + + //Validate the ent number + if ( ( entID < 0 ) || ( entID > ENTITYNUM_NONE ) ) + { +#ifndef FINAL_BUILD + Com_Printf( S_COLOR_RED"NAV ERROR: envalid ent %d\n", entID ); + assert(0&&"invalid entID"); +#endif + return; + } + + //Validate the start position + if ( ( startID < 0 ) || ( startID >= (int)m_nodes.size() ) ) + { +#ifndef FINAL_BUILD + Com_Printf( S_COLOR_RED"NAV ERROR: tried to fail invalid waypoint %d\n", startID ); + assert(0&&"invalid failed edge"); +#endif + return; + } + + //Validate the end position + if ( ( endID < 0 ) || ( endID >= (int)m_nodes.size() ) ) + { +#ifndef FINAL_BUILD + Com_Printf( S_COLOR_RED"NAV ERROR: tried to fail invalid waypoint %d\n", endID ); + assert(0&&"invalid failed edge"); +#endif + return; + } + + //First see if we already have this one + if ( (j = EdgeFailed( startID, endID )) != -1 ) + { + //just remember this guy instead + failedEdges[j].entID = entID; + return; + } + + //Okay, new one, find an empty slot + for ( j = 0; j < MAX_FAILED_EDGES; j++ ) + { + if ( failedEdges[j].startID == WAYPOINT_NONE ) + { + failedEdges[j].startID = startID; + failedEdges[j].endID = endID; + //Check one second from now to see if it's clear + failedEdges[j].checkTime = svs.time + CHECK_FAILED_EDGE_INTERVAL + Q_irand( 0, 1000 ); + + m_edgeLookupMap.insert(std::pair(startID, j)); + + /* + //DISABLED this for now, makes people stand around too long when + // collision avoidance just wasn't at it's best but path is clear + CNode *start = m_nodes[startID]; + CNode *end = m_nodes[endID]; + + for ( int i = 0; i < start->GetNumEdges(); i++ ) + { + nextID = start->GetEdge(i); + + if ( EdgeFailed( startID, nextID ) != -1 ) + { + //This edge blocked, check next + continue; + } + + if ( nextID == endID || end->GetRank( nextID ) >= 0 ) + {//neighbor of or route to end + //There's an alternate route, so don't check this one for 10 seconds + failedEdges[j].checkTime = svs.time + CHECK_FAILED_EDGE_INTITIAL; + break; + } + } + */ + + //Remember who needed it + failedEdges[j].entID = entID; + + //set the edge failed flags + /* + CNode *node = m_nodes[startID]; + int edgeNum = node->GetEdgeNumToNode( endID ); + int flags; + if ( edgeNum != -1 ) + { + flags = node->GetEdgeFlags( edgeNum )|EFLAG_FAILED; + node->SetEdgeFlags( edgeNum, flags ); + } + node = m_nodes[endID]; + edgeNum = node->GetEdgeNumToNode( startID ); + if ( edgeNum != -1 ) + { + flags = node->GetEdgeFlags( edgeNum )|EFLAG_FAILED; + node->SetEdgeFlags( edgeNum, flags ); + } + */ + + //stuff the index to this one in our lookup map + + //now recalc all the paths! + if ( pathsCalculated ) + { + //reconnect the nodes and mark every node's flag NF_RECALC + //Com_Printf( S_COLOR_CYAN"%d marking all nodes for recalc\n", svs.time ); + SetEdgeCost( startID, endID, Q3_INFINITE ); + FlagAllNodes( NF_RECALC ); + } + return; + } + } + +#ifndef FINAL_BUILD + Com_Printf( S_COLOR_RED"NAV ERROR: too many blocked waypoint connections (%d)!!!\n", j ); +#endif +} + +qboolean CNavigator::CheckFailedEdge( failedEdge_t *failedEdge ) +{ + if ( !failedEdge ) + { + return qfalse; + } + + //Every 1 second, see if our failed edges are clear + if ( failedEdge->checkTime < svs.time ) + { + if ( failedEdge->startID != WAYPOINT_NONE ) + { + vec3_t start, end, mins, maxs; + int ignore, clipmask; + sharedEntity_t *ent = SV_GentityNum(failedEdge->entID); //(failedEdge->entIDentID]:NULL; + int hitEntNum; + + if ( !ent || /*!ent->inuse || !ent->client || ent->health <= 0*/ (ent->s.eType != ET_PLAYER && ent->s.eType != ET_NPC) || + (ent->s.eFlags & EF_DEAD)) + { + VectorSet( mins, -15, -15, DEFAULT_MINS_2+STEPSIZE ); + VectorSet( maxs, 15, 15, DEFAULT_MAXS_2 ); + ignore = ENTITYNUM_NONE; + clipmask = MASK_NPCSOLID; + } + else + { + VectorCopy( ent->r.mins, mins ); + mins[2] += STEPSIZE; + VectorCopy( ent->r.maxs, maxs ); + ignore = failedEdge->entID; + clipmask = MASK_SOLID;//ent->clipmask; //rwwFIXMEFIXME: share clipmask? + } + + if ( maxs[2] < mins[2] ) + {//don't invert bounding box + maxs[2] = mins[2]; + } + + m_nodes[failedEdge->startID]->GetPosition( start ); + m_nodes[failedEdge->endID]->GetPosition( end ); + + //See if it's NAV_ClearPath... +#if 0 + hitEntNum = NAVNEW_ClearPathBetweenPoints( start, end, mins, maxs, ignore, clipmask|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP );//NOTE: should we really always include monsterclip (physically blocks NPCs) and botclip (do not enter)? +#else + trace_t trace; + + //Test if they're even conceivably close to one another + if ( !SV_inPVS( start, end ) ) + { + return qfalse; + } + + SV_Trace( &trace, start, mins, maxs, end, ignore, clipmask|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP, qfalse, 0, 10 );//NOTE: should we really always include monsterclip (physically blocks NPCs) and botclip (do not enter)? + + if( trace.startsolid == qtrue || trace.allsolid == qtrue ) + { + return qfalse; + } + hitEntNum = trace.entityNum; +#endif + //if we did hit something, see if it's just an auto-door and allow it + if ( hitEntNum != ENTITYNUM_NONE && GVM_NAV_EntIsUnlockedDoor( hitEntNum ) ) + { + hitEntNum = ENTITYNUM_NONE; + } + else if ( hitEntNum == failedEdge->entID ) + {//don't hit the person who initially marked the edge failed + hitEntNum = ENTITYNUM_NONE; + } + if ( hitEntNum == ENTITYNUM_NONE ) + { + //If so, clear it + ClearFailedEdge( failedEdge ); + return qtrue; + } + else + { + //Check again in one second + failedEdge->checkTime = svs.time + CHECK_FAILED_EDGE_INTERVAL + Q_irand( 0, 1000 ); + } + } + } + return qfalse; +} + +void CNavigator::CheckAllFailedEdges( void ) +{ + failedEdge_t *failedEdge; + qboolean clearedAny = qfalse; + + //Must have nodes + if ( m_nodes.size() == 0 ) + return; + + for ( int j = 0; j < MAX_FAILED_EDGES; j++ ) + { + failedEdge = &failedEdges[j]; + + clearedAny = CheckFailedEdge( failedEdge )?qtrue:clearedAny; + } + if ( clearedAny ) + {//need to recalc the paths + if ( pathsCalculated ) + { + //reconnect the nodes and mark every node's flag NF_RECALC + //Com_Printf( S_COLOR_CYAN"%d marking all nodes for recalc\n", svs.time ); + FlagAllNodes( NF_RECALC ); + } + } +} + +qboolean CNavigator::RouteBlocked( int startID, int testEdgeID, int endID, int rejectRank ) +{ + int nextID, edgeID, lastID, bestNextID = NODE_NONE; + int bestRank = rejectRank; + int testRank; + qboolean allEdgesFailed; + CNode *end; + CNode *next; + + + if ( EdgeFailed( startID, testEdgeID ) != -1 ) + { + return qtrue; + } + + if ( testEdgeID == endID ) + {//Neighbors, checked out, all clear + return qfalse; + } + + //Okay, first edge is clear, now check rest of route! + end = m_nodes[ endID ]; + nextID = testEdgeID; + lastID = startID; + + while( 1 ) + { + next = m_nodes[ nextID ]; + allEdgesFailed = qtrue; + + for ( int i = 0; i < next->GetNumEdges(); i++ ) + { + edgeID = next->GetEdge(i); + + if ( edgeID == lastID ) + {//Don't backtrack + continue; + } + + if ( edgeID == startID ) + {//Don't loop around + continue; + } + + if ( EdgeFailed( nextID, edgeID ) != -1 ) + { + //This edge blocked, check next + continue; + } + + if ( edgeID == endID ) + {//We got there all clear! + return qfalse; + } + + //Still going... + testRank = end->GetRank( edgeID ); + + if ( testRank < 0 ) + {//No route this way + continue; + } + + //Is the rank good enough? + if ( testRank < bestRank ) + { + bestNextID = edgeID; + bestRank = testRank; + allEdgesFailed = qfalse; + } + } + + if ( allEdgesFailed ) + { + //This route has no clear way of getting to end + return qtrue; + } + else + { + lastID = nextID; + nextID = bestNextID; + } + } +} + +/* +------------------------- +GetBestNodeAltRoute +------------------------- +*/ + +int CNavigator::GetBestNodeAltRoute( int startID, int endID, int *pathCost, int rejectID ) +{ + //Must have nodes + if ( m_nodes.size() == 0 ) + return WAYPOINT_NONE; + + //Validate the start position + if ( ( startID < 0 ) || ( startID >= (int)m_nodes.size() ) ) + return WAYPOINT_NONE; + + //Validate the end position + if ( ( endID < 0 ) || ( endID >= (int)m_nodes.size() ) ) + return WAYPOINT_NONE; + + //Is it the same node? + if ( startID == endID ) + { + if ( !d_altRoutes->integer || EdgeFailed( startID, endID ) == -1 ) + { + return startID; + } + else + { + return WAYPOINT_NONE; + } + } + + CNode *start = m_nodes[ startID ]; + + int bestNode = -1; + int bestRank = Q3_INFINITE; + int testRank, rejectRank = Q3_INFINITE; + int bestCost = Q3_INFINITE; + + *pathCost = 0; + + //Find the minimum rank of the edge(s) we want to reject as paths + if ( rejectID != WAYPOINT_NONE ) + { + for ( int i = 0; i < start->GetNumEdges(); i++ ) + { + if ( start->GetEdge(i) == rejectID ) + { + rejectRank = GetPathCost( startID, endID );//end->GetRank( start->GetEdge(i) ); + break; + } + } + } + + for ( int i = 0; i < start->GetNumEdges(); i++ ) + { + int edgeID = start->GetEdge(i); + + testRank = GetPathCost( edgeID, endID );//end->GetRank( edgeID ); + + //Make sure it's not worse than our reject rank + if ( testRank >= rejectRank ) + continue; + + //Found one + if ( edgeID == endID ) + { + if ( !d_altRoutes->integer || !RouteBlocked( startID, edgeID, endID, rejectRank ) ) + { + *pathCost += start->GetEdgeCost( i ); + return edgeID; + } + else + {//this is blocked, can't consider it + continue; + } + } + + //No possible connection + if ( testRank == NODE_NONE ) + { + *pathCost = Q3_INFINITE; + return NODE_NONE; + } + + //Found a better one + if ( testRank < bestRank ) + { + //FIXME: make sure all the edges down from startID through edgeID to endID + // does NOT include a failedEdge... + if ( !d_altRoutes->integer || !RouteBlocked( startID, edgeID, endID, rejectRank ) ) + { + bestNode = edgeID; + bestRank = testRank; + bestCost = start->GetEdgeCost(i)+testRank; + } + } + } + + *pathCost = bestCost; + + return bestNode; +} +/* +------------------------- +GetBestNodeAltRoute +overloaded so you don't have to pass a pathCost int pointer in +------------------------- +*/ + +int CNavigator::GetBestNodeAltRoute( int startID, int endID, int rejectID ) +{ + int junk; + return GetBestNodeAltRoute( startID, endID, &junk, rejectID ); +} +/* +------------------------- +GetBestNode +------------------------- +*/ + +int CNavigator::GetBestNode( int startID, int endID, int rejectID ) +{ + //Validate the start position + if ( ( startID < 0 ) || ( startID >= (int)m_nodes.size() ) ) + return WAYPOINT_NONE; + + //Validate the end position + if ( ( endID < 0 ) || ( endID >= (int)m_nodes.size() ) ) + return WAYPOINT_NONE; + + if ( startID == endID ) + return startID; + + CNode *start = m_nodes[ startID ]; + CNode *end = m_nodes[ endID ]; + + int bestNode = -1; + int bestRank = Q3_INFINITE; + int testRank, rejectRank = 0; + + if ( rejectID != WAYPOINT_NONE ) + { + for ( int i = 0; i < start->GetNumEdges(); i++ ) + { + if ( start->GetEdge(i) == rejectID ) + { + rejectRank = end->GetRank( start->GetEdge(i) ); + break; + } + } + } + + for ( int i = 0; i < start->GetNumEdges(); i++ ) + { + int edgeID = start->GetEdge(i); + + //Found one + if ( edgeID == endID ) + return edgeID; + + testRank = end->GetRank( edgeID ); + + //Found one + if ( testRank <= rejectRank ) + continue; + + //No possible connection + if ( testRank == NODE_NONE ) + return NODE_NONE; + + //Found a better one + if ( testRank < bestRank ) + { + bestNode = edgeID; + bestRank = testRank; + } + } + + return bestNode; +} + +/* +------------------------- +GetNodePosition +------------------------- +*/ + +int CNavigator::GetNodePosition( int nodeID, vec3_t out ) +{ + //Validate the number + if ( ( nodeID < 0 ) || ( nodeID >= (int)m_nodes.size() ) ) + return false; + + CNode *node = m_nodes[ nodeID ]; + + node->GetPosition( out ); + + return true; +} + +/* +------------------------- +GetNodeNumEdges +------------------------- +*/ + +int CNavigator::GetNodeNumEdges( int nodeID ) +{ + if ( ( nodeID < 0 ) || ( nodeID >= (int)m_nodes.size() ) ) + return -1; + + CNode *node = m_nodes[ nodeID ]; + + assert( node ); + + return node->GetNumEdges(); +} + +/* +------------------------- +GetNodeEdge +------------------------- +*/ + +int CNavigator::GetNodeEdge( int nodeID, int edge ) +{ + if ( ( nodeID < 0 ) || ( nodeID >= (int)m_nodes.size() ) ) + return -1; + + CNode *node = m_nodes[ nodeID ]; + + assert( node ); + + return node->GetEdge( edge ); +} + +/* +------------------------- +Connected +------------------------- +*/ + +bool CNavigator::Connected( int startID, int endID ) +{ + //Validate the start position + if ( ( startID < 0 ) || ( startID >= (int)m_nodes.size() ) ) + return false; + + //Validate the end position + if ( ( endID < 0 ) || ( endID >= (int)m_nodes.size() ) ) + return false; + + if ( startID == endID ) + return true; + + CNode *start = m_nodes[ startID ]; + CNode *end = m_nodes[ endID ]; + + for ( int i = 0; i < start->GetNumEdges(); i++ ) + { + int edgeID = start->GetEdge(i); + + //Found one + if ( edgeID == endID ) + return true; + + if ( ( end->GetRank( edgeID ) ) != NODE_NONE ) + return true; + } + + return false; +} + +/* +------------------------- +GetPathCost +------------------------- +*/ + +unsigned int CNavigator::GetPathCost( int startID, int endID ) +{ + //Validate the start position + if ( ( startID < 0 ) || ( startID >= (int)m_nodes.size() ) ) + return Q3_INFINITE; // return 0; + + //Validate the end position + if ( ( endID < 0 ) || ( endID >= (int)m_nodes.size() ) ) + return Q3_INFINITE; // return 0; + + CNode *startNode = m_nodes[ startID ]; + + if ( !startNode->GetNumEdges() ) + {//WTF? Solitary waypoint! Bad designer! + return Q3_INFINITE; // return 0; + } + + CNode *endNode = m_nodes[ endID ]; + + CNode *moveNode = startNode; + + int bestNode; + int pathCost = 0; + int bestCost; + + int bestRank; + int testRank; + + int dontScrewUp = 0; + + //Draw out our path + while ( moveNode != endNode ) + { + bestRank = WORLD_SIZE; + bestNode = -1; + bestCost = 0; + + for ( int i = 0; i < moveNode->GetNumEdges(); i++ ) + { + int edgeID = moveNode->GetEdge(i); + + //Done + if ( edgeID == endID ) + { + return pathCost + moveNode->GetEdgeCost( i ); + } + + testRank = endNode->GetRank( edgeID ); + + //No possible connection + if ( testRank == NODE_NONE ) + { + return Q3_INFINITE; // return 0; + } + + //Found a better one + if ( testRank < bestRank ) + { + bestNode = edgeID; + bestRank = testRank; + bestCost = moveNode->GetEdgeCost( i ); + } + } + + pathCost += bestCost; + + //Take a new best node + moveNode = m_nodes[ bestNode ]; + dontScrewUp++; + + if (dontScrewUp > 40000) + { //ok, I think something probably screwed up. + break; + } + } + + return pathCost; +} + +/* +------------------------- +GetEdgeCost +------------------------- +*/ + +unsigned int CNavigator::GetEdgeCost( int startID, int endID ) +{ + //Validate the start position + if ( ( startID < 0 ) || ( startID >= (int)m_nodes.size() ) ) + return Q3_INFINITE; // return 0; + + //Validate the end position + if ( ( endID < 0 ) || ( endID >= (int)m_nodes.size() ) ) + return Q3_INFINITE; // return 0; + + CNode *start = m_nodes[startID]; + CNode *end = m_nodes[endID]; + + return GetEdgeCost( start, end ); +} + +/* +------------------------- +GetProjectedNode +------------------------- +*/ + +int CNavigator::GetProjectedNode( vec3_t origin, int nodeID ) +{ + //Validate the start position + if ( ( nodeID < 0 ) || ( nodeID >= (int)m_nodes.size() ) ) + return NODE_NONE; + + CNode *node = m_nodes[nodeID]; + CNode *tempNode; + + float bestDot = 0.0f; + int bestNode = NODE_NONE; + + vec3_t targetDir, basePos, tempDir, tempPos; + float dot; + + //Setup our target direction + node->GetPosition( basePos ); + + VectorSubtract( origin, basePos, targetDir ); + VectorNormalize( targetDir ); + + //Go through all the edges + for ( int i = 0; i < node->GetNumEdges(); i++ ) + { + tempNode = m_nodes[node->GetEdge(i)]; + tempNode->GetPosition( tempPos ); + + VectorSubtract( tempPos, basePos, tempDir ); + VectorNormalize( tempDir ); //FIXME: Retain the length here if you want it + + dot = DotProduct( targetDir, tempDir ); + + if ( dot < 0.0f ) + continue; + + if ( dot > bestDot ) + { + bestDot = dot; + bestNode = tempNode->GetID(); + } + } + + return bestNode; +} + +// This is the PriorityQueue stuff for lists of connections +// better than linear (1/21/02 BJG) +////////////////////////////////////////////////////////////////// +// Helper pop_mHeap algorithm class +////////////////////////////////////////////////////////////////// +class NodeTotalGreater +{ +public: + bool operator()( CEdge * first, CEdge * second ) const { + return( first->m_cost > second->m_cost ); + } +}; + + +////////////////////////////////////////////////////////////////// +// Destructor - Deallocate any remaining pointers in the queue +////////////////////////////////////////////////////////////////// +CPriorityQueue::~CPriorityQueue() +{ + while (!Empty()) + { + delete Pop(); + } +} + +////////////////////////////////////////////////////////////////// +// Standard Iterative Search +////////////////////////////////////////////////////////////////// +CEdge* CPriorityQueue::Find(int npNum) +{ + for(std::vector::iterator HeapIter=mHeap.begin(); HeapIter!=mHeap.end(); ++HeapIter) + { + if ((*HeapIter)->m_first == npNum) + { + return *HeapIter; + } + } + return 0; +} + +////////////////////////////////////////////////////////////////// +// Remove Node And Resort +////////////////////////////////////////////////////////////////// +CEdge* CPriorityQueue::Pop() +{ + CEdge *edge = mHeap.front(); + + //pop_mHeap will move the node at the front to the position N + //and then sort the mHeap to make positions 1 through N-1 correct + //(STL makes no assumptions about your data and doesn't want to change + //the size of the container.) + std::pop_heap(mHeap.begin(), mHeap.end(), NodeTotalGreater() ); + + //pop_back() will actually remove the last element from the mHeap + //now the mHeap is sorted for positions 1 through N + mHeap.pop_back(); + + return( edge ); +} + +////////////////////////////////////////////////////////////////// +// Add New Node And Resort +////////////////////////////////////////////////////////////////// +void CPriorityQueue::Push(CEdge* theEdge ) +{ + //Pushes the node onto the back of the mHeap + mHeap.push_back( theEdge ); + + //Sorts the new element into the mHeap + std::push_heap( mHeap.begin(), mHeap.end(), NodeTotalGreater() ); +} + +////////////////////////////////////////////////////////////////// +// Find The Node In Question And Resort mHeap Around It +////////////////////////////////////////////////////////////////// +void CPriorityQueue::Update( CEdge* edge ) +{ + for(std::vector::iterator i=mHeap.begin(); i!=mHeap.end(); ++i) + { + if( (*i)->m_first == edge->m_first ) + { //Found node - resort from this position in the mHeap + //(its total value was changed before this function was called) + std::push_heap( mHeap.begin(), i+1, NodeTotalGreater() ); + return; + } + } +} + +////////////////////////////////////////////////////////////////// +// Just a wrapper for stl empty function. +////////////////////////////////////////////////////////////////// +bool CPriorityQueue::Empty() +{ + return( mHeap.empty() ); +}; + diff --git a/Projects/Android/jni/OpenJK/codemp_delete/server/NPCNav/navigator.h b/Projects/Android/jni/OpenJK/codemp_delete/server/NPCNav/navigator.h new file mode 100644 index 0000000..d026322 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/server/NPCNav/navigator.h @@ -0,0 +1,288 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#pragma once + +#define __NEWCOLLECT 1 + +#define _HARD_CONNECT 1 + +//Node flags +#define NF_ANY 0 +#define NF_CLEAR_PATH 0x00000002 +#define NF_RECALC 0x00000004 + +//Edge flags +#define EFLAG_NONE 0 +#define EFLAG_BLOCKED 0x00000001 +#define EFLAG_FAILED 0x00000002 + +#include +#include +#include + +#include "server/server.h" +#include "qcommon/q_shared.h" + +//Miscellaneous defines +#define NODE_NONE -1 +#define NAV_HEADER_ID INT_ID('J','N','V','5') +#define NODE_HEADER_ID INT_ID('N','O','D','E') + +typedef std::multimap EdgeMultimap; +typedef EdgeMultimap::iterator EdgeMultimapIt; + + +/* +------------------------- +CEdge +------------------------- +*/ + +class CEdge +{ + +public: + + CEdge( void ) : m_first(-1), m_second(-1), m_cost(-1) {} + CEdge( int first, int second, int cost ); + ~CEdge( void ); + + int m_first; + int m_second; + int m_cost; +}; + +/* +------------------------- +CNode +------------------------- +*/ + +class CNode +{ + typedef struct edge_s + { + int ID; + int cost; + byte flags; + } edge_t; + + typedef std::vector< edge_t > edge_v; + +public: + + CNode( void ); + ~CNode( void ); + + static CNode *Create( vec3_t position, int flags, int radius, int ID ); + static CNode *Create( void ); + + void AddEdge( int ID, int cost, int flags = EFLAG_NONE ); + void AddRank( int ID, int rank ); + + void Draw( qboolean radius ); + + int GetID( void ) const { return m_ID; } + void GetPosition( vec3_t position ) const { if ( position ) VectorCopy( m_position, position ); } + + int GetNumEdges( void ) const { return m_numEdges; } + int GetEdgeNumToNode( int ID ); + int GetEdge( int edgeNum ); + int GetEdgeCost( int edgeNum ); + byte GetEdgeFlags( int edgeNum ); + void SetEdgeFlags( int edgeNum, int newFlags ); + int GetRadius( void ) const { return m_radius; } + + void InitRanks( int size ); + int GetRank( int ID ); + + int GetFlags( void ) const { return m_flags; } + void AddFlag( int newFlag ) { m_flags |= newFlag; } + void RemoveFlag( int oldFlag ) { m_flags &= ~oldFlag; } + + int Save( int numNodes, fileHandle_t file ); + int Load( int numNodes, fileHandle_t file ); + +protected: + + vec3_t m_position; + int m_flags; + int m_radius; + int m_ID; + + edge_v m_edges; + + int *m_ranks; + int m_numEdges; +}; + +/* +------------------------- +CNavigator +------------------------- +*/ +#define MAX_FAILED_EDGES 32 +class CNavigator +{ + typedef std::vector < CNode * > node_v; + typedef std::list < CEdge > edge_l; + +#if __NEWCOLLECT + + struct nodeList_t + { + int nodeID; + unsigned int distance; + }; + + typedef std::list < nodeList_t > nodeChain_l; + +#endif //__NEWCOLLECT + +public: + + CNavigator( void ); + ~CNavigator( void ); + + void Init( void ); + void Free( void ); + + bool Load( const char *filename, int checksum ); + bool Save( const char *filename, int checksum ); + + int AddRawPoint( vec3_t point, int flags, int radius ); + void CalculatePaths( qboolean recalc=qfalse ); + +#if _HARD_CONNECT + + void HardConnect( int first, int second ); + +#endif + + void ShowNodes( void ); + void ShowEdges( void ); + void ShowPath( int start, int end ); + + int GetNearestNode( sharedEntity_t *ent, int lastID, int flags, int targetID ); + + int GetBestNode( int startID, int endID, int rejectID = NODE_NONE ); + + int GetNodePosition( int nodeID, vec3_t out ); + int GetNodeNumEdges( int nodeID ); + int GetNodeEdge( int nodeID, int edge ); + float GetNodeLeadDistance( int nodeID ); + + int GetNumNodes( void ) const { return (int)m_nodes.size(); } + + bool Connected( int startID, int endID ); + + unsigned int GetPathCost( int startID, int endID ); + unsigned int GetEdgeCost( int startID, int endID ); + + int GetProjectedNode( vec3_t origin, int nodeID ); +//MCG Added BEGIN + void CheckFailedNodes( sharedEntity_t *ent ); + void AddFailedNode( sharedEntity_t *ent, int nodeID ); + qboolean NodeFailed( sharedEntity_t *ent, int nodeID ); + qboolean NodesAreNeighbors( int startID, int endID ); + void ClearFailedEdge( failedEdge_t *failedEdge ); + void ClearAllFailedEdges( void ); + int EdgeFailed( int startID, int endID ); + void AddFailedEdge( int entID, int startID, int endID ); + qboolean CheckFailedEdge( failedEdge_t *failedEdge ); + void CheckAllFailedEdges( void ); + qboolean RouteBlocked( int startID, int testEdgeID, int endID, int rejectRank ); + int GetBestNodeAltRoute( int startID, int endID, int *pathCost, int rejectID = NODE_NONE ); + int GetBestNodeAltRoute( int startID, int endID, int rejectID = NODE_NONE ); + int GetBestPathBetweenEnts( sharedEntity_t *ent, sharedEntity_t *goal, int flags ); + int GetNodeRadius( int nodeID ); + void CheckBlockedEdges( void ); + void ClearCheckedNodes( void ); + byte CheckedNode(int wayPoint,int ent); + void SetCheckedNode(int wayPoint,int ent,byte value); + + void FlagAllNodes( int newFlag ); + + qboolean pathsCalculated; +//MCG Added END + +protected: + + int TestNodePath( sharedEntity_t *ent, int okToHitEntNum, vec3_t position, qboolean includeEnts ); + int TestNodeLOS( sharedEntity_t *ent, vec3_t position ); + int TestBestFirst( sharedEntity_t *ent, int lastID, int flags ); + +#if __NEWCOLLECT + int CollectNearestNodes( vec3_t origin, int radius, int maxCollect, nodeChain_l &nodeChain ); +#else + int CollectNearestNodes( vec3_t origin, int radius, int maxCollect, int *nodeChain ); +#endif //__NEWCOLLECT + + char GetChar( fileHandle_t file ); + int GetInt( fileHandle_t file ); + float GetFloat( fileHandle_t file ); + long GetLong( fileHandle_t file ); + + void SetEdgeCost( int ID1, int ID2, int cost ); + int GetEdgeCost( CNode *first, CNode *second ); + void AddNodeEdges( CNode *node, int addDist, edge_l &edgeList, bool *checkedNodes ); + + void CalculatePath( CNode *node ); + + //rww - made failedEdges private as it doesn't seem to need to be public. + //And I'd rather shoot myself than have to devise a way of setting/accessing this + //array via trap calls. + failedEdge_t failedEdges[MAX_FAILED_EDGES]; + + node_v m_nodes; + EdgeMultimap m_edgeLookupMap; +}; + +////////////////////////////////////////////////////////////////////// +// class Priority Queue +////////////////////////////////////////////////////////////////////// +class CPriorityQueue +{ +// CONSTRUCTION /DESTRUCTION +//-------------------------------------------------------------- +public: + CPriorityQueue() {}; + ~CPriorityQueue(); + +// Functionality +//-------------------------------------------------------------- +public: + CEdge* Pop(); + CEdge* Find(int npNum); + void Push( CEdge* theEdge ); + void Update(CEdge* edge ); + bool Empty(); + + +// DATA +//-------------------------------------------------------------- +private: + std::vector mHeap; +}; + +extern CNavigator navigator; diff --git a/Projects/Android/jni/OpenJK/codemp/server/server.h b/Projects/Android/jni/OpenJK/codemp_delete/server/server.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/server/server.h rename to Projects/Android/jni/OpenJK/codemp_delete/server/server.h diff --git a/Projects/Android/jni/OpenJK/codemp_delete/server/sv_bot.cpp b/Projects/Android/jni/OpenJK/codemp_delete/server/sv_bot.cpp new file mode 100644 index 0000000..3dfa473 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/server/sv_bot.cpp @@ -0,0 +1,814 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +// sv_bot.c +#include "server.h" +#include "botlib/botlib.h" +#include "qcommon/cm_public.h" +#include "server/sv_gameapi.h" + +typedef struct bot_debugpoly_s +{ + int inuse; + int color; + int numPoints; + vec3_t points[128]; +} bot_debugpoly_t; + +static bot_debugpoly_t *debugpolygons; +int bot_maxdebugpolys; + +extern botlib_export_t *botlib_export; +int bot_enable; + +static int gWPNum = 0; +static wpobject_t *gWPArray[MAX_WPARRAY_SIZE]; + +static int NotWithinRange(int base, int extent) +{ + if (extent > base && base+5 >= extent) + { + return 0; + } + + if (extent < base && base-5 <= extent) + { + return 0; + } + + return 1; +} + +int SV_OrgVisibleBox(vec3_t org1, vec3_t mins, vec3_t maxs, vec3_t org2, int ignore) +{ + trace_t tr; + + + SV_Trace(&tr, org1, mins, maxs, org2, ignore, MASK_SOLID, 0, 0, 10); + + if (tr.fraction == 1 && !tr.startsolid && !tr.allsolid) + { + return 1; + } + + return 0; +} + +void *BotVMShift( intptr_t ptr ); + +void SV_BotWaypointReception(int wpnum, wpobject_t **wps) +{ + int i = 0; + + gWPNum = wpnum; + + while (i < gWPNum) + { + gWPArray[i] = wps[i]; + i++; + } +} + +/* +================== +SV_BotCalculatePaths +================== +*/ +void SV_BotCalculatePaths( int /*rmg*/ ) +{ + int i; + int c; + int forceJumpable; + int maxNeighborDist = MAX_NEIGHBOR_LINK_DISTANCE; + float nLDist; + vec3_t a; + vec3_t mins, maxs; + + if (!gWPNum) + { + return; + } + + mins[0] = -15; + mins[1] = -15; + mins[2] = -15; //-1 + maxs[0] = 15; + maxs[1] = 15; + maxs[2] = 15; //1 + + //now clear out all the neighbor data before we recalculate + i = 0; + + while (i < gWPNum) + { + if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i]->neighbornum) + { + while (gWPArray[i]->neighbornum >= 0) + { + gWPArray[i]->neighbors[gWPArray[i]->neighbornum].num = 0; + gWPArray[i]->neighbors[gWPArray[i]->neighbornum].forceJumpTo = 0; + gWPArray[i]->neighbornum--; + } + gWPArray[i]->neighbornum = 0; + } + + i++; + } + + i = 0; + + while (i < gWPNum) + { + if (gWPArray[i] && gWPArray[i]->inuse) + { + c = 0; + + while (c < gWPNum) + { + if (gWPArray[c] && gWPArray[c]->inuse && i != c && + NotWithinRange(i, c)) + { + VectorSubtract(gWPArray[i]->origin, gWPArray[c]->origin, a); + + nLDist = VectorLength(a); + forceJumpable = qfalse;//CanForceJumpTo(i, c, nLDist); + + if ((nLDist < maxNeighborDist || forceJumpable) && + ((int)gWPArray[i]->origin[2] == (int)gWPArray[c]->origin[2] || forceJumpable) && + (SV_OrgVisibleBox(gWPArray[i]->origin, mins, maxs, gWPArray[c]->origin, ENTITYNUM_NONE) || forceJumpable)) + { + gWPArray[i]->neighbors[gWPArray[i]->neighbornum].num = c; + if (forceJumpable && ((int)gWPArray[i]->origin[2] != (int)gWPArray[c]->origin[2] || nLDist < maxNeighborDist)) + { + gWPArray[i]->neighbors[gWPArray[i]->neighbornum].forceJumpTo = 999;//forceJumpable; //FJSR + } + else + { + gWPArray[i]->neighbors[gWPArray[i]->neighbornum].forceJumpTo = 0; + } + gWPArray[i]->neighbornum++; + } + + if (gWPArray[i]->neighbornum >= MAX_NEIGHBOR_SIZE) + { + break; + } + } + c++; + } + } + i++; + } +} + +/* +================== +SV_BotAllocateClient +================== +*/ +int SV_BotAllocateClient(void) { + int i; + client_t *cl; + + // find a client slot + for ( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ ) { + if ( cl->state == CS_FREE ) { + break; + } + } + + if ( i == sv_maxclients->integer ) { + return -1; + } + + cl->gentity = SV_GentityNum( i ); + cl->gentity->s.number = i; + cl->state = CS_ACTIVE; + cl->lastPacketTime = svs.time; + cl->netchan.remoteAddress.type = NA_BOT; + cl->rate = 16384; + + // cannot start recording auto demos here since bot's name is not set yet + return i; +} + +/* +================== +SV_BotFreeClient +================== +*/ +void SV_BotFreeClient( int clientNum ) { + client_t *cl; + + if ( clientNum < 0 || clientNum >= sv_maxclients->integer ) { + Com_Error( ERR_DROP, "SV_BotFreeClient: bad clientNum: %i", clientNum ); + } + cl = &svs.clients[clientNum]; + cl->state = CS_FREE; + cl->name[0] = 0; + if ( cl->gentity ) { + cl->gentity->r.svFlags &= ~SVF_BOT; + } + + if ( cl->demo.demorecording ) { + SV_StopRecordDemo( cl ); + } +} + +/* +================== +BotDrawDebugPolygons +================== +*/ +void BotDrawDebugPolygons(void (*drawPoly)(int color, int numPoints, float *points), int value) { + static cvar_t *bot_debug, *bot_groundonly, *bot_reachability, *bot_highlightarea; + bot_debugpoly_t *poly; + int i, parm0; + + if (!debugpolygons) + return; + //bot debugging + if (!bot_debug) bot_debug = Cvar_Get("bot_debug", "0", 0); + // + if (bot_enable && bot_debug->integer) { + //show reachabilities + if (!bot_reachability) bot_reachability = Cvar_Get("bot_reachability", "0", 0); + //show ground faces only + if (!bot_groundonly) bot_groundonly = Cvar_Get("bot_groundonly", "1", 0); + //get the hightlight area + if (!bot_highlightarea) bot_highlightarea = Cvar_Get("bot_highlightarea", "0", 0); + // + parm0 = 0; + if (svs.clients[0].lastUsercmd.buttons & BUTTON_ATTACK) parm0 |= 1; + if (bot_reachability->integer) parm0 |= 2; + if (bot_groundonly->integer) parm0 |= 4; + botlib_export->BotLibVarSet("bot_highlightarea", bot_highlightarea->string); + botlib_export->Test(parm0, NULL, svs.clients[0].gentity->r.currentOrigin, + svs.clients[0].gentity->r.currentAngles); + } //end if + //draw all debug polys + for (i = 0; i < bot_maxdebugpolys; i++) { + poly = &debugpolygons[i]; + if (!poly->inuse) continue; + drawPoly(poly->color, poly->numPoints, (float *) poly->points); + //Com_Printf("poly %i, numpoints = %d\n", i, poly->numPoints); + } +} + +/* +================== +BotImport_Print +================== +*/ +void QDECL BotImport_Print(int type, char *fmt, ...) +{ + char str[2048]; + va_list ap; + + va_start(ap, fmt); + Q_vsnprintf(str, sizeof(str), fmt, ap); + va_end(ap); + + switch(type) { + case PRT_MESSAGE: { + Com_Printf("%s", str); + break; + } + case PRT_WARNING: { + Com_Printf(S_COLOR_YELLOW "Warning: %s", str); + break; + } + case PRT_ERROR: { + Com_Printf(S_COLOR_RED "Error: %s", str); + break; + } + case PRT_FATAL: { + Com_Printf(S_COLOR_RED "Fatal: %s", str); + break; + } + case PRT_EXIT: { + Com_Error(ERR_DROP, S_COLOR_RED "Exit: %s", str); + break; + } + default: { + Com_Printf("unknown print type\n"); + break; + } + } +} + +/* +================== +BotImport_Trace +================== +*/ +void BotImport_Trace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask) { + trace_t trace; + + SV_Trace(&trace, start, mins, maxs, end, passent, contentmask, qfalse, 0, 10); + //copy the trace information + bsptrace->allsolid = (qboolean)trace.allsolid; + bsptrace->startsolid = (qboolean)trace.startsolid; + bsptrace->fraction = trace.fraction; + VectorCopy(trace.endpos, bsptrace->endpos); + bsptrace->plane.dist = trace.plane.dist; + VectorCopy(trace.plane.normal, bsptrace->plane.normal); + bsptrace->plane.signbits = trace.plane.signbits; + bsptrace->plane.type = trace.plane.type; + bsptrace->surface.value = trace.surfaceFlags; + bsptrace->ent = trace.entityNum; + bsptrace->exp_dist = 0; + bsptrace->sidenum = 0; + bsptrace->contents = 0; +} + +/* +================== +BotImport_EntityTrace +================== +*/ +void BotImport_EntityTrace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int entnum, int contentmask) { + trace_t trace; + + SV_ClipToEntity(&trace, start, mins, maxs, end, entnum, contentmask, qfalse); + //copy the trace information + bsptrace->allsolid = (qboolean)trace.allsolid; + bsptrace->startsolid = (qboolean)trace.startsolid; + bsptrace->fraction = trace.fraction; + VectorCopy(trace.endpos, bsptrace->endpos); + bsptrace->plane.dist = trace.plane.dist; + VectorCopy(trace.plane.normal, bsptrace->plane.normal); + bsptrace->plane.signbits = trace.plane.signbits; + bsptrace->plane.type = trace.plane.type; + bsptrace->surface.value = trace.surfaceFlags; + bsptrace->ent = trace.entityNum; + bsptrace->exp_dist = 0; + bsptrace->sidenum = 0; + bsptrace->contents = 0; +} + + +/* +================== +BotImport_PointContents +================== +*/ +int BotImport_PointContents(vec3_t point) { + return SV_PointContents(point, -1); +} + +/* +================== +BotImport_inPVS +================== +*/ +int BotImport_inPVS(vec3_t p1, vec3_t p2) { + return SV_inPVS (p1, p2); +} + +/* +================== +BotImport_BSPEntityData +================== +*/ +char *BotImport_BSPEntityData(void) { + return CM_EntityString(); +} + +/* +================== +BotImport_BSPModelMinsMaxsOrigin +================== +*/ +void BotImport_BSPModelMinsMaxsOrigin(int modelnum, vec3_t angles, vec3_t outmins, vec3_t outmaxs, vec3_t origin) { + clipHandle_t h; + vec3_t mins, maxs; + float max; + int i; + + h = CM_InlineModel(modelnum); + CM_ModelBounds(h, mins, maxs); + //if the model is rotated + if ((angles[0] || angles[1] || angles[2])) { + // expand for rotation + + max = RadiusFromBounds(mins, maxs); + for (i = 0; i < 3; i++) { + mins[i] = -max; + maxs[i] = max; + } + } + if (outmins) VectorCopy(mins, outmins); + if (outmaxs) VectorCopy(maxs, outmaxs); + if (origin) VectorClear(origin); +} + +/* +================== +BotImport_GetMemoryGame +================== +*/ +void *Bot_GetMemoryGame(int size) { + void *ptr; + + ptr = Z_Malloc( size, TAG_BOTGAME, qtrue ); + + return ptr; +} + +/* +================== +BotImport_FreeMemoryGame +================== +*/ +void Bot_FreeMemoryGame(void *ptr) { + Z_Free(ptr); +} + +/* +================== +BotImport_GetMemory +================== +*/ +void *BotImport_GetMemory(int size) { + void *ptr; + + ptr = Z_Malloc( size, TAG_BOTLIB, qtrue ); + return ptr; +} + +/* +================== +BotImport_FreeMemory +================== +*/ +void BotImport_FreeMemory(void *ptr) { + Z_Free(ptr); +} + +/* +================= +BotImport_HunkAlloc +================= +*/ +void *BotImport_HunkAlloc( int size ) { + if( Hunk_CheckMark() ) { + Com_Error( ERR_DROP, "SV_Bot_HunkAlloc: Alloc with marks already set\n" ); + } + return Hunk_Alloc( size, h_high ); +} + +/* +================== +BotImport_DebugPolygonCreate +================== +*/ +int BotImport_DebugPolygonCreate(int color, int numPoints, vec3_t *points) { + bot_debugpoly_t *poly; + int i; + + if (!debugpolygons) + return 0; + + for (i = 1; i < bot_maxdebugpolys; i++) { + if (!debugpolygons[i].inuse) + break; + } + if (i >= bot_maxdebugpolys) + return 0; + poly = &debugpolygons[i]; + poly->inuse = qtrue; + poly->color = color; + poly->numPoints = numPoints; + Com_Memcpy(poly->points, points, numPoints * sizeof(vec3_t)); + // + return i; +} + +/* +================== +BotImport_DebugPolygonShow +================== +*/ +void BotImport_DebugPolygonShow(int id, int color, int numPoints, vec3_t *points) { + bot_debugpoly_t *poly; + + if (!debugpolygons) return; + poly = &debugpolygons[id]; + poly->inuse = qtrue; + poly->color = color; + poly->numPoints = numPoints; + Com_Memcpy(poly->points, points, numPoints * sizeof(vec3_t)); +} + +/* +================== +BotImport_DebugPolygonDelete +================== +*/ +void BotImport_DebugPolygonDelete(int id) +{ + if (!debugpolygons) return; + debugpolygons[id].inuse = qfalse; +} + +/* +================== +BotImport_DebugLineCreate +================== +*/ +int BotImport_DebugLineCreate(void) { + vec3_t points[1]; + return BotImport_DebugPolygonCreate(0, 0, points); +} + +/* +================== +BotImport_DebugLineDelete +================== +*/ +void BotImport_DebugLineDelete(int line) { + BotImport_DebugPolygonDelete(line); +} + +/* +================== +BotImport_DebugLineShow +================== +*/ +void BotImport_DebugLineShow(int line, vec3_t start, vec3_t end, int color) { + vec3_t points[4], dir, cross, up = {0, 0, 1}; + float dot; + + VectorCopy(start, points[0]); + VectorCopy(start, points[1]); + //points[1][2] -= 2; + VectorCopy(end, points[2]); + //points[2][2] -= 2; + VectorCopy(end, points[3]); + + + VectorSubtract(end, start, dir); + VectorNormalize(dir); + dot = DotProduct(dir, up); + if (dot > 0.99 || dot < -0.99) VectorSet(cross, 1, 0, 0); + else CrossProduct(dir, up, cross); + + VectorNormalize(cross); + + VectorMA(points[0], 2, cross, points[0]); + VectorMA(points[1], -2, cross, points[1]); + VectorMA(points[2], -2, cross, points[2]); + VectorMA(points[3], 2, cross, points[3]); + + BotImport_DebugPolygonShow(line, color, 4, points); +} + +/* +================== +SV_BotClientCommand +================== +*/ +void BotClientCommand( int client, char *command ) { + SV_ExecuteClientCommand( &svs.clients[client], command, qtrue ); +} + +/* +================== +SV_BotFrame +================== +*/ +void SV_BotFrame( int time ) { + if (!bot_enable) + return; + //NOTE: maybe the game is already shutdown + if (!svs.gameStarted) + return; + GVM_BotAIStartFrame( time ); +} + +/* +=============== +SV_BotLibSetup +=============== +*/ +int SV_BotLibSetup( void ) { + if (!bot_enable) { + return 0; + } + + if ( !botlib_export ) { + Com_Printf( S_COLOR_RED "Error: SV_BotLibSetup without SV_BotInitBotLib\n" ); + return -1; + } + + return botlib_export->BotLibSetup(); +} + +/* +=============== +SV_ShutdownBotLib + +Called when either the entire server is being killed, or +it is changing to a different game directory. +=============== +*/ +int SV_BotLibShutdown( void ) { + + if ( !botlib_export ) { + return -1; + } + + return botlib_export->BotLibShutdown(); +} + +/* +================== +SV_BotInitCvars +================== +*/ +void SV_BotInitCvars(void) { + + Cvar_Get("bot_enable", "1", 0); //enable the bot + Cvar_Get("bot_developer", "0", CVAR_CHEAT); //bot developer mode + Cvar_Get("bot_debug", "0", CVAR_CHEAT); //enable bot debugging + Cvar_Get("bot_maxdebugpolys", "2", 0); //maximum number of debug polys + Cvar_Get("bot_groundonly", "1", 0); //only show ground faces of areas + Cvar_Get("bot_reachability", "0", 0); //show all reachabilities to other areas + Cvar_Get("bot_visualizejumppads", "0", CVAR_CHEAT); //show jumppads + Cvar_Get("bot_forceclustering", "0", 0); //force cluster calculations + Cvar_Get("bot_forcereachability", "0", 0); //force reachability calculations + Cvar_Get("bot_forcewrite", "0", 0); //force writing aas file + Cvar_Get("bot_aasoptimize", "0", 0); //no aas file optimisation + Cvar_Get("bot_saveroutingcache", "0", 0); //save routing cache + Cvar_Get("bot_thinktime", "100", CVAR_CHEAT); //msec the bots thinks + Cvar_Get("bot_reloadcharacters", "0", 0); //reload the bot characters each time + Cvar_Get("bot_testichat", "0", 0); //test ichats + Cvar_Get("bot_testrchat", "0", 0); //test rchats + Cvar_Get("bot_testsolid", "0", CVAR_CHEAT); //test for solid areas + Cvar_Get("bot_testclusters", "0", CVAR_CHEAT); //test the AAS clusters + Cvar_Get("bot_fastchat", "0", 0); //fast chatting bots + Cvar_Get("bot_nochat", "0", 0); //disable chats + Cvar_Get("bot_pause", "0", CVAR_CHEAT); //pause the bots thinking + Cvar_Get("bot_report", "0", CVAR_CHEAT); //get a full report in ctf + Cvar_Get("bot_grapple", "0", 0); //enable grapple + Cvar_Get("bot_rocketjump", "1", 0); //enable rocket jumping + Cvar_Get("bot_challenge", "0", 0); //challenging bot + Cvar_Get("bot_minplayers", "0", 0); //minimum players in a team or the game + Cvar_Get("bot_interbreedchar", "", CVAR_CHEAT); //bot character used for interbreeding + Cvar_Get("bot_interbreedbots", "10", CVAR_CHEAT); //number of bots used for interbreeding + Cvar_Get("bot_interbreedcycle", "20", CVAR_CHEAT); //bot interbreeding cycle + Cvar_Get("bot_interbreedwrite", "", CVAR_CHEAT); //write interbreeded bots to this file +} + +extern botlib_export_t *GetBotLibAPI( int apiVersion, botlib_import_t *import ); + +// there's no such thing as this now, since the zone is unlimited, but I have to provide something +// so it doesn't run out of control alloc-wise (since the bot code calls this in a while() loop to free +// up bot mem until zone has > 1MB available again. So, simulate a reasonable limit... +// +static int bot_Z_AvailableMemory(void) +{ + const int iMaxBOTLIBMem = 8 * 1024 * 1024; // adjust accordingly. + return iMaxBOTLIBMem - Z_MemSize( TAG_BOTLIB ); +} + +/* +================== +SV_BotInitBotLib +================== +*/ +void SV_BotInitBotLib(void) { + botlib_import_t botlib_import; + + if (debugpolygons) Z_Free(debugpolygons); + bot_maxdebugpolys = Cvar_VariableIntegerValue("bot_maxdebugpolys"); + debugpolygons = (struct bot_debugpoly_s *)Z_Malloc(sizeof(bot_debugpoly_t) * bot_maxdebugpolys, TAG_BOTLIB, qtrue); + + botlib_import.Print = BotImport_Print; + botlib_import.Trace = BotImport_Trace; + botlib_import.EntityTrace = BotImport_EntityTrace; + botlib_import.PointContents = BotImport_PointContents; + botlib_import.inPVS = BotImport_inPVS; + botlib_import.BSPEntityData = BotImport_BSPEntityData; + botlib_import.BSPModelMinsMaxsOrigin = BotImport_BSPModelMinsMaxsOrigin; + botlib_import.BotClientCommand = BotClientCommand; + + //memory management + botlib_import.GetMemory = BotImport_GetMemory; + botlib_import.FreeMemory = BotImport_FreeMemory; + botlib_import.AvailableMemory = bot_Z_AvailableMemory; //Z_AvailableMemory; + botlib_import.HunkAlloc = BotImport_HunkAlloc; + + // file system access + botlib_import.FS_FOpenFile = FS_FOpenFileByMode; + botlib_import.FS_Read = FS_Read; + botlib_import.FS_Write = FS_Write; + botlib_import.FS_FCloseFile = FS_FCloseFile; + botlib_import.FS_Seek = FS_Seek; + + //debug lines + botlib_import.DebugLineCreate = BotImport_DebugLineCreate; + botlib_import.DebugLineDelete = BotImport_DebugLineDelete; + botlib_import.DebugLineShow = BotImport_DebugLineShow; + + //debug polygons + botlib_import.DebugPolygonCreate = BotImport_DebugPolygonCreate; + botlib_import.DebugPolygonDelete = BotImport_DebugPolygonDelete; + + botlib_export = (botlib_export_t *)GetBotLibAPI( BOTLIB_API_VERSION, &botlib_import ); + assert(botlib_export); +} + + +// +// * * * BOT AI CODE IS BELOW THIS POINT * * * +// + +/* +================== +SV_BotGetConsoleMessage +================== +*/ +int SV_BotGetConsoleMessage( int client, char *buf, int size ) +{ + client_t *cl; + int index; + + cl = &svs.clients[client]; + cl->lastPacketTime = svs.time; + + if ( cl->reliableAcknowledge == cl->reliableSequence ) { + return qfalse; + } + + cl->reliableAcknowledge++; + index = cl->reliableAcknowledge & ( MAX_RELIABLE_COMMANDS - 1 ); + + if ( !cl->reliableCommands[index][0] ) { + return qfalse; + } + + Q_strncpyz( buf, cl->reliableCommands[index], size ); + return qtrue; +} + +#if 0 +/* +================== +EntityInPVS +================== +*/ +int EntityInPVS( int client, int entityNum ) { + client_t *cl; + clientSnapshot_t *frame; + int i; + + cl = &svs.clients[client]; + frame = &cl->frames[cl->netchan.outgoingSequence & PACKET_MASK]; + for ( i = 0; i < frame->num_entities; i++ ) { + if ( svs.snapshotEntities[(frame->first_entity + i) % svs.numSnapshotEntities].number == entityNum ) { + return qtrue; + } + } + return qfalse; +} +#endif + +/* +================== +SV_BotGetSnapshotEntity +================== +*/ +int SV_BotGetSnapshotEntity( int client, int sequence ) { + client_t *cl; + clientSnapshot_t *frame; + + cl = &svs.clients[client]; + frame = &cl->frames[cl->netchan.outgoingSequence & PACKET_MASK]; + if (sequence < 0 || sequence >= frame->num_entities) { + return -1; + } + return svs.snapshotEntities[(frame->first_entity + sequence) % svs.numSnapshotEntities].number; +} + diff --git a/Projects/Android/jni/OpenJK/codemp/server/sv_ccmds.cpp b/Projects/Android/jni/OpenJK/codemp_delete/server/sv_ccmds.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/server/sv_ccmds.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/server/sv_ccmds.cpp diff --git a/Projects/Android/jni/OpenJK/codemp_delete/server/sv_challenge.cpp b/Projects/Android/jni/OpenJK/codemp_delete/server/sv_challenge.cpp new file mode 100644 index 0000000..147c48d --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/server/sv_challenge.cpp @@ -0,0 +1,186 @@ +/* +=========================================================================== +Copyright (C) 2013 - 2016, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +// sv_challenge.cpp -- stateless challenge creation and verification functions + +#include "server.h" +#include "qcommon/md5.h" + +//#define DEBUG_SV_CHALLENGE // Enable for Com_DPrintf debugging output + +static const size_t SECRET_KEY_LENGTH = MD5_DIGEST_SIZE; // Key length equal to digest length is adequate + +static qboolean challengerInitialized = qfalse; +static hmacMD5Context_t challenger; + +#ifdef DEBUG_SV_CHALLENGE +/* +==================== +BufferToHexString + +Format a byte buffer as a lower-case hex string. +==================== +*/ +static const char *BufferToHexString(byte *buffer, size_t bufferLen) +{ + static char hexString[1023]; + static const size_t maxBufferLen = (sizeof(hexString) - 1) / 2; + static const char *hex = "0123456789abcdef"; + if (bufferLen > maxBufferLen) { + bufferLen = maxBufferLen; + } + for (size_t i = 0; i < bufferLen; i++) { + hexString[i * 2] = hex[buffer[i] / 16]; + hexString[i * 2 + 1] = hex[buffer[i] % 16]; + } + hexString[bufferLen * 2] = '\0'; + return hexString; +} +#endif + +/* +==================== +SV_ChallengeInit + +Initialize the HMAC context for generating challenges. +==================== +*/ +void SV_ChallengeInit() +{ + if (challengerInitialized) { + SV_ChallengeShutdown(); + } + + // Generate a secret key from the OS RNG + byte secretKey[SECRET_KEY_LENGTH]; + if (!Sys_RandomBytes(secretKey, sizeof(secretKey))) { + Com_Error(ERR_FATAL, "SV_ChallengeInit: Sys_RandomBytes failed"); + } + +#ifdef DEBUG_SV_CHALLENGE + Com_DPrintf("Initialize challenger: %s\n", BufferToHexString(secretKey, sizeof(secretKey))); +#endif + + HMAC_MD5_Init(&challenger, secretKey, sizeof(secretKey)); + + challengerInitialized = qtrue; +} + +/* +==================== +SV_ChallengeShutdown + +Clear the HMAC context used to generate challenges. +==================== +*/ +void SV_ChallengeShutdown() +{ + if (challengerInitialized) { + memset(&challenger, 0, sizeof(challenger)); + challengerInitialized = qfalse; + } +} + +/* +==================== +SV_CreateChallenge (internal) + +Create a challenge for the given client address and timestamp. +==================== +*/ +static int SV_CreateChallenge(int timestamp, netadr_t from) +{ + const char *clientParams = NET_AdrToString(from); + size_t clientParamsLen = strlen(clientParams); + + // Create an unforgeable, temporal challenge for this client using HMAC(secretKey, clientParams + timestamp) + byte digest[MD5_DIGEST_SIZE]; + HMAC_MD5_Update(&challenger, (byte*)clientParams, clientParamsLen); + HMAC_MD5_Update(&challenger, (byte*)×tamp, sizeof(timestamp)); + HMAC_MD5_Final(&challenger, digest); + HMAC_MD5_Reset(&challenger); + + // Use first 4 bytes of the HMAC digest as an int (client only deals with numeric challenges) + // The most-significant bit stores whether the timestamp is odd or even. This lets later verification code handle the + // case where the engine timestamp has incremented between the time this challenge is sent and the client replies. + int challenge; + memcpy(&challenge, digest, sizeof(challenge)); + challenge &= 0x7FFFFFFF; + challenge |= (unsigned int)(timestamp & 0x1) << 31; + +#ifdef DEBUG_SV_CHALLENGE + if ( com_developer->integer ) { + Com_Printf( "Generated challenge %d (timestamp = %d) for %s\n", challenge, timestamp, NET_AdrToString( from ) ); + } +#endif + + return challenge; +} + +/* +==================== +SV_CreateChallenge + +Create an unforgeable, temporal challenge for the given client address. +==================== +*/ +int SV_CreateChallenge(netadr_t from) +{ + if (!challengerInitialized) { + Com_Error(ERR_FATAL, "SV_CreateChallenge: The challenge subsystem has not been initialized"); + } + + // The current time gets 14 bits chopped off to create a challenge timestamp that changes every 16.384 seconds + // This allows clients at least ~16 seconds from now to reply to the challenge + int currentTimestamp = svs.time >> 14; + return SV_CreateChallenge(currentTimestamp, from); +} + +/* +==================== +SV_VerifyChallenge + +Verify a challenge received by the client matches the expected challenge. +==================== +*/ +qboolean SV_VerifyChallenge(int receivedChallenge, netadr_t from) +{ + if (!challengerInitialized) { + Com_Error(ERR_FATAL, "SV_VerifyChallenge: The challenge subsystem has not been initialized"); + } + + int currentTimestamp = svs.time >> 14; + int currentPeriod = currentTimestamp & 0x1; + + // Use the current timestamp for verification if the current period matches the client challenge's period. + // Otherwise, use the previous timestamp in case the current timestamp incremented in the time between the + // client being sent a challenge and the client's reply that's being verified now. + int challengePeriod = ((unsigned int)receivedChallenge >> 31) & 0x1; + int challengeTimestamp = currentTimestamp - (currentPeriod ^ challengePeriod); + +#ifdef DEBUG_SV_CHALLENGE + if ( com_developer->integer ) { + Com_Printf( "Verifying challenge %d (timestamp = %d) for %s\n", receivedChallenge, challengeTimestamp, NET_AdrToString( from ) ); + } +#endif + + int expectedChallenge = SV_CreateChallenge(challengeTimestamp, from); + return (qboolean)(receivedChallenge == expectedChallenge); +} diff --git a/Projects/Android/jni/OpenJK/codemp/server/sv_client.cpp b/Projects/Android/jni/OpenJK/codemp_delete/server/sv_client.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/server/sv_client.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/server/sv_client.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/server/sv_game.cpp b/Projects/Android/jni/OpenJK/codemp_delete/server/sv_game.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/server/sv_game.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/server/sv_game.cpp diff --git a/Projects/Android/jni/OpenJK/codemp_delete/server/sv_gameapi.cpp b/Projects/Android/jni/OpenJK/codemp_delete/server/sv_gameapi.cpp new file mode 100644 index 0000000..d216669 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/server/sv_gameapi.cpp @@ -0,0 +1,3160 @@ +/* +=========================================================================== +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +// sv_gameapi.cpp -- interface to the game dll +//Anything above this #include will be ignored by the compiler + +#include "server.h" +#include "botlib/botlib.h" +#include "qcommon/stringed_ingame.h" +#include "qcommon/RoffSystem.h" +#include "ghoul2/ghoul2_shared.h" +#include "qcommon/cm_public.h" +#include "icarus/GameInterface.h" +#include "qcommon/timing.h" +#include "NPCNav/navigator.h" + +botlib_export_t *botlib_export; + +// game interface +static gameExport_t *ge; // game export table +static vm_t *gvm; // game vm, valid for legacy and new api + +// +// game vmMain calls +// + +void GVM_InitGame( int levelTime, int randomSeed, int restart ) { + if ( gvm->isLegacy ) { + VM_Call( gvm, GAME_INIT, levelTime, randomSeed, restart ); + return; + } + VMSwap v( gvm ); + + ge->InitGame( levelTime, randomSeed, restart ); +} + +void GVM_ShutdownGame( int restart ) { + if ( gvm->isLegacy ) { + VM_Call( gvm, GAME_SHUTDOWN, restart ); + return; + } + VMSwap v( gvm ); + + ge->ShutdownGame( restart ); +} + +char *GVM_ClientConnect( int clientNum, qboolean firstTime, qboolean isBot ) { + if ( gvm->isLegacy ) + return (char *)VM_Call( gvm, GAME_CLIENT_CONNECT, clientNum, firstTime, isBot ); + VMSwap v( gvm ); + + return ge->ClientConnect( clientNum, firstTime, isBot ); +} + +void GVM_ClientBegin( int clientNum ) { + if ( gvm->isLegacy ) { + VM_Call( gvm, GAME_CLIENT_BEGIN, clientNum ); + return; + } + VMSwap v( gvm ); + + ge->ClientBegin( clientNum, qtrue ); +} + +qboolean GVM_ClientUserinfoChanged( int clientNum ) { + if ( gvm->isLegacy ) + return (qboolean)VM_Call( gvm, GAME_CLIENT_USERINFO_CHANGED, clientNum ); + VMSwap v( gvm ); + + return ge->ClientUserinfoChanged( clientNum ); +} + +void GVM_ClientDisconnect( int clientNum ) { + if ( gvm->isLegacy ) { + VM_Call( gvm, GAME_CLIENT_DISCONNECT, clientNum ); + return; + } + VMSwap v( gvm ); + + ge->ClientDisconnect( clientNum ); +} + +void GVM_ClientCommand( int clientNum ) { + if ( gvm->isLegacy ) { + VM_Call( gvm, GAME_CLIENT_COMMAND, clientNum ); + return; + } + VMSwap v( gvm ); + + ge->ClientCommand( clientNum ); +} + +void GVM_ClientThink( int clientNum, usercmd_t *ucmd ) { + if ( gvm->isLegacy ) { + VM_Call( gvm, GAME_CLIENT_THINK, clientNum, reinterpret_cast< intptr_t >( ucmd ) ); + return; + } + VMSwap v( gvm ); + + ge->ClientThink( clientNum, ucmd ); +} + +void GVM_RunFrame( int levelTime ) { + if ( gvm->isLegacy ) { + VM_Call( gvm, GAME_RUN_FRAME, levelTime ); + return; + } + VMSwap v( gvm ); + + ge->RunFrame( levelTime ); +} + +qboolean GVM_ConsoleCommand( void ) { + if ( gvm->isLegacy ) + return (qboolean)VM_Call( gvm, GAME_CONSOLE_COMMAND ); + VMSwap v( gvm ); + + return ge->ConsoleCommand(); +} + +int GVM_BotAIStartFrame( int time ) { + if ( gvm->isLegacy ) + return VM_Call( gvm, BOTAI_START_FRAME, time ); + VMSwap v( gvm ); + + return ge->BotAIStartFrame( time ); +} + +void GVM_ROFF_NotetrackCallback( int entID, const char *notetrack ) { + if ( gvm->isLegacy ) { + VM_Call( gvm, GAME_ROFF_NOTETRACK_CALLBACK, entID, reinterpret_cast< intptr_t >( notetrack ) ); + return; + } + VMSwap v( gvm ); + + ge->ROFF_NotetrackCallback( entID, notetrack ); +} + +void GVM_SpawnRMGEntity( void ) { + if ( gvm->isLegacy ) { + VM_Call( gvm, GAME_SPAWN_RMG_ENTITY ); + return; + } + VMSwap v( gvm ); + + ge->SpawnRMGEntity(); +} + +int GVM_ICARUS_PlaySound( void ) { + if ( gvm->isLegacy ) + return VM_Call( gvm, GAME_ICARUS_PLAYSOUND ); + VMSwap v( gvm ); + + return ge->ICARUS_PlaySound(); +} + +qboolean GVM_ICARUS_Set( void ) { + if ( gvm->isLegacy ) + return (qboolean)VM_Call( gvm, GAME_ICARUS_SET ); + VMSwap v( gvm ); + + return ge->ICARUS_Set(); +} + +void GVM_ICARUS_Lerp2Pos( void ) { + if ( gvm->isLegacy ) { + VM_Call( gvm, GAME_ICARUS_LERP2POS ); + return; + } + VMSwap v( gvm ); + + ge->ICARUS_Lerp2Pos(); +} + +void GVM_ICARUS_Lerp2Origin( void ) { + if ( gvm->isLegacy ) { + VM_Call( gvm, GAME_ICARUS_LERP2ORIGIN ); + return; + } + VMSwap v( gvm ); + + ge->ICARUS_Lerp2Origin(); +} + +void GVM_ICARUS_Lerp2Angles( void ) { + if ( gvm->isLegacy ) { + VM_Call( gvm, GAME_ICARUS_LERP2ANGLES ); + return; + } + VMSwap v( gvm ); + + ge->ICARUS_Lerp2Angles(); +} + +int GVM_ICARUS_GetTag( void ) { + if ( gvm->isLegacy ) + return VM_Call( gvm, GAME_ICARUS_GETTAG ); + VMSwap v( gvm ); + + return ge->ICARUS_GetTag(); +} + +void GVM_ICARUS_Lerp2Start( void ) { + if ( gvm->isLegacy ) { + VM_Call( gvm, GAME_ICARUS_LERP2START ); + return; + } + VMSwap v( gvm ); + + ge->ICARUS_Lerp2Start(); +} + +void GVM_ICARUS_Lerp2End( void ) { + if ( gvm->isLegacy ) { + VM_Call( gvm, GAME_ICARUS_LERP2END ); + return; + } + VMSwap v( gvm ); + + ge->ICARUS_Lerp2End(); +} + +void GVM_ICARUS_Use( void ) { + if ( gvm->isLegacy ) { + VM_Call( gvm, GAME_ICARUS_USE ); + return; + } + VMSwap v( gvm ); + + ge->ICARUS_Use(); +} + +void GVM_ICARUS_Kill( void ) { + if ( gvm->isLegacy ) { + VM_Call( gvm, GAME_ICARUS_KILL ); + return; + } + VMSwap v( gvm ); + + ge->ICARUS_Kill(); +} + +void GVM_ICARUS_Remove( void ) { + if ( gvm->isLegacy ) { + VM_Call( gvm, GAME_ICARUS_REMOVE ); + return; + } + VMSwap v( gvm ); + + ge->ICARUS_Remove(); +} + +void GVM_ICARUS_Play( void ) { + if ( gvm->isLegacy ) { + VM_Call( gvm, GAME_ICARUS_PLAY ); + return; + } + VMSwap v( gvm ); + + ge->ICARUS_Play(); +} + +int GVM_ICARUS_GetFloat( void ) { + if ( gvm->isLegacy ) + return VM_Call( gvm, GAME_ICARUS_GETFLOAT ); + VMSwap v( gvm ); + + return ge->ICARUS_GetFloat(); +} + +int GVM_ICARUS_GetVector( void ) { + if ( gvm->isLegacy ) + return VM_Call( gvm, GAME_ICARUS_GETVECTOR ); + VMSwap v( gvm ); + + return ge->ICARUS_GetVector(); +} + +int GVM_ICARUS_GetString( void ) { + if ( gvm->isLegacy ) + return VM_Call( gvm, GAME_ICARUS_GETSTRING ); + VMSwap v( gvm ); + + return ge->ICARUS_GetString(); +} + +void GVM_ICARUS_SoundIndex( void ) { + if ( gvm->isLegacy ) { + VM_Call( gvm, GAME_ICARUS_SOUNDINDEX ); + return; + } + VMSwap v( gvm ); + + ge->ICARUS_SoundIndex(); +} + +int GVM_ICARUS_GetSetIDForString( void ) { + if ( gvm->isLegacy ) + return VM_Call( gvm, GAME_ICARUS_GETSETIDFORSTRING ); + VMSwap v( gvm ); + + return ge->ICARUS_GetSetIDForString(); +} + +qboolean GVM_NAV_ClearPathToPoint( int entID, vec3_t pmins, vec3_t pmaxs, vec3_t point, int clipmask, int okToHitEnt ) { + if ( gvm->isLegacy ) + return (qboolean)VM_Call( gvm, GAME_NAV_CLEARPATHTOPOINT, entID, reinterpret_cast< intptr_t >( pmins ), reinterpret_cast< intptr_t >( pmaxs ), reinterpret_cast< intptr_t >( point ), clipmask, okToHitEnt ); + VMSwap v( gvm ); + + return ge->NAV_ClearPathToPoint( entID, pmins, pmaxs, point, clipmask, okToHitEnt ); +} + +qboolean GVM_NPC_ClearLOS2( int entID, const vec3_t end ) { + if ( gvm->isLegacy ) + return (qboolean)VM_Call( gvm, GAME_NAV_CLEARLOS, entID, reinterpret_cast< intptr_t >( end ) ); + VMSwap v( gvm ); + + return ge->NPC_ClearLOS2( entID, end ); +} + +int GVM_NAVNEW_ClearPathBetweenPoints( vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, int ignore, int clipmask ) { + if ( gvm->isLegacy ) + return VM_Call( gvm, GAME_NAV_CLEARPATHBETWEENPOINTS, reinterpret_cast< intptr_t >( start ), reinterpret_cast< intptr_t >( end ), reinterpret_cast< intptr_t >( mins ), reinterpret_cast< intptr_t >( maxs ), ignore, clipmask ); + VMSwap v( gvm ); + + return ge->NAVNEW_ClearPathBetweenPoints( start, end, mins, maxs, ignore, clipmask ); +} + +qboolean GVM_NAV_CheckNodeFailedForEnt( int entID, int nodeNum ) { + if ( gvm->isLegacy ) + return (qboolean)VM_Call( gvm, GAME_NAV_CHECKNODEFAILEDFORENT, entID, nodeNum ); + VMSwap v( gvm ); + + return ge->NAV_CheckNodeFailedForEnt( entID, nodeNum ); +} + +qboolean GVM_NAV_EntIsUnlockedDoor( int entityNum ) { + if ( gvm->isLegacy ) + return (qboolean)VM_Call( gvm, GAME_NAV_ENTISUNLOCKEDDOOR, entityNum ); + VMSwap v( gvm ); + + return ge->NAV_EntIsUnlockedDoor( entityNum ); +} + +qboolean GVM_NAV_EntIsDoor( int entityNum ) { + if ( gvm->isLegacy ) + return (qboolean)VM_Call( gvm, GAME_NAV_ENTISDOOR, entityNum ); + VMSwap v( gvm ); + + return ge->NAV_EntIsDoor( entityNum ); +} + +qboolean GVM_NAV_EntIsBreakable( int entityNum ) { + if ( gvm->isLegacy ) + return (qboolean)VM_Call( gvm, GAME_NAV_ENTISBREAKABLE, entityNum ); + VMSwap v( gvm ); + + return ge->NAV_EntIsBreakable( entityNum ); +} + +qboolean GVM_NAV_EntIsRemovableUsable( int entNum ) { + if ( gvm->isLegacy ) + return (qboolean)VM_Call( gvm, GAME_NAV_ENTISREMOVABLEUSABLE, entNum ); + VMSwap v( gvm ); + + return ge->NAV_EntIsRemovableUsable( entNum ); +} + +void GVM_NAV_FindCombatPointWaypoints( void ) { + if ( gvm->isLegacy ) { + VM_Call( gvm, GAME_NAV_FINDCOMBATPOINTWAYPOINTS ); + return; + } + VMSwap v( gvm ); + + ge->NAV_FindCombatPointWaypoints(); +} + +int GVM_BG_GetItemIndexByTag( int tag, int type ) { + if ( gvm->isLegacy ) + return VM_Call( gvm, GAME_GETITEMINDEXBYTAG, tag, type ); + VMSwap v( gvm ); + + return ge->BG_GetItemIndexByTag( tag, type ); +} + +// +// game syscalls +// only used by legacy mods! +// + +// legacy syscall + +siegePers_t sv_siegePersData = {qfalse, 0, 0}; + +extern float g_svCullDist; +int CM_ModelContents( clipHandle_t model, int subBSPIndex ); +int CM_LoadSubBSP( const char *name, qboolean clientload ); +int CM_FindSubBSP( int modelIndex ); +char *CM_SubBSPEntityString( int index ); +qboolean Q3_TaskIDPending( sharedEntity_t *ent, taskID_t taskType ); +void Q3_TaskIDSet( sharedEntity_t *ent, taskID_t taskType, int taskID ); +void Q3_TaskIDComplete( sharedEntity_t *ent, taskID_t taskType ); +void Q3_SetVar( int taskID, int entID, const char *type_name, const char *data ); +int Q3_VariableDeclared( const char *name ); +int Q3_GetFloatVariable( const char *name, float *value ); +int Q3_GetStringVariable( const char *name, const char **value ); +int Q3_GetVectorVariable( const char *name, vec3_t value ); +void SV_BotWaypointReception( int wpnum, wpobject_t **wps ); +void SV_BotCalculatePaths( int rmg ); + +static void SV_LocateGameData( sharedEntity_t *gEnts, int numGEntities, int sizeofGEntity_t, playerState_t *clients, int sizeofGameClient ) { + sv.gentities = gEnts; + sv.gentitySize = sizeofGEntity_t; + sv.num_entities = numGEntities; + + sv.gameClients = clients; + sv.gameClientSize = sizeofGameClient; +} + +static void SV_GameDropClient( int clientNum, const char *reason ) { + if ( clientNum < 0 || clientNum >= sv_maxclients->integer ) { + return; + } + SV_DropClient( svs.clients + clientNum, reason ); +} + +static void SV_GameSendServerCommand( int clientNum, const char *text ) { + if ( clientNum == -1 ) { + SV_SendServerCommand( NULL, "%s", text ); + } else { + if ( clientNum < 0 || clientNum >= sv_maxclients->integer ) { + return; + } + SV_SendServerCommand( svs.clients + clientNum, "%s", text ); + } +} + +static qboolean SV_EntityContact( const vec3_t mins, const vec3_t maxs, const sharedEntity_t *gEnt, int capsule ) { + const float *origin, *angles; + clipHandle_t ch; + trace_t trace; + + // check for exact collision + origin = gEnt->r.currentOrigin; + angles = gEnt->r.currentAngles; + + ch = SV_ClipHandleForEntity( gEnt ); + CM_TransformedBoxTrace ( &trace, vec3_origin, vec3_origin, mins, maxs, + ch, -1, origin, angles, capsule ); + + return (qboolean)trace.startsolid; +} + +static void SV_SetBrushModel( sharedEntity_t *ent, const char *name ) { + clipHandle_t h; + vec3_t mins, maxs; + + if (!name) + { + Com_Error( ERR_DROP, "SV_SetBrushModel: NULL" ); + } + + if (name[0] == '*') + { + ent->s.modelindex = atoi( name + 1 ); + + if (sv.mLocalSubBSPIndex != -1) + { + ent->s.modelindex += sv.mLocalSubBSPModelOffset; + } + + h = CM_InlineModel( ent->s.modelindex ); + + CM_ModelBounds(h, mins, maxs); + + VectorCopy (mins, ent->r.mins); + VectorCopy (maxs, ent->r.maxs); + ent->r.bmodel = qtrue; + ent->r.contents = CM_ModelContents( h, -1 ); + } + else if (name[0] == '#') + { + ent->s.modelindex = CM_LoadSubBSP(va("maps/%s.bsp", name + 1), qfalse); + CM_ModelBounds( ent->s.modelindex, mins, maxs ); + + VectorCopy (mins, ent->r.mins); + VectorCopy (maxs, ent->r.maxs); + ent->r.bmodel = qtrue; + + //rwwNOTE: We don't ever want to set contents -1, it includes CONTENTS_LIGHTSABER. + //Lots of stuff will explode if there's a brush with CONTENTS_LIGHTSABER that isn't attached to a client owner. + //ent->contents = -1; // we don't know exactly what is in the brushes + h = CM_InlineModel( ent->s.modelindex ); + ent->r.contents = CM_ModelContents( h, CM_FindSubBSP(ent->s.modelindex) ); + } + else + { + Com_Error( ERR_DROP, "SV_SetBrushModel: %s isn't a brush model", name ); + } +} + +static qboolean SV_inPVSIgnorePortals( const vec3_t p1, const vec3_t p2 ) { + int leafnum, cluster; +// int area1, area2; + byte *mask; + + leafnum = CM_PointLeafnum( p1 ); + cluster = CM_LeafCluster( leafnum ); +// area1 = CM_LeafArea( leafnum ); + mask = CM_ClusterPVS( cluster ); + + leafnum = CM_PointLeafnum( p2 ); + cluster = CM_LeafCluster( leafnum ); +// area2 = CM_LeafArea( leafnum ); + + if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) ) + return qfalse; + + return qtrue; +} + +static void SV_GetServerinfo( char *buffer, int bufferSize ) { + if ( bufferSize < 1 ) { + Com_Error( ERR_DROP, "SV_GetServerinfo: bufferSize == %i", bufferSize ); + return; + } + Q_strncpyz( buffer, Cvar_InfoString( CVAR_SERVERINFO ), bufferSize ); +} + +static void SV_AdjustAreaPortalState( sharedEntity_t *ent, qboolean open ) { + svEntity_t *svEnt; + + svEnt = SV_SvEntityForGentity( ent ); + if ( svEnt->areanum2 == -1 ) + return; + + CM_AdjustAreaPortalState( svEnt->areanum, svEnt->areanum2, open ); +} + +static void SV_GetUsercmd( int clientNum, usercmd_t *cmd ) { + if ( clientNum < 0 || clientNum >= sv_maxclients->integer ) { + Com_Error( ERR_DROP, "SV_GetUsercmd: bad clientNum:%i", clientNum ); + return; + } + *cmd = svs.clients[clientNum].lastUsercmd; +} + +static sharedEntity_t gLocalModifier; +static sharedEntity_t *ConvertedEntity( sharedEntity_t *ent ) { //Return an entity with the memory shifted around to allow reading/modifying VM memory + int i = 0; + + assert(ent); + + gLocalModifier.s = ent->s; + gLocalModifier.r = ent->r; + while (i < NUM_TIDS) + { + gLocalModifier.taskID[i] = ent->taskID[i]; + i++; + } + i = 0; + gLocalModifier.parms = (parms_t *)VM_ArgPtr((intptr_t)ent->parms); + while (i < NUM_BSETS) + { + gLocalModifier.behaviorSet[i] = (char *)VM_ArgPtr((intptr_t)ent->behaviorSet[i]); + i++; + } + i = 0; + gLocalModifier.script_targetname = (char *)VM_ArgPtr((intptr_t)ent->script_targetname); + gLocalModifier.delayScriptTime = ent->delayScriptTime; + gLocalModifier.fullName = (char *)VM_ArgPtr((intptr_t)ent->fullName); + gLocalModifier.targetname = (char *)VM_ArgPtr((intptr_t)ent->targetname); + gLocalModifier.classname = (char *)VM_ArgPtr((intptr_t)ent->classname); + + gLocalModifier.ghoul2 = ent->ghoul2; + + return &gLocalModifier; +} + +static const char *SV_SetActiveSubBSP( int index ) { + if ( index >= 0 ) { + sv.mLocalSubBSPIndex = CM_FindSubBSP( index ); + sv.mLocalSubBSPModelOffset = index; + sv.mLocalSubBSPEntityParsePoint = CM_SubBSPEntityString( sv.mLocalSubBSPIndex ); + return sv.mLocalSubBSPEntityParsePoint; + } + + sv.mLocalSubBSPIndex = -1; + return NULL; +} + +static qboolean SV_GetEntityToken( char *buffer, int bufferSize ) { + char *s; + + if ( sv.mLocalSubBSPIndex == -1 ) { + s = COM_Parse( (const char **)&sv.entityParsePoint ); + Q_strncpyz( buffer, s, bufferSize ); + if ( !sv.entityParsePoint && !s[0] ) + return qfalse; + else + return qtrue; + } + else { + s = COM_Parse( (const char **)&sv.mLocalSubBSPEntityParsePoint); + Q_strncpyz( buffer, s, bufferSize ); + if ( !sv.mLocalSubBSPEntityParsePoint && !s[0] ) + return qfalse; + else + return qtrue; + } +} + +static void SV_PrecisionTimerStart( void **timer ) { + timing_c *newTimer = new timing_c; //create the new timer + *timer = newTimer; //assign the pointer within the pointer to point at the mem addr of our new timer + newTimer->Start(); //start the timer +} + +static int SV_PrecisionTimerEnd( void *timer ) { + int r; + timing_c *theTimer = (timing_c *)timer; //this is the pointer we assigned in start, so we can directly cast it back + r = theTimer->End(); //get the result + delete theTimer; //delete the timer since we're done with it + return r; //return the result +} + +static void SV_RegisterSharedMemory( char *memory ) { + sv.mSharedMemory = memory; +} + +static void SV_SetServerCull( float cullDistance ) { + g_svCullDist = cullDistance; +} + +static void SV_SiegePersSet( siegePers_t *siegePers ) { + sv_siegePersData = *siegePers; +} + +static void SV_SiegePersGet( siegePers_t *siegePers ) { + *siegePers = sv_siegePersData; +} + +qboolean SV_ROFF_Clean( void ) { + return theROFFSystem.Clean( qfalse ); +} + +void SV_ROFF_UpdateEntities( void ) { + theROFFSystem.UpdateEntities( qfalse ); +} + +int SV_ROFF_Cache( char *file ) { + return theROFFSystem.Cache( file, qfalse ); +} + +qboolean SV_ROFF_Play( int entID, int roffID, qboolean doTranslation ) { + return theROFFSystem.Play( entID, roffID, doTranslation, qfalse ); +} + +qboolean SV_ROFF_Purge_Ent( int entID ) { + return theROFFSystem.PurgeEnt( entID, qfalse ); +} + +static qboolean SV_ICARUS_RegisterScript( const char *name, qboolean bCalledDuringInterrogate ) { + return (qboolean)ICARUS_RegisterScript( name, bCalledDuringInterrogate ); +} + +static qboolean SV_ICARUS_ValidEnt( sharedEntity_t *ent ) { + return (qboolean)ICARUS_ValidEnt( ent ); +} + +static qboolean ICARUS_IsInitialized( int entID ) { + if ( !gSequencers[entID] || !gTaskManagers[entID] ) + return qfalse; + + return qtrue; +} + +static qboolean ICARUS_MaintainTaskManager( int entID ) { + if ( gTaskManagers[entID] ) { + gTaskManagers[entID]->Update(); + return qtrue; + } + return qfalse; +} + +static qboolean ICARUS_IsRunning( int entID ) { + if ( !gTaskManagers[entID] || !gTaskManagers[entID]->IsRunning() ) + return qfalse; + return qtrue; +} + +static qboolean ICARUS_TaskIDPending( sharedEntity_t *ent, int taskID ) { + return Q3_TaskIDPending( ent, (taskID_t)taskID ); +} + +static void SV_ICARUS_TaskIDSet( sharedEntity_t *ent, int taskType, int taskID ) { + Q3_TaskIDSet( ent, (taskID_t)taskType, taskID ); +} + +static void SV_ICARUS_TaskIDComplete( sharedEntity_t *ent, int taskType ) { + Q3_TaskIDComplete( ent, (taskID_t)taskType ); +} + +static int SV_ICARUS_GetStringVariable( const char *name, const char *value ) { + const char *rec = (const char *)value; + return Q3_GetStringVariable( name, (const char **)&rec ); +} +static int SV_ICARUS_GetVectorVariable( const char *name, const vec3_t value ) { + return Q3_GetVectorVariable( name, (float *)value ); +} + +static void SV_Nav_Init( void ) { + navigator.Init(); +} + +static void SV_Nav_Free( void ) { + navigator.Free(); +} + +static qboolean SV_Nav_Load( const char *filename, int checksum ) { + return (qboolean)navigator.Load( filename, checksum ); +} + +static qboolean SV_Nav_Save( const char *filename, int checksum ) { + return (qboolean)navigator.Save( filename, checksum ); +} + +static int SV_Nav_AddRawPoint( vec3_t point, int flags, int radius ) { + return navigator.AddRawPoint( point, flags, radius ); +} + +static void SV_Nav_CalculatePaths( qboolean recalc ) { + navigator.CalculatePaths( recalc ); +} + +static void SV_Nav_HardConnect( int first, int second ) { + navigator.HardConnect( first, second ); +} + +static void SV_Nav_ShowNodes( void ) { + navigator.ShowNodes(); +} + +static void SV_Nav_ShowEdges( void ) { + navigator.ShowEdges(); +} + +static void SV_Nav_ShowPath( int start, int end ) { + navigator.ShowPath( start, end ); +} + +static int SV_Nav_GetNearestNode( sharedEntity_t *ent, int lastID, int flags, int targetID ) { + return navigator.GetNearestNode( ent, lastID, flags, targetID ); +} + +static int SV_Nav_GetBestNode( int startID, int endID, int rejectID ) { + return navigator.GetBestNode( startID, endID, rejectID ); +} + +static int SV_Nav_GetNodePosition( int nodeID, vec3_t out ) { + return navigator.GetNodePosition( nodeID, out ); +} + +static int SV_Nav_GetNodeNumEdges( int nodeID ) { + return navigator.GetNodeNumEdges( nodeID ); +} + +static int SV_Nav_GetNodeEdge( int nodeID, int edge ) { + return navigator.GetNodeEdge( nodeID, edge ); +} + +static int SV_Nav_GetNumNodes( void ) { + return navigator.GetNumNodes(); +} + +static qboolean SV_Nav_Connected( int startID, int endID ) { + return (qboolean)navigator.Connected( startID, endID ); +} + +static int SV_Nav_GetPathCost( int startID, int endID ) { + return navigator.GetPathCost( startID, endID ); +} + +static int SV_Nav_GetEdgeCost( int startID, int endID ) { + return navigator.GetEdgeCost( startID, endID ); +} + +static int SV_Nav_GetProjectedNode( vec3_t origin, int nodeID ) { + return navigator.GetProjectedNode( origin, nodeID ); +} + +static void SV_Nav_CheckFailedNodes( sharedEntity_t *ent ) { + navigator.CheckFailedNodes( ent ); +} + +static void SV_Nav_AddFailedNode( sharedEntity_t *ent, int nodeID ) { + navigator.AddFailedNode( ent, nodeID ); +} + +static qboolean SV_Nav_NodeFailed( sharedEntity_t *ent, int nodeID ) { + return navigator.NodeFailed( ent, nodeID ); +} + +static qboolean SV_Nav_NodesAreNeighbors( int startID, int endID ) { + return navigator.NodesAreNeighbors( startID, endID ); +} + +static void SV_Nav_ClearFailedEdge( failedEdge_t *failedEdge ) { + navigator.ClearFailedEdge( failedEdge ); +} + +static void SV_Nav_ClearAllFailedEdges( void ) { + navigator.ClearAllFailedEdges(); +} + +static int SV_Nav_EdgeFailed( int startID, int endID ) { + return navigator.EdgeFailed( startID, endID ); +} + +static void SV_Nav_AddFailedEdge( int entID, int startID, int endID ) { + navigator.AddFailedEdge( entID, startID, endID ); +} + +static qboolean SV_Nav_CheckFailedEdge( failedEdge_t *failedEdge ) { + return navigator.CheckFailedEdge( failedEdge ); +} + +static void SV_Nav_CheckAllFailedEdges( void ) { + navigator.CheckAllFailedEdges(); +} + +static qboolean SV_Nav_RouteBlocked( int startID, int testEdgeID, int endID, int rejectRank ) { + return navigator.RouteBlocked( startID, testEdgeID, endID, rejectRank ); +} + +static int SV_Nav_GetBestNodeAltRoute( int startID, int endID, int *pathCost, int rejectID ) { + return navigator.GetBestNodeAltRoute( startID, endID, pathCost, rejectID ); +} + +static int SV_Nav_GetBestNodeAltRoute2( int startID, int endID, int rejectID ) { + return navigator.GetBestNodeAltRoute( startID, endID, rejectID ); +} + +static int SV_Nav_GetBestPathBetweenEnts( sharedEntity_t *ent, sharedEntity_t *goal, int flags ) { + return navigator.GetBestPathBetweenEnts( ent, goal, flags ); +} + +static int SV_Nav_GetNodeRadius( int nodeID ) { + return navigator.GetNodeRadius( nodeID ); +} + +static void SV_Nav_CheckBlockedEdges( void ) { + navigator.CheckBlockedEdges(); +} + +static void SV_Nav_ClearCheckedNodes( void ) { + navigator.ClearCheckedNodes(); +} + +static int SV_Nav_CheckedNode( int wayPoint, int ent ) { + return navigator.CheckedNode( wayPoint, ent ); +} + +static void SV_Nav_SetCheckedNode( int wayPoint, int ent, int value ) { + navigator.SetCheckedNode( wayPoint, ent, value ); +} + +static void SV_Nav_FlagAllNodes( int newFlag ) { + navigator.FlagAllNodes( newFlag ); +} + +static qboolean SV_Nav_GetPathsCalculated( void ) { + return navigator.pathsCalculated; +} + +static void SV_Nav_SetPathsCalculated( qboolean newVal ) { + navigator.pathsCalculated = newVal; +} + +static int SV_BotLoadCharacter( char *charfile, float skill ) { + return botlib_export->ai.BotLoadCharacter( charfile, skill ); +} + +static void SV_BotFreeCharacter( int character ) { + botlib_export->ai.BotFreeCharacter( character ); +} + +static float SV_Characteristic_Float( int character, int index ) { + return botlib_export->ai.Characteristic_Float( character, index ); +} + +static float SV_Characteristic_BFloat( int character, int index, float min, float max ) { + return botlib_export->ai.Characteristic_BFloat( character, index, min, max ); +} + +static int SV_Characteristic_Integer( int character, int index ) { + return botlib_export->ai.Characteristic_Integer( character, index ); +} + +static int SV_Characteristic_BInteger( int character, int index, int min, int max ) { + return botlib_export->ai.Characteristic_BInteger( character, index, min, max ); +} + +static void SV_Characteristic_String( int character, int index, char *buf, int size ) { + botlib_export->ai.Characteristic_String( character, index, buf, size ); +} + +static int SV_BotAllocChatState( void ) { + return botlib_export->ai.BotAllocChatState(); +} + +static void SV_BotFreeChatState( int handle ) { + botlib_export->ai.BotFreeChatState( handle ); +} + +static void SV_BotQueueConsoleMessage( int chatstate, int type, char *message ) { + botlib_export->ai.BotQueueConsoleMessage( chatstate, type, message ); +} + +static void SV_BotRemoveConsoleMessage( int chatstate, int handle ) { + botlib_export->ai.BotRemoveConsoleMessage( chatstate, handle ); +} + +static int SV_BotNextConsoleMessage( int chatstate, void *cm ) { + return botlib_export->ai.BotNextConsoleMessage( chatstate, (bot_consolemessage_s *)cm ); +} + +static int SV_BotNumConsoleMessages( int chatstate ) { + return botlib_export->ai.BotNumConsoleMessages( chatstate ); +} + +static void SV_BotInitialChat( int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7 ) { + botlib_export->ai.BotInitialChat( chatstate, type, mcontext, var0, var1, var2, var3, var4, var5, var6, var7 ); +} + +static int SV_BotReplyChat( int chatstate, char *message, int mcontext, int vcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7 ) { + return botlib_export->ai.BotReplyChat( chatstate, message, mcontext, vcontext, var0, var1, var2, var3, var4, var5, var6, var7 ); +} + +static int SV_BotChatLength( int chatstate ) { + return botlib_export->ai.BotChatLength( chatstate ); +} + +static void SV_BotEnterChat( int chatstate, int client, int sendto ) { + botlib_export->ai.BotEnterChat( chatstate, client, sendto ); +} + +static int SV_StringContains( char *str1, char *str2, int casesensitive ) { + return botlib_export->ai.StringContains( str1, str2, casesensitive ); +} + +static int SV_BotFindMatch( char *str, void *match, unsigned long int context ) { + return botlib_export->ai.BotFindMatch( str, (bot_match_s *)match, context ); +} + +static void SV_BotMatchVariable( void *match, int variable, char *buf, int size ) { + botlib_export->ai.BotMatchVariable( (bot_match_s *)match, variable, buf, size ); +} + +static void SV_UnifyWhiteSpaces( char *string ) { + botlib_export->ai.UnifyWhiteSpaces( string ); +} + +static void SV_BotReplaceSynonyms( char *string, unsigned long int context ) { + botlib_export->ai.BotReplaceSynonyms( string, context ); +} + +static int SV_BotLoadChatFile( int chatstate, char *chatfile, char *chatname ) { + return botlib_export->ai.BotLoadChatFile( chatstate, chatfile, chatname ); +} + +static void SV_BotSetChatGender( int chatstate, int gender ) { + botlib_export->ai.BotSetChatGender( chatstate, gender ); +} + +static void SV_BotSetChatName( int chatstate, char *name, int client ) { + botlib_export->ai.BotSetChatName( chatstate, name, client ); +} + +static void SV_BotResetGoalState( int goalstate ) { + botlib_export->ai.BotResetGoalState( goalstate ); +} + +static void SV_BotResetAvoidGoals( int goalstate ) { + botlib_export->ai.BotResetAvoidGoals( goalstate ); +} + +static void SV_BotPushGoal( int goalstate, void *goal ) { + botlib_export->ai.BotPushGoal( goalstate, (bot_goal_s *)goal ); +} + +static void SV_BotPopGoal( int goalstate ) { + botlib_export->ai.BotPopGoal( goalstate ); +} + +static void SV_BotEmptyGoalStack( int goalstate ) { + botlib_export->ai.BotEmptyGoalStack( goalstate ); +} + +static void SV_BotDumpAvoidGoals( int goalstate ) { + botlib_export->ai.BotDumpAvoidGoals( goalstate ); +} + +static void SV_BotDumpGoalStack( int goalstate ) { + botlib_export->ai.BotDumpGoalStack( goalstate ); +} + +static void SV_BotGoalName( int number, char *name, int size ) { + botlib_export->ai.BotGoalName( number, name, size ); +} + +static int SV_BotGetTopGoal( int goalstate, void *goal ) { + return botlib_export->ai.BotGetTopGoal( goalstate, (bot_goal_s *)goal ); +} + +static int SV_BotGetSecondGoal( int goalstate, void *goal ) { + return botlib_export->ai.BotGetSecondGoal( goalstate, (bot_goal_s *)goal ); +} + +static int SV_BotChooseLTGItem( int goalstate, vec3_t origin, int *inventory, int travelflags ) { + return botlib_export->ai.BotChooseLTGItem( goalstate, origin, inventory, travelflags ); +} + +static int SV_BotChooseNBGItem( int goalstate, vec3_t origin, int *inventory, int travelflags, void *ltg, float maxtime ) { + return botlib_export->ai.BotChooseNBGItem( goalstate, origin, inventory, travelflags, (bot_goal_s *)ltg, maxtime ); +} + +static int SV_BotTouchingGoal( vec3_t origin, void *goal ) { + return botlib_export->ai.BotTouchingGoal( origin, (bot_goal_s *)goal ); +} + +static int SV_BotItemGoalInVisButNotVisible( int viewer, vec3_t eye, vec3_t viewangles, void *goal ) { + return botlib_export->ai.BotItemGoalInVisButNotVisible( viewer, eye, viewangles, (bot_goal_s *)goal ); +} + +static int SV_BotGetLevelItemGoal( int index, char *classname, void *goal ) { + return botlib_export->ai.BotGetLevelItemGoal( index, classname, (bot_goal_s *)goal ); +} + +static float SV_BotAvoidGoalTime( int goalstate, int number ) { + return botlib_export->ai.BotAvoidGoalTime( goalstate, number ); +} + +static void SV_BotInitLevelItems( void ) { + botlib_export->ai.BotInitLevelItems(); +} + +static void SV_BotUpdateEntityItems( void ) { + botlib_export->ai.BotUpdateEntityItems(); +} + +static int SV_BotLoadItemWeights( int goalstate, char *filename ) { + return botlib_export->ai.BotLoadItemWeights( goalstate, filename ); +} + +static void SV_BotFreeItemWeights( int goalstate ) { + botlib_export->ai.BotFreeItemWeights( goalstate ); +} + +static void SV_BotSaveGoalFuzzyLogic( int goalstate, char *filename ) { + botlib_export->ai.BotSaveGoalFuzzyLogic( goalstate, filename ); +} + +static int SV_BotAllocGoalState( int state ) { + return botlib_export->ai.BotAllocGoalState( state ); +} + +static void SV_BotFreeGoalState( int handle ) { + botlib_export->ai.BotFreeGoalState( handle ); +} + +static void SV_BotResetMoveState( int movestate ) { + botlib_export->ai.BotResetMoveState( movestate ); +} + +static void SV_BotMoveToGoal( void *result, int movestate, void *goal, int travelflags ) { + botlib_export->ai.BotMoveToGoal( (bot_moveresult_s *)result, movestate, (bot_goal_s *)goal, travelflags ); +} + +static int SV_BotMoveInDirection( int movestate, vec3_t dir, float speed, int type ) { + return botlib_export->ai.BotMoveInDirection( movestate, dir, speed, type ); +} + +static void SV_BotResetAvoidReach( int movestate ) { + botlib_export->ai.BotResetAvoidReach( movestate ); +} + +static void SV_BotResetLastAvoidReach( int movestate ) { + botlib_export->ai.BotResetLastAvoidReach( movestate ); +} + +static int SV_BotReachabilityArea( vec3_t origin, int testground ) { + return botlib_export->ai.BotReachabilityArea( origin, testground ); +} + +static int SV_BotMovementViewTarget( int movestate, void *goal, int travelflags, float lookahead, vec3_t target ) { + return botlib_export->ai.BotMovementViewTarget( movestate, (bot_goal_s *)goal, travelflags, lookahead, target ); +} + +static int SV_BotAllocMoveState( void ) { + return botlib_export->ai.BotAllocMoveState(); +} + +static void SV_BotFreeMoveState( int handle ) { + botlib_export->ai.BotFreeMoveState( handle ); +} + +static void SV_BotInitMoveState( int handle, void *initmove ) { + botlib_export->ai.BotInitMoveState( handle, (bot_initmove_s *)initmove ); +} + +static int SV_BotChooseBestFightWeapon( int weaponstate, int *inventory ) { + return botlib_export->ai.BotChooseBestFightWeapon( weaponstate, inventory ); +} + +static void SV_BotGetWeaponInfo( int weaponstate, int weapon, void *weaponinfo ) { + botlib_export->ai.BotGetWeaponInfo( weaponstate, weapon, (weaponinfo_s *)weaponinfo ); +} + +static int SV_BotLoadWeaponWeights( int weaponstate, char *filename ) { + return botlib_export->ai.BotLoadWeaponWeights( weaponstate, filename ); +} + +static int SV_BotAllocWeaponState( void ) { + return botlib_export->ai.BotAllocWeaponState(); +} + +static void SV_BotFreeWeaponState( int weaponstate ) { + botlib_export->ai.BotFreeWeaponState( weaponstate ); +} + +static void SV_BotResetWeaponState( int weaponstate ) { + botlib_export->ai.BotResetWeaponState( weaponstate ); +} + +static int SV_GeneticParentsAndChildSelection( int numranks, float *ranks, int *parent1, int *parent2, int *child ) { + return botlib_export->ai.GeneticParentsAndChildSelection( numranks, ranks, parent1, parent2, child ); +} + +static void SV_BotInterbreedGoalFuzzyLogic( int parent1, int parent2, int child ) { + botlib_export->ai.BotInterbreedGoalFuzzyLogic( parent1, parent2, child ); +} + +static void SV_BotMutateGoalFuzzyLogic( int goalstate, float range ) { + botlib_export->ai.BotMutateGoalFuzzyLogic( goalstate, range ); +} + +static int SV_BotGetNextCampSpotGoal( int num, void *goal ) { + return botlib_export->ai.BotGetNextCampSpotGoal( num, (bot_goal_s *)goal ); +} + +static int SV_BotGetMapLocationGoal( char *name, void *goal ) { + return botlib_export->ai.BotGetMapLocationGoal( name, (bot_goal_s *)goal ); +} + +static int SV_BotNumInitialChats( int chatstate, char *type ) { + return botlib_export->ai.BotNumInitialChats( chatstate, type ); +} + +static void SV_BotGetChatMessage( int chatstate, char *buf, int size ) { + botlib_export->ai.BotGetChatMessage( chatstate, buf, size ); +} + +static void SV_BotRemoveFromAvoidGoals( int goalstate, int number ) { + botlib_export->ai.BotRemoveFromAvoidGoals( goalstate, number ); +} + +static int SV_BotPredictVisiblePosition( vec3_t origin, int areanum, void *goal, int travelflags, vec3_t target ) { + return botlib_export->ai.BotPredictVisiblePosition( origin, areanum, (bot_goal_s *)goal, travelflags, target ); +} + +static void SV_BotSetAvoidGoalTime( int goalstate, int number, float avoidtime ) { + botlib_export->ai.BotSetAvoidGoalTime( goalstate, number, avoidtime ); +} + +static void SV_BotAddAvoidSpot( int movestate, vec3_t origin, float radius, int type ) { + botlib_export->ai.BotAddAvoidSpot( movestate, origin, radius, type ); +} + +static int SV_BotLibSetup( void ) { + return botlib_export->BotLibSetup(); +} + +static int SV_BotLibShutdown( void ) { + return botlib_export->BotLibShutdown(); +} + +static int SV_BotLibVarSet( char *var_name, char *value ) { + return botlib_export->BotLibVarSet( var_name, value ); +} + +static int SV_BotLibVarGet( char *var_name, char *value, int size ) { + return botlib_export->BotLibVarGet( var_name, value, size ); +} + +static int SV_BotLibDefine( char *string ) { + return botlib_export->PC_AddGlobalDefine( string ); +} + +static int SV_BotLibStartFrame( float time ) { + return botlib_export->BotLibStartFrame( time ); +} + +static int SV_BotLibLoadMap( const char *mapname ) { + return botlib_export->BotLibLoadMap( mapname ); +} + +static int SV_BotLibUpdateEntity( int ent, void *bue ) { + return botlib_export->BotLibUpdateEntity( ent, (bot_entitystate_t *)bue ); +} + +static int SV_BotLibTest( int parm0, char *parm1, vec3_t parm2, vec3_t parm3 ) { + return botlib_export->Test( parm0, parm1, parm2, parm3 ); +} + +static int SV_BotGetServerCommand( int clientNum, char *message, int size ) { + return SV_BotGetConsoleMessage( clientNum, message, size ); +} + +static void SV_BotUserCommand( int clientNum, usercmd_t *ucmd ) { + SV_ClientThink( &svs.clients[clientNum], ucmd ); +} + +static int SV_AAS_EnableRoutingArea( int areanum, int enable ) { + return botlib_export->aas.AAS_EnableRoutingArea( areanum, enable ); +} + +static int SV_AAS_BBoxAreas( vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas ) { + return botlib_export->aas.AAS_BBoxAreas( absmins, absmaxs, areas, maxareas ); +} + +static int SV_AAS_AreaInfo( int areanum, void *info ) { + return botlib_export->aas.AAS_AreaInfo( areanum, (aas_areainfo_s *)info ); +} + +static void SV_AAS_EntityInfo( int entnum, void *info ) { + botlib_export->aas.AAS_EntityInfo( entnum, (aas_entityinfo_s *)info ); +} + +static int SV_AAS_Initialized( void ) { + return botlib_export->aas.AAS_Initialized(); +} + +static void SV_AAS_PresenceTypeBoundingBox( int presencetype, vec3_t mins, vec3_t maxs ) { + botlib_export->aas.AAS_PresenceTypeBoundingBox( presencetype, mins, maxs ); +} + +static float SV_AAS_Time( void ) { + return botlib_export->aas.AAS_Time(); +} + +static int SV_AAS_PointAreaNum( vec3_t point ) { + return botlib_export->aas.AAS_PointAreaNum( point ); +} + +static int SV_AAS_TraceAreas( vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas ) { + return botlib_export->aas.AAS_TraceAreas( start, end, areas, points, maxareas ); +} + +static int SV_AAS_PointContents( vec3_t point ) { + return botlib_export->aas.AAS_PointContents( point ); +} + +static int SV_AAS_NextBSPEntity( int ent ) { + return botlib_export->aas.AAS_NextBSPEntity( ent ); +} + +static int SV_AAS_ValueForBSPEpairKey( int ent, char *key, char *value, int size ) { + return botlib_export->aas.AAS_ValueForBSPEpairKey( ent, key, value, size ); +} + +static int SV_AAS_VectorForBSPEpairKey( int ent, char *key, vec3_t v ) { + return botlib_export->aas.AAS_VectorForBSPEpairKey( ent, key, v ); +} + +static int SV_AAS_FloatForBSPEpairKey( int ent, char *key, float *value ) { + return botlib_export->aas.AAS_FloatForBSPEpairKey( ent, key, value ); +} + +static int SV_AAS_IntForBSPEpairKey( int ent, char *key, int *value ) { + return botlib_export->aas.AAS_IntForBSPEpairKey( ent, key, value ); +} + +static int SV_AAS_AreaReachability( int areanum ) { + return botlib_export->aas.AAS_AreaReachability( areanum ); +} + +static int SV_AAS_AreaTravelTimeToGoalArea( int areanum, vec3_t origin, int goalareanum, int travelflags ) { + return botlib_export->aas.AAS_AreaTravelTimeToGoalArea( areanum, origin, goalareanum, travelflags ); +} + +static int SV_AAS_Swimming( vec3_t origin ) { + return botlib_export->aas.AAS_Swimming( origin ); +} + +static int SV_AAS_PredictClientMovement( void *move, int entnum, vec3_t origin, int presencetype, int onground, vec3_t velocity, vec3_t cmdmove, int cmdframes, int maxframes, float frametime, int stopevent, int stopareanum, int visualize ) { + return botlib_export->aas.AAS_PredictClientMovement( (aas_clientmove_s *)move, entnum, origin, presencetype, onground, velocity, cmdmove, cmdframes, maxframes, frametime, stopevent, stopareanum, visualize ); +} + +static int SV_AAS_AlternativeRouteGoals( vec3_t start, int startareanum, vec3_t goal, int goalareanum, int travelflags, void *altroutegoals, int maxaltroutegoals, int type ) { + return botlib_export->aas.AAS_AlternativeRouteGoals( start, startareanum, goal, goalareanum, travelflags, (aas_altroutegoal_s *)altroutegoals, maxaltroutegoals, type ); +} + +static int SV_AAS_PredictRoute( void *route, int areanum, vec3_t origin, int goalareanum, int travelflags, int maxareas, int maxtime, int stopevent, int stopcontents, int stoptfl, int stopareanum ) { + return botlib_export->aas.AAS_PredictRoute( (aas_predictroute_s *)route, areanum, origin, goalareanum, travelflags, maxareas, maxtime, stopevent, stopcontents, stoptfl, stopareanum ); +} + +static int SV_AAS_PointReachabilityAreaIndex( vec3_t point ) { + return botlib_export->aas.AAS_PointReachabilityAreaIndex( point ); +} + +static void SV_EA_Say( int client, char *str ) { + botlib_export->ea.EA_Say( client, str ); +} + +static void SV_EA_SayTeam( int client, char *str ) { + botlib_export->ea.EA_SayTeam( client, str ); +} + +static void SV_EA_Command( int client, char *command ) { + botlib_export->ea.EA_Command( client, command ); +} + +static void SV_EA_Action( int client, int action ) { + botlib_export->ea.EA_Action( client, action ); +} + +static void SV_EA_Gesture( int client ) { + botlib_export->ea.EA_Gesture( client ); +} + +static void SV_EA_Talk( int client ) { + botlib_export->ea.EA_Talk( client ); +} + +static void SV_EA_Attack( int client ) { + botlib_export->ea.EA_Attack( client ); +} + +static void SV_EA_Alt_Attack( int client ) { + botlib_export->ea.EA_Alt_Attack( client ); +} + +static void SV_EA_ForcePower( int client ) { + botlib_export->ea.EA_ForcePower( client ); +} + +static void SV_EA_Use( int client ) { + botlib_export->ea.EA_Use( client ); +} + +static void SV_EA_Respawn( int client ) { + botlib_export->ea.EA_Respawn( client ); +} + +static void SV_EA_Crouch( int client ) { + botlib_export->ea.EA_Crouch( client ); +} + +static void SV_EA_MoveUp( int client ) { + botlib_export->ea.EA_MoveUp( client ); +} + +static void SV_EA_MoveDown( int client ) { + botlib_export->ea.EA_MoveDown( client ); +} + +static void SV_EA_MoveForward( int client ) { + botlib_export->ea.EA_MoveForward( client ); +} + +static void SV_EA_MoveBack( int client ) { + botlib_export->ea.EA_MoveBack( client ); +} + +static void SV_EA_MoveLeft( int client ) { + botlib_export->ea.EA_MoveLeft( client ); +} + +static void SV_EA_MoveRight( int client ) { + botlib_export->ea.EA_MoveRight( client ); +} + +static void SV_EA_SelectWeapon( int client, int weapon ) { + botlib_export->ea.EA_SelectWeapon( client, weapon ); +} + +static void SV_EA_Jump( int client ) { + botlib_export->ea.EA_Jump( client ); +} + +static void SV_EA_DelayedJump( int client ) { + botlib_export->ea.EA_DelayedJump( client ); +} + +static void SV_EA_Move( int client, vec3_t dir, float speed ) { + botlib_export->ea.EA_Move( client, dir, speed ); +} + +static void SV_EA_View( int client, vec3_t viewangles ) { + botlib_export->ea.EA_View( client, viewangles ); +} + +static void SV_EA_EndRegular( int client, float thinktime ) { + botlib_export->ea.EA_EndRegular( client, thinktime ); +} + +static void SV_EA_GetInput( int client, float thinktime, void *input ) { + botlib_export->ea.EA_GetInput( client, thinktime, (bot_input_t *)input ); +} + +static void SV_EA_ResetInput( int client ) { + botlib_export->ea.EA_ResetInput( client ); +} + +static int SV_PC_LoadSource( const char *filename ) { + return botlib_export->PC_LoadSourceHandle( filename ); +} + +static int SV_PC_FreeSource( int handle ) { + return botlib_export->PC_FreeSourceHandle( handle ); +} + +static int SV_PC_ReadToken( int handle, pc_token_t *pc_token ) { + return botlib_export->PC_ReadTokenHandle( handle, pc_token ); +} + +static int SV_PC_SourceFileAndLine( int handle, char *filename, int *line ) { + return botlib_export->PC_SourceFileAndLine( handle, filename, line ); +} + +static qhandle_t SV_RE_RegisterSkin( const char *name ) { + return re->RegisterServerSkin( name ); +} + +static int SV_CM_RegisterTerrain( const char *config ) { + return 0; +} + +static void SV_RMG_Init( void ) { } + +static void SV_G2API_ListModelSurfaces( void *ghlInfo ) { + re->G2API_ListSurfaces( (CGhoul2Info *)ghlInfo ); +} + +static void SV_G2API_ListModelBones( void *ghlInfo, int frame ) { + re->G2API_ListBones( (CGhoul2Info *)ghlInfo, frame ); +} + +static void SV_G2API_SetGhoul2ModelIndexes( void *ghoul2, qhandle_t *modelList, qhandle_t *skinList ) { + if ( !ghoul2 ) return; + re->G2API_SetGhoul2ModelIndexes( *((CGhoul2Info_v *)ghoul2), modelList, skinList ); +} + +static qboolean SV_G2API_HaveWeGhoul2Models( void *ghoul2) { + if ( !ghoul2 ) return qfalse; + return re->G2API_HaveWeGhoul2Models( *((CGhoul2Info_v *)ghoul2) ); +} + +static qboolean SV_G2API_GetBoltMatrix( void *ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale ) { + if ( !ghoul2 ) return qfalse; + return re->G2API_GetBoltMatrix( *((CGhoul2Info_v *)ghoul2), modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale ); +} + +static qboolean SV_G2API_GetBoltMatrix_NoReconstruct( void *ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale ) { + if ( !ghoul2 ) return qfalse; + re->G2API_BoltMatrixReconstruction( qfalse ); + return re->G2API_GetBoltMatrix( *((CGhoul2Info_v *)ghoul2), modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale ); +} + +static qboolean SV_G2API_GetBoltMatrix_NoRecNoRot( void *ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale ) { + if ( !ghoul2 ) return qfalse; + re->G2API_BoltMatrixReconstruction( qfalse ); + re->G2API_BoltMatrixSPMethod( qtrue ); + return re->G2API_GetBoltMatrix( *((CGhoul2Info_v *)ghoul2), modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale ); +} + +static int SV_G2API_InitGhoul2Model( void **ghoul2Ptr, const char *fileName, int modelIndex, qhandle_t customSkin, qhandle_t customShader, int modelFlags, int lodBias ) { +#ifdef _FULL_G2_LEAK_CHECKING + g_G2AllocServer = 1; +#endif + return re->G2API_InitGhoul2Model( (CGhoul2Info_v **)ghoul2Ptr, fileName, modelIndex, customSkin, customShader, modelFlags, lodBias ); +} + +static qboolean SV_G2API_SetSkin( void *ghoul2, int modelIndex, qhandle_t customSkin, qhandle_t renderSkin ) { + if ( !ghoul2 ) return qfalse; + CGhoul2Info_v &g2 = *((CGhoul2Info_v *)ghoul2); + return re->G2API_SetSkin( g2, modelIndex, customSkin, renderSkin ); +} + +static void SV_G2API_CollisionDetect( CollisionRecord_t *collRecMap, void* ghoul2, const vec3_t angles, const vec3_t position, int frameNumber, int entNum, vec3_t rayStart, vec3_t rayEnd, vec3_t scale, int traceFlags, int useLod, float fRadius ) { + if ( !ghoul2 ) return; + re->G2API_CollisionDetect( collRecMap, *((CGhoul2Info_v *)ghoul2), angles, position, frameNumber, entNum, rayStart, rayEnd, scale, G2VertSpaceServer, traceFlags, useLod, fRadius ); +} + +static void SV_G2API_CollisionDetectCache( CollisionRecord_t *collRecMap, void* ghoul2, const vec3_t angles, const vec3_t position, int frameNumber, int entNum, vec3_t rayStart, vec3_t rayEnd, vec3_t scale, int traceFlags, int useLod, float fRadius ) { + if ( !ghoul2 ) return; + re->G2API_CollisionDetectCache( collRecMap, *((CGhoul2Info_v *)ghoul2), angles, position, frameNumber, entNum, rayStart, rayEnd, scale, G2VertSpaceServer, traceFlags, useLod, fRadius ); +} + +static void SV_G2API_CleanGhoul2Models( void **ghoul2Ptr ) { +#ifdef _FULL_G2_LEAK_CHECKING + g_G2AllocServer = 1; +#endif + re->G2API_CleanGhoul2Models( (CGhoul2Info_v **)ghoul2Ptr ); +} + +static qboolean SV_G2API_SetBoneAngles( void *ghoul2, int modelIndex, const char *boneName, const vec3_t angles, const int flags, const int up, const int right, const int forward, qhandle_t *modelList, int blendTime , int currentTime ) { + if ( !ghoul2 ) return qfalse; + return re->G2API_SetBoneAngles( *((CGhoul2Info_v *)ghoul2), modelIndex, boneName, angles, flags, (const Eorientations)up, (const Eorientations)right, (const Eorientations)forward, modelList, blendTime , currentTime ); +} + +static qboolean SV_G2API_SetBoneAnim( void *ghoul2, const int modelIndex, const char *boneName, const int startFrame, const int endFrame, const int flags, const float animSpeed, const int currentTime, const float setFrame, const int blendTime ) { + if ( !ghoul2 ) return qfalse; + return re->G2API_SetBoneAnim( *((CGhoul2Info_v *)ghoul2), modelIndex, boneName, startFrame, endFrame, flags, animSpeed, currentTime, setFrame, blendTime ); +} + +static qboolean SV_G2API_GetBoneAnim( void *ghoul2, const char *boneName, const int currentTime, float *currentFrame, int *startFrame, int *endFrame, int *flags, float *animSpeed, int *modelList, const int modelIndex ) { + if ( !ghoul2 ) return qfalse; + CGhoul2Info_v &g2 = *((CGhoul2Info_v *)ghoul2); + return re->G2API_GetBoneAnim( g2, modelIndex, boneName, currentTime, currentFrame, startFrame, endFrame, flags, animSpeed, modelList ); +} + +static void SV_G2API_GetGLAName( void *ghoul2, int modelIndex, char *fillBuf ) { + if ( !ghoul2 ) + { + fillBuf[0] = '\0'; + return; + } + + char *tmp = re->G2API_GetGLAName( *((CGhoul2Info_v *)ghoul2), modelIndex ); + if ( tmp ) + strcpy( fillBuf, tmp ); + else + fillBuf[0] = '\0'; +} + +static int SV_G2API_CopyGhoul2Instance( void *g2From, void *g2To, int modelIndex ) { + if ( !g2From || !g2To ) return 0; + return re->G2API_CopyGhoul2Instance( *((CGhoul2Info_v *)g2From), *((CGhoul2Info_v *)g2To), modelIndex ); +} + +static void SV_G2API_CopySpecificGhoul2Model( void *g2From, int modelFrom, void *g2To, int modelTo ) { + if ( !g2From || !g2To ) return; + re->G2API_CopySpecificG2Model( *((CGhoul2Info_v *)g2From), modelFrom, *((CGhoul2Info_v *)g2To), modelTo ); +} + +static void SV_G2API_DuplicateGhoul2Instance( void *g2From, void **g2To ) { +#ifdef _FULL_G2_LEAK_CHECKING + g_G2AllocServer = 1; +#endif + if ( !g2From || !g2To ) return; + re->G2API_DuplicateGhoul2Instance( *((CGhoul2Info_v *)g2From), (CGhoul2Info_v **)g2To ); +} + +static qboolean SV_G2API_HasGhoul2ModelOnIndex( void *ghlInfo, int modelIndex ) { + return re->G2API_HasGhoul2ModelOnIndex( (CGhoul2Info_v **)ghlInfo, modelIndex ); +} + +static qboolean SV_G2API_RemoveGhoul2Model( void *ghlInfo, int modelIndex ) { +#ifdef _FULL_G2_LEAK_CHECKING + g_G2AllocServer = 1; +#endif + return re->G2API_RemoveGhoul2Model( (CGhoul2Info_v **)ghlInfo, modelIndex ); +} + +static qboolean SV_G2API_RemoveGhoul2Models( void *ghlInfo ) { +#ifdef _FULL_G2_LEAK_CHECKING + g_G2AllocServer = 1; +#endif + return re->G2API_RemoveGhoul2Models( (CGhoul2Info_v **)ghlInfo ); +} + +static int SV_G2API_Ghoul2Size( void *ghlInfo ) { + if ( !ghlInfo ) return 0; + return re->G2API_Ghoul2Size( *((CGhoul2Info_v *)ghlInfo) ); +} + +static int SV_G2API_AddBolt( void *ghoul2, int modelIndex, const char *boneName ) { + if ( !ghoul2 ) return -1; + return re->G2API_AddBolt( *((CGhoul2Info_v *)ghoul2), modelIndex, boneName ); +} + +static void SV_G2API_SetBoltInfo( void *ghoul2, int modelIndex, int boltInfo ) { + if ( !ghoul2 ) return; + re->G2API_SetBoltInfo( *((CGhoul2Info_v *)ghoul2), modelIndex, boltInfo ); +} + +static qboolean SV_G2API_SetRootSurface( void *ghoul2, const int modelIndex, const char *surfaceName ) { + if ( !ghoul2 ) return qfalse; + return re->G2API_SetRootSurface( *((CGhoul2Info_v *)ghoul2), modelIndex, surfaceName ); +} + +static qboolean SV_G2API_SetSurfaceOnOff( void *ghoul2, const char *surfaceName, const int flags ) { + if ( !ghoul2 ) return qfalse; + return re->G2API_SetSurfaceOnOff( *((CGhoul2Info_v *)ghoul2), surfaceName, flags ); +} + +static qboolean SV_G2API_SetNewOrigin( void *ghoul2, const int boltIndex ) { + if ( !ghoul2 ) return qfalse; + return re->G2API_SetNewOrigin( *((CGhoul2Info_v *)ghoul2), boltIndex ); +} + +static qboolean SV_G2API_DoesBoneExist( void *ghoul2, int modelIndex, const char *boneName ) { + if ( !ghoul2 ) return qfalse; + CGhoul2Info_v &g2 = *((CGhoul2Info_v *)ghoul2); + return re->G2API_DoesBoneExist( g2, modelIndex, boneName ); +} + +static int SV_G2API_GetSurfaceRenderStatus( void *ghoul2, const int modelIndex, const char *surfaceName ) { + if ( !ghoul2 ) return -1; + CGhoul2Info_v &g2 = *((CGhoul2Info_v *)ghoul2); + return re->G2API_GetSurfaceRenderStatus( g2, modelIndex, surfaceName ); +} + +static void SV_G2API_AbsurdSmoothing( void *ghoul2, qboolean status ) { + if ( !ghoul2 ) return; + CGhoul2Info_v &g2 = *((CGhoul2Info_v *)ghoul2); + re->G2API_AbsurdSmoothing( g2, status ); +} + +static void SV_G2API_SetRagDoll( void *ghoul2, sharedRagDollParams_t *params ) { + if ( !ghoul2 ) return; + + CRagDollParams rdParams; + + if ( !params ) { + re->G2API_ResetRagDoll( *((CGhoul2Info_v *)ghoul2) ); + return; + } + + VectorCopy( params->angles, rdParams.angles ); + VectorCopy( params->position, rdParams.position ); + VectorCopy( params->scale, rdParams.scale ); + VectorCopy( params->pelvisAnglesOffset, rdParams.pelvisAnglesOffset ); + VectorCopy( params->pelvisPositionOffset, rdParams.pelvisPositionOffset ); + + rdParams.fImpactStrength = params->fImpactStrength; + rdParams.fShotStrength = params->fShotStrength; + rdParams.me = params->me; + + rdParams.startFrame = params->startFrame; + rdParams.endFrame = params->endFrame; + + rdParams.collisionType = params->collisionType; + rdParams.CallRagDollBegin = params->CallRagDollBegin; + + rdParams.RagPhase = (CRagDollParams::ERagPhase)params->RagPhase; + rdParams.effectorsToTurnOff = (CRagDollParams::ERagEffector)params->effectorsToTurnOff; + + re->G2API_SetRagDoll( *((CGhoul2Info_v *)ghoul2), &rdParams ); +} + +static void SV_G2API_AnimateG2Models( void *ghoul2, int time, sharedRagDollUpdateParams_t *params ) { + CRagDollUpdateParams rduParams; + + if ( !params ) + return; + + VectorCopy( params->angles, rduParams.angles ); + VectorCopy( params->position, rduParams.position ); + VectorCopy( params->scale, rduParams.scale ); + VectorCopy( params->velocity, rduParams.velocity ); + + rduParams.me = params->me; + rduParams.settleFrame = params->settleFrame; + + re->G2API_AnimateG2ModelsRag( *((CGhoul2Info_v *)ghoul2), time, &rduParams ); +} + +static qboolean SV_G2API_RagPCJConstraint( void *ghoul2, const char *boneName, vec3_t min, vec3_t max ) { + return re->G2API_RagPCJConstraint( *((CGhoul2Info_v *)ghoul2), boneName, min, max ); +} + +static qboolean SV_G2API_RagPCJGradientSpeed( void *ghoul2, const char *boneName, const float speed ) { + return re->G2API_RagPCJGradientSpeed( *((CGhoul2Info_v *)ghoul2), boneName, speed ); +} + +static qboolean SV_G2API_RagEffectorGoal( void *ghoul2, const char *boneName, vec3_t pos ) { + return re->G2API_RagEffectorGoal( *((CGhoul2Info_v *)ghoul2), boneName, pos ); +} + +static qboolean SV_G2API_GetRagBonePos( void *ghoul2, const char *boneName, vec3_t pos, vec3_t entAngles, vec3_t entPos, vec3_t entScale ) { + return re->G2API_GetRagBonePos( *((CGhoul2Info_v *)ghoul2), boneName, pos, entAngles, entPos, entScale ); +} + +static qboolean SV_G2API_RagEffectorKick( void *ghoul2, const char *boneName, vec3_t velocity ) { + return re->G2API_RagEffectorKick( *((CGhoul2Info_v *)ghoul2), boneName, velocity ); +} + +static qboolean SV_G2API_RagForceSolve( void *ghoul2, qboolean force ) { + return re->G2API_RagForceSolve( *((CGhoul2Info_v *)ghoul2), force ); +} + +static qboolean SV_G2API_SetBoneIKState( void *ghoul2, int time, const char *boneName, int ikState, sharedSetBoneIKStateParams_t *params ) { + return re->G2API_SetBoneIKState( *((CGhoul2Info_v *)ghoul2), time, boneName, ikState, params ); +} + +static qboolean SV_G2API_IKMove( void *ghoul2, int time, sharedIKMoveParams_t *params ) { + return re->G2API_IKMove( *((CGhoul2Info_v *)ghoul2), time, params ); +} + +static qboolean SV_G2API_RemoveBone( void *ghoul2, const char *boneName, int modelIndex ) { + CGhoul2Info_v &g2 = *((CGhoul2Info_v *)ghoul2); + return re->G2API_RemoveBone( g2, modelIndex, boneName ); +} + +static void SV_G2API_AttachInstanceToEntNum( void *ghoul2, int entityNum, qboolean server ) { + re->G2API_AttachInstanceToEntNum( *((CGhoul2Info_v *)ghoul2), entityNum, server ); +} + +static void SV_G2API_ClearAttachedInstance( int entityNum ) { + re->G2API_ClearAttachedInstance( entityNum ); +} + +static void SV_G2API_CleanEntAttachments( void ) { + re->G2API_CleanEntAttachments(); +} + +static qboolean SV_G2API_OverrideServer( void *serverInstance ) { + CGhoul2Info_v &g2 = *((CGhoul2Info_v *)serverInstance); + return re->G2API_OverrideServerWithClientData( g2, 0 ); +} + +static void SV_G2API_GetSurfaceName( void *ghoul2, int surfNumber, int modelIndex, char *fillBuf ) { + CGhoul2Info_v &g2 = *((CGhoul2Info_v *)ghoul2); + char *tmp = re->G2API_GetSurfaceName( g2, modelIndex, surfNumber ); + strcpy( fillBuf, tmp ); +} + +static void GVM_Cvar_Set( const char *var_name, const char *value ) { + Cvar_VM_Set( var_name, value, VM_GAME ); +} + +// legacy syscall + +intptr_t SV_GameSystemCalls( intptr_t *args ) { + switch( args[0] ) { + + //rww - alright, DO NOT EVER add a game/cgame/ui generic call without adding a trap to match, and + //all of these traps must be shared and have cases in sv_game, cl_cgame, and cl_ui. They must also + //all be in the same order, and start at 100. + case TRAP_MEMSET: + Com_Memset( VMA(1), args[2], args[3] ); + return 0; + + case TRAP_MEMCPY: + Com_Memcpy( VMA(1), VMA(2), args[3] ); + return 0; + + case TRAP_STRNCPY: + strncpy( (char *)VMA(1), (const char *)VMA(2), args[3] ); + return args[1]; + + case TRAP_SIN: + return FloatAsInt( sin( VMF(1) ) ); + + case TRAP_COS: + return FloatAsInt( cos( VMF(1) ) ); + + case TRAP_ATAN2: + return FloatAsInt( atan2( VMF(1), VMF(2) ) ); + + case TRAP_SQRT: + return FloatAsInt( sqrt( VMF(1) ) ); + + case TRAP_MATRIXMULTIPLY: + MatrixMultiply( (vec3_t *)VMA(1), (vec3_t *)VMA(2), (vec3_t *)VMA(3) ); + return 0; + + case TRAP_ANGLEVECTORS: + AngleVectors( (const float *)VMA(1), (float *)VMA(2), (float *)VMA(3), (float *)VMA(4) ); + return 0; + + case TRAP_PERPENDICULARVECTOR: + PerpendicularVector( (float *)VMA(1), (const float *)VMA(2) ); + return 0; + + case TRAP_FLOOR: + return FloatAsInt( floor( VMF(1) ) ); + + case TRAP_CEIL: + return FloatAsInt( ceil( VMF(1) ) ); + + case TRAP_TESTPRINTINT: + return 0; + + case TRAP_TESTPRINTFLOAT: + return 0; + + case TRAP_ACOS: + return FloatAsInt( Q_acos( VMF(1) ) ); + + case TRAP_ASIN: + return FloatAsInt( Q_asin( VMF(1) ) ); + + case G_PRINT: + Com_Printf( "%s", VMA(1) ); + return 0; + + case G_ERROR: + Com_Error( ERR_DROP, "%s", VMA(1) ); + return 0; + + case G_MILLISECONDS: + return Sys_Milliseconds(); + + case G_PRECISIONTIMER_START: + SV_PrecisionTimerStart( (void **)VMA(1) ); + return 0; + + case G_PRECISIONTIMER_END: + return SV_PrecisionTimerEnd( (void *)args[1] ); + + case G_CVAR_REGISTER: + Cvar_Register( (vmCvar_t *)VMA(1), (const char *)VMA(2), (const char *)VMA(3), args[4] ); + return 0; + + case G_CVAR_UPDATE: + Cvar_Update( (vmCvar_t *)VMA(1) ); + return 0; + + case G_CVAR_SET: + Cvar_VM_Set( (const char *)VMA(1), (const char *)VMA(2), VM_GAME ); + return 0; + + case G_CVAR_VARIABLE_INTEGER_VALUE: + return Cvar_VariableIntegerValue( (const char *)VMA(1) ); + + case G_CVAR_VARIABLE_STRING_BUFFER: + Cvar_VariableStringBuffer( (const char *)VMA(1), (char *)VMA(2), args[3] ); + return 0; + + case G_ARGC: + return Cmd_Argc(); + + case G_ARGV: + Cmd_ArgvBuffer( args[1], (char *)VMA(2), args[3] ); + return 0; + + case G_SEND_CONSOLE_COMMAND: + Cbuf_ExecuteText( args[1], (const char *)VMA(2) ); + return 0; + + case G_FS_FOPEN_FILE: + return FS_FOpenFileByMode( (const char *)VMA(1), (int *)VMA(2), (fsMode_t)args[3] ); + + case G_FS_READ: + FS_Read( VMA(1), args[2], args[3] ); + return 0; + + case G_FS_WRITE: + FS_Write( VMA(1), args[2], args[3] ); + return 0; + + case G_FS_FCLOSE_FILE: + FS_FCloseFile( args[1] ); + return 0; + + case G_FS_GETFILELIST: + return FS_GetFileList( (const char *)VMA(1), (const char *)VMA(2), (char *)VMA(3), args[4] ); + + case G_LOCATE_GAME_DATA: + SV_LocateGameData( (sharedEntity_t *)VMA(1), args[2], args[3], (struct playerState_s *)VMA(4), args[5] ); + return 0; + + case G_DROP_CLIENT: + SV_GameDropClient( args[1], (const char *)VMA(2) ); + return 0; + + case G_SEND_SERVER_COMMAND: + SV_GameSendServerCommand( args[1], (const char *)VMA(2) ); + return 0; + + case G_LINKENTITY: + SV_LinkEntity( (sharedEntity_t *)VMA(1) ); + return 0; + + case G_UNLINKENTITY: + SV_UnlinkEntity( (sharedEntity_t *)VMA(1) ); + return 0; + + case G_ENTITIES_IN_BOX: + return SV_AreaEntities( (const float *)VMA(1), (const float *)VMA(2), (int *)VMA(3), args[4] ); + + case G_ENTITY_CONTACT: + return SV_EntityContact( (const float *)VMA(1), (const float *)VMA(2), (const sharedEntity_t *)VMA(3), /*int capsule*/ qfalse ); + + case G_ENTITY_CONTACTCAPSULE: + return SV_EntityContact( (const float *)VMA(1), (const float *)VMA(2), (const sharedEntity_t *)VMA(3), /*int capsule*/ qtrue ); + + case G_TRACE: + SV_Trace( (trace_t *)VMA(1), (const float *)VMA(2), (const float *)VMA(3), (const float *)VMA(4), (const float *)VMA(5), args[6], args[7], /*int capsule*/ qfalse, /*args[8]*/0, args[9] ); + return 0; + case G_G2TRACE: + SV_Trace( (trace_t *)VMA(1), (const float *)VMA(2), (const float *)VMA(3), (const float *)VMA(4), (const float *)VMA(5), args[6], args[7], /*int capsule*/ qfalse, args[8], args[9] ); + return 0; + case G_TRACECAPSULE: + SV_Trace( (trace_t *)VMA(1), (const float *)VMA(2), (const float *)VMA(3), (const float *)VMA(4), (const float *)VMA(5), args[6], args[7], /*int capsule*/ qtrue, args[8], args[9] ); + return 0; + case G_POINT_CONTENTS: + return SV_PointContents( (const float *)VMA(1), args[2] ); + case G_SET_SERVER_CULL: + SV_SetServerCull( VMF( 1 ) ); + return 0; + case G_SET_BRUSH_MODEL: + SV_SetBrushModel( (sharedEntity_t *)VMA(1), (const char *)VMA(2) ); + return 0; + case G_IN_PVS: + return SV_inPVS( (const float *)VMA(1), (const float *)VMA(2) ); + case G_IN_PVS_IGNORE_PORTALS: + return SV_inPVSIgnorePortals( (const float *)VMA(1), (const float *)VMA(2) ); + + case G_SET_CONFIGSTRING: + SV_SetConfigstring( args[1], (const char *)VMA(2) ); + return 0; + case G_GET_CONFIGSTRING: + SV_GetConfigstring( args[1], (char *)VMA(2), args[3] ); + return 0; + case G_SET_USERINFO: + SV_SetUserinfo( args[1], (const char *)VMA(2) ); + return 0; + case G_GET_USERINFO: + SV_GetUserinfo( args[1], (char *)VMA(2), args[3] ); + return 0; + case G_GET_SERVERINFO: + SV_GetServerinfo( (char *)VMA(1), args[2] ); + return 0; + case G_ADJUST_AREA_PORTAL_STATE: + SV_AdjustAreaPortalState( (sharedEntity_t *)VMA(1), (qboolean)args[2] ); + return 0; + case G_AREAS_CONNECTED: + return CM_AreasConnected( args[1], args[2] ); + + case G_BOT_ALLOCATE_CLIENT: + return SV_BotAllocateClient(); + case G_BOT_FREE_CLIENT: + SV_BotFreeClient( args[1] ); + return 0; + + case G_GET_USERCMD: + SV_GetUsercmd( args[1], (struct usercmd_s *)VMA(2) ); + return 0; + + case G_SIEGEPERSSET: + SV_SiegePersSet( (siegePers_t *)VMA( 1 ) ); + return 0; + + case G_SIEGEPERSGET: + SV_SiegePersGet( (siegePers_t *)VMA( 1 ) ); + return 0; + + //rwwRMG - see below + /* + case G_GET_ENTITY_TOKEN: + { + const char *s; + + s = COM_Parse( (const char **) &sv.entityParsePoint ); + Q_strncpyz( (char *)VMA(1), s, args[2] ); + if ( !sv.entityParsePoint && !s[0] ) { + return qfalse; + } else { + return qtrue; + } + } + */ + + /* + case G_BOT_GET_MEMORY: + void *ptr; + ptr = Bot_GetMemoryGame(args[1]); + return (int)ptr; + case G_BOT_FREE_MEMORY: + Bot_FreeMemoryGame((void *)VMA(1)); + return 0; + */ + case G_DEBUG_POLYGON_CREATE: + return BotImport_DebugPolygonCreate( args[1], args[2], (float (*)[3])VMA(3) ); + case G_DEBUG_POLYGON_DELETE: + BotImport_DebugPolygonDelete( args[1] ); + return 0; + case G_REAL_TIME: + return Com_RealTime( (struct qtime_s *)VMA(1) ); + case G_SNAPVECTOR: + Sys_SnapVector( (float *)VMA(1) ); + return 0; + + case SP_GETSTRINGTEXTSTRING: + return qfalse; + break; + + case G_ROFF_CLEAN: + return SV_ROFF_Clean(); + + case G_ROFF_UPDATE_ENTITIES: + SV_ROFF_UpdateEntities(); + return 0; + + case G_ROFF_CACHE: + return SV_ROFF_Cache( (char *)VMA(1) ); + + case G_ROFF_PLAY: + return SV_ROFF_Play( args[1], args[2], (qboolean)args[3] ); + + case G_ROFF_PURGE_ENT: + return SV_ROFF_Purge_Ent( args[1] ); + + //rww - dynamic vm memory allocation! + case G_TRUEMALLOC: + VM_Shifted_Alloc((void **)VMA(1), args[2]); + return 0; + case G_TRUEFREE: + VM_Shifted_Free((void **)VMA(1)); + return 0; + + //rww - icarus traps + case G_ICARUS_RUNSCRIPT: + return ICARUS_RunScript(ConvertedEntity((sharedEntity_t *)VMA(1)), (const char *)VMA(2)); + + case G_ICARUS_REGISTERSCRIPT: + return ICARUS_RegisterScript((const char *)VMA(1), (qboolean)args[2]); + + case G_ICARUS_INIT: + ICARUS_Init(); + return 0; + + case G_ICARUS_VALIDENT: + return ICARUS_ValidEnt(ConvertedEntity((sharedEntity_t *)VMA(1))); + + case G_ICARUS_ISINITIALIZED: + return ICARUS_IsInitialized( args[1] ); + + case G_ICARUS_MAINTAINTASKMANAGER: + return ICARUS_MaintainTaskManager( args[1] ); + + case G_ICARUS_ISRUNNING: + return ICARUS_IsRunning( args[1] ); + + case G_ICARUS_TASKIDPENDING: + return Q3_TaskIDPending((sharedEntity_t *)VMA(1), (taskID_t)args[2]); + + case G_ICARUS_INITENT: + ICARUS_InitEnt(ConvertedEntity((sharedEntity_t *)VMA(1))); + return 0; + + case G_ICARUS_FREEENT: + ICARUS_FreeEnt(ConvertedEntity((sharedEntity_t *)VMA(1))); + return 0; + + case G_ICARUS_ASSOCIATEENT: + ICARUS_AssociateEnt(ConvertedEntity((sharedEntity_t *)VMA(1))); + return 0; + + case G_ICARUS_SHUTDOWN: + ICARUS_Shutdown(); + return 0; + + case G_ICARUS_TASKIDSET: + //rww - note that we are passing in the true entity here. + //This is because we allow modification of certain non-pointer values, + //which is valid. + Q3_TaskIDSet((sharedEntity_t *)VMA(1), (taskID_t)args[2], args[3]); + return 0; + + case G_ICARUS_TASKIDCOMPLETE: + //same as above. + Q3_TaskIDComplete((sharedEntity_t *)VMA(1), (taskID_t)args[2]); + return 0; + + case G_ICARUS_SETVAR: + Q3_SetVar(args[1], args[2], (const char *)VMA(3), (const char *)VMA(4)); + return 0; + + case G_ICARUS_VARIABLEDECLARED: + return Q3_VariableDeclared((const char *)VMA(1)); + + case G_ICARUS_GETFLOATVARIABLE: + return Q3_GetFloatVariable((const char *)VMA(1), (float *)VMA(2)); + + case G_ICARUS_GETSTRINGVARIABLE: + { + const char *rec = (const char *)VMA(2); + return Q3_GetStringVariable((const char *)VMA(1), (const char **)&rec); + } + + case G_ICARUS_GETVECTORVARIABLE: + return Q3_GetVectorVariable((const char *)VMA(1), (float *)VMA(2)); + + + //rww - BEGIN NPC NAV TRAPS + case G_NAV_INIT: + navigator.Init(); + return 0; + case G_NAV_FREE: + navigator.Free(); + return 0; + case G_NAV_LOAD: + return navigator.Load((const char *)VMA(1), args[2]); + case G_NAV_SAVE: + return navigator.Save((const char *)VMA(1), args[2]); + case G_NAV_ADDRAWPOINT: + return navigator.AddRawPoint((float *)VMA(1), args[2], args[3]); + case G_NAV_CALCULATEPATHS: + navigator.CalculatePaths((qboolean)args[1]); + return 0; + case G_NAV_HARDCONNECT: + navigator.HardConnect(args[1], args[2]); + return 0; + case G_NAV_SHOWNODES: + navigator.ShowNodes(); + return 0; + case G_NAV_SHOWEDGES: + navigator.ShowEdges(); + return 0; + case G_NAV_SHOWPATH: + navigator.ShowPath(args[1], args[2]); + return 0; + case G_NAV_GETNEARESTNODE: + return navigator.GetNearestNode((sharedEntity_t *)VMA(1), args[2], args[3], args[4]); + case G_NAV_GETBESTNODE: + return navigator.GetBestNode(args[1], args[2], args[3]); + case G_NAV_GETNODEPOSITION: + return navigator.GetNodePosition(args[1], (float *)VMA(2)); + case G_NAV_GETNODENUMEDGES: + return navigator.GetNodeNumEdges(args[1]); + case G_NAV_GETNODEEDGE: + return navigator.GetNodeEdge(args[1], args[2]); + case G_NAV_GETNUMNODES: + return navigator.GetNumNodes(); + case G_NAV_CONNECTED: + return navigator.Connected(args[1], args[2]); + case G_NAV_GETPATHCOST: + return navigator.GetPathCost(args[1], args[2]); + case G_NAV_GETEDGECOST: + return navigator.GetEdgeCost(args[1], args[2]); + case G_NAV_GETPROJECTEDNODE: + return navigator.GetProjectedNode((float *)VMA(1), args[2]); + case G_NAV_CHECKFAILEDNODES: + navigator.CheckFailedNodes((sharedEntity_t *)VMA(1)); + return 0; + case G_NAV_ADDFAILEDNODE: + navigator.AddFailedNode((sharedEntity_t *)VMA(1), args[2]); + return 0; + case G_NAV_NODEFAILED: + return navigator.NodeFailed((sharedEntity_t *)VMA(1), args[2]); + case G_NAV_NODESARENEIGHBORS: + return navigator.NodesAreNeighbors(args[1], args[2]); + case G_NAV_CLEARFAILEDEDGE: + navigator.ClearFailedEdge((failedEdge_t *)VMA(1)); + return 0; + case G_NAV_CLEARALLFAILEDEDGES: + navigator.ClearAllFailedEdges(); + return 0; + case G_NAV_EDGEFAILED: + return navigator.EdgeFailed(args[1], args[2]); + case G_NAV_ADDFAILEDEDGE: + navigator.AddFailedEdge(args[1], args[2], args[3]); + return 0; + case G_NAV_CHECKFAILEDEDGE: + return navigator.CheckFailedEdge((failedEdge_t *)VMA(1)); + case G_NAV_CHECKALLFAILEDEDGES: + navigator.CheckAllFailedEdges(); + return 0; + case G_NAV_ROUTEBLOCKED: + return navigator.RouteBlocked(args[1], args[2], args[3], args[4]); + case G_NAV_GETBESTNODEALTROUTE: + return navigator.GetBestNodeAltRoute(args[1], args[2], (int *)VMA(3), args[4]); + case G_NAV_GETBESTNODEALT2: + return navigator.GetBestNodeAltRoute(args[1], args[2], args[3]); + case G_NAV_GETBESTPATHBETWEENENTS: + return navigator.GetBestPathBetweenEnts((sharedEntity_t *)VMA(1), (sharedEntity_t *)VMA(2), args[3]); + case G_NAV_GETNODERADIUS: + return navigator.GetNodeRadius(args[1]); + case G_NAV_CHECKBLOCKEDEDGES: + navigator.CheckBlockedEdges(); + return 0; + case G_NAV_CLEARCHECKEDNODES: + navigator.ClearCheckedNodes(); + return 0; + case G_NAV_CHECKEDNODE: + return navigator.CheckedNode(args[1], args[2]); + case G_NAV_SETCHECKEDNODE: + navigator.SetCheckedNode(args[1], args[2], args[3]); + return 0; + case G_NAV_FLAGALLNODES: + navigator.FlagAllNodes(args[1]); + return 0; + case G_NAV_GETPATHSCALCULATED: + return navigator.pathsCalculated; + case G_NAV_SETPATHSCALCULATED: + navigator.pathsCalculated = (qboolean)args[1]; + return 0; + //rww - END NPC NAV TRAPS + + case G_SET_SHARED_BUFFER: + SV_RegisterSharedMemory( (char *)VMA(1) ); + return 0; + //==================================== + + case BOTLIB_SETUP: + return SV_BotLibSetup(); + case BOTLIB_SHUTDOWN: + return SV_BotLibShutdown(); + case BOTLIB_LIBVAR_SET: + return botlib_export->BotLibVarSet( (char *)VMA(1), (char *)VMA(2) ); + case BOTLIB_LIBVAR_GET: + return botlib_export->BotLibVarGet( (char *)VMA(1), (char *)VMA(2), args[3] ); + + case BOTLIB_PC_ADD_GLOBAL_DEFINE: + return botlib_export->PC_AddGlobalDefine( (char *)VMA(1) ); + case BOTLIB_PC_LOAD_SOURCE: + return botlib_export->PC_LoadSourceHandle( (const char *)VMA(1) ); + case BOTLIB_PC_FREE_SOURCE: + return botlib_export->PC_FreeSourceHandle( args[1] ); + case BOTLIB_PC_READ_TOKEN: + return botlib_export->PC_ReadTokenHandle( args[1], (struct pc_token_s *)VMA(2) ); + case BOTLIB_PC_SOURCE_FILE_AND_LINE: + return botlib_export->PC_SourceFileAndLine( args[1], (char *)VMA(2), (int *)VMA(3) ); + + case BOTLIB_START_FRAME: + return botlib_export->BotLibStartFrame( VMF(1) ); + case BOTLIB_LOAD_MAP: + return botlib_export->BotLibLoadMap( (const char *)VMA(1) ); + case BOTLIB_UPDATENTITY: + return botlib_export->BotLibUpdateEntity( args[1], (struct bot_entitystate_s *)VMA(2) ); + case BOTLIB_TEST: + return botlib_export->Test( args[1], (char *)VMA(2), (float *)VMA(3), (float *)VMA(4) ); + + case BOTLIB_GET_SNAPSHOT_ENTITY: + return SV_BotGetSnapshotEntity( args[1], args[2] ); + case BOTLIB_GET_CONSOLE_MESSAGE: + return SV_BotGetConsoleMessage( args[1], (char *)VMA(2), args[3] ); + case BOTLIB_USER_COMMAND: + SV_ClientThink( &svs.clients[args[1]], (struct usercmd_s *)VMA(2) ); + return 0; + + case BOTLIB_AAS_BBOX_AREAS: + return botlib_export->aas.AAS_BBoxAreas( (float *)VMA(1), (float *)VMA(2), (int *)VMA(3), args[4] ); + case BOTLIB_AAS_AREA_INFO: + return botlib_export->aas.AAS_AreaInfo( args[1], (struct aas_areainfo_s *)VMA(2) ); + case BOTLIB_AAS_ALTERNATIVE_ROUTE_GOAL: + return botlib_export->aas.AAS_AlternativeRouteGoals( (float *)VMA(1), args[2], (float *)VMA(3), args[4], args[5], (struct aas_altroutegoal_s *)VMA(6), args[7], args[8] ); + case BOTLIB_AAS_ENTITY_INFO: + botlib_export->aas.AAS_EntityInfo( args[1], (struct aas_entityinfo_s *)VMA(2) ); + return 0; + + case BOTLIB_AAS_INITIALIZED: + return botlib_export->aas.AAS_Initialized(); + case BOTLIB_AAS_PRESENCE_TYPE_BOUNDING_BOX: + botlib_export->aas.AAS_PresenceTypeBoundingBox( args[1], (float *)VMA(2), (float *)VMA(3) ); + return 0; + case BOTLIB_AAS_TIME: + return FloatAsInt( botlib_export->aas.AAS_Time() ); + + case BOTLIB_AAS_POINT_AREA_NUM: + return botlib_export->aas.AAS_PointAreaNum( (float *)VMA(1) ); + case BOTLIB_AAS_POINT_REACHABILITY_AREA_INDEX: + return botlib_export->aas.AAS_PointReachabilityAreaIndex( (float *)VMA(1) ); + case BOTLIB_AAS_TRACE_AREAS: + return botlib_export->aas.AAS_TraceAreas( (float *)VMA(1), (float *)VMA(2), (int *)VMA(3), (float (*)[3])VMA(4), args[5] ); + + case BOTLIB_AAS_POINT_CONTENTS: + return botlib_export->aas.AAS_PointContents( (float *)VMA(1) ); + case BOTLIB_AAS_NEXT_BSP_ENTITY: + return botlib_export->aas.AAS_NextBSPEntity( args[1] ); + case BOTLIB_AAS_VALUE_FOR_BSP_EPAIR_KEY: + return botlib_export->aas.AAS_ValueForBSPEpairKey( args[1], (char *)VMA(2), (char *)VMA(3), args[4] ); + case BOTLIB_AAS_VECTOR_FOR_BSP_EPAIR_KEY: + return botlib_export->aas.AAS_VectorForBSPEpairKey( args[1], (char *)VMA(2), (float *)VMA(3) ); + case BOTLIB_AAS_FLOAT_FOR_BSP_EPAIR_KEY: + return botlib_export->aas.AAS_FloatForBSPEpairKey( args[1], (char *)VMA(2), (float *)VMA(3) ); + case BOTLIB_AAS_INT_FOR_BSP_EPAIR_KEY: + return botlib_export->aas.AAS_IntForBSPEpairKey( args[1], (char *)VMA(2), (int *)VMA(3) ); + + case BOTLIB_AAS_AREA_REACHABILITY: + return botlib_export->aas.AAS_AreaReachability( args[1] ); + + case BOTLIB_AAS_AREA_TRAVEL_TIME_TO_GOAL_AREA: + return botlib_export->aas.AAS_AreaTravelTimeToGoalArea( args[1], (float *)VMA(2), args[3], args[4] ); + case BOTLIB_AAS_ENABLE_ROUTING_AREA: + return botlib_export->aas.AAS_EnableRoutingArea( args[1], args[2] ); + case BOTLIB_AAS_PREDICT_ROUTE: + return botlib_export->aas.AAS_PredictRoute( (struct aas_predictroute_s *)VMA(1), args[2], (float *)VMA(3), args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11] ); + + case BOTLIB_AAS_SWIMMING: + return botlib_export->aas.AAS_Swimming( (float *)VMA(1) ); + case BOTLIB_AAS_PREDICT_CLIENT_MOVEMENT: + return botlib_export->aas.AAS_PredictClientMovement( (struct aas_clientmove_s *)VMA(1), args[2], (float *)VMA(3), args[4], args[5], + (float *)VMA(6), (float *)VMA(7), args[8], args[9], VMF(10), args[11], args[12], args[13] ); + + case BOTLIB_EA_SAY: + botlib_export->ea.EA_Say( args[1], (char *)VMA(2) ); + return 0; + case BOTLIB_EA_SAY_TEAM: + botlib_export->ea.EA_SayTeam( args[1], (char *)VMA(2) ); + return 0; + case BOTLIB_EA_COMMAND: + botlib_export->ea.EA_Command( args[1], (char *)VMA(2) ); + return 0; + + case BOTLIB_EA_ACTION: + botlib_export->ea.EA_Action( args[1], args[2] ); + break; + case BOTLIB_EA_GESTURE: + botlib_export->ea.EA_Gesture( args[1] ); + return 0; + case BOTLIB_EA_TALK: + botlib_export->ea.EA_Talk( args[1] ); + return 0; + case BOTLIB_EA_ATTACK: + botlib_export->ea.EA_Attack( args[1] ); + return 0; + case BOTLIB_EA_ALT_ATTACK: + botlib_export->ea.EA_Alt_Attack( args[1] ); + return 0; + case BOTLIB_EA_FORCEPOWER: + botlib_export->ea.EA_ForcePower( args[1] ); + return 0; + case BOTLIB_EA_USE: + botlib_export->ea.EA_Use( args[1] ); + return 0; + case BOTLIB_EA_RESPAWN: + botlib_export->ea.EA_Respawn( args[1] ); + return 0; + case BOTLIB_EA_CROUCH: + botlib_export->ea.EA_Crouch( args[1] ); + return 0; + case BOTLIB_EA_MOVE_UP: + botlib_export->ea.EA_MoveUp( args[1] ); + return 0; + case BOTLIB_EA_MOVE_DOWN: + botlib_export->ea.EA_MoveDown( args[1] ); + return 0; + case BOTLIB_EA_MOVE_FORWARD: + botlib_export->ea.EA_MoveForward( args[1] ); + return 0; + case BOTLIB_EA_MOVE_BACK: + botlib_export->ea.EA_MoveBack( args[1] ); + return 0; + case BOTLIB_EA_MOVE_LEFT: + botlib_export->ea.EA_MoveLeft( args[1] ); + return 0; + case BOTLIB_EA_MOVE_RIGHT: + botlib_export->ea.EA_MoveRight( args[1] ); + return 0; + + case BOTLIB_EA_SELECT_WEAPON: + botlib_export->ea.EA_SelectWeapon( args[1], args[2] ); + return 0; + case BOTLIB_EA_JUMP: + botlib_export->ea.EA_Jump( args[1] ); + return 0; + case BOTLIB_EA_DELAYED_JUMP: + botlib_export->ea.EA_DelayedJump( args[1] ); + return 0; + case BOTLIB_EA_MOVE: + botlib_export->ea.EA_Move( args[1], (float *)VMA(2), VMF(3) ); + return 0; + case BOTLIB_EA_VIEW: + botlib_export->ea.EA_View( args[1], (float *)VMA(2) ); + return 0; + + case BOTLIB_EA_END_REGULAR: + botlib_export->ea.EA_EndRegular( args[1], VMF(2) ); + return 0; + case BOTLIB_EA_GET_INPUT: + botlib_export->ea.EA_GetInput( args[1], VMF(2), (struct bot_input_s *)VMA(3) ); + return 0; + case BOTLIB_EA_RESET_INPUT: + botlib_export->ea.EA_ResetInput( args[1] ); + return 0; + + case BOTLIB_AI_LOAD_CHARACTER: + return botlib_export->ai.BotLoadCharacter( (char *)VMA(1), VMF(2) ); + case BOTLIB_AI_FREE_CHARACTER: + botlib_export->ai.BotFreeCharacter( args[1] ); + return 0; + case BOTLIB_AI_CHARACTERISTIC_FLOAT: + return FloatAsInt( botlib_export->ai.Characteristic_Float( args[1], args[2] ) ); + case BOTLIB_AI_CHARACTERISTIC_BFLOAT: + return FloatAsInt( botlib_export->ai.Characteristic_BFloat( args[1], args[2], VMF(3), VMF(4) ) ); + case BOTLIB_AI_CHARACTERISTIC_INTEGER: + return botlib_export->ai.Characteristic_Integer( args[1], args[2] ); + case BOTLIB_AI_CHARACTERISTIC_BINTEGER: + return botlib_export->ai.Characteristic_BInteger( args[1], args[2], args[3], args[4] ); + case BOTLIB_AI_CHARACTERISTIC_STRING: + botlib_export->ai.Characteristic_String( args[1], args[2], (char *)VMA(3), args[4] ); + return 0; + + case BOTLIB_AI_ALLOC_CHAT_STATE: + return botlib_export->ai.BotAllocChatState(); + case BOTLIB_AI_FREE_CHAT_STATE: + botlib_export->ai.BotFreeChatState( args[1] ); + return 0; + case BOTLIB_AI_QUEUE_CONSOLE_MESSAGE: + botlib_export->ai.BotQueueConsoleMessage( args[1], args[2], (char *)VMA(3) ); + return 0; + case BOTLIB_AI_REMOVE_CONSOLE_MESSAGE: + botlib_export->ai.BotRemoveConsoleMessage( args[1], args[2] ); + return 0; + case BOTLIB_AI_NEXT_CONSOLE_MESSAGE: + return botlib_export->ai.BotNextConsoleMessage( args[1], (struct bot_consolemessage_s *)VMA(2) ); + case BOTLIB_AI_NUM_CONSOLE_MESSAGE: + return botlib_export->ai.BotNumConsoleMessages( args[1] ); + case BOTLIB_AI_INITIAL_CHAT: + botlib_export->ai.BotInitialChat( args[1], (char *)VMA(2), args[3], (char *)VMA(4), (char *)VMA(5), (char *)VMA(6), (char *)VMA(7), (char *)VMA(8), (char *)VMA(9), (char *)VMA(10), (char *)VMA(11) ); + return 0; + case BOTLIB_AI_NUM_INITIAL_CHATS: + return botlib_export->ai.BotNumInitialChats( args[1], (char *)VMA(2) ); + case BOTLIB_AI_REPLY_CHAT: + return botlib_export->ai.BotReplyChat( args[1], (char *)VMA(2), args[3], args[4], (char *)VMA(5), (char *)VMA(6), (char *)VMA(7), (char *)VMA(8), (char *)VMA(9), (char *)VMA(10), (char *)VMA(11), (char *)VMA(12) ); + case BOTLIB_AI_CHAT_LENGTH: + return botlib_export->ai.BotChatLength( args[1] ); + case BOTLIB_AI_ENTER_CHAT: + botlib_export->ai.BotEnterChat( args[1], args[2], args[3] ); + return 0; + case BOTLIB_AI_GET_CHAT_MESSAGE: + botlib_export->ai.BotGetChatMessage( args[1], (char *)VMA(2), args[3] ); + return 0; + case BOTLIB_AI_STRING_CONTAINS: + return botlib_export->ai.StringContains( (char *)VMA(1), (char *)VMA(2), args[3] ); + case BOTLIB_AI_FIND_MATCH: + return botlib_export->ai.BotFindMatch( (char *)VMA(1), (struct bot_match_s *)VMA(2), args[3] ); + case BOTLIB_AI_MATCH_VARIABLE: + botlib_export->ai.BotMatchVariable( (struct bot_match_s *)VMA(1), args[2], (char *)VMA(3), args[4] ); + return 0; + case BOTLIB_AI_UNIFY_WHITE_SPACES: + botlib_export->ai.UnifyWhiteSpaces( (char *)VMA(1) ); + return 0; + case BOTLIB_AI_REPLACE_SYNONYMS: + botlib_export->ai.BotReplaceSynonyms( (char *)VMA(1), args[2] ); + return 0; + case BOTLIB_AI_LOAD_CHAT_FILE: + return botlib_export->ai.BotLoadChatFile( args[1], (char *)VMA(2), (char *)VMA(3) ); + case BOTLIB_AI_SET_CHAT_GENDER: + botlib_export->ai.BotSetChatGender( args[1], args[2] ); + return 0; + case BOTLIB_AI_SET_CHAT_NAME: + botlib_export->ai.BotSetChatName( args[1], (char *)VMA(2), args[3] ); + return 0; + + case BOTLIB_AI_RESET_GOAL_STATE: + botlib_export->ai.BotResetGoalState( args[1] ); + return 0; + case BOTLIB_AI_RESET_AVOID_GOALS: + botlib_export->ai.BotResetAvoidGoals( args[1] ); + return 0; + case BOTLIB_AI_REMOVE_FROM_AVOID_GOALS: + botlib_export->ai.BotRemoveFromAvoidGoals( args[1], args[2] ); + return 0; + case BOTLIB_AI_PUSH_GOAL: + botlib_export->ai.BotPushGoal( args[1], (struct bot_goal_s *)VMA(2) ); + return 0; + case BOTLIB_AI_POP_GOAL: + botlib_export->ai.BotPopGoal( args[1] ); + return 0; + case BOTLIB_AI_EMPTY_GOAL_STACK: + botlib_export->ai.BotEmptyGoalStack( args[1] ); + return 0; + case BOTLIB_AI_DUMP_AVOID_GOALS: + botlib_export->ai.BotDumpAvoidGoals( args[1] ); + return 0; + case BOTLIB_AI_DUMP_GOAL_STACK: + botlib_export->ai.BotDumpGoalStack( args[1] ); + return 0; + case BOTLIB_AI_GOAL_NAME: + botlib_export->ai.BotGoalName( args[1], (char *)VMA(2), args[3] ); + return 0; + case BOTLIB_AI_GET_TOP_GOAL: + return botlib_export->ai.BotGetTopGoal( args[1], (struct bot_goal_s *)VMA(2) ); + case BOTLIB_AI_GET_SECOND_GOAL: + return botlib_export->ai.BotGetSecondGoal( args[1], (struct bot_goal_s *)VMA(2) ); + case BOTLIB_AI_CHOOSE_LTG_ITEM: + return botlib_export->ai.BotChooseLTGItem( args[1], (float *)VMA(2), (int *)VMA(3), args[4] ); + case BOTLIB_AI_CHOOSE_NBG_ITEM: + return botlib_export->ai.BotChooseNBGItem( args[1], (float *)VMA(2), (int *)VMA(3), args[4], (struct bot_goal_s *)VMA(5), VMF(6) ); + case BOTLIB_AI_TOUCHING_GOAL: + return botlib_export->ai.BotTouchingGoal( (float *)VMA(1), (struct bot_goal_s *)VMA(2) ); + case BOTLIB_AI_ITEM_GOAL_IN_VIS_BUT_NOT_VISIBLE: + return botlib_export->ai.BotItemGoalInVisButNotVisible( args[1], (float *)VMA(2), (float *)VMA(3), (struct bot_goal_s *)VMA(4) ); + case BOTLIB_AI_GET_LEVEL_ITEM_GOAL: + return botlib_export->ai.BotGetLevelItemGoal( args[1], (char *)VMA(2), (struct bot_goal_s *)VMA(3) ); + case BOTLIB_AI_GET_NEXT_CAMP_SPOT_GOAL: + return botlib_export->ai.BotGetNextCampSpotGoal( args[1], (struct bot_goal_s *)VMA(2) ); + case BOTLIB_AI_GET_MAP_LOCATION_GOAL: + return botlib_export->ai.BotGetMapLocationGoal( (char *)VMA(1), (struct bot_goal_s *)VMA(2) ); + case BOTLIB_AI_AVOID_GOAL_TIME: + return FloatAsInt( botlib_export->ai.BotAvoidGoalTime( args[1], args[2] ) ); + case BOTLIB_AI_SET_AVOID_GOAL_TIME: + botlib_export->ai.BotSetAvoidGoalTime( args[1], args[2], VMF(3)); + return 0; + case BOTLIB_AI_INIT_LEVEL_ITEMS: + botlib_export->ai.BotInitLevelItems(); + return 0; + case BOTLIB_AI_UPDATE_ENTITY_ITEMS: + botlib_export->ai.BotUpdateEntityItems(); + return 0; + case BOTLIB_AI_LOAD_ITEM_WEIGHTS: + return botlib_export->ai.BotLoadItemWeights( args[1], (char *)VMA(2) ); + case BOTLIB_AI_FREE_ITEM_WEIGHTS: + botlib_export->ai.BotFreeItemWeights( args[1] ); + return 0; + case BOTLIB_AI_INTERBREED_GOAL_FUZZY_LOGIC: + botlib_export->ai.BotInterbreedGoalFuzzyLogic( args[1], args[2], args[3] ); + return 0; + case BOTLIB_AI_SAVE_GOAL_FUZZY_LOGIC: + botlib_export->ai.BotSaveGoalFuzzyLogic( args[1], (char *)VMA(2) ); + return 0; + case BOTLIB_AI_MUTATE_GOAL_FUZZY_LOGIC: + botlib_export->ai.BotMutateGoalFuzzyLogic( args[1], VMF(2) ); + return 0; + case BOTLIB_AI_ALLOC_GOAL_STATE: + return botlib_export->ai.BotAllocGoalState( args[1] ); + case BOTLIB_AI_FREE_GOAL_STATE: + botlib_export->ai.BotFreeGoalState( args[1] ); + return 0; + + case BOTLIB_AI_RESET_MOVE_STATE: + botlib_export->ai.BotResetMoveState( args[1] ); + return 0; + case BOTLIB_AI_ADD_AVOID_SPOT: + botlib_export->ai.BotAddAvoidSpot( args[1], (float *)VMA(2), VMF(3), args[4] ); + return 0; + case BOTLIB_AI_MOVE_TO_GOAL: + botlib_export->ai.BotMoveToGoal( (struct bot_moveresult_s *)VMA(1), args[2], (struct bot_goal_s *)VMA(3), args[4] ); + return 0; + case BOTLIB_AI_MOVE_IN_DIRECTION: + return botlib_export->ai.BotMoveInDirection( args[1], (float *)VMA(2), VMF(3), args[4] ); + case BOTLIB_AI_RESET_AVOID_REACH: + botlib_export->ai.BotResetAvoidReach( args[1] ); + return 0; + case BOTLIB_AI_RESET_LAST_AVOID_REACH: + botlib_export->ai.BotResetLastAvoidReach( args[1] ); + return 0; + case BOTLIB_AI_REACHABILITY_AREA: + return botlib_export->ai.BotReachabilityArea( (float *)VMA(1), args[2] ); + case BOTLIB_AI_MOVEMENT_VIEW_TARGET: + return botlib_export->ai.BotMovementViewTarget( args[1], (struct bot_goal_s *)VMA(2), args[3], VMF(4), (float *)VMA(5) ); + case BOTLIB_AI_PREDICT_VISIBLE_POSITION: + return botlib_export->ai.BotPredictVisiblePosition( (float *)VMA(1), args[2], (struct bot_goal_s *)VMA(3), args[4], (float *)VMA(5) ); + case BOTLIB_AI_ALLOC_MOVE_STATE: + return botlib_export->ai.BotAllocMoveState(); + case BOTLIB_AI_FREE_MOVE_STATE: + botlib_export->ai.BotFreeMoveState( args[1] ); + return 0; + case BOTLIB_AI_INIT_MOVE_STATE: + botlib_export->ai.BotInitMoveState( args[1], (struct bot_initmove_s *)VMA(2) ); + return 0; + + case BOTLIB_AI_CHOOSE_BEST_FIGHT_WEAPON: + return botlib_export->ai.BotChooseBestFightWeapon( args[1], (int *)VMA(2) ); + case BOTLIB_AI_GET_WEAPON_INFO: + botlib_export->ai.BotGetWeaponInfo( args[1], args[2], (struct weaponinfo_s *)VMA(3) ); + return 0; + case BOTLIB_AI_LOAD_WEAPON_WEIGHTS: + return botlib_export->ai.BotLoadWeaponWeights( args[1], (char *)VMA(2) ); + case BOTLIB_AI_ALLOC_WEAPON_STATE: + return botlib_export->ai.BotAllocWeaponState(); + case BOTLIB_AI_FREE_WEAPON_STATE: + botlib_export->ai.BotFreeWeaponState( args[1] ); + return 0; + case BOTLIB_AI_RESET_WEAPON_STATE: + botlib_export->ai.BotResetWeaponState( args[1] ); + return 0; + + case BOTLIB_AI_GENETIC_PARENTS_AND_CHILD_SELECTION: + return botlib_export->ai.GeneticParentsAndChildSelection(args[1], (float *)VMA(2), (int *)VMA(3), (int *)VMA(4), (int *)VMA(5)); + + case G_R_REGISTERSKIN: + return re->RegisterServerSkin((const char *)VMA(1)); + + case G_G2_LISTBONES: + SV_G2API_ListModelBones( VMA(1), args[2] ); + return 0; + + case G_G2_LISTSURFACES: + SV_G2API_ListModelSurfaces( VMA(1) ); + return 0; + + case G_G2_HAVEWEGHOULMODELS: + return SV_G2API_HaveWeGhoul2Models( VMA(1) ); + + case G_G2_SETMODELS: + SV_G2API_SetGhoul2ModelIndexes( VMA(1),(qhandle_t *)VMA(2),(qhandle_t *)VMA(3)); + return 0; + + case G_G2_GETBOLT: + return SV_G2API_GetBoltMatrix(VMA(1), args[2], args[3], (mdxaBone_t *)VMA(4), (const float *)VMA(5),(const float *)VMA(6), args[7], (qhandle_t *)VMA(8), (float *)VMA(9)); + + case G_G2_GETBOLT_NOREC: + return SV_G2API_GetBoltMatrix_NoReconstruct(VMA(1), args[2], args[3], (mdxaBone_t *)VMA(4), (const float *)VMA(5),(const float *)VMA(6), args[7], (qhandle_t *)VMA(8), (float *)VMA(9)); + + case G_G2_GETBOLT_NOREC_NOROT: + return SV_G2API_GetBoltMatrix_NoRecNoRot(VMA(1), args[2], args[3], (mdxaBone_t *)VMA(4), (const float *)VMA(5),(const float *)VMA(6), args[7], (qhandle_t *)VMA(8), (float *)VMA(9)); + + case G_G2_INITGHOUL2MODEL: +#ifdef _FULL_G2_LEAK_CHECKING + g_G2AllocServer = 1; +#endif + return SV_G2API_InitGhoul2Model((void **)VMA(1), (const char *)VMA(2), args[3], (qhandle_t) args[4], + (qhandle_t) args[5], args[6], args[7]); + + case G_G2_SETSKIN: + return SV_G2API_SetSkin(VMA(1), args[2], args[3], args[4]); + + case G_G2_SIZE: + return SV_G2API_Ghoul2Size ( VMA(1) ); + + case G_G2_ADDBOLT: + return SV_G2API_AddBolt(VMA(1), args[2], (const char *)VMA(3)); + + case G_G2_SETBOLTINFO: + SV_G2API_SetBoltInfo(VMA(1), args[2], args[3]); + return 0; + + case G_G2_ANGLEOVERRIDE: + return SV_G2API_SetBoneAngles(VMA(1), args[2], (const char *)VMA(3), (float *)VMA(4), args[5], + (const Eorientations) args[6], (const Eorientations) args[7], (const Eorientations) args[8], + (qhandle_t *)VMA(9), args[10], args[11] ); + + case G_G2_PLAYANIM: + return SV_G2API_SetBoneAnim(VMA(1), args[2], (const char *)VMA(3), args[4], args[5], + args[6], VMF(7), args[8], VMF(9), args[10]); + + case G_G2_GETBONEANIM: + return SV_G2API_GetBoneAnim(VMA(1), (const char*)VMA(2), args[3], (float *)VMA(4), (int *)VMA(5), + (int *)VMA(6), (int *)VMA(7), (float *)VMA(8), (int *)VMA(9), args[10]); + + case G_G2_GETGLANAME: + SV_G2API_GetGLAName( VMA(1), args[2], (char *)VMA(3) ); + return 0; + + case G_G2_COPYGHOUL2INSTANCE: + return (int)SV_G2API_CopyGhoul2Instance(VMA(1), VMA(2), args[3]); + + case G_G2_COPYSPECIFICGHOUL2MODEL: + SV_G2API_CopySpecificGhoul2Model(VMA(1), args[2], VMA(3), args[4]); + return 0; + + case G_G2_DUPLICATEGHOUL2INSTANCE: +#ifdef _FULL_G2_LEAK_CHECKING + g_G2AllocServer = 1; +#endif + SV_G2API_DuplicateGhoul2Instance(VMA(1), (void **)VMA(2)); + return 0; + + case G_G2_HASGHOUL2MODELONINDEX: + return (int)SV_G2API_HasGhoul2ModelOnIndex((void **)VMA(1), args[2]); + + case G_G2_REMOVEGHOUL2MODEL: +#ifdef _FULL_G2_LEAK_CHECKING + g_G2AllocServer = 1; +#endif + //return (int)G2API_RemoveGhoul2Model((CGhoul2Info_v **)args[1], args[2]); + return (int)SV_G2API_RemoveGhoul2Model((void **)VMA(1), args[2]); + + case G_G2_REMOVEGHOUL2MODELS: +#ifdef _FULL_G2_LEAK_CHECKING + g_G2AllocServer = 1; +#endif + //return (int)G2API_RemoveGhoul2Models((CGhoul2Info_v **)args[1]); + return (int)SV_G2API_RemoveGhoul2Models((void **)VMA(1)); + + case G_G2_CLEANMODELS: +#ifdef _FULL_G2_LEAK_CHECKING + g_G2AllocServer = 1; +#endif + SV_G2API_CleanGhoul2Models((void **)VMA(1)); + // re->G2API_CleanGhoul2Models((CGhoul2Info_v **)args[1]); + return 0; + + case G_G2_COLLISIONDETECT: + SV_G2API_CollisionDetect ( (CollisionRecord_t*)VMA(1), VMA(2), (const float*)VMA(3), (const float*)VMA(4), args[5], args[6], (float*)VMA(7), (float*)VMA(8), (float*)VMA(9), args[10], args[11], VMF(12) ); + return 0; + + case G_G2_COLLISIONDETECTCACHE: + SV_G2API_CollisionDetectCache ( (CollisionRecord_t*)VMA(1), VMA(2), (const float*)VMA(3), (const float*)VMA(4), args[5], args[6], (float*)VMA(7), (float*)VMA(8), (float*)VMA(9), args[10], args[11], VMF(12) ); + return 0; + + case G_G2_SETROOTSURFACE: + return SV_G2API_SetRootSurface(VMA(1), args[2], (const char *)VMA(3)); + + case G_G2_SETSURFACEONOFF: + return SV_G2API_SetSurfaceOnOff(VMA(1), (const char *)VMA(2), /*(const int)VMA(3)*/args[3]); + + case G_G2_SETNEWORIGIN: + return SV_G2API_SetNewOrigin(VMA(1), /*(const int)VMA(2)*/args[2]); + + case G_G2_DOESBONEEXIST: + return SV_G2API_DoesBoneExist(VMA(1), args[2], (const char *)VMA(3)); + + case G_G2_GETSURFACERENDERSTATUS: + return SV_G2API_GetSurfaceRenderStatus(VMA(1), args[2], (const char *)VMA(3)); + + case G_G2_ABSURDSMOOTHING: + SV_G2API_AbsurdSmoothing(VMA(1), (qboolean)args[2]); + return 0; + + case G_G2_SETRAGDOLL: + SV_G2API_SetRagDoll( VMA(1), (sharedRagDollParams_t *)VMA(2) ); + return 0; + + case G_G2_ANIMATEG2MODELS: + SV_G2API_AnimateG2Models( VMA(1), args[2], (sharedRagDollUpdateParams_t *)VMA(3) ); + return 0; + + //additional ragdoll options -rww + case G_G2_RAGPCJCONSTRAINT: + return SV_G2API_RagPCJConstraint(VMA(1), (const char *)VMA(2), (float *)VMA(3), (float *)VMA(4)); + case G_G2_RAGPCJGRADIENTSPEED: + return SV_G2API_RagPCJGradientSpeed(VMA(1), (const char *)VMA(2), VMF(3)); + case G_G2_RAGEFFECTORGOAL: + return SV_G2API_RagEffectorGoal(VMA(1), (const char *)VMA(2), (float *)VMA(3)); + case G_G2_GETRAGBONEPOS: + return SV_G2API_GetRagBonePos(VMA(1), (const char *)VMA(2), (float *)VMA(3), (float *)VMA(4), (float *)VMA(5), (float *)VMA(6)); + case G_G2_RAGEFFECTORKICK: + return SV_G2API_RagEffectorKick(VMA(1), (const char *)VMA(2), (float *)VMA(3)); + case G_G2_RAGFORCESOLVE: + return SV_G2API_RagForceSolve(VMA(1), (qboolean)args[2]); + + case G_G2_SETBONEIKSTATE: + return SV_G2API_SetBoneIKState(VMA(1), args[2], (const char *)VMA(3), args[4], (sharedSetBoneIKStateParams_t *)VMA(5)); + case G_G2_IKMOVE: + return SV_G2API_IKMove(VMA(1), args[2], (sharedIKMoveParams_t *)VMA(3)); + + case G_G2_REMOVEBONE: + return SV_G2API_RemoveBone(VMA(1), (const char *)VMA(2), args[3]); + + case G_G2_ATTACHINSTANCETOENTNUM: + SV_G2API_AttachInstanceToEntNum(VMA(1), args[2], (qboolean)args[3]); + return 0; + case G_G2_CLEARATTACHEDINSTANCE: + SV_G2API_ClearAttachedInstance(args[1]); + return 0; + case G_G2_CLEANENTATTACHMENTS: + SV_G2API_CleanEntAttachments(); + return 0; + case G_G2_OVERRIDESERVER: + return SV_G2API_OverrideServer(VMA(1)); + + case G_G2_GETSURFACENAME: + SV_G2API_GetSurfaceName(VMA(1), args[2], args[3], (char *)VMA(4)); + return 0; + + case G_SET_ACTIVE_SUBBSP: + SV_SetActiveSubBSP(args[1]); + return 0; + + case G_RMG_INIT: + return 0; + + case G_CM_REGISTER_TERRAIN: + return 0; + + case G_BOT_UPDATEWAYPOINTS: + SV_BotWaypointReception(args[1], (wpobject_t **)VMA(2)); + return 0; + case G_BOT_CALCULATEPATHS: + SV_BotCalculatePaths(args[1]); + return 0; + + case G_GET_ENTITY_TOKEN: + return SV_GetEntityToken((char *)VMA(1), args[2]); + + default: + Com_Error( ERR_DROP, "Bad game system trap: %ld", (long int) args[0] ); + } + return -1; +} + +void SV_InitGame( qboolean restart ) { + int i=0; + client_t *cl = NULL; + + // clear level pointers + sv.entityParsePoint = CM_EntityString(); + for ( i=0, cl=svs.clients; iinteger; i++, cl++ ) + cl->gentity = NULL; + + GVM_InitGame( sv.time, Com_Milliseconds(), restart ); +} + +void SV_BindGame( void ) { + static gameImport_t gi; + gameExport_t *ret; + GetGameAPI_t GetGameAPI; + char dllName[MAX_OSPATH] = "jampgame" ARCH_STRING DLL_EXT; + + memset( &gi, 0, sizeof( gi ) ); + + gvm = VM_Create( VM_GAME ); + if ( gvm && !gvm->isLegacy ) { + gi.Print = Com_Printf; + gi.Error = Com_Error; + gi.Milliseconds = Com_Milliseconds; + gi.PrecisionTimerStart = SV_PrecisionTimerStart; + gi.PrecisionTimerEnd = SV_PrecisionTimerEnd; + gi.SV_RegisterSharedMemory = SV_RegisterSharedMemory; + gi.RealTime = Com_RealTime; + gi.TrueMalloc = VM_Shifted_Alloc; + gi.TrueFree = VM_Shifted_Free; + gi.SnapVector = Sys_SnapVector; + gi.Cvar_Register = Cvar_Register; + gi.Cvar_Set = GVM_Cvar_Set; + gi.Cvar_Update = Cvar_Update; + gi.Cvar_VariableIntegerValue = Cvar_VariableIntegerValue; + gi.Cvar_VariableStringBuffer = Cvar_VariableStringBuffer; + gi.Argc = Cmd_Argc; + gi.Argv = Cmd_ArgvBuffer; + gi.FS_Close = FS_FCloseFile; + gi.FS_GetFileList = FS_GetFileList; + gi.FS_Open = FS_FOpenFileByMode; + gi.FS_Read = FS_Read; + gi.FS_Write = FS_Write; + gi.AdjustAreaPortalState = SV_AdjustAreaPortalState; + gi.AreasConnected = CM_AreasConnected; + gi.DebugPolygonCreate = BotImport_DebugPolygonCreate; + gi.DebugPolygonDelete = BotImport_DebugPolygonDelete; + gi.DropClient = SV_GameDropClient; + gi.EntitiesInBox = SV_AreaEntities; + gi.EntityContact = SV_EntityContact; + gi.Trace = SV_Trace; + gi.GetConfigstring = SV_GetConfigstring; + gi.GetEntityToken = SV_GetEntityToken; + gi.GetServerinfo = SV_GetServerinfo; + gi.GetUsercmd = SV_GetUsercmd; + gi.GetUserinfo = SV_GetUserinfo; + gi.InPVS = SV_inPVS; + gi.InPVSIgnorePortals = SV_inPVSIgnorePortals; + gi.LinkEntity = SV_LinkEntity; + gi.LocateGameData = SV_LocateGameData; + gi.PointContents = SV_PointContents; + gi.SendConsoleCommand = Cbuf_ExecuteText; + gi.SendServerCommand = SV_GameSendServerCommand; + gi.SetBrushModel = SV_SetBrushModel; + gi.SetConfigstring = SV_SetConfigstring; + gi.SetServerCull = SV_SetServerCull; + gi.SetUserinfo = SV_SetUserinfo; + gi.SiegePersSet = SV_SiegePersSet; + gi.SiegePersGet = SV_SiegePersGet; + gi.UnlinkEntity = SV_UnlinkEntity; + gi.ROFF_Clean = SV_ROFF_Clean; + gi.ROFF_UpdateEntities = SV_ROFF_UpdateEntities; + gi.ROFF_Cache = SV_ROFF_Cache; + gi.ROFF_Play = SV_ROFF_Play; + gi.ROFF_Purge_Ent = SV_ROFF_Purge_Ent; + gi.ICARUS_RunScript = ICARUS_RunScript; + gi.ICARUS_RegisterScript = SV_ICARUS_RegisterScript; + gi.ICARUS_Init = ICARUS_Init; + gi.ICARUS_ValidEnt = SV_ICARUS_ValidEnt; + gi.ICARUS_IsInitialized = ICARUS_IsInitialized; + gi.ICARUS_MaintainTaskManager = ICARUS_MaintainTaskManager; + gi.ICARUS_IsRunning = ICARUS_IsRunning; + gi.ICARUS_TaskIDPending = ICARUS_TaskIDPending; + gi.ICARUS_InitEnt = ICARUS_InitEnt; + gi.ICARUS_FreeEnt = ICARUS_FreeEnt; + gi.ICARUS_AssociateEnt = ICARUS_AssociateEnt; + gi.ICARUS_Shutdown = ICARUS_Shutdown; + gi.ICARUS_TaskIDSet = SV_ICARUS_TaskIDSet; + gi.ICARUS_TaskIDComplete = SV_ICARUS_TaskIDComplete; + gi.ICARUS_SetVar = Q3_SetVar; + gi.ICARUS_VariableDeclared = Q3_VariableDeclared; + gi.ICARUS_GetFloatVariable = Q3_GetFloatVariable; + gi.ICARUS_GetStringVariable = SV_ICARUS_GetStringVariable; + gi.ICARUS_GetVectorVariable = SV_ICARUS_GetVectorVariable; + gi.Nav_Init = SV_Nav_Init; + gi.Nav_Free = SV_Nav_Free; + gi.Nav_Load = SV_Nav_Load; + gi.Nav_Save = SV_Nav_Save; + gi.Nav_AddRawPoint = SV_Nav_AddRawPoint; + gi.Nav_CalculatePaths = SV_Nav_CalculatePaths; + gi.Nav_HardConnect = SV_Nav_HardConnect; + gi.Nav_ShowNodes = SV_Nav_ShowNodes; + gi.Nav_ShowEdges = SV_Nav_ShowEdges; + gi.Nav_ShowPath = SV_Nav_ShowPath; + gi.Nav_GetNearestNode = SV_Nav_GetNearestNode; + gi.Nav_GetBestNode = SV_Nav_GetBestNode; + gi.Nav_GetNodePosition = SV_Nav_GetNodePosition; + gi.Nav_GetNodeNumEdges = SV_Nav_GetNodeNumEdges; + gi.Nav_GetNodeEdge = SV_Nav_GetNodeEdge; + gi.Nav_GetNumNodes = SV_Nav_GetNumNodes; + gi.Nav_Connected = SV_Nav_Connected; + gi.Nav_GetPathCost = SV_Nav_GetPathCost; + gi.Nav_GetEdgeCost = SV_Nav_GetEdgeCost; + gi.Nav_GetProjectedNode = SV_Nav_GetProjectedNode; + gi.Nav_CheckFailedNodes = SV_Nav_CheckFailedNodes; + gi.Nav_AddFailedNode = SV_Nav_AddFailedNode; + gi.Nav_NodeFailed = SV_Nav_NodeFailed; + gi.Nav_NodesAreNeighbors = SV_Nav_NodesAreNeighbors; + gi.Nav_ClearFailedEdge = SV_Nav_ClearFailedEdge; + gi.Nav_ClearAllFailedEdges = SV_Nav_ClearAllFailedEdges; + gi.Nav_EdgeFailed = SV_Nav_EdgeFailed; + gi.Nav_AddFailedEdge = SV_Nav_AddFailedEdge; + gi.Nav_CheckFailedEdge = SV_Nav_CheckFailedEdge; + gi.Nav_CheckAllFailedEdges = SV_Nav_CheckAllFailedEdges; + gi.Nav_RouteBlocked = SV_Nav_RouteBlocked; + gi.Nav_GetBestNodeAltRoute = SV_Nav_GetBestNodeAltRoute; + gi.Nav_GetBestNodeAltRoute2 = SV_Nav_GetBestNodeAltRoute2; + gi.Nav_GetBestPathBetweenEnts = SV_Nav_GetBestPathBetweenEnts; + gi.Nav_GetNodeRadius = SV_Nav_GetNodeRadius; + gi.Nav_CheckBlockedEdges = SV_Nav_CheckBlockedEdges; + gi.Nav_ClearCheckedNodes = SV_Nav_ClearCheckedNodes; + gi.Nav_CheckedNode = SV_Nav_CheckedNode; + gi.Nav_SetCheckedNode = SV_Nav_SetCheckedNode; + gi.Nav_FlagAllNodes = SV_Nav_FlagAllNodes; + gi.Nav_GetPathsCalculated = SV_Nav_GetPathsCalculated; + gi.Nav_SetPathsCalculated = SV_Nav_SetPathsCalculated; + gi.BotAllocateClient = SV_BotAllocateClient; + gi.BotFreeClient = SV_BotFreeClient; + gi.BotLoadCharacter = SV_BotLoadCharacter; + gi.BotFreeCharacter = SV_BotFreeCharacter; + gi.Characteristic_Float = SV_Characteristic_Float; + gi.Characteristic_BFloat = SV_Characteristic_BFloat; + gi.Characteristic_Integer = SV_Characteristic_Integer; + gi.Characteristic_BInteger = SV_Characteristic_BInteger; + gi.Characteristic_String = SV_Characteristic_String; + gi.BotAllocChatState = SV_BotAllocChatState; + gi.BotFreeChatState = SV_BotFreeChatState; + gi.BotQueueConsoleMessage = SV_BotQueueConsoleMessage; + gi.BotRemoveConsoleMessage = SV_BotRemoveConsoleMessage; + gi.BotNextConsoleMessage = SV_BotNextConsoleMessage; + gi.BotNumConsoleMessages = SV_BotNumConsoleMessages; + gi.BotInitialChat = SV_BotInitialChat; + gi.BotReplyChat = SV_BotReplyChat; + gi.BotChatLength = SV_BotChatLength; + gi.BotEnterChat = SV_BotEnterChat; + gi.StringContains = SV_StringContains; + gi.BotFindMatch = SV_BotFindMatch; + gi.BotMatchVariable = SV_BotMatchVariable; + gi.UnifyWhiteSpaces = SV_UnifyWhiteSpaces; + gi.BotReplaceSynonyms = SV_BotReplaceSynonyms; + gi.BotLoadChatFile = SV_BotLoadChatFile; + gi.BotSetChatGender = SV_BotSetChatGender; + gi.BotSetChatName = SV_BotSetChatName; + gi.BotResetGoalState = SV_BotResetGoalState; + gi.BotResetAvoidGoals = SV_BotResetAvoidGoals; + gi.BotPushGoal = SV_BotPushGoal; + gi.BotPopGoal = SV_BotPopGoal; + gi.BotEmptyGoalStack = SV_BotEmptyGoalStack; + gi.BotDumpAvoidGoals = SV_BotDumpAvoidGoals; + gi.BotDumpGoalStack = SV_BotDumpGoalStack; + gi.BotGoalName = SV_BotGoalName; + gi.BotGetTopGoal = SV_BotGetTopGoal; + gi.BotGetSecondGoal = SV_BotGetSecondGoal; + gi.BotChooseLTGItem = SV_BotChooseLTGItem; + gi.BotChooseNBGItem = SV_BotChooseNBGItem; + gi.BotTouchingGoal = SV_BotTouchingGoal; + gi.BotItemGoalInVisButNotVisible = SV_BotItemGoalInVisButNotVisible; + gi.BotGetLevelItemGoal = SV_BotGetLevelItemGoal; + gi.BotAvoidGoalTime = SV_BotAvoidGoalTime; + gi.BotInitLevelItems = SV_BotInitLevelItems; + gi.BotUpdateEntityItems = SV_BotUpdateEntityItems; + gi.BotLoadItemWeights = SV_BotLoadItemWeights; + gi.BotFreeItemWeights = SV_BotFreeItemWeights; + gi.BotSaveGoalFuzzyLogic = SV_BotSaveGoalFuzzyLogic; + gi.BotAllocGoalState = SV_BotAllocGoalState; + gi.BotFreeGoalState = SV_BotFreeGoalState; + gi.BotResetMoveState = SV_BotResetMoveState; + gi.BotMoveToGoal = SV_BotMoveToGoal; + gi.BotMoveInDirection = SV_BotMoveInDirection; + gi.BotResetAvoidReach = SV_BotResetAvoidReach; + gi.BotResetLastAvoidReach = SV_BotResetLastAvoidReach; + gi.BotReachabilityArea = SV_BotReachabilityArea; + gi.BotMovementViewTarget = SV_BotMovementViewTarget; + gi.BotAllocMoveState = SV_BotAllocMoveState; + gi.BotFreeMoveState = SV_BotFreeMoveState; + gi.BotInitMoveState = SV_BotInitMoveState; + gi.BotChooseBestFightWeapon = SV_BotChooseBestFightWeapon; + gi.BotGetWeaponInfo = SV_BotGetWeaponInfo; + gi.BotLoadWeaponWeights = SV_BotLoadWeaponWeights; + gi.BotAllocWeaponState = SV_BotAllocWeaponState; + gi.BotFreeWeaponState = SV_BotFreeWeaponState; + gi.BotResetWeaponState = SV_BotResetWeaponState; + gi.GeneticParentsAndChildSelection = SV_GeneticParentsAndChildSelection; + gi.BotInterbreedGoalFuzzyLogic = SV_BotInterbreedGoalFuzzyLogic; + gi.BotMutateGoalFuzzyLogic = SV_BotMutateGoalFuzzyLogic; + gi.BotGetNextCampSpotGoal = SV_BotGetNextCampSpotGoal; + gi.BotGetMapLocationGoal = SV_BotGetMapLocationGoal; + gi.BotNumInitialChats = SV_BotNumInitialChats; + gi.BotGetChatMessage = SV_BotGetChatMessage; + gi.BotRemoveFromAvoidGoals = SV_BotRemoveFromAvoidGoals; + gi.BotPredictVisiblePosition = SV_BotPredictVisiblePosition; + gi.BotSetAvoidGoalTime = SV_BotSetAvoidGoalTime; + gi.BotAddAvoidSpot = SV_BotAddAvoidSpot; + gi.BotLibSetup = SV_BotLibSetup; + gi.BotLibShutdown = SV_BotLibShutdown; + gi.BotLibVarSet = SV_BotLibVarSet; + gi.BotLibVarGet = SV_BotLibVarGet; + gi.BotLibDefine = SV_BotLibDefine; + gi.BotLibStartFrame = SV_BotLibStartFrame; + gi.BotLibLoadMap = SV_BotLibLoadMap; + gi.BotLibUpdateEntity = SV_BotLibUpdateEntity; + gi.BotLibTest = SV_BotLibTest; + gi.BotGetSnapshotEntity = SV_BotGetSnapshotEntity; + gi.BotGetServerCommand = SV_BotGetServerCommand; + gi.BotUserCommand = SV_BotUserCommand; + gi.BotUpdateWaypoints = SV_BotWaypointReception; + gi.BotCalculatePaths = SV_BotCalculatePaths; + gi.AAS_EnableRoutingArea = SV_AAS_EnableRoutingArea; + gi.AAS_BBoxAreas = SV_AAS_BBoxAreas; + gi.AAS_AreaInfo = SV_AAS_AreaInfo; + gi.AAS_EntityInfo = SV_AAS_EntityInfo; + gi.AAS_Initialized = SV_AAS_Initialized; + gi.AAS_PresenceTypeBoundingBox = SV_AAS_PresenceTypeBoundingBox; + gi.AAS_Time = SV_AAS_Time; + gi.AAS_PointAreaNum = SV_AAS_PointAreaNum; + gi.AAS_TraceAreas = SV_AAS_TraceAreas; + gi.AAS_PointContents = SV_AAS_PointContents; + gi.AAS_NextBSPEntity = SV_AAS_NextBSPEntity; + gi.AAS_ValueForBSPEpairKey = SV_AAS_ValueForBSPEpairKey; + gi.AAS_VectorForBSPEpairKey = SV_AAS_VectorForBSPEpairKey; + gi.AAS_FloatForBSPEpairKey = SV_AAS_FloatForBSPEpairKey; + gi.AAS_IntForBSPEpairKey = SV_AAS_IntForBSPEpairKey; + gi.AAS_AreaReachability = SV_AAS_AreaReachability; + gi.AAS_AreaTravelTimeToGoalArea = SV_AAS_AreaTravelTimeToGoalArea; + gi.AAS_Swimming = SV_AAS_Swimming; + gi.AAS_PredictClientMovement = SV_AAS_PredictClientMovement; + gi.AAS_AlternativeRouteGoals = SV_AAS_AlternativeRouteGoals; + gi.AAS_PredictRoute = SV_AAS_PredictRoute; + gi.AAS_PointReachabilityAreaIndex = SV_AAS_PointReachabilityAreaIndex; + gi.EA_Say = SV_EA_Say; + gi.EA_SayTeam = SV_EA_SayTeam; + gi.EA_Command = SV_EA_Command; + gi.EA_Action = SV_EA_Action; + gi.EA_Gesture = SV_EA_Gesture; + gi.EA_Talk = SV_EA_Talk; + gi.EA_Attack = SV_EA_Attack; + gi.EA_Alt_Attack = SV_EA_Alt_Attack; + gi.EA_ForcePower = SV_EA_ForcePower; + gi.EA_Use = SV_EA_Use; + gi.EA_Respawn = SV_EA_Respawn; + gi.EA_Crouch = SV_EA_Crouch; + gi.EA_MoveUp = SV_EA_MoveUp; + gi.EA_MoveDown = SV_EA_MoveDown; + gi.EA_MoveForward = SV_EA_MoveForward; + gi.EA_MoveBack = SV_EA_MoveBack; + gi.EA_MoveLeft = SV_EA_MoveLeft; + gi.EA_MoveRight = SV_EA_MoveRight; + gi.EA_SelectWeapon = SV_EA_SelectWeapon; + gi.EA_Jump = SV_EA_Jump; + gi.EA_DelayedJump = SV_EA_DelayedJump; + gi.EA_Move = SV_EA_Move; + gi.EA_View = SV_EA_View; + gi.EA_EndRegular = SV_EA_EndRegular; + gi.EA_GetInput = SV_EA_GetInput; + gi.EA_ResetInput = SV_EA_ResetInput; + gi.PC_LoadSource = SV_PC_LoadSource; + gi.PC_FreeSource = SV_PC_FreeSource; + gi.PC_ReadToken = SV_PC_ReadToken; + gi.PC_SourceFileAndLine = SV_PC_SourceFileAndLine; + gi.R_RegisterSkin = SV_RE_RegisterSkin; + gi.SetActiveSubBSP = SV_SetActiveSubBSP; + gi.CM_RegisterTerrain = SV_CM_RegisterTerrain; + gi.RMG_Init = SV_RMG_Init; + gi.G2API_ListModelBones = SV_G2API_ListModelBones; + gi.G2API_ListModelSurfaces = SV_G2API_ListModelSurfaces; + gi.G2API_HaveWeGhoul2Models = SV_G2API_HaveWeGhoul2Models; + gi.G2API_SetGhoul2ModelIndexes = SV_G2API_SetGhoul2ModelIndexes; + gi.G2API_GetBoltMatrix = SV_G2API_GetBoltMatrix; + gi.G2API_GetBoltMatrix_NoReconstruct = SV_G2API_GetBoltMatrix_NoReconstruct; + gi.G2API_GetBoltMatrix_NoRecNoRot = SV_G2API_GetBoltMatrix_NoRecNoRot; + gi.G2API_InitGhoul2Model = SV_G2API_InitGhoul2Model; + gi.G2API_SetSkin = SV_G2API_SetSkin; + gi.G2API_Ghoul2Size = SV_G2API_Ghoul2Size; + gi.G2API_AddBolt = SV_G2API_AddBolt; + gi.G2API_SetBoltInfo = SV_G2API_SetBoltInfo; + gi.G2API_SetBoneAngles = SV_G2API_SetBoneAngles; + gi.G2API_SetBoneAnim = SV_G2API_SetBoneAnim; + gi.G2API_GetBoneAnim = SV_G2API_GetBoneAnim; + gi.G2API_GetGLAName = SV_G2API_GetGLAName; + gi.G2API_CopyGhoul2Instance = SV_G2API_CopyGhoul2Instance; + gi.G2API_CopySpecificGhoul2Model = SV_G2API_CopySpecificGhoul2Model; + gi.G2API_DuplicateGhoul2Instance = SV_G2API_DuplicateGhoul2Instance; + gi.G2API_HasGhoul2ModelOnIndex = SV_G2API_HasGhoul2ModelOnIndex; + gi.G2API_RemoveGhoul2Model = SV_G2API_RemoveGhoul2Model; + gi.G2API_RemoveGhoul2Models = SV_G2API_RemoveGhoul2Models; + gi.G2API_CleanGhoul2Models = SV_G2API_CleanGhoul2Models; + gi.G2API_CollisionDetect = SV_G2API_CollisionDetect; + gi.G2API_CollisionDetectCache = SV_G2API_CollisionDetectCache; + gi.G2API_SetRootSurface = SV_G2API_SetRootSurface; + gi.G2API_SetSurfaceOnOff = SV_G2API_SetSurfaceOnOff; + gi.G2API_SetNewOrigin = SV_G2API_SetNewOrigin; + gi.G2API_DoesBoneExist = SV_G2API_DoesBoneExist; + gi.G2API_GetSurfaceRenderStatus = SV_G2API_GetSurfaceRenderStatus; + gi.G2API_AbsurdSmoothing = SV_G2API_AbsurdSmoothing; + gi.G2API_SetRagDoll = SV_G2API_SetRagDoll; + gi.G2API_AnimateG2Models = SV_G2API_AnimateG2Models; + gi.G2API_RagPCJConstraint = SV_G2API_RagPCJConstraint; + gi.G2API_RagPCJGradientSpeed = SV_G2API_RagPCJGradientSpeed; + gi.G2API_RagEffectorGoal = SV_G2API_RagEffectorGoal; + gi.G2API_GetRagBonePos = SV_G2API_GetRagBonePos; + gi.G2API_RagEffectorKick = SV_G2API_RagEffectorKick; + gi.G2API_RagForceSolve = SV_G2API_RagForceSolve; + gi.G2API_SetBoneIKState = SV_G2API_SetBoneIKState; + gi.G2API_IKMove = SV_G2API_IKMove; + gi.G2API_RemoveBone = SV_G2API_RemoveBone; + gi.G2API_AttachInstanceToEntNum = SV_G2API_AttachInstanceToEntNum; + gi.G2API_ClearAttachedInstance = SV_G2API_ClearAttachedInstance; + gi.G2API_CleanEntAttachments = SV_G2API_CleanEntAttachments; + gi.G2API_OverrideServer = SV_G2API_OverrideServer; + gi.G2API_GetSurfaceName = SV_G2API_GetSurfaceName; + + GetGameAPI = (GetGameAPI_t)gvm->GetModuleAPI; + ret = GetGameAPI( GAME_API_VERSION, &gi ); + if ( !ret ) { + //free VM? + svs.gameStarted = qfalse; + Com_Error( ERR_FATAL, "GetGameAPI failed on %s", dllName ); + } + ge = ret; + + return; + } + + // fall back to legacy syscall/vm_call api + gvm = VM_CreateLegacy( VM_GAME, SV_GameSystemCalls ); + if ( !gvm ) { + svs.gameStarted = qfalse; + Com_Error( ERR_DROP, "VM_CreateLegacy on game failed" ); + } +} + +void SV_UnbindGame( void ) { + GVM_ShutdownGame( qfalse ); + VM_Free( gvm ); + gvm = NULL; +} + +void SV_RestartGame( void ) { + GVM_ShutdownGame( qtrue ); + + gvm = VM_Restart( gvm ); + SV_BindGame(); + if ( !gvm ) { + svs.gameStarted = qfalse; + Com_Error( ERR_DROP, "VM_Restart on game failed" ); + return; + } + + SV_InitGame( qtrue ); +} diff --git a/Projects/Android/jni/OpenJK/codemp_delete/server/sv_gameapi.h b/Projects/Android/jni/OpenJK/codemp_delete/server/sv_gameapi.h new file mode 100644 index 0000000..ea651e5 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/server/sv_gameapi.h @@ -0,0 +1,67 @@ +/* +=========================================================================== +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#pragma once + +void GVM_InitGame ( int levelTime, int randomSeed, int restart ); +void GVM_ShutdownGame ( int restart ); +char * GVM_ClientConnect ( int clientNum, qboolean firstTime, qboolean isBot ); +void GVM_ClientBegin ( int clientNum ); +qboolean GVM_ClientUserinfoChanged ( int clientNum ); +void GVM_ClientDisconnect ( int clientNum ); +void GVM_ClientCommand ( int clientNum ); +void GVM_ClientThink ( int clientNum, usercmd_t *ucmd ); +void GVM_RunFrame ( int levelTime ); +qboolean GVM_ConsoleCommand ( void ); +int GVM_BotAIStartFrame ( int time ); +void GVM_ROFF_NotetrackCallback ( int entID, const char *notetrack ); +void GVM_SpawnRMGEntity ( void ); +int GVM_ICARUS_PlaySound ( void ); +qboolean GVM_ICARUS_Set ( void ); +void GVM_ICARUS_Lerp2Pos ( void ); +void GVM_ICARUS_Lerp2Origin ( void ); +void GVM_ICARUS_Lerp2Angles ( void ); +int GVM_ICARUS_GetTag ( void ); +void GVM_ICARUS_Lerp2Start ( void ); +void GVM_ICARUS_Lerp2End ( void ); +void GVM_ICARUS_Use ( void ); +void GVM_ICARUS_Kill ( void ); +void GVM_ICARUS_Remove ( void ); +void GVM_ICARUS_Play ( void ); +int GVM_ICARUS_GetFloat ( void ); +int GVM_ICARUS_GetVector ( void ); +int GVM_ICARUS_GetString ( void ); +void GVM_ICARUS_SoundIndex ( void ); +int GVM_ICARUS_GetSetIDForString ( void ); +qboolean GVM_NAV_ClearPathToPoint ( int entID, vec3_t pmins, vec3_t pmaxs, vec3_t point, int clipmask, int okToHitEnt ); +qboolean GVM_NPC_ClearLOS2 ( int entID, const vec3_t end ); +int GVM_NAVNEW_ClearPathBetweenPoints ( vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, int ignore, int clipmask ); +qboolean GVM_NAV_CheckNodeFailedForEnt ( int entID, int nodeNum ); +qboolean GVM_NAV_EntIsUnlockedDoor ( int entityNum ); +qboolean GVM_NAV_EntIsDoor ( int entityNum ); +qboolean GVM_NAV_EntIsBreakable ( int entityNum ); +qboolean GVM_NAV_EntIsRemovableUsable ( int entNum ); +void GVM_NAV_FindCombatPointWaypoints ( void ); +int GVM_BG_GetItemIndexByTag ( int tag, int type ); + +void SV_BindGame( void ); +void SV_UnbindGame( void ); +void SV_InitGame( qboolean restart ); +void SV_RestartGame( void ); diff --git a/Projects/Android/jni/OpenJK/codemp/server/sv_init.cpp b/Projects/Android/jni/OpenJK/codemp_delete/server/sv_init.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/server/sv_init.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/server/sv_init.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/server/sv_main.cpp b/Projects/Android/jni/OpenJK/codemp_delete/server/sv_main.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/server/sv_main.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/server/sv_main.cpp diff --git a/Projects/Android/jni/OpenJK/codemp_delete/server/sv_net_chan.cpp b/Projects/Android/jni/OpenJK/codemp_delete/server/sv_net_chan.cpp new file mode 100644 index 0000000..24b2915 --- /dev/null +++ b/Projects/Android/jni/OpenJK/codemp_delete/server/sv_net_chan.cpp @@ -0,0 +1,184 @@ +/* +=========================================================================== +Copyright (C) 1999 - 2005, Id Software, Inc. +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program 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 this program; if not, see . +=========================================================================== +*/ + +#include "server.h" + +// TTimo: unused, commenting out to make gcc happy +#if 1 +/* +============== +SV_Netchan_Encode + + // first four bytes of the data are always: + long reliableAcknowledge; + +============== +*/ +static void SV_Netchan_Encode( client_t *client, msg_t *msg ) { + long /*reliableAcknowledge,*/ i, index; + byte key, *string; + int srdc, sbit; + qboolean soob; + + if ( msg->cursize < SV_ENCODE_START ) { + return; + } + + srdc = msg->readcount; + sbit = msg->bit; + soob = msg->oob; + + msg->bit = 0; + msg->readcount = 0; + msg->oob = qfalse; + + /*reliableAcknowledge =*/ MSG_ReadLong(msg); + + msg->oob = soob; + msg->bit = sbit; + msg->readcount = srdc; + + string = (byte *)client->lastClientCommandString; + index = 0; + // xor the client challenge with the netchan sequence number + key = client->challenge ^ client->netchan.outgoingSequence; + for (i = SV_ENCODE_START; i < msg->cursize; i++) { + // modify the key with the last received and with this message acknowledged client command + if (!string[index]) + index = 0; + if (/*string[index] > 127 ||*/ // eurofix: remove this so we can chat in european languages... -ste + string[index] == '%') + { + key ^= '.' << (i & 1); + } + else { + key ^= string[index] << (i & 1); + } + index++; + // encode the data with this key + *(msg->data + i) = *(msg->data + i) ^ key; + } +} + +/* +============== +SV_Netchan_Decode + + // first 12 bytes of the data are always: + long serverId; + long messageAcknowledge; + long reliableAcknowledge; + +============== +*/ +static void SV_Netchan_Decode( client_t *client, msg_t *msg ) { + int serverId, messageAcknowledge, reliableAcknowledge; + int i, index, srdc, sbit; + qboolean soob; + byte key, *string; + + srdc = msg->readcount; + sbit = msg->bit; + soob = msg->oob; + + msg->oob = qfalse; + + serverId = MSG_ReadLong(msg); + messageAcknowledge = MSG_ReadLong(msg); + reliableAcknowledge = MSG_ReadLong(msg); + + msg->oob = soob; + msg->bit = sbit; + msg->readcount = srdc; + + string = (byte *)client->reliableCommands[ reliableAcknowledge & (MAX_RELIABLE_COMMANDS-1) ]; + index = 0; + // + key = client->challenge ^ serverId ^ messageAcknowledge; + for (i = msg->readcount + SV_DECODE_START; i < msg->cursize; i++) { + // modify the key with the last sent and acknowledged server command + if (!string[index]) + index = 0; + if (/*string[index] > 127 || */ // eurofix: remove this so we can chat in european languages... -ste + string[index] == '%') + { + key ^= '.' << (i & 1); + } + else { + key ^= string[index] << (i & 1); + } + index++; + // decode the data with this key + *(msg->data + i) = *(msg->data + i) ^ key; + } +} +#endif + +/* +================= +SV_Netchan_TransmitNextFragment +================= +*/ +void SV_Netchan_TransmitNextFragment( netchan_t *chan ) { + Netchan_TransmitNextFragment( chan ); +} + + +/* +=============== +SV_Netchan_Transmit +================ +*/ + +void SV_Netchan_Transmit( client_t *client, msg_t *msg) { //int length, const byte *data ) { +// int i; + MSG_WriteByte( msg, svc_EOF ); +// for(i=SV_ENCODE_START;icursize;i++) { +// chksum[i-SV_ENCODE_START] = msg->data[i]; +// } +// Huff_Compress( msg, SV_ENCODE_START ); + SV_Netchan_Encode( client, msg ); + Netchan_Transmit( &client->netchan, msg->cursize, msg->data ); +} + +/* +================= +Netchan_SV_Process +================= +*/ +qboolean SV_Netchan_Process( client_t *client, msg_t *msg ) { + int ret; +// int i; + ret = Netchan_Process( &client->netchan, msg ); + if (!ret) + return qfalse; + SV_Netchan_Decode( client, msg ); +// Huff_Decompress( msg, SV_DECODE_START ); +// for(i=SV_DECODE_START+msg->readcount;icursize;i++) { +// if (msg->data[i] != chksum[i-(SV_DECODE_START+msg->readcount)]) { +// Com_Error(ERR_DROP,"bad\n"); +// } +// } + return qtrue; +} + diff --git a/Projects/Android/jni/OpenJK/codemp/server/sv_snapshot.cpp b/Projects/Android/jni/OpenJK/codemp_delete/server/sv_snapshot.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/server/sv_snapshot.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/server/sv_snapshot.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/server/sv_world.cpp b/Projects/Android/jni/OpenJK/codemp_delete/server/sv_world.cpp similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/server/sv_world.cpp rename to Projects/Android/jni/OpenJK/codemp_delete/server/sv_world.cpp diff --git a/Projects/Android/jni/OpenJK/codemp/ui/CMakeLists.txt b/Projects/Android/jni/OpenJK/codemp_delete/ui/CMakeLists.txt similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/ui/CMakeLists.txt rename to Projects/Android/jni/OpenJK/codemp_delete/ui/CMakeLists.txt diff --git a/Projects/Android/jni/OpenJK/codemp/ui/keycodes.h b/Projects/Android/jni/OpenJK/codemp_delete/ui/keycodes.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/ui/keycodes.h rename to Projects/Android/jni/OpenJK/codemp_delete/ui/keycodes.h diff --git a/Projects/Android/jni/OpenJK/codemp/ui/menudef.h b/Projects/Android/jni/OpenJK/codemp_delete/ui/menudef.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/ui/menudef.h rename to Projects/Android/jni/OpenJK/codemp_delete/ui/menudef.h diff --git a/Projects/Android/jni/OpenJK/codemp/ui/ui_atoms.c b/Projects/Android/jni/OpenJK/codemp_delete/ui/ui_atoms.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/ui/ui_atoms.c rename to Projects/Android/jni/OpenJK/codemp_delete/ui/ui_atoms.c diff --git a/Projects/Android/jni/OpenJK/codemp/ui/ui_cvar.c b/Projects/Android/jni/OpenJK/codemp_delete/ui/ui_cvar.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/ui/ui_cvar.c rename to Projects/Android/jni/OpenJK/codemp_delete/ui/ui_cvar.c diff --git a/Projects/Android/jni/OpenJK/codemp/ui/ui_force.c b/Projects/Android/jni/OpenJK/codemp_delete/ui/ui_force.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/ui/ui_force.c rename to Projects/Android/jni/OpenJK/codemp_delete/ui/ui_force.c diff --git a/Projects/Android/jni/OpenJK/codemp/ui/ui_force.h b/Projects/Android/jni/OpenJK/codemp_delete/ui/ui_force.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/ui/ui_force.h rename to Projects/Android/jni/OpenJK/codemp_delete/ui/ui_force.h diff --git a/Projects/Android/jni/OpenJK/codemp/ui/ui_gameinfo.c b/Projects/Android/jni/OpenJK/codemp_delete/ui/ui_gameinfo.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/ui/ui_gameinfo.c rename to Projects/Android/jni/OpenJK/codemp_delete/ui/ui_gameinfo.c diff --git a/Projects/Android/jni/OpenJK/codemp/ui/ui_local.h b/Projects/Android/jni/OpenJK/codemp_delete/ui/ui_local.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/ui/ui_local.h rename to Projects/Android/jni/OpenJK/codemp_delete/ui/ui_local.h diff --git a/Projects/Android/jni/OpenJK/codemp/ui/ui_main.c b/Projects/Android/jni/OpenJK/codemp_delete/ui/ui_main.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/ui/ui_main.c rename to Projects/Android/jni/OpenJK/codemp_delete/ui/ui_main.c diff --git a/Projects/Android/jni/OpenJK/codemp/ui/ui_public.h b/Projects/Android/jni/OpenJK/codemp_delete/ui/ui_public.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/ui/ui_public.h rename to Projects/Android/jni/OpenJK/codemp_delete/ui/ui_public.h diff --git a/Projects/Android/jni/OpenJK/codemp/ui/ui_saber.c b/Projects/Android/jni/OpenJK/codemp_delete/ui/ui_saber.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/ui/ui_saber.c rename to Projects/Android/jni/OpenJK/codemp_delete/ui/ui_saber.c diff --git a/Projects/Android/jni/OpenJK/codemp/ui/ui_shared.c b/Projects/Android/jni/OpenJK/codemp_delete/ui/ui_shared.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/ui/ui_shared.c rename to Projects/Android/jni/OpenJK/codemp_delete/ui/ui_shared.c diff --git a/Projects/Android/jni/OpenJK/codemp/ui/ui_shared.h b/Projects/Android/jni/OpenJK/codemp_delete/ui/ui_shared.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/ui/ui_shared.h rename to Projects/Android/jni/OpenJK/codemp_delete/ui/ui_shared.h diff --git a/Projects/Android/jni/OpenJK/codemp/ui/ui_syscalls.c b/Projects/Android/jni/OpenJK/codemp_delete/ui/ui_syscalls.c similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/ui/ui_syscalls.c rename to Projects/Android/jni/OpenJK/codemp_delete/ui/ui_syscalls.c diff --git a/Projects/Android/jni/OpenJK/codemp/ui/ui_xcvar.h b/Projects/Android/jni/OpenJK/codemp_delete/ui/ui_xcvar.h similarity index 100% rename from Projects/Android/jni/OpenJK/codemp/ui/ui_xcvar.h rename to Projects/Android/jni/OpenJK/codemp_delete/ui/ui_xcvar.h diff --git a/Projects/Android/jni/SupportLibs/minizip/Android.mk b/Projects/Android/jni/SupportLibs/minizip/Android.mk new file mode 100644 index 0000000..a42da7b --- /dev/null +++ b/Projects/Android/jni/SupportLibs/minizip/Android.mk @@ -0,0 +1,17 @@ + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := libminizip + +LOCAL_SRC_FILES = \ + ioapi.c \ + unzip.c + + +LOCAL_LDLIBS := -lz +LOCAL_EXPORT_LDLIBS := -lz +LOCAL_STATIC_LIBRARIES := +#include $(BUILD_SHARED_LIBRARY) +include $(BUILD_STATIC_LIBRARY) \ No newline at end of file diff --git a/Projects/Android/jni/SupportLibs/minizip/CMakeLists.txt b/Projects/Android/jni/SupportLibs/minizip/CMakeLists.txt new file mode 100644 index 0000000..0d1a14b --- /dev/null +++ b/Projects/Android/jni/SupportLibs/minizip/CMakeLists.txt @@ -0,0 +1,59 @@ +#============================================================================ +# Copyright (C) 2013 - 2018, OpenJK contributors +# +# This file is part of the OpenJK source code. +# +# OpenJK is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program 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 this program; if not, see . +#============================================================================ + +# Build our bundled minizip. +# +# It is built as a static relocatable library, and linked into any target that +# requires it. Other targets in OpenJK that consume need to add +# MINZIP_INCLUDE_DIRS and MINIZIP_LIBRARIES to their lists of include +# directories and target link libraries. +# +# The bundled copy is produced by taking the files ioapi.{c,h} and unzip.{c,h} +# from the contrib/minizip directory of the zlib release tarball. The only +# changes applied are modifications of the macros ALLOC and TRYFREE in unzip.c, +# and a compatibility definition of the macro OF in include/ioapi.h +# +# Since minizip is expected to be reference by user code as +# +# #include +# +# the public header files are split into the include/minizip subdirectory. +# +# The current bundled copy comes from the zlib 1.2.8 release. + +# These settings only apply to this directory. +include_directories(${ZLIB_INCLUDE_DIR}) +include_directories(include/minizip) + +if(MSVC) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) +endif(MSVC) + +add_library(bundled_minizip STATIC ioapi.c unzip.c) + +# Let consumers get at our bundled copy in the standard CMake way. These +# variables are not set in the cache, but instead shadow the variables in the +# cache. +set(MINIZIP_LIBRARIES bundled_minizip PARENT_SCOPE) +set(MINIZIP_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/lib/minizip/include/ PARENT_SCOPE) + +mark_as_advanced(MINIZIP_LIBRARIES MINIZIP_INCLUDE_DIRS) + +# We need to build it as position-independent code, because it might get linked +# into dynamic libraries. +set_property(TARGET bundled_minizip PROPERTY POSITION_INDEPENDENT_CODE True) diff --git a/Projects/Android/jni/SupportLibs/minizip/include/minizip/ioapi.h b/Projects/Android/jni/SupportLibs/minizip/include/minizip/ioapi.h new file mode 100644 index 0000000..cd02d02 --- /dev/null +++ b/Projects/Android/jni/SupportLibs/minizip/include/minizip/ioapi.h @@ -0,0 +1,213 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + Changes + + Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this) + Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux. + More if/def section may be needed to support other platforms + Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows. + (but you should use iowin32.c for windows instead) + +*/ + +#ifndef _ZLIBIOAPI64_H +#define _ZLIBIOAPI64_H + +#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) + + // Linux needs this to support file operation on files larger then 4+GB + // But might need better if/def to select just the platforms that needs them. + + #ifndef __USE_FILE_OFFSET64 + #define __USE_FILE_OFFSET64 + #endif + #ifndef __USE_LARGEFILE64 + #define __USE_LARGEFILE64 + #endif + #ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE + #endif + #ifndef _FILE_OFFSET_BIT + #define _FILE_OFFSET_BIT 64 + #endif + +#endif + +#include +#include +#include "zlib.h" + +#if defined(USE_FILE32API) +#define fopen64 fopen +#define ftello64 ftell +#define fseeko64 fseek +#else +#ifdef __FreeBSD__ +#define fopen64 fopen +#define ftello64 ftello +#define fseeko64 fseeko +#endif +#ifdef _MSC_VER + #define fopen64 fopen + #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) + #define ftello64 _ftelli64 + #define fseeko64 _fseeki64 + #else // old MSC + #define ftello64 ftell + #define fseeko64 fseek + #endif +#endif +#endif + +/* +#ifndef ZPOS64_T + #ifdef _WIN32 + #define ZPOS64_T fpos_t + #else + #include + #define ZPOS64_T uint64_t + #endif +#endif +*/ + +#ifdef HAVE_MINIZIP64_CONF_H +#include "mz64conf.h" +#endif + +/* a type choosen by DEFINE */ +#ifdef HAVE_64BIT_INT_CUSTOM +typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; +#else +#ifdef HAS_STDINT_H +#include "stdint.h" +typedef uint64_t ZPOS64_T; +#else + +/* Maximum unsigned 32-bit value used as placeholder for zip64 */ +#define MAXU32 0xffffffff + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef unsigned __int64 ZPOS64_T; +#else +typedef unsigned long long int ZPOS64_T; +#endif +#endif +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define ZLIB_FILEFUNC_SEEK_CUR (1) +#define ZLIB_FILEFUNC_SEEK_END (2) +#define ZLIB_FILEFUNC_SEEK_SET (0) + +#define ZLIB_FILEFUNC_MODE_READ (1) +#define ZLIB_FILEFUNC_MODE_WRITE (2) +#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) + +#define ZLIB_FILEFUNC_MODE_EXISTING (4) +#define ZLIB_FILEFUNC_MODE_CREATE (8) + + +#ifndef ZCALLBACK + #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) + #define ZCALLBACK CALLBACK + #else + #define ZCALLBACK + #endif +#endif + +/* Small workaround. zlibs provided by most distributions are modified so that + the macro OF is renamed to _Z_OF, since they rightly recognize that putting a + two-letter macro in the global namespace is totally insane. Of course, the + bundled minizip is minimally modified, so it expects OF.*/ +#ifndef OF +#define OF(args) args +#endif + +typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); +typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); + +typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); + + +/* here is the "old" 32 bits structure structure */ +typedef struct zlib_filefunc_def_s +{ + open_file_func zopen_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell_file_func ztell_file; + seek_file_func zseek_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc_def; + +typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode)); + +typedef struct zlib_filefunc64_def_s +{ + open64_file_func zopen64_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell64_file_func ztell64_file; + seek64_file_func zseek64_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc64_def; + +void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + +/* now internal definition, only for zip.c and unzip.h */ +typedef struct zlib_filefunc64_32_def_s +{ + zlib_filefunc64_def zfile_func64; + open_file_func zopen32_file; + tell_file_func ztell32_file; + seek_file_func zseek32_file; +} zlib_filefunc64_32_def; + + +#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +//#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream)) +//#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode)) +#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) +#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) + +voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)); +long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); +ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); + +#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) +#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) +#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Projects/Android/jni/SupportLibs/minizip/include/minizip/unzip.h b/Projects/Android/jni/SupportLibs/minizip/include/minizip/unzip.h new file mode 100644 index 0000000..2104e39 --- /dev/null +++ b/Projects/Android/jni/SupportLibs/minizip/include/minizip/unzip.h @@ -0,0 +1,437 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + --------------------------------------------------------------------------------- + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + --------------------------------------------------------------------------------- + + Changes + + See header of unzip64.c + +*/ + +#ifndef _unz64_H +#define _unz64_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef voidp unzFile; +#endif + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info64_s +{ + ZPOS64_T number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info64; + +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info64_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + ZPOS64_T compressed_size; /* compressed size 8 bytes */ + ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info64; + +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info; + +extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + + +extern unzFile ZEXPORT unzOpen OF((const char *path)); +extern unzFile ZEXPORT unzOpen64 OF((const void *path)); +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer + "zlib/zlib113.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. + the "64" function take a const void* pointer, because the path is just the + value passed to the open64_file_func callback. + Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path + is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* + does not describe the reality +*/ + + +extern unzFile ZEXPORT unzOpen2 OF((const char *path, + zlib_filefunc_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unzOpen, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern unzFile ZEXPORT unzOpen2_64 OF((const void *path, + zlib_filefunc64_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unz64Open, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern int ZEXPORT unzClose OF((unzFile file)); +/* + Close a ZipFile opened with unzOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzCloseCurrentFile before call unzClose. + return UNZ_OK if there is no problem. */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); + +extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, + unz_global_info64 *pglobal_info)); +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int ZEXPORT unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +/* ****************************************** */ +/* Ryan supplied functions */ +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; /* offset in zip file directory */ + uLong num_of_file; /* # of file */ +} unz_file_pos; + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos); + +typedef struct unz64_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */ + ZPOS64_T num_of_file; /* # of file */ +} unz64_file_pos; + +extern int ZEXPORT unzGetFilePos64( + unzFile file, + unz64_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos64( + unzFile file, + const unz64_file_pos* file_pos); + +/* ****************************************** */ + +extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, + unz_file_info64 *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + + +/** Addition for GDAL : START */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); + +/** Addition for GDAL : END */ + + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, + const char* password)); +/* + Open for reading data the current file in the zipfile. + password is a crypting password + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, + int* method, + int* level, + int raw)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + +extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, + int* method, + int* level, + int raw, + const char* password)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + + +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern z_off_t ZEXPORT unztell OF((unzFile file)); + +extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file)); +/* + Give the current position in uncompressed data +*/ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ + +/***************************************************************************/ + +/* Get the current file offset */ +extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file); +extern uLong ZEXPORT unzGetOffset (unzFile file); + +/* Set the current file offset */ +extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos); +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); + + + +#ifdef __cplusplus +} +#endif + +#endif /* _unz64_H */ diff --git a/Projects/Android/jni/SupportLibs/minizip/ioapi.c b/Projects/Android/jni/SupportLibs/minizip/ioapi.c new file mode 100644 index 0000000..7f5c191 --- /dev/null +++ b/Projects/Android/jni/SupportLibs/minizip/ioapi.c @@ -0,0 +1,247 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + +*/ + +#if defined(_WIN32) && (!(defined(_CRT_SECURE_NO_WARNINGS))) + #define _CRT_SECURE_NO_WARNINGS +#endif + +#if defined(__APPLE__) || defined(IOAPI_NO_64) +// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions +#define FOPEN_FUNC(filename, mode) fopen(filename, mode) +#define FTELLO_FUNC(stream) ftello(stream) +#define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin) +#else +#define FOPEN_FUNC(filename, mode) fopen64(filename, mode) +#define FTELLO_FUNC(stream) ftello64(stream) +#define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin) +#endif + + +#include "ioapi.h" + +voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode) +{ + if (pfilefunc->zfile_func64.zopen64_file != NULL) + return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode); + else + { + return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode); + } +} + +long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) +{ + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin); + else + { + uLong offsetTruncated = (uLong)offset; + if (offsetTruncated != offset) + return -1; + else + return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin); + } +} + +ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream) +{ + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream); + else + { + uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); + if ((tell_uLong) == MAXU32) + return (ZPOS64_T)-1; + else + return tell_uLong; + } +} + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32) +{ + p_filefunc64_32->zfile_func64.zopen64_file = NULL; + p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; + p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; + p_filefunc64_32->zfile_func64.ztell64_file = NULL; + p_filefunc64_32->zfile_func64.zseek64_file = NULL; + p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque; + p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file; + p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file; +} + + + +static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode)); +static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size)); +static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream)); +static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream)); +static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream)); + +static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode) +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = fopen(filename, mode_fopen); + return file; +} + +static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode) +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = FOPEN_FUNC((const char*)filename, mode_fopen); + return file; +} + + +static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size) +{ + uLong ret; + ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size) +{ + uLong ret; + ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream) +{ + long ret; + ret = ftell((FILE *)stream); + return ret; +} + + +static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream) +{ + ZPOS64_T ret; + ret = FTELLO_FUNC((FILE *)stream); + return ret; +} + +static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin) +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + if (fseek((FILE *)stream, offset, fseek_origin) != 0) + ret = -1; + return ret; +} + +static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + + if(FSEEKO_FUNC((FILE *)stream, offset, fseek_origin) != 0) + ret = -1; + + return ret; +} + + +static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream) +{ + int ret; + ret = fclose((FILE *)stream); + return ret; +} + +static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream) +{ + int ret; + ret = ferror((FILE *)stream); + return ret; +} + +void fill_fopen_filefunc (pzlib_filefunc_def) + zlib_filefunc_def* pzlib_filefunc_def; +{ + pzlib_filefunc_def->zopen_file = fopen_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell_file = ftell_file_func; + pzlib_filefunc_def->zseek_file = fseek_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} + +void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = fopen64_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell64_file = ftell64_file_func; + pzlib_filefunc_def->zseek64_file = fseek64_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} diff --git a/Projects/Android/jni/SupportLibs/minizip/unzip.c b/Projects/Android/jni/SupportLibs/minizip/unzip.c new file mode 100644 index 0000000..e93e46c --- /dev/null +++ b/Projects/Android/jni/SupportLibs/minizip/unzip.c @@ -0,0 +1,2132 @@ +/* unzip.c -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + + ------------------------------------------------------------------------------------ + Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of + compatibility with older software. The following is from the original crypt.c. + Code woven in by Terry Thorsen 1/2003. + + Copyright (c) 1990-2000 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 or later + (the contents of which are also included in zip.h) for terms of use. + If, for some reason, all these files are missing, the Info-ZIP license + also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html + + crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + ------------------------------------------------------------------------------------ + + Changes in unzip.c + + 2007-2008 - Even Rouault - Addition of cpl_unzGetCurrentFileZStreamPos + 2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz* + 2007-2008 - Even Rouault - Remove old C style function prototypes + 2007-2008 - Even Rouault - Add unzip support for ZIP64 + + Copyright (C) 2007-2008 Even Rouault + + + Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again). + Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G + should only read the compressed/uncompressed size from the Zip64 format if + the size from normal header was 0xFFFFFFFF + Oct-2009 - Mathias Svensson - Applied some bug fixes from paches received from Gilles Vollant + Oct-2009 - Mathias Svensson - Applied support to unzip files with compression mathod BZIP2 (bzip2 lib is required) + Patch created by Daniel Borca + + Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer + + Copyright (C) 1998 - 2010 Gilles Vollant, Even Rouault, Mathias Svensson + +*/ + + +#include +#include +#include + +#ifndef NOUNCRYPT + #define NOUNCRYPT +#endif + +#include "zlib.h" +#include "unzip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + + +#ifndef CASESENSITIVITYDEFAULT_NO +# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) +# define CASESENSITIVITYDEFAULT_NO +# endif +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (16384) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +/* Normally, these forward declarations are a bad thing, but this seems to be + the best way to get at openjk_minizip_malloc and Z_Free without tightly + binding the bundled minizip lib to the rest of the engine. */ + +void* openjk_minizip_malloc(int); +int openjk_minizip_free(void*); + +#ifndef ALLOC +# define ALLOC(size) (openjk_minizip_malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) openjk_minizip_free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + +const char unz_copyright[] = + " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info64_internal_s +{ + ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */ +} unz_file_info64_internal; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif + + ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ + uLong stream_initialised; /* flag set if stream structure is initialised*/ + + ZPOS64_T offset_local_extrafield;/* offset of the local extra field */ + uInt size_local_extrafield;/* size of the local extra field */ + ZPOS64_T pos_local_extrafield; /* position in the local extra field in read*/ + ZPOS64_T total_out_64; + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */ + ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/ + zlib_filefunc64_32_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + int raw; +} file_in_zip64_read_info_s; + + +/* unz64_s contain internal information about the zipfile +*/ +typedef struct +{ + zlib_filefunc64_32_def z_filefunc; + int is64bitOpenFunction; + voidpf filestream; /* io structore of the zipfile */ + unz_global_info64 gi; /* public global information */ + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + ZPOS64_T num_file; /* number of the current file in the zipfile*/ + ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/ + ZPOS64_T current_file_ok; /* flag about the usability of the current file*/ + ZPOS64_T central_pos; /* position of the beginning of the central dir*/ + + ZPOS64_T size_central_dir; /* size of the central directory */ + ZPOS64_T offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info64 cur_file_info; /* public info about the current file in zip*/ + unz_file_info64_internal cur_file_info_internal; /* private info about it*/ + file_in_zip64_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ + int encrypted; + + int isZip64; + +# ifndef NOUNCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const z_crc_t* pcrc_32_tab; +# endif +} unz64_s; + + +#ifndef NOUNCRYPT +#include "crypt.h" +#endif + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been successfully opened for reading. +*/ + + +local int unz64local_getByte OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + int *pi)); + +local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi) +{ + unsigned char c; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ZERROR64(*pzlib_filefunc_def,filestream)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int unz64local_getShort OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) +{ + uLong x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) +{ + uLong x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong64 OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX)); + + +local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX) +{ + ZPOS64_T x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (ZPOS64_T)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<8; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<16; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<24; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<32; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<40; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<48; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<56; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +/* My own strcmpi / strcasecmp */ +local int strcmpcasenosensitive_internal (const char* fileName1, const char* fileName2) +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparison is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparison is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int ZEXPORT unzStringFileNameCompare (const char* fileName1, + const char* fileName2, + int iCaseSensitivity) + +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); +local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + + +/* + Locate the Central directory 64 of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T unz64local_SearchCentralDir64 OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream)); + +local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + uLong uL; + ZPOS64_T relativeOffset; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + if (uPosFound == 0) + return 0; + + /* Zip64 end of central directory locator */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature, already checked */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + + /* number of the disk with the start of the zip64 end of central directory */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + if (uL != 0) + return 0; + + /* relative offset of the zip64 end of central directory record */ + if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK) + return 0; + + /* total number of disks */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + if (uL != 1) + return 0; + + /* Goto end of central directory record */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + + if (uL != 0x06064b50) + return 0; + + return relativeOffset; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer + "zlib/zlib114.zip". + If the zipfile cannot be opened (file doesn't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +local unzFile unzOpenInternal (const void *path, + zlib_filefunc64_32_def* pzlib_filefunc64_32_def, + int is64bitOpenFunction) +{ + unz64_s us; + unz64_s *s; + ZPOS64_T central_pos; + uLong uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + ZPOS64_T number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + if (unz_copyright[0]!=' ') + return NULL; + + us.z_filefunc.zseek32_file = NULL; + us.z_filefunc.ztell32_file = NULL; + if (pzlib_filefunc64_32_def==NULL) + fill_fopen64_filefunc(&us.z_filefunc.zfile_func64); + else + us.z_filefunc = *pzlib_filefunc64_32_def; + us.is64bitOpenFunction = is64bitOpenFunction; + + + + us.filestream = ZOPEN64(us.z_filefunc, + path, + ZLIB_FILEFUNC_MODE_READ | + ZLIB_FILEFUNC_MODE_EXISTING); + if (us.filestream==NULL) + return NULL; + + central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream); + if (central_pos) + { + uLong uS; + ZPOS64_T uL64; + + us.isZip64 = 1; + + if (ZSEEK64(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* size of zip64 end of central directory record */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&uL64)!=UNZ_OK) + err=UNZ_ERRNO; + + /* version made by */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) + err=UNZ_ERRNO; + + /* version needed to extract */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central directory on this disk */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + us.gi.size_comment = 0; + } + else + { + central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream); + if (central_pos==0) + err=UNZ_ERRNO; + + us.isZip64 = 0; + + if (ZSEEK64(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.gi.number_entry = uL; + + /* total number of entries in the central dir */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + number_entry_CD = uL; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.size_central_dir = uL; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.offset_central_dir = uL; + + /* zipfile comment length */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + } + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + ZCLOSE64(s->z_filefunc, s->filestream); + TRYFREE(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int ZEXPORT unzGetGlobalInfo64 (unzFile file, unz_global_info64* pglobal_info) +{ + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + +extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info32) +{ + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + /* to do : check if number_entry is not truncated */ + pglobal_info32->number_entry = (uLong)s->gi.number_entry; + pglobal_info32->size_comment = s->gi.size_comment; + return UNZ_OK; +} +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +local void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm) +{ + ZPOS64_T uDate; + uDate = (ZPOS64_T)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +local int unz64local_GetCurrentFileInfoInternal OF((unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +local int unz64local_GetCurrentFileInfoInternal (unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize) +{ + unz64_s* s; + unz_file_info64 file_info; + unz_file_info64_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + uLong uL; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (ZSEEK64(s->z_filefunc, s->filestream, + s->pos_in_central_dir+s->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + } + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unz64local_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info.compressed_size = uL; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info.uncompressed_size = uL; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + // relative offset of local header + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info_internal.offset_curfile = uL; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + // Read extrafield + if ((err==UNZ_OK) && (extraField!=NULL)) + { + ZPOS64_T uSizeRead ; + if (file_info.size_file_extraz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,extraField,(uLong)uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + + lSeek += file_info.size_file_extra - (uLong)uSizeRead; + } + else + lSeek += file_info.size_file_extra; + + + if ((err==UNZ_OK) && (file_info.size_file_extra != 0)) + { + uLong acc = 0; + + // since lSeek now points to after the extra field we need to move back + lSeek -= file_info.size_file_extra; + + if (lSeek!=0) + { + if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + while(acc < file_info.size_file_extra) + { + uLong headerId; + uLong dataSize; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK) + err=UNZ_ERRNO; + + /* ZIP64 extra fields */ + if (headerId == 0x0001) + { + uLong uL; + + if(file_info.uncompressed_size == MAXU32) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info.compressed_size == MAXU32) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info_internal.offset_curfile == MAXU32) + { + /* Relative Header offset */ + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info.disk_num_start == MAXU32) + { + /* Disk Start Number */ + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + } + + } + else + { + if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0) + err=UNZ_ERRNO; + } + + acc += 2 + 2 + dataSize; + } + } + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int ZEXPORT unzGetCurrentFileInfo64 (unzFile file, + unz_file_info64 * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) +{ + return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +extern int ZEXPORT unzGetCurrentFileInfo (unzFile file, + unz_file_info * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) +{ + int err; + unz_file_info64 file_info64; + err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); + if ((err==UNZ_OK) && (pfile_info != NULL)) + { + pfile_info->version = file_info64.version; + pfile_info->version_needed = file_info64.version_needed; + pfile_info->flag = file_info64.flag; + pfile_info->compression_method = file_info64.compression_method; + pfile_info->dosDate = file_info64.dosDate; + pfile_info->crc = file_info64.crc; + + pfile_info->size_filename = file_info64.size_filename; + pfile_info->size_file_extra = file_info64.size_file_extra; + pfile_info->size_file_comment = file_info64.size_file_comment; + + pfile_info->disk_num_start = file_info64.disk_num_start; + pfile_info->internal_fa = file_info64.internal_fa; + pfile_info->external_fa = file_info64.external_fa; + + pfile_info->tmu_date = file_info64.tmu_date, + + + pfile_info->compressed_size = (uLong)file_info64.compressed_size; + pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size; + + } + return err; +} +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int ZEXPORT unzGoToFirstFile (unzFile file) +{ + int err=UNZ_OK; + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int ZEXPORT unzGoToNextFile (unzFile file) +{ + unz64_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int ZEXPORT unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) +{ + unz64_s* s; + int err; + + /* We remember the 'current' position in the file so that we can jump + * back there if we fail. + */ + unz_file_info64 cur_file_infoSaved; + unz_file_info64_internal cur_file_info_internalSaved; + ZPOS64_T num_fileSaved; + ZPOS64_T pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + /* Save the current state */ + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + cur_file_infoSaved = s->cur_file_info; + cur_file_info_internalSaved = s->cur_file_info_internal; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + err = unzGetCurrentFileInfo64(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (err == UNZ_OK) + { + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + } + + /* We failed, so restore the state of the 'current file' to where we + * were. + */ + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + s->cur_file_info = cur_file_infoSaved; + s->cur_file_info_internal = cur_file_info_internalSaved; + return err; +} + + +/* +/////////////////////////////////////////// +// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) +// I need random access +// +// Further optimization could be realized by adding an ability +// to cache the directory in memory. The goal being a single +// comprehensive file read to put the file I need in a memory. +*/ + +/* +typedef struct unz_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; // offset in file + ZPOS64_T num_of_file; // # of file +} unz_file_pos; +*/ + +extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) +{ + unz64_s* s; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + file_pos->pos_in_zip_directory = s->pos_in_central_dir; + file_pos->num_of_file = s->num_file; + + return UNZ_OK; +} + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + int err = unzGetFilePos64(file,&file_pos64); + if (err==UNZ_OK) + { + file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory; + file_pos->num_of_file = (uLong)file_pos64.num_of_file; + } + return err; +} + +extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) +{ + unz64_s* s; + int err; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + + /* jump to the right spot */ + s->pos_in_central_dir = file_pos->pos_in_zip_directory; + s->num_file = file_pos->num_of_file; + + /* set the current file */ + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + /* return results */ + s->current_file_ok = (err == UNZ_OK); + return err; +} + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + if (file_pos == NULL) + return UNZ_PARAMERROR; + + file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory; + file_pos64.num_of_file = file_pos->num_of_file; + return unzGoToFilePos64(file,&file_pos64); +} + +/* +// Unzip Helper Functions - should be here? +/////////////////////////////////////////// +*/ + +/* + Read the local header of the current zipfile + Check the coherency of the local header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in local header + (filename and size of extra field data) +*/ +local int unz64local_CheckCurrentFileCoherencyHeader (unz64_s* s, uInt* piSizeVar, + ZPOS64_T * poffset_local_extrafield, + uInt * psize_local_extrafield) +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (ZSEEK64(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + } + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && +/* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +/* #endif */ + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method, + int* level, int raw, const char* password) +{ + int err=UNZ_OK; + uInt iSizeVar; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + ZPOS64_T offset_local_extrafield; /* offset of the local extra field */ + uInt size_local_extrafield; /* size of the local extra field */ +# ifndef NOUNCRYPT + char source[12]; +# else + if (password != NULL) + return UNZ_PARAMERROR; +# endif + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unz64local_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + pfile_in_zip_read_info->raw=raw; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + TRYFREE(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if (method!=NULL) + *method = (int)s->cur_file_info.compression_method; + + if (level!=NULL) + { + *level = 6; + switch (s->cur_file_info.flag & 0x06) + { + case 6 : *level = 1; break; + case 4 : *level = 2; break; + case 2 : *level = 9; break; + } + } + + if ((s->cur_file_info.compression_method!=0) && +/* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +/* #endif */ + (s->cur_file_info.compression_method!=Z_DEFLATED)) + + err=UNZ_BADZIPFILE; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->total_out_64=0; + pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method; + pfile_in_zip_read_info->filestream=s->filestream; + pfile_in_zip_read_info->z_filefunc=s->z_filefunc; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if ((s->cur_file_info.compression_method==Z_BZIP2ED) && (!raw)) + { +#ifdef HAVE_BZIP2 + pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0; + pfile_in_zip_read_info->bstream.bzfree = (free_func)0; + pfile_in_zip_read_info->bstream.opaque = (voidpf)0; + pfile_in_zip_read_info->bstream.state = (voidpf)0; + + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = (voidpf)0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } +#else + pfile_in_zip_read_info->raw=1; +#endif + } + else if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw)) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = 0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_DEFLATED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + s->pfile_in_zip_read = pfile_in_zip_read_info; + s->encrypted = 0; + +# ifndef NOUNCRYPT + if (password != NULL) + { + int i; + s->pcrc_32_tab = get_crc_table(); + init_keys(password,s->keys,s->pcrc_32_tab); + if (ZSEEK64(s->z_filefunc, s->filestream, + s->pfile_in_zip_read->pos_in_zipfile + + s->pfile_in_zip_read->byte_before_the_zipfile, + SEEK_SET)!=0) + return UNZ_INTERNALERROR; + if(ZREAD64(s->z_filefunc, s->filestream,source, 12)<12) + return UNZ_INTERNALERROR; + + for (i = 0; i<12; i++) + zdecode(s->keys,s->pcrc_32_tab,source[i]); + + s->pfile_in_zip_read->pos_in_zipfile+=12; + s->encrypted=1; + } +# endif + + + return UNZ_OK; +} + +extern int ZEXPORT unzOpenCurrentFile (unzFile file) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); +} + +extern int ZEXPORT unzOpenCurrentFilePassword (unzFile file, const char* password) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, password); +} + +extern int ZEXPORT unzOpenCurrentFile2 (unzFile file, int* method, int* level, int raw) +{ + return unzOpenCurrentFile3(file, method, level, raw, NULL); +} + +/** Addition for GDAL : START */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64( unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + s=(unz64_s*)file; + if (file==NULL) + return 0; //UNZ_PARAMERROR; + pfile_in_zip_read_info=s->pfile_in_zip_read; + if (pfile_in_zip_read_info==NULL) + return 0; //UNZ_PARAMERROR; + return pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile; +} + +/** Addition for GDAL : END */ + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len) +{ + int err=UNZ_OK; + uInt iRead = 0; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if (pfile_in_zip_read_info->read_buffer == NULL) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && + (!(pfile_in_zip_read_info->raw))) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + if ((len>pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in) && + (pfile_in_zip_read_info->raw)) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + if (ZREAD64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->read_buffer, + uReadThis)!=uReadThis) + return UNZ_ERRNO; + + +# ifndef NOUNCRYPT + if(s->encrypted) + { + uInt i; + for(i=0;iread_buffer[i] = + zdecode(s->keys,s->pcrc_32_tab, + pfile_in_zip_read_info->read_buffer[i]); + } +# endif + + + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Bytef*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) + { + uInt uDoCopy,i ; + + if ((pfile_in_zip_read_info->stream.avail_in == 0) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + return (iRead==0) ? UNZ_EOF : iRead; + + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uDoCopy; + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + + pfile_in_zip_read_info->bstream.next_in = (char*)pfile_in_zip_read_info->stream.next_in; + pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in; + pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in; + pfile_in_zip_read_info->bstream.total_in_hi32 = 0; + pfile_in_zip_read_info->bstream.next_out = (char*)pfile_in_zip_read_info->stream.next_out; + pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out; + pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out; + pfile_in_zip_read_info->bstream.total_out_hi32 = 0; + + uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32; + bufBefore = (const Bytef *)pfile_in_zip_read_info->bstream.next_out; + + err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream); + + uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis)); + pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->bstream.next_in; + pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in; + pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32; + pfile_in_zip_read_info->stream.next_out = (Bytef*)pfile_in_zip_read_info->bstream.next_out; + pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out; + pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32; + + if (err==BZ_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=BZ_OK) + break; +#endif + } // end Z_BZIP2ED + else + { + ZPOS64_T uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + ZPOS64_T uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) + err = Z_DATA_ERROR; + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern z_off_t ZEXPORT unztell (unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (z_off_t)pfile_in_zip_read_info->stream.total_out; +} + +extern ZPOS64_T ZEXPORT unztell64 (unzFile file) +{ + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return (ZPOS64_T)-1; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return (ZPOS64_T)-1; + + return pfile_in_zip_read_info->total_out_64; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int ZEXPORT unzeof (unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* +Read extra field from the current file (opened by unzOpenCurrentFile) +This is the local-header version of the extra field (sometimes, there is +more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int ZEXPORT unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + uInt read_now; + ZPOS64_T size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (ZREAD64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + buf,read_now)!=read_now) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int ZEXPORT unzCloseCurrentFile (unzFile file) +{ + int err=UNZ_OK; + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && + (!pfile_in_zip_read_info->raw)) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + TRYFREE(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED) + inflateEnd(&pfile_in_zip_read_info->stream); +#ifdef HAVE_BZIP2 + else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED) + BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream); +#endif + + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int ZEXPORT unzGetGlobalComment (unzFile file, char * szComment, uLong uSizeBuf) +{ + unz64_s* s; + uLong uReadThis ; + if (file==NULL) + return (int)UNZ_PARAMERROR; + s=(unz64_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (ZSEEK64(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (ZREAD64(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} + +/* Additions by RX '2004 */ +extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) +{ + unz64_s* s; + + if (file==NULL) + return 0; //UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return 0; + if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) + if (s->num_file==s->gi.number_entry) + return 0; + return s->pos_in_central_dir; +} + +extern uLong ZEXPORT unzGetOffset (unzFile file) +{ + ZPOS64_T offset64; + + if (file==NULL) + return 0; //UNZ_PARAMERROR; + offset64 = unzGetOffset64(file); + return (uLong)offset64; +} + +extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) +{ + unz64_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + + s->pos_in_central_dir = pos; + s->num_file = s->gi.number_entry; /* hack */ + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos) +{ + return unzSetOffset64(file,pos); +}