diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 751de41a..15351f1c 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -30,7 +30,7 @@ jobs: run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} - name: Upload a Build Artifact - uses: actions/upload-artifact@v3.1.2 + uses: actions/upload-artifact@v4 with: name: game-ubuntu-x86_64 # optional, default is artifact path: "game*.so" diff --git a/.gitignore b/.gitignore index 20ce572d..af5bdcbc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,20 +1,32 @@ -cmake-build-debug/* -cmake-build-debug -cmake-build-release -cmake-build-release/* -.idea -/.vscode -/build -msvc/* +# IDEs +/.idea/ +/.vscode/ +/.vs/ + +# macOS +.DS_Store + +# Generic build dirs +/build/ +/out/ +/cmake-build-*/ +/build-clang*/ +/build-*/ + +# CMake user/generated files +/CMakeSettings.txt +/CMakeSettings.json +/CMakeUserPresets.json +/CppProperties.json +/compile_commands.json + +# Logs +*.log + +# Utility/generated local files util/nomatch.txt util/list.lua util/settings.txt -util/v_luasettings_decl.c -util/v_luasettings_game.c -util/v_luasettings_game.h -/.vs -/out/build/x64-Debug -/out/build -CmakeSettings.txt -/CMakeSettings.json -/CppProperties.json +util/v_luasettings_*.c +util/v_luasettings_*.h + diff --git a/CMakeLists.txt b/CMakeLists.txt index bf530ff3..2a93d916 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,19 +17,35 @@ option(VRX_USEHASH "Use hashing on commands instead of iterating through the lis option(VRX_Q2PRO "Use map/gamemap differentiation (for q2pro)." TRUE) option(VRX_OLD_NOLAG "Use old NOLAG style. Not recommended." FALSE) option(VRX_OLD_VOTE "Use old vote system." FALSE) +option(VRX_REPRO "Support q2repro (remaster, EXPERIMENTAL)" TRUE) -set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD 23) set(CMAKE_C_STANDARD_REQUIRED TRUE) # Source files -file(GLOB_RECURSE VRX_FILES ./src/*.c) +file(GLOB_RECURSE VRX_FILES CONFIGURE_DEPENDS ./src/*.c) + +if (NOT VRX_USE_MYSQL) + list(FILTER VRX_FILES EXCLUDE REGEX ".*/src/characters/io/v_mysql_gds\\.c$") +endif () + +if (NOT VRX_REPRO) + set(GAME_NAME game) +else () + # serraboof comments: game_ is the remaster's convention for game dlls + set(GAME_NAME game_) +endif () # Set the platform-specific library name and use platform-specific files. if (WIN32) - if (CMAKE_CL_64) - set(CC_LIB_NAME gamex86_64) + if (CMAKE_SIZEOF_VOID_P EQUAL 8) + if (VRX_REPRO) + set(CC_LIB_NAME ${GAME_NAME}x64) + else () + set(CC_LIB_NAME ${GAME_NAME}x86_64) + endif () else () - set(CC_LIB_NAME gamex86) + set(CC_LIB_NAME ${GAME_NAME}x86) endif () add_definitions(-DWIN32) @@ -38,7 +54,7 @@ elseif (UNIX) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-return-mismatch -Wno-incompatible-pointer-types -Wno-implicit-function-declaration") # Get machine hardware name (arch), force 386 (if applicable), strip newlines, and store in ARCH execute_process(COMMAND uname -m COMMAND sed s/i.86/i386/ COMMAND tr -d \n OUTPUT_VARIABLE ARCH) - set(CC_LIB_NAME game${ARCH}) + set(CC_LIB_NAME ${GAME_NAME}${ARCH}) #file (GLOB CC_PLATFORM_FILES source/Platform/unix/*) link_libraries(dl m) else () @@ -49,6 +65,14 @@ include_directories(./src/) # Specify the source files for the game library add_library(${CC_LIB_NAME} SHARED ${VRX_FILES}) +set_target_properties(${CC_LIB_NAME} PROPERTIES PREFIX "") + +if (WIN32 AND CMAKE_C_COMPILER_ID STREQUAL "Clang") + target_compile_options(${CC_LIB_NAME} PRIVATE + -Wno-incompatible-function-pointer-types + -Wno-incompatible-pointer-types + ) +endif () if (VRX_USE_MYSQL) find_library(MYSQL_LIBRARY_CLIENT @@ -56,7 +80,7 @@ if (VRX_USE_MYSQL) PATHS $ENV{ProgramFiles}/MySQL/*/lib /usr/lib/mysql - ) + ) find_path( MYSQL_INCLUDE_DIR @@ -76,7 +100,6 @@ endif () if (WIN32) set(CC_LINK_LIBS ${CC_LINK_LIBS} Wininet Winmm Ws2_32) - if (MSVC) FetchContent_Declare( pthreads @@ -86,9 +109,23 @@ if (WIN32) FetchContent_MakeAvailable(pthreads) target_include_directories(${CC_LIB_NAME} PRIVATE ${pthreads_SOURCE_DIR}) target_link_libraries(${CC_LIB_NAME} pthreadVC3) - else() - target_link_libraries(${CC_LIB_NAME} pthread) - endif() + else () + if (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_FRONTEND_VARIANT STREQUAL "GNU") + execute_process( + COMMAND ${CMAKE_C_COMPILER} --print-file-name=libwinpthread.a + OUTPUT_VARIABLE WINPTHREAD_STATIC + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + if (EXISTS "${WINPTHREAD_STATIC}") + target_link_libraries(${CC_LIB_NAME} "${WINPTHREAD_STATIC}") + else () + target_link_libraries(${CC_LIB_NAME} pthread) + endif () + else () + target_link_libraries(${CC_LIB_NAME} pthread) + endif () + endif () # add /fsanitize=address to the compiler flags # if (SANITIZE_ADDRESS) @@ -133,29 +170,36 @@ if (VRX_LOCKDEFAULTS) add_definitions(-DLOCK_DEFAULTS) endif () +if (VRX_REPRO) + add_definitions(-DVRX_REPRO) +endif () + +set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) +set(MSGPACK_ENABLE_SHARED OFF CACHE BOOL "" FORCE) +set(MSGPACK_ENABLE_STATIC ON CACHE BOOL "" FORCE) +set(MSGPACK_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) +set(MSGPACK_BUILD_TESTS OFF CACHE BOOL "" FORCE) + FetchContent_Declare( - MsgPack - GIT_REPOSITORY https://github.com/msgpack/msgpack-c/ - GIT_TAG c_master + MsgPack + GIT_REPOSITORY https://github.com/msgpack/msgpack-c/ + GIT_TAG c_master ) FetchContent_MakeAvailable(MsgPack) set(CC_LINK_LIBS ${CC_LINK_LIBS} msgpack-c) -target_include_directories(${CC_LIB_NAME} PRIVATE ${msgpack_SOURCE_DIR}/include ${msgpack_BINARY_DIR}/include/msgpack ${msgpack_BINARY_DIR}/include ) +target_include_directories(${CC_LIB_NAME} PRIVATE + ${msgpack_SOURCE_DIR}/include + ${msgpack_BINARY_DIR}/include/msgpack + ${msgpack_BINARY_DIR}/include +) target_link_libraries(${CC_LIB_NAME} ${CC_LINK_LIBS}) -include (TestBigEndian) +include(TestBigEndian) TEST_BIG_ENDIAN(IS_BIG_ENDIAN) -if(IS_BIG_ENDIAN) +if (IS_BIG_ENDIAN) target_compile_definitions(${CC_LIB_NAME} PRIVATE BIG_ENDIAN) -else() - target_compile_definitions(${CC_LIB_NAME} PRIVATE LITTLE_ENDIAN) -endif() - -# If host is Unix-like, remove "lib" prefix from the library's file name -if (UNIX) - add_custom_command(TARGET ${CC_LIB_NAME} POST_BUILD COMMAND mv lib${CC_LIB_NAME}.so ${CC_LIB_NAME}.so) else () - # add_custom_command (TARGET ${CC_LIB_NAME} POST_BUILD COMMAND copy lib${CC_LIB_NAME}.dll ${CC_LIB_NAME}.dll) + target_compile_definitions(${CC_LIB_NAME} PRIVATE LITTLE_ENDIAN) endif () diff --git a/src/ai/AStar.c b/src/ai/AStar.c index dfdb02cc..033cde5a 100644 --- a/src/ai/AStar.c +++ b/src/ai/AStar.c @@ -222,7 +222,7 @@ static int AStar_FindInOpen_BestF ( void ) for ( i=0; i #include "g_local.h" #include "ai_local.h" @@ -131,9 +132,9 @@ qboolean BOT_DMclass_Ucmd_Move(edict_t* self, float movespeed, usercmd_t* ucmd, if (move_vertical) { if (AI_MoveUp(self)) - ucmd->upmove = movespeed; + cmd_jump(ucmd); else - ucmd->upmove = -movespeed; + cmd_duck(ucmd); moved = true; } @@ -176,7 +177,7 @@ void BOT_DMclass_AvoidDrowning(edict_t* self, usercmd_t *ucmd) { // we're 3 seconds away from drowning--move up! if (level.time + 3.0 > self->air_finished) - ucmd->upmove = 400; + cmd_jump(ucmd); } void BOT_DMclass_AvoidObstacles(edict_t* self, usercmd_t* ucmd, int current_node_flags) @@ -291,7 +292,7 @@ void BOT_DMclass_MoveAttack(edict_t* self, usercmd_t* ucmd) if (self->ai.is_ladder) // climbing ladder { ucmd->forwardmove = 70; - ucmd->upmove = 200; + cmd_jump(ucmd); ucmd->sidemove = 0; return; } @@ -343,7 +344,7 @@ void BOT_DMclass_MoveAttack(edict_t* self, usercmd_t* ucmd) v1[2] += self->mins[2]; trace = gi.trace(v1, tv(-12, -12, -8), tv(12, 12, 0), v1, self, MASK_AISOLID); if (trace.startsolid) - ucmd->upmove = 400; + cmd_jump(ucmd); return; } } @@ -364,7 +365,7 @@ void BOT_DMclass_MoveAttack(edict_t* self, usercmd_t* ucmd) //AI_ChangeAngle(self); if (!(gi.pointcontents(nodes[self->ai.next_node].origin) & MASK_WATER)) // Exit water - ucmd->upmove = 400; + cmd_jump(ucmd); else BOT_DMclass_AvoidDrowning(self, ucmd);//GHz: exit water if we're running out of air @@ -490,7 +491,7 @@ void BOT_DMclass_Move(edict_t *self, usercmd_t *ucmd) if( self->ai.is_ladder ) { ucmd->forwardmove = 70; - ucmd->upmove = 200; + cmd_jump(ucmd); ucmd->sidemove = 0; return; } @@ -538,7 +539,7 @@ void BOT_DMclass_Move(edict_t *self, usercmd_t *ucmd) v1[2] += self->mins[2]; trace = gi.trace( v1, tv(-12, -12, -8), tv(12, 12, 0), v1, self, MASK_AISOLID ); if( trace.startsolid ) - ucmd->upmove = 400; + cmd_jump(ucmd); return; } } @@ -559,8 +560,8 @@ void BOT_DMclass_Move(edict_t *self, usercmd_t *ucmd) AI_ChangeAngle(self); if( !(gi.pointcontents(nodes[self->ai.next_node].origin) & MASK_WATER) ) // Exit water - ucmd->upmove = 400; - + cmd_jump(ucmd); + ucmd->forwardmove = 300; return; } @@ -635,11 +636,11 @@ void BOT_DMclass_Wander(edict_t *self, usercmd_t *ucmd) // If drowning and no node, move up if( self->client && self->client->next_drown_time > 0 ) //jalfixme: client references must pass into botStatus { - ucmd->upmove = 100; + cmd_jump(ucmd); self->s.angles[PITCH] = -45; } else - ucmd->upmove = 15; + cmd_jump(ucmd); ucmd->forwardmove = 300; } @@ -654,9 +655,9 @@ void BOT_DMclass_Wander(edict_t *self, usercmd_t *ucmd) self->s.angles[YAW] += random() * 360 - 180; ucmd->forwardmove = 400; if(self->groundentity) - ucmd->upmove = 400; + cmd_jump(ucmd); else - ucmd->upmove = 0; + cmd_stand(ucmd); return; } @@ -903,7 +904,7 @@ void BOT_DMclassJumpAttack(edict_t* self, usercmd_t* ucmd, float ideal_range) if (self->s.origin[2] + self->viewheight + ideal_range + AI_JUMPABLE_HEIGHT >= self->enemy->absmin[2]) { //gi.dprintf("***JUMP ATTACK****\n"); - ucmd->upmove = 400; + cmd_jump(ucmd); } } @@ -949,7 +950,7 @@ void BOT_DMclass_BunnyHop(edict_t* self, usercmd_t* ucmd, qboolean forwardmove) //gi.dprintf("dot:%f mv_spd:%f fwd_spd:%f\n", dot, mv_spd, AI_ForwardVelocity(self)); if (dot > 0.9 && mv_spd > 280) { - ucmd->upmove = 400; + cmd_jump(ucmd); self->ai.is_bunnyhop = true; } return; @@ -1050,7 +1051,7 @@ void BOT_DMclass_BunnyHop(edict_t* self, usercmd_t* ucmd, qboolean forwardmove) //{ //VectorCopy(self->s.origin, self->monsterinfo.spot1);//GHz: for testing to determine maximum jump distance // jump immediately after touching down in order to maintain momentum - ucmd->upmove = 400; + cmd_jump(ucmd); //} @@ -1522,7 +1523,7 @@ void BOT_DMclass_ChooseWeapon(edict_t *self) continue; //compare range weights - float weight = AIWeapons[i].RangeWeight[weapon_range] + self->ai.status.weaponWeights[i];//GHz + const float weight = AIWeapons[i].RangeWeight[weapon_range] + self->ai.status.weaponWeights[i];//GHz //gi.dprintf("%f\n", weight); if (weight > best_weight) { best_weight = weight; @@ -1619,7 +1620,7 @@ void BOT_DMclass_FireWeapon (edict_t *self, usercmd_t *ucmd) //jalToDo // move our target point based on projectile and enemy velocity - if (projectile_speed = AI_GetWeaponProjectileVelocity(self, weapon)) + if ((projectile_speed = AI_GetWeaponProjectileVelocity(self, weapon))) VectorMA(target, (float)dist / projectile_speed, self->enemy->velocity, target); //gi.dprintf("projectile speed: %f\n", projectile_speed); } @@ -1837,7 +1838,7 @@ void AI_AdjustAmmoNeedFactor(edict_t *self, gitem_t *ammoItem, ...) va_list list; va_start(list, ammoItem); - int ammo_index = ITEM_INDEX(ammoItem); + const int ammo_index = ITEM_INDEX(ammoItem); // if we can't pick it up, reduce the weight to 0 if (!AI_CanPick_Ammo(self, ammoItem)) @@ -1876,7 +1877,7 @@ void AI_AdjustAmmoNeedFactor(edict_t *self, gitem_t *ammoItem, ...) // is the bot fighting and is this weapon our respawn weapon? if (is_fighting && weapIndex != AI_RespawnWeaponToWeapIndex(self->myskills.respawn_weapon)) continue; // nope, check the next weapon on the list - gitem_t* weaponItem = AIWeapons[weapIndex].weaponItem; + const gitem_t* weaponItem = AIWeapons[weapIndex].weaponItem; // does the bot have this weapon? if (self->client->pers.inventory[ITEM_INDEX(weaponItem)]) { @@ -1995,7 +1996,7 @@ void BOT_DMclass_WeightInventory(edict_t *self) // weapon doesn't exist in the AIWeapons list if (!it) continue; - int weap_index = ITEM_INDEX(AIWeapons[i].weaponItem); + const int weap_index = ITEM_INDEX(AIWeapons[i].weaponItem); // morphed players have no use for weapons if (self->mtype || PM_PlayerHasMonster(self)) self->ai.status.inventoryWeights[weap_index] = 0.0; @@ -2170,7 +2171,7 @@ void BOT_DMclass_RunFrame( edict_t *self ) BOT_DMclass_UseBoost(self); // if we have boost, use it to get closer to the enemy BOT_DMclass_UseBlinkStrike(self); // if we have blinkstrike, use it to get closer & behind the enemy - int attack_ability = BOT_DMclass_ChooseAbility(self); // chose the best ability to attack with + const int attack_ability = BOT_DMclass_ChooseAbility(self); // chose the best ability to attack with BOT_DMclass_FireAbility(self, attack_ability); // fire! if (level.time > self->ai.evade_delay) // not a tactical retreat (aka run away while attacking) @@ -2376,7 +2377,7 @@ void BOT_DMclass_Pain(edict_t* self, edict_t* other, float kick, int damage) if (self->health < (0.4 * self->max_health) && level.time > self->pain_debounce_time) { - float r = random(); + const float r = random(); if (r < 0.33) gi.sound(self, CHAN_VOICE, gi.soundindex("speech/yell/saveme1.wav"), 1, ATTN_NORM, 0); else if (r < 0.66) diff --git a/src/ai/ai_class_monster_default.c b/src/ai/ai_class_monster_default.c index 0b53f811..97546825 100644 --- a/src/ai/ai_class_monster_default.c +++ b/src/ai/ai_class_monster_default.c @@ -79,8 +79,8 @@ void M_default_Move(edict_t *self, usercmd_t *ucmd) //if( !(trap_PointContents(nodes[self->ai.next_node].origin) & MASK_WATER) ) // Exit water if( !(gi.pointcontents(nodes[self->ai.next_node].origin) & MASK_WATER) ) // Exit water - ucmd->upmove = 400; - + cmd_jump(ucmd); + ucmd->forwardmove = 300; return; } @@ -695,8 +695,8 @@ void M_default_Spawn (void) { edict_t *ent; vec3_t spawn_origin, spawn_angles;//spawn at a spawnpoint - vec3_t mins = {-15, -15, -24}; - vec3_t maxs = {15, 15, 32}; + const vec3_t mins = {-15, -15, -24}; + const vec3_t maxs = {15, 15, 32}; ent = G_Spawn(); diff --git a/src/ai/ai_dropnodes.c b/src/ai/ai_dropnodes.c index c199bd88..2b385bfa 100644 --- a/src/ai/ai_dropnodes.c +++ b/src/ai/ai_dropnodes.c @@ -583,8 +583,8 @@ qboolean AI_SavePLKFile( char *mapname ) FILE *pOut; char filename[MAX_OSPATH]; int i; - int version = NAV_FILE_VERSION; - cvar_t *game_dir = gi.cvar("game_dir", "vortex", 0); + const int version = NAV_FILE_VERSION; + const cvar_t *game_dir = gi.cvar("game_dir", "vortex", 0); Com_sprintf (filename, sizeof(filename), "%s/%s/%s.%s", AI_MOD_FOLDER, AI_NODES_FOLDER, mapname, NAV_FILE_EXTENSION ); pOut = fopen (filename, "wb"); diff --git a/src/ai/ai_items.c b/src/ai/ai_items.c index 4a2d2e10..1237773d 100644 --- a/src/ai/ai_items.c +++ b/src/ai/ai_items.c @@ -25,6 +25,7 @@ in NO WAY supported by Steve Yeager. #include "g_local.h" #include "ai_local.h" +#include "characters/class_limits.h" //ACE @@ -343,7 +344,7 @@ float AI_ItemWeight(edict_t *self, edict_t *it) if (!Q_stricmp(it->classname, "item_adrenaline")) { - float health_f = self->health / self->max_health; + const float health_f = self->health / self->max_health; weight = 1.0 - health_f; if (weight < 0) weight = 0; diff --git a/src/ai/ai_links.c b/src/ai/ai_links.c index 479518cb..4339218d 100644 --- a/src/ai/ai_links.c +++ b/src/ai/ai_links.c @@ -458,7 +458,7 @@ int AI_RunGravityBox( int n1, int n2 ) { int move; int movemask = 0; - float movescale = 8; + const float movescale = 8; trace_t trace; vec3_t boxmins, boxmaxs; vec3_t o1; @@ -600,7 +600,7 @@ int AI_FindFallOrigin( int n1, int n2, vec3_t fallorigin ) { int move; int movemask = 0; - float movescale = 8; + const float movescale = 8; trace_t trace; vec3_t boxmins, boxmaxs; vec3_t o1; @@ -770,7 +770,7 @@ int AI_IsLadderLink( int n1, int n2 ) //if both are ladder nodes if( nodes[n1].flags & NODEFLAGS_LADDER && nodes[n2].flags & NODEFLAGS_LADDER ) { - int candidate = AI_LadderLink_FindUpperNode( n1 ); + const int candidate = AI_LadderLink_FindUpperNode( n1 ); if( candidate != n2 ) return LINK_INVALID; @@ -953,8 +953,8 @@ int AI_LinkCloseNodes_JumpPass( int start ) { int n1, n2; int count = 0; - float pLinkRadius = NODE_DENSITY*2; - qboolean ignoreHeight = true; + const float pLinkRadius = NODE_DENSITY*2; + const qboolean ignoreHeight = true; int linkType; if( nav.num_nodes < 1 ) @@ -999,8 +999,8 @@ int AI_LinkCloseNodes( void ) { int n1, n2; int count = 0; - float pLinkRadius = NODE_DENSITY*1.5; - qboolean ignoreHeight = true; + const float pLinkRadius = NODE_DENSITY*1.5; + const qboolean ignoreHeight = true; //do it for everynode in the list for( n1=0; n1ai.state == BOT_STATE_ATTACK && self->enemy && self->enemy->inuse) { // calculate distance between entity and our enemy - float enemy_dist = entdist(e, self->enemy); + const float enemy_dist = entdist(e, self->enemy); // bots should move toward their summons in combat if (AI_NumSummons(self) > 0 && AI_IsOwnedSummons(self, e) && dist > AI_RANGE_SHORT && visible(self, e) @@ -738,7 +738,7 @@ void AI_PickShortRangeGoal(edict_t *self) //=================== void AI_CategorizePosition (edict_t *ent) { - qboolean stepping = AI_IsStep(ent); + const qboolean stepping = AI_IsStep(ent); //AI_DebugPrintf("AI_CategorizePosition()\n"); diff --git a/src/ai/ai_movement.c b/src/ai/ai_movement.c index 2f0bbcdb..4b91d8be 100644 --- a/src/ai/ai_movement.c +++ b/src/ai/ai_movement.c @@ -315,7 +315,7 @@ qboolean AI_SpecialMove(edict_t *self, usercmd_t *ucmd) BOT_DMclass_Ucmd_Move(self, 400, ucmd, false, false); else ucmd->forwardmove = 400; - ucmd->upmove = -400; + cmd_duck(ucmd); return true; } } @@ -342,7 +342,7 @@ qboolean AI_SpecialMove(edict_t *self, usercmd_t *ucmd) BOT_DMclass_Ucmd_Move(self, 400, ucmd, false, false); else ucmd->forwardmove = 400; - ucmd->upmove = 400; + cmd_jump(ucmd); return true; } @@ -389,7 +389,7 @@ void AI_ChangeAngle (edict_t *ent) if (current_yaw != ideal_yaw) { move = ideal_yaw - current_yaw; - speed = ent->yaw_speed; + speed = ent->yaw_speed * FRAMETIME * 10.0f; if (ideal_yaw > current_yaw) { if (move >= 180) @@ -418,7 +418,7 @@ void AI_ChangeAngle (edict_t *ent) if (current_pitch != ideal_pitch) { move = ideal_pitch - current_pitch; - speed = ent->yaw_speed; + speed = ent->yaw_speed * FRAMETIME * 10.0f; if (ideal_pitch > current_pitch) { if (move >= 180) @@ -513,7 +513,7 @@ qboolean AI_DodgeProjectiles(edict_t* self, usercmd_t* ucmd) mv_spd = fabsf(DotProduct(self->ai.move_vector, self->velocity)); // if we're going fast enough in that direction, jump to gain additional speed and distance if (mv_spd > 250 && self->groundentity) - ucmd->upmove = 400; + cmd_jump(ucmd); //gi.dprintf("AI_DodgeProjectiles: *** INCOMING %s! eta:%.2f GET OUTTA THE WAY! ***\n", self->movetarget->classname, eta); gi.sound(self, CHAN_VOICE, gi.soundindex("speech/yell/lookout.wav"), 1, ATTN_NORM, 0); gi.WriteByte(svc_temp_entity); @@ -568,7 +568,7 @@ qboolean AI_DodgeProjectiles(edict_t* self, usercmd_t* ucmd) BOT_DMclass_Ucmd_Move(self, 400, ucmd, false, false);//move! mv_spd = fabsf(DotProduct(self->ai.move_vector, self->velocity));// speed in the direction of escape vector if (mv_spd > 250 && self->groundentity) - ucmd->upmove = 400;//jump! + cmd_jump(ucmd); //gi.dprintf("%d: %s: *** EXPLOSIVE %s NEARBY! GET OUTTA THE WAY! ***\n", (int)level.framenum, __func__, self->movetarget->classname); gi.sound(self, CHAN_VOICE, gi.soundindex("speech/yell/firehole.wav"), 1, ATTN_NORM, 0); gi.WriteByte(svc_temp_entity); diff --git a/src/ai/ai_nodes.c b/src/ai/ai_nodes.c index e9c8c240..84cc165b 100644 --- a/src/ai/ai_nodes.c +++ b/src/ai/ai_nodes.c @@ -641,7 +641,7 @@ void AI_CreateNodesForEntities ( void ) { edict_t *ent; int node; - int nodes_start=nav.num_nodes;//GHz + const int nodes_start=nav.num_nodes;//GHz nav.num_ents = 0; memset( nav.ents, 0, sizeof(nav_ents_t) * MAX_EDICTS ); @@ -969,8 +969,8 @@ int AI_LinkServerNodes( int start ) { int n1, n2; int count = 0; - float pLinkRadius = NODE_DENSITY*1.2; - qboolean ignoreHeight = true; + const float pLinkRadius = NODE_DENSITY*1.2; + const qboolean ignoreHeight = true; if( start >= nav.num_nodes ) return 0; diff --git a/src/ai/ai_util.c b/src/ai/ai_util.c index 05e3f86a..beaeea96 100644 --- a/src/ai/ai_util.c +++ b/src/ai/ai_util.c @@ -184,10 +184,10 @@ float BOT_DMclass_ThrowingPitch2(edict_t* self, float v_xy, float v_z) //FIXME: move to q_shared.c if this function is used elsewhere void ProjectOnPlane(vec3_t dst, const vec3_t p, const vec3_t normal) { - float sqrMag = DotProduct(normal, normal); + const float sqrMag = DotProduct(normal, normal); if (sqrMag < FLT_EPSILON) return; - float dot = DotProduct(normal, p); + const float dot = DotProduct(normal, p); dst[0] = p[0] - normal[0] * dot / sqrMag; dst[1] = p[1] - normal[1] * dot / sqrMag; dst[2] = p[2] - normal[2] * dot / sqrMag; @@ -263,7 +263,7 @@ float BOT_DMclass_ThrowingPitch1(edict_t* self, float v) //AngleVectors(self->client->v_angle, forward, right, NULL); //P_ProjectSource(self->client, self->s.origin, offset, forward, right, start); - float g = sv_gravity->value; + const float g = sv_gravity->value; float d;// = Get2dDistance(start, self->enemy->s.origin);//Horizontal distance to the target. float h;// = self->enemy->s.origin[2] - start[2]; //Vertical difference between the projectile's initial height and the target height. @@ -273,7 +273,7 @@ float BOT_DMclass_ThrowingPitch1(edict_t* self, float v) //gi.dprintf("displacement: h: %.0f v: %.0f\n", h_d, v_d); //float h = 1.0*(self->enemy->absmin[2] - self->absmax[2]); - double discriminant = pow(v, 4) - g * (g * pow(d, 2) + (2 * h * pow(v, 2))); + const double discriminant = pow(v, 4) - g * (g * pow(d, 2) + (2 * h * pow(v, 2))); if (discriminant <= 0) { diff --git a/src/ai/bot_abilities.c b/src/ai/bot_abilities.c index ddb8b026..003408a6 100644 --- a/src/ai/bot_abilities.c +++ b/src/ai/bot_abilities.c @@ -222,7 +222,7 @@ float AI_GetAbilityRangeWeightByDistance(int ability_index, float distance) float AI_GetAbilityProjectileVelocity(edict_t* ent, int ability_index) { - int slvl = ent->myskills.abilities[ability_index].current_level; + const int slvl = ent->myskills.abilities[ability_index].current_level; switch (ability_index) { case MIRV: return 600; @@ -336,7 +336,7 @@ int BOT_DMclass_ChooseAbility(edict_t* self) continue; //compare range weights - float weight = AIAbilities[i].RangeWeight[weapon_range]; + const float weight = AIAbilities[i].RangeWeight[weapon_range]; if (weight > best_weight) { best_weight = weight; best_ability = i; @@ -382,7 +382,7 @@ void BOT_DMclass_FireAbility(edict_t* self, int ability_index) return; // range check - float dist = entdist(self, self->enemy); + const float dist = entdist(self, self->enemy); // don't bother firing if we're unlikely to hit anything if (AI_GetAbilityRangeWeightByDistance(ability_index, dist) < 0.1) @@ -396,8 +396,8 @@ void BOT_DMclass_FireAbility(edict_t* self, int ability_index) // return; // get firing parameters - int aimType = AIAbilities[ability_index].aimType; - float speed = AI_GetAbilityProjectileVelocity(self, ability_index); + const int aimType = AIAbilities[ability_index].aimType; + const float speed = AI_GetAbilityProjectileVelocity(self, ability_index); if (aimType == AI_AIMSTYLE_BALLISTIC) is_ballistic = true; else if (aimType == AI_AIMSTYLE_PREDICTION_EXPLOSIVE) @@ -482,7 +482,7 @@ void BOT_DMclass_UseBlinkStrike(edict_t* self) return; //gi.dprintf("%s: %s\n", self->ai.pers.netname, __func__); // range check - float dist = entdist(self, self->enemy); + const float dist = entdist(self, self->enemy); if (dist > AI_RANGE_SNIPER || dist < AI_RANGE_SHORT) return; // don't bother against flying opponents @@ -510,7 +510,7 @@ void BOT_DMclass_UseBoost(edict_t* self) if (self->ai.state != BOT_STATE_ATTACK) return; // range check - float dist = entdist(self, self->enemy); + const float dist = entdist(self, self->enemy); if (dist > AI_RANGE_SNIPER || dist < AI_RANGE_SHORT) return; @@ -584,7 +584,7 @@ void BOT_DMclass_UseGolem(edict_t* self) int AI_NearbyEnemies(edict_t* self, vec3_t org, float radius) { int enemies = 0; - edict_t* e = NULL; + const edict_t* e = NULL; while ((e = findradius(e, org, radius)) != NULL) { diff --git a/src/ai/bot_common.c b/src/ai/bot_common.c index 429256af..74fd331b 100644 --- a/src/ai/bot_common.c +++ b/src/ai/bot_common.c @@ -18,6 +18,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include + #include "g_local.h" #include "ai_local.h" @@ -124,7 +126,7 @@ char *bot_names[] = void BOT_AutoSpawn(void) { - int num_bots = bot_autospawn->value; + const int num_bots = bot_autospawn->value; char* name; if (!nav.loaded) return; @@ -135,7 +137,7 @@ void BOT_AutoSpawn(void) return; for (int i = 0; i < num_bots; i++) { - bot_selection_t e = get_random_unique_entry(); + const bot_selection_t e = get_random_unique_entry(); //name = bot_names[GetRandom(0, sizeof(bot_names - 1))]; name = e.name; BOT_SpawnBot(NULL, name, NULL, NULL, e.class); @@ -169,7 +171,7 @@ qboolean BOT_ServerCommand (void) if (!name || strlen(name) < 5) { - name = bot_names[GetRandom(0, sizeof(bot_names - 1))]; + name = bot_names[GetRandom(0, sizeof(bot_names) - 1)]; } if (!Q_stricmp(cmd, "addbot")) diff --git a/src/ai/bot_spawn.c b/src/ai/bot_spawn.c index 88ac9af5..b6b023fa 100644 --- a/src/ai/bot_spawn.c +++ b/src/ai/bot_spawn.c @@ -135,7 +135,7 @@ void BOT_SetName(edict_t *bot, char *name, char *skin, char *team) if(!skin || strlen(skin) == 0) { // randomly choose skin - float rnd = random(); + const float rnd = random(); if(rnd < 0.05) sprintf(bot_skin,"female/athena"); else if(rnd < 0.1) @@ -189,7 +189,7 @@ void BOT_SetName(edict_t *bot, char *name, char *skin, char *team) Info_SetValueForKey (userinfo, "hand", "2"); // bot is center handed for now! Info_SetValueForKey(userinfo, "ip", "127.0.0.1"); - ClientConnect (bot, userinfo); + ClientConnect (bot, userinfo, NULL, true); // ACESP_SaveBots(); // make sure to save the bots } @@ -292,12 +292,12 @@ void BOT_UpgradeTalent(edict_t* ent, int talent_index, int amount) // cap amount to the number of talent points we have if (amount > ent->myskills.talents.talentPoints) amount = ent->myskills.talents.talentPoints; - int slot = vrx_get_talent_slot(ent, talent_index); + const int slot = vrx_get_talent_slot(ent, talent_index); // invalid talent if (slot == -1) return; talent_t* talent = &ent->myskills.talents.talent[slot]; - int levels_to_max = talent->maxLevel - talent->upgradeLevel; + const int levels_to_max = talent->maxLevel - talent->upgradeLevel; // talent can't be upgraded any further if (levels_to_max < 1) return; @@ -574,7 +574,7 @@ void BOT_SelectRespawnWeapon(edict_t* ent) //weaponCount = sizeof(&weaponArray) / sizeof(&weaponArray[0]); randomIndex = GetRandom(0, weaponCount-1); - int i = weaponArray[randomIndex]; + const int i = weaponArray[randomIndex]; //gi.dprintf("%s: weaponCount: %d randomIndex: %d selected: %d\n", __func__, weaponCount, randomIndex, i); ent->myskills.respawn_weapon = i; } @@ -706,7 +706,7 @@ void BOT_DMClass_JoinGame (edict_t *ent, char *team_name) } gi.linkentity (ent); - int Windex = vrx_WeapIDtoWeapIndex(ent->myskills.respawn_weapon); + const int Windex = vrx_WeapIDtoWeapIndex(ent->myskills.respawn_weapon); gitem_t *it = &itemlist[Windex]; //gi.dprintf("bot spawned in game, weapon: %s\n", it->pickup_name); } @@ -776,7 +776,7 @@ void BOT_SpawnBot (char *team, char *name, char *skin, char *userinfo, char *cla if(userinfo == NULL) BOT_SetName(bot, name, skin, team); else - ClientConnect (bot, userinfo); + ClientConnect (bot, userinfo, NULL, true); bot->ai.is_bot = true;//GHz: because this gets set to 'false' in ClientConnect G_InitEdict (bot); InitClientResp (bot->client); diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h new file mode 100644 index 00000000..6d619401 --- /dev/null +++ b/src/cgame/cg_local.h @@ -0,0 +1,17 @@ +// Copyright (c) ZeniMax Media Inc. +// Licensed under the GNU General Public License 2.0. + +// g_local.h -- local definitions for game module +#pragma once + +#include "../q_shared.h" + +extern struct cgame_import_t cgi; +extern struct cgame_export_t cglobals; + +// az: bleh +struct configstring_remap_t CS_REMAP(int32_t id); + +#define SERVER_TICK_RATE cgi.tick_rate // in hz +#define FRAME_TIME_S cgi.frame_time_s +#define FRAME_TIME_MS cgi.frame_time_ms diff --git a/src/cgame/cg_main.c b/src/cgame/cg_main.c new file mode 100644 index 00000000..70108dc7 --- /dev/null +++ b/src/cgame/cg_main.c @@ -0,0 +1,122 @@ +// Copyright (c) ZeniMax Media Inc. +// Licensed under the GNU General Public License 2.0. + +#include "cg_local.h" + +struct cgame_import_t cgi; +struct cgame_export_t cglobals; + +static void *CG_GetExtension(const char *name) +{ + return nullptr; +} + +void CG_InitScreen(); + +uint64_t cgame_init_time = 0; + +static void InitCGame() +{ + CG_InitScreen(); + cgame_init_time = cgi.CL_ClientRealTime(); + + pm_config.n64_physics = !!atoi(cgi.get_configstring(CONFIG_N64_PHYSICS)); + pm_config.airaccel = atoi(cgi.get_configstring(CS_AIRACCEL)); +} + +static void ShutdownCGame() +{ +} + +void CG_DrawHUD (int32_t isplit, const struct cg_server_data_t *data, struct vrect_t hud_vrect, struct vrect_t hud_safe, int32_t scale, int32_t playernum, const player_state_t *ps); +void CG_TouchPics(); +enum layout_flags_t CG_LayoutFlags(const player_state_t *ps); + +int32_t CG_GetActiveWeaponWheelWeapon(const player_state_t *ps) +{ + return ps->stats[STAT_ACTIVE_WHEEL_WEAPON]; +} + +uint32_t CG_GetOwnedWeaponWheelWeapons(const player_state_t *ps) +{ + return ((uint32_t) (uint16_t) ps->stats[STAT_WEAPONS_OWNED_1]) | ((uint32_t) (uint16_t) (ps->stats[STAT_WEAPONS_OWNED_2]) << 16); +} + +int16_t CG_GetWeaponWheelAmmoCount(const player_state_t *ps, int32_t ammo_id) +{ + const uint16_t ammo = G_GetAmmoStat((uint16_t *) &ps->stats[STAT_AMMO_INFO_START], ammo_id); + + if (ammo == AMMO_VALUE_INFINITE) + return -1; + + return ammo; +} + +int16_t CG_GetPowerupWheelCount(const player_state_t *ps, int32_t powerup_id) +{ + return G_GetPowerupStat((uint16_t *) &ps->stats[STAT_POWERUP_INFO_START], powerup_id); +} + +int16_t CG_GetHitMarkerDamage(const player_state_t *ps) +{ + return ps->stats[STAT_HIT_MARKER]; +} + +static void CG_ParseConfigString(int32_t i, const char *s) +{ + if (i == CONFIG_N64_PHYSICS) + pm_config.n64_physics = !!atoi(s); + else if (i == CS_AIRACCEL) + pm_config.airaccel = atoi(s); +} + +void CG_ParseCenterPrint (const char *str, int isplit, bool instant); +void CG_ClearNotify(int32_t isplit); +void CG_ClearCenterprint(int32_t isplit); +void CG_NotifyMessage(int32_t isplit, const char *msg, bool is_chat); + +void CG_GetMonsterFlashOffset(enum monster_muzzleflash_id_t id, vec3_t offset) +{ + if (id >= q_countof(monster_flash_offset)) + cgi.Com_Error("Bad muzzle flash offset"); + + offset = monster_flash_offset[id]; +} + +/* +================= +GetCGameAPI + +Returns a pointer to the structure with all entry points +and global variables +================= +*/ +q_export struct cgame_export_t *GetCGameAPI(struct cgame_import_t *import) +{ + cgi = *import; + + cglobals.apiversion = CGAME_API_VERSION; + cglobals.Init = InitCGame; + cglobals.Shutdown = ShutdownCGame; + + cglobals.Pmove = Pmove; + cglobals.DrawHUD = CG_DrawHUD; + cglobals.LayoutFlags = CG_LayoutFlags; + cglobals.TouchPics = CG_TouchPics; + + cglobals.GetActiveWeaponWheelWeapon = CG_GetActiveWeaponWheelWeapon; + cglobals.GetOwnedWeaponWheelWeapons = CG_GetOwnedWeaponWheelWeapons; + cglobals.GetWeaponWheelAmmoCount = CG_GetWeaponWheelAmmoCount; + cglobals.GetPowerupWheelCount = CG_GetPowerupWheelCount; + cglobals.GetHitMarkerDamage = CG_GetHitMarkerDamage; + cglobals.ParseConfigString = CG_ParseConfigString; + cglobals.ParseCenterPrint = CG_ParseCenterPrint; + cglobals.ClearNotify = CG_ClearNotify; + cglobals.ClearCenterprint = CG_ClearCenterprint; + cglobals.NotifyMessage = CG_NotifyMessage; + cglobals.GetMonsterFlashOffset = CG_GetMonsterFlashOffset; + + cglobals.GetExtension = CG_GetExtension; + + return &cglobals; +} diff --git a/src/cgame/cg_screen.c b/src/cgame/cg_screen.c new file mode 100644 index 00000000..2591cec7 --- /dev/null +++ b/src/cgame/cg_screen.c @@ -0,0 +1,1897 @@ +// Copyright (c) ZeniMax Media Inc. +// Licensed under the GNU General Public License 2.0. +#include + +#include "cg_local.h" +#include "quake2/q_recompat.h" + +#if defined(CHAR_WIDTH) +#undef CHAR_WIDTH +#endif + +constexpr int32_t STAT_MINUS = 10; // num frame for '-' stats digit +const char *sb_nums[2][11] = +{ + { + "num_0", "num_1", "num_2", "num_3", "num_4", "num_5", + "num_6", "num_7", "num_8", "num_9", "num_minus" + }, + { + "anum_0", "anum_1", "anum_2", "anum_3", "anum_4", "anum_5", + "anum_6", "anum_7", "anum_8", "anum_9", "anum_minus" + } +}; + +constexpr int32_t CHAR_WIDTH = 16; +constexpr int32_t CONCHAR_WIDTH = 8; + +static int32_t font_y_offset; + +// constexpr rgba_t alt_color = {.r = 112, 255, 52, 255}; +constexpr rgba_t alt_color = {.r = 240, 140, 60, 255}; + +static cvar_t *scr_usekfont; + +static cvar_t *scr_centertime; +static cvar_t *scr_printspeed; +static cvar_t *cl_notifytime; +static cvar_t *scr_maxlines; +static cvar_t *ui_acc_contrast; +static cvar_t *ui_acc_alttypeface; + +// static temp data used for hud +static struct { + struct { + struct { + char text[24]; + } table_cells[6]; + } table_rows[11]; // just enough to store 8 levels + header + total (+ one slack) + + size_t column_widths[6]; + int32_t num_rows; + int32_t num_columns; +} hud_temp = {0}; + +// max number of centerprints in the rotating buffer +constexpr size_t MAX_CENTER_PRINTS = 4; +constexpr size_t MAX_BIND_STR_LEN = 256; + +struct cl_bind_t { + char bind[MAX_BIND_STR_LEN]; + char purpose[MAX_BIND_STR_LEN]; +}; + +#define MAX_CENTERPRINT_BINDS 16 +#define MAX_CENTERPRINT_LINES 8 + +struct cl_centerprint_t { + struct cl_bind_t binds[MAX_CENTERPRINT_BINDS]; // binds + size_t bind_count; // current number of binds + + char lines[MAX_CENTERPRINT_LINES][MAX_BIND_STR_LEN]; + size_t row_count; // number of centerprint lines + + bool instant; // don't type out + + size_t current_line; // current line we're typing out + size_t line_count; // byte count to draw on current line + bool finished; // done typing it out + uint64_t time_tick, time_off; // time to remove at +}; + +void centerprint_clear_lines(struct cl_centerprint_t *self) { + memset(self->lines, 0, sizeof(self->lines)); + self->row_count = 0; +} + +void centerprint_add_line(struct cl_centerprint_t *self, const char *line) { + if (!line) + return; + if (self->row_count >= MAX_CENTERPRINT_LINES) + return; + + size_t len = strlen(line); + if (len + 1 >= MAX_BIND_STR_LEN) + return; + + memmove(&self->lines[self->row_count], line, len); + self->lines[self->row_count][len] = '\0'; + self->row_count++; +} + +void centerprint_add_bind(struct cl_centerprint_t *self, const struct cl_bind_t bind) { + if (self->bind_count >= MAX_CENTERPRINT_BINDS) + return; + + memcpy(&self->binds[self->bind_count], &bind, sizeof(struct cl_bind_t)); + self->bind_count++; +} + +struct cl_bind_t bind_from_string(const char *bind_str, const char *purpose_str) { + struct cl_bind_t bind; + strncpy(bind.bind, bind_str, sizeof bind.bind); + strncpy(bind.purpose, purpose_str, sizeof bind.purpose); + bind.bind[sizeof bind.bind - 1] = '\0'; + bind.purpose[sizeof bind.purpose - 1] = '\0'; + return bind; +} + +int32_t ps_instant_dmg_value(const player_state_t *ps) { + return (int32_t) (((uint32_t) (uint16_t) ps->stats[STAT_ID_DAMAGE]) | ( + ((uint32_t) (uint16_t) ps->stats[STAT_ID_DAMAGE2]) << 16)); +} + +int32_t ps_score_value(const player_state_t *ps) { + return (int32_t) ((uint32_t) (uint16_t) ps->stats[STAT_SCORE] | (uint32_t) (uint16_t) ps->stats[STAT_SCORE2] << 16); +} + +bool CG_ViewingLayout(const player_state_t *ps) { + return ps->stats[STAT_LAYOUTS] & (LAYOUTS_LAYOUT | LAYOUTS_INVENTORY); +} + +bool CG_InIntermission(const player_state_t *ps) { + return ps->stats[STAT_LAYOUTS] & LAYOUTS_INTERMISSION; +} + +inline bool CG_HudHidden(const player_state_t *ps) { + return ps->stats[STAT_LAYOUTS] & LAYOUTS_HIDE_HUD; +} + +enum layout_flags_t CG_LayoutFlags(const player_state_t *ps) { + return (enum layout_flags_t) ps->stats[STAT_LAYOUTS]; +} + +constexpr size_t MAX_NOTIFY = 8; +constexpr size_t MAX_MESSAGE_LEN = 2048; + +struct cl_notify_t { + char message[MAX_MESSAGE_LEN]; // utf8 message + bool is_active; // filled or not + bool is_chat; // green or not + uint64_t time; // rotate us when < CL_Time() +}; + +// per-splitscreen client hud storage +struct hud_data_t { + struct cl_centerprint_t centers[MAX_CENTER_PRINTS]; // list of centers + int32_t center_index; // current index we're drawing, or -1 if none left + struct cl_notify_t notify[MAX_NOTIFY]; // list of notifies + + // damage counter + int32_t dmg_counter; + int32_t dmg_instant; + uint64_t last_dmg_time; + + // experience + int16_t last_value; + int16_t next_value; +}; + + +static struct hud_data_t hud_data[MAX_SPLIT_PLAYERS]; + +void CG_ClearCenterprint(const int32_t isplit) { + hud_data[isplit].center_index = -1; +} + +void CG_ClearNotify(const int32_t isplit) { + for (size_t i = 0; i < MAX_NOTIFY; i++) + hud_data[isplit].notify[i].is_active = false; +} + +// if the top one is expired, cycle the ones ahead backwards (since +// the times are always increasing) +static void CG_Notify_CheckExpire(struct hud_data_t *data) { + while (data->notify[0].is_active && data->notify[0].time < cgi.CL_ClientTime()) { + data->notify[0].is_active = false; + + for (size_t i = 1; i < MAX_NOTIFY; i++) + if (data->notify[i].is_active) { + const struct cl_notify_t cur = data->notify[i]; + data->notify[i] = data->notify[i - 1]; + data->notify[i - 1] = cur; + } + } +} + +// add notify to list +static void CG_AddNotify(struct hud_data_t *data, const char *msg, const bool is_chat) { + size_t i = 0; + + if (scr_maxlines->integer <= 0) + return; + + const int max = min(MAX_NOTIFY, (size_t)scr_maxlines->integer); + + for (; i < max; i++) + if (!data->notify[i].is_active) + break; + + // none left, so expire the topmost one + if (i == max) { + data->notify[0].time = 0; + CG_Notify_CheckExpire(data); + i = max - 1; + } + + size_t len = min(strlen(msg), MAX_MESSAGE_LEN - 1); + + memmove(data->notify[i].message, msg, len); + data->notify[i].message[len] = '\0'; + + data->notify[i].is_active = true; + data->notify[i].is_chat = is_chat; + data->notify[i].time = cgi.CL_ClientTime() + cl_notifytime->value * 1000; +} + +// draw notifies +static void CG_DrawNotify(const int32_t isplit, const struct vrect_t hud_vrect, const struct vrect_t hud_safe, + const int32_t scale) { + const auto data = &hud_data[isplit]; + + CG_Notify_CheckExpire(data); + + int y = hud_vrect.y * scale + hud_safe.y; + + cgi.SCR_SetAltTypeface(ui_acc_alttypeface->integer && true); + + if (ui_acc_contrast->integer) { + for (size_t i = 0; i < MAX_NOTIFY; i++) { + const auto msg = &data->notify[i]; + const auto len = strlen(msg->message); + if (!msg->is_active || len == 0) + break; + + vec2_t sz = cgi.SCR_MeasureFontString(msg->message, scale); + sz.x += 10; // extra padding for black bars + cgi.SCR_DrawColorPic(hud_vrect.x * scale + hud_safe.x - 5, y, sz.x, 15 * scale, "_white", &rgba_black); + y += 10 * scale; + } + } + + y = hud_vrect.y * scale + hud_safe.y; + for (size_t i = 0; i < MAX_NOTIFY; i++) { + const auto msg = data->notify[i]; + if (!msg.is_active) + break; + + cgi.SCR_DrawFontString(msg.message, hud_vrect.x * scale + hud_safe.x, y, scale, + msg.is_chat ? &alt_color : &rgba_white, true, LEFT); + y += 10 * scale; + } + + cgi.SCR_SetAltTypeface(false); + + // draw text input (only the main player can really chat anyways...) + if (isplit == 0) { + const char *input_msg; + bool input_team; + + if (cgi.CL_GetTextInput(&input_msg, &input_team)) + cgi.SCR_DrawFontString( + va("%s: %s", input_team ? "say_team" : "say", input_msg), + hud_vrect.x * scale + hud_safe.x, + y, + scale, + &rgba_white, + true, + LEFT + ); + } +} + +/* +============== +CG_DrawHUDString +============== +*/ +static int CG_DrawHUDString(const char *string, int x, int y, const int centerwidth, const int _xor, const int scale, + const bool shadow /*= true*/) { + char line[1024]; + + const int margin = x; + + while (*string) { + // scan out one line of text from the string + int width = 0; + while (*string && *string != '\n') + line[width++] = *string++; + line[width] = 0; + + vec2_t size; + + if (scr_usekfont->integer) + size = cgi.SCR_MeasureFontString(line, scale); + + if (centerwidth) { + if (!scr_usekfont->integer) + x = margin + (centerwidth - width * CONCHAR_WIDTH * scale) / 2; + else + x = margin + (centerwidth - size.x) / 2; + } else + x = margin; + + if (!scr_usekfont->integer) { + for (int i = 0; i < width; i++) { + cgi.SCR_DrawChar(x, y, scale, line[i] ^ _xor, shadow); + x += CONCHAR_WIDTH * scale; + } + } else { + cgi.SCR_DrawFontString(line, x, y - font_y_offset * scale, scale, _xor ? &alt_color : &rgba_white, true, + LEFT); + x += size.x; + } + + if (*string) { + string++; // skip the \n + x = margin; + if (!scr_usekfont->integer) + y += CONCHAR_WIDTH * scale; + else + // TODO + y += 10 * scale; //size.y; + } + } + + return x; +} + +// Shamefully stolen from Kex +size_t FindStartOfUTF8Codepoint(const char *str, const size_t pos) { + if (pos >= strlen(str)) { + return SIZE_MAX; + } + + for (ptrdiff_t i = pos; i >= 0; i--) { + const char ch = str[i]; + + if ((ch & 0x80) == 0) { + // character is one byte + return i; + } + if ((ch & 0xC0) == 0x80) { + // character is part of a multi-byte sequence, keep going + continue; + } + // character is the start of a multi-byte sequence, so stop now + return i; + } + + return SIZE_MAX; +} + +size_t FindEndOfUTF8Codepoint(const char *str, const size_t pos) { + if (pos >= strlen(str)) { + return SIZE_MAX; + } + + for (size_t i = pos; i < strlen(str); i++) { + const char ch = str[i]; + + if ((ch & 0x80) == 0) { + // character is one byte + return i; + } + + if ((ch & 0xC0) == 0x80) { + // character is part of a multi-byte sequence, keep going + continue; + } + + // character is the start of a multi-byte sequence, so stop now + return i; + } + + return SIZE_MAX; +} + +void CG_NotifyMessage(const int32_t isplit, const char *msg, const bool is_chat) { + CG_AddNotify(&hud_data[isplit], msg, is_chat); +} + +// centerprint stuff +static struct cl_centerprint_t *CG_QueueCenterPrint(const int isplit, const bool instant) { + auto icl = &hud_data[isplit]; + + // just use first index + if (icl->center_index == -1 || instant) { + icl->center_index = 0; + + + for (size_t i = 1; i < MAX_CENTER_PRINTS; i++) + centerprint_clear_lines(&icl->centers[i]); + + return &icl->centers[0]; + } + + // pick the next free index if we can find one + for (size_t i = 1; i < MAX_CENTER_PRINTS; i++) { + const auto center = &icl->centers[(icl->center_index + i) % MAX_CENTER_PRINTS]; + + if (center->row_count == 0) + return center; + } + + // none, so update the current one (the new end of buffer) + // and skip ahead + const auto center = &icl->centers[icl->center_index]; + icl->center_index = (icl->center_index + 1) % MAX_CENTER_PRINTS; + return center; +} + +/* +============== +SCR_CenterPrint + +Called for important messages that should stay in the center of the screen +for a few moments +============== +*/ +void CG_ParseCenterPrint(const char *str, const int isplit, const bool instant) // [Sam-KEX] Made 1st param const +{ + char line[64]; + int i, l; + + // handle center queueing + struct cl_centerprint_t *center = CG_QueueCenterPrint(isplit, instant); + + centerprint_clear_lines(center); + + // split the string into lines + size_t line_start = 0; + + const size_t slen = strlen(str); + char string[slen + 1]; + strncpy(string, str, slen + 1); + + center->bind_count = 0; + + // [Paril-KEX] pull out bindings. they'll always be at the start + const char *s = string; + while (strncmp(s, "%bind:", 6) == 0) { + const char *end_of_bind = strchr(s, '%'); + + if (end_of_bind == nullptr) + break; + + const char *bind = s + 6; + + const char *purpose_ptr = strchr(bind, ':'); + size_t bind_length = purpose_ptr ? purpose_ptr - bind : strlen(bind); + size_t purpose_length = purpose_ptr ? end_of_bind - purpose_ptr : 0; + + char bind_string[bind_length + 1]; + char purpose_string[purpose_length + 1]; + strncpy(bind_string, bind, bind_length); + strncpy(purpose_string, purpose_ptr + 1, purpose_length); + bind_string[bind_length] = '\0'; + purpose_string[purpose_length] = '\0'; + + if (purpose_ptr != nullptr) { + centerprint_add_bind(center, bind_from_string(bind_string, purpose_string)); + } else + centerprint_add_bind(center, bind_from_string(bind_string, "")); + + s = end_of_bind + 1; + center->bind_count++; + } + + const char *s_start = s; + // echo it to the console + cgi.Com_Print( + "\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n"); + + // const char *s = string.c_str(); + do { + // scan the width of the line + for (l = 0; l < 40; l++) + if (s[l] == '\n' || !s[l]) + break; + for (i = 0; i < (40 - l) / 2; i++) + line[i] = ' '; + + for (int j = 0; j < l; j++) { + line[i++] = s[j]; + } + + line[i] = '\n'; + line[i + 1] = 0; + + cgi.Com_Print(line); + + while (*s && *s != '\n') + s++; + + if (!*s) + break; + s++; // skip the \n + } while (1); + cgi.Com_Print( + "\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n"); + CG_ClearNotify(isplit); + + s = s_start; + for (size_t line_end = 0; ;) { + line_end = FindEndOfUTF8Codepoint(s, line_end); + + if (line_end == SIZE_MAX) { + // final line + if (line_start < slen) + centerprint_add_line(center, s + line_start); + break; + } + + // char part of current line; + // if newline, end line and cut off + const char ch = s[line_end]; + + if (ch == '\n') { + if (line_end > line_start) { + char _s[line_end - line_start + 1]; + strncpy(_s, s + line_start, line_end - line_start); + _s[line_end - line_start] = '\0'; + centerprint_add_line(center, _s); + } else + centerprint_add_line(center, ""); + line_start = line_end + 1; + line_end++; + continue; + } + + line_end++; + } + + if (center->row_count == 0) { + center->finished = true; + return; + } + + center->time_tick = cgi.CL_ClientRealTime() + scr_printspeed->value * 1000; + center->instant = instant; + center->finished = false; + center->current_line = 0; + center->line_count = 0; +} + + +static void CG_DrawCenterString(const player_state_t *ps, const struct vrect_t hud_vrect, const struct vrect_t hud_safe, + const int isplit, const int scale, struct cl_centerprint_t *center) { + int32_t y = hud_vrect.y * scale; + + if (CG_ViewingLayout(ps)) + y += hud_safe.y; + else if (center->row_count <= 4) + y += hud_vrect.height * 0.2f * scale; + else + y += 48 * scale; + + int lineHeight = (scr_usekfont->integer ? 10 : 8) * scale; + if (ui_acc_alttypeface->integer) lineHeight *= 1.5f; + + // easy! + if (center->instant) { + for (size_t i = 0; i < center->row_count; i++) { + const auto line = center->lines[i]; + + cgi.SCR_SetAltTypeface(ui_acc_alttypeface->integer && true); + + if (ui_acc_contrast->integer && strlen(line)) { + vec2_t sz = cgi.SCR_MeasureFontString(line, scale); + sz.x += 10; // extra padding for black bars + const int barY = ui_acc_alttypeface->integer ? y - 8 : y; + cgi.SCR_DrawColorPic((hud_vrect.x + hud_vrect.width / 2) * scale - sz.x / 2, barY, sz.x, lineHeight, + "_white", &rgba_black); + } + CG_DrawHUDString(line, (hud_vrect.x + hud_vrect.width / 2 + -160) * scale, y, 320 / 2 * 2 * scale, 0, scale, + true); + + cgi.SCR_SetAltTypeface(false); + + y += lineHeight; + } + + for (size_t i = 0; i < center->bind_count; i++) { + const auto bind = ¢er->binds[i]; + y += lineHeight * 2; + cgi.SCR_DrawBind(isplit, bind->bind, bind->purpose, (hud_vrect.x + hud_vrect.width / 2) * scale, y, scale); + } + + if (!center->finished) { + center->finished = true; + center->time_off = cgi.CL_ClientRealTime() + scr_centertime->value * 1000; + } + + return; + } + + // hard and annoying! + // check if it's time to fetch a new char + const uint64_t t = cgi.CL_ClientRealTime(); + + if (!center->finished) { + if (center->time_tick < t) { + center->time_tick = t + scr_printspeed->value * 1000; + center->line_count = FindEndOfUTF8Codepoint(center->lines[center->current_line], center->line_count + 1); + + if (center->line_count == SIZE_MAX) { + center->current_line++; + center->line_count = 0; + + if (center->current_line == center->row_count) { + center->current_line--; + center->finished = true; + center->time_off = t + scr_centertime->value * 1000; + } + } + } + } + + // smallish byte buffer for single line of data... + char buffer[256]; + + for (size_t i = 0; i < center->row_count; i++) { + cgi.SCR_SetAltTypeface(ui_acc_alttypeface->integer && true); + + const auto line = center->lines[i]; + const auto len = strlen(line); + + buffer[0] = 0; + + if (center->finished || i != center->current_line) + Q_strlcpy(buffer, line, sizeof(buffer)); + else + Q_strlcpy(buffer, line, min(center->line_count + 1, sizeof(buffer))); + + int blinky_x; + + if (ui_acc_contrast->integer && len) { + vec2_t sz = cgi.SCR_MeasureFontString(line, scale); + sz.x += 10; // extra padding for black bars + const int barY = ui_acc_alttypeface->integer ? y - 8 : y; + cgi.SCR_DrawColorPic((hud_vrect.x + hud_vrect.width / 2) * scale - sz.x / 2, barY, sz.x, lineHeight, + "_white", &rgba_black); + } + + if (buffer[0]) + blinky_x = CG_DrawHUDString(buffer, (hud_vrect.x + hud_vrect.width / 2 + -160) * scale, y, + 320 / 2 * 2 * scale, 0, scale, true); + else + blinky_x = hud_vrect.width / 2 * scale; + + cgi.SCR_SetAltTypeface(false); + + if (i == center->current_line && !ui_acc_alttypeface->integer) + cgi.SCR_DrawChar(blinky_x, y, scale, 10 + (cgi.CL_ClientRealTime() >> 8 & 1), true); + + y += lineHeight; + + if (i == center->current_line) + break; + } +} + +static void CG_CheckDrawCenterString(const player_state_t *ps, const struct vrect_t hud_vrect, + const struct vrect_t hud_safe, const int isplit, const int scale) { + if (CG_InIntermission(ps)) + return; + if (hud_data[isplit].center_index == -1) + return; + + const auto data = &hud_data[isplit]; + const auto center = &data->centers[data->center_index]; + + // ran out of center time + if (center->finished && center->time_off < cgi.CL_ClientRealTime()) { + centerprint_clear_lines(center); + + const size_t next_index = (data->center_index + 1) % MAX_CENTER_PRINTS; + const auto next_center = &data->centers[next_index]; + + // no more + if (next_center->row_count == 0) { + data->center_index = -1; + return; + } + + // buffer rotated; start timer now + data->center_index = next_index; + next_center->current_line = next_center->line_count = 0; + } + + if (data->center_index == -1) + return; + + CG_DrawCenterString(ps, hud_vrect, hud_safe, isplit, scale, &data->centers[data->center_index]); +} + +/* +============== +CG_DrawString +============== +*/ +static void CG_DrawString(int x, const int y, const int scale, const char *s, const bool alt /* false */, + const bool shadow /*= true*/) { + while (*s) { + cgi.SCR_DrawChar(x, y, scale, *s ^ (alt ? 0x80 : 0), shadow); + x += 8 * scale; + s++; + } +} + +/* +============== +CG_DrawField +============== +*/ +static void CG_DrawField(int x, const int y, const int color, int width, int value, int scale) { + char num[16]; + int frame; + + if (width < 1) + return; + + // draw number string + // az: from 5 + if (width > 7) + width = 7; + + int l = snprintf(num, sizeof(num), "%d", value); + if (l >= sizeof(num)) + l = sizeof(num) - 1; + + if (l > width) + l = width; + + x += (2 + CHAR_WIDTH * (width - l)) * scale; + + char *ptr = num; + while (*ptr && l) { + if (*ptr == '-') + frame = STAT_MINUS; + else + frame = *ptr - '0'; + int w, h; + cgi.Draw_GetPicSize(&w, &h, sb_nums[color][frame]); + cgi.SCR_DrawPic(x, y, w * scale, h * scale, sb_nums[color][frame]); + x += CHAR_WIDTH * scale; + ptr++; + l--; + } +} + +// [Paril-KEX] +static void CG_DrawTable(int x, int y, const uint32_t width, const uint32_t height, const int32_t scale) { + // half left + const int32_t width_pixels = width; + x -= width_pixels / 2; + y += CONCHAR_WIDTH * scale; + // use Y as top though + + const int32_t height_pixels = height; + + // draw border + // KEX_FIXME method that requires less chars + cgi.SCR_DrawChar(x - CONCHAR_WIDTH * scale, y - CONCHAR_WIDTH * scale, scale, 18, false); + cgi.SCR_DrawChar(x + width_pixels, y - CONCHAR_WIDTH * scale, scale, 20, false); + cgi.SCR_DrawChar(x - CONCHAR_WIDTH * scale, y + height_pixels, scale, 24, false); + cgi.SCR_DrawChar(x + width_pixels, y + height_pixels, scale, 26, false); + + for (int cx = x; cx < x + width_pixels; cx += CONCHAR_WIDTH * scale) { + cgi.SCR_DrawChar(cx, y - CONCHAR_WIDTH * scale, scale, 19, false); + cgi.SCR_DrawChar(cx, y + height_pixels, scale, 25, false); + } + + for (int cy = y; cy < y + height_pixels; cy += CONCHAR_WIDTH * scale) { + cgi.SCR_DrawChar(x - CONCHAR_WIDTH * scale, cy, scale, 21, false); + cgi.SCR_DrawChar(x + width_pixels, cy, scale, 23, false); + } + + cgi.SCR_DrawColorPic(x, y, width_pixels, height_pixels, "_white", &rgba_black); + + // draw in columns + for (int i = 0; i < hud_temp.num_columns; i++) { + for (int r = 0, ry = y; r < hud_temp.num_rows; r++, ry += (CONCHAR_WIDTH + font_y_offset) * scale) { + int x_offset = 0; + + // center + if (r == 0) { + x_offset = hud_temp.column_widths[i] / 2 - + cgi.SCR_MeasureFontString(hud_temp.table_rows[r].table_cells[i].text, scale).x / 2; + } + // right align + else if (i != 0) { + x_offset = hud_temp.column_widths[i] - cgi.SCR_MeasureFontString( + hud_temp.table_rows[r].table_cells[i].text, scale).x; + } + + //CG_DrawString(x + x_offset, ry, scale, hud_temp.table_rows[r].table_cells[i].text, r == 0, true); + cgi.SCR_DrawFontString(hud_temp.table_rows[r].table_cells[i].text, x + x_offset, ry - font_y_offset * scale, + scale, r == 0 ? &alt_color : &rgba_white, true, LEFT); + } + + x += hud_temp.column_widths[i] + cgi.SCR_MeasureFontString(" ", 1).x; + } +} + + +static void vrx_apply_stat_hax(const player_state_t *ps, int *value, int stat) { + if (stat == STAT_ID_DAMAGE) { + *value = ps_instant_dmg_value(ps); + } + + if (stat == STAT_SCORE) { + *value = ps_score_value(ps); + } +} + +/* +================ +CG_ExecuteLayoutString + +================ +*/ +static void CG_ExecuteLayoutString(const char *s, struct vrect_t hud_vrect, struct vrect_t hud_safe, int32_t scale, + int32_t playernum, const player_state_t *ps) { + int x, y; + int w, h; + int hx, hy; + int value; + const char *token; + int width; + int index; + + if (!s[0]) + return; + + x = hud_vrect.x; + y = hud_vrect.y; + width = 3; + + hx = 320 / 2; + hy = 240 / 2; + + bool flash_frame = cgi.CL_ClientTime() % 1000 < 500; + + // if non-zero, parse but don't affect state + int32_t if_depth = 0; // current if statement depth + int32_t endif_depth = 0; // at this depth, toggle skip_depth + bool skip_depth = false; // whether we're in a dead stmt or not + + while (s) { + token = COM_Parse(&s); + if (!strcmp(token, "xl")) { + token = COM_Parse(&s); + if (!skip_depth) + x = (hud_vrect.x + atoi(token)) * scale + hud_safe.x; + continue; + } + if (!strcmp(token, "xr")) { + token = COM_Parse(&s); + if (!skip_depth) + x = (hud_vrect.x + hud_vrect.width + atoi(token)) * scale - hud_safe.x; + continue; + } + if (!strcmp(token, "xv")) { + token = COM_Parse(&s); + if (!skip_depth) + x = (hud_vrect.x + hud_vrect.width / 2 + (atoi(token) - hx)) * scale; + continue; + } + + if (!strcmp(token, "yt")) { + token = COM_Parse(&s); + if (!skip_depth) + y = (hud_vrect.y + atoi(token)) * scale + hud_safe.y; + continue; + } + if (!strcmp(token, "yb")) { + token = COM_Parse(&s); + if (!skip_depth) + y = (hud_vrect.y + hud_vrect.height + atoi(token)) * scale - hud_safe.y; + continue; + } + if (!strcmp(token, "yv")) { + token = COM_Parse(&s); + if (!skip_depth) + y = (hud_vrect.y + hud_vrect.height / 2 + (atoi(token) - hy)) * scale; + continue; + } + + if (!strcmp(token, "pic")) { + // draw a pic from a stat number + token = COM_Parse(&s); + if (!skip_depth) { + value = ps->stats[atoi(token)]; + if (value >= MAX_IMAGES) + cgi.Com_Error("Pic >= MAX_IMAGES"); + + const char *const pic = cgi.get_configstring(CS_IMAGES + value); + + if (pic && *pic) { + cgi.Draw_GetPicSize(&w, &h, pic); + cgi.SCR_DrawPic(x, y, w * scale, h * scale, pic); + } + } + + continue; + } + + if (!strcmp(token, "client")) { + // draw a deathmatch client block + token = COM_Parse(&s); + if (!skip_depth) { + x = (hud_vrect.x + hud_vrect.width / 2 + (atoi(token) - hx)) * scale; + x += 8 * scale; + } + token = COM_Parse(&s); + if (!skip_depth) { + y = (hud_vrect.y + hud_vrect.height / 2 + (atoi(token) - hy)) * scale; + y += 7 * scale; + } + + token = COM_Parse(&s); + + if (!skip_depth) { + value = atoi(token); + if (value >= MAX_CLIENTS || value < 0) + cgi.Com_Error("client >= MAX_CLIENTS"); + } + + int score; + + token = COM_Parse(&s); + if (!skip_depth) + score = atoi(token); + + token = COM_Parse(&s); + if (!skip_depth) { + int ping; + ping = atoi(token); + + if (!scr_usekfont->integer) + CG_DrawString(x + 32 * scale, y, scale, cgi.CL_GetClientName(value), false, true); + else + cgi.SCR_DrawFontString(cgi.CL_GetClientName(value), x + 32 * scale, y - font_y_offset * scale, + scale, &rgba_white, true, LEFT); + + if (!scr_usekfont->integer) + CG_DrawString(x + 32 * scale, y + 10 * scale, scale, va("%d", score), true, true); + else + cgi.SCR_DrawFontString(va("%d", score), x + 32 * scale, y + (10 - font_y_offset) * scale, scale, + &rgba_white, true, LEFT); + + cgi.SCR_DrawPic(x + 96 * scale, y + 10 * scale, 9 * scale, 9 * scale, "ping"); + + if (!scr_usekfont->integer) + CG_DrawString(x + 73 * scale + 32 * scale, y + 10 * scale, scale, va("%d", ping), false, true); + else + cgi.SCR_DrawFontString(va("%d", ping), x + 107 * scale, y + (10 - font_y_offset) * scale, scale, + &rgba_white, true, LEFT); + } + continue; + } + + if (!strcmp(token, "ctf")) { + // draw a ctf client block + int score, ping; + + token = COM_Parse(&s); + if (!skip_depth) + x = (hud_vrect.x + hud_vrect.width / 2 - hx + atoi(token)) * scale; + token = COM_Parse(&s); + if (!skip_depth) + y = (hud_vrect.y + hud_vrect.height / 2 - hy + atoi(token)) * scale; + + token = COM_Parse(&s); + if (!skip_depth) { + value = atoi(token); + if (value >= MAX_CLIENTS || value < 0) + cgi.Com_Error("client >= MAX_CLIENTS"); + } + + token = COM_Parse(&s); + if (!skip_depth) + score = atoi(token); + + token = COM_Parse(&s); + if (!skip_depth) { + ping = atoi(token); + if (ping > 999) + ping = 999; + } + + token = COM_Parse(&s); + + if (!skip_depth) { + cgi.SCR_DrawFontString(va("%d", score), x, y - font_y_offset * scale, scale, + value == playernum ? &alt_color : &rgba_white, true, LEFT); + x += 3 * 9 * scale; + cgi.SCR_DrawFontString(va("%d", ping), x, y - font_y_offset * scale, scale, + value == playernum ? &alt_color : &rgba_white, true, LEFT); + x += 3 * 9 * scale; + cgi.SCR_DrawFontString(cgi.CL_GetClientName(value), x, y - font_y_offset * scale, scale, + value == playernum ? &alt_color : &rgba_white, true, LEFT); + + if (*token) { + cgi.Draw_GetPicSize(&w, &h, token); + cgi.SCR_DrawPic(x - (w + 2) * scale, y, w * scale, h * scale, token); + } + } + continue; + } + + if (!strcmp(token, "picn")) { + // draw a pic from a name + token = COM_Parse(&s); + if (!skip_depth) { + cgi.Draw_GetPicSize(&w, &h, token); + cgi.SCR_DrawPic(x, y, w * scale, h * scale, token); + } + continue; + } + + if (!strcmp(token, "num")) { + // draw a number + token = COM_Parse(&s); + if (!skip_depth) + width = atoi(token); + token = COM_Parse(&s); + if (!skip_depth) { + int stat = atoi(token); + value = ps->stats[stat]; + + // az: the damage and game hacks for vortex + vrx_apply_stat_hax(ps, &value, stat); + + + CG_DrawField(x, y, 0, width, value, scale); + } + continue; + } + // [Paril-KEX] special handling for the lives number + if (!strcmp(token, "lives_num")) { + token = COM_Parse(&s); + if (!skip_depth) { + value = ps->stats[atoi(token)]; + CG_DrawField(x, y, value <= 2 ? flash_frame : 0, 1, max(0, value - 2), scale); + } + } + + if (!strcmp(token, "hnum")) { + // health number + if (!skip_depth) { + int color; + + width = 5; + value = ps->stats[STAT_HEALTH]; + if (value > 25) + color = 0; // green + else if (value > 0) + color = flash_frame; // flash + else + color = 1; + if (ps->stats[STAT_FLASHES] & 1) { + cgi.Draw_GetPicSize(&w, &h, "field_3"); + cgi.SCR_DrawPic(x, y, w * scale, h * scale, "field_3"); + } + + CG_DrawField(x, y, color, width, value, scale); + } + continue; + } + + if (!strcmp(token, "dmgnum")) { + // damage number + if (!skip_depth && hud_data[playernum].dmg_counter) { + width = 8; + value = hud_data[playernum].dmg_counter; + + if (hud_data[playernum].last_dmg_time + 50 > cgi.CL_ClientTime()) { + cgi.SCR_DrawColorPic(x, y, 16 * (width - 1) * scale, 28 * scale, "_white", &rgba_orange); + } + + const char *total_s = va("%d total", value); + auto len = strlen(total_s) + 2; + CG_DrawField(x, y, 0, width, hud_data[playernum].dmg_instant, scale); + CG_DrawString(x + (16 * width - len * 8) * scale, y + 32 * scale, scale, total_s, false, true); + } + continue; + } + + if (!strcmp(token, "anum")) { + // ammo number + if (!skip_depth) { + int color; + + width = 5; + value = ps->stats[STAT_AMMO]; + + int32_t min_ammo = cgi.CL_GetWarnAmmoCount(ps->stats[STAT_ACTIVE_WEAPON]); + + if (!min_ammo) + min_ammo = 5; // back compat + + if (value > min_ammo) + color = 0; // green + else if (value >= 0) + color = flash_frame; // flash + else + continue; // negative number = don't show + if (ps->stats[STAT_FLASHES] & 4) { + cgi.Draw_GetPicSize(&w, &h, "field_3"); + cgi.SCR_DrawPic(x, y, w * scale, h * scale, "field_3"); + } + + CG_DrawField(x, y, color, width, value, scale); + } + continue; + } + + if (!strcmp(token, "rnum")) { + // armor number + if (!skip_depth) { + int color; + + width = 5; + value = ps->stats[STAT_ARMOR]; + if (value < 0) + continue; + + color = 0; // green + if (ps->stats[STAT_FLASHES] & 2) { + cgi.Draw_GetPicSize(&w, &h, "field_3"); + cgi.SCR_DrawPic(x, y, w * scale, h * scale, "field_3"); + } + + CG_DrawField(x, y, color, width, value, scale); + } + continue; + } + + if (!strcmp(token, "stat_string")) { + token = COM_Parse(&s); + + if (!skip_depth) { + index = atoi(token); + if (index < 0 || index >= MAX_STATS) + cgi.Com_Error("Bad stat_string index"); + index = ps->stats[index]; + + if (cgi.CL_ServerProtocol() <= PROTOCOL_VERSION_3XX) + index = CS_REMAP(index).start / CS_MAX_STRING_LENGTH; + + if (index < 0 || index >= MAX_CONFIGSTRINGS) + cgi.Com_Error("Bad stat_string index"); + if (!scr_usekfont->integer) + CG_DrawString(x, y, scale, cgi.get_configstring(index), false, true); + else + cgi.SCR_DrawFontString(cgi.get_configstring(index), x, y - font_y_offset * scale, scale, + &rgba_white, true, LEFT); + } + continue; + } + + if (!strcmp(token, "cstring")) { + token = COM_Parse(&s); + if (!skip_depth) + CG_DrawHUDString(token, x, y, hx * 2 * scale, 0, scale, true); + continue; + } + + if (!strcmp(token, "string")) { + token = COM_Parse(&s); + if (!skip_depth) { + if (!scr_usekfont->integer) + CG_DrawString(x, y, scale, token, false, true); + else + cgi.SCR_DrawFontString(token, x, y - font_y_offset * scale, scale, &rgba_white, true, LEFT); + } + continue; + } + + if (!strcmp(token, "cstring2")) { + token = COM_Parse(&s); + if (!skip_depth) + CG_DrawHUDString(token, x, y, hx * 2 * scale, 0x80, scale, true); + continue; + } + + if (!strcmp(token, "string2")) { + token = COM_Parse(&s); + if (!skip_depth) { + if (!scr_usekfont->integer) + CG_DrawString(x, y, scale, token, true, true); + else + cgi.SCR_DrawFontString(token, x, y - font_y_offset * scale, scale, &alt_color, true, LEFT); + } + continue; + } + + if (!strcmp(token, "if")) { + // if stmt + token = COM_Parse(&s); + + if_depth++; + + // skip to endif + if (!skip_depth && !ps->stats[atoi(token)]) { + skip_depth = true; + endif_depth = if_depth; + } + + continue; + } + + if (!strcmp(token, "ifeq")) { + // stat index + token = COM_Parse(&s); + + if_depth++; + + int stat_index = atoi(token); + if (stat_index < 0 || stat_index >= MAX_STATS) + cgi.Com_Error("Bad stat_index"); + + token = COM_Parse(&s); + int value = atoi(token); + if (ps->stats[stat_index] != value) { + skip_depth = true; + endif_depth = if_depth; + } + } + + if (!strcmp(token, "ifgef")) { + // if stmt + token = COM_Parse(&s); + + if_depth++; + + // skip to endif + if (!skip_depth && cgi.CL_ServerFrame() < atoi(token)) { + skip_depth = true; + endif_depth = if_depth; + } + + continue; + } + + if (!strcmp(token, "endif")) { + if (skip_depth && if_depth == endif_depth) + skip_depth = false; + + if_depth--; + + if (if_depth < 0) + cgi.Com_Error("endif without matching if"); + + continue; + } + + // localization stuff + if (!strcmp(token, "loc_stat_string")) { + token = COM_Parse(&s); + + if (!skip_depth) { + index = atoi(token); + if (index < 0 || index >= MAX_STATS) + cgi.Com_Error("Bad stat_string index"); + index = ps->stats[index]; + + if (cgi.CL_ServerProtocol() <= PROTOCOL_VERSION_3XX) + index = CS_REMAP(index).start / CS_MAX_STRING_LENGTH; + + if (index < 0 || index >= MAX_CONFIGSTRINGS) + cgi.Com_Error("Bad stat_string index"); + if (!scr_usekfont->integer) + CG_DrawString(x, y, scale, cgi.Localize(cgi.get_configstring(index), nullptr, 0), false, true); + else + cgi.SCR_DrawFontString(cgi.Localize(cgi.get_configstring(index), nullptr, 0), x, + y - font_y_offset * scale, scale, &rgba_white, true, LEFT); + } + continue; + } + + if (!strcmp(token, "loc_stat_rstring")) { + token = COM_Parse(&s); + + if (!skip_depth) { + index = atoi(token); + if (index < 0 || index >= MAX_STATS) + cgi.Com_Error("Bad stat_string index"); + index = ps->stats[index]; + + if (cgi.CL_ServerProtocol() <= PROTOCOL_VERSION_3XX) + index = CS_REMAP(index).start / CS_MAX_STRING_LENGTH; + + if (index < 0 || index >= MAX_CONFIGSTRINGS) + cgi.Com_Error("Bad stat_string index"); + const char *s = cgi.Localize(cgi.get_configstring(index), nullptr, 0); + if (!scr_usekfont->integer) + CG_DrawString(x - strlen(s) * CONCHAR_WIDTH * scale, y, scale, s, false, true); + else { + vec2_t size = cgi.SCR_MeasureFontString(s, scale); + cgi.SCR_DrawFontString(s, x - size.x, y - font_y_offset * scale, scale, &rgba_white, true, LEFT); + } + } + continue; + } + + if (!strcmp(token, "loc_stat_cstring")) { + token = COM_Parse(&s); + + if (!skip_depth) { + index = atoi(token); + if (index < 0 || index >= MAX_STATS) + cgi.Com_Error("Bad stat_string index"); + index = ps->stats[index]; + + if (cgi.CL_ServerProtocol() <= PROTOCOL_VERSION_3XX) + index = CS_REMAP(index).start / CS_MAX_STRING_LENGTH; + + if (index < 0 || index >= MAX_CONFIGSTRINGS) + cgi.Com_Error("Bad stat_string index"); + CG_DrawHUDString(cgi.Localize(cgi.get_configstring(index), nullptr, 0), x, y, hx * 2 * scale, 0, scale, + true); + } + continue; + } + + if (!strcmp(token, "loc_stat_cstring2")) { + token = COM_Parse(&s); + + if (!skip_depth) { + index = atoi(token); + if (index < 0 || index >= MAX_STATS) + cgi.Com_Error("Bad stat_string index"); + index = ps->stats[index]; + + if (cgi.CL_ServerProtocol() <= PROTOCOL_VERSION_3XX) + index = CS_REMAP(index).start / CS_MAX_STRING_LENGTH; + + if (index < 0 || index >= MAX_CONFIGSTRINGS) + cgi.Com_Error("Bad stat_string index"); + CG_DrawHUDString(cgi.Localize(cgi.get_configstring(index), nullptr, 0), x, y, hx * 2 * scale, 0x80, + scale, true); + } + continue; + } + + static char arg_tokens[MAX_LOCALIZATION_ARGS + 1][MAX_TOKEN_CHARS]; + static const char *arg_buffers[MAX_LOCALIZATION_ARGS]; + + if (!strcmp(token, "loc_cstring")) { + int32_t num_args = atoi(COM_Parse(&s)); + + if (num_args < 0 || num_args >= MAX_LOCALIZATION_ARGS) + cgi.Com_Error("Bad loc string"); + + // parse base + token = COM_Parse(&s); + Q_strlcpy(arg_tokens[0], token, sizeof(arg_tokens[0])); + + // parse args + for (int32_t i = 0; i < num_args; i++) { + token = COM_Parse(&s); + Q_strlcpy(arg_tokens[1 + i], token, sizeof(arg_tokens[0])); + arg_buffers[i] = arg_tokens[1 + i]; + } + + if (!skip_depth) + CG_DrawHUDString(cgi.Localize(arg_tokens[0], arg_buffers, num_args), x, y, hx * 2 * scale, 0, scale, + true); + continue; + } + + if (!strcmp(token, "loc_string")) { + int32_t num_args = atoi(COM_Parse(&s)); + + if (num_args < 0 || num_args >= MAX_LOCALIZATION_ARGS) + cgi.Com_Error("Bad loc string"); + + // parse base + token = COM_Parse(&s); + Q_strlcpy(arg_tokens[0], token, sizeof(arg_tokens[0])); + + // parse args + for (int32_t i = 0; i < num_args; i++) { + token = COM_Parse(&s); + Q_strlcpy(arg_tokens[1 + i], token, sizeof(arg_tokens[0])); + arg_buffers[i] = arg_tokens[1 + i]; + } + + if (!skip_depth) { + if (!scr_usekfont->integer) + CG_DrawString(x, y, scale, cgi.Localize(arg_tokens[0], arg_buffers, num_args), false, true); + else + cgi.SCR_DrawFontString(cgi.Localize(arg_tokens[0], arg_buffers, num_args), x, + y - font_y_offset * scale, scale, &rgba_white, true, LEFT); + } + continue; + } + + if (!strcmp(token, "loc_cstring2")) { + int32_t num_args = atoi(COM_Parse(&s)); + + if (num_args < 0 || num_args >= MAX_LOCALIZATION_ARGS) + cgi.Com_Error("Bad loc string"); + + // parse base + token = COM_Parse(&s); + Q_strlcpy(arg_tokens[0], token, sizeof(arg_tokens[0])); + + // parse args + for (int32_t i = 0; i < num_args; i++) { + token = COM_Parse(&s); + Q_strlcpy(arg_tokens[1 + i], token, sizeof(arg_tokens[0])); + arg_buffers[i] = arg_tokens[1 + i]; + } + + if (!skip_depth) + CG_DrawHUDString(cgi.Localize(arg_tokens[0], arg_buffers, num_args), x, y, hx * 2 * scale, 0x80, scale, + true); + continue; + } + + if (!strcmp(token, "loc_string2") || !strcmp(token, "loc_rstring2") || + !strcmp(token, "loc_string") || !strcmp(token, "loc_rstring")) { + bool green = token[strlen(token) - 1] == '2'; + bool rightAlign = !Q_strncasecmp(token, "loc_rstring", strlen("loc_rstring")); + int32_t num_args = atoi(COM_Parse(&s)); + + if (num_args < 0 || num_args >= MAX_LOCALIZATION_ARGS) + cgi.Com_Error("Bad loc string"); + + // parse base + token = COM_Parse(&s); + Q_strlcpy(arg_tokens[0], token, sizeof(arg_tokens[0])); + + // parse args + for (int32_t i = 0; i < num_args; i++) { + token = COM_Parse(&s); + Q_strlcpy(arg_tokens[1 + i], token, sizeof(arg_tokens[0])); + arg_buffers[i] = arg_tokens[1 + i]; + } + + if (!skip_depth) { + const char *locStr = cgi.Localize(arg_tokens[0], arg_buffers, num_args); + int xOffs = 0; + if (rightAlign) { + xOffs = scr_usekfont->integer + ? cgi.SCR_MeasureFontString(locStr, scale).x + : strlen(locStr) * CONCHAR_WIDTH * scale; + } + + if (!scr_usekfont->integer) + CG_DrawString(x - xOffs, y, scale, locStr, green, true); + else + cgi.SCR_DrawFontString(locStr, x - xOffs, y - font_y_offset * scale, scale, + green ? &alt_color : &rgba_white, true, LEFT); + } + continue; + } + + // draw time remaining + if (!strcmp(token, "time_limit")) { + // end frame + token = COM_Parse(&s); + + if (!skip_depth) { + int32_t end_frame = atoi(token); + + if (end_frame < cgi.CL_ServerFrame()) + continue; + + uint64_t remaining_ms = (end_frame - cgi.CL_ServerFrame()) * cgi.frame_time_ms; + + const bool green = true; + arg_buffers[0] = va("%02d:%02d", remaining_ms / 1000 / 60, remaining_ms / 1000 % 60); + + const char *locStr = cgi.Localize("$g_score_time", arg_buffers, 1); + int xOffs = scr_usekfont->integer + ? cgi.SCR_MeasureFontString(locStr, scale).x + : strlen(locStr) * CONCHAR_WIDTH * scale; + if (!scr_usekfont->integer) + CG_DrawString(x - xOffs, y, scale, locStr, green, true); + else + cgi.SCR_DrawFontString(locStr, x - xOffs, y - font_y_offset * scale, scale, + green ? &alt_color : &rgba_white, true, LEFT); + } + } + + // draw client dogtag + if (!strcmp(token, "dogtag")) { + token = COM_Parse(&s); + + if (!skip_depth) { + value = atoi(token); + if (value >= MAX_CLIENTS || value < 0) + cgi.Com_Error("client >= MAX_CLIENTS"); + + const char *path = va("/tags/%s", cgi.CL_GetClientDogtag(value)); + cgi.SCR_DrawPic(x, y, 198 * scale, 32 * scale, path); + } + } + + if (!strcmp(token, "start_table")) { + token = COM_Parse(&s); + value = atoi(token); + + if (!skip_depth) { + if (value >= q_countof(hud_temp.table_rows[0].table_cells)) + cgi.Com_Error("table too big"); + + hud_temp.num_columns = value; + hud_temp.num_rows = 1; + + for (int i = 0; i < value; i++) + hud_temp.column_widths[i] = 0; + } + + for (int i = 0; i < value; i++) { + token = COM_Parse(&s); + if (!skip_depth) { + token = cgi.Localize(token, nullptr, 0); + Q_strlcpy(hud_temp.table_rows[0].table_cells[i].text, token, + sizeof(hud_temp.table_rows[0].table_cells[i].text)); + hud_temp.column_widths[i] = max(hud_temp.column_widths[i], + (size_t) cgi.SCR_MeasureFontString(hud_temp.table_rows[0]. + table_cells[i].text, scale).x); + } + } + } + + if (!strcmp(token, "table_row")) { + token = COM_Parse(&s); + value = atoi(token); + + if (!skip_depth) { + if (hud_temp.num_rows >= q_countof(hud_temp.table_rows)) { + cgi.Com_Error("table too big"); + return; + } + } + + auto row = &hud_temp.table_rows[hud_temp.num_rows]; + + for (int i = 0; i < value; i++) { + token = COM_Parse(&s); + if (!skip_depth) { + Q_strlcpy(row->table_cells[i].text, token, sizeof(row->table_cells[i].text)); + hud_temp.column_widths[i] = max(hud_temp.column_widths[i], + (size_t) cgi.SCR_MeasureFontString(row->table_cells[i].text, scale). + x); + } + } + + if (!skip_depth) { + for (int i = value; i < hud_temp.num_columns; i++) + row->table_cells[i].text[0] = '\0'; + + hud_temp.num_rows++; + } + } + + if (!strcmp(token, "draw_table")) { + if (!skip_depth) { + // in scaled pixels, incl padding between elements + uint32_t total_inner_table_width = 0; + + for (int i = 0; i < hud_temp.num_columns; i++) { + if (i != 0) + total_inner_table_width += cgi.SCR_MeasureFontString(" ", scale).x; + + total_inner_table_width += hud_temp.column_widths[i]; + } + + // in scaled pixels + uint32_t total_table_height = hud_temp.num_rows * (CONCHAR_WIDTH + font_y_offset) * scale; + + CG_DrawTable(x, y, total_inner_table_width, total_table_height, scale); + } + } + + if (!strcmp(token, "stat_pname")) { + token = COM_Parse(&s); + + if (!skip_depth) { + index = atoi(token); + if (index < 0 || index >= MAX_STATS) + cgi.Com_Error("Bad stat_string index"); + index = ps->stats[index] - 1; + + if (!scr_usekfont->integer) + CG_DrawString(x, y, scale, cgi.CL_GetClientName(index), false, true); + else + cgi.SCR_DrawFontString(cgi.CL_GetClientName(index), x, y - font_y_offset * scale, scale, + &rgba_white, true, LEFT); + } + continue; + } + + if (!strcmp(token, "health_bars")) { + if (skip_depth) + continue; + + const byte *stat = (const byte *) &ps->stats[STAT_HEALTH_BARS]; + const char *name = cgi.Localize(cgi.get_configstring(CONFIG_HEALTH_BAR_NAME), nullptr, 0); + + CG_DrawHUDString(name, (hud_vrect.x + hud_vrect.width / 2 + -160) * scale, y, 320 / 2 * 2 * scale, 0, scale, + true); + + float bar_width = (hud_vrect.width * scale - hud_safe.x * 2) * 0.50f; + float bar_height = 4 * scale; + + y += cgi.SCR_FontLineHeight(scale); + + float x = (hud_vrect.x + hud_vrect.width * 0.5f) * scale - bar_width * 0.5f; + + // 2 health bars, hardcoded + for (size_t i = 0; i < 2; i++, stat++) { + if (!(*stat & 0b10000000)) + continue; + + float percent = (*stat & 0b01111111) / 127.f; + + cgi.SCR_DrawColorPic(x, y, bar_width + scale, bar_height + scale, "_white", &rgba_black); + + if (percent > 0) + cgi.SCR_DrawColorPic(x, y, bar_width * percent, bar_height, "_white", &rgba_red); + + auto col = (rgba_t){.r = 80, .g = 80, .b = 80, .a = 255}; + if (percent < 1) + cgi.SCR_DrawColorPic(x + bar_width * percent, y, bar_width * (1.f - percent), bar_height, "_white", + &col); + + y += bar_height * 3; + } + } + + if (!strcmp(token, "story")) { + const char *story_str = cgi.get_configstring(CONFIG_STORY); + + if (!*story_str) + continue; + + const char *localized = cgi.Localize(story_str, nullptr, 0); + vec2_t size = cgi.SCR_MeasureFontString(localized, scale); + float centerx = (hud_vrect.x + hud_vrect.width * 0.5f) * scale; + float centery = (hud_vrect.y + hud_vrect.height * 0.5f) * scale - size.y * 0.5f; + + cgi.SCR_DrawFontString(localized, centerx, centery, scale, &rgba_white, true, CENTER); + } + } + + if (skip_depth) + cgi.Com_Error("if with no matching endif"); +} + +static cvar_t *cl_skipHud; +static cvar_t *cl_paused; + +/* +================ +CL_DrawInventory +================ +*/ +constexpr size_t DISPLAY_ITEMS = 19; + +static void CG_DrawInventory(const player_state_t *ps, const int16_t inventory[MAX_ITEMS], + const struct vrect_t hud_vrect, const int32_t scale) { + int i; + int index[MAX_ITEMS]; + + const int selected = ps->stats[STAT_SELECTED_ITEM]; + + int num = 0; + int selected_num = 0; + for (i = 0; i < MAX_ITEMS; i++) { + if (i == selected) { + selected_num = num; + } + if (inventory[i]) { + index[num] = i; + num++; + } + } + + // determine scroll point + int top = selected_num - DISPLAY_ITEMS / 2; + if (num - top < DISPLAY_ITEMS) + top = num - DISPLAY_ITEMS; + if (top < 0) + top = 0; + + int x = hud_vrect.x * scale; + int y = hud_vrect.y * scale; + const int width = hud_vrect.width; + const int height = hud_vrect.height; + + x += (width / 2 - 256 / 2) * scale; + y += (height / 2 - 216 / 2) * scale; + + int pich, picw; + cgi.Draw_GetPicSize(&picw, &pich, "inventory"); + cgi.SCR_DrawPic(x, y + 8 * scale, picw * scale, pich * scale, "inventory"); + + y += 27 * scale; + x += 22 * scale; + + for (i = top; i < num && i < top + DISPLAY_ITEMS; i++) { + const int item = index[i]; + if (item == selected) // draw a blinky cursor by the selected item + { + if (cgi.CL_ClientRealTime() * 10 & 1) + cgi.SCR_DrawChar(x - 8, y, scale, 15, false); + } + + if (!scr_usekfont->integer) { + CG_DrawString(x, y, scale, + va("%03d %s", inventory[item], + cgi.Localize(cgi.get_configstring(CS_ITEMS + item), nullptr, 0)), + item == selected, false); + } else { + const char *string = va("%03d", inventory[item]); + cgi.SCR_DrawFontString(string, x + 216 * scale - 16 * scale, y - font_y_offset * scale, scale, + item == selected ? &alt_color : &rgba_white, true, RIGHT); + + string = cgi.Localize(cgi.get_configstring(CS_ITEMS + item), nullptr, 0); + cgi.SCR_DrawFontString(string, x + 16 * scale, y - font_y_offset * scale, scale, + item == selected ? &alt_color : &rgba_white, true, LEFT); + } + + y += 8 * scale; + } +} + +extern uint64_t cgame_init_time; + +void CG_DrawCharge(const player_state_t *ps, struct vrect_t hud_vrect, struct vrect_t hud_safe, int32_t scale) { + const int charge = ps->stats[STAT_CHARGE_LEVEL]; + const int cx = (hud_vrect.width / 2) * scale + hud_safe.x; + const int cy = (hud_vrect.height / 2) * scale + hud_safe.y + 96 * scale; + + if (charge > 0) { + const int charge_width = 100; + const int charge_height = 8 * scale; + CG_DrawString(cx - 3 * CONCHAR_WIDTH * scale, cy - 8 * scale, scale, "charge", false, true); + cgi.SCR_DrawColorPic(cx - charge_width * 0.5f, cy, charge_width, charge_height, "_white", &rgba_black); + cgi.SCR_DrawColorPic(cx - charge_width * 0.5f, cy, charge_width * charge / 100.f, charge_height, "_white", + &rgba_green); + } +} + +void CG_DrawSidebar(const player_state_t *ps, struct vrect_t hud_vrect, struct vrect_t hud_safe, int32_t scale, + int pnum) { + if (!(ps->stats[STAT_LAYOUTS] & LAYOUTS_SIDEBAR)) + return; + + + const char *cs = cgi.get_configstring(CS_GENERAL + 2); + CG_ExecuteLayoutString(cs, hud_vrect, hud_safe, scale, pnum, ps); +} + +void CG_DoExperienceBar(struct vrect_t hud_vrect, int32_t scale, int32_t playernum, const player_state_t *ps) { + const auto hud = &hud_data[playernum]; + const auto xppst = ps->stats[STAT_XP_PERCENT]; + if (hud->next_value != xppst) { + hud->next_value = xppst; + } + + // update last_value at a rate of 10% per sec + const auto rate = INT16_MAX / 10.0f * cgi.frame_time_s; + const auto vdelta = (hud->next_value - hud->last_value); + auto delta = vdelta / rate; + if (delta < 1.00 && vdelta) { + delta = 1.00f; + } + hud->last_value += delta; + + + if (hud->last_value > hud->next_value) { + hud->last_value = hud->next_value; + } + + const float xp_percent = hud->last_value / (float) (INT16_MAX); + const float filling_xp_percent = hud->next_value / (float) (INT16_MAX); + + const float xp_width = hud_vrect.width * scale; + const float xp_height = 8 * scale; + + const float xp_x = hud_vrect.x * scale; + const float xp_y = hud_vrect.height - xp_height; + + cgi.SCR_DrawColorPic(xp_x, xp_y, xp_width, xp_height, "_white", &rgba_black); + cgi.SCR_DrawColorPic(xp_x, xp_y, xp_width * filling_xp_percent, xp_height, "_white", + &rgba_orange); + cgi.SCR_DrawColorPic(xp_x, xp_y, xp_width * xp_percent, xp_height, "_white", &rgba_darkgreen); +} + +void CG_DrawHUD( + const int32_t isplit, + const struct cg_server_data_t *data, + const struct vrect_t hud_vrect, + const struct vrect_t hud_safe, + const int32_t scale, + const int32_t playernum, + const player_state_t *ps) { + if (cgi.CL_InAutoDemoLoop()) { + if (cl_paused->integer) return; // demo is paused, menu is open + + const uint64_t time = cgi.CL_ClientRealTime() - cgame_init_time; + if (time < 20000 && + time % 4000 < 2000) + cgi.SCR_DrawFontString(cgi.Localize("$m_eou_press_button", nullptr, 0), hud_vrect.width * 0.5f * scale, + (hud_vrect.height - 64.f) * scale, scale, &rgba_green, true, CENTER); + return; + } + + const int instant_dmg = ps_instant_dmg_value(ps); + if (instant_dmg) { + hud_data[playernum].dmg_instant = instant_dmg; + hud_data[playernum].dmg_counter += hud_data[playernum].dmg_instant; + hud_data[playernum].last_dmg_time = cgi.CL_ClientTime(); + } + + if (cgi.CL_ClientTime() > hud_data[playernum].last_dmg_time + 2000 && hud_data[playernum].dmg_counter) { + hud_data[playernum].dmg_counter = 0; + hud_data[playernum].dmg_instant = 0; + } + + CG_DoExperienceBar(hud_vrect, scale, playernum, ps); + + // draw HUD + if (!cl_skipHud->integer && !(ps->stats[STAT_LAYOUTS] & LAYOUTS_HIDE_HUD)) { + const auto sbar = cgi.get_configstring(CS_STATUSBAR); + CG_ExecuteLayoutString(sbar, hud_vrect, hud_safe, scale, playernum, ps); + } + + // draw centerprint string + CG_CheckDrawCenterString(ps, hud_vrect, hud_safe, isplit, scale); + + // draw notify + CG_DrawNotify(isplit, hud_vrect, hud_safe, scale); + + CG_DrawCharge(ps, hud_vrect, hud_safe, scale); + CG_DrawSidebar(ps, hud_vrect, hud_safe, scale, isplit); + + // svc_layout still drawn with hud off + if (ps->stats[STAT_LAYOUTS] & LAYOUTS_LAYOUT) + CG_ExecuteLayoutString(data->layout, hud_vrect, hud_safe, scale, playernum, ps); + + // inventory too + if (ps->stats[STAT_LAYOUTS] & LAYOUTS_INVENTORY) + CG_DrawInventory(ps, data->inventory, hud_vrect, scale); +} + +/* +================ +CG_TouchPics + +================ +*/ +void CG_TouchPics() { + for (int i = 0; i < 2; i++) + for (int j = 0; j < 11; j++) + cgi.Draw_RegisterPic(sb_nums[i][j]); + + cgi.Draw_RegisterPic("inventory"); + + font_y_offset = (cgi.SCR_FontLineHeight(1) - CONCHAR_WIDTH) / 2; +} + +void CG_InitScreen() { + cl_paused = cgi.cvar("paused", "0", CVAR_NOFLAGS); + cl_skipHud = cgi.cvar("cl_skipHud", "0", CVAR_ARCHIVE); + scr_usekfont = cgi.cvar("scr_usekfont", "1", CVAR_NOFLAGS); + + scr_centertime = cgi.cvar("scr_centertime", "5.0", CVAR_ARCHIVE); // [Sam-KEX] Changed from 2.5 + scr_printspeed = cgi.cvar("scr_printspeed", "0.04", CVAR_NOFLAGS); // [Sam-KEX] Changed from 8 + cl_notifytime = cgi.cvar("cl_notifytime", "5.0", CVAR_ARCHIVE); + scr_maxlines = cgi.cvar("scr_maxlines", "4", CVAR_ARCHIVE); + ui_acc_contrast = cgi.cvar("ui_acc_contrast", "0", CVAR_NOFLAGS); + ui_acc_alttypeface = cgi.cvar("ui_acc_alttypeface", "0", CVAR_NOFLAGS); + + memset(&hud_data, 0, sizeof(hud_data)); + for (int i = 0; i < MAX_SPLIT_PLAYERS; i++) + hud_data[i].center_index = -1; +} diff --git a/src/characters/Player.c b/src/characters/Player.c index 7b332e4c..19c19dad 100644 --- a/src/characters/Player.c +++ b/src/characters/Player.c @@ -5,11 +5,11 @@ // returns true if the player should be affected by newbie protection qboolean vrx_is_newbie_basher(const edict_t *player) { - qboolean levelAboveAverage = player->myskills.level > newbie_protection->value * AveragePlayerLevel(); - qboolean isHighLevel = player->myskills.level >= 8; - qboolean isNotPVM = !(pvm->value != 0 || invasion->value != 0); - qboolean situationRequestsProtection = newbie_protection->value && player->client && (vrx_get_joined_players(true) > 1); - qboolean levelQualifies = isHighLevel && levelAboveAverage; + const qboolean levelAboveAverage = player->myskills.level > newbie_protection->value * AveragePlayerLevel(); + const qboolean isHighLevel = player->myskills.level >= 8; + const qboolean isNotPVM = !(pvm->value != 0 || invasion->value != 0); + const qboolean situationRequestsProtection = newbie_protection->value && player->client && (vrx_get_joined_players(true) > 1); + const qboolean levelQualifies = isHighLevel && levelAboveAverage; return (situationRequestsProtection && isNotPVM && levelQualifies); } diff --git a/src/characters/Talents.c b/src/characters/Talents.c index 08960a8f..6c4c0169 100644 --- a/src/characters/Talents.c +++ b/src/characters/Talents.c @@ -149,7 +149,7 @@ const talentclasslist_t talents_by_class[] = { * @param maxLevel max level of the talent */ void vrx_add_talent(edict_t *ent, int talentID, int maxLevel) { - int nextEmptySlot = ent->myskills.talents.count; + const int nextEmptySlot = ent->myskills.talents.count; int i = 0; //Don't add too many talents. @@ -173,11 +173,11 @@ void vrx_add_talent(edict_t *ent, int talentID, int maxLevel) { /// \param talentID talent id to remove /// \return number of points the talent was upgraded int vrx_remove_talent(edict_t *ent, int talentID) { - int count = ent->myskills.talents.count; + const int count = ent->myskills.talents.count; int ret = 0; for (int i = 0; i < count; i++) { - talent_t *player_talent = &ent->myskills.talents.talent[i]; + const talent_t *player_talent = &ent->myskills.talents.talent[i]; if (player_talent->id != talentID) { continue; } @@ -280,7 +280,7 @@ int vrx_get_talent_level(const edict_t *ent, int talentID) { //Upgrades the talent with a matching talentID void vrx_upgrade_talent(edict_t *ent, int talentID) { - int slot = vrx_get_talent_slot(ent, talentID); + const int slot = vrx_get_talent_slot(ent, talentID); talent_t *talent; if (slot == -1) @@ -344,7 +344,7 @@ void TalentUpgradeMenu_handler(edict_t *ent, int option) { OpenTalentUpgradeMenu(ent, vrx_get_talent_slot(ent, option - 1) + 1); } else //upgrading { - int talentID = (option * -1) - 1; + const int talentID = (option * -1) - 1; // upgrade the talent vrx_upgrade_talent(ent, talentID); // refresh the menu @@ -692,8 +692,8 @@ int writeTalentDescription(edict_t *ent, int talentID) { void vrx_open_talent_menu(edict_t *ent, int talentID, qboolean select_upgrade) { talent_t* talent;// = &ent->myskills.talents.talent[vrx_get_talent_slot(ent, talentID)]; int level;// = talent->upgradeLevel; - int slot = vrx_get_talent_slot(ent, talentID); - int talentPoints = ent->myskills.talents.talentPoints; + const int slot = vrx_get_talent_slot(ent, talentID); + const int talentPoints = ent->myskills.talents.talentPoints; int lineCount = 7;//12; qboolean can_upgrade = false; @@ -806,7 +806,7 @@ void V_UpdatePlayerTalents(edict_t *ent) { // see differences between class talents and player talents for (int i = 0; i < ent->myskills.talents.count; ++i) { - int talentId = ent->myskills.talents.talent[i].id; + const int talentId = ent->myskills.talents.talent[i].id; talent_t *player_talent = &ent->myskills.talents.talent[i]; const talentdef_t *class_talent = NULL; @@ -835,7 +835,7 @@ void V_UpdatePlayerTalents(edict_t *ent) { // upgrade level past max level if (player_talent->upgradeLevel > player_talent->maxLevel) { - int difference = player_talent->upgradeLevel - player_talent->maxLevel; + const int difference = player_talent->upgradeLevel - player_talent->maxLevel; player_talent->upgradeLevel -= difference; refunded += difference; } @@ -846,7 +846,7 @@ void V_UpdatePlayerTalents(edict_t *ent) { for (const talentdef_t* talent = talents_by_class[ent->myskills.class_num]; talent->talent_id != -1; talent++) { - int talentLevel = vrx_get_talent_slot(ent, talent->talent_id); + const int talentLevel = vrx_get_talent_slot(ent, talent->talent_id); if (talentLevel == -1) { // not found vrx_add_talent(ent, talent->talent_id, talent->max_level); } diff --git a/src/characters/class_limits.c b/src/characters/class_limits.c index 1c382684..41c6f2b0 100644 --- a/src/characters/class_limits.c +++ b/src/characters/class_limits.c @@ -4,7 +4,7 @@ #pragma clang diagnostic push #pragma ide diagnostic ignored "cppcoreguidelines-narrowing-conversions" -int MAX_ARMOR(struct edict_s *ent) { +int MAX_ARMOR(const struct edict_s *ent) { int vitlvl = 0; int talentlevel; int value; @@ -136,37 +136,37 @@ int MAX_HEALTH(const edict_t *ent) { return value; } -int MAX_BULLETS(struct edict_s *ent) { +int MAX_BULLETS(const struct edict_s *ent) { if (ent->myskills.abilities[MAX_AMMO].disable) return 0; return (100 * ent->myskills.abilities[MAX_AMMO].current_level); } -int MAX_SHELLS(struct edict_s *ent) { +int MAX_SHELLS(const struct edict_s *ent) { if (ent->myskills.abilities[MAX_AMMO].disable) return 0; return (50 * ent->myskills.abilities[MAX_AMMO].current_level); } -int MAX_ROCKETS(struct edict_s *ent) { +int MAX_ROCKETS(const struct edict_s *ent) { if (ent->myskills.abilities[MAX_AMMO].disable) return 0; return (25 * ent->myskills.abilities[MAX_AMMO].current_level); } -int MAX_GRENADES(struct edict_s *ent) { +int MAX_GRENADES(const struct edict_s *ent) { if (ent->myskills.abilities[MAX_AMMO].disable) return 0; return (25 * ent->myskills.abilities[MAX_AMMO].current_level); } -int MAX_CELLS(struct edict_s *ent) { +int MAX_CELLS(const struct edict_s *ent) { if (ent->myskills.abilities[MAX_AMMO].disable) return 0; return (100 * ent->myskills.abilities[MAX_AMMO].current_level); } -int MAX_SLUGS(struct edict_s *ent) { +int MAX_SLUGS(const struct edict_s *ent) { if (ent->myskills.abilities[MAX_AMMO].disable) return 0; return (25 * ent->myskills.abilities[MAX_AMMO].current_level); @@ -175,7 +175,7 @@ int MAX_SLUGS(struct edict_s *ent) { #pragma clang diagnostic push #pragma ide diagnostic ignored "cppcoreguidelines-narrowing-conversions" -int MAX_POWERCUBES(struct edict_s *ent) { +int MAX_POWERCUBES(const struct edict_s *ent) { int value = 100, clvl; if (ent->myskills.abilities[MAX_AMMO].disable) diff --git a/src/characters/class_limits.h b/src/characters/class_limits.h index 33ad56a5..c16e3261 100644 --- a/src/characters/class_limits.h +++ b/src/characters/class_limits.h @@ -4,24 +4,24 @@ #define INITIAL_HEALTH_FC 200 #define ADDON_HEALTH_FC 30 -int MAX_ARMOR(struct edict_s *ent); +int MAX_ARMOR( const struct edict_s *ent); int MAX_HEALTH(const struct edict_s *ent); -int MAX_BULLETS(struct edict_s *ent); +int MAX_BULLETS(const struct edict_s *ent); -int MAX_SHELLS(struct edict_s *ent); +int MAX_SHELLS(const struct edict_s *ent); -int MAX_ROCKETS(struct edict_s *ent); +int MAX_ROCKETS(const struct edict_s *ent); -int MAX_GRENADES(struct edict_s *ent); +int MAX_GRENADES(const struct edict_s *ent); -int MAX_CELLS(struct edict_s *ent); +int MAX_CELLS(const struct edict_s *ent); -int MAX_SLUGS(struct edict_s *ent); +int MAX_SLUGS(const struct edict_s *ent); -int MAX_POWERCUBES(struct edict_s *ent); +int MAX_POWERCUBES(const struct edict_s *ent); -int MAX_POWERCUBES(struct edict_s *ent); +int MAX_POWERCUBES(const struct edict_s *ent); #endif //VORTEXQUAKE2_CLASS_LIMITS_H diff --git a/src/characters/class_skin.c b/src/characters/class_skin.c index 2a9589b2..81d0a77b 100644 --- a/src/characters/class_skin.c +++ b/src/characters/class_skin.c @@ -69,7 +69,7 @@ char *V_GetClassSkin(edict_t *ent) { } qboolean vrx_assign_character_skin(edict_t *ent, char *s) { - int playernum = ent - g_edicts - 1; + const int playernum = ent - g_edicts - 1; char *p; char t[64]; char *c_skin; diff --git a/src/characters/io/v_characterio.c b/src/characters/io/v_characterio.c index bab2864c..46d9ca41 100644 --- a/src/characters/io/v_characterio.c +++ b/src/characters/io/v_characterio.c @@ -17,7 +17,7 @@ void vrx_init_char_io() { return; } - int method = savemethod->value; + const int method = savemethod->value; switch (method) { #ifndef NO_GDS case SAVEMETHOD_MYSQL: @@ -37,7 +37,7 @@ void vrx_init_char_io() { void vrx_close_char_io() { memset(&vrx_char_io, 0, sizeof vrx_char_io); - int method = savemethod->value; + const int method = savemethod->value; switch (method) { #ifndef NO_GDS case 2: @@ -65,7 +65,7 @@ void vrx_notify_owner_nonexistent(void* args) void vrx_notify_owner_bad_password(void* args) { - event_owner_error_t* evt = args; + const event_owner_error_t* evt = args; if (evt->connection_id != evt->ent->gds_connection_id) { return; @@ -76,7 +76,7 @@ void vrx_notify_owner_bad_password(void* args) void vrx_notify_owner_success(void* args) { - event_owner_error_t* evt = args; + const event_owner_error_t* evt = args; if (evt->connection_id != evt->ent->gds_connection_id) { return; diff --git a/src/characters/io/v_memory.c b/src/characters/io/v_memory.c new file mode 100644 index 00000000..58091e56 --- /dev/null +++ b/src/characters/io/v_memory.c @@ -0,0 +1,42 @@ +#include "../../g_local.h" +#include "gds.h" + +#include + +static pthread_once_t mem_mutex_once = PTHREAD_ONCE_INIT; +static pthread_mutex_t mem_mutex_free; +static pthread_mutex_t mem_mutex_malloc; + +static void vrx_prepare_memory_mutexes(void) +{ + pthread_mutex_init(&mem_mutex_malloc, NULL); + pthread_mutex_init(&mem_mutex_free, NULL); +} + +void Mem_PrepareMutexes() +{ + pthread_once(&mem_mutex_once, vrx_prepare_memory_mutexes); +} + +void *vrx_malloc(size_t Size, int Tag) +{ + void *memory; + + Mem_PrepareMutexes(); + pthread_mutex_lock(&mem_mutex_malloc); + memory = gi.TagMalloc(Size, Tag); + pthread_mutex_unlock(&mem_mutex_malloc); + + return memory; +} + +void vrx_free(void *mem) +{ + if (!mem) + return; + + Mem_PrepareMutexes(); + pthread_mutex_lock(&mem_mutex_free); + gi.TagFree(mem); + pthread_mutex_unlock(&mem_mutex_free); +} diff --git a/src/characters/io/v_mysql_gds.c b/src/characters/io/v_mysql_gds.c index 3c2d9c0b..96198a56 100644 --- a/src/characters/io/v_mysql_gds.c +++ b/src/characters/io/v_mysql_gds.c @@ -7,8 +7,6 @@ static pthread_t QueueThread; static pthread_attr_t attr; static pthread_mutex_t mutex_gds_queue; -static pthread_mutex_t MemMutex_Free; -static pthread_mutex_t MemMutex_Malloc; static pthread_mutex_t mutex_gds_thread_status; #ifndef NO_GDS @@ -1977,21 +1975,3 @@ void gds_finish_thread() { #endif // NO_GDS -void Mem_PrepareMutexes() { - pthread_mutex_init(&MemMutex_Malloc, NULL); - pthread_mutex_init(&MemMutex_Free, NULL); -} - -void *vrx_malloc(size_t Size, int Tag) { - void *Memory; - pthread_mutex_lock(&MemMutex_Malloc); - Memory = gi.TagMalloc(Size, Tag); - pthread_mutex_unlock(&MemMutex_Malloc); - return Memory; -} - -void vrx_free(void *mem) { - pthread_mutex_lock(&MemMutex_Free); - gi.TagFree(mem); - pthread_mutex_unlock(&MemMutex_Free); -} diff --git a/src/characters/io/v_sqlite_unidb.c b/src/characters/io/v_sqlite_unidb.c index 6c19d431..d27a8de3 100644 --- a/src/characters/io/v_sqlite_unidb.c +++ b/src/characters/io/v_sqlite_unidb.c @@ -92,22 +92,35 @@ const char* VSFU_UPDATEPDATA = "UPDATE point_data SET exp=%d, exptnl=%d, level=% const char* VSFU_UPDATECTFSTATS = "UPDATE ctf_stats SET flag_pickups=%d, flag_captures=%d, flag_returns=%d, flag_kills=%d, offense_kills=%d, defense_kills=%d, assists=%d WHERE char_idx=%d;"; -#define CHECK_ERR_RETURN() if(r!=SQLITE_OK){ if(r != SQLITE_ROW && r != SQLITE_OK && r != SQLITE_DONE){gi.dprintf("sqlite error %d: %s\n", r, sqlite3_errmsg(db));return false;}} -#define CHECK_ERR() if(r!=SQLITE_OK){ if(r != SQLITE_ROW && r != SQLITE_OK && r != SQLITE_DONE){gi.dprintf("sqlite error %d: %s\n", r, sqlite3_errmsg(db));}} +#define SQLITE_ERR_OK(r) ((r) == SQLITE_OK || (r) == SQLITE_ROW || (r) == SQLITE_DONE) +#define CHECK_ERR_RETURN_FALSE() { if (!SQLITE_ERR_OK(r)) { gi.dprintf("sqlite error %d: %s\n", r, sqlite3_errmsg(db)); return false; } } +#define CHECK_ERR_RETURN() { if (!SQLITE_ERR_OK(r)) { gi.dprintf("sqlite error %d: %s\n", r, sqlite3_errmsg(db)); return; } } +#define CHECK_ERR() { if (!SQLITE_ERR_OK(r)) { gi.dprintf("sqlite error %d: %s\n", r, sqlite3_errmsg(db)); } } -#define QUERY(x) { char* format=x;\ +#define QUERY(x) { const char* format = (x); \ sqlite3_stmt* statement; \ int r = sqlite3_prepare_v2(db, format, strlen(format), &statement, NULL); \ - CHECK_ERR_RETURN()\ + CHECK_ERR_RETURN_FALSE(); \ r = sqlite3_step(statement); \ - CHECK_ERR_RETURN()\ - sqlite3_finalize(statement); } + CHECK_ERR_RETURN_FALSE(); \ + sqlite3_finalize(statement); \ +} + +#define QUERY_VOID(x) { const char* format = (x); \ + sqlite3_stmt* statement; \ + int r = sqlite3_prepare_v2(db, format, strlen(format), &statement, NULL); \ + CHECK_ERR_RETURN(); \ + r = sqlite3_step(statement); \ + CHECK_ERR_RETURN(); \ + sqlite3_finalize(statement); \ +} -#define QUERY_RESULT(x) { char* format=x;\ - r=sqlite3_prepare_v2(db, format, strlen(format), &statement, NULL);\ - CHECK_ERR()\ - r=sqlite3_step(statement);\ - CHECK_ERR()} +#define QUERY_RESULT(x) { const char* format = (x); \ + r = sqlite3_prepare_v2(db, format, strlen(format), &statement, NULL); \ + CHECK_ERR(); \ + r = sqlite3_step(statement); \ + CHECK_ERR(); \ +} #define DEFAULT_PATH va("%s/settings/characters.db", game_path->string) sqlite3* db = NULL; @@ -115,12 +128,12 @@ sqlite3* db = NULL; void cdb_begin_tran(sqlite3* db) { - QUERY("BEGIN TRANSACTION;"); + QUERY_VOID("BEGIN TRANSACTION;"); } void cdb_commit_tran(sqlite3* db) { - QUERY("COMMIT;") + QUERY_VOID("COMMIT;"); } int cdb_get_id(char* playername) @@ -128,7 +141,7 @@ int cdb_get_id(char* playername) sqlite3_stmt* stmt; int r, id; - char sql[] = "SELECT char_idx FROM userdata WHERE playername=?"; + const char sql[] = "SELECT char_idx FROM userdata WHERE playername=?"; sqlite3_prepare_v2(db, sql, sizeof sql, &stmt, NULL); sqlite3_bind_text(stmt, 1, playername, strlen(playername), SQLITE_STATIC); r = sqlite3_step(stmt); @@ -145,10 +158,10 @@ int cdb_get_id(char* playername) } // az begin -void cdb_save_runes(edict_t* player) +qboolean cdb_save_runes(edict_t* player) { - int numRunes = CountRunes(player); - int id = cdb_get_id(player->client->pers.netname); + const int numRunes = CountRunes(player); + const int id = cdb_get_id(player->client->pers.netname); cdb_begin_tran(db); @@ -158,7 +171,7 @@ void cdb_save_runes(edict_t* player) //begin runes for (int i = 0; i < numRunes; ++i) { - int index = FindRuneIndex(i + 1, player); + const int index = FindRuneIndex(i + 1, player); if (index != -1) { QUERY(va(VSFU_INSERTRMETA, @@ -198,6 +211,7 @@ void cdb_save_runes(edict_t* player) //end runes cdb_commit_tran(db); + return true; } int cdb_make_id() @@ -485,7 +499,7 @@ qboolean cdb_save_player(edict_t* player) qboolean cdb_saveclose_player(edict_t* player) { - int id = cdb_get_id(player->client->pers.netname); + const int id = cdb_get_id(player->client->pers.netname); cdb_save_player(player); QUERY(va("update stash set lock_char_id = NULL where lock_char_id=%d", id)); @@ -848,9 +862,9 @@ qboolean cdb_load_player(edict_t* player) r = sqlite3_prepare_v2(db, format, strlen(format), &statement, NULL); while(sqlite3_step(statement) == SQLITE_ROW) { - int pindex = sqlite3_column_int(statement, 1); - int param = sqlite3_column_int(statement, 2); - int level = sqlite3_column_int(statement, 3); + const int pindex = sqlite3_column_int(statement, 1); + const int param = sqlite3_column_int(statement, 2); + const int level = sqlite3_column_int(statement, 3); switch (pindex) { @@ -893,7 +907,7 @@ qboolean cdb_load_player(edict_t* player) } int cdb_get_owner_id (edict_t* ent) { - char sql[] = + const char sql[] = "select char_idx from userdata " "where playername = (select owner from userdata where playername = :1) " "or (playername = :1 and email is not null and LENGTH(email) > 0)"; @@ -916,7 +930,7 @@ int cdb_get_owner_id (edict_t* ent) { qboolean cdb_stash_store(edict_t* ent, int itemindex) { - int owner_id = cdb_get_owner_id(ent); + const int owner_id = cdb_get_owner_id(ent); if (owner_id == -1) { stash_event_t* notif = vrx_malloc(sizeof(stash_event_t), TAG_GAME); @@ -942,7 +956,7 @@ qboolean cdb_stash_store(edict_t* ent, int itemindex) while (r == SQLITE_ROW) { - int index_result = sqlite3_column_int(statement, 0); + const int index_result = sqlite3_column_int(statement, 0); // we found a free slot if (index < index_result) @@ -991,7 +1005,7 @@ qboolean cdb_stash_store(edict_t* ent, int itemindex) qboolean cdb_stash_get_page(edict_t* ent, int page_index, int items_per_page) { - int owner_id = cdb_get_owner_id(ent); + const int owner_id = cdb_get_owner_id(ent); stash_page_event_t* evt = vrx_malloc(sizeof(stash_page_event_t), TAG_GAME); evt->gds_connection_id = ent->gds_connection_id; evt->gds_owner_id = owner_id; @@ -1090,7 +1104,7 @@ qboolean cdb_stash_get_page(edict_t* ent, int page_index, int items_per_page) qboolean cdb_stash_open(edict_t* ent) { - int owner_id = cdb_get_owner_id(ent); + const int owner_id = cdb_get_owner_id(ent); if (owner_id == -1) { stash_event_t* notif = vrx_malloc(sizeof(stash_event_t), TAG_GAME); @@ -1126,7 +1140,7 @@ qboolean cdb_stash_open(edict_t* ent) sqlite3_finalize(statement); } - int id = cdb_get_id(ent->client->pers.netname); + const int id = cdb_get_id(ent->client->pers.netname); QUERY(va("update stash set lock_char_id=%d where char_idx=%d", id, owner_id)); cdb_stash_get_page(ent, 0, sizeof ent->client->stash.page / sizeof(item_t)); @@ -1141,14 +1155,14 @@ qboolean cdb_stash_close_id(int owner_id) qboolean cdb_stash_close(edict_t* ent) { - int owner_id = cdb_get_owner_id(ent); + const int owner_id = cdb_get_owner_id(ent); cdb_stash_close_id(owner_id); return true; } void cdb_set_owner(edict_t* ent, char* owner_name, char* masterpw, qboolean reset) { - int new_owner_id = cdb_get_id(owner_name); + const int new_owner_id = cdb_get_id(owner_name); event_owner_error_t* evt = vrx_malloc(sizeof(event_owner_error_t), TAG_GAME); strcpy(evt->owner_name, owner_name); @@ -1157,11 +1171,11 @@ void cdb_set_owner(edict_t* ent, char* owner_name, char* masterpw, qboolean rese // if reset is true, make a sqlite query that resets the owner to null if (reset) { - int id = cdb_get_id(ent->client->pers.netname); + const int id = cdb_get_id(ent->client->pers.netname); sqlite3_stmt* statement; int r; - char sql[] = "update userdata " + const char sql[] = "update userdata " "set owner = '' " "where char_idx = ?"; @@ -1184,11 +1198,11 @@ void cdb_set_owner(edict_t* ent, char* owner_name, char* masterpw, qboolean rese return; } - int id = cdb_get_id(ent->client->pers.netname); + const int id = cdb_get_id(ent->client->pers.netname); sqlite3_stmt* statement; int r; - char sql[] = "update userdata " + const char sql[] = "update userdata " "set owner = ? " "from (select 1 as e from userdata o " " where " @@ -1208,7 +1222,7 @@ void cdb_set_owner(edict_t* ent, char* owner_name, char* masterpw, qboolean rese sqlite3_step(statement); sqlite3_finalize(statement); - int rows = sqlite3_changes(db); + const int rows = sqlite3_changes(db); if (rows == 0) { vrx_notify_owner_bad_password(evt); vrx_free(evt); @@ -1221,8 +1235,8 @@ void cdb_set_owner(edict_t* ent, char* owner_name, char* masterpw, qboolean rese qboolean cdb_stash_take(edict_t* ent, int stash_index) { - int owner_id = cdb_get_owner_id(ent); - int id = cdb_get_id(ent->client->pers.netname); + const int owner_id = cdb_get_owner_id(ent); + const int id = cdb_get_id(ent->client->pers.netname); // check if we're the owners of the stash before taking { @@ -1230,7 +1244,7 @@ qboolean cdb_stash_take(edict_t* ent, int stash_index) int r; QUERY_RESULT(va("select char_idx from stash where lock_char_id=%d", id)); - qboolean got_result = r == SQLITE_ROW; + const qboolean got_result = r == SQLITE_ROW; qboolean someone_else_locked_it = false; if (got_result) @@ -1348,7 +1362,7 @@ void cdb_start_connection() { for (i = 0; i < TOTAL_TABLES; i++) { - QUERY(va(VSFU_CREATEDBQUERY[i])) + QUERY_VOID(va(VSFU_CREATEDBQUERY[i])); } } diff --git a/src/characters/player_points.c b/src/characters/player_points.c index e319bf63..abfecb2f 100644 --- a/src/characters/player_points.c +++ b/src/characters/player_points.c @@ -77,13 +77,13 @@ double vrx_get_points_tnl (int level) { long tnl = 0; // this is the top of our sigmoid 'S' curve, where it becomes asymptotic - long max_exp_tnl = 50000; + const long max_exp_tnl = 50000; // note: for loop below can be removed to make curve more 'S' like than current exponential curve by changing the max_exp_tnl, e.g. 250000 // for reference, the old system would return 149K TNL at level 20, whereas this one returns 546K for (int i = 0; i <= level; i++) { // this is the 'x' input value into the sigmoid function that allows up to determine which part of the curve to utilize - double x = i - 5 - (0.5 * i); + const double x = i - 5 - (0.5 * i); tnl += (long)(sigmoid(x) * max_exp_tnl) + 1000; //gi.dprintf("%i x: %f tnl: %d\n", i, x, tnl); } @@ -138,6 +138,28 @@ double vrx_get_points_tnl(int level) { } #endif +// xptbl[i] = exp to get to level i +static uint32_t xptbl[MAX_LEVEL] = {0}; +void vrx_fill_xp_accum_table() { + for (int i = 1; i < MAX_LEVEL; i++) { + xptbl[i] = xptbl[i - 1] + vrx_get_points_tnl(i - 1); + } +} + +int16_t vrx_get_xp_percent(long xp, int level) { + if (level == MAX_LEVEL || level < 0) + return INT16_MAX; + + const auto difference = xp - xptbl[level]; + const auto range = xptbl[level + 1] - xptbl[level]; + const auto ratio = difference / (double) range; + + if (difference < 0) + return 0; + + return ratio * INT16_MAX; +} + void vrx_check_for_levelup(edict_t *ent, qboolean print_message) { qboolean levelup = false; @@ -148,14 +170,14 @@ void vrx_check_for_levelup(edict_t *ent, qboolean print_message) { levelup = true; // maximum level cap - if (!ent->myskills.administrator && ent->myskills.level >= 50) // cap to 50 + if (!ent->myskills.administrator && ent->myskills.level >= MAX_LEVEL) // cap to 50 { ent->myskills.next_level = ent->myskills.experience; return; } ent->myskills.level++; - double points_needed = vrx_get_points_tnl(ent->myskills.level); + const double points_needed = vrx_get_points_tnl(ent->myskills.level); ent->myskills.next_level += points_needed; @@ -178,7 +200,7 @@ void vrx_check_for_levelup(edict_t *ent, qboolean print_message) { } // maximum level cap - if (!ent->myskills.administrator && ent->myskills.level >= 50) { + if (!ent->myskills.administrator && ent->myskills.level >= MAX_LEVEL) { ent->myskills.next_level = ent->myskills.experience; break; } @@ -223,8 +245,8 @@ void vrx_trigger_spree_abilities(edict_t *attacker) { // otherwise the player will keep getting 10 seconds of quad/invuln //New quad/invin duration variables - int base_duration = 5 / FRAMETIME; //5 seconds - int kill_duration = 0.5 / FRAMETIME; //0.5 seconds per kill + const int base_duration = 5 / FRAMETIME; //5 seconds + const int kill_duration = 0.5 / FRAMETIME; //0.5 seconds per kill if (!attacker->client) return; @@ -395,7 +417,7 @@ int vrx_get_kill_base_experience( // apply the damage mod? if (dmgmod_out) { // calculate damage modifier - float damage = GetPlayerBossDamage(attacker, targ); + const float damage = GetPlayerBossDamage(attacker, targ); if (damage < 1) { // az: EVERYONE. I MEAN EVERYONE GETS A BONUS. EVERYONE!! @@ -516,7 +538,7 @@ int vrx_award_exp(edict_t *attacker, edict_t *targ, edict_t *targetclient, int b void vrx_inv_award_curse_exp( edict_t *attacker, edict_t *targ, edict_t *targetclient, que_t *que, int type, float mult, qboolean is_blessing ) { int leveldiff = 0, exp = 0, credits = 0; - que_t *slot = NULL; + const que_t *slot = NULL; edict_t *assister = NULL; if ((slot = que_findtype(que, NULL, type)) != NULL) { @@ -572,7 +594,7 @@ void vrx_inv_award_cooldown_exp( edict_t *attacker, edict_t *targ, edict_t *targ void vrx_inv_award_totem_exp( edict_t *attacker, edict_t *targ, edict_t *targetclient, int type, float mult, qboolean is_allied ) { int exp = 0, credits = 0, leveldiff = 0; - edict_t *totem = NULL; + const edict_t *totem = NULL; if ( is_allied ) { totem = NextNearestTotem(attacker, type, NULL, true); @@ -610,7 +632,7 @@ void vrx_inv_award_exp(edict_t *attacker, edict_t *targ, edict_t *targetclient) float player_cnt = 0; float dmgmod = 0; que_t *slot = NULL; - qboolean attacker_was_null = attacker == NULL; + const qboolean attacker_was_null = attacker == NULL; for (i = 1; i <= maxclients->value; i++) { player = &g_edicts[i]; @@ -777,7 +799,7 @@ void vrx_get_player_kill_xp( int *break_points, float *bonus) { - qboolean is_mini = vrx_is_newbie_basher(target); + const qboolean is_mini = vrx_is_newbie_basher(target); // spree break bonus points if (target->myskills.streak >= SPREE_START) (*break_points) = SPREE_BREAKBONUS; @@ -961,7 +983,7 @@ void vrx_process_exp(edict_t *attacker, edict_t *targ) { // give your team some experience if ((int) (dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS)) { - int exp_points = vrx_award_exp(attacker, targ, targetclient, 0); + const int exp_points = vrx_award_exp(attacker, targ, targetclient, 0); vrx_add_team_exp(attacker, (int) (0.5 * exp_points)); return; } diff --git a/src/characters/prestige.c b/src/characters/prestige.c index 0816e602..e63b3ed0 100644 --- a/src/characters/prestige.c +++ b/src/characters/prestige.c @@ -36,7 +36,7 @@ uint32_t vrx_prestige_get_upgrade_points(uint32_t exp) { } qboolean vrx_prestige_filter_class_skill(const abilitydef_t *pAbility, void *user) { - edict_t *pUser = user; + const edict_t *pUser = user; // general skills cannot become class skills if (pAbility->general) @@ -54,7 +54,7 @@ qboolean vrx_prestige_filter_class_skill(const abilitydef_t *pAbility, void *use } qboolean vrx_prestige_filter_softmax_bump(const abilitydef_t *pAbility, void *user) { - edict_t *pUser = user; + const edict_t *pUser = user; if (pAbility->softmax != DEFAULT_SOFTMAX) return false; @@ -135,7 +135,7 @@ void vrx_prestige_ascend(edict_t *self) { return; // check how many levels the player can ascend - int upgradePoints = vrx_prestige_get_upgrade_points(self->myskills.experience); + const int upgradePoints = vrx_prestige_get_upgrade_points(self->myskills.experience); // add the upgrade points to the player's prestige total and current self->myskills.prestige.total += upgradePoints; @@ -206,7 +206,7 @@ void vrx_prestige_open_menu(edict_t *self) { menu_add_line(self, va("Prestige %d", self->myskills.prestige.total), MENU_GREEN_CENTERED); menu_add_line(self, va("You have %d points available", self->myskills.prestige.points), MENU_WHITE_CENTERED); - int rem = self->myskills.experience % PRESTIGE_THRESHOLD; + const int rem = self->myskills.experience % PRESTIGE_THRESHOLD; menu_add_line(self, va("%d xp until next point", PRESTIGE_THRESHOLD - rem), MENU_WHITE_CENTERED); if (self->myskills.prestige.creditLevel) { @@ -221,7 +221,7 @@ void vrx_prestige_open_menu(edict_t *self) { menu_add_line(self, prestige[i].name, prestige[i].id); } - int upgradePoints = self->myskills.experience / PRESTIGE_THRESHOLD; + const int upgradePoints = self->myskills.experience / PRESTIGE_THRESHOLD; menu_add_line(self, " ", 0); if (upgradePoints) { @@ -236,8 +236,8 @@ void vrx_prestige_open_menu(edict_t *self) { } qboolean vrx_prestige_has_ability(struct prestigelist_s *pre, uint32_t abIndex) { - uint32_t arrIdx = abIndex / 32; - uint32_t mask = 1 << (abIndex % 32); + const uint32_t arrIdx = abIndex / 32; + const uint32_t mask = 1 << (abIndex % 32); return (pre->classSkill[arrIdx] & mask) != 0; } @@ -254,7 +254,7 @@ void vrx_prestige_reapply_abilities(edict_t* self) { // must be applied after abilities void vrx_prestige_reapply_all(edict_t *self) { - struct prestigelist_s *pre = &self->myskills.prestige; + const struct prestigelist_s *pre = &self->myskills.prestige; self->myskills.speciality_points += pre->abilityPoints; self->myskills.weapon_points += pre->weaponPoints * 4; @@ -262,7 +262,7 @@ void vrx_prestige_reapply_all(edict_t *self) { } qboolean vrx_prestige_has_class_skills(edict_t *self) { - int size = sizeof(self->myskills.prestige.classSkill) / sizeof(self->myskills.prestige.classSkill[0]); + const int size = sizeof(self->myskills.prestige.classSkill) / sizeof(self->myskills.prestige.classSkill[0]); for (uint32_t i = 0; i < size; i++) { if (self->myskills.prestige.classSkill[i]) return true; diff --git a/src/characters/v_abilitylist.c b/src/characters/v_abilitylist.c index 045bfe4b..af0d6258 100644 --- a/src/characters/v_abilitylist.c +++ b/src/characters/v_abilitylist.c @@ -1,6 +1,6 @@ #include "g_local.h" -abilitydef_t *abilities_by_index[MAX_ABILITIES]; +const abilitydef_t *abilities_by_index[MAX_ABILITIES]; uint8_t ability_class[MAX_ABILITIES][CLASS_MAX]; // whether ability i is in character class k (1 or 0) const abilitydef_t ability_general[] = { @@ -211,8 +211,7 @@ void vrx_assign_abilities(edict_t *ent) { // enable all skills (weaponmaster/ab or generalabmode is on) if (ent->myskills.class_num == CLASS_WEAPONMASTER || generalabmode->value) { - int i; - for (i = 0; i < MAX_ABILITIES; i++) { + for (int i = 0; i < MAX_ABILITIES; i++) { const abilitydef_t *first = abilities_by_index[i]; if (first) { @@ -328,7 +327,7 @@ void vrx_add_ability(edict_t* ent, int index) { if (index < 0 || index >= MAX_ABILITIES) return; - int class = vrx_get_ability_class(index); + const int class = vrx_get_ability_class(index); if (class == CLASS_NULL) return; @@ -460,7 +459,6 @@ const abilitydef_t * vrx_get_random_ability() { } void vrx_init_ability_list() { - const abilitydef_t *first; // gi.dprintf("INFO: Initializing ability list... "); memset(abilities_by_index, 0, sizeof abilities_by_index); @@ -468,7 +466,7 @@ void vrx_init_ability_list() { for (int i = 0; i < CLASS_MAX; i++) { // iterate through our pointer list - first = abilities_by_class[i]; + const abilitydef_t *first = abilities_by_class[i]; // iterate through class' ability list while (first->index != -1) { @@ -647,7 +645,7 @@ void vrx_ability_open_select_menu( int ab_count_on_page = 0; int limit = 10; for (int i = 0; i < limit && ab_count_on_page <= 10 && i < MAX_ABILITIES; i++) { - int index = start_index + i; + const int index = start_index + i; // if the ability is enabled by the filter if (skills[index / 32] & (1 << (index % 32))) { const abilitydef_t *ability = vrx_get_ability_by_index(index); diff --git a/src/characters/v_stash.c b/src/characters/v_stash.c index 6da7e21f..63148919 100644 --- a/src/characters/v_stash.c +++ b/src/characters/v_stash.c @@ -74,7 +74,7 @@ void vrx_setup_sqlite_stash() void vrx_init_stash_io() { - int method = savemethod->value; + const int method = savemethod->value; switch (method) { #ifndef NO_GDS case SAVEMETHOD_MYSQL: @@ -106,7 +106,7 @@ void vrx_stash_store(edict_t* ent, int itemindex) void vrx_notify_stash_no_owner(void* args) { - stash_event_t* notif = args; + const stash_event_t* notif = args; if (notif->ent->gds_connection_id == notif->gds_connection_id && notif->ent->inuse) gi.cprintf(notif->ent, PRINT_HIGH, @@ -138,7 +138,7 @@ void vrx_notify_stash_taken(void* args) void vrx_notify_stash_locked(void* args) { - stash_event_t* notif = args; + const stash_event_t* notif = args; if (notif->ent->gds_connection_id == notif->gds_connection_id && notif->ent->inuse) gi.cprintf(notif->ent, PRINT_HIGH, @@ -229,8 +229,8 @@ void handler_stash_page(edict_t* ent, int opt) // show stash item const int page_len = sizeof ent->client->stash.page / sizeof(item_t); - int item_index = (opt - 100) % page_len; - int page = (opt - 100) / page_len; + const int item_index = (opt - 100) % page_len; + const int page = (opt - 100) / page_len; item_t* it = &ent->client->stash.page[item_index]; if (it->itemtype != ITEM_NONE) vrx_show_stash_item(ent, it, opt - 100); @@ -258,8 +258,8 @@ void vrx_stash_open_page(edict_t* ent, item_t* page, int item_count, int page_in for (int i = 0; i < item_count; i++) { - lva_result_t line = vrx_get_item_menu_line(&page[i]); - int opt = 100 + page_index * 10 + i; + const lva_result_t line = vrx_get_item_menu_line(&page[i]); + const int opt = 100 + page_index * 10 + i; menu_add_line(ent, line.str, opt); } diff --git a/src/characters/v_utils.c b/src/characters/v_utils.c index 9b565ac0..44d08252 100644 --- a/src/characters/v_utils.c +++ b/src/characters/v_utils.c @@ -903,7 +903,7 @@ class_rune_string_t weaponmaster_rune_val = { }; const char *GetRuneValString(item_t *rune) { - int level = rune->itemLevel; + const int level = rune->itemLevel; switch (rune->itemtype) { case ITEM_WEAPON: @@ -937,7 +937,7 @@ const char *GetRuneValString(item_t *rune) { } } case ITEM_CLASSRUNE: { - int idx = min(level / 2, 6); + const int idx = min(level / 2, 6); switch (rune->classNum) { case CLASS_SOLDIER: return soldier_rune_val[idx]; @@ -1353,7 +1353,7 @@ void ReadString(char *buf, FILE *fptr) { //************************************************************************************************ void WriteString(FILE *fptr, char *String) { - int Length = strlen(String); + const int Length = strlen(String); WriteChar(fptr, (char) Length); fwrite(String, Length, 1, fptr); } @@ -1588,7 +1588,7 @@ char *V_TruncateString(char *string, int newStringLength) { void V_RegenAbilityAmmo(edict_t *ent, int ability_index, int regen_frames, int regen_delay) { int ammo; - int max = ent->myskills.abilities[ability_index].max_ammo; + const int max = ent->myskills.abilities[ability_index].max_ammo; int *current = &ent->myskills.abilities[ability_index].ammo; int *delay = &ent->myskills.abilities[ability_index].ammo_regenframe; @@ -2289,8 +2289,8 @@ void EmpEffects(edict_t *ent); void SV_AddBlend(float r, float g, float b, float a, float *v_blend); void V_ShellNonAbilityEffects(edict_t *ent) { - qboolean finalEffects = true; - edict_t *cl_ent = G_GetClient(ent); + const qboolean finalEffects = true; + const edict_t *cl_ent = G_GetClient(ent); // ********** NON-ENTITY SPECIFIC EFFECTS BELOW ********** // drones flash briefly when selected for orders @@ -2424,7 +2424,7 @@ void V_ShellAbilityEffects(edict_t *ent) { (ent->chill_time > level.time)) { // client-specific if (ent->client) { - SV_AddBlend(0.75, 0.75, 0.75, 0.6, ent->client->ps.blend); + SV_AddBlend(0.75, 0.75, 0.75, 0.6, ent->client->ps.screen_blend); ent->client->ps.rdflags |= RDF_UNDERWATER; } @@ -2440,7 +2440,7 @@ void V_ShellAbilityEffects(edict_t *ent) { else if (que_typeexists(ent->curses, POISON)) { if (ent->client) { - SV_AddBlend(0, 0.75, 0, 0.6, ent->client->ps.blend); + SV_AddBlend(0, 0.75, 0, 0.6, ent->client->ps.screen_blend); ent->client->ps.rdflags |= RDF_UNDERWATER; } ent->s.effects |= EF_BLASTER | EF_TRACKER; @@ -2507,6 +2507,10 @@ void V_NonShellEffects(edict_t *ent) { if (ent->superspeed) ent->s.effects |= EF_TAGTRAIL; + if (ent->flags & FL_FLASHLIGHT) { + ent->s.effects |= EF_FLASHLIGHT; + } + // ********** CLIENT-SPECIFIC EFFECTS BELOW ********** if (ent->client) { // shield ability effect @@ -2533,7 +2537,7 @@ void V_NonShellEffects(edict_t *ent) { // chat protect changes view, but doesn't add effects //FIXME: move this? if (ent->flags & FL_CHATPROTECT) - SV_AddBlend(0.5, 0, 0, 0.3, ent->client->ps.blend); + SV_AddBlend(0.5, 0, 0, 0.3, ent->client->ps.screen_blend); // manashield effects = EF_HALF_DAMAGE and EF_TAGTRAIL if (ent->manashield) diff --git a/src/characters/weapons.c b/src/characters/weapons.c index ee6ea2ef..fcc5ce34 100644 --- a/src/characters/weapons.c +++ b/src/characters/weapons.c @@ -6,7 +6,7 @@ qboolean GiveWeaponMasterUpgrade(edict_t *ent, int WeaponIndex, int ModIndex) { weapon_t *weapon; - int maxLevel = 40; //All hard maximums for the weapon master are set to this number. + const int maxLevel = 40; //All hard maximums for the weapon master are set to this number. if (generalabmode->value == 0) // No weapon master bonuses in non-general ab mode. return false; @@ -137,7 +137,7 @@ qboolean GiveKnightUpgrade(edict_t *ent, int WeaponIndex, int ModIndex) { return false; weapon_t *weapon; - int maxLevel = 40; // Sword hard maximums for the knight are set to this number. + const int maxLevel = 40; // Sword hard maximums for the knight are set to this number. //Point to the correct weapon weapon = &ent->myskills.weapons[WeaponIndex]; diff --git a/src/combat/abilities/Spirit.c b/src/combat/abilities/Spirit.c index 45a12c44..57a78206 100644 --- a/src/combat/abilities/Spirit.c +++ b/src/combat/abilities/Spirit.c @@ -30,9 +30,9 @@ void Spirit_Shoot(edict_t *self, edict_t *target, int damage, float next_shot) void Spirit_AttackSomething(edict_t *self) { edict_t *target = NULL; - int abilitylevel = self->activator->myskills.abilities[YANG].current_level; + const int abilitylevel = self->activator->myskills.abilities[YANG].current_level; int damage = YANG_DAMAGE_BASE + (abilitylevel * YANG_DAMAGE_MULT); - float refire = YANG_ATTACK_DELAY_BASE / (1 + (abilitylevel * YANG_ATTACK_DELAY_MULT)); + const float refire = YANG_ATTACK_DELAY_BASE / (1 + (abilitylevel * YANG_ATTACK_DELAY_MULT)); int talentLevel; //Randomize damage @@ -74,7 +74,7 @@ void Spirit_AttackSomething(edict_t *self) void Spirit_AttackCorpse(edict_t *self) { edict_t *target = NULL; - int abilitylevel = self->activator->myskills.abilities[YIN].current_level; + const int abilitylevel = self->activator->myskills.abilities[YIN].current_level; int heal = YIN_HEAL_BASE + (abilitylevel * YIN_HEAL_MULT); float refire = YIN_ATTACK_DELAY_BASE / (1 + (abilitylevel * YIN_ATTACK_DELAY_MULT)); edict_t *caster = self->activator; @@ -94,8 +94,8 @@ void Spirit_AttackCorpse(edict_t *self) if ((caster->health < MAX_HEALTH(caster)) || (ammo < 1.0) //4.2 added ammo check || (caster->client->pers.inventory[body_armor_index] < MAX_ARMOR(caster))) { - int max_hp = MAX_HEALTH(caster); - int max_ar = MAX_ARMOR(caster); + const int max_hp = MAX_HEALTH(caster); + const int max_ar = MAX_ARMOR(caster); int talentLevel; //Randomize healing amount diff --git a/src/combat/abilities/auras.c b/src/combat/abilities/auras.c index f0024fac..3bf343d2 100644 --- a/src/combat/abilities/auras.c +++ b/src/combat/abilities/auras.c @@ -17,7 +17,7 @@ qboolean CheckAuraOwner (edict_t *self, int aura_cost) qboolean que_valident (que_t *que) { // 3.5 aura/curse is no longer valid if the owner dies - qboolean owner_valid = (que->ent && que->ent->inuse && que->time > level.time); + const qboolean owner_valid = (que->ent && que->ent->inuse && que->time > level.time); if (owner_valid) { if (pvm->value) return G_EntExists(que->ent->owner); @@ -337,7 +337,7 @@ void holyfreeze_think (edict_t *self) // use cubes if (!(sf2qf(level.framenum) % DEFAULT_AURA_FRAMES)) { - int cube_cost = DEFAULT_AURA_COST; + const int cube_cost = DEFAULT_AURA_COST; self->owner->client->pers.inventory[power_cube_index] -= cube_cost; } @@ -440,7 +440,7 @@ void Cmd_HolyFreeze(edict_t *ent) if(ent->myskills.abilities[HOLY_FREEZE].disable) return; - int aura_level = ent->myskills.abilities[HOLY_FREEZE].current_level; + const int aura_level = ent->myskills.abilities[HOLY_FREEZE].current_level; if (!G_CanUseAbilities(ent, aura_level, 0)) return; @@ -488,7 +488,7 @@ void salvation_think (edict_t *self) // use cubes if (!(sf2qf(level.framenum) % DEFAULT_AURA_FRAMES)) { - int cube_cost = DEFAULT_AURA_COST; + const int cube_cost = DEFAULT_AURA_COST; self->owner->client->pers.inventory[power_cube_index] -= cube_cost; } @@ -556,7 +556,7 @@ void Cmd_Salvation(edict_t *ent) if(ent->myskills.abilities[SALVATION].disable) return; - int aura_level = ent->myskills.abilities[SALVATION].current_level; + const int aura_level = ent->myskills.abilities[SALVATION].current_level; if (!G_CanUseAbilities(ent, aura_level, 0)) return; @@ -607,7 +607,7 @@ void thorns_think(edict_t* self) // use cubes if (!(sf2qf(level.framenum) % DEFAULT_AURA_FRAMES)) { - int cube_cost = DEFAULT_AURA_COST; + const int cube_cost = DEFAULT_AURA_COST; if (self->owner->client) self->owner->client->pers.inventory[power_cube_index] -= cube_cost; diff --git a/src/combat/abilities/autocannon.c b/src/combat/abilities/autocannon.c index e3d4ef68..d384703b 100644 --- a/src/combat/abilities/autocannon.c +++ b/src/combat/abilities/autocannon.c @@ -66,7 +66,7 @@ void autocannon_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int d void mzfire_think (edict_t *self) { - int attack_frame=AUTOCANNON_FRAME_ATTACK_START; + const int attack_frame=AUTOCANNON_FRAME_ATTACK_START; float dist=10; vec3_t start, forward; @@ -99,7 +99,7 @@ void mzfire_think (edict_t *self) // play frame sequence - G_RunFrames(self, 4, 15, false); + G_RunFrames(self, 4, 15, false, true); self->nextthink = level.time + FRAMETIME; } @@ -170,7 +170,7 @@ void autocannon_runframes (edict_t *self) { if (self->style == AUTOCANNON_STATUS_ATTACK) { - G_RunFrames(self, AUTOCANNON_FRAME_ATTACK_START, AUTOCANNON_FRAME_ATTACK_END, false); + G_RunFrames(self, AUTOCANNON_FRAME_ATTACK_START, AUTOCANNON_FRAME_ATTACK_END, false, true); if (self->s.frame == AUTOCANNON_FRAME_ATTACK_END) { self->s.frame = 0; // reset frame @@ -190,7 +190,7 @@ void autocannon_aim (edict_t *self) { VectorCopy(self->move_origin, v); // 0.1=5-6 degrees/frame, 0.2=11-12 degrees/frame, 0.3=17-18 degrees/frame - VectorScale(v, 0.1, v); + VectorScale(v, FRAMETIME, v); VectorAdd(v, self->movedir, v); VectorNormalize(v); VectorCopy(v, self->movedir); @@ -260,7 +260,7 @@ void autocannon_think (edict_t *self) if (!autocannon_checkstatus(self)) { - autocannon_remove(self, NULL); + autocannon_remove(self, nullptr); return; } @@ -322,7 +322,7 @@ void autocannon_think (edict_t *self) void autocannon_buildthink (edict_t *self) { // play sleep frames in reverse, gun is waking up - G_RunFrames(self, AUTOCANNON_FRAME_SLEEP_START, AUTOCANNON_FRAME_SLEEP_END, true); + G_RunFrames(self, AUTOCANNON_FRAME_SLEEP_START, AUTOCANNON_FRAME_SLEEP_END, true, true); if (self->s.frame == AUTOCANNON_FRAME_SLEEP_START) { if (!autocannon_checkstatus(self)) @@ -350,7 +350,7 @@ void autocannon_status (edict_t *self, edict_t *other) void autocannon_reload (edict_t *self, edict_t *other) { - int required_ammo = self->count-self->light_level; + const int required_ammo = self->count-self->light_level; int *player_ammo = &other->client->pers.inventory[shell_index]; // full ammo diff --git a/src/combat/abilities/bombspell.c b/src/combat/abilities/bombspell.c index d1afcb4b..b34db400 100644 --- a/src/combat/abilities/bombspell.c +++ b/src/combat/abilities/bombspell.c @@ -238,7 +238,7 @@ void BombArea (edict_t *ent, float skill_mult, float cost_mult) vec3_t forward, right, start, end; trace_t tr; edict_t *bomb; - int cost=COST_FOR_BOMB*cost_mult; + const int cost=COST_FOR_BOMB*cost_mult; #ifdef OLD_NOLAG_STYLE // 3.5 don't allow bomb area to prevent lag @@ -374,7 +374,7 @@ void BombPerson (edict_t *target, edict_t *owner, float skill_mult) void Cmd_BombPlayer(edict_t *ent, float skill_mult, float cost_mult) { - int cost=COST_FOR_BOMB*cost_mult; + const int cost=COST_FOR_BOMB*cost_mult; vec3_t forward, right, start, end, offset; trace_t tr; // edict_t *other=NULL; diff --git a/src/combat/abilities/chainlightning.c b/src/combat/abilities/chainlightning.c index 56c9fa2c..d707abdb 100644 --- a/src/combat/abilities/chainlightning.c +++ b/src/combat/abilities/chainlightning.c @@ -126,8 +126,15 @@ void chainlightning_think(edict_t* self) // lightning graphical effect gi.WriteByte(svc_temp_entity); +#ifndef VRX_REPRO gi.WriteByte(TE_HEATBEAM); gi.WriteShort(self - g_edicts); +#else + gi.WriteByte(TE_LIGHTNING); + gi.WriteShort(self - g_edicts); + gi.WriteShort(0); +#endif + gi.WritePosition(self->s.old_origin); gi.WritePosition(self->s.origin); gi.multicast(self->s.origin, MULTICAST_PVS); @@ -181,7 +188,7 @@ void fire_chainlightning(edict_t* self, vec3_t start, vec3_t aimdir, int damage, end[0] = end[0] + GetRandom(0, (int)targ->maxs[0]) * crandom(); end[1] = end[1] + GetRandom(0, (int)targ->maxs[1]) * crandom(); // recalculate starting position directly above endpoint - trace_t tr = gi.trace(end, NULL, NULL, tv(end[0], end[1], 8192), self, MASK_SOLID); + const trace_t tr = gi.trace(end, NULL, NULL, tv(end[0], end[1], 8192), self, MASK_SOLID); VectorCopy(tr.endpos, start); } else @@ -351,9 +358,9 @@ void ChainLightning (edict_t *ent, vec3_t start, vec3_t aimdir, int damage, int void Cmd_ChainLightning_f (edict_t *ent, float skill_mult, float cost_mult) { int damage=CLIGHTNING_INITIAL_DMG+CLIGHTNING_ADDON_DMG*ent->myskills.abilities[LIGHTNING].current_level; - int attack_range=CLIGHTNING_INITIAL_AR+CLIGHTNING_ADDON_AR*ent->myskills.abilities[LIGHTNING].current_level; - int hop_range=CLIGHTNING_INITIAL_HR+CLIGHTNING_ADDON_HR*ent->myskills.abilities[LIGHTNING].current_level; - int cost=CLIGHTNING_COST*cost_mult; + const int attack_range=CLIGHTNING_INITIAL_AR+CLIGHTNING_ADDON_AR*ent->myskills.abilities[LIGHTNING].current_level; + const int hop_range=CLIGHTNING_INITIAL_HR+CLIGHTNING_ADDON_HR*ent->myskills.abilities[LIGHTNING].current_level; + const int cost=CLIGHTNING_COST*cost_mult; vec3_t start, forward, right, offset; if (!G_CanUseAbilities(ent, ent->myskills.abilities[LIGHTNING].current_level, cost)) @@ -372,7 +379,7 @@ void Cmd_ChainLightning_f (edict_t *ent, float skill_mult, float cost_mult) fire_chainlightning(ent, start, forward, damage, 0, attack_range, hop_range, 4); //Talent: Wizardry - makes spell timer ability-specific instead of global - int talentLevel = vrx_get_talent_level(ent, TALENT_WIZARDRY); + const int talentLevel = vrx_get_talent_level(ent, TALENT_WIZARDRY); if (talentLevel > 0) { ent->myskills.abilities[LIGHTNING].delay = level.time + CLIGHTNING_DELAY; diff --git a/src/combat/abilities/conversion.c b/src/combat/abilities/conversion.c index bc8a9b63..10fd2ad8 100644 --- a/src/combat/abilities/conversion.c +++ b/src/combat/abilities/conversion.c @@ -15,7 +15,7 @@ qboolean ConvertOwner (edict_t *ent, edict_t *other, float duration, qboolean pa { int current_num, max_num; edict_t *old_owner, **new_owner; - qboolean was_packanimal = other->flags & FL_PACKANIMAL; + const qboolean was_packanimal = other->flags & FL_PACKANIMAL; // don't convert to a player if they are not a valid target //FIXME: this fails on players with godmode :( @@ -27,7 +27,7 @@ qboolean ConvertOwner (edict_t *ent, edict_t *other, float duration, qboolean pa if (pack_animal) { - qboolean player_tank = PM_PlayerHasMonster(ent); + const qboolean player_tank = PM_PlayerHasMonster(ent); // player isn't morphed if (!ent->mtype && !player_tank) return false; @@ -332,9 +332,9 @@ qboolean CanConvert (edict_t *ent, edict_t *other) void Cmd_Conversion_f (edict_t *ent) { - int duration = CONVERSION_INITIAL_DURATION + CONVERSION_ADDON_DURATION * ent->myskills.abilities[CONVERSION].current_level; + const int duration = CONVERSION_INITIAL_DURATION + CONVERSION_ADDON_DURATION * ent->myskills.abilities[CONVERSION].current_level; float chance = CONVERSION_INITIAL_CHANCE + CONVERSION_ADDON_CHANCE * ent->myskills.abilities[CONVERSION].current_level; - float range = CONVERSION_INITIAL_RANGE + CONVERSION_ADDON_RANGE * ent->myskills.abilities[CONVERSION].current_level; + const float range = CONVERSION_INITIAL_RANGE + CONVERSION_ADDON_RANGE * ent->myskills.abilities[CONVERSION].current_level; edict_t *e=NULL; if (!V_CanUseAbilities(ent, CONVERSION, CONVERSION_COST, true)) @@ -345,7 +345,7 @@ void Cmd_Conversion_f (edict_t *ent) while ((e = findclosestreticle(e, ent, range)) != NULL) { - float r = random(); + const float r = random(); if (!CanConvert(ent, e)) continue; @@ -378,7 +378,7 @@ void Cmd_Conversion_f (edict_t *ent) // Note: On-hold for now void think_talent_pack_animal(edict_t* ent) { - int talent_level = vrx_get_talent_level(ent, TALENT_PACK_ANIMAL); + const int talent_level = vrx_get_talent_level(ent, TALENT_PACK_ANIMAL); // talent isn't upgraded if (talent_level < 1) return; @@ -389,7 +389,7 @@ void think_talent_pack_animal(edict_t* ent) return; } // time between conversions gets shorter as the talent is upgraded (10s - 5s) - int cooldown = (int)(6.0f / FRAMETIME) - 10 * talent_level; + const int cooldown = (int)(6.0f / FRAMETIME) - 10 * talent_level; if (level.framenum % cooldown) return; //gi.dprintf("searching for monsters to convert...\n"); diff --git a/src/combat/abilities/curses.c b/src/combat/abilities/curses.c index 6e7a05da..c043fb1b 100644 --- a/src/combat/abilities/curses.c +++ b/src/combat/abilities/curses.c @@ -82,7 +82,7 @@ void Healing_think(edict_t *self) //Find my slot que_t *slot = NULL; int heal_amount = HEALING_HEAL_BASE + HEALING_HEAL_BONUS * self->owner->myskills.abilities[HEALING].current_level; - float cooldown = 1.0; + const float cooldown = 1.0; slot = que_findtype(self->enemy->curses, NULL, HEALING); @@ -230,7 +230,7 @@ void curse_think(edict_t *self) qboolean curse_add(edict_t *target, edict_t *caster, int type, int curse_level, float duration) { edict_t *curse; - que_t *slot = NULL; + const que_t *slot = NULL; if (type != BLESS && type != HEALING && type != DEFLECT) if (target == caster) @@ -696,7 +696,7 @@ void Cmd_Curse(edict_t *ent) { int range, radius, talentLevel, curseLevel, cost=CURSE_COST; float duration; - edict_t *target = NULL; + const edict_t *target = NULL; if (debuginfo->value) gi.dprintf("DEBUG: %s just called Cmd_Curse()\n", ent->client->pers.netname); @@ -1014,7 +1014,7 @@ void Cmd_Healing(edict_t *ent) } if (target != NULL) { - que_t *slot = NULL; + const que_t *slot = NULL; //Finish casting the spell ent->client->ability_delay = level.time + HEALING_DELAY; @@ -1093,7 +1093,7 @@ void Cmd_Bless(edict_t *ent) if (target != NULL) { - que_t *slot = NULL; + const que_t *slot = NULL; //Finish casting the spell ent->client->ability_delay = level.time + BLESS_DELAY; @@ -1201,7 +1201,7 @@ void Cmd_Deflect_f(edict_t *ent) if (target != NULL) { - que_t *slot = NULL; + const que_t *slot = NULL; //Finish casting the spell ent->client->ability_delay = level.time + DEFLECT_DELAY; @@ -1249,7 +1249,7 @@ void MindAbsorb(edict_t *ent) int radius; int take; int total; - int abilityLevel = ent->myskills.abilities[MIND_ABSORB].current_level; + const int abilityLevel = ent->myskills.abilities[MIND_ABSORB].current_level; if(ent->myskills.abilities[MIND_ABSORB].disable) return; @@ -1416,8 +1416,8 @@ int SelectRandomTopCurse(edict_t* player) // Find the two highest level curses for (int i = 0; i < NUM_CURSES; i++) { - int index = CURSE_INDICES[i]; // Get the actual ability index - int level = player->myskills.abilities[index].current_level; + const int index = CURSE_INDICES[i]; // Get the actual ability index + const int level = player->myskills.abilities[index].current_level; if (level > highest_level) { second_highest_level = highest_level; diff --git a/src/combat/abilities/detector.c b/src/combat/abilities/detector.c index a456bb7d..136fb4ae 100644 --- a/src/combat/abilities/detector.c +++ b/src/combat/abilities/detector.c @@ -43,7 +43,7 @@ edict_t *detector_findprojtarget (edict_t *self, edict_t *projectile) // find enemy that is closest to the projectile //while ((target = findclosestradius_targets(target, projectile, self->dmg_radius)) != NULL) - while (target = findradius(target, projectile->s.origin, self->dmg_radius)) + while ((target = findradius(target, projectile->s.origin, self->dmg_radius))) { // valid target must be within range of the detector //if (G_ValidTarget_Lite(self, target, true) && entdist(self, target) < self->dmg_radius) diff --git a/src/combat/abilities/emp.c b/src/combat/abilities/emp.c index 80746c21..cdb04a4f 100644 --- a/src/combat/abilities/emp.c +++ b/src/combat/abilities/emp.c @@ -187,7 +187,7 @@ void EMP_Explode (edict_t *self) { int damage; float radius; - float time = EMP_INITIAL_TIME + (EMP_ADDON_TIME * self->monsterinfo.level); + const float time = EMP_INITIAL_TIME + (EMP_ADDON_TIME * self->monsterinfo.level); edict_t *e=NULL; qboolean ammoBox; @@ -256,7 +256,7 @@ void EMP_Touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf) } // bounce off things that can't be hurt - if (!other->takedamage) + if (!other->takedamage && ent != other) { if (random() > 0.5) gi.sound (ent, CHAN_VOICE, gi.soundindex ("weapons/hgrenb1a.wav"), 1, ATTN_NORM, 0); diff --git a/src/combat/abilities/explodingarmor.c b/src/combat/abilities/explodingarmor.c index 5d8e5837..55254f12 100644 --- a/src/combat/abilities/explodingarmor.c +++ b/src/combat/abilities/explodingarmor.c @@ -122,7 +122,7 @@ void explodingarmor_touch (edict_t *self, edict_t *other, cplane_t *plane, csurf qboolean NearbyEnemy (edict_t *self, float radius) { - edict_t *e=NULL; + const edict_t *e=NULL; while ((e = findradius(e, self->s.origin, radius)) != NULL) { diff --git a/src/combat/abilities/fire.c b/src/combat/abilities/fire.c index b17da52c..d2cbb8a1 100644 --- a/src/combat/abilities/fire.c +++ b/src/combat/abilities/fire.c @@ -7,7 +7,7 @@ void bfire_think(edict_t* self) { if (self->s.frame > 3) - G_RunFrames(self, 4, 15, false); // burning frames + G_RunFrames(self, 4, 15, false, true); // burning frames else self->s.frame++; // ignite frames @@ -203,7 +203,7 @@ void fireball_think(edict_t* self) vectoangles(self->velocity, angles); VectorCopy(angles, self->s.angles); // run model animation - G_RunFrames(self, 0, 3, false); + G_RunFrames(self, 0, 3, false, true); self->nextthink = level.time + FRAMETIME; } @@ -259,7 +259,7 @@ void fire_fireball(edict_t* self, vec3_t start, vec3_t aimdir, int damage, float void Cmd_Fireball_f(edict_t* ent, float skill_mult, float cost_mult) { - int slvl = ent->myskills.abilities[FIREBALL].current_level; + const int slvl = ent->myskills.abilities[FIREBALL].current_level; int damage, speed, flames, flamedmg, cost = FIREBALL_COST * cost_mult; float radius; vec3_t forward, right, start, offset; @@ -285,7 +285,7 @@ void Cmd_Fireball_f(edict_t* ent, float skill_mult, float cost_mult) fire_fireball(ent, start, forward, damage, radius, speed, flames, flamedmg); //Talent: Wizardry - makes spell timer ability-specific instead of global - int talentLevel = vrx_get_talent_level(ent, TALENT_WIZARDRY); + const int talentLevel = vrx_get_talent_level(ent, TALENT_WIZARDRY); if (talentLevel > 0) { ent->myskills.abilities[FIREBALL].delay = level.time + FIREBALL_DELAY; @@ -307,13 +307,13 @@ void Cmd_Fireball_f(edict_t* ent, float skill_mult, float cost_mult) void ShootFireballsAtNearbyEnemies(edict_t* self, float radius, int max_targets, int fireball_level) { - edict_t* e = NULL; + const edict_t* e = NULL; - int damage = FIREBALL_INITIAL_DAMAGE + FIREBALL_ADDON_DAMAGE * fireball_level; - float fb_radius = FIREBALL_INITIAL_RADIUS + FIREBALL_ADDON_RADIUS * fireball_level; + const int damage = FIREBALL_INITIAL_DAMAGE + FIREBALL_ADDON_DAMAGE * fireball_level; + const float fb_radius = FIREBALL_INITIAL_RADIUS + FIREBALL_ADDON_RADIUS * fireball_level; //float speed = FIREBALL_INITIAL_SPEED + FIREBALL_ADDON_SPEED * fireball_level; - int flames = FIREBALL_INITIAL_FLAMES + FIREBALL_ADDON_FLAMES * fireball_level; - int flamedmg = 0.1 * damage; + const int flames = FIREBALL_INITIAL_FLAMES + FIREBALL_ADDON_FLAMES * fireball_level; + const int flamedmg = 0.1 * damage; vec3_t forward, start; edict_t* owner = G_GetSummoner(self); @@ -375,7 +375,7 @@ void flames_attack(edict_t* self) if (level.framenum >= self->monsterinfo.nextattack) { edict_t* touch[MAX_EDICTS], * hit; - int num_edicts = gi.BoxEdicts(self->absmin, self->absmax, touch, MAX_EDICTS, AREA_SOLID); + const int num_edicts = gi.BoxEdicts(self->absmin, self->absmax, touch, MAX_EDICTS, AREA_SOLID); for (int i = 0; i < num_edicts; i++) { @@ -420,7 +420,7 @@ void flames_adjust_size(edict_t* self) { vec3_t mins, maxs; flames_lg_bbox(mins, maxs); - trace_t tr = gi.trace(self->s.origin, mins, maxs, self->s.origin, self, MASK_SOLID); + const trace_t tr = gi.trace(self->s.origin, mins, maxs, self->s.origin, self, MASK_SOLID); if (tr.fraction == 1.0) { self->s.modelindex = gi.modelindex("models/flames_big/tris.md2"); @@ -445,7 +445,7 @@ void flames_runframes(edict_t* self) { self->s.frame++; int firstframe = 0, lastframe; - int style = self->style; // growth/lifecycle stage + const int style = self->style; // growth/lifecycle stage if (style) { @@ -543,8 +543,8 @@ edict_t* CreateFirewallFlames(edict_t* ent, int skill_level, float skill_mult) void Cmd_Firewall_f(edict_t* ent, float skill_mult, float cost_mult) { - int cost = FIREWALL_COST * cost_mult; - int skill_level = ent->myskills.abilities[FIREWALL].current_level; + const int cost = FIREWALL_COST * cost_mult; + const int skill_level = ent->myskills.abilities[FIREWALL].current_level; if (ent->num_firewalls > FIREWALL_MAX) { @@ -580,7 +580,7 @@ void Cmd_Firewall_f(edict_t* ent, float skill_mult, float cost_mult) ent->lastsound = level.framenum; //Talent: Wizardry - makes spell timer ability-specific instead of global - int talentLevel = vrx_get_talent_level(ent, TALENT_WIZARDRY); + const int talentLevel = vrx_get_talent_level(ent, TALENT_WIZARDRY); if (talentLevel > 0) { ent->myskills.abilities[FIREWALL].delay = level.time + FIREWALL_DELAY; diff --git a/src/combat/abilities/flying_skull.c b/src/combat/abilities/flying_skull.c index f8f23df2..6b6777a8 100644 --- a/src/combat/abilities/flying_skull.c +++ b/src/combat/abilities/flying_skull.c @@ -11,915 +11,850 @@ #define SKULL_FLOAT_HEIGHT 3 // max float travel #define SKULL_FLOAT_SPEED 1 // vertical float speed -qboolean skull_findtarget (edict_t *self) -{ - edict_t *e=NULL; - - while ((e = findclosestradius_targets(e, self, - SKULL_TARGET_RANGE)) != NULL) - { - if (e == self) - continue; - if (!G_ValidTarget_Lite(self, e, true)) - continue; - // ignore enemies that are too far away from activator to prevent wandering - // FIXME: we may want to add a hurt function so that we can retaliate if we are attacked out of range - if (entdist(e, self->activator) > SKULL_MAX_RANGE) - continue; - self->enemy = e; - self->monsterinfo.search_frames = 0; - return true; - } - - return false; +qboolean skull_findtarget(edict_t *self) { + edict_t *e = NULL; + + while ((e = findclosestradius_targets(e, self, + SKULL_TARGET_RANGE)) != NULL) { + if (e == self) + continue; + if (!G_ValidTarget_Lite(self, e, true)) + continue; + // ignore enemies that are too far away from activator to prevent wandering + // FIXME: we may want to add a hurt function so that we can retaliate if we are attacked out of range + if (entdist(e, self->activator) > SKULL_MAX_RANGE) + continue; + self->enemy = e; + self->monsterinfo.search_frames = 0; + return true; + } + + return false; } -qboolean skull_checkposition (edict_t *self) -{ - if (gi.pointcontents(self->s.origin) & MASK_SOLID) - { - if (self->activator) - { - self->activator->skull = NULL; - self->activator->client->pers.inventory[power_cube_index] += SKULL_COST; - safe_centerprintf(self->activator, "Skull was removed.\n"); - } - G_FreeEdict(self);//FIXME: this is not a very safe way to remove an entity! - gi.dprintf("WARNING: Skull removed from solid.\n"); - return false; - } - - self->velocity[0] *= 0.6; - self->velocity[1] *= 0.6; - self->velocity[2] *= 0.6; - return true; +qboolean skull_checkposition(edict_t *self) { + if (gi.pointcontents(self->s.origin) & MASK_SOLID) { + if (self->activator) { + self->activator->skull = NULL; + self->activator->client->pers.inventory[power_cube_index] += SKULL_COST; + safe_centerprintf(self->activator, "Skull was removed.\n"); + } + G_FreeEdict(self); //FIXME: this is not a very safe way to remove an entity! + gi.dprintf("WARNING: Skull removed from solid.\n"); + return false; + } + + self->velocity[0] *= 0.6; + self->velocity[1] *= 0.6; + self->velocity[2] *= 0.6; + return true; } -void skull_bumparound (edict_t *self) -{ - float yaw, min_yaw, max_yaw; - vec3_t forward, start; - trace_t tr; - - AngleVectors(self->s.angles, forward, NULL, NULL); - VectorMA(self->s.origin, 0.5*SKULL_MOVE_HORIZONTAL_SPEED, forward, start); - tr = gi.trace(self->s.origin, self->mins, self->maxs, start, self, MASK_SHOT); - if (tr.fraction < 1) - { - yaw = vectoyaw(tr.plane.normal); - min_yaw = yaw-90; - max_yaw = yaw+90; - self->ideal_yaw = GetRandom(min_yaw, max_yaw); - return; - } - VectorCopy(start, self->s.origin); +void skull_bumparound(edict_t *self) { + float yaw, min_yaw, max_yaw; + vec3_t forward, start; + trace_t tr; + + AngleVectors(self->s.angles, forward, NULL, NULL); + VectorMA(self->s.origin, 0.5 * SKULL_MOVE_HORIZONTAL_SPEED, forward, start); + tr = gi.trace(self->s.origin, self->mins, self->maxs, start, self, MASK_SHOT); + if (tr.fraction < 1) { + yaw = vectoyaw(tr.plane.normal); + min_yaw = yaw - 90; + max_yaw = yaw + 90; + self->ideal_yaw = GetRandom(min_yaw, max_yaw); + return; + } + VectorCopy(start, self->s.origin); } -void skull_move_forward (edict_t *self, float dist) -{ - float yaw, min_yaw, max_yaw; - vec3_t forward, start; - trace_t tr; - - if (self->wait+1 > level.time) - dist *= 0.5; // slow down while we turn - - AngleVectors(self->s.angles, forward, NULL, NULL); - VectorMA(self->s.origin, dist, forward, start); - tr = gi.trace(self->s.origin, self->mins, self->maxs, start, self, MASK_SHOT); - // bump away from obstructions - if ((level.time > self->wait) && (tr.fraction < 1)) - { - //gi.dprintf("fwd bump\n"); - yaw = vectoyaw(tr.plane.normal); - min_yaw = yaw - 90; - max_yaw = yaw + 90; - self->ideal_yaw = GetRandom(min_yaw, max_yaw); - self->wait = level.time + 0.5; // time before we can make another course correction - } - - // double-check final move - if (!(gi.pointcontents(tr.endpos) & MASK_SOLID)) - VectorCopy(tr.endpos, self->s.origin); +void skull_move_forward(edict_t *self, float dist) { + float yaw, min_yaw, max_yaw; + vec3_t forward, start; + trace_t tr; + + if (self->wait + 1 > level.time) + dist *= 0.5; // slow down while we turn + + AngleVectors(self->s.angles, forward, NULL, NULL); + VectorMA(self->s.origin, dist, forward, start); + tr = gi.trace(self->s.origin, self->mins, self->maxs, start, self, MASK_SHOT); + // bump away from obstructions + if ((level.time > self->wait) && (tr.fraction < 1)) { + //gi.dprintf("fwd bump\n"); + yaw = vectoyaw(tr.plane.normal); + min_yaw = yaw - 90; + max_yaw = yaw + 90; + self->ideal_yaw = GetRandom(min_yaw, max_yaw); + self->wait = level.time + 0.5; // time before we can make another course correction + } + + // double-check final move + if (!(gi.pointcontents(tr.endpos) & MASK_SOLID)) + VectorCopy(tr.endpos, self->s.origin); } -void skull_strafe (edict_t *self, float dist) -{ - vec3_t right, start; - trace_t tr; - - // don't strafe if we don't have an enemy or we are chasing activator - if (!self->enemy) - return; - - // don't begin strafing until we are close - if (entdist(self, self->enemy)-32 > 512) - return; - - // change direction - if (entdist(self, self->enemy)-32 > SKULL_MAX_DIST && - level.time > self->monsterinfo.dodge_time) - { - if (self->monsterinfo.lefty) - self->monsterinfo.lefty = 0; - else - self->monsterinfo.lefty = 1; - self->monsterinfo.dodge_time = level.time + 0.5; - } - -// gi.dprintf("skull_strafe()\n"); - - AngleVectors(self->s.angles, NULL, right, NULL); - - if (self->monsterinfo.lefty) - { - VectorMA(self->s.origin, dist, right, start); - tr = gi.trace(self->s.origin, self->mins, self->maxs, start, self, MASK_SHOT); - if (tr.fraction == 1) - { - VectorCopy(tr.endpos, self->s.origin); - return; - } - self->monsterinfo.lefty = 0; - } - - VectorMA(self->s.origin, -dist, right, start); - tr = gi.trace(self->s.origin, self->mins, self->maxs, start, self, MASK_SHOT); - if (tr.fraction == 1) - { - VectorCopy(tr.endpos, self->s.origin); - return; - } - self->monsterinfo.lefty = 1; +void skull_strafe(edict_t *self, float dist) { + vec3_t right, start; + trace_t tr; + + // don't strafe if we don't have an enemy or we are chasing activator + if (!self->enemy) + return; + + // don't begin strafing until we are close + if (entdist(self, self->enemy) - 32 > 512) + return; + + // change direction + if (entdist(self, self->enemy) - 32 > SKULL_MAX_DIST && + level.time > self->monsterinfo.dodge_time) { + if (self->monsterinfo.lefty) + self->monsterinfo.lefty = 0; + else + self->monsterinfo.lefty = 1; + self->monsterinfo.dodge_time = level.time + 0.5; + } + + // gi.dprintf("skull_strafe()\n"); + + AngleVectors(self->s.angles, NULL, right, NULL); + + if (self->monsterinfo.lefty) { + VectorMA(self->s.origin, dist, right, start); + tr = gi.trace(self->s.origin, self->mins, self->maxs, start, self, MASK_SHOT); + if (tr.fraction == 1) { + VectorCopy(tr.endpos, self->s.origin); + return; + } + self->monsterinfo.lefty = 0; + } + + VectorMA(self->s.origin, -dist, right, start); + tr = gi.trace(self->s.origin, self->mins, self->maxs, start, self, MASK_SHOT); + if (tr.fraction == 1) { + VectorCopy(tr.endpos, self->s.origin); + return; + } + self->monsterinfo.lefty = 1; } -void skull_move_vertical (edict_t *self, float dist) -{ - vec3_t start; - trace_t tr; +void skull_move_vertical(edict_t *self, float dist) { + vec3_t start; + trace_t tr; - VectorCopy(self->s.origin, start); - start[2] += dist; - tr = gi.trace(self->s.origin, self->mins, self->maxs, start, self, MASK_SHOT); + VectorCopy(self->s.origin, start); + start[2] += dist; + tr = gi.trace(self->s.origin, self->mins, self->maxs, start, self, MASK_SHOT); - // double-check final move - if (!(gi.pointcontents(tr.endpos) & MASK_SOLID)) - VectorCopy(tr.endpos, self->s.origin); + // double-check final move + if (!(gi.pointcontents(tr.endpos) & MASK_SOLID)) + VectorCopy(tr.endpos, self->s.origin); } // traces forward then down until it reaches a height at which it's able to move forward -float V_LookAheadCeilingHeight (edict_t *self, float lookAheadDist, int stepHeight, int stepSize) -{ - vec3_t start, end, forward; - trace_t tr; - - // trace forward - VectorCopy(self->s.origin, start); - AngleVectors(self->s.angles, forward, NULL, NULL); - VectorMA(start, lookAheadDist, forward, end); - tr = gi.trace(start, NULL, NULL, end, self, MASK_SOLID); - // check for obstruction - if (tr.fraction < 1) - { - /* - gi.WriteByte(svc_temp_entity); - gi.WriteByte(TE_DEBUGTRAIL); - gi.WritePosition(start); - gi.WritePosition(tr.endpos); - gi.multicast(tr.endpos, MULTICAST_ALL); - */ - VectorCopy(tr.endpos, start); - VectorCopy(tr.endpos, end); - - while (1) // if we want to save cpu cycles, we could limit this to x vertical steps - { - // begin loop - end[2] -= stepHeight; - // trace down 1 step - tr = gi.trace(start, NULL, NULL, end, self, MASK_SOLID); - if (tr.fraction < 1) - { - //gi.dprintf("can't avoid obstruction with vertical move\n"); - return self->s.origin[2]; // obstruction below, can't proceed any further (FIXME: returned value should be outside valid Z range, or just return current Z height) - } - - // vertical line from wall to step below - /* - gi.WriteByte(svc_temp_entity); - gi.WriteByte(TE_DEBUGTRAIL); - gi.WritePosition(start); - gi.WritePosition(end); - gi.multicast(end, MULTICAST_ALL); - */ - - start[2] = end[2]; // stepdown successful, start tracing at lower height - // trace forward 1 step - VectorMA(start, stepSize, forward, end); - tr = gi.trace(start, NULL, NULL, end, self, MASK_SOLID); - if (tr.fraction < 1) - continue; // obstruction ahead, continue loop until cleared or floor is reached - - //gi.dprintf("cleared obstruction with vertical move!\n"); - - // horizontal line from step below to step forward below obstruction - /* - gi.WriteByte(svc_temp_entity); - gi.WriteByte(TE_DEBUGTRAIL); - gi.WritePosition(start); - gi.WritePosition(end); - gi.multicast(end, MULTICAST_ALL); - */ - //success = true; // found height that clears obstruction! - // now trace up from end to find the ceiling height - /* - VectorCopy(end, start); - end[2] += 8192; - tr = gi.trace(start, self->mins, self->maxs, end, self, MASK_SHOT); - - // vertical line from cleared obstruction to ceiling - gi.WriteByte(svc_temp_entity); - gi.WriteByte(TE_DEBUGTRAIL); - gi.WritePosition(start); - gi.WritePosition(end); - gi.multicast(end, MULTICAST_ALL); - - return tr.endpos[2];*/ - return end[2]; - } - } - // no obstruction - // now trace up from end to find the ceiling height - //gi.dprintf("no obstruction ahead\n"); - VectorCopy(end, start); - end[2] += 8192; - tr = gi.trace(start, NULL, NULL, end, self, MASK_SOLID); - return tr.endpos[2]; +float V_LookAheadCeilingHeight(edict_t *self, float lookAheadDist, int stepHeight, int stepSize) { + vec3_t start, end, forward; + trace_t tr; + + // trace forward + VectorCopy(self->s.origin, start); + AngleVectors(self->s.angles, forward, NULL, NULL); + VectorMA(start, lookAheadDist, forward, end); + tr = gi.trace(start, NULL, NULL, end, self, MASK_SOLID); + // check for obstruction + if (tr.fraction < 1) { + /* + gi.WriteByte(svc_temp_entity); + gi.WriteByte(TE_DEBUGTRAIL); + gi.WritePosition(start); + gi.WritePosition(tr.endpos); + gi.multicast(tr.endpos, MULTICAST_ALL); + */ + VectorCopy(tr.endpos, start); + VectorCopy(tr.endpos, end); + + while (1) // if we want to save cpu cycles, we could limit this to x vertical steps + { + // begin loop + end[2] -= stepHeight; + // trace down 1 step + tr = gi.trace(start, NULL, NULL, end, self, MASK_SOLID); + if (tr.fraction < 1) { + //gi.dprintf("can't avoid obstruction with vertical move\n"); + return self->s.origin[2]; + // obstruction below, can't proceed any further (FIXME: returned value should be outside valid Z range, or just return current Z height) + } + + // vertical line from wall to step below + /* + gi.WriteByte(svc_temp_entity); + gi.WriteByte(TE_DEBUGTRAIL); + gi.WritePosition(start); + gi.WritePosition(end); + gi.multicast(end, MULTICAST_ALL); + */ + + start[2] = end[2]; // stepdown successful, start tracing at lower height + // trace forward 1 step + VectorMA(start, stepSize, forward, end); + tr = gi.trace(start, NULL, NULL, end, self, MASK_SOLID); + if (tr.fraction < 1) + continue; // obstruction ahead, continue loop until cleared or floor is reached + + //gi.dprintf("cleared obstruction with vertical move!\n"); + + // horizontal line from step below to step forward below obstruction + /* + gi.WriteByte(svc_temp_entity); + gi.WriteByte(TE_DEBUGTRAIL); + gi.WritePosition(start); + gi.WritePosition(end); + gi.multicast(end, MULTICAST_ALL); + */ + //success = true; // found height that clears obstruction! + // now trace up from end to find the ceiling height + /* + VectorCopy(end, start); + end[2] += 8192; + tr = gi.trace(start, self->mins, self->maxs, end, self, MASK_SHOT); + + // vertical line from cleared obstruction to ceiling + gi.WriteByte(svc_temp_entity); + gi.WriteByte(TE_DEBUGTRAIL); + gi.WritePosition(start); + gi.WritePosition(end); + gi.multicast(end, MULTICAST_ALL); + + return tr.endpos[2];*/ + return end[2]; + } + } + // no obstruction + // now trace up from end to find the ceiling height + //gi.dprintf("no obstruction ahead\n"); + VectorCopy(end, start); + end[2] += 8192; + tr = gi.trace(start, NULL, NULL, end, self, MASK_SOLID); + return tr.endpos[2]; } -void skull_move_vertical_goalpos(edict_t* self, float goalpos) -{ - // move up or down to get to the desired height - if (goalpos > self->s.origin[2]) - skull_move_vertical(self, SKULL_MOVE_VERTICAL_SPEED); - if (goalpos < self->s.origin[2]) - skull_move_vertical(self, -SKULL_MOVE_VERTICAL_SPEED); +void skull_move_vertical_goalpos(edict_t *self, float goalpos) { + // move up or down to get to the desired height + if (goalpos > self->s.origin[2]) + skull_move_vertical(self, SKULL_MOVE_VERTICAL_SPEED); + if (goalpos < self->s.origin[2]) + skull_move_vertical(self, -SKULL_MOVE_VERTICAL_SPEED); } -void skull_movetogoal (edict_t *self, edict_t *goal) -{ - float temp, dist, speed, goalpos, ceilHeight; - vec3_t v; - que_t *slot=NULL; - qboolean goalVis = visible(self, goal); - - self->style = SKULL_ATTACK; - - - // lock-on to enemy if he is visible, and we're not busy - // trying to avoid an obstruction - if (level.time > self->wait) - { - trace_t tr; - if (level.time > self->monsterinfo.Zchange_delay) // not trying to avoid obstruction vertically - { - ceilHeight = V_LookAheadCeilingHeight(self, 128, SKULL_MOVE_VERTICAL_SPEED, SKULL_MOVE_HORIZONTAL_SPEED); - if (ceilHeight < self->s.origin[2]) // found ceiling below us - { - ceilHeight -= 32; // subtract half-height of our bbox + 1, this is the highest we can go - //gi.dprintf("hellspawn is moving lower to clear obstruction\n"); - goalpos = ceilHeight; - self->monsterinfo.eta = ceilHeight; - self->monsterinfo.Zchange_delay = level.time + 1.0; - skull_move_vertical_goalpos(self, goalpos); - } - else if (goalVis) // no obstructions found, goal is visible - { - //gi.dprintf("goal visible, move above it\n"); - // set ideal yaw to look at the goal - VectorSubtract(goal->s.origin, self->s.origin, v); - self->ideal_yaw = vectoyaw(v); - - // check for obstruction between goal origin and a position above it - goalpos = goal->absmax[2] + SKULL_HEIGHT; // float above enemy - VectorCopy(goal->s.origin, v); - v[2] = goalpos; - tr = gi.trace(goal->s.origin, NULL, NULL, v, goal, MASK_SOLID); - goalpos = tr.endpos[2]; - - // move up or down to get to the desired height - skull_move_vertical_goalpos(self, goalpos); - - // strafe left or right around the goal once we get within desired range - skull_strafe(self, 0.5 * SKULL_MOVE_HORIZONTAL_SPEED); - } - else - { - //gi.dprintf("can't see goal. ceil %.0f height %.0f\n", ceilHeight, self->s.origin[2]); - } - - //gi.dprintf("ceiling height %.1f\n", ceilHeight); - } - else // moving vertically to clear obstruction - { - //gi.dprintf("hellspawn is moving lower to clear obstruction...\n"); - goalpos = self->monsterinfo.eta; // this is the height of the ceiling below us - skull_move_vertical_goalpos(self, goalpos); - } - - } - else - { - //gi.dprintf("hellspawn is bumping around\n"); - } - - // horizontal movement - if (goalVis) - dist = entdist(self, goal); - else - dist = 8192; // keep travelling in a straight line if goal isn't visible - - if (dist > SKULL_MAX_DIST) - { - if (dist-SKULL_MOVE_HORIZONTAL_SPEED < SKULL_MAX_DIST) - speed = dist-SKULL_MAX_DIST; - else - speed = SKULL_MOVE_HORIZONTAL_SPEED; - } - else - { - if (dist+SKULL_MOVE_HORIZONTAL_SPEED > SKULL_MAX_DIST) - speed = -(SKULL_MAX_DIST-dist); - else - speed = -SKULL_MOVE_HORIZONTAL_SPEED; - } - - // are we slowed by holy freeze? - slot = que_findtype(self->curses, slot, AURA_HOLYFREEZE); - if (slot) - { - temp = 1 / (1 + 0.1 * slot->ent->owner->myskills.abilities[HOLY_FREEZE].current_level); - if (temp < 0.25) temp = 0.25; - speed *= temp; - } - - //Talent: Frost Nova - if(self->chill_time > level.time) - { - speed *= 1 / (1 + CHILL_DEFAULT_BASE + CHILL_DEFAULT_ADDON * self->chill_level); - } - - // 3.5 weaken slows down target - if ((slot = que_findtype(self->curses, NULL, WEAKEN)) != NULL) - { - temp = 1 / (1 + WEAKEN_SLOW_BASE + WEAKEN_SLOW_BONUS - * slot->ent->owner->myskills.abilities[WEAKEN].current_level); - speed *= temp; - } - - skull_move_forward(self, speed); - M_ChangeYaw(self); - gi.linkentity(self); +void skull_movetogoal(edict_t *self, edict_t *goal) { + float temp, dist, speed, goalpos, ceilHeight; + vec3_t v; + que_t *slot = NULL; + const qboolean goalVis = visible(self, goal); + + self->style = SKULL_ATTACK; + + + // lock-on to enemy if he is visible, and we're not busy + // trying to avoid an obstruction + if (level.time > self->wait) { + trace_t tr; + if (level.time > self->monsterinfo.Zchange_delay) // not trying to avoid obstruction vertically + { + ceilHeight = V_LookAheadCeilingHeight(self, 128, SKULL_MOVE_VERTICAL_SPEED, SKULL_MOVE_HORIZONTAL_SPEED); + if (ceilHeight < self->s.origin[2]) // found ceiling below us + { + ceilHeight -= 32; // subtract half-height of our bbox + 1, this is the highest we can go + //gi.dprintf("hellspawn is moving lower to clear obstruction\n"); + goalpos = ceilHeight; + self->monsterinfo.eta = ceilHeight; + self->monsterinfo.Zchange_delay = level.time + 1.0; + skull_move_vertical_goalpos(self, goalpos); + } else if (goalVis) // no obstructions found, goal is visible + { + //gi.dprintf("goal visible, move above it\n"); + // set ideal yaw to look at the goal + VectorSubtract(goal->s.origin, self->s.origin, v); + self->ideal_yaw = vectoyaw(v); + + // check for obstruction between goal origin and a position above it + goalpos = goal->absmax[2] + SKULL_HEIGHT; // float above enemy + VectorCopy(goal->s.origin, v); + v[2] = goalpos; + tr = gi.trace(goal->s.origin, NULL, NULL, v, goal, MASK_SOLID); + goalpos = tr.endpos[2]; + + // move up or down to get to the desired height + skull_move_vertical_goalpos(self, goalpos); + + // strafe left or right around the goal once we get within desired range + skull_strafe(self, 0.5 * SKULL_MOVE_HORIZONTAL_SPEED * (FRAMETIME * 10)); + } else { + //gi.dprintf("can't see goal. ceil %.0f height %.0f\n", ceilHeight, self->s.origin[2]); + } + + //gi.dprintf("ceiling height %.1f\n", ceilHeight); + } else // moving vertically to clear obstruction + { + //gi.dprintf("hellspawn is moving lower to clear obstruction...\n"); + goalpos = self->monsterinfo.eta; // this is the height of the ceiling below us + skull_move_vertical_goalpos(self, goalpos); + } + } else { + //gi.dprintf("hellspawn is bumping around\n"); + } + + // horizontal movement + if (goalVis) + dist = entdist(self, goal); + else + dist = 8192; // keep travelling in a straight line if goal isn't visible + + if (dist > SKULL_MAX_DIST) { + if (dist - SKULL_MOVE_HORIZONTAL_SPEED < SKULL_MAX_DIST) + speed = dist - SKULL_MAX_DIST; + else + speed = SKULL_MOVE_HORIZONTAL_SPEED; + } else { + if (dist + SKULL_MOVE_HORIZONTAL_SPEED > SKULL_MAX_DIST) + speed = -(SKULL_MAX_DIST - dist); + else + speed = -SKULL_MOVE_HORIZONTAL_SPEED; + } + + // scale by server tickrate + speed *= (FRAMETIME * 10); + + // are we slowed by holy freeze? + slot = que_findtype(self->curses, slot, AURA_HOLYFREEZE); + if (slot) { + temp = 1 / (1 + 0.1 * slot->ent->owner->myskills.abilities[HOLY_FREEZE].current_level); + if (temp < 0.25) temp = 0.25; + speed *= temp; + } + + //Talent: Frost Nova + if (self->chill_time > level.time) { + speed *= 1 / (1 + CHILL_DEFAULT_BASE + CHILL_DEFAULT_ADDON * self->chill_level); + } + + // 3.5 weaken slows down target + if ((slot = que_findtype(self->curses, NULL, WEAKEN)) != NULL) { + temp = 1 / (1 + WEAKEN_SLOW_BASE + WEAKEN_SLOW_BONUS + * slot->ent->owner->myskills.abilities[WEAKEN].current_level); + speed *= temp; + } + + skull_move_forward(self, speed); + M_ChangeYaw(self); + gi.linkentity(self); } //void ChainLightning(edict_t* ent, vec3_t start, vec3_t aimdir, int damage, int attack_range, int hop_range); -void skull_attack (edict_t *self) -{ - int damage;//, knockback; - float dist, chance; - vec3_t forward, start, end, v; - trace_t tr; - - skull_movetogoal(self, self->enemy); - - dist = entdist(self, self->enemy); - - if (!visible(self, self->enemy)) - return; - //if (!nearfov(self, self->enemy, 180, 180)) - //if (!infov(self, self->enemy, 216)) - if (!infront(self, self->enemy)) - return; - //gi.dprintf("hellspawn distance to enemy: %0.1f\n", dist); - if (dist > SKULL_ATTACK_RANGE) - return; - if (que_typeexists(self->curses, AURA_HOLYFREEZE) && !(level.framenum % 2)) - return; - - // chill effect reduces attack rate/refire - if (self->chill_time > level.time) - { - chance = 1 / (1 + CHILL_DEFAULT_BASE + CHILL_DEFAULT_ADDON * self->chill_level); - if (random() > chance) - return; - } - - self->lastsound = level.framenum; - - // get muzzle origin - AngleVectors(self->s.angles, forward, NULL, NULL); - VectorCopy(self->s.origin, start); - start[2] = self->absmin[2]+8; - VectorMA(start, self->maxs[1]+1, forward, start); - - G_EntMidPoint(self->enemy, end); - - // get attack vector - VectorSubtract(end , start, v); - VectorNormalize(v); - //forward[2] = v[2]; - VectorMA(start, 8192, v, end); - - // do the damage - damage = self->dmg; - - //knockback = 2*damage; - tr = gi.trace(start, NULL, NULL, end, self, MASK_SHOT); - if (G_EntExists(tr.ent)) - { - // damage to non-players is increased - //if (!tr.ent->client) - // damage *= 2; - // Talent: Hellspawn Mastery - // each talent upgrade increases the chance to proc a chainlightning attack - float chance = 0.1 * self->light_level; - if (level.framenum > self->autocurse_delay && chance > random()) - { - int cl_dmg = 10 * damage; - //gi.dprintf("hellspawn firing CL. base dmg %d modified %d CL %d\n", self->dmg, damage, cl_dmg); - //ChainLightning(self, start, v, cl_dmg, SKULL_ATTACK_RANGE, CLIGHTNING_INITIAL_HR); - fire_chainlightning(self, start, v, cl_dmg, 0, SKULL_ATTACK_RANGE, CLIGHTNING_INITIAL_HR, 4); - self->autocurse_delay = level.framenum + (int)(1 / FRAMETIME); - return; // done attacking - } - - //if (tr.ent->groundentity) - // knockback *= 2; - T_Damage(tr.ent, self, self, forward, tr.endpos, tr.plane.normal, - damage, 0, DAMAGE_ENERGY, MOD_SKULL); - } - - gi.WriteByte (svc_temp_entity); - gi.WriteByte (TE_MONSTER_HEATBEAM); - //gi.WriteByte (TE_LIGHTNING); - gi.WriteShort (self - g_edicts); - gi.WritePosition (start); - gi.WritePosition (tr.endpos); - gi.multicast (start, MULTICAST_PVS); - - if (!(sf2qf(level.framenum) % 10 )) - gi.sound(self, CHAN_ITEM, gi.soundindex("abilities/chargedbolt1.wav"), 1, ATTN_NORM, 0); +void skull_attack(edict_t *self) { + int damage; //, knockback; + float dist, chance; + vec3_t forward, start, end, v; + trace_t tr; + + skull_movetogoal(self, self->enemy); + + dist = entdist(self, self->enemy); + + if (!visible(self, self->enemy)) + return; + //if (!nearfov(self, self->enemy, 180, 180)) + //if (!infov(self, self->enemy, 216)) + if (!infront(self, self->enemy)) + return; + //gi.dprintf("hellspawn distance to enemy: %0.1f\n", dist); + if (dist > SKULL_ATTACK_RANGE) + return; + if (que_typeexists(self->curses, AURA_HOLYFREEZE) && !(level.framenum % 2)) + return; + + // chill effect reduces attack rate/refire + if (self->chill_time > level.time) { + chance = 1 / (1 + CHILL_DEFAULT_BASE + CHILL_DEFAULT_ADDON * self->chill_level); + if (random() > chance) + return; + } + + self->lastsound = level.framenum; + + // get muzzle origin + AngleVectors(self->s.angles, forward, NULL, NULL); + VectorCopy(self->s.origin, start); + start[2] = self->absmin[2] + 8; + VectorMA(start, self->maxs[1] + 1, forward, start); + + G_EntMidPoint(self->enemy, end); + + // get attack vector + VectorSubtract(end, start, v); + VectorNormalize(v); + //forward[2] = v[2]; + VectorMA(start, 8192, v, end); + + // do the damage, but only at 10 ticks per second + damage = self->dmg; + + //knockback = 2*damage; + tr = gi.trace(start, NULL, NULL, end, self, MASK_SHOT); + if (G_EntExists(tr.ent)) { + // damage to non-players is increased + //if (!tr.ent->client) + // damage *= 2; + // Talent: Hellspawn Mastery + // each talent upgrade increases the chance to proc a chainlightning attack + const float chance = 0.1 * self->light_level; + if (level.framenum > self->autocurse_delay && chance > random()) { + const int cl_dmg = 10 * damage; + //gi.dprintf("hellspawn firing CL. base dmg %d modified %d CL %d\n", self->dmg, damage, cl_dmg); + //ChainLightning(self, start, v, cl_dmg, SKULL_ATTACK_RANGE, CLIGHTNING_INITIAL_HR); + fire_chainlightning(self, start, v, cl_dmg, 0, SKULL_ATTACK_RANGE, CLIGHTNING_INITIAL_HR, 4); + self->autocurse_delay = level.framenum + (int) (1 / FRAMETIME); + return; // done attacking + } + + //if (tr.ent->groundentity) + // knockback *= 2; + if ((level.framenum % qf2sf(1)) == 0) { + T_Damage(tr.ent, self, self, forward, tr.endpos, tr.plane.normal, + damage, 0, DAMAGE_ENERGY, MOD_SKULL); + } + } + + gi.WriteByte(svc_temp_entity); +#ifndef VRX_REPRO + gi.WriteByte(TE_MONSTER_HEATBEAM); + gi.WriteShort(self - g_edicts); +#else + gi.WriteByte(TE_LIGHTNING); + gi.WriteShort(self - g_edicts); + gi.WriteShort(0); +#endif + gi.WritePosition(start); + gi.WritePosition(tr.endpos); + gi.multicast(start, MULTICAST_PVS); + + if (!(sf2qf(level.framenum) % 10)) + gi.sound(self, CHAN_ITEM, gi.soundindex("abilities/chargedbolt1.wav"), 1, ATTN_NORM, 0); } -void skull_runframes (edict_t *self) -{ - if (self->style == SKULL_ATTACK) - G_RunFrames(self, SKULL_FRAMES_ATTACK_START, SKULL_FRAMES_ATTACK_END, false); - else - G_RunFrames(self, SKULL_FRAMES_IDLE_START, SKULL_FRAMES_IDLE_END, false); +void skull_runframes(edict_t *self) { + if (self->style == SKULL_ATTACK) + G_RunFrames(self, SKULL_FRAMES_ATTACK_START, SKULL_FRAMES_ATTACK_END, false, true); + else + G_RunFrames(self, SKULL_FRAMES_IDLE_START, SKULL_FRAMES_IDLE_END, false, true); } -void skull_regenerate (edict_t *self) -{ - if (self->health < self->max_health) - self->health += self->max_health/SKULL_REGEN_FRAMES; - if (self->health > self->max_health) - self->health = self->max_health; +void skull_regenerate(edict_t *self) { + if (self->health < self->max_health) + self->health += self->max_health / SKULL_REGEN_FRAMES; + if (self->health > self->max_health) + self->health = self->max_health; } #define SKULL_RECALL_HEIGHT 64 #define SKULL_RECALL_RANGE 512 -void skull_recall (edict_t *self) -{ - vec3_t start; - -// if (!visible(self, self->activator) -// && (entdist(self->activator, self) > SKULL_RECALL_RANGE)) - if (level.time > self->monsterinfo.teleport_delay) - { - VectorCopy(self->activator->s.origin, start); - start[2] = self->activator->absmax[2]+SKULL_RECALL_HEIGHT; - - if (!G_IsClearPath(self->activator, MASK_SHOT, self->activator->s.origin, start)) - return; - if (!G_IsValidLocation(self, start, self->mins, self->maxs)) - return; - if (gi.pointcontents(start) & MASK_SOLID) - return; - - VectorCopy(start, self->s.origin); - VectorCopy(start, self->move_origin); // must set this or we may float up or down forever! - self->s.event = EV_PLAYER_TELEPORT; - - self->monsterinfo.teleport_delay = level.time + 1.0; - } +void skull_recall(edict_t *self) { + vec3_t start; + + // if (!visible(self, self->activator) + // && (entdist(self->activator, self) > SKULL_RECALL_RANGE)) + if (level.time > self->monsterinfo.teleport_delay) { + VectorCopy(self->activator->s.origin, start); + start[2] = self->activator->absmax[2] + SKULL_RECALL_HEIGHT; + + if (!G_IsClearPath(self->activator, MASK_SHOT, self->activator->s.origin, start)) + return; + if (!G_IsValidLocation(self, start, self->mins, self->maxs)) + return; + if (gi.pointcontents(start) & MASK_SOLID) + return; + + VectorCopy(start, self->s.origin); + VectorCopy(start, self->move_origin); // must set this or we may float up or down forever! + self->s.event = EV_PLAYER_TELEPORT; + + self->monsterinfo.teleport_delay = level.time + 1.0; + } } -void skull_idle (edict_t *self) -{ -// vec3_t start; - - if (self->lockon) - skull_recall(self); - - if (self->enemy) - //{ - self->enemy = NULL; - // VectorCopy(self->s.origin, self->move_origin); // this is the point we float up and down from -// } - /* - VectorCopy(self->s.origin, start); - if (self->style == SKULL_IDLE_UP) - { - start[2] += SKULL_FLOAT_SPEED; - if (start[2] >= self->move_origin[2]+SKULL_FLOAT_HEIGHT) - self->style = SKULL_IDLE_DOWN; - } - else - { - start[2] -= SKULL_FLOAT_SPEED; - if (start[2] <= self->move_origin[2]-SKULL_FLOAT_HEIGHT) - self->style = SKULL_IDLE_UP; - } - - if (!(gi.pointcontents(start) & MASK_SOLID)) - { - VectorCopy(start, self->s.origin); - gi.linkentity(self); - } +void skull_idle(edict_t *self) { + // vec3_t start; + + if (self->lockon) + skull_recall(self); + + if (self->enemy) + //{ + self->enemy = NULL; + // VectorCopy(self->s.origin, self->move_origin); // this is the point we float up and down from + // } + /* + VectorCopy(self->s.origin, start); + if (self->style == SKULL_IDLE_UP) + { + start[2] += SKULL_FLOAT_SPEED; + if (start[2] >= self->move_origin[2]+SKULL_FLOAT_HEIGHT) + self->style = SKULL_IDLE_DOWN; + } + else + { + start[2] -= SKULL_FLOAT_SPEED; + if (start[2] <= self->move_origin[2]-SKULL_FLOAT_HEIGHT) + self->style = SKULL_IDLE_UP; + } + + if (!(gi.pointcontents(start) & MASK_SOLID)) + { + VectorCopy(start, self->s.origin); + gi.linkentity(self); + } */ -// skull_regenerate(self); + // skull_regenerate(self); - self->style = 0; // reset to idle state + self->style = 0; // reset to idle state - self->monsterinfo.idle_frames++; + self->monsterinfo.idle_frames++; } -void skull_remove (edict_t *self) -{ - if (self->deadflag == DEAD_DEAD) - return; - - // reset owner's pointer to this entity - if (self->activator && self->activator->inuse) { - self->activator->skull = NULL; - - if (self->activator->client) - layout_remove_tracked_entity(&self->activator->client->layout, self); - } - AI_EnemyRemoved(self); - // prep for removal - self->think = BecomeExplosion1; - self->takedamage = DAMAGE_NO; - self->solid = SOLID_NOT; - self->deadflag = DEAD_DEAD; - self->svflags |= SVF_NOCLIENT; - self->nextthink = level.time + FRAMETIME; - gi.unlinkentity(self); +void skull_remove(edict_t *self) { + if (self->deadflag == DEAD_DEAD) + return; + + // reset owner's pointer to this entity + if (self->activator && self->activator->inuse) { + self->activator->skull = NULL; + + if (self->activator->client) + layout_remove_tracked_entity(&self->activator->client->layout, self); + } + AI_EnemyRemoved(self); + // prep for removal + self->think = BecomeExplosion1; + self->takedamage = DAMAGE_NO; + self->solid = SOLID_NOT; + self->deadflag = DEAD_DEAD; + self->svflags |= SVF_NOCLIENT; + self->nextthink = level.time + FRAMETIME; + gi.unlinkentity(self); } #define SKULL_FOLLOW_DISTANCE 512 // skull will move towards activator if this range is exceeded -void skull_return (edict_t *self) -{ - self->enemy = NULL; - - // is our activator visible? - if (visible(self, self->activator)) - { - // follow within defined range - if (entdist(self, self->activator) > SKULL_FOLLOW_DISTANCE) - { - skull_movetogoal(self, self->activator); - return; - } - } - // can't see activator, so teleport instead - else - skull_recall(self); - - // reset to idle state - self->style = 0; - self->monsterinfo.idle_frames++; +void skull_return(edict_t *self) { + self->enemy = NULL; + + // is our activator visible? + if (visible(self, self->activator)) { + // follow within defined range + if (entdist(self, self->activator) > SKULL_FOLLOW_DISTANCE) { + skull_movetogoal(self, self->activator); + return; + } + } + // can't see activator, so teleport instead + else + skull_recall(self); + + // reset to idle state + self->style = 0; + self->monsterinfo.idle_frames++; } -void skull_think (edict_t *self) -{ - if (!skull_checkposition(self)) - return; // skull was removed - - CTF_SummonableCheck(self); - - // hellspawn will auto-remove if it is asked to - if (self->removetime > 0) - { - qboolean converted=false; - - if (self->flags & FL_CONVERTED) - converted = true; - - if (level.time > self->removetime) - { - if (!RestorePreviousOwner(self)) - { - skull_remove(self); - return; - } - } - // warn the converted monster's current owner - else if (converted && self->activator && self->activator->inuse && self->activator->client - && (level.time > self->removetime-5) && !(sf2qf(level.framenum)%10)) - safe_cprintf(self->activator, PRINT_HIGH, "%s conversion will expire in %.0f seconds\n", - V_GetMonsterName(self), self->removetime-level.time); - } - - if (!M_Upkeep(self, 1 / FRAMETIME, 2)) - return; - - // hellspawn can't lock-on to enemy easily while cursed - if ((level.time > self->wait) && que_typeexists(self->curses, CURSE) - && (random() <= 0.2)) - self->wait = level.time + 2*random(); - - if (self->linkcount != self->monsterinfo.linkcount) - { - self->monsterinfo.linkcount = self->linkcount; - M_CheckGround(self); - } - - // hellspawn is stunned - if (self->holdtime > level.time || que_typeexists(self->curses, CURSE_FROZEN)) - { - // reset to idle state - self->style = 0; - self->monsterinfo.idle_frames++; - self->enemy = NULL; - skull_runframes(self); - M_SetEffects(self); - self->nextthink = level.time + FRAMETIME; - return; - } - - //if (!self->enemy) - // skull_findtarget(self); - if (G_ValidTarget(self, self->enemy, false, true) // is the target still valid? - && entdist(self->activator, self->enemy) <= SKULL_MAX_RANGE) // make sure the target isn't too far from activator (don't wander) - { - if (!visible(self, self->enemy)) - { - // try to find an easier target - if (!skull_findtarget(self)) - self->monsterinfo.search_frames++; - - // give up searching for enemy after awhile - if (self->monsterinfo.search_frames > SKULL_SEARCH_TIMEOUT) - { - self->enemy = NULL; - skull_idle(self); //skull_return(self); - self->nextthink = level.time + FRAMETIME; - return; - } - } - else - self->monsterinfo.search_frames = 0; - - //gi.dprintf("hellspawn is attacking %s\n", self->enemy->classname); - skull_attack(self); - } - else - { - // no target or target isn't valid - self->enemy = NULL; - // try to find another target, otherwise return to the activator - if (skull_findtarget(self)) - skull_attack(self); - else - skull_return(self);//skull_idle(self); - } - - skull_runframes(self); - M_SetEffects(self); - - self->nextthink = level.time + FRAMETIME; +void skull_think(edict_t *self) { + if (!skull_checkposition(self)) + return; // skull was removed + + CTF_SummonableCheck(self); + + // hellspawn will auto-remove if it is asked to + if (self->removetime > 0) { + qboolean converted = false; + + if (self->flags & FL_CONVERTED) + converted = true; + + if (level.time > self->removetime) { + if (!RestorePreviousOwner(self)) { + skull_remove(self); + return; + } + } + // warn the converted monster's current owner + else if (converted && self->activator && self->activator->inuse && self->activator->client + && (level.time > self->removetime - 5) && !(sf2qf(level.framenum) % 10)) + safe_cprintf(self->activator, PRINT_HIGH, "%s conversion will expire in %.0f seconds\n", + V_GetMonsterName(self), self->removetime - level.time); + } + + if (!M_Upkeep(self, 1 / FRAMETIME, 2)) + return; + + // hellspawn can't lock-on to enemy easily while cursed + if ((level.time > self->wait) && que_typeexists(self->curses, CURSE) + && (random() <= 0.2)) + self->wait = level.time + 2 * random(); + + if (self->linkcount != self->monsterinfo.linkcount) { + self->monsterinfo.linkcount = self->linkcount; + M_CheckGround(self); + } + + // hellspawn is stunned + if (self->holdtime > level.time || que_typeexists(self->curses, CURSE_FROZEN)) { + // reset to idle state + self->style = 0; + self->monsterinfo.idle_frames++; + self->enemy = NULL; + skull_runframes(self); + M_SetEffects(self); + self->nextthink = level.time + FRAMETIME; + return; + } + + //if (!self->enemy) + // skull_findtarget(self); + if (G_ValidTarget(self, self->enemy, false, true) // is the target still valid? + && entdist(self->activator, self->enemy) <= SKULL_MAX_RANGE) + // make sure the target isn't too far from activator (don't wander) + { + if (!visible(self, self->enemy)) { + // try to find an easier target + if (!skull_findtarget(self)) + self->monsterinfo.search_frames++; + + // give up searching for enemy after awhile + if (self->monsterinfo.search_frames > SKULL_SEARCH_TIMEOUT) { + self->enemy = NULL; + skull_idle(self); //skull_return(self); + self->nextthink = level.time + FRAMETIME; + return; + } + } else + self->monsterinfo.search_frames = 0; + + //gi.dprintf("hellspawn is attacking %s\n", self->enemy->classname); + skull_attack(self); + } else { + // no target or target isn't valid + self->enemy = NULL; + // try to find another target, otherwise return to the activator + if (skull_findtarget(self)) + skull_attack(self); + else + skull_return(self); //skull_idle(self); + } + + skull_runframes(self); + M_SetEffects(self); + + self->nextthink = level.time + FRAMETIME; } -void skull_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) -{ - safe_centerprintf(self->activator, "Hell spawn died.\n"); - skull_remove(self); +void skull_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) { + safe_centerprintf(self->activator, "Hell spawn died.\n"); + skull_remove(self); } -void skull_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) -{ - vec3_t forward, right, start, offset; +void skull_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) { + vec3_t forward, right, start, offset; - V_Touch(self, other, plane, surf); + V_Touch(self, other, plane, surf); - if (other && other->inuse && other->client && self->activator - && (other == self->activator || IsAlly(self->activator, other))) - { - AngleVectors (other->client->v_angle, forward, right, NULL); - VectorScale (forward, -3, other->client->kick_origin); - VectorSet(offset, 0, 7, other->viewheight-8); - P_ProjectSource (other->client, other->s.origin, offset, forward, right, start); + if (other && other->inuse && other->client && self->activator + && (other == self->activator || IsAlly(self->activator, other))) { + AngleVectors(other->client->v_angle, forward, right, NULL); + VectorScale(forward, -3, other->client->kick_origin); + VectorSet(offset, 0, 7, other->viewheight-8); + P_ProjectSource(other->client, other->s.origin, offset, forward, right, start); - self->velocity[0] += forward[0] * 100; - self->velocity[1] += forward[1] * 100; - self->velocity[2] += forward[2] * 100; - } + self->velocity[0] += forward[0] * 100; + self->velocity[1] += forward[1] * 100; + self->velocity[2] += forward[2] * 100; + } } float vrx_increase_monster_damage_by_talent(edict_t *owner, float damage); -void SpawnSkull (edict_t *ent) -{ - int cost = SKULL_COST; - float mult = 1.0; - vec3_t forward, right, start, end, offset; - edict_t *skull, *ignore = ent; - trace_t tr; - - //gi.dprintf("SpawnSkull\n"); - - // cost is doubled if you are a flyer below skill level 5 - if (ent->mtype == MORPH_FLYER && ent->myskills.abilities[FLYER].current_level < 5) - cost *= 2; - - skull = G_Spawn(); - skull->svflags |= SVF_MONSTER; - skull->classname = "hellspawn"; - skull->yaw_speed = 30; - skull->s.effects |= EF_PLASMA; - skull->activator = ent; - skull->takedamage = DAMAGE_YES; - skull->monsterinfo.level = ent->myskills.abilities[HELLSPAWN].current_level; // used for monster exp - skull->light_level = vrx_get_talent_level(ent, TALENT_HELLSPAWN_MASTERY); // Talent: Hellspawn Mastery - skull->monsterinfo.control_cost = 3; // used for monster exp - skull->health = SKULL_INITIAL_HEALTH + SKULL_ADDON_HEALTH*ent->myskills.abilities[HELLSPAWN].current_level;//ent->myskills.level; - skull->dmg = SKULL_INITIAL_DAMAGE + SKULL_ADDON_DAMAGE*ent->myskills.abilities[HELLSPAWN].current_level;//*ent->myskills.level; - //gi.dprintf("skull base dmg %d at creation\n", skull->dmg); - skull->dmg *= 1.0 + 0.1 * skull->light_level; // Talent: Hellspawn Mastery increases damage - //gi.dprintf("skull dmg %d with talent %d\n", skull->dmg, skull->light_level); - - // az: add decino's fix from vrx-indy - // az: un-add. let's make a new talent for this. -// skull->dmg = vrx_increase_monster_damage_by_talent(ent, skull->dmg); -// -// if ((ent && ent->inuse && ent->client) || (skull->activator && skull->activator->inuse && skull->activator->client)) -// { -// int talentLevel = vrx_get_talent_level(ent, TALENT_CORPULENCE); -// int talentLevel2 = vrx_get_talent_level(ent, TALENT_LIFE_TAP); -// if(talentLevel > 0) mult += 0.3 * talentLevel; //+30% per upgrade -// if(talentLevel2 > 0) mult += 1.1 * talentLevel2; -// } - skull->health *= mult; - - skull->max_health = skull->health; - skull->gib_health = -BASE_GIB_HEALTH * 1.5; - skull->mass = 200; - skull->monsterinfo.power_armor_power = 0; - skull->monsterinfo.power_armor_type = POWER_ARMOR_NONE; - skull->clipmask = MASK_MONSTERSOLID; - skull->movetype = MOVETYPE_FLY; - skull->s.renderfx |= RF_IR_VISIBLE; - // nope - //skull->flags |= FL_CHASEABLE; // 3.65 indicates entity can be chase cammed - skull->solid = SOLID_BBOX; - skull->think = skull_think; - skull->die = skull_die; - skull->mtype = M_SKULL; - skull->touch = skull_touch; - VectorSet(skull->mins, -16, -16, -16); - VectorSet(skull->maxs, 16, 16, 16); - skull->s.modelindex = gi.modelindex("models/skull/tris.md2"); - skull->nextthink = level.time + SKULL_DELAY; - skull->monsterinfo.upkeep_delay = skull->nextthink + 1 / FRAMETIME; // 3.2 upkeep starts 1 second after spawn - skull->monsterinfo.cost = cost; - - AngleVectors (ent->client->v_angle, forward, right, NULL); - VectorScale (forward, -3, ent->client->kick_origin); - VectorSet(offset, 0, 7, ent->viewheight-8); - P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start); - VectorMA(start, 64, forward, end); - - if (PM_PlayerHasMonster(ent)) - ignore = ent->owner; - - tr = gi.trace(start, skull->mins, skull->maxs, end, ignore, MASK_SHOT); - - if (tr.fraction < 1) - { - //gi.dprintf("tr.ent %s allsolid %d startsolid %d fraction %.1f\n", tr.ent->classname, tr.allsolid, tr.startsolid, tr.fraction); - G_FreeEdict(skull); - return; - } - - if (ent->client) - layout_add_tracked_entity(&ent->client->layout, skull); - AI_EnemyAdded(skull); - - VectorCopy(end, skull->s.origin); - VectorCopy(end, skull->move_origin); - gi.linkentity(skull); - - ent->skull = skull; - ent->client->pers.inventory[power_cube_index] -= cost; - ent->client->ability_delay = level.time + SKULL_DELAY; - ent->holdtime = level.time + SKULL_DELAY; +void SpawnSkull(edict_t *ent) { + int cost = SKULL_COST; + const float mult = 1.0; + vec3_t forward, right, start, end, offset; + edict_t *skull, *ignore = ent; + trace_t tr; + + //gi.dprintf("SpawnSkull\n"); + + // cost is doubled if you are a flyer below skill level 5 + if (ent->mtype == MORPH_FLYER && ent->myskills.abilities[FLYER].current_level < 5) + cost *= 2; + + skull = G_Spawn(); + skull->svflags |= SVF_MONSTER; + skull->classname = "hellspawn"; + skull->yaw_speed = 30; + skull->s.effects |= EF_PLASMA; + skull->activator = ent; + skull->takedamage = DAMAGE_YES; + skull->monsterinfo.level = ent->myskills.abilities[HELLSPAWN].current_level; // used for monster exp + skull->light_level = vrx_get_talent_level(ent, TALENT_HELLSPAWN_MASTERY); // Talent: Hellspawn Mastery + skull->monsterinfo.control_cost = 3; // used for monster exp + skull->health = SKULL_INITIAL_HEALTH + SKULL_ADDON_HEALTH * ent->myskills.abilities[HELLSPAWN].current_level; + //ent->myskills.level; + skull->dmg = SKULL_INITIAL_DAMAGE + SKULL_ADDON_DAMAGE * ent->myskills.abilities[HELLSPAWN].current_level; + //*ent->myskills.level; + //gi.dprintf("skull base dmg %d at creation\n", skull->dmg); + skull->dmg *= 1.0 + 0.1 * skull->light_level; // Talent: Hellspawn Mastery increases damage + //gi.dprintf("skull dmg %d with talent %d\n", skull->dmg, skull->light_level); + + // az: add decino's fix from vrx-indy + // az: un-add. let's make a new talent for this. + // skull->dmg = vrx_increase_monster_damage_by_talent(ent, skull->dmg); + // + // if ((ent && ent->inuse && ent->client) || (skull->activator && skull->activator->inuse && skull->activator->client)) + // { + // int talentLevel = vrx_get_talent_level(ent, TALENT_CORPULENCE); + // int talentLevel2 = vrx_get_talent_level(ent, TALENT_LIFE_TAP); + // if(talentLevel > 0) mult += 0.3 * talentLevel; //+30% per upgrade + // if(talentLevel2 > 0) mult += 1.1 * talentLevel2; + // } + skull->health *= mult; + + skull->max_health = skull->health; + skull->gib_health = -BASE_GIB_HEALTH * 1.5; + skull->mass = 200; + skull->monsterinfo.power_armor_power = 0; + skull->monsterinfo.power_armor_type = POWER_ARMOR_NONE; + skull->clipmask = MASK_MONSTERSOLID; + skull->movetype = MOVETYPE_FLY; + skull->s.renderfx |= RF_IR_VISIBLE; + // nope + //skull->flags |= FL_CHASEABLE; // 3.65 indicates entity can be chase cammed + skull->solid = SOLID_BBOX; + skull->think = skull_think; + skull->die = skull_die; + skull->mtype = M_SKULL; + skull->touch = skull_touch; + VectorSet(skull->mins, -16, -16, -16); + VectorSet(skull->maxs, 16, 16, 16); + skull->s.modelindex = gi.modelindex("models/skull/tris.md2"); + skull->nextthink = level.time + SKULL_DELAY; + skull->monsterinfo.upkeep_delay = skull->nextthink + 1 / FRAMETIME; // 3.2 upkeep starts 1 second after spawn + skull->monsterinfo.cost = cost; + + AngleVectors(ent->client->v_angle, forward, right, NULL); + VectorScale(forward, -3, ent->client->kick_origin); + VectorSet(offset, 0, 7, ent->viewheight-8); + P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); + VectorMA(start, 64, forward, end); + + if (PM_PlayerHasMonster(ent)) + ignore = ent->owner; + + tr = gi.trace(start, skull->mins, skull->maxs, end, ignore, MASK_SHOT); + + if (tr.fraction < 1) { + //gi.dprintf("tr.ent %s allsolid %d startsolid %d fraction %.1f\n", tr.ent->classname, tr.allsolid, tr.startsolid, tr.fraction); + G_FreeEdict(skull); + return; + } + + if (ent->client) + layout_add_tracked_entity(&ent->client->layout, skull); + AI_EnemyAdded(skull); + + VectorCopy(end, skull->s.origin); + VectorCopy(end, skull->move_origin); + gi.linkentity(skull); + + ent->skull = skull; + ent->client->pers.inventory[power_cube_index] -= cost; + ent->client->ability_delay = level.time + SKULL_DELAY; + ent->holdtime = level.time + SKULL_DELAY; } -void RemoveHellspawn (edict_t *ent) -{ - if (ent->skull && ent->skull->inuse) - skull_remove(ent->skull); +void RemoveHellspawn(edict_t *ent) { + if (ent->skull && ent->skull->inuse) + skull_remove(ent->skull); } -void skull_attackcmd (edict_t *self) -{ - vec3_t forward, right, start, end, offset; - trace_t tr; +void skull_attackcmd(edict_t *self) { + vec3_t forward, right, start, end, offset; + trace_t tr; - AngleVectors (self->activator->client->v_angle, forward, right, NULL); - VectorSet(offset, 0, 7, self->activator->viewheight-8); - P_ProjectSource (self->activator->client, self->activator->s.origin, offset, forward, right, start); - - VectorMA(start, 8192, forward, end); + AngleVectors(self->activator->client->v_angle, forward, right, NULL); + VectorSet(offset, 0, 7, self->activator->viewheight-8); + P_ProjectSource(self->activator->client, self->activator->s.origin, offset, forward, right, start); - tr = gi.trace(start, NULL, NULL, end, self->activator, MASK_SHOT); + VectorMA(start, 8192, forward, end); - if (G_ValidTarget(self, tr.ent, false, true)) - { - self->enemy = tr.ent; - self->monsterinfo.search_frames = 0; - safe_cprintf(self->activator, PRINT_HIGH, "Skull will attack target.\n"); - } + tr = gi.trace(start, NULL, NULL, end, self->activator, MASK_SHOT); + if (G_ValidTarget(self, tr.ent, false, true)) { + self->enemy = tr.ent; + self->monsterinfo.search_frames = 0; + safe_cprintf(self->activator, PRINT_HIGH, "Skull will attack target.\n"); + } } -void Cmd_HellSpawn_f (edict_t *ent) -{ - int cost = SKULL_COST; - - if (debuginfo->value) - gi.dprintf("DEBUG: %s just called Cmd_HellSpawn_f()\n", ent->client->pers.netname); - - if (!Q_strcasecmp(gi.args(), "attack") && ent->skull && ent->skull->inuse) - { - skull_attackcmd(ent->skull); - return; - } - - if (!Q_strcasecmp(gi.args(), "recall") && ent->skull && ent->skull->inuse) - { - // toggle - if (!ent->skull->lockon) - { - safe_cprintf(ent, PRINT_HIGH, "Hellspawn recall enabled.\n"); - ent->skull->lockon = 1; - } - else - { - safe_cprintf(ent, PRINT_HIGH, "Hellspawn recall disabled.\n"); - ent->skull->lockon = 0; - } - return; - } - - if (G_EntExists(ent->skull)) - { - // try to restore previous owner - if (!RestorePreviousOwner(ent->skull)) - { - if (ent->skull->health >= ent->skull->max_health) - ent->client->pers.inventory[power_cube_index] += ent->skull->monsterinfo.cost; - RemoveHellspawn(ent); - safe_cprintf(ent, PRINT_HIGH, "Hell spawn removed.\n"); - } - else - { - safe_cprintf(ent, PRINT_HIGH, "Conversion removed.\n"); - } - return; - } - - if(ent->myskills.abilities[HELLSPAWN].disable) - return; - - // cost is doubled if you are a flyer below skill level 5 - if (ent->mtype == MORPH_FLYER && ent->myskills.abilities[FLYER].current_level < 5) - cost *= 2; - - if (!G_CanUseAbilities(ent, ent->myskills.abilities[HELLSPAWN].current_level, cost)) - { - //gi.dprintf("cant use abilities\n"); - return; - } - if (ctf->value && (CTF_DistanceFromBase(ent, NULL, CTF_GetEnemyTeam(ent->teamnum)) < CTF_BASE_DEFEND_RANGE)) - { - safe_cprintf(ent, PRINT_HIGH, "Can't build in enemy base!\n"); - return; - } - - SpawnSkull(ent); +void Cmd_HellSpawn_f(edict_t *ent) { + int cost = SKULL_COST; + + if (debuginfo->value) + gi.dprintf("DEBUG: %s just called Cmd_HellSpawn_f()\n", ent->client->pers.netname); + + if (!Q_strcasecmp(gi.args(), "attack") && ent->skull && ent->skull->inuse) { + skull_attackcmd(ent->skull); + return; + } + + if (!Q_strcasecmp(gi.args(), "recall") && ent->skull && ent->skull->inuse) { + // toggle + if (!ent->skull->lockon) { + safe_cprintf(ent, PRINT_HIGH, "Hellspawn recall enabled.\n"); + ent->skull->lockon = 1; + } else { + safe_cprintf(ent, PRINT_HIGH, "Hellspawn recall disabled.\n"); + ent->skull->lockon = 0; + } + return; + } + + if (G_EntExists(ent->skull)) { + // try to restore previous owner + if (!RestorePreviousOwner(ent->skull)) { + if (ent->skull->health >= ent->skull->max_health) + ent->client->pers.inventory[power_cube_index] += ent->skull->monsterinfo.cost; + RemoveHellspawn(ent); + safe_cprintf(ent, PRINT_HIGH, "Hell spawn removed.\n"); + } else { + safe_cprintf(ent, PRINT_HIGH, "Conversion removed.\n"); + } + return; + } + + if (ent->myskills.abilities[HELLSPAWN].disable) + return; + + // cost is doubled if you are a flyer below skill level 5 + if (ent->mtype == MORPH_FLYER && ent->myskills.abilities[FLYER].current_level < 5) + cost *= 2; + + if (!G_CanUseAbilities(ent, ent->myskills.abilities[HELLSPAWN].current_level, cost)) { + //gi.dprintf("cant use abilities\n"); + return; + } + if (ctf->value && (CTF_DistanceFromBase(ent, NULL, CTF_GetEnemyTeam(ent->teamnum)) < CTF_BASE_DEFEND_RANGE)) { + safe_cprintf(ent, PRINT_HIGH, "Can't build in enemy base!\n"); + return; + } + + SpawnSkull(ent); } diff --git a/src/combat/abilities/gloom.c b/src/combat/abilities/gloom.c index 8efc3f7f..0571092d 100644 --- a/src/combat/abilities/gloom.c +++ b/src/combat/abilities/gloom.c @@ -12,7 +12,7 @@ static int sound_gas; // az's note for anyone who looks at this in the future: for organ_touch void V_Push (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) { - float maxvel = 300; + const float maxvel = 300; // our activator or ally can push us if (other && other->inuse && other->client && self->activator && self->activator->inuse @@ -419,7 +419,7 @@ qboolean healer_heal (edict_t *self, edict_t *other) // but used G_EntIsAlive for consistency. //if (G_EntIsAlive(other) && G_EntIsAlive(self) && OnSameTeam(self, other) && other != self) //{ - int frames = qf2sf(5000 / (15 * self->monsterinfo.level)); // idk how much would this change tbh + const int frames = qf2sf(5000 / (15 * self->monsterinfo.level)); // idk how much would this change tbh value = 1.0f + 0.1f * vrx_get_talent_level(self->activator, TALENT_SUPER_HEALER); @@ -546,7 +546,7 @@ void healer_healeffects(edict_t* self, edict_t *target) void healer_attack (edict_t *self) { edict_t* target =NULL; - float range = self->monsterinfo.sight_range; + const float range = self->monsterinfo.sight_range; //vec3_t start, end, forward;//, angles; //trace_t tr; @@ -613,7 +613,7 @@ void healer_think (edict_t *self) } } - G_RunFrames(self, HEALER_FRAMES_START, HEALER_FRAMES_END, false); + G_RunFrames(self, HEALER_FRAMES_START, HEALER_FRAMES_END, false, true); self->nextthink = level.time + FRAMETIME; } @@ -664,7 +664,7 @@ void healer_grow (edict_t *self) if (self->s.frame == HEALER_FRAMES_GROW_START) gi.sound(self, CHAN_VOICE, gi.soundindex("organ/organe3.wav"), 1, ATTN_STATIC, 0); - G_RunFrames(self, HEALER_FRAMES_GROW_START, HEALER_FRAMES_GROW_END, false); + G_RunFrames(self, HEALER_FRAMES_GROW_START, HEALER_FRAMES_GROW_END, false, true); } void healer_dead (edict_t *self) @@ -873,8 +873,8 @@ void spiker_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damag void spiker_attack (edict_t *self) { float dist, chance = 0.05 * self->light_level; // Talent: Deadly Spikes gives 5% chance/level to stun - float range=SPIKER_INITIAL_RANGE+SPIKER_ADDON_RANGE*self->monsterinfo.level; - int speed=SPIKER_INITIAL_SPEED+SPIKER_ADDON_SPEED*self->monsterinfo.level; + const float range=SPIKER_INITIAL_RANGE+SPIKER_ADDON_RANGE*self->monsterinfo.level; + const int speed=SPIKER_INITIAL_SPEED+SPIKER_ADDON_SPEED*self->monsterinfo.level; vec3_t forward, start, end; edict_t *e=NULL; @@ -981,12 +981,12 @@ void spiker_think (edict_t *self) if (self->monsterinfo.attack_finished - 0.5 > level.time) { if (self->s.frame != SPIKER_FRAME_READY) - G_RunFrames(self, SPIKER_FRAMES_NOAMMO_START, SPIKER_FRAMES_NOAMMO_END, false); + G_RunFrames(self, SPIKER_FRAMES_NOAMMO_START, SPIKER_FRAMES_NOAMMO_END, false, true); } else { if (self->s.frame != SPIKER_FRAME_READY && self->s.frame != SPIKER_FRAMES_REARM_END) - G_RunFrames(self, SPIKER_FRAMES_REARM_START, SPIKER_FRAMES_REARM_END, false); + G_RunFrames(self, SPIKER_FRAMES_REARM_START, SPIKER_FRAMES_REARM_END, false, true); else self->s.frame = SPIKER_FRAME_READY; } @@ -1061,7 +1061,7 @@ void spiker_grow (edict_t *self) gi.sound(self, CHAN_VOICE, gi.soundindex("organ/organe3.wav"), 1, ATTN_NORM, 0); if (self->s.frame != SPIKER_FRAMES_GROW_END) - G_RunFrames(self, SPIKER_FRAMES_GROW_START, SPIKER_FRAMES_GROW_END, false); + G_RunFrames(self, SPIKER_FRAMES_GROW_START, SPIKER_FRAMES_GROW_END, false, true); } edict_t *CreateSpiker (edict_t *ent, int skill_level) @@ -1202,7 +1202,7 @@ void obstacle_return(edict_t* self) void obstacle_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) { - int max = OBSTACLE_MAX_COUNT; + const int max = OBSTACLE_MAX_COUNT; int cur; qboolean flipped = false; @@ -1512,7 +1512,7 @@ void obstacle_grow (edict_t *self) gi.sound(self, CHAN_VOICE, gi.soundindex("organ/organe3.wav"), 1, ATTN_NORM, 0); if (self->s.frame != OBSTACLE_FRAMES_GROW_END) - G_RunFrames(self, OBSTACLE_FRAMES_GROW_START, OBSTACLE_FRAMES_GROW_END, false); + G_RunFrames(self, OBSTACLE_FRAMES_GROW_START, OBSTACLE_FRAMES_GROW_END, false, true); } edict_t *CreateObstacle (edict_t *ent, int skill_level, int talent_level) @@ -1678,7 +1678,7 @@ void poison_think (edict_t *self) { //self->dmg_counter += self->dmg; T_Damage(self->enemy, self, self->activator, vec3_origin, self->enemy->s.origin, vec3_origin, self->dmg, 0, 0, self->style); - self->monsterinfo.nextattack = level.framenum + floattoint(self->random); + self->monsterinfo.nextattack = level.framenum + qf2sf( floattoint(self->random) ); self->random *= 1.25; } @@ -1697,7 +1697,7 @@ void CreatePoison (edict_t *ent, edict_t *targ, int damage, float duration, int e->classname = "poison"; e->delay = level.time + duration; e->owner = e->enemy = targ; - e->random = 1; // starting refire delay (in frames) + e->random = 1; // starting refire delay (in quake frames) e->dmg = damage; e->mtype = e->atype = POISON; e->style = meansOfDeath; @@ -1740,11 +1740,11 @@ void gascloud_runframes (edict_t *self) { if (level.time > self->delay - 0.8) { - G_RunFrames(self, GASCLOUD_FRAMES_GROW_START, GASCLOUD_FRAMES_GROW_END, true); + G_RunFrames(self, GASCLOUD_FRAMES_GROW_START, GASCLOUD_FRAMES_GROW_END, true, true); self->s.effects |= EF_SPHERETRANS; } else if (self->s.frame < GASCLOUD_FRAMES_GROW_END) - G_RunFrames(self, GASCLOUD_FRAMES_GROW_START, GASCLOUD_FRAMES_GROW_END, false); + G_RunFrames(self, GASCLOUD_FRAMES_GROW_START, GASCLOUD_FRAMES_GROW_END, false, true); } void poison_curse_sound(edict_t* self) @@ -1769,7 +1769,7 @@ void poison_target(edict_t* ent, edict_t* target, int damage, float duration, in if (!stack) // stacking of poison curses is not allowed, so refresh the curse instead { slot->ent->random = 1; // initial refire delay for next attack - slot->ent->monsterinfo.nextattack = level.framenum + 1; // next attack server frame + slot->ent->monsterinfo.nextattack = level.framenum + qf2sf(1); slot->ent->delay = level.time + duration; slot->time = level.time + duration; return; @@ -1938,7 +1938,7 @@ void tempent_ball_think(edict_t* self) return; } - G_RunFrames(self, 0, 7, false); + G_RunFrames(self, 0, 7, false, true); self->nextthink = level.time + FRAMETIME; } @@ -2139,7 +2139,7 @@ void gasser_acidattack (edict_t *self) { float dist, chance; //float range=self->monsterinfo.sight_range; - int speed= ACID_INITIAL_SPEED; + const int speed= ACID_INITIAL_SPEED; vec3_t forward, start, end; edict_t *e=NULL; @@ -2249,13 +2249,13 @@ void gasser_think (edict_t *self) //gi.dprintf("cant attack\n"); if (self->s.frame < GASSER_FRAMES_ATTACK_END) - G_RunFrames(self, GASSER_FRAMES_ATTACK_START, GASSER_FRAMES_ATTACK_END, false); + G_RunFrames(self, GASSER_FRAMES_ATTACK_START, GASSER_FRAMES_ATTACK_END, false, true); else if (self->s.frame < GASSER_FRAMES_REARM_END && level.time > self->monsterinfo.attack_finished - 0.2) - G_RunFrames(self, GASSER_FRAMES_REARM_START, GASSER_FRAMES_REARM_END, false); + G_RunFrames(self, GASSER_FRAMES_REARM_START, GASSER_FRAMES_REARM_END, false, true); else if (level.time > self->monsterinfo.attack_finished) { gascloud_sparks(self, 1, 32); - G_RunFrames(self, GASSER_FRAMES_IDLE_START, GASSER_FRAMES_IDLE_END, false); + G_RunFrames(self, GASSER_FRAMES_IDLE_START, GASSER_FRAMES_IDLE_END, false, true); } } @@ -2381,7 +2381,7 @@ void gasser_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damag edict_t *CreateGasser (edict_t *ent, int skill_level, int talent_level) { - float synergy_bonus = vrx_get_synergy_mult(ent, GASSER); + const float synergy_bonus = vrx_get_synergy_mult(ent, GASSER); edict_t *e; // initialize sound @@ -2624,8 +2624,8 @@ void cocoon_attack (edict_t *self) if (level.framenum >= self->monsterinfo.nextattack) { int heal; - float duration = COCOON_INITIAL_TIME + COCOON_ADDON_TIME * self->monsterinfo.level; - float factor = COCOON_INITIAL_FACTOR + COCOON_ADDON_FACTOR * self->monsterinfo.level; + const float duration = COCOON_INITIAL_TIME + COCOON_ADDON_TIME * self->monsterinfo.level; + const float factor = COCOON_INITIAL_FACTOR + COCOON_ADDON_FACTOR * self->monsterinfo.level; // give them a damage/defense bonus for awhile self->enemy->cocoon_time = level.time + duration; @@ -2637,7 +2637,7 @@ void cocoon_attack (edict_t *self) if (self->enemy->client && !self->enemy->ai.is_bot) gi.cprintf(self->enemy, PRINT_HIGH, "You have gained a damage/defense bonus of +%.0f%c for %.0f seconds\n", - (factor * 100) - 100, '%', duration); + (factor * 100) - 100, '%', duration); //4.4 give some health heal = self->enemy->max_health * (0.25 + (0.075 * self->monsterinfo.level)); @@ -2656,6 +2656,7 @@ void cocoon_attack (edict_t *self) self->enemy->svflags &= ~SVF_NOCLIENT; self->enemy->movetype = self->count; self->enemy->flags &= ~FL_COCOONED;//4.4 + self->enemy->holdtime = 0; // self->owner = self->enemy; self->enemy = NULL; self->s.frame = COCOON_FRAME_STANDBY; @@ -2664,11 +2665,17 @@ void cocoon_attack (edict_t *self) return; } - if (!(level.framenum % (int)(sv_fps->value)) && self->enemy->client) - safe_cprintf(self->enemy, PRINT_HIGH, "You will emerge from the cocoon in %d second(s)\n", - (int)((self->monsterinfo.nextattack - level.framenum) * FRAMETIME)); + const auto frames_left = (int)(self->monsterinfo.nextattack - level.framenum); + const int secs_left = (int)((float)frames_left * FRAMETIME); + if (frames_left % (int)sv_fps->value == 0 && self->enemy->client) + safe_cprintf( + self->enemy, + PRINT_HIGH, + "You will emerge from the cocoon in %d second(s)\n", + secs_left + ); - time = level.time + FRAMETIME; + time = level.time + qf2sf(1); // hold target in-place if (!strcmp(self->enemy->classname, "drone")) @@ -2720,8 +2727,6 @@ void cocoon_attack (edict_t *self) void cocoon_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf) { - int frames; - V_Touch(ent, other, plane, surf); if (!ent->groundentity || ent->groundentity != world) @@ -2737,10 +2742,10 @@ void cocoon_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *su ent->enemy = other; - frames = COCOON_INITIAL_DURATION + COCOON_ADDON_DURATION * ent->monsterinfo.level; + int frames = COCOON_INITIAL_DURATION + COCOON_ADDON_DURATION * ent->monsterinfo.level; if (frames < COCOON_MINIMUM_DURATION) frames = COCOON_MINIMUM_DURATION; - ent->monsterinfo.nextattack = level.framenum + sf2qf(frames); + ent->monsterinfo.nextattack = level.framenum + qf2sf(frames); // don't let them move (or fall out of the map) ent->count = other->movetype; @@ -2807,9 +2812,10 @@ void cocoon_think (edict_t *self) } return; } - else if (self->s.frame > COCOON_FRAME_STANDBY && self->s.frame < COCOON_FRAMES_GROW_END) + + if (self->s.frame > COCOON_FRAME_STANDBY && self->s.frame < COCOON_FRAMES_GROW_END) { - G_RunFrames(self, COCOON_FRAMES_GROW_START, COCOON_FRAMES_GROW_END, false); + G_RunFrames(self, COCOON_FRAMES_GROW_START, COCOON_FRAMES_GROW_END, false, true); } else if (self->s.frame == COCOON_FRAMES_GROW_END) { @@ -2818,7 +2824,7 @@ void cocoon_think (edict_t *self) self->s.frame = COCOON_FRAMES_IDLE_START; } else - G_RunFrames(self, COCOON_FRAMES_IDLE_START, COCOON_FRAMES_IDLE_END, false); + G_RunFrames(self, COCOON_FRAMES_IDLE_START, COCOON_FRAMES_IDLE_END, false, true); } edict_t *CreateCocoon (edict_t *ent, int skill_level) @@ -2967,7 +2973,7 @@ void spikeball_move (edict_t *self) { vec3_t start, forward, end, goalpos; trace_t tr; - float max_velocity = 350; + const float max_velocity = 350; if (self->monsterinfo.attack_finished > level.time) return; @@ -3248,10 +3254,10 @@ void Cmd_TossSpikeball (edict_t *ent) { int talentLevel; int cost = SPIKEBALL_COST, max_count = SPIKEBALL_MAX_COUNT; - int health = SPIKEBALL_INITIAL_HEALTH + SPIKEBALL_ADDON_HEALTH * ent->myskills.abilities[SPORE].current_level; + const int health = SPIKEBALL_INITIAL_HEALTH + SPIKEBALL_ADDON_HEALTH * ent->myskills.abilities[SPORE].current_level; int damage = SPIKEBALL_INITIAL_DAMAGE + SPIKEBALL_ADDON_DAMAGE * ent->myskills.abilities[SPORE].current_level; - float duration = SPIKEBALL_INITIAL_DURATION + SPIKEBALL_ADDON_DURATION * ent->myskills.abilities[SPORE].current_level; - float range = SPIKEBALL_INITIAL_RANGE + SPIKEBALL_ADDON_RANGE * ent->myskills.abilities[SPORE].current_level; + const float duration = SPIKEBALL_INITIAL_DURATION + SPIKEBALL_ADDON_DURATION * ent->myskills.abilities[SPORE].current_level; + const float range = SPIKEBALL_INITIAL_RANGE + SPIKEBALL_ADDON_RANGE * ent->myskills.abilities[SPORE].current_level; vec3_t forward, right, start, offset; if (ent->num_spikeball > 0 && Q_strcasecmp (gi.args(), "move") == 0) @@ -3496,10 +3502,11 @@ void fire_acid (edict_t *self, vec3_t start, vec3_t aimdir, int projectile_damag void Cmd_FireAcid_f (edict_t *ent) { - int acid_level = ent->myskills.abilities[ACID].current_level; + + const int acid_level = ent->myskills.abilities[ACID].current_level; int damage = ACID_INITIAL_DAMAGE + ACID_ADDON_DAMAGE * acid_level; - int speed = ACID_INITIAL_SPEED + ACID_ADDON_SPEED * acid_level; - float radius = ACID_INITIAL_RADIUS + ACID_ADDON_RADIUS * acid_level; + const int speed = ACID_INITIAL_SPEED + ACID_ADDON_SPEED * acid_level; + const float radius = ACID_INITIAL_RADIUS + ACID_ADDON_RADIUS * acid_level; float chance_gascloud = SPITTING_GASSER_CHANCE * vrx_get_talent_level(ent, TALENT_SPITTING_GASSER); // percent chance to spawn gas cloud on impact/explosion //float synergy_bonus = 1.0 + ACID_GASSER_SYNERGY_BONUS * gasser_level; // synergy bonus from gasser vec3_t forward, right, start, offset; diff --git a/src/combat/abilities/holyground.c b/src/combat/abilities/holyground.c index b74d2044..4179b8d3 100644 --- a/src/combat/abilities/holyground.c +++ b/src/combat/abilities/holyground.c @@ -186,7 +186,7 @@ void CreateHolyGround (edict_t *ent, int type, int skill_level) void Cmd_HolyGround_f (edict_t *ent) { //Talent: Holy Ground - int talentLevel = vrx_get_talent_level(ent, TALENT_HOLY_GROUND); + const int talentLevel = vrx_get_talent_level(ent, TALENT_HOLY_GROUND); if (level.time < pregame_time->value) return; @@ -222,7 +222,7 @@ void Cmd_HolyGround_f (edict_t *ent) void Cmd_UnHolyGround_f (edict_t *ent) { //Talent: Unholy Ground - int talentLevel = vrx_get_talent_level(ent, TALENT_UNHOLY_GROUND); + const int talentLevel = vrx_get_talent_level(ent, TALENT_UNHOLY_GROUND); if (talentLevel < 1) { diff --git a/src/combat/abilities/ice.c b/src/combat/abilities/ice.c index 0f9b2e37..b01bbc7b 100644 --- a/src/combat/abilities/ice.c +++ b/src/combat/abilities/ice.c @@ -186,7 +186,7 @@ void icebolt_think(edict_t* self) void glacial_spike_sound(edict_t* self) { - float r = random(); + const float r = random(); if (r < 0.33) gi.sound(self, CHAN_WEAPON, gi.soundindex("abilities/icespike1.wav"), 1, ATTN_NORM, 0); else if (r < 0.66) @@ -320,7 +320,7 @@ void Cmd_GlacialSpike_f(edict_t* ent, float skill_mult, float cost_mult) if (!V_CanUseAbilities(ent, GLACIAL_SPIKE, cost, true)) return; - int skill_level = ent->myskills.abilities[GLACIAL_SPIKE].current_level; + const int skill_level = ent->myskills.abilities[GLACIAL_SPIKE].current_level; chill_duration = (GLACIAL_SPIKE_INITIAL_CHILL + GLACIAL_SPIKE_ADDON_CHILL * skill_level) * skill_mult; freeze_duration = (GLACIAL_SPIKE_INITIAL_FREEZE + GLACIAL_SPIKE_ADDON_FREEZE * skill_level) * skill_mult; @@ -340,7 +340,7 @@ void Cmd_GlacialSpike_f(edict_t* ent, float skill_mult, float cost_mult) fire_icebolt(ent, start, forward, damage, radius, speed, 2 * skill_level, chill_duration, freeze_duration); //Talent: Wizardry - makes spell timer ability-specific instead of global - int talentLevel = vrx_get_talent_level(ent, TALENT_WIZARDRY); + const int talentLevel = vrx_get_talent_level(ent, TALENT_WIZARDRY); if (talentLevel > 0) { ent->myskills.abilities[GLACIAL_SPIKE].delay = level.time + GLACIAL_SPIKE_DELAY; @@ -419,18 +419,18 @@ void fire_iceshard(edict_t* self, vec3_t start, vec3_t dir, float speed, int dam void frozenorb_attack(edict_t* self, int num_shards, qboolean explode) { - float turn_degrees = 360 / num_shards; + const float turn_degrees = 360 / num_shards; vec3_t forward; //Talent: Nova Orb - adds chance for frozen orb to explode into a frost nova - int talentLevel = vrx_get_talent_level(self->owner, TALENT_NOVA_ORB); - float chance = 0.2 * talentLevel; + const int talentLevel = vrx_get_talent_level(self->owner, TALENT_NOVA_ORB); + const float chance = 0.2 * talentLevel; if (explode && talentLevel > 0 && chance > random()) { - int skill_level = self->owner->myskills.abilities[NOVA].current_level; - int damage = (FROST_NOVA_INITIAL_DAMAGE + FROST_NOVA_ADDON_DAMAGE * skill_level) * vrx_get_synergy_mult(self->owner, NOVA); - float radius = FROST_NOVA_INITIAL_RADIUS + FROST_NOVA_ADDON_RADIUS * skill_level; - float chill = (FROST_NOVA_INITIAL_CHILL + FROST_NOVA_ADDON_CHILL * skill_level); + const int skill_level = self->owner->myskills.abilities[NOVA].current_level; + const int damage = (FROST_NOVA_INITIAL_DAMAGE + FROST_NOVA_ADDON_DAMAGE * skill_level) * vrx_get_synergy_mult(self->owner, NOVA); + const float radius = FROST_NOVA_INITIAL_RADIUS + FROST_NOVA_ADDON_RADIUS * skill_level; + const float chill = (FROST_NOVA_INITIAL_CHILL + FROST_NOVA_ADDON_CHILL * skill_level); fire_nova(self, self->owner, damage, radius, 2 * skill_level, chill); } @@ -557,14 +557,14 @@ void Cmd_FrozenOrb_f(edict_t* ent, float skill_mult, float cost_mult) { vec3_t forward, right, start, offset; - int cost = FROZEN_ORB_COST * cost_mult; + const int cost = FROZEN_ORB_COST * cost_mult; if (!V_CanUseAbilities(ent, FROZEN_ORB, cost, true)) return; - int skill_level = ent->myskills.abilities[FROZEN_ORB].current_level; - int damage = (FROZEN_ORB_INITIAL_DAMAGE + FROZEN_ORB_ADDON_DAMAGE * skill_level) * (skill_mult * vrx_get_synergy_mult(ent, FROZEN_ORB)); - float chill_duration = (FROZEN_ORB_INITIAL_CHILL + FROZEN_ORB_ADDON_CHILL * skill_level) * skill_mult; + const int skill_level = ent->myskills.abilities[FROZEN_ORB].current_level; + const int damage = (FROZEN_ORB_INITIAL_DAMAGE + FROZEN_ORB_ADDON_DAMAGE * skill_level) * (skill_mult * vrx_get_synergy_mult(ent, FROZEN_ORB)); + const float chill_duration = (FROZEN_ORB_INITIAL_CHILL + FROZEN_ORB_ADDON_CHILL * skill_level) * skill_mult; // get starting position and forward vector AngleVectors(ent->client->v_angle, forward, right, NULL); @@ -574,7 +574,7 @@ void Cmd_FrozenOrb_f(edict_t* ent, float skill_mult, float cost_mult) fire_frozenorb(ent, start, forward, damage, (2 * skill_level), chill_duration); //Talent: Wizardry - makes spell timer ability-specific instead of global - int talentLevel = vrx_get_talent_level(ent, TALENT_WIZARDRY); + const int talentLevel = vrx_get_talent_level(ent, TALENT_WIZARDRY); if (talentLevel > 0) { ent->myskills.abilities[FROZEN_ORB].delay = level.time + FROZEN_ORB_DELAY; diff --git a/src/combat/abilities/jump.c b/src/combat/abilities/jump.c index e83b998f..a8399ec8 100644 --- a/src/combat/abilities/jump.c +++ b/src/combat/abilities/jump.c @@ -18,7 +18,7 @@ void V_PlayerJump(edict_t *ent) { ent->monsterinfo.jumpup = 1; // player has jumped, cleared on touch-down - qboolean has_cloak = ent->myskills.abilities[CLOAK].current_level > 0; + const qboolean has_cloak = ent->myskills.abilities[CLOAK].current_level > 0; if (ent->mtype == MORPH_MUTANT) { if (mutant_boost(ent) && !has_cloak) gi.sound(ent, CHAN_VOICE, gi.soundindex("mutant/mutsght1.wav"), 1, ATTN_NORM, 0); @@ -41,12 +41,12 @@ void V_PlayerJump(edict_t *ent) { qboolean CanDoubleJump(edict_t *ent, usercmd_t *ucmd) { if (ent->client) return (!ent->waterlevel && !ent->groundentity && !(ent->v_flags & SFLG_DOUBLEJUMP) && !vrx_has_flag(ent) - && (ucmd->upmove > 0) && !ent->client->jump && !ent->myskills.abilities[DOUBLE_JUMP].disable + && (cmd_jumping(ucmd)) && !ent->client->jump && !ent->myskills.abilities[DOUBLE_JUMP].disable && (ent->myskills.abilities[DOUBLE_JUMP].current_level > 0)); else if (PM_MonsterHasPilot(ent)) return (!ent->waterlevel && !ent->groundentity && !(ent->v_flags & SFLG_DOUBLEJUMP) && !vrx_has_flag( ent->activator) - && (ucmd->upmove > 0) && !ent->activator->client->jump && + && (cmd_jumping(ucmd)) && !ent->activator->client->jump && !ent->activator->myskills.abilities[DOUBLE_JUMP].disable && (ent->activator->myskills.abilities[DOUBLE_JUMP].current_level > 0)); else diff --git a/src/combat/abilities/laserplatform.c b/src/combat/abilities/laserplatform.c index a9022661..27161b4b 100644 --- a/src/combat/abilities/laserplatform.c +++ b/src/combat/abilities/laserplatform.c @@ -116,9 +116,9 @@ void RemoveAllLaserPlatforms (edict_t *ent) } void Cmd_CreateLaserPlatform_f (edict_t *ent) -{ - int *cubes = &ent->client->pers.inventory[power_cube_index]; - int talentLevel = vrx_get_talent_level(ent, TALENT_LASER_PLATFORM); +{ + const int *cubes = &ent->client->pers.inventory[power_cube_index]; + const int talentLevel = vrx_get_talent_level(ent, TALENT_LASER_PLATFORM); vec3_t start; edict_t *laserplatform; diff --git a/src/combat/abilities/lasers.c b/src/combat/abilities/lasers.c index c6769b94..d24e77cb 100644 --- a/src/combat/abilities/lasers.c +++ b/src/combat/abilities/lasers.c @@ -42,7 +42,7 @@ void RemoveLasers (edict_t *ent) qboolean NearbyLasers (edict_t *ent, vec3_t org) { - edict_t *e=NULL; + const edict_t *e=NULL; while((e = findradius(e, org, 8)) != NULL) { @@ -57,7 +57,7 @@ qboolean NearbyLasers (edict_t *ent, vec3_t org) qboolean NearbyProxy (edict_t *ent, vec3_t org) { - edict_t *e=NULL; + const edict_t *e=NULL; while((e = findradius(e, org, 8)) != NULL) { diff --git a/src/combat/abilities/lasertrap.c b/src/combat/abilities/lasertrap.c index be853a38..36e29776 100644 --- a/src/combat/abilities/lasertrap.c +++ b/src/combat/abilities/lasertrap.c @@ -317,7 +317,7 @@ void ThrowLaserTrap (edict_t *self, vec3_t start, vec3_t aimdir, int skill_level void Cmd_LaserTrap_f (edict_t *ent) { - int talentLevel = vrx_get_talent_level(ent, TALENT_ALARM); + const int talentLevel = vrx_get_talent_level(ent, TALENT_ALARM); vec3_t forward, start; if (Q_strcasecmp (gi.args(), "remove") == 0) diff --git a/src/combat/abilities/lightningstorm.c b/src/combat/abilities/lightningstorm.c index 91d1c2d7..20936989 100644 --- a/src/combat/abilities/lightningstorm.c +++ b/src/combat/abilities/lightningstorm.c @@ -2,7 +2,7 @@ void lightningstorm_sound(edict_t* self) { - float r = random(); + const float r = random(); if (r > 0.33) gi.sound(self, CHAN_ITEM, gi.soundindex("abilities/chargedbolt1.wav"), 1, ATTN_NORM, 0); else if (r < 0.66) @@ -48,8 +48,14 @@ void lightningstorm_attack(edict_t* self, vec3_t start) } gi.WriteByte(svc_temp_entity); +#ifndef VRX_REPRO gi.WriteByte(TE_HEATBEAM); gi.WriteShort(self - g_edicts); +#else + gi.WriteByte(TE_LIGHTNING); + gi.WriteShort(self - g_edicts); + gi.WriteShort(0); +#endif gi.WritePosition(start); gi.WritePosition(end); gi.multicast(end, MULTICAST_PVS); @@ -76,7 +82,7 @@ void lightningstorm_think (edict_t *self) tr = gi.trace(self->pos1, NULL, NULL, start, self, MASK_SOLID); // Talent: Chainlightning Storm - int talentLevel = vrx_get_talent_level(self->owner, TALENT_CL_STORM); + const int talentLevel = vrx_get_talent_level(self->owner, TALENT_CL_STORM); if (talentLevel && 0.05 * talentLevel > random()) fire_chainlightning(self, tr.endpos, tv(0, 0, -1), self->dmg_counter, self->dmg_radius, 8192, CLIGHTNING_INITIAL_HR, 4); @@ -115,7 +121,7 @@ void SpawnLightningStorm (edict_t *ent, vec3_t start, float radius, int duration gi.linkentity(storm); // Talent: Chainlightning Storm - int talentLevel = vrx_get_talent_level(ent, TALENT_CL_STORM); + const int talentLevel = vrx_get_talent_level(ent, TALENT_CL_STORM); if (talentLevel > 1) { int skill_level = ent->myskills.abilities[LIGHTNING].current_level; @@ -128,7 +134,7 @@ void SpawnLightningStorm (edict_t *ent, vec3_t start, float radius, int duration void Cmd_LightningStorm_f (edict_t *ent, float skill_mult, float cost_mult) { - int slvl = ent->myskills.abilities[LIGHTNING_STORM].current_level; + const int slvl = ent->myskills.abilities[LIGHTNING_STORM].current_level; int damage, duration, cost=LIGHTNING_COST*cost_mult; float radius; vec3_t forward, offset, right, start, end; @@ -164,7 +170,7 @@ void Cmd_LightningStorm_f (edict_t *ent, float skill_mult, float cost_mult) SpawnLightningStorm(ent, tr.endpos, radius, duration, damage); //Talent: Wizardry - makes spell timer ability-specific instead of global - int talentLevel = vrx_get_talent_level(ent, TALENT_WIZARDRY); + const int talentLevel = vrx_get_talent_level(ent, TALENT_WIZARDRY); if (talentLevel > 0) { ent->myskills.abilities[LIGHTNING_STORM].delay = level.time + LIGHTNING_ABILITY_DELAY; diff --git a/src/combat/abilities/magic.c b/src/combat/abilities/magic.c index 90629a23..14373329 100644 --- a/src/combat/abilities/magic.c +++ b/src/combat/abilities/magic.c @@ -339,7 +339,9 @@ void Cmd_CorpseExplode(edict_t *ent) //Spells like corpse explode shouldn't display 10000 damage, so show the corpse damage instead ent->client->ps.stats[STAT_ID_DAMAGE] = damage; - +#ifdef VRX_REPRO + ent->client->ps.stats[STAT_ID_DAMAGE2] = damage >> 16; +#endif gi.sound(e, CHAN_ITEM, gi.soundindex("abilities/corpseexplodecast.wav"), 1, ATTN_NORM, 0); ent->client->pers.inventory[power_cube_index] -= COST_FOR_CORPSEEXPLODE; ent->client->ability_delay = level.time + DELAY_CORPSEEXPLODE; @@ -662,7 +664,7 @@ void CrippleAttack (edict_t *ent) void Cmd_StaticField_f (edict_t *ent) { - int ability_level=ent->myskills.abilities[STATIC_FIELD].current_level; + const int ability_level=ent->myskills.abilities[STATIC_FIELD].current_level; if (!G_CanUseAbilities(ent, ability_level, STATICFIELD_COST)) return; @@ -858,7 +860,7 @@ void meditate_think (edict_t *self) void Cmd_Meditate_f (edict_t *ent) { //Talent: Meditation - int talentLevel = vrx_get_talent_level(ent, TALENT_MEDITATION); + const int talentLevel = vrx_get_talent_level(ent, TALENT_MEDITATION); if (talentLevel < 1) return; @@ -895,7 +897,7 @@ void Cmd_Meditate_f (edict_t *ent) void Cmd_Purge_f (edict_t *ent) { //Talent: Purge - int talentLevel = vrx_get_talent_level(ent, TALENT_PURGE); + const int talentLevel = vrx_get_talent_level(ent, TALENT_PURGE); if (talentLevel < 1) { diff --git a/src/combat/abilities/magmine.c b/src/combat/abilities/magmine.c index 28c8e5c7..748feacf 100644 --- a/src/combat/abilities/magmine.c +++ b/src/combat/abilities/magmine.c @@ -140,7 +140,7 @@ void magmine_think(edict_t *self) if (self->light_level > 0) // magmine has enough energy to operate { - int pull = MAGMINE_DEFAULT_PULL + MAGMINE_ADDON_PULL * self->monsterinfo.level; + const int pull = MAGMINE_DEFAULT_PULL + MAGMINE_ADDON_PULL * self->monsterinfo.level; if (magmine_findtarget(self, self->dmg_radius, pull)) { magmine_throwsparks(self); @@ -341,7 +341,7 @@ void RemoveMagmines(edict_t* ent) void Cmd_SpawnMagmine_f(edict_t *ent) { int talentLevel, cost = MAGMINE_COST; float skill_mult = 1.0, cost_mult = 1.0, delay_mult = 1.0;//Talent: Rapid Assembly & Precision Tuning - char *opt = gi.argv(1); + const char *opt = gi.argv(1); if (ent->myskills.abilities[MAGMINE].disable) return; diff --git a/src/combat/abilities/meteor.c b/src/combat/abilities/meteor.c index 5374b150..bf02ba59 100644 --- a/src/combat/abilities/meteor.c +++ b/src/combat/abilities/meteor.c @@ -128,7 +128,7 @@ void fire_meteor (edict_t *self, vec3_t end, int damage, int radius, int speed) meteor->classname = "meteor"; // Talent: Meteoric Fire - spawns a firewall on meteor impact - int talentLevel = vrx_get_talent_level(self, TALENT_METEORIC_FIRE); + const int talentLevel = vrx_get_talent_level(self, TALENT_METEORIC_FIRE); if (talentLevel > 0) { meteor->style = talentLevel; @@ -254,7 +254,7 @@ void MeteorAttack (edict_t *ent, int damage, int radius, int speed, float skill_ //gi.sound(meteor, CHAN_WEAPON, gi.soundindex("abilities/meteorlaunch_short.wav"), 1, ATTN_NORM, 0); //Talent: Wizardry - makes spell timer ability-specific instead of global - int talentLevel = vrx_get_talent_level(ent, TALENT_WIZARDRY); + const int talentLevel = vrx_get_talent_level(ent, TALENT_WIZARDRY); if (talentLevel > 0) { ent->myskills.abilities[METEOR].delay = level.time + METEOR_DELAY; @@ -270,10 +270,10 @@ void MeteorAttack (edict_t *ent, int damage, int radius, int speed, float skill_ void Cmd_Meteor_f (edict_t *ent, float skill_mult, float cost_mult) { - int damage=METEOR_INITIAL_DMG+METEOR_ADDON_DMG*ent->myskills.abilities[METEOR].current_level; - int speed=METEOR_INITIAL_SPEED+METEOR_ADDON_SPEED*ent->myskills.abilities[METEOR].current_level; - int radius=METEOR_INITIAL_RADIUS+METEOR_ADDON_RADIUS*ent->myskills.abilities[METEOR].current_level; - int cost=METEOR_COST*cost_mult; + const int damage=METEOR_INITIAL_DMG+METEOR_ADDON_DMG*ent->myskills.abilities[METEOR].current_level; + const int speed=METEOR_INITIAL_SPEED+METEOR_ADDON_SPEED*ent->myskills.abilities[METEOR].current_level; + const int radius=METEOR_INITIAL_RADIUS+METEOR_ADDON_RADIUS*ent->myskills.abilities[METEOR].current_level; + const int cost=METEOR_COST*cost_mult; //if (!G_CanUseAbilities(ent, ent->myskills.abilities[METEOR].current_level, cost)) // return; diff --git a/src/combat/abilities/minisentry.c b/src/combat/abilities/minisentry.c index 9fd058a2..e8c1c222 100644 --- a/src/combat/abilities/minisentry.c +++ b/src/combat/abilities/minisentry.c @@ -609,10 +609,10 @@ void minisentry_think (edict_t *self) minisentry_checkstatus(self); // toggle sentry spotlight - if (level.daytime && self->flashlight) - FL_make(self); - else if (!level.daytime && !self->flashlight) - FL_make(self); + if (level.daytime && FL_exists(self)) + FL_toggle(self); + else if (!level.daytime && !FL_exists(self)) + FL_toggle(self); // is the sentry slowed by holy freeze? temp = self->yaw_speed; diff --git a/src/combat/abilities/mirror.c b/src/combat/abilities/mirror.c index 04ae05af..39469fe8 100644 --- a/src/combat/abilities/mirror.c +++ b/src/combat/abilities/mirror.c @@ -267,7 +267,7 @@ void dummy_die(edict_t* self, edict_t* inflictor, edict_t* attacker, int damage, void dummy_copy_activator(edict_t* self) { - int skin_number = maxclients->value + self->s.number - 1;//self - g_edicts - 1;//maxclients->value; // the first "free" index + const int skin_number = maxclients->value + self->s.number - 1;//self - g_edicts - 1;//maxclients->value; // the first "free" index //int weap_index = WEAP_HYPERBLASTER; if (!self->activator || !self->activator->inuse) diff --git a/src/combat/abilities/mirv.c b/src/combat/abilities/mirv.c index fcd0cc74..01240487 100644 --- a/src/combat/abilities/mirv.c +++ b/src/combat/abilities/mirv.c @@ -90,7 +90,7 @@ void mirv_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf } // bounce off things that can't be hurt - if (!other->takedamage) + if (!other->takedamage && ent != other) { if (random() > 0.5) gi.sound (ent, CHAN_VOICE, gi.soundindex ("weapons/hgrenb1a.wav"), 1, ATTN_NORM, 0); diff --git a/src/combat/abilities/nova.c b/src/combat/abilities/nova.c index a313a9f3..59fd15cc 100644 --- a/src/combat/abilities/nova.c +++ b/src/combat/abilities/nova.c @@ -116,7 +116,7 @@ void Cmd_FrostNova_f (edict_t *ent, float skill_mult, float cost_mult) gi.sound(ent, CHAN_WEAPON, gi.soundindex("abilities/novaice.wav"), 1, ATTN_NORM, 0); //Talent: Wizardry - makes spell timer ability-specific instead of global - int talentLevel = vrx_get_talent_level(ent, TALENT_WIZARDRY); + const int talentLevel = vrx_get_talent_level(ent, TALENT_WIZARDRY); if (talentLevel > 0) { ent->myskills.abilities[NOVA].delay = level.time + FROST_NOVA_DELAY; diff --git a/src/combat/abilities/plaguecloud.c b/src/combat/abilities/plaguecloud.c index 2e7a2bc5..3de7ef69 100644 --- a/src/combat/abilities/plaguecloud.c +++ b/src/combat/abilities/plaguecloud.c @@ -13,7 +13,7 @@ void PlagueCloud(edict_t *ent, edict_t *target); void InfectedCorpseTouch(edict_t* self, edict_t* other) { - que_t* q = NULL; + const que_t* q = NULL; if (!G_EntExists(self)) return; // invalid entity @@ -160,8 +160,7 @@ void plague_think(edict_t *self) { self->wait = level.time + PLAGUE_DELAY; } - self->nextthink = level.time + FRAMETIME; - + self->nextthink = level.time + 0.1f; } void PlagueCloud(edict_t *ent, edict_t *target) { diff --git a/src/combat/abilities/plasmabolt.c b/src/combat/abilities/plasmabolt.c index b93e1504..bb18bf20 100644 --- a/src/combat/abilities/plasmabolt.c +++ b/src/combat/abilities/plasmabolt.c @@ -87,7 +87,7 @@ void fire_plasmabolt (edict_t *self, vec3_t start, vec3_t aimdir, int damage, fl void Cmd_Plasmabolt_f (edict_t *ent) { - int slvl = ent->myskills.abilities[PLASMA_BOLT].current_level; + const int slvl = ent->myskills.abilities[PLASMA_BOLT].current_level; int damage, speed, duration; float radius; vec3_t forward, right, start, offset; diff --git a/src/combat/abilities/playermonster/playertoberserk.c b/src/combat/abilities/playermonster/playertoberserk.c index 785473d8..15983be0 100644 --- a/src/combat/abilities/playermonster/playertoberserk.c +++ b/src/combat/abilities/playermonster/playertoberserk.c @@ -97,7 +97,7 @@ void p_berserk_crush (edict_t *self, int damage, float range, int mod) return; // Talent: Melee Mastery - int talentLevel = vrx_get_talent_level(self, TALENT_MELEE_MASTERY); + const int talentLevel = vrx_get_talent_level(self, TALENT_MELEE_MASTERY); self->lastsound = level.framenum; @@ -140,7 +140,7 @@ void p_berserk_jump (edict_t *ent) { // run jump animation forward until last frame, then hold it if (ent->s.frame != BERSERK_FRAMES_JUMP_END) - G_RunFrames(ent, BERSERK_FRAMES_DUCK_START, BERSERK_FRAMES_DUCK_END, false); + G_RunFrames(ent, BERSERK_FRAMES_DUCK_START, BERSERK_FRAMES_DUCK_END, false, true); } void p_berserk_swing (edict_t *ent) @@ -166,9 +166,9 @@ int berserk_translate_attack_frame(int input_frame) void p_berserk_attack (edict_t *ent, int move_state) { - int punch_dmg = BERSERK_PUNCH_INITIAL_DAMAGE + BERSERK_PUNCH_ADDON_DAMAGE * ent->myskills.abilities[BERSERK].current_level; - int slash_dmg = BERSERK_SLASH_INITIAL_DAMAGE + BERSERK_SLASH_ADDON_DAMAGE * ent->myskills.abilities[BERSERK].current_level; - int crush_dmg = BERSERK_CRUSH_INITIAL_DAMAGE + BERSERK_CRUSH_ADDON_DAMAGE * ent->myskills.abilities[BERSERK].current_level; + const int punch_dmg = BERSERK_PUNCH_INITIAL_DAMAGE + BERSERK_PUNCH_ADDON_DAMAGE * ent->myskills.abilities[BERSERK].current_level; + const int slash_dmg = BERSERK_SLASH_INITIAL_DAMAGE + BERSERK_SLASH_ADDON_DAMAGE * ent->myskills.abilities[BERSERK].current_level; + const int crush_dmg = BERSERK_CRUSH_INITIAL_DAMAGE + BERSERK_CRUSH_ADDON_DAMAGE * ent->myskills.abilities[BERSERK].current_level; vec3_t forward, right, up, angles; //gi.dprintf("%d: %s: frame: %d state: %d\n", (int)level.framenum, __func__, ent->s.frame, move_state); @@ -184,7 +184,7 @@ void p_berserk_attack (edict_t *ent, int move_state) if (berserk_frames_in_range(ent->s.frame, BERSERK_FRAMES_PUNCH_START, BERSERK_FRAMES_PUNCH_END)) ent->s.frame = berserk_translate_attack_frame(ent->s.frame); - G_RunFrames(ent, BERSERK_FRAMES_RUNATTACK1_START, BERSERK_FRAMES_RUNATTACK1_END, false); + G_RunFrames(ent, BERSERK_FRAMES_RUNATTACK1_START, BERSERK_FRAMES_RUNATTACK1_END, false, true); // swing left-right if (ent->s.frame == 124) @@ -214,7 +214,7 @@ void p_berserk_attack (edict_t *ent, int move_state) if (berserk_frames_in_range(ent->s.frame, BERSERK_FRAMES_PUNCH_START, BERSERK_FRAMES_PUNCH_END)) ent->s.frame = berserk_translate_attack_frame(ent->s.frame); - G_RunFrames(ent, BERSERK_FRAMES_RUNATTACK1_START, BERSERK_FRAMES_RUNATTACK1_END, true); + G_RunFrames(ent, BERSERK_FRAMES_RUNATTACK1_START, BERSERK_FRAMES_RUNATTACK1_END, true, true); // swing left-right if (ent->s.frame == 124) @@ -240,14 +240,14 @@ void p_berserk_attack (edict_t *ent, int move_state) } else if (ent->client->weapon_mode == 1) // slash { - G_RunFrames(ent, BERSERK_FRAMES_SLASH_START, BERSERK_FRAMES_SLASH_END, false); + G_RunFrames(ent, BERSERK_FRAMES_SLASH_START, BERSERK_FRAMES_SLASH_END, false, true); if ((ent->s.frame == 79) || (ent->s.frame == 80)) p_berserk_melee(ent, forward, up, slash_dmg, BERSERK_SLASH_KNOCKBACK, BERSERK_SLASH_RANGE, MOD_BERSERK_SLASH); } else if (ent->client->weapon_mode == 2) // crush { - G_RunFrames(ent, BERSERK_FRAMES_SLAM_START, BERSERK_FRAMES_SLAM_END, false); + G_RunFrames(ent, BERSERK_FRAMES_SLAM_START, BERSERK_FRAMES_SLAM_END, false, true); if (ent->s.frame == 154) p_berserk_crush(ent, crush_dmg, BERSERK_CRUSH_RANGE, MOD_BERSERK_CRUSH); @@ -258,7 +258,7 @@ void p_berserk_attack (edict_t *ent, int move_state) if (berserk_frames_in_range(ent->s.frame, BERSERK_FRAMES_RUNATTACK1_START, BERSERK_FRAMES_RUNATTACK1_END)) ent->s.frame = berserk_translate_attack_frame(ent->s.frame); - G_RunFrames(ent, BERSERK_FRAMES_PUNCH_START, BERSERK_FRAMES_PUNCH_END, false); + G_RunFrames(ent, BERSERK_FRAMES_PUNCH_START, BERSERK_FRAMES_PUNCH_END, false, true); // swing left-right if (ent->s.frame == 66) @@ -316,7 +316,7 @@ void RunBerserkFrames (edict_t *ent, usercmd_t *ucmd) if ((ent->client->buttons & BUTTON_ATTACK) && (level.time > ent->monsterinfo.attack_finished)) p_berserk_attack(ent, BERSERK_RUN_FORWARD); else - G_RunFrames(ent, BERSERK_FRAMES_RUN_START, BERSERK_FRAMES_RUN_END, false); + G_RunFrames(ent, BERSERK_FRAMES_RUN_START, BERSERK_FRAMES_RUN_END, false, true); } // play animation in reverse if we are going backwards else if (ucmd->forwardmove < 0) @@ -324,7 +324,7 @@ void RunBerserkFrames (edict_t *ent, usercmd_t *ucmd) if ((ent->client->buttons & BUTTON_ATTACK) && (level.time > ent->monsterinfo.attack_finished)) p_berserk_attack(ent, BERSERK_RUN_BACKWARD); else - G_RunFrames(ent, BERSERK_FRAMES_RUN_START, BERSERK_FRAMES_RUN_END, true); + G_RunFrames(ent, BERSERK_FRAMES_RUN_START, BERSERK_FRAMES_RUN_END, true, true); } // standing attack else if ((ent->client->buttons & BUTTON_ATTACK) && (level.time > ent->monsterinfo.attack_finished)) @@ -333,7 +333,7 @@ void RunBerserkFrames (edict_t *ent, usercmd_t *ucmd) else if (!ent->groundentity && (ent->waterlevel < 2)) p_berserk_jump(ent); else - G_RunFrames(ent, BERSERK_FRAMES_IDLE1_START, BERSERK_FRAMES_IDLE1_END, false); // run idle frames + G_RunFrames(ent, BERSERK_FRAMES_IDLE1_START, BERSERK_FRAMES_IDLE1_END, false, true); // run idle frames ent->count = level.framenum + qf2sf(1); } @@ -341,7 +341,7 @@ void RunBerserkFrames (edict_t *ent, usercmd_t *ucmd) void Cmd_PlayerToBerserk_f (edict_t *ent) { - int cost = BERSERK_COST; + const int cost = BERSERK_COST; if (debuginfo->value) gi.dprintf("DEBUG: %s just called Cmd_PlayerToBerserk_f()\n", ent->client->pers.netname); diff --git a/src/combat/abilities/playermonster/playertobrain.c b/src/combat/abilities/playermonster/playertobrain.c index 692cd575..5acc8094 100644 --- a/src/combat/abilities/playermonster/playertobrain.c +++ b/src/combat/abilities/playermonster/playertobrain.c @@ -72,9 +72,6 @@ void brain_fire_beam (edict_t *self) return; } - self->client->charge_index = BEAM+1; - self->myskills.abilities[BEAM].charge -= BRAIN_BEAM_COST; - //self->client->pers.inventory[cell_index] -= BRAIN_BEAM_COST; self->client->idle_frames = 0; // calculate starting point @@ -86,9 +83,14 @@ void brain_fire_beam (edict_t *self) tr = gi.trace(start, NULL, NULL, end, self, MASK_SHOT); brain_beam_sparks(tr.endpos); - damage = BRAIN_BEAM_DEFAULT_DMG+BRAIN_BEAM_ADDON_DMG*self->myskills.abilities[BEAM].current_level; - - T_Damage(tr.ent, self, self, forward, tr.endpos, tr.plane.normal, damage, damage, DAMAGE_ENERGY, MOD_BEAM); + // only run the actual damage/charge calc at 10tps, not server rate + if ( ( level.framenum % qf2sf( 1 ) ) == 0 ) { + self->client->charge_index = BEAM+1; + self->myskills.abilities[BEAM].charge -= BRAIN_BEAM_COST; + //self->client->pers.inventory[cell_index] -= BRAIN_BEAM_COST; + damage = BRAIN_BEAM_DEFAULT_DMG+BRAIN_BEAM_ADDON_DMG*self->myskills.abilities[BEAM].current_level; + T_Damage(tr.ent, self, self, forward, tr.endpos, tr.plane.normal, damage, damage, DAMAGE_ENERGY, MOD_BEAM); + } gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_BFG_LASER); @@ -231,10 +233,10 @@ void tentacle_attack (edict_t *self) VectorCopy(self->s.origin, start); start[2] += self->viewheight; // Talent: Melee Mastery - adds projectile (gib) vomit to brain's primary attack - int talentLevel = vrx_get_talent_level(self, TALENT_MELEE_MASTERY); + const int talentLevel = vrx_get_talent_level(self, TALENT_MELEE_MASTERY); if (talentLevel > 0) { - int frames = 11 - (2 * talentLevel); + const int frames = 11 - (2 * talentLevel); if (level.framenum % frames == 0) { VectorMA(start, 16, forward, start); @@ -286,12 +288,12 @@ void RunBrainFrames (edict_t *ent, usercmd_t *ucmd) // moving forward animation else if ((ucmd->forwardmove > 0) || ucmd->sidemove) { - G_RunFrames(ent, BRAIN_WALK_START, BRAIN_WALK_END, false); + G_RunFrames(ent, BRAIN_WALK_START, BRAIN_WALK_END, false, true); } // play animation in reverse if we are going backwards else if (ucmd->forwardmove < 0) { - G_RunFrames(ent, BRAIN_WALK_START, BRAIN_WALK_END, true); + G_RunFrames(ent, BRAIN_WALK_START, BRAIN_WALK_END, true, true); } else if (BrainCanAttack(ent) && (ent->client->buttons & BUTTON_ATTACK)) { @@ -305,7 +307,7 @@ void RunBrainFrames (edict_t *ent, usercmd_t *ucmd) else if (level.time > ent->monsterinfo.attack_finished) { // tentacle attack - G_RunFrames(ent, BRAIN_FRAME_TENTACLE_START, BRAIN_FRAME_TENTACLE_END, false); + G_RunFrames(ent, BRAIN_FRAME_TENTACLE_START, BRAIN_FRAME_TENTACLE_END, false, true); tentacle_attack(ent); ent->client->idle_frames = 0; } @@ -313,7 +315,7 @@ void RunBrainFrames (edict_t *ent, usercmd_t *ucmd) else { // run idle frames - G_RunFrames(ent, BRAIN_FRAME_IDLE_START, BRAIN_FRAME_IDLE_END, false); + G_RunFrames(ent, BRAIN_FRAME_IDLE_START, BRAIN_FRAME_IDLE_END, false, true); } ent->count = level.framenum + qf2sf(1); @@ -322,7 +324,7 @@ void RunBrainFrames (edict_t *ent, usercmd_t *ucmd) void Cmd_PlayerToBrain_f (edict_t *ent) { - int brain_cubecost = BRAIN_INIT_COST; + const int brain_cubecost = BRAIN_INIT_COST; if (debuginfo->value) gi.dprintf("DEBUG: %s just called Cmd_PlayerToBrain_f()\n", ent->client->pers.netname); diff --git a/src/combat/abilities/playermonster/playertocacodemon.c b/src/combat/abilities/playermonster/playertocacodemon.c index 735bdff0..00c009b3 100644 --- a/src/combat/abilities/playermonster/playertocacodemon.c +++ b/src/combat/abilities/playermonster/playertocacodemon.c @@ -12,8 +12,8 @@ void bskull_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) { int num; - int skill_level = self->owner->myskills.abilities[CACODEMON].current_level; - int damage = CACODEMON_ADDON_BURN * skill_level; + const int skill_level = self->owner->myskills.abilities[CACODEMON].current_level; + const int damage = CACODEMON_ADDON_BURN * skill_level; // deal direct damage if (G_EntExists(other)) @@ -33,7 +33,7 @@ void bskull_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *su SpawnFlames(self->owner, self->s.origin, num, damage, 100); // Talent: Range Mastery - int talentLevel = vrx_get_talent_level(self, TALENT_RANGE_MASTERY); + const int talentLevel = vrx_get_talent_level(self, TALENT_RANGE_MASTERY); if (talentLevel > 0) ShootFireballsAtNearbyEnemies(self, 200, talentLevel, skill_level); BecomeExplosion1(self); @@ -122,7 +122,7 @@ void RunCacodemonFrames(edict_t *ent, usercmd_t *ucmd) { if (ent->client->buttons & BUTTON_ATTACK) { ent->client->idle_frames = 0; // run attack frames - G_RunFrames(ent, CACODEMON_FRAME_ATTACK_START, CACODEMON_FRAME_ATTACK_END, false); + G_RunFrames(ent, CACODEMON_FRAME_ATTACK_START, CACODEMON_FRAME_ATTACK_END, false, true); cacodemon_attack(ent); } else { frame = ent->s.frame; @@ -133,11 +133,12 @@ void RunCacodemonFrames(edict_t *ent, usercmd_t *ucmd) { G_RunFrames(ent, CACODEMON_FRAME_BLINK_START, CACODEMON_FRAME_BLINK_END, false); else*/ // run idle frames - G_RunFrames(ent, CACODEMON_FRAME_IDLE_START, CACODEMON_FRAME_IDLE_END, false); + G_RunFrames(ent, CACODEMON_FRAME_IDLE_START, CACODEMON_FRAME_IDLE_END, false, true); } // add thrust - if (ucmd->upmove > 0) { +#ifndef VRX_REPRO + if (cmd_jumping(ucmd)) { ent->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION; if (ent->groundentity) ent->velocity[2] = 150; @@ -148,6 +149,9 @@ void RunCacodemonFrames(edict_t *ent, usercmd_t *ucmd) { } else { ent->client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION; } +#else + // pmove handles it +#endif ent->count = (int)(level.framenum + qf2sf(1)); } @@ -156,9 +160,9 @@ void RunCacodemonFrames(edict_t *ent, usercmd_t *ucmd) { void Cmd_PlayerToCacodemon_f(edict_t *ent) { vec3_t mins, maxs; //trace_t tr; - int caco_cubecost = CACODEMON_INIT_COST; + const int caco_cubecost = CACODEMON_INIT_COST; //Talent: More Ammo - int talentLevel = vrx_get_talent_level(ent, TALENT_MORE_AMMO); + const int talentLevel = vrx_get_talent_level(ent, TALENT_MORE_AMMO); if (debuginfo->value) gi.dprintf("DEBUG: %s just called Cmd_PlayerToCacodemon_f()\n", ent->client->pers.netname); diff --git a/src/combat/abilities/playermonster/playertoflyer.c b/src/combat/abilities/playermonster/playertoflyer.c index 56659cf3..9b1490b7 100644 --- a/src/combat/abilities/playermonster/playertoflyer.c +++ b/src/combat/abilities/playermonster/playertoflyer.c @@ -138,13 +138,13 @@ void FlyerVerticalThrust (edict_t *ent, int speed, int max_speed) void PlayerAutoThrust (edict_t *ent, usercmd_t *ucmd) { vec3_t forward, right; - int max_velocity = FLYER_MAX_VELOCITY; + const int max_velocity = FLYER_MAX_VELOCITY; AngleVectors(ent->s.angles, forward, right, NULL); - if (ucmd->upmove > 0) // up + if (cmd_jumping(ucmd)) // up FlyerVerticalThrust(ent, FLYER_ACCEL_SPEED*2, max_velocity); - else if (ucmd->upmove < 0) // down + else if (cmd_ducking(ucmd)) // down FlyerVerticalThrust(ent, -FLYER_ACCEL_SPEED*2, max_velocity); else FlyerBrakeVertical(ent); @@ -173,7 +173,7 @@ void FlyerCheckForImpact (edict_t *ent) speed = VectorLength(ent->velocity); if (ent->client->oldspeed-speed > FLYER_IMPACT_VELOCITY) // check for drastic decelleration { - int flyer_selfdamage = FLYER_IMPACT_DAMAGE; + const int flyer_selfdamage = FLYER_IMPACT_DAMAGE; gi.sound (ent, CHAN_AUTO, gi.soundindex ("tank/thud.wav"), 1, ATTN_NORM, 0); T_Damage(ent, ent, ent, vec3_origin, ent->s.origin, @@ -368,24 +368,24 @@ void RunFlyerFrames (edict_t *ent, usercmd_t *ucmd) { if (ent->s.frame == FLYER_FRAMES_BANK_R_END) // done with bank animation return; // so don't update the frames - G_RunFrames(ent, FLYER_FRAMES_BANK_R_START, FLYER_FRAMES_BANK_R_END, false); + G_RunFrames(ent, FLYER_FRAMES_BANK_R_START, FLYER_FRAMES_BANK_R_END, false, true); } else if (ucmd->sidemove < 0) // left { if (ent->s.frame == FLYER_FRAMES_BANK_L_END) return; - G_RunFrames(ent, FLYER_FRAMES_BANK_L_START, FLYER_FRAMES_BANK_L_END, false); + G_RunFrames(ent, FLYER_FRAMES_BANK_L_START, FLYER_FRAMES_BANK_L_END, false, true); } else // default - G_RunFrames(ent, FLYER_FRAMES_STAND_START, FLYER_FRAMES_STAND_END, false); + G_RunFrames(ent, FLYER_FRAMES_STAND_START, FLYER_FRAMES_STAND_END, false, true); } } void Cmd_PlayerToFlyer_f (edict_t *ent) { - int flyer_cubecost = FLYER_INIT_COST; + const int flyer_cubecost = FLYER_INIT_COST; //Talent: More Ammo - int talentLevel = vrx_get_talent_level(ent, TALENT_MORE_AMMO); + const int talentLevel = vrx_get_talent_level(ent, TALENT_MORE_AMMO); if (debuginfo->value) gi.dprintf("DEBUG: %s just called Cmd_PlayerToFlyer_f()\n", ent->client->pers.netname); @@ -452,6 +452,9 @@ void Cmd_PlayerToFlyer_f (edict_t *ent) ent->client->pers.weapon = NULL; ent->client->ps.gunindex = 0; + // az: how did we forget this + ent->v_flags |= SFLG_NO_BOB; + lasersight_off(ent); gi.sound(ent, CHAN_WEAPON, gi.soundindex("abilities/morph.wav"), 1, ATTN_NORM, 0); diff --git a/src/combat/abilities/playermonster/playertomedic.c b/src/combat/abilities/playermonster/playertomedic.c index e7055534..a99783df 100644 --- a/src/combat/abilities/playermonster/playertomedic.c +++ b/src/combat/abilities/playermonster/playertomedic.c @@ -43,7 +43,7 @@ edict_t* CreateHealer(edict_t* ent, int skill_level); void p_medic_reanimate (edict_t *ent, edict_t *target) { int res_level; - int medic_level = ent->myskills.abilities[MEDIC].current_level; + const int medic_level = ent->myskills.abilities[MEDIC].current_level; int skill_level; float skill_bonus, res_time; vec3_t bmin, bmax; @@ -92,7 +92,7 @@ void p_medic_reanimate (edict_t *ent, edict_t *target) else if ((!strcmp(target->classname, "bodyque") || !strcmp(target->classname, "player")) && (ent->num_monsters + 1 <= MAX_MONSTERS)) { - int random=GetRandom(1, 3); + const int random=GetRandom(1, 3); vec3_t start; e = G_Spawn(); @@ -387,13 +387,13 @@ void p_medic_heal (edict_t *ent) else if (ent->s.frame == 227) gi.sound (ent, CHAN_WEAPON, gi.soundindex("medic/medatck5.wav"), 1, ATTN_NORM, 0); - int frames = qf2sf(600 / (float)ent->myskills.abilities[MEDIC].current_level); + const int frames = qf2sf(600 / (float)ent->myskills.abilities[MEDIC].current_level); // Talent: Range Mastery - allows medic to heal/resurrect multiple targets - int talentLevel = vrx_get_talent_level(ent, TALENT_RANGE_MASTERY); + const int talentLevel = vrx_get_talent_level(ent, TALENT_RANGE_MASTERY); if (talentLevel > 0) { - float range = 40 * talentLevel; + const float range = 40 * talentLevel; p_medic_healradius(ent, range, frames); if (ent->s.frame == 220) gi.sound(ent, CHAN_WEAPON, gi.soundindex("medic/medatck4.wav"), 1, ATTN_NORM, 0); @@ -479,7 +479,7 @@ void p_medic_heal (edict_t *ent) void p_medic_hb_regen (edict_t *ent, int regen_frames, int regen_delay) { int ammo; - int max = ent->myskills.abilities[MEDIC].max_ammo; + const int max = ent->myskills.abilities[MEDIC].max_ammo; int *current = &ent->myskills.abilities[MEDIC].ammo; int *delay = &ent->myskills.abilities[MEDIC].ammo_regenframe; @@ -531,13 +531,13 @@ void p_medic_jump (edict_t *ent) { // run jump animation forward until last frame, then hold it if (ent->s.frame != MEDIC_FRAMES_JUMP_END) - G_RunFrames(ent, MEDIC_FRAMES_JUMP_START, MEDIC_FRAMES_JUMP_END, false); + G_RunFrames(ent, MEDIC_FRAMES_JUMP_START, MEDIC_FRAMES_JUMP_END, false, true); } void p_medic_firehb (edict_t *ent) { - int damage = MEDIC_HB_INITIAL_DMG+MEDIC_HB_ADDON_DMG*ent->myskills.abilities[MEDIC].current_level; - int speed = MEDIC_HB_INITIAL_SPEED+MEDIC_HB_ADDON_SPEED*ent->myskills.abilities[MEDIC].current_level; + const int damage = MEDIC_HB_INITIAL_DMG+MEDIC_HB_ADDON_DMG*ent->myskills.abilities[MEDIC].current_level; + const int speed = MEDIC_HB_INITIAL_SPEED+MEDIC_HB_ADDON_SPEED*ent->myskills.abilities[MEDIC].current_level; vec3_t forward, right, start; if (!ent->myskills.abilities[MEDIC].ammo) @@ -558,7 +558,7 @@ void p_medic_firebolt (edict_t *ent) { int min_dmg; int damage = MEDIC_BOLT_INITIAL_DMG+MEDIC_BOLT_ADDON_DMG*ent->myskills.abilities[MEDIC].current_level; - int speed = MEDIC_BOLT_INITIAL_SPEED+MEDIC_BOLT_ADDON_SPEED*ent->myskills.abilities[MEDIC].current_level; + const int speed = MEDIC_BOLT_INITIAL_SPEED+MEDIC_BOLT_ADDON_SPEED*ent->myskills.abilities[MEDIC].current_level; vec3_t forward, right, start; // is this a firing frame? @@ -594,7 +594,7 @@ void p_medic_attack (edict_t *ent) { // cable/healing mode if (ent->s.frame != MEDIC_FRAMES_CABLE_END) - G_RunFrames(ent, MEDIC_FRAMES_CABLE_START, MEDIC_FRAMES_CABLE_END, false); + G_RunFrames(ent, MEDIC_FRAMES_CABLE_START, MEDIC_FRAMES_CABLE_END, false, true); else ent->s.frame = 218; // loop from this frame forward p_medic_heal(ent); @@ -603,7 +603,7 @@ void p_medic_attack (edict_t *ent) { // blaster bolt mode if (ent->s.frame != MEDIC_FRAMES_BOLT_END) - G_RunFrames(ent, MEDIC_FRAMES_BOLT_START, MEDIC_FRAMES_BOLT_END, false); + G_RunFrames(ent, MEDIC_FRAMES_BOLT_START, MEDIC_FRAMES_BOLT_END, false, true); else ent->s.frame = 185; // loop from this frame forward p_medic_firebolt(ent); @@ -612,7 +612,7 @@ void p_medic_attack (edict_t *ent) { // hyperblaster mode if (ent->s.frame != MEDIC_FRAMES_HB_END) - G_RunFrames(ent, MEDIC_FRAMES_HB_START, MEDIC_FRAMES_HB_END, false); + G_RunFrames(ent, MEDIC_FRAMES_HB_START, MEDIC_FRAMES_HB_END, false, true); else ent->s.frame = 195; // loop from this frame forward p_medic_firehb(ent); @@ -638,10 +638,10 @@ void RunMedicFrames (edict_t *ent, usercmd_t *ucmd) // play running animation if we are moving forward or strafing if ((ucmd->forwardmove > 0) || ucmd->sidemove) - G_RunFrames(ent, MEDIC_FRAMES_RUN_START, MEDIC_FRAMES_RUN_END, false); + G_RunFrames(ent, MEDIC_FRAMES_RUN_START, MEDIC_FRAMES_RUN_END, false, true); // play animation in reverse if we are going backwards else if (ucmd->forwardmove < 0) - G_RunFrames(ent, MEDIC_FRAMES_RUN_START, MEDIC_FRAMES_RUN_END, true); + G_RunFrames(ent, MEDIC_FRAMES_RUN_START, MEDIC_FRAMES_RUN_END, true, true); // attack else if ((ent->client->buttons & BUTTON_ATTACK) && (level.time > ent->monsterinfo.attack_finished)) @@ -650,7 +650,7 @@ void RunMedicFrames (edict_t *ent, usercmd_t *ucmd) else if (!ent->groundentity && (ent->waterlevel < 2)) p_medic_jump(ent); else - G_RunFrames(ent, MEDIC_FRAMES_IDLE_START, MEDIC_FRAMES_IDLE_END, false); // run idle frames + G_RunFrames(ent, MEDIC_FRAMES_IDLE_START, MEDIC_FRAMES_IDLE_END, false, true); // run idle frames ent->count = level.framenum + qf2sf(1); } @@ -660,9 +660,9 @@ void Cmd_PlayerToMedic_f (edict_t *ent) { vec3_t boxmin, boxmax; //trace_t tr; - int cost = MEDIC_INIT_COST; + const int cost = MEDIC_INIT_COST; //Talent: More Ammo - int talentLevel = vrx_get_talent_level(ent, TALENT_MORE_AMMO); + const int talentLevel = vrx_get_talent_level(ent, TALENT_MORE_AMMO); if (debuginfo->value) gi.dprintf("DEBUG: %s just called Cmd_PlayerToMedic_f()\n", ent->client->pers.netname); diff --git a/src/combat/abilities/playermonster/playertomutant.c b/src/combat/abilities/playermonster/playertomutant.c index 69b00763..ad1272d4 100644 --- a/src/combat/abilities/playermonster/playertomutant.c +++ b/src/combat/abilities/playermonster/playertomutant.c @@ -48,7 +48,7 @@ int melee_attack (edict_t *self, int damage, int range) void mutant_swing_attack (edict_t *self) { - int dmg = MUTANT_INITIAL_SWING_DMG+MUTANT_ADDON_SWING_DMG*self->myskills.abilities[MUTANT].current_level; + const int dmg = MUTANT_INITIAL_SWING_DMG+MUTANT_ADDON_SWING_DMG*self->myskills.abilities[MUTANT].current_level; if (self->s.frame == 10) // left { @@ -167,7 +167,7 @@ void mutant_stunattack(edict_t* ent) if (ent->mtype != MORPH_MUTANT) return; // Talent: Melee Mastery - int talentLevel = vrx_get_talent_level(ent, TALENT_MELEE_MASTERY); + const int talentLevel = vrx_get_talent_level(ent, TALENT_MELEE_MASTERY); // talent isn't upgraded if (talentLevel < 1) return; @@ -182,7 +182,7 @@ void mutant_stunattack(edict_t* ent) } } - int damage = (0.2 * talentLevel) * (MUTANT_INITIAL_JUMP_DMG + MUTANT_ADDON_JUMP_DMG * ent->myskills.abilities[MUTANT].current_level); + const int damage = (0.2 * talentLevel) * (MUTANT_INITIAL_JUMP_DMG + MUTANT_ADDON_JUMP_DMG * ent->myskills.abilities[MUTANT].current_level); fire_nova(ent, ent, damage, 150.0, 0, 0); } @@ -256,21 +256,21 @@ void RunMutantFrames (edict_t *ent, usercmd_t *ucmd) ent->s.frame = MUTANT_FRAMES_JUMP; // play running animation if we are moving forward or strafing else if ((ucmd->forwardmove > 0) || ucmd->sidemove) - G_RunFrames(ent, MUTANT_FRAMES_WALK_START, MUTANT_FRAMES_WALK_END, false); + G_RunFrames(ent, MUTANT_FRAMES_WALK_START, MUTANT_FRAMES_WALK_END, false, true); // play animation in reverse if we are going backwards else if (ucmd->forwardmove < 0) - G_RunFrames(ent, MUTANT_FRAMES_WALK_START, MUTANT_FRAMES_WALK_END, true); + G_RunFrames(ent, MUTANT_FRAMES_WALK_START, MUTANT_FRAMES_WALK_END, true, true); else if ((ent->client->buttons & BUTTON_ATTACK) && (level.time > ent->monsterinfo.attack_finished)) { ent->client->idle_frames = 0; // run attack frames - G_RunFrames(ent, MUTANT_FRAMES_SWING_START, MUTANT_FRAMES_SWING_END, false); + G_RunFrames(ent, MUTANT_FRAMES_SWING_START, MUTANT_FRAMES_SWING_END, false, true); mutant_swing_attack(ent); } else { - G_RunFrames(ent, MUTANT_FRAMES_IDLE_START, MUTANT_FRAMES_IDLE_END, false); // run idle frames + G_RunFrames(ent, MUTANT_FRAMES_IDLE_START, MUTANT_FRAMES_IDLE_END, false, true); // run idle frames } ent->count = level.framenum + qf2sf(1); @@ -281,7 +281,7 @@ void Cmd_PlayerToMutant_f (edict_t *ent) { vec3_t boxmin, boxmax; //trace_t tr; - int mutant_cubecost = MUTANT_INIT_COST; + const int mutant_cubecost = MUTANT_INIT_COST; if (debuginfo->value) gi.dprintf("DEBUG: %s just called Cmd_PlayerToMutant_f()\n", ent->client->pers.netname); diff --git a/src/combat/abilities/playermonster/playertoparasite.c b/src/combat/abilities/playermonster/playertoparasite.c index 9745881d..99a7b126 100644 --- a/src/combat/abilities/playermonster/playertoparasite.c +++ b/src/combat/abilities/playermonster/playertoparasite.c @@ -13,7 +13,7 @@ qboolean ParasiteAttack(edict_t* ent, vec3_t start, vec3_t aimdir, float damage, static qboolean parasite_cantarget (edict_t *self, edict_t *target) { - int para_range = PARASITE_ATTACK_RANGE; + const int para_range = PARASITE_ATTACK_RANGE; return (G_EntExists(target) /* && !que_typeexists(target->curses, CURSE_FROZEN) */ && !OnSameTeam(self, target) && visible(self, target) && nearfov(self, target, 45, 45) @@ -24,7 +24,7 @@ static qboolean parasite_cantarget (edict_t *self, edict_t *target) qboolean myparasite_findtarget (edict_t *self) { edict_t *other=NULL; - int para_range = PARASITE_ATTACK_RANGE; + const int para_range = PARASITE_ATTACK_RANGE; while ((other = findclosestradius(other, self->s.origin, para_range)) != NULL) { @@ -44,7 +44,7 @@ void myparasite_fire (edict_t *self) { int pull; int damage; - int para_range = PARASITE_ATTACK_RANGE; + const int para_range = PARASITE_ATTACK_RANGE; vec3_t v, start, end, forward; trace_t tr; @@ -218,17 +218,17 @@ void RunParasiteFrames (edict_t *ent, usercmd_t *ucmd) // play running animation if we are moving forward or strafing if ((ucmd->forwardmove > 0) || ucmd->sidemove) - G_RunFrames(ent, 70, 76, false); + G_RunFrames(ent, 70, 76, false, true); // play animation in reverse if we are going backwards else if (ucmd->forwardmove < 0) - G_RunFrames(ent, 70, 76, true); + G_RunFrames(ent, 70, 76, true, true); else idle = true; if ((ent->client->buttons & BUTTON_ATTACK) && myparasite_attack(ent) && idle) { // run attack frames - G_RunFrames(ent, 39, 51, false); + G_RunFrames(ent, 39, 51, false, true); ent->client->idle_frames = 0; } else if (idle) @@ -245,12 +245,12 @@ void RunParasiteFrames (edict_t *ent, usercmd_t *ucmd) if (ent->oldenemy) { if (ent->s.frame < 56) - G_RunFrames(ent, 39, 56, false); // run end attack frames + G_RunFrames(ent, 39, 56, false, true); // run end attack frames else ent->oldenemy = NULL; // we're done } else - G_RunFrames(ent, 83, 99, false); // run idle frames + G_RunFrames(ent, 83, 99, false, true); // run idle frames // play parasite's tapping sound if (ent->groundentity && ((ent->s.frame==85) || (ent->s.frame==87) || (ent->s.frame==91) @@ -338,7 +338,7 @@ void think_ability_parasite_attack(edict_t *ent) void Cmd_PlayerToParasite_f (edict_t *ent) { - int para_cubecost = PARASITE_INIT_COST; + const int para_cubecost = PARASITE_INIT_COST; if (debuginfo->value) gi.dprintf("DEBUG: %s just called Cmd_PlayerToParasite_f()\n", ent->client->pers.netname); diff --git a/src/combat/abilities/playermonster/playertotank.c b/src/combat/abilities/playermonster/playertotank.c index ddb72c36..245400c2 100644 --- a/src/combat/abilities/playermonster/playertotank.c +++ b/src/combat/abilities/playermonster/playertotank.c @@ -343,10 +343,10 @@ int p_tank_getFirePos(edict_t *self, vec3_t start, vec3_t forward) { } void p_tank_20mm(edict_t* self, vec3_t start, vec3_t forward, int flash_number, int talentLevel) { - int skill_level = self->monsterinfo.level; - int damage = WEAPON_20MM_INITIAL_DMG + WEAPON_20MM_ADDON_DMG * skill_level; - int kick = damage; - float range = 250 + talentLevel * 150; + const int skill_level = self->monsterinfo.level; + const int damage = WEAPON_20MM_INITIAL_DMG + WEAPON_20MM_ADDON_DMG * skill_level; + const int kick = damage; + const float range = 250 + talentLevel * 150; // bullet ammo counter if (!self->monsterinfo.lefty) @@ -367,8 +367,8 @@ void p_tank_20mm(edict_t* self, vec3_t start, vec3_t forward, int flash_number, } void p_tank_bullet(edict_t *self, vec3_t start, vec3_t forward, int flash_number) { - int damage = P_TANK_BULLET_INITIAL_DMG + P_TANK_BULLET_ADDON_DMG * self->monsterinfo.level; - int kick = damage; + const int damage = P_TANK_BULLET_INITIAL_DMG + P_TANK_BULLET_ADDON_DMG * self->monsterinfo.level; + const int kick = damage; // bullet ammo counter if (!self->monsterinfo.lefty) @@ -384,7 +384,7 @@ void p_tank_bullet(edict_t *self, vec3_t start, vec3_t forward, int flash_number } void p_tank_rocket(edict_t *self, vec3_t start, vec3_t forward, int flash_number) { - int damage = P_TANK_ROCKET_INITIAL_DMG + P_TANK_ROCKET_ADDON_DMG * self->monsterinfo.level; + const int damage = P_TANK_ROCKET_INITIAL_DMG + P_TANK_ROCKET_ADDON_DMG * self->monsterinfo.level; int speed = P_TANK_ROCKET_INITIAL_SPD + P_TANK_ROCKET_ADDON_SPD * self->monsterinfo.level; float radius = damage; @@ -408,8 +408,8 @@ void p_tank_rocket(edict_t *self, vec3_t start, vec3_t forward, int flash_number } void p_tank_blaster(edict_t *self, vec3_t start, vec3_t forward, int flash_number) { - int damage = P_TANK_BLASTER_INITIAL_DMG + P_TANK_BLASTER_ADDON_DMG * self->monsterinfo.level; - int speed = P_TANK_BLASTER_INITIAL_SPD + P_TANK_BLASTER_ADDON_SPD * self->monsterinfo.level; + const int damage = P_TANK_BLASTER_INITIAL_DMG + P_TANK_BLASTER_ADDON_DMG * self->monsterinfo.level; + const int speed = P_TANK_BLASTER_INITIAL_SPD + P_TANK_BLASTER_ADDON_SPD * self->monsterinfo.level; // blaster ammo counter if (!self->monsterinfo.radius) @@ -456,7 +456,7 @@ void p_tank_attack(edict_t *ent) { } // bullet attack else if (ent->owner->client->weapon_mode == 2) { - int talentLevel = vrx_get_talent_level(ent, TALENT_RANGE_MASTERY); + const int talentLevel = vrx_get_talent_level(ent, TALENT_RANGE_MASTERY); if (talentLevel > 0) p_tank_20mm(ent, start, forward, flash_number, talentLevel); else @@ -472,7 +472,7 @@ void p_tank_attack(edict_t *ent) { } void p_tank_idle(edict_t *self) { - G_RunFrames(self, TANK_FRAMES_START_STAND, TANK_FRAMES_END_STAND, false); + G_RunFrames(self, TANK_FRAMES_START_STAND, TANK_FRAMES_END_STAND, false, true); } void p_tank_think(edict_t *self) { @@ -495,21 +495,21 @@ void p_tank_think(edict_t *self) { PM_SyncWithPlayer(self); if (self->style == FRAMES_RUN_FORWARD) - G_RunFrames(self, TANK_FRAMES_START_WALK, TANK_FRAMES_END_WALK, false); + G_RunFrames(self, TANK_FRAMES_START_WALK, TANK_FRAMES_END_WALK, false, false); else if (self->style == FRAMES_RUN_BACKWARD) - G_RunFrames(self, TANK_FRAMES_START_WALK, TANK_FRAMES_END_WALK, true); + G_RunFrames(self, TANK_FRAMES_START_WALK, TANK_FRAMES_END_WALK, true, false); else if ((self->style == FRAMES_ATTACK) && (level.time > self->owner->monsterinfo.attack_finished)) { if (self->owner->client->weapon_mode == 1) - G_RunFrames(self, TANK_FRAMES_START_PUNCH, TANK_FRAMES_END_PUNCH, false); + G_RunFrames(self, TANK_FRAMES_START_PUNCH, TANK_FRAMES_END_PUNCH, false, false); else if (self->owner->client->weapon_mode == 2) - G_RunFrames(self, TANK_FRAMES_START_BULLET, TANK_FRAMES_END_BULLET, false); + G_RunFrames(self, TANK_FRAMES_START_BULLET, TANK_FRAMES_END_BULLET, false, false); else if (self->owner->client->weapon_mode == 3) { if (self->s.frame != TANK_FRAMES_BLASTER_END) - G_RunFrames(self, TANK_FRAMES_BLASTER_START, TANK_FRAMES_BLASTER_END, false); + G_RunFrames(self, TANK_FRAMES_BLASTER_START, TANK_FRAMES_BLASTER_END, false, false); else self->s.frame = 65; // cycle from this frame forward } else - G_RunFrames(self, TANK_FRAMES_START_ROCKET, TANK_FRAMES_END_ROCKET, false); + G_RunFrames(self, TANK_FRAMES_START_ROCKET, TANK_FRAMES_END_ROCKET, false, false); } else p_tank_idle(self); @@ -558,7 +558,7 @@ void p_tank_spawn(edict_t *ent, int cost) { vec3_t boxmin, boxmax; //trace_t tr; //Talent: More Ammo - int talentLevel = vrx_get_talent_level(ent, TALENT_MORE_AMMO); + const int talentLevel = vrx_get_talent_level(ent, TALENT_MORE_AMMO); // make sure we don't get stuck in a wall VectorSet (boxmin, -24, -24, -16); @@ -664,7 +664,7 @@ void p_tank_spawn(edict_t *ent, int cost) { } void Cmd_PlayerToTank_f(edict_t *ent) { - int tank_cubecost = P_TANK_INIT_COST; + const int tank_cubecost = P_TANK_INIT_COST; if (debuginfo->value) gi.dprintf("DEBUG: %s just called Cmd_PlayerToTank_f()\n", ent->client->pers.netname); diff --git a/src/combat/abilities/scanner.c b/src/combat/abilities/scanner.c index 0a930f94..09a37897 100644 --- a/src/combat/abilities/scanner.c +++ b/src/combat/abilities/scanner.c @@ -113,7 +113,7 @@ void ShowScanner (edict_t *ent, char *layout) { int sx, sy; vec3_t v, dp; - vec3_t normal = {0,0,-1}; + const vec3_t normal = {0,0,-1}; float dist, heightDelta; // sanity check diff --git a/src/combat/abilities/sentrygun2.c b/src/combat/abilities/sentrygun2.c index ca343fbf..fe8b9de1 100644 --- a/src/combat/abilities/sentrygun2.c +++ b/src/combat/abilities/sentrygun2.c @@ -319,46 +319,47 @@ void attack(edict_t *self) return; // 3.19 sentry can't fire outside its FOV //Fire - switch (self->mtype) - { - case M_SENTRY: - //Fire a rocket if there is sufficient ammo - if ((level.time >= self->delay) && (self->style >= SENTRY_ROCKETCOST) && (self->orders >= 3)) - sentFireRocket(self); - // are we affected by holy freeze? - if (que_typeexists(self->curses, AURA_HOLYFREEZE)/*HasActiveCurse(self, AURA_HOLYFREEZE)*/ && !(level.framenum % 2)) - break; - // chill effect reduces attack rate/refire - if (self->chill_time > level.time) - { - chance = 1 / (1 + CHILL_DEFAULT_BASE + CHILL_DEFAULT_ADDON * self->chill_level); - if (random() > chance) + if ( ( level.framenum % qf2sf( 1 ) ) == 0 ) { + switch (self->mtype) { + case M_SENTRY: + //Fire a rocket if there is sufficient ammo + if ((level.time >= self->delay) && (self->style >= SENTRY_ROCKETCOST) && (self->orders >= 3)) + sentFireRocket(self); + // are we affected by holy freeze? + if (que_typeexists(self->curses, AURA_HOLYFREEZE)/*HasActiveCurse(self, AURA_HOLYFREEZE)*/ && !(level.framenum % 2)) break; - } - //Fire a bullet if there is sufficient ammo - if (self->light_level >= SENTRY_BULLETCOST) - { - sentFireBullet(self); + // chill effect reduces attack rate/refire + if (self->chill_time > level.time) + { + chance = 1 / (1 + CHILL_DEFAULT_BASE + CHILL_DEFAULT_ADDON * self->chill_level); + if (random() > chance) + break; + } + //Fire a bullet if there is sufficient ammo + if (self->light_level >= SENTRY_BULLETCOST) + { + sentFireBullet(self); - // firing animation - if (self->s.frame == 1) - self->s.frame = 2; - else - self->s.frame = 1; - } - break; - /* - //New bfg firing (wee!) - case M_BFG_SENTRY: - if(self->count >= SENTRY_BFG_AMMOCOST) - { - if(self->delay <= level.time) - sentFireBFG(self); - else if(self->delay - 1 == level.time) - gi.sound(self, CHAN_AUTO, gi.soundindex("misc/power1.wav"), 1, ATTN_STATIC, 0); + // firing animation + if (self->s.frame == 1) + self->s.frame = 2; + else + self->s.frame = 1; + } + break; + /* + //New bfg firing (wee!) + case M_BFG_SENTRY: + if(self->count >= SENTRY_BFG_AMMOCOST) + { + if(self->delay <= level.time) + sentFireBFG(self); + else if(self->delay - 1 == level.time) + gi.sound(self, CHAN_AUTO, gi.soundindex("misc/power1.wav"), 1, ATTN_STATIC, 0); + } + break; + */ } - break; - */ } // if(self->s.angles[PITCH] != 0) @@ -528,7 +529,7 @@ qboolean sentReload(edict_t *self, edict_t *other) case M_SENTRY: { int client_bullets, client_rockets; - edict_t *player = other; + const edict_t *player = other; //Point to player's ammo client_bullets = player->client->pers.inventory[ITEM_INDEX(FindItem("Bullets"))]; @@ -764,7 +765,7 @@ void sentRotate(edict_t *self) void sentrygun_think(edict_t *self) { - edict_t *target = NULL; + const edict_t *target = NULL; qboolean damaged = false; float temp, modifier; que_t *slot = NULL; @@ -809,10 +810,10 @@ void sentrygun_think(edict_t *self) } // toggle sentry spotlight - if (level.daytime && self->flashlight) - FL_make(self); - else if (!level.daytime && !self->flashlight) - FL_make(self); + if (level.daytime && FL_exists(self)) + FL_toggle(self); + else if (!level.daytime && !FL_exists(self)) + FL_toggle(self); // is the sentry slowed by holy freeze? temp = self->yaw_speed; @@ -829,7 +830,7 @@ void sentrygun_think(edict_t *self) if (!self->enemy) //If we do not have a target yet { - if (target = sentry_findtarget(self)) + if ((target = sentry_findtarget(self))) attack(self); } else if (CanTarget(self)) diff --git a/src/combat/abilities/spike.c b/src/combat/abilities/spike.c index 85c58000..b2ec8dac 100644 --- a/src/combat/abilities/spike.c +++ b/src/combat/abilities/spike.c @@ -55,11 +55,11 @@ void fire_spike (edict_t *self, vec3_t start, vec3_t dir, int damage, float stun void SpikeAttack (edict_t *ent) { - int spike_level = ent->myskills.abilities[SPIKE].current_level; - int spiker_level = ent->myskills.abilities[SPIKER].current_level; + const int spike_level = ent->myskills.abilities[SPIKE].current_level; + const int spiker_level = ent->myskills.abilities[SPIKER].current_level; int i, move, damage; float delay; - float synergy_bonus = 1.0 + SPIKE_SPIKER_SYNERGY_BONUS * spiker_level; + const float synergy_bonus = 1.0 + SPIKE_SPIKER_SYNERGY_BONUS * spiker_level; vec3_t angles, v, org; vec3_t offset, forward, right, start; diff --git a/src/combat/abilities/supplystation.c b/src/combat/abilities/supplystation.c index a9519f82..41edf5c2 100644 --- a/src/combat/abilities/supplystation.c +++ b/src/combat/abilities/supplystation.c @@ -300,8 +300,8 @@ void station_dropitem (edict_t *self) // have some rockets or bullets to feed the sentry if ((ammo == 1.0) && PlayerHasSentry(self->enemy)) { - int bullet_ammo = self->enemy->client->pers.inventory[bullet_index]; - int rocket_ammo = self->enemy->client->pers.inventory[rocket_index]; + const int bullet_ammo = self->enemy->client->pers.inventory[bullet_index]; + const int rocket_ammo = self->enemy->client->pers.inventory[rocket_index]; if (!bullet_ammo || !rocket_ammo) { diff --git a/src/combat/abilities/totems.c b/src/combat/abilities/totems.c index d6c09de6..b42df4f5 100644 --- a/src/combat/abilities/totems.c +++ b/src/combat/abilities/totems.c @@ -4,6 +4,7 @@ #include "g_local.h" #include "../../gamemodes/ctf.h" #include "../../characters/class_limits.h" +void fire_meteor(edict_t *self, vec3_t end, int damage, int radius, int speed); void RemoveTotem(edict_t *self) { @@ -101,7 +102,7 @@ edict_t *NextNearestTotem(edict_t *ent, int totemType, edict_t *lastTotem, qbool int GetTotemLevel(edict_t *ent, int totemType, qboolean allied) { - edict_t *totem = NextNearestTotem(ent, totemType, NULL, allied); + const edict_t *totem = NextNearestTotem(ent, totemType, NULL, allied); if(totem != NULL) return totem->monsterinfo.level; return 0; @@ -114,7 +115,7 @@ int GetTotemLevel(edict_t *ent, int totemType, qboolean allied) void FireTotem_meteor_attack(edict_t* self, edict_t *target) { int damage, radius, speed; - float slvl = self->monsterinfo.level; + const float slvl = self->monsterinfo.level; //if (!G_EntExists(self->enemy)) // return; @@ -141,11 +142,11 @@ void FireTotem_meteor_attack(edict_t* self, edict_t *target) void FireTotem_fireball_attack(edict_t* self, edict_t *target, qboolean fireball) { - int damage = FIRETOTEM_DAMAGE_BASE + self->monsterinfo.level * FIRETOTEM_DAMAGE_MULT; - int fb_dmg = FIREBALL_INITIAL_DAMAGE + self->monsterinfo.level * FIREBALL_ADDON_DAMAGE; - int speed = 600; + const int damage = FIRETOTEM_DAMAGE_BASE + self->monsterinfo.level * FIRETOTEM_DAMAGE_MULT; + const int fb_dmg = FIREBALL_INITIAL_DAMAGE + self->monsterinfo.level * FIREBALL_ADDON_DAMAGE; + const int speed = 600; float val, dist; - float rad = FIREBALL_INITIAL_RADIUS + FIREBALL_ADDON_RADIUS * self->monsterinfo.level; + const float rad = FIREBALL_INITIAL_RADIUS + FIREBALL_ADDON_RADIUS * self->monsterinfo.level; vec3_t start, forward, end; //int count = 10 + self->monsterinfo.level; @@ -194,7 +195,7 @@ void FireTotem_fireball_attack(edict_t* self, edict_t *target, qboolean fireball void FireTotem_think(edict_t *self, edict_t *caster) { - int talentLevel = vrx_get_talent_level(caster, TALENT_VOLCANIC); + const int talentLevel = vrx_get_talent_level(caster, TALENT_VOLCANIC); // regenerate fireballs every 1 second if (level.framenum > self->monsterinfo.lefty && self->light_level < 3) @@ -258,12 +259,12 @@ void WaterTotem_glacialspike_attack(edict_t* self, edict_t* target) float val, dist; vec3_t start, forward, end; - int skill_level = self->monsterinfo.level; - float chill_duration = GLACIAL_SPIKE_INITIAL_CHILL + GLACIAL_SPIKE_ADDON_CHILL * skill_level; - float freeze_duration = GLACIAL_SPIKE_INITIAL_FREEZE + GLACIAL_SPIKE_ADDON_FREEZE * skill_level; - int damage = GLACIAL_SPIKE_INITIAL_DAMAGE + GLACIAL_SPIKE_ADDON_DAMAGE * skill_level; - float radius = GLACIAL_SPIKE_INITIAL_RADIUS + GLACIAL_SPIKE_ADDON_RADIUS * skill_level; - float speed = GLACIAL_SPIKE_INITIAL_SPEED + GLACIAL_SPIKE_ADDON_SPEED * skill_level; + const int skill_level = self->monsterinfo.level; + const float chill_duration = GLACIAL_SPIKE_INITIAL_CHILL + GLACIAL_SPIKE_ADDON_CHILL * skill_level; + const float freeze_duration = GLACIAL_SPIKE_INITIAL_FREEZE + GLACIAL_SPIKE_ADDON_FREEZE * skill_level; + const int damage = GLACIAL_SPIKE_INITIAL_DAMAGE + GLACIAL_SPIKE_ADDON_DAMAGE * skill_level; + const float radius = GLACIAL_SPIKE_INITIAL_RADIUS + GLACIAL_SPIKE_ADDON_RADIUS * skill_level; + const float speed = GLACIAL_SPIKE_INITIAL_SPEED + GLACIAL_SPIKE_ADDON_SPEED * skill_level; // copy target location G_EntMidPoint(target, end); @@ -298,9 +299,9 @@ void WaterTotem_frozenorb_attack(edict_t* self, edict_t* target) float val, dist; vec3_t start, forward, end; - int skill_level = self->monsterinfo.level; - int damage = FROZEN_ORB_INITIAL_DAMAGE + FROZEN_ORB_ADDON_DAMAGE * skill_level; - float chill_duration = FROZEN_ORB_INITIAL_CHILL + FROZEN_ORB_ADDON_CHILL * skill_level; + const int skill_level = self->monsterinfo.level; + const int damage = FROZEN_ORB_INITIAL_DAMAGE + FROZEN_ORB_ADDON_DAMAGE * skill_level; + const float chill_duration = FROZEN_ORB_INITIAL_CHILL + FROZEN_ORB_ADDON_CHILL * skill_level; // copy target location G_EntMidPoint(target, end); @@ -339,8 +340,8 @@ void WaterTotem_frozenorb_attack(edict_t* self, edict_t* target) void WaterTotem_think(edict_t* self, edict_t* caster) { edict_t* e = NULL; - int talentLevel = vrx_get_talent_level(caster, TALENT_ICE); - float FO_refire = 5.0 - (0.8 * talentLevel); // talent level reduces refire time + const int talentLevel = vrx_get_talent_level(caster, TALENT_ICE); + const float FO_refire = 5.0 - (0.8 * talentLevel); // talent level reduces refire time // regen frozen orbs if we've upgraded Volcanic talent if (talentLevel && level.time > self->monsterinfo.attack_finished && self->monsterinfo.jumpdn < 1) @@ -534,7 +535,7 @@ void totem_general_think(edict_t *self) int *cubes = &caster->client->pers.inventory[ITEM_INDEX(Fdi_POWERCUBE)]; //Talent: Totemic Focus. - int cost = 10;//30 - vrx_get_talent_level(caster, TALENT_TOTEM) * 5; + const int cost = 10;//30 - vrx_get_talent_level(caster, TALENT_TOTEM) * 5; if(*cubes < cost) { *cubes = 0; @@ -581,7 +582,7 @@ void totem_general_think(edict_t *self) // run firetotem model frames if (self->mtype == TOTEM_FIRE) - G_RunFrames(self, 0, 4, false); + G_RunFrames(self, 0, 4, false, true); M_CatagorizePosition (self); M_WorldEffects (self); diff --git a/src/combat/abilities/v_think.c b/src/combat/abilities/v_think.c index 9a433eba..01a94500 100644 --- a/src/combat/abilities/v_think.c +++ b/src/combat/abilities/v_think.c @@ -12,7 +12,7 @@ void think_ability_ammo_regen(edict_t* ent) { } if (level.time > ent->client->ammo_regentime) { - float regen_level = (float)ent->myskills.abilities[AMMO_REGEN].current_level; + const float regen_level = (float)ent->myskills.abilities[AMMO_REGEN].current_level; V_GiveAmmoClip(ent, regen_level * 0.2f * amount_mult, @@ -42,7 +42,7 @@ void think_ability_power_regen(edict_t* ent) { ent->pcr_time += FRAMETIME; - double regen_time = (5.0f / ent->myskills.abilities[POWER_REGEN].current_level); + const double regen_time = (5.0f / ent->myskills.abilities[POWER_REGEN].current_level); if (ent->myskills.abilities[POWER_REGEN].disable) return; @@ -50,7 +50,7 @@ void think_ability_power_regen(edict_t* ent) { gitem_t* item = Fdi_POWERCUBE; if (!item) return; - int index = ITEM_INDEX(item); + const int index = ITEM_INDEX(item); while (ent->pcr_time > regen_time) { if (ent->client->pers.inventory[index] < ent->client->pers.max_powercubes) { @@ -99,20 +99,20 @@ void think_trade(edict_t* ent) {//3.0 new trading } -void think_chat_protect_activate(edict_t* ent) { - if (!ptr->value && !domination->value && !ctf->value && - !(hw->value && vrx_has_flag(ent)) // the game isn't holywars and the player doesn't have the flag - && !ent->myskills.administrator // Not an admin - && !que_typeexists(ent->curses, 0) // Not cursed - && (ent->myskills.streak < SPREE_START)) // Not on a spree - { - if (!((!ent->myskills.abilities[CLOAK].disable) && ((ent->myskills.abilities[CLOAK].current_level > 0)))) { - if (!trading->value && !ent->automag) // trading mode no chat protection or if automagging either - { - if (sf2qf(ent->client->idle_frames) == CHAT_PROTECT_FRAMES - 100) - safe_centerprintf(ent, "10 seconds to chat-protect.\n"); - else if (sf2qf(ent->client->idle_frames) == CHAT_PROTECT_FRAMES - 50) - safe_centerprintf(ent, "5 seconds to chat-protect.\n"); +void think_chat_protect_activate(edict_t *ent) { + if (!ptr->value && !domination->value && !ctf->value && + !(hw->value && vrx_has_flag(ent)) // the game isn't holywars and the player doesn't have the flag + && !ent->myskills.administrator // Not an admin + && !que_typeexists(ent->curses, 0) // Not cursed + && (ent->myskills.streak < SPREE_START)) // Not on a spree + { + if (!((!ent->myskills.abilities[CLOAK].disable) && ((ent->myskills.abilities[CLOAK].current_level > 0)))) { + if (!trading->value && !ent->automag) // trading mode no chat protection or if automagging either + { + if (sf2qf(ent->client->idle_frames) == qf2sf(CHAT_PROTECT_FRAMES - 100)) + safe_centerprintf(ent, "10 seconds to chat-protect.\n"); + else if (sf2qf(ent->client->idle_frames) == qf2sf(CHAT_PROTECT_FRAMES - 50)) + safe_centerprintf(ent, "5 seconds to chat-protect.\n"); if (sf2qf(ent->client->idle_frames) == qf2sf(CHAT_PROTECT_FRAMES)) { safe_centerprintf(ent, "Now in chat-protect mode.\n"); @@ -132,7 +132,7 @@ void think_chat_protect_activate(edict_t* ent) { void think_player_inactivity(edict_t* ent) { if (level.time > pregame_time->value && vrx_get_joined_players(false) > maxclients->value * 0.8) { - int frames = MAX_IDLE_FRAMES; + const int frames = MAX_IDLE_FRAMES; if (!ent->myskills.administrator && !trading->value) { if (ent->client->still_frames == frames - 300) @@ -159,7 +159,7 @@ void think_idle_frame_counter(const edict_t* ent) { //Make sure they have the talent - int talentLevel = vrx_get_talent_level(ent, TALENT_IMP_CLOAK); + const int talentLevel = vrx_get_talent_level(ent, TALENT_IMP_CLOAK); if (talentLevel > 0) { int cloak_cubecost = 6 - talentLevel; @@ -225,69 +225,6 @@ qboolean CanSuperSpeed(edict_t* ent) { return false; } -/* -pmove_t -V_Think_ApplySuperSpeed(edict_t *ent, const usercmd_t *ucmd, gclient_t *client, int i, pmove_t *pm, int viewheight) { - if (ent->superspeed) { - - if (!CanSuperSpeed(ent)) { - ent->superspeed = false; - } else if (level.time > ent->lasthurt + DAMAGE_ESCAPE_DELAY) { - // ent->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION; - (*pm).s = client->ps.pmove; - - { - (*pm).s.origin[i] = ent->s.origin[i] * 6; - //pm.s.velocity[i] = ent->velocity[i]*8; - } - (*pm).s.velocity[0] = ent->velocity[0] * 6; - (*pm).s.velocity[1] = ent->velocity[1] * 6; - - if (memcmp(&client->old_pmove, &(*pm).s, sizeof((*pm).s)) != 0) { - (*pm).snapinitial = true; - // gi.dprintf ("pmove changed!\n"); - } - - (*pm).cmd = *ucmd; - - (*pm).trace = PM_trace; // adds default parms - - (*pm).pointcontents = gi.pointcontents; - - // perform a pmove - gi.Pmove(pm); - -// GHz START - // if this is a morphed player, restore saved viewheight - // this locks them into that viewheight - if (ent->mtype) - (*pm).viewheight = viewheight; -//GHz END - // save results of pmove - client->ps.pmove = (*pm).s; - client->old_pmove = (*pm).s; - - for (i = 0; i < 3; i++) { - ent->s.origin[i] = (*pm).s.origin[i] * 0.125; - //ent->velocity[i] = pm.s.velocity[i]*0.125; - } - ent->velocity[0] = (*pm).s.velocity[0] * 0.125; - ent->velocity[1] = (*pm).s.velocity[1] * 0.125; - - VectorCopy ((*pm).mins, ent->mins); - VectorCopy ((*pm).maxs, ent->maxs); - - client->resp.cmd_angles[0] = SHORT2ANGLE(ucmd->angles[0]); - client->resp.cmd_angles[1] = SHORT2ANGLE(ucmd->angles[1]); - client->resp.cmd_angles[2] = SHORT2ANGLE(ucmd->angles[2]); - - // ent->client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION; - } - } - //K03 End - - return (*pm); -}*/ float V_ModifyMovement(edict_t* ent, usercmd_t* ucmd, que_t* curse) {// assault cannon slows you down float vel_modification = 1; @@ -329,7 +266,7 @@ float V_ModifyMovement(edict_t* ent, usercmd_t* ucmd, que_t* curse) {// assault // 3.5 weaken slows down target if ((curse = que_findtype(ent->curses, NULL, WEAKEN)) != NULL) { - float modifier = 1 / (1 + WEAKEN_SLOW_BASE + WEAKEN_SLOW_BONUS + const float modifier = 1 / (1 + WEAKEN_SLOW_BASE + WEAKEN_SLOW_BONUS * curse->ent->owner->myskills.abilities[WEAKEN].current_level); vel_modification *= modifier; } @@ -383,14 +320,21 @@ float V_ModifyMovement(edict_t* ent, usercmd_t* ucmd, que_t* curse) {// assault /* az: rewrite how superspeed works because it fucking sucks */ - qboolean superspeed = ent->superspeed && CanSuperSpeed(ent) && level.time > ent->lasthurt + DAMAGE_ESCAPE_DELAY; + const qboolean superspeed = ent->superspeed && CanSuperSpeed(ent) && level.time > ent->lasthurt + DAMAGE_ESCAPE_DELAY; +#ifndef VRX_REPRO if (superspeed) { vel_modification *= 1.75; } - +#else + // handled by pmove + if (superspeed) + ent->client->ps.pmove.pm_flags |= PMF_SUPERSPEED; + else + ent->client->ps.pmove.pm_flags &= ~PMF_SUPERSPEED; +#endif //K03 Begin - qboolean hook = (ent->client->hook_state == HOOK_ON) && (VectorLength(ent->velocity) < 10); + const qboolean hook = (ent->client->hook_state == HOOK_ON) && (VectorLength(ent->velocity) < 10); if (hook/* || vel_modification != 1*/) { ent->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION; @@ -400,6 +344,16 @@ float V_ModifyMovement(edict_t* ent, usercmd_t* ucmd, que_t* curse) {// assault } //K03 End + if (ent->mtype == MORPH_CACODEMON) + ent->client->ps.pmove.pm_flags |= PMF_CACODEMON; + else + ent->client->ps.pmove.pm_flags &= ~PMF_CACODEMON; + + if (ent->mtype == MORPH_FLYER) + ent->client->ps.pmove.pm_flags |= PMF_NOCROUCH; + else + ent->client->ps.pmove.pm_flags &= ~PMF_NOCROUCH; + return vel_modification; } @@ -448,7 +402,7 @@ void think_recharge_abilities(edict_t* ent) { } // az: super speed sprint - qboolean can_superspeed = !ent->myskills.abilities[SUPER_SPEED].disable && ent->myskills.abilities[SUPER_SPEED].current_level; + const qboolean can_superspeed = !ent->myskills.abilities[SUPER_SPEED].disable && ent->myskills.abilities[SUPER_SPEED].current_level; if (!ent->superspeed && can_superspeed) { if (ent->myskills.abilities[SUPER_SPEED].charge < SPRINT_MAX_CHARGE) { ent->myskills.abilities[SUPER_SPEED].charge += SPRINT_CHARGE_RATE; @@ -480,13 +434,13 @@ void think_ability_cloak(edict_t* ent) { min_idle_frames = 1; } - qboolean idled_enough = ent->client->idle_frames >= min_idle_frames; - qboolean has_no_curses = !que_typeexists(ent->auras, 0); - qboolean ability_delay_over = (level.time > ent->client->ability_delay); - qboolean has_no_flag = !vrx_has_flag(ent); - qboolean has_no_summons = !V_HasSummons(ent); - qboolean is_not_automagging = !ent->automag; - qboolean can_cloak = idled_enough + const qboolean idled_enough = ent->client->idle_frames >= min_idle_frames; + const qboolean has_no_curses = !que_typeexists(ent->auras, 0); + const qboolean ability_delay_over = (level.time > ent->client->ability_delay); + const qboolean has_no_flag = !vrx_has_flag(ent); + const qboolean has_no_summons = !V_HasSummons(ent); + const qboolean is_not_automagging = !ent->automag; + const qboolean can_cloak = idled_enough && has_no_curses && ability_delay_over && has_no_flag @@ -529,7 +483,7 @@ void think_ability_antigrav(edict_t* ent) { void think_ability_superspeed(edict_t* ent) { if (ent->superspeed && ent->deadflag != DEAD_DEAD) { //3.0 Blessed players get a speed boost too - que_t* slot = NULL; + const que_t* slot = NULL; slot = que_findtype(ent->curses, NULL, BLESS); //eat cubes if the player isn't blessed @@ -607,7 +561,7 @@ void think_ability_health_regen(edict_t* ent) { && !(ctf->value && ctf_enable_balanced_fc->value && vrx_has_flag(ent))) { //3.0 cursed players can't heal through regeneration if (que_findtype(ent->curses, NULL, CURSE) == NULL) { - int health_factor = 1 * ent->myskills.abilities[REGENERATION].current_level; // Regeneration OP. :D + const int health_factor = 1 * ent->myskills.abilities[REGENERATION].current_level; // Regeneration OP. :D ent->health += health_factor; if (ent->health > ent->max_health) @@ -651,9 +605,9 @@ void think_tech_regeneration(edict_t* ent) { void think_ability_fury(edict_t* ent) { if (!(level.framenum % (int)(1 / FRAMETIME)) && (ent->fury_time > level.time && ent->client)) { if (G_EntIsAlive(ent) && !(ctf->value && ctf_enable_balanced_fc->value && vrx_has_flag(ent))) { - int maxHP = MAX_HEALTH(ent); - int maxAP = MAX_ARMOR(ent); - int* armor = &ent->client->pers.inventory[body_armor_index]; + const int maxHP = MAX_HEALTH(ent); + const int maxAP = MAX_ARMOR(ent); + const int* armor = &ent->client->pers.inventory[body_armor_index]; float factor = FURY_INITIAL_REGEN + (FURY_ADDON_REGEN * ent->myskills.abilities[FURY].current_level); if (factor > FURY_MAX_REGEN) @@ -715,9 +669,9 @@ void think_talent_life_regen(edict_t* ent) { && vrx_get_talent_slot(ent, TALENT_LIFE_REG) != -1 && G_EntIsAlive(ent) && (ent->health < ent->max_health)) { - talent_t* talent = &ent->myskills.talents.talent[vrx_get_talent_slot(ent, TALENT_LIFE_REG)]; + const talent_t* talent = &ent->myskills.talents.talent[vrx_get_talent_slot(ent, TALENT_LIFE_REG)]; if (talent->upgradeLevel > 0) { - int health_factor = 1; + const int health_factor = 1; ent->health += health_factor; if (ent->health > ent->max_health) ent->health = ent->max_health; diff --git a/src/combat/common/damage.c b/src/combat/common/damage.c index 49a243fb..9a98b653 100644 --- a/src/combat/common/damage.c +++ b/src/combat/common/damage.c @@ -155,7 +155,7 @@ qboolean IsMonster(const edict_t* ent) { float vrx_get_pack_modifier(const edict_t *ent) { //Talent: Pack Animal int talentLevel = 0; - edict_t *e = NULL; + const edict_t *e = NULL; if (ent->client) talentLevel = vrx_get_talent_level(ent, TALENT_PACK_ANIMAL); @@ -192,7 +192,7 @@ void vrx_apply_player_damage_bonus(edict_t *targ, edict_t *attacker, float *dama // Blink Strike damage bonus applies before attacker has to teleport back, targ is our Blink Strike target, and attacker is not in-front of target if (attacker->client->tele_timeout > level.framenum && attacker->client->blinkStrike_targ && attacker->client->blinkStrike_targ == targ && !infront(targ, attacker)) { - float temp = 1 + BLINKSTRIKE_INITIAL_BONUS + BLINKSTRIKE_ADDON_BONUS * attacker->myskills.abilities[BLINKSTRIKE].current_level; + const float temp = 1 + BLINKSTRIKE_INITIAL_BONUS + BLINKSTRIKE_ADDON_BONUS * attacker->myskills.abilities[BLINKSTRIKE].current_level; //gi.dprintf("Blink Strike damage bonus: %.1fx\n", temp); *damage *= temp; } @@ -245,7 +245,7 @@ void vrx_apply_player_damage_bonus(edict_t *targ, edict_t *attacker, float *dama // ******TALENT BLOOD OF ARES START {****** // if (vrx_get_talent_slot(attacker, TALENT_BLOOD_OF_ARES) != -1) { - int level = vrx_get_talent_level(attacker, TALENT_BLOOD_OF_ARES); + const int level = vrx_get_talent_level(attacker, TALENT_BLOOD_OF_ARES); float temp; // BoA is more effective in PvM @@ -278,7 +278,7 @@ float vrx_increase_damage(edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t point, float damage, int dflags, int mod) { int dtype; float temp; - que_t *slot = NULL; + const que_t *slot = NULL; qboolean physicalDamage; dtype = G_DamageType(mod, dflags); @@ -322,8 +322,8 @@ float vrx_increase_damage(edict_t *targ, edict_t *inflictor, edict_t *attacker, damage *= 3; if (ctf->value) { - int delta = fabsf(red_flag_caps - blue_flag_caps); - edict_t *cl_targ = G_GetClient(targ); + const int delta = abs(red_flag_caps - blue_flag_caps); + const edict_t *cl_targ = G_GetClient(targ); if ((delta > 1) && cl_targ) // need at least 2 caps { @@ -421,7 +421,7 @@ float vrx_apply_morph_talent_damage(const edict_t *targ, const edict_t *attacker if (attacker->owner && attacker->owner->inuse && attacker->owner->client) attacker = attacker->owner; - float levels = attacker->myskills.level - 10; + const float levels = attacker->myskills.level - 10; // Talent: Retaliation // increases damage as percentage of remaining health is reduced @@ -429,7 +429,7 @@ float vrx_apply_morph_talent_damage(const edict_t *targ, const edict_t *attacker // Talent: Superiority // increases damage/resistance of morphed players against monsters - int talentLevel = vrx_get_talent_level(attacker, TALENT_SUPERIORITY); + const int talentLevel = vrx_get_talent_level(attacker, TALENT_SUPERIORITY); if (talentLevel > 0 && targ->activator && targ->mtype != P_TANK && targ->svflags & SVF_MONSTER) damage *= 1.0f + 0.2f * (float)talentLevel; @@ -501,9 +501,9 @@ float vrx_apply_bless_damage_bonus(const edict_t *attacker, float damage, int dt } float vrx_apply_weaken(const edict_t *targ, float damage) { - que_t *slot = que_findtype(targ->curses, NULL, WEAKEN); + const que_t *slot = que_findtype(targ->curses, NULL, WEAKEN); if (slot != NULL) { - float temp = WEAKEN_MULT_BASE + (slot->ent->monsterinfo.level * WEAKEN_MULT_BONUS); + const float temp = WEAKEN_MULT_BASE + (slot->ent->monsterinfo.level * WEAKEN_MULT_BONUS); //(slot->ent->owner->myskills.abilities[WEAKEN].current_level * WEAKEN_MULT_BONUS); damage *= temp; } @@ -511,7 +511,7 @@ float vrx_apply_weaken(const edict_t *targ, float damage) { } float vrx_apply_amp_damage(const edict_t *targ, float damage) { - que_t *slot = que_findtype(targ->curses, NULL, AMP_DAMAGE); + const que_t *slot = que_findtype(targ->curses, NULL, AMP_DAMAGE); if (slot != NULL) { float temp = AMP_DAMAGE_MULT_BASE + (slot->ent->monsterinfo.level * AMP_DAMAGE_MULT_BONUS); //(slot->ent->owner->myskills.abilities[AMP_DAMAGE].current_level * AMP_DAMAGE_MULT_BONUS); @@ -527,7 +527,7 @@ float vrx_apply_amp_damage(const edict_t *targ, float damage) { float vrx_apply_monster_mastery(const edict_t *attacker, float damage) { if (vrx_get_talent_slot(attacker, TALENT_MONSTER_MASTERY) != -1) { - int level = vrx_get_talent_level(attacker, TALENT_MONSTER_MASTERY); + const int level = vrx_get_talent_level(attacker, TALENT_MONSTER_MASTERY); float temp; if (pvm->value || invasion->value) { @@ -543,8 +543,8 @@ float vrx_apply_monster_mastery(const edict_t *attacker, float damage) { float vrx_apply_manashield(edict_t *targ, float damage) { if (vrx_get_talent_level(targ, TALENT_MANASHIELD) > 0 && targ->manashield) { int damage_absorbed = 0.8 * damage; - float absorb_mult = 3.5 - 0.5668 * vrx_get_talent_level(targ, TALENT_MANASHIELD); - int pc_cost = damage_absorbed * absorb_mult; + const float absorb_mult = 3.5 - 0.5668 * vrx_get_talent_level(targ, TALENT_MANASHIELD); + const int pc_cost = damage_absorbed * absorb_mult; int *cubes = &targ->client->pers.inventory[power_cube_index]; if (pc_cost > *cubes) { @@ -576,7 +576,7 @@ float vrx_apply_fury(const edict_t *targ, const edict_t *attacker, float temp, f float vrx_apply_blast_resist(const edict_t *targ, int dflags, int mod, float temp, float Resistance) { { - int talentLevel = vrx_get_talent_level(targ, TALENT_BLAST_RESIST); + const int talentLevel = vrx_get_talent_level(targ, TALENT_BLAST_RESIST); if (talentLevel && ((dflags & DAMAGE_RADIUS) || mod == MOD_SELFDESTRUCT)) { temp = 1 - 0.15 * talentLevel; @@ -587,7 +587,7 @@ float vrx_apply_blast_resist(const edict_t *targ, int dflags, int mod, float tem } float vrx_apply_combat_experience_damage_increase(const edict_t *targ, float damage) { - int talentLevel = vrx_get_talent_level(targ, TALENT_COMBAT_EXP); + const int talentLevel = vrx_get_talent_level(targ, TALENT_COMBAT_EXP); if (talentLevel > 0) damage *= 1.0 + 0.05 * talentLevel; //-5% per upgrade @@ -629,7 +629,7 @@ void vrx_apply_resistance(const edict_t *targ, float *Resistance) { float vrx_apply_blood_of_ares(const edict_t *targ, const edict_t *attacker, float damage) { if (vrx_get_talent_slot(targ, TALENT_BLOOD_OF_ARES) != -1) { - int level = vrx_get_talent_level(targ, TALENT_BLOOD_OF_ARES); + const int level = vrx_get_talent_level(targ, TALENT_BLOOD_OF_ARES); float temp; // BoA is more effective in PvM @@ -686,7 +686,7 @@ void vrx_apply_morph_modifiers(const edict_t *targ, const edict_t *attacker, flo // Talent: Superiority // increases damage/resistance of morphed players against monsters - int talentLevel = vrx_get_talent_level(targ, TALENT_SUPERIORITY); + const int talentLevel = vrx_get_talent_level(targ, TALENT_SUPERIORITY); if (attacker->activator && attacker->mtype != P_TANK && (attacker->svflags & SVF_MONSTER) && talentLevel > 0) temp += 0.2f * talentLevel; @@ -772,7 +772,7 @@ float vrx_apply_bombardier(const edict_t *targ, const edict_t *attacker, int mod if (PM_GetPlayer(targ) == PM_GetPlayer(attacker) && (mod == MOD_EMP || mod == MOD_MIRV || mod == MOD_NAPALM || mod == MOD_GRENADE || mod == MOD_HG_SPLASH || mod == MOD_HANDGRENADE)) { - int talentLevel = vrx_get_talent_level(targ, TALENT_BOMBARDIER); + const int talentLevel = vrx_get_talent_level(targ, TALENT_BOMBARDIER); if (mod == MOD_EMP) Resistance = fminf(Resistance, 1.0f - 0.16f * talentLevel); else @@ -784,9 +784,9 @@ float vrx_apply_bombardier(const edict_t *targ, const edict_t *attacker, int mod qboolean vrx_should_apply_ghost(edict_t *targ) { if (!targ->myskills.abilities[GHOST].disable) { - int talentSlot = vrx_get_talent_slot(targ, TALENT_SECOND_CHANCE); + const int talentSlot = vrx_get_talent_slot(targ, TALENT_SECOND_CHANCE); float temp = 1 + 0.05f * targ->myskills.abilities[GHOST].current_level; - edict_t* dclient = G_GetClient(targ); + const edict_t* dclient = G_GetClient(targ); temp = 1.0f / temp; @@ -816,7 +816,7 @@ qboolean vrx_should_apply_ghost(edict_t *targ) { //Make sure the talent is not on cooldown if (talent->upgradeLevel > 0 && talent->delay < level.time) { //Cooldown should be 3 minutes - 0.5min per upgrade level - float cooldown = 180.f - 30.f * vrx_get_talent_level(targ, TALENT_SECOND_CHANCE); + const float cooldown = 180.f - 30.f * vrx_get_talent_level(targ, TALENT_SECOND_CHANCE); talent->delay = level.time + cooldown; return true; } @@ -828,12 +828,12 @@ qboolean vrx_should_apply_ghost(edict_t *targ) { float vrx_resist_damage(edict_t *targ, edict_t *inflictor, edict_t *attacker, float damage, int dflags, int mod) { int dtype; - float temp = 0; + const float temp = 0; que_t *aura = NULL; // int talentLevel; qboolean invasion_friendlyfire = false; float Resistance = 1.0; // We find the highest resist value and only use THAT. - qboolean is_target_morphed_player = IsMorphedPlayer(targ); + const qboolean is_target_morphed_player = IsMorphedPlayer(targ); //gi.dprintf("G_SubDamage()\n"); //gi.dprintf("%d damage before G_SubDamage() modification\n", damage); @@ -1042,8 +1042,8 @@ int vrx_apply_pierce(const edict_t *targ, const edict_t *attacker, const float d } if (pierceLevel > 0) { - float temp = 1.0f / (1.0f + pierceFactor * pierceLevel); - double rnd = random(); + const float temp = 1.0f / (1.0f + pierceFactor * pierceLevel); + const double rnd = random(); if (rnd >= temp) dflags |= DAMAGE_NO_ARMOR; diff --git a/src/combat/common/g_combat.c b/src/combat/common/g_combat.c index 26747bc1..87fa9e83 100644 --- a/src/combat/common/g_combat.c +++ b/src/combat/common/g_combat.c @@ -52,7 +52,7 @@ float vrx_get_curse_duration(edict_t* ent, int type); qboolean HitTheWeapon (edict_t *targ, edict_t *attacker, const vec3_t point, int take, int dflags) { - edict_t *cl_ent=attacker; + const edict_t *cl_ent=attacker; float z_rel; if (PM_MonsterHasPilot(attacker)) @@ -173,13 +173,13 @@ qboolean CanDamage (edict_t *targ, edict_t *inflictor) void G_ApplyFury(edict_t *attacker) { - int chance = attacker->myskills.abilities[FURY].current_level; - int r = GetRandom(0, 100); + const int chance = attacker->myskills.abilities[FURY].current_level; + const int r = GetRandom(0, 100); //The following is truncated so that every 4th point adds an extra 1%. if (r < chance) { - float duration = FURY_DURATION_BASE + FURY_DURATION_BONUS * chance; + const float duration = FURY_DURATION_BASE + FURY_DURATION_BONUS * chance; if (attacker->client) safe_cprintf(attacker, PRINT_HIGH, "For the next %0.1f seconds you will become the fury.\n", duration); @@ -366,7 +366,7 @@ dflags these flags are used to control how T_Damage works static int CheckShield (edict_t *ent, vec3_t point, vec3_t normal, int damage, int dflags) { int save, pa_te_type; - edict_t *cl_ent = NULL; + const edict_t *cl_ent = NULL; if (!damage) return 0; @@ -631,7 +631,7 @@ static int CheckArmor(edict_t *ent, vec3_t point, vec3_t normal, int damage, int qboolean CanUseVampire (edict_t *targ, edict_t *attacker, int dflags, int mod) { - int dtype = G_DamageType(mod, dflags); + const int dtype = G_DamageType(mod, dflags); //const edict_t* dclient = PM_GetPlayer(attacker); // get a pointer to the player, even if they're a player-tank qboolean has_pilot; @@ -677,7 +677,7 @@ qboolean CanUseVampire (edict_t *targ, edict_t *attacker, int dflags, int mod) void ApplyThorns(edict_t* targ, edict_t* inflictor, edict_t* attacker, vec3_t point, float damage, int knockback, int dflags, int mod) { - que_t* slot = NULL; + const que_t* slot = NULL; // no damage if (damage < 1) @@ -708,8 +708,8 @@ void ApplyThorns(edict_t* targ, edict_t* inflictor, edict_t* attacker, vec3_t po void DeflectHitscan(edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t point, float damage, int knockback, int dflags, int mod) -{ - que_t *slot = NULL; +{ + const que_t *slot = NULL; float modifier, chance; trace_t tr; vec3_t newDir, end; @@ -758,7 +758,7 @@ void DeflectHitscan(edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t void V_ApplyVampire(edict_t* attacker, float take, float vamp_factor, float health_factor, qboolean use_cache) { int armorVampBase, steal; - int delta = (health_factor * attacker->max_health) - attacker->health; + const int delta = (health_factor * attacker->max_health) - attacker->health; armorVampBase = steal = vamp_factor * take; @@ -785,7 +785,7 @@ void G_ApplyVampire(edict_t *attacker, float take) attacker = attacker->activator; } - int* armor = &attacker->client->pers.inventory[body_armor_index]; + const int* armor = &attacker->client->pers.inventory[body_armor_index]; float temp = 0.075*attacker->myskills.abilities[VAMPIRE].current_level; if (attacker->mtype || has_pilot) @@ -814,7 +814,7 @@ void G_ApplyVampire(edict_t *attacker, float take) if (*armor < MAX_ARMOR(attacker) && vrx_get_talent_level(attacker, TALENT_ARMOR_VAMP) > 0) { //16.6% per point of health stolen gives armor as a bonus. - float mult = 0.1666 * vrx_get_talent_level(attacker, TALENT_ARMOR_VAMP); + const float mult = 0.1666 * vrx_get_talent_level(attacker, TALENT_ARMOR_VAMP); attacker->armor_cache += (int)(take * temp * mult); } } @@ -915,7 +915,7 @@ qboolean vrx_reduce_knockback(edict_t *targ, edict_t *inflictor, edict_t *attack void vrx_apply_darkness_totem(edict_t *attacker, float take, edict_t *player, qboolean attacker_has_pilot) { if(player && (attacker_has_pilot || attacker->client) && !OnSameTeam(player, attacker)) { - edict_t *totem = NextNearestTotem(player, TOTEM_DARKNESS, NULL, true); + const edict_t *totem = NextNearestTotem(player, TOTEM_DARKNESS, NULL, true); int maxHP = player->max_health;//MAX_HEALTH(player); if(totem != NULL) @@ -938,7 +938,7 @@ void vrx_apply_darkness_totem(edict_t *attacker, float take, edict_t *player, qb } void vrx_apply_vampire_abilities(edict_t *targ, edict_t *attacker, int dflags, int mod, float take, que_t *slot) { - qboolean same_team = OnSameTeam(targ, attacker); + const qboolean same_team = OnSameTeam(targ, attacker); //4.2 give hellspawn vampire ability (50% = 150hp/sec assuming 300dmg/sec) if (attacker->monsterinfo.bonus_flags & BF_STYGIAN) @@ -961,7 +961,7 @@ void vrx_apply_vampire_abilities(edict_t *targ, edict_t *attacker, int dflags, i // life tap vampire effect if ((slot = que_findtype(targ->curses, NULL, LIFE_TAP)) != NULL && mod != MOD_CRIPPLE) { - float lifeTapFactor = LIFE_TAP_INITIAL_FACTOR + LIFE_TAP_ADDON_FACTOR * slot->ent->monsterinfo.level; + const float lifeTapFactor = LIFE_TAP_INITIAL_FACTOR + LIFE_TAP_ADDON_FACTOR * slot->ent->monsterinfo.level; //slot->ent->owner->myskills.abilities[LIFE_TAP].current_level; //gi.dprintf("%s: take: %.0f lifeTapFactor: %.1f\n", __func__, take, lifeTapFactor); V_ApplyVampire(attacker, take, lifeTapFactor, 1.0, true); @@ -989,7 +989,7 @@ void vrx_apply_autocurse(edict_t *targ, edict_t *attacker) { if ((curse_index = SelectRandomTopCurse(targ_player)) != -1) { - int curse_level = targ_player->myskills.abilities[curse_index].current_level; + const int curse_level = targ_player->myskills.abilities[curse_index].current_level; CurseRadius(targ, attacker, curse_index, curse_level, 150, vrx_get_curse_duration(targ_player, curse_index), true, true); } } @@ -1024,9 +1024,9 @@ void vrx_apply_knockback(edict_t *targ, edict_t *attacker, vec_t *dir, int knock } void vrx_apply_invincibility(edict_t *targ, float damage, int dflags, float *take, float *save) { - edict_t* cl_ent = PM_GetPlayer(targ);//G_GetClient(targ); - qboolean invincible = (cl_ent && cl_ent->client->invincible_framenum > level.framenum); - qboolean bypass_invincibility = (dflags & DAMAGE_NO_PROTECTION); + const edict_t* cl_ent = PM_GetPlayer(targ);//G_GetClient(targ); + const qboolean invincible = (cl_ent && cl_ent->client->invincible_framenum > level.framenum); + const qboolean bypass_invincibility = (dflags & DAMAGE_NO_PROTECTION); // az: add decino's invincibility not working for tank morphs from indy //qboolean is_player_tank = targ->mtype == P_TANK && targ->owner && targ->owner->client; @@ -1082,7 +1082,7 @@ void vrx_apply_champion_autocurse(edict_t *targ, edict_t *attacker) { } void vrx_apply_talent_stone(edict_t *targ, float *damage, float startDamage) { - qboolean target_has_pilot = PM_MonsterHasPilot(targ); + const qboolean target_has_pilot = PM_MonsterHasPilot(targ); if(!target_has_pilot && !targ->client) return; @@ -1091,20 +1091,20 @@ void vrx_apply_talent_stone(edict_t *targ, float *damage, float startDamage) { edict_t *targ_player = G_GetClient(targ); //Calculate the amount of resist the player has already received. - double x = (double)(startDamage - *damage) / startDamage; + const double x = (double)(startDamage - *damage) / startDamage; //Talent: Stone. totem = NextNearestTotem(targ_player, TOTEM_EARTH, NULL, true); if(totem && totem->activator) { - int resistLevel = vrx_get_talent_level(totem->activator, TALENT_STONE); + const int resistLevel = vrx_get_talent_level(totem->activator, TALENT_STONE); if(x < resistLevel * EARTHTOTEM_RESIST_MULT) *damage = startDamage * (1.0 - EARTHTOTEM_RESIST_MULT * resistLevel); } } void vrx_do_friendly_fire(edict_t *targ, edict_t *attacker, float *damage, int *mod) { - qboolean same_team = OnSameTeam(targ, attacker); + const qboolean same_team = OnSameTeam(targ, attacker); if ((targ != attacker) && ((deathmatch->value && ((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS))) || coop->value)) { @@ -1123,13 +1123,17 @@ void vrx_do_dmg_counter(float damage, edict_t *player) { { // keep a counter for rapid-fire weapons so we have a more // accurate reading of their damage over time + +#ifndef VRX_REPRO if (level.time-player->lastdmg <= 0.2 && player->dmg_counter <= 32767) player->dmg_counter += damage; else player->dmg_counter = damage; player->client->ps.stats[STAT_ID_DAMAGE] = player->dmg_counter; - +#else + player->dmg_counter += damage; +#endif player->lastdmg = level.time; player->client->idle_frames = 0; // player is no longer idle! (uncloak em!) } @@ -1144,13 +1148,13 @@ int T_Damage (edict_t *targ, edict_t *inflictor, edict_t *attacker, int psave; //int thorns_dmg;//GHz float before_add,before_sub;//GHz - int dtype = G_DamageType(mod, dflags); + const int dtype = G_DamageType(mod, dflags); edict_t *player = G_GetClient(attacker); - float startDamage = damage; //doomie + const float startDamage = damage; //doomie upgrade_t *ability;//4.2 for fury - qboolean target_has_pilot = PM_MonsterHasPilot(targ); - qboolean attacker_has_pilot = PM_MonsterHasPilot(attacker); + const qboolean target_has_pilot = PM_MonsterHasPilot(targ); + const qboolean attacker_has_pilot = PM_MonsterHasPilot(attacker); que_t *slot=NULL; //gi.dprintf("T_damage\n"); @@ -1183,7 +1187,7 @@ int T_Damage (edict_t *targ, edict_t *inflictor, edict_t *attacker, edict_t *totem; //Calculate the damage bonus the player has already received. - double x = (double)(damage - startDamage) / startDamage; + const double x = (double)(damage - startDamage) / startDamage; //4.1 earth totem strength bonus. totem = NextNearestTotem(player, TOTEM_EARTH, NULL, true); diff --git a/src/combat/common/g_items.c b/src/combat/common/g_items.c index 7479f4ad..13a7dbf0 100644 --- a/src/combat/common/g_items.c +++ b/src/combat/common/g_items.c @@ -621,7 +621,7 @@ int ArmorIndex(edict_t *ent) { qboolean Pickup_Armor(edict_t *ent, edict_t *other) { int armor, current_armor, max_armor, delta; - gitem_armor_t *newinfo = (gitem_armor_t *) ent->item->info; + const gitem_armor_t *newinfo = (gitem_armor_t *) ent->item->info; qboolean shard = false; float temp = 1.0; @@ -885,7 +885,7 @@ qboolean CanTball(edict_t *ent, qboolean print) { void Tball_Aura(edict_t *owner, vec3_t origin) { edict_t *other = NULL; int i = 0; - int radius = 160; + const int radius = 160; //3.0 new algorithm for tball code (faster) for (i = 1; i <= game.maxclients; i++) { @@ -1032,7 +1032,7 @@ void Touch_Item(edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf) //GHz START // if this is a player-controlled monster, then the player should // be able to pick up the items that the monster touches - int pm = PM_MonsterHasPilot(other); + const int pm = PM_MonsterHasPilot(other); if (pm && (other->mtype != BOSS_TANK) && (other->mtype != BOSS_MAKRON)) other = other->activator; @@ -2948,7 +2948,7 @@ void SetItemNames(void) { int GetWorldAmmoCount(char *pickupName) { int count = 0; edict_t *e = NULL; - gitem_t *it = FindItem(pickupName); + const gitem_t *it = FindItem(pickupName); while ((e = G_Find(e, FOFS(classname), it->classname)) != NULL) { if (e->inuse && !(e->spawnflags & DROPPED_ITEM)) diff --git a/src/combat/common/v_misc.c b/src/combat/common/v_misc.c index 997e6cd9..e81c9125 100644 --- a/src/combat/common/v_misc.c +++ b/src/combat/common/v_misc.c @@ -283,7 +283,7 @@ void vrx_pvm_try_spawn_boss(edict_t* self, int players) //qboolean SpawnWorldMonster(edict_t *ent, int mtype); void vrx_pvm_spawn_world_monsters(edict_t* self) { - int players = vrx_get_joined_players(true); + const int players = vrx_get_joined_players(true); total_monsters = vrx_pvm_update_total_owned_monsters(self, false); // dm_monsters cvar sets the default number of monsters in a given map @@ -291,13 +291,13 @@ void vrx_pvm_spawn_world_monsters(edict_t* self) { if (level.r_monsters <= 0) max_monsters = dm_monsters->value; - int threshold = 0.66f * max_monsters; - int levelup_threshold = 0.4f * max_monsters; + const int threshold = 0.66f * max_monsters; + const int levelup_threshold = 0.4f * max_monsters; if (level.time > self->delay) { - int total_monsters = vrx_pvm_update_total_owned_monsters(self, true); + const int total_monsters = vrx_pvm_update_total_owned_monsters(self, true); // adjust spawning delay based on efficiency of player monster kills if (total_monsters < max_monsters) { // if a minimum of monsters has been killed consider scaling monsters up @@ -359,7 +359,7 @@ void vrx_pvm_spawn_world_monsters(edict_t* self) { void SpawnRandomBoss(edict_t* self) { // 3% chance for a boss to spawn a boss if there isn't already one spawned if (!SPREE_WAR && vrx_get_alive_players() >= 8 && self->num_sentries < 1) { - int chance = GetRandom(1, 100); + const int chance = GetRandom(1, 100); if ((chance >= 97) && vrx_create_new_drone(self, GetRandom(30, 31), true, true, 0)) { //gi.dprintf("Spawning a boss monster (chance = %d) at %.1f. Waiting 300 seconds to try again.\n", @@ -549,9 +549,8 @@ void vrx_remove_player_summonables(edict_t* self) { G_FreeEdict(self->lasersight); self->lasersight = NULL; } - if (self->flashlight) { - G_FreeEdict(self->flashlight); - self->flashlight = NULL; + if (FL_exists(self)) { + FL_toggle(self); } if (self->supplystation) { @@ -745,7 +744,7 @@ void ThrowShrapnel(edict_t* self, char* modelname, float speed, vec3_t origin, i chunk->die = shrapnel_die; chunk->touch = shrapnel_touch; chunk->style = mod; // means-of-death - if (cl = G_GetClient(self)) + if ((cl = G_GetClient(self))) chunk->creator = cl; // owner-creator of shrapnel else chunk->creator = self; @@ -781,7 +780,7 @@ void ThrowDeadlyGib(edict_t* self, char* modelname, vec3_t origin, vec3_t dir, i gib->takedamage = DAMAGE_YES; gib->dmg = dmg; gib->style = mod; - if (cl = G_GetClient(self)) + if ((cl = G_GetClient(self))) gib->creator = cl; // owner-creator of shrapnel else gib->creator = self; @@ -806,7 +805,7 @@ void ThrowDeadlyGib(edict_t* self, char* modelname, vec3_t origin, vec3_t dir, i void projectOntoWall(vec3_t lookDir, vec3_t wallNormal, vec3_t parallelVector) { vec3_t projectionOntoNormal; // Calculate dot product L � N - float dot = DotProduct(lookDir, wallNormal); + const float dot = DotProduct(lookDir, wallNormal); // Project L onto N: (L � N) * N VectorScale(wallNormal, dot, projectionOntoNormal); @@ -940,7 +939,7 @@ qboolean vrx_position_player_summonable(edict_t* ent, edict_t* other, float dist // return true if there isn't a previously dropped entity that would prevent us from dropping another qboolean CanDropPickupEnt(edict_t* ent) { - edict_t* pickup_prev = ent->client->pickup_prev; + const edict_t* pickup_prev = ent->client->pickup_prev; // don't have a pickup entity to drop if (!ent->client->pickup || !ent->client->pickup->inuse) return false; @@ -992,7 +991,7 @@ void vrx_set_pickup_owner(edict_t* self) // need to make this null first so that the trace works self->owner = NULL; // barrel isn't being held, so make it solid again to player if it's clear of obstructions - trace_t tr = gi.trace(self->s.origin, self->mins, self->maxs, self->s.origin, self, MASK_PLAYERSOLID); + const trace_t tr = gi.trace(self->s.origin, self->mins, self->maxs, self->s.origin, self, MASK_PLAYERSOLID); //FIXME: the owner won't be cleared if the player managed to stick the barrel in a bad spot if (tr.allsolid || tr.startsolid || tr.fraction < 1) { diff --git a/src/combat/weapons/g_sword.c b/src/combat/weapons/g_sword.c index 19ecd2a3..e2b97c88 100644 --- a/src/combat/weapons/g_sword.c +++ b/src/combat/weapons/g_sword.c @@ -33,9 +33,9 @@ void Laser_PreThink(edict_t *self) //if the radius isn't the final length then adjust it if (self->s.frame != self->health) { - int difference = self->health - self->max_health; - float total_time = self->delay - self->wait; - float time_ellapsed = level.time - self->wait; + const int difference = self->health - self->max_health; + const float total_time = self->delay - self->wait; + const float time_ellapsed = level.time - self->wait; self->s.frame = self->max_health + (int)((difference / total_time) * time_ellapsed); } @@ -109,12 +109,12 @@ void fire_sword_old ( edict_t *self, vec3_t start, vec3_t aimdir, int damage, in vec3_t end; vec3_t begin; vec3_t begin_offset; - float sword_bonus = 1; + const float sword_bonus = 1; // calling entity made a sound, used to alert monsters self->lastsound = level.framenum; - float swordrange = SABRE_INITIAL_RANGE * sword_bonus + + const float swordrange = SABRE_INITIAL_RANGE * sword_bonus + (SABRE_ADDON_RANGE * self->myskills.weapons[WEAPON_SWORD].mods[2].current_level); VectorSet(begin_offset, 0, 0, self->viewheight - 8); @@ -414,9 +414,6 @@ void sword_attack (edict_t *ent, vec3_t g_offset, int damage) } */ - if (ent->swordtimer >= level.time) - return; - fire_sword ( ent, start, @@ -452,15 +449,20 @@ void Weapon_Sword_Fire (edict_t *ent) { if ((ent->client->ps.gunframe == 5) && (ent->myskills.weapons[WEAPON_SWORD].mods[4].current_level < 1)) gi.sound (ent, CHAN_WEAPON, gi.soundindex("misc/power1.wav") , 1, ATTN_NORM, 0); + const int frames_per_frame = sv_fps->value / 10.0; + if ( ent->client->buttons & BUTTON_ATTACK ) - sword_attack (ent, vec3_origin, damage); - ent->client->ps.gunframe++; + sword_attack (ent, vec3_origin, damage / frames_per_frame); + + ent->client->vrr.stretched_frames++; + if (ent->client->vrr.stretched_frames >= frames_per_frame) { + ent->client->ps.gunframe++; + ent->client->vrr.stretched_frames -= frames_per_frame; + } } void Weapon_Lance_Fire (edict_t *ent) { - int sword_bonus = 1.0; - int damage, burn_damage; - float speed; + float sword_bonus = 1.0; vec3_t forward, start, right, offset; // special rules; flag carrier can't use weapons @@ -471,10 +473,10 @@ void Weapon_Lance_Fire (edict_t *ent) { if (ent->myskills.class_num == CLASS_KNIGHT) sword_bonus = 1.5; - damage = SABRE_INITIAL_DAMAGE + - (SABRE_ADDON_DAMAGE * ent->myskills.weapons[WEAPON_SWORD].mods[0].current_level * sword_bonus); - burn_damage = SABRE_ADDON_HEATDAMAGE * ent->myskills.weapons[WEAPON_SWORD].mods[3].current_level * sword_bonus; - speed = 850 + (15 * ent->myskills.weapons[WEAPON_SWORD].mods[2].current_level * sword_bonus); + int damage = SABRE_INITIAL_DAMAGE + + (SABRE_ADDON_DAMAGE * ent->myskills.weapons[WEAPON_SWORD].mods[0].current_level * sword_bonus); + const int burn_damage = SABRE_ADDON_HEATDAMAGE * ent->myskills.weapons[WEAPON_SWORD].mods[3].current_level * sword_bonus; + const float speed = 850 + (15 * ent->myskills.weapons[WEAPON_SWORD].mods[2].current_level * sword_bonus); // lance modifier damage *= 2; diff --git a/src/combat/weapons/g_weapon.c b/src/combat/weapons/g_weapon.c index f79617d3..43097004 100644 --- a/src/combat/weapons/g_weapon.c +++ b/src/combat/weapons/g_weapon.c @@ -45,7 +45,7 @@ void check_dodge (edict_t *self, vec3_t start, vec3_t dir, int speed, int radius { vec3_t end; vec3_t v; - vec3_t zvec = {0,0,0}; + const vec3_t zvec = {0,0,0}; trace_t tr; float eta; edict_t *blip = NULL; @@ -1136,7 +1136,7 @@ void fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed //K03 Begin rocket->nextthink = level.time + FRAMETIME; rocket->think = rocket_think;// GHz v3.1 - rocket->delay = level.time + 8000/speed; + rocket->delay = level.time + 8000*(sv_fps->value) / speed; //rocket->think = G_FreeEdict; //K03 End rocket->dmg = damage; @@ -1278,10 +1278,10 @@ void smartrocket_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_ T_Damage (other, ent, ent->owner, ent->velocity, ent->s.origin, plane->normal, ent->dmg, 0, 0, MOD_ROCKET); // Talent: Range Mastery - int talentLevel = vrx_get_talent_level(ent->owner, TALENT_RANGE_MASTERY); + const int talentLevel = vrx_get_talent_level(ent->owner, TALENT_RANGE_MASTERY); if (talentLevel > 0) { - int damage = ent->dmg * (0.2 * talentLevel); + const int damage = ent->dmg * (0.2 * talentLevel); fire_mirv_grenade(ent->owner, ent->s.origin, vec3_origin, damage, ent->dmg_radius, 0, FRAMETIME); } @@ -1482,11 +1482,8 @@ void fire_20mm (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick vec3_t end; vec3_t forward, right, start1, offset; trace_t tr; - edict_t *ignore; - int mask; - qboolean water, ducked; - - //int range = WEAPON_20MM_INITIAL_RANGE + (WEAPON_20MM_ADDON_RANGE * self->myskills.weapons[WEAPON_20MM].mods[1].current_level); + qboolean ducked; + int itercount = 0; // calling entity made a sound, used to alert monsters self->lastsound = level.framenum; @@ -1495,17 +1492,16 @@ void fire_20mm (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick VectorMA (start, range, aimdir, end); VectorCopy (start, from); - ignore = self; - water = false; - mask = MASK_SHOT|CONTENTS_SLIME|CONTENTS_LAVA; - while (ignore) + const edict_t *ignore = self; + int mask = MASK_SHOT | CONTENTS_SLIME | CONTENTS_LAVA; + + while (ignore && itercount++ < 500) { tr = gi.trace (from, NULL, NULL, end, ignore, mask); if (tr.contents & (CONTENTS_SLIME|CONTENTS_LAVA)) { mask &= ~(CONTENTS_SLIME|CONTENTS_LAVA); - water = true; } else { @@ -1540,7 +1536,7 @@ void fire_20mm (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick } //GHz Start - if (!self->client || (self->client->ps.pmove.pm_flags & PMF_DUCKED)) + if (!self->client || self->client->ps.pmove.pm_flags & PMF_DUCKED) ducked = true; else ducked = false; diff --git a/src/combat/weapons/p_weapon.c b/src/combat/weapons/p_weapon.c index f4000c27..ed432329 100644 --- a/src/combat/weapons/p_weapon.c +++ b/src/combat/weapons/p_weapon.c @@ -8,24 +8,24 @@ qboolean is_quad; qboolean is_quadfire; byte is_silenced; -void lasersight_on(edict_t *ent); +void lasersight_on(edict_t* ent); -void lasersight_off(edict_t *ent); +void lasersight_off(edict_t* ent); -void weapon_grenade_fire(edict_t *ent, qboolean held); +void weapon_grenade_fire(edict_t* ent, qboolean held); // RAFAEL -void weapon_trap_fire(edict_t *ent, qboolean held); +void weapon_trap_fire(edict_t* ent, qboolean held); -void P_ProjectSource(gclient_t *client, vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result) { - vec3_t _distance; +void P_ProjectSource(gclient_t* client, vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result) { + vec3_t _distance; - VectorCopy (distance, _distance); - if (client->pers.hand == LEFT_HANDED) - _distance[1] *= -1; - else if (client->pers.hand == CENTER_HANDED) - _distance[1] = 0; - G_ProjectSource(point, _distance, forward, right, result); + VectorCopy(distance, _distance); + if (client->pers.hand == LEFT_HANDED) + _distance[1] *= -1; + else if (client->pers.hand == CENTER_HANDED) + _distance[1] = 0; + G_ProjectSource(point, _distance, forward, right, result); } @@ -41,113 +41,113 @@ Monsters that don't directly see the player can move to a noise in hopes of seeing the player from there. =============== */ -void PlayerNoise(edict_t *who, vec3_t where, int type) { - /*edict_t *noise; - - if (type == PNOISE_WEAPON) - { - if (who->client->silencer_shots) - { - who->client->silencer_shots--; - return; - } - } +void PlayerNoise(edict_t* who, vec3_t where, int type) { + /*edict_t *noise; - if (deathmatch->value) - return; + if (type == PNOISE_WEAPON) + { + if (who->client->silencer_shots) + { + who->client->silencer_shots--; + return; + } + } - if (who->flags & FL_NOTARGET) - return; + if (deathmatch->value) + return; + if (who->flags & FL_NOTARGET) + return; - if (!who->mynoise) - { - noise = G_Spawn(); - noise->classname = "player_noise"; - VectorSet (noise->mins, -8, -8, -8); - VectorSet (noise->maxs, 8, 8, 8); - noise->owner = who; - noise->svflags = SVF_NOCLIENT; - who->mynoise = noise; - - noise = G_Spawn(); - noise->classname = "player_noise"; - VectorSet (noise->mins, -8, -8, -8); - VectorSet (noise->maxs, 8, 8, 8); - noise->owner = who; - noise->svflags = SVF_NOCLIENT; - who->mynoise2 = noise; - } - if (type == PNOISE_SELF || type == PNOISE_WEAPON) - { - noise = who->mynoise; - level.sound_entity = noise; - level.sound_entity_framenum = level.framenum; - } - else // type == PNOISE_IMPACT - { - noise = who->mynoise2; - level.sound2_entity = noise; - level.sound2_entity_framenum = level.framenum; - } + if (!who->mynoise) + { + noise = G_Spawn(); + noise->classname = "player_noise"; + VectorSet (noise->mins, -8, -8, -8); + VectorSet (noise->maxs, 8, 8, 8); + noise->owner = who; + noise->svflags = SVF_NOCLIENT; + who->mynoise = noise; + + noise = G_Spawn(); + noise->classname = "player_noise"; + VectorSet (noise->mins, -8, -8, -8); + VectorSet (noise->maxs, 8, 8, 8); + noise->owner = who; + noise->svflags = SVF_NOCLIENT; + who->mynoise2 = noise; + } + + if (type == PNOISE_SELF || type == PNOISE_WEAPON) + { + noise = who->mynoise; + level.sound_entity = noise; + level.sound_entity_framenum = level.framenum; + } + else // type == PNOISE_IMPACT + { + noise = who->mynoise2; + level.sound2_entity = noise; + level.sound2_entity_framenum = level.framenum; + } - VectorCopy (where, noise->s.origin); - VectorSubtract (where, noise->maxs, noise->absmin); - VectorAdd (where, noise->maxs, noise->absmax); - noise->teleport_time = level.time; - gi.linkentity (noise);*/ + VectorCopy (where, noise->s.origin); + VectorSubtract (where, noise->maxs, noise->absmin); + VectorAdd (where, noise->maxs, noise->absmax); + noise->teleport_time = level.time; + gi.linkentity (noise);*/ } -void ShowGun(edict_t *ent); +void ShowGun(edict_t* ent); -qboolean Pickup_Weapon(edict_t *ent, edict_t *other) { - int index; - gitem_t *ammo; +qboolean Pickup_Weapon(edict_t* ent, edict_t* other) { + int index; + gitem_t* ammo; - index = ITEM_INDEX(ent->item); + index = ITEM_INDEX(ent->item); - if ((((int) (dmflags->value) & DF_WEAPONS_STAY) || coop->value) - && other->client->pers.inventory[index]) { - if (!(ent->spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM))) - return false; // leave the weapon for others to pickup - } + if ((((int)(dmflags->value) & DF_WEAPONS_STAY) || coop->value) + && other->client->pers.inventory[index]) { + if (!(ent->spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM))) + return false; // leave the weapon for others to pickup + } - //K03 Begin - if (other->client->pers.inventory[index] == 0) - other->client->pers.inventory[index]++; - //K03 End - - if (!(ent->spawnflags & DROPPED_ITEM)) { - // give them some ammo with it - ammo = FindItem(ent->item->ammo); - - if ((int) dmflags->value & DF_INFINITE_AMMO) - Add_Ammo(other, ammo, 1000); - else - Add_Ammo(other, ammo, ammo->quantity); - - if (!(ent->spawnflags & DROPPED_PLAYER_ITEM)) { - if (deathmatch->value) { - if ((int) (dmflags->value) & DF_WEAPONS_STAY) - ent->flags |= FL_RESPAWN; - else - SetRespawn(ent, 30); - } - if (coop->value) - ent->flags |= FL_RESPAWN; - } - } + //K03 Begin + if (other->client->pers.inventory[index] == 0) + other->client->pers.inventory[index]++; + //K03 End + + if (!(ent->spawnflags & DROPPED_ITEM)) { + // give them some ammo with it + ammo = FindItem(ent->item->ammo); + + if ((int)dmflags->value & DF_INFINITE_AMMO) + Add_Ammo(other, ammo, 1000); + else + Add_Ammo(other, ammo, ammo->quantity); + + if (!(ent->spawnflags & DROPPED_PLAYER_ITEM)) { + if (deathmatch->value) { + if ((int)(dmflags->value) & DF_WEAPONS_STAY) + ent->flags |= FL_RESPAWN; + else + SetRespawn(ent, 30); + } + if (coop->value) + ent->flags |= FL_RESPAWN; + } + } - if (other->client->pers.weapon != ent->item && // not the same weapon equipped - (other->client->pers.inventory[index] == 1) && // do not already have one - (!deathmatch->value || other->client->pers.weapon == Fdi_BLASTER)) { - if ((V_WeaponUpgradeVal(other, WEAPON_BLASTER) < 1) - && (other->myskills.respawn_weapon != 13)) //4.2 don't switch weapons if blaster is set as respawn weapon - other->client->newweapon = ent->item; - } + if (other->client->pers.weapon != ent->item && // not the same weapon equipped + (other->client->pers.inventory[index] == 1) && // do not already have one + (!deathmatch->value || other->client->pers.weapon == Fdi_BLASTER)) { + if ((V_WeaponUpgradeVal(other, WEAPON_BLASTER) < 1) + && (other->myskills.respawn_weapon != 13)) //4.2 don't switch weapons if blaster is set as respawn weapon + other->client->newweapon = ent->item; + } - return true; + return true; } /* @@ -158,86 +158,87 @@ Returns true if this weapon has secondary fire, and prints client messages confirming mode change ================ */ -qboolean ToggleSecondary(edict_t *ent, gitem_t *item, qboolean printmsg) { - if (!ent->mtype) { - if (!item) - return false; // must have a weapon - if (ent->client->weaponstate != WEAPON_READY) - return false; // weapon must be ready - } +qboolean ToggleSecondary(edict_t* ent, gitem_t* item, qboolean printmsg) { + if (!ent->mtype) { + if (!item) + return false; // must have a weapon + if (ent->client->weaponstate != WEAPON_READY) + return false; // weapon must be ready + } - if (ent->client->weapon_mode) { - // flag carrier in CTF can't use weapons - if (ctf->value && ctf_enable_balanced_fc->value && vrx_has_flag(ent)) - return false; - - - if (strcmp(item->pickup_name, "Sword") == 0) { - if (printmsg) - safe_cprintf(ent, PRINT_HIGH, "Normal firing\n"); - return true; - } - if (strcmp(item->pickup_name, "Blaster") == 0) { - if (printmsg) - safe_cprintf(ent, PRINT_HIGH, "Normal firing\n"); - return true; - } - if (strcmp(item->pickup_name, "Railgun") == 0) { - if (printmsg) - safe_cprintf(ent, PRINT_HIGH, "Normal firing\n"); - return true; - } - if (strcmp(item->pickup_name, "Grenade Launcher") == 0) { - if (printmsg) - safe_cprintf(ent, PRINT_HIGH, "Normal firing\n"); - return true; - } - if (strcmp(item->pickup_name, "Machinegun") == 0) { - if (printmsg) - safe_cprintf(ent, PRINT_HIGH, "Full automatic\n"); - return true; - } - if (strcmp(item->pickup_name, "Chaingun") == 0) { - if (printmsg) - safe_cprintf(ent, PRINT_HIGH, "Normal firing\n"); - return true; - } - } else { - if (!item) // TODO: Should the check be here, or should togglesecondary not be called? - return false; - - if (strcmp(item->pickup_name, "Sword") == 0) { - if (printmsg) - safe_cprintf(ent, PRINT_HIGH, "Lance mode\n"); - return true; - } - if (strcmp(item->pickup_name, "Blaster") == 0) { - if (printmsg) - safe_cprintf(ent, PRINT_HIGH, "Blast mode\n"); - return true; - } - if (strcmp(item->pickup_name, "Railgun") == 0) { - if (printmsg) - safe_cprintf(ent, PRINT_HIGH, "Sniper mode\n"); - return true; - } - if (strcmp(item->pickup_name, "Grenade Launcher") == 0) { - if (printmsg) - safe_cprintf(ent, PRINT_HIGH, "Pipebomb mode\n"); - return true; - } - if (strcmp(item->pickup_name, "Machinegun") == 0) { - if (printmsg) - safe_cprintf(ent, PRINT_HIGH, "Burst fire\n"); - return true; - } - if (strcmp(item->pickup_name, "Chaingun") == 0) { - if (printmsg) - safe_cprintf(ent, PRINT_HIGH, "Assault cannon\n"); - return true; - } - } - return false; + if (ent->client->weapon_mode) { + // flag carrier in CTF can't use weapons + if (ctf->value && ctf_enable_balanced_fc->value && vrx_has_flag(ent)) + return false; + + + if (strcmp(item->pickup_name, "Sword") == 0) { + if (printmsg) + safe_cprintf(ent, PRINT_HIGH, "Normal firing\n"); + return true; + } + if (strcmp(item->pickup_name, "Blaster") == 0) { + if (printmsg) + safe_cprintf(ent, PRINT_HIGH, "Normal firing\n"); + return true; + } + if (strcmp(item->pickup_name, "Railgun") == 0) { + if (printmsg) + safe_cprintf(ent, PRINT_HIGH, "Normal firing\n"); + return true; + } + if (strcmp(item->pickup_name, "Grenade Launcher") == 0) { + if (printmsg) + safe_cprintf(ent, PRINT_HIGH, "Normal firing\n"); + return true; + } + if (strcmp(item->pickup_name, "Machinegun") == 0) { + if (printmsg) + safe_cprintf(ent, PRINT_HIGH, "Full automatic\n"); + return true; + } + if (strcmp(item->pickup_name, "Chaingun") == 0) { + if (printmsg) + safe_cprintf(ent, PRINT_HIGH, "Normal firing\n"); + return true; + } + } + else { + if (!item) // TODO: Should the check be here, or should togglesecondary not be called? + return false; + + if (strcmp(item->pickup_name, "Sword") == 0) { + if (printmsg) + safe_cprintf(ent, PRINT_HIGH, "Lance mode\n"); + return true; + } + if (strcmp(item->pickup_name, "Blaster") == 0) { + if (printmsg) + safe_cprintf(ent, PRINT_HIGH, "Blast mode\n"); + return true; + } + if (strcmp(item->pickup_name, "Railgun") == 0) { + if (printmsg) + safe_cprintf(ent, PRINT_HIGH, "Sniper mode\n"); + return true; + } + if (strcmp(item->pickup_name, "Grenade Launcher") == 0) { + if (printmsg) + safe_cprintf(ent, PRINT_HIGH, "Pipebomb mode\n"); + return true; + } + if (strcmp(item->pickup_name, "Machinegun") == 0) { + if (printmsg) + safe_cprintf(ent, PRINT_HIGH, "Burst fire\n"); + return true; + } + if (strcmp(item->pickup_name, "Chaingun") == 0) { + if (printmsg) + safe_cprintf(ent, PRINT_HIGH, "Assault cannon\n"); + return true; + } + } + return false; } /* @@ -249,86 +250,88 @@ current =============== */ // ### Hentai ### BEGIN -void ShowGun(edict_t *ent) { - int i, j; +void ShowGun(edict_t* ent) { + int i, j; - if (!ent->client->pers.weapon) { - ent->s.modelindex2 = 0; - return; - } - if (!vwep->value) { - ent->s.modelindex2 = 255; - return; - } + if (!ent->client->pers.weapon) { + ent->s.modelindex2 = 0; + return; + } + if (!vwep->value) { + ent->s.modelindex2 = 255; + return; + } - j = Get_KindWeapon(ent->client->pers.weapon); - if (j == WEAP_GRAPPLE) j = WEAP_BLASTER; + j = Get_KindWeapon(ent->client->pers.weapon); + if (j == WEAP_GRAPPLE) j = WEAP_BLASTER; - ent->s.modelindex2 = 255; - if (ent->client->pers.weapon) - i = ((j & 0xff) << 8); - else - i = 0; + ent->s.modelindex2 = 255; + if (ent->client->pers.weapon) + i = ((j & 0xff) << 8); + else + i = 0; - ent->s.skinnum = (ent - g_edicts - 1) | i; + ent->s.skinnum = (ent - g_edicts - 1) | i; } // ### Hentai ### END -void ChangeWeapon(edict_t *ent) { - char *mdl; +void ChangeWeapon(edict_t* ent) { + char* mdl; - ent->client->refire_frames = 0; - lasersight_off(ent); + ent->client->refire_frames = 0; + lasersight_off(ent); - if (ent->client->grenade_time) { - ent->client->grenade_time = level.time; - ent->client->weapon_sound = 0; - ent->client->grenade_time = 0; - } + if (ent->client->grenade_time) { + ent->client->grenade_time = level.time; + ent->client->weapon_sound = 0; + ent->client->grenade_time = 0; + } - ent->client->pers.lastweapon = ent->client->pers.weapon; - ent->client->pers.weapon = ent->client->newweapon; - ent->client->newweapon = NULL; - ent->client->machinegun_shots = 0; - ent->client->burst_count = 0; + ent->client->pers.lastweapon = ent->client->pers.weapon; + ent->client->pers.weapon = ent->client->newweapon; + ent->client->newweapon = NULL; + ent->client->machinegun_shots = 0; + ent->client->burst_count = 0; + ent->client->vrr.gun_statemachine_time = 0; - if (ent->client->pers.weapon && ent->client->pers.weapon->ammo) - ent->client->ammo_index = ITEM_INDEX(FindItem(ent->client->pers.weapon->ammo)); - else - ent->client->ammo_index = 0; + if (ent->client->pers.weapon && ent->client->pers.weapon->ammo) + ent->client->ammo_index = ITEM_INDEX(FindItem(ent->client->pers.weapon->ammo)); + else + ent->client->ammo_index = 0; if (!ent->client->pers.weapon || ent->deadflag == DEAD_DEAD) { // dead ent->client->ps.gunindex = 0; return; } - ent->client->weaponstate = WEAPON_ACTIVATING; - ent->client->ps.gunframe = 0; -//lm ctf - mdl = ent->client->pers.weapon->view_model; - ent->client->ps.gunindex = gi.modelindex(mdl/*ent->client->pers.weapon->view_model*/); -//lm ctf + ent->client->weaponstate = WEAPON_ACTIVATING; + ent->client->ps.gunframe = 0; + //lm ctf + mdl = ent->client->pers.weapon->view_model; + ent->client->ps.gunindex = gi.modelindex(mdl/*ent->client->pers.weapon->view_model*/); + //lm ctf - //K03 Begin - if (ent->client->pers.weapon == FindItem("Sword")) - ent->client->ps.gunindex = 0; - //K03 End + //K03 Begin + if (ent->client->pers.weapon == FindItem("Sword")) + ent->client->ps.gunindex = 0; + //K03 End - // ### Hentai ### BEGIN - ent->client->anim_priority = ANIM_PAIN; - if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) { - ent->s.frame = FRAME_crpain1; - ent->client->anim_end = FRAME_crpain4; - } else { - ent->s.frame = FRAME_pain301; - ent->client->anim_end = FRAME_pain304; + // ### Hentai ### BEGIN + ent->client->anim_priority = ANIM_PAIN; + if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) { + ent->s.frame = FRAME_crpain1; + ent->client->anim_end = FRAME_crpain4; + } + else { + ent->s.frame = FRAME_pain301; + ent->client->anim_end = FRAME_pain304; - } + } - ShowGun(ent); + ShowGun(ent); - // ### Hentai ### END + // ### Hentai ### END } /* @@ -336,37 +339,42 @@ void ChangeWeapon(edict_t *ent) { NoAmmoWeaponChange ================= */ -void NoAmmoWeaponChange(edict_t *ent) { - gitem_t *item = NULL; - - //GHz START - ent->client->refire_frames = 0; - lasersight_off(ent); - //GHz END - - if (ent->client->pers.inventory[ITEM_INDEX(Fdi_SLUGS)] - && ent->client->pers.inventory[ITEM_INDEX(Fdi_RAILGUN)]) { - item = Fdi_RAILGUN; - } else if (ent->client->pers.inventory[ITEM_INDEX(Fdi_CELLS)] - && ent->client->pers.inventory[ITEM_INDEX(Fdi_HYPERBLASTER)]) { - item = Fdi_HYPERBLASTER; - } else if (ent->client->pers.inventory[ITEM_INDEX(Fdi_BULLETS)] - && ent->client->pers.inventory[ITEM_INDEX(Fdi_CHAINGUN)]) { - item = Fdi_CHAINGUN; - } else if (ent->client->pers.inventory[ITEM_INDEX(Fdi_BULLETS)] - && ent->client->pers.inventory[ITEM_INDEX(Fdi_MACHINEGUN)]) { - item = Fdi_MACHINEGUN; - } else if (ent->client->pers.inventory[ITEM_INDEX(Fdi_SHELLS)] > 1 - && ent->client->pers.inventory[ITEM_INDEX(Fdi_SUPERSHOTGUN)]) { - item = Fdi_SUPERSHOTGUN; - } else if (ent->client->pers.inventory[ITEM_INDEX(Fdi_SHELLS)] - && ent->client->pers.inventory[ITEM_INDEX(Fdi_SHOTGUN)]) { - item = Fdi_SHOTGUN; - } - if (item == NULL) item = Fdi_BLASTER; +void NoAmmoWeaponChange(edict_t* ent) { + gitem_t* item = NULL; + + //GHz START + ent->client->refire_frames = 0; + lasersight_off(ent); + //GHz END - if (ent->svflags & SVF_MONSTER) item->use(ent, item); - else ent->client->newweapon = item; + if (ent->client->pers.inventory[ITEM_INDEX(Fdi_SLUGS)] + && ent->client->pers.inventory[ITEM_INDEX(Fdi_RAILGUN)]) { + item = Fdi_RAILGUN; + } + else if (ent->client->pers.inventory[ITEM_INDEX(Fdi_CELLS)] + && ent->client->pers.inventory[ITEM_INDEX(Fdi_HYPERBLASTER)]) { + item = Fdi_HYPERBLASTER; + } + else if (ent->client->pers.inventory[ITEM_INDEX(Fdi_BULLETS)] + && ent->client->pers.inventory[ITEM_INDEX(Fdi_CHAINGUN)]) { + item = Fdi_CHAINGUN; + } + else if (ent->client->pers.inventory[ITEM_INDEX(Fdi_BULLETS)] + && ent->client->pers.inventory[ITEM_INDEX(Fdi_MACHINEGUN)]) { + item = Fdi_MACHINEGUN; + } + else if (ent->client->pers.inventory[ITEM_INDEX(Fdi_SHELLS)] > 1 + && ent->client->pers.inventory[ITEM_INDEX(Fdi_SUPERSHOTGUN)]) { + item = Fdi_SUPERSHOTGUN; + } + else if (ent->client->pers.inventory[ITEM_INDEX(Fdi_SHELLS)] + && ent->client->pers.inventory[ITEM_INDEX(Fdi_SHOTGUN)]) { + item = Fdi_SHOTGUN; + } + if (item == NULL) item = Fdi_BLASTER; + + if (ent->svflags & SVF_MONSTER) item->use(ent, item); + else ent->client->newweapon = item; } @@ -377,29 +385,27 @@ Think_Weapon Called by ClientBeginServerFrame and ClientThink ================= */ -void Think_Weapon(edict_t *ent) { - // if just died, put the weapon away - if (ent->health < 1) { - ent->client->newweapon = NULL; - ChangeWeapon(ent); - } +void Think_Weapon(edict_t* ent) { + // if just died, put the weapon away + if (ent->health < 1) { + ent->client->newweapon = NULL; + ChangeWeapon(ent); + } - // Run weapons at 10 FPS - if ( sf2qf(1) != 1) - return; + ent->client->vrr.gun_statemachine_time += FRAMETIME; - // call active weapon think routine - if (ent->client->pers.weapon && ent->client->pers.weapon->weaponthink) { - is_quad = (ent->client->quad_framenum > level.framenum); - // RAFAEL - is_quadfire = (ent->client->quadfire_framenum > level.framenum); - if (ent->client->silencer_shots) - is_silenced = MZ_SILENCED; - else - is_silenced = 0; - - ent->client->pers.weapon->weaponthink(ent); - } + // call active weapon think routine + if (ent->client->pers.weapon && ent->client->pers.weapon->weaponthink) { + is_quad = (ent->client->quad_framenum > level.framenum); + // RAFAEL + is_quadfire = (ent->client->quadfire_framenum > level.framenum); + if (ent->client->silencer_shots) + is_silenced = MZ_SILENCED; + else + is_silenced = 0; + + ent->client->pers.weapon->weaponthink(ent); + } } /* @@ -409,67 +415,67 @@ Use_Weapon Make the weapon ready if there is ammo ================ */ -void Use_Weapon(edict_t *ent, gitem_t *item) { - int ammo_index; - gitem_t *ammo_item; - - // see if we're already using it - if (item == ent->client->pers.weapon) - return; - - if (ent->svflags & SVF_MONSTER) { - if (ent->client->newweapon != NULL) return; - if (!Q_stricmp(item->pickup_name, "Blaster")) { - ent->client->newweapon = item; - return; - } - } +void Use_Weapon(edict_t* ent, gitem_t* item) { + int ammo_index; + gitem_t* ammo_item; + + // see if we're already using it + if (item == ent->client->pers.weapon) + return; + + if (ent->svflags & SVF_MONSTER) { + if (ent->client->newweapon != NULL) return; + if (!Q_stricmp(item->pickup_name, "Blaster")) { + ent->client->newweapon = item; + return; + } + } - if (item->ammo && !g_select_empty->value && !(item->flags & IT_AMMO)) { - ammo_item = FindItem(item->ammo); - ammo_index = ITEM_INDEX(ammo_item); - - if (!ent->client->pers.inventory[ammo_index]) { - if (!(ent->svflags & SVF_MONSTER)) - safe_cprintf(ent, PRINT_HIGH, "No %s for %s.\n", ammo_item->pickup_name, item->pickup_name); - return; - } - - if (ent->client->pers.inventory[ammo_index] < item->quantity) { - if (!(ent->svflags & SVF_MONSTER)) - safe_cprintf(ent, PRINT_HIGH, "Not enough %s for %s.\n", ammo_item->pickup_name, item->pickup_name); - return; - } - } + if (item->ammo && !g_select_empty->value && !(item->flags & IT_AMMO)) { + ammo_item = FindItem(item->ammo); + ammo_index = ITEM_INDEX(ammo_item); + + if (!ent->client->pers.inventory[ammo_index]) { + if (!(ent->svflags & SVF_MONSTER)) + safe_cprintf(ent, PRINT_HIGH, "No %s for %s.\n", ammo_item->pickup_name, item->pickup_name); + return; + } + + if (ent->client->pers.inventory[ammo_index] < item->quantity) { + if (!(ent->svflags & SVF_MONSTER)) + safe_cprintf(ent, PRINT_HIGH, "Not enough %s for %s.\n", ammo_item->pickup_name, item->pickup_name); + return; + } + } - // change to this weapon when down - ent->client->newweapon = item; + // change to this weapon when down + ent->client->newweapon = item; } -void Use_Weapon2(edict_t *ent, gitem_t *item) { - int ammo_index; - gitem_t *ammo_item; - - if (ent->svflags & SVF_MONSTER) { - Use_Weapon(ent, item); - return; - } +void Use_Weapon2(edict_t* ent, gitem_t* item) { + int ammo_index; + gitem_t* ammo_item; - // see if we're already using it - if (item == ent->client->pers.weapon) - return; + if (ent->svflags & SVF_MONSTER) { + Use_Weapon(ent, item); + return; + } - if (item->ammo) { - ammo_item = FindItem(item->ammo); - ammo_index = ITEM_INDEX(ammo_item); - if (!ent->client->pers.inventory[ammo_index] && !g_select_empty->value) { - safe_cprintf(ent, PRINT_HIGH, "No %s for %s.\n", ammo_item->pickup_name, item->pickup_name); - return; - } - } + // see if we're already using it + if (item == ent->client->pers.weapon) + return; + + if (item->ammo) { + ammo_item = FindItem(item->ammo); + ammo_index = ITEM_INDEX(ammo_item); + if (!ent->client->pers.inventory[ammo_index] && !g_select_empty->value) { + safe_cprintf(ent, PRINT_HIGH, "No %s for %s.\n", ammo_item->pickup_name, item->pickup_name); + return; + } + } - // change to this weapon when down - ent->client->newweapon = item; + // change to this weapon when down + ent->client->newweapon = item; } @@ -478,22 +484,22 @@ void Use_Weapon2(edict_t *ent, gitem_t *item) { Drop_Weapon ================ */ -void Drop_Weapon(edict_t *ent, gitem_t *item) { - int index; - - if ((int) (dmflags->value) & DF_WEAPONS_STAY) - return; - - index = ITEM_INDEX(item); - // see if we're already using it - if (((item == ent->client->pers.weapon) || (item == ent->client->newweapon)) && - (ent->client->pers.inventory[index] == 1)) { - if (!(ent->svflags & SVF_MONSTER)) safe_cprintf(ent, PRINT_HIGH, "Can't drop current weapon\n"); - return; - } +void Drop_Weapon(edict_t* ent, gitem_t* item) { + int index; + + if ((int)(dmflags->value) & DF_WEAPONS_STAY) + return; + + index = ITEM_INDEX(item); + // see if we're already using it + if (((item == ent->client->pers.weapon) || (item == ent->client->newweapon)) && + (ent->client->pers.inventory[index] == 1)) { + if (!(ent->svflags & SVF_MONSTER)) safe_cprintf(ent, PRINT_HIGH, "Can't drop current weapon\n"); + return; + } - Drop_Item(ent, item); - ent->client->pers.inventory[index]--; + Drop_Item(ent, item); + ent->client->pers.inventory[index]--; } @@ -508,293 +514,370 @@ A generic function to handle the basics of weapon thinking #define FRAME_IDLE_FIRST (FRAME_FIRE_LAST + 1) #define FRAME_DEACTIVATE_FIRST (FRAME_IDLE_LAST + 1) -void Weapon_Generic2(edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST, int FRAME_IDLE_LAST, - int FRAME_DEACTIVATE_LAST, int *pause_frames, int *fire_frames, void (*fire)(edict_t *ent)) { - int n; - - //K03 Begin - // can't use gun if we are just spawning, or we - // are a morphed player using anything other - // than a player model - if (ent->deadflag || (ent->s.modelindex != 255) || (vrx_is_morphing_polt(ent)) - || (ctf->value && ctf_enable_balanced_fc->value && vrx_has_flag(ent)) // special rules, fc can't attack - // || ((ent->client->respawn_time/* - (0.1 * FRAME_ACTIVATE_LAST)*/ ) > level.time) - || (ent->flags & FL_WORMHOLE)//4.2 can't use weapons in wormhole - || ent->shield) // can't use weapons while shield is deployed - return; - if (ent->client->ps.gunframe > FRAME_DEACTIVATE_LAST) { - ent->client->weaponstate = WEAPON_READY; - ent->client->ps.gunframe = FRAME_IDLE_FIRST; - } - //K03 End - - if (ent->client->weaponstate == WEAPON_DROPPING) { - if (ent->client->ps.gunframe == FRAME_DEACTIVATE_LAST) { - ChangeWeapon(ent); - return; - }// ### Hentai ### BEGIN - else if ((FRAME_DEACTIVATE_LAST - ent->client->ps.gunframe) == 4) { - ent->client->anim_priority = ANIM_REVERSE; - if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) { - ent->s.frame = FRAME_crpain4 + 1; - ent->client->anim_end = FRAME_crpain1; - } else { - ent->s.frame = FRAME_pain304 + 1; - ent->client->anim_end = FRAME_pain301; - - } - } - // ### Hentai ### END - - ent->client->ps.gunframe++; - return; - } - - if (ent->client->weaponstate == WEAPON_ACTIVATING) { - // fast weapon switch - //3.0 weapon masters get free fast weapon switch - if ((ent->myskills.level >= 10 || ent->myskills.class_num == CLASS_WEAPONMASTER) && - (ent->client->newweapon != ent->client->pers.weapon)) - ent->client->ps.gunframe = FRAME_ACTIVATE_LAST; - if (ent->client->ps.gunframe == FRAME_ACTIVATE_LAST) { - ent->client->weaponstate = WEAPON_READY; - ent->client->ps.gunframe = FRAME_IDLE_FIRST; - return; - } - - ent->client->ps.gunframe++; - return; - } +#define T_EPSILON 0.001 +#ifdef DEBUG_WEAPONS +void print_wp_state(edict_t* ent, char* state) +{ + gi.dprintf("%f\t%f\t%f\t%d\t%d\t%s\n", + level.time, + ent->client->vrr.gun_statemachine_time, + ent->client->vrr.gun_fire_time, + ent->client->vrr.gun_statemachine_time >= 0.1 - 0.0001, + ent->client->ps.gunframe, + state + ); +} +#else +#define print_wp_state(...) +#endif + +/** + * Manages the state and behavior of a generic weapon, including activation, firing, idle, and deactivation states. + * + * This function handles weapon state transitions (activating, ready, firing, dropping), animating frames, + * and calling the weapon's firing logic. It also enforces constraints like preventing the weapon's usage + * under specific conditions (e.g., player morphed, shield active, no ammo, etc.). + * + * @param ent Pointer to the entity using the weapon (usually the player). + * @param FRAME_ACTIVATE_LAST The last frame of the activation animation. + * @param FRAME_FIRE_LAST The last frame of the firing animation sequence. + * @param FRAME_IDLE_LAST The last frame of the idle animation sequence. + * @param FRAME_DEACTIVATE_LAST The last frame of the deactivation animation. + * @param pause_frames A pointer to an array of frame numbers where the weapon may pause in its idle state. + * @param fire_frames A pointer to an array of frame numbers that represent firing animation frames. + * @param fire A function pointer representing the weapon's firing logic. It is called during the firing state. + */ +void Weapon_Generic2(edict_t* ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST, int FRAME_IDLE_LAST, + int FRAME_DEACTIVATE_LAST, int* pause_frames, int* fire_frames, void (*fire)(edict_t* ent)) { + int n; + const qboolean can_run_frame = ent->client->vrr.gun_statemachine_time >= 0.1 - T_EPSILON; + qboolean started_at_ready = false; + + //K03 Begin + // can't use gun if we are just spawning, or we + // are a morphed player using anything other + // than a player model + if (ent->deadflag || (ent->s.modelindex != 255) || (vrx_is_morphing_polt(ent)) + || (ctf->value && ctf_enable_balanced_fc->value && vrx_has_flag(ent)) // special rules, fc can't attack + // || ((ent->client->respawn_time/* - (0.1 * FRAME_ACTIVATE_LAST)*/ ) > level.time) + || (ent->flags & FL_WORMHOLE)//4.2 can't use weapons in wormhole + || ent->shield) // can't use weapons while shield is deployed + return; + + + if (ent->client->ps.gunframe > FRAME_DEACTIVATE_LAST) { + ent->client->weaponstate = WEAPON_READY; + ent->client->ps.gunframe = FRAME_IDLE_FIRST; + } + //K03 End + + if (ent->client->weaponstate == WEAPON_DROPPING) { + if (ent->client->ps.gunframe == FRAME_DEACTIVATE_LAST) { + ChangeWeapon(ent); + return; + }// ### Hentai ### BEGIN + else if ((FRAME_DEACTIVATE_LAST - ent->client->ps.gunframe) == 4) { + ent->client->anim_priority = ANIM_REVERSE; + if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) { + ent->s.frame = FRAME_crpain4 + 1; + ent->client->anim_end = FRAME_crpain1; + } + else { + ent->s.frame = FRAME_pain304 + 1; + ent->client->anim_end = FRAME_pain301; + + } + } + // ### Hentai ### END + + if (can_run_frame) { + ent->client->ps.gunframe++; + ent->client->vrr.gun_statemachine_time -= 0.1; + } + return; + } - if ((ent->client->newweapon) && (ent->client->weaponstate != WEAPON_FIRING)) { - // fast weapon switch - //3.0 weapon masters get free fast weapon switch - ent->client->weaponstate = WEAPON_DROPPING; - if ((ent->myskills.level >= 10 || ent->myskills.class_num == CLASS_WEAPONMASTER) && - (ent->client->newweapon != ent->client->pers.weapon)) { - ChangeWeapon(ent); - return; - } else - ent->client->ps.gunframe = FRAME_DEACTIVATE_FIRST; - - // ### Hentai ### BEGIN - if ((FRAME_DEACTIVATE_LAST - FRAME_DEACTIVATE_FIRST) < 4) { - ent->client->anim_priority = ANIM_REVERSE; - if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) { - ent->s.frame = FRAME_crpain4 + 1; - ent->client->anim_end = FRAME_crpain1; - } else { - ent->s.frame = FRAME_pain304 + 1; - ent->client->anim_end = FRAME_pain301; - - } - } - // ### Hentai ### END + if (ent->client->weaponstate == WEAPON_ACTIVATING) { + // fast weapon switch + //3.0 weapon masters get free fast weapon switch + if ((ent->myskills.level >= 10 || ent->myskills.class_num == CLASS_WEAPONMASTER) && + (ent->client->newweapon != ent->client->pers.weapon)) + ent->client->ps.gunframe = FRAME_ACTIVATE_LAST; + if (ent->client->ps.gunframe == FRAME_ACTIVATE_LAST) { + ent->client->weaponstate = WEAPON_READY; + ent->client->ps.gunframe = FRAME_IDLE_FIRST; + return; + } + + if (can_run_frame) { + ent->client->ps.gunframe++; + ent->client->vrr.gun_statemachine_time -= 0.1; + } + + return; + } - return; - } + if ((ent->client->newweapon) && (ent->client->weaponstate != WEAPON_FIRING)) { + // fast weapon switch + //3.0 weapon masters get free fast weapon switch + ent->client->weaponstate = WEAPON_DROPPING; + if ((ent->myskills.level >= 10 || ent->myskills.class_num == CLASS_WEAPONMASTER) && + (ent->client->newweapon != ent->client->pers.weapon)) { + ChangeWeapon(ent); + return; + } + else + ent->client->ps.gunframe = FRAME_DEACTIVATE_FIRST; + + // ### Hentai ### BEGIN + if ((FRAME_DEACTIVATE_LAST - FRAME_DEACTIVATE_FIRST) < 4) { + ent->client->anim_priority = ANIM_REVERSE; + if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) { + ent->s.frame = FRAME_crpain4 + 1; + ent->client->anim_end = FRAME_crpain1; + } + else { + ent->s.frame = FRAME_pain304 + 1; + ent->client->anim_end = FRAME_pain301; + + } + } + // ### Hentai ### END + + return; + } - if (ent->client->weaponstate == WEAPON_READY) { - if (((ent->client->latched_buttons | ent->client->buttons) & BUTTON_ATTACK)) { - ent->client->latched_buttons &= ~BUTTON_ATTACK; - if ((!ent->client->ammo_index) || - (ent->client->pers.inventory[ent->client->ammo_index] >= ent->client->pers.weapon->quantity)) { - //GHz START - ent->client->idle_frames = 0; - //4.5 the first shot merely resets the chatprotect state, but doesn't actually fire - if (ent->flags & FL_CHATPROTECT) { - // reset chat protect and cloaking flags - vrx_remove_chat_protect(ent); - - // re-draw weapon - ent->client->newweapon = ent->client->pers.weapon; - ent->client->weaponstate = WEAPON_DROPPING; - ChangeWeapon(ent); - return; - } - //GHz END - ent->client->ps.gunframe = FRAME_FIRE_FIRST; - ent->client->weaponstate = WEAPON_FIRING; - - // start the animation - ent->client->anim_priority = ANIM_ATTACK; - if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) { - ent->s.frame = FRAME_crattak1 - 1; - ent->client->anim_end = FRAME_crattak9; - } else { - ent->s.frame = FRAME_attack1 - 1; - ent->client->anim_end = FRAME_attack8; - } - } else { - if (level.time >= ent->pain_debounce_time) { - gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0); - ent->pain_debounce_time = level.time + 1; - } - NoAmmoWeaponChange(ent); - } - } else { - if (ent->client->ps.gunframe == FRAME_IDLE_LAST) { - ent->client->ps.gunframe = FRAME_IDLE_FIRST; - return; - } - - if (pause_frames) { - for (n = 0; pause_frames[n]; n++) { - if (ent->client->ps.gunframe == pause_frames[n]) { - if (randomMT() & 15) - return; - } - } - } - - ent->client->ps.gunframe++; - return; - } - } + if (ent->client->weaponstate == WEAPON_READY) { + if (((ent->client->latched_buttons | ent->client->buttons) & BUTTON_ATTACK)) { + if (ent->client->vrr.gun_fire_time > level.time + T_EPSILON) + return; + + print_wp_state(ent, "READY"); + ent->client->latched_buttons &= ~BUTTON_ATTACK; + if ((!ent->client->ammo_index) || + (ent->client->pers.inventory[ent->client->ammo_index] >= ent->client->pers.weapon->quantity)) { + //GHz START + ent->client->idle_frames = 0; + //4.5 the first shot merely resets the chatprotect state, but doesn't actually fire + if (ent->flags & FL_CHATPROTECT) { + // reset chat protect and cloaking flags + vrx_remove_chat_protect(ent); + + // re-draw weapon + ent->client->newweapon = ent->client->pers.weapon; + ent->client->weaponstate = WEAPON_DROPPING; + ChangeWeapon(ent); + return; + } + //GHz END + started_at_ready = true; + ent->client->ps.gunframe = FRAME_FIRE_FIRST; + ent->client->weaponstate = WEAPON_FIRING; + + print_wp_state(ent, "READY DONE"); + + // start the animation + ent->client->anim_priority = ANIM_ATTACK; + if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) { + ent->s.frame = FRAME_crattak1 - 1; + ent->client->anim_end = FRAME_crattak9; + } + else { + ent->s.frame = FRAME_attack1 - 1; + ent->client->anim_end = FRAME_attack8; + } + } + else { + if (level.time >= ent->pain_debounce_time) { + gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0); + ent->pain_debounce_time = level.time + 1; + } + NoAmmoWeaponChange(ent); + } + } + else { + if (ent->client->ps.gunframe == FRAME_IDLE_LAST) { + ent->client->ps.gunframe = FRAME_IDLE_FIRST; + return; + } + // don't run idle frames at 60 fps + if (can_run_frame) { + if (pause_frames) { + for (n = 0; pause_frames[n]; n++) { + if (ent->client->ps.gunframe == pause_frames[n]) { + if (randomMT() & 15) + return; + } + } + } + + + ent->client->ps.gunframe++; + ent->client->vrr.gun_statemachine_time -= 0.1; + } + return; + } + } - if (ent->client->weaponstate == WEAPON_FIRING) { - for (n = 0; fire_frames[n]; n++) { - if (ent->client->ps.gunframe == fire_frames[n]) { - if (level.time > ent->client->ctf_techsndtime) { - qboolean quad = false; - - if (ent->client->quad_framenum > level.framenum) - quad = true; - - if (ent->client->pers.inventory[strength_index]) { - if (quad) - gi.sound(ent, CHAN_ITEM, gi.soundindex("ctf/tech2x.wav"), 1, ATTN_NORM, 0); - else - gi.sound(ent, CHAN_ITEM, gi.soundindex("ctf/tech2.wav"), 1, ATTN_NORM, 0); - } else if (ent->client->pers.inventory[haste_index]) - gi.sound(ent, CHAN_ITEM, gi.soundindex("ctf/tech3.wav"), 1, ATTN_NORM, 0); - else if (quad) - gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage3.wav"), 1, ATTN_NORM, 0); - - ent->client->ctf_techsndtime = level.time + 0.9; - } - - //K03 Begin - ent->shots++; - ent->myskills.shots++; - if (ent->movetype != MOVETYPE_NOCLIP || (ent->myskills.abilities[CLOAK].current_level == 10 && - vrx_get_talent_level(ent, TALENT_IMP_CLOAK) == - 4)) // don't uncloak if they are in noclip, or permacloaked due to upgrade levels - ent->svflags &= ~SVF_NOCLIENT; - ent->client->cloaking = false; - ent->client->cloakable = 0; - //K03 End - - fire(ent); - //gi.dprintf("fired at %d\n",level.framenum); - break; - } - } - - if (!fire_frames[n]) - ent->client->ps.gunframe++; - - if (ent->client->ps.gunframe == FRAME_IDLE_FIRST + 1) - ent->client->weaponstate = WEAPON_READY; - } + if (ent->client->weaponstate == WEAPON_FIRING) { + + for (n = 0; fire_frames[n]; n++) { + if (ent->client->ps.gunframe == fire_frames[n]) { + // a small epsilon for rounding issues that skips frames that shouldn't + if (ent->client->vrr.gun_fire_time >= level.time + T_EPSILON) + { + return; + } + + + if (level.time > ent->client->ctf_techsndtime) { + qboolean quad = false; + + if (ent->client->quad_framenum > level.framenum) + quad = true; + + if (ent->client->pers.inventory[strength_index]) { + if (quad) + gi.sound(ent, CHAN_ITEM, gi.soundindex("ctf/tech2x.wav"), 1, ATTN_NORM, 0); + else + gi.sound(ent, CHAN_ITEM, gi.soundindex("ctf/tech2.wav"), 1, ATTN_NORM, 0); + } + else if (ent->client->pers.inventory[haste_index]) + gi.sound(ent, CHAN_ITEM, gi.soundindex("ctf/tech3.wav"), 1, ATTN_NORM, 0); + else if (quad) + gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage3.wav"), 1, ATTN_NORM, 0); + + ent->client->ctf_techsndtime = level.time + 0.9; + } + + //K03 Begin + ent->shots++; + ent->myskills.shots++; + if (ent->movetype != MOVETYPE_NOCLIP || (ent->myskills.abilities[CLOAK].current_level == 10 && + vrx_get_talent_level(ent, TALENT_IMP_CLOAK) == + 4)) // don't uncloak if they are in noclip, or permacloaked due to upgrade levels + ent->svflags &= ~SVF_NOCLIENT; + ent->client->cloaking = false; + ent->client->cloakable = 0; + //K03 End + + print_wp_state(ent, "FIRE"); + fire(ent); + ent->client->vrr.gun_statemachine_time = 0.0f; + //gi.dprintf("fired at %d\n",level.framenum); + break; + } + } + + if (!fire_frames[n]) { + if (can_run_frame) { + ent->client->ps.gunframe++; + ent->client->vrr.gun_statemachine_time -= 0.1; + print_wp_state(ent, "CD"); + } + } + + if (ent->client->ps.gunframe == FRAME_IDLE_FIRST + 1) { + ent->client->weaponstate = WEAPON_READY; + ent->client->vrr.gun_fire_time = level.time + 0.1; + } + } } //K03 Begin void Weapon_Generic( - edict_t *ent, - int FRAME_ACTIVATE_LAST, - int FRAME_FIRE_LAST, - int FRAME_IDLE_LAST, - int FRAME_DEACTIVATE_LAST, - int *pause_frames, - int *fire_frames, - void (*fire)(edict_t *ent)) { - int freezeLevel = 0; - que_t *curse; - - // pick the highest level freeze - if ((curse = que_findtype(ent->curses, NULL, AURA_HOLYFREEZE)) != NULL) - freezeLevel = curse->ent->owner->myskills.abilities[HOLY_FREEZE].current_level; - if (ent->chill_time > level.time && ent->chill_level > freezeLevel) - freezeLevel = ent->chill_level; - - //3.0 New hfa code (more balanced?) - if (freezeLevel) { - int Continue; - - //Figure out what frame should be skipped (every x frames) - switch (freezeLevel) { - case 0: - case 1: - case 2: - case 3: - Continue = qf2sf(7); - break; - case 4: - case 5: - Continue = qf2sf(6); - break; - case 6: - case 7: - Continue = qf2sf(5); - break; - case 8: - case 9: - default: - Continue = qf2sf(4); - break; // 25% reduced firing rate - } - - //Examples: - //If Continue == 2, every second frame is skipped (50% slower firing rate) - //If Continue == 6, every sixth frame is skipped (17% slower firing rate) - - ent->FrameShot++; - if (ent->FrameShot >= Continue) { - ent->FrameShot = 0; - return; - } - } - - // Run weapons at 10 FPS - if ( (level.framenum % qf2sf(1)) != 0) - return; + edict_t* ent, + int FRAME_ACTIVATE_LAST, + int FRAME_FIRE_LAST, + int FRAME_IDLE_LAST, + int FRAME_DEACTIVATE_LAST, + int* pause_frames, + int* fire_frames, + void (*fire)(edict_t* ent)) { + int freezeLevel = 0; + que_t* curse; + + // pick the highest level freeze + if ((curse = que_findtype(ent->curses, NULL, AURA_HOLYFREEZE)) != NULL) + freezeLevel = curse->ent->owner->myskills.abilities[HOLY_FREEZE].current_level; + if (ent->chill_time > level.time && ent->chill_level > freezeLevel) + freezeLevel = ent->chill_level; + + //3.0 New hfa code (more balanced?) + if (freezeLevel) { + int Continue; + + //Figure out what frame should be skipped (every x frames) + switch (freezeLevel) { + case 0: + case 1: + case 2: + case 3: + Continue = qf2sf(7); + break; + case 4: + case 5: + Continue = qf2sf(6); + break; + case 6: + case 7: + Continue = qf2sf(5); + break; + case 8: + case 9: + default: + Continue = qf2sf(4); + break; // 25% reduced firing rate + } + + //Examples: + //If Continue == 2, every second frame is skipped (50% slower firing rate) + //If Continue == 6, every sixth frame is skipped (17% slower firing rate) + + ent->FrameShot++; + if (ent->FrameShot >= Continue) { + ent->FrameShot = 0; + return; + } + } - Weapon_Generic2(ent, FRAME_ACTIVATE_LAST, FRAME_FIRE_LAST, - FRAME_IDLE_LAST, FRAME_DEACTIVATE_LAST, pause_frames, fire_frames, fire); + Weapon_Generic2(ent, FRAME_ACTIVATE_LAST, FRAME_FIRE_LAST, + FRAME_IDLE_LAST, FRAME_DEACTIVATE_LAST, pause_frames, fire_frames, fire); - // ent->FrameShot = 0; + // ent->FrameShot = 0; - if ((!ent->myskills.abilities[HASTE].disable && ent->myskills.abilities[HASTE].current_level >= 1) - || ent->client->pers.inventory[haste_index]) { - // time when to fire next shot - float haste_wait = -1; - float haste_tech = INFINITY; // "never" - float haste_skill = INFINITY; // "never" + if ((!ent->myskills.abilities[HASTE].disable && ent->myskills.abilities[HASTE].current_level >= 1) + || ent->client->pers.inventory[haste_index]) { + // time when to fire next shot + float haste_wait = -1; + float haste_tech = INFINITY; // "never" + float haste_skill = INFINITY; // "never" - if (ent->myskills.abilities[HASTE].current_level >= 1) - haste_skill = 1.0f / ent->myskills.abilities[HASTE].current_level; + if (ent->myskills.abilities[HASTE].current_level >= 1) + haste_skill = 1.0f / ent->myskills.abilities[HASTE].current_level; - // haste tech - if (ent->client->pers.inventory[haste_index]) { + // haste tech + if (ent->client->pers.inventory[haste_index]) { haste_tech = 0.1; // 100% improvement (2x firing rate) - } - - haste_wait = min(haste_tech, haste_skill); - if (haste_wait <= 0) // safeguard lol - return; - - // if enough frames have passed by, then call the weapon func - // an additional time - while (ent->haste_time >= haste_wait) { - Weapon_Generic2(ent, FRAME_ACTIVATE_LAST, FRAME_FIRE_LAST, - FRAME_IDLE_LAST, FRAME_DEACTIVATE_LAST, pause_frames, fire_frames, fire); - ent->haste_time -= haste_wait; - } - ent->haste_time += FRAMETIME; - } + } + + haste_wait = min(haste_tech, haste_skill); + if (haste_wait <= 0) // safeguard lol + return; + + // if enough frames have passed by, then call the weapon func + // an additional time + while (ent->haste_time >= haste_wait) { + ent->client->vrr.gun_statemachine_time += 0.1; + ent->client->vrr.gun_fire_time = level.time; + Weapon_Generic2(ent, FRAME_ACTIVATE_LAST, FRAME_FIRE_LAST, + FRAME_IDLE_LAST, FRAME_DEACTIVATE_LAST, pause_frames, fire_frames, fire); + ent->haste_time -= haste_wait; + } + ent->haste_time += FRAMETIME; + } - //gi.dprintf("gunframe=%d\n", ent->client->ps.gunframe); + //gi.dprintf("gunframe=%d\n", ent->client->ps.gunframe); } //K03 End /* @@ -814,7 +897,7 @@ GRENADE float get_weapon_grenade_speed(edict_t* ent) { int speed, min_speed; - int max_speed = GRENADE_INITIAL_SPEED + GRENADE_ADDON_SPEED * ent->myskills.weapons[WEAPON_HANDGRENADE].mods[1].current_level; + const int max_speed = GRENADE_INITIAL_SPEED + GRENADE_ADDON_SPEED * ent->myskills.weapons[WEAPON_HANDGRENADE].mods[1].current_level; float timer; timer = ent->client->grenade_time - level.time; @@ -827,43 +910,43 @@ float get_weapon_grenade_speed(edict_t* ent) return speed; } -void weapon_grenade_fire(edict_t *ent, qboolean held) { - vec3_t offset; - vec3_t forward, right; - vec3_t start; - int damage = GRENADE_INITIAL_DAMAGE + - GRENADE_ADDON_DAMAGE * ent->myskills.weapons[WEAPON_HANDGRENADE].mods[0].current_level;//K03 - int radius_damage = GRENADE_INITIAL_RADIUS_DAMAGE + - GRENADE_ADDON_RADIUS_DAMAGE * ent->myskills.weapons[WEAPON_HANDGRENADE].mods[0].current_level; - float timer; +void weapon_grenade_fire(edict_t* ent, qboolean held) { + vec3_t offset; + vec3_t forward, right; + vec3_t start; + int damage = GRENADE_INITIAL_DAMAGE + + GRENADE_ADDON_DAMAGE * ent->myskills.weapons[WEAPON_HANDGRENADE].mods[0].current_level;//K03 + const int radius_damage = GRENADE_INITIAL_RADIUS_DAMAGE + + GRENADE_ADDON_RADIUS_DAMAGE * ent->myskills.weapons[WEAPON_HANDGRENADE].mods[0].current_level; + float timer; float speed; // int speed, min_speed; // int max_speed = GRENADE_INITIAL_SPEED + // GRENADE_ADDON_SPEED * ent->myskills.weapons[WEAPON_HANDGRENADE].mods[1].current_level; - float radius; - - //3.0 disable chat protect (somehow throwing a hg does not reset a client's idle frames) - //4.5 the first shot merely resets the chatprotect state, but doesn't actually fire - if (ent->flags & FL_CHATPROTECT) { - vrx_remove_chat_protect(ent); - - // re-draw weapon - ent->client->newweapon = ent->client->pers.weapon; - ent->client->weaponstate = WEAPON_DROPPING; - ChangeWeapon(ent); - return; - } + float radius; + + //3.0 disable chat protect (somehow throwing a hg does not reset a client's idle frames) + //4.5 the first shot merely resets the chatprotect state, but doesn't actually fire + if (ent->flags & FL_CHATPROTECT) { + vrx_remove_chat_protect(ent); + + // re-draw weapon + ent->client->newweapon = ent->client->pers.weapon; + ent->client->weaponstate = WEAPON_DROPPING; + ChangeWeapon(ent); + return; + } - radius = GRENADE_INITIAL_RADIUS + - GRENADE_ADDON_RADIUS * ent->myskills.weapons[WEAPON_HANDGRENADE].mods[2].current_level;//K03 - if (is_quad) - damage *= 4; + radius = GRENADE_INITIAL_RADIUS + + GRENADE_ADDON_RADIUS * ent->myskills.weapons[WEAPON_HANDGRENADE].mods[2].current_level;//K03 + if (is_quad) + damage *= 4; - VectorSet(offset, 8, 8, ent->viewheight - 8); - AngleVectors(ent->client->v_angle, forward, right, NULL); - P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); + VectorSet(offset, 8, 8, ent->viewheight - 8); + AngleVectors(ent->client->v_angle, forward, right, NULL); + P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); - timer = ent->client->grenade_time - level.time; + timer = ent->client->grenade_time - level.time; /* min_speed = 0.5 * max_speed; @@ -874,21 +957,21 @@ void weapon_grenade_fire(edict_t *ent, qboolean held) { */ speed = get_weapon_grenade_speed(ent); - fire_grenade2(ent, start, forward, damage, speed, timer, radius, radius_damage, held); - //gi.dprintf("fired grenade at %.1f\n", level.time); - //gi.dprintf("fired grenade at %.1f\n", timer); - - //K03 Begin - ent->shots++; - ent->myskills.shots++; - ent->svflags &= ~SVF_NOCLIENT; - if (ent->myskills.abilities[CLOAK].current_level < 10 || vrx_get_talent_level(ent, TALENT_IMP_CLOAK) < 4) { - ent->client->cloaking = false; - ent->client->cloakable = 0; - } - //K03 End + fire_grenade2(ent, start, forward, damage, speed, timer, radius, radius_damage, held); + //gi.dprintf("fired grenade at %.1f\n", level.time); + //gi.dprintf("fired grenade at %.1f\n", timer); + + //K03 Begin + ent->shots++; + ent->myskills.shots++; + ent->svflags &= ~SVF_NOCLIENT; + if (ent->myskills.abilities[CLOAK].current_level < 10 || vrx_get_talent_level(ent, TALENT_IMP_CLOAK) < 4) { + ent->client->cloaking = false; + ent->client->cloakable = 0; + } + //K03 End - // ### Hentai ### BEGIN + // ### Hentai ### BEGIN /* if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) { @@ -902,170 +985,202 @@ void weapon_grenade_fire(edict_t *ent, qboolean held) { ent->s.frame = FRAME_wave08; ent->client->anim_end = FRAME_wave01; }*/ - // ### Hentai ### END + // ### Hentai ### END - if (!((int) dmflags->value & DF_INFINITE_AMMO)) - ent->client->pers.inventory[ent->client->ammo_index]--; + if (!((int)dmflags->value & DF_INFINITE_AMMO)) + ent->client->pers.inventory[ent->client->ammo_index]--; - ent->client->grenade_time = level.time + 1.0; + ent->client->grenade_time = level.time + 1.0; - //K03 Begin - if (ent->myskills.weapons[WEAPON_HANDGRENADE].mods[4].current_level < 1) { - gi.WriteByte(svc_muzzleflash); - gi.WriteShort(ent - g_edicts); - gi.WriteByte(MZ_BLASTER | is_silenced); - gi.multicast(ent->s.origin, MULTICAST_PVS); - } - //K03 ENd + //K03 Begin + if (ent->myskills.weapons[WEAPON_HANDGRENADE].mods[4].current_level < 1) { + gi.WriteByte(svc_muzzleflash); + gi.WriteShort(ent - g_edicts); + gi.WriteByte(MZ_BLASTER | is_silenced); + gi.multicast(ent->s.origin, MULTICAST_PVS); + } + //K03 ENd - if (ent->deadflag || ent->s.modelindex != 255) // VWep animations screw up corpses - { - return; - } + if (ent->deadflag || ent->s.modelindex != 255) // VWep animations screw up corpses + { + return; + } - if (ent->health <= 0) - return; + if (ent->health <= 0) + return; - if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) { - ent->client->anim_priority = ANIM_ATTACK; - ent->s.frame = FRAME_crattak1 - 1; - ent->client->anim_end = FRAME_crattak3; - } else { - ent->client->anim_priority = ANIM_REVERSE; - ent->s.frame = FRAME_wave08; - ent->client->anim_end = FRAME_wave01; - } + if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) { + ent->client->anim_priority = ANIM_ATTACK; + ent->s.frame = FRAME_crattak1 - 1; + ent->client->anim_end = FRAME_crattak3; + } + else { + ent->client->anim_priority = ANIM_REVERSE; + ent->s.frame = FRAME_wave08; + ent->client->anim_end = FRAME_wave01; + } } -void Weapon_Grenade2(edict_t *ent) { - if (ent->shield) - return; - //gi.dprintf("gunframe = %d\n", ent->client->ps.gunframe); - if ((ent->client->newweapon) && (ent->client->weaponstate == WEAPON_READY)) { - ChangeWeapon(ent); - return; - } +void Weapon_Grenade2(edict_t* ent) { + qboolean can_run_frame = ent->client->vrr.gun_statemachine_time >= 0.1; - if (ent->client->weaponstate == WEAPON_ACTIVATING) { - ent->client->weaponstate = WEAPON_READY; - ent->client->ps.gunframe = 16; - return; - } + if (ent->shield) + return; + //gi.dprintf("gunframe = %d\n", ent->client->ps.gunframe); + if ((ent->client->newweapon) && (ent->client->weaponstate == WEAPON_READY)) { + ChangeWeapon(ent); + return; + } - if (ent->client->weaponstate == WEAPON_READY) { - if (((ent->client->latched_buttons | ent->client->buttons) & BUTTON_ATTACK)) { - ent->client->latched_buttons &= ~BUTTON_ATTACK; - if (ent->client->pers.inventory[ent->client->ammo_index]) { - ent->client->ps.gunframe = 1; - ent->client->weaponstate = WEAPON_FIRING; - ent->client->grenade_time = 0; - ent->client->grenade_delay = 0; - } else { - if (level.time >= ent->pain_debounce_time) { - if (ent->myskills.weapons[WEAPON_HANDGRENADE].mods[4].current_level < 1)//K03 - gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0); - ent->pain_debounce_time = level.time + 1; - } - NoAmmoWeaponChange(ent); - } - return; - } - - if ((ent->client->ps.gunframe == 29) || (ent->client->ps.gunframe == 34) || (ent->client->ps.gunframe == 39) || - (ent->client->ps.gunframe == 48)) { - if (randomMT() & 15) - return; - } - - if (++ent->client->ps.gunframe > 48) - ent->client->ps.gunframe = 16; - return; - } + - if (ent->client->weaponstate == WEAPON_FIRING) { - if (ent->client->ps.gunframe == 5 && ent->myskills.weapons[WEAPON_HANDGRENADE].mods[4].current_level < 1)//K03 - gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/hgrena1b.wav"), 1, ATTN_NORM, 0); - - if (ent->client->ps.gunframe == 11) { - if (!ent->client->grenade_time) { - ent->client->grenade_time = level.time + GRENADE_TIMER + 0.2; - if (ent->myskills.weapons[WEAPON_HANDGRENADE].mods[4].current_level < 1)//K03 - ent->client->weapon_sound = gi.soundindex("weapons/hgrenc1b.wav"); - } - - - // they waited too long, detonate it in their hand - if (!ent->client->grenade_blew_up && level.time >= ent->client->grenade_time) { - ent->client->weapon_sound = 0; - weapon_grenade_fire(ent, true); - ent->client->grenade_blew_up = true; - } - - if (ent->client->buttons & BUTTON_ATTACK) - return; - - if (ent->client->grenade_blew_up) { - if (level.time >= ent->client->grenade_time) { - ent->client->ps.gunframe = 15; - ent->client->grenade_blew_up = false; - } else { - return; - } - } - } - - if (ent->client->ps.gunframe == 12) { - ent->client->weapon_sound = 0; - weapon_grenade_fire(ent, false); - } - - if ((ent->client->ps.gunframe == 15) && (level.time < ent->client->grenade_time)) - return; - - //ent->client->ps.gunframe++; - - // (apple) - // This will skip half the priming animation, thus shortening - // the firing delay by about half. To keep the same refire rate - // a delay is applied after the priming phase. This will keep the - // HG from going into its next weaponstate until delay is done. - if (ent->client->ps.gunframe < 11) { - ent->client->ps.gunframe += 2; - ent->client->grenade_delay++; - } else if (ent->client->grenade_delay > 0) { - ent->client->grenade_delay--; - ent->client->ps.gunframe++; - } else - ent->client->ps.gunframe++; - - if (ent->client->ps.gunframe >= 16 && ent->client->grenade_delay == 0) { - ent->client->grenade_time = 0; - ent->client->weaponstate = WEAPON_READY; - } - } -} + if (ent->client->weaponstate == WEAPON_ACTIVATING) { + ent->client->weaponstate = WEAPON_READY; + ent->client->ps.gunframe = 16; + return; + } -//K03 Begin -void Weapon_Grenade(edict_t *ent) { - // can't use gun if we are just spawning, or we - // are a morphed player using anything other - // than a player model - if (ent->deadflag || (ent->s.modelindex != 255) || (vrx_is_morphing_polt(ent)) - || (ctf->value && ctf_enable_balanced_fc->value && vrx_has_flag(ent)) - || (ent->client->respawn_time > level.time) - || (ent->flags & FL_WORMHOLE)) - return; - - // Run weapons at 10 FPS - if ( (level.framenum % qf2sf(1)) != 0) - return; + if (ent->client->weaponstate == WEAPON_READY) { + if (((ent->client->latched_buttons | ent->client->buttons) & BUTTON_ATTACK)) { + ent->client->latched_buttons &= ~BUTTON_ATTACK; + if (ent->client->pers.inventory[ent->client->ammo_index]) { + print_wp_state(ent, "firingSTART"); + ent->client->ps.gunframe = 1; + ent->client->weaponstate = WEAPON_FIRING; + ent->client->grenade_time = 0; + ent->client->grenade_delay = 0; + } + else { + if (level.time >= ent->pain_debounce_time) { + if (ent->myskills.weapons[WEAPON_HANDGRENADE].mods[4].current_level < 1)//K03 + gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0); + ent->pain_debounce_time = level.time + 1; + } + NoAmmoWeaponChange(ent); + } + + ent->client->vrr.gun_statemachine_time = 0.0; + return; + } + + if ((ent->client->ps.gunframe == 29) || (ent->client->ps.gunframe == 34) || (ent->client->ps.gunframe == 39) || + (ent->client->ps.gunframe == 48)) { + if (randomMT() & 15) { + ent->client->vrr.gun_statemachine_time -= 0.1; // advance the frame timer anyway + return; + } + } + + if (can_run_frame) { + // print_wp_state(ent, "READY"); + ++ent->client->ps.gunframe; + ent->client->vrr.gun_statemachine_time -= 0.1; + } + + if (ent->client->ps.gunframe > 48) + ent->client->ps.gunframe = 16; + + + return; + } - Weapon_Grenade2(ent); + if (ent->client->weaponstate == WEAPON_FIRING) { + if (ent->client->ps.gunframe == 5 && ent->myskills.weapons[WEAPON_HANDGRENADE].mods[4].current_level < 1) {//K03 + if (can_run_frame) + gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/hgrena1b.wav"), 1, ATTN_NORM, 0); + } + + if (ent->client->ps.gunframe == 11) { + if (!ent->client->grenade_time) { + ent->client->grenade_time = level.time + GRENADE_TIMER + 0.2; + if (ent->myskills.weapons[WEAPON_HANDGRENADE].mods[4].current_level < 1)//K03 + ent->client->weapon_sound = gi.soundindex("weapons/hgrenc1b.wav"); + } + + + // they waited too long, detonate it in their hand + if (!ent->client->grenade_blew_up && level.time >= ent->client->grenade_time) { + ent->client->weapon_sound = 0; + weapon_grenade_fire(ent, true); + ent->client->grenade_blew_up = true; + } + + + print_wp_state(ent, "firing"); + + if (ent->client->buttons & BUTTON_ATTACK) + return; + + if (ent->client->grenade_blew_up) { + if (level.time >= ent->client->grenade_time) { + ent->client->ps.gunframe = 15; + ent->client->grenade_blew_up = false; + } + else { + return; + } + } + } + + if (ent->client->ps.gunframe == 12) { + ent->client->weapon_sound = 0; + weapon_grenade_fire(ent, false); + ent->client->vrr.gun_statemachine_time = 0.1; + can_run_frame = true; + } + + if ((ent->client->ps.gunframe == 15) && (level.time < ent->client->grenade_time)) + return; + + //ent->client->ps.gunframe++; + + // (apple) + // This will skip half the priming animation, thus shortening + // the firing delay by about half. To keep the same refire rate + // a delay is applied after the priming phase. This will keep the + // HG from going into its next weaponstate until delay is done. + if (can_run_frame) { + print_wp_state(ent, "adv frame"); + if (ent->client->ps.gunframe < 11) { + ent->client->ps.gunframe += 2; + ent->client->grenade_delay++; + } + else if (ent->client->grenade_delay > 0) { + ent->client->ps.gunframe++; + ent->client->grenade_delay--; + } + else { + ent->client->ps.gunframe++; + + } + ent->client->vrr.gun_statemachine_time -= 0.1; + } + + if (ent->client->ps.gunframe >= 16 && ent->client->grenade_delay == 0) { + ent->client->grenade_time = 0; + ent->client->weaponstate = WEAPON_READY; + print_wp_state(ent, "ChangetoREADY"); + } + } +} -// if (ent->myskills.weapons[WEAPON_HANDGRENADE].mods[1].current_level > 9) -// Weapon_Grenade2(ent); -// if (ent->myskills.weapons[WEAPON_HANDGRENADE].mods[1].current_level > 4) -// Weapon_Grenade2(ent); +//K03 Begin +void Weapon_Grenade(edict_t* ent) { + // can't use gun if we are just spawning, or we + // are a morphed player using anything other + // than a player model + if (ent->deadflag || (ent->s.modelindex != 255) || (vrx_is_morphing_polt(ent)) + || (ctf->value && ctf_enable_balanced_fc->value && vrx_has_flag(ent)) + || (ent->client->respawn_time > level.time) + || (ent->flags & FL_WORMHOLE)) + return; + + Weapon_Grenade2(ent); + + // if (ent->myskills.weapons[WEAPON_HANDGRENADE].mods[1].current_level > 9) + // Weapon_Grenade2(ent); + // if (ent->myskills.weapons[WEAPON_HANDGRENADE].mods[1].current_level > 4) + // Weapon_Grenade2(ent); } //K03 End @@ -1078,77 +1193,77 @@ GRENADE LAUNCHER ====================================================================== */ -void weapon_grenadelauncher_fire(edict_t *ent) { - vec3_t offset; - vec3_t forward, right; - vec3_t start; - - int damage = (int) (GRENADELAUNCHER_INITIAL_DAMAGE + - GRENADELAUNCHER_ADDON_DAMAGE * - ent->myskills.weapons[WEAPON_GRENADELAUNCHER].mods[0].current_level); - float radius = (float) (GRENADELAUNCHER_INITIAL_RADIUS + - GRENADELAUNCHER_ADDON_RADIUS * - ent->myskills.weapons[WEAPON_GRENADELAUNCHER].mods[1].current_level); - int speed = (int) (GRENADELAUNCHER_INITIAL_SPEED + - (GRENADELAUNCHER_ADDON_SPEED * - ent->myskills.weapons[WEAPON_GRENADELAUNCHER].mods[2].current_level)); - int radius_damage = (int) (GRENADELAUNCHER_INITIAL_RADIUS_DAMAGE + - GRENADELAUNCHER_ADDON_RADIUS_DAMAGE * - ent->myskills.weapons[WEAPON_GRENADELAUNCHER].mods[0].current_level); - - if (is_quad) - damage *= 4; - - //GHz: We dont have enough ammo to fire, so change weapon and abort - if (ent->client->pers.inventory[ent->client->ammo_index] < 1) { - ent->client->ps.gunframe++; - gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0); - NoAmmoWeaponChange(ent); - return; - } +void weapon_grenadelauncher_fire(edict_t* ent) { + vec3_t offset; + vec3_t forward, right; + vec3_t start; + + int damage = (int)(GRENADELAUNCHER_INITIAL_DAMAGE + + GRENADELAUNCHER_ADDON_DAMAGE * + ent->myskills.weapons[WEAPON_GRENADELAUNCHER].mods[0].current_level); + const float radius = (float)(GRENADELAUNCHER_INITIAL_RADIUS + + GRENADELAUNCHER_ADDON_RADIUS * + ent->myskills.weapons[WEAPON_GRENADELAUNCHER].mods[1].current_level); + const int speed = (int)(GRENADELAUNCHER_INITIAL_SPEED + + (GRENADELAUNCHER_ADDON_SPEED * + ent->myskills.weapons[WEAPON_GRENADELAUNCHER].mods[2].current_level)); + const int radius_damage = (int)(GRENADELAUNCHER_INITIAL_RADIUS_DAMAGE + + GRENADELAUNCHER_ADDON_RADIUS_DAMAGE * + ent->myskills.weapons[WEAPON_GRENADELAUNCHER].mods[0].current_level); + + if (is_quad) + damage *= 4; + + //GHz: We dont have enough ammo to fire, so change weapon and abort + if (ent->client->pers.inventory[ent->client->ammo_index] < 1) { + ent->client->ps.gunframe++; + gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0); + NoAmmoWeaponChange(ent); + return; + } - VectorSet(offset, 8, 8, ent->viewheight - 8); - AngleVectors(ent->client->v_angle, forward, right, NULL); - P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); + VectorSet(offset, 8, 8, ent->viewheight - 8); + AngleVectors(ent->client->v_angle, forward, right, NULL); + P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); - VectorScale(forward, -2, ent->client->kick_origin); - ent->client->kick_angles[0] = -1; + VectorScale(forward, -2, ent->client->kick_origin); + ent->client->kick_angles[0] = -1; - //K03 Begin - if ((ent->max_pipes < MAX_PIPES) || !ent->client->weapon_mode) { - fire_grenade(ent, start, forward, damage, speed, 2.5, radius, radius_damage); - if (!((int) dmflags->value & DF_INFINITE_AMMO)) - ent->client->pers.inventory[ent->client->ammo_index]--; - if (ent->client->weapon_mode) - ent->max_pipes++; - } + //K03 Begin + if ((ent->max_pipes < MAX_PIPES) || !ent->client->weapon_mode) { + fire_grenade(ent, start, forward, damage, speed, 2.5, radius, radius_damage); + if (!((int)dmflags->value & DF_INFINITE_AMMO)) + ent->client->pers.inventory[ent->client->ammo_index]--; + if (ent->client->weapon_mode) + ent->max_pipes++; + } - if (ent->myskills.weapons[WEAPON_GRENADELAUNCHER].mods[4].current_level < 1) { - gi.WriteByte(svc_muzzleflash); - gi.WriteShort(ent - g_edicts); - gi.WriteByte(MZ_GRENADE | is_silenced); - gi.multicast(ent->s.origin, MULTICAST_PVS); - } - //K03 End + if (ent->myskills.weapons[WEAPON_GRENADELAUNCHER].mods[4].current_level < 1) { + gi.WriteByte(svc_muzzleflash); + gi.WriteShort(ent - g_edicts); + gi.WriteByte(MZ_GRENADE | is_silenced); + gi.multicast(ent->s.origin, MULTICAST_PVS); + } + //K03 End - ent->client->ps.gunframe++; + ent->client->ps.gunframe++; - //K03 Begin - if (ent->myskills.weapons[WEAPON_GRENADELAUNCHER].mods[4].current_level < 1) - PlayerNoise(ent, start, PNOISE_WEAPON); - //K03 End + //K03 Begin + if (ent->myskills.weapons[WEAPON_GRENADELAUNCHER].mods[4].current_level < 1) + PlayerNoise(ent, start, PNOISE_WEAPON); + //K03 End } -void Weapon_GrenadeLauncher(edict_t *ent) { - int fire_last = 13;//16; - static int pause_frames[] = {34, 51, 59, 0}; - static int fire_frames[] = {6, 0}; +void Weapon_GrenadeLauncher(edict_t* ent) { + const int fire_last = 13;//16; + static int pause_frames[] = { 34, 51, 59, 0 }; + static int fire_frames[] = { 6, 0 }; - Weapon_Generic(ent, 5, fire_last, 59, 64, pause_frames, fire_frames, weapon_grenadelauncher_fire); + Weapon_Generic(ent, 5, fire_last, 59, 64, pause_frames, fire_frames, weapon_grenadelauncher_fire); - // RAFAEL - if (is_quadfire) - Weapon_Generic(ent, 5, 16, 59, 64, pause_frames, fire_frames, weapon_grenadelauncher_fire); + // RAFAEL + if (is_quadfire) + Weapon_Generic(ent, 5, 16, 59, 64, pause_frames, fire_frames, weapon_grenadelauncher_fire); } /* @@ -1158,73 +1273,73 @@ ROCKET ====================================================================== */ -void fire_lockon_rocket(edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, - int radius_damage); - - -void Weapon_RocketLauncher_Fire(edict_t *ent) { - vec3_t offset, start; - vec3_t forward, right; - int damage; - float damage_radius; - int radius_damage; - - //K03 Begin - int speed = ROCKETLAUNCHER_INITIAL_SPEED + - ROCKETLAUNCHER_ADDON_SPEED * ent->myskills.weapons[WEAPON_ROCKETLAUNCHER].mods[2].current_level; - damage = ROCKETLAUNCHER_INITIAL_DAMAGE + - ROCKETLAUNCHER_ADDON_DAMAGE * ent->myskills.weapons[WEAPON_ROCKETLAUNCHER].mods[0].current_level; - radius_damage = ROCKETLAUNCHER_INITIAL_RADIUS_DAMAGE + ROCKETLAUNCHER_ADDON_RADIUS_DAMAGE * - ent->myskills.weapons[WEAPON_ROCKETLAUNCHER].mods[0].current_level; - damage_radius = ROCKETLAUNCHER_INITIAL_DAMAGE_RADIUS + ROCKETLAUNCHER_ADDON_DAMAGE_RADIUS * - ent->myskills.weapons[WEAPON_ROCKETLAUNCHER].mods[1].current_level; - //K03 End - if (is_quad) { - damage *= 4; - radius_damage *= 4; - } +void fire_lockon_rocket(edict_t* self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, + int radius_damage); + + +void Weapon_RocketLauncher_Fire(edict_t* ent) { + vec3_t offset, start; + vec3_t forward, right; + int damage; + float damage_radius; + int radius_damage; + + //K03 Begin + const int speed = ROCKETLAUNCHER_INITIAL_SPEED + + ROCKETLAUNCHER_ADDON_SPEED * ent->myskills.weapons[WEAPON_ROCKETLAUNCHER].mods[2].current_level; + damage = ROCKETLAUNCHER_INITIAL_DAMAGE + + ROCKETLAUNCHER_ADDON_DAMAGE * ent->myskills.weapons[WEAPON_ROCKETLAUNCHER].mods[0].current_level; + radius_damage = ROCKETLAUNCHER_INITIAL_RADIUS_DAMAGE + ROCKETLAUNCHER_ADDON_RADIUS_DAMAGE * + ent->myskills.weapons[WEAPON_ROCKETLAUNCHER].mods[0].current_level; + damage_radius = ROCKETLAUNCHER_INITIAL_DAMAGE_RADIUS + ROCKETLAUNCHER_ADDON_DAMAGE_RADIUS * + ent->myskills.weapons[WEAPON_ROCKETLAUNCHER].mods[1].current_level; + //K03 End + if (is_quad) { + damage *= 4; + radius_damage *= 4; + } - AngleVectors(ent->client->v_angle, forward, right, NULL); + AngleVectors(ent->client->v_angle, forward, right, NULL); - VectorScale(forward, -2, ent->client->kick_origin); - ent->client->kick_angles[0] = -1; + VectorScale(forward, -2, ent->client->kick_origin); + ent->client->kick_angles[0] = -1; - VectorSet(offset, 8, 8, ent->viewheight - 8); - P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); - //K03 Begin - //gi.dprintf("called rocketlauncher_fire at %d (%d)\n", level.framenum, ent->client->ps.gunframe); - fire_rocket(ent, start, forward, damage, speed, damage_radius, radius_damage); + VectorSet(offset, 8, 8, ent->viewheight - 8); + P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); + //K03 Begin + //gi.dprintf("called rocketlauncher_fire at %d (%d)\n", level.framenum, ent->client->ps.gunframe); + fire_rocket(ent, start, forward, damage, speed, damage_radius, radius_damage); - if (ent->myskills.weapons[WEAPON_ROCKETLAUNCHER].mods[4].current_level < 1) { - // send muzzle flash - gi.WriteByte(svc_muzzleflash); - gi.WriteShort(ent - g_edicts); - gi.WriteByte(MZ_ROCKET | is_silenced); - gi.multicast(ent->s.origin, MULTICAST_PVS); - } - //K03 End + if (ent->myskills.weapons[WEAPON_ROCKETLAUNCHER].mods[4].current_level < 1) { + // send muzzle flash + gi.WriteByte(svc_muzzleflash); + gi.WriteShort(ent - g_edicts); + gi.WriteByte(MZ_ROCKET | is_silenced); + gi.multicast(ent->s.origin, MULTICAST_PVS); + } + //K03 End - ent->client->ps.gunframe++; + ent->client->ps.gunframe++; - if (ent->myskills.weapons[WEAPON_ROCKETLAUNCHER].mods[4].current_level < 1)//K03 - PlayerNoise(ent, start, PNOISE_WEAPON); + if (ent->myskills.weapons[WEAPON_ROCKETLAUNCHER].mods[4].current_level < 1)//K03 + PlayerNoise(ent, start, PNOISE_WEAPON); - if (!((int) dmflags->value & DF_INFINITE_AMMO)) - ent->client->pers.inventory[ent->client->ammo_index]--; + if (!((int)dmflags->value & DF_INFINITE_AMMO)) + ent->client->pers.inventory[ent->client->ammo_index]--; } -void Weapon_RocketLauncher(edict_t *ent) { - static int pause_frames[] = {25, 33, 42, 50, 0}; - static int fire_frames[] = {5, 0}; +void Weapon_RocketLauncher(edict_t* ent) { + static int pause_frames[] = { 25, 33, 42, 50, 0 }; + static int fire_frames[] = { 5, 0 }; - //K03 Begin - int fire_last = 12; + //K03 Begin + const int fire_last = 12; - Weapon_Generic(ent, 4, fire_last, 50, 54, pause_frames, fire_frames, Weapon_RocketLauncher_Fire); - //K03 End - // RAFAEL - if (is_quadfire) - Weapon_Generic(ent, 4, 12, 50, 54, pause_frames, fire_frames, Weapon_RocketLauncher_Fire); + Weapon_Generic(ent, 4, fire_last, 50, 54, pause_frames, fire_frames, Weapon_RocketLauncher_Fire); + //K03 End + // RAFAEL + if (is_quadfire) + Weapon_Generic(ent, 4, 12, 50, 54, pause_frames, fire_frames, Weapon_RocketLauncher_Fire); } @@ -1237,268 +1352,278 @@ BLASTER / HYPERBLASTER ====================================================================== */ -void Blaster_Fire(edict_t *ent, vec3_t g_offset, int damage, qboolean hyperblaster, int effect, int speed) { - vec3_t forward, right; - vec3_t start; - vec3_t offset; - //K03 Begin - //trace_t tr; - //vec3_t end; - //K03 End - - //gi.dprintf("blaster_fire()\n"); - if (is_quad) - damage *= 4; - AngleVectors(ent->client->v_angle, forward, right, NULL); - VectorSet(offset, 24, 8, ent->viewheight - 8); - - if (!(ent->svflags & SVF_MONSTER)) { - VectorAdd (offset, g_offset, offset); - P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); - VectorScale(forward, -2, ent->client->kick_origin); - ent->client->kick_angles[0] = -1; - } else { - VectorSet(offset, 0, 0, ent->viewheight - 8); - VectorAdd (offset, ent->s.origin, start); - } +void Blaster_Fire(edict_t* ent, vec3_t g_offset, int damage, qboolean hyperblaster, int effect, int speed) { + vec3_t forward, right; + vec3_t start; + vec3_t offset; + //K03 Begin + //trace_t tr; + //vec3_t end; + //K03 End + + //gi.dprintf("blaster_fire()\n"); + if (is_quad) + damage *= 4; + AngleVectors(ent->client->v_angle, forward, right, NULL); + VectorSet(offset, 24, 8, ent->viewheight - 8); + + if (!(ent->svflags & SVF_MONSTER)) { + VectorAdd(offset, g_offset, offset); + P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); + VectorScale(forward, -2, ent->client->kick_origin); + ent->client->kick_angles[0] = -1; + } + else { + VectorSet(offset, 0, 0, ent->viewheight - 8); + VectorAdd(offset, ent->s.origin, start); + } - // blast mode? - if (!hyperblaster && ent->client && ent->client->weapon_mode) - fire_blaster(ent, start, forward, damage, speed, effect, BLASTER_PROJ_BLAST, MOD_BLASTER, 2.0, true); - // hyperblaster shot? - else if (hyperblaster) - fire_blaster(ent, start, forward, damage, speed, effect, BLASTER_PROJ_BOLT, MOD_HYPERBLASTER, 2.0, false); - // normal blaster shot - else - fire_blaster(ent, start, forward, damage, speed, effect, BLASTER_PROJ_BOLT, MOD_BLASTER, 2.0, true); - - if (hyperblaster && ent->myskills.weapons[WEAPON_HYPERBLASTER].mods[4].current_level < 1) { - if (ent->myskills.weapons[WEAPON_HYPERBLASTER].mods[4].current_level) - is_silenced = MZ_SILENCED; - // send muzzle flash - gi.WriteByte(svc_muzzleflash); - gi.WriteShort(ent - g_edicts); - gi.WriteByte(MZ_HYPERBLASTER | is_silenced); - gi.multicast(ent->s.origin, MULTICAST_PVS); - } else if (!hyperblaster) { - // send muzzle flash - if (ent->client && ent->client->weapon_mode) { - gi.WriteByte(svc_muzzleflash); - gi.WriteShort(ent - g_edicts); - gi.WriteByte(MZ_IONRIPPER | MZ_SILENCED); - gi.multicast(ent->s.origin, MULTICAST_PVS); - if (ent->myskills.weapons[WEAPON_BLASTER].mods[4].current_level < 1) - gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/photon.wav"), 1, ATTN_NORM, 0); - //else - //gi.sound (ent, CHAN_WEAPON, gi.soundindex("weapons/photon.wav"), 0.3, ATTN_NORM, 0); - } else { - if (ent->myskills.weapons[WEAPON_BLASTER].mods[4].current_level > 0) - is_silenced = MZ_SILENCED; - - gi.WriteByte(svc_muzzleflash); - gi.WriteShort(ent - g_edicts); - gi.WriteByte(MZ_BLASTER | is_silenced); - gi.multicast(ent->s.origin, MULTICAST_PVS); - } - } + // blast mode? + if (!hyperblaster && ent->client && ent->client->weapon_mode) + fire_blaster(ent, start, forward, damage, speed, effect, BLASTER_PROJ_BLAST, MOD_BLASTER, 2.0, true); + // hyperblaster shot? + else if (hyperblaster) + fire_blaster(ent, start, forward, damage, speed, effect, BLASTER_PROJ_BOLT, MOD_HYPERBLASTER, 2.0, false); + // normal blaster shot + else + fire_blaster(ent, start, forward, damage, speed, effect, BLASTER_PROJ_BOLT, MOD_BLASTER, 2.0, true); + + if (hyperblaster && ent->myskills.weapons[WEAPON_HYPERBLASTER].mods[4].current_level < 1) { + if (ent->myskills.weapons[WEAPON_HYPERBLASTER].mods[4].current_level) + is_silenced = MZ_SILENCED; + // send muzzle flash + gi.WriteByte(svc_muzzleflash); + gi.WriteShort(ent - g_edicts); + gi.WriteByte(MZ_HYPERBLASTER | is_silenced); + gi.multicast(ent->s.origin, MULTICAST_PVS); + } + else if (!hyperblaster) { + // send muzzle flash + if (ent->client && ent->client->weapon_mode) { + gi.WriteByte(svc_muzzleflash); + gi.WriteShort(ent - g_edicts); + gi.WriteByte(MZ_IONRIPPER | MZ_SILENCED); + gi.multicast(ent->s.origin, MULTICAST_PVS); + if (ent->myskills.weapons[WEAPON_BLASTER].mods[4].current_level < 1) + gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/photon.wav"), 1, ATTN_NORM, 0); + //else + //gi.sound (ent, CHAN_WEAPON, gi.soundindex("weapons/photon.wav"), 0.3, ATTN_NORM, 0); + } + else { + if (ent->myskills.weapons[WEAPON_BLASTER].mods[4].current_level > 0) + is_silenced = MZ_SILENCED; + + gi.WriteByte(svc_muzzleflash); + gi.WriteShort(ent - g_edicts); + gi.WriteByte(MZ_BLASTER | is_silenced); + gi.multicast(ent->s.origin, MULTICAST_PVS); + } + } - if (hyperblaster && ent->myskills.weapons[WEAPON_HYPERBLASTER].mods[4].current_level < 1) - PlayerNoise(ent, start, PNOISE_WEAPON); - else if (!hyperblaster && ent->myskills.weapons[WEAPON_BLASTER].mods[4].current_level < 1) - PlayerNoise(ent, start, PNOISE_WEAPON); - //K03 End + if (hyperblaster && ent->myskills.weapons[WEAPON_HYPERBLASTER].mods[4].current_level < 1) + PlayerNoise(ent, start, PNOISE_WEAPON); + else if (!hyperblaster && ent->myskills.weapons[WEAPON_BLASTER].mods[4].current_level < 1) + PlayerNoise(ent, start, PNOISE_WEAPON); + //K03 End } -void Weapon_Blaster_Fire(edict_t *ent) { - int min, max, damage, effect, ammo; - int speed = - BLASTER_INITIAL_SPEED + BLASTER_ADDON_SPEED * ent->myskills.weapons[WEAPON_BLASTER].mods[2].current_level; - float temp; +void Weapon_Blaster_Fire(edict_t* ent) { + int min, max, damage, effect, ammo; + const int speed = + BLASTER_INITIAL_SPEED + BLASTER_ADDON_SPEED * ent->myskills.weapons[WEAPON_BLASTER].mods[2].current_level; + float temp; - if (ent->myskills.weapons[WEAPON_BLASTER].mods[3].current_level < 1) - effect = EF_BLASTER; - else - effect = EF_HYPERBLASTER; - - min = BLASTER_INITIAL_DAMAGE_MIN + - (BLASTER_ADDON_DAMAGE_MIN * ent->myskills.weapons[WEAPON_BLASTER].mods[0].current_level); - max = BLASTER_INITIAL_DAMAGE_MAX + - (BLASTER_ADDON_DAMAGE_MAX * ent->myskills.weapons[WEAPON_BLASTER].mods[0].current_level); - damage = GetRandom(min, max); - - - if (ent->client->weapon_mode) { - temp = (float) ent->client->refire_frames / 10 * 2.0; - if (temp > 5) - temp = 5; - damage *= temp; - - // ammo - ammo = floattoint(temp); - if (ammo < 1) - ammo = 1; - } else - ammo = 1; - - // insufficient ammo - if (ent->monsterinfo.lefty < ammo) { - // play no ammo sound - if (level.time >= ent->pain_debounce_time) { - gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0); - ent->pain_debounce_time = level.time + 1; - } - - // keep weapon ready - ent->client->ps.gunframe = 10; - return; - } + if (ent->myskills.weapons[WEAPON_BLASTER].mods[3].current_level < 1) + effect = EF_BLASTER; + else + effect = EF_HYPERBLASTER; + + min = BLASTER_INITIAL_DAMAGE_MIN + + (BLASTER_ADDON_DAMAGE_MIN * ent->myskills.weapons[WEAPON_BLASTER].mods[0].current_level); + max = BLASTER_INITIAL_DAMAGE_MAX + + (BLASTER_ADDON_DAMAGE_MAX * ent->myskills.weapons[WEAPON_BLASTER].mods[0].current_level); + damage = GetRandom(min, max); - ent->monsterinfo.lefty -= ammo; // decrement ammo counter - if (ent->client->weapon_mode) - safe_cprintf(ent, PRINT_HIGH, "%d damage blaster bolt fired (%.1fx).\n", damage, temp); + if (ent->client->weapon_mode) { + temp = (float)ent->client->refire_frames / 10 * 2.0; + if (temp > 5) + temp = 5; + damage *= temp; + + // ammo + ammo = floattoint(temp); + if (ammo < 1) + ammo = 1; + } + else + ammo = 1; + + // insufficient ammo + if (ent->monsterinfo.lefty < ammo) { + // play no ammo sound + if (level.time >= ent->pain_debounce_time) { + gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0); + ent->pain_debounce_time = level.time + 1; + } + + // keep weapon ready + ent->client->ps.gunframe = 10; + return; + } + + ent->monsterinfo.lefty -= ammo; // decrement ammo counter - Blaster_Fire(ent, vec3_origin, damage, false, effect, speed); - ent->client->ps.gunframe++; - ent->client->refire_frames = 0; + if (ent->client->weapon_mode) + safe_cprintf(ent, PRINT_HIGH, "%d damage blaster bolt fired (%.1fx).\n", damage, temp); + + Blaster_Fire(ent, vec3_origin, damage, false, effect, speed); + // az FIXME: the blaster skips 2 frames at 10 fps at the first shot. it doesn't at 60. + ent->client->ps.gunframe++; + ent->client->refire_frames = 0; } -void Weapon_Blaster(edict_t *ent) { - static int pause_frames[] = {19, 32, 0}; - static int fire_frames[] = {5, 0}; -//GHz START - if (ent->mtype) - return; // morph does not use weapons - - // are we in secondary mode? - if (ent->client->weapon_mode) { - // fire when button is released - if (!(ent->client->buttons & BUTTON_ATTACK)) { - if ((ent->client->ps.gunframe > 9) && (ent->client->refire_frames >= 10)) - ent->client->buttons |= BUTTON_ATTACK; - else - ent->client->refire_frames = 0; - } else { - // charge up weapon - if (ent->client->refire_frames == 20) { - gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0); - gi.centerprintf(ent, "Blaster fully charged.\n(4.0x damage)\n"); - } - - if (ent->client->refire_frames == 10) - gi.centerprintf(ent, "Blaster 50%c charged.\n(2.0x damage)\n", '%'); - - // dont fire yet - ent->client->buttons &= ~BUTTON_ATTACK; - ent->client->latched_buttons &= ~BUTTON_ATTACK; - ent->client->refire_frames++; - } - } -//GHz END - Weapon_Generic(ent, 4, 8, 52, 55, pause_frames, fire_frames, Weapon_Blaster_Fire); - // RAFAEL - if (is_quadfire) - Weapon_Generic(ent, 4, 8, 52, 55, pause_frames, fire_frames, Weapon_Blaster_Fire); +void Weapon_Blaster(edict_t* ent) { + static int pause_frames[] = { 19, 32, 0 }; + static int fire_frames[] = { 5, 0 }; + //GHz START + if (ent->mtype) + return; // morph does not use weapons + + // are we in secondary mode? + if (ent->client->weapon_mode) { + // fire when button is released + if (!(ent->client->buttons & BUTTON_ATTACK)) { + if ((ent->client->ps.gunframe > 9) && (ent->client->refire_frames >= 10)) + ent->client->buttons |= BUTTON_ATTACK; + else + ent->client->refire_frames = 0; + } + else { + // charge up weapon + if (ent->client->refire_frames == 20) { + gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0); + gi.centerprintf(ent, "Blaster fully charged.\n(4.0x damage)\n"); + } + + if (ent->client->refire_frames == 10) + gi.centerprintf(ent, "Blaster 50%c charged.\n(2.0x damage)\n", '%'); + + // dont fire yet + ent->client->buttons &= ~BUTTON_ATTACK; + ent->client->latched_buttons &= ~BUTTON_ATTACK; + ent->client->refire_frames++; + } + } + //GHz END + Weapon_Generic(ent, 4, 8, 52, 55, pause_frames, fire_frames, Weapon_Blaster_Fire); + // RAFAEL + if (is_quadfire) + Weapon_Generic(ent, 4, 8, 52, 55, pause_frames, fire_frames, Weapon_Blaster_Fire); } -void Weapon_HyperBlaster_Fire(edict_t *ent) { - float rotation; - vec3_t offset; - int effect; - int damage; -//GHz START - int i; - int speed, shots = 0; - qboolean fire_this_frame = false; - - // only fire every other frame - //if (ent->client->ps.gunframe == 6 || ent->client->ps.gunframe == 9 - // || ent->client->ps.gunframe == 15) - //{ - fire_this_frame = true; - shots++; - //} - // get weapon properties - damage = HYPERBLASTER_INITIAL_DAMAGE + - HYPERBLASTER_ADDON_DAMAGE * ent->myskills.weapons[WEAPON_HYPERBLASTER].mods[0].current_level; - speed = HYPERBLASTER_INITIAL_SPEED + - HYPERBLASTER_ADDON_SPEED * ent->myskills.weapons[WEAPON_HYPERBLASTER].mods[2].current_level; - - if (ent->myskills.weapons[WEAPON_HYPERBLASTER].mods[4].current_level) - is_silenced = MZ_SILENCED; -//GHz END - - ent->client->weapon_sound = gi.soundindex("weapons/hyprbl1a.wav"); - - if (!(ent->client->buttons & BUTTON_ATTACK)) { - ent->client->ps.gunframe++; - } else { - //GHz START - if (ent->client->pers.inventory[ent->client->ammo_index] < shots) - shots = ent->client->pers.inventory[ent->client->ammo_index]; - - if (!shots && !ent->client->pers.inventory[ent->client->ammo_index]) - //GHz END - { - if (level.time >= ent->pain_debounce_time) { - gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0); - ent->pain_debounce_time = level.time + 1; - } - NoAmmoWeaponChange(ent); - } else { - //GHz START - for (i = 0; i < shots; i++) { - //gi.dprintf("Fired HB for %d damage at %.1f\n", damage, level.time); - - rotation = (ent->client->ps.gunframe + i - 5) * 2 * M_PI / 6; - offset[0] = -4 * sin(rotation); - offset[1] = 0; - offset[2] = 4 * cos(rotation); - - if ((ent->client->ps.gunframe == 6) || (ent->client->ps.gunframe == 9)) - effect = EF_HYPERBLASTER; - else - effect = 0; - - Blaster_Fire(ent, offset, damage, true, effect, speed); - - if (!((int) dmflags->value & DF_INFINITE_AMMO)) - ent->client->pers.inventory[ent->client->ammo_index]--; - } - //GHz END - - ent->client->anim_priority = ANIM_ATTACK; - if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) { - ent->s.frame = FRAME_crattak1 - 1; - ent->client->anim_end = FRAME_crattak9; - } else { - ent->s.frame = FRAME_attack1 - 1; - ent->client->anim_end = FRAME_attack8; - } - } - - ent->client->ps.gunframe++; - if (ent->client->ps.gunframe == 12 && ent->client->pers.inventory[ent->client->ammo_index]) - ent->client->ps.gunframe = 6; - } +void Weapon_HyperBlaster_Fire(edict_t* ent) { + float rotation; + vec3_t offset; + int effect; + int damage; + //GHz START + int i; + int speed, shots = 0; + qboolean fire_this_frame = false; + + // only fire every other frame + //if (ent->client->ps.gunframe == 6 || ent->client->ps.gunframe == 9 + // || ent->client->ps.gunframe == 15) + //{ + fire_this_frame = true; + shots++; + //} + // get weapon properties + damage = HYPERBLASTER_INITIAL_DAMAGE + + HYPERBLASTER_ADDON_DAMAGE * ent->myskills.weapons[WEAPON_HYPERBLASTER].mods[0].current_level; + speed = HYPERBLASTER_INITIAL_SPEED + + HYPERBLASTER_ADDON_SPEED * ent->myskills.weapons[WEAPON_HYPERBLASTER].mods[2].current_level; + + if (ent->myskills.weapons[WEAPON_HYPERBLASTER].mods[4].current_level) + is_silenced = MZ_SILENCED; + //GHz END + + ent->client->weapon_sound = gi.soundindex("weapons/hyprbl1a.wav"); + + if (!(ent->client->buttons & BUTTON_ATTACK)) { + ent->client->ps.gunframe++; + } + else { + //GHz START + if (ent->client->pers.inventory[ent->client->ammo_index] < shots) + shots = ent->client->pers.inventory[ent->client->ammo_index]; + + if (!shots && !ent->client->pers.inventory[ent->client->ammo_index]) + //GHz END + { + if (level.time >= ent->pain_debounce_time) { + gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0); + ent->pain_debounce_time = level.time + 1; + } + NoAmmoWeaponChange(ent); + } + else { + //GHz START + for (i = 0; i < shots; i++) { + //gi.dprintf("Fired HB for %d damage at %.1f\n", damage, level.time); + + rotation = (ent->client->ps.gunframe + i - 5) * 2 * M_PI / 6; + offset[0] = -4 * sin(rotation); + offset[1] = 0; + offset[2] = 4 * cos(rotation); + + if ((ent->client->ps.gunframe == 6) || (ent->client->ps.gunframe == 9)) + effect = EF_HYPERBLASTER; + else + effect = 0; + + Blaster_Fire(ent, offset, damage, true, effect, speed); + + if (!((int)dmflags->value & DF_INFINITE_AMMO)) + ent->client->pers.inventory[ent->client->ammo_index]--; + } + //GHz END + + ent->client->anim_priority = ANIM_ATTACK; + if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) { + ent->s.frame = FRAME_crattak1 - 1; + ent->client->anim_end = FRAME_crattak9; + } + else { + ent->s.frame = FRAME_attack1 - 1; + ent->client->anim_end = FRAME_attack8; + } + } + + ent->client->vrr.gun_fire_time = level.time + 0.1; + ent->client->ps.gunframe++; + if (ent->client->ps.gunframe == 12 && ent->client->pers.inventory[ent->client->ammo_index]) + ent->client->ps.gunframe = 6; + } - if (ent->client->ps.gunframe == 12) { - gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/hyprbd1a.wav"), 1, ATTN_NORM, 0); - ent->client->weapon_sound = 0; - } + if (ent->client->ps.gunframe == 12) { + gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/hyprbd1a.wav"), 1, ATTN_NORM, 0); + ent->client->weapon_sound = 0; + } } -void Weapon_HyperBlaster(edict_t *ent) { - static int pause_frames[] = {0}; - static int fire_frames[] = {6, 7, 8, 9, 10, 11, 0}; +void Weapon_HyperBlaster(edict_t* ent) { + static int pause_frames[] = { 0 }; + static int fire_frames[] = { 6, 7, 8, 9, 10, 11, 0 }; - Weapon_Generic(ent, 5, 20, 49, 53, pause_frames, fire_frames, Weapon_HyperBlaster_Fire); + Weapon_Generic(ent, 5, 20, 49, 53, pause_frames, fire_frames, Weapon_HyperBlaster_Fire); - // RAFAEL - if (is_quadfire) - Weapon_Generic(ent, 5, 20, 49, 53, pause_frames, fire_frames, Weapon_HyperBlaster_Fire); + // RAFAEL + if (is_quadfire) + Weapon_Generic(ent, 5, 20, 49, 53, pause_frames, fire_frames, Weapon_HyperBlaster_Fire); } /* @@ -1509,428 +1634,447 @@ MACHINEGUN / CHAINGUN ====================================================================== */ -void Machinegun_Fire(edict_t *ent) { - int i; - vec3_t start; - vec3_t forward, right; - vec3_t angles; - int kick = 2; - vec3_t offset; - float damage = MACHINEGUN_INITIAL_DAMAGE + - MACHINEGUN_ADDON_DAMAGE * ent->myskills.weapons[WEAPON_MACHINEGUN].mods[0].current_level; - int vspread = DEFAULT_BULLET_VSPREAD; - int hspread = DEFAULT_BULLET_HSPREAD; - int shots = 1; - - if (ent->myskills.weapons[WEAPON_MACHINEGUN].mods[4].current_level) - is_silenced = MZ_SILENCED; - - // bullet spread is reduced while in burst mode - if (ent->client->weapon_mode) { - vspread *= 0.5; - hspread *= 0.5; - } - // bullet spread is reduced when mg is upgraded - if (ent->myskills.weapons[WEAPON_MACHINEGUN].mods[3].current_level >= 1) { - vspread *= 0.75; - hspread *= 0.75; - } +void Machinegun_Fire(edict_t* ent) { + int i; + vec3_t start; + vec3_t forward, right; + vec3_t angles; + int kick = 2; + vec3_t offset; + float damage = MACHINEGUN_INITIAL_DAMAGE + + MACHINEGUN_ADDON_DAMAGE * ent->myskills.weapons[WEAPON_MACHINEGUN].mods[0].current_level; + int vspread = DEFAULT_BULLET_VSPREAD; + int hspread = DEFAULT_BULLET_HSPREAD; + int shots = 1; + + if (ent->myskills.weapons[WEAPON_MACHINEGUN].mods[4].current_level) + is_silenced = MZ_SILENCED; + + // bullet spread is reduced while in burst mode + if (ent->client->weapon_mode) { + vspread *= 0.5; + hspread *= 0.5; + } + // bullet spread is reduced when mg is upgraded + if (ent->myskills.weapons[WEAPON_MACHINEGUN].mods[3].current_level >= 1) { + vspread *= 0.75; + hspread *= 0.75; + } - if (!(ent->client->buttons & BUTTON_ATTACK)) { - ent->client->machinegun_shots = 0; - ent->client->ps.gunframe++; - return; - } - // keep track of burst bullets - if (ent->client->weapon_mode) - ent->client->burst_count++; + if (!(ent->client->buttons & BUTTON_ATTACK)) { + ent->client->machinegun_shots = 0; + ent->client->ps.gunframe++; + return; + } + // keep track of burst bullets + if (ent->client->weapon_mode) + ent->client->burst_count++; - if (ent->client->ps.gunframe == 5) - ent->client->ps.gunframe = 4; - else - ent->client->ps.gunframe = 5; - - if (ent->client->pers.inventory[ent->client->ammo_index] < shots) - shots = ent->client->pers.inventory[ent->client->ammo_index]; - if (!shots && !ent->client->pers.inventory[ent->client->ammo_index]) { - if (level.time >= ent->pain_debounce_time) { - gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0); - ent->pain_debounce_time = level.time + 1; - } - ent->client->burst_count = 0; - NoAmmoWeaponChange(ent); - return; - } + if (ent->client->ps.gunframe == 5) + ent->client->ps.gunframe = 4; + else + ent->client->ps.gunframe = 5; + + if (ent->client->pers.inventory[ent->client->ammo_index] < shots) + shots = ent->client->pers.inventory[ent->client->ammo_index]; + if (!shots && !ent->client->pers.inventory[ent->client->ammo_index]) { + if (level.time >= ent->pain_debounce_time) { + gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0); + ent->pain_debounce_time = level.time + 1; + } + ent->client->burst_count = 0; + NoAmmoWeaponChange(ent); + return; + } - if (is_quad) { - damage *= 4; - kick *= 4; - } + if (is_quad) { + damage *= 4; + kick *= 4; + } - for (i = 1; i < 3; i++) { - ent->client->kick_origin[i] = crandom() * 0.35; - ent->client->kick_angles[i] = crandom() * 0.7; - } - ent->client->kick_origin[0] = crandom() * 0.35; - ent->client->kick_angles[0] = ent->client->machinegun_shots * -1.5; - - // get start / end positions - VectorAdd (ent->client->v_angle, ent->client->kick_angles, angles); - AngleVectors(angles, forward, right, NULL); - VectorSet(offset, 0, 8, ent->viewheight - 8); - P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); - //K03 Begin - if (ent->client->weapon_mode) { - // shots *= 2; - damage *= 2; - } - for (i = 0; i < shots; i++) { - fire_bullet(ent, start, forward, damage, kick, hspread, vspread, MOD_MACHINEGUN); - } - // fire tracers - if (ent->lasthbshot <= level.time) { - if (ent->myskills.weapons[WEAPON_MACHINEGUN].mods[2].current_level >= 1) { - damage = MACHINEGUN_ADDON_TRACERDAMAGE * ent->myskills.weapons[WEAPON_MACHINEGUN].mods[2].current_level; - fire_blaster(ent, start, forward, damage, 2000, EF_BLUEHYPERBLASTER, BLASTER_PROJ_BOLT, MOD_HYPERBLASTER, - 2.0, false); - } - ent->lasthbshot = level.time + 0.5; - } + for (i = 1; i < 3; i++) { + ent->client->kick_origin[i] = crandom() * 0.35; + ent->client->kick_angles[i] = crandom() * 0.7; + } + ent->client->kick_origin[0] = crandom() * 0.35; + ent->client->kick_angles[0] = ent->client->machinegun_shots * -1.5; + + // get start / end positions + VectorAdd(ent->client->v_angle, ent->client->kick_angles, angles); + AngleVectors(angles, forward, right, NULL); + VectorSet(offset, 0, 8, ent->viewheight - 8); + P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); + //K03 Begin + if (ent->client->weapon_mode) { + // shots *= 2; + damage *= 2; + } + for (i = 0; i < shots; i++) { + fire_bullet(ent, start, forward, damage, kick, hspread, vspread, MOD_MACHINEGUN); + } + // fire tracers + if (ent->lasthbshot <= level.time) { + if (ent->myskills.weapons[WEAPON_MACHINEGUN].mods[2].current_level >= 1) { + damage = MACHINEGUN_ADDON_TRACERDAMAGE * ent->myskills.weapons[WEAPON_MACHINEGUN].mods[2].current_level; + fire_blaster(ent, start, forward, damage, 2000, EF_BLUEHYPERBLASTER, BLASTER_PROJ_BOLT, MOD_HYPERBLASTER, + 2.0, false); + } + ent->lasthbshot = level.time + 0.5; + } - if (is_silenced) - gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/mg_silenced.wav"), 0.5, ATTN_NORM, 0); - else - gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/mg_unsilenced.wav"), 1, ATTN_NORM, 0); + if (is_silenced) + gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/mg_silenced.wav"), 0.5, ATTN_NORM, 0); + else + gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/mg_unsilenced.wav"), 1, ATTN_NORM, 0); - if (ent->myskills.weapons[WEAPON_MACHINEGUN].mods[4].current_level < 1) { - gi.WriteByte(svc_muzzleflash); - gi.WriteShort(ent - g_edicts); - gi.WriteByte(MZ_IONRIPPER | MZ_SILENCED); - gi.multicast(ent->s.origin, MULTICAST_PVS); - } - if (ent->myskills.weapons[WEAPON_MACHINEGUN].mods[4].current_level < 1) - PlayerNoise(ent, start, PNOISE_WEAPON); - //K03 End - - if (!((int) dmflags->value & DF_INFINITE_AMMO)) - ent->client->pers.inventory[ent->client->ammo_index] -= shots; - - ent->client->anim_priority = ANIM_ATTACK; - if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) { - ent->s.frame = FRAME_crattak1 - (int) (random() + 0.25); - ent->client->anim_end = FRAME_crattak9; - } else { - ent->s.frame = FRAME_attack1 - (int) (random() + 0.25); - ent->client->anim_end = FRAME_attack8; - } - ent->client->weaponstate = WEAPON_READY; + if (ent->myskills.weapons[WEAPON_MACHINEGUN].mods[4].current_level < 1) { + gi.WriteByte(svc_muzzleflash); + gi.WriteShort(ent - g_edicts); + gi.WriteByte(MZ_IONRIPPER | MZ_SILENCED); + gi.multicast(ent->s.origin, MULTICAST_PVS); + } + if (ent->myskills.weapons[WEAPON_MACHINEGUN].mods[4].current_level < 1) + PlayerNoise(ent, start, PNOISE_WEAPON); + //K03 End + + if (!((int)dmflags->value & DF_INFINITE_AMMO)) + ent->client->pers.inventory[ent->client->ammo_index] -= shots; + + ent->client->anim_priority = ANIM_ATTACK; + if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) { + ent->s.frame = FRAME_crattak1 - (int)(random() + 0.25); + ent->client->anim_end = FRAME_crattak9; + } + else { + ent->s.frame = FRAME_attack1 - (int)(random() + 0.25); + ent->client->anim_end = FRAME_attack8; + } + ent->client->weaponstate = WEAPON_READY; + ent->client->vrr.gun_fire_time = level.time + 0.1; // wait before next firing } -void Weapon_Machinegun(edict_t *ent) { - static int pause_frames[] = {23, 45, 0}; - static int fire_frames[] = {4, 5, 0}; - - // burst fire mode fires 5 shots and then waits 0.5 seconds to fire another burst - if (ent->client->weapon_mode) { - - if (!(ent->client->buttons & BUTTON_ATTACK)) { - // reset counters if we have completed a burst or are idle - if (ent->client->burst_count > 4 || ent->client->burst_count == 0) { - ent->client->machinegun_shots = 0; - ent->client->burst_count = 0; - } else { - // continue burst if it wasn't completed - if (ent->client->burst_count < 5) { - ent->client->buttons |= BUTTON_ATTACK; - ent->client->trap_time = level.time + 1.0; - } - } - } else { - // delay between each burst - if (ent->client->trap_time > level.time) { - ent->client->burst_count = 0; - ent->client->buttons &= ~BUTTON_ATTACK; - ent->client->latched_buttons &= ~BUTTON_ATTACK; - } - // burst completed - if (ent->client->burst_count >= 4) - ent->client->trap_time = level.time + 1.0; - } - } - Weapon_Generic(ent, 3, 5, 45, 49, pause_frames, fire_frames, Machinegun_Fire); +void Weapon_Machinegun(edict_t* ent) { + static int pause_frames[] = { 23, 45, 0 }; + static int fire_frames[] = { 4, 5, 0 }; + + // burst fire mode fires 5 shots and then waits 0.5 seconds to fire another burst + if (ent->client->weapon_mode) { + + if (!(ent->client->buttons & BUTTON_ATTACK)) { + // reset counters if we have completed a burst or are idle + if (ent->client->burst_count > 4 || ent->client->burst_count == 0) { + ent->client->machinegun_shots = 0; + ent->client->burst_count = 0; + } + else { + // continue burst if it wasn't completed + if (ent->client->burst_count < 5) { + ent->client->buttons |= BUTTON_ATTACK; + ent->client->trap_time = level.time + 1.0; + } + } + } + else { + // delay between each burst + if (ent->client->trap_time > level.time) { + ent->client->burst_count = 0; + ent->client->buttons &= ~BUTTON_ATTACK; + ent->client->latched_buttons &= ~BUTTON_ATTACK; + } + // burst completed + if (ent->client->burst_count >= 4) + ent->client->trap_time = level.time + 1.0; + } + } + Weapon_Generic(ent, 3, 5, 45, 49, pause_frames, fire_frames, Machinegun_Fire); - // RAFAEL - if (is_quadfire) - Weapon_Generic(ent, 3, 5, 45, 49, pause_frames, fire_frames, Machinegun_Fire); + // RAFAEL + if (is_quadfire) + Weapon_Generic(ent, 3, 5, 45, 49, pause_frames, fire_frames, Machinegun_Fire); } -void Chaingun_Fire(edict_t *ent) { - int i; - int shots; - vec3_t start; - vec3_t forward, right, up; - float r, u; - vec3_t offset; - //int kick = 2; - - //K03 Begin - float damage = CHAINGUN_INITIAL_DAMAGE + - CHAINGUN_ADDON_DAMAGE * ent->myskills.weapons[WEAPON_CHAINGUN].mods[0].current_level; - - int vspread = DEFAULT_BULLET_VSPREAD; - int hspread = DEFAULT_BULLET_HSPREAD; - - if (ent->myskills.weapons[WEAPON_CHAINGUN].mods[3].current_level >= 1) { - vspread *= 0.75; - hspread *= 0.75; - } - //K03 End +void Chaingun_Fire(edict_t* ent) { + int i; + int shots; + vec3_t start; + vec3_t forward, right, up; + float r, u; + vec3_t offset; + //int kick = 2; + + //K03 Begin + float damage = CHAINGUN_INITIAL_DAMAGE + + CHAINGUN_ADDON_DAMAGE * ent->myskills.weapons[WEAPON_CHAINGUN].mods[0].current_level; + + int vspread = DEFAULT_BULLET_VSPREAD; + int hspread = DEFAULT_BULLET_HSPREAD; + + if (ent->myskills.weapons[WEAPON_CHAINGUN].mods[3].current_level >= 1) { + vspread *= 0.75; + hspread *= 0.75; + } + //K03 End - if (ent->client->ps.gunframe == 5) - gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnu1a.wav"), 1, ATTN_IDLE, 0); + if (ent->client->ps.gunframe == 5) + gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnu1a.wav"), 1, ATTN_IDLE, 0); - if ((ent->client->ps.gunframe == 14) && !(ent->client->buttons & BUTTON_ATTACK)) { - ent->client->ps.gunframe = 32; - ent->client->weapon_sound = 0; - ent->client->weaponstate = WEAPON_READY; - return; - } else if ((ent->client->ps.gunframe == 21) && (ent->client->buttons & BUTTON_ATTACK) - && ent->client->pers.inventory[ent->client->ammo_index]) { - ent->client->ps.gunframe = 15; - } else { - if (ent->client->ps.gunframe < 64)//K03 - ent->client->ps.gunframe++; - } + if ((ent->client->ps.gunframe == 14) && !(ent->client->buttons & BUTTON_ATTACK)) { + ent->client->ps.gunframe = 32; + ent->client->weapon_sound = 0; + ent->client->weaponstate = WEAPON_READY; + return; + } + else if ((ent->client->ps.gunframe == 21) && (ent->client->buttons & BUTTON_ATTACK) + && ent->client->pers.inventory[ent->client->ammo_index]) { + ent->client->ps.gunframe = 15; + } + else { + if (ent->client->ps.gunframe < 64)//K03 + ent->client->ps.gunframe++; + } - if (ent->client->ps.gunframe == 22) { - ent->client->weapon_sound = 0; - gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnd1a.wav"), 1, ATTN_IDLE, 0); - } else { - ent->client->weapon_sound = gi.soundindex("weapons/chngnl1a.wav"); - } + if (ent->client->ps.gunframe == 22) { + ent->client->weapon_sound = 0; + gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnd1a.wav"), 1, ATTN_IDLE, 0); + } + else { + ent->client->weapon_sound = gi.soundindex("weapons/chngnl1a.wav"); + } - if (ent->client->ps.gunframe <= 9) - shots = 2; - else if (ent->client->ps.gunframe <= 14) { - if (ent->client->buttons & BUTTON_ATTACK) - shots = 3; - else - shots = 2; - } else - shots = 4; - - if (ent->client->pers.inventory[ent->client->ammo_index] < shots) - shots = ent->client->pers.inventory[ent->client->ammo_index]; - - if (!shots) { - if (level.time >= ent->pain_debounce_time) { - gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0); - ent->pain_debounce_time = level.time + 1; - } - NoAmmoWeaponChange(ent); - return; - } + if (ent->client->ps.gunframe <= 9) + shots = 2; + else if (ent->client->ps.gunframe <= 14) { + if (ent->client->buttons & BUTTON_ATTACK) + shots = 3; + else + shots = 2; + } + else + shots = 4; + + if (ent->client->pers.inventory[ent->client->ammo_index] < shots) + shots = ent->client->pers.inventory[ent->client->ammo_index]; + + if (!shots) { + if (level.time >= ent->pain_debounce_time) { + gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0); + ent->pain_debounce_time = level.time + 1; + } + NoAmmoWeaponChange(ent); + return; + } - if (is_quad) - damage *= 4; + if (is_quad) + damage *= 4; - for (i = 0; i < 3; i++) { - ent->client->kick_origin[i] = crandom() * 0.35; - ent->client->kick_angles[i] = crandom() * 0.7; - } + for (i = 0; i < 3; i++) { + ent->client->kick_origin[i] = crandom() * 0.35; + ent->client->kick_angles[i] = crandom() * 0.7; + } - for (i = 0; i < shots; i++) { - // get start / end positions - AngleVectors(ent->client->v_angle, forward, right, up); - r = 7 + crandom() * 4; - u = crandom() * 4; - VectorSet(offset, 0, r, u + ent->viewheight - 8); - P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); + for (i = 0; i < shots; i++) { + // get start / end positions + AngleVectors(ent->client->v_angle, forward, right, up); + r = 7 + crandom() * 4; + u = crandom() * 4; + VectorSet(offset, 0, r, u + ent->viewheight - 8); + P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); - fire_bullet(ent, start, forward, damage, 5, hspread, vspread, MOD_CHAINGUN); - } + fire_bullet(ent, start, forward, damage, 5, hspread, vspread, MOD_CHAINGUN); + } - //K03 begin - if (ent->myskills.weapons[WEAPON_CHAINGUN].mods[2].current_level >= 1) - if (ent->lasthbshot <= level.time) { - damage = CHAINGUN_ADDON_TRACERDAMAGE * ent->myskills.weapons[WEAPON_CHAINGUN].mods[2].current_level; - fire_blaster(ent, start, forward, damage, 2000, EF_BLUEHYPERBLASTER, BLASTER_PROJ_BOLT, MOD_HYPERBLASTER, - 2.0, false); - ent->lasthbshot = level.time + 0.5; - } - if (ent->myskills.weapons[WEAPON_CHAINGUN].mods[4].current_level < 1) { - // send muzzle flash - gi.WriteByte(svc_muzzleflash); - gi.WriteShort(ent - g_edicts); - gi.WriteByte((MZ_CHAINGUN1 + shots - 1) | is_silenced); - gi.multicast(ent->s.origin, MULTICAST_PVS); - } - if (ent->myskills.weapons[WEAPON_CHAINGUN].mods[4].current_level < 1) - PlayerNoise(ent, start, PNOISE_WEAPON); - //K03 End - - // ### Hentai ### BEGIN - - ent->client->anim_priority = ANIM_ATTACK; - if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) { - ent->s.frame = FRAME_crattak1 - 1 + (ent->client->ps.gunframe % 3); - ent->client->anim_end = FRAME_crattak9; - } else { - ent->s.frame = FRAME_attack1 - 1 + (ent->client->ps.gunframe % 3); - ent->client->anim_end = FRAME_attack8; - } + ent->client->vrr.gun_fire_time = level.time + 0.1; + + //K03 begin + if (ent->myskills.weapons[WEAPON_CHAINGUN].mods[2].current_level >= 1) + if (ent->lasthbshot <= level.time) { + damage = CHAINGUN_ADDON_TRACERDAMAGE * ent->myskills.weapons[WEAPON_CHAINGUN].mods[2].current_level; + fire_blaster(ent, start, forward, damage, 2000, EF_BLUEHYPERBLASTER, BLASTER_PROJ_BOLT, MOD_HYPERBLASTER, + 2.0, false); + ent->lasthbshot = level.time + 0.5; + } + if (ent->myskills.weapons[WEAPON_CHAINGUN].mods[4].current_level < 1) { + // send muzzle flash + gi.WriteByte(svc_muzzleflash); + gi.WriteShort(ent - g_edicts); + gi.WriteByte((MZ_CHAINGUN1 + shots - 1) | is_silenced); + gi.multicast(ent->s.origin, MULTICAST_PVS); + } + if (ent->myskills.weapons[WEAPON_CHAINGUN].mods[4].current_level < 1) + PlayerNoise(ent, start, PNOISE_WEAPON); + //K03 End + + // ### Hentai ### BEGIN + ent->client->anim_priority = ANIM_ATTACK; + if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) { + ent->s.frame = FRAME_crattak1 - 1 + (ent->client->ps.gunframe % 3); + ent->client->anim_end = FRAME_crattak9; + } + else { + ent->s.frame = FRAME_attack1 - 1 + (ent->client->ps.gunframe % 3); + ent->client->anim_end = FRAME_attack8; + } - // ### Hentai ### END - if (!((int) dmflags->value & DF_INFINITE_AMMO)) - ent->client->pers.inventory[ent->client->ammo_index] -= shots; + // ### Hentai ### END + + if (!((int)dmflags->value & DF_INFINITE_AMMO)) + ent->client->pers.inventory[ent->client->ammo_index] -= shots; } -void AssaultCannon_Fire(edict_t *ent) { - int shots, i; - int damage, kick, vspread, hspread; - float f, r, u; - qboolean canfire = false; - vec3_t forward, right, start, up, offset; - - damage = kick = 2 * (CHAINGUN_INITIAL_DAMAGE + - CHAINGUN_ADDON_DAMAGE * ent->myskills.weapons[WEAPON_CHAINGUN].mods[0].current_level); - vspread = DEFAULT_BULLET_VSPREAD; - hspread = DEFAULT_BULLET_HSPREAD; - - if (is_quad) { - damage *= 4; - kick *= 4; - } +void AssaultCannon_Fire(edict_t* ent) { + int shots, i; + int damage, kick, vspread, hspread; + float f, r, u; + qboolean canfire = false; + vec3_t forward, right, start, up, offset; + + damage = kick = 2 * (CHAINGUN_INITIAL_DAMAGE + + CHAINGUN_ADDON_DAMAGE * ent->myskills.weapons[WEAPON_CHAINGUN].mods[0].current_level); + vspread = DEFAULT_BULLET_VSPREAD; + hspread = DEFAULT_BULLET_HSPREAD; + + if (is_quad) { + damage *= 4; + kick *= 4; + } - if (ent->myskills.weapons[WEAPON_CHAINGUN].mods[3].current_level > 0) { - vspread *= 0.75; - hspread *= 0.75; - } + if (ent->myskills.weapons[WEAPON_CHAINGUN].mods[3].current_level > 0) { + vspread *= 0.75; + hspread *= 0.75; + } - if (ent->myskills.weapons[WEAPON_CHAINGUN].mods[4].current_level > 0) - f = 0.3; - else - f = 1; + if (ent->myskills.weapons[WEAPON_CHAINGUN].mods[4].current_level > 0) + f = 0.3; + else + f = 1; - if (ent->client->ps.gunframe <= 14) { - // beginning animation, so play spin-up sound - if (ent->client->ps.gunframe == 5) - gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/asscan_spinup.wav"), f, ATTN_NORM, 0); - ent->client->ps.gunframe++; // we're done, so advance to next frame - return; - } else if ((ent->client->ps.gunframe == 15) && !(ent->client->buttons & BUTTON_ATTACK)) { - ent->client->ps.gunframe = 32; - ent->client->weapon_sound = 0; - ent->client->weaponstate = WEAPON_READY; - return; - } - // attack frames loop - else if ((ent->client->ps.gunframe == 21) && (ent->client->buttons & BUTTON_ATTACK) - && ent->client->pers.inventory[ent->client->ammo_index]) { - ent->client->ps.gunframe = 15; // go to beginning of fire frames - } else { - ent->client->ps.gunframe++; - } + if (ent->client->ps.gunframe <= 14) { + // beginning animation, so play spin-up sound + if (ent->client->ps.gunframe == 5) + gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/asscan_spinup.wav"), f, ATTN_NORM, 0); - if (ent->groundentity && (VectorLength(ent->velocity) < 1)) - canfire = true; + ent->client->ps.gunframe++; // we're done, so advance to next frame + ent->client->vrr.gun_fire_time = level.time + 0.1; + return; + } + else if ((ent->client->ps.gunframe == 15) && !(ent->client->buttons & BUTTON_ATTACK)) { + ent->client->ps.gunframe = 32; + ent->client->weapon_sound = 0; + ent->client->weaponstate = WEAPON_READY; + ent->client->vrr.gun_fire_time = level.time + 0.1; + return; + } + // attack frames loop + else if ((ent->client->ps.gunframe == 21) && (ent->client->buttons & BUTTON_ATTACK) + && ent->client->pers.inventory[ent->client->ammo_index]) { + ent->client->ps.gunframe = 15; // go to beginning of fire frames + } + else { + ent->client->ps.gunframe++; + } - if (ent->client->ps.gunframe == 22) - gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/asscan_endfire.wav"), f, ATTN_NORM, 0); - else if (!(sf2qf(level.framenum) % 2)) { - if (canfire) - gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/asscan_fire.wav"), f, ATTN_NORM, 0); - else - gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/asscan_pause.wav"), f, ATTN_NORM, 0); - } + ent->client->vrr.gun_fire_time = level.time + 0.1; - if (!canfire) - return; + if (ent->groundentity && (VectorLength(ent->velocity) < 1)) + canfire = true; - shots = 4; + if (ent->client->ps.gunframe == 22) + gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/asscan_endfire.wav"), f, ATTN_NORM, 0); + else if (!(sf2qf(level.framenum) % 2)) { + if (canfire) + gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/asscan_fire.wav"), f, ATTN_NORM, 0); + else + gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/asscan_pause.wav"), f, ATTN_NORM, 0); + } - // if we don't have enough ammo, use whatever we have - if (ent->client->pers.inventory[ent->client->ammo_index] < shots) - shots = ent->client->pers.inventory[ent->client->ammo_index]; - // out of ammo - if (!shots) { - if (level.time >= ent->pain_debounce_time) { - gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0); - ent->pain_debounce_time = level.time + 1; - } - NoAmmoWeaponChange(ent); - return; - } + if (!canfire) + return; - // change player view - for (i = 0; i < 3; i++) { - ent->client->kick_origin[i] = crandom() * 1.5; - ent->client->kick_angles[i] = crandom() * 3; - } + shots = 4; - if (ent->myskills.weapons[WEAPON_CHAINGUN].mods[4].current_level < 1) { - // send muzzle flash - gi.WriteByte(svc_muzzleflash); - gi.WriteShort(ent - g_edicts); - gi.WriteByte(MZ_IONRIPPER | MZ_SILENCED); - gi.multicast(ent->s.origin, MULTICAST_PVS); - } - PlayerNoise(ent, ent->s.origin, PNOISE_WEAPON); + // if we don't have enough ammo, use whatever we have + if (ent->client->pers.inventory[ent->client->ammo_index] < shots) + shots = ent->client->pers.inventory[ent->client->ammo_index]; - for (i = 0; i < shots; i++) { - // get start / end positions - AngleVectors(ent->client->v_angle, forward, right, up); - r = 7 + crandom() * 4; - u = crandom() * 4; - VectorSet(offset, 0, r, u + ent->viewheight - 8); - P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); + // out of ammo + if (!shots) { + if (level.time >= ent->pain_debounce_time) { + gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0); + ent->pain_debounce_time = level.time + 1; + } + NoAmmoWeaponChange(ent); + return; + } - fire_bullet(ent, start, forward, damage, kick, hspread, vspread, MOD_CHAINGUN); - } + // change player view + for (i = 0; i < 3; i++) { + ent->client->kick_origin[i] = crandom() * 1.5; + ent->client->kick_angles[i] = crandom() * 3; + } - if ((ent->myskills.weapons[WEAPON_CHAINGUN].mods[2].current_level > 0) && (level.time >= ent->lasthbshot)) { - damage = CHAINGUN_ADDON_TRACERDAMAGE * ent->myskills.weapons[WEAPON_CHAINGUN].mods[2].current_level; - fire_blaster(ent, start, forward, damage, 2000, 0, BLASTER_PROJ_BOLT, MOD_HYPERBLASTER, 2.0, false); - ent->lasthbshot = level.time + 0.3; - } + if (ent->myskills.weapons[WEAPON_CHAINGUN].mods[4].current_level < 1) { + // send muzzle flash + gi.WriteByte(svc_muzzleflash); + gi.WriteShort(ent - g_edicts); + gi.WriteByte(MZ_IONRIPPER | MZ_SILENCED); + gi.multicast(ent->s.origin, MULTICAST_PVS); + } + PlayerNoise(ent, ent->s.origin, PNOISE_WEAPON); + + for (i = 0; i < shots; i++) { + // get start / end positions + AngleVectors(ent->client->v_angle, forward, right, up); + r = 7 + crandom() * 4; + u = crandom() * 4; + VectorSet(offset, 0, r, u + ent->viewheight - 8); + P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); + + fire_bullet(ent, start, forward, damage, kick, hspread, vspread, MOD_CHAINGUN); + } + + if ((ent->myskills.weapons[WEAPON_CHAINGUN].mods[2].current_level > 0) && (level.time >= ent->lasthbshot)) { + damage = CHAINGUN_ADDON_TRACERDAMAGE * ent->myskills.weapons[WEAPON_CHAINGUN].mods[2].current_level; + fire_blaster(ent, start, forward, damage, 2000, 0, BLASTER_PROJ_BOLT, MOD_HYPERBLASTER, 2.0, false); + ent->lasthbshot = level.time + 0.3; + } - if (!((int) dmflags->value & DF_INFINITE_AMMO)) - ent->client->pers.inventory[ent->client->ammo_index] -= shots; + if (!((int)dmflags->value & DF_INFINITE_AMMO)) + ent->client->pers.inventory[ent->client->ammo_index] -= shots; } -void Weapon_Chaingun(edict_t *ent) { - static int pause_frames[] = {38, 43, 51, 61, 0}; - static int fire_frames[] = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0}; - - - //K03 Begin - int fire_last = 31; - - // spin-up delay - if (ent->myskills.weapons[WEAPON_CHAINGUN].mods[1].current_level > 0) { - if (ent->myskills.weapons[WEAPON_CHAINGUN].mods[1].current_level > 9) - fire_last = 21; - else if (ent->myskills.weapons[WEAPON_CHAINGUN].mods[1].current_level > 7) - fire_last = 23; - else if (ent->myskills.weapons[WEAPON_CHAINGUN].mods[1].current_level > 5) - fire_last = 25; - else if (ent->myskills.weapons[WEAPON_CHAINGUN].mods[1].current_level > 2) - fire_last = 27; - else fire_last = 29; - } +void Weapon_Chaingun(edict_t* ent) { + static int pause_frames[] = { 38, 43, 51, 61, 0 }; + static int fire_frames[] = { 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0 }; + + + //K03 Begin + int fire_last = 31; + + // spin-up delay + if (ent->myskills.weapons[WEAPON_CHAINGUN].mods[1].current_level > 0) { + if (ent->myskills.weapons[WEAPON_CHAINGUN].mods[1].current_level > 9) + fire_last = 21; + else if (ent->myskills.weapons[WEAPON_CHAINGUN].mods[1].current_level > 7) + fire_last = 23; + else if (ent->myskills.weapons[WEAPON_CHAINGUN].mods[1].current_level > 5) + fire_last = 25; + else if (ent->myskills.weapons[WEAPON_CHAINGUN].mods[1].current_level > 2) + fire_last = 27; + else fire_last = 29; + } - if (ent->client->weapon_mode) - Weapon_Generic(ent, 4, fire_last, 61, 64, pause_frames, fire_frames, AssaultCannon_Fire); - else - Weapon_Generic(ent, 4, fire_last, 61, 64, pause_frames, fire_frames, Chaingun_Fire); - //K03 End + if (ent->client->weapon_mode) + Weapon_Generic(ent, 4, fire_last, 61, 64, pause_frames, fire_frames, AssaultCannon_Fire); + else + Weapon_Generic(ent, 4, fire_last, 61, 64, pause_frames, fire_frames, Chaingun_Fire); + //K03 End - // RAFAEL - if (is_quadfire) - Weapon_Generic(ent, 4, 31, 61, 64, pause_frames, fire_frames, Chaingun_Fire); + // RAFAEL + if (is_quadfire) + Weapon_Generic(ent, 4, 31, 61, 64, pause_frames, fire_frames, Chaingun_Fire); } @@ -1944,186 +2088,186 @@ SHOTGUN / SUPERSHOTGUN ====================================================================== */ -void weapon_shotgun_fire(edict_t *ent) { - vec3_t start; - vec3_t forward, right; - vec3_t offset; - int kick = 8; - float temp; - - //K03 Begin - float damage = - SHOTGUN_INITIAL_DAMAGE + SHOTGUN_ADDON_DAMAGE * ent->myskills.weapons[WEAPON_SHOTGUN].mods[0].current_level; - int vspread = 500; - int hspread = 500; - int bullets = SHOTGUN_INITIAL_BULLETS + - SHOTGUN_ADDON_BULLETS * ent->myskills.weapons[WEAPON_SHOTGUN].mods[2].current_level; - if (ent->myskills.weapons[WEAPON_SHOTGUN].mods[3].current_level >= 1) { - vspread *= 0.75; - hspread *= 0.75; - } +void weapon_shotgun_fire(edict_t* ent) { + vec3_t start; + vec3_t forward, right; + vec3_t offset; + int kick = 8; + float temp; + + //K03 Begin + float damage = + SHOTGUN_INITIAL_DAMAGE + SHOTGUN_ADDON_DAMAGE * ent->myskills.weapons[WEAPON_SHOTGUN].mods[0].current_level; + int vspread = 500; + int hspread = 500; + const int bullets = SHOTGUN_INITIAL_BULLETS + + SHOTGUN_ADDON_BULLETS * ent->myskills.weapons[WEAPON_SHOTGUN].mods[2].current_level; + if (ent->myskills.weapons[WEAPON_SHOTGUN].mods[3].current_level >= 1) { + vspread *= 0.75; + hspread *= 0.75; + } - //K03 End + //K03 End - if (ent->client->ps.gunframe == 9) { - ent->client->ps.gunframe++; - return; - } + if (ent->client->ps.gunframe == 9) { + ent->client->ps.gunframe++; + return; + } - //gi.dprintf("fired shotgun at %d\n", level.framenum); + //gi.dprintf("fired shotgun at %d\n", level.framenum); - AngleVectors(ent->client->v_angle, forward, right, NULL); + AngleVectors(ent->client->v_angle, forward, right, NULL); - VectorScale(forward, -2, ent->client->kick_origin); - ent->client->kick_angles[0] = -2; + VectorScale(forward, -2, ent->client->kick_origin); + ent->client->kick_angles[0] = -2; - VectorSet(offset, 0, 8, ent->viewheight - 8); - P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); + VectorSet(offset, 0, 8, ent->viewheight - 8); + P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); - if (is_quad) { - damage *= 4; - kick *= 4; - } + if (is_quad) { + damage *= 4; + kick *= 4; + } - // shotgun strike upgrade - // 20% chance to deal double damage at level 10 - temp = 1.0 / (1.0 + 0.025 * ent->myskills.weapons[WEAPON_SHOTGUN].mods[1].current_level); + // shotgun strike upgrade + // 20% chance to deal double damage at level 10 + temp = 1.0 / (1.0 + 0.025 * ent->myskills.weapons[WEAPON_SHOTGUN].mods[1].current_level); - if (random() > temp) { - damage *= 1.5; - gi.sound(ent, CHAN_WEAPON, gi.soundindex("ctf/tech2.wav"), 1, ATTN_NORM, 0); - } + if (random() > temp) { + damage *= 1.5; + gi.sound(ent, CHAN_WEAPON, gi.soundindex("ctf/tech2.wav"), 1, ATTN_NORM, 0); + } - fire_shotgun(ent, start, forward, damage, kick, vspread, hspread, bullets, MOD_SHOTGUN); - // send muzzle flash - if (ent->myskills.weapons[WEAPON_SHOTGUN].mods[4].current_level < 1) { - gi.WriteByte(svc_muzzleflash); - gi.WriteShort(ent - g_edicts); - gi.WriteByte(MZ_SHOTGUN | is_silenced); - gi.multicast(ent->s.origin, MULTICAST_PVS); - } - //K03 End + fire_shotgun(ent, start, forward, damage, kick, vspread, hspread, bullets, MOD_SHOTGUN); + // send muzzle flash + if (ent->myskills.weapons[WEAPON_SHOTGUN].mods[4].current_level < 1) { + gi.WriteByte(svc_muzzleflash); + gi.WriteShort(ent - g_edicts); + gi.WriteByte(MZ_SHOTGUN | is_silenced); + gi.multicast(ent->s.origin, MULTICAST_PVS); + } + //K03 End - ent->client->ps.gunframe++; - //K03 Begin - if (ent->myskills.weapons[WEAPON_SHOTGUN].mods[4].current_level < 1) - PlayerNoise(ent, start, PNOISE_WEAPON); - //K03 End + ent->client->ps.gunframe++; + //K03 Begin + if (ent->myskills.weapons[WEAPON_SHOTGUN].mods[4].current_level < 1) + PlayerNoise(ent, start, PNOISE_WEAPON); + //K03 End - if (!((int) dmflags->value & DF_INFINITE_AMMO)) - ent->client->pers.inventory[ent->client->ammo_index]--; + if (!((int)dmflags->value & DF_INFINITE_AMMO)) + ent->client->pers.inventory[ent->client->ammo_index]--; } -void Weapon_Shotgun(edict_t *ent) { - static int pause_frames[] = {22, 28, 34, 0}; - static int fire_frames[] = {8, 9, 0}; +void Weapon_Shotgun(edict_t* ent) { + static int pause_frames[] = { 22, 28, 34, 0 }; + static int fire_frames[] = { 8, 9, 0 }; - //K03 Begin - int fire_last = 16; - /* - if (ent->myskills.weapons[WEAPON_SHOTGUN].mods[1].current_level > 0) - { - if (ent->myskills.weapons[WEAPON_SHOTGUN].mods[1].current_level > 9) - fire_last = 14; - else if (ent->myskills.weapons[WEAPON_SHOTGUN].mods[1].current_level > 6) - fire_last = 15; - else if (ent->myskills.weapons[WEAPON_SHOTGUN].mods[1].current_level > 3) - fire_last = 16; - else fire_last = 17; - }*/ - - Weapon_Generic(ent, 7, fire_last, 36, 39, pause_frames, fire_frames, weapon_shotgun_fire); - //K03 End - - // RAFAEL - if (is_quadfire) - Weapon_Generic(ent, 7, 18, 36, 39, pause_frames, fire_frames, weapon_shotgun_fire); -} + //K03 Begin + const int fire_last = 16; + /* + if (ent->myskills.weapons[WEAPON_SHOTGUN].mods[1].current_level > 0) + { + if (ent->myskills.weapons[WEAPON_SHOTGUN].mods[1].current_level > 9) + fire_last = 14; + else if (ent->myskills.weapons[WEAPON_SHOTGUN].mods[1].current_level > 6) + fire_last = 15; + else if (ent->myskills.weapons[WEAPON_SHOTGUN].mods[1].current_level > 3) + fire_last = 16; + else fire_last = 17; + }*/ + Weapon_Generic(ent, 7, fire_last, 36, 39, pause_frames, fire_frames, weapon_shotgun_fire); + //K03 End + + // RAFAEL + if (is_quadfire) + Weapon_Generic(ent, 7, 18, 36, 39, pause_frames, fire_frames, weapon_shotgun_fire); +} -void weapon_supershotgun_fire(edict_t *ent) { - vec3_t start; - vec3_t forward, right; - vec3_t offset; - vec3_t v; - int kick = 12; - //K03 Begin - float damage = SUPERSHOTGUN_INITIAL_DAMAGE + - SUPERSHOTGUN_ADDON_DAMAGE * ent->myskills.weapons[WEAPON_SUPERSHOTGUN].mods[0].current_level; - int vspread = DEFAULT_SHOTGUN_VSPREAD; - int hspread = DEFAULT_SHOTGUN_HSPREAD; - int bullets = SUPERSHOTGUN_INITIAL_BULLETS + - SUPERSHOTGUN_ADDON_BULLETS * ent->myskills.weapons[WEAPON_SUPERSHOTGUN].mods[2].current_level; -// float temp; - - if (ent->myskills.weapons[WEAPON_SUPERSHOTGUN].mods[3].current_level >= 1) { - vspread *= 0.75; - hspread *= 0.75; - } - //K03 End +void weapon_supershotgun_fire(edict_t* ent) { + vec3_t start; + vec3_t forward, right; + vec3_t offset; + vec3_t v; + int kick = 12; + //K03 Begin + float damage = SUPERSHOTGUN_INITIAL_DAMAGE + + SUPERSHOTGUN_ADDON_DAMAGE * ent->myskills.weapons[WEAPON_SUPERSHOTGUN].mods[0].current_level; + int vspread = DEFAULT_SHOTGUN_VSPREAD; + int hspread = DEFAULT_SHOTGUN_HSPREAD; + int bullets = SUPERSHOTGUN_INITIAL_BULLETS + + SUPERSHOTGUN_ADDON_BULLETS * ent->myskills.weapons[WEAPON_SUPERSHOTGUN].mods[2].current_level; + // float temp; + + if (ent->myskills.weapons[WEAPON_SUPERSHOTGUN].mods[3].current_level >= 1) { + vspread *= 0.75; + hspread *= 0.75; + } - AngleVectors(ent->client->v_angle, forward, right, NULL); + //K03 End - VectorScale(forward, -2, ent->client->kick_origin); - ent->client->kick_angles[0] = -2; + AngleVectors(ent->client->v_angle, forward, right, NULL); - VectorSet(offset, 0, 8, ent->viewheight - 8); - P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); + VectorScale(forward, -2, ent->client->kick_origin); + ent->client->kick_angles[0] = -2; - if (is_quad) { - damage *= 4; - kick *= 4; - } + VectorSet(offset, 0, 8, ent->viewheight - 8); + P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); - v[PITCH] = ent->client->v_angle[PITCH]; - v[YAW] = ent->client->v_angle[YAW] - 5; - v[ROLL] = ent->client->v_angle[ROLL]; - AngleVectors(v, forward, NULL, NULL); - /* - // special handling of pellet weapons with ghost - temp = 0.033 * ent->myskills.ghost_level; - if (temp >= random()) - damage = 0; - */ + if (is_quad) { + damage *= 4; + kick *= 4; + } - bullets = ceil((float) bullets / 2); -// gi.dprintf("%d dmg %d bullets\n", damage, bullets); - fire_shotgun(ent, start, forward, damage, kick, hspread, vspread, bullets, MOD_SSHOTGUN);//K03 - v[YAW] = ent->client->v_angle[YAW] + 5; - AngleVectors(v, forward, NULL, NULL); - fire_shotgun(ent, start, forward, damage, kick, hspread, vspread, bullets, MOD_SSHOTGUN);//K03 - - //K03 Begin - if (ent->myskills.weapons[WEAPON_SUPERSHOTGUN].mods[4].current_level < 1) { - // send muzzle flash - gi.WriteByte(svc_muzzleflash); - gi.WriteShort(ent - g_edicts); - gi.WriteByte(MZ_SSHOTGUN | is_silenced); - gi.multicast(ent->s.origin, MULTICAST_PVS); - } - //K03 End + v[PITCH] = ent->client->v_angle[PITCH]; + v[YAW] = ent->client->v_angle[YAW] - 5; + v[ROLL] = ent->client->v_angle[ROLL]; + AngleVectors(v, forward, NULL, NULL); + /* + // special handling of pellet weapons with ghost + temp = 0.033 * ent->myskills.ghost_level; + if (temp >= random()) + damage = 0; + */ + + bullets = ceil((float)bullets / 2); + // gi.dprintf("%d dmg %d bullets\n", damage, bullets); + fire_shotgun(ent, start, forward, damage, kick, hspread, vspread, bullets, MOD_SSHOTGUN);//K03 + v[YAW] = ent->client->v_angle[YAW] + 5; + AngleVectors(v, forward, NULL, NULL); + fire_shotgun(ent, start, forward, damage, kick, hspread, vspread, bullets, MOD_SSHOTGUN);//K03 + + //K03 Begin + if (ent->myskills.weapons[WEAPON_SUPERSHOTGUN].mods[4].current_level < 1) { + // send muzzle flash + gi.WriteByte(svc_muzzleflash); + gi.WriteShort(ent - g_edicts); + gi.WriteByte(MZ_SSHOTGUN | is_silenced); + gi.multicast(ent->s.origin, MULTICAST_PVS); + } + //K03 End - ent->client->ps.gunframe++; - //K03 Begin - if (ent->myskills.weapons[WEAPON_SUPERSHOTGUN].mods[4].current_level < 1) - PlayerNoise(ent, start, PNOISE_WEAPON); - //K03 End + ent->client->ps.gunframe++; + //K03 Begin + if (ent->myskills.weapons[WEAPON_SUPERSHOTGUN].mods[4].current_level < 1) + PlayerNoise(ent, start, PNOISE_WEAPON); + //K03 End - if (!((int) dmflags->value & DF_INFINITE_AMMO)) - ent->client->pers.inventory[ent->client->ammo_index] -= 2; + if (!((int)dmflags->value & DF_INFINITE_AMMO)) + ent->client->pers.inventory[ent->client->ammo_index] -= 2; } -void Weapon_SuperShotgun(edict_t *ent) { - static int pause_frames[] = {29, 42, 57, 0}; - static int fire_frames[] = {7, 0}; +void Weapon_SuperShotgun(edict_t* ent) { + static int pause_frames[] = { 29, 42, 57, 0 }; + static int fire_frames[] = { 7, 0 }; - Weapon_Generic(ent, 6, 17, 57, 61, pause_frames, fire_frames, weapon_supershotgun_fire); - //K03 End + Weapon_Generic(ent, 6, 17, 57, 61, pause_frames, fire_frames, weapon_supershotgun_fire); + //K03 End - // RAFAEL - if (is_quadfire) - Weapon_Generic(ent, 6, 17, 57, 61, pause_frames, fire_frames, weapon_supershotgun_fire); + // RAFAEL + if (is_quadfire) + Weapon_Generic(ent, 6, 17, 57, 61, pause_frames, fire_frames, weapon_supershotgun_fire); } @@ -2134,172 +2278,174 @@ RAILGUN ====================================================================== */ -void weapon_railgun_fire(edict_t *ent) { - vec3_t start; - vec3_t forward, right; - vec3_t offset; - int kick = 200; - - //K03 Begin - int damage = - RAILGUN_INITIAL_DAMAGE + RAILGUN_ADDON_DAMAGE * ent->myskills.weapons[WEAPON_RAILGUN].mods[0].current_level; - //K03 End - - if (is_quad) { - damage *= 4; - kick *= 4; - } +void weapon_railgun_fire(edict_t* ent) { + vec3_t start; + vec3_t forward, right; + vec3_t offset; + int kick = 200; + + //K03 Begin + int damage = + RAILGUN_INITIAL_DAMAGE + RAILGUN_ADDON_DAMAGE * ent->myskills.weapons[WEAPON_RAILGUN].mods[0].current_level; + //K03 End + + if (is_quad) { + damage *= 4; + kick *= 4; + } - // sniper shots deal massive damage - if (ent->client->weapon_mode) { - damage *= 3; - is_silenced = MZ_SILENCED; - } + // sniper shots deal massive damage + if (ent->client->weapon_mode) { + damage *= 3; + is_silenced = MZ_SILENCED; + } - AngleVectors(ent->client->v_angle, forward, right, NULL); + AngleVectors(ent->client->v_angle, forward, right, NULL); - VectorScale(forward, -3, ent->client->kick_origin); - ent->client->kick_angles[0] = -3; + VectorScale(forward, -3, ent->client->kick_origin); + ent->client->kick_angles[0] = -3; - VectorSet(offset, 0, 7, ent->viewheight - 8); + VectorSet(offset, 0, 7, ent->viewheight - 8); - P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); + P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); - fire_rail(ent, start, forward, damage, kick); + fire_rail(ent, start, forward, damage, kick); - if (ent->myskills.weapons[WEAPON_RAILGUN].mods[4].current_level < 1) { - // send muzzle flash - gi.WriteByte(svc_muzzleflash); - gi.WriteShort(ent - g_edicts); - gi.WriteByte(MZ_RAILGUN | is_silenced); - gi.multicast(ent->s.origin, MULTICAST_PVS); - } - //K03 End + if (ent->myskills.weapons[WEAPON_RAILGUN].mods[4].current_level < 1) { + // send muzzle flash + gi.WriteByte(svc_muzzleflash); + gi.WriteShort(ent - g_edicts); + gi.WriteByte(MZ_RAILGUN | is_silenced); + gi.multicast(ent->s.origin, MULTICAST_PVS); + } + //K03 End - ent->client->ps.gunframe++; - //K03 Begin - if (ent->myskills.weapons[WEAPON_RAILGUN].mods[4].current_level < 1) - PlayerNoise(ent, start, PNOISE_WEAPON); - //K03 End + ent->client->ps.gunframe++; + //K03 Begin + if (ent->myskills.weapons[WEAPON_RAILGUN].mods[4].current_level < 1) + PlayerNoise(ent, start, PNOISE_WEAPON); + //K03 End - if (!((int) dmflags->value & DF_INFINITE_AMMO)) - ent->client->pers.inventory[ent->client->ammo_index]--; + if (!((int)dmflags->value & DF_INFINITE_AMMO)) + ent->client->pers.inventory[ent->client->ammo_index]--; - ent->client->refire_frames = 0; + ent->client->refire_frames = 0; } //void fire_20mm(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, float range); -void weapon_20mm_fire(edict_t *ent) { - vec3_t start; - vec3_t forward, right; - vec3_t offset; - - int damage;//25 + (int) floor(2.5 * ent->myskills.weapons[WEAPON_20MM].mods[0].current_level); - int kick;//= 150 - (100 * ent->myskills.weapons[WEAPON_20MM].mods[3].current_level); - - //min = WEAPON_20MM_INITIAL_DMG_MIN + WEAPON_20MM_ADDON_DMG_MIN*ent->myskills.weapons[WEAPON_20MM].mods[0].current_level; - //max = WEAPON_20MM_INITIAL_DMG_MAX + WEAPON_20MM_ADDON_DMG_MAX*ent->myskills.weapons[WEAPON_20MM].mods[0].current_level; - //damage = GetRandom(min, max); - - //4.57 - damage = WEAPON_20MM_INITIAL_DMG + WEAPON_20MM_ADDON_DMG * ent->myskills.weapons[WEAPON_20MM].mods[0].current_level; - kick = damage; - if (ent->myskills.weapons[WEAPON_20MM].mods[3].current_level) - kick *= 0.5; - //if (kick < 0) - // kick = 0; - - if (!ent->groundentity && !ent->waterlevel) { - ent->client->ps.gunframe = 5; - if (ent->client && !(ent->svflags & SVF_MONSTER)) - safe_cprintf(ent, PRINT_HIGH, "You must be stepping on the ground or in water to fire the 20mm cannon.\n"); - return; - } +void weapon_20mm_fire(edict_t* ent) { + vec3_t start; + vec3_t forward, right; + vec3_t offset; + + int damage;//25 + (int) floor(2.5 * ent->myskills.weapons[WEAPON_20MM].mods[0].current_level); + int kick;//= 150 - (100 * ent->myskills.weapons[WEAPON_20MM].mods[3].current_level); + + //min = WEAPON_20MM_INITIAL_DMG_MIN + WEAPON_20MM_ADDON_DMG_MIN*ent->myskills.weapons[WEAPON_20MM].mods[0].current_level; + //max = WEAPON_20MM_INITIAL_DMG_MAX + WEAPON_20MM_ADDON_DMG_MAX*ent->myskills.weapons[WEAPON_20MM].mods[0].current_level; + //damage = GetRandom(min, max); + + //4.57 + damage = WEAPON_20MM_INITIAL_DMG + WEAPON_20MM_ADDON_DMG * ent->myskills.weapons[WEAPON_20MM].mods[0].current_level; + kick = damage; + if (ent->myskills.weapons[WEAPON_20MM].mods[3].current_level) + kick *= 0.5; + //if (kick < 0) + // kick = 0; + + if (!ent->groundentity && !ent->waterlevel) { + ent->client->ps.gunframe = 5; + if (ent->client && !(ent->svflags & SVF_MONSTER)) + safe_cprintf(ent, PRINT_HIGH, "You must be stepping on the ground or in water to fire the 20mm cannon.\n"); + return; + } - if (is_quad) { - damage *= 4; - } + if (is_quad) { + damage *= 4; + } - AngleVectors(ent->client->v_angle, forward, right, NULL); - VectorScale(forward, -3, ent->client->kick_origin); - VectorSet(offset, 0, 7, ent->viewheight - 8); - P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); + AngleVectors(ent->client->v_angle, forward, right, NULL); + VectorScale(forward, -3, ent->client->kick_origin); + VectorSet(offset, 0, 7, ent->viewheight - 8); + P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); - int range = WEAPON_20MM_INITIAL_RANGE + (WEAPON_20MM_ADDON_RANGE * ent->myskills.weapons[WEAPON_20MM].mods[1].current_level); - //gi.dprintf("called fire_20mm() at %f for %d damage\n", level.time, damage); + const int range = WEAPON_20MM_INITIAL_RANGE + (WEAPON_20MM_ADDON_RANGE * ent->myskills.weapons[WEAPON_20MM].mods[1].current_level); + //gi.dprintf("called fire_20mm() at %f for %d damage\n", level.time, damage); fire_20mm(ent, start, forward, damage, kick, range); - if (ent->myskills.weapons[WEAPON_20MM].mods[4].current_level < 1) { - // send muzzle flash - gi.WriteByte(svc_muzzleflash); - gi.WriteShort(ent - g_edicts); - gi.WriteByte(MZ_IONRIPPER | MZ_SILENCED); - gi.multicast(ent->s.origin, MULTICAST_PVS); - } - + if (ent->myskills.weapons[WEAPON_20MM].mods[4].current_level < 1) { + // send muzzle flash + gi.WriteByte(svc_muzzleflash); + gi.WriteShort(ent - g_edicts); + gi.WriteByte(MZ_IONRIPPER | MZ_SILENCED); + gi.multicast(ent->s.origin, MULTICAST_PVS); + } - ent->client->ps.gunframe++; + ent->client->ps.gunframe++; + ent->client->vrr.gun_fire_time = level.time + 0.1; - if (ent->myskills.weapons[WEAPON_20MM].mods[4].current_level < 1) { - PlayerNoise(ent, start, PNOISE_WEAPON); - gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/sgun1.wav"), 1, ATTN_NORM, 0); - } else { - gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/sgun1.wav"), 0.3, ATTN_NORM, 0); - } + if (ent->myskills.weapons[WEAPON_20MM].mods[4].current_level < 1) { + PlayerNoise(ent, start, PNOISE_WEAPON); + gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/sgun1.wav"), 1, ATTN_NORM, 0); + } + else { + gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/sgun1.wav"), 0.3, ATTN_NORM, 0); + } - if (!((int) dmflags->value & DF_INFINITE_AMMO)) - ent->client->pers.inventory[ent->client->ammo_index]--; + if (!((int)dmflags->value & DF_INFINITE_AMMO)) + ent->client->pers.inventory[ent->client->ammo_index]--; } -void Weapon_Railgun(edict_t *ent) { - static int pause_frames[] = {56, 0}; - static int fire_frames[] = {4, 0}; - int fire_last = 18; - - if (ent->mtype) - return; - - // are we in sniper mode? - if (ent->client->weapon_mode) { - // fire when button is released - if (!(ent->client->buttons & BUTTON_ATTACK)) { - if (ent->client->ps.gunframe > (fire_last + 1) && ent->client->refire_frames >= 2 * (fire_last - 2)) - ent->client->buttons |= BUTTON_ATTACK; - else - ent->client->refire_frames = 0; - ent->client->snipertime = 0;//4.5 - lasersight_off(ent); - } else { - // charge up weapon - if (ent->client->refire_frames == 2 * (fire_last - 2)) - gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0); - // make sure laser sight is on to alert enemies - if ((ent->client->refire_frames >= 2 * (fire_last - 2)) && !ent->lasersight) - lasersight_on(ent); - // dont fire yet - ent->client->buttons &= ~BUTTON_ATTACK; - ent->client->latched_buttons &= ~BUTTON_ATTACK; - ent->client->refire_frames++; - ent->client->snipertime = level.time + FRAMETIME; - } - } - Weapon_Generic(ent, 3, fire_last, 56, 61, pause_frames, fire_frames, weapon_railgun_fire); +void Weapon_Railgun(edict_t* ent) { + static int pause_frames[] = { 56, 0 }; + static int fire_frames[] = { 4, 0 }; + const int fire_last = 18; + + if (ent->mtype) + return; + + // are we in sniper mode? + if (ent->client->weapon_mode) { + // fire when button is released + if (!(ent->client->buttons & BUTTON_ATTACK)) { + if (ent->client->ps.gunframe > (fire_last + 1) && ent->client->refire_frames >= 2 * (fire_last - 2)) + ent->client->buttons |= BUTTON_ATTACK; + else + ent->client->refire_frames = 0; + ent->client->snipertime = 0;//4.5 + lasersight_off(ent); + } + else { + // charge up weapon + if (ent->client->refire_frames == 2 * (fire_last - 2)) + gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0); + // make sure laser sight is on to alert enemies + if ((ent->client->refire_frames >= 2 * (fire_last - 2)) && !ent->lasersight) + lasersight_on(ent); + // dont fire yet + ent->client->buttons &= ~BUTTON_ATTACK; + ent->client->latched_buttons &= ~BUTTON_ATTACK; + ent->client->refire_frames++; + ent->client->snipertime = level.time + FRAMETIME; + } + } + Weapon_Generic(ent, 3, fire_last, 56, 61, pause_frames, fire_frames, weapon_railgun_fire); } -void Weapon_20mm(edict_t *ent) { - static int pause_frames[] = {56, 0}; - static int fire_frames[] = {4, 0}; +void Weapon_20mm(edict_t* ent) { + static int pause_frames[] = { 56, 0 }; + static int fire_frames[] = { 4, 0 }; - //K03 Begin - int fire_last = 18; + //K03 Begin + int fire_last = 18; - Weapon_Generic(ent, 3, 4, 56, 61, pause_frames, fire_frames, weapon_20mm_fire); - //K03 End + Weapon_Generic(ent, 3, 4, 56, 61, pause_frames, fire_frames, weapon_20mm_fire); + //K03 End - // RAFAEL - if (is_quadfire) - Weapon_Generic(ent, 3, 18, 56, 61, pause_frames, fire_frames, weapon_railgun_fire); + // RAFAEL + if (is_quadfire) + Weapon_Generic(ent, 3, 18, 56, 61, pause_frames, fire_frames, weapon_railgun_fire); } @@ -2311,179 +2457,180 @@ BFG10K ====================================================================== */ -void weapon_bfg_fire(edict_t *ent) { - vec3_t offset, start; - vec3_t forward, right; - int dmg, speed; - float range; - - speed = BFG10K_INITIAL_SPEED + BFG10K_ADDON_SPEED * ent->myskills.weapons[WEAPON_BFG10K].mods[2].current_level; - range = BFG10K_RADIUS; - dmg = BFG10K_INITIAL_DAMAGE + BFG10K_ADDON_DAMAGE * ent->myskills.weapons[WEAPON_BFG10K].mods[0].current_level; - - if (is_quad) - dmg *= 4; - - if (ent->client->ps.gunframe == 9) { - // gi.dprintf("fired bfg at %.1f\n", level.time); - // send muzzle flash - if (ent->myskills.weapons[WEAPON_BFG10K].mods[4].current_level < 1) { - gi.WriteByte(svc_muzzleflash); - gi.WriteShort(ent - g_edicts); - gi.WriteByte(MZ_BFG | is_silenced); - gi.multicast(ent->s.origin, MULTICAST_PVS); - } - - ent->client->ps.gunframe++; - - if (ent->client->pers.inventory[ent->client->ammo_index] >= 50) { - AngleVectors(ent->client->v_angle, forward, right, NULL); - VectorScale(forward, -2, ent->client->kick_origin); - - // make a big pitch kick with an inverse fall - ent->client->v_dmg_pitch = -20; - ent->client->v_dmg_roll = crandom() * 4; - ent->client->v_dmg_time = level.time + DAMAGE_TIME; - - VectorSet(offset, 8, 8, ent->viewheight - 8); - P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); - - if (ent->myskills.weapons[WEAPON_BFG10K].mods[4].current_level < 1) - PlayerNoise(ent, start, PNOISE_WEAPON); - fire_bfg(ent, start, forward, dmg, speed, range); - - if (!((int) dmflags->value & DF_INFINITE_AMMO)) - ent->client->pers.inventory[ent->client->ammo_index] -= 50; - } - return; - } +void weapon_bfg_fire(edict_t* ent) { + vec3_t offset, start; + vec3_t forward, right; + int dmg, speed; + float range; + + speed = BFG10K_INITIAL_SPEED + BFG10K_ADDON_SPEED * ent->myskills.weapons[WEAPON_BFG10K].mods[2].current_level; + range = BFG10K_RADIUS; + dmg = BFG10K_INITIAL_DAMAGE + BFG10K_ADDON_DAMAGE * ent->myskills.weapons[WEAPON_BFG10K].mods[0].current_level; + + if (is_quad) + dmg *= 4; + + if (ent->client->ps.gunframe == 9) { + // gi.dprintf("fired bfg at %.1f\n", level.time); + // send muzzle flash + if (ent->myskills.weapons[WEAPON_BFG10K].mods[4].current_level < 1) { + gi.WriteByte(svc_muzzleflash); + gi.WriteShort(ent - g_edicts); + gi.WriteByte(MZ_BFG | is_silenced); + gi.multicast(ent->s.origin, MULTICAST_PVS); + } + + ent->client->ps.gunframe++; + + if (ent->client->pers.inventory[ent->client->ammo_index] >= 50) { + AngleVectors(ent->client->v_angle, forward, right, NULL); + VectorScale(forward, -2, ent->client->kick_origin); + + // make a big pitch kick with an inverse fall + ent->client->v_dmg_pitch = -20; + ent->client->v_dmg_roll = crandom() * 4; + ent->client->v_dmg_time = level.time + DAMAGE_TIME; + + VectorSet(offset, 8, 8, ent->viewheight - 8); + P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); + + if (ent->myskills.weapons[WEAPON_BFG10K].mods[4].current_level < 1) + PlayerNoise(ent, start, PNOISE_WEAPON); + fire_bfg(ent, start, forward, dmg, speed, range); + + if (!((int)dmflags->value & DF_INFINITE_AMMO)) + ent->client->pers.inventory[ent->client->ammo_index] -= 50; + } + return; + } - // cells can go down during windup (from power armor hits), so - // check again and abort firing if we don't have enough now - if (ent->client->pers.inventory[ent->client->ammo_index] < 50) { - ent->client->ps.gunframe++; - return; - } + // cells can go down during windup (from power armor hits), so + // check again and abort firing if we don't have enough now + if (ent->client->pers.inventory[ent->client->ammo_index] < 50) { + ent->client->ps.gunframe++; + return; + } - AngleVectors(ent->client->v_angle, forward, right, NULL); + AngleVectors(ent->client->v_angle, forward, right, NULL); - VectorScale(forward, -2, ent->client->kick_origin); -/* - // make a big pitch kick with an inverse fall - ent->client->v_dmg_pitch = -40; - ent->client->v_dmg_roll = crandom()*8; - ent->client->v_dmg_time = level.time + DAMAGE_TIME; + VectorScale(forward, -2, ent->client->kick_origin); + /* + // make a big pitch kick with an inverse fall + ent->client->v_dmg_pitch = -40; + ent->client->v_dmg_roll = crandom()*8; + ent->client->v_dmg_time = level.time + DAMAGE_TIME; - VectorSet(offset, 8, 8, ent->viewheight-8); - P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start); - fire_bfg (ent, start, forward, dmg, speed, range); */ + VectorSet(offset, 8, 8, ent->viewheight-8); + P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start); + fire_bfg (ent, start, forward, dmg, speed, range); */ - ent->client->ps.gunframe++; + ent->client->ps.gunframe++; - /*if (ent->myskills.weapons[WEAPON_BFG10K].mods[4].current_level < 1) - PlayerNoise(ent, start, PNOISE_WEAPON); + /*if (ent->myskills.weapons[WEAPON_BFG10K].mods[4].current_level < 1) + PlayerNoise(ent, start, PNOISE_WEAPON); - if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) ) - ent->client->pers.inventory[ent->client->ammo_index] -= 25;*/ + if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) ) + ent->client->pers.inventory[ent->client->ammo_index] -= 25;*/ } -void Weapon_BFG(edict_t *ent) { - static int pause_frames[] = {39, 45, 50, 55, 0}; - static int fire_frames[] = {9, 17, 0}; +void Weapon_BFG(edict_t* ent) { + static int pause_frames[] = { 39, 45, 50, 55, 0 }; + static int fire_frames[] = { 9, 17, 0 }; - Weapon_Generic(ent, 8, 32, 55, 58, pause_frames, fire_frames, weapon_bfg_fire); - //K03 Endda - // RAFAEL + Weapon_Generic(ent, 8, 32, 55, 58, pause_frames, fire_frames, weapon_bfg_fire); + //K03 Endda + // RAFAEL // if (is_quadfire) // Weapon_Generic (ent, 8, 32, 55, 58, pause_frames, fire_frames, weapon_bfg_fire); } -void fire_flame (edict_t *self, vec3_t start, vec3_t dir, int speed, int damage); +void fire_flame(edict_t* self, vec3_t start, vec3_t dir, int speed, int damage); -void Flamethrower_Fire(edict_t *ent) { - vec3_t start; - vec3_t forward, right; - vec3_t angles; - int kick = 2; - vec3_t offset; - float damage = 10; - int shots = 1; - - if (!(ent->client->buttons & BUTTON_ATTACK)) { - ent->client->ps.gunframe++; - return; - } +void Flamethrower_Fire(edict_t* ent) { + vec3_t start; + vec3_t forward, right; + vec3_t angles; + int kick = 2; + vec3_t offset; + float damage = 10; + int shots = 1; - if (ent->client->ps.gunframe == 5) - ent->client->ps.gunframe = 4; - else - ent->client->ps.gunframe = 5; + if (!(ent->client->buttons & BUTTON_ATTACK)) { + ent->client->ps.gunframe++; + return; + } - /* - if (ent->client->pers.inventory[ent->client->ammo_index] < shots) - shots = ent->client->pers.inventory[ent->client->ammo_index]; + if (ent->client->ps.gunframe == 5) + ent->client->ps.gunframe = 4; + else + ent->client->ps.gunframe = 5; - if (!shots && !ent->client->pers.inventory[ent->client->ammo_index]) { + /* + if (ent->client->pers.inventory[ent->client->ammo_index] < shots) + shots = ent->client->pers.inventory[ent->client->ammo_index]; - if (level.time >= ent->pain_debounce_time) { - gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0); - ent->pain_debounce_time = level.time + 1; - } + if (!shots && !ent->client->pers.inventory[ent->client->ammo_index]) { - NoAmmoWeaponChange(ent); - return; - }*/ + if (level.time >= ent->pain_debounce_time) { + gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0); + ent->pain_debounce_time = level.time + 1; + } - if (is_quad) { - damage *= 4; - kick *= 4; - } - - // get start / end positions - VectorAdd (ent->client->v_angle, ent->client->kick_angles, angles); - AngleVectors(angles, forward, right, NULL); - VectorSet(offset, 0, 8, ent->viewheight - 8); - P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); + NoAmmoWeaponChange(ent); + return; + }*/ - fire_flame(ent, start, forward, 600, 50); + if (is_quad) { + damage *= 4; + kick *= 4; + } - /*if (is_silenced) - gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/mg_silenced.wav"), 0.5, ATTN_NORM, 0); - else - gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/mg_unsilenced.wav"), 1, ATTN_NORM, 0);*/ + // get start / end positions + VectorAdd(ent->client->v_angle, ent->client->kick_angles, angles); + AngleVectors(angles, forward, right, NULL); + VectorSet(offset, 0, 8, ent->viewheight - 8); + P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); - //if (ent->myskills.weapons[WEAPON_MACHINEGUN].mods[4].current_level < 1) { - gi.WriteByte(svc_muzzleflash); - gi.WriteShort(ent - g_edicts); - gi.WriteByte(MZ_PHALANX | MZ_SILENCED); - gi.multicast(ent->s.origin, MULTICAST_PVS); - //} - //if (ent->myskills.weapons[WEAPON_MACHINEGUN].mods[4].current_level < 1) - PlayerNoise(ent, start, PNOISE_WEAPON); + fire_flame(ent, start, forward, 600, 50); - /* - if (!((int) dmflags->value & DF_INFINITE_AMMO)) - ent->client->pers.inventory[ent->client->ammo_index] -= shots; - */ - - ent->client->anim_priority = ANIM_ATTACK; - if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) { - ent->s.frame = FRAME_crattak1 - (int) (random() + 0.25); - ent->client->anim_end = FRAME_crattak9; - } else { - ent->s.frame = FRAME_attack1 - (int) (random() + 0.25); - ent->client->anim_end = FRAME_attack8; - } - ent->client->weaponstate = WEAPON_READY; + /*if (is_silenced) + gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/mg_silenced.wav"), 0.5, ATTN_NORM, 0); + else + gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/mg_unsilenced.wav"), 1, ATTN_NORM, 0);*/ + + //if (ent->myskills.weapons[WEAPON_MACHINEGUN].mods[4].current_level < 1) { + gi.WriteByte(svc_muzzleflash); + gi.WriteShort(ent - g_edicts); + gi.WriteByte(MZ_PHALANX | MZ_SILENCED); + gi.multicast(ent->s.origin, MULTICAST_PVS); + //} + //if (ent->myskills.weapons[WEAPON_MACHINEGUN].mods[4].current_level < 1) + PlayerNoise(ent, start, PNOISE_WEAPON); + + /* + if (!((int) dmflags->value & DF_INFINITE_AMMO)) + ent->client->pers.inventory[ent->client->ammo_index] -= shots; + */ + + ent->client->anim_priority = ANIM_ATTACK; + if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) { + ent->s.frame = FRAME_crattak1 - (int)(random() + 0.25); + ent->client->anim_end = FRAME_crattak9; + } + else { + ent->s.frame = FRAME_attack1 - (int)(random() + 0.25); + ent->client->anim_end = FRAME_attack8; + } + ent->client->weaponstate = WEAPON_READY; } -void Weapon_Flamethrower(edict_t *ent) { - static int pause_frames[] = {23, 45, 0}; - static int fire_frames[] = {4, 5, 0}; +void Weapon_Flamethrower(edict_t* ent) { + static int pause_frames[] = { 23, 45, 0 }; + static int fire_frames[] = { 4, 5, 0 }; - Weapon_Generic(ent, 3, 5, 45, 49, pause_frames, fire_frames, Flamethrower_Fire); + Weapon_Generic(ent, 3, 5, 45, 49, pause_frames, fire_frames, Flamethrower_Fire); - // RAFAEL - if (is_quadfire) - Weapon_Generic(ent, 3, 5, 45, 49, pause_frames, fire_frames, Flamethrower_Fire); + // RAFAEL + if (is_quadfire) + Weapon_Generic(ent, 3, 5, 45, 49, pause_frames, fire_frames, Flamethrower_Fire); } diff --git a/src/entities/backpack.c b/src/entities/backpack.c index 9aabf413..eae217fa 100644 --- a/src/entities/backpack.c +++ b/src/entities/backpack.c @@ -57,7 +57,7 @@ edict_t *pack; vec3_t forward, right, up; float dist; vec3_t v; - edict_t *enemy = NULL; + const edict_t *enemy = NULL; if (!deathmatch->value) return; diff --git a/src/entities/boss_general.c b/src/entities/boss_general.c index 4c2052ca..a632e02f 100644 --- a/src/entities/boss_general.c +++ b/src/entities/boss_general.c @@ -2,402 +2,357 @@ #include "../gamemodes/boss.h" #include "../combat/abilities/jump.h" -qboolean IsABoss(const edict_t *ent) -{ - return (ent && ent->inuse && !ent->client && ((ent->mtype == BOSS_TANK) || (ent->mtype == BOSS_MAKRON))); +qboolean IsABoss(const edict_t *ent) { + return (ent && ent->inuse && !ent->client && ((ent->mtype == BOSS_TANK) || (ent->mtype == BOSS_MAKRON))); } -qboolean IsBossTeam (const edict_t *ent) -{ - const edict_t *e = G_GetClient(ent); +qboolean IsBossTeam(const edict_t *ent) { + const edict_t *e = G_GetClient(ent); - return (e && IsABoss(e->owner)); + return (e && IsABoss(e->owner)); } +void boss_update(edict_t *ent, usercmd_t *ucmd) { + int div, forwardspeed, sidespeed, maxspeed; + int frames = 0; + vec3_t forward, right, angles; + edict_t *boss; + + boss = ent->owner; + // make sure this is a valid boss entity + if (!G_EntIsAlive(boss)) + return; + if (!IsABoss(boss) && (boss->mtype != P_TANK)) + return; + VectorCopy(ent->s.origin, ent->s.old_origin); + // update player state + //ent->client->ps.pmove.pm_type = PM_FREEZE; + ent->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION; + //ent->client->ability_delay = level.time + FRAMETIME; + // copy player angles to boss + boss->s.angles[YAW] = ent->s.angles[YAW]; + boss->s.angles[PITCH] = 0; + boss->s.angles[ROLL] = 0; + AngleVectors(boss->s.angles, forward, right, NULL); + vectoangles(right, angles); + + // move player into position + boss_position_player(ent, boss); + + // speed divider, lower is faster (ucmd is 400) + if (boss->mtype == BOSS_TANK) + div = 20; + else if (boss->mtype == BOSS_MAKRON) + div = 10; + else + div = 26; + + // speed limiter, dont allow client to speed cheat using higher cl_speeds + + maxspeed = 400; + forwardspeed = ucmd->forwardmove; + sidespeed = ucmd->sidemove; + //gi.dprintf("%d %d\n", forwardspeed, sidespeed); + + if ((forwardspeed > 0) && forwardspeed > maxspeed) + forwardspeed = maxspeed; + else if (forwardspeed < -maxspeed) + forwardspeed = -maxspeed; + + if ((sidespeed > 0) && sidespeed > maxspeed) + sidespeed = maxspeed; + else if (sidespeed < -maxspeed) + sidespeed = -maxspeed; + + //4.2 allow superspeed + if (ent->superspeed && (level.time > ent->lasthurt + DAMAGE_ESCAPE_DELAY)) { + forwardspeed *= 3; + sidespeed *= 3; + maxspeed = 3 * BOSS_MAXVELOCITY; + } else if (boss->monsterinfo.air_frames) // used for boost + maxspeed = 9999; + else + maxspeed = BOSS_MAXVELOCITY; + + const float norm_fspeed = scale_fps(forwardspeed / div); + const float norm_sspeed = scale_fps(sidespeed / div); + + if (!(ent->client->buttons & BUTTON_ATTACK)) { + if (forwardspeed > 0) { + M_walkmove(boss, boss->s.angles[YAW], norm_fspeed); + frames = FRAMES_RUN_FORWARD; + } else if (forwardspeed < 0) { + M_walkmove(boss, boss->s.angles[YAW], norm_fspeed); + frames = FRAMES_RUN_BACKWARD; + } + + if (sidespeed > 0) { + M_walkmove(boss, angles[YAW], norm_sspeed); + frames = FRAMES_RUN_FORWARD; + } else if (sidespeed < 0) { + M_walkmove(boss, angles[YAW], norm_sspeed); + frames = FRAMES_RUN_FORWARD; + } + } else { + frames = FRAMES_ATTACK; + } -void boss_update(edict_t *ent, usercmd_t *ucmd) { - int div, forwardspeed, sidespeed, maxspeed; - int frames=0; - vec3_t forward, right, angles; - edict_t *boss; - - boss = ent->owner; - // make sure this is a valid boss entity - if (!G_EntIsAlive(boss)) - return; - if (!IsABoss(boss) && (boss->mtype != P_TANK)) - return; - - VectorCopy(ent->s.origin, ent->s.old_origin); - // update player state - //ent->client->ps.pmove.pm_type = PM_FREEZE; - ent->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION; - //ent->client->ability_delay = level.time + FRAMETIME; - // copy player angles to boss - boss->s.angles[YAW] = ent->s.angles[YAW]; - boss->s.angles[PITCH] = 0; - boss->s.angles[ROLL] = 0; - AngleVectors(boss->s.angles, forward, right, NULL); - vectoangles(right, angles); - - // move player into position - boss_position_player(ent, boss); - - // speed divider, lower is faster (ucmd is 400) - if (boss->mtype == BOSS_TANK) - div = 20; - else if (boss->mtype == BOSS_MAKRON) - div = 10; - else - div = 26; - - // speed limiter, dont allow client to speed cheat using higher cl_speeds - - maxspeed = 400; - forwardspeed = ucmd->forwardmove; - sidespeed = ucmd->sidemove; - //gi.dprintf("%d %d\n", forwardspeed, sidespeed); - - if ((forwardspeed > 0) && forwardspeed > maxspeed) - forwardspeed = maxspeed; - else if (forwardspeed < -maxspeed) - forwardspeed = -maxspeed; - - if ((sidespeed > 0) && sidespeed > maxspeed) - sidespeed = maxspeed; - else if (sidespeed < -maxspeed) - sidespeed = -maxspeed; - - //4.2 allow superspeed - if (ent->superspeed && (level.time > ent->lasthurt + DAMAGE_ESCAPE_DELAY)) - { - forwardspeed *= 3; - sidespeed *= 3; - maxspeed = 3*BOSS_MAXVELOCITY; - } - - else if (boss->monsterinfo.air_frames)// used for boost - maxspeed = 9999; - else - maxspeed = BOSS_MAXVELOCITY; - - if (level.framenum >= boss->count) - { - if (!(ent->client->buttons & BUTTON_ATTACK)) - { - if (forwardspeed > 0) - { - M_walkmove(boss, boss->s.angles[YAW], forwardspeed/div); - frames = FRAMES_RUN_FORWARD; - } - else if (forwardspeed < 0) - { - M_walkmove(boss, boss->s.angles[YAW], forwardspeed/div); - frames = FRAMES_RUN_BACKWARD; - } - - if (sidespeed > 0) - { - M_walkmove(boss, angles[YAW], sidespeed/div); - frames = FRAMES_RUN_FORWARD; - } - else if (sidespeed < 0) - { - M_walkmove(boss, angles[YAW], sidespeed/div); - frames = FRAMES_RUN_FORWARD; - } - } - else - { - frames = FRAMES_ATTACK; - } - - if (boss->groundentity) - { - boss->monsterinfo.air_frames = 0;//we're done boosting - VectorClear(boss->velocity); - if (ucmd->upmove > 0 && !ent->client->jump) - { - //gi.sound (ent, CHAN_WEAPON, gi.soundindex ("tank/sight1.wav"), 1, ATTN_NORM, 0); - // jump in the direction we are trying to move - boss->velocity[0] = 0.1*((forwardspeed*forward[0])+(sidespeed*right[0])); - boss->velocity[1] = 0.1*((forwardspeed*forward[1])+(sidespeed*right[1])); - boss->velocity[2] = 350; - - ent->client->jump = true; - } - - boss->v_flags &= ~SFLG_DOUBLEJUMP; - } - else - { - if (ucmd->upmove < 1) - ent->client->jump = false; - - if (CanDoubleJump(boss, ucmd)) - { - boss->velocity[2] += 350; - boss->v_flags |= SFLG_DOUBLEJUMP; - } - - // steer in the direction we are trying to move - boss->velocity[0] += 0.1*((forwardspeed*forward[0])+(sidespeed*right[0])); - boss->velocity[1] += 0.1*((forwardspeed*forward[1])+(sidespeed*right[1])); - - if (ucmd->upmove && (boss->waterlevel > 1)) - { - if (ucmd->upmove > 0) - { - if (boss->waterlevel == 2) - boss->velocity[2] = 200; - else if (boss->velocity[2] < 50) - boss->velocity[2] = 50; - } - else - { - if (boss->velocity[2] > -50) - boss->velocity[2] = -50; - } - } - - // don't move too fast - if (boss->velocity[0] > maxspeed) - boss->velocity[0] = maxspeed; - if (boss->velocity[0] < -maxspeed) - boss->velocity[0] = -maxspeed; - if (boss->velocity[1] > maxspeed) - boss->velocity[1] = maxspeed; - if (boss->velocity[1] < -maxspeed) - boss->velocity[1] = -maxspeed; - } - - boss->style = frames; // set frame set boss should use - gi.linkentity(boss); - boss->count = level.framenum + qf2sf(1); - } - - // move player into position - //boss_position_player(ent, boss); - - // if we are standing on a live entity, call its touch function - // this prevents player-bosses from being invulnerable to obstacles - //FIXME: it may be dangerous to call a touch function without a NULL plane or surf - /* - if (boss->groundentity && G_EntIsAlive(boss->groundentity) && boss->groundentity->touch) - boss->groundentity->touch(boss->groundentity, boss, NULL, NULL); - */ + if (boss->groundentity) { + boss->monsterinfo.air_frames = 0; //we're done boosting + VectorClear(boss->velocity); + if (cmd_jumping(ucmd) && !ent->client->jump) { + //gi.sound (ent, CHAN_WEAPON, gi.soundindex ("tank/sight1.wav"), 1, ATTN_NORM, 0); + // jump in the direction we are trying to move + boss->velocity[0] = 0.1 * ((forwardspeed * forward[0]) + (sidespeed * right[0])); + boss->velocity[1] = 0.1 * ((forwardspeed * forward[1]) + (sidespeed * right[1])); + boss->velocity[2] = 350; + + ent->client->jump = true; + } + + boss->v_flags &= ~SFLG_DOUBLEJUMP; + } else { + if (!cmd_jumping(ucmd)) + ent->client->jump = false; + + if (CanDoubleJump(boss, ucmd)) { + boss->velocity[2] += scale_fps(350); + boss->v_flags |= SFLG_DOUBLEJUMP; + } + + // steer in the direction we are trying to move + boss->velocity[0] += scale_fps(0.1 * ((forwardspeed * forward[0]) + (sidespeed * right[0]))); + boss->velocity[1] += scale_fps(0.1 * ((forwardspeed * forward[1]) + (sidespeed * right[1]))); + + if (!cmd_standing(ucmd) && (boss->waterlevel > 1)) { + if (cmd_jumping(ucmd)) { + if (boss->waterlevel == 2) + boss->velocity[2] = scale_fps(200); + else if (boss->velocity[2] < scale_fps(50)) + boss->velocity[2] = scale_fps(50); + } else { + if (boss->velocity[2] > scale_fps(-50)) + boss->velocity[2] = scale_fps(-50); + } + } + + // don't move too fast + if (boss->velocity[0] > maxspeed) + boss->velocity[0] = maxspeed; + if (boss->velocity[0] < -maxspeed) + boss->velocity[0] = -maxspeed; + if (boss->velocity[1] > maxspeed) + boss->velocity[1] = maxspeed; + if (boss->velocity[1] < -maxspeed) + boss->velocity[1] = -maxspeed; + } + + boss->style = frames; // set frame set boss should use + gi.linkentity(boss); + + // move player into position + //boss_position_player(ent, boss); + + // if we are standing on a live entity, call its touch function + // this prevents player-bosses from being invulnerable to obstacles + //FIXME: it may be dangerous to call a touch function without a NULL plane or surf + /* + if (boss->groundentity && G_EntIsAlive(boss->groundentity) && boss->groundentity->touch) + boss->groundentity->touch(boss->groundentity, boss, NULL, NULL); + */ } -qboolean validDmgPlayer (edict_t *player) -{ - return (player && player->inuse && player->client && !G_IsSpectator(player)); +qboolean validDmgPlayer(edict_t *player) { + return (player && player->inuse && player->client && !G_IsSpectator(player)); } -void vrx_clean_damage_list (edict_t *self, qboolean clear_all) -{ - int i; +void vrx_clean_damage_list(edict_t *self, qboolean clear_all) { + int i; - for (i=0; i < MAX_CLIENTS; i++) - { - // is this a valid player? - if (!clear_all && validDmgPlayer(self->monsterinfo.dmglist[i].player)) - continue; + for (i = 0; i < MAX_CLIENTS; i++) { + // is this a valid player? + if (!clear_all && validDmgPlayer(self->monsterinfo.dmglist[i].player)) + continue; - // clear this entry - self->monsterinfo.dmglist[i].player = NULL; - self->monsterinfo.dmglist[i].damage = 0; - } + // clear this entry + self->monsterinfo.dmglist[i].player = NULL; + self->monsterinfo.dmglist[i].damage = 0; + } } -dmglist_t *findDmgSlot (edict_t *self, edict_t *other) -{ - int i; +dmglist_t *findDmgSlot(edict_t *self, edict_t *other) { + int i; - for (i=0; i < MAX_CLIENTS; i++) { - if (self->monsterinfo.dmglist[i].player == other) - return &self->monsterinfo.dmglist[i]; - } - return NULL; + for (i = 0; i < MAX_CLIENTS; i++) { + if (self->monsterinfo.dmglist[i].player == other) + return &self->monsterinfo.dmglist[i]; + } + return NULL; } -dmglist_t *findEmptyDmgSlot (edict_t *self) -{ - int i; +dmglist_t *findEmptyDmgSlot(edict_t *self) { + int i; - for (i=0; i < MAX_CLIENTS; i++) { - if (!validDmgPlayer(self->monsterinfo.dmglist[i].player)) - return &self->monsterinfo.dmglist[i]; - } - return NULL; + for (i = 0; i < MAX_CLIENTS; i++) { + if (!validDmgPlayer(self->monsterinfo.dmglist[i].player)) + return &self->monsterinfo.dmglist[i]; + } + return NULL; } -float GetTotalBossDamage (edict_t *self) -{ - int i; - float dmg=0; +float GetTotalBossDamage(edict_t *self) { + int i; + float dmg = 0; - for (i=0; i < MAX_CLIENTS; i++) { - if (validDmgPlayer(self->monsterinfo.dmglist[i].player)) - dmg += self->monsterinfo.dmglist[i].damage; - } + for (i = 0; i < MAX_CLIENTS; i++) { + if (validDmgPlayer(self->monsterinfo.dmglist[i].player)) + dmg += self->monsterinfo.dmglist[i].damage; + } - if (dmg < 1) - dmg = 1; + if (dmg < 1) + dmg = 1; - return dmg; + return dmg; } -float GetPlayerBossDamage (edict_t *player, edict_t *boss) -{ - int i; +float GetPlayerBossDamage(edict_t *player, edict_t *boss) { + int i; - for (i=0; i < MAX_CLIENTS; i++) { - if (boss->monsterinfo.dmglist[i].player == player) - return boss->monsterinfo.dmglist[i].damage; - } - return 0; + for (i = 0; i < MAX_CLIENTS; i++) { + if (boss->monsterinfo.dmglist[i].player == player) + return boss->monsterinfo.dmglist[i].damage; + } + return 0; } -dmglist_t *findHighestDmgPlayer (edict_t *self) -{ - int i; - dmglist_t *slot=NULL; +dmglist_t *findHighestDmgPlayer(edict_t *self) { + int i; + dmglist_t *slot = NULL; - for (i=0; i < MAX_CLIENTS; i++) - { - if (!validDmgPlayer(self->monsterinfo.dmglist[i].player)) - continue; + for (i = 0; i < MAX_CLIENTS; i++) { + if (!validDmgPlayer(self->monsterinfo.dmglist[i].player)) + continue; - if (!self->monsterinfo.dmglist[i].damage) - continue; + if (!self->monsterinfo.dmglist[i].damage) + continue; - if (!slot) - slot = &self->monsterinfo.dmglist[i]; - else if (self->monsterinfo.dmglist[i].damage > slot->damage) - slot = &self->monsterinfo.dmglist[i]; - } + if (!slot) + slot = &self->monsterinfo.dmglist[i]; + else if (self->monsterinfo.dmglist[i].damage > slot->damage) + slot = &self->monsterinfo.dmglist[i]; + } - return slot; + return slot; } -void printDmgList (edict_t *self) -{ - int i; - float percent; - dmglist_t *slot; - - for (i=0; i < MAX_CLIENTS; i++) - { - slot = &self->monsterinfo.dmglist[i]; - if (self->monsterinfo.dmglist[i].player) - { - percent = 100*(slot->damage/GetTotalBossDamage(self)); - - if (self->client) - gi.dprintf("(%s) slot %d: %s, %.0f damage (%.1f%c)\n", - self->client->pers.netname, i, slot->player->client->pers.netname, slot->damage, percent, '%'); - else if (self->mtype) - gi.dprintf("(%s) slot %d: %s, %.0f damage (%.1f%c)\n", - V_GetMonsterName(self), i, slot->player->client->pers.netname, slot->damage, percent, '%'); - else - gi.dprintf("(%s) slot %d: %s, %.0f damage (%.1f%c)\n", - self->classname, i, slot->player->client->pers.netname, slot->damage, percent, '%'); - } - } +void printDmgList(edict_t *self) { + int i; + float percent; + dmglist_t *slot; + + for (i = 0; i < MAX_CLIENTS; i++) { + slot = &self->monsterinfo.dmglist[i]; + if (self->monsterinfo.dmglist[i].player) { + percent = 100 * (slot->damage / GetTotalBossDamage(self)); + + if (self->client) + gi.dprintf("(%s) slot %d: %s, %.0f damage (%.1f%c)\n", + self->client->pers.netname, i, slot->player->client->pers.netname, slot->damage, percent, + '%'); + else if (self->mtype) + gi.dprintf("(%s) slot %d: %s, %.0f damage (%.1f%c)\n", + V_GetMonsterName(self), i, slot->player->client->pers.netname, slot->damage, percent, '%'); + else + gi.dprintf("(%s) slot %d: %s, %.0f damage (%.1f%c)\n", + self->classname, i, slot->player->client->pers.netname, slot->damage, percent, '%'); + } + } } -void AddDmgList (edict_t *self, edict_t *other, int damage) -{ - edict_t *cl_ent; - dmglist_t *slot; - - if (damage < 1) - return; - - // sanity checks - if (!self || !self->inuse || self->deadflag == DEAD_DEAD) - return; - if (!other || !other->inuse || other->deadflag == DEAD_DEAD) - return; - - // don't count self-inflicted damage - if (other == self) - return; - - // we're only adding non-spectator clients to this list - cl_ent = G_GetClient(other); - if (!validDmgPlayer(cl_ent)) - return; - - // prune list of disconnected clients +void AddDmgList(edict_t *self, edict_t *other, int damage) { + edict_t *cl_ent; + dmglist_t *slot; + + if (damage < 1) + return; + + // sanity checks + if (!self || !self->inuse || self->deadflag == DEAD_DEAD) + return; + if (!other || !other->inuse || other->deadflag == DEAD_DEAD) + return; + + // don't count self-inflicted damage + if (other == self) + return; + + // we're only adding non-spectator clients to this list + cl_ent = G_GetClient(other); + if (!validDmgPlayer(cl_ent)) + return; + + // prune list of disconnected clients vrx_clean_damage_list(self, false); - // already in the queue? - if ( (slot=findDmgSlot(self, cl_ent)) != NULL ) - { - slot->damage += damage; - } - // add attacker to the queue - else if ( (slot=findEmptyDmgSlot(self)) != NULL ) - { - slot->player = cl_ent; - slot->damage += damage; - } - - //gi.dprintf("adding %d damage\n", damage); - //printDmgList(self); + // already in the queue? + if ((slot = findDmgSlot(self, cl_ent)) != NULL) { + slot->damage += damage; + } + // add attacker to the queue + else if ((slot = findEmptyDmgSlot(self)) != NULL) { + slot->player = cl_ent; + slot->damage += damage; + } + + //gi.dprintf("adding %d damage\n", damage); + //printDmgList(self); } -void boss_pain (edict_t *self, edict_t *other, float kick, int damage) -{ - //edict_t *cl_ent; - //dmglist_t *slot; +void boss_pain(edict_t *self, edict_t *other, float kick, int damage) { + //edict_t *cl_ent; + //dmglist_t *slot; - if (self->health < 0.3*self->max_health) - self->s.skinnum |= 1; // use damaged skin - AddDmgList(self, other, damage); + if (self->health < 0.3 * self->max_health) + self->s.skinnum |= 1; // use damaged skin + AddDmgList(self, other, damage); } // returns true if there is a nearby, visible player boss -qboolean findNearbyBoss (edict_t *self) -{ - edict_t *other=NULL; - - while ((other = findradius(other, self->s.origin, BOSS_ALLY_BONUS_RANGE)) != NULL) - { - if (!IsABoss(other)) - continue; - if (!G_EntIsAlive(other)) - continue; - return true; - } - return false; +qboolean findNearbyBoss(edict_t *self) { + const edict_t *other = NULL; + + while ((other = findradius(other, self->s.origin, BOSS_ALLY_BONUS_RANGE)) != NULL) { + if (!IsABoss(other)) + continue; + if (!G_EntIsAlive(other)) + continue; + return true; + } + return false; } -void boss_eyecam (edict_t *player, edict_t *boss) -{ - vec3_t forward, goal; +void boss_eyecam(edict_t *player, edict_t *boss) { + vec3_t forward, goal; - AngleVectors(boss->s.angles, forward, NULL, NULL); - VectorCopy(boss->s.origin, goal); - goal[2] = boss->absmax[2]-24; - VectorMA(goal, boss->maxs[1], forward, goal); // move cam forward + AngleVectors(boss->s.angles, forward, NULL, NULL); + VectorCopy(boss->s.origin, goal); + goal[2] = boss->absmax[2] - 24; + VectorMA(goal, boss->maxs[1], forward, goal); // move cam forward - // move player into position - VectorCopy(goal, player->s.origin); - gi.linkentity(player); + // move player into position + VectorCopy(goal, player->s.origin); + gi.linkentity(player); } #define BOSS_CHASEMODE_BUFFER 10 // time in seconds before allowing mode switch -void boss_position_player (edict_t *player, edict_t *boss) -{ +void boss_position_player(edict_t *player, edict_t *boss) { float hdist = 0, vdist = 0; vec3_t forward, start, goal; - vec3_t boxmin = {-4, -4, 0}; - vec3_t boxmax = {4, 4, 0}; + const vec3_t boxmin = {-4, -4, 0}; + const vec3_t boxmax = {4, 4, 0}; trace_t tr; if (boss->monsterinfo.trail_time > level.time) { @@ -405,182 +360,166 @@ void boss_position_player (edict_t *player, edict_t *boss) return; } - if (boss->mtype == BOSS_TANK) - { - hdist = boss->mins[1]-96; - vdist = boss->absmax[2]+8; - } - else if (boss->mtype == BOSS_MAKRON) - { - hdist = boss->mins[1]-32; - vdist = boss->absmax[2]+64; - } - - // get starting position - VectorCopy(boss->s.origin, start); - start[2] += 40; - - // get ideal viewing position - AngleVectors(boss->s.angles, forward, NULL, NULL); - VectorCopy(start, goal); - goal[2] = vdist; // move cam up - VectorMA(goal, hdist, forward, goal); // move cam backward - tr = gi.trace(start, boxmin, boxmax, goal, boss, MASK_SOLID); - VectorCopy(tr.endpos, goal); - - // check for ceiling - VectorCopy(goal, start); - start[2] += 128; - // trace from goal to point above it - tr = gi.trace(goal, boxmin, boxmax, start, boss, MASK_SHOT); - // if there's a collision, we've got a ceiling over us, so stay well below it - if ((tr.fraction < 1) && (goal[2] > tr.endpos[2]-28)) - goal[2] = tr.endpos[2]-28; - - // check for minimum height; below this makes it difficult to see past the boss - if (boss->groundentity && (goal[2] < boss->absmax[2]-32)) - { - boss_eyecam(player, boss); - // delay before going back to 3rd-person view, so player isn't - // spammed by switching chasecam modes - boss->monsterinfo.trail_time = level.time + BOSS_CHASEMODE_BUFFER; // delay before switching mode - return; - } - - // move player into position - VectorCopy(goal, player->s.origin); - gi.linkentity(player); + if (boss->mtype == BOSS_TANK) { + hdist = boss->mins[1] - 96; + vdist = boss->absmax[2] + 8; + } else if (boss->mtype == BOSS_MAKRON) { + hdist = boss->mins[1] - 32; + vdist = boss->absmax[2] + 64; + } + + // get starting position + VectorCopy(boss->s.origin, start); + start[2] += 40; + + // get ideal viewing position + AngleVectors(boss->s.angles, forward, NULL, NULL); + VectorCopy(start, goal); + goal[2] = vdist; // move cam up + VectorMA(goal, hdist, forward, goal); // move cam backward + tr = gi.trace(start, boxmin, boxmax, goal, boss, MASK_SOLID); + VectorCopy(tr.endpos, goal); + + // check for ceiling + VectorCopy(goal, start); + start[2] += 128; + // trace from goal to point above it + tr = gi.trace(goal, boxmin, boxmax, start, boss, MASK_SHOT); + // if there's a collision, we've got a ceiling over us, so stay well below it + if ((tr.fraction < 1) && (goal[2] > tr.endpos[2] - 28)) + goal[2] = tr.endpos[2] - 28; + + // check for minimum height; below this makes it difficult to see past the boss + if (boss->groundentity && (goal[2] < boss->absmax[2] - 32)) { + boss_eyecam(player, boss); + // delay before going back to 3rd-person view, so player isn't + // spammed by switching chasecam modes + boss->monsterinfo.trail_time = level.time + BOSS_CHASEMODE_BUFFER; // delay before switching mode + return; + } + + // move player into position + VectorCopy(goal, player->s.origin); + gi.linkentity(player); } -qboolean boss_findtarget (edict_t *boss) -{ - edict_t *target = NULL; - - while ((target = findclosestradius_targets(target, boss, BOSS_TARGET_RADIUS)) != NULL) - { - if (!G_ValidTarget_Lite(boss, target, true)) - continue; - if (!infront(boss, target)) - continue; - boss->enemy = target; - //if (target->client) - // gi.dprintf("found %s\n", target->client->pers.netname); - //else - // gi.dprintf("found target %s\n", target->classname); - // gi.sound (boss, CHAN_WEAPON, gi.soundindex ("tank/sight1.wav"), 1, ATTN_NORM, 0); - return true; - } - return false; +qboolean boss_findtarget(edict_t *boss) { + edict_t *target = NULL; + + while ((target = findclosestradius_targets(target, boss, BOSS_TARGET_RADIUS)) != NULL) { + if (!G_ValidTarget_Lite(boss, target, true)) + continue; + if (!infront(boss, target)) + continue; + boss->enemy = target; + //if (target->client) + // gi.dprintf("found %s\n", target->client->pers.netname); + //else + // gi.dprintf("found target %s\n", target->classname); + // gi.sound (boss, CHAN_WEAPON, gi.soundindex ("tank/sight1.wav"), 1, ATTN_NORM, 0); + return true; + } + return false; } -qboolean boss_checkstatus (edict_t *self) -{ - if (!self->activator || !self->activator->inuse) - { - M_Remove(self, false, true); - gi.dprintf("WARNING: boss_checkstatus() removed player-less boss!\n"); - return false; - } - - M_WorldEffects (self); - M_CatagorizePosition (self); - //M_SetEffects (self); - - if (level.time > self->wait) - { - if (self->health <= (0.1*self->max_health)) - safe_centerprintf(self->owner, "***HEALTH LEVEL CRITICAL***\n"); - else if (self->health <= (0.3*self->max_health)) - safe_centerprintf(self->owner, "Low health warning.\n"); - self->wait = level.time + BOSS_STATUS_DELAY; - } - - // monitor boss idle frames - if (!self->style) - self->monsterinfo.idle_frames++; - else - self->monsterinfo.idle_frames = 0; - - //if (self->mtype != P_TANK && !self->activator->myskills.administrator)//4.2 player-tank exception - // self->activator->client->ability_delay = level.time + 1; // don't let them use abilities! - return true; +qboolean boss_checkstatus(edict_t *self) { + if (!self->activator || !self->activator->inuse) { + M_Remove(self, false, true); + gi.dprintf("WARNING: boss_checkstatus() removed player-less boss!\n"); + return false; + } + + M_WorldEffects(self); + M_CatagorizePosition(self); + //M_SetEffects (self); + + if (level.time > self->wait) { + if (self->health <= (0.1 * self->max_health)) + safe_centerprintf(self->owner, "***HEALTH LEVEL CRITICAL***\n"); + else if (self->health <= (0.3 * self->max_health)) + safe_centerprintf(self->owner, "Low health warning.\n"); + self->wait = level.time + BOSS_STATUS_DELAY; + } + + // monitor boss idle frames + if (!self->style) + self->monsterinfo.idle_frames++; + else + self->monsterinfo.idle_frames = 0; + + //if (self->mtype != P_TANK && !self->activator->myskills.administrator)//4.2 player-tank exception + // self->activator->client->ability_delay = level.time + 1; // don't let them use abilities! + return true; } -void boss_regenerate (edict_t *self) -{ - int health, armor, regen_frames; - - if (self->waterlevel > 0) - return; // boss can't regenerate in water (too cheap!) - - if (self->monsterinfo.idle_frames) - regen_frames = BOSS_REGEN_IDLE_FRAMES; - else - regen_frames = BOSS_REGEN_ACTIVE_FRAMES; - - health = self->max_health/regen_frames; - if (self->health < self->max_health) - self->health += health; - if (self->health > self->max_health) - self->health = self->max_health; - - if (self->health >= 0.3*self->max_health) - self->s.skinnum &= ~1; // use normal skin - - if (!self->monsterinfo.power_armor_type) - return; - armor = self->monsterinfo.max_armor/regen_frames; - if (self->monsterinfo.power_armor_power < self->monsterinfo.max_armor) - self->monsterinfo.power_armor_power += armor; - if (self->monsterinfo.power_armor_power > self->monsterinfo.max_armor) - self->monsterinfo.power_armor_power = self->monsterinfo.max_armor; +void boss_regenerate(edict_t *self) { + int health, armor, regen_frames; + + if (self->waterlevel > 0) + return; // boss can't regenerate in water (too cheap!) + + if (self->monsterinfo.idle_frames) + regen_frames = BOSS_REGEN_IDLE_FRAMES; + else + regen_frames = BOSS_REGEN_ACTIVE_FRAMES; + + health = self->max_health / regen_frames; + if (self->health < self->max_health) + self->health += health; + if (self->health > self->max_health) + self->health = self->max_health; + + if (self->health >= 0.3 * self->max_health) + self->s.skinnum &= ~1; // use normal skin + + if (!self->monsterinfo.power_armor_type) + return; + armor = self->monsterinfo.max_armor / regen_frames; + if (self->monsterinfo.power_armor_power < self->monsterinfo.max_armor) + self->monsterinfo.power_armor_power += armor; + if (self->monsterinfo.power_armor_power > self->monsterinfo.max_armor) + self->monsterinfo.power_armor_power = self->monsterinfo.max_armor; } -qboolean SkipFrame (int frame, int *skip_frames) -{ - int i; +qboolean SkipFrame(int frame, int *skip_frames) { + int i; - for (i=0; skip_frames[i]; i++) { - if (frame == skip_frames[i]) - return true; - } - return false; + for (i = 0; skip_frames[i]; i++) { + if (frame == skip_frames[i]) + return true; + } + return false; } -void G_RunFrames1 (edict_t *ent, int start_frame, int end_frame, int *skip_frames, qboolean reverse) -{ - int next_frame=ent->s.frame; - - if (reverse) - next_frame = ent->s.frame-1; - else - next_frame = ent->s.frame+1; - - while (ent->s.frame != next_frame) - { - if (reverse) // run frames backwards - { - if (skip_frames && SkipFrame(next_frame, skip_frames)) // skip this frame - { - next_frame--; - continue; - } - if ((next_frame >= start_frame) && (next_frame <= end_frame)) - ent->s.frame=next_frame; - else - ent->s.frame = next_frame = end_frame; - } - else - { - if (skip_frames && SkipFrame(next_frame, skip_frames)) - { - next_frame++; - continue; - } - if ((next_frame <= end_frame) && (next_frame >= start_frame)) - ent->s.frame=next_frame; - else - ent->s.frame = next_frame = start_frame; - } - } -} \ No newline at end of file +void G_RunFrames1(edict_t *ent, int start_frame, int end_frame, int *skip_frames, qboolean reverse) { + int next_frame = ent->s.frame; + + if (reverse) + next_frame = ent->s.frame - 1; + else + next_frame = ent->s.frame + 1; + + while (ent->s.frame != next_frame) { + if (reverse) // run frames backwards + { + if (skip_frames && SkipFrame(next_frame, skip_frames)) // skip this frame + { + next_frame--; + continue; + } + if ((next_frame >= start_frame) && (next_frame <= end_frame)) + ent->s.frame = next_frame; + else + ent->s.frame = next_frame = end_frame; + } else { + if (skip_frames && SkipFrame(next_frame, skip_frames)) { + next_frame++; + continue; + } + if ((next_frame <= end_frame) && (next_frame >= start_frame)) + ent->s.frame = next_frame; + else + ent->s.frame = next_frame = start_frame; + } + } +} diff --git a/src/entities/boss_makron.c b/src/entities/boss_makron.c index ba760c52..afd721e1 100644 --- a/src/entities/boss_makron.c +++ b/src/entities/boss_makron.c @@ -38,7 +38,7 @@ void boss_makron_sounds (edict_t *self) void boss_makron_idle (edict_t *self) { - G_RunFrames(self, MAKRON_FRAMES_STAND_START, MAKRON_FRAMES_STAND_END, false); + G_RunFrames(self, MAKRON_FRAMES_STAND_START, MAKRON_FRAMES_STAND_END, false, true); } void boss_makron_locktarget (edict_t *self) @@ -181,9 +181,9 @@ void boss_makron_think (edict_t *self) else if (self->style == FRAMES_ATTACK) { if (self->owner->client->weapon_mode) - G_RunFrames(self, MAKRON_FRAMES_BFG_START, MAKRON_FRAMES_BFG_END, false); + G_RunFrames(self, MAKRON_FRAMES_BFG_START, MAKRON_FRAMES_BFG_END, false, true); else - G_RunFrames(self, MAKRON_FRAMES_CHAIN_START, MAKRON_FRAMES_CHAIN_END, false); + G_RunFrames(self, MAKRON_FRAMES_CHAIN_START, MAKRON_FRAMES_CHAIN_END, false, true); boss_makron_attack(self); } else diff --git a/src/entities/boss_tank.c b/src/entities/boss_tank.c index a59fed04..7852a80d 100644 --- a/src/entities/boss_tank.c +++ b/src/entities/boss_tank.c @@ -120,7 +120,7 @@ void boss_tank_attack (edict_t *ent) void boss_idle (edict_t *self) { - G_RunFrames(self, TANK_FRAMES_START_STAND, TANK_FRAMES_END_STAND, false); + G_RunFrames(self, TANK_FRAMES_START_STAND, TANK_FRAMES_END_STAND, false, true); } void boss_tank_think (edict_t *self) @@ -139,15 +139,15 @@ void boss_tank_think (edict_t *self) self->monsterinfo.trail_time = level.time + 1; // stay in eye-cam if (self->style == FRAMES_RUN_FORWARD) - G_RunFrames(self, TANK_FRAMES_START_WALK, TANK_FRAMES_END_WALK, false); + G_RunFrames(self, TANK_FRAMES_START_WALK, TANK_FRAMES_END_WALK, false, true); else if (self->style == FRAMES_RUN_BACKWARD) - G_RunFrames(self, TANK_FRAMES_START_WALK, TANK_FRAMES_END_WALK, true); + G_RunFrames(self, TANK_FRAMES_START_WALK, TANK_FRAMES_END_WALK, true, true); else if (self->style == FRAMES_ATTACK) { if (self->owner->client->weapon_mode) - G_RunFrames(self, TANK_FRAMES_START_PUNCH, TANK_FRAMES_END_PUNCH, false); + G_RunFrames(self, TANK_FRAMES_START_PUNCH, TANK_FRAMES_END_PUNCH, false, true); else - G_RunFrames(self, TANK_FRAMES_START_ROCKET, TANK_FRAMES_END_ROCKET, false); + G_RunFrames(self, TANK_FRAMES_START_ROCKET, TANK_FRAMES_END_ROCKET, false, true); } else boss_idle(self); diff --git a/src/entities/drone/baron_fire.c b/src/entities/drone/baron_fire.c index dd4c833a..eb88d9b1 100644 --- a/src/entities/drone/baron_fire.c +++ b/src/entities/drone/baron_fire.c @@ -136,7 +136,7 @@ mmove_t baron_fire_move_pain = { FRAME_pain101, FRAME_pain106, baron_fire_frames void baron_fire_pain(edict_t* self, edict_t* other, float kick, int damage) { - double rng = random(); + const double rng = random(); //if (self->health < (self->max_health / 2)) // self->s.skinnum = 1; @@ -188,7 +188,7 @@ void baron_fire_check_landing(edict_t* self) void baron_fire_jump(edict_t* self) { - int speed = 1000; + const int speed = 1000; vec3_t forward, start; //gi.dprintf("%d: baron_fire_jump %d\n", (int)(level.framenum), self->s.frame); @@ -235,7 +235,7 @@ mmove_t baron_fire_move_jump = { FRAME_jump01, FRAME_jump16, baron_fire_frames_j void baron_fire_meteor(edict_t* self) { int damage, radius, speed; - float slvl = drone_damagelevel(self); + const float slvl = drone_damagelevel(self); if (!G_EntExists(self->enemy)) return; @@ -288,7 +288,7 @@ mmove_t baron_fire_move_crush = { FRAME_crush01, FRAME_crush23, baron_fire_frame void flame_think(edict_t* self) { if (self->style != 1 && self->s.frame > 20) - G_RunFrames(self, 21, 32, false); // burning frames + G_RunFrames(self, 21, 32, false, true); // burning frames else self->s.frame++; // ignite frames @@ -386,7 +386,7 @@ void circle_of_flames(edict_t* self, int count, int damage, int burn_damage, flo void fire_baron_cof_attack(edict_t* self) { int damage, burn; - float slvl = drone_damagelevel(self); + const float slvl = drone_damagelevel(self); damage = METEOR_INITIAL_DMG + METEOR_ADDON_DMG * slvl; burn = 0.1 * damage; @@ -422,7 +422,7 @@ void baron_fire_fireball(edict_t* self) if (!G_EntExists(self->enemy)) return; - float slvl = drone_damagelevel(self); + const float slvl = drone_damagelevel(self); damage = FIREBALL_INITIAL_DAMAGE + FIREBALL_ADDON_DAMAGE * slvl; radius = FIREBALL_INITIAL_RADIUS + FIREBALL_ADDON_RADIUS * slvl; @@ -466,9 +466,9 @@ void baron_fire_attack_sound(edict_t* self) void baron_fire_stand_attack(edict_t* self) { - float zDelta = fabs(self->absmin[2] - self->enemy->absmin[2]); - float dist = entdist(self, self->enemy); - float r = random(); + const float zDelta = fabs(self->absmin[2] - self->enemy->absmin[2]); + const float dist = entdist(self, self->enemy); + const float r = random(); if (dist <= 512) { @@ -485,9 +485,9 @@ void baron_fire_stand_attack(edict_t* self) void baron_fire_move_attack(edict_t* self) { - float zDelta = fabs(self->absmin[2] - self->enemy->absmin[2]); - float dist = entdist(self, self->enemy); - float r = random(); + const float zDelta = fabs(self->absmin[2] - self->enemy->absmin[2]); + const float dist = entdist(self, self->enemy); + const float r = random(); if (dist <= 256) { diff --git a/src/entities/drone/drone_ai.c b/src/entities/drone/drone_ai.c index a6623bfb..d0a3b89b 100644 --- a/src/entities/drone/drone_ai.c +++ b/src/entities/drone/drone_ai.c @@ -15,7 +15,6 @@ #define DRONE_DEBUG 0 // set to 1 to enable drone AI debugging qboolean drone_ValidChaseTarget (edict_t *self, edict_t *target); -float distance (vec3_t p1, vec3_t p2); edict_t *SpawnGoalEntity (edict_t *ent, vec3_t org); void drone_ai_checkattack (edict_t *self); qboolean drone_findtarget (edict_t *self, qboolean force); @@ -74,7 +73,7 @@ void ai_eval_targets() { VectorSubtract(potential_targets[i]->s.origin, potential_targets[j]->s.origin, eorg); // make use of that symmetry - float len = VectorLengthSqr(eorg); + const float len = VectorLengthSqr(eorg); //gi.dprintf("%s %s distance to %s %s is %.0f\n", potential_targets[i]->classname, V_GetMonsterName(potential_targets[i]), potential_targets[j]->classname, V_GetMonsterName(potential_targets[j]), len); potential_target_distances[i][j] = len; potential_target_distances[j][i] = len; @@ -116,7 +115,7 @@ edict_t *findclosestradius_targets(edict_t *prev_ed, edict_t* self, float rad) for (int i = 0; i < potential_target_count; i++) { edict_t* from = potential_targets[i]; - float vlen = potential_target_distances[self->monsterinfo.target_index][i]; + const float vlen = potential_target_distances[self->monsterinfo.target_index][i]; /*for (int j = 0; j < 3; j++) eorg[j] = self->s.origin[j] - (from->s.origin[j] + (from->mins[j] + from->maxs[j])*0.5); @@ -468,7 +467,7 @@ qboolean drone_heartarget (edict_t *target) return true; // target used an ability - if (target->client->ability_delay + 0.4 >= level.time) + if (target->client->ability_delay + (0.4 / FRAMETIME) >= level.time) return true; return false; @@ -593,11 +592,12 @@ qboolean drone_findtarget (edict_t *self, qboolean force) if (level.time < pregame_time->value) return false; // pre-game time + // if a monster hasn't found a target for awhile, it becomes less alert // and searches less often, freeing up CPU cycles if (!(self->monsterinfo.aiflags & AI_STAND_GROUND) - && self->monsterinfo.idle_frames > DRONE_SLEEP_FRAMES) - frames = (int)(0.4 / FRAMETIME); + && self->monsterinfo.idle_frames > qf2sf(DRONE_SLEEP_FRAMES)) + frames = qf2sf(DRONE_FINDTARGET_FRAMES * 5); else frames = qf2sf(DRONE_FINDTARGET_FRAMES); @@ -707,7 +707,7 @@ void drone_ai_idle (edict_t *self) // world monsters suicide if they haven't found an enemy in awhile if (self->activator && !self->activator->client && !(self->monsterinfo.aiflags & AI_STAND_GROUND) - && (self->monsterinfo.idle_frames > DRONE_SUICIDE_FRAMES)) + && (self->monsterinfo.idle_frames > qf2sf(DRONE_SUICIDE_FRAMES))) { if (self->monsterinfo.control_cost >= M_TANK_CONTROL_COST) // we're a boss self->activator->num_sentries--; @@ -1685,7 +1685,7 @@ qboolean M_CanCircleStrafe (edict_t *self, edict_t *target) if (entdist(self, target) > 256) return false; // target must be within +/- 18 units (1 step) on the Z axis - if (!self->flags & FL_FLY && fabs(self->absmin[2] - target->absmin[2]) > 18) + if (!(self->flags & FL_FLY) && fabs(self->absmin[2] - target->absmin[2]) > 18) return false; // check if anything is blocking our attack G_EntMidPoint(self, start); @@ -1834,11 +1834,11 @@ void drone_ai_run1 (edict_t *self, float dist) return; } - if (DRONE_DEBUG) - { - if (self->monsterinfo.last_sighting) - gi.dprintf("drone last sighting: %f %f %f\n", self->monsterinfo.last_sighting[0], self->monsterinfo.last_sighting[1], self->monsterinfo.last_sighting[2]); - } + // if (DRONE_DEBUG) + // { + // if (self->monsterinfo.last_sighting) + // gi.dprintf("drone last sighting: %f %f %f\n", self->monsterinfo.last_sighting[0], self->monsterinfo.last_sighting[1], self->monsterinfo.last_sighting[2]); + // } /* az note 2: move towards last sighting */ // goal position is within +/- 1 step of our elevation and we have a clear line of sight //FIXME: if goal entity is taller than us (e.g. jorg), this wont work very well! @@ -1849,16 +1849,17 @@ void drone_ai_run1 (edict_t *self, float dist) else maxZ = 18;// step size - if (self->monsterinfo.last_sighting) - { - // if we lose line-of-sight to the last known coordinates of our goal, then delay any rettempt of a direct approach - // this is to prevent rapidly going back and forth between last sighting coordinates and waypoints, causing the monster to get stuck - if ((clearPath = G_IsClearPath(self, MASK_SOLID, self->s.origin, self->monsterinfo.last_sighting)) == false) - self->monsterinfo.trail_time = level.time + 2.0; - } + // if (self->monsterinfo.last_sighting) + // { + // // if we lose line-of-sight to the last known coordinates of our goal, then delay any rettempt of a direct approach + // // this is to prevent rapidly going back and forth between last sighting coordinates and waypoints, causing the monster to get stuck + // if ((clearPath = G_IsClearPath(self, MASK_SOLID, self->s.origin, self->monsterinfo.last_sighting)) == false) + // self->monsterinfo.trail_time = level.time + 2.0; + // } if (DRONE_DEBUG) { + /* if (self->monsterinfo.last_sighting) { float Zdelta = fabs(self->s.origin[2] - self->monsterinfo.last_sighting[2]); @@ -1869,6 +1870,7 @@ void drone_ai_run1 (edict_t *self, float dist) { gi.dprintf("can't move to goal with no last sighting!\n"); } + */ } @@ -2456,34 +2458,23 @@ void drone_togglelight (edict_t *self) { if (self->health > 0) { - if (level.daytime && self->flashlight) - { - // turn light off - G_FreeEdict(self->flashlight); - self->flashlight = NULL; - return;; - } - else if (!level.daytime && !self->flashlight) - { - FL_make(self); - } + if (level.daytime && FL_exists(self)) + FL_toggle(self); + else if (!level.daytime && !FL_exists(self)) + FL_toggle(self); } else { // turn off the flashlight if we're dead! - if (self->flashlight) - { - G_FreeEdict(self->flashlight); - self->flashlight = NULL; - return; - } + if (FL_exists(self)) + FL_toggle(self); } } void drone_dodgeprojectiles (edict_t *self) { - qboolean alive = self->health > 0; - qboolean can_dodge = self->monsterinfo.dodge && (self->monsterinfo.aiflags & AI_DODGE); - qboolean stand_ground = (self->monsterinfo.aiflags & AI_STAND_GROUND); + const qboolean alive = self->health > 0; + const qboolean can_dodge = self->monsterinfo.dodge && (self->monsterinfo.aiflags & AI_DODGE); + const qboolean stand_ground = (self->monsterinfo.aiflags & AI_STAND_GROUND); // dodge incoming projectiles if (alive && can_dodge && !stand_ground) // don't dodge if we are holding position @@ -2605,7 +2596,7 @@ void M_UpdateLastSight (edict_t *self) void drone_return(edict_t* self) { - edict_t* leader = self->monsterinfo.leader; + const edict_t* leader = self->monsterinfo.leader; if (self->mtype != M_DECOY) return; @@ -2746,26 +2737,7 @@ void drone_think (edict_t *self) // this must come before M_MoveFrame() because a monster's dead // function may set the nextthink to 0 - self->nextthink = level.time + 0.1; // run at 10 frames/sec - /* - if (self->mtype == M_DECOY && level.framenum % 10) - { - self->model = self->activator->model; - self->s.skinnum = self->activator->s.skinnum; - self->s.modelindex = self->activator->s.modelindex; - self->s.modelindex2 = self->activator->s.modelindex2; - self->s.modelindex3 = self->activator->s.modelindex3; - self->s.modelindex4 = self->activator->s.modelindex4; - - if (self->activator && self->activator->inuse) - { - gi.dprintf("class skin: %s\n", V_GetClassModel(self->activator)); - gi.dprintf("activator model: %s skinnum: %d modelindex: %d modelindex2: %d\n", self->activator->model, self->activator->s.skinnum, self->activator->s.modelindex, self->activator->s.modelindex2); - gi.dprintf("decoy model: %s skinnum: %d modelindex: %d modelindex2: %d\n", self->model, self->s.skinnum, self->s.modelindex, self->s.modelindex2); - } - else - gi.dprintf("no activator\n"); - }*/ + self->nextthink = level.time + FRAMETIME; // run at 10 frames/sec M_MoveFrame (self); M_CatagorizePosition (self); diff --git a/src/entities/drone/drone_berserk.c b/src/entities/drone/drone_berserk.c index 78c336c8..8634a934 100644 --- a/src/entities/drone/drone_berserk.c +++ b/src/entities/drone/drone_berserk.c @@ -319,7 +319,7 @@ mmove_t berserk_move_pain_long = { FRAME_painb1, FRAME_painb20, berserk_frames_p void berserk_pain(edict_t* self, edict_t* other, float kick, int damage) { - double rng = random(); + const double rng = random(); if (self->health < (self->max_health / 2)) self->s.skinnum = 1; @@ -414,7 +414,7 @@ void berserk_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int dama void berserk_attack (edict_t *self) { float r = random(); - float dist = entdist(self, self->enemy); + const float dist = entdist(self, self->enemy); if (dist > 128) return; diff --git a/src/entities/drone/drone_bitch.c b/src/entities/drone/drone_bitch.c index f14e209c..e564f0f3 100644 --- a/src/entities/drone/drone_bitch.c +++ b/src/entities/drone/drone_bitch.c @@ -479,7 +479,7 @@ void myChickFireball (edict_t *self) if (!G_EntExists(self->enemy)) return; - float slvl = drone_damagelevel(self); + const float slvl = drone_damagelevel(self); damage = 50 + 15 * slvl; // dmg: myChickFireball flame_damage = 2 * slvl; // dmg: myChickFireballFlames @@ -672,7 +672,7 @@ void mychick_reslash(edict_t *self) { if (self->enemy->health > 0) { - if (entdist (self, self->enemy) == 32) + if (entdist (self, self->enemy) == 32) { if (random() <= 0.9) { self->monsterinfo.currentmove = &mychick_move_slash; @@ -683,6 +683,7 @@ void mychick_reslash(edict_t *self) self->monsterinfo.currentmove = &mychick_move_end_slash; return; } + } } self->monsterinfo.currentmove = &mychick_move_end_slash; } @@ -710,8 +711,8 @@ void mychick_melee(edict_t *self) void chick_fire_attack (edict_t *self) { - float r = random(); - float range = entdist(self, self->enemy); + const float r = random(); + const float range = entdist(self, self->enemy); // medium-long range if (range <= 768) @@ -828,7 +829,7 @@ mmove_t mychick_move_pain_long = { FRAME_pain301, FRAME_pain321, mychick_frames_ void mychick_pain(edict_t* self, edict_t* other, float kick, int damage) { - double rng = random(); + const double rng = random(); if (self->health < (self->max_health / 2)) self->s.skinnum = 1; diff --git a/src/entities/drone/drone_decoy.c b/src/entities/drone/drone_decoy.c index 3b5d524c..bf5a03bf 100644 --- a/src/entities/drone/drone_decoy.c +++ b/src/entities/drone/drone_decoy.c @@ -294,8 +294,8 @@ void decoy_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage if(damage > 0 && self->activator && self->activator->inuse)// && getTalentLevel(self->activator, TALENT_EXPLODING_DECOY) != -1) { //int talentLevel = vrx_get_talent_level(self->activator, TALENT_EXPLODING_DECOY); - int decoyDamage = 0.2 * self->max_health; - int decoyRadius = 100 + 5 * self->monsterinfo.level;// +talentLevel * 25; + const int decoyDamage = 0.2 * self->max_health; + const int decoyRadius = 100 + 5 * self->monsterinfo.level;// +talentLevel * 25; T_RadiusDamage(self, self->activator, decoyDamage, self, decoyRadius, MOD_DECOY); @@ -357,7 +357,7 @@ mmove_t actor_move_attack = {FRAME_attack1, FRAME_attack8, actor_frames_attack, void actor_attack(edict_t *self) { int weap_index; - float dist = entdist(self, self->enemy); + const float dist = entdist(self, self->enemy); // we're dying, get up close! if (self->health < 0.3 * self->max_health) @@ -400,8 +400,8 @@ void actor_attack(edict_t *self) char* V_GetClassSkin(edict_t* ent); void decoy_assign_class_skin(edict_t* self) { - int skin_number = maxclients->value + self->s.number - 1; - char* c_skin = va("decoy\\%s\0", V_GetClassSkin(self->activator)); + const int skin_number = maxclients->value + self->s.number - 1; + const char* c_skin = va("decoy\\%s\0", V_GetClassSkin(self->activator)); gi.configstring(CS_PLAYERSKINS + skin_number, c_skin); self->s.skinnum = skin_number; //gi.dprintf("set class skin %s\n", c_skin); @@ -410,7 +410,7 @@ void decoy_assign_class_skin(edict_t* self) //FIXME: this won't work correctly for player morphs--need to default to some other model, either class model or grunt void decoy_copy (edict_t *self) { - edict_t *target = self->activator; + const edict_t *target = self->activator; if (!self->activator || !self->activator->inuse || !self->activator->client) return; diff --git a/src/entities/drone/drone_gladiator.c b/src/entities/drone/drone_gladiator.c index dfcf67fa..85916dcf 100644 --- a/src/entities/drone/drone_gladiator.c +++ b/src/entities/drone/drone_gladiator.c @@ -294,7 +294,7 @@ mmove_t gladiator_move_attack_gun = {FRAME_attack4, FRAME_attack8, gladiator_fra void gladiator_lightning_attack (edict_t *self) { - float r = random(); + const float r = random(); // medium range (30% chance LS, 70% chance CL) if (entdist(self, self->enemy) <= 512) diff --git a/src/entities/drone/drone_gunner.c b/src/entities/drone/drone_gunner.c index 399dfd39..b9efb675 100644 --- a/src/entities/drone/drone_gunner.c +++ b/src/entities/drone/drone_gunner.c @@ -426,8 +426,8 @@ void gunner_stand_attack (edict_t *self) void gunner_attack (edict_t *self) { - float r = random(); - float dist = entdist(self, self->enemy); + const float r = random(); + const float dist = entdist(self, self->enemy); // short range (20% chance grenade, 80% chance run and shoot) if (dist <= 128) @@ -628,7 +628,7 @@ mmove_t mygunnermove_pain_short = { FRAME_pain301, FRAME_pain305, mygunnerframes void mygunner_pain(edict_t* self, edict_t* other, float kick, int damage) { - double rng = random(); + const double rng = random(); if (self->health < (self->max_health / 2)) self->s.skinnum = 1; diff --git a/src/entities/drone/drone_infantry.c b/src/entities/drone/drone_infantry.c index 3e628b59..6c05c58c 100644 --- a/src/entities/drone/drone_infantry.c +++ b/src/entities/drone/drone_infantry.c @@ -213,7 +213,7 @@ void Infantry20mm(edict_t* self) { vec3_t start, forward, right, vec; int damage, flash_number; - float range = M_20MM_RANGE_BASE + M_20MM_RANGE_ADDON * drone_damagelevel(self); + const float range = M_20MM_RANGE_BASE + M_20MM_RANGE_ADDON * drone_damagelevel(self); damage = M_20MM_DMG_BASE + M_20MM_DMG_ADDON * drone_damagelevel(self); if (M_20MM_DMG_MAX && damage > M_20MM_DMG_MAX) @@ -285,7 +285,7 @@ mmove_t infantry_move_pain2 = { FRAME_pain201, FRAME_pain210, infantry_frames_pa void infantry_pain(edict_t* self, edict_t* other, float kick, int damage) { - double rng = random(); + const double rng = random(); if (self->health < (self->max_health / 2)) self->s.skinnum = 1; @@ -607,15 +607,15 @@ void infantry_grenade(edict_t* self) if (M_GRENADELAUNCHER_SPEED_MAX && speed > M_GRENADELAUNCHER_SPEED_MAX) speed = M_GRENADELAUNCHER_SPEED_MAX; - float timer = 2.5; + const float timer = 2.5; int damage = M_GRENADELAUNCHER_DMG_BASE + M_GRENADELAUNCHER_DMG_ADDON * drone_damagelevel(self); if (M_GRENADELAUNCHER_DMG_MAX && damage > M_GRENADELAUNCHER_DMG_MAX) damage = M_GRENADELAUNCHER_DMG_MAX; - float damage_radius = 150; - int radius_damage = 100; - float accuracy = 0.8; + const float damage_radius = 150; + const int radius_damage = 100; + const float accuracy = 0.8; MonsterAim(self, accuracy, speed, true, MZ2_INFANTRY_MACHINEGUN_1, forward, start); @@ -640,8 +640,8 @@ mmove_t infantry_move_attack_grenade = { FRAME_attak201, FRAME_attak208, infantr void infantry_attack(edict_t* self) { int maxrange; - int range = entdist(self, self->enemy); - float r = random(); + const int range = entdist(self, self->enemy); + const float r = random(); if (self->monsterinfo.aiflags & AI_STAND_GROUND) { diff --git a/src/entities/drone/drone_medic.c b/src/entities/drone/drone_medic.c index 5dd26018..0c14c992 100644 --- a/src/entities/drone/drone_medic.c +++ b/src/entities/drone/drone_medic.c @@ -177,7 +177,7 @@ void mymedic_run (edict_t *self) void mymedic_fire_blaster (edict_t *self) { int effect, damage; - float speed = 2000; // speed: medic_blaster + const float speed = 2000; // speed: medic_blaster vec3_t forward, start; qboolean bounce = false; @@ -700,7 +700,7 @@ void M_Reanimate (edict_t *ent, edict_t *target, int r_level, float r_modifier, } else if ((!strcmp(target->classname, "bodyque") || !strcmp(target->classname, "player"))) { - int random=GetRandom(1, 3); + const int random=GetRandom(1, 3); vec3_t start; // if the summoner is a player, check for sufficient monster slots diff --git a/src/entities/drone/drone_misc.c b/src/entities/drone/drone_misc.c index 8404706c..1af314b6 100644 --- a/src/entities/drone/drone_misc.c +++ b/src/entities/drone/drone_misc.c @@ -94,7 +94,7 @@ void DroneList_Remove(edict_t *ent) { // is monster index within valid range of list? if (ent->monsterinfo.dronelist_index >= 0 && ent->monsterinfo.dronelist_index < DroneCount) { - int index = ent->monsterinfo.dronelist_index; + const int index = ent->monsterinfo.dronelist_index; // have we found this monster within the drone list? if (DroneList[index] == ent) { // follows the same logic as player spawn list DroneCount--; // reduce the count, and hence, the length of the list, by 1 @@ -174,7 +174,7 @@ void DroneList_Print(edict_t* ent, edict_t *owner) float drone_damagelevel(const edict_t* ent) { - int level = ent->monsterinfo.level; + const int level = ent->monsterinfo.level; // player monsters don't get softcapped if (G_GetClient(ent)) @@ -737,7 +737,7 @@ void vrx_roll_to_make_champion(edict_t *drone, int *drone_type) if ( (!invasion->value && GetRandom(1, 100) <= 33) // 33% chance to spawn a special champion || (invasion->value == 2 && GetRandom(1, 100) <= 5) ) // 5% chance in invasion. { - int r = GetRandom(1, 7); + const int r = GetRandom(1, 7); switch (r) { @@ -828,6 +828,7 @@ edict_t *vrx_create_drone_from_ent(edict_t *drone, edict_t *ent, int drone_type, drone->monsterinfo.control_cost = M_DEFAULT_CONTROL_COST; drone->monsterinfo.cost = M_DEFAULT_COST; drone->monsterinfo.sight_range = 1024; // 3.56 default sight range for finding targets + drone->monsterinfo.frametimer = level.framenum; drone->inuse = true; switch(drone_type) // not to be confused with mtype! @@ -1446,7 +1447,7 @@ qboolean infov (edict_t *self, edict_t *other, int degrees) // return a random double in [0.0, 1.0) double randfrac(void) { - double res = (rand() % RAND_MAX) / (double)RAND_MAX; + const double res = (rand() % RAND_MAX) / (double)RAND_MAX; return res; } @@ -1732,7 +1733,7 @@ qboolean M_Regenerate (edict_t *self, int regen_frames, int delay, float mult, q // heal them if they are weakened if (self->health < max_health) { - int health_needed = max_health - self->health; + const int health_needed = max_health - self->health; if (health > health_needed) health = health_needed; self->health += health; @@ -1814,8 +1815,8 @@ qboolean M_Regenerate (edict_t *self, int regen_frames, int delay, float mult, q { if (self->client) { - int ammoIndex = G_GetAmmoIndexByWeaponIndex(G_GetRespawnWeaponIndex(self)); - int maxAmmo = MaxAmmoType(self, ammoIndex) * mult; + const int ammoIndex = G_GetAmmoIndexByWeaponIndex(G_GetRespawnWeaponIndex(self)); + const int maxAmmo = MaxAmmoType(self, ammoIndex) * mult; if (AmmoLevel(self, ammoIndex) < mult) { @@ -2863,7 +2864,7 @@ void M_DelayNextAttack(edict_t* self, float delay, qboolean add_attack_frames) if (add_attack_frames) { int startframe; - mmove_t* move = self->monsterinfo.currentmove; + const mmove_t* move = self->monsterinfo.currentmove; // if we haven't begun this move yet or we are at the tail-end of // an attack (re-attack) then start at the first frame diff --git a/src/entities/drone/drone_move.c b/src/entities/drone/drone_move.c index 0c651db1..6aff8075 100644 --- a/src/entities/drone/drone_move.c +++ b/src/entities/drone/drone_move.c @@ -2,7 +2,6 @@ #include "g_local.h" -#define STEPSIZE 18 /* ============= @@ -252,7 +251,7 @@ qboolean M_Move (edict_t *ent, vec3_t move, qboolean relink) { vec3_t oldorg, neworg, end; trace_t trace;//, tr; - float stepsize=STEPSIZE; + const float stepsize=STEPSIZE; // try the move VectorCopy (ent->s.origin, oldorg); @@ -339,7 +338,7 @@ qboolean M_MoveVertical(edict_t* ent, vec3_t dest, vec3_t neworg) { float dz; // delta Z float idealZ; // ideal Z position, either a destination waypoint/node or a goal entity - float zSpeed = 8; // Z movement speed + const float zSpeed = 8; // Z movement speed vec3_t end, goalpos; trace_t trace; //qboolean stopOnCollision=false; @@ -353,7 +352,7 @@ qboolean M_MoveVertical(edict_t* ent, vec3_t dest, vec3_t neworg) } else if (ent->goalentity) { - if (ent->goalentity = world) + if (ent->goalentity == world) return true; idealZ = ent->goalentity->s.origin[2] + 16; VectorCopy(ent->goalentity->s.origin, goalpos); @@ -1042,7 +1041,7 @@ void SV_NewChaseDir3(edict_t* actor, vec3_t goalpos, float dist) } // try other directions - if (((rand() & 3) & 1) || abs(deltay) > abs(deltax)) + if (((rand() & 3) & 1) || fabsf(deltay) > fabsf(deltax)) { tdir = d[1]; d[1] = d[2]; @@ -1160,7 +1159,7 @@ void M_ChangeYaw (edict_t *ent) return; move = ideal - current; - speed = ent->yaw_speed; + speed = ent->yaw_speed * FRAMETIME * 10; if (ideal > current) { if (move >= 180) @@ -1483,14 +1482,14 @@ M_walkmove */ qboolean M_walkmove (edict_t *ent, float yaw, float dist) { - float original_yaw=yaw;//GHz + const float original_yaw=yaw;//GHz vec3_t move; if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM))) return false; yaw = yaw*M_PI*2 / 360; - + move[0] = cos(yaw)*dist; move[1] = sin(yaw)*dist; move[2] = 0; diff --git a/src/entities/drone/drone_mutant.c b/src/entities/drone/drone_mutant.c index 95868d8b..d7fb023f 100644 --- a/src/entities/drone/drone_mutant.c +++ b/src/entities/drone/drone_mutant.c @@ -567,7 +567,7 @@ mmove_t mutant_move_pain_short2 = { FRAME_pain101, FRAME_pain105, mutant_frames_ void mutant_pain(edict_t* self, edict_t* other, float kick, int damage) { - double rng = random(); + const double rng = random(); if (self->health < (self->max_health / 2)) self->s.skinnum = 1; @@ -631,7 +631,7 @@ void init_drone_mutant (edict_t *self) sound_pain1 = gi.soundindex ("mutant/mutpain1.wav"); sound_pain2 = gi.soundindex ("mutant/mutpain2.wav"); sound_sight = gi.soundindex ("mutant/mutsght1.wav"); - 0;//sound_search = gi.soundindex ("mutant/mutsrch1.wav"); + //sound_search = gi.soundindex ("mutant/mutsrch1.wav"); sound_step1 = gi.soundindex ("mutant/step1.wav"); sound_step2 = gi.soundindex ("mutant/step2.wav"); sound_step3 = gi.soundindex ("mutant/step3.wav"); diff --git a/src/entities/drone/drone_parasite.c b/src/entities/drone/drone_parasite.c index d3d2fd32..46833522 100644 --- a/src/entities/drone/drone_parasite.c +++ b/src/entities/drone/drone_parasite.c @@ -569,7 +569,7 @@ void myparasite_melee (edict_t *self) void myparasite_pain(edict_t* self, edict_t* other, float kick, int damage) { - double rng = random(); + const double rng = random(); if (self->health < (self->max_health / 2)) self->s.skinnum = 1; diff --git a/src/entities/drone/drone_shambler.c b/src/entities/drone/drone_shambler.c index 420ee3d0..f2b13f48 100644 --- a/src/entities/drone/drone_shambler.c +++ b/src/entities/drone/drone_shambler.c @@ -60,7 +60,7 @@ void shambler_frostnova(edict_t* self) return; edict_t* target = NULL; - int damage = NOVA_DEFAULT_DAMAGE + NOVA_ADDON_DAMAGE * self->monsterinfo.level; + const int damage = NOVA_DEFAULT_DAMAGE + NOVA_ADDON_DAMAGE * self->monsterinfo.level; // nova dmg T_RadiusDamage(self, self, damage, self, FROSTNOVA_RADIUS, MOD_NOVA); @@ -206,11 +206,11 @@ void shambler_melee(edict_t* self) if (!G_EntExists(self->enemy)) return; - float dist = entdist(self, self->enemy); + const float dist = entdist(self, self->enemy); if (dist <= 100) //MELEE_DISTANCE +20 { - float r = random(); + const float r = random(); if (r > 0.6 || self->health == 600) self->monsterinfo.currentmove = &shambler_move_smash; else if (r > 0.3) @@ -302,7 +302,7 @@ static const vec3_t lightning_right_hand[] = { //attack lightning stuff static void shambler_lightning_update(edict_t* self) { - int frame_offset = self->s.frame - FRAME_magic1; + const int frame_offset = self->s.frame - FRAME_magic1; if (frame_offset >= MAX_LIGHTNING_FRAMES) { return; @@ -319,8 +319,14 @@ static void shambler_lightning_update(edict_t* self) right_pos[2] += lightning_right_hand[frame_offset][2]; gi.WriteByte(svc_temp_entity); - gi.WriteByte(TE_MONSTER_HEATBEAM); +#ifdef VRX_REPRO + gi.WriteByte(TE_LIGHTNING); + gi.WriteShort(self - g_edicts); + gi.WriteShort(0); +#else + gi.WriteByte(TE_MONSTER_HEATBEAM) gi.WriteShort(self - g_edicts); +#endif gi.WritePosition(left_pos); gi.WritePosition(right_pos); gi.multicast(left_pos, MULTICAST_PVS); @@ -407,8 +413,14 @@ void ShamblerCastLightning(edict_t* self) //unused TE_LIGHTNING, doesn't work here or any attack gi.WriteByte(svc_temp_entity); +#ifdef VRX_REPRO + gi.WriteByte(TE_LIGHTNING); + gi.WriteShort(self - g_edicts); + gi.WriteShort(0); +#else gi.WriteByte(TE_MONSTER_HEATBEAM); gi.WriteShort(self - g_edicts); +#endif gi.WritePosition(start); gi.WritePosition(tr.endpos); gi.multicast(start, MULTICAST_PVS); @@ -421,7 +433,7 @@ void ShamblerCastLightning(edict_t* self) if (tr.fraction < 1.0 && tr.ent) { //int damage = M_SHAMBLER_LIGHTNING_BASE_DMG + M_SHAMBLER_ADDON_LIGHTNING_DMG; //* self->monsterinfo.level; ? - int damage = 4 + 3 * drone_damagelevel(self); + const int damage = 4 + 3 * drone_damagelevel(self); //if (M_SHAMBLER_LIGHTNING_MAX_DMG && damage > M_SHAMBLER_LIGHTNING_MAX_DMG) // damage = M_SHAMBLER_LIGHTNING_MAX_DMG; @@ -451,7 +463,7 @@ mmove_t shambler_move_attack = { FRAME_magic1, FRAME_magic12, shambler_frames_ma static void shambler_fieryskull_update(edict_t* self) { - int frame_offset = self->s.frame - FRAME_magic1; + const int frame_offset = self->s.frame - FRAME_magic1; if (frame_offset >= MAX_LIGHTNING_FRAMES) { return; @@ -470,8 +482,15 @@ static void shambler_fieryskull_update(edict_t* self) right_pos[2] += lightning_right_hand[frame_offset][2]; gi.WriteByte(svc_temp_entity); +#ifndef VRX_REPRO gi.WriteByte(TE_MONSTER_HEATBEAM); gi.WriteShort(self - g_edicts); +#else + gi.WriteByte(TE_LIGHTNING); + gi.WriteShort(self - g_edicts); + gi.WriteShort(0); +#endif + gi.WritePosition(left_pos); gi.WritePosition(right_pos); gi.multicast(left_pos, MULTICAST_PVS); @@ -496,7 +515,7 @@ void ShamblerCastIcebolt(edict_t* self) vec3_t forward, right, up; vec3_t start_left, start_right; vec3_t aim_left, aim_right; - float accuracy = 0.8; // Aumentamos la precisión base + const float accuracy = 0.8; // Aumentamos la precisi�n base if (!G_EntIsAlive(self->enemy)) return; @@ -522,12 +541,12 @@ void ShamblerCastIcebolt(edict_t* self) start_right[2] = self->s.origin[2] + lightning_right_hand[frame_offset][2]; // Calculate damage and other parameters - float slvl = drone_damagelevel(self); - int damage = ICEBOLT_INITIAL_DAMAGE + ICEBOLT_ADDON_DAMAGE * slvl; - float damage_radius = ICEBOLT_INITIAL_RADIUS + ICEBOLT_ADDON_RADIUS * slvl; - int speed = ICEBOLT_INITIAL_SPEED + ICEBOLT_ADDON_SPEED * slvl; - int chillLevel = 2 * slvl; - float chillDuration = ICEBOLT_INITIAL_CHILL_DURATION + ICEBOLT_ADDON_CHILL_DURATION * slvl; + const float slvl = drone_damagelevel(self); + const int damage = ICEBOLT_INITIAL_DAMAGE + ICEBOLT_ADDON_DAMAGE * slvl; + const float damage_radius = ICEBOLT_INITIAL_RADIUS + ICEBOLT_ADDON_RADIUS * slvl; + const int speed = ICEBOLT_INITIAL_SPEED + ICEBOLT_ADDON_SPEED * slvl; + const int chillLevel = 2 * slvl; + const float chillDuration = ICEBOLT_INITIAL_CHILL_DURATION + ICEBOLT_ADDON_CHILL_DURATION * slvl; // Use MonsterAim for both hands MonsterAim(self, accuracy, speed, false, -1, aim_left, start_left); @@ -546,7 +565,7 @@ void ShamblerCastIcebolt(edict_t* self) static void shambler_ice_update(edict_t* self) { - int frame_offset = self->s.frame - FRAME_magic1; + const int frame_offset = self->s.frame - FRAME_magic1; if (frame_offset >= MAX_LIGHTNING_FRAMES) { return; @@ -634,7 +653,7 @@ void shambler_windupFire(edict_t* self) // lightning preparing //pre fire attack stuff static void shambler_fire_update(edict_t* self) { - int frame_offset = self->s.frame - FRAME_magic1; + const int frame_offset = self->s.frame - FRAME_magic1; if (frame_offset >= MAX_LIGHTNING_FRAMES) { return; @@ -652,7 +671,7 @@ static void shambler_fire_update(edict_t* self) VectorMA(right_pos, lightning_right_hand[frame_offset][1], r, right_pos); right_pos[2] += lightning_right_hand[frame_offset][2]; - // Crear efectos de cráneo en ambas manos + // Crear efectos de cr�neo en ambas manos edict_t* left_fire = G_Spawn(); edict_t* right_fire = G_Spawn(); @@ -713,7 +732,7 @@ void ShamblerCastSkull(edict_t* self) { vec3_t forward, right; vec3_t start_left, start_right; - float accuracy = M_PROJECTILE_ACC; + const float accuracy = M_PROJECTILE_ACC; if (!G_EntIsAlive(self->enemy)) return; @@ -739,7 +758,7 @@ void ShamblerCastSkull(edict_t* self) start_right[2] = self->s.origin[2] + lightning_right_hand[frame_offset][2]; // Calculate damage - int damage = 30 + 15 * self->monsterinfo.level; + const int damage = 30 + 15 * self->monsterinfo.level; // Fire skull from left hand MonsterAim(self, accuracy, 1200, false, -1, forward, start_left); @@ -860,8 +879,8 @@ void shambler_meleehit(edict_t* self) void shambler_attack(edict_t* self) { - float r = random(); - float dist = entdist(self, self->enemy); + const float r = random(); + const float dist = entdist(self, self->enemy); if (dist <= MELEE_DISTANCE) { diff --git a/src/entities/drone/drone_supertank.c b/src/entities/drone/drone_supertank.c index 29dce9cf..9d990e38 100644 --- a/src/entities/drone/drone_supertank.c +++ b/src/entities/drone/drone_supertank.c @@ -457,8 +457,8 @@ void supertankMachineGun (edict_t *self) void supertank_attack(edict_t *self) { - float range = entdist(self, self->enemy); - float r = random(); + const float range = entdist(self, self->enemy); + const float r = random(); // medium range if (range <= 512) diff --git a/src/entities/drone/drone_tank.c b/src/entities/drone/drone_tank.c index 6614ec54..a01c9018 100644 --- a/src/entities/drone/drone_tank.c +++ b/src/entities/drone/drone_tank.c @@ -774,7 +774,7 @@ qboolean TeleportNearTarget (edict_t *self, edict_t *target) void commander_attack (edict_t *self) { - float r = random(); + const float r = random(); float range = entdist(self, self->enemy); // short range attack @@ -822,8 +822,8 @@ void commander_attack (edict_t *self) void tank_attack(edict_t* self) { - float r = random(); - float range = entdist(self, self->enemy); + const float r = random(); + const float range = entdist(self, self->enemy); //gi.dprintf("%d tank_attack()\n", level.framenum); diff --git a/src/entities/drone/g_monster.c b/src/entities/drone/g_monster.c index 40f33684..366f9652 100644 --- a/src/entities/drone/g_monster.c +++ b/src/entities/drone/g_monster.c @@ -9,7 +9,7 @@ float vrx_increase_monster_damage_by_talent(edict_t *owner, float damage) // oblation talent provides +10-20% dmg/lv if (pvm->value) bonus = 0.2; - int talentLevel = vrx_get_talent_level(owner, TALENT_OBLATION); + const int talentLevel = vrx_get_talent_level(owner, TALENT_OBLATION); if (talentLevel > 0) damage *= 1 + bonus * talentLevel; } return damage; @@ -339,7 +339,7 @@ void monster_fire_fireball(edict_t* self) if (!G_EntExists(self->enemy)) return; - float slvl = drone_damagelevel(self); + const float slvl = drone_damagelevel(self); damage = FIREBALL_INITIAL_DAMAGE + FIREBALL_ADDON_DAMAGE * slvl; damage = vrx_increase_monster_damage_by_talent(self->activator, damage); @@ -702,7 +702,7 @@ void M_MoveFrame_Reverse (edict_t* self) } index = move->firstframe - self->s.frame; - if (move->frame[index].aifunc) + if (move->frame[index].aifunc) { if (!vrx_holdframe(self)) { self->monsterinfo.scale = 1.0; @@ -715,6 +715,7 @@ void M_MoveFrame_Reverse (edict_t* self) // we're not going anywhere! move->frame[index].aifunc(self, 0); } + } if (move->frame[index].thinkfunc && !vrx_is_frozen(self)) move->frame[index].thinkfunc(self); @@ -728,6 +729,7 @@ void M_MoveFrame (edict_t *self) // edict_t *curse; + qboolean runthink = false; if (!self->inuse) return; @@ -776,20 +778,24 @@ void M_MoveFrame (edict_t *self) } else { + if ( self->monsterinfo.frametimer <= level.framenum ) { if (!vrx_holdframe(self)) - { - self->s.frame++; - if (self->s.frame > move->lastframe) - self->s.frame = move->firstframe; + { + self->s.frame++; + if (self->s.frame > move->lastframe) + self->s.frame = move->firstframe; + } + self->monsterinfo.frametimer = level.framenum + qf2sf(1); + runthink = true; } } } index = self->s.frame - move->firstframe; - if (move->frame[index].aifunc) + if (move->frame[index].aifunc) { if (!vrx_holdframe(self)) { - self->monsterinfo.scale = 1.0; + self->monsterinfo.scale = FRAMETIME * 10; vrx_adjust_moveframe_scale(self); move->frame[index].aifunc (self, move->frame[index].dist * self->monsterinfo.scale); @@ -799,8 +805,9 @@ void M_MoveFrame (edict_t *self) // we're not going anywhere! move->frame[index].aifunc (self, 0); } + } - if (move->frame[index].thinkfunc && !vrx_is_frozen(self)) + if (move->frame[index].thinkfunc && !vrx_is_frozen(self) && runthink) move->frame[index].thinkfunc (self); } diff --git a/src/entities/drone/golem.c b/src/entities/drone/golem.c index 18614d26..b6993ecb 100644 --- a/src/entities/drone/golem.c +++ b/src/entities/drone/golem.c @@ -8,6 +8,8 @@ GOLEM #include "g_local.h" #include "../../quake2/monsterframes/golem.h" +void MonsterCommand(edict_t *ent); +void MonsterFollowMe(edict_t *ent); #define GOLEM_BACKHAND_RANGE 512 // range for backhand attack (throw rocks) #define GOLEM_AOE_ATTACK_RANGE 200 // range for punch/avalanche/stun attacks @@ -289,7 +291,7 @@ mmove_t golem_move_pain = { FRAME_pain101, FRAME_pain116, golem_frames_pain, gol void golem_pain(edict_t* self, edict_t* other, float kick, int damage) { - double rng = random(); + const double rng = random(); //if (self->health < (self->max_health / 2)) // self->s.skinnum = 1; @@ -330,10 +332,10 @@ void fire_rocks(edict_t* self, vec3_t start, vec3_t aimdir, int damage, float sp // drops rocks on nearby enemies void golem_avalanche(edict_t* self) { - int damage = 50 * self->monsterinfo.level; - float speed = 650; + const int damage = 50 * self->monsterinfo.level; + const float speed = 650; vec3_t start, end; - edict_t* e = NULL; + const edict_t* e = NULL; trace_t tr; while ((e = findradius(e, self->s.origin, GOLEM_AOE_ATTACK_RANGE)) != NULL) @@ -362,7 +364,7 @@ void golem_avalanche(edict_t* self) void golem_stunattack(edict_t* self) { qboolean found_target = false; - float stuntime = EMP_INITIAL_TIME + EMP_ADDON_TIME * self->monsterinfo.level; + const float stuntime = EMP_INITIAL_TIME + EMP_ADDON_TIME * self->monsterinfo.level; edict_t* e = NULL; while ((e = findradius(e, self->s.origin, GOLEM_AOE_ATTACK_RANGE)) != NULL) @@ -601,15 +603,15 @@ void golem_nearbyenemies(edict_t* self, float radius, int *num, int *in_front, i void golem_attack(edict_t* self) { int nearby, in_front, stunned; - float range = entdist(self, self->enemy); + const float range = entdist(self, self->enemy); // Talent: Golem Mastery - allows golem to self-heal when his health is low - int talentLevel = vrx_get_talent_level(self->activator, TALENT_GOLEM_MASTERY); - float healthFrac = (float)self->health / self->max_health; + const int talentLevel = vrx_get_talent_level(self->activator, TALENT_GOLEM_MASTERY); + const float healthFrac = (float)self->health / self->max_health; if (talentLevel > 1 && healthFrac < 0.5 && level.framenum > self->monsterinfo.regen_delay1) { //gi.dprintf("%s: healthFrac %.1f\n", __func__, healthFrac); - float chance = (1 - healthFrac) + 0.1; + const float chance = (1 - healthFrac) + 0.1; if (chance > random()) golem_flex(self); return; @@ -631,10 +633,10 @@ void golem_attack(edict_t* self) return; } - float r = random(); + const float r = random(); // calculate number of enemies in the periphery - int peripheral = nearby - in_front; + const int peripheral = nearby - in_front; // more enemies in front of the golem if (in_front > peripheral) @@ -857,7 +859,7 @@ void init_golem(edict_t* self) self->nextthink = level.time + FRAMETIME; // Talent: Golem Mastery - allows golem to activate thorns aura - int talentLevel = vrx_get_talent_level(self->activator, TALENT_GOLEM_MASTERY); + const int talentLevel = vrx_get_talent_level(self->activator, TALENT_GOLEM_MASTERY); if (talentLevel > 0) aura_create(self, AURA_THORNS, (2*talentLevel), DEFAULT_AURA_DURATION, 256, thorns_think); } @@ -895,7 +897,7 @@ qboolean create_golem(edict_t* ent, vec3_t start, int skill_level) // calculate spawn location for golem and then try to create it void spawn_golem(edict_t* ent) { - int slvl = ent->myskills.abilities[GOLEM].current_level; + const int slvl = ent->myskills.abilities[GOLEM].current_level; vec3_t forward, right, start, offset, mins, maxs; // write a nice effect so everyone knows we've cast a spell diff --git a/src/entities/drone/grid.c b/src/entities/drone/grid.c index fa0c8233..d518013c 100644 --- a/src/entities/drone/grid.c +++ b/src/entities/drone/grid.c @@ -109,7 +109,7 @@ node_t *tNode; void PrintNodes (node_t *Node, qboolean reverse) { int nodeNumber; - node_t *tNode = Node; + const node_t *tNode = Node; while (tNode) { @@ -469,7 +469,7 @@ int GetVerticalNodeNum (vec3_t start, float x, float y, float max_z_range, int n if (Get2dDistance(v, pathnode[i]) > 1) continue; // is it within our specified z range? - if (fabsf((int)pathnode[i][2]-(int)start[2]) > max_z_range) + if (abs((int)pathnode[i][2]-(int)start[2]) > max_z_range) continue; return i; } @@ -519,7 +519,7 @@ qboolean CheckPath1 (vec3_t start, vec3_t end) { int i; vec3_t from; - edict_t *ignore=NULL; + const edict_t *ignore=NULL; trace_t tr; VectorCopy(start, from); diff --git a/src/entities/drone/skeleton.c b/src/entities/drone/skeleton.c index f872c6a7..ecc04b29 100644 --- a/src/entities/drone/skeleton.c +++ b/src/entities/drone/skeleton.c @@ -225,7 +225,7 @@ void skeleton_check_landing(edict_t* self) void skeleton_jump(edict_t* self) { - int speed = 800; + const int speed = 800; vec3_t forward, start; //gi.dprintf("%d: baron_fire_jump %d\n", (int)(level.framenum), self->s.frame); @@ -335,10 +335,10 @@ void skeleton_attack_swing(edict_t* self) // a successful strike has a chance to cause elemental damage/effects if (random() <= SKELETON_ELEMENTAL_CHANCE) { - int slvl = drone_damagelevel(self); + const int slvl = drone_damagelevel(self); if (self->s.skinnum == SKELETON_TYPE_ICE) // blue skin = cold enchanted { - float duration = ICEBOLT_INITIAL_CHILL_DURATION + ICEBOLT_ADDON_CHILL_DURATION * slvl; + const float duration = ICEBOLT_INITIAL_CHILL_DURATION + ICEBOLT_ADDON_CHILL_DURATION * slvl; chill_target(self, e, (2 * slvl), duration); } else if (self->s.skinnum == SKELETON_TYPE_POISON) // green skin = poison enchanted @@ -411,9 +411,9 @@ mmove_t skeleton_move_wave = { FRAME_wave01, FRAME_wave11, skeleton_frames_wave, void skeleton_attack(edict_t* self) { - float r = random(); - float dist = entdist(self, self->enemy); - mmove_t* prev_move = self->monsterinfo.currentmove; + const float r = random(); + const float dist = entdist(self, self->enemy); + const mmove_t* prev_move = self->monsterinfo.currentmove; self->light_level = 0; // reset counter for continuous or rapid-fire slashing attacks @@ -666,7 +666,7 @@ qboolean spawn_skeleton(edict_t* ent, vec3_t start, int skill_level, int type) // find a single valid target that is in-range and nearest to the aiming reticle qboolean raise_skeleton_from_corpse(edict_t* ent, float range, int type) { - int slvl = ent->myskills.abilities[SKELETON].current_level; + const int slvl = ent->myskills.abilities[SKELETON].current_level; edict_t* e = NULL; vec3_t start; qboolean found = false; @@ -710,7 +710,7 @@ qboolean raise_skeleton_from_corpse(edict_t* ent, float range, int type) void raise_skeleton(edict_t* ent, int type) { - int slvl = ent->myskills.abilities[SKELETON].current_level; + const int slvl = ent->myskills.abilities[SKELETON].current_level; vec3_t forward, right, start, offset, mins, maxs; // get view origin diff --git a/src/entities/g_misc.c b/src/entities/g_misc.c index 224f0317..cf90a662 100644 --- a/src/entities/g_misc.c +++ b/src/entities/g_misc.c @@ -72,7 +72,8 @@ gibs */ void gib_think(edict_t *self) { - self->s.frame++; + if ( ( level.framenum % qf2sf(1) ) == 0 ) + self->s.frame++; self->nextthink = level.time + FRAMETIME; if (self->s.frame == 10) @@ -699,6 +700,7 @@ Default _cone value is 10 (used to set size of light for spotlights) */ #define START_OFF 1 +// TODO: shadow light data setup static void light_use(edict_t *self, edict_t *other, edict_t *activator) { @@ -1640,7 +1642,8 @@ void SP_misc_transport(edict_t *ent) */ void misc_satellite_dish_think(edict_t *self) { - self->s.frame++; + if ( ( level.framenum % qf2sf(1) ) == 0 ) + self->s.frame++; if (self->s.frame < 38) self->nextthink = level.time + FRAMETIME; } @@ -1709,8 +1712,8 @@ void SP_misc_gib_arm(edict_t *ent) void misc_dummy_think(edict_t* ent) { if (ent->health < ent->max_health) { - int rate = max(ent->max_health - ent->health, 10); - int effective_heal_rate = rate * FRAMETIME; + const int rate = max(ent->max_health - ent->health, 10); + const int effective_heal_rate = rate * FRAMETIME; if (ent->health + effective_heal_rate > ent->max_health) { ent->health = ent->max_health; diff --git a/src/entities/g_spawn.c b/src/entities/g_spawn.c index d01a1ee1..d37ff8db 100644 --- a/src/entities/g_spawn.c +++ b/src/entities/g_spawn.c @@ -924,7 +924,12 @@ char *dm_statusbar = "yb -72 " // health "xl 24 " +#ifndef VRX_REPRO "num 4 1 " +#else +// we can go back to hnum because we can set the width with cgame +"hnum " +#endif // armor "yb -24 " @@ -985,9 +990,14 @@ char *dm_statusbar = "yb -116 " "string \"Game\" " -"xr -81 " "yb -108 " +#ifdef VRX_REPRO +"xr -113 " +"num 7 14 " +#else +"xr -81 " "num 5 14 " +#endif //K03 End // spectator "if 29 " @@ -1038,6 +1048,8 @@ char *dm_statusbar = //GHz START // show damage done to target +#ifndef VRX_REPRO + "if 24 " "xv 136 " "yv 150 " @@ -1046,6 +1058,11 @@ char *dm_statusbar = "yv 159 " "num 5 24 " "endif " +#else // az: repro-enhanced dmg num +"xv 130 " +"yv 159 " +"dmgnum " +#endif //GHz END //Show the Streak "xr -42 " @@ -1067,16 +1084,10 @@ char *dm_statusbar = "num 4 28 " //GHz START -"if 24 " - "xv 136 " - "yv 150 " - "string2 \"DMG-ID\" " - "xv 130 " - "yv 159 " - "num 5 24 " -"endif " // 3.5 show ability charge percent +// az: manually shown in cgame +#ifndef VRX_REPRO "if 20 " "xr -50 " "yt 133 " @@ -1084,6 +1095,7 @@ char *dm_statusbar = "yt 142 " "num 3 20 " "endif " +#endif //GHz END ; @@ -1206,7 +1218,7 @@ void SP_worldspawn (edict_t *ent) else gi.configstring (CS_SKY, "unit1_"); - gi.configstring (CS_SKYROTATE, va("%f", st.skyrotate) ); + gi.configstring (CS_SKYROTATE, va("%f", scale_fps(st.skyrotate)) ); gi.configstring (CS_SKYAXIS, va("%f %f %f", st.skyaxis[0], st.skyaxis[1], st.skyaxis[2]) ); @@ -1216,10 +1228,7 @@ void SP_worldspawn (edict_t *ent) gi.configstring (CS_MAXCLIENTS, va("%i", (int)(maxclients->value) ) ); // status bar program - if (deathmatch->value) - gi.configstring (CS_STATUSBAR, dm_statusbar); - else - gi.configstring (CS_STATUSBAR, single_statusbar); + gi.configstring (CS_STATUSBAR, dm_statusbar); //--------------- diff --git a/src/entities/tech.c b/src/entities/tech.c index 9b0419e2..ff1679d5 100644 --- a/src/entities/tech.c +++ b/src/entities/tech.c @@ -93,7 +93,7 @@ void tech_spawnall(void) { qboolean tech_pickup(edict_t *ent, edict_t *other) { int index; - int maxLevel = 1.7 * AveragePlayerLevel(); + const int maxLevel = 1.7 * AveragePlayerLevel(); // can't pick-up more than 1 tech if (other->client->pers.inventory[resistance_index] diff --git a/src/entities/v_items.c b/src/entities/v_items.c index 478a6c09..4078978c 100644 --- a/src/entities/v_items.c +++ b/src/entities/v_items.c @@ -242,9 +242,9 @@ void vrx_join_redundant_mods(edict_t *rune, int mod_index) } else { /* weapon mods are a little trickier*/ - int mod = rune->vrxitem.modifiers[mod_index].index; - int weap_mod_index = vrx_weapon_mod_index_from_mod_index(mod); - int weap = vrx_weapon_index_from_mod_index(mod); + const int mod = rune->vrxitem.modifiers[mod_index].index; + const int weap_mod_index = vrx_weapon_mod_index_from_mod_index(mod); + const int weap = vrx_weapon_index_from_mod_index(mod); if (weap_mod_index <= 3 && (weap_mod_index <= 2 || weap == WEAPON_SWORD)) { @@ -317,7 +317,7 @@ void vrx_create_ability_modifier(edict_t *rune, qboolean is_class, int i, int ta } else { - int modmax = max((int)roundf(5.0f * ((min(targ_level, 25.0f)) / 15.0f)), 1); + const int modmax = max((int)roundf(5.0f * ((min(targ_level, 25.0f)) / 15.0f)), 1); rune->vrxitem.modifiers[i].value = min(rand_clt_distribute(1, modmax, 3), RUNE_ABILITY_MAXVALUE); } @@ -341,7 +341,7 @@ edict_t* vrx_do_random_rune_drop(edict_t* spawner, int targ_level) { rune->vrxitem.quantity = 1; //Spawn a random rune - int iRandom = GetRandom(0, 1000); + const int iRandom = GetRandom(0, 1000); if (iRandom < CHANCE_UNIQUE) { @@ -448,7 +448,7 @@ void vrx_roll_rune_drop(edict_t *self, edict_t *attacker, qboolean debug) // is this a world monster? if (self->mtype && (self->svflags & SVF_MONSTER) && self->activator && !self->activator->client) { - float levelRatio = (float) (self->monsterinfo.level + 1) / (attacker->myskills.level + 1); + const float levelRatio = (float) (self->monsterinfo.level + 1) / (attacker->myskills.level + 1); if (IsABoss(self) || (self->mtype == M_COMMANDER)) //boss has a 100% chance to spawn a rune temp = levelRatio * 100.0f; @@ -517,7 +517,7 @@ void vrx_make_weapon_rune(edict_t* rune, int targ_level) { int max_mods = 1 + (0.25 * targ_level); //This means lvl 16+ can get all 5 mods int num_mods; - int weaponIndex = GetRandom(0, MAX_WEAPONS-1); // random weapon + const int weaponIndex = GetRandom(0, MAX_WEAPONS-1); // random weapon if (max_mods > MAX_WEAPONMODS) @@ -531,7 +531,7 @@ void vrx_make_weapon_rune(edict_t* rune, int targ_level) for (int i = 0; i < num_mods; ++i) { - int modIndex = i; + const int modIndex = i; //25% chance for rune mod not to show up if (GetRandom(0, 4) == 0) @@ -563,7 +563,7 @@ void vrx_make_ability_rune(edict_t* rune, int targ_level) if (max_mods > MAX_VRXITEMMODS) max_mods = MAX_VRXITEMMODS; - int num_mods = rand_clt_distribute(1, max_mods, 6); + const int num_mods = rand_clt_distribute(1, max_mods, 6); for (int i = 0; i < num_mods; ++i) { @@ -597,8 +597,8 @@ void vrx_spawn_normal_rune(edict_t *rune, int targ_level, int type) //************************************************************************************************ void vrx_spawn_class_rune(edict_t *rune, int targ_level) { - int max_mods = 1 + (0.2 * targ_level); //This means lvl 15+ can get 4 mods - int num_mods = min(rand_clt_distribute(1, max_mods, 3), 5); // az: from 1 - don't be a dick + const int max_mods = 1 + (0.2 * targ_level); //This means lvl 15+ can get 4 mods + const int num_mods = min(rand_clt_distribute(1, max_mods, 3), 5); // az: from 1 - don't be a dick rune->vrxitem.itemtype = ITEM_CLASSRUNE; rune->vrxitem.classNum = GetRandom(1, CLASS_MAX - 1); //class number @@ -683,7 +683,7 @@ qboolean vrx_spawn_unique_rune(edict_t *rune, int index) rewind(fptr); //Find a unique - int maxlines = V_tFileCountLines(fptr, size); + const int maxlines = V_tFileCountLines(fptr, size); if ((index == 0) || (index > maxlines)) { @@ -1202,7 +1202,7 @@ void cmd_Drink(edict_t *ent, int itemtype, int index) { { case ITEM_POTION: { - int max_hp = MAX_HEALTH(ent); + const int max_hp = MAX_HEALTH(ent); if (ent->health < max_hp) { @@ -1264,10 +1264,10 @@ item_menu_t vrx_get_weapon_rune_string(item_t* item) for (int i = 0; i < MAX_VRXITEMMODS; i++) { - imodifier_t* mod = &item->modifiers[i]; + const imodifier_t* mod = &item->modifiers[i]; if (mod->index > 0 && mod->value > 0 && mod->type == TYPE_WEAPON) { - int weap = vrx_weapon_index_from_mod_index(mod->index); + const int weap = vrx_weapon_index_from_mod_index(mod->index); wstring = GetWeaponString(weap); if (mod->value > max) max = mod->value; } @@ -1324,7 +1324,7 @@ item_menu_t vrx_get_ability_rune_string(item_t* item) for (int i = 0; i < MAX_VRXITEMMODS; i++) { - imodifier_t* mod = &item->modifiers[i]; + const imodifier_t* mod = &item->modifiers[i]; if (mod->index > 0 && mod->value > 0 && mod->type == TYPE_ABILITY && max < mod->value) { max = mod->value; @@ -1340,12 +1340,12 @@ item_menu_t vrx_get_ability_rune_string(item_t* item) item_menu_t vrx_get_combo_rune_string(item_t* item) { - char *astring = "Combo"; + const char *astring = "Combo"; int max = 0; for (int i = 0; i < MAX_VRXITEMMODS; i++) { - imodifier_t* mod = &item->modifiers[i]; + const imodifier_t* mod = &item->modifiers[i]; if (mod->index > 0 && mod->value > 0 && mod->type == TYPE_ABILITY && max < mod->value) { max = mod->value; diff --git a/src/g_local.h b/src/g_local.h index 4735b49a..3b28b0da 100644 --- a/src/g_local.h +++ b/src/g_local.h @@ -25,17 +25,18 @@ /* twister.c */ #include +#include "quake2/q_recompat.h" #include "server/defer.h" + void seedMT(uint32_t seed); + uint32_t randomMT(void); // the "gameversion" client command will print this plus compile date -#define GAMEVERSION "Vortex"//K03 "baseq2" +#define GAMEVERSION "vortex"//K03 "baseq2" //#define MAX_NODES 1024 //K03 Begin -extern qboolean MonstersInUse; -extern qboolean found_flag; extern int total_monsters; extern edict_t *SPREE_DUDE; extern edict_t *red_base; @@ -56,13 +57,57 @@ extern long FLAG_FRAMES; //K03 End // protocol bytes that can be directly added to messages -#define svc_muzzleflash 1 -#define svc_muzzleflash2 2 -#define svc_temp_entity 3 -#define svc_layout 4 -#define svc_inventory 5 -#define svc_stufftext 11 -#define svc_configstring 13 +enum server_command_t : uint8_t { + svc_bad, + + svc_muzzleflash, + svc_muzzleflash2, + svc_temp_entity, + svc_layout, + svc_inventory, + +#ifdef VRX_REPRO + svc_nop, + svc_disconnect, + svc_reconnect, + svc_sound, // + svc_print, // [byte] id [string] null terminated string +#endif + + svc_stufftext = 11, // [string] stuffed into client's console buffer, should be \n terminated + +#ifdef VRX_REPRO + svc_serverdata, // [long] protocol ... +#endif + + svc_configstring = 13, // [short] [string] +#ifdef VRX_REPRO + svc_spawnbaseline, + svc_centerprint, // [string] to put in center of the screen + svc_download, // [short] size [size bytes] + svc_playerinfo, // variable + svc_packetentities, // [...] + svc_deltapacketentities, // [...] + svc_frame, + + svc_splitclient, + + svc_configblast, // [Kex] A compressed version of svc_configstring + svc_spawnbaselineblast, // [Kex] A compressed version of svc_spawnbaseline + svc_level_restart, // [Paril-KEX] level was soft-rebooted + svc_damage, // [Paril-KEX] damage indicators + svc_locprint, // [Kex] localized + libfmt version of print + svc_fog, // [Paril-KEX] change current fog values + svc_waitingforplayers, // [Kex-Edward] Inform clients that the server is waiting for remaining players + svc_bot_chat, // [Kex] bot specific chat + svc_poi, // [Paril-KEX] point of interest + svc_help_path, // [Paril-KEX] help path + svc_muzzleflash3, // [Paril-KEX] muzzleflashes, but ushort id + svc_achievement, // [Paril-KEX] +#endif + svc_last // only for checks +}; + //================================================================== // view pitching times @@ -80,34 +125,39 @@ extern long FLAG_FRAMES; //#define SPAWNFLAG_BOMBS 0x00002000 //GHz // edict->flags -#define FL_FLY 0x00000001 -#define FL_SWIM 0x00000002 // implied immunity to drowining -#define FL_IMMUNE_LASER 0x00000004 -#define FL_INWATER 0x00000008 -#define FL_GODMODE 0x00000010 -#define FL_NOTARGET 0x00000020 // monsters won't target this entity until it hurts them -#define FL_IMMUNE_SLIME 0x00000040 -#define FL_IMMUNE_LAVA 0x00000080 -#define FL_PARTIALGROUND 0x00000100 // not all corners are valid -#define FL_WATERJUMP 0x00000200 // player jumping out of water -#define FL_TEAMSLAVE 0x00000400 // not the first on the team -#define FL_NO_KNOCKBACK 0x00000800 -#define FL_POWER_ARMOR 0x00001000 // power armor (if any) is active -#define FL_CHATPROTECT 0x00002000 // in chat-protect mode -#define FL_CHASEABLE 0x00004000 // 3.65 indicates non-client ent can be chased -#define FL_CLIGHTNING 0x00008000 // 4.0 indicates entity has already been targetted by CL this frame -#define FL_WORMHOLE 0x00010000 // player is in a wormhole -#define FL_DETECTED 0x00020000 // player was detected -#define FL_CONVERTED 0x00040000 // entity was converted -#define FL_COCOONED 0x00080000 // entitiy is cocooned -#define FL_NO_TRADING_PROTECT 0x00100000 // let it be hurt in trading mode -#define FL_BLACK_DEATH 0x00200000 // extra damage from plague -#define FL_PICKUP 0x00400000 // entity is being picked up by player -#define FL_UNDEAD 0x00800000 // entity cannot die (temporary death until resurrection) -#define FL_PACKANIMAL 0x01000000 // pack animal: use num_packanimals to track active quantity -#define FL_RESPAWN 0x80000000 // used for item respawning - -#define FRAMETIME (1/sv_fps->value) +enum flags_t { + FL_FLY = 1 << 0, + FL_SWIM = 1 << 1, // implied immunity to drowining + FL_IMMUNE_LASER = 1 << 2, + FL_INWATER = 1 << 3, + FL_GODMODE = 1 << 4, + FL_NOTARGET = 1 << 5, // monsters won't target this entity until it hurts them + FL_IMMUNE_SLIME = 1 << 6, + FL_IMMUNE_LAVA = 1 << 7, + FL_PARTIALGROUND = 1 << 8, // not all corners are valid + FL_WATERJUMP = 1 << 9, // player jumping out of water + FL_TEAMSLAVE = 1 << 10, // not the first on the team + FL_NO_KNOCKBACK = 1 << 11, + FL_POWER_ARMOR = 1 << 12, // power armor (if any) is active + FL_CHATPROTECT = 1 << 13, // in chat-protect mode + FL_CHASEABLE = 1 << 14, // 3.65 indicates non-client ent can be chased + FL_CLIGHTNING = 1 << 15, // 4.0 indicates entity has already been targetted by CL this frame + FL_WORMHOLE = 1 << 16, // player is in a wormhole + FL_DETECTED = 1 << 17, // player was detected + FL_CONVERTED = 1 << 18, // entity was converted + FL_COCOONED = 1 << 19, // entitiy is cocooned + FL_NO_TRADING_PROTECT = 1 << 20, // let it be hurt in trading mode + FL_BLACK_DEATH = 1 << 21, // extra damage from plague + FL_PICKUP = 1 << 22, // entity is being picked up by player + FL_UNDEAD = 1 << 23, // entity cannot die (temporary death until resurrection) + FL_PACKANIMAL = 1 << 24, // pack animal: use num_packanimals to track active quantity + FL_RESPAWN = 1 << 25, // used for item respawning + FL_FLASHLIGHT = 1 << 26 +}; + + +#define FRAMETIME (1.0f/sv_fps->value) +#define VectorScaleFPS(v, o) (VectorScale(v, 10.0f/sv_fps->value, o)) // scale 10 fps value to sv_fps value double scale_fps(double value); @@ -127,36 +177,19 @@ uint64_t qf2sf(uint64_t frames); #define BODY_QUEUE_SIZE 8 // max number of corpses -typedef enum -{ - DAMAGE_NO, - DAMAGE_YES, // will take damage if hit - DAMAGE_AIM // auto targeting recognizes this +typedef enum { + DAMAGE_NO, + DAMAGE_YES, // will take damage if hit + DAMAGE_AIM // auto targeting recognizes this } damage_t; -typedef enum -{ - WEAPON_READY, - WEAPON_ACTIVATING, - WEAPON_DROPPING, - WEAPON_FIRING +typedef enum { + WEAPON_READY, + WEAPON_ACTIVATING, + WEAPON_DROPPING, + WEAPON_FIRING } weaponstate_t; -typedef enum -{ - AMMO_BULLETS = 1, - AMMO_SHELLS = 2, - AMMO_ROCKETS = 3, - AMMO_GRENADES = 4, - AMMO_CELLS = 5, - AMMO_SLUGS = 6, - // RAFAEL - AMMO_MAGSLUG = 7, - AMMO_TRAP = 8, - // 3.5 - AMMO_GENERATOR = 9 -} ammo_t; - //deadflag #define DEAD_NO 0 @@ -256,8 +289,9 @@ typedef enum #define GENDER_FEMALE 2 #define GENDER_MAX 3 -char *GetReflexivePronoun( edict_t *ent ); -char *GetPossesiveAdjective( edict_t *ent ); +char *GetReflexivePronoun(edict_t *ent); + +char *GetPossesiveAdjective(edict_t *ent); //3ZB CTF state @@ -267,33 +301,30 @@ char *GetPossesiveAdjective( edict_t *ent ); #define CARRIER 3 // edict->movetype values -typedef enum -{ - MOVETYPE_NONE, // never moves - MOVETYPE_NOCLIP, // origin and angles change with no interaction - MOVETYPE_PUSH, // no clip to world, push on box contact - MOVETYPE_STOP, // no clip to world, stops on box contact - - MOVETYPE_WALK, // gravity - MOVETYPE_STEP, // gravity, special edge handling - MOVETYPE_FLY, - MOVETYPE_TOSS, // gravity - MOVETYPE_FLYMISSILE, // extra size to monsters - MOVETYPE_BOUNCE, -// RAFAEL - MOVETYPE_WALLBOUNCE, - MOVETYPE_SLIDE +typedef enum { + MOVETYPE_NONE, // never moves + MOVETYPE_NOCLIP, // origin and angles change with no interaction + MOVETYPE_PUSH, // no clip to world, push on box contact + MOVETYPE_STOP, // no clip to world, stops on box contact + + MOVETYPE_WALK, // gravity + MOVETYPE_STEP, // gravity, special edge handling + MOVETYPE_FLY, + MOVETYPE_TOSS, // gravity + MOVETYPE_FLYMISSILE, // extra size to monsters + MOVETYPE_BOUNCE, + // RAFAEL + MOVETYPE_WALLBOUNCE, + MOVETYPE_SLIDE } movetype_t; - -typedef struct -{ - int base_count; - int max_count; - float normal_protection; - float energy_protection; - int armor; +typedef struct { + int base_count; + int max_count; + float normal_protection; + float energy_protection; + int armor; } gitem_armor_t; @@ -349,35 +380,36 @@ typedef struct #define MPI_INDEX 24 //MPI count +typedef struct gitem_s { + char *classname; // spawning name + qboolean (*pickup)(struct edict_s *ent, struct edict_s *other); -typedef struct gitem_s -{ - char *classname; // spawning name - qboolean (*pickup)(struct edict_s *ent, struct edict_s *other); - void (*use)(struct edict_s *ent, struct gitem_s *item); - void (*drop)(struct edict_s *ent, struct gitem_s *item); - void (*weaponthink)(struct edict_s *ent); - char *pickup_sound; - char *world_model; - int world_model_flags; - char *view_model; + void (*use)(struct edict_s *ent, struct gitem_s *item); - // client side info - char *icon; - char *pickup_name; // for printing on pickup - int count_width; // number of digits to display by icon + void (*drop)(struct edict_s *ent, struct gitem_s *item); - int quantity; // for ammo how much, for weapons how much is used per shot - char *ammo; // for weapons - int flags; // IT_* flags + void (*weaponthink)(struct edict_s *ent); - void *info; - int tag; + char *pickup_sound; + char *world_model; + int world_model_flags; + char *view_model; - char *precaches; // string of all models, sounds, and images this item will use - int weapmodel; // weapon model index (for weapons) -} gitem_t; + // client side info + char *icon; + char *pickup_name; // for printing on pickup + int count_width; // number of digits to display by icon + int quantity; // for ammo how much, for weapons how much is used per shot + char *ammo; // for weapons + int flags; // IT_* flags + + void *info; + int tag; + + char *precaches; // string of all models, sounds, and images this item will use + int weapmodel; // weapon model index (for weapons) +} gitem_t; // @@ -385,314 +417,333 @@ typedef struct gitem_s // it should be initialized at dll load time, and read/written to // the server.ssv file for savegames // -typedef struct -{ - char helpmessage1[512]; - char helpmessage2[512]; - int helpchanged; // flash F1 icon if non 0, play sound - // and increment only if 1, 2, or 3 +typedef struct { + char helpmessage1[512]; + char helpmessage2[512]; + int helpchanged; // flash F1 icon if non 0, play sound + // and increment only if 1, 2, or 3 - gclient_t *clients; // [maxclients] + gclient_t *clients; // [maxclients] - // can't store spawnpoint in level, because - // it would get overwritten by the savegame restore - char spawnpoint[512]; // needed for coop respawns + // can't store spawnpoint in level, because + // it would get overwritten by the savegame restore + char spawnpoint[512]; // needed for coop respawns - // store latched cvars here that we want to get at often - int maxclients; - int maxentities; + // store latched cvars here that we want to get at often + int maxclients; + int maxentities; - // cross level triggers - int serverflags; + // cross level triggers + int serverflags; - // items - int num_items; + // items + int num_items; - qboolean autosaved; + qboolean autosaved; } game_locals_t; +struct shadow_light_info_t { + int entity_number; + shadow_light_data_t shadowlight; +}; + + // // this structure is cleared as each map is entered // it is read/written to the level.sav file for savegames // -typedef struct -{ - uint64_t framenum; - double time; +typedef struct { + uint64_t framenum; + double time; - char level_name[MAX_QPATH]; // the descriptive name (Outer Base, etc) - char mapname[MAX_QPATH]; // the server name (base1, etc) - char nextmap[MAX_QPATH]; // go here when fraglimit is hit + char level_name[MAX_QPATH]; // the descriptive name (Outer Base, etc) + char mapname[MAX_QPATH]; // the server name (base1, etc) + char nextmap[MAX_QPATH]; // go here when fraglimit is hit - // intermission state - double intermissiontime; // time the intermission was started - char *changemap; - int exitintermission; - vec3_t intermission_origin; - vec3_t intermission_angle; + // intermission state + double intermissiontime; // time the intermission was started + char *changemap; + int exitintermission; + vec3_t intermission_origin; + vec3_t intermission_angle; - edict_t *sight_client; // changed once each frame for coop games + edict_t *sight_client; // changed once each frame for coop games - edict_t *sight_entity; - int sight_entity_framenum; - edict_t *sound_entity; - int sound_entity_framenum; - edict_t *sound2_entity; - int sound2_entity_framenum; + edict_t *sight_entity; + int sight_entity_framenum; + edict_t *sound_entity; + int sound_entity_framenum; + edict_t *sound2_entity; + int sound2_entity_framenum; - int pic_health; + int pic_health; - int total_secrets; - int found_secrets; + int total_secrets; + int found_secrets; - int total_goals; - int found_goals; + int total_goals; + int found_goals; - int total_monsters; - int killed_monsters; + int total_monsters; + int killed_monsters; - edict_t *current_entity; // entity running from G_RunFrame - int body_que; // dead bodies + edict_t *current_entity; // entity running from G_RunFrame + int body_que; // dead bodies - int power_cubes; // ugly necessity for coop + int power_cubes; // ugly necessity for coop - int num_bots; - int r_monsters; //4.5 recommended monster value for this map - qboolean daytime; //GHz: Is the sun going up or down? - qboolean modechange; - // qboolean pathfinding; + int num_bots; + int r_monsters; //4.5 recommended monster value for this map + qboolean daytime; //GHz: Is the sun going up or down? + qboolean modechange; + // qboolean pathfinding; qboolean warning_given; qboolean sounds[4]; - struct { - vec3_t blueflag_fallback; - vec3_t redflag_fallback; - qboolean has_blue_fallback; - qboolean has_red_fallback; - } ctf; + struct { + vec3_t blueflag_fallback; + vec3_t redflag_fallback; + qboolean has_blue_fallback; + qboolean has_red_fallback; + } ctf; - struct { - int level_bonus; - float time_to_next_respawn; - } pvm; + struct { + int level_bonus; + float time_to_next_respawn; + } pvm; -/* gdsfiles_t gdsfiles[MAX_CLIENTS];*/ + struct { + int32_t count; + struct shadow_light_info_t info[MAX_SHADOW_LIGHTS]; + } shadow_lights; - // experimental monster pathfinding - //int total_nodes; - //nodedata_t nodes[MAX_NODES]; + /* gdsfiles_t gdsfiles[MAX_CLIENTS];*/ + + // experimental monster pathfinding + //int total_nodes; + //nodedata_t nodes[MAX_NODES]; } level_locals_t; // spawn_temp_t is only used to hold entity field values that // can be set from the editor, but aren't actualy present // in edict_t during gameplay -typedef struct -{ - // world vars - char *sky; - float skyrotate; - vec3_t skyaxis; - char *nextmap; - - int lip; - int distance; - int height; - char *noise; - float pausetime; - char *item; - char *gravity; - - float minyaw; - float maxyaw; - float minpitch; - float maxpitch; - float weight; +typedef struct { + // world vars + char *sky; + float skyrotate; + vec3_t skyaxis; + char *nextmap; + + int lip; + int distance; + int height; + char *noise; + float pausetime; + char *item; + char *gravity; + + float minyaw; + float maxyaw; + float minpitch; + float maxpitch; + float weight; } spawn_temp_t; -typedef struct -{ - // fixed data - vec3_t start_origin; - vec3_t start_angles; - vec3_t end_origin; //BFG�̃^�[�Q�b�g�|�C���g�ɕs���g�p - vec3_t end_angles; - - int sound_start; //�X�i�C�p�[�̃A�N�e�B�x�[�g�t���O - int sound_middle; - int sound_end; //hokuto�̃N���X - - float accel; - float speed; //bot �������̈ړ��ʂɕs���g�p - float decel; //���ʑØÝŽï¿½ï¿½Ô‚É•s���g�p - float distance; //�X�i�C�p�[�pFOV�l - - float wait; - - // state data - int state; //CTF�X�e�[�^�X�ɕs���g�p - vec3_t dir; - float current_speed; - float move_speed; - float next_speed; - float remaining_distance; - float decel_distance; - void (*endfunc)(edict_t *); +typedef struct { + // fixed data + vec3_t start_origin; + vec3_t start_angles; + vec3_t end_origin; //BFG�̃^�[�Q�b�g�|�C���g�ɕs���g�p + vec3_t end_angles; + + int sound_start; //�X�i�C�p�[�̃A�N�e�B�x�[�g�t���O + int sound_middle; + int sound_end; //hokuto�̃N���X + + float accel; + float speed; //bot �������̈ړ��ʂɕs���g�p + float decel; //���ʑØÝŽï¿½ï¿½Ô‚É•s���g�p + float distance; //�X�i�C�p�[�pFOV�l + + float wait; + + // state data + int state; //CTF�X�e�[�^�X�ɕs���g�p + vec3_t dir; + float current_speed; + float move_speed; + float next_speed; + float remaining_distance; + float decel_distance; + + void (*endfunc)(edict_t *); } moveinfo_t; -typedef struct -{ - void (*aifunc)(edict_t *self, float dist); - float dist; - void (*thinkfunc)(edict_t *self); +typedef struct { + void (*aifunc)(edict_t *self, float dist); + + float dist; + + void (*thinkfunc)(edict_t *self); } mframe_t; -typedef struct -{ - int firstframe; - int lastframe; - mframe_t *frame; - void (*endfunc)(edict_t *self); +typedef struct { + int firstframe; + int lastframe; + mframe_t *frame; + + void (*endfunc)(edict_t *self); } mmove_t; //GHz START -typedef struct dmglist_s -{ - edict_t *player; // attacker who hurt us - float damage; // total damage done -}dmglist_t; +typedef struct dmglist_s { + edict_t *player; // attacker who hurt us + float damage; // total damage done +} dmglist_t; + //GHz END -typedef struct -{ - mmove_t *currentmove; - int aiflags; - int nextframe; - float scale; - - void (*stand)(edict_t *self); - void (*idle)(edict_t *self); // called when monster is doing nothing -// void (*search)(edict_t *self); - void (*walk)(edict_t *self); - void (*run)(edict_t *self); - void (*dodge)(edict_t *self, edict_t *attacker, vec3_t dir, int radius); - void (*attack)(edict_t *self); - void (*melee)(edict_t *self); - void (*sight)(edict_t *self, edict_t *other); // called when monster acquires a target -// qboolean (*checkattack)(edict_t *self); - void (*touchdown)(edict_t* self); // GHz: called when airborne monster touches the ground - - float pausetime; - float attack_finished; - float melee_finished; - float touchdown_delay; // GHz: to prevent touchdown() function from being called too often - -// vec3_t saved_goal; - int search_frames; // number of frames enemy has not been visible - int stuck_frames; // number of frames monster has been stuck in-place - vec3_t stuck_org; // location used for comparison to determine if monster is stuck - float selected_time; // time monster flashes after being selected - float teleport_delay; // time before drone can teleport again - float trail_time; - vec3_t last_sighting; // last known position of enemy -// int attack_state; - int lefty; - float idle_delay; // how often idle func is called - int idle_frames; // number of frames monster has been idle - int air_frames; // how many frames monster has been off the ground - int linkcount; - - int power_armor_type; - int power_armor_power; - int max_armor; - int control_cost; - int cost; - int level; // used to determine monster toughness - int jumpup; // max height we can jump up - int jumpdn; // max height we can jump down - int radius; // radius (if any) if projectile explosion - int regen_delay1; // level.framenum when we can regenerate again - int regen_delay2; // secondary regen level.framenum when we can regenerate again - int regen_delay3; // secondary regen level.framenum when we can regenerate again - int upkeep_delay; // frames before upkeep is checked again - int inv_framenum; // frame when quad+invuln wears out, used to prevent spawn camping in invasion mode - int nextattack; // used for mutant to check for next attack frame - int bonus_flags; //4.5 used for special bonus flags (e.g. champion, unique monster bonuses) - int waypoint[1000]; // pathfinding node indices leading to final destination - int nextWaypoint; // next waypoint index to follow - int numWaypoints; // total number of waypoints - edict_t *attacker; // edict that triggered our dodge routines - edict_t *leader; // edict that we have been commanded to follow - vec3_t spot1; // position we have been commanded to move to/defend - vec3_t spot2; // position we have been commanded to move to/defend - vec3_t dir; // direction of oncoming projectile - float eta; // time projectile will impact - float dodge_time; // delay before we can dodge again - float sight_range; // 3.56 how far the drone can see to acquire targets - float bump_delay; // delay before we can make another course-correction - float Zchange_delay; // delay before we can adjust Z position again (to prevent bouncing) - qboolean Zchanged; // has our Z position changed recently? - float resurrected_time; // time when resurrection from a medic is complete - int resurrected_level; // used to store the original level of the monster before resurrection bonus is applied - float resurrected_timeout;// time when the resurrected monster will expire - float backtrack_delay; // delay until we can backtrack to a closer waypoint (to prevent getting stuck) - float path_time; // time when monster can compute a path - vec3_t prevGoalPos; // last goal position, used for deciding when to re-compute paths - qboolean updatePath; // if true, update path to goal when level.time > path_time - edict_t *lastGoal; // last goal we were chasing, used for deciding when to re-compute paths -// qboolean melee; // whether or not the monster should circle strafe - dmglist_t dmglist[MAX_CLIENTS]; // keep track of damage by players - qboolean slots_freed; // true if player slots have been refunded prior to removal - - // az begin - - // targeting - int target_index; // for ai - edict_t *last_target_scanner; - - // drone list - int dronelist_index; - - // odds that a hit will induce a pain state - float pain_chance; - - // az end +typedef struct { + mmove_t *currentmove; + int aiflags; + int nextframe; + int frametimer; + float scale; + + void (*stand)(edict_t *self); + + void (*idle)(edict_t *self); // called when monster is doing nothing + // void (*search)(edict_t *self); + void (*walk)(edict_t *self); + + void (*run)(edict_t *self); + + void (*dodge)(edict_t *self, edict_t *attacker, vec3_t dir, int radius); + + void (*attack)(edict_t *self); + + void (*melee)(edict_t *self); + + void (*sight)(edict_t *self, edict_t *other); // called when monster acquires a target + // qboolean (*checkattack)(edict_t *self); + void (*touchdown)(edict_t *self); // GHz: called when airborne monster touches the ground + + float pausetime; + float attack_finished; + float melee_finished; + float touchdown_delay; // GHz: to prevent touchdown() function from being called too often + + // vec3_t saved_goal; + int search_frames; // number of frames enemy has not been visible + int stuck_frames; // number of frames monster has been stuck in-place + vec3_t stuck_org; // location used for comparison to determine if monster is stuck + float selected_time; // time monster flashes after being selected + float teleport_delay; // time before drone can teleport again + float trail_time; + vec3_t last_sighting; // last known position of enemy + // int attack_state; + int lefty; + float idle_delay; // how often idle func is called + int idle_frames; // number of frames monster has been idle + int air_frames; // how many frames monster has been off the ground + int linkcount; + + int power_armor_type; + int power_armor_power; + int max_armor; + int control_cost; + int cost; + int level; // used to determine monster toughness + int jumpup; // max height we can jump up + int jumpdn; // max height we can jump down + int radius; // radius (if any) if projectile explosion + int regen_delay1; // level.framenum when we can regenerate again + int regen_delay2; // secondary regen level.framenum when we can regenerate again + int regen_delay3; // secondary regen level.framenum when we can regenerate again + int upkeep_delay; // frames before upkeep is checked again + int inv_framenum; // frame when quad+invuln wears out, used to prevent spawn camping in invasion mode + int nextattack; // used for mutant to check for next attack frame + int bonus_flags; //4.5 used for special bonus flags (e.g. champion, unique monster bonuses) + int waypoint[1000]; // pathfinding node indices leading to final destination + int nextWaypoint; // next waypoint index to follow + int numWaypoints; // total number of waypoints + edict_t *attacker; // edict that triggered our dodge routines + edict_t *leader; // edict that we have been commanded to follow + vec3_t spot1; // position we have been commanded to move to/defend + vec3_t spot2; // position we have been commanded to move to/defend + vec3_t dir; // direction of oncoming projectile + float eta; // time projectile will impact + float dodge_time; // delay before we can dodge again + float sight_range; // 3.56 how far the drone can see to acquire targets + float bump_delay; // delay before we can make another course-correction + float Zchange_delay; // delay before we can adjust Z position again (to prevent bouncing) + qboolean Zchanged; // has our Z position changed recently? + float resurrected_time; // time when resurrection from a medic is complete + int resurrected_level; // used to store the original level of the monster before resurrection bonus is applied + float resurrected_timeout; // time when the resurrected monster will expire + float backtrack_delay; // delay until we can backtrack to a closer waypoint (to prevent getting stuck) + float path_time; // time when monster can compute a path + vec3_t prevGoalPos; // last goal position, used for deciding when to re-compute paths + qboolean updatePath; // if true, update path to goal when level.time > path_time + edict_t *lastGoal; // last goal we were chasing, used for deciding when to re-compute paths + // qboolean melee; // whether or not the monster should circle strafe + dmglist_t dmglist[MAX_CLIENTS]; // keep track of damage by players + qboolean slots_freed; // true if player slots have been refunded prior to removal + + // az begin + + // targeting + int target_index; // for ai + edict_t *last_target_scanner; + + // drone list + int dronelist_index; + + // odds that a hit will induce a pain state + float pain_chance; + + // az end } monsterinfo_t; -extern game_locals_t game; -extern level_locals_t level; -extern game_import_t gi; -extern game_export_t globals; -extern spawn_temp_t st; - -extern int sm_meat_index; -extern int snd_fry; - -extern int jacket_armor_index; -extern int combat_armor_index; -extern int body_armor_index; -extern int armor_shard_index; -extern int power_cube_index; -extern int flag_index; -extern int red_flag_index; -extern int blue_flag_index; -extern int halo_index; -extern int resistance_index; -extern int strength_index; -extern int regeneration_index; -extern int haste_index; +extern game_locals_t game; +extern level_locals_t level; +extern game_import_t gi; +#ifndef VRX_REPRO +extern game_export_t globals; +#else +extern repro_export_t globals; +#endif +extern spawn_temp_t st; + +extern int sm_meat_index; +extern int snd_fry; + +extern int jacket_armor_index; +extern int combat_armor_index; +extern int body_armor_index; +extern int armor_shard_index; +extern int power_cube_index; +extern int flag_index; +extern int red_flag_index; +extern int blue_flag_index; +extern int halo_index; +extern int resistance_index; +extern int strength_index; +extern int regeneration_index; +extern int haste_index; //ammo -extern int bullet_index; -extern int shell_index; -extern int grenade_index; -extern int rocket_index; -extern int slug_index; -extern int cell_index; +extern int bullet_index; +extern int shell_index; +extern int grenade_index; +extern int rocket_index; +extern int slug_index; +extern int cell_index; //weapons extern int sword_index; @@ -709,8 +760,8 @@ extern int _20mmcannon_index; extern int bfg10k_index; //pre searched items -extern gitem_t *Fdi_GRAPPLE; -extern gitem_t *Fdi_BLASTER; +extern gitem_t *Fdi_GRAPPLE; +extern gitem_t *Fdi_BLASTER; extern gitem_t *Fdi_SHOTGUN; extern gitem_t *Fdi_SUPERSHOTGUN; extern gitem_t *Fdi_MACHINEGUN; @@ -733,10 +784,10 @@ extern gitem_t *Fdi_ROCKETS; extern gitem_t *Fdi_SLUGS; extern gitem_t *Fdi_MAGSLUGS; extern gitem_t *Fdi_TBALL; -extern gitem_t *Fdi_POWERCUBE; +extern gitem_t *Fdi_POWERCUBE; extern int headindex; -extern int skullindex; +extern int skullindex; // means of death #define MOD_UNKNOWN 0 @@ -852,10 +903,10 @@ extern int skullindex; #define MOD_FRIENDLY_FIRE 0x8000000 #define MOD_FMEDICPACK 150 -extern int meansOfDeath; +extern int meansOfDeath; -extern edict_t *g_edicts; +extern edict_t *g_edicts; #define FOFS(x) (size_t)&(((edict_t *)0)->x) #define STOFS(x) (size_t)&(((spawn_temp_t *)0)->x) @@ -865,50 +916,50 @@ extern edict_t *g_edicts; #define random() ((double)randomMT() / (double)(0xffffffff)) #define crandom() (2.0 * (random() - 0.5)) -extern cvar_t *maxentities; -extern cvar_t *deathmatch; -extern cvar_t *coop; -extern cvar_t *dmflags; -extern cvar_t *skill; -extern cvar_t *fraglimit; -extern cvar_t *timelimit; +extern cvar_t *maxentities; +extern cvar_t *deathmatch; +extern cvar_t *coop; +extern cvar_t *dmflags; +extern cvar_t *skill; +extern cvar_t *fraglimit; +extern cvar_t *timelimit; //ZOID -extern cvar_t *capturelimit; +extern cvar_t *capturelimit; //ZOID -extern cvar_t *password; -extern cvar_t *spectator_password; -extern cvar_t *g_select_empty; -extern cvar_t *dedicated; +extern cvar_t *password; +extern cvar_t *spectator_password; +extern cvar_t *g_select_empty; +extern cvar_t *dedicated; -extern cvar_t *sv_gravity; -extern cvar_t *sv_maxvelocity; +extern cvar_t *sv_gravity; +extern cvar_t *sv_maxvelocity; -extern cvar_t *gun_x, *gun_y, *gun_z; -extern cvar_t *sv_rollspeed; -extern cvar_t *sv_rollangle; +extern cvar_t *gun_x, *gun_y, *gun_z; +extern cvar_t *sv_rollspeed; +extern cvar_t *sv_rollangle; -extern cvar_t *run_pitch; -extern cvar_t *run_roll; -extern cvar_t *bob_up; -extern cvar_t *bob_pitch; -extern cvar_t *bob_roll; +extern cvar_t *run_pitch; +extern cvar_t *run_roll; +extern cvar_t *bob_up; +extern cvar_t *bob_pitch; +extern cvar_t *bob_roll; -extern cvar_t *sv_cheats; -extern cvar_t *maxclients; -extern cvar_t *maxspectators; +extern cvar_t *sv_cheats; +extern cvar_t *maxclients; +extern cvar_t *maxspectators; -extern cvar_t *filterban; +extern cvar_t *filterban; //ponpoko -extern cvar_t *gamepath; -extern cvar_t *chedit; -extern cvar_t *vwep; -extern float spawncycle; +extern cvar_t *gamepath; +extern cvar_t *chedit; +extern cvar_t *vwep; +extern float spawncycle; //ponpoko //K03 Begin -extern cvar_t *killboxspawn; +extern cvar_t *killboxspawn; extern cvar_t *save_path; extern cvar_t *particles; @@ -917,7 +968,6 @@ extern cvar_t *vrx_creditmult; extern cvar_t *vrx_pointmult; - extern cvar_t *flood_msgs; extern cvar_t *flood_persecond; extern cvar_t *flood_waitdelay; @@ -991,14 +1041,14 @@ extern cvar_t *world_min_slugs; //K03 End //ZOID -extern qboolean is_quad; +extern qboolean is_quad; //ZOID // az begin extern cvar_t *savemethod; extern cvar_t *tbi; -extern cvar_t *sv_fps; +extern cvar_t *sv_fps; extern cvar_t *vrx_pvppointmult; extern cvar_t *vrx_pvmpointmult; @@ -1029,148 +1079,213 @@ extern cvar_t *vrx_pvmcreditmult; #define FFL_NOSPAWN 2 typedef enum { - F_INT, - F_FLOAT, - F_LSTRING, // string on disk, pointer in memory, TAG_LEVEL - F_GSTRING, // string on disk, pointer in memory, TAG_GAME - F_VECTOR, - F_ANGLEHACK, - F_EDICT, // index on disk, pointer in memory - F_ITEM, // index on disk, pointer in memory - F_CLIENT, // index on disk, pointer in memory - F_FUNCTION, - F_MMOVE, - F_IGNORE + F_INT, + F_FLOAT, + F_LSTRING, // string on disk, pointer in memory, TAG_LEVEL + F_GSTRING, // string on disk, pointer in memory, TAG_GAME + F_VECTOR, + F_ANGLEHACK, + F_EDICT, // index on disk, pointer in memory + F_ITEM, // index on disk, pointer in memory + F_CLIENT, // index on disk, pointer in memory + F_FUNCTION, + F_MMOVE, + F_IGNORE } fieldtype_t; -typedef struct -{ - char *name; - size_t ofs; - fieldtype_t type; - int flags; +typedef struct { + char *name; + size_t ofs; + fieldtype_t type; + int flags; } field_t; -extern field_t fields[]; -extern gitem_t itemlist[]; +extern field_t fields[]; +extern gitem_t itemlist[]; // // g_cmds.c // -void Cmd_Help_f (edict_t *ent); -void Cmd_Score_f (edict_t *ent); -void FL_make (edict_t *self); +void Cmd_Help_f(edict_t *ent); + +void Cmd_Score_f(edict_t *ent); + +void FL_toggle(edict_t *self); +bool FL_exists(edict_t *self); // // g_items.c // -void PrecacheItem (gitem_t *it); -void InitItems (void); -void SetItemNames (void); -gitem_t *FindItem (char *pickup_name); -gitem_t *FindItemByClassname (char *classname); +void PrecacheItem(gitem_t *it); + +void InitItems(void); + +void SetItemNames(void); + +gitem_t *FindItem(char *pickup_name); + +gitem_t *FindItemByClassname(char *classname); + #define ITEM_INDEX(x) ((x)-itemlist) -edict_t *Drop_Item (edict_t *ent, gitem_t *item); -void SetRespawn (edict_t *ent, float delay); -void ChangeWeapon (edict_t *ent); -void SpawnItem (edict_t *ent, gitem_t *item); -void Think_Weapon (edict_t *ent); -int ArmorIndex (edict_t *ent); -int PowerArmorType (edict_t *ent); -gitem_t *GetItemByIndex (int index); -qboolean Add_Ammo (edict_t *ent, gitem_t *item, float count); -void Touch_Item (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf); -edict_t *Spawn_Item (gitem_t *item); + +edict_t *Drop_Item(edict_t *ent, gitem_t *item); + +void SetRespawn(edict_t *ent, float delay); + +void ChangeWeapon(edict_t *ent); + +void SpawnItem(edict_t *ent, gitem_t *item); + +void Think_Weapon(edict_t *ent); + +int ArmorIndex(edict_t *ent); + +int PowerArmorType(edict_t *ent); + +gitem_t *GetItemByIndex(int index); + +qboolean Add_Ammo(edict_t *ent, gitem_t *item, float count); + +void Touch_Item(edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf); + +edict_t *Spawn_Item(gitem_t *item); // // g_utils.c // -qboolean KillBox (edict_t *ent); -void G_ProjectSource (vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result); -edict_t *G_Find (edict_t *from, int fieldofs, char *match); +qboolean KillBox(edict_t *ent); + +void G_ProjectSource(vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result); + +edict_t *G_Find(edict_t *from, int fieldofs, char *match); edict_t *findradius(const edict_t *from, vec3_t const org, float rad); -edict_t *findclosestreticle (edict_t *prev_ed, edict_t *ent, float rad); -edict_t *findreticle (edict_t *from, edict_t *ent, float range, int degrees, qboolean vis); -edict_t *findclosestradius (edict_t *prev_ed, vec3_t org, float rad);//GHz +edict_t *findclosestreticle(edict_t *prev_ed, edict_t *ent, float rad); + +edict_t *findreticle(edict_t *from, edict_t *ent, float range, int degrees, qboolean vis); + +edict_t *findclosestradius(edict_t *prev_ed, vec3_t org, float rad); //GHz + + +edict_t *findclosestradius1(edict_t *prev_ed, vec3_t org, float rad); //GHz +edict_t *G_FindEntityByMtype(int mtype, edict_t *from); //GHz +float Get2dDistance(vec3_t v1, vec3_t v2); //GHz +void G_DrawSparks(vec3_t start, vec3_t end, int primary_color, int secondary_color, int num, float dist_between_sparks, + int min_rad, int max_rad); //GHz +int G_NearbyEnts(vec3_t const org, float rad, qboolean is_visible); //GHz +edict_t *G_CreateArrowMarker(vec3_t start, vec3_t dir, int skinnum, float duration); //GHz +edict_t *G_PickTarget(char *targetname); + +void G_UseTargets(edict_t *ent, edict_t *activator); + +void G_SetMovedir(vec3_t angles, vec3_t movedir); + +void G_InitEdict(edict_t *e); + +edict_t *G_Spawn(void); -edict_t *findclosestradius1 (edict_t *prev_ed, vec3_t org, float rad);//GHz -edict_t *G_FindEntityByMtype (int mtype, edict_t *from);//GHz -float Get2dDistance (vec3_t v1, vec3_t v2);//GHz -void G_DrawSparks(vec3_t start, vec3_t end, int primary_color, int secondary_color, int num, float dist_between_sparks, int min_rad, int max_rad);//GHz -int G_NearbyEnts(vec3_t const org, float rad, qboolean is_visible);//GHz -edict_t* G_CreateArrowMarker(vec3_t start, vec3_t dir, int skinnum, float duration);//GHz -edict_t *G_PickTarget (char *targetname); -void G_UseTargets (edict_t *ent, edict_t *activator); -void G_SetMovedir (vec3_t angles, vec3_t movedir); +void G_FreeEdict(edict_t *e); -void G_InitEdict (edict_t *e); -edict_t *G_Spawn (void); -void G_FreeEdict (edict_t *e); -void G_FreeAnyEdict (edict_t *e); +void G_FreeAnyEdict(edict_t *e); -void G_TouchTriggers (edict_t *ent); -void G_TouchSolids (edict_t *ent); +void G_TouchTriggers(edict_t *ent); -char *G_CopyString (char *in); +void G_TouchSolids(edict_t *ent); -float *tv (float x, float y, float z); -char *vtos (vec3_t v); +char *G_CopyString(char *in); -float vectoyaw (vec3_t vec); -void vectoangles (vec3_t vec, vec3_t angles); +float *tv(float x, float y, float z); + +char *vtos(vec3_t v); + +float vectoyaw(vec3_t vec); + +void vectoangles(vec3_t vec, vec3_t angles); + +qboolean G_EntIsAlive(const edict_t *ent); //GHz +qboolean G_IsValidLocation(edict_t *ignore, vec3_t point, vec3_t mins, vec3_t maxs); //GHz +qboolean G_IsClearPath(edict_t *ignore, int mask, const vec3_t spot1, const vec3_t spot2); -qboolean G_EntIsAlive(const edict_t *ent);//GHz -qboolean G_IsValidLocation (edict_t *ignore, vec3_t point, vec3_t mins, vec3_t maxs);//GHz -qboolean G_IsClearPath (edict_t *ignore, int mask, const vec3_t spot1, const vec3_t spot2); qboolean G_ClientExists(edict_t *player); -qboolean visible1 (edict_t *ent1, edict_t *ent2); -qboolean G_CanUseAbilities (edict_t *ent, int ability_lvl, int pc_cost); -qboolean V_CanUseAbilities (edict_t *ent, int ability_index, int ability_cost, qboolean print_msg); -qboolean V_CanUseAbility(edict_t* ent, int ability_index, int ability_cost, qboolean print_msg); + +qboolean visible1(edict_t *ent1, edict_t *ent2); + +qboolean G_CanUseAbilities(edict_t *ent, int ability_lvl, int pc_cost); + +qboolean V_CanUseAbilities(edict_t *ent, int ability_index, int ability_cost, qboolean print_msg); + +qboolean V_CanUseAbility(edict_t *ent, int ability_index, int ability_cost, qboolean print_msg); + qboolean G_ValidTarget(const edict_t *self, const edict_t *target, qboolean vis, qboolean alive); -qboolean G_ValidTargetEnt(edict_t* self, edict_t* target, qboolean alive); + +qboolean G_ValidTargetEnt(const edict_t *self, const edict_t *target, qboolean alive); + qboolean G_ValidTarget_Lite(const edict_t *self, const edict_t *target, qboolean vis); -qboolean G_ValidAlliedTarget(edict_t *self, edict_t *target, qboolean vis);//4.1 Archer +qboolean G_ValidAlliedTarget(edict_t *self, edict_t *target, qboolean vis); //4.1 Archer edict_t *G_GetClient(const edict_t *ent); + // G_GetSpawnLocation #define PROJECT_HITBOX_NEAR 1 #define PROJECT_HITBOX_FAR 2 #define PROJECT_HITBOX_FLOOR 3 -qboolean G_GetSpawnLocation (edict_t *ent, float range, vec3_t mins, vec3_t maxs, vec3_t start, vec3_t normal, int mode, qboolean ignore_self_clip); -void G_DrawBoundingBox (edict_t *ent); -void G_DrawLaserBBox (edict_t *ent, int laser_color, int laser_size); -void G_DrawLaser (edict_t *ent, vec3_t v1, vec3_t v2, int laser_color, int laser_size); +qboolean G_GetSpawnLocation(edict_t *ent, float range, vec3_t mins, vec3_t maxs, vec3_t start, vec3_t normal, int mode, + qboolean ignore_self_clip); + +void G_DrawBoundingBox(edict_t *ent); + +void G_DrawLaserBBox(edict_t *ent, int laser_color, int laser_size); + +void G_DrawLaser(edict_t *ent, vec3_t v1, vec3_t v2, int laser_color, int laser_size); + void G_DrawDebugTrail(vec3_t start, vec3_t end); -void G_ResetPlayerState (edict_t *ent); // 3.78 -int G_GetNumSummonable (edict_t *ent, char *classname); // 3.9 -void G_EntMidPoint (const edict_t *ent, vec3_t point); -void G_EntViewPoint (const edict_t *ent, vec3_t point); //4.55 -qboolean G_ClearShot (const edict_t *shooter, vec3_t start, const edict_t *target); -float distance (vec3_t p1, vec3_t p2); -void G_RunFrames (edict_t *ent, int start_frame, int end_frame, qboolean reverse); -void AngleCheck (float *val); -int Get_KindWeapon (gitem_t *it); - -edict_t *FindPlayerByName(char *name); //4.0 was (const char *name); + +void G_ResetPlayerState(edict_t *ent); // 3.78 +int G_GetNumSummonable(edict_t *ent, char *classname); // 3.9 +void G_EntMidPoint(const edict_t *ent, vec3_t point); + +void G_EntViewPoint(const edict_t *ent, vec3_t point); //4.55 +qboolean G_ClearShot(const edict_t *shooter, vec3_t start, const edict_t *target); + +float distance(const vec3_t p1, const vec3_t p2); + +void G_RunFrames(edict_t *ent, int start_frame, int end_frame, qboolean reverse, bool limit_rate); + +void AngleCheck(float *val); + +int Get_KindWeapon(gitem_t *it); + +edict_t *FindPlayerByName(char *name); //4.0 was (const char *name); edict_t *FindPlayer(char *s); -edict_t *InitMonsterEntity (qboolean manual_spawn); -edict_t *G_GetSummoner (const edict_t *ent); -void InitJoinedQueue (void); -void AddJoinedQueue (edict_t *ent); -qboolean TeleportNearArea (edict_t *ent, vec3_t point, int area_size, qboolean air); -qboolean HasActiveCurse (edict_t *ent, int curse_type); -qboolean HasActiveAura (edict_t *ent, int aura_type); -void RemoveCurse (edict_t *ent, edict_t *curse_ent); -edict_t *G_FindCurseByType (edict_t *ent, int curse_type); -edict_t *G_FindAuraByType (edict_t *ent, int aura_type); -qboolean AddCurse (edict_t *owner, edict_t *targ, edict_t *curse_ent, int type, float duration); + +edict_t *InitMonsterEntity(qboolean manual_spawn); + +edict_t *G_GetSummoner(const edict_t *ent); + +void InitJoinedQueue(void); + +void AddJoinedQueue(edict_t *ent); + +qboolean TeleportNearArea(edict_t *ent, vec3_t point, int area_size, qboolean air); + +qboolean HasActiveCurse(edict_t *ent, int curse_type); + +qboolean HasActiveAura(edict_t *ent, int aura_type); + +void RemoveCurse(edict_t *ent, edict_t *curse_ent); + +edict_t *G_FindCurseByType(edict_t *ent, int curse_type); + +edict_t *G_FindAuraByType(edict_t *ent, int aura_type); + +qboolean AddCurse(edict_t *owner, edict_t *targ, edict_t *curse_ent, int type, float duration); + void ShowGun(edict_t *ent); + void EndDMLevel(void); void vrx_start_reign(edict_t *ent); @@ -1187,7 +1302,7 @@ void OpenPTRJoinMenu(edict_t *ent); void AssignTeamSkin(edict_t *ent, char *s); -qboolean vrx_has_flag(const edict_t *ent);// 3.7 +qboolean vrx_has_flag(const edict_t *ent); // 3.7 qboolean ClientCanConnect(edict_t *ent, char *userinfo); void dom_awardpoints(void); @@ -1199,17 +1314,19 @@ void dom_checkforflag(edict_t *ent); void dom_fragaward(edict_t *attacker, edict_t *target); qboolean nearfov(edict_t *ent, edict_t *other, int vertical_degrees, int horizontal_degrees); -qboolean toright(edict_t* self, vec3_t point); + +qboolean toright(edict_t *self, vec3_t point); + void StuffPlayerCmds(edict_t *ent); //3.50 qboolean G_StuffPlayerCmds(edict_t *ent, const char *s); int floattoint(float input); //3.50 void SpawnFlames(edict_t *self, vec3_t start, int num_flames, int damage, int toss_speed); // 3.6 -void ThrowFlame (edict_t *ent, vec3_t start, vec3_t forward, float dist, int speed, int damage, int ttl);//4.2 -void G_PrintGreenText (char *text); // 3.7 +void ThrowFlame(edict_t *ent, vec3_t start, vec3_t forward, float dist, int speed, int damage, int ttl); //4.2 +void G_PrintGreenText(char *text); // 3.7 char *HiPrint(char *text); -qboolean G_IsSpectator(const edict_t *ent);// 3.7 +qboolean G_IsSpectator(const edict_t *ent); // 3.7 void G_TeleportNearbyEntities(vec3_t point, float radius, qboolean vis, edict_t *ignore); // 3.7 void stuffcmd(edict_t *ent, char *s); @@ -1221,34 +1338,51 @@ void vrx_check_for_levelup(edict_t *ent, qboolean print_message); double vrx_get_points_tnl(int level); -void Weapon_Blaster (edict_t *ent); -void Weapon_Shotgun (edict_t *ent); -void Weapon_SuperShotgun (edict_t *ent); -void Weapon_Machinegun (edict_t *ent); -void Weapon_Chaingun (edict_t *ent); -void Weapon_HyperBlaster (edict_t *ent); -void Weapon_RocketLauncher (edict_t *ent); -void Weapon_Grenade (edict_t *ent); -void Weapon_GrenadeLauncher (edict_t *ent); -void Weapon_Railgun (edict_t *ent); -void Weapon_BFG (edict_t *ent); +void Weapon_Blaster(edict_t *ent); + +void Weapon_Shotgun(edict_t *ent); + +void Weapon_SuperShotgun(edict_t *ent); + +void Weapon_Machinegun(edict_t *ent); + +void Weapon_Chaingun(edict_t *ent); + +void Weapon_HyperBlaster(edict_t *ent); + +void Weapon_RocketLauncher(edict_t *ent); + +void Weapon_Grenade(edict_t *ent); + +void Weapon_GrenadeLauncher(edict_t *ent); + +void Weapon_Railgun(edict_t *ent); + +void Weapon_BFG(edict_t *ent); // RAFAEL -void Weapon_Ionripper (edict_t *ent); -void Weapon_Phalanx (edict_t *ent); -void Weapon_Trap (edict_t *ent); +void Weapon_Ionripper(edict_t *ent); + +void Weapon_Phalanx(edict_t *ent); + +void Weapon_Trap(edict_t *ent); //K03 Begin -void Weapon_Sword (edict_t *ent); +void Weapon_Sword(edict_t *ent); // // g_combat.c // int OnSameTeam(const edict_t *ent1, const edict_t *ent2); -qboolean CanDamage (edict_t *targ, edict_t *inflictor); -qboolean CheckTeamDamage (edict_t *targ, edict_t *attacker); -int T_Damage (edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t normal, float damage, int knockback, int dflags, int mod); -void T_RadiusDamage (edict_t *inflictor, edict_t *attacker, float damage, edict_t *ignore, float radius, int mod); + +qboolean CanDamage(edict_t *targ, edict_t *inflictor); + +qboolean CheckTeamDamage(edict_t *targ, edict_t *attacker); + +int T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t normal, + float damage, int knockback, int dflags, int mod); + +void T_RadiusDamage(edict_t *inflictor, edict_t *attacker, float damage, edict_t *ignore, float radius, int mod); // damage flags #define DAMAGE_RADIUS 0x00000001 // damage was indirect @@ -1275,132 +1409,223 @@ void T_RadiusDamage (edict_t *inflictor, edict_t *attacker, float damage, edict_ // // g_monster.c // -void monster_fire_bullet (edict_t *self, vec3_t start, vec3_t dir, int damage, int kick, int hspread, int vspread, int flashtype); -void monster_fire_shotgun (edict_t *self, vec3_t start, vec3_t aimdir, float damage, int kick, int hspread, int vspread, int count, int flashtype); -void monster_fire_blaster (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int effect, int proj_type, float duration, qboolean bounce, int flashtype); -void monster_fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int flashtype); -void monster_fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype); -void monster_fire_railgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int flashtype); -void monster_fire_bfg (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int kick, float damage_radius, int flashtype); -void monster_fire_sword (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int flashtype); //Ghz -void monster_fire_20mm(edict_t* self, vec3_t start, vec3_t dir, int damage, int kick, float range, int flashtype); -void monster_fire_fireball(edict_t* self); -void monster_fire_poison(edict_t* self); -void monster_fire_icebolt(edict_t* self); -void monster_fire_rocks(edict_t* self); -void M_droptofloor (edict_t *ent); -void monster_think (edict_t *self); -void walkmonster_start (edict_t *self); -void swimmonster_start (edict_t *self); -void flymonster_start (edict_t *self); -void AttackFinished (edict_t *self, float time); -void monster_death_use (edict_t *self); -void M_CatagorizePosition (edict_t *ent); -qboolean M_CheckAttack (edict_t *self); -void M_FlyCheck (edict_t *self); -void M_CheckGround (edict_t *ent); -void M_SetEffects (edict_t *ent); -void M_MoveFrame (edict_t *self); -void M_WorldEffects (edict_t *ent); +void monster_fire_bullet(edict_t *self, vec3_t start, vec3_t dir, int damage, int kick, int hspread, int vspread, + int flashtype); + +void monster_fire_shotgun(edict_t *self, vec3_t start, vec3_t aimdir, float damage, int kick, int hspread, int vspread, + int count, int flashtype); + +void monster_fire_blaster(edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int effect, int proj_type, + float duration, qboolean bounce, int flashtype); + +void monster_fire_grenade(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int flashtype); + +void monster_fire_rocket(edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype); + +void monster_fire_railgun(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int flashtype); + +void monster_fire_bfg(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int kick, float damage_radius, + int flashtype); + +void monster_fire_sword(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int flashtype); //Ghz +void monster_fire_20mm(edict_t *self, vec3_t start, vec3_t dir, int damage, int kick, float range, int flashtype); + +void monster_fire_fireball(edict_t *self); + +void monster_fire_poison(edict_t *self); + +void monster_fire_icebolt(edict_t *self); + +void monster_fire_rocks(edict_t *self); + +void M_droptofloor(edict_t *ent); + +void monster_think(edict_t *self); + +void walkmonster_start(edict_t *self); + +void swimmonster_start(edict_t *self); + +void flymonster_start(edict_t *self); + +void AttackFinished(edict_t *self, float time); + +void monster_death_use(edict_t *self); + +void M_CatagorizePosition(edict_t *ent); + +qboolean M_CheckAttack(edict_t *self); + +void M_FlyCheck(edict_t *self); + +void M_CheckGround(edict_t *ent); + +void M_SetEffects(edict_t *ent); + +void M_MoveFrame(edict_t *self); + +void M_WorldEffects(edict_t *ent); + edict_t *vrx_create_new_drone(edict_t *ent, int drone_type, qboolean worldspawn, qboolean link_now, int bonus_level); + edict_t * -vrx_create_drone_from_ent(edict_t *drone, edict_t *ent, int drone_type, qboolean worldspawn, qboolean link_now, int bonus_level); +vrx_create_drone_from_ent(edict_t *drone, edict_t *ent, int drone_type, qboolean worldspawn, qboolean link_now, + int bonus_level); // // g_misc.c // -void ThrowHead (edict_t *self, char *gibname, int damage, int type); -void ThrowClientHead (edict_t *self, int damage); -void ThrowGib (edict_t *self, char *gibname, int damage, int type); +void ThrowHead(edict_t *self, char *gibname, int damage, int type); + +void ThrowClientHead(edict_t *self, int damage); + +void ThrowGib(edict_t *self, char *gibname, int damage, int type); + void BecomeExplosion1(edict_t *self); -void BecomeTE(edict_t *self);//GHz -void BecomeBigExplosion(edict_t *self);//GHz + +void BecomeTE(edict_t *self); //GHz +void BecomeBigExplosion(edict_t *self); //GHz void SV_SaveAllCharacters(void); -int HighestLevelPlayer(void);//GHz + +int HighestLevelPlayer(void); //GHz int LowestLevelPlayer(void); -int PvMHighestLevelPlayer(void);//GHz + +int PvMHighestLevelPlayer(void); //GHz int PvMLowestLevelPlayer(void); -int vrx_get_alive_players (void);//Apple -int vrx_GetMonsterCost(int mtype);//GHz -int vrx_GetMonsterControlCost(int mtype);//GHz -void vrx_remove_player_summonables(edict_t *self);//GHz + +int vrx_get_alive_players(void); //Apple +int vrx_GetMonsterCost(int mtype); //GHz +int vrx_GetMonsterControlCost(int mtype); //GHz +void vrx_remove_player_summonables(edict_t *self); //GHz // // g_ai.c // -void AI_SetSightClient (void); - -void ai_stand (edict_t *self, float dist); -void ai_move (edict_t *self, float dist); -void ai_walk (edict_t *self, float dist); -void ai_turn (edict_t *self, float dist); -void ai_run (edict_t *self, float dist); -void ai_charge (edict_t *self, float dist); -int range (edict_t *self, edict_t *other); - -void FoundTarget (edict_t *self); -qboolean infront (edict_t *self, edict_t *other); -qboolean visible (const edict_t *self, const edict_t *other); +void AI_SetSightClient(void); + +void ai_stand(edict_t *self, float dist); + +void ai_move(edict_t *self, float dist); + +void ai_walk(edict_t *self, float dist); + +void ai_turn(edict_t *self, float dist); + +void ai_run(edict_t *self, float dist); + +void ai_charge(edict_t *self, float dist); + +int range(edict_t *self, edict_t *other); + +void FoundTarget(edict_t *self); + +qboolean infront(edict_t *self, edict_t *other); + +qboolean visible(const edict_t *self, const edict_t *other); + qboolean FacingIdeal(edict_t *self); -qboolean infov (edict_t *self, edict_t *other, int degrees); + +qboolean infov(edict_t *self, edict_t *other, int degrees); // // drone_ai.c // -void drone_ai_stand (edict_t *self, float dist); -void drone_ai_run (edict_t *self, float dist); -void drone_ai_run1 (edict_t *self, float dist); -void drone_ai_walk (edict_t *self, float dist); +void drone_ai_stand(edict_t *self, float dist); + +void drone_ai_run(edict_t *self, float dist); + +void drone_ai_run1(edict_t *self, float dist); + +void drone_ai_walk(edict_t *self, float dist); // az begin void ai_eval_targets(); -float drone_damagelevel(const edict_t* ent); -edict_t *findclosestradius_targets(edict_t *prev_ed, edict_t* self, float radius); + +float drone_damagelevel(const edict_t *ent); + +edict_t *findclosestradius_targets(edict_t *prev_ed, edict_t *self, float radius); + qboolean vrx_is_in_target_list(edict_t *ent); + // az end // // g_weapon.c // -void ThrowDebris (edict_t *self, char *modelname, float speed, vec3_t origin); -qboolean fire_hit (edict_t *self, vec3_t aim, int damage, int kick); -void fire_bullet (edict_t *self, vec3_t start, vec3_t aimdir, float damage, int kick, int hspread, int vspread, int mod); -void fire_shotgun (edict_t *self, vec3_t start, vec3_t aimdir, float damage, int kick, int hspread, int vspread, int count, int mod); -void fire_blaster (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int effect, int proj_type, int mod, float duration, qboolean bounce); -void fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius, int radius_damage); -edict_t *fire_grenade2 (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius, int radius_damage, qboolean held); -void fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, int radius_damage); -void fire_rail (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick); -void fire_bfg (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius); +void ThrowDebris(edict_t *self, char *modelname, float speed, vec3_t origin); + +qboolean fire_hit(edict_t *self, vec3_t aim, int damage, int kick); + +void fire_bullet(edict_t *self, vec3_t start, vec3_t aimdir, float damage, int kick, int hspread, int vspread, int mod); + +void fire_shotgun(edict_t *self, vec3_t start, vec3_t aimdir, float damage, int kick, int hspread, int vspread, + int count, int mod); + +void fire_blaster(edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int effect, int proj_type, int mod, + float duration, qboolean bounce); + +void fire_grenade(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius, + int radius_damage); + +edict_t *fire_grenade2(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, + float damage_radius, int radius_damage, qboolean held); + +void fire_rocket(edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, + int radius_damage); + +void fire_rail(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick); + +void fire_bfg(edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius); + // RAFAEL -void fire_ionripper (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int effect); -void fire_heat (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, int radius_damage); -void fire_blueblaster (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int effect); -void fire_plasma (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, int radius_damage); -void fire_trap (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius, qboolean held); -void fire_smartrocket (edict_t *self, edict_t *target, vec3_t start, vec3_t dir, int damage, int speed, int turn_speed, float damage_radius, int radius_damage); -void fire_20mm(edict_t* self, vec3_t start, vec3_t aimdir, int damage, int kick, float range); +void fire_ionripper(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int effect); + +void fire_heat(edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, int radius_damage); + +void fire_blueblaster(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int effect); + +void fire_plasma(edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, + int radius_damage); + +void fire_trap(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius, + qboolean held); + +void fire_smartrocket(edict_t *self, edict_t *target, vec3_t start, vec3_t dir, int damage, int speed, int turn_speed, + float damage_radius, int radius_damage); + +void fire_20mm(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, float range); // // g_ptrail.c // -void PlayerTrail_Init (void); -void PlayerTrail_Add (vec3_t spot); -void PlayerTrail_New (vec3_t spot); -edict_t *PlayerTrail_PickFirst (edict_t *self); -edict_t *PlayerTrail_PickNext (edict_t *self); -edict_t *PlayerTrail_LastSpot (void); +void PlayerTrail_Init(void); + +void PlayerTrail_Add(vec3_t spot); + +void PlayerTrail_New(vec3_t spot); + +edict_t *PlayerTrail_PickFirst(edict_t *self); + +edict_t *PlayerTrail_PickNext(edict_t *self); + +edict_t *PlayerTrail_LastSpot(void); // // g_client.c // -void respawn (edict_t *ent); -void BeginIntermission (edict_t *targ); -void PutClientInServer (edict_t *ent); -void InitClientPersistant (gclient_t *client); -void InitClientResp (gclient_t *client); -void InitBodyQue (void); -void ClientBeginServerFrame (edict_t *ent); +void respawn(edict_t *ent); + +void BeginIntermission(edict_t *targ); + +void PutClientInServer(edict_t *ent); + +void InitClientPersistant(gclient_t *client); + +void InitClientResp(gclient_t *client); + +void InitBodyQue(void); + +void ClientBeginServerFrame(edict_t *ent); // // v_think.c @@ -1410,65 +1635,84 @@ void vrx_client_think(edict_t *ent); // // g_player.c // -void player_pain (edict_t *self, edict_t *other, float kick, int damage); -void player_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point); +void player_pain(edict_t *self, edict_t *other, float kick, int damage); + +void player_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point); // // g_svcmds.c // -void ServerCommand (void); -qboolean SV_FilterPacket (char *from); -qboolean SV_IpSilenced (char* from); // az +void ServerCommand(void); + +qboolean SV_FilterPacket(char *from); + +qboolean SV_IpSilenced(char *from); // az // m_move.c // -qboolean M_CheckBottom (edict_t *ent); -qboolean M_walkmove (edict_t *ent, float yaw, float dist); -void M_MoveToGoal (edict_t *ent, float dist); -void M_ChangeYaw (edict_t *ent); +qboolean M_CheckBottom(edict_t *ent); + +qboolean M_walkmove(edict_t *ent, float yaw, float dist); + +void M_MoveToGoal(edict_t *ent, float dist); + +void M_ChangeYaw(edict_t *ent); // // p_view.c // -void ClientEndServerFrame (edict_t *ent); +void ClientEndServerFrame(edict_t *ent); // // p_hud.c // -void MoveClientToIntermission (edict_t *client); -void G_SetStats (edict_t *ent); -void G_SetSpectatorStats (edict_t *ent); -void G_CheckChaseStats (edict_t *ent); -void ValidateSelectedItem (edict_t *ent); -void DeathmatchScoreboardMessage (edict_t *client, edict_t *killer); +void MoveClientToIntermission(edict_t *client); + +void G_SetStats(edict_t *ent); + +void G_SetSpectatorStats(edict_t *ent); + +void G_CheckChaseStats(edict_t *ent); + +void ValidateSelectedItem(edict_t *ent); + +void DeathmatchScoreboardMessage(edict_t *client, edict_t *killer); // // p_weapon.c // void PlayerNoise(edict_t *who, vec3_t where, int type); -void P_ProjectSource (gclient_t *client, vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result); -void Weapon_Generic (edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST, int FRAME_IDLE_LAST, int FRAME_DEACTIVATE_LAST, int *pause_frames, int *fire_frames, void (*fire)(edict_t *ent)); + +void P_ProjectSource(gclient_t *client, vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result); + +void Weapon_Generic(edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST, int FRAME_IDLE_LAST, + int FRAME_DEACTIVATE_LAST, int *pause_frames, int *fire_frames, void (*fire)(edict_t *ent)); // // g_phys.c // -void G_RunEntity (edict_t *ent); +void G_RunEntity(edict_t *ent); // // g_main.c // -void SaveClientData (void); -void FetchClientEntData (edict_t *ent); +void SaveClientData(void); + +void FetchClientEntData(edict_t *ent); // // g_chase.c // void UpdateChaseCam(edict_t *ent); + void ChaseNext(edict_t *ent); + void ChasePrev(edict_t *ent); + void GetChaseTarget(edict_t *ent); -void DisableChaseCam(edict_t* ent); // az + +void DisableChaseCam(edict_t *ent); // az //============================================================================ //jabot @@ -1487,597 +1731,741 @@ void DisableChaseCam(edict_t* ent); // az // ### Hentai ### END // client data that stays across multiple level loads -typedef struct -{ - char userinfo[MAX_INFO_STRING]; - char netname[16]; - int hand; - - qboolean connected; // a loadgame will leave valid entities that - // just don't have a connection yet - - // values saved and restored from edicts when changing levels - int health; - int max_health; - qboolean powerArmorActive; - - int selected_item; - int inventory[MAX_ITEMS]; - - // ammo capacities - int max_bullets; - int max_shells; - int max_rockets; - int max_grenades; - int max_cells; - int max_slugs; - // RAFAEL - int max_magslug; - int max_trap; - - gitem_t *weapon; - gitem_t *lastweapon; - - int power_cubes; // used for tracking the cubes in coop games - int score; // for calculating total unit score in coop games - - int game_helpchanged; - int helpchanged; - - qboolean spectator; // client is a spectator - - //K03 Begin - int max_powercubes; - int max_tballs; - char orginal_netname[16]; - char current_ip[16]; - //4.0 ctf stuff - float ctf_assist_frag; // used to give the player a "kill the flag carrier" assist - float ctf_assist_return; // used to give the player a "return the flag" assist - int scanner_active; - //K03 End +typedef struct { + char userinfo[MAX_INFO_STRING]; + char netname[16]; + int hand; + + qboolean connected; // a loadgame will leave valid entities that + // just don't have a connection yet + + // values saved and restored from edicts when changing levels + int health; + int max_health; + qboolean powerArmorActive; + + int selected_item; + int inventory[MAX_ITEMS]; + + // ammo capacities + int max_bullets; + int max_shells; + int max_rockets; + int max_grenades; + int max_cells; + int max_slugs; + // RAFAEL + int max_magslug; + int max_trap; + + gitem_t *weapon; + gitem_t *lastweapon; + + int power_cubes; // used for tracking the cubes in coop games + int score; // for calculating total unit score in coop games + + int game_helpchanged; + int helpchanged; + + qboolean spectator; // client is a spectator + + //K03 Begin + int max_powercubes; + int max_tballs; + char orginal_netname[16]; + char current_ip[16]; + //4.0 ctf stuff + float ctf_assist_frag; // used to give the player a "kill the flag carrier" assist + float ctf_assist_return; // used to give the player a "return the flag" assist + int scanner_active; + //K03 End } client_persistant_t; // client data that stays across deathmatch respawns -typedef struct -{ - client_persistant_t coop_respawn; // what to set client->pers to on a respawn - int enterframe; // level.framenum the client entered the game - int score; // frags, etc -//ponko - int context; -//ponko - vec3_t cmd_angles; // angles sent over in the last command - int game_helpchanged; - int helpchanged; - - qboolean spectator; // client is a spectator - - //K03 Begin - int frags; - //K03 End - qboolean HasVoted; //GHz - int voteType; // 1 yes, 2 no, 0 neither - float VoteTimeout; - - // 3.5 delayed stuffcmd commands - char stuffbuf[500]; // commands that will be stuffed to client; delay prevents overflow - char *stuffptr; - - // invasion wave stat tracking - int wave_solo_dmgmod; - int wave_solo_targets; - int wave_solo_exp; - int wave_solo_credits; - int wave_shared_exp; - int wave_shared_credits; - int wave_assist_exp; - int wave_assist_credits; +typedef struct { + client_persistant_t coop_respawn; // what to set client->pers to on a respawn + int enterframe; // level.framenum the client entered the game + int score; // frags, etc + //ponko + int context; + //ponko + vec3_t cmd_angles; // angles sent over in the last command + int game_helpchanged; + int helpchanged; + + qboolean spectator; // client is a spectator + + //K03 Begin + int frags; + //K03 End + qboolean HasVoted; //GHz + int voteType; // 1 yes, 2 no, 0 neither + float VoteTimeout; + + // 3.5 delayed stuffcmd commands + char stuffbuf[500]; // commands that will be stuffed to client; delay prevents overflow + char *stuffptr; + + // invasion wave stat tracking + int wave_solo_dmgmod; + int wave_solo_targets; + int wave_solo_exp; + int wave_solo_credits; + int wave_shared_exp; + int wave_shared_credits; + int wave_assist_exp; + int wave_assist_credits; } client_respawn_t; #include "combat/abilities/g_abilities.h" #include "menus/menu.h" +/* az: variable refresh rate stuff */ +struct vrr_t { + // az note: + // haste works by causing a weapon to fire more often according to a timer, + // and it assumes the weapon works at 10hz. + // gun_fire_time makes it so fire state cannot change gunframes until + // its time arrives, so that animations and weapon states don't advance ahead of schedule. + // the statemachine time handles the activation, deactivation, ready states across all weapons + // enforcing a steady 10 hz. the firing state always lets the gun run at whatever framerate, + // so gun_fire_time steadies that at-will. + + // makes it so that during firing frames (call to Fire function) + // you have to wait until this level time to fire the next shot + float gun_fire_time; + + // weapon_generic2 handling of activate/ready/deactivate time + float gun_statemachine_time; // weapon animations time + + int stretched_frames; // for sword +}; + // this structure is cleared on each PutClientInServer(), // except for 'client->pers' -struct gclient_s -{ - // known to server - player_state_t ps; // communicated by server to clients - int ping; - - // private to game - client_persistant_t pers; - client_respawn_t resp; - pmove_state_t old_pmove; // for detecting out-of-pmove changes - - qboolean showscores; // set layout stat - - // az begin - // for the dynamic hud - layout_t layout; - - // for calls that are initiated in a secondary thread that must be done in the main thread - deferrals_t defers; - - stash_state_t stash; - // az end - - qboolean showinventory; // set layout stat - qboolean showhelp; - - int ammo_index; - - int buttons; - int oldbuttons; - int latched_buttons; - - qboolean weapon_thunk; - - gitem_t *newweapon; - - // sum up damage over an entire frame, so - // shotgun blasts give a single big kick - int damage_armor; // damage absorbed by armor - int damage_parmor; // damage absorbed by power armor - int damage_blood; // damage taken out of health - int damage_knockback; // impact damage - vec3_t damage_from; // origin for vector calculation - - float killer_yaw; // when dead, look at killer - - weaponstate_t weaponstate; - vec3_t kick_angles; // weapon kicks - vec3_t kick_origin; - float v_dmg_roll, v_dmg_pitch, v_dmg_time; // damage kicks - float fall_time, fall_value; // for view drop on fall - float damage_alpha; - float bonus_alpha; - vec3_t damage_blend; - vec3_t v_angle; // aiming direction - float bobtime; // so off-ground doesn't change it - vec3_t oldviewangles; - vec3_t oldvelocity; - - float next_drown_time; - int old_waterlevel; - int breather_sound; - - int machinegun_shots; // for weapon raising - - // animation vars - int anim_end; - int anim_priority; - qboolean anim_duck; - qboolean anim_run; - - // powerup timers - float quad_framenum; - float invincible_framenum; - float breather_framenum; - float enviro_framenum; - - qboolean grenade_blew_up; - float grenade_time; - int grenade_delay; - // RAFAEL - float quadfire_framenum; - int burst_count; - float trap_time; - - int silencer_shots; - int weapon_sound; - - float pickup_msg_time; - - float respawn_time; // can respawn when time > this - -//ZOID - float ctf_techsndtime; - edict_t *chase_target; - edict_t *idtarget; -//ZOID - //K03 Begin - float flood_locktill; // locked from talking - float flood_when[10]; // when messages were said - int flood_whenhead; // head pointer for when said - qboolean thrusting; - int thrustdrain; - float next_thrust_sound; - - qboolean cloakable; - qboolean cloaking; - float cloaktime; - int cloakdrain; - - qboolean boosted; //Talent: Leap Attack - true if player used boost and is still airbourne - - float healthregen_time; - float armorregen_time; - - int hook_state; - qboolean firebeam;//GHz - float beamtime;//GHz - edict_t *hook; - int chasecam_mode; - - int bfg_blend; - - //K03 End - int weapon_mode;//GHz - int last_weapon_mode; - int refire_frames; - int idle_frames; // number of frames player has been standing still and not firing - int still_frames; // number of frames player has been standing still (used for idle kick) - qboolean lowlight; - float tball_delay; - float ability_delay; - float disconnect_time; - float rune_delay; // time when we can pick up runes again (to prevent hogging) - float snipertime; - float oldfov; - float oldspeed; // GHz: used for flyer for comparison (impact with object) - - qboolean trading; // is player trading? - qboolean trade_off; // is the player blocking trades? - qboolean trade_accepted; // has player accepted trade? - qboolean trade_final; // is the player in the final trade menu? - edict_t *menutarget; // ent stats we are viewing with menu (ent->other is just for clients) - menusystem_t menustorage; // stores menu data - - int vamp_counter; // used to track vamped health per second - int vamp_frames; // used for vamp delay - - int lock_frames; // how many frames player's cursor has been on lock_target - edict_t *lock_target; // entity player has locked his cursor on - - // v3.12 ally menu stuff - edict_t *allytarget; // player we are trying to ally with - qboolean ally_accept; // have we accepted the alliance? - qboolean allying; // is the player trying to ally with someone? - float ally_time; // when did we begin invitation? - - // 3.5 some abilties don't use power cubes, and instead rely on a charge - int charge_index; // index of ability charge we're showing - float charge_time; // level time the index is reset - float charge_regentime; // time when the ability can begin recharging - float menu_delay; // time before we can cycle thru next menu option (to prevent overflow!) - float ammo_regentime; // next ammo regen tick - float wormhole_time; // must exit wormhole by this time - - qboolean jump; - qboolean show_allyinfo; // displays ally info data (health/armor bars) - - qboolean waiting_to_join; // this player has indicated that they want to join the game (used for teamplay queues) - float waiting_time; // the exact time when the player indicated they wanted to join - int showGridDebug; // show grid debug information (0=off,1=grid,2=children) - float lastCommand; // 'double click' delay for monster commands - vec3_t lastPosition; // last selected position for monster command - edict_t *lastEnt; // last selected entity for monster command +struct gclient_s { + // known to server + player_state_t ps; // communicated by server to clients + int ping; + + // private to game + client_persistant_t pers; + client_respawn_t resp; + pmove_state_t old_pmove; // for detecting out-of-pmove changes + + qboolean showscores; // set layout stat + + // az begin + // for the dynamic hud + layout_t layout; + + // for calls that are initiated in a secondary thread that must be done in the main thread + deferrals_t defers; + + stash_state_t stash; + // az end + + qboolean showinventory; // set layout stat + qboolean showhelp; + + int ammo_index; + + int buttons; + int oldbuttons; + int latched_buttons; + + qboolean weapon_thunk; + + gitem_t *newweapon; + + // sum up damage over an entire frame, so + // shotgun blasts give a single big kick + int damage_armor; // damage absorbed by armor + int damage_parmor; // damage absorbed by power armor + int damage_blood; // damage taken out of health + int damage_knockback; // impact damage + vec3_t damage_from; // origin for vector calculation + + float killer_yaw; // when dead, look at killer + + weaponstate_t weaponstate; + vec3_t kick_angles; // weapon kicks + vec3_t kick_origin; + float v_dmg_roll, v_dmg_pitch, v_dmg_time; // damage kicks + float fall_time, fall_value; // for view drop on fall + float damage_alpha; + float bonus_alpha; + vec3_t damage_blend; + vec3_t v_angle; // aiming direction + float bobtime; // so off-ground doesn't change it + vec3_t oldviewangles; + vec3_t oldvelocity; + + float next_drown_time; + int old_waterlevel; + int breather_sound; + + int machinegun_shots; // for weapon raising + + // animation vars + int anim_end; + int anim_priority; + qboolean anim_duck; + qboolean anim_run; + + // powerup timers + float quad_framenum; + float invincible_framenum; + float breather_framenum; + float enviro_framenum; + + qboolean grenade_blew_up; + float grenade_time; + int grenade_delay; + // RAFAEL + float quadfire_framenum; + int burst_count; + float trap_time; + + int silencer_shots; + int weapon_sound; + + float pickup_msg_time; + + float respawn_time; // can respawn when time > this + + //ZOID + float ctf_techsndtime; + edict_t *chase_target; + edict_t *idtarget; + //ZOID + //K03 Begin + float flood_locktill; // locked from talking + float flood_when[10]; // when messages were said + int flood_whenhead; // head pointer for when said + qboolean thrusting; + int thrustdrain; + float next_thrust_sound; + + qboolean cloakable; + qboolean cloaking; + float cloaktime; + int cloakdrain; + + qboolean boosted; //Talent: Leap Attack - true if player used boost and is still airbourne + + float healthregen_time; + float armorregen_time; + + int hook_state; + qboolean firebeam; //GHz + float beamtime; //GHz + edict_t *hook; + int chasecam_mode; + + int bfg_blend; + + //K03 End + int weapon_mode; //GHz + int last_weapon_mode; + int refire_frames; + int idle_frames; // number of frames player has been standing still and not firing + int still_frames; // number of frames player has been standing still (used for idle kick) + qboolean lowlight; + float tball_delay; + float ability_delay; + float disconnect_time; + float rune_delay; // time when we can pick up runes again (to prevent hogging) + float snipertime; + float oldfov; + float oldspeed; // GHz: used for flyer for comparison (impact with object) + + qboolean trading; // is player trading? + qboolean trade_off; // is the player blocking trades? + qboolean trade_accepted; // has player accepted trade? + qboolean trade_final; // is the player in the final trade menu? + edict_t *menutarget; // ent stats we are viewing with menu (ent->other is just for clients) + menusystem_t menustorage; // stores menu data + + int vamp_counter; // used to track vamped health per second + int vamp_frames; // used for vamp delay + + int lock_frames; // how many frames player's cursor has been on lock_target + edict_t *lock_target; // entity player has locked his cursor on + + // v3.12 ally menu stuff + edict_t *allytarget; // player we are trying to ally with + qboolean ally_accept; // have we accepted the alliance? + qboolean allying; // is the player trying to ally with someone? + float ally_time; // when did we begin invitation? + + // 3.5 some abilties don't use power cubes, and instead rely on a charge + int charge_index; // index of ability charge we're showing + float charge_time; // level time the index is reset + float charge_regentime; // time when the ability can begin recharging + float menu_delay; // time before we can cycle thru next menu option (to prevent overflow!) + float ammo_regentime; // next ammo regen tick + float wormhole_time; // must exit wormhole by this time + + qboolean jump; + qboolean show_allyinfo; // displays ally info data (health/armor bars) + + qboolean waiting_to_join; // this player has indicated that they want to join the game (used for teamplay queues) + float waiting_time; // the exact time when the player indicated they wanted to join + int showGridDebug; // show grid debug information (0=off,1=grid,2=children) + float lastCommand; // 'double click' delay for monster commands + vec3_t lastPosition; // last selected position for monster command + edict_t *lastEnt; // last selected entity for monster command qboolean update_chase; - vec3_t oldpos; // used by Blink Strike to store position prior to teleportation - int tele_timeout; // used by Blink Strike to store level.framenum when attack ends and player teleports (back) to oldpos - edict_t *blinkStrike_targ; // used by Blink Strike - target entity for attack - edict_t *pickup; // entity we are holding/have picked up - edict_t *pickup_prev; // previously picked up entity + + struct vrr_t vrr; // variable refresh rate data + vec3_t oldpos; // used by Blink Strike to store position prior to teleportation + int tele_timeout; + // used by Blink Strike to store level.framenum when attack ends and player teleports (back) to oldpos + edict_t *blinkStrike_targ; // used by Blink Strike - target entity for attack + edict_t *pickup; // entity we are holding/have picked up + edict_t *pickup_prev; // previously picked up entity }; -struct edict_s -{ - entity_state_t s; - struct gclient_s *client; // NULL if not a player - // the server expects the first part - // of gclient_s to be a player_state_t - // but the rest of it is opaque - - qboolean inuse; - int linkcount; - - // FIXME: move these fields to a server private sv_entity_t - link_t area; // linked to a division node or leaf - - int num_clusters; // if -1, use headnode instead - int clusternums[MAX_ENT_CLUSTERS]; - int headnode; // unused if num_clusters != -1 - int areanum, areanum2; - - //================================ - - int svflags; // note: SVF_MONSTER tells physics to clip on any solid object (not just walls) - vec3_t mins, maxs; - vec3_t absmin, absmax, size; - solid_t solid; - int clipmask; - edict_t *owner; - - - // DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER - // EXPECTS THE FIELDS IN THAT ORDER! - - //================================ - int movetype; - int flags; - int v_flags; //3.0 New flag variable (so nothing else previously coded is screwed up) - - char *model; - float freetime; // sv.time when the object was freed - - // - // only used locally in game, not by server - // - char *message; - char *classname; - int spawnflags; - - float timestamp; - - float angle; // set in qe3, -1 = up, -2 = down - char *target; - char *targetname; - char *killtarget; - char *team; - char *pathtarget; - edict_t *target_ent; -//ponko - edict_t *union_ent; //union item - edict_t *trainteam; //train team -//ponko - float speed, accel, decel; - vec3_t movedir; - vec3_t pos1, pos2; - - vec3_t velocity; - vec3_t avelocity; - int mass; - float air_finished; - float gravity; // per entity gravity multiplier (1.0 is normal) - // use for lowgrav artifact, flares - - edict_t *goalentity; - edict_t *movetarget; - float yaw_speed; - float ideal_yaw; - - float nextthink; - void (*prethink) (edict_t *ent); - void (*think)(edict_t *self); - void (*blocked)(edict_t *self, edict_t *other); //move to moveinfo? - void (*touch)(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf); - void (*use)(edict_t *self, edict_t *other, edict_t *activator); - void (*pain)(edict_t *self, edict_t *other, float kick, int damage); - void (*pain_inner)(edict_t* self, edict_t* other, float kick, int damage); // az: for monsters that use drone_pain - void (*die)(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point); - void (*notify_drone_death)(edict_t *self); - - float touch_debounce_time; // are all these legit? do we need more/less of them? - float pain_debounce_time; - float damage_debounce_time; - float fly_sound_debounce_time; //move to clientinfo - float knockweapon_debounce_time; // time when knockweapon code can be run again - float last_move_time; - - long health; - long max_health; - int gib_health; - int deadflag; - - float powerarmor_time; - - char *map; // target_changelevel - - int viewheight; // height above origin where eyesight is determined - int takedamage; - int dmg; - int radius_dmg; - float dmg_radius; - int sounds; //make this a spawntemp var? - int count; - - edict_t *chain; - edict_t *prev_chain; - edict_t *memchain; - edict_t *enemy; - edict_t *oldenemy; - edict_t *activator; - edict_t *groundentity; - int groundentity_linkcount; - edict_t *teamchain; - edict_t *teammaster; - - int noise_index; - float volume; - float attenuation; - - // timing variables - float wait; - float delay; // before firing targets - float random; - - float teleport_time; - - int watertype; - int waterlevel; - - vec3_t move_origin; - vec3_t move_angles; - - // move this to clientinfo? - int light_level; - - int style; // also used as areaportal number - - gitem_t *item; // for bonus items - - // common data blocks - moveinfo_t moveinfo; - monsterinfo_t monsterinfo; - - // jabot (vrxcl/newvrx) - ai_handle_t ai; - - // RAFAEL - int orders; - - //K03 Begin - int packitems[MAX_ITEMS]; - float PlasmaDelay; - float holdtime; - qboolean slow; - qboolean superspeed; - qboolean sucking;//GHz - qboolean antigrav; - qboolean automag; // az: magmining self? - qboolean manacharging; // az: charging mana? - int lockon; - - int FrameShot; - int Slower; - skills_t myskills; - float haste_time; - int rocket_shots; - - int shots_hit; - int shots; - float lastkill; - int nfer; - float lastdmg; - float lasthurt; // last time we took non-world damage - int lastsound; // last frame we made a sound - int dmg_counter; - int flipping; // flipping data - edict_t *creator; - //sentry stuff - edict_t *sentry; - edict_t *selectedsentry; - edict_t *standowner; - float sentrydelay; - edict_t *lasersight; - float lasthbshot; - edict_t *decoy; - edict_t *flashlight; - int mtype; // Type of Monstersee M_* defines.. (M_HOVER, etc) - int atype; //3.0 used for new curses - int num_sentries; - int num_monsters; - int num_monsters_real; - int num_lasers; - int max_pipes; - int num_armor; // 3.5 keep track of armor bombs out - int num_proxy; // 3.6 keep track of proxy grenades out - int num_napalm; // 3.6 keep track of napalm grenades out - int num_spikegrenades; // number of spike greandes out - int num_autocannon; //4.1 keep track of live autocannons - int num_caltrops;//4.2 keep track of live caltrops - int num_detectors; // number of live detectors - int num_spikers; - int num_gasser; - int num_obstacle; - int num_magmine; - int num_barrels; - int num_skeletons; - int num_golems; - int num_packanimals; - int num_firewalls; - int num_spikeball; - int num_laserplatforms; //4.4 Talent: Laser Platform - int num_hammers; //4.4 Talent: Boomerang - int health_cache; // accumulated health that entity will recover - int health_cache_nextframe; // the next server frame we will attempt to transfer from health_cache to entity's health - int armor_cache; - int armor_cache_nextframe; - qboolean spikeball_follow; - qboolean spikeball_recall; - int shield; //4.2 shielding value, 0=no shield, 1=front, 2=whole body - float shield_activate_time; // when shield will activate - int movetype_prev; // previous movetype, used by V_Push() - int movetype_frame; // server frame to restore old movetype - //K03 End - - // az begin - qboolean exploded; // az: don't explode more than once at death. lol - int list_index; - // az end - - edict_t *selected[4]; - edict_t *other; - edict_t *supplystation; - //edict_t *magmine; -//GHz START - // rune stuff - edict_t *trade_with; - item_t *trade_item[3]; - float msg_time; - //3.0 rune stuff - item_t vrxitem; - // teamplay - int teamnum; - float incontrol_time; - edict_t *skull; - que_t auras[QUE_MAXSIZE]; - que_t curses[QUE_MAXSIZE]; - float corpseeater_time; - int parasite_frames; - edict_t *parasite_target; - // 3.03+ spirit - edict_t *spirit; - // 3.12 curse effects - int curse_dir; - int curse_delay; - //4.0 "chilled effect" - int chill_level; - float chill_time; - edict_t *chill_owner; // for assist exp tracking - //4.0 "manashield" - qboolean manashield; - //4.0 - edict_t *megahealth; - edict_t *spawn; // available invasion-mode spawn point - float holywaterProtection; //holy water gives a few seconds of curse immunity - //4.1 - edict_t *totem1; - edict_t *totem2; - edict_t *mirror1; - edict_t *mirror2; - edict_t *healer; - edict_t *cocoon; - edict_t *holyground; //Talent: Holy/Unholy Ground - int mirroredPosition; - int autocurse_delay; //Talent: Autocurse - next server frame that chance trigger is rolled - float fury_time; - float slowed_factor; - float slowed_time; - float detected_time; - float empeffect_time; - edict_t *empeffect_owner; // for assist exp tracking - float cocoon_time; - float cocoon_factor; - edict_t *cocoon_owner; // for assist exp tracking - - float heal_exp_time; - edict_t *heal_exp_owner; // for assist exp tracking - - float supply_exp_time; - edict_t *supply_exp_owner; // for assist exp tracking - - int showPathDebug; // show path debug information (0=off,1=on) - - float swordtimer; //decino: time before we can reattack - - float pcr_time; // time elapsed since last power cube regen +#ifdef VRX_REPRO + +static constexpr int32_t Team_None = 0; +static constexpr int32_t Item_UnknownRespawnTime = INT_MAX; +static constexpr int32_t Item_Invalid = -1; +static constexpr int32_t Item_Null = 0; + +enum sv_ent_flags_t : uint64_t { + SVFL_NONE = 0, // no flags + SVFL_ONGROUND = 1 << 0, + SVFL_HAS_DMG_BOOST = 1 << 1, + SVFL_HAS_PROTECTION = 1 << 2, + SVFL_HAS_INVISIBILITY = 1 << 3, + SVFL_IS_JUMPING = 1 << 4, + SVFL_IS_CROUCHING = 1 << 5, + SVFL_IS_ITEM = 1 << 6, + SVFL_IS_OBJECTIVE = 1 << 7, + SVFL_HAS_TELEPORTED = 1 << 8, + SVFL_TAKES_DAMAGE = 1 << 9, + SVFL_IS_HIDDEN = 1 << 10, + SVFL_IS_NOCLIP = 1 << 11, + SVFL_IN_WATER = 1 << 12, + SVFL_NO_TARGET = 1 << 13, + SVFL_GOD_MODE = 1 << 14, + SVFL_IS_FLIPPING_OFF = 1 << 15, + SVFL_IS_SALUTING = 1 << 16, + SVFL_IS_TAUNTING = 1 << 17, + SVFL_IS_WAVING = 1 << 18, + SVFL_IS_POINTING = 1 << 19, + SVFL_ON_LADDER = 1 << 20, + SVFL_MOVESTATE_TOP = 1 << 21, + SVFL_MOVESTATE_BOTTOM = 1 << 22, + SVFL_MOVESTATE_MOVING = 1 << 23, + SVFL_IS_LOCKED_DOOR = 1 << 24, + SVFL_CAN_GESTURE = 1 << 25, + SVFL_WAS_TELEFRAGGED = 1 << 26, + SVFL_TRAP_DANGER = 1 << 27, + SVFL_ACTIVE = 1 << 28, + SVFL_IS_SPECTATOR = 1 << 29, + SVFL_IN_TEAM = 1 << 30 +}; + + +struct armorInfo_t { + int32_t item_id; + int32_t max_count; +}; + + +#define MAX_NETNAME 32 +#define MAX_ARMOR_TYPES 3 +#define MAX_ITEMS 256 + +typedef struct sv_entity_s { + bool init; + enum sv_ent_flags_t ent_flags; + enum button_t buttons; + uint32_t spawnflags; + int32_t item_id; + int32_t armor_type; + int32_t armor_value; + int32_t health; + int32_t max_health; + int32_t starting_health; + int32_t weapon; + int32_t team; + int32_t lobby_usernum; + int32_t respawntime; + int32_t viewheight; + int32_t last_attackertime; + enum water_level_t waterlevel; + vec3_t viewangles; + vec3_t viewforward; + vec3_t velocity; + vec3_t start_origin; + vec3_t end_origin; + edict_t *enemy; + edict_t *ground_entity; + const char *classname; + const char *targetname; + char netname[MAX_NETNAME]; + int32_t inventory[MAX_ITEMS]; + struct armorInfo_t armor_info[MAX_ARMOR_TYPES]; +} sv_entity_t; + +#endif + +struct edict_s { + entity_state_t s; + struct gclient_s *client; // NULL if not a player + // the server expects the first part + // of gclient_s to be a player_state_t + // but the rest of it is opaque + +#ifndef VRX_REPRO + _rebool inuse; + int linkcount; + + // FIXME: move these fields to a server private sv_entity_t + link_t area; // linked to a division node or leaf + + int num_clusters; // if -1, use headnode instead + int clusternums[MAX_ENT_CLUSTERS]; + int headnode; // unused if num_clusters != -1 + int areanum, areanum2; +#else + sv_entity_t sv; + bool inuse; + + bool linked; + int32_t linkcount; + int32_t areanum, areanum2; +#endif + //================================ + + enum svflags_t svflags; // note: SVF_MONSTER tells physics to clip on any solid object (not just walls) + vec3_t mins, maxs; + vec3_t absmin, absmax, size; + solid_t solid; + enum contents_t clipmask; + edict_t *owner; + + + // DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER + // EXPECTS THE FIELDS IN THAT ORDER! + + //================================ + int movetype; + enum flags_t flags; + int v_flags; //3.0 New flag variable (so nothing else previously coded is screwed up) + + char *model; + float freetime; // sv.time when the object was freed + + // + // only used locally in game, not by server + // + char *message; + char *classname; + int spawnflags; + + float timestamp; + + float angle; // set in qe3, -1 = up, -2 = down + char *target; + char *targetname; + char *killtarget; + char *team; + char *pathtarget; + edict_t *target_ent; + //ponko + edict_t *union_ent; //union item + edict_t *trainteam; //train team + //ponko + float speed, accel, decel; + vec3_t movedir; + vec3_t pos1, pos2; + + vec3_t velocity; + vec3_t avelocity; + int mass; + float air_finished; + float gravity; // per entity gravity multiplier (1.0 is normal) + // use for lowgrav artifact, flares + + edict_t *goalentity; + edict_t *movetarget; + float yaw_speed; + float ideal_yaw; + + float nextthink; + + void (*prethink)(edict_t *ent); + + void (*think)(edict_t *self); + + void (*blocked)(edict_t *self, edict_t *other); //move to moveinfo? + void (*touch)(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf); + + void (*use)(edict_t *self, edict_t *other, edict_t *activator); + + void (*pain)(edict_t *self, edict_t *other, float kick, int damage); + + void (*pain_inner)(edict_t *self, edict_t *other, float kick, int damage); // az: for monsters that use drone_pain + void (*die)(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point); + + void (*notify_drone_death)(edict_t *self); + + float touch_debounce_time; // are all these legit? do we need more/less of them? + float pain_debounce_time; + float damage_debounce_time; + float fly_sound_debounce_time; //move to clientinfo + float knockweapon_debounce_time; // time when knockweapon code can be run again + float last_move_time; + + long health; + long max_health; + int gib_health; + int deadflag; + + float powerarmor_time; + + char *map; // target_changelevel + + int viewheight; // height above origin where eyesight is determined + int takedamage; + int dmg; + int radius_dmg; + float dmg_radius; + int sounds; //make this a spawntemp var? + int count; + + edict_t *chain; + edict_t *prev_chain; + edict_t *memchain; + edict_t *enemy; + edict_t *oldenemy; + edict_t *activator; + edict_t *groundentity; + int groundentity_linkcount; + edict_t *teamchain; + edict_t *teammaster; + + int noise_index; + float volume; + float attenuation; + + // timing variables + float wait; + float delay; // before firing targets + float random; + + float teleport_time; + + int watertype; + int waterlevel; + + vec3_t move_origin; + vec3_t move_angles; + + // move this to clientinfo? + int light_level; + + int style; // also used as areaportal number + + gitem_t *item; // for bonus items + + // common data blocks + moveinfo_t moveinfo; + monsterinfo_t monsterinfo; + + // jabot (vrxcl/newvrx) + ai_handle_t ai; + + // RAFAEL + int orders; + + //K03 Begin + int packitems[MAX_ITEMS]; + float PlasmaDelay; + float holdtime; + qboolean slow; + qboolean superspeed; + qboolean sucking; //GHz + qboolean antigrav; + qboolean automag; // az: magmining self? + qboolean manacharging; // az: charging mana? + int lockon; + + int FrameShot; + int Slower; + skills_t myskills; + float haste_time; + int rocket_shots; + + int shots_hit; + int shots; + + float lastkill; + int nfer; + double lastdmg; + float lasthurt; // last time we took non-world damage + uint64_t lastsound; // last frame we made a sound + int32_t dmg_counter; + int flipping; // flipping data + edict_t *creator; + //sentry stuff + edict_t *sentry; + edict_t *selectedsentry; + edict_t *standowner; + float sentrydelay; + edict_t *lasersight; + float lasthbshot; + edict_t *decoy; + edict_t *flashlight; + int mtype; // Type of Monstersee M_* defines.. (M_HOVER, etc) + int atype; //3.0 used for new curses + int num_sentries; + int num_monsters; + int num_monsters_real; + int num_lasers; + int max_pipes; + int num_armor; // 3.5 keep track of armor bombs out + int num_proxy; // 3.6 keep track of proxy grenades out + int num_napalm; // 3.6 keep track of napalm grenades out + int num_spikegrenades; // number of spike greandes out + int num_autocannon; //4.1 keep track of live autocannons + int num_caltrops; //4.2 keep track of live caltrops + int num_detectors; // number of live detectors + int num_spikers; + int num_gasser; + int num_obstacle; + int num_magmine; + int num_barrels; + int num_skeletons; + int num_golems; + int num_packanimals; + int num_firewalls; + int num_spikeball; + int num_laserplatforms; //4.4 Talent: Laser Platform + int num_hammers; //4.4 Talent: Boomerang + int health_cache; // accumulated health that entity will recover + int health_cache_nextframe; + // the next server frame we will attempt to transfer from health_cache to entity's health + int armor_cache; + int armor_cache_nextframe; + qboolean spikeball_follow; + qboolean spikeball_recall; + int shield; //4.2 shielding value, 0=no shield, 1=front, 2=whole body + float shield_activate_time; // when shield will activate + int movetype_prev; // previous movetype, used by V_Push() + int movetype_frame; // server frame to restore old movetype + //K03 End + + // az begin + qboolean exploded; // az: don't explode more than once at death. lol + int list_index; // invasion queue position + // az end + + edict_t *selected[4]; // drone selection + edict_t *other; // laser effect for hw/ctf + edict_t *supplystation; + //edict_t *magmine; + //GHz START + + // trade + edict_t *trade_with; + item_t *trade_item[3]; + float msg_time; + + //3.0 rune stuff + item_t vrxitem; + + int teamnum; // teamplay, team we belong to + edict_t *skull; // hellspawn + + que_t auras[QUE_MAXSIZE]; + que_t curses[QUE_MAXSIZE]; + float corpseeater_time; + + // parasite + int parasite_frames; + edict_t *parasite_target; + + // 3.03+ spirit + edict_t *spirit; + + // 3.12 curse effects + int curse_dir; + int curse_delay; + + //4.0 "chilled effect" + int chill_level; + float chill_time; + edict_t *chill_owner; // for assist exp tracking + + //4.0 "manashield" + qboolean manashield; + + //4.0 + edict_t *megahealth; + edict_t *spawn; // available invasion-mode spawn point + float holywaterProtection; //holy water gives a few seconds of curse immunity + + //4.1 + edict_t *totem1; + edict_t *totem2; + + edict_t *mirror1; + edict_t *mirror2; + + edict_t *holyground; //Talent: Holy/Unholy Ground + int mirroredPosition; + int autocurse_delay; //Talent: Autocurse - next server frame that chance trigger is rolled + float fury_time; + + // caltrops + float slowed_factor; + float slowed_time; + + // detector + float detected_time; + + // EMP + float empeffect_time; + edict_t *empeffect_owner; // for assist exp tracking + + // cocoon + edict_t *cocoon; + float cocoon_time; + float cocoon_factor; + edict_t *cocoon_owner; // for assist exp tracking + + edict_t *healer; + float heal_exp_time; + edict_t *heal_exp_owner; // for assist exp tracking + + float supply_exp_time; + edict_t *supply_exp_owner; // for assist exp tracking + + int showPathDebug; // show path debug information (0=off,1=on) + + + // time elapsed since last power cube regen + float pcr_time; float detected_factor; // how much extra damage we take from being detected - // "connection" id, not database id. - // kept around without NO_GDS to simplify preprocessor macros - volatile int gds_connection_id; + // "connection" id, not database id. + // kept around without NO_GDS to simplify preprocessor macros + volatile int gds_connection_id; - // -1 and 0 should both be invalid. - volatile int gds_connection_load_id; + // -1 and 0 should both be invalid. + volatile int gds_connection_load_id; - float removetime; //4.07 time to auto-remove - edict_t *prev_owner; // for conversion -//GHz END - edict_t *prev_navi; - edict_t *laser; + float removetime; //4.07 time to auto-remove + edict_t *prev_owner; // for conversion + //GHz END + edict_t *prev_navi; + edict_t *laser; // for hook }; #include "combat/abilities/auras.h" @@ -2089,7 +2477,7 @@ struct edict_s extern v_maplist_t maplist_PVP; extern v_maplist_t maplist_DOM; extern v_maplist_t maplist_PVM; -extern v_maplist_t maplist_CTF; +extern v_maplist_t maplist_CTF; extern v_maplist_t maplist_FFA; extern v_maplist_t maplist_INV; extern v_maplist_t maplist_TRA; @@ -2111,30 +2499,37 @@ extern armoryRune_t ComboRunes[20]; // teamplay stuff -typedef struct -{ - char name [16]; - int team; - float time; -}joined_t; -extern joined_t players[MAX_CLIENTS]; -joined_t *GetJoinedSlot (edict_t *ent); -void ClearJoinedSlot (joined_t *slot); - -int GetRandom(int min,int max); +typedef struct { + char name[16]; + int team; + float time; +} joined_t; + +extern joined_t players[MAX_CLIENTS]; + +joined_t *GetJoinedSlot(edict_t *ent); + +void ClearJoinedSlot(joined_t *slot); + +int GetRandom(int min, int max); + void stuffcmd(edict_t *e, char *s); void think_ability_jetpack(edict_t *ent); + int OpenConfigFile(edict_t *ent); void vrx_update_all_character_maximums(edict_t *ent); void vrx_update_health_max(edict_t *ent); + void vrx_save_character(edict_t *ent, qboolean unlock); void vrx_write_to_logfile(edict_t *ent, char *s); -void WriteToLogFile (char *char_name, char *s) ; -void WriteServerMsg (char *s, char *error_string, qboolean print_msg, qboolean save_to_logfile); + +void WriteToLogFile(char *char_name, char *s); + +void WriteServerMsg(char *s, char *error_string, qboolean print_msg, qboolean save_to_logfile); void cloak(edict_t *ent); @@ -2150,33 +2545,45 @@ void vrx_init_ability_list(); void CreateDirIfNotExists(char *path); - // q2pro gmf #define GMF_VARIABLE_FPS 0x00000800 // az end qboolean StartClient(edict_t *ent); + void ChaseCam(edict_t *ent); + void JoinTheGame(edict_t *ent); + void OpenJoinMenu(edict_t *ent); + qboolean StartClient(edict_t *ent); + void OpenJoinMenu(edict_t *ent); -void Cmd_Maplist_f (edict_t *ent); -char *TeamName (edict_t *ent); + +void Cmd_Maplist_f(edict_t *ent); + +char *TeamName(edict_t *ent); // az: global defs from magic.c -qboolean ValidTeleportSpot (edict_t *ent, vec3_t spot); -void fire_spike (edict_t *self, vec3_t start, vec3_t dir, int damage, float stun_length, int speed); -void lasertrap_removeall (edict_t *ent, qboolean effect); +qboolean ValidTeleportSpot(edict_t *ent, vec3_t spot); + +void fire_spike(edict_t *self, vec3_t start, vec3_t dir, int damage, float stun_length, int speed); + +void lasertrap_removeall(edict_t *ent, qboolean effect); + void detector_removeall(edict_t *ent); void KickPlayerBack(edict_t *ent); -void P_ProjectSource (gclient_t *client, vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result); -void GetScorePosition (); + +void P_ProjectSource(gclient_t *client, vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result); + +void GetScorePosition(); void vrx_add_respawn_weapon(edict_t *ent, int weaponID); void vrx_add_respawn_items(edict_t *ent); + void vrx_pick_respawn_weapon(edict_t *ent); #define for_each_player(JOE_BLOGGS,INDEX) \ @@ -2184,36 +2591,68 @@ for(INDEX=1;INDEX<=maxclients->value;INDEX++) \ if ((JOE_BLOGGS=&g_edicts[i]) && JOE_BLOGGS->inuse && JOE_BLOGGS->client) void Teleport_them(edict_t *ent); + void Check_full(edict_t *ent); -void MonsterAim(edict_t *self, float accuracy, int projectile_speed, qboolean rocket, int flash_number, vec3_t forward, vec3_t start); + +void MonsterAim(edict_t *self, float accuracy, int projectile_speed, qboolean rocket, int flash_number, vec3_t forward, + vec3_t start); + float entdist(const edict_t *ent1, const edict_t *ent2); + void burn_person(edict_t *target, edict_t *owner, int damage); -void hook_laser_think (edict_t *self); + +void hook_laser_think(edict_t *self); + void Cmd_Salvation(edict_t *ent); + void Cmd_BoostPlayer(edict_t *ent); -void Cmd_Drone_f (edict_t *ent); -void Cmd_PlayerToParasite_f (edict_t *ent); -void Cmd_MiniSentry_f (edict_t *ent); -void Cmd_CreateSupplyStation_f (edict_t *ent); -void Cmd_Decoy_f (edict_t *ent); -qboolean M_Regenerate (edict_t *self, int regen_frames, int delay, float mult, qboolean regen_health, qboolean regen_armor, qboolean regen_ammo, int *nextframe); -qboolean M_NeedRegen (const edict_t *ent); -qboolean M_IgnoreInferiorTarget (edict_t *self, edict_t *target);//4.5 + +void Cmd_Drone_f(edict_t *ent); + +void Cmd_PlayerToParasite_f(edict_t *ent); + +void Cmd_MiniSentry_f(edict_t *ent); + +void Cmd_CreateSupplyStation_f(edict_t *ent); + +void Cmd_Decoy_f(edict_t *ent); + +qboolean M_Regenerate(edict_t *self, int regen_frames, int delay, float mult, qboolean regen_health, + qboolean regen_armor, qboolean regen_ammo, int *nextframe); + +qboolean M_NeedRegen(const edict_t *ent); + +qboolean M_IgnoreInferiorTarget(edict_t *self, edict_t *target); //4.5 edict_t *M_MeleeAttack(edict_t *self, edict_t *targ, float range, int damage, int knockback); -qboolean M_ContinueAttack(edict_t* self, mmove_t* attack_move, mmove_t* end_move, float min_dist, float max_dist, float chance); -void M_DelayNextAttack(edict_t* self, float delay, qboolean add_attack_frames); + +qboolean M_ContinueAttack(edict_t *self, mmove_t *attack_move, mmove_t *end_move, float min_dist, float max_dist, + float chance); + +void M_DelayNextAttack(edict_t *self, float delay, qboolean add_attack_frames); + qboolean M_ValidMedicTarget(const edict_t *self, const edict_t *target); -void M_Touchdown(edict_t* self); + +void M_Touchdown(edict_t *self); + qboolean M_Upkeep(edict_t *self, int delay, int upkeep_cost); -void M_FindPath (edict_t *self, vec3_t goalpos, qboolean compute_path_now); -void M_Remove (edict_t *self, qboolean refund, qboolean effect); -qboolean M_SetBoundingBox (int mtype, vec3_t boxmin, vec3_t boxmax); -qboolean M_Initialize (edict_t *ent, edict_t *monster, float dur_bonus); -void M_Notify (edict_t *monster); -void M_BodyThink (edict_t *self); -void M_PrepBodyRemoval (edict_t *self); -char *GetMonsterKindString (int mtype); -void PrintNumEntities (qboolean list); + +void M_FindPath(edict_t *self, vec3_t goalpos, qboolean compute_path_now); + +void M_Remove(edict_t *self, qboolean refund, qboolean effect); + +qboolean M_SetBoundingBox(int mtype, vec3_t boxmin, vec3_t boxmax); + +qboolean M_Initialize(edict_t *ent, edict_t *monster, float dur_bonus); + +void M_Notify(edict_t *monster); + +void M_BodyThink(edict_t *self); + +void M_PrepBodyRemoval(edict_t *self); + +char *GetMonsterKindString(int mtype); + +void PrintNumEntities(qboolean list); #define Laser_Red 0xf2f2f0f0 // bright red #define Laser_Green 0xd0d1d2d3 // bright green @@ -2232,21 +2671,31 @@ void PrintNumEntities (qboolean list); #define Laser_GreenY 0xdad0dcd2 // inner = green, outer = yellow #define Laser_YellowG 0xd0dad2dc // inner = yellow, outer = green -void Weapon_Generic (edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST, int FRAME_IDLE_LAST, int FRAME_DEACTIVATE_LAST, int *pause_frames, int *fire_frames, void (*fire)(edict_t *ent)); -void ClientUserinfoChanged (edict_t *ent, char *userinfo); -qboolean ClientConnect (edict_t *ent, char *userinfo); +void Weapon_Generic(edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST, int FRAME_IDLE_LAST, + int FRAME_DEACTIVATE_LAST, int *pause_frames, int *fire_frames, void (*fire)(edict_t *ent)); + +void ClientUserinfoChanged(edict_t *ent, char *userinfo); +#ifndef VRX_REPRO +qboolean ClientConnect(edict_t *ent, char *userinfo); +#else +bool ClientConnect(edict_t *ent, char *userinfo, const char *social_id, bool is_bot); +#endif void SpawnDamage(int type, vec3_t origin, vec3_t normal); -qboolean SelectSpawnPoint (edict_t *ent, vec3_t origin, vec3_t angles); + +qboolean SelectSpawnPoint(edict_t *ent, vec3_t origin, vec3_t angles); void think_ability_ammo_regen(edict_t *ent); void think_ability_power_regen(edict_t *ent); -void CTF_SummonableCheck (edict_t *self); + +void CTF_SummonableCheck(edict_t *self); // FLIP status: #define FLIP_SHELL 1 #define FLIP_WATER 2 -void Use_Lasers (edict_t *ent, gitem_t *item); + +void Use_Lasers(edict_t *ent, gitem_t *item); + void Cmd_LaserSight_f(edict_t *ent); //========================================== @@ -2363,28 +2812,49 @@ void Cmd_LaserSight_f(edict_t *ent); #define VectorEmpty(a) ((a[0]==0)&&(a[1]==0)&&(a[2]==0)) #define SENTRY_UPRIGHT 1 #define SENTRY_FLIPPED 2 + int V_GetRuneWeaponPts(edict_t *ent, item_t *rune); + int V_GetRuneAbilityPts(edict_t *ent, item_t *rune); qboolean vrx_commit_character(edict_t *ent, qboolean unlock); -qboolean vrx_is_newbie_basher (const edict_t *player); + +qboolean vrx_is_newbie_basher(const edict_t *player); + void vrx_trigger_spree_abilities(edict_t *attacker); -qboolean TeleportNearTarget (edict_t *self, edict_t *target, float dist, qboolean effect); -qboolean vrx_find_random_spawn_point (edict_t *ent, qboolean air); -void ValidateAngles (vec3_t angles); -int InJoinedQueue (edict_t *ent); + +qboolean TeleportNearTarget(edict_t *self, edict_t *target, float dist, qboolean effect); + +qboolean vrx_find_random_spawn_point(edict_t *ent, qboolean air); + +void ValidateAngles(vec3_t angles); + +int InJoinedQueue(edict_t *ent); + qboolean IsABoss(const edict_t *ent); -qboolean IsBossTeam (const edict_t *ent); -void AddBossExp (edict_t *attacker, edict_t *target); -void vrx_award_boss_kill (edict_t *boss); -void CreateRandomPlayerBoss (qboolean find_new_candidate); -qboolean BossExists (void); -int numNearbyEntities (edict_t *ent, float dist, qboolean vis); -void RemoveLasers (edict_t *ent); -int vrx_apply_experience (edict_t *player, int exp); -void vrx_award_all_attackers(edict_t* targ, edict_t* targetclient, edict_t* player, int bonus_xp); -int vrx_award_exp(edict_t* attacker, edict_t* targ, edict_t* targetclient, int bonus_xp); + +qboolean IsBossTeam(const edict_t *ent); + +void AddBossExp(edict_t *attacker, edict_t *target); + +void vrx_award_boss_kill(edict_t *boss); + +void CreateRandomPlayerBoss(qboolean find_new_candidate); + +qboolean BossExists(void); + +int numNearbyEntities(edict_t *ent, float dist, qboolean vis); + +void RemoveLasers(edict_t *ent); + +int vrx_apply_experience(edict_t *player, int exp); + +void vrx_award_all_attackers(edict_t *targ, edict_t *targetclient, edict_t *player, int bonus_xp); + +int vrx_award_exp(edict_t *attacker, edict_t *targ, edict_t *targetclient, int bonus_xp); + float vrx_increase_monster_damage_by_talent(edict_t *owner, float damage); + //K03 End #define NEARBY_ENTITIES_MAX 100 // max # of ents before we start trying to limit them @@ -2404,46 +2874,54 @@ do { \ // missing definitions void vrx_open_mode_menu(edict_t *ent); + qboolean vrx_print_login_status(edict_t *ent, int returned); -qboolean ToggleSecondary (edict_t *ent, gitem_t *item, qboolean printmsg); -void plat_go_up (edict_t *ent); + +qboolean ToggleSecondary(edict_t *ent, gitem_t *item, qboolean printmsg); + +void plat_go_up(edict_t *ent); + void weapon_grenade_fire(edict_t *ent, qboolean held); // az begin // New AutoStuff -void V_AutoStuff(edict_t* ent); +void V_AutoStuff(edict_t *ent); // new command system #include "server/v_cmd.h" qboolean V_VoteInProgress(); -/* active drones linked list */ +/* active drones linked list */ edict_t *DroneList_Iterate(); + edict_t *DroneList_Next(edict_t *ent); -void DroneList_Insert(edict_t* new_ent); + +void DroneList_Insert(edict_t *new_ent); + void DroneList_Remove(edict_t *ent); // 3.4 new team vs invasion mode -edict_t* TBI_FindSpawn(edict_t *ent); +edict_t *TBI_FindSpawn(edict_t *ent); + void InitTBI(); #include "server/v_luasettings.h" /* g_configstring_override.c */ -typedef void (*gi_sound_func_t) (const edict_t *ent, int channel, int soundindex, float volume, float attenuation, float timeofs); +typedef void (*gi_sound_func_t)(const edict_t *ent, int channel, int soundindex, float volume, float attenuation, + float timeofs); + void cs_override_init(); + void cs_reset(); /* v_newbie_tips.c */ void vrx_print_newbie_tip(edict_t *ent); -//az end +void pm_set_viewheight(pmove_t *pm, int viewheight); -#ifndef min -#define min(a,b) ((a) > (b) ? (b) : (a)) -#endif -#ifndef max -#define max(a,b) ((a) > (b) ? (a) : (b)) -#endif \ No newline at end of file +int pm_get_viewheight(pmove_t *pm); + +//az end diff --git a/src/gamemodes/ctf.c b/src/gamemodes/ctf.c index a00dc532..9e17c74d 100644 --- a/src/gamemodes/ctf.c +++ b/src/gamemodes/ctf.c @@ -753,9 +753,9 @@ int CTF_NumPlayerSpawns (int type, int teamnum) void CTF_PlayerRespawnTime (edict_t *ent) { - int team_spawns = CTF_NumPlayerSpawns(0, ent->teamnum) + 1; - int total_spawns = CTF_NumPlayerSpawns(0, 0) + 1; - float ratio = team_spawns / total_spawns; + const int team_spawns = CTF_NumPlayerSpawns(0, ent->teamnum) + 1; + const int total_spawns = CTF_NumPlayerSpawns(0, 0) + 1; + const float ratio = team_spawns / total_spawns; float time = CTF_PLAYERSPAWN_TIME; // don't apply ratio unless all spawns have been captured @@ -796,8 +796,8 @@ edict_t *CTF_NearestPlayerSpawn (edict_t *ent, int teamnum, float range, qboolea void ctf_playerspawn_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) { - int points = CTF_PLAYERSPAWN_CAPTURE_EXPERIENCE; - int credits = CTF_PLAYERSPAWN_CAPTURE_CREDITS; + const int points = CTF_PLAYERSPAWN_CAPTURE_EXPERIENCE; + const int credits = CTF_PLAYERSPAWN_CAPTURE_CREDITS; edict_t *cl; if (attacker && attacker->inuse && ((cl = G_GetClient(attacker)) != NULL)) @@ -1333,7 +1333,7 @@ qboolean CTF_GetFlagPosition (int teamnum, vec3_t pos) const vec3_t up = { 0, 0, 24 }; VectorAdd(pos, down, down); - trace_t tr = gi.trace(pos, vec3_origin, vec3_origin, down, NULL, MASK_SOLID); + const trace_t tr = gi.trace(pos, vec3_origin, vec3_origin, down, NULL, MASK_SOLID); VectorCopy(tr.endpos, pos); VectorAdd(up, pos, pos); @@ -1821,7 +1821,7 @@ qboolean CTF_CorrectSpawnPosition(edict_t* self) const vec3_t down = { 0, 0, -8192 }; vec3_t end; VectorAdd(self->s.origin, down, end); - trace_t tr = gi.trace(self->s.origin, mins, maxs, end, self, MASK_PLAYERSOLID); + const trace_t tr = gi.trace(self->s.origin, mins, maxs, end, self, MASK_PLAYERSOLID); if (tr.ent == g_edicts) { @@ -1854,7 +1854,7 @@ void SP_info_player_team1(edict_t* self) return; } - qboolean success = CTF_CorrectSpawnPosition(self); + const qboolean success = CTF_CorrectSpawnPosition(self); if (ctf->value && debuginfo->value > 0 && success) { @@ -1873,8 +1873,8 @@ void SP_info_player_team2(edict_t* self) G_FreeEdict(self); return; } - - qboolean success = CTF_CorrectSpawnPosition(self); + + const qboolean success = CTF_CorrectSpawnPosition(self); if (ctf->value && debuginfo->value > 0 && success) { diff --git a/src/gamemodes/invasion.c b/src/gamemodes/invasion.c index 61d8d5ce..6cf66046 100644 --- a/src/gamemodes/invasion.c +++ b/src/gamemodes/invasion.c @@ -153,7 +153,7 @@ edict_t *vrx_inv_give_random_p_spawn() if (invasion_spawncount > 1) { // pick a random active spawn - int rand = GetRandom(1, invasion_spawncount) - 1; + const int rand = GetRandom(1, invasion_spawncount) - 1; return INV_PlayerSpawns[rand]; } else if (invasion_spawncount == 1) @@ -209,7 +209,7 @@ edict_t* vrx_inv_closest_navi_any(edict_t* self) { void DrawNavi(edict_t* ent) { float dist, flrht; - edict_t* navi=NULL; + const edict_t* navi=NULL; vec3_t start, end; trace_t tr; @@ -423,7 +423,7 @@ void vrx_inv_award_players(void) if (!G_IsSpectator(player)) { - int fexp = vrx_apply_experience(player, points); + const int fexp = vrx_apply_experience(player, points); player->myskills.credits += credits; safe_cprintf(player, PRINT_MEDIUM, "Earned %d exp and %d credits!\n", fexp, credits); @@ -440,7 +440,7 @@ edict_t* vrx_inv_spawn_drone(edict_t* self, edict_t *spawn_point, int index) { edict_t *monster = vrx_create_new_drone(self, index, true, false, invasion_bonus_levels); vec3_t start; - float mhealth = 1; + const float mhealth = 1; if (!monster) { @@ -452,7 +452,7 @@ edict_t* vrx_inv_spawn_drone(edict_t* self, edict_t *spawn_point, int index) VectorCopy(spawn_point->s.origin, start); start[2] = spawn_point->absmax[2] + 1 + fabsf(monster->mins[2]); - trace_t tr = gi.trace(start, monster->mins, monster->maxs, start, NULL, MASK_SHOT); + const trace_t tr = gi.trace(start, monster->mins, monster->maxs, start, NULL, MASK_SHOT); // starting point is occupied if (tr.fraction < 1) @@ -540,9 +540,9 @@ edict_t* vrx_inv_spawn_drone(edict_t* self, edict_t *spawn_point, int index) float vrx_inv_time_formula() { - int base = 4 * 60; - int playeramt = vrx_get_alive_players() * 8; - int levelamt = next_invasion_wave_level * 7; + const int base = 4 * 60; + const int playeramt = vrx_get_alive_players() * 8; + const int levelamt = next_invasion_wave_level * 7; int cap = 60; int rval = base - playeramt - levelamt; @@ -579,9 +579,9 @@ void vrx_inv_spawn_boss(edict_t* self, int index) if (index < 30) return; - while (spawn = vrx_inv_get_monster_spawn(spawn)) + while ((spawn = vrx_inv_get_monster_spawn(spawn))) { - if (!(invasion_data.boss = vrx_inv_spawn_drone(self, spawn, index))) + if (!((invasion_data.boss = vrx_inv_spawn_drone(self, spawn, index)))) continue; else { @@ -851,7 +851,7 @@ void vrx_inv_on_begin_wave(edict_t *self) { vrx_inv_show_last_wave_summary(); } - int next_max_monsters = vrx_inv_get_max_monsters(invasion_data.wave); + const int next_max_monsters = vrx_inv_get_max_monsters(invasion_data.wave); gi.bprintf(PRINT_HIGH, "Welcome to level %d. %d monsters incoming!\n", invasion_data.wave, next_max_monsters); G_PrintGreenText(va("Timelimit: %02d:%02d.\n", (int)vrx_inv_time_formula() / 60, (int)vrx_inv_time_formula() % 60)); @@ -986,10 +986,10 @@ void vrx_inv_spawn_monsters(edict_t *self) // were enough monsters eliminated? - qboolean boss_wave = vrx_inv_is_boss_wave(invasion_data.wave); - qboolean boss_eliminated = boss_wave && !invasion_data.boss; - qboolean forces_eliminated = !boss_wave && (invasion_data.wave_remaining <= 0); - qboolean force_next_wave = + const qboolean boss_wave = vrx_inv_is_boss_wave(invasion_data.wave); + const qboolean boss_eliminated = boss_wave && !invasion_data.boss; + const qboolean forces_eliminated = !boss_wave && (invasion_data.wave_remaining <= 0); + const qboolean force_next_wave = boss_eliminated || forces_eliminated; if (force_next_wave && invasion_data.started) { // start spawning diff --git a/src/gamemodes/pvb.c b/src/gamemodes/pvb.c index df7527fb..4835d1b4 100644 --- a/src/gamemodes/pvb.c +++ b/src/gamemodes/pvb.c @@ -219,7 +219,7 @@ void vrx_award_boss_kill (edict_t *boss) int i, damage, exp_points, credits, players; float levelmod, dmgmod; edict_t *player; - dmglist_t *slot=NULL; + const dmglist_t *slot=NULL; // find the player that did the most damage slot = findHighestDmgPlayer(boss); diff --git a/src/gamemodes/teamplay.c b/src/gamemodes/teamplay.c index 6600b7f0..92c3c213 100644 --- a/src/gamemodes/teamplay.c +++ b/src/gamemodes/teamplay.c @@ -18,7 +18,7 @@ joined_t players[MAX_CLIENTS]; void AssignTeamSkin (edict_t *ent, char *s) { - int playernum = ent-g_edicts-1; + const int playernum = ent-g_edicts-1; char *p; char t[64]; diff --git a/src/gamemodes/v_hw.c b/src/gamemodes/v_hw.c index 4f832dfe..b9ee76c9 100644 --- a/src/gamemodes/v_hw.c +++ b/src/gamemodes/v_hw.c @@ -286,7 +286,7 @@ void hw_touch_flag(edict_t* ent, edict_t* other, cplane_t* plane, csurface_t* su void hw_find_spawn_point(edict_t* flag) { vec3_t dir = { 0, 0, 0 }; - float speed = 600; + const float speed = 600; edict_t* it = NULL; edict_t* candidates[32]; int cnt = 0; @@ -329,7 +329,7 @@ void hw_find_spawn_point(edict_t* flag) void hw_die(edict_t* self, edict_t* inflictor, edict_t* attacker, int damage, vec3_t point) { vec3_t start, end, dir; - float knockback = 600; + const float knockback = 600; G_EntMidPoint(self, start); @@ -364,7 +364,7 @@ void hw_toss(edict_t* flag, float speed) void hw_pain(edict_t* self, edict_t* other, float kick, int damage) { vec3_t start, end, dir; - float knockback_dmg = 500; + const float knockback_dmg = 500; edict_t* cl = G_GetClient(other); if (!cl) @@ -388,7 +388,7 @@ void hw_pain(edict_t* self, edict_t* other, float kick, int damage) void hw_dropflag (edict_t *ent, gitem_t *item) { edict_t *flag; - float speed = 600; + const float speed = 600; //if (!G_EntExists(ent)) // return; diff --git a/src/gamemodes/v_tbi.c b/src/gamemodes/v_tbi.c index 98029f98..cb9675a8 100644 --- a/src/gamemodes/v_tbi.c +++ b/src/gamemodes/v_tbi.c @@ -66,7 +66,7 @@ qboolean TBI_CheckRules(edict_t* self) void TBI_SpawnPlayers() { int CurrentRedSpawn, CurrentBlueSpawn; - int i_maxclients = maxclients->value; + const int i_maxclients = maxclients->value; edict_t *cl_ent; CurrentRedSpawn = CurrentBlueSpawn = 0; @@ -211,14 +211,14 @@ void TBI_CheckSpawns() for (i = 0; i < tbi_game.TotalRedSpawns; i++) { - edict_t *e = tbi_game.EntRedSpawns[i]; + const edict_t *e = tbi_game.EntRedSpawns[i]; if (e->deadflag != DEAD_DEAD) tbi_game.RedSpawns++; } for (i = 0; i < tbi_game.TotalBlueSpawns; i++) { - edict_t *e = tbi_game.EntBlueSpawns[i]; + const edict_t *e = tbi_game.EntBlueSpawns[i]; if (e->deadflag != DEAD_DEAD) tbi_game.BlueSpawns++; } @@ -227,7 +227,7 @@ void TBI_CheckSpawns() int TBI_CountTeamPlayers(int team) { edict_t *cl_ent; - int i_maxclients = maxclients->value; + const int i_maxclients = maxclients->value; int total = 0; for (cl_ent = g_edicts + 1; cl_ent != g_edicts + i_maxclients + 1; cl_ent++) @@ -241,7 +241,7 @@ int TBI_CountTeamPlayers(int team) int TBI_CountActivePlayers() { edict_t *cl_ent; - int i_maxclients = maxclients->value; + const int i_maxclients = maxclients->value; int total = 0; for (cl_ent = g_edicts + 1; cl_ent != g_edicts + i_maxclients + 1; cl_ent++) @@ -256,7 +256,7 @@ int TBI_CountActivePlayers() void TBI_AwardTeam(int Teamnum, int exp, qboolean Broadcast) { edict_t *cl_ent; - int i_maxclients = maxclients->value; + const int i_maxclients = maxclients->value; if (TBI_CountActivePlayers() < 4) // we can't give experience if there's not enough active players return; diff --git a/src/libraries/hash_32a.c b/src/libraries/hash_32a.c index 725f6046..bf6aac88 100644 --- a/src/libraries/hash_32a.c +++ b/src/libraries/hash_32a.c @@ -82,7 +82,7 @@ Fnv32_t fnv_32a_buf(void *buf, size_t len, Fnv32_t hval) { unsigned char *bp = (unsigned char *)buf; /* start of buffer */ - unsigned char *be = bp + len; /* beyond end of buffer */ + const unsigned char *be = bp + len; /* beyond end of buffer */ /* * FNV-1a hash each octet in the buffer @@ -121,7 +121,7 @@ fnv_32a_buf(void *buf, size_t len, Fnv32_t hval) Fnv32_t fnv_32a_str(const char *str, Fnv32_t hval) { - unsigned char *s = (unsigned char *)str; /* unsigned string */ + const unsigned char *s = (unsigned char *)str; /* unsigned string */ /* * FNV-1a hash each octet in the buffer diff --git a/src/libraries/lua.c b/src/libraries/lua.c index 5a85422d..3c6f7b40 100644 --- a/src/libraries/lua.c +++ b/src/libraries/lua.c @@ -3766,7 +3766,7 @@ const char lua_ident[] = static TValue *index2addr (lua_State *L, int idx) { - CallInfo *ci = L->ci; + const CallInfo *ci = L->ci; if (idx > 0) { TValue *o = ci->func + idx; api_check(L, idx <= ci->top - (ci->func + 1), "unacceptable index"); @@ -3797,7 +3797,7 @@ static TValue *index2addr (lua_State *L, int idx) { ** capturing memory errors */ static void growstack (lua_State *L, void *ud) { - int size = *(int *)ud; + const int size = *(int *)ud; luaD_growstack(L, size); } @@ -3809,7 +3809,7 @@ LUA_API int lua_checkstack (lua_State *L, int size) { if (L->stack_last - L->top > size) /* stack large enough? */ res = 1; /* yes; check is OK */ else { /* no; need to grow stack */ - int inuse = cast_int(L->top - L->stack) + EXTRA_STACK; + const int inuse = cast_int(L->top - L->stack) + EXTRA_STACK; if (inuse > LUAI_MAXSTACK - size) /* can grow without overflow? */ res = 0; /* no */ else /* try to grow stack */ @@ -3876,7 +3876,7 @@ LUA_API int lua_gettop (lua_State *L) { LUA_API void lua_settop (lua_State *L, int idx) { - StkId func = L->ci->func; + const StkId func = L->ci->func; lua_lock(L); if (idx >= 0) { api_check(L, idx <= L->stack_last - (func + 1), "new top too large"); @@ -3960,7 +3960,7 @@ LUA_API void lua_pushvalue (lua_State *L, int idx) { LUA_API int lua_type (lua_State *L, int idx) { - StkId o = index2addr(L, idx); + const StkId o = index2addr(L, idx); return (isvalid(o) ? ttypenv(o) : LUA_TNONE); } @@ -3972,7 +3972,7 @@ LUA_API const char *lua_typename (lua_State *L, int t) { LUA_API int lua_iscfunction (lua_State *L, int idx) { - StkId o = index2addr(L, idx); + const StkId o = index2addr(L, idx); return (ttislcf(o) || (ttisCclosure(o))); } @@ -3985,7 +3985,7 @@ LUA_API int lua_isnumber (lua_State *L, int idx) { LUA_API int lua_isstring (lua_State *L, int idx) { - int t = lua_type(L, idx); + const int t = lua_type(L, idx); return (t == LUA_TSTRING || t == LUA_TNUMBER); } @@ -3997,8 +3997,8 @@ LUA_API int lua_isuserdata (lua_State *L, int idx) { LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { - StkId o1 = index2addr(L, index1); - StkId o2 = index2addr(L, index2); + const StkId o1 = index2addr(L, index1); + const StkId o2 = index2addr(L, index2); return (isvalid(o1) && isvalid(o2)) ? luaV_rawequalobj(o1, o2) : 0; } @@ -4064,7 +4064,7 @@ LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *isnum) { const TValue *o = index2addr(L, idx); if (tonumber(o, &n)) { lua_Integer res; - lua_Number num = nvalue(o); + const lua_Number num = nvalue(o); lua_number2integer(res, num); if (isnum) *isnum = 1; return res; @@ -4081,7 +4081,7 @@ LUA_API lua_Unsigned lua_tounsignedx (lua_State *L, int idx, int *isnum) { const TValue *o = index2addr(L, idx); if (tonumber(o, &n)) { lua_Unsigned res; - lua_Number num = nvalue(o); + const lua_Number num = nvalue(o); lua_number2unsigned(res, num); if (isnum) *isnum = 1; return res; @@ -4118,7 +4118,7 @@ LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { LUA_API size_t lua_rawlen (lua_State *L, int idx) { - StkId o = index2addr(L, idx); + const StkId o = index2addr(L, idx); switch (ttypenv(o)) { case LUA_TSTRING: return tsvalue(o)->len; case LUA_TUSERDATA: return uvalue(o)->len; @@ -4129,7 +4129,7 @@ LUA_API size_t lua_rawlen (lua_State *L, int idx) { LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { - StkId o = index2addr(L, idx); + const StkId o = index2addr(L, idx); if (ttislcf(o)) return fvalue(o); else if (ttisCclosure(o)) return clCvalue(o)->f; @@ -4138,7 +4138,7 @@ LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { LUA_API void *lua_touserdata (lua_State *L, int idx) { - StkId o = index2addr(L, idx); + const StkId o = index2addr(L, idx); switch (ttypenv(o)) { case LUA_TUSERDATA: return (rawuvalue(o) + 1); case LUA_TLIGHTUSERDATA: return pvalue(o); @@ -4148,13 +4148,13 @@ LUA_API void *lua_touserdata (lua_State *L, int idx) { LUA_API lua_State *lua_tothread (lua_State *L, int idx) { - StkId o = index2addr(L, idx); + const StkId o = index2addr(L, idx); return (!ttisthread(o)) ? NULL : thvalue(o); } LUA_API const void *lua_topointer (lua_State *L, int idx) { - StkId o = index2addr(L, idx); + const StkId o = index2addr(L, idx); switch (ttype(o)) { case LUA_TTABLE: return hvalue(o); case LUA_TLCL: return clLvalue(o); @@ -4638,7 +4638,7 @@ struct CallS { /* data to `f_call' */ static void f_call (lua_State *L, void *ud) { - struct CallS *c = cast(struct CallS *, ud); + const struct CallS *c = cast(struct CallS *, ud); luaD_call(L, c->func, c->nresults, 0); } @@ -4658,7 +4658,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc, if (errfunc == 0) func = 0; else { - StkId o = index2addr(L, errfunc); + const StkId o = index2addr(L, errfunc); api_checkvalidindex(L, o); func = savestack(L, o); } @@ -4698,7 +4698,7 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, luaZ_init(L, &z, reader, data); status = luaD_protectedparser(L, &z, chunkname, mode); if (status == LUA_OK) { /* no errors? */ - LClosure *f = clLvalue(L->top - 1); /* get newly created function */ + const LClosure *f = clLvalue(L->top - 1); /* get newly created function */ if (f->nupvalues == 1) { /* does it have one upvalue? */ /* get global table from registry */ Table *reg = hvalue(&G(L)->l_registry); @@ -4915,9 +4915,9 @@ static const char *aux_upvalue (StkId fi, int n, TValue **val, return ""; } case LUA_TLCL: { /* Lua closure */ - LClosure *f = clLvalue(fi); + const LClosure *f = clLvalue(fi); TString *name; - Proto *p = f->p; + const Proto *p = f->p; if (!(1 <= n && n <= p->sizeupvalues)) return NULL; *val = f->upvals[n-1]->v; if (owner) *owner = obj2gco(f->upvals[n - 1]); @@ -4964,7 +4964,7 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) { LClosure *f; - StkId fi = index2addr(L, fidx); + const StkId fi = index2addr(L, fidx); api_check(L, ttisLclosure(fi), "Lua function expected"); f = clLvalue(fi); api_check(L, (1 <= n && n <= f->p->sizeupvalues), "invalid upvalue index"); @@ -4974,7 +4974,7 @@ static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) { LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) { - StkId fi = index2addr(L, fidx); + const StkId fi = index2addr(L, fidx); switch (ttype(fi)) { case LUA_TLCL: { /* lua closure */ return *getupvalref(L, fidx, n, NULL); @@ -5043,8 +5043,8 @@ void luaK_nil (FuncState *fs, int from, int n) { if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ previous = &fs->f->code[fs->pc-1]; if (GET_OPCODE(*previous) == OP_LOADNIL) { - int pfrom = GETARG_A(*previous); - int pl = pfrom + GETARG_B(*previous); + const int pfrom = GETARG_A(*previous); + const int pl = pfrom + GETARG_B(*previous); if ((pfrom <= from && from <= pl + 1) || (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */ if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */ @@ -5060,7 +5060,7 @@ void luaK_nil (FuncState *fs, int from, int n) { int luaK_jump (FuncState *fs) { - int jpc = fs->jpc; /* save list of jumps to here */ + const int jpc = fs->jpc; /* save list of jumps to here */ int j; fs->jpc = NO_JUMP; j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); @@ -5082,7 +5082,7 @@ static int condjump (FuncState *fs, OpCode op, int A, int B, int C) { static void fixjump (FuncState *fs, int pc, int dest) { Instruction *jmp = &fs->f->code[pc]; - int offset = dest-(pc+1); + const int offset = dest-(pc+1); lua_assert(dest != NO_JUMP); if (abs(offset) > MAXARG_sBx) luaX_syntaxerror(fs->ls, "control structure too long"); @@ -5101,7 +5101,7 @@ int luaK_getlabel (FuncState *fs) { static int getjump (FuncState *fs, int pc) { - int offset = GETARG_sBx(fs->f->code[pc]); + const int offset = GETARG_sBx(fs->f->code[pc]); if (offset == NO_JUMP) /* point to itself represents end of list */ return NO_JUMP; /* end of list */ else @@ -5124,7 +5124,7 @@ static Instruction *getjumpcontrol (FuncState *fs, int pc) { */ static int need_value (FuncState *fs, int list) { for (; list != NO_JUMP; list = getjump(fs, list)) { - Instruction i = *getjumpcontrol(fs, list); + const Instruction i = *getjumpcontrol(fs, list); if (GET_OPCODE(i) != OP_TESTSET) return 1; } return 0; /* not found */ @@ -5153,7 +5153,7 @@ static void removevalues (FuncState *fs, int list) { static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, int dtarget) { while (list != NO_JUMP) { - int next = getjump(fs, list); + const int next = getjump(fs, list); if (patchtestreg(fs, list, reg)) fixjump(fs, list, vtarget); else @@ -5182,7 +5182,7 @@ void luaK_patchlist (FuncState *fs, int list, int target) { LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level) { level++; /* argument is +1 to reserve 0 as non-op */ while (list != NO_JUMP) { - int next = getjump(fs, list); + const int next = getjump(fs, list); lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP && (GETARG_A(fs->f->code[list]) == 0 || GETARG_A(fs->f->code[list]) >= level)); @@ -5254,7 +5254,7 @@ int luaK_codek (FuncState *fs, int reg, int k) { if (k <= MAXARG_Bx) return luaK_codeABx(fs, OP_LOADK, reg, k); else { - int p = luaK_codeABx(fs, OP_LOADKX, reg, 0); + const int p = luaK_codeABx(fs, OP_LOADKX, reg, 0); codeextraarg(fs, k); return p; } @@ -5262,7 +5262,7 @@ int luaK_codek (FuncState *fs, int reg, int k) { void luaK_checkstack (FuncState *fs, int n) { - int newstack = fs->freereg + n; + const int newstack = fs->freereg + n; if (newstack > fs->f->maxstacksize) { if (newstack >= MAXSTACK) luaX_syntaxerror(fs->ls, "function or expression too complex"); @@ -5297,7 +5297,7 @@ static int addk (FuncState *fs, TValue *key, TValue *v) { Proto *f = fs->f; int k, oldsize; if (ttisnumber(idx)) { - lua_Number n = nvalue(idx); + const lua_Number n = nvalue(idx); lua_number2int(k, n); if (luaV_rawequalobj(&f->k[k], v)) return k; @@ -5478,7 +5478,7 @@ static void exp2reg (FuncState *fs, expdesc *e, int reg) { int p_f = NO_JUMP; /* position of an eventual LOAD false */ int p_t = NO_JUMP; /* position of an eventual LOAD true */ if (need_value(fs, e->t) || need_value(fs, e->f)) { - int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); + const int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); p_f = code_label(fs, reg, 0, 1); p_t = code_label(fs, reg, 1, 0); luaK_patchtohere(fs, fj); @@ -5567,13 +5567,13 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { return; } case VUPVAL: { - int e = luaK_exp2anyreg(fs, ex); + const int e = luaK_exp2anyreg(fs, ex); luaK_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0); break; } case VINDEXED: { - OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE : OP_SETTABUP; - int e = luaK_exp2RK(fs, ex); + const OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE : OP_SETTABUP; + const int e = luaK_exp2RK(fs, ex); luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e); break; } @@ -5609,7 +5609,7 @@ static void invertjump (FuncState *fs, expdesc *e) { static int jumponcond (FuncState *fs, expdesc *e, int cond) { if (e->k == VRELOCABLE) { - Instruction ie = getcode(fs, e); + const Instruction ie = getcode(fs, e); if (GET_OPCODE(ie) == OP_NOT) { fs->pc--; /* remove previous OP_NOT */ return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); @@ -5698,7 +5698,8 @@ static void codenot (FuncState *fs, expdesc *e) { } } /* interchange true and false lists */ - { int temp = e->f; e->f = e->t; e->t = temp; } + { + const int temp = e->f; e->f = e->t; e->t = temp; } removevalues(fs, e->f); removevalues(fs, e->t); } @@ -5730,8 +5731,8 @@ static void codearith (FuncState *fs, OpCode op, if (constfolding(op, e1, e2)) return; else { - int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0; - int o1 = luaK_exp2RK(fs, e1); + const int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0; + const int o1 = luaK_exp2RK(fs, e1); if (o1 > o2) { freeexp(fs, e1); freeexp(fs, e2); @@ -5869,8 +5870,8 @@ void luaK_fixline (FuncState *fs, int line) { void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { - int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1; - int b = (tostore == LUA_MULTRET) ? 0 : tostore; + const int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1; + const int b = (tostore == LUA_MULTRET) ? 0 : tostore; lua_assert(tostore != 0); if (c <= MAXARG_C) luaK_codeABC(fs, OP_SETLIST, base, b, c); @@ -5983,14 +5984,14 @@ LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { static const char *upvalname (Proto *p, int uv) { - TString *s = check_exp(uv < p->sizeupvalues, p->upvalues[uv].name); + const TString *s = check_exp(uv < p->sizeupvalues, p->upvalues[uv].name); if (s == NULL) return "?"; else return getstr(s); } static const char *findvararg (CallInfo *ci, int n, StkId *pos) { - int nparams = clLvalue(ci->func)->p->numparams; + const int nparams = clLvalue(ci->func)->p->numparams; if (n >= ci->u.l.base - ci->func - nparams) return NULL; /* no such vararg */ else { @@ -6015,7 +6016,7 @@ static const char *findlocal (lua_State *L, CallInfo *ci, int n, else base = ci->func + 1; if (name == NULL) { /* no 'standard' name? */ - StkId limit = (ci == L->ci) ? L->top : ci->next->func; + const StkId limit = (ci == L->ci) ? L->top : ci->next->func; if (limit - base >= n && n > 0) /* is 'n' inside 'ci' stack? */ name = "(*temporary)"; /* generic name for any valid slot */ else @@ -6068,7 +6069,7 @@ static void funcinfo (lua_Debug *ar, Closure *cl) { ar->what = "C"; } else { - Proto *p = cl->l.p; + const Proto *p = cl->l.p; ar->source = p->source ? getstr(p->source) : "=?"; ar->linedefined = p->linedefined; ar->lastlinedefined = p->lastlinedefined; @@ -6086,7 +6087,7 @@ static void collectvalidlines (lua_State *L, Closure *f) { else { int i; TValue v; - int *lineinfo = f->l.p->lineinfo; + const int *lineinfo = f->l.p->lineinfo; Table *t = luaH_new(L); /* new table to store active lines */ sethvalue(L, L->top, t); /* push it on stack */ incr_top(L); @@ -6194,7 +6195,7 @@ static const char *getobjname (Proto *p, int lastpc, int reg, */ static void kname (Proto *p, int pc, int c, const char **name) { if (ISK(c)) { /* is 'c' a constant? */ - TValue *kvalue = &p->k[INDEXK(c)]; + const TValue *kvalue = &p->k[INDEXK(c)]; if (ttisstring(kvalue)) { /* literal constant? */ *name = svalue(kvalue); /* it is its own name */ return; @@ -6219,12 +6220,12 @@ static int findsetreg (Proto *p, int lastpc, int reg) { int pc; int setreg = -1; /* keep last instruction that changed 'reg' */ for (pc = 0; pc < lastpc; pc++) { - Instruction i = p->code[pc]; - OpCode op = GET_OPCODE(i); - int a = GETARG_A(i); + const Instruction i = p->code[pc]; + const OpCode op = GET_OPCODE(i); + const int a = GETARG_A(i); switch (op) { case OP_LOADNIL: { - int b = GETARG_B(i); + const int b = GETARG_B(i); if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */ setreg = pc; break; @@ -6239,8 +6240,8 @@ static int findsetreg (Proto *p, int lastpc, int reg) { break; } case OP_JMP: { - int b = GETARG_sBx(i); - int dest = pc + 1 + b; + const int b = GETARG_sBx(i); + const int dest = pc + 1 + b; /* jump is forward and do not skip `lastpc'? */ if (pc < dest && dest <= lastpc) pc += b; /* do the jump */ @@ -6269,19 +6270,19 @@ static const char *getobjname (Proto *p, int lastpc, int reg, /* else try symbolic execution */ pc = findsetreg(p, lastpc, reg); if (pc != -1) { /* could find instruction? */ - Instruction i = p->code[pc]; - OpCode op = GET_OPCODE(i); + const Instruction i = p->code[pc]; + const OpCode op = GET_OPCODE(i); switch (op) { case OP_MOVE: { - int b = GETARG_B(i); /* move from 'b' to 'a' */ + const int b = GETARG_B(i); /* move from 'b' to 'a' */ if (b < GETARG_A(i)) return getobjname(p, pc, b, name); /* get name for 'b' */ break; } case OP_GETTABUP: case OP_GETTABLE: { - int k = GETARG_C(i); /* key index */ - int t = GETARG_B(i); /* table index */ + const int k = GETARG_C(i); /* key index */ + const int t = GETARG_B(i); /* table index */ const char *vn = (op == OP_GETTABLE) /* name of indexed variable */ ? luaF_getlocalname(p, t + 1, pc) : upvalname(p, t); @@ -6294,7 +6295,7 @@ static const char *getobjname (Proto *p, int lastpc, int reg, } case OP_LOADK: case OP_LOADKX: { - int b = (op == OP_LOADK) ? GETARG_Bx(i) + const int b = (op == OP_LOADK) ? GETARG_Bx(i) : GETARG_Ax(p->code[pc + 1]); if (ttisstring(&p->k[b])) { *name = svalue(&p->k[b]); @@ -6303,7 +6304,7 @@ static const char *getobjname (Proto *p, int lastpc, int reg, break; } case OP_SELF: { - int k = GETARG_C(i); /* key index */ + const int k = GETARG_C(i); /* key index */ kname(p, pc, k, name); return "method"; } @@ -6317,8 +6318,8 @@ static const char *getobjname (Proto *p, int lastpc, int reg, static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { TMS tm; Proto *p = ci_func(ci)->p; /* calling function */ - int pc = currentpc(ci); /* calling instruction index */ - Instruction i = p->code[pc]; /* calling instruction */ + const int pc = currentpc(ci); /* calling instruction index */ + const Instruction i = p->code[pc]; /* calling instruction */ switch (GET_OPCODE(i)) { case OP_CALL: case OP_TAILCALL: /* get function name */ @@ -6370,7 +6371,7 @@ static int isinstack (CallInfo *ci, const TValue *o) { static const char *getupvalname (CallInfo *ci, const TValue *o, const char **name) { - LClosure *c = ci_func(ci); + const LClosure *c = ci_func(ci); int i; for (i = 0; i < c->nupvalues; i++) { if (c->upvals[i]->v == o) { @@ -6430,8 +6431,8 @@ static void addinfo (lua_State *L, const char *msg) { CallInfo *ci = L->ci; if (isLua(ci)) { /* is Lua code? */ char buff[LUA_IDSIZE]; /* add file:line information */ - int line = currentline(ci); - TString *src = ci_func(ci)->p->source; + const int line = currentline(ci); + const TString *src = ci_func(ci)->p->source; if (src) luaO_chunkid(buff, getstr(src), LUA_IDSIZE); else { /* no source available; use "?" instead */ @@ -6444,7 +6445,7 @@ static void addinfo (lua_State *L, const char *msg) { l_noret luaG_errormsg (lua_State *L) { if (L->errfunc != 0) { /* is there an error handling function? */ - StkId errfunc = restorestack(L, L->errfunc); + const StkId errfunc = restorestack(L, L->errfunc); if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR); setobjs2s(L, L->top, L->top - 1); /* move argument */ setobjs2s(L, L->top - 1, errfunc); /* push function */ @@ -6588,7 +6589,7 @@ l_noret luaD_throw (lua_State *L, int errcode) { int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { - unsigned short oldnCcalls = L->nCcalls; + const unsigned short oldnCcalls = L->nCcalls; struct lua_longjmp lj; lj.status = LUA_OK; lj.previous = L->errorJmp; /* chain new error handler */ @@ -6638,11 +6639,11 @@ void luaD_reallocstack (lua_State *L, int newsize) { void luaD_growstack (lua_State *L, int n) { - int size = L->stacksize; + const int size = L->stacksize; if (size > LUAI_MAXSTACK) /* error after extra size? */ luaD_throw(L, LUA_ERRERR); else { - int needed = cast_int(L->top - L->stack) + n + EXTRA_STACK; + const int needed = cast_int(L->top - L->stack) + n + EXTRA_STACK; int newsize = 2 * size; if (newsize > LUAI_MAXSTACK) newsize = LUAI_MAXSTACK; if (newsize < needed) newsize = needed; @@ -6668,7 +6669,7 @@ static int stackinuse (lua_State *L) { void luaD_shrinkstack (lua_State *L) { - int inuse = stackinuse(L); + const int inuse = stackinuse(L); int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK; if (goodsize > LUAI_MAXSTACK) goodsize = LUAI_MAXSTACK; if (inuse > LUAI_MAXSTACK || /* handling stack overflow? */ @@ -6680,11 +6681,11 @@ void luaD_shrinkstack (lua_State *L) { void luaD_hook (lua_State *L, int event, int line) { - lua_Hook hook = L->hook; + const lua_Hook hook = L->hook; if (hook && L->allowhook) { CallInfo *ci = L->ci; - ptrdiff_t top = savestack(L, L->top); - ptrdiff_t ci_top = savestack(L, ci->top); + const ptrdiff_t top = savestack(L, L->top); + const ptrdiff_t ci_top = savestack(L, ci->top); lua_Debug ar; ar.event = event; ar.currentline = line; @@ -6721,7 +6722,7 @@ static void callhook (lua_State *L, CallInfo *ci) { static StkId adjust_varargs (lua_State *L, Proto *p, int actual) { int i; - int nfixargs = p->numparams; + const int nfixargs = p->numparams; StkId base, fixed; lua_assert(actual >= nfixargs); /* move fixed parameters to final position */ @@ -6738,7 +6739,7 @@ static StkId adjust_varargs (lua_State *L, Proto *p, int actual) { static StkId tryfuncTM (lua_State *L, StkId func) { const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL); StkId p; - ptrdiff_t funcr = savestack(L, func); + const ptrdiff_t funcr = savestack(L, func); if (!ttisfunction(tm)) luaG_typeerror(L, func, "call"); /* Open a hole inside the stack at `func' */ @@ -6761,7 +6762,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { lua_CFunction f; CallInfo *ci; int n; /* number of arguments (Lua) or returns (C) */ - ptrdiff_t funcr = savestack(L, func); + const ptrdiff_t funcr = savestack(L, func); switch (ttype(func)) { case LUA_TLCF: /* light C function */ f = fvalue(func); @@ -6818,10 +6819,10 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { int luaD_poscall (lua_State *L, StkId firstResult) { StkId res; int wanted, i; - CallInfo *ci = L->ci; + const CallInfo *ci = L->ci; if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) { if (L->hookmask & LUA_MASKRET) { - ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */ + const ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */ luaD_hook(L, LUA_HOOKRET, -1); firstResult = restorestack(L, fr); } @@ -6947,7 +6948,7 @@ static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) { ** do the work for 'lua_resume' in protected mode */ static void resume (lua_State *L, void *ud) { - int nCcalls = L->nCcalls; + const int nCcalls = L->nCcalls; StkId firstArg = cast(StkId, ud); CallInfo *ci = L->ci; if (nCcalls >= LUAI_MAXCCALLS) @@ -7048,13 +7049,13 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t old_top, ptrdiff_t ef) { int status; CallInfo *old_ci = L->ci; - lu_byte old_allowhooks = L->allowhook; - unsigned short old_nny = L->nny; - ptrdiff_t old_errfunc = L->errfunc; + const lu_byte old_allowhooks = L->allowhook; + const unsigned short old_nny = L->nny; + const ptrdiff_t old_errfunc = L->errfunc; L->errfunc = ef; status = luaD_rawrunprotected(L, func, u); if (status != LUA_OK) { /* an error occurred? */ - StkId oldtop = restorestack(L, old_top); + const StkId oldtop = restorestack(L, old_top); luaF_close(L, oldtop); /* close possible pending closures */ seterrorobj(L, status, oldtop); L->ci = old_ci; @@ -7093,7 +7094,7 @@ static void f_parser (lua_State *L, void *ud) { int i; Closure *cl; struct SParser *p = cast(struct SParser *, ud); - int c = zgetc(p->z); /* read first character */ + const int c = zgetc(p->z); /* read first character */ if (c == LUA_SIGNATURE[0]) { checkmode(L, p->mode, "binary"); cl = luaU_undump(L, p->z, &p->buff, p->name); @@ -7171,7 +7172,7 @@ static void DumpBlock(const void* b, size_t size, DumpState* D) static void DumpChar(int y, DumpState* D) { - char x=(char)y; + const char x=(char)y; DumpVar(x,D); } @@ -7195,12 +7196,12 @@ static void DumpString(const TString* s, DumpState* D) { if (s==NULL) { - size_t size=0; + const size_t size=0; DumpVar(size,D); } else { - size_t size=s->tsv.len+1; /* include trailing '\0' */ + const size_t size=s->tsv.len+1; /* include trailing '\0' */ DumpVar(size,D); DumpBlock(getstr(s),size*sizeof(char),D); } @@ -7733,7 +7734,7 @@ static void reallymarkobject (global_State *g, GCObject *o) { break; } case LUA_TUPVAL: { - UpVal *uv = gco2uv(o); + const UpVal *uv = gco2uv(o); markvalue(g, uv->v); if (uv->v != &uv->u.value) /* open? */ return; /* open upvalues remain gray */ @@ -7975,7 +7976,7 @@ static lu_mem traversestack (global_State *g, lua_State *th) { for (; o < th->top; o++) markvalue(g, o); if (g->gcstate == GCSatomic) { /* final traversal? */ - StkId lim = th->stack + th->stacksize; /* real end of stack */ + const StkId lim = th->stack + th->stacksize; /* real end of stack */ for (; o < lim; o++) /* clear not-marked stack slice */ setnilvalue(o); } @@ -8093,7 +8094,7 @@ static void convergeephemerons (global_State *g) { */ static void clearkeys (global_State *g, GCObject *l, GCObject *f) { for (; l != f; l = gco2t(l)->gclist) { - Table *h = gco2t(l); + const Table *h = gco2t(l); Node *n, *limit = gnodelast(h); for (n = gnode(h, 0); n < limit; n++) { if (!ttisnil(gval(n)) && (iscleared(g, gkey(n)))) { @@ -8111,7 +8112,7 @@ static void clearkeys (global_State *g, GCObject *l, GCObject *f) { */ static void clearvalues (global_State *g, GCObject *l, GCObject *f) { for (; l != f; l = gco2t(l)->gclist) { - Table *h = gco2t(l); + const Table *h = gco2t(l); Node *n, *limit = gnodelast(h); int i; for (i = 0; i < h->sizearray; i++) { @@ -8186,8 +8187,8 @@ static void sweepthread (lua_State *L, lua_State *L1) { ** When object is a thread, sweep its list of open upvalues too. */ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { - global_State *g = G(L); - int ow = otherwhite(g); + const global_State *g = G(L); + const int ow = otherwhite(g); int toclear, toset; /* bits to clear and to set in all live objects */ int tostop; /* stop sweep when this is true */ if (isgenerational(g)) { /* generational mode? */ @@ -8202,7 +8203,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { } while (*p != NULL && count-- > 0) { GCObject *curr = *p; - int marked = gch(curr)->marked; + const int marked = gch(curr)->marked; if (isdeadm(ow, marked)) { /* is 'curr' dead? */ *p = gch(curr)->next; /* remove 'curr' from list */ freeobj(L, curr); /* erase 'curr' */ @@ -8247,7 +8248,7 @@ static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) { static void checkSizes (lua_State *L) { global_State *g = G(L); if (g->gckind != KGC_EMERGENCY) { /* do not change sizes in emergency */ - int hs = g->strt.size / 2; /* half the size of the string table */ + const int hs = g->strt.size / 2; /* half the size of the string table */ if (g->strt.nuse < cast(lu_int32, hs)) /* using less than that half? */ luaS_resize(L, hs); /* halve its size */ luaZ_freebuffer(L, &g->buff); /* free concatenation buffer */ @@ -8283,8 +8284,8 @@ static void GCTM (lua_State *L, int propagateerrors) { tm = luaT_gettmbyobj(L, &v, TM_GC); if (tm != NULL && ttisfunction(tm)) { /* is there a finalizer? */ int status; - lu_byte oldah = L->allowhook; - int running = g->gcrunning; + const lu_byte oldah = L->allowhook; + const int running = g->gcrunning; L->allowhook = 0; /* stop debug hooks during GC metamethod */ g->gcrunning = 0; /* avoid GC steps */ setobj2s(L, L->top, tm); /* push finalizer... */ @@ -8426,7 +8427,7 @@ void luaC_changemode (lua_State *L, int mode) { ** call all pending finalizers */ static void callallpendingfinalizers (lua_State *L, int propagateerrors) { - global_State *g = G(L); + const global_State *g = G(L); while (g->tobefnz) { resetoldbit(g->tobefnz); GCTM(L, propagateerrors); @@ -8506,7 +8507,7 @@ static lu_mem singlestep (lua_State *L) { } case GCSpropagate: { if (g->gray) { - lu_mem oldtrav = g->GCmemtrav; + const lu_mem oldtrav = g->GCmemtrav; propagatemark(g); return g->GCmemtrav - oldtrav; /* memory traversed in this step */ } @@ -8564,7 +8565,7 @@ static lu_mem singlestep (lua_State *L) { ** by 'statemask' */ void luaC_runtilstate (lua_State *L, int statesmask) { - global_State *g = G(L); + const global_State *g = G(L); while (!testbit(statesmask, g->gcstate)) singlestep(L); } @@ -8577,7 +8578,7 @@ static void generationalcollection (lua_State *L) { g->GCestimate = gettotalbytes(g); /* update control */ } else { - lu_mem estimate = g->GCestimate; + const lu_mem estimate = g->GCestimate; luaC_runtilstate(L, ~bitmask(GCSpause)); /* run complete cycle */ luaC_runtilstate(L, bitmask(GCSpause)); if (gettotalbytes(g) > (estimate / 100) * g->gcmajorinc) @@ -8596,7 +8597,7 @@ static void incstep (lua_State *L) { debt = (debt / STEPMULADJ) + 1; debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM; do { /* always perform at least one single step */ - lu_mem work = singlestep(L); /* do some work */ + const lu_mem work = singlestep(L); /* do some work */ debt -= work; } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause); if (g->gcstate == GCSpause) @@ -8611,7 +8612,7 @@ static void incstep (lua_State *L) { ** performs a basic GC step */ void luaC_forcestep (lua_State *L) { - global_State *g = G(L); + const global_State *g = G(L); int i; if (isgenerational(g)) generationalcollection(L); else incstep(L); @@ -8638,8 +8639,8 @@ void luaC_step (lua_State *L) { */ void luaC_fullgc (lua_State *L, int isemergency) { global_State *g = G(L); - int origkind = g->gckind; - int someblack = keepinvariant(g); + const int origkind = g->gckind; + const int someblack = keepinvariant(g); lua_assert(origkind != KGC_EMERGENCY); if (isemergency) /* do not run finalizers during emergency GC */ g->gckind = KGC_EMERGENCY; @@ -8815,7 +8816,7 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) { ** \n, \r, \n\r, or \r\n) */ static void inclinenumber (LexState *ls) { - int old = ls->current; + const int old = ls->current; lua_assert(currIsNewline(ls)); next(ls); /* skip `\n' or `\r' */ if (currIsNewline(ls) && ls->current != old) @@ -8882,7 +8883,7 @@ static void buffreplace (LexState *ls, char from, char to) { ** the one defined in the current locale and check again */ static void trydecpoint (LexState *ls, SemInfo *seminfo) { - char old = ls->decpoint; + const char old = ls->decpoint; ls->decpoint = getlocaledecpoint(); buffreplace(ls, old, ls->decpoint); /* try new decimal separator */ if (!buff2d(ls->buff, &seminfo->r)) { @@ -8900,7 +8901,7 @@ static void trydecpoint (LexState *ls, SemInfo *seminfo) { */ static void read_numeral (LexState *ls, SemInfo *seminfo) { const char *expo = "Ee"; - int first = ls->current; + const int first = ls->current; lua_assert(lisdigit(ls->current)); save_and_next(ls); if (first == '0' && check_next(ls, "Xx")) /* hexadecimal? */ @@ -8925,7 +8926,7 @@ static void read_numeral (LexState *ls, SemInfo *seminfo) { */ static int skip_sep (LexState *ls) { int count = 0; - int s = ls->current; + const int s = ls->current; lua_assert(s == '[' || s == ']'); save_and_next(ls); while (ls->current == '=') { @@ -9085,7 +9086,7 @@ static int llex (LexState *ls, SemInfo *seminfo) { /* else is a comment */ next(ls); if (ls->current == '[') { /* long comment? */ - int sep = skip_sep(ls); + const int sep = skip_sep(ls); luaZ_resetbuffer(ls->buff); /* `skip_sep' may dirty the buffer */ if (sep >= 0) { read_long_string(ls, NULL, sep); /* skip long comment */ @@ -9099,7 +9100,7 @@ static int llex (LexState *ls, SemInfo *seminfo) { break; } case '[': { /* long string or simply '[' */ - int sep = skip_sep(ls); + const int sep = skip_sep(ls); if (sep >= 0) { read_long_string(ls, seminfo, sep); return TK_STRING; @@ -9170,7 +9171,7 @@ static int llex (LexState *ls, SemInfo *seminfo) { } } else { /* single-char tokens (+ - / ...) */ - int c = ls->current; + const int c = ls->current; next(ls); return c; } @@ -9274,7 +9275,7 @@ l_noret luaM_toobig (lua_State *L) { void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { void *newblock; global_State *g = G(L); - size_t realosize = (block) ? osize : 0; + const size_t realosize = (block) ? osize : 0; lua_assert((realosize == 0) == (block == NULL)); #if defined(HARDMEMTESTS) if (nsize > realosize && g->gcrunning) @@ -9344,7 +9345,7 @@ int luaO_int2fb (unsigned int x) { /* converts back */ int luaO_fb2int (int x) { - int e = (x >> 3) & 0x1f; + const int e = (x >> 3) & 0x1f; if (e == 0) return x; else return ((x & 7) + 8) << (e - 1); } @@ -9507,7 +9508,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { } case 'p': { char buff[4*sizeof(void *) + 8]; /* should be enough space for a `%p' */ - int l = sprintf(buff, "%p", va_arg(argp, void *)); + const int l = sprintf(buff, "%p", va_arg(argp, void *)); pushstr(L, buff, l); break; } @@ -9755,7 +9756,7 @@ static void anchor_token (LexState *ls) { /* last token from outer function must be EOS */ lua_assert(ls->fs != NULL || ls->t.token == TK_EOS); if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) { - TString *ts = ls->t.seminfo.ts; + const TString *ts = ls->t.seminfo.ts; luaX_newstring(ls, getstr(ts), ts->tsv.len); } } @@ -9777,7 +9778,7 @@ static l_noret error_expected (LexState *ls, int token) { static l_noret errorlimit (FuncState *fs, int limit, const char *what) { lua_State *L = fs->ls->L; const char *msg; - int line = fs->f->linedefined; + const int line = fs->f->linedefined; const char *where = (line == 0) ? "main function" : luaO_pushfstring(L, "function at line %d", line); @@ -9872,7 +9873,7 @@ static int registerlocalvar (LexState *ls, TString *varname) { static void new_localvar (LexState *ls, TString *name) { FuncState *fs = ls->fs; Dyndata *dyd = ls->dyd; - int reg = registerlocalvar(ls, name); + const int reg = registerlocalvar(ls, name); checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, MAXVARS, "local variables"); luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1, @@ -9890,7 +9891,7 @@ static void new_localvarliteral_ (LexState *ls, const char *name, size_t sz) { static LocVar *getlocvar (FuncState *fs, int i) { - int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx; + const int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx; lua_assert(idx < fs->nlocvars); return &fs->f->locvars[idx]; } @@ -9914,7 +9915,7 @@ static void removevars (FuncState *fs, int tolevel) { static int searchupvalue (FuncState *fs, TString *name) { int i; - Upvaldesc *up = fs->f->upvalues; + const Upvaldesc *up = fs->f->upvalues; for (i = 0; i < fs->nups; i++) { if (luaS_eqstr(up[i].name, name)) return i; } @@ -9966,7 +9967,7 @@ static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { if (fs == NULL) /* no more levels? */ return VVOID; /* default is global */ else { - int v = searchvar(fs, n); /* look up locals at current level */ + const int v = searchvar(fs, n); /* look up locals at current level */ if (v >= 0) { /* found? */ init_exp(var, VLOCAL, v); /* variable is local */ if (!base) @@ -10013,7 +10014,7 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { else { if (e->k != VVOID) luaK_exp2nextreg(fs, e); /* close last expression */ if (extra > 0) { - int reg = fs->freereg; + const int reg = fs->freereg; luaK_reserveregs(fs, extra); luaK_nil(fs, reg, extra); } @@ -10035,10 +10036,10 @@ static void closegoto (LexState *ls, int g, Labeldesc *label) { int i; FuncState *fs = ls->fs; Labellist *gl = &ls->dyd->gt; - Labeldesc *gt = &gl->arr[g]; + const Labeldesc *gt = &gl->arr[g]; lua_assert(luaS_eqstr(gt->name, label->name)); if (gt->nactvar < label->nactvar) { - TString *vname = getlocvar(fs, gt->nactvar)->varname; + const TString *vname = getlocvar(fs, gt->nactvar)->varname; const char *msg = luaO_pushfstring(ls->L, " at line %d jumps into the scope of local " LUA_QS, getstr(gt->name), gt->line, getstr(vname)); @@ -10057,9 +10058,9 @@ static void closegoto (LexState *ls, int g, Labeldesc *label) { */ static int findlabel (LexState *ls, int g) { int i; - BlockCnt *bl = ls->fs->bl; - Dyndata *dyd = ls->dyd; - Labeldesc *gt = &dyd->gt.arr[g]; + const BlockCnt *bl = ls->fs->bl; + const Dyndata *dyd = ls->dyd; + const Labeldesc *gt = &dyd->gt.arr[g]; /* check labels in current block for a match */ for (i = bl->firstlabel; i < dyd->label.n; i++) { Labeldesc *lb = &dyd->label.arr[i]; @@ -10077,7 +10078,7 @@ static int findlabel (LexState *ls, int g) { static int newlabelentry (LexState *ls, Labellist *l, TString *name, int line, int pc) { - int n = l->n; + const int n = l->n; luaM_growvector(ls->L, l->arr, n, l->size, Labeldesc, SHRT_MAX, "labels/gotos"); l->arr[n].name = name; @@ -10094,7 +10095,7 @@ static int newlabelentry (LexState *ls, Labellist *l, TString *name, ** block; solves forward jumps */ static void findgotos (LexState *ls, Labeldesc *lb) { - Labellist *gl = &ls->dyd->gt; + const Labellist *gl = &ls->dyd->gt; int i = ls->fs->bl->firstgoto; while (i < gl->n) { if (luaS_eqstr(gl->arr[i].name, lb->name)) @@ -10113,7 +10114,7 @@ static void findgotos (LexState *ls, Labeldesc *lb) { */ static void movegotosout (FuncState *fs, BlockCnt *bl) { int i = bl->firstgoto; - Labellist *gl = &fs->ls->dyd->gt; + const Labellist *gl = &fs->ls->dyd->gt; /* correct pending gotos to current block and try to close it with visible labels */ while (i < gl->n) { @@ -10146,7 +10147,7 @@ static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) { */ static void breaklabel (LexState *ls) { TString *n = luaS_new(ls->L, "break"); - int l = newlabelentry(ls, &ls->dyd->label, n, 0, ls->fs->pc); + const int l = newlabelentry(ls, &ls->dyd->label, n, 0, ls->fs->pc); findgotos(ls, &ls->dyd->label.arr[l]); } @@ -10168,7 +10169,7 @@ static void leaveblock (FuncState *fs) { LexState *ls = fs->ls; if (bl->previous && bl->upval) { /* create a 'jump to here' to close upvalues */ - int j = luaK_jump(fs); + const int j = luaK_jump(fs); luaK_patchclose(fs, j, bl->nactvar); luaK_patchtohere(fs, j); } @@ -10343,7 +10344,7 @@ struct ConsControl { static void recfield (LexState *ls, struct ConsControl *cc) { /* recfield -> (NAME | `['exp1`]') = exp1 */ FuncState *fs = ls->fs; - int reg = ls->fs->freereg; + const int reg = ls->fs->freereg; expdesc key, val; int rkkey; if (ls->t.token == TK_NAME) { @@ -10422,8 +10423,8 @@ static void constructor (LexState *ls, expdesc *t) { /* constructor -> '{' [ field { sep field } [sep] ] '}' sep -> ',' | ';' */ FuncState *fs = ls->fs; - int line = ls->linenumber; - int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); + const int line = ls->linenumber; + const int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); struct ConsControl cc; cc.na = cc.nh = cc.tostore = 0; cc.t = t; @@ -10569,7 +10570,7 @@ static void primaryexp (LexState *ls, expdesc *v) { /* primaryexp -> NAME | '(' expr ')' */ switch (ls->t.token) { case '(': { - int line = ls->linenumber; + const int line = ls->linenumber; luaX_next(ls); expr(ls, v); check_match(ls, ')', '(', line); @@ -10591,7 +10592,7 @@ static void suffixedexp (LexState *ls, expdesc *v) { /* suffixedexp -> primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */ FuncState *fs = ls->fs; - int line = ls->linenumber; + const int line = ls->linenumber; primaryexp(ls, v); for (;;) { switch (ls->t.token) { @@ -10731,7 +10732,7 @@ static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { enterlevel(ls); uop = getunopr(ls->t.token); if (uop != OPR_NOUNOPR) { - int line = ls->linenumber; + const int line = ls->linenumber; luaX_next(ls); subexpr(ls, v, UNARY_PRIORITY); luaK_prefix(ls->fs, uop, v, line); @@ -10742,7 +10743,7 @@ static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { while (op != OPR_NOBINOPR && priority[op].left > limit) { expdesc v2; BinOpr nextop; - int line = ls->linenumber; + const int line = ls->linenumber; luaX_next(ls); luaK_infix(ls->fs, op, v); /* read sub-expression with higher priority */ @@ -10798,7 +10799,7 @@ struct LHS_assign { */ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { FuncState *fs = ls->fs; - int extra = fs->freereg; /* eventual position to save local variable */ + const int extra = fs->freereg; /* eventual position to save local variable */ int conflict = 0; for (; lh; lh = lh->prev) { /* check all previous assignments */ if (lh->v.k == VINDEXED) { /* assigning to a table? */ @@ -10817,7 +10818,7 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { } if (conflict) { /* copy upvalue/local value to a temporary (in position 'extra') */ - OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; + const OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; luaK_codeABC(fs, op, extra, v->u.info, 0); luaK_reserveregs(fs, 1); } @@ -10868,7 +10869,7 @@ static int cond (LexState *ls) { static void gotostat (LexState *ls, int pc) { - int line = ls->linenumber; + const int line = ls->linenumber; TString *label; int g; if (testnext(ls, TK_GOTO)) @@ -10944,7 +10945,7 @@ static void repeatstat (LexState *ls, int line) { /* repeatstat -> REPEAT block UNTIL cond */ int condexit; FuncState *fs = ls->fs; - int repeat_init = luaK_getlabel(fs); + const int repeat_init = luaK_getlabel(fs); BlockCnt bl1, bl2; enterblock(fs, &bl1, 1); /* loop block */ enterblock(fs, &bl2, 0); /* scope block */ @@ -11000,7 +11001,7 @@ static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { static void fornum (LexState *ls, TString *varname, int line) { /* fornum -> NAME = exp1,exp1[,exp1] forbody */ FuncState *fs = ls->fs; - int base = fs->freereg; + const int base = fs->freereg; new_localvarliteral(ls, "(for index)"); new_localvarliteral(ls, "(for limit)"); new_localvarliteral(ls, "(for step)"); @@ -11025,7 +11026,7 @@ static void forlist (LexState *ls, TString *indexname) { expdesc e; int nvars = 4; /* gen, state, control, plus at least one declared var */ int line; - int base = fs->freereg; + const int base = fs->freereg; /* create control variables */ new_localvarliteral(ls, "(for generator)"); new_localvarliteral(ls, "(for state)"); @@ -11170,7 +11171,7 @@ static void funcstat (LexState *ls, int line) { static void exprstat (LexState *ls) { /* stat -> func | assignment */ - FuncState *fs = ls->fs; + const FuncState *fs = ls->fs; struct LHS_assign v; suffixedexp(ls, &v.v); if (ls->t.token == '=' || ls->t.token == ',') { /* stat -> assignment ? */ @@ -11218,7 +11219,7 @@ static void retstat (LexState *ls) { static void statement (LexState *ls) { - int line = ls->linenumber; /* may be needed for error messages */ + const int line = ls->linenumber; /* may be needed for error messages */ enterlevel(ls); switch (ls->t.token) { case ';': { /* stat -> ';' (empty statement) */ @@ -11682,7 +11683,7 @@ LUA_API void lua_close (lua_State *L) { ** equality for long strings */ int luaS_eqlngstr (TString *a, TString *b) { - size_t len = a->tsv.len; + const size_t len = a->tsv.len; lua_assert(a->tsv.tt == LUA_TLNGSTR && b->tsv.tt == LUA_TLNGSTR); return (a == b) || /* same instance or... */ ((len == b->tsv.len) && /* equal length and ... */ @@ -11702,7 +11703,7 @@ int luaS_eqstr (TString *a, TString *b) { unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) { unsigned int h = seed ^ l; size_t l1; - size_t step = (l >> LUAI_HASHLIMIT) + 1; + const size_t step = (l >> LUAI_HASHLIMIT) + 1; for (l1 = l; l1 >= step; l1 -= step) h = h ^ ((h<<5) + (h>>2) + cast_byte(str[l1 - 1])); return h; @@ -11727,7 +11728,7 @@ void luaS_resize (lua_State *L, int newsize) { tb->hash[i] = NULL; while (p) { /* for each node in the list */ GCObject *next = gch(p)->next; /* save next */ - unsigned int h = lmod(gco2ts(p)->hash, newsize); /* new position */ + const unsigned int h = lmod(gco2ts(p)->hash, newsize); /* new position */ gch(p)->next = tb->hash[h]; /* chain it */ tb->hash[h] = p; resetoldbit(p); /* see MOVE OLD rule */ @@ -11783,8 +11784,8 @@ static TString *newshrstr (lua_State *L, const char *str, size_t l, */ static TString *internshrstr (lua_State *L, const char *str, size_t l) { GCObject *o; - global_State *g = G(L); - unsigned int h = luaS_hash(str, l, g->seed); + const global_State *g = G(L); + const unsigned int h = luaS_hash(str, l, g->seed); for (o = g->strt.hash[lmod(h, g->strt.size)]; o != NULL; o = gch(o)->next) { @@ -12000,7 +12001,7 @@ static TString* LoadString(LoadState* S) static void LoadCode(LoadState* S, Proto* f) { - int n=LoadInt(S); + const int n=LoadInt(S); f->code=luaM_newvector(S->L,n,Instruction); f->sizecode=n; LoadVector(S,f->code,n,sizeof(Instruction)); @@ -12018,7 +12019,7 @@ static void LoadConstants(LoadState* S, Proto* f) for (i=0; ik[i]; - int t=LoadChar(S); + const int t=LoadChar(S); switch (t) { case LUA_TNIL: @@ -12274,8 +12275,8 @@ int luaV_tostring (lua_State *L, StkId obj) { return 0; else { char s[LUAI_MAXNUMBER2STR]; - lua_Number n = nvalue(obj); - int l = lua_number2str(s, n); + const lua_Number n = nvalue(obj); + const int l = lua_number2str(s, n); setsvalue2s(L, obj, luaS_newlstr(L, s, l)); return 1; } @@ -12284,8 +12285,8 @@ int luaV_tostring (lua_State *L, StkId obj) { static void traceexec (lua_State *L) { CallInfo *ci = L->ci; - lu_byte mask = L->hookmask; - int counthook = ((mask & LUA_MASKCOUNT) && L->hookcount == 0); + const lu_byte mask = L->hookmask; + const int counthook = ((mask & LUA_MASKCOUNT) && L->hookcount == 0); if (counthook) resethookcount(L); /* reset count */ if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */ @@ -12295,9 +12296,9 @@ static void traceexec (lua_State *L) { if (counthook) luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */ if (mask & LUA_MASKLINE) { - Proto *p = ci_func(ci)->p; - int npc = pcRel(ci->u.l.savedpc, p); - int newline = getfuncline(p, npc); + const Proto *p = ci_func(ci)->p; + const int npc = pcRel(ci->u.l.savedpc, p); + const int newline = getfuncline(p, npc); if (npc == 0 || /* call linehook when enter a new function, */ ci->u.l.savedpc <= L->oldpc || /* when jump back (loop), or when */ newline != getfuncline(p, pcRel(L->oldpc, p))) /* enter a new line */ @@ -12317,7 +12318,7 @@ static void traceexec (lua_State *L) { static void callTM (lua_State *L, const TValue *f, const TValue *p1, const TValue *p2, TValue *p3, int hasres) { - ptrdiff_t result = savestack(L, p3); + const ptrdiff_t result = savestack(L, p3); setobj2s(L, L->top++, f); /* push function */ setobj2s(L, L->top++, p1); /* 1st argument */ setobj2s(L, L->top++, p2); /* 2nd argument */ @@ -12438,7 +12439,7 @@ static int l_strcmp (const TString *ls, const TString *rs) { const char *r = getstr(rs); size_t lr = rs->tsv.len; for (;;) { - int temp = strcoll(l, r); + const int temp = strcoll(l, r); if (temp != 0) return temp; else { /* strings are equal up to a `\0' */ size_t len = strlen(l); /* index of first `\0' in both strings */ @@ -12519,7 +12520,7 @@ int luaV_equalobj_ (lua_State *L, const TValue *t1, const TValue *t2) { void luaV_concat (lua_State *L, int total) { lua_assert(total >= 2); do { - StkId top = L->top; + const StkId top = L->top; int n = 2; /* number of elements handled in this pass (at least 2) */ if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) { if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) @@ -12537,7 +12538,7 @@ void luaV_concat (lua_State *L, int total) { int i; /* collect total length */ for (i = 1; i < total && tostring(L, top-i-1); i++) { - size_t l = tsvalue(top-i-1)->len; + const size_t l = tsvalue(top-i-1)->len; if (l >= (MAX_SIZET/sizeof(char)) - tl) luaG_runerror(L, "string length overflow"); tl += l; @@ -12546,7 +12547,7 @@ void luaV_concat (lua_State *L, int total) { tl = 0; n = i; do { /* concat all strings */ - size_t l = tsvalue(top-i)->len; + const size_t l = tsvalue(top-i)->len; memcpy(buffer+tl, svalue(top-i), l * sizeof(char)); tl += l; } while (--i > 0); @@ -12589,7 +12590,7 @@ void luaV_arith (lua_State *L, StkId ra, const TValue *rb, const TValue *b, *c; if ((b = luaV_tonumber(rb, &tempb)) != NULL && (c = luaV_tonumber(rc, &tempc)) != NULL) { - lua_Number res = luaO_arith(op - TM_ADD + LUA_OPADD, nvalue(b), nvalue(c)); + const lua_Number res = luaO_arith(op - TM_ADD + LUA_OPADD, nvalue(b), nvalue(c)); setnvalue(ra, res); } else if (!call_binTM(L, rb, rc, ra, op)) @@ -12605,11 +12606,11 @@ void luaV_arith (lua_State *L, StkId ra, const TValue *rb, static Closure *getcached (Proto *p, UpVal **encup, StkId base) { Closure *c = p->cache; if (c != NULL) { /* is there a cached closure? */ - int nup = p->sizeupvalues; - Upvaldesc *uv = p->upvalues; + const int nup = p->sizeupvalues; + const Upvaldesc *uv = p->upvalues; int i; for (i = 0; i < nup; i++) { /* check whether it has right upvalues */ - TValue *v = uv[i].instack ? base + uv[i].idx : encup[uv[i].idx]->v; + const TValue *v = uv[i].instack ? base + uv[i].idx : encup[uv[i].idx]->v; if (c->l.upvals[i]->v != v) return NULL; /* wrong upvalue; cannot reuse closure */ } @@ -12626,8 +12627,8 @@ static Closure *getcached (Proto *p, UpVal **encup, StkId base) { */ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base, StkId ra) { - int nup = p->sizeupvalues; - Upvaldesc *uv = p->upvalues; + const int nup = p->sizeupvalues; + const Upvaldesc *uv = p->upvalues; int i; Closure *ncl = luaF_newLclosure(L, nup); ncl->l.p = p; @@ -12648,9 +12649,9 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base, */ void luaV_finishOp (lua_State *L) { CallInfo *ci = L->ci; - StkId base = ci->u.l.base; - Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */ - OpCode op = GET_OPCODE(inst); + const StkId base = ci->u.l.base; + const Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */ + const OpCode op = GET_OPCODE(inst); switch (op) { /* finish its execution */ case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_MOD: case OP_POW: case OP_UNM: case OP_LEN: @@ -12672,9 +12673,9 @@ void luaV_finishOp (lua_State *L) { break; } case OP_CONCAT: { - StkId top = L->top - 1; /* top when 'call_binTM' was called */ - int b = GETARG_B(inst); /* first element to concatenate */ - int total = cast_int(top - 1 - (base + b)); /* yet to concatenate */ + const StkId top = L->top - 1; /* top when 'call_binTM' was called */ + const int b = GETARG_B(inst); /* first element to concatenate */ + const int total = cast_int(top - 1 - (base + b)); /* yet to concatenate */ setobj2s(L, top - 2, top); /* put TM result in proper position */ if (total > 1) { /* are there elements to concat? */ L->top = top - 1; /* top is one after last element (at top-2) */ @@ -13307,7 +13308,7 @@ static Node *mainposition (const Table *t, const TValue *key) { */ static int arrayindex (const TValue *key) { if (ttisnumber(key)) { - lua_Number n = nvalue(key); + const lua_Number n = nvalue(key); int k; lua_number2int(k, n); if (luai_numeq(cast_num(k), n)) @@ -13329,7 +13330,7 @@ static int findindex (lua_State *L, Table *t, StkId key) { if (0 < i && i <= t->sizearray) /* is `key' inside array part? */ return i-1; /* yes; that's the index (corrected to C) */ else { - Node *n = mainposition(t, key); + const Node *n = mainposition(t, key); for (;;) { /* check whether `key' is somewhere in the chain */ /* key may be dead already, but it is ok to use it in `next' */ if (luaV_rawequalobj(gkey(n), key) || @@ -13397,7 +13398,7 @@ static int computesizes (int nums[], int *narray) { static int countint (const TValue *key, int *nums) { - int k = arrayindex(key); + const int k = arrayindex(key); if (0 < k && k <= MAXASIZE) { /* is `key' an appropriate array index? */ nums[luaO_ceillog2(k)]++; /* count as such */ return 1; @@ -13437,7 +13438,7 @@ static int numusehash (const Table *t, int *nums, int *pnasize) { int ause = 0; /* summation of `nums' */ int i = sizenode(t); while (i--) { - Node *n = &t->node[i]; + const Node *n = &t->node[i]; if (!ttisnil(gval(n))) { ause += countint(gkey(n), nums); totaluse++; @@ -13484,8 +13485,8 @@ static void setnodevector (lua_State *L, Table *t, int size) { void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize) { int i; - int oldasize = t->sizearray; - int oldhsize = t->lsizenode; + const int oldasize = t->sizearray; + const int oldhsize = t->lsizenode; Node *nold = t->node; /* save old hash ... */ if (nasize > oldasize) /* array part must grow? */ setarrayvector(L, t, nasize); @@ -13503,7 +13504,7 @@ void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize) { } /* re-insert elements from hash part */ for (i = twoto(oldhsize) - 1; i >= 0; i--) { - Node *old = nold+i; + const Node *old = nold+i; if (!ttisnil(gval(old))) { /* doesn't need barrier/invalidate cache, as entry was already present in the table */ @@ -13516,7 +13517,7 @@ void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize) { void luaH_resizearray (lua_State *L, Table *t, int nasize) { - int nsize = isdummy(t->node) ? 0 : sizenode(t); + const int nsize = isdummy(t->node) ? 0 : sizenode(t); luaH_resize(L, t, nasize, nsize); } @@ -13629,8 +13630,8 @@ const TValue *luaH_getint (Table *t, int key) { if (cast(unsigned int, key-1) < cast(unsigned int, t->sizearray)) return &t->array[key-1]; else { - lua_Number nk = cast_num(key); - Node *n = hashnum(t, nk); + const lua_Number nk = cast_num(key); + const Node *n = hashnum(t, nk); do { /* check whether `key' is somewhere in the chain */ if (ttisnumber(gkey(n)) && luai_numeq(nvalue(gkey(n)), nk)) return gval(n); /* that's it */ @@ -13645,7 +13646,7 @@ const TValue *luaH_getint (Table *t, int key) { ** search function for short strings */ const TValue *luaH_getstr (Table *t, TString *key) { - Node *n = hashstr(t, key); + const Node *n = hashstr(t, key); lua_assert(key->tsv.tt == LUA_TSHRSTR); do { /* check whether `key' is somewhere in the chain */ if (ttisshrstring(gkey(n)) && eqshrstr(rawtsvalue(gkey(n)), key)) @@ -13665,14 +13666,14 @@ const TValue *luaH_get (Table *t, const TValue *key) { case LUA_TSHRSTR: return luaH_getstr(t, rawtsvalue(key)); case LUA_TNUMBER: { int k; - lua_Number n = nvalue(key); + const lua_Number n = nvalue(key); lua_number2int(k, n); if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */ return luaH_getint(t, k); /* use specialized version */ /* else go through */ } default: { - Node *n = mainposition(t, key); + const Node *n = mainposition(t, key); do { /* check whether `key' is somewhere in the chain */ if (luaV_rawequalobj(gkey(n), key)) return gval(n); /* that's it */ @@ -13726,7 +13727,7 @@ static int unbound_search (Table *t, unsigned int j) { } /* now do a binary search between them */ while (j - i > 1) { - unsigned int m = (i+j)/2; + const unsigned int m = (i+j)/2; if (ttisnil(luaH_getint(t, m))) j = m; else i = m; } @@ -13744,7 +13745,7 @@ int luaH_getn (Table *t) { /* there is a boundary in the array part: (binary) search for it */ unsigned int i = 0; while (j - i > 1) { - unsigned int m = (i+j)/2; + const unsigned int m = (i+j)/2; if (ttisnil(&t->array[m - 1])) j = m; else i = m; } @@ -13838,7 +13839,7 @@ static int findfield (lua_State *L, int objidx, int level) { static int pushglobalfuncname (lua_State *L, lua_Debug *ar) { - int top = lua_gettop(L); + const int top = lua_gettop(L); lua_getinfo(L, "f", ar); /* push function */ lua_pushglobaltable(L); if (findfield(L, top + 1, 2)) { @@ -13878,7 +13879,7 @@ static int countlevels (lua_State *L) { while (lua_getstack(L, le, &ar)) { li = le; le *= 2; } /* do a binary search */ while (li < le) { - int m = (li + le)/2; + const int m = (li + le)/2; if (lua_getstack(L, m, &ar)) li = m + 1; else le = m; } @@ -13889,9 +13890,9 @@ static int countlevels (lua_State *L) { LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg, int level) { lua_Debug ar; - int top = lua_gettop(L); - int numlevels = countlevels(L1); - int mark = (numlevels > LEVELS1 + LEVELS2) ? LEVELS1 : 0; + const int top = lua_gettop(L); + const int numlevels = countlevels(L1); + const int mark = (numlevels > LEVELS1 + LEVELS2) ? LEVELS1 : 0; if (msg) lua_pushfstring(L, "%s\n", msg); lua_pushliteral(L, "stack traceback:"); while (lua_getstack(L1, level++, &ar)) { @@ -13977,7 +13978,7 @@ LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { - int en = errno; /* calls to Lua API may change this value */ + const int en = errno; /* calls to Lua API may change this value */ if (stat) { lua_pushboolean(L, 1); return 1; @@ -14146,7 +14147,7 @@ LUALIB_API const char *luaL_optlstring (lua_State *L, int narg, LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) { int isnum; - lua_Number d = lua_tonumberx(L, narg, &isnum); + const lua_Number d = lua_tonumberx(L, narg, &isnum); if (!isnum) tag_error(L, narg, LUA_TNUMBER); return d; @@ -14160,7 +14161,7 @@ LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) { LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) { int isnum; - lua_Integer d = lua_tointegerx(L, narg, &isnum); + const lua_Integer d = lua_tointegerx(L, narg, &isnum); if (!isnum) tag_error(L, narg, LUA_TNUMBER); return d; @@ -14169,7 +14170,7 @@ LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) { LUALIB_API lua_Unsigned luaL_checkunsigned (lua_State *L, int narg) { int isnum; - lua_Unsigned d = lua_tounsignedx(L, narg, &isnum); + const lua_Unsigned d = lua_tounsignedx(L, narg, &isnum); if (!isnum) tag_error(L, narg, LUA_TNUMBER); return d; @@ -14404,7 +14405,7 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename, LoadF lf; int status, readstatus; int c; - int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ + const int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ if (filename == NULL) { lua_pushliteral(L, "=stdin"); lf.f = stdin; @@ -14674,7 +14675,7 @@ LUALIB_API void luaL_requiref (lua_State *L, const char *modname, LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, const char *r) { const char *wild; - size_t l = strlen(p); + const size_t l = strlen(p); luaL_Buffer b; luaL_buffinit(L, &b); while ((wild = strstr(s, p)) != NULL) { @@ -14755,7 +14756,7 @@ LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver) { static int luaB_print (lua_State *L) { - int n = lua_gettop(L); /* number of arguments */ + const int n = lua_gettop(L); /* number of arguments */ int i; lua_getglobal(L, "tostring"); for (i=1; i<=n; i++) { @@ -14782,7 +14783,7 @@ static int luaB_print (lua_State *L) { static int luaB_tonumber (lua_State *L) { if (lua_isnoneornil(L, 2)) { /* standard conversion */ int isnum; - lua_Number n = lua_tonumberx(L, 1, &isnum); + const lua_Number n = lua_tonumberx(L, 1, &isnum); if (isnum) { lua_pushnumber(L, n); return 1; @@ -14793,7 +14794,7 @@ static int luaB_tonumber (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); const char *e = s + l; /* end point for 's' */ - int base = luaL_checkint(L, 2); + const int base = luaL_checkint(L, 2); int neg = 0; luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); s += strspn(s, SPACECHARS); /* skip initial spaces */ @@ -14802,7 +14803,7 @@ static int luaB_tonumber (lua_State *L) { if (isalnum((unsigned char)*s)) { lua_Number n = 0; do { - int digit = (isdigit((unsigned char)*s)) ? *s - '0' + const int digit = (isdigit((unsigned char)*s)) ? *s - '0' : toupper((unsigned char)*s) - 'A' + 10; if (digit >= base) break; /* invalid numeral; force a fail */ n = n * (lua_Number)base + (lua_Number)digit; @@ -14821,7 +14822,7 @@ static int luaB_tonumber (lua_State *L) { static int luaB_error (lua_State *L) { - int level = luaL_optint(L, 2, 1); + const int level = luaL_optint(L, 2, 1); lua_settop(L, 1); if (lua_isstring(L, 1) && level > 0) { /* add extra information? */ luaL_where(L, level); @@ -14844,7 +14845,7 @@ static int luaB_getmetatable (lua_State *L) { static int luaB_setmetatable (lua_State *L) { - int t = lua_type(L, 2); + const int t = lua_type(L, 2); luaL_checktype(L, 1, LUA_TTABLE); luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table expected"); @@ -14865,7 +14866,7 @@ static int luaB_rawequal (lua_State *L) { static int luaB_rawlen (lua_State *L) { - int t = lua_type(L, 1); + const int t = lua_type(L, 1); luaL_argcheck(L, t == LUA_TTABLE || t == LUA_TSTRING, 1, "table or string expected"); lua_pushinteger(L, lua_rawlen(L, 1)); @@ -14898,12 +14899,12 @@ static int luaB_collectgarbage (lua_State *L) { static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, LUA_GCSETMAJORINC, LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC}; - int o = optsnum[luaL_checkoption(L, 1, "collect", opts)]; - int ex = luaL_optint(L, 2, 0); - int res = lua_gc(L, o, ex); + const int o = optsnum[luaL_checkoption(L, 1, "collect", opts)]; + const int ex = luaL_optint(L, 2, 0); + const int res = lua_gc(L, o, ex); switch (o) { case LUA_GCCOUNT: { - int b = lua_gc(L, LUA_GCCOUNTB, 0); + const int b = lua_gc(L, LUA_GCCOUNTB, 0); lua_pushnumber(L, res + ((lua_Number)b/1024)); lua_pushinteger(L, b); return 2; @@ -14990,8 +14991,8 @@ static int load_aux (lua_State *L, int status) { static int luaB_loadfile (lua_State *L) { const char *fname = luaL_optstring(L, 1, NULL); const char *mode = luaL_optstring(L, 2, NULL); - int env = !lua_isnone(L, 3); /* 'env' parameter? */ - int status = luaL_loadfilex(L, fname, mode); + const int env = !lua_isnone(L, 3); /* 'env' parameter? */ + const int status = luaL_loadfilex(L, fname, mode); if (status == LUA_OK && env) { /* 'env' parameter? */ lua_pushvalue(L, 3); lua_setupvalue(L, -2, 1); /* set it as 1st upvalue of loaded chunk */ @@ -15041,7 +15042,7 @@ static const char *generic_reader (lua_State *L, void *ud, size_t *size) { static int luaB_load (lua_State *L) { int status; size_t l; - int top = lua_gettop(L); + const int top = lua_gettop(L); const char *s = lua_tolstring(L, 1, &l); const char *mode = luaL_optstring(L, 3, "bt"); if (s != NULL) { /* loading a string? */ @@ -15086,7 +15087,7 @@ static int luaB_assert (lua_State *L) { static int luaB_select (lua_State *L) { - int n = lua_gettop(L); + const int n = lua_gettop(L); if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') { lua_pushinteger(L, n-1); return 1; @@ -15115,7 +15116,7 @@ static int finishpcall (lua_State *L, int status) { static int pcallcont (lua_State *L) { - int status = lua_getctx(L, NULL); + const int status = lua_getctx(L, NULL); return finishpcall(L, (status == LUA_YIELD)); } @@ -15132,7 +15133,7 @@ static int luaB_pcall (lua_State *L) { static int luaB_xpcall (lua_State *L) { int status; - int n = lua_gettop(L); + const int n = lua_gettop(L); luaL_argcheck(L, n >= 2, 2, "value expected"); lua_pushvalue(L, 1); /* exchange function... */ lua_copy(L, 2, 1); /* ...and error handler */ @@ -15236,14 +15237,14 @@ static b_uint andaux (lua_State *L) { static int b_and (lua_State *L) { - b_uint r = andaux(L); + const b_uint r = andaux(L); lua_pushunsigned(L, r); return 1; } static int b_test (lua_State *L) { - b_uint r = andaux(L); + const b_uint r = andaux(L); lua_pushboolean(L, r != 0); return 1; } @@ -15270,7 +15271,7 @@ static int b_xor (lua_State *L) { static int b_not (lua_State *L) { - b_uint r = ~luaL_checkunsigned(L, 1); + const b_uint r = ~luaL_checkunsigned(L, 1); lua_pushunsigned(L, trim(r)); return 1; } @@ -15305,7 +15306,7 @@ static int b_rshift (lua_State *L) { static int b_arshift (lua_State *L) { b_uint r = luaL_checkunsigned(L, 1); - int i = luaL_checkint(L, 2); + const int i = luaL_checkint(L, 2); if (i < 0 || !(r & ((b_uint)1 << (LUA_NBITS - 1)))) return b_shift(L, r, -i); else { /* arithmetic shift for 'negative' number */ @@ -15343,8 +15344,8 @@ static int b_rrot (lua_State *L) { ** checking whether they are valid */ static int fieldargs (lua_State *L, int farg, int *width) { - int f = luaL_checkint(L, farg); - int w = luaL_optint(L, farg + 1, 1); + const int f = luaL_checkint(L, farg); + const int w = luaL_optint(L, farg + 1, 1); luaL_argcheck(L, 0 <= f, farg, "field cannot be negative"); luaL_argcheck(L, 0 < w, farg + 1, "width must be positive"); if (f + w > LUA_NBITS) @@ -15357,7 +15358,7 @@ static int fieldargs (lua_State *L, int farg, int *width) { static int b_extract (lua_State *L) { int w; b_uint r = luaL_checkunsigned(L, 1); - int f = fieldargs(L, 2, &w); + const int f = fieldargs(L, 2, &w); r = (r >> f) & mask(w); lua_pushunsigned(L, r); return 1; @@ -15368,8 +15369,8 @@ static int b_replace (lua_State *L) { int w; b_uint r = luaL_checkunsigned(L, 1); b_uint v = luaL_checkunsigned(L, 2); - int f = fieldargs(L, 3, &w); - int m = mask(w); + const int f = fieldargs(L, 3, &w); + const int m = mask(w); v &= m; /* erase bits outside given width */ r = (r & ~(m << f)) | (v << f); lua_pushunsigned(L, r); @@ -15432,7 +15433,7 @@ static int auxresume (lua_State *L, lua_State *co, int narg) { lua_xmove(L, co, narg); status = lua_resume(co, L, narg); if (status == LUA_OK || status == LUA_YIELD) { - int nres = lua_gettop(co); + const int nres = lua_gettop(co); if (!lua_checkstack(L, nres + 1)) { lua_pop(co, nres); /* remove results anyway */ lua_pushliteral(L, "too many results to resume"); @@ -15468,7 +15469,7 @@ static int luaB_coresume (lua_State *L) { static int luaB_auxwrap (lua_State *L) { lua_State *co = lua_tothread(L, lua_upvalueindex(1)); - int r = auxresume(L, co, lua_gettop(L)); + const int r = auxresume(L, co, lua_gettop(L)); if (r < 0) { if (lua_isstring(L, -1)) { /* error object is a string? */ luaL_where(L, 1); /* add extra info */ @@ -15532,7 +15533,7 @@ static int luaB_costatus (lua_State *L) { static int luaB_corunning (lua_State *L) { - int ismain = lua_pushthread(L); + const int ismain = lua_pushthread(L); lua_pushboolean(L, ismain); return 2; } @@ -15595,7 +15596,7 @@ static int db_getmetatable (lua_State *L) { static int db_setmetatable (lua_State *L) { - int t = lua_type(L, 2); + const int t = lua_type(L, 2); luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table expected"); lua_settop(L, 2); @@ -15721,7 +15722,7 @@ static int db_getlocal (lua_State *L) { lua_State *L1 = getthread(L, &arg); lua_Debug ar; const char *name; - int nvar = luaL_checkint(L, arg+2); /* local-variable index */ + const int nvar = luaL_checkint(L, arg+2); /* local-variable index */ if (lua_isfunction(L, arg + 1)) { /* function argument? */ lua_pushvalue(L, arg + 1); /* push function */ lua_pushstring(L, lua_getlocal(L, NULL, nvar)); /* push local name */ @@ -15761,7 +15762,7 @@ static int db_setlocal (lua_State *L) { static int auxupvalue (lua_State *L, int get) { const char *name; - int n = luaL_checkint(L, 2); + const int n = luaL_checkint(L, 2); luaL_checktype(L, 1, LUA_TFUNCTION); name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); if (name == NULL) return 0; @@ -15784,7 +15785,7 @@ static int db_setupvalue (lua_State *L) { static int checkupval (lua_State *L, int argf, int argnup) { lua_Debug ar; - int nup = luaL_checkint(L, argnup); + const int nup = luaL_checkint(L, argnup); luaL_checktype(L, argf, LUA_TFUNCTION); lua_pushvalue(L, argf); lua_getinfo(L, ">u", &ar); @@ -15794,15 +15795,15 @@ static int checkupval (lua_State *L, int argf, int argnup) { static int db_upvalueid (lua_State *L) { - int n = checkupval(L, 1, 2); + const int n = checkupval(L, 1, 2); lua_pushlightuserdata(L, lua_upvalueid(L, 1, n)); return 1; } static int db_upvaluejoin (lua_State *L) { - int n1 = checkupval(L, 1, 2); - int n2 = checkupval(L, 3, 4); + const int n1 = checkupval(L, 1, 2); + const int n2 = checkupval(L, 3, 4); luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected"); luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected"); lua_upvaluejoin(L, 1, n1, 3, n2); @@ -15882,8 +15883,8 @@ static int db_gethook (lua_State *L) { int arg; lua_State *L1 = getthread(L, &arg); char buff[5]; - int mask = lua_gethookmask(L1); - lua_Hook hook = lua_gethook(L1); + const int mask = lua_gethookmask(L1); + const lua_Hook hook = lua_gethook(L1); if (hook != NULL && hook != hookf) /* external hook? */ lua_pushliteral(L, "external hook"); else { @@ -15920,7 +15921,7 @@ static int db_traceback (lua_State *L) { if (msg == NULL && !lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */ lua_pushvalue(L, arg + 1); /* return it untouched */ else { - int level = luaL_optint(L, arg + 2, (L == L1) ? 1 : 0); + const int level = luaL_optint(L, arg + 2, (L == L1) ? 1 : 0); luaL_traceback(L, L1, msg, level); } return 1; @@ -16082,7 +16083,7 @@ static int io_type (lua_State *L) { static int f_tostring (lua_State *L) { - LStream *p = tolstream(L); + const LStream *p = tolstream(L); if (isclosed(p)) lua_pushliteral(L, "file (closed)"); else @@ -16092,7 +16093,7 @@ static int f_tostring (lua_State *L) { static FILE *tofile (lua_State *L) { - LStream *p = tolstream(L); + const LStream *p = tolstream(L); if (isclosed(p)) luaL_error(L, "attempt to use a closed file"); lua_assert(p->f); @@ -16115,7 +16116,7 @@ static LStream *newprefile (lua_State *L) { static int aux_close (lua_State *L) { LStream *p = tolstream(L); - lua_CFunction cf = p->closef; + const lua_CFunction cf = p->closef; p->closef = NULL; /* mark stream as closed */ return (*cf)(L); /* close it */ } @@ -16130,7 +16131,7 @@ static int io_close (lua_State *L) { static int f_gc (lua_State *L) { - LStream *p = tolstream(L); + const LStream *p = tolstream(L); if (!isclosed(p) && p->f != NULL) aux_close(L); /* ignore closed and incompletely open files */ return 0; @@ -16141,8 +16142,8 @@ static int f_gc (lua_State *L) { ** function to close regular files */ static int io_fclose (lua_State *L) { - LStream *p = tolstream(L); - int res = fclose(p->f); + const LStream *p = tolstream(L); + const int res = fclose(p->f); return luaL_fileresult(L, (res == 0), NULL); } @@ -16248,7 +16249,7 @@ static int io_readline (lua_State *L); static void aux_lines (lua_State *L, int toclose) { int i; - int n = lua_gettop(L) - 1; /* number of arguments to read */ + const int n = lua_gettop(L) - 1; /* number of arguments to read */ /* ensure that arguments will fit here and into 'io_readline' stack */ luaL_argcheck(L, n <= LUA_MINSTACK - 3, LUA_MINSTACK - 3, "too many options"); lua_pushvalue(L, 1); /* file handle */ @@ -16307,7 +16308,7 @@ static int read_number (lua_State *L, FILE *f) { static int test_eof (lua_State *L, FILE *f) { - int c = getc(f); + const int c = getc(f); ungetc(c, f); lua_pushlstring(L, NULL, 0); return (c != EOF); @@ -16344,7 +16345,7 @@ static void read_all (lua_State *L, FILE *f) { luaL_buffinit(L, &b); for (;;) { char *p = luaL_prepbuffsize(&b, rlen); - size_t nr = fread(p, sizeof(char), rlen, f); + const size_t nr = fread(p, sizeof(char), rlen, f); luaL_addsize(&b, nr); if (nr < rlen) break; /* eof? */ else if (rlen <= (MAX_SIZE_T / 4)) /* avoid buffers too large */ @@ -16381,7 +16382,7 @@ static int g_read (lua_State *L, FILE *f, int first) { success = 1; for (n = first; nargs-- && success; n++) { if (lua_type(L, n) == LUA_TNUMBER) { - size_t l = (size_t)lua_tointeger(L, n); + const size_t l = (size_t)lua_tointeger(L, n); success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); } else { @@ -16428,7 +16429,7 @@ static int f_read (lua_State *L) { static int io_readline (lua_State *L) { - LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1)); + const LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1)); int i; int n = (int)lua_tointeger(L, lua_upvalueindex(2)); if (isclosed(p)) /* file is already closed? */ @@ -16494,7 +16495,7 @@ static int f_seek (lua_State *L) { static const char *const modenames[] = {"set", "cur", "end", NULL}; FILE *f = tofile(L); int op = luaL_checkoption(L, 2, "cur", modenames); - lua_Number p3 = luaL_optnumber(L, 3, 0); + const lua_Number p3 = luaL_optnumber(L, 3, 0); l_seeknum offset = (l_seeknum)p3; luaL_argcheck(L, (lua_Number)offset == p3, 3, "not an integer in proper range"); @@ -16512,9 +16513,9 @@ static int f_setvbuf (lua_State *L) { static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; static const char *const modenames[] = {"no", "full", "line", NULL}; FILE *f = tofile(L); - int op = luaL_checkoption(L, 2, NULL, modenames); - lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); - int res = setvbuf(f, NULL, mode[op], sz); + const int op = luaL_checkoption(L, 2, NULL, modenames); + const lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); + const int res = setvbuf(f, NULL, mode[op], sz); return luaL_fileresult(L, res == 0, NULL); } @@ -16715,7 +16716,7 @@ static int math_fmod (lua_State *L) { static int math_modf (lua_State *L) { lua_Number ip; - lua_Number fp = l_tg(modf)(luaL_checknumber(L, 1), &ip); + const lua_Number fp = l_tg(modf)(luaL_checknumber(L, 1), &ip); lua_pushnumber(L, ip); lua_pushnumber(L, fp); return 2; @@ -16733,12 +16734,12 @@ static int math_pow (lua_State *L) { } static int math_log (lua_State *L) { - lua_Number x = luaL_checknumber(L, 1); + const lua_Number x = luaL_checknumber(L, 1); lua_Number res; if (lua_isnoneornil(L, 2)) res = l_tg(log)(x); else { - lua_Number base = luaL_checknumber(L, 2); + const lua_Number base = luaL_checknumber(L, 2); if (base == 10.0) res = l_tg(log10)(x); else res = l_tg(log)(x)/l_tg(log)(base); } @@ -16784,11 +16785,11 @@ static int math_ldexp (lua_State *L) { static int math_min (lua_State *L) { - int n = lua_gettop(L); /* number of arguments */ + const int n = lua_gettop(L); /* number of arguments */ lua_Number dmin = luaL_checknumber(L, 1); int i; for (i=2; i<=n; i++) { - lua_Number d = luaL_checknumber(L, i); + const lua_Number d = luaL_checknumber(L, i); if (d < dmin) dmin = d; } @@ -16798,11 +16799,11 @@ static int math_min (lua_State *L) { static int math_max (lua_State *L) { - int n = lua_gettop(L); /* number of arguments */ + const int n = lua_gettop(L); /* number of arguments */ lua_Number dmax = luaL_checknumber(L, 1); int i; for (i=2; i<=n; i++) { - lua_Number d = luaL_checknumber(L, i); + const lua_Number d = luaL_checknumber(L, i); if (d > dmax) dmax = d; } @@ -16814,21 +16815,21 @@ static int math_max (lua_State *L) { static int math_random (lua_State *L) { /* the `%' avoids the (rare) case of r==1, and is needed also because on some systems (SunOS!) `randomMT()' may return a value larger than RAND_MAX */ - lua_Number r = (lua_Number)(rand()%RAND_MAX) / (lua_Number)RAND_MAX; + const lua_Number r = (lua_Number)(rand()%RAND_MAX) / (lua_Number)RAND_MAX; switch (lua_gettop(L)) { /* check number of arguments */ case 0: { /* no arguments */ lua_pushnumber(L, r); /* Number between 0 and 1 */ break; } case 1: { /* only upper limit */ - lua_Number u = luaL_checknumber(L, 1); + const lua_Number u = luaL_checknumber(L, 1); luaL_argcheck(L, 1.0 <= u, 1, "interval is empty"); lua_pushnumber(L, l_tg(floor)(r*u) + 1.0); /* int in [1, u] */ break; } case 2: { /* lower and upper limits */ - lua_Number l = luaL_checknumber(L, 1); - lua_Number u = luaL_checknumber(L, 2); + const lua_Number l = luaL_checknumber(L, 1); + const lua_Number u = luaL_checknumber(L, 2); luaL_argcheck(L, l <= u, 2, "interval is empty"); lua_pushnumber(L, l_tg(floor)(r*(u-l+1)) + l); /* int in [l, u] */ break; @@ -16838,7 +16839,7 @@ static int math_random (lua_State *L) { return 1; } - +int randomMT();// twister.c static int math_randomseed (lua_State *L) { srand(luaL_checkunsigned(L, 1)); (void)randomMT(); /* discard first value to avoid undesirable correlations */ @@ -17190,7 +17191,7 @@ static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { return 0; /* no errors */ } else { - lua_CFunction f = ll_sym(L, reg, sym); + const lua_CFunction f = ll_sym(L, reg, sym); if (f == NULL) return ERRFUNC; /* unable to find function */ lua_pushcfunction(L, f); /* else create new function */ @@ -17202,7 +17203,7 @@ static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { static int ll_loadlib (lua_State *L) { const char *path = luaL_checkstring(L, 1); const char *init = luaL_checkstring(L, 2); - int stat = ll_loadfunc(L, path, init); + const int stat = ll_loadfunc(L, path, init); if (stat == 0) /* no errors? */ return 1; /* return the loaded function */ else { /* error; error message is on stack top */ @@ -17699,7 +17700,7 @@ LUAMOD_API int luaopen_package (lua_State *L) { static int os_execute (lua_State *L) { const char *cmd = luaL_optstring(L, 1, NULL); - int stat = system(cmd); + const int stat = system(cmd); if (cmd != NULL) return luaL_execresult(L, stat); else { @@ -17814,7 +17815,7 @@ static const char *checkoption (lua_State *L, const char *conv, char *buff) { static int os_date (lua_State *L) { const char *s = luaL_optstring(L, 1, "%c"); - time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL)); + const time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL)); struct tm tmr, *stm; if (*s == '!') { /* UTC? */ stm = l_gmtime(&t, &tmr); @@ -17898,7 +17899,7 @@ static int os_setlocale (lua_State *L) { static const char *const catnames[] = {"all", "collate", "ctype", "monetary", "numeric", "time", NULL}; const char *l = luaL_optstring(L, 1, NULL); - int op = luaL_checkoption(L, 2, "all", catnames); + const int op = luaL_checkoption(L, 2, "all", catnames); lua_pushstring(L, setlocale(cat[op], l)); return 1; } @@ -18057,7 +18058,7 @@ static int str_rep (lua_State *L) { else if (l + lsep < l || l + lsep >= MAXSIZE / n) /* may overflow? */ return luaL_error(L, "resulting string too large"); else { - size_t totallen = n * l + (n - 1) * lsep; + const size_t totallen = n * l + (n - 1) * lsep; luaL_Buffer b; char *p = luaL_buffinitsize(L, &b, totallen); while (n-- > 1) { /* first n-1 copies (followed by separator) */ @@ -18093,12 +18094,12 @@ static int str_byte (lua_State *L) { static int str_char (lua_State *L) { - int n = lua_gettop(L); /* number of arguments */ + const int n = lua_gettop(L); /* number of arguments */ int i; luaL_Buffer b; char *p = luaL_buffinitsize(L, &b, n); for (i=1; i<=n; i++) { - int c = luaL_checkint(L, i); + const int c = luaL_checkint(L, i); luaL_argcheck(L, uchar(c) == c, i, "value out of range"); p[i - 1] = uchar(c); } @@ -18257,8 +18258,8 @@ static const char *matchbalance (MatchState *ms, const char *s, "(missing arguments to " LUA_QL("%%b") ")"); if (*s != *p) return NULL; else { - int b = *p; - int e = *(p+1); + const int b = *p; + const int e = *(p+1); int cont = 1; while (++s < ms->src_end) { if (*s == e) { @@ -18302,7 +18303,7 @@ static const char *min_expand (MatchState *ms, const char *s, static const char *start_capture (MatchState *ms, const char *s, const char *p, int what) { const char *res; - int level = ms->level; + const int level = ms->level; if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); ms->capture[level].init = s; ms->capture[level].len = what; @@ -18315,7 +18316,7 @@ static const char *start_capture (MatchState *ms, const char *s, static const char *end_capture (MatchState *ms, const char *s, const char *p) { - int l = capture_to_close(ms); + const int l = capture_to_close(ms); const char *res; ms->capture[l].len = s - ms->capture[l].init; /* close capture */ if ((res = match(ms, s, p)) == NULL) /* match failed? */ @@ -18385,7 +18386,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) { } default: dflt: { /* pattern class plus optional suffix */ const char *ep = classend(ms, p); /* points to what is next */ - int m = s < ms->src_end && singlematch(uchar(*s), p, ep); + const int m = s < ms->src_end && singlematch(uchar(*s), p, ep); switch (*ep) { case '?': { /* optional */ const char *res; @@ -18444,7 +18445,7 @@ static void push_onecapture (MatchState *ms, int i, const char *s, luaL_error(ms->L, "invalid capture index"); } else { - ptrdiff_t l = ms->capture[i].len; + const ptrdiff_t l = ms->capture[i].len; if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); if (l == CAP_POSITION) lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1); @@ -18456,7 +18457,7 @@ static void push_onecapture (MatchState *ms, int i, const char *s, static int push_captures (MatchState *ms, const char *s, const char *e) { int i; - int nlevels = (ms->level == 0 && s) ? 1 : ms->level; + const int nlevels = (ms->level == 0 && s) ? 1 : ms->level; luaL_checkstack(ms->L, nlevels, "too many captures"); for (i = 0; i < nlevels; i++) push_onecapture(ms, i, s, e); @@ -18499,7 +18500,7 @@ static int str_find_aux (lua_State *L, int find) { else { MatchState ms; const char *s1 = s + init - 1; - int anchor = (*p == '^'); + const int anchor = (*p == '^'); if (anchor) { p++; lp--; /* skip anchor character */ } @@ -18634,9 +18635,9 @@ static int str_gsub (lua_State *L) { size_t srcl, lp; const char *src = luaL_checklstring(L, 1, &srcl); const char *p = luaL_checklstring(L, 2, &lp); - int tr = lua_type(L, 3); - size_t max_s = luaL_optinteger(L, 4, srcl+1); - int anchor = (*p == '^'); + const int tr = lua_type(L, 3); + const size_t max_s = luaL_optinteger(L, 4, srcl+1); + const int anchor = (*p == '^'); size_t n = 0; MatchState ms; luaL_Buffer b; @@ -18776,9 +18777,9 @@ static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { ** add length modifier into formats */ static void addlenmod (char *form, const char *lenmod) { - size_t l = strlen(form); - size_t lm = strlen(lenmod); - char spec = form[l - 1]; + const size_t l = strlen(form); + const size_t lm = strlen(lenmod); + const char spec = form[l - 1]; strcpy(form + l - 1, lenmod); form[l + lm - 1] = spec; form[l + lm] = '\0'; @@ -18786,7 +18787,7 @@ static void addlenmod (char *form, const char *lenmod) { static int str_format (lua_State *L) { - int top = lua_gettop(L); + const int top = lua_gettop(L); int arg = 1; size_t sfl; const char *strfrmt = luaL_checklstring(L, arg, &sfl); @@ -18811,9 +18812,9 @@ static int str_format (lua_State *L) { break; } case 'd': case 'i': { - lua_Number n = luaL_checknumber(L, arg); + const lua_Number n = luaL_checknumber(L, arg); LUA_INTFRM_T ni = (LUA_INTFRM_T)n; - lua_Number diff = n - (lua_Number)ni; + const lua_Number diff = n - (lua_Number)ni; luaL_argcheck(L, -1 < diff && diff < 1, arg, "not a number in proper range"); addlenmod(form, LUA_INTFRMLEN); @@ -18821,9 +18822,9 @@ static int str_format (lua_State *L) { break; } case 'o': case 'u': case 'x': case 'X': { - lua_Number n = luaL_checknumber(L, arg); - unsigned LUA_INTFRM_T ni = (unsigned LUA_INTFRM_T)n; - lua_Number diff = n - (lua_Number)ni; + const lua_Number n = luaL_checknumber(L, arg); + const unsigned LUA_INTFRM_T ni = (unsigned LUA_INTFRM_T)n; + const lua_Number diff = n - (lua_Number)ni; luaL_argcheck(L, -1 < diff && diff < 1, arg, "not a non-negative number in proper range"); addlenmod(form, LUA_INTFRMLEN); @@ -18981,7 +18982,7 @@ static int tinsert (lua_State *L) { static int tremove (lua_State *L) { - int e = aux_getn(L, 1); + const int e = aux_getn(L, 1); int pos = luaL_optint(L, 2, e); if (!(1 <= pos && pos <= e)) /* position is outside bounds? */ return 0; /* nothing to remove */ @@ -19032,7 +19033,7 @@ static int tconcat (lua_State *L) { */ static int pack (lua_State *L) { - int n = lua_gettop(L); /* number of elements to pack */ + const int n = lua_gettop(L); /* number of elements to pack */ lua_createtable(L, n, 1); /* create result table */ lua_pushinteger(L, n); lua_setfield(L, -2, "n"); /* t.n = number of elements */ @@ -19160,7 +19161,7 @@ static void auxsort (lua_State *L, int l, int u) { } static int sort (lua_State *L) { - int n = aux_getn(L, 1); + const int n = aux_getn(L, 1); luaL_checkstack(L, 40, ""); /* assume array is smaller than 2^40 */ if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ luaL_checktype(L, 2, LUA_TFUNCTION); diff --git a/src/menus/ally.c b/src/menus/ally.c index da2e002a..6d0051d8 100644 --- a/src/menus/ally.c +++ b/src/menus/ally.c @@ -22,7 +22,7 @@ int team_colors[] = int GetTeamColor (int teamnum) { - int index = teamnum - 100; + const int index = teamnum - 100; if (index < 10) return team_colors[index]; @@ -117,7 +117,7 @@ qboolean CanAlly (edict_t *ent, edict_t *other, int range) // only allow allies that are close in level // FIXME: we should get an average or median player level if there are >1 allies - if (fabsf(ent->myskills.level - other->myskills.level) > ALLY_MAX_LEVEL_DELTA) + if (abs(ent->myskills.level - other->myskills.level) > ALLY_MAX_LEVEL_DELTA) { //gi.dprintf("no3\n"); return false; @@ -412,7 +412,7 @@ void AllyID (edict_t *ent) { vec3_t forward, right, offset, start, end; trace_t tr; - edict_t *e=NULL; + const edict_t *e=NULL; if (!allies->value) return; @@ -509,7 +509,7 @@ void ShowAllyInviteMenu_handler (edict_t *ent, int option) void ShowAllyInviteMenu (edict_t *ent) { - edict_t *e = ent->client->allytarget; + const edict_t *e = ent->client->allytarget; if (!menu_can_show(ent)) return; diff --git a/src/menus/armory.c b/src/menus/armory.c index 3f8cde42..764c38af 100644 --- a/src/menus/armory.c +++ b/src/menus/armory.c @@ -89,8 +89,8 @@ void GiveRuneToArmory(item_t *rune) { armoryRune_t *firstItem; item_t *slot; - int type = rune->itemtype; - int newPrice = getBuyValue(rune); + const int type = rune->itemtype; + const int newPrice = getBuyValue(rune); int i; //discard the rune if it's worthless @@ -201,8 +201,8 @@ void armoryConfirmOption(edict_t *ent, int selection) void Cmd_Armory_f(edict_t *ent, int selection) { - int cur_credits=ent->myskills.credits; - gitem_t *item = 0; + const int cur_credits=ent->myskills.credits; + const gitem_t *item = 0; int price = 0; int qty = 0; item_t *slot; @@ -479,7 +479,7 @@ void Cmd_Armory_f(edict_t *ent, int selection) void PurchaseMenu_handler (edict_t *ent, int option) { int page_num = (option / 1000); - int page_choice = (option % 1000); + const int page_choice = (option % 1000); if ((page_num == 1) && (page_choice == 1)) { @@ -582,7 +582,7 @@ void vrx_reapply_items(edict_t *ent) { } int vrx_sell_item(edict_t *ent, item_t* slot) { - int value = GetSellValue(slot); + const int value = GetSellValue(slot); int wpts, apts, total_pts; wpts = V_GetRuneWeaponPts(ent, slot); @@ -609,7 +609,7 @@ void SellConfirmMenu_handler(edict_t *ent, int option) item_t *slot = &ent->myskills.items[option - 778]; //log the sale - int value = vrx_sell_item(ent, slot); + const int value = vrx_sell_item(ent, slot); vrx_write_to_logfile(ent, va("Selling rune for %d credits. [%s]", value, slot->id)); safe_cprintf(ent, PRINT_HIGH, "Item Sold for %d credits.\n", value); @@ -719,8 +719,8 @@ void BuyRuneConfirmMenu_handler (edict_t *ent, int option) //Navigating the menu? if (option > 100) { - int page_num = option / 1000; - int selection = (option % 1000)-1; + const int page_num = option / 1000; + const int selection = (option % 1000)-1; item_t *slot = V_FindFreeItemSlot(ent); int cost; @@ -780,8 +780,8 @@ void BuyRuneConfirmMenu_handler (edict_t *ent, int option) } else { - int page_num = option / 10; - int selection = option % 10; + const int page_num = option / 10; + const int selection = option % 10; OpenBuyRuneMenu(ent, page_num, selection); return; @@ -793,8 +793,8 @@ void BuyRuneConfirmMenu_handler (edict_t *ent, int option) void OpenBuyRuneConfirmMenu(edict_t *ent, int option) { - int page_num = option / 1000; - int selection = (option % 1000)-1; + const int page_num = option / 1000; + const int selection = (option % 1000)-1; armoryRune_t *firstItem; item_t *rune; @@ -843,7 +843,7 @@ void OpenBuyRuneConfirmMenu(edict_t *ent, int option) void BuyRuneMenu_handler (edict_t *ent, int option) { int page_num = (option / 10); - int page_choice = (option % 10); + const int page_choice = (option % 10); if (option == 99) { @@ -867,7 +867,7 @@ void BuyRuneMenu_handler (edict_t *ent, int option) //don't cause an invalid item to be selected else { - int selection = (option % 1000); + const int selection = (option % 1000); page_num = option / 1000; if ((selection > ARMORY_MAX_RUNES) || (selection < 1)) @@ -931,8 +931,8 @@ void OpenBuyRuneMenu(edict_t *ent, int page_num, int lastline) item_t *rune = &((firstItem + i)->rune); if (rune->itemtype != ITEM_NONE) { - item_menu_t fmt = vrx_menu_item_display(rune);//, ' '); - lva_result_t txt = lva("%-13.13s %2d/%2d %5d", fmt.str, fmt.num, rune->itemLevel, getBuyValue(rune)); + const item_menu_t fmt = vrx_menu_item_display(rune);//, ' '); + const lva_result_t txt = lva("%-13.13s %2d/%2d %5d", fmt.str, fmt.num, rune->itemLevel, getBuyValue(rune)); menu_add_line(ent, txt.str, (page_num * 1000) + i + 1); } else diff --git a/src/menus/item_menu.c b/src/menus/item_menu.c index 96554f39..586ff75e 100644 --- a/src/menus/item_menu.c +++ b/src/menus/item_menu.c @@ -86,7 +86,7 @@ void StartShowInventoryMenu(edict_t *ent, item_t *item) { //Item's stats switch (type) { case ITEM_WEAPON: { - int wIndex = (item->modifiers[0].index / 100) - 10; + const int wIndex = (item->modifiers[0].index / 100) - 10; menu_add_line(ent, " ", 0); menu_add_line(ent, va(" %s", GetWeaponString(wIndex)), 0); @@ -150,8 +150,8 @@ void StartShowInventoryMenu(edict_t *ent, item_t *item) { } break; case TYPE_WEAPON: { - int wIndex = (item->modifiers[i].index / 100) - 10; - int mIndex = item->modifiers[i].index % 100; + const int wIndex = (item->modifiers[i].index / 100) - 10; + const int mIndex = item->modifiers[i].index % 100; strcpy(buf, GetShortWeaponString(wIndex)); strcat(buf, va(" %s", GetModString(wIndex, mIndex))); @@ -247,7 +247,7 @@ void ShowItemMenu(edict_t *ent, int itemindex) { menu_add_line(ent, "Exit", 666); menu_add_line(ent, " ", 0); - qboolean hasStash = strlen(ent->myskills.owner) > 0 || strlen(ent->myskills.email) > 0; + const qboolean hasStash = strlen(ent->myskills.owner) > 0 || strlen(ent->myskills.email) > 0; if (hasStash && itemindex >= 3) menu_add_line(ent, "Stash this item", 10000 + itemindex); menu_add_line(ent, "Sell this item", 15000 + itemindex); @@ -286,7 +286,7 @@ void ShowInventoryMenu_handler(edict_t *ent, int option) { lva_result_t vrx_get_item_menu_line(item_t* item) { - item_menu_t fmt = vrx_menu_item_display(item);//, ' '); + const item_menu_t fmt = vrx_menu_item_display(item);//, ' '); if (fmt.num >= 0) { char* abbr = ""; if (item->itemtype == ITEM_COMBO) @@ -336,7 +336,7 @@ void ShowInventoryMenu(edict_t *ent, int lastline, qboolean selling) { break; } - lva_result_t s = vrx_get_item_menu_line(item); + const lva_result_t s = vrx_get_item_menu_line(item); menu_add_line(ent, s.str, i + 1); } diff --git a/src/menus/menu.c b/src/menus/menu.c index b250da49..c5e8c601 100644 --- a/src/menus/menu.c +++ b/src/menus/menu.c @@ -22,7 +22,7 @@ void menu_add_line (edict_t *ent, const char *line,int option) ent->client->menustorage.num_of_lines++; // adds to the number of lines that can be seen - size_t size = strlen(line) + 1; + const size_t size = strlen(line) + 1; ent->client->menustorage.messages[ent->client->menustorage.num_of_lines].msg = vrx_malloc (size, TAG_GAME); strcpy(ent->client->menustorage.messages[ent->client->menustorage.num_of_lines].msg, line); ent->client->menustorage.messages[ent->client->menustorage.num_of_lines].option = option; diff --git a/src/menus/trade.c b/src/menus/trade.c index 16c3591d..802e6507 100644 --- a/src/menus/trade.c +++ b/src/menus/trade.c @@ -198,7 +198,7 @@ void TradeFinalMenu_handler(edict_t *ent, int option) else if(option % 10 == 0) { int type; - int itemnumber = (option / 10) - 1; + const int itemnumber = (option / 10) - 1; // GHz START // 3.7 make sure this item is still valid // it is possible the other player somehow unselected it @@ -272,7 +272,7 @@ void TradeFinalMenu(edict_t *ent) item = ent->trade_with->trade_item[i]; if (item != NULL) { - lva_result_t s = vrx_get_item_menu_line(item); + const lva_result_t s = vrx_get_item_menu_line(item); menu_add_line(ent, s.str, (i+1)*10); //10, 20, 30 ++linecount; } diff --git a/src/menus/upgrades.c b/src/menus/upgrades.c index a10bee6f..78419ed4 100644 --- a/src/menus/upgrades.c +++ b/src/menus/upgrades.c @@ -12,13 +12,13 @@ void OpenMultiUpgradeMenu (edict_t *ent, int lastline, int page, int generaltype void upgradeSpecialMenu_handler(edict_t *ent, int option) { int cost = vrx_get_ability_upgrade_cost(option - 1); - int inc_max = ent->myskills.abilities[option - 1].max_level + 1; + const int inc_max = ent->myskills.abilities[option - 1].max_level + 1; qboolean isLimitedMax = true; qboolean doubledcost = false; if (ent->myskills.abilities[option - 1].level == inc_max - 1) // we've reached the limit of this skill { - int hmax = vrx_get_hard_max(option - 1, ent->myskills.abilities[option - 1].general_skill, ent->myskills.class_num); + const int hmax = vrx_get_hard_max(option - 1, ent->myskills.abilities[option - 1].general_skill, ent->myskills.class_num); cost *= 2; doubledcost = true; // we're getting past the max level @@ -85,7 +85,7 @@ void OpenSpecialUpgradeMenu(edict_t *ent, int lastline) for (i = 0; i < MAX_ABILITIES; i++) { upgrade_t *upgrade; - int num = i + 1; + const int num = i + 1; char buffer[30]; upgrade = &ent->myskills.abilities[i]; @@ -217,8 +217,8 @@ void UpgradeAbility(edict_t *ent, int ability_index) { return; } - qboolean below_max = ent->myskills.abilities[ability_index].level < ent->myskills.abilities[ability_index].max_level; - qboolean below_hardmax = ent->myskills.abilities[ability_index].current_level < ent->myskills.abilities[ability_index].hard_max; + const qboolean below_max = ent->myskills.abilities[ability_index].level < ent->myskills.abilities[ability_index].max_level; + const qboolean below_hardmax = ent->myskills.abilities[ability_index].current_level < ent->myskills.abilities[ability_index].hard_max; if (below_max || ent->myskills.administrator > 999) { ent->myskills.speciality_points -= cost; @@ -1055,8 +1055,8 @@ void vrx_open_ability_menu( int last_line, qboolean use_upgrade_line ) { - upgrade_t* ability = &ent->myskills.abilities[ability_index]; - int level = ability->level;//current_level; + const upgrade_t* ability = &ent->myskills.abilities[ability_index]; + const int level = ability->level;//current_level; int lineCount = 7;//12; if (!menu_can_show(ent)) diff --git a/src/menus/v_menu.c b/src/menus/v_menu.c index 806cbca4..61b1f8af 100644 --- a/src/menus/v_menu.c +++ b/src/menus/v_menu.c @@ -293,7 +293,11 @@ void OpenJoinMenu (edict_t *ent) // xxxxxxxxxxxxxxxxxxxxxxxxxxx (max length 27 chars) menu_add_line(ent, "Vortex Revival", MENU_GREEN_CENTERED); - menu_add_line(ent, va("vrxcl v%s", VRX_VERSION), MENU_GREEN_CENTERED); +#ifndef VRX_REPRO + menu_add_line(ent, va("vrx v%s", VRX_VERSION), MENU_GREEN_CENTERED); +#else + menu_add_line(ent, va("vrx-repro v%s", VRX_VERSION), MENU_GREEN_CENTERED); +#endif menu_add_line(ent, "http://q2vortex.com", MENU_WHITE_CENTERED); menu_add_line(ent, " ", 0); menu_add_line(ent, " ", 0); @@ -434,8 +438,8 @@ void OpenRespawnWeapMenu(edict_t *ent) void classmenu_handler (edict_t *ent, int option) { - int page_num = (option / 1000); - int page_choice = (option % 1000); + const int page_num = (option / 1000); + const int page_choice = (option % 1000); int i; if ((page_num == 1) && (page_choice == 1)) @@ -633,7 +637,7 @@ void OpenGeneralMenu (edict_t *ent) else menu_add_line(ent, va("Upgrade talents (%d)", ent->myskills.talents.talentPoints), 3); - int prestigePotential = vrx_prestige_get_upgrade_points(ent->myskills.experience); + const int prestigePotential = vrx_prestige_get_upgrade_points(ent->myskills.experience); if (prestigePotential) menu_add_line(ent, va("Prestige %d (%d)", ent->myskills.prestige.total, prestigePotential), 20); else diff --git a/src/menus/weapon_upgrades.c b/src/menus/weapon_upgrades.c index baf7e262..b70b7b01 100644 --- a/src/menus/weapon_upgrades.c +++ b/src/menus/weapon_upgrades.c @@ -68,8 +68,8 @@ int V_WeaponUpgradeVal(edict_t *ent, int weapnum) void generalWeaponMenu_handler(edict_t *ent, int option) { - int WeaponIndex = (option / 100)-10; - int ModIndex = (option % 100) - 1; + const int WeaponIndex = (option / 100)-10; + const int ModIndex = (option % 100) - 1; //Are we just navigating? if (option == 6666) @@ -80,7 +80,7 @@ void generalWeaponMenu_handler(edict_t *ent, int option) else if (option >= 7777) { if (ent->myskills.class_num != CLASS_KNIGHT) { - int LastWeapon = option - 7777; + const int LastWeapon = option - 7777; OpenWeaponUpgradeMenu(ent, LastWeapon + 1); } else { OpenWeaponUpgradeMenu(ent, 0); @@ -120,8 +120,8 @@ void generalWeaponMenu_handler(edict_t *ent, int option) void OpenGeneralWeaponMenu (edict_t *ent, int lastline) { - int WeaponIndex = (lastline / 100) - 10; - int modIndex = (lastline % 100); + const int WeaponIndex = (lastline / 100) - 10; + const int modIndex = (lastline % 100); int i; if (!menu_can_show(ent)) @@ -169,7 +169,7 @@ void OpenGeneralWeaponMenu (edict_t *ent, int lastline) void weaponmenu_handler (edict_t *ent, int option) { - int weap_num = (option/100)-10; + const int weap_num = (option/100)-10; if (weap_num > MAX_WEAPONS || weap_num < 0) { menu_close(ent, true); @@ -201,14 +201,14 @@ void OpenWeaponUpgradeMenu (edict_t *ent, int lastline) menu_add_line(ent, "want to upgrade:", 0); menu_add_line(ent, " ", 0); - qboolean is_knight = ent->myskills.class_num == CLASS_KNIGHT; + const qboolean is_knight = ent->myskills.class_num == CLASS_KNIGHT; for (i = 0; i < MAX_WEAPONS; ++i) { char weaponString[24]; strcpy(weaponString, GetWeaponString(i)); - qboolean is_sword = !strcmp(weaponString, "Sword"); + const qboolean is_sword = !strcmp(weaponString, "Sword"); padRight(weaponString, 18); if (!is_knight || (is_knight && is_sword)) diff --git a/src/q_shared.h b/src/q_shared.h index ef2461eb..4391f78d 100644 --- a/src/q_shared.h +++ b/src/q_shared.h @@ -1,60 +1,45 @@ - // q_shared.h -- included first by ALL program modules #ifndef Q_SHARED #define Q_SHARED #define __STDC_LIB_EXT1__ 1 +#include + #ifdef _MSC_VER // unknown pragmas are SUPPOSED to be ignored, but.... -#pragma warning(disable : 4244) // MIPS -#pragma warning(disable : 4136) // X86 -#pragma warning(disable : 4051) // ALPHA - #pragma warning(disable : 4018) // signed/unsigned mismatch #pragma warning(disable : 4305) // truncation from const double to float #pragma warning(disable : 4996) // deprecation #endif //K03 Begin -#ifndef __cplusplus #include #include #include -#include #include #include #include #include -#endif //K03 End -#if defined _M_IX86 && !defined C_ONLY -#define id386 1 -#else -#define id386 0 +#ifndef M_PI +#define M_PI 3.14159265358979323846 #endif -#if defined _M_ALPHA && !defined C_ONLY -#define idaxp 1 -#else -#define idaxp 0 -#endif +typedef unsigned char byte; -typedef unsigned char byte; -//k03 Begin -#ifndef __cplusplus -typedef enum { false, true } qboolean; -#else -typedef bool qboolean; -#endif +typedef int32_t qboolean; #define DEG2RAD( a ) ( a * M_PI ) / 180.0F //K03 End -#ifndef NULL -#define NULL ((void *)0) +// for things we need abi compatibility for with the old version of the api +#ifndef VRX_REPRO +typedef qboolean _rebool; +#else +typedef bool _rebool; #endif // angle indexes @@ -64,30 +49,51 @@ typedef bool qboolean; #define MAX_STRING_CHARS 1024 // max length of a string passed to Cmd_TokenizeString #define MAX_STRING_TOKENS 80 // max tokens resulting from Cmd_TokenizeString -#define MAX_TOKEN_CHARS 256 // max length of an individual token +#define MAX_TOKEN_CHARS 512 // max length of an individual token #define MAX_QPATH 64 // max length of a quake game pathname #define MAX_OSPATH 128 // max length of a filesystem pathname +#define MAX_SPLIT_PLAYERS 4 // // per-level limits // #define MAX_CLIENTS 256 // absolute limit +#ifndef VRX_REPRO #define MAX_EDICTS 1024 // must change protocol to increase more -#define MAX_LIGHTSTYLES 256 #define MAX_MODELS 256 // these are sent over the net as bytes #define MAX_SOUNDS 256 // so they cannot be blindly increased #define MAX_IMAGES 256 +#else +#define MAX_EDICTS 8192 +#define MAX_MODELS 8192 +#define MAX_SOUNDS 2048 // so they cannot be blindly increased +#define MAX_IMAGES 512 + +#endif +#define MAX_LIGHTSTYLES 256 #define MAX_ITEMS 256 #define MAX_GENERAL (MAX_CLIENTS*2) // general config strings +#define MAX_SHADOW_LIGHTS 256 -// game print flags -#define PRINT_LOW 0 // pickup messages -#define PRINT_MEDIUM 1 // death messages -#define PRINT_HIGH 2 // critical messages -#define PRINT_CHAT 3 // chat messages +#define U32BIT(x) ((uint32_t)1 << (uint32_t)x) +#define U64BIT(x) ((uint64_t)1 << (uint64_t)x) +// game print flags +enum print_type_t { + PRINT_LOW = 0, // pickup messages + PRINT_MEDIUM = 1, // death messages + PRINT_HIGH = 2, // critical messages + PRINT_CHAT = 3, // chat messages +#ifdef VRX_REPRO + PRINT_TYPEWRITER = 4, // centerpritnt but one char at a time + PRINT_CENTER = 5, // centerprint without a separate function + PRINT_TTS = 6, // PRINT_HIGH but will speak for players with narration on + PRINT_BROADCAST = 1 << 3, // bitflag, add message to broadcast print to all clients + PRINT_NO_NOTIFY = 1 << 4 // bitflag, don't put on notify +#endif +}; #define ERR_FATAL 0 // exit the entire game with a popup window @@ -96,20 +102,44 @@ typedef bool qboolean; #define PRINT_ALL 0 #define PRINT_DEVELOPER 1 // only print when "developer 1" -#define PRINT_ALERT 2 - +#define PRINT_ALERT 2 + +// [Paril-KEX] max number of arguments (not including the base) for +// localization prints +constexpr size_t MAX_LOCALIZATION_ARGS = 8; + +// remaps old configstring IDs to new ones +// for old DLL & demo support +struct configstring_remap_t { + // start position in the configstring list + // to write into + size_t start; + // max length to write into; [start+length-1] should always + // be set to '\0' + size_t length; +}; // destination class for gi.multicast() -typedef enum -{ -MULTICAST_ALL, -MULTICAST_PHS, -MULTICAST_PVS, -MULTICAST_ALL_R, -MULTICAST_PHS_R, -MULTICAST_PVS_R +typedef enum { + MULTICAST_ALL, + MULTICAST_PHS, + MULTICAST_PVS, + MULTICAST_ALL_R, + MULTICAST_PHS_R, + MULTICAST_PVS_R } multicast_t; +// player_state_t->refdef flags +enum refdef_flags_t : uint8_t { + RDF_NONE = 0, + RDF_UNDERWATER = 1, // warp the screen as apropriate + RDF_NOWORLDMODEL = 2, // used for player configuration screen + //ROGUE + RDF_IRGOGGLES = 4, + RDF_UVGOGGLES = 8, + //ROGUE + RDF_NO_WEAPON_LERP = 1 << 4 +}; /* ============================================================== @@ -119,17 +149,43 @@ MATHLIB ============================================================== */ +#ifndef min +#define min(a,b) ((a) > (b) ? (b) : (a)) +#endif +#ifndef max +#define max(a,b) ((a) > (b) ? (a) : (b)) +#endif + typedef float vec_t; typedef vec_t vec3_t[3]; +typedef vec_t vec4_t[4]; typedef vec_t vec5_t[5]; -typedef int fixed4_t; -typedef int fixed8_t; -typedef int fixed16_t; +typedef union { + uint32_t u32; + uint8_t u8[4]; -#ifndef M_PI -#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h -#endif + struct { + uint8_t r, g, b, a; + }; +} color_t; + +typedef union { + struct { + vec_t x, y; + }; + + vec_t v[2]; +} vec2_t; + +typedef color_t rgba_t; +constexpr rgba_t rgba_white = {.r = 255, .g = 255, .b = 255, .a = 255}; +constexpr rgba_t rgba_black = {.r = 0, .g = 0, .b = 0, .a = 255}; +constexpr rgba_t rgba_red = {.r = 255, .g = 0, .b = 0, .a = 255}; +constexpr rgba_t rgba_orange = {.r = 255, .g = 127, .b = 0, .a = 255}; +constexpr rgba_t rgba_green = {.r = 0, .g = 255, .b = 0, .a = 255}; +constexpr rgba_t rgba_darkgreen = {.r = 0, .g = 127, .b = 0, .a = 255}; +constexpr rgba_t rgba_blue = {.r = 0, .g = 0, .b = 255, .a = 255}; struct cplane_s; @@ -140,7 +196,7 @@ extern vec3_t vec3_origin; #define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask) #if !defined C_ONLY -extern long Q_ftol( float f ); +extern long Q_ftol(float f); #else #define Q_ftol( f ) ( long ) (f) #endif @@ -160,46 +216,51 @@ double __fastcall sqrt14(double n); #define VectorNegate(a,b) (b[0]=-a[0],b[1]=-a[1],b[2]=-a[2]) #define VectorSet(v, x, y, z) (v[0]=(x), v[1]=(y), v[2]=(z)) -void VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc); +void VectorMA(vec3_t veca, float scale, vec3_t vecb, vec3_t vecc); // just in case you do't want to use the macros -vec_t _DotProduct (vec3_t v1, vec3_t v2); -void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out); -void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out); -void _VectorCopy (vec3_t in, vec3_t out); +vec_t _DotProduct(vec3_t v1, vec3_t v2); + +void _VectorSubtract(vec3_t veca, vec3_t vecb, vec3_t out); + +void _VectorAdd(vec3_t veca, vec3_t vecb, vec3_t out); + +void _VectorCopy(vec3_t in, vec3_t out); + +void ClearBounds(vec3_t mins, vec3_t maxs); -void ClearBounds (vec3_t mins, vec3_t maxs); -void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs); -int VectorCompare (vec3_t v1, vec3_t v2); -vec_t VectorLength (vec3_t v); +void AddPointToBounds(vec3_t v, vec3_t mins, vec3_t maxs); + +int VectorCompare(vec3_t v1, vec3_t v2); + +vec_t VectorLength(vec3_t v); #if (defined WIN32) && (defined ASMOPT) -__inline vec_t VectorLength(vec3_t v) -{ - float len; - __asm { - fldz - push eax - - mov eax,dword ptr[v] - fld dword ptr[eax] - fmul dword ptr[eax] - - fld dword ptr[eax+4] - fmul dword ptr[eax+4] - faddp st(1),st(0) - fstp st(1) - - fld dword ptr[eax+8] - fmul dword ptr[eax+8] - faddp st(1),st(0) - fstp st(1) - fsqrt - pop eax - fstp dword ptr[len] - } - return len; +__inline vec_t VectorLength(vec3_t v) { + float len; + __asm { + fldz + push eax + + mov eax,dword ptr[v] + fld dword ptr[eax] + fmul dword ptr[eax] + + fld dword ptr[eax+4] + fmul dword ptr[eax+4] + faddp st(1),st(0) + fstp st(1) + + fld dword ptr[eax+8] + fmul dword ptr[eax+8] + faddp st(1),st(0) + fstp st(1) + fsqrt + pop eax + fstp dword ptr[len] + } + return len; } #else vec_t VectorLength(vec3_t v); @@ -207,20 +268,28 @@ vec_t VectorLength(vec3_t v); vec_t VectorLengthSqr(vec3_t v); -void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross); -vec_t VectorNormalize (vec3_t v); // returns vector length -vec_t VectorNormalize2 (vec3_t v, vec3_t out); -void VectorInverse (vec3_t v); -void VectorScale (vec3_t in, vec_t scale, vec3_t out); +void CrossProduct(vec3_t v1, vec3_t v2, vec3_t cross); + +vec_t VectorNormalize(vec3_t v); // returns vector length +vec_t VectorNormalize2(vec3_t v, vec3_t out); + +void VectorInverse(vec3_t v); + +void VectorScale(vec3_t in, vec_t scale, vec3_t out); + int Q_log2(int val); -void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]); -void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]); +void R_ConcatRotations(float in1[3][3], float in2[3][3], float out[3][3]); + +void R_ConcatTransforms(float in1[3][4], float in2[3][4], float out[3][4]); + +void AngleVectors(vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); + +int BoxOnPlaneSide(vec3_t emins, vec3_t emaxs, struct cplane_s *plane); -void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); -int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *plane); -float anglemod(float a); -float LerpAngle (float a1, float a2, float frac); +float anglemod(float a); + +float LerpAngle(float a1, float a2, float frac); #define BOX_ON_PLANE_SIDE(emins, emaxs, p) \ (((p)->type < 3)? \ @@ -238,44 +307,61 @@ float LerpAngle (float a1, float a2, float frac); : \ BoxOnPlaneSide( (emins), (emaxs), (p))) -void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal ); -void PerpendicularVector( vec3_t dst, const vec3_t src ); -void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees ); +void ProjectPointOnPlane(vec3_t dst, const vec3_t p, const vec3_t normal); + +void PerpendicularVector(vec3_t dst, const vec3_t src); + +void RotatePointAroundVector(vec3_t dst, const vec3_t dir, const vec3_t point, float degrees); //============================================= -char *COM_SkipPath (char *pathname); -void COM_StripExtension (char *in, char *out); -void COM_FileBase (char *in, char *out); -void COM_FilePath (char *in, char *out); -void COM_DefaultExtension (char *path, char *extension); +char *COM_SkipPath(char *pathname); + +void COM_StripExtension(char *in, char *out); + +void COM_FileBase(char *in, char *out); + +void COM_FilePath(char *in, char *out); + +void COM_DefaultExtension(char *path, char *extension); + +char *COM_Parse(const char **data_p); -char *COM_Parse (const char **data_p); // data is an in/out parm, returns a parsed out token -void Com_sprintf (char *dest, int size, char *fmt, ...); +void Com_sprintf(char *dest, int size, char *fmt, ...); -void Com_PageInMemory (const byte *buffer, int size); +void Com_PageInMemory(const byte *buffer, int size); //============================================= // portable case insensitive compare -int Q_stricmp (char *s1, char *s2); -int Q_strcasecmp (const char *s1, const char *s2); -int Q_strncasecmp (const char *s1, const char *s2, int n); +int Q_stricmp(char *s1, char *s2); + +int Q_strcasecmp(const char *s1, const char *s2); + +int Q_strncasecmp(const char *s1, const char *s2, int n); + +size_t Q_strlcpy(char *dst, const char *src, size_t siz); //============================================= -short BigShort(short l); -short LittleShort(short l); -int BigLong (int l); -int LittleLong (int l); -float BigFloat (float l); -float LittleFloat (float l); +short BigShort(short l); + +short LittleShort(short l); + +int BigLong(int l); + +int LittleLong(int l); + +float BigFloat(float l); + +float LittleFloat(float l); -void Swap_Init (void); -char *va(const char *format, ...); +void Swap_Init(void); + +char *va(const char *format, ...); //============================================= @@ -283,13 +369,24 @@ char *va(const char *format, ...); // key / value info strings // #define MAX_INFO_KEY 64 + +#ifndef VRX_REPRO #define MAX_INFO_VALUE 64 #define MAX_INFO_STRING 512 +#else +#define MAX_INFO_VALUE 256 +#define MAX_INFO_STRING 2048 +#endif + +#define MAX_WHEEL_ITEMS 32 + +char *Info_ValueForKey(char *s, char *key); + +void Info_RemoveKey(char *s, const char *key); -char *Info_ValueForKey (char *s, char *key); -void Info_RemoveKey (char *s, const char *key); -void Info_SetValueForKey (char *s, char *key, char *value); -qboolean Info_Validate (char *s); +void Info_SetValueForKey(char *s, char *key, char *value); + +qboolean Info_Validate(char *s); /* ============================================================== @@ -299,16 +396,20 @@ SYSTEM SPECIFIC ============================================================== */ -extern int curtime; // time returned by last Sys_Milliseconds +extern int curtime; // time returned by last Sys_Milliseconds + +int Sys_Milliseconds(void); -int Sys_Milliseconds (void); -void Sys_Mkdir (char *path); +void Sys_Mkdir(char *path); // large block stack allocation routines -void *Hunk_Begin (int maxsize); -void *Hunk_Alloc (int size); -void Hunk_Free (void *buf); -int Hunk_End (void); +void *Hunk_Begin(int maxsize); + +void *Hunk_Alloc(int size); + +void Hunk_Free(void *buf); + +int Hunk_End(void); // directory searching #define SFF_ARCH 0x01 @@ -320,14 +421,14 @@ int Hunk_End (void); /* ** pass in an attribute mask of things you wish to REJECT */ -char *Sys_FindFirst (char *path, unsigned musthave, unsigned canthave ); -char *Sys_FindNext ( unsigned musthave, unsigned canthave ); -void Sys_FindClose (void); +char *Sys_FindFirst(char *path, unsigned musthave, unsigned canthave); + +char *Sys_FindNext(unsigned musthave, unsigned canthave); + +void Sys_FindClose(void); -// this is only here so the functions in q_shared.c and q_shwin.c can link -void Sys_Error (char *error, ...); -void Com_Printf (char *msg, ...); +void Com_Printf(const char *msg, ...); /* @@ -341,23 +442,37 @@ CVARS (console variables) #ifndef CVAR #define CVAR -#define CVAR_ARCHIVE 1 // set to cause it to be saved to vars.rc -#define CVAR_USERINFO 2 // added to userinfo when changed -#define CVAR_SERVERINFO 4 // added to serverinfo when changed -#define CVAR_NOSET 8 // don't allow change from console at all, - // but can be set from the command line -#define CVAR_LATCH 16 // save changes until server restart +enum cvar_flags_t { + CVAR_NOFLAGS = 0, + CVAR_ARCHIVE = 1, // set to cause it to be saved to vars.rc + CVAR_USERINFO = 2, // added to userinfo when changed + CVAR_SERVERINFO = 4, // added to serverinfo when changed + CVAR_NOSET = 8, // don't allow change from console at all, + // but can be set from the command line + CVAR_LATCH = 16, // save changes until server restart +#ifdef VRX_REPRO + CVAR_USER_PROFILE = 32 // like cvar_userinfo but not sent to server +#endif +}; + +struct edict_t; // nothing outside the Cvar_*() functions should modify these fields! -typedef struct cvar_s -{ - char *name; - char *string; - char *latched_string; // for CVAR_LATCH vars - int flags; - qboolean modified; // set each time the cvar is changed - float value; - struct cvar_s *next; +typedef struct cvar_s { + char *name; + char *string; + char *latched_string; // for CVAR_LATCH vars + int flags; +#if VRX_REPRO + int32_t modified_count; // set each time the cvar is changed but never zero +#else + qboolean modified; // set each time the cvar is changed +#endif + float value; + struct cvar_s *next; +#if VRX_REPRO + int32_t integer; // integral value +#endif } cvar_t; #endif // CVAR @@ -371,51 +486,60 @@ COLLISION DETECTION */ // lower bits are stronger, and will eat weaker brushes completely -#define CONTENTS_SOLID 1 // an eye is never valid in a solid -#define CONTENTS_WINDOW 2 // translucent, but not watery -#define CONTENTS_AUX 4 -#define CONTENTS_LAVA 8 -#define CONTENTS_SLIME 16 -#define CONTENTS_WATER 32 -#define CONTENTS_MIST 64 -#define LAST_VISIBLE_CONTENTS 64 - -// remaining contents are non-visible, and don't eat brushes - -#define CONTENTS_AREAPORTAL 0x8000 - -#define CONTENTS_PLAYERCLIP 0x10000 -#define CONTENTS_MONSTERCLIP 0x20000 - -// currents can be added to any other contents, and may be mixed -#define CONTENTS_CURRENT_0 0x40000 -#define CONTENTS_CURRENT_90 0x80000 -#define CONTENTS_CURRENT_180 0x100000 -#define CONTENTS_CURRENT_270 0x200000 -#define CONTENTS_CURRENT_UP 0x400000 -#define CONTENTS_CURRENT_DOWN 0x800000 - -#define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity - -#define CONTENTS_MONSTER 0x2000000 // should never be on a brush, only in game -#define CONTENTS_DEADMONSTER 0x4000000 -#define CONTENTS_DETAIL 0x8000000 // brushes to be added after vis leafs -#define CONTENTS_TRANSLUCENT 0x10000000 // auto set if any surface has trans -#define CONTENTS_LADDER 0x20000000 - - - -#define SURF_LIGHT 0x1 // value will hold the light strength - -#define SURF_SLICK 0x2 // effects game physics - -#define SURF_SKY 0x4 // don't draw, but add to skybox -#define SURF_WARP 0x8 // turbulent water warp -#define SURF_TRANS33 0x10 -#define SURF_TRANS66 0x20 -#define SURF_FLOWING 0x40 // scroll towards angle -#define SURF_NODRAW 0x80 // don't bother referencing the texture - +enum contents_t : uint32_t { + CONTENTS_NONE = 0, + CONTENTS_SOLID = 1, // an eye is never valid in a solid + CONTENTS_WINDOW = 2, // translucent, but not watery + CONTENTS_AUX = 4, + CONTENTS_LAVA = 8, + CONTENTS_SLIME = 16, + CONTENTS_WATER = 32, + CONTENTS_MIST = 64, + +#ifdef VRX_REPRO + CONTENTS_NO_WATERJUMP = U64BIT(13), + CONTENTS_PROJECTILECLIP = U64BIT(14), + CONTENTS_AREAPROTAL = U64BIT(15), + CONTENTS_PLAYERCLIP = U64BIT(16), + CONTENTS_MONSTERCLIP = U64BIT(17), + + CONTENTS_CURRENT_0 = U64BIT(18), + CONTENTS_CURRENT_90 = U64BIT(19), + CONTENTS_CURRENT_180 = U64BIT(20), + CONTENTS_CURRENT_270 = U64BIT(21), + CONTENT_CURRENTS_UP = U64BIT(22), + CONTENT_CURRENTS_DOWN = U64BIT(23), + + CONTENTS_ORIGIN = U64BIT(24), // removed before bsping an entity + + CONTENTS_MONSTER = U64BIT(25), + CONTENTS_DEADMONSTER = U64BIT(26), + CONTENTS_DETAIL = U64BIT(27), + CONTENTS_TRANSLUCENT = U64BIT(28), + CONTENTS_LADDER = U64BIT(29), + CONTENTS_PLAYER = U64BIT(30), + CONTENTS_PROJECTILE = U64BIT(31) +#endif +}; + +enum surfflags_t : uint32_t { + SURF_LIGHT = 1 << 0, // value will hold the light strength + SURF_SLICK = 1 << 1, // effects game physics + SURF_SKY = 1 << 2, // don't draw, but add to skybox + SURF_WARP = 1 << 3, // turbulent water warp + SURF_TRANS33 = 1 << 4, + SURF_TRANS66 = 1 << 5, + SURF_FLOWING = 1 << 6, // scroll towards angle + SURF_NODRAW = 1 << 7, // don't bother referencing the texture + +#ifdef VRX_REPRO + SURF_ALPHATEST = 1 << 25, // [Paril-KEX] alpha test using widely supported flag + SURF_N64_UV = U32BIT(28), // [Sam-KEX] Stretches texture UVs + SURF_N64_SCROLL_X = U32BIT(29), // [Sam-KEX] Texture scroll X-axis + SURF_N64_SCROLL_Y = U32BIT(30), // [Sam-KEX] Texture scroll Y-axis + SURF_N64_SCROLL_FLIP = U32BIT(31) // [Sam-KEX] Flip direction of texture scroll +#endif +}; // content masks @@ -434,19 +558,19 @@ COLLISION DETECTION // gi.BoxEdicts() can return a list of either solid or trigger entities // FIXME: eliminate AREA_ distinction? -#define AREA_SOLID 1 -#define AREA_TRIGGERS 2 - +enum solidity_area_t { + AREA_SOLID = 1, + AREA_TRIGGERS = 2 +}; // plane_t structure // !!! if this is changed, it must be changed in asm code too !!! -typedef struct cplane_s -{ - vec3_t normal; - float dist; - byte type; // for fast side tests - byte signbits; // signx + (signy<<1) + (signz<<1) - byte pad[2]; +typedef struct cplane_s { + vec3_t normal; + float dist; + byte type; // for fast side tests + byte signbits; // signx + (signy<<1) + (signz<<1) + byte pad[2]; } cplane_t; // structure offset for asm code @@ -459,128 +583,250 @@ typedef struct cplane_s #define CPLANE_PAD0 18 #define CPLANE_PAD1 19 -typedef struct cmodel_s -{ - vec3_t mins, maxs; - vec3_t origin; // for sounds or lights - int headnode; +typedef struct cmodel_s { + vec3_t mins, maxs; + vec3_t origin; // for sounds or lights + int headnode; } cmodel_t; -typedef struct csurface_s -{ - char name[16]; - int flags; - int value; -} csurface_t; +// [Paril-KEX] +#define MAX_MATERIAL_NAME 16 -typedef struct mapsurface_s // used internally due to name len probs //ZOID -{ - csurface_t c; - char rname[32]; -} mapsurface_t; +typedef struct csurface_s { +#ifndef VRX_REPRO + char name[16]; +#else + char name[32]; +#endif + int32_t flags; // surfflags_t + int32_t value; + +#ifdef VRX_REPRO + // [Paril-KEX] + uint32_t id; // unique texinfo ID, offset by 1 (0 is 'null') + char material[MAX_MATERIAL_NAME]; +#endif +} csurface_t; // a trace is returned when a box is swept through the world -typedef struct -{ - 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 - csurface_t *surface; // surface hit - int contents; // contents on other side of surface hit - struct edict_s *ent; // not set by CM_*() functions +typedef struct { +#ifndef VRX_REPRO + 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 + csurface_t *surface; // surface hit + int contents; // contents on other side of surface hit + struct edict_s *ent; // not set by CM_*() functions +#else + byte allsolid; // if true, plane is not valid + byte 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 + csurface_t *surface; // surface hit + enum contents_t contents; // contents on other side of surface hit (contents_t) + struct edict_s *ent; // not set by CM_*() functions + + // [Paril-KEX] the second-best surface hit from a trace + cplane_t plane2; // second surface normal at impact + csurface_t *surface2; // second surface hit +#endif } trace_t; - // pmove_state_t is the information necessary for client side movement // prediction -typedef enum -{ - // can accelerate and turn - PM_NORMAL, - PM_SPECTATOR, - // no acceleration or turning - PM_DEAD, - PM_GIB, // different bounding box - PM_FREEZE +typedef enum { + // can accelerate and turn + PM_NORMAL, +#ifdef VRX_REPRO + PM_GRAPPLE, + PM_NOCLIP, +#endif + PM_SPECTATOR, + // no acceleration or turning + PM_DEAD, + PM_GIB, // different bounding box + PM_FREEZE } pmtype_t; // pmove->pm_flags -#define PMF_DUCKED 1 -#define PMF_JUMP_HELD 2 -#define PMF_ON_GROUND 4 -#define PMF_TIME_WATERJUMP 8 // pm_time is waterjump -#define PMF_TIME_LAND 16 // pm_time is time before rejump -#define PMF_TIME_TELEPORT 32 // pm_time is non-moving time -#define PMF_NO_PREDICTION 64 // temporarily disables prediction (used for grappling hook) +enum pmflags_t : uint16_t { + PMF_NONE = 0, +#ifndef VRX_REPRO + PMF_DUCKED = 1, + PMF_JUMP_HELD = 2, + PMF_ON_GROUND = 4, + PMF_TIME_WATERJUMP = 8, // pm_time is waterjump + PMF_TIME_LAND = 16, // pm_time is time before rejump + PMF_TIME_TELEPORT = 32, // pm_time is non-moving time + PMF_NO_PREDICTION = 64, // temporarily disables prediction (used for grappling hook) +#else + PMF_DUCKED = 1 << 0, + PMF_JUMP_HELD = 1 << 1, + PMF_ON_GROUND = 1 << 2, + PMF_TIME_WATERJUMP = 1 << 3, // pm_time is waterjump + PMF_TIME_LAND = 1 << 4, // pm_time is time before rejump + PMF_TIME_TELEPORT = 1 << 5, // pm_time is non-moving time + PMF_NO_POSITIONAL_PREDICTION = 1 << 6, // temporarily disables positional prediction (used for grappling hook) + PMF_ON_LADDER = 1 << 7, // signal to game that we are on a ladder + PMF_NO_ANGULAR_PREDICTION = 1 << 8, // temporary disables angular prediction + PMF_IGNORE_PLAYER_COLLISION = 1 << 9, // don't collide with other players + PMF_TIME_TRICK = 1 << 10, // pm_time is trick jump time + PMF_CACODEMON = 1 << 11, // do not apply gravity on upmove + PMF_NOCROUCH = 1 << 12, // We can't actually crouch in this shape. + PMF_SUPERSPEED = 1 << 13, + PMF_NO_PREDICTION = PMF_NO_ANGULAR_PREDICTION | PMF_NO_POSITIONAL_PREDICTION +#endif +}; // this structure needs to be communicated bit-accurate // from the server to the client to guarantee that // prediction stays in sync, so no floats are used. // if any part of the game code modifies this struct, it // will result in a prediction error of some degree. -typedef struct -{ - pmtype_t pm_type; - - short origin[3]; // 12.3 - short velocity[3]; // 12.3 - byte pm_flags; // ducked, jump_held, etc - byte pm_time; // each unit = 8 ms - short gravity; - short delta_angles[3]; // add to command angles to get view direction - // changed by spawns, rotating objects, and teleporters + +#ifndef VRX_REPRO +typedef struct { + pmtype_t pm_type; + + short origin[3]; // 12.3 + short velocity[3]; // 12.3 + byte pm_flags; // ducked, jump_held, etc + byte pm_time; // each unit = 8 ms + short gravity; + short delta_angles[3]; // add to command angles to get view direction + // changed by spawns, rotating objects, and teleporters } pmove_state_t; +#else +typedef struct pmove_state_s { + pmtype_t pm_type; + vec3_t origin; + vec3_t velocity; + enum pmflags_t pm_flags; + + uint16_t pm_time; + int16_t gravity; + vec3_t delta_angles; + + int8_t viewheight; +} pmove_state_t; +#endif // // button bits // -#define BUTTON_ATTACK 1 -#define BUTTON_USE 2 -#define BUTTON_ANY 128 // any key whatsoever +enum button_t : uint8_t { + BUTTON_NONE = 0, + BUTTON_ATTACK = 1 << 0, + BUTTON_USE = 1 << 1, + BUTTON_HOLSTER = 1 << 2, // [Paril-KEX] + BUTTON_JUMP = 1 << 3, + BUTTON_CROUCH = 1 << 4, + BUTTON_ANY = 1 << 7 // any key whatsoever +}; // usercmd_t is sent to the server each client frame -typedef struct usercmd_s -{ - byte msec; - byte buttons; - short angles[3]; - short forwardmove, sidemove, upmove; - byte impulse; // remove? - byte lightlevel; // light level the player is standing on +typedef struct usercmd_s { +#ifndef VRX_REPRO + byte msec; + enum button_t buttons; + short angles[3]; + short forwardmove, sidemove, upmove; + byte impulse; // remove? + byte lightlevel; // light level the player is standing on +#else + byte msec; + enum button_t buttons; + vec3_t angles; + float forwardmove, sidemove; + uint32_t server_frame; +#endif } usercmd_t; +bool cmd_jumping(usercmd_t *cmd); +bool cmd_ducking(usercmd_t *cmd); +bool cmd_standing(usercmd_t *cmd); +void cmd_jump(usercmd_t *cmd); +void cmd_duck(usercmd_t *cmd); +void cmd_stand(usercmd_t *cmd); #define MAXTOUCH 32 -typedef struct -{ - // state (in / out) - pmove_state_t s; - - // command (in) - usercmd_t cmd; - qboolean snapinitial; // if s has been changed outside pmove - // results (out) - int numtouch; - struct edict_s *touchents[MAXTOUCH]; +// [Paril-KEX] generic touch list; used for contact entities +typedef struct touch_list_s +{ + size_t num; + trace_t traces[MAXTOUCH]; +} touch_list_t; + +typedef struct { + // state (in / out) + pmove_state_t s; + + // command (in) + usercmd_t cmd; + _rebool snapinitial; // if s has been changed outside pmove + + // results (out) +#ifndef VRX_REPRO + int numtouch; + struct edict_s *touchents[MAXTOUCH]; +#else + struct touch_list_s touch; +#endif + vec3_t viewangles; // clamped +#ifndef VRX_REPRO + float viewheight; +#endif - vec3_t viewangles; // clamped - float viewheight; + vec3_t mins, maxs; // bounding box size - vec3_t mins, maxs; // bounding box size + struct edict_s *groundentity; +#ifdef VRX_REPRO + cplane_t groundplane; +#endif - struct edict_s *groundentity; - int watertype; - int waterlevel; + enum contents_t watertype; + int waterlevel; - // callbacks to test the world - trace_t (*trace) (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end); - int (*pointcontents) (vec3_t point); +#ifndef VRX_REPRO + // callbacks to test the world + trace_t (*trace)(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end); + int (*pointcontents)(vec3_t point); +#else + struct edict_s *player; // edict_t + + // clip against world & entities + trace_t (*trace)( + vec3_t start, + const vec3_t *mins, + const vec3_t *maxs, + vec3_t end, + const struct edict_s *passent, + enum contents_t contentmask); + + // [Paril-KEX] clip against world only + trace_t (*clip)( + vec3_t start, + vec3_t *mins, + vec3_t *maxs, + vec3_t end, + enum contents_t contentmask); + + int (*pointcontents)(vec3_t point); + vec3_t viewoffset; + + vec4_t screen_blend; + enum refdef_flags_t rdflags; + _rebool jump_sound; + _rebool step_clip; + float impact_delta; +#endif } pmove_t; @@ -589,350 +835,492 @@ typedef struct // that happen constantly on the given entity. // An entity that has effects will be sent to the client // even if it has a zero index model. -#define EF_ROTATE 0x00000001 // rotate (bonus items) -#define EF_GIB 0x00000002 // leave a trail -#define EF_BLASTER 0x00000008 // redlight + trail -#define EF_ROCKET 0x00000010 // redlight + trail -#define EF_GRENADE 0x00000020 -#define EF_HYPERBLASTER 0x00000040 -#define EF_BFG 0x00000080 -#define EF_COLOR_SHELL 0x00000100 -#define EF_POWERSCREEN 0x00000200 -#define EF_ANIM01 0x00000400 // automatically cycle between frames 0 and 1 at 2 hz -#define EF_ANIM23 0x00000800 // automatically cycle between frames 2 and 3 at 2 hz -#define EF_ANIM_ALL 0x00001000 // automatically cycle through all frames at 2hz -#define EF_ANIM_ALLFAST 0x00002000 // automatically cycle through all frames at 10hz -#define EF_FLIES 0x00004000 -#define EF_QUAD 0x00008000 -#define EF_PENT 0x00010000 -#define EF_TELEPORTER 0x00020000 // particle fountain -#define EF_FLAG1 0x00040000 -#define EF_FLAG2 0x00080000 -// RAFAEL -#define EF_IONRIPPER 0x00100000 -#define EF_GREENGIB 0x00200000 -#define EF_BLUEHYPERBLASTER 0x00400000 -#define EF_SPINNINGLIGHTS 0x00800000 -#define EF_PLASMA 0x01000000 -#define EF_TRAP 0x02000000 - -//ROGUE -#define EF_TRACKER 0x04000000 -#define EF_DOUBLE 0x08000000 -#define EF_SPHERETRANS 0x10000000 -#define EF_TAGTRAIL 0x20000000 -#define EF_HALF_DAMAGE 0x40000000 -#define EF_TRACKERTRAIL 0x80000000 -//ROGUE +enum effects_t : +#ifndef VRX_REPRO + int +#else + uint64_t +#endif +{ + EF_ROTATE = 0x00000001, // rotate (bonus items) + EF_GIB = 0x00000002, // leave a trail +#ifdef VRX_REPRO + EF_BOB = 1 << 2, // bob +#endif + EF_BLASTER = 0x00000008, // redlight + trail + EF_ROCKET = 0x00000010, // redlight + trail + EF_GRENADE = 0x00000020, + EF_HYPERBLASTER = 0x00000040, + EF_BFG = 0x00000080, + EF_COLOR_SHELL = 0x00000100, + EF_POWERSCREEN = 0x00000200, + EF_ANIM01 = 0x00000400, // automatically cycle between frames 0 and 1 at 2 hz + EF_ANIM23 = 0x00000800, // automatically cycle between frames 2 and 3 at 2 hz + EF_ANIM_ALL = 0x00001000, // automatically cycle through all frames at 2hz + EF_ANIM_ALLFAST = 0x00002000, // automatically cycle through all frames at 10hz + EF_FLIES = 0x00004000, + EF_QUAD = 0x00008000, + EF_PENT = 0x00010000, + EF_TELEPORTER = 0x00020000, // particle fountain + EF_FLAG1 = 0x00040000, + EF_FLAG2 = 0x00080000, + // RAFAEL + EF_IONRIPPER = 0x00100000, + EF_GREENGIB = 0x00200000, + EF_BLUEHYPERBLASTER = 0x00400000, + EF_SPINNINGLIGHTS = 0x00800000, + EF_PLASMA = 0x01000000, + EF_TRAP = 0x02000000, + + //ROGUE + EF_TRACKER = 0x04000000, + EF_DOUBLE = 0x08000000, + EF_SPHERETRANS = 0x10000000, + EF_TAGTRAIL = 0x20000000, + EF_HALF_DAMAGE = 0x40000000, + EF_TRACKERTRAIL = 0x80000000, + //ROGUE + +#ifdef VRX_REPRO + EF_DUALFIRE = U64BIT(32), // [KEX] dualfire damage color shell + EF_HOLOGRAM = U64BIT(33), // [Paril-KEX] N64 hologram + EF_FLASHLIGHT = U64BIT(34), // [Paril-KEX] project flashlight, only for players + EF_BARREL_EXPLODING = U64BIT(35), + EF_TELEPORTER2 = U64BIT(36), // [Paril-KEX] n64 teleporter + EF_GRENADE_LIGHT = U64BIT(37) +#endif +}; // entity_state_t->renderfx flags -#define RF_MINLIGHT 1 // allways have some light (viewmodel) -#define RF_VIEWERMODEL 2 // don't draw through eyes, only mirrors -#define RF_WEAPONMODEL 4 // only draw through eyes -#define RF_FULLBRIGHT 8 // allways draw full intensity -#define RF_DEPTHHACK 16 // for view weapon Z crunching -#define RF_TRANSLUCENT 32 -#define RF_FRAMELERP 64 -#define RF_BEAM 128 -#define RF_CUSTOMSKIN 256 // skin is an index in image_precache -#define RF_GLOW 512 // pulse lighting for bonus items -#define RF_SHELL_RED 1024 -#define RF_SHELL_GREEN 2048 -#define RF_SHELL_BLUE 4096 -#define RF_SHELL_YELLOW 65536//K03 -#define RF_SHELL_CYAN (RF_SHELL_GREEN | RF_SHELL_BLUE) /* cyan shell */ - - -//ROGUE -#define RF_IR_VISIBLE 0x00008000 // 32768 -#define RF_SHELL_DOUBLE 0x00010000 // 65536 -#define RF_SHELL_HALF_DAM 0x00020000 -#define RF_USE_DISGUISE 0x00040000 -//ROGUE +enum renderfx_t : uint32_t { + RF_NONE = 0, + RF_MINLIGHT = 1, // allways have some light (viewmodel) + RF_VIEWERMODEL = U32BIT(1), // don't draw through eyes, only mirrors + RF_WEAPONMODEL = U32BIT(2), // only draw through eyes + RF_FULLBRIGHT = U32BIT(3), // allways draw full intensity + RF_DEPTHHACK = U32BIT(4), // for view weapon Z crunching + RF_TRANSLUCENT = U32BIT(5), + RF_FRAMELERP = U32BIT(6), // "No interpolation for origins" + RF_BEAM = U32BIT(7), + RF_CUSTOMSKIN = U32BIT(8), // skin is an index in image_precache + RF_GLOW = U32BIT(9), // pulse lighting for bonus items + RF_SHELL_RED = U32BIT(10), + RF_SHELL_GREEN = U32BIT(11), + RF_SHELL_BLUE = U32BIT(12), +#ifdef VRX_REPRO + RF_NOSHADOW = U32BIT(13), + RF_CASTSHADOW = U32BIT(14), + + // ROGUE + RF_IR_VISIBLE = U32BIT(15), // [Paril-KEX] IR visible + RF_SHELL_DOUBLE = U32BIT(16), + RF_SHELL_HALF_DAM = U32BIT(17), + RF_USE_DISGUISE = U32BIT(18), + // ROGUE + + RF_SHELL_LITE_GREEN = U32BIT(19), + RF_CUSTOM_LIGHT = U32BIT(20), + // [Paril-KEX] custom point dlight that is designed to strobe/be turned off; s.frame is radius, s.skinnum is color + RF_FLARE = U32BIT(21), + RF_OLD_FRAME_LERP = U32BIT(22), + // [Paril-KEX] force model to lerp from oldframe in entity state; otherwise it uses last frame client received + RF_DOT_SHADOW = U32BIT(23), // [Paril-KEX] draw blobby shadow + RF_LOW_PRIORITY = U32BIT(24), + // low primority object; if we can't be added to the scene, don't bother replacing entities, + // and we can be replaced if anything non-low-priority needs room + RF_NO_LOD = U32BIT(25), + RF_NO_STEREO = RF_WEAPONMODEL, // this is a bit dumb, but, for looping noises if this is set there's no stereo + RF_STAIR_STEP = U32BIT(26), // [Paril-KEX] re-tuned, now used to handle stair steps for monsters + + RF_FLARE_LOCK_ANGLE = RF_MINLIGHT, +#endif + RF_SHELL_YELLOW = RF_SHELL_DOUBLE, //K03 +}; -// player_state_t->refdef flags -#define RDF_UNDERWATER 1 // warp the screen as apropriate -#define RDF_NOWORLDMODEL 2 // used for player configuration screen +#define RF_SHELL_CYAN (RF_SHELL_GREEN | RF_SHELL_BLUE) /* cyan shell */ -//ROGUE -#define RDF_IRGOGGLES 4 -#define RDF_UVGOGGLES 8 -//ROGUE +// [Paril-KEX] make a lightning bolt instead of a laser +#define RF_BEAM_LIGHTNING (RF_BEAM | RF_GLOW) // // muzzle flashes / player effects // -#define MZ_BLASTER 0 -#define MZ_MACHINEGUN 1 -#define MZ_SHOTGUN 2 -#define MZ_CHAINGUN1 3 -#define MZ_CHAINGUN2 4 -#define MZ_CHAINGUN3 5 -#define MZ_RAILGUN 6 -#define MZ_ROCKET 7 -#define MZ_GRENADE 8 -#define MZ_LOGIN 9 -#define MZ_LOGOUT 10 -#define MZ_RESPAWN 11 -#define MZ_BFG 12 -#define MZ_SSHOTGUN 13 -#define MZ_HYPERBLASTER 14 -#define MZ_ITEMRESPAWN 15 -// RAFAEL -#define MZ_IONRIPPER 16 -#define MZ_BLUEHYPERBLASTER 17 -#define MZ_PHALANX 18 -#define MZ_SILENCED 128 // bit flag ORed with one of the above numbers - -//ROGUE -#define MZ_ETF_RIFLE 30 -#define MZ_UNUSED 31 -#define MZ_SHOTGUN2 32 -#define MZ_HEATBEAM 33 -#define MZ_BLASTER2 34 -#define MZ_TRACKER 35 -#define MZ_NUKE1 36 -#define MZ_NUKE2 37 -#define MZ_NUKE4 38 -#define MZ_NUKE8 39 -//ROGUE - -#define MZ_SILENCED 128 // bit flag ORed with one of the above numbers +enum player_muzzle_t : uint8_t { + MZ_BLASTER = 0, + MZ_MACHINEGUN = 1, + MZ_SHOTGUN = 2, + MZ_CHAINGUN1 = 3, + MZ_CHAINGUN2 = 4, + MZ_CHAINGUN3 = 5, + MZ_RAILGUN = 6, + MZ_ROCKET = 7, + MZ_GRENADE = 8, + MZ_LOGIN = 9, + MZ_LOGOUT = 10, + MZ_RESPAWN = 11, + MZ_BFG = 12, + MZ_SSHOTGUN = 13, + MZ_HYPERBLASTER = 14, + MZ_ITEMRESPAWN = 15, + // RAFAEL + MZ_IONRIPPER = 16, + MZ_BLUEHYPERBLASTER = 17, + MZ_PHALANX = 18, + MZ_BFG2 = 19, + MZ_PHALANX2 = 20, + + //ROGUE + MZ_ETF_RIFLE = 30, + MZ_UNUSED = 31, + MZ_SHOTGUN2 = 32, + MZ_HEATBEAM = 33, + MZ_BLASTER2 = 34, + MZ_TRACKER = 35, + MZ_NUKE1 = 36, + MZ_NUKE2 = 37, + MZ_NUKE4 = 38, + MZ_NUKE8 = 39, + //ROGUE + + MZ_SILENCED = 128 // bit flag ORed with one of the above numbers +}; // // monster muzzle flashes // -#define MZ2_TANK_BLASTER_1 1 -#define MZ2_TANK_BLASTER_2 2 -#define MZ2_TANK_BLASTER_3 3 -#define MZ2_TANK_MACHINEGUN_1 4 -#define MZ2_TANK_MACHINEGUN_2 5 -#define MZ2_TANK_MACHINEGUN_3 6 -#define MZ2_TANK_MACHINEGUN_4 7 -#define MZ2_TANK_MACHINEGUN_5 8 -#define MZ2_TANK_MACHINEGUN_6 9 -#define MZ2_TANK_MACHINEGUN_7 10 -#define MZ2_TANK_MACHINEGUN_8 11 -#define MZ2_TANK_MACHINEGUN_9 12 -#define MZ2_TANK_MACHINEGUN_10 13 -#define MZ2_TANK_MACHINEGUN_11 14 -#define MZ2_TANK_MACHINEGUN_12 15 -#define MZ2_TANK_MACHINEGUN_13 16 -#define MZ2_TANK_MACHINEGUN_14 17 -#define MZ2_TANK_MACHINEGUN_15 18 -#define MZ2_TANK_MACHINEGUN_16 19 -#define MZ2_TANK_MACHINEGUN_17 20 -#define MZ2_TANK_MACHINEGUN_18 21 -#define MZ2_TANK_MACHINEGUN_19 22 -#define MZ2_TANK_ROCKET_1 23 -#define MZ2_TANK_ROCKET_2 24 -#define MZ2_TANK_ROCKET_3 25 - -#define MZ2_INFANTRY_MACHINEGUN_1 26 -#define MZ2_INFANTRY_MACHINEGUN_2 27 -#define MZ2_INFANTRY_MACHINEGUN_3 28 -#define MZ2_INFANTRY_MACHINEGUN_4 29 -#define MZ2_INFANTRY_MACHINEGUN_5 30 -#define MZ2_INFANTRY_MACHINEGUN_6 31 -#define MZ2_INFANTRY_MACHINEGUN_7 32 -#define MZ2_INFANTRY_MACHINEGUN_8 33 -#define MZ2_INFANTRY_MACHINEGUN_9 34 -#define MZ2_INFANTRY_MACHINEGUN_10 35 -#define MZ2_INFANTRY_MACHINEGUN_11 36 -#define MZ2_INFANTRY_MACHINEGUN_12 37 -#define MZ2_INFANTRY_MACHINEGUN_13 38 - -#define MZ2_SOLDIER_BLASTER_1 39 -#define MZ2_SOLDIER_BLASTER_2 40 -#define MZ2_SOLDIER_SHOTGUN_1 41 -#define MZ2_SOLDIER_SHOTGUN_2 42 -#define MZ2_SOLDIER_MACHINEGUN_1 43 -#define MZ2_SOLDIER_MACHINEGUN_2 44 - -#define MZ2_GUNNER_MACHINEGUN_1 45 -#define MZ2_GUNNER_MACHINEGUN_2 46 -#define MZ2_GUNNER_MACHINEGUN_3 47 -#define MZ2_GUNNER_MACHINEGUN_4 48 -#define MZ2_GUNNER_MACHINEGUN_5 49 -#define MZ2_GUNNER_MACHINEGUN_6 50 -#define MZ2_GUNNER_MACHINEGUN_7 51 -#define MZ2_GUNNER_MACHINEGUN_8 52 -#define MZ2_GUNNER_GRENADE_1 53 -#define MZ2_GUNNER_GRENADE_2 54 -#define MZ2_GUNNER_GRENADE_3 55 -#define MZ2_GUNNER_GRENADE_4 56 - -#define MZ2_CHICK_ROCKET_1 57 - -#define MZ2_FLYER_BLASTER_1 58 -#define MZ2_FLYER_BLASTER_2 59 - -#define MZ2_MEDIC_BLASTER_1 60 - -#define MZ2_GLADIATOR_RAILGUN_1 61 - -#define MZ2_HOVER_BLASTER_1 62 - -#define MZ2_ACTOR_MACHINEGUN_1 63 - -#define MZ2_SUPERTANK_MACHINEGUN_1 64 -#define MZ2_SUPERTANK_MACHINEGUN_2 65 -#define MZ2_SUPERTANK_MACHINEGUN_3 66 -#define MZ2_SUPERTANK_MACHINEGUN_4 67 -#define MZ2_SUPERTANK_MACHINEGUN_5 68 -#define MZ2_SUPERTANK_MACHINEGUN_6 69 -#define MZ2_SUPERTANK_ROCKET_1 70 -#define MZ2_SUPERTANK_ROCKET_2 71 -#define MZ2_SUPERTANK_ROCKET_3 72 - -#define MZ2_BOSS2_MACHINEGUN_L1 73 -#define MZ2_BOSS2_MACHINEGUN_L2 74 -#define MZ2_BOSS2_MACHINEGUN_L3 75 -#define MZ2_BOSS2_MACHINEGUN_L4 76 -#define MZ2_BOSS2_MACHINEGUN_L5 77 -#define MZ2_BOSS2_ROCKET_1 78 -#define MZ2_BOSS2_ROCKET_2 79 -#define MZ2_BOSS2_ROCKET_3 80 -#define MZ2_BOSS2_ROCKET_4 81 - -#define MZ2_FLOAT_BLASTER_1 82 - -#define MZ2_SOLDIER_BLASTER_3 83 -#define MZ2_SOLDIER_SHOTGUN_3 84 -#define MZ2_SOLDIER_MACHINEGUN_3 85 -#define MZ2_SOLDIER_BLASTER_4 86 -#define MZ2_SOLDIER_SHOTGUN_4 87 -#define MZ2_SOLDIER_MACHINEGUN_4 88 -#define MZ2_SOLDIER_BLASTER_5 89 -#define MZ2_SOLDIER_SHOTGUN_5 90 -#define MZ2_SOLDIER_MACHINEGUN_5 91 -#define MZ2_SOLDIER_BLASTER_6 92 -#define MZ2_SOLDIER_SHOTGUN_6 93 -#define MZ2_SOLDIER_MACHINEGUN_6 94 -#define MZ2_SOLDIER_BLASTER_7 95 -#define MZ2_SOLDIER_SHOTGUN_7 96 -#define MZ2_SOLDIER_MACHINEGUN_7 97 -#define MZ2_SOLDIER_BLASTER_8 98 -#define MZ2_SOLDIER_SHOTGUN_8 99 -#define MZ2_SOLDIER_MACHINEGUN_8 100 - -// --- Xian shit below --- -#define MZ2_MAKRON_BFG 101 -#define MZ2_MAKRON_BLASTER_1 102 -#define MZ2_MAKRON_BLASTER_2 103 -#define MZ2_MAKRON_BLASTER_3 104 -#define MZ2_MAKRON_BLASTER_4 105 -#define MZ2_MAKRON_BLASTER_5 106 -#define MZ2_MAKRON_BLASTER_6 107 -#define MZ2_MAKRON_BLASTER_7 108 -#define MZ2_MAKRON_BLASTER_8 109 -#define MZ2_MAKRON_BLASTER_9 110 -#define MZ2_MAKRON_BLASTER_10 111 -#define MZ2_MAKRON_BLASTER_11 112 -#define MZ2_MAKRON_BLASTER_12 113 -#define MZ2_MAKRON_BLASTER_13 114 -#define MZ2_MAKRON_BLASTER_14 115 -#define MZ2_MAKRON_BLASTER_15 116 -#define MZ2_MAKRON_BLASTER_16 117 -#define MZ2_MAKRON_BLASTER_17 118 -#define MZ2_MAKRON_RAILGUN_1 119 -#define MZ2_JORG_MACHINEGUN_L1 120 -#define MZ2_JORG_MACHINEGUN_L2 121 -#define MZ2_JORG_MACHINEGUN_L3 122 -#define MZ2_JORG_MACHINEGUN_L4 123 -#define MZ2_JORG_MACHINEGUN_L5 124 -#define MZ2_JORG_MACHINEGUN_L6 125 -#define MZ2_JORG_MACHINEGUN_R1 126 -#define MZ2_JORG_MACHINEGUN_R2 127 -#define MZ2_JORG_MACHINEGUN_R3 128 -#define MZ2_JORG_MACHINEGUN_R4 129 -#define MZ2_JORG_MACHINEGUN_R5 130 -#define MZ2_JORG_MACHINEGUN_R6 131 -#define MZ2_JORG_BFG_1 132 -#define MZ2_BOSS2_MACHINEGUN_R1 133 -#define MZ2_BOSS2_MACHINEGUN_R2 134 -#define MZ2_BOSS2_MACHINEGUN_R3 135 -#define MZ2_BOSS2_MACHINEGUN_R4 136 -#define MZ2_BOSS2_MACHINEGUN_R5 137 - -//ROGUE -#define MZ2_CARRIER_MACHINEGUN_L1 138 -#define MZ2_CARRIER_MACHINEGUN_R1 139 -#define MZ2_CARRIER_GRENADE 140 -#define MZ2_TURRET_MACHINEGUN 141 -#define MZ2_TURRET_ROCKET 142 -#define MZ2_TURRET_BLASTER 143 -#define MZ2_STALKER_BLASTER 144 -#define MZ2_DAEDALUS_BLASTER 145 -#define MZ2_MEDIC_BLASTER_2 146 -#define MZ2_CARRIER_RAILGUN 147 -#define MZ2_WIDOW_DISRUPTOR 148 -#define MZ2_WIDOW_BLASTER 149 -#define MZ2_WIDOW_RAIL 150 -#define MZ2_WIDOW_PLASMABEAM 151 // PMM - not used -#define MZ2_CARRIER_MACHINEGUN_L2 152 -#define MZ2_CARRIER_MACHINEGUN_R2 153 -#define MZ2_WIDOW_RAIL_LEFT 154 -#define MZ2_WIDOW_RAIL_RIGHT 155 -#define MZ2_WIDOW_BLASTER_SWEEP1 156 -#define MZ2_WIDOW_BLASTER_SWEEP2 157 -#define MZ2_WIDOW_BLASTER_SWEEP3 158 -#define MZ2_WIDOW_BLASTER_SWEEP4 159 -#define MZ2_WIDOW_BLASTER_SWEEP5 160 -#define MZ2_WIDOW_BLASTER_SWEEP6 161 -#define MZ2_WIDOW_BLASTER_SWEEP7 162 -#define MZ2_WIDOW_BLASTER_SWEEP8 163 -#define MZ2_WIDOW_BLASTER_SWEEP9 164 -#define MZ2_WIDOW_BLASTER_100 165 -#define MZ2_WIDOW_BLASTER_90 166 -#define MZ2_WIDOW_BLASTER_80 167 -#define MZ2_WIDOW_BLASTER_70 168 -#define MZ2_WIDOW_BLASTER_60 169 -#define MZ2_WIDOW_BLASTER_50 170 -#define MZ2_WIDOW_BLASTER_40 171 -#define MZ2_WIDOW_BLASTER_30 172 -#define MZ2_WIDOW_BLASTER_20 173 -#define MZ2_WIDOW_BLASTER_10 174 -#define MZ2_WIDOW_BLASTER_0 175 -#define MZ2_WIDOW_BLASTER_10L 176 -#define MZ2_WIDOW_BLASTER_20L 177 -#define MZ2_WIDOW_BLASTER_30L 178 -#define MZ2_WIDOW_BLASTER_40L 179 -#define MZ2_WIDOW_BLASTER_50L 180 -#define MZ2_WIDOW_BLASTER_60L 181 -#define MZ2_WIDOW_BLASTER_70L 182 -#define MZ2_WIDOW_RUN_1 183 -#define MZ2_WIDOW_RUN_2 184 -#define MZ2_WIDOW_RUN_3 185 -#define MZ2_WIDOW_RUN_4 186 -#define MZ2_WIDOW_RUN_5 187 -#define MZ2_WIDOW_RUN_6 188 -#define MZ2_WIDOW_RUN_7 189 -#define MZ2_WIDOW_RUN_8 190 -#define MZ2_CARRIER_ROCKET_1 191 -#define MZ2_CARRIER_ROCKET_2 192 -#define MZ2_CARRIER_ROCKET_3 193 -#define MZ2_CARRIER_ROCKET_4 194 -#define MZ2_WIDOW2_BEAMER_1 195 -#define MZ2_WIDOW2_BEAMER_2 196 -#define MZ2_WIDOW2_BEAMER_3 197 -#define MZ2_WIDOW2_BEAMER_4 198 -#define MZ2_WIDOW2_BEAMER_5 199 -#define MZ2_WIDOW2_BEAM_SWEEP_1 200 -#define MZ2_WIDOW2_BEAM_SWEEP_2 201 -#define MZ2_WIDOW2_BEAM_SWEEP_3 202 -#define MZ2_WIDOW2_BEAM_SWEEP_4 203 -#define MZ2_WIDOW2_BEAM_SWEEP_5 204 -#define MZ2_WIDOW2_BEAM_SWEEP_6 205 -#define MZ2_WIDOW2_BEAM_SWEEP_7 206 -#define MZ2_WIDOW2_BEAM_SWEEP_8 207 -#define MZ2_WIDOW2_BEAM_SWEEP_9 208 -#define MZ2_WIDOW2_BEAM_SWEEP_10 209 -#define MZ2_WIDOW2_BEAM_SWEEP_11 210 - -// ROGUE - -extern vec3_t monster_flash_offset []; +enum monster_muzzleflash_id_t : uint16_t { + MZ2_UNUSED, + MZ2_TANK_BLASTER_1, + MZ2_TANK_BLASTER_2, + MZ2_TANK_BLASTER_3, + MZ2_TANK_MACHINEGUN_1, + MZ2_TANK_MACHINEGUN_2, + MZ2_TANK_MACHINEGUN_3, + MZ2_TANK_MACHINEGUN_4, + MZ2_TANK_MACHINEGUN_5, + MZ2_TANK_MACHINEGUN_6, + MZ2_TANK_MACHINEGUN_7, + MZ2_TANK_MACHINEGUN_8, + MZ2_TANK_MACHINEGUN_9, + MZ2_TANK_MACHINEGUN_10, + MZ2_TANK_MACHINEGUN_11, + MZ2_TANK_MACHINEGUN_12, + MZ2_TANK_MACHINEGUN_13, + MZ2_TANK_MACHINEGUN_14, + MZ2_TANK_MACHINEGUN_15, + MZ2_TANK_MACHINEGUN_16, + MZ2_TANK_MACHINEGUN_17, + MZ2_TANK_MACHINEGUN_18, + MZ2_TANK_MACHINEGUN_19, + MZ2_TANK_ROCKET_1, + MZ2_TANK_ROCKET_2, + MZ2_TANK_ROCKET_3, + + MZ2_INFANTRY_MACHINEGUN_1, + MZ2_INFANTRY_MACHINEGUN_2, + MZ2_INFANTRY_MACHINEGUN_3, + MZ2_INFANTRY_MACHINEGUN_4, + MZ2_INFANTRY_MACHINEGUN_5, + MZ2_INFANTRY_MACHINEGUN_6, + MZ2_INFANTRY_MACHINEGUN_7, + MZ2_INFANTRY_MACHINEGUN_8, + MZ2_INFANTRY_MACHINEGUN_9, + MZ2_INFANTRY_MACHINEGUN_10, + MZ2_INFANTRY_MACHINEGUN_11, + MZ2_INFANTRY_MACHINEGUN_12, + MZ2_INFANTRY_MACHINEGUN_13, + + MZ2_SOLDIER_BLASTER_1, + MZ2_SOLDIER_BLASTER_2, + MZ2_SOLDIER_SHOTGUN_1, + MZ2_SOLDIER_SHOTGUN_2, + MZ2_SOLDIER_MACHINEGUN_1, + MZ2_SOLDIER_MACHINEGUN_2, + + MZ2_GUNNER_MACHINEGUN_1, + MZ2_GUNNER_MACHINEGUN_2, + MZ2_GUNNER_MACHINEGUN_3, + MZ2_GUNNER_MACHINEGUN_4, + MZ2_GUNNER_MACHINEGUN_5, + MZ2_GUNNER_MACHINEGUN_6, + MZ2_GUNNER_MACHINEGUN_7, + MZ2_GUNNER_MACHINEGUN_8, + MZ2_GUNNER_GRENADE_1, + MZ2_GUNNER_GRENADE_2, + MZ2_GUNNER_GRENADE_3, + MZ2_GUNNER_GRENADE_4, + + MZ2_CHICK_ROCKET_1, + + MZ2_FLYER_BLASTER_1, + MZ2_FLYER_BLASTER_2, + + MZ2_MEDIC_BLASTER_1, + + MZ2_GLADIATOR_RAILGUN_1, + + MZ2_HOVER_BLASTER_1, + + MZ2_ACTOR_MACHINEGUN_1, + + MZ2_SUPERTANK_MACHINEGUN_1, + MZ2_SUPERTANK_MACHINEGUN_2, + MZ2_SUPERTANK_MACHINEGUN_3, + MZ2_SUPERTANK_MACHINEGUN_4, + MZ2_SUPERTANK_MACHINEGUN_5, + MZ2_SUPERTANK_MACHINEGUN_6, + MZ2_SUPERTANK_ROCKET_1, + MZ2_SUPERTANK_ROCKET_2, + MZ2_SUPERTANK_ROCKET_3, + + MZ2_BOSS2_MACHINEGUN_L1, + MZ2_BOSS2_MACHINEGUN_L2, + MZ2_BOSS2_MACHINEGUN_L3, + MZ2_BOSS2_MACHINEGUN_L4, + MZ2_BOSS2_MACHINEGUN_L5, + MZ2_BOSS2_ROCKET_1, + MZ2_BOSS2_ROCKET_2, + MZ2_BOSS2_ROCKET_3, + MZ2_BOSS2_ROCKET_4, + + MZ2_FLOAT_BLASTER_1, + + MZ2_SOLDIER_BLASTER_3, + MZ2_SOLDIER_SHOTGUN_3, + MZ2_SOLDIER_MACHINEGUN_3, + MZ2_SOLDIER_BLASTER_4, + MZ2_SOLDIER_SHOTGUN_4, + MZ2_SOLDIER_MACHINEGUN_4, + MZ2_SOLDIER_BLASTER_5, + MZ2_SOLDIER_SHOTGUN_5, + MZ2_SOLDIER_MACHINEGUN_5, + MZ2_SOLDIER_BLASTER_6, + MZ2_SOLDIER_SHOTGUN_6, + MZ2_SOLDIER_MACHINEGUN_6, + MZ2_SOLDIER_BLASTER_7, + MZ2_SOLDIER_SHOTGUN_7, + MZ2_SOLDIER_MACHINEGUN_7, + MZ2_SOLDIER_BLASTER_8, + MZ2_SOLDIER_SHOTGUN_8, + MZ2_SOLDIER_MACHINEGUN_8, + + // --- Xian shit below --- + MZ2_MAKRON_BFG, + MZ2_MAKRON_BLASTER_1, + MZ2_MAKRON_BLASTER_2, + MZ2_MAKRON_BLASTER_3, + MZ2_MAKRON_BLASTER_4, + MZ2_MAKRON_BLASTER_5, + MZ2_MAKRON_BLASTER_6, + MZ2_MAKRON_BLASTER_7, + MZ2_MAKRON_BLASTER_8, + MZ2_MAKRON_BLASTER_9, + MZ2_MAKRON_BLASTER_10, + MZ2_MAKRON_BLASTER_11, + MZ2_MAKRON_BLASTER_12, + MZ2_MAKRON_BLASTER_13, + MZ2_MAKRON_BLASTER_14, + MZ2_MAKRON_BLASTER_15, + MZ2_MAKRON_BLASTER_16, + MZ2_MAKRON_BLASTER_17, + MZ2_MAKRON_RAILGUN_1, + MZ2_JORG_MACHINEGUN_L1, + MZ2_JORG_MACHINEGUN_L2, + MZ2_JORG_MACHINEGUN_L3, + MZ2_JORG_MACHINEGUN_L4, + MZ2_JORG_MACHINEGUN_L5, + MZ2_JORG_MACHINEGUN_L6, + MZ2_JORG_MACHINEGUN_R1, + MZ2_JORG_MACHINEGUN_R2, + MZ2_JORG_MACHINEGUN_R3, + MZ2_JORG_MACHINEGUN_R4, + MZ2_JORG_MACHINEGUN_R5, + MZ2_JORG_MACHINEGUN_R6, + MZ2_JORG_BFG_1, + MZ2_BOSS2_MACHINEGUN_R1, + MZ2_BOSS2_MACHINEGUN_R2, + MZ2_BOSS2_MACHINEGUN_R3, + MZ2_BOSS2_MACHINEGUN_R4, + MZ2_BOSS2_MACHINEGUN_R5, + + //ROGUE + MZ2_CARRIER_MACHINEGUN_L1, + MZ2_CARRIER_MACHINEGUN_R1, + MZ2_CARRIER_GRENADE, + MZ2_TURRET_MACHINEGUN, + MZ2_TURRET_ROCKET, + MZ2_TURRET_BLASTER, + MZ2_STALKER_BLASTER, + MZ2_DAEDALUS_BLASTER, + MZ2_MEDIC_BLASTER_2, + MZ2_CARRIER_RAILGUN, + MZ2_WIDOW_DISRUPTOR, + MZ2_WIDOW_BLASTER, + MZ2_WIDOW_RAIL, + MZ2_WIDOW_PLASMABEAM = 151, // PMM unused + MZ2_CARRIER_MACHINEGUN_L2, + MZ2_CARRIER_MACHINEGUN_R2, + MZ2_WIDOW_RAIL_LEFT, + MZ2_WIDOW_RAIL_RIGHT, + MZ2_WIDOW_BLASTER_SWEEP1, + MZ2_WIDOW_BLASTER_SWEEP2, + MZ2_WIDOW_BLASTER_SWEEP3, + MZ2_WIDOW_BLASTER_SWEEP4, + MZ2_WIDOW_BLASTER_SWEEP5, + MZ2_WIDOW_BLASTER_SWEEP6, + MZ2_WIDOW_BLASTER_SWEEP7, + MZ2_WIDOW_BLASTER_SWEEP8, + MZ2_WIDOW_BLASTER_SWEEP9, + MZ2_WIDOW_BLASTER_100, + MZ2_WIDOW_BLASTER_90, + MZ2_WIDOW_BLASTER_80, + MZ2_WIDOW_BLASTER_70, + MZ2_WIDOW_BLASTER_60, + MZ2_WIDOW_BLASTER_50, + MZ2_WIDOW_BLASTER_40, + MZ2_WIDOW_BLASTER_30, + MZ2_WIDOW_BLASTER_20, + MZ2_WIDOW_BLASTER_10, + MZ2_WIDOW_BLASTER_0, + MZ2_WIDOW_BLASTER_10L, + MZ2_WIDOW_BLASTER_20L, + MZ2_WIDOW_BLASTER_30L, + MZ2_WIDOW_BLASTER_40L, + MZ2_WIDOW_BLASTER_50L, + MZ2_WIDOW_BLASTER_60L, + MZ2_WIDOW_BLASTER_70L, + MZ2_WIDOW_RUN_1, + MZ2_WIDOW_RUN_2, + MZ2_WIDOW_RUN_3, + MZ2_WIDOW_RUN_4, + MZ2_WIDOW_RUN_5, + MZ2_WIDOW_RUN_6, + MZ2_WIDOW_RUN_7, + MZ2_WIDOW_RUN_8, + MZ2_CARRIER_ROCKET_1, + MZ2_CARRIER_ROCKET_2, + MZ2_CARRIER_ROCKET_3, + MZ2_CARRIER_ROCKET_4, + MZ2_WIDOW2_BEAMER_1, + MZ2_WIDOW2_BEAMER_2, + MZ2_WIDOW2_BEAMER_3, + MZ2_WIDOW2_BEAMER_4, + MZ2_WIDOW2_BEAMER_5, + MZ2_WIDOW2_BEAM_SWEEP_1, + MZ2_WIDOW2_BEAM_SWEEP_2, + MZ2_WIDOW2_BEAM_SWEEP_3, + MZ2_WIDOW2_BEAM_SWEEP_4, + MZ2_WIDOW2_BEAM_SWEEP_5, + MZ2_WIDOW2_BEAM_SWEEP_6, + MZ2_WIDOW2_BEAM_SWEEP_7, + MZ2_WIDOW2_BEAM_SWEEP_8, + MZ2_WIDOW2_BEAM_SWEEP_9, + MZ2_WIDOW2_BEAM_SWEEP_10, + MZ2_WIDOW2_BEAM_SWEEP_11, + + // ROGUE + + // [Paril-KEX] + MZ2_SOLDIER_RIPPER_1, + MZ2_SOLDIER_RIPPER_2, + MZ2_SOLDIER_RIPPER_3, + MZ2_SOLDIER_RIPPER_4, + MZ2_SOLDIER_RIPPER_5, + MZ2_SOLDIER_RIPPER_6, + MZ2_SOLDIER_RIPPER_7, + MZ2_SOLDIER_RIPPER_8, + + MZ2_SOLDIER_HYPERGUN_1, + MZ2_SOLDIER_HYPERGUN_2, + MZ2_SOLDIER_HYPERGUN_3, + MZ2_SOLDIER_HYPERGUN_4, + MZ2_SOLDIER_HYPERGUN_5, + MZ2_SOLDIER_HYPERGUN_6, + MZ2_SOLDIER_HYPERGUN_7, + MZ2_SOLDIER_HYPERGUN_8, + MZ2_GUARDIAN_BLASTER, + MZ2_ARACHNID_RAIL1, + MZ2_ARACHNID_RAIL2, + MZ2_ARACHNID_RAIL_UP1, + MZ2_ARACHNID_RAIL_UP2, + + MZ2_INFANTRY_MACHINEGUN_14, // run-attack + MZ2_INFANTRY_MACHINEGUN_15, // run-attack + MZ2_INFANTRY_MACHINEGUN_16, // run-attack + MZ2_INFANTRY_MACHINEGUN_17, // run-attack + MZ2_INFANTRY_MACHINEGUN_18, // run-attack + MZ2_INFANTRY_MACHINEGUN_19, // run-attack + MZ2_INFANTRY_MACHINEGUN_20, // run-attack + MZ2_INFANTRY_MACHINEGUN_21, // run-attack + + MZ2_GUNCMDR_CHAINGUN_1, // straight + MZ2_GUNCMDR_CHAINGUN_2, // dodging + + MZ2_GUNCMDR_GRENADE_MORTAR_1, + MZ2_GUNCMDR_GRENADE_MORTAR_2, + MZ2_GUNCMDR_GRENADE_MORTAR_3, + MZ2_GUNCMDR_GRENADE_FRONT_1, + MZ2_GUNCMDR_GRENADE_FRONT_2, + MZ2_GUNCMDR_GRENADE_FRONT_3, + MZ2_GUNCMDR_GRENADE_CROUCH_1, + MZ2_GUNCMDR_GRENADE_CROUCH_2, + MZ2_GUNCMDR_GRENADE_CROUCH_3, + + // prone + MZ2_SOLDIER_BLASTER_9, + MZ2_SOLDIER_SHOTGUN_9, + MZ2_SOLDIER_MACHINEGUN_9, + MZ2_SOLDIER_RIPPER_9, + MZ2_SOLDIER_HYPERGUN_9, + + // alternate frontwards grenades + MZ2_GUNNER_GRENADE2_1, + MZ2_GUNNER_GRENADE2_2, + MZ2_GUNNER_GRENADE2_3, + MZ2_GUNNER_GRENADE2_4, + + MZ2_INFANTRY_MACHINEGUN_22, + + // supertonk + MZ2_SUPERTANK_GRENADE_1, + MZ2_SUPERTANK_GRENADE_2, + + // hover & daedalus other side + MZ2_HOVER_BLASTER_2, + MZ2_DAEDALUS_BLASTER_2, + + // medic (commander) sweeps + MZ2_MEDIC_HYPERBLASTER1_1, + MZ2_MEDIC_HYPERBLASTER1_2, + MZ2_MEDIC_HYPERBLASTER1_3, + MZ2_MEDIC_HYPERBLASTER1_4, + MZ2_MEDIC_HYPERBLASTER1_5, + MZ2_MEDIC_HYPERBLASTER1_6, + MZ2_MEDIC_HYPERBLASTER1_7, + MZ2_MEDIC_HYPERBLASTER1_8, + MZ2_MEDIC_HYPERBLASTER1_9, + MZ2_MEDIC_HYPERBLASTER1_10, + MZ2_MEDIC_HYPERBLASTER1_11, + MZ2_MEDIC_HYPERBLASTER1_12, + + MZ2_MEDIC_HYPERBLASTER2_1, + MZ2_MEDIC_HYPERBLASTER2_2, + MZ2_MEDIC_HYPERBLASTER2_3, + MZ2_MEDIC_HYPERBLASTER2_4, + MZ2_MEDIC_HYPERBLASTER2_5, + MZ2_MEDIC_HYPERBLASTER2_6, + MZ2_MEDIC_HYPERBLASTER2_7, + MZ2_MEDIC_HYPERBLASTER2_8, + MZ2_MEDIC_HYPERBLASTER2_9, + MZ2_MEDIC_HYPERBLASTER2_10, + MZ2_MEDIC_HYPERBLASTER2_11, + MZ2_MEDIC_HYPERBLASTER2_12, + + // only used for compile time checks + MZ2_LAST +}; + +extern vec3_t monster_flash_offset[212]; // temp entity events @@ -941,88 +1329,114 @@ extern vec3_t monster_flash_offset []; // at a location seperate from any existing entity. // Temporary entity messages are explicitly constructed // and broadcast. -typedef enum -{ - TE_GUNSHOT, - TE_BLOOD, - TE_BLASTER, - TE_RAILTRAIL, - TE_SHOTGUN, - TE_EXPLOSION1, - TE_EXPLOSION2, - TE_ROCKET_EXPLOSION, - TE_GRENADE_EXPLOSION, - TE_SPARKS, - TE_SPLASH, - TE_BUBBLETRAIL, - TE_SCREEN_SPARKS, - TE_SHIELD_SPARKS, - TE_BULLET_SPARKS, - TE_LASER_SPARKS, - TE_PARASITE_ATTACK, - TE_ROCKET_EXPLOSION_WATER, - TE_GRENADE_EXPLOSION_WATER, - TE_MEDIC_CABLE_ATTACK, - TE_BFG_EXPLOSION, - TE_BFG_BIGEXPLOSION, - TE_BOSSTPORT, // used as '22' in a map, so DON'T RENUMBER!!! - TE_BFG_LASER, - TE_GRAPPLE_CABLE, - TE_WELDING_SPARKS, - TE_GREENBLOOD, - TE_BLUEHYPERBLASTER, - TE_PLASMA_EXPLOSION, - TE_TUNNEL_SPARKS, -//ROGUE - TE_BLASTER2, - TE_RAILTRAIL2, - TE_FLAME, - TE_LIGHTNING, - TE_DEBUGTRAIL, - TE_PLAIN_EXPLOSION, - TE_FLASHLIGHT, - TE_FORCEWALL, - TE_HEATBEAM, - TE_MONSTER_HEATBEAM, - TE_STEAM, - TE_BUBBLETRAIL2, - TE_MOREBLOOD, - TE_HEATBEAM_SPARKS, - TE_HEATBEAM_STEAM, - TE_CHAINFIST_SMOKE, - TE_ELECTRIC_SPARKS, - TE_TRACKER_EXPLOSION, - TE_TELEPORT_EFFECT, - TE_DBALL_GOAL, - TE_WIDOWBEAMOUT, - TE_NUKEBLAST, - TE_WIDOWSPLASH, - TE_EXPLOSION1_BIG, - TE_EXPLOSION1_NP, - TE_FLECHETTE -//ROGUE +typedef enum { + TE_GUNSHOT, + TE_BLOOD, + TE_BLASTER, + TE_RAILTRAIL, + TE_SHOTGUN, + TE_EXPLOSION1, + TE_EXPLOSION2, + TE_ROCKET_EXPLOSION, + TE_GRENADE_EXPLOSION, + TE_SPARKS, + TE_SPLASH, + TE_BUBBLETRAIL, + TE_SCREEN_SPARKS, + TE_SHIELD_SPARKS, + TE_BULLET_SPARKS, + TE_LASER_SPARKS, + TE_PARASITE_ATTACK, + TE_ROCKET_EXPLOSION_WATER, + TE_GRENADE_EXPLOSION_WATER, + TE_MEDIC_CABLE_ATTACK, + TE_BFG_EXPLOSION, + TE_BFG_BIGEXPLOSION, + TE_BOSSTPORT = 22, // used as '22' in a map, so DON'T RENUMBER!!! + TE_BFG_LASER, + TE_GRAPPLE_CABLE, + TE_WELDING_SPARKS, + TE_GREENBLOOD, + TE_BLUEHYPERBLASTER_DUMMY, // for compat, use TE_BLUEHYPERBLASTER + TE_PLASMA_EXPLOSION, + TE_TUNNEL_SPARKS, + //ROGUE + TE_BLASTER2, + TE_RAILTRAIL2, + TE_FLAME, + TE_LIGHTNING, + TE_DEBUGTRAIL, + TE_PLAIN_EXPLOSION, + TE_FLASHLIGHT, + TE_FORCEWALL, + TE_HEATBEAM, + TE_MONSTER_HEATBEAM, + TE_STEAM, + TE_BUBBLETRAIL2, + TE_MOREBLOOD, + TE_HEATBEAM_SPARKS, + TE_HEATBEAM_STEAM, + TE_CHAINFIST_SMOKE, + TE_ELECTRIC_SPARKS, + TE_TRACKER_EXPLOSION, + TE_TELEPORT_EFFECT, + TE_DBALL_GOAL, + TE_WIDOWBEAMOUT, + TE_NUKEBLAST, + TE_WIDOWSPLASH, + TE_EXPLOSION1_BIG, + TE_EXPLOSION1_NP, + TE_FLECHETTE, + //ROGUE + +#ifdef VRX_REPRO + // [Paril-KEX] + TE_BLUEHYPERBLASTER, + TE_BFG_ZAP, + TE_BERSERK_SLAM, + TE_GRAPPLE_CABLE_2, + TE_POWER_SPLASH, + TE_LIGHTNING_BEAM, + TE_EXPLOSION1_NL, + TE_EXPLOSION2_NL, +#endif } temp_event_t; -#define SPLASH_UNKNOWN 0 -#define SPLASH_SPARKS 1 -#define SPLASH_BLUE_WATER 2 -#define SPLASH_BROWN_WATER 3 -#define SPLASH_SLIME 4 -#define SPLASH_LAVA 5 -#define SPLASH_BLOOD 6 +enum splash_color_t : uint8_t { + SPLASH_UNKNOWN = 0, + SPLASH_SPARKS = 1, + SPLASH_BLUE_WATER = 2, + SPLASH_BROWN_WATER = 3, + SPLASH_SLIME = 4, + SPLASH_LAVA = 5, + SPLASH_BLOOD = 6, +#ifdef VRX_REPRO + // [Paril-KEX] N64 electric sparks that go zap + SPLASH_ELECTRIC = 7, +#endif +}; // sound channels // channel 0 never willingly overrides // other channels (1-7) allways override a playing sound on that channel -#define CHAN_AUTO 0 -#define CHAN_WEAPON 1 -#define CHAN_VOICE 2 -#define CHAN_ITEM 3 -#define CHAN_BODY 4 -// modifier flags -#define CHAN_NO_PHS_ADD 8 // send to all clients, not just ones in PHS (ATTN 0 will also do this) -#define CHAN_RELIABLE 16 // send by reliable message, not datagram +enum soundchan_t : uint8_t { + CHAN_AUTO = 0, + CHAN_WEAPON = 1, + CHAN_VOICE = 2, + CHAN_ITEM = 3, + CHAN_BODY = 4, +#ifdef VRX_REPRO + CHAN_AUX = 5, + CHAN_FOOTSTEP = 6, + CHAN_AUX3 = 7, +#endif + + // modifier flags + CHAN_NO_PHS_ADD = 8, // send to all clients, not just ones in PHS (ATTN 0 will also do this) + CHAN_RELIABLE = 16, // send by reliable message, not datagram +}; + // sound attenuation values @@ -1032,46 +1446,6 @@ typedef enum #define ATTN_STATIC 3 // diminish very rapidly with distance -// player_state->stats[] indexes -// #define STAT_HEALTH_ICON 0 -#define STAT_HEALTH 1 -#define STAT_AMMO_ICON 2 -#define STAT_AMMO 3 -// #define STAT_ARMOR_ICON 4 -#define STAT_ARMOR 5 -#define STAT_SELECTED_ICON 6 -#define STAT_PICKUP_ICON 7 -#define STAT_PICKUP_STRING 8 -#define STAT_TIMER_ICON 9 -#define STAT_TIMER 10 -#define STAT_HELPICON 11 -#define STAT_SELECTED_ITEM 12 -#define STAT_LAYOUTS 13 -#define STAT_FRAGS 14 -#define STAT_FLASHES 15 // cleared each frame, 1 = health, 2 = armor -#define STAT_CHASE 16 - -//K03 Begin -#define STAT_TEAM_ICON 17 -#define STAT_STATION_ICON 18 -#define STAT_STATION_TIME 19 -#define STAT_CHARGE_LEVEL 20 -#define STAT_INVASIONTIME 21 // -az -#define STAT_VOTESTRING 22 -//#define STAT_RANK 24 -#define STAT_ID_DAMAGE 24 -#define STAT_STREAK 25 -#define STAT_ID_ARMOR 26 -#define STAT_SELECTED_NUM 27 -#define STAT_TIMEMIN 28 -#define STAT_SPECTATOR 29 -#define STAT_ID_HEALTH 30 -#define STAT_ID_AMMO 31 -//K03 End - -#define MAX_STATS 32 - - // dmflags->value flags #define DF_NO_HEALTH 0x00000001 // 1 #define DF_NO_ITEMS 0x00000002 // 2 @@ -1119,70 +1493,224 @@ typedef enum // the server to all connected clients. // Each config string can be at most MAX_QPATH characters. // -#define CS_NAME 0 -#define CS_CDTRACK 1 -#define CS_SKY 2 -#define CS_SKYAXIS 3 // %f %f %f format -#define CS_SKYROTATE 4 -#define CS_STATUSBAR 5 // display program string - -#define CS_AIRACCEL 29 // air acceleration control -#define CS_MAXCLIENTS 30 -#define CS_MAPCHECKSUM 31 // for catching cheater maps - -#define CS_MODELS 32 -#define CS_SOUNDS (CS_MODELS+MAX_MODELS) -#define CS_IMAGES (CS_SOUNDS+MAX_SOUNDS) -#define CS_LIGHTS (CS_IMAGES+MAX_IMAGES) -#define CS_ITEMS (CS_LIGHTS+MAX_LIGHTSTYLES) -#define CS_PLAYERSKINS (CS_ITEMS+MAX_ITEMS) -#define CS_GENERAL (CS_PLAYERSKINS+MAX_CLIENTS) -#define MAX_CONFIGSTRINGS (CS_GENERAL+MAX_GENERAL) +enum { + CS_NAME, + CS_CDTRACK, + CS_SKY, + CS_SKYAXIS, // %f %f %f format + CS_SKYROTATE, + CS_STATUSBAR, // display program string + +#ifndef VRX_REPRO + CS_AIRACCEL = 29, // air acceleration control +#else + CS_AIRACCEL = 59, // air acceleration control +#endif + CS_MAXCLIENTS, + CS_MAPCHECKSUM, // for catching cheater maps + + CS_MODELS, + CS_SOUNDS = CS_MODELS + MAX_MODELS, + CS_IMAGES = CS_SOUNDS + MAX_SOUNDS, + CS_LIGHTS = CS_IMAGES + MAX_IMAGES, +#ifdef VRX_REPRO + CS_SHADOWLIGHTS = CS_LIGHTS + MAX_LIGHTSTYLES, + CS_ITEMS = CS_SHADOWLIGHTS + MAX_SHADOW_LIGHTS, +#else + CS_ITEMS = CS_LIGHTS + MAX_LIGHTSTYLES, +#endif + CS_PLAYERSKINS = CS_ITEMS + MAX_ITEMS, + CS_GENERAL = CS_PLAYERSKINS + MAX_CLIENTS, + +#ifdef VRX_REPRO + CS_WHEEL_WEAPONS = CS_GENERAL + MAX_GENERAL, // [Paril-KEX] see MAX_WHEEL_ITEMS + CS_WHEEL_AMMO = CS_WHEEL_WEAPONS + MAX_WHEEL_ITEMS, // [Paril-KEX] see MAX_WHEEL_ITEMS + CS_WHEEL_POWERUPS = CS_WHEEL_AMMO + MAX_WHEEL_ITEMS, // [Paril-KEX] see MAX_WHEEL_ITEMS + CS_CD_LOOP_COUNT = CS_WHEEL_POWERUPS + MAX_WHEEL_ITEMS, // [Paril-KEX] override default loop count + // az: repro doesn't seem to care about this + //CS_GAME_STYLE, // [Paril-KEX] see game_style_t +#endif + MAX_CONFIGSTRINGS +}; + +static_assert(MAX_CONFIGSTRINGS <= 0x7FFF, "too many configstrings"); + +// [Sam-KEX] New define for max config string length +#ifdef VRX_REPRO +constexpr size_t CS_MAX_STRING_LENGTH = 96; +#else +constexpr size_t CS_MAX_STRING_LENGTH = 64; +#endif +constexpr size_t CS_MAX_STRING_LENGTH_OLD = 64; + +#include "quake2/bg_local.h" //============================================== +// player_state->stats[] indexes +enum player_stat_t { + // #define STAT_HEALTH_ICON 0 + STAT_HEALTH = 1, + STAT_AMMO_ICON = 2, + STAT_AMMO = 3, + // STAT_ARMOR_ICON = 4, + STAT_ARMOR = 5, + STAT_SELECTED_ICON = 6, + STAT_PICKUP_ICON = 7, + STAT_PICKUP_STRING = 8, + STAT_TIMER_ICON = 9, + STAT_TIMER = 10, + STAT_HELPICON = 11, + STAT_SELECTED_ITEM = 12, + STAT_LAYOUTS = 13, + STAT_SCORE = 14, + STAT_FLASHES = 15, // cleared each frame, 1 = health, 2 = armor + STAT_CHASE = 16, + + //K03 Begin + STAT_TEAM_ICON = 17, + STAT_STATION_ICON = 18, + STAT_STATION_TIME = 19, + STAT_CHARGE_LEVEL = 20, + STAT_INVASIONTIME = 21, // -az + STAT_VOTESTRING = 22, + // STAT_RANK = 24, + STAT_ID_DAMAGE = 24, + STAT_STREAK = 25, + STAT_ID_ARMOR = 26, + STAT_SELECTED_NUM = 27, + STAT_TIMEMIN = 28, + STAT_SPECTATOR = 29, + STAT_ID_HEALTH = 30, + STAT_ID_AMMO = 31, + //K03 End + +#ifdef VRX_REPRO + // [Kex] More stats for weapon wheel + STAT_WEAPONS_OWNED_1 = 32, + STAT_WEAPONS_OWNED_2 = 33, + STAT_AMMO_INFO_START = 34, + STAT_AMMO_INFO_END = STAT_AMMO_INFO_START + NUM_AMMO_STATS - 1, + STAT_POWERUP_INFO_START, + STAT_POWERUP_INFO_END = STAT_POWERUP_INFO_START + NUM_POWERUP_STATS - 1, + + STAT_XP_PERCENT, + + // [Paril-KEX] Key display + STAT_KEY_A, + STAT_KEY_B, + STAT_KEY_C, + + // [Paril-KEX] currently active wheel weapon (or one we're switching to) + STAT_ACTIVE_WHEEL_WEAPON, + // [Paril-KEX] top of screen coop respawn state + STAT_COOP_RESPAWN, + // [Paril-KEX] respawns remaining + STAT_LIVES, + // [Paril-KEX] hit marker; # of damage we successfully landed + STAT_HIT_MARKER, + // [Paril-KEX] + STAT_SELECTED_ITEM_NAME, + // [Paril-KEX] + STAT_HEALTH_BARS, // two health bar values; 7 bits for value, 1 bit for active + // [Paril-KEX] + STAT_ACTIVE_WEAPON, + // az, for repro higher capacity numbers + STAT_ID_DAMAGE2, + STAT_SCORE2, +#endif + // don't use; just for verification + STAT_LAST +} +; + +#ifdef VRX_REPRO +#define MAX_STATS 64 +#else +#define MAX_STATS 32 +#endif + +static_assert(STAT_LAST <= MAX_STATS, "playerstats overfilled"); + // entity_state_t->event values // ertity events are for effects that take place reletive // to an existing entities origin. Very network efficient. // All muzzle flashes really should be converted to events... -typedef enum -{ - EV_NONE, - EV_ITEM_RESPAWN, - EV_FOOTSTEP, - EV_FALLSHORT, - EV_FALL, - EV_FALLFAR, - EV_PLAYER_TELEPORT, - EV_OTHER_TELEPORT +typedef enum { + EV_NONE, + EV_ITEM_RESPAWN, + EV_FOOTSTEP, + EV_FALLSHORT, + EV_FALL, + EV_FALLFAR, + EV_PLAYER_TELEPORT, + EV_OTHER_TELEPORT, + +#ifdef VRX_REPRO + // [Paril-KEX] + EV_OTHER_FOOTSTEP, + EV_LADDER_STEP, +#endif } entity_event_t; +#ifdef VRX_REPRO +// [Paril-KEX] player s.skinnum's encode additional data +union player_skinnum_t { + int32_t skinnum; + + struct { + uint8_t client_num; // client index + uint8_t vwep_index; // vwep index + int8_t viewheight; // viewheight + uint8_t team_index: 4; // team #; note that teams are 1-indexed here, with 0 meaning no team + // (spectators in CTF would be 0, for instance) + uint8_t poi_icon: 4; // poi icon; 0 default friendly, 1 dead, others unused + }; +}; +#endif // entity_state_t is the information conveyed from the server // in an update message about entities that the client will // need to render in some way -typedef struct entity_state_s -{ - int number; // edict index - - vec3_t origin; - vec3_t angles; - vec3_t old_origin; // for lerping - int modelindex; - int modelindex2, modelindex3, modelindex4; // weapons, CTF flags, etc - int frame; - int skinnum; - unsigned int effects; // PGM - we're filling it, so it needs to be unsigned - int renderfx; - int solid; // for client side prediction, 8*(bits 0-4) is x/y radius - // 8*(bits 5-9) is z down distance, 8(bits10-15) is z up - // gi.linkentity sets this properly - int sound; // for looping sounds, to guarantee shutoff - int event; // impulse events -- muzzle flashes, footsteps, etc - // events only go out for a single frame, they - // are automatically cleared each frame +typedef struct entity_state_s { + uint32_t number; // edict index + + vec3_t origin; + vec3_t angles; + vec3_t old_origin; // for lerping + int32_t modelindex; + int32_t modelindex2, modelindex3, modelindex4; // weapons, CTF flags, etc + int32_t frame; + int32_t skinnum; + enum effects_t effects; // PGM - we're filling it, so it needs to be unsigned + enum renderfx_t renderfx; + uint32_t solid; // for client side prediction, 8*(bits 0-4) is x/y radius + // 8*(bits 5-9) is z down distance, 8(bits10-15) is z up + // gi.linkentity sets this properly + int32_t sound; // for looping sounds, to guarantee shutoff + entity_event_t event; // impulse events -- muzzle flashes, footsteps, etc + // events only go out for a single frame, they + // are automatically cleared each frame + +#ifdef VRX_REPRO + float alpha; // [Paril-KEX] alpha scalar; 0 is a "default" value, which will respect other + // settings (default 1.0 for most things, EF_TRANSLUCENT will default this + // to 0.3, etc) + float scale; // [Paril-KEX] model scale scalar; 0 is a "default" value, like with alpha. + uint8_t instance_bits; // [Paril-KEX] players that *can't* see this entity will have a bit of 1. handled by + // the server, do not set directly. + // [Paril-KEX] allow specifying volume/attn for looping noises; note that + // zero will be defaults (1.0 and 3.0 respectively); -1 attenuation is used + // for "none" (similar to target_speaker) for no phs/pvs looping noises + float loop_volume; + float loop_attenuation; + // [Paril-KEX] for proper client-side owner collision skipping + int32_t owner; + // [Paril-KEX] for custom interpolation stuff + int32_t old_frame; +#endif } entity_state_t; //============================================== @@ -1192,51 +1720,70 @@ typedef struct entity_state_s // to rendered a view. There will only be 10 player_state_t sent each second, // but the number of pmove_state_t changes will be reletive to client // frame rates -typedef struct -{ - pmove_state_t pmove; // for prediction +typedef struct { + pmove_state_t pmove; // for prediction + + // these fields do not need to be communicated bit-precise + + vec3_t viewangles; // for fixed views + vec3_t viewoffset; // add to pmovestate->origin + vec3_t kick_angles; // add to view direction to get render angles + // set by weapon kicks, pain effects, etc - // these fields do not need to be communicated bit-precise + vec3_t gunangles; + vec3_t gunoffset; + int32_t gunindex; +#ifdef VRX_REPRO + int32_t gunskin; +#endif + int32_t gunframe; +#ifdef VRX_REPRO + int32_t gunrate; // [Paril-KEX] tickrate of gun animations; 0 and 10 are equivalent +#endif - vec3_t viewangles; // for fixed views - vec3_t viewoffset; // add to pmovestate->origin - vec3_t kick_angles; // add to view direction to get render angles - // set by weapon kicks, pain effects, etc + float screen_blend[4]; // rgba full screen effect +#ifdef VRX_REPRO + float damage_blend[4]; // [Paril-KEX] rgba full screen effect +#endif - vec3_t gunangles; - vec3_t gunoffset; - int gunindex; - int gunframe; + float fov; // horizontal field of view - float blend[4]; // rgba full screen effect - - float fov; // horizontal field of view + enum refdef_flags_t rdflags; // refdef flags - int rdflags; // refdef flags + int16_t stats[MAX_STATS]; // fast status bar updates - short stats[MAX_STATS]; // fast status bar updates +#ifdef VRX_REPRO + uint8_t team_id; +#endif } player_state_t; -// ================== -// PGM -#define VIDREF_GL 1 -#define VIDREF_SOFT 2 -#define VIDREF_OTHER 3 - -extern int vidref_val; -// PGM // ================== // Wrapped, thread safe mem allocation. void *vrx_malloc(size_t Size, int Tag); -void vrx_free (void* mem); -double sigmoid (const double x); +void vrx_free(void *mem); + +double sigmoid(const double x); + int sigmoid_distribute(int min, int max, int value); -int rand_sigmoid_distribute (int min, int max); + +int rand_sigmoid_distribute(int min, int max); // rng a number within the range with a uniform distribution n times and take the average. // simulates a bell curve. more iters = more centralized int rand_clt_distribute(int min, int max, int itercnt); +#define BITSET(count, name) \ +uint32_t name[count / 32 + 1] = {0} + +#define BITSET_SET(bitset, n) {\ +size_t index = (n) / 32;\ +size_t bit = 1 << ((n) % 32);\ +bitset[index] |= bit;\ +} + +#define BITSET_GET(bitset, n) \ +(bitset[n / 32] & ((1 << n) % 32)) + #endif diff --git a/src/quake2/bg_local.h b/src/quake2/bg_local.h new file mode 100644 index 00000000..8a3e5ad4 --- /dev/null +++ b/src/quake2/bg_local.h @@ -0,0 +1,240 @@ +#pragma once + +// define GAME_INCLUDE so that game.h does not define the +// short, server-visible gclient_t and edict_t structures, +// because we define the full size ones in this file +#define GAME_INCLUDE +#include "game.h" + + +// +// p_move.c +// +typedef struct +{ + int32_t airaccel; + qboolean n64_physics; +} pm_config_t; + +extern pm_config_t pm_config; + +void Pmove(pmove_t *pmove); +typedef trace_t (*pm_trace_func_t)(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end); +void PM_StepSlideMove_Generic(vec3_t origin, vec3_t velocity, float frametime, const vec3_t mins, const vec3_t maxs, touch_list_t *touch, qboolean has_time, pm_trace_func_t trace); + +typedef enum +{ + STUCK_GOOD_POSITION, + STUCK_FIXED, + STUCK_NO_GOOD_POSITION +} stuck_result_t; + +typedef trace_t (*stuck_object_trace_fn_t)(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end); + +stuck_result_t G_FixStuckObject_Generic(vec3_t origin, const vec3_t own_mins, const vec3_t own_maxs, stuck_object_trace_fn_t trace); + +// state for coop respawning; used to select which +// message to print for the player this is set on. +typedef enum +{ + COOP_RESPAWN_NONE, // no messagee + COOP_RESPAWN_IN_COMBAT, // player is in combat + COOP_RESPAWN_BAD_AREA, // player not in a good spot + COOP_RESPAWN_BLOCKED, // spawning was blocked by something + COOP_RESPAWN_WAITING, // for players that are waiting to respawn + COOP_RESPAWN_NO_LIVES, // out of lives, so need to wait until level switch + COOP_RESPAWN_TOTAL +} coop_respawn_t; + +// reserved general CS ranges +#define MAX_SIDEBAR_LAYOUT 1024 +#define SIDEBAR_MAX_CONFIGSTRINGS (MAX_SIDEBAR_LAYOUT / CS_MAX_STRING_LENGTH) +enum +{ + // az: reserved for vortex + CONFIG_CHASE = CS_GENERAL + 1, + CONFIG_SIDEBAR = CONFIG_CHASE + 1, // 11 * 96 = 1056 (sidebar layout string) + CONFIG_CTF_MATCH = CONFIG_SIDEBAR + SIDEBAR_MAX_CONFIGSTRINGS, + CONFIG_CTF_TEAMINFO, + CONFIG_CTF_PLAYER_NAME, + CONFIG_CTF_PLAYER_NAME_END = CONFIG_CTF_PLAYER_NAME + MAX_CLIENTS, + + // nb: offset by 1 since NONE is zero + CONFIG_COOP_RESPAWN_STRING, + CONFIG_COOP_RESPAWN_STRING_END = CONFIG_COOP_RESPAWN_STRING + (COOP_RESPAWN_TOTAL - 1), + + // [Paril-KEX] if 1, n64 player physics apply + CONFIG_N64_PHYSICS, + CONFIG_HEALTH_BAR_NAME, // active health bar name + + CONFIG_STORY, + + CONFIG_LAST +}; + +_Static_assert(CONFIG_LAST <= CS_GENERAL + MAX_GENERAL, "config list overflow"); + +// powerup IDs +typedef enum +{ + POWERUP_SCREEN, + POWERUP_SHIELD, + + POWERUP_AM_BOMB, + + POWERUP_QUAD, + POWERUP_QUADFIRE, + POWERUP_INVULNERABILITY, + POWERUP_INVISIBILITY, + POWERUP_SILENCER, + POWERUP_REBREATHER, + POWERUP_ENVIROSUIT, + POWERUP_ADRENALINE, + POWERUP_IR_GOGGLES, + POWERUP_DOUBLE, + POWERUP_SPHERE_VENGEANCE, + POWERUP_SPHERE_HUNTER, + POWERUP_SPHERE_DEFENDER, + POWERUP_DOPPELGANGER, + + POWERUP_FLASHLIGHT, + POWERUP_COMPASS, + POWERUP_TECH1, + POWERUP_TECH2, + POWERUP_TECH3, + POWERUP_TECH4, + POWERUP_MAX +} powerup_t; + +typedef enum +{ + AMMO_BULLETS = 1, + AMMO_SHELLS = 2, + AMMO_ROCKETS = 3, + AMMO_GRENADES = 4, + AMMO_CELLS = 5, + AMMO_SLUGS = 6, + // RAFAEL + AMMO_MAGSLUG = 7, + AMMO_TRAP = 8, + // 3.5 + AMMO_GENERATOR = 9, + + // ROGUE + AMMO_FLECHETTES, + AMMO_TESLA, + AMMO_DISRUPTOR, + AMMO_PROX, + // ROGUE + AMMO_MAX +} ammo_t; + + +// ammo stats compressed in 9 bits per entry +// since the range is 0-300 +#define BITS_PER_AMMO 9 + +#define num_of_type_for_bits(TI, num_bits) ((num_bits + (sizeof(TI) * 8) - 1) / ((sizeof(TI) * 8))) + +#define set_compressed_integer(bits_per_value, start, id, count) { \ + uint16_t bit_offset = bits_per_value * id; \ + uint16_t byte_off = bit_offset / 8; \ + uint16_t bit_shift = bit_offset % 8; \ + uint16_t mask = ((1 << bits_per_value) - 1) << bit_shift; \ + uint16_t *base = (uint16_t *) ((uint8_t *) start + byte_off); \ + *base = (*base & ~mask) | ((count << bit_shift) & mask); \ +} + +#define get_compressed_integer(bits_per_value, start, id) ({ \ + uint16_t bit_offset = bits_per_value * id; \ + uint16_t byte_off = bit_offset / 8; \ + uint16_t bit_shift = bit_offset % 8; \ + uint16_t mask = ((1 << bits_per_value) - 1) << bit_shift; \ + uint16_t *base = (uint16_t *) ((uint8_t *) start + byte_off); \ + (*base & mask) >> bit_shift; \ +}) + +#define NUM_BITS_FOR_AMMO 9 +#define NUM_AMMO_STATS num_of_type_for_bits(uint16_t, NUM_BITS_FOR_AMMO * AMMO_MAX) +// if this value is set on an STAT_AMMO_INFO_xxx, don't render ammo +#define AMMO_VALUE_INFINITE ((1 << NUM_BITS_FOR_AMMO) - 1) + +static inline void G_SetAmmoStat(uint16_t *start, uint8_t ammo_id, uint16_t count) +{ + set_compressed_integer(NUM_BITS_FOR_AMMO, start, ammo_id, count); +} + +static inline uint16_t G_GetAmmoStat(uint16_t *start, uint8_t ammo_id) +{ + return get_compressed_integer(NUM_BITS_FOR_AMMO, start, ammo_id); +} + +// powerup stats compressed in 2 bits per entry; +// 3 is the max you'll ever hold, and for some +// (flashlight) it's to indicate on/off state +#define NUM_BITS_PER_POWERUP 2 +constexpr size_t NUM_POWERUP_STATS = num_of_type_for_bits(uint16_t, NUM_BITS_PER_POWERUP * POWERUP_MAX); + +static inline void G_SetPowerupStat(uint16_t *start, uint8_t powerup_id, uint16_t count) +{ + set_compressed_integer(NUM_BITS_PER_POWERUP, start, powerup_id, count); +} + +static inline uint16_t G_GetPowerupStat(uint16_t *start, uint8_t powerup_id) +{ + return get_compressed_integer(NUM_BITS_PER_POWERUP, start, powerup_id); +} + +// player_state->stats[] indexes +typedef enum +{ + BG_STAT_CTF_TEAM1_PIC = 18, + BG_STAT_CTF_TEAM1_CAPS = 19, + BG_STAT_CTF_TEAM2_PIC = 20, + BG_STAT_CTF_TEAM2_CAPS = 21, + BG_STAT_CTF_FLAG_PIC = 22, + BG_STAT_CTF_JOINED_TEAM1_PIC = 23, + BG_STAT_CTF_JOINED_TEAM2_PIC = 24, + BG_STAT_CTF_TEAM1_HEADER = 25, + BG_STAT_CTF_TEAM2_HEADER = 26, + BG_STAT_CTF_TECH = 27, + BG_STAT_CTF_ID_VIEW = 28, + BG_STAT_CTF_MATCH = 29, + BG_STAT_CTF_ID_VIEW_COLOR = 30, + BG_STAT_CTF_TEAMINFO = 31, + + // [Kex] More stats for weapon wheel + BG_STAT_WEAPONS_OWNED_1 = 32, + BG_STAT_WEAPONS_OWNED_2 = 33, + BG_STAT_AMMO_INFO_START = 34, + BG_STAT_AMMO_INFO_END = BG_STAT_AMMO_INFO_START + NUM_AMMO_STATS - 1, + BG_STAT_POWERUP_INFO_START, + BG_STAT_POWERUP_INFO_END = BG_STAT_POWERUP_INFO_START + NUM_POWERUP_STATS - 1, + + // [Paril-KEX] Key display + BG_STAT_KEY_A, + BG_STAT_KEY_B, + BG_STAT_KEY_C, + + // [Paril-KEX] currently active wheel weapon (or one we're switching to) + BG_STAT_ACTIVE_WHEEL_WEAPON, + // [Paril-KEX] top of screen coop respawn state + BG_STAT_COOP_RESPAWN, + // [Paril-KEX] respawns remaining + BG_STAT_LIVES, + // [Paril-KEX] hit marker; # of damage we successfully landed + BG_STAT_HIT_MARKER, + // [Paril-KEX] + BG_STAT_SELECTED_ITEM_NAME, + // [Paril-KEX] + BG_STAT_HEALTH_BARS, // two health bar values; 7 bits for value, 1 bit for active + // [Paril-KEX] + BG_STAT_ACTIVE_WEAPON, + + // don't use; just for verification + BG_STAT_LAST +} bg_player_stat_t; + +// [KEX] we have a lot of stats, but let's just make sure we don't overflow the max. +// MAX_STATS is usually 32 in vanilla, but we might have increased it. +_Static_assert(BG_STAT_LAST <= 128, "stats list overflow"); \ No newline at end of file diff --git a/src/quake2/g_chase.c b/src/quake2/g_chase.c index 05e82ea5..471a854b 100644 --- a/src/quake2/g_chase.c +++ b/src/quake2/g_chase.c @@ -113,7 +113,7 @@ void UpdateChaseCam (edict_t *ent) if (eyecam) { // save current player fov - float fov = ent->client->ps.fov; + const float fov = ent->client->ps.fov; if (targ->viewheight) start[2] += targ->viewheight; @@ -191,7 +191,7 @@ void UpdateChaseCam (edict_t *ent) vec3_t dist; VectorSubtract(goal, pivot, dist); - vec_t len = VectorLength(dist); + const vec_t len = VectorLength(dist); if (len < 24) { eyecam = true; goto retry_eyecam; diff --git a/src/quake2/g_cmds.c b/src/quake2/g_cmds.c index 2c22040a..cdb69126 100644 --- a/src/quake2/g_cmds.c +++ b/src/quake2/g_cmds.c @@ -208,41 +208,58 @@ void FL_think (edict_t *self) self->nextthink = level.time + FRAMETIME; } +bool create_flashlight_entity(edict_t *self, vec3_t start, vec3_t forward, vec3_t right, vec3_t end) { + if (self->flashlight) + { + G_FreeEdict(self->flashlight); + self->flashlight = NULL; + return true; + } + if (self->client) + AngleVectors(self->client->v_angle, forward, right, NULL); + else + AngleVectors(self->s.angles, forward, right, NULL); + VectorSet(end, 100, 0, 0); + G_ProjectSource(self->s.origin, end, forward, right, start); + self->flashlight = G_Spawn (); + self->flashlight->owner = self; + self->flashlight->movetype = MOVETYPE_NOCLIP; + self->flashlight->solid = SOLID_NOT; + self->flashlight->classname = "flashlight"; + self->flashlight->s.modelindex = gi.modelindex ("models/objects/flash/tris.md2"); + self->flashlight->s.skinnum = 0; + self->flashlight->s.effects |= 0x10000000; //transparency + self->flashlight->s.effects |= EF_HYPERBLASTER; + + self->flashlight->think = FL_think; + self->flashlight->nextthink = level.time + FRAMETIME; + return false; +} + /* =============== FL_make =============== */ -void FL_make(edict_t *self) +void FL_toggle(edict_t *self) { vec3_t start,forward,right,end; - if (self->flashlight) - { - G_FreeEdict(self->flashlight); - self->flashlight = NULL; - return; - } - if (self->client) - AngleVectors(self->client->v_angle, forward, right, NULL); - else - AngleVectors(self->s.angles, forward, right, NULL); - VectorSet(end, 100, 0, 0); - G_ProjectSource(self->s.origin, end, forward, right, start); - self->flashlight = G_Spawn (); - self->flashlight->owner = self; - self->flashlight->movetype = MOVETYPE_NOCLIP; - self->flashlight->solid = SOLID_NOT; - self->flashlight->classname = "flashlight"; - self->flashlight->s.modelindex = gi.modelindex ("models/objects/flash/tris.md2"); - self->flashlight->s.skinnum = 0; - self->flashlight->s.effects |= 0x10000000; //transparency - self->flashlight->s.effects |= EF_HYPERBLASTER; - - self->flashlight->think = FL_think; - self->flashlight->nextthink = level.time + FRAMETIME; - -} +#ifndef VRX_REPRO + if (create_flashlight_entity(self, start, forward, right, end)) return; +#else + self->flags ^= FL_FLASHLIGHT; +#endif + +} + +bool FL_exists(edict_t *self) { +#ifndef VRX_REPRO + return self->flashlight != NULL; +#else + return self->flags & FL_FLASHLIGHT; +#endif +} //K03 End char *ClientTeam (const edict_t *ent) @@ -980,7 +997,7 @@ Use an inventory item void Cmd_Use_f (edict_t *ent) { int index; - int weapMode=ent->client->weapon_mode; + const int weapMode=ent->client->weapon_mode; gitem_t *it; char *s; @@ -1344,7 +1361,7 @@ void Cmd_WeapLast_f (edict_t *ent) // player-monsters switch between weapon modes if (ent->mtype || PM_PlayerHasMonster(ent)) { - int currentMode = ent->client->weapon_mode; + const int currentMode = ent->client->weapon_mode; ent->client->weapon_mode = ent->client->last_weapon_mode; ent->client->last_weapon_mode = currentMode; @@ -1384,7 +1401,7 @@ void Cmd_InvDrop_f (edict_t *ent) if (ent->myskills.administrator && ent->client->menustorage.menu_active) { - int index = ent->client->menustorage.messages[ent->client->menustorage.currentline].option-2; + const int index = ent->client->menustorage.messages[ent->client->menustorage.currentline].option-2; if (menu_active(ent, MENU_SPECIAL_UPGRADES, upgradeSpecialMenu_handler) && index < 500) { @@ -1517,8 +1534,8 @@ int PlayerSort (void const *a, void const *b) anum = *(int *)a; bnum = *(int *)b; - anum = game.clients[anum].ps.stats[STAT_FRAGS]; - bnum = game.clients[bnum].ps.stats[STAT_FRAGS]; + anum = game.clients[anum].ps.stats[STAT_SCORE]; + bnum = game.clients[bnum].ps.stats[STAT_SCORE]; if (anum < bnum) return -1; @@ -1557,7 +1574,7 @@ void Cmd_Players_f (edict_t *ent) for (i = 0 ; i < count ; i++) { Com_sprintf (smallq2, sizeof(smallq2), "%3i %s\n", - game.clients[indexq2[i]].ps.stats[STAT_FRAGS], + game.clients[indexq2[i]].ps.stats[STAT_SCORE], game.clients[indexq2[i]].pers.netname); if (strlen (smallq2) + strlen(largeq2) > sizeof(largeq2) - 100 ) { // can't print all of them in one packet @@ -1699,7 +1716,7 @@ void Cmd_Say_f (edict_t *ent, qboolean team, qboolean arg0) // master password prompt if (menu_active(ent, MENU_MASTER_PASSWORD, masterpw_handler) && !strcmp(ent->myskills.email, "")) { - int len=strlen(p); + const int len=strlen(p); // check for valid input if ((len < 4) || (len > 23) || strstr(p, "@")) @@ -2292,7 +2309,7 @@ void Cmd_SetOwner_f (edict_t *ent) return; } - int mpwlen = strlen(mpw); + const int mpwlen = strlen(mpw); if (mpwlen == 0) { safe_cprintf(ent, PRINT_HIGH, "Please include the master password of the owner.\n"); @@ -2630,7 +2647,7 @@ void Cmd_AdminCmd (edict_t *ent) } else if (Q_stricmp(cmd1, "srune") == 0) { - int index = atoi(cmd3); + const int index = atoi(cmd3); int type = ITEM_ABILITY; if (ent->myskills.administrator < 10) @@ -2860,7 +2877,7 @@ que_t *que_ptr (que_t *src, que_t *dst) qboolean GetOverloadValues (edict_t *ent, int talentLevel, int cubes, int cost, float *cost_mult, float *skill_mult) { // maximum skill/cost multiplier - float max_multiplier = 1 + 0.2 * talentLevel; + const float max_multiplier = 1 + 0.2 * talentLevel; // input skill/cost multiplier *cost_mult = (float)cubes / cost; @@ -3086,7 +3103,7 @@ void Cmd_Rune_f(edict_t *ent) { if (!strcmp(gi.argv(1), "manip")) { - int index = atoi(gi.argv(2)); + const int index = atoi(gi.argv(2)); if (index < 0) { safe_cprintf(ent, PRINT_LOW, "Very funny.\n"); @@ -3105,8 +3122,8 @@ void Cmd_Rune_f(edict_t *ent) { if (!strcmp(gi.argv(1), "swap")) { - int index = atoi(gi.argv(2)); // where from - int moveto = atoi(gi.argv(3)); // where to + const int index = atoi(gi.argv(2)); // where from + const int moveto = atoi(gi.argv(3)); // where to if (index < 3) // Equiped rune { @@ -3287,7 +3304,7 @@ void ClientCommand (edict_t *ent) //NewB else if (Q_stricmp (cmd, "trade") == 0) { - char *opt = gi.argv(1); + const char *opt = gi.argv(1); if (Q_strcasecmp(opt, "on") == 0) { safe_cprintf(ent, PRINT_HIGH, "Trading is enabled.\nPlayers may now trade with you.\n"); @@ -3396,7 +3413,7 @@ void ClientCommand (edict_t *ent) else if (Q_stricmp (cmd, "abilityindex") == 0) { //Return string of ability at that index - int index = atoi(gi.argv(1)); + const int index = atoi(gi.argv(1)); if ((index < 0) || (index > MAX_ABILITIES)) safe_cprintf(ent, PRINT_HIGH, "Bad Ability index: %d\n", index); else safe_cprintf(ent, PRINT_HIGH, "Ability number %d = %s\n", index, GetAbilityString(index)); @@ -3405,7 +3422,7 @@ void ClientCommand (edict_t *ent) //3.0 bless commands else if (Q_stricmp (cmd, "mute") == 0) { - int time = atoi(gi.argv(2)); + const int time = atoi(gi.argv(2)); if (time > 0) cmd_PlayerMute(ent, gi.argv(1), time); else safe_cprintf(ent, PRINT_HIGH, "Invalid mute duration.\n Command: mute \n"); } diff --git a/src/quake2/g_layout.c b/src/quake2/g_layout.c index e02b3938..ff9d25f9 100644 --- a/src/quake2/g_layout.c +++ b/src/quake2/g_layout.c @@ -1,3 +1,5 @@ +#include + #include "g_local.h" lva_result_t lva(const char* format, ...) @@ -245,7 +247,7 @@ qboolean layout_add_tracked_entity(layout_t* layout, edict_t* ent) qboolean layout_remove_tracked_entity(layout_t* layout, edict_t* ent) { - int index = layout_has_tracked_entity(layout, ent); + const int index = layout_has_tracked_entity(layout, ent); if (index == -1) return false; @@ -273,7 +275,7 @@ void layout_clean_tracked_entity_list(layout_t* layout) layout_pos_t sidebar_get_next_line_pos(sidebar_t* sidebar) { - layout_pos_t ret = layout_set_cursor_xy( + const layout_pos_t ret = layout_set_cursor_xy( 5, XM_LEFT, (sidebar->line + 2) * 8 + sidebar->y_offset, YM_CENTER ); @@ -720,7 +722,15 @@ void layout_send(edict_t* ent) if (ent->ai.is_bot) return; +#ifndef VRX_REPRO gi.WriteByte(svc_layout); gi.WriteString(ent->client->layout.layout); gi.unicast(ent, false); +#else + // as above but sent to CS_GENERAL + 2. + gi.WriteByte(svc_configstring); + gi.WriteShort(CONFIG_SIDEBAR); + gi.WriteString(ent->client->layout.layout); + gi.unicast(ent, false); +#endif } \ No newline at end of file diff --git a/src/quake2/g_main.c b/src/quake2/g_main.c index 002acaab..9d61be95 100644 --- a/src/quake2/g_main.c +++ b/src/quake2/g_main.c @@ -1,3 +1,5 @@ +#include + #include "g_local.h" #include "../gamemodes/ctf.h" #include "../gamemodes/v_hw.h" @@ -5,10 +7,17 @@ #include +#include "bg_local.h" +#include "q_recompat.h" + game_locals_t game; level_locals_t level; game_import_t gi; +#ifndef VRX_REPRO game_export_t globals; +#else +repro_export_t globals = {0}; +#endif spawn_temp_t st; int sm_meat_index; @@ -98,7 +107,6 @@ int pvm_average_level; qboolean SPREE_WAR; qboolean INVASION_OTHERSPAWNS_REMOVED; int next_invasion_wave_level; -qboolean found_flag; cvar_t *gamedir; cvar_t *hostname; @@ -181,10 +189,10 @@ cvar_t *generalabmode; void SpawnEntities(char *mapname, char *entities, char *spawnpoint); void ClientThink(edict_t *ent, usercmd_t *cmd); -qboolean ClientConnect(edict_t *ent, char *userinfo); +bool ClientConnect(edict_t *ent, char *userinfo, const char *social_id, bool is_bot); void ClientUserinfoChanged(edict_t *ent, char *userinfo); void ClientDisconnect(edict_t *ent); -void ClientBegin(edict_t *ent, qboolean loadgame); +void ClientBegin(edict_t *ent); void ClientCommand(edict_t *ent); void RunEntity(edict_t *ent); void WriteGame(char *filename, qboolean autosave); @@ -192,7 +200,11 @@ void ReadGame(char *filename); void WriteLevel(char *filename); void ReadLevel(char *filename); void InitGame(void); +#ifndef VRX_REPRO void G_RunFrame(void); +#else +void G_RunFrame(bool main_loop); +#endif void dom_init(void); void dom_awardpoints(void); void PTRCheckJoinedQue(void); @@ -231,12 +243,8 @@ void ShutdownGame(void) gi.FreeTags(TAG_GAME); } -#ifndef _WINDOWS -__attribute__((visibility("default"))) -#else -__declspec(dllexport) -#endif -game_export_t *GetGameAPI(game_import_t *import) +#ifndef VRX_REPRO +q_export game_export_t *GetGameAPI(game_import_t *import) { gi = *import; @@ -267,35 +275,78 @@ game_export_t *GetGameAPI(game_import_t *import) return &globals; } +#else + +bool CanSave() { + // not supported + return false; +} -#ifndef GAME_HARD_LINKED -// this is only here so the functions in q_shared.c and q_shwin.c can link -void Sys_Error(char *error, ...) +void PreInit(); +// TODO: all these missing thingies. +q_export repro_export_t *GetGameAPI(repro_import_t *import) { - va_list argptr; - char text[1024]; + vrx_repro_getgameapi(import, &gi); - va_start(argptr, error); - vsprintf(text, error, argptr); - va_end(argptr); + globals.apiversion = GAME_API_VERSION; + globals.PreInit = PreInit; + globals.Init = InitGame; + globals.Shutdown = ShutdownGame; + globals.SpawnEntities = SpawnEntities; + + globals.WriteGameJson = repro_write_game_json; + globals.ReadGameJson = repro_read_game_json; + globals.WriteLevelJson = repro_write_level_json; + globals.ReadLevelJson = repro_read_level_json; + + globals.CanSave = CanSave; + + globals.ClientChooseSlot = repro_choose_client_slot; + + globals.ClientConnect = ClientConnect; + globals.ClientBegin = ClientBegin; + globals.ClientUserinfoChanged = ClientUserinfoChanged; + globals.ClientDisconnect = ClientDisconnect; + globals.ClientCommand = ClientCommand; + globals.ClientThink = ClientThink; - gi.error(ERR_FATAL, "%s", text); + + globals.RunFrame = G_RunFrame; + globals.PrepFrame = repro_prep_frame; + + globals.ServerCommand = ServerCommand; + + globals.edict_size = sizeof(edict_t); + + globals.server_flags = SERVER_FLAGS_NONE; + globals.Pmove = Pmove; + globals.GetExtension = repro_get_extension; + globals.Bot_SetWeapon = repro_bot_set_weapon; + globals.Bot_TriggerEdict = repro_bot_trigger_edict; + globals.Bot_UseItem = repro_bot_use_item; + globals.Bot_GetItemID = repro_bot_get_item_id; + globals.Edict_ForceLookAtPoint = repro_edict_force_look_at_point; + globals.Bot_PickedUpItem = repro_bot_picked_up_item; + + globals.Entity_IsVisibleToPlayer = repro_visible_to_player; + globals.GetShadowLightData = repro_get_shadow_light_data; + + return &globals; } +#endif -void Com_Printf(char *msg, ...) +void Com_Printf(const char *msg, ...) { va_list argptr; char text[1024]; va_start(argptr, msg); - vsprintf(text, msg, argptr); + vsnprintf(text, sizeof(text), msg, argptr); va_end(argptr); gi.dprintf("%s", text); } -#endif - //====================================================================== @@ -544,7 +595,7 @@ void EndDMLevel(void) //Select a random map for this game mode while (1) { - int max = maplist->nummaps - 1; + const int max = maplist->nummaps - 1; // get a random map index from the map list if (max <= 0) { @@ -594,31 +645,7 @@ void EndDMLevel(void) } -/* -================= -CheckNeedPass -================= -*/ -void CheckNeedPass(void) -{ - int need; - - // if password or spectator_password has changed, update needpass - // as needed - if (password->modified || spectator_password->modified) - { - password->modified = spectator_password->modified = false; - - need = 0; - if (*password->string && Q_stricmp(password->string, "none")) - need |= 1; - if (*spectator_password->string && Q_stricmp(spectator_password->string, "none")) - need |= 2; - - gi.cvar_set("needpass", va("%d", need)); - } -} /* ================= @@ -631,7 +658,7 @@ void SP_target_speaker(edict_t *ent); void CheckDMRules(void) { int i, check;//K03 - float totaltime = ((timelimit->value * 60) - level.time);//K03 added totaltime + const float totaltime = ((timelimit->value * 60) - level.time);//K03 added totaltime gclient_t *cl; if (level.intermissiontime) @@ -904,17 +931,17 @@ double scale_fps(double value) { } uint64_t sf2qf(uint64_t framecount) { - double ratio = 10.0 / sv_fps->value; + const double ratio = 10.0 / sv_fps->value; uint64_t rounded = (uint64_t)round(framecount * ratio); if ( rounded == 0 ) { - uint64_t iratio = sv_fps->value / 10; + const uint64_t iratio = sv_fps->value / 10; rounded = level.framenum % iratio ? 0 : 1; } return rounded; } uint64_t qf2sf(uint64_t frames) { - double ratio = sv_fps->value / 10.0f; + const double ratio = sv_fps->value / 10.0f; return (uint64_t)round(frames * ratio); } @@ -928,7 +955,11 @@ Advances the world by void RunVotes(); +#ifndef VRX_REPRO void G_RunFrame(void) +#else +void G_RunFrame(bool main_loop) +#endif { int i;//j; edict_t *ent; @@ -1005,9 +1036,6 @@ void G_RunFrame(void) // see if it is time to end a deathmatch CheckDMRules(); - // see if needpass needs updated - CheckNeedPass(); - // build the playerstate_t structures for all players ClientEndServerFrames(); diff --git a/src/quake2/g_phys.c b/src/quake2/g_phys.c index 88524579..c1014e91 100644 --- a/src/quake2/g_phys.c +++ b/src/quake2/g_phys.c @@ -93,7 +93,7 @@ qboolean SV_RunThink (edict_t *ent) thinktime = ent->nextthink; if (thinktime <= 0) return true; - if (thinktime > level.time+0.001) + if (thinktime > level.time+FRAMETIME-0.001) return true; //gi.dprintf("SV_RunThink()\n"); //GHz START @@ -485,9 +485,6 @@ qboolean SV_Push (edict_t *pusher, vec3_t move, vec3_t amove) if (!check->solid) continue; //ponko - //r1: FIXME: what the fuck? - if(check->classname[0] == 'R' && (check->classname[6] == 'X' || check->classname[6] == '3') ) continue; - if (check->movetype == MOVETYPE_PUSH || check->movetype == MOVETYPE_STOP || check->movetype == MOVETYPE_NONE @@ -495,8 +492,13 @@ qboolean SV_Push (edict_t *pusher, vec3_t move, vec3_t amove) continue; // if(check->movetype == MOVETYPE_STEP) M_CheckGround(check); +#ifndef VRX_REPRO if (!check->area.prev) continue; // not linked in anywhere +#else + if (!check->linked) + continue; +#endif // if the entity is standing on the pusher, it will definitely be moved if (check->groundentity != pusher) @@ -722,7 +724,7 @@ void SV_Physics_Toss (edict_t *ent) qboolean isinwater; vec3_t old_origin; - qboolean forcethrough = false; + const qboolean forcethrough = false; // regular thinking SV_RunThink (ent); @@ -739,8 +741,6 @@ void SV_Physics_Toss (edict_t *ent) if (!ent->groundentity->inuse) ent->groundentity = NULL; - - // if onground, return without moving if (ent->groundentity) { @@ -748,7 +748,6 @@ void SV_Physics_Toss (edict_t *ent) return; } - VectorCopy (ent->s.origin, old_origin); SV_CheckVelocity (ent); @@ -800,7 +799,7 @@ void SV_Physics_Toss (edict_t *ent) // spikeball never stops bouncing if (ent->mtype == M_SPIKEBALL) { - float delta = 275 - ent->velocity[2]; + const float delta = 275 - ent->velocity[2]; // don't get stuck on the ceiling if (trace.plane.normal[2] != -1.0) diff --git a/src/quake2/g_save.c b/src/quake2/g_save.c index 50ba9517..1149abd4 100644 --- a/src/quake2/g_save.c +++ b/src/quake2/g_save.c @@ -173,13 +173,26 @@ is loaded. ============ */ +#ifdef VRX_REPRO +void PreInit() { + maxclients = gi.cvar("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH); + gi.cvar_forceset("sv_fps", va("%d", gire.tick_rate)); + + deathmatch = gire.cvar("deathmatch", "0", CVAR_LATCH); + coop = gire.cvar("coop", "0", CVAR_LATCH); + + if (!deathmatch->integer && !coop->integer) { + gire.cvar_forceset("deathmatch", "1"); + } +} +#endif + void InitGame(void) { gi.dprintf("==== InitGame ====\n"); - //K03 Begin srand((unsigned)time(0)); @@ -187,7 +200,6 @@ void InitGame(void) save_path = gi.cvar("save_path", va("%s//characters", gamedir->string), CVAR_LATCH); //K03 End - // az begin gi.cvar_forceset("g_features", va("%d", GMF_VARIABLE_FPS)); @@ -234,11 +246,13 @@ void InitGame(void) gi.cvar("gamename", GAMEVERSION, CVAR_SERVERINFO | CVAR_LATCH); gi.cvar("gamedate", __DATE__, CVAR_SERVERINFO | CVAR_LATCH); - maxclients = gi.cvar("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH); - deathmatch = gi.cvar("deathmatch", "0", CVAR_LATCH); - coop = gi.cvar("coop", "0", CVAR_LATCH); skill = gi.cvar("skill", "1", CVAR_SERVERINFO); +#ifndef VRX_REPRO + maxclients = gi.cvar("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH); maxentities = gi.cvar("maxentities", "1024", CVAR_LATCH); +#else + maxentities = gi.cvar("maxentities", "8096", CVAR_LATCH); +#endif //chain edit flag //vwep support vwep = gi.cvar("vwep", "1", CVAR_LATCH); @@ -411,19 +425,35 @@ void InitGame(void) // az: requires hostname and g_edicts to be initialized, so it's placed here vrx_relay_connect(); + vrx_fill_xp_accum_table(); //3.0 Load the custom map lists - if (vrx_load_map_list(MAPMODE_PVP) && vrx_load_map_list(MAPMODE_PVM) && vrx_load_map_list(MAPMODE_INV) - && vrx_load_map_list(MAPMODE_DOM) && vrx_load_map_list(MAPMODE_CTF) && vrx_load_map_list(MAPMODE_FFA) - && vrx_load_map_list(MAPMODE_TRA) && vrx_load_map_list(MAPMODE_INH) && vrx_load_map_list(MAPMODE_VHW) - && vrx_load_map_list(MAPMODE_TBI)) + const int modes[] = { + MAPMODE_PVP, + MAPMODE_PVM, + MAPMODE_INV, + MAPMODE_DOM, + MAPMODE_CTF, + MAPMODE_FFA, + MAPMODE_TRA, + MAPMODE_INH, + MAPMODE_VHW, + MAPMODE_TBI + }; + + qboolean mload_success = true; + for (int i = 0; i < (sizeof(modes) / sizeof(modes[0])); i++) { + if (!vrx_load_map_list(modes[i])) { + gi.dprintf("WARNING: Error loading custom map list (%d)\n", i); + mload_success = false; + } + } + + if (mload_success) gi.dprintf("INFO: Vortex Custom Map Lists loaded successfully\n"); - else - gi.dprintf("WARNING: Error loading custom map lists\n"); //3.0 Load the armory LoadArmory(); - InitializeTeamNumbers(); // for allies // az begin @@ -918,7 +948,10 @@ void ReadLevel(char *filename) ReadEdict(f, ent); // let the server rebuild world links for this ent + // TODO? +#ifndef VRX_REPRO memset(&ent->area, 0, sizeof(ent->area)); +#endif gi.linkentity(ent); } diff --git a/src/quake2/g_svcmds.c b/src/quake2/g_svcmds.c index c662972f..77bb7a27 100644 --- a/src/quake2/g_svcmds.c +++ b/src/quake2/g_svcmds.c @@ -664,7 +664,7 @@ void SVCmd_MakeBoss_f (void) void SVCmd_ChangeClass_f (void) { char *playername = gi.argv(2); - int newclass = getClassNum(gi.argv(3)); + const int newclass = getClassNum(gi.argv(3)); edict_t *p; if ((newclass < 1) || (newclass > CLASS_MAX)) @@ -683,7 +683,7 @@ void SVCmd_ExpHole_f() { char *pname = gi.argv(2); edict_t *p; - int value = atoi(gi.argv(3)); + const int value = atoi(gi.argv(3)); if ((value < 0) || (value > 1000000) || (strlen(pname) < 1)) { @@ -706,7 +706,7 @@ void SVCmd_SetTeam_f() { char *pname = gi.argv(2); edict_t *p; - int value = atoi(gi.argv(3)); + const int value = atoi(gi.argv(3)); if ((value < 0) || (strlen(pname) < 0)) { @@ -779,7 +779,7 @@ void DoMaplistFilename(int mode, char* filename); void SV_AddMapToMaplist() { - int mode = atoi(gi.argv(2)); + const int mode = atoi(gi.argv(2)); char* map = gi.argv(3); char filename[256]; qboolean IsAppend = true; diff --git a/src/quake2/g_utils.c b/src/quake2/g_utils.c index 163f30d4..e4f67dde 100644 --- a/src/quake2/g_utils.c +++ b/src/quake2/g_utils.c @@ -1077,26 +1077,30 @@ qboolean G_EntIsAlive(const edict_t *ent) return true; } - -void G_RunFrames (edict_t *ent, int start_frame, int end_frame, qboolean reverse) +// if something is already limiting the frequency at which G_RunFrames is ran to 10hz +// and it is not ran every frame +// set limit_rate to true. +void G_RunFrames (edict_t *ent, int start_frame, int end_frame, qboolean reverse, bool limit_rate) { - if (reverse) - { - if ((ent->s.frame > start_frame) && (ent->s.frame <= end_frame)) - ent->s.frame--; - else - ent->s.frame = end_frame; - } - else - { - if ((ent->s.frame < end_frame) && (ent->s.frame >= start_frame)) - ent->s.frame++; + if ( ( level.framenum % qf2sf(1) ) == 0 || !limit_rate) { + if (reverse) + { + if ((ent->s.frame > start_frame) && (ent->s.frame <= end_frame)) + ent->s.frame--; + else + ent->s.frame = end_frame; + } else - ent->s.frame = start_frame; + { + if ((ent->s.frame < end_frame) && (ent->s.frame >= start_frame)) + ent->s.frame++; + else + ent->s.frame = start_frame; + } } } -float distance (vec3_t p1, vec3_t p2) +float distance (const vec3_t p1, const vec3_t p2) { vec3_t v; @@ -1185,7 +1189,7 @@ edict_t *G_GetSummoner (const edict_t *ent) return NULL; } -qboolean G_ValidTargetEnt(edict_t *self, edict_t *target, qboolean alive) +qboolean G_ValidTargetEnt(const edict_t *self, const edict_t *target, qboolean alive) { if (alive) { if (!G_EntIsAlive(target)) @@ -1818,7 +1822,7 @@ float G_PushAwayFromPlane(vec3_t start, trace_t tr, vec3_t mins, vec3_t maxs) // calculate worst case distance VectorSet(size, fabs(mins[0]) + maxs[0], fabs(mins[1]) + maxs[1], fabs(mins[2]) + maxs[2]); // distance is half of the longest line (i.e diagonal) that can fit within our mins/maxs box - float max_dist = 0.5 * G_GetBoxHypotenuse(size) + 1; + const float max_dist = 0.5 * G_GetBoxHypotenuse(size) + 1; // calculate the pitch angle of the clipped solid vectoangles(tr.plane.normal, angles); diff --git a/src/quake2/game.h b/src/quake2/game.h index 8895f6bc..ea1c6d25 100644 --- a/src/quake2/game.h +++ b/src/quake2/game.h @@ -2,13 +2,45 @@ #define GAMEHEAD // game.h -- game dll information visible to server -#define GAME_API_VERSION 3 +#define GAME_API_VERSION 2023 +#define CGAME_API_VERSION 2022 +#include + +#include "q_shared.h" + +#define STEPSIZE 18 + +#define q_countof(a) (sizeof(a) / sizeof((a)[0])) + +enum water_level_t : uint8_t +{ + WATER_NONE, + WATER_FEET, + WATER_WAIST, + WATER_UNDER +}; // edict->svflags +enum svflags_t : uint32_t +{ + SVF_NONE = 0, // no serverflags + SVF_NOCLIENT = 1 << 0, // don't send entity to clients, even if it has effects + SVF_DEADMONSTER = 1 << 1, // treat as CONTENTS_DEADMONSTER for collision + SVF_MONSTER = 1 << 2, // treat as CONTENTS_MONSTER for collision +#ifdef VRX_REPRO + SVF_PLAYER = 1 << 3, // [Paril-KEX] treat as CONTENTS_PLAYER for collision + SVF_BOT = 1 << 4, // entity is controlled by a bot AI. + SVF_NOBOTS = 1 << 5, // don't allow bots to use/interact with entity + SVF_RESPAWNING = 1 << 6, // entity will respawn on it's next think. + SVF_PROJECTILE = 1 << 7, // treat as CONTENTS_PROJECTILE for collision + SVF_INSTANCED = 1 << 8, // entity has different visibility per player + SVF_DOOR = 1 << 9, // entity is a door of some kind + SVF_NOCULL = 1 << 10, // always send, even if we normally wouldn't + SVF_HULL = 1 << 11 // always use hull when appropriate (triggers, etc; for gi.clip) +#endif +}; + -#define SVF_NOCLIENT 0x00000001 // don't send entity to clients, even if it has effects -#define SVF_DEADMONSTER 0x00000002 // treat as CONTENTS_DEADMONSTER for collision -#define SVF_MONSTER 0x00000004 // treat as CONTENTS_MONSTER for collision // edict->solid values @@ -20,6 +52,19 @@ typedef enum SOLID_BSP // bsp clip, touch on edge } solid_t; +// bitflags for STAT_LAYOUTS +enum layout_flags_t : int16_t +{ + LAYOUTS_LAYOUT = 1 << 0, // svc_layout is active; escape remapped to putaway + LAYOUTS_INVENTORY = 1 << 1, // inventory is active; escape remapped to putaway + LAYOUTS_HIDE_HUD = 1 << 2, // hide entire hud, for cameras, etc + LAYOUTS_INTERMISSION = 1 << 3, // intermission is being drawn; collapse splitscreen into 1 view + LAYOUTS_HELP = 1 << 4, // help is active; escape remapped to putaway + LAYOUTS_HIDE_CROSSHAIR = 1 << 5, // hide crosshair only + LAYOUTS_SIDEBAR = 1 << 6, +}; + + //=============================================================== // link_t is only used for entity area links now @@ -30,53 +75,20 @@ typedef struct link_s #define MAX_ENT_CLUSTERS 16 - typedef struct edict_s edict_t; typedef struct gclient_s gclient_t; +//=============================================================== -#ifndef GAME_INCLUDE - -typedef struct gclient_s -{ - player_state_t ps; // communicated by server to clients - int ping; - // the game dll can add anything it wants after - // this point in the structure -} gclient_t; - - -struct edict_s -{ - entity_state_t s; - struct gclient_s *client; - qboolean inuse; - int linkcount; - - // FIXME: move these fields to a server private sv_entity_t - link_t area; // linked to a division node or leaf - - int num_clusters; // if -1, use headnode instead - int clusternums[MAX_ENT_CLUSTERS]; - int headnode; // unused if num_clusters != -1 - int areanum, areanum2; - - //================================ - - int svflags; // SVF_NOCLIENT, SVF_DEADMONSTER, SVF_MONSTER, etc - vec3_t mins, maxs; - vec3_t absmin, absmax, size; - solid_t solid; - int clipmask; - edict_t *owner; - - // the game dll can add anything it wants after - // this point in the structure -}; - -#endif // GAME_INCLUDE +#if (!defined _MSC_VER) && ((defined __linux__) || (defined __APPLE__)) +#define q_export __attribute__((visibility("default"))) +#elif defined(_WIN32) +#define q_export __declspec(dllexport) +#endif -//=============================================================== +#ifndef q_export +#define q_export +#endif // // functions provided by the main engine @@ -88,7 +100,7 @@ typedef struct void (*dprintf) (const char *fmt, ...); void (*cprintf) (const edict_t *ent, int printlevel, const char *fmt, ...); void (*centerprintf) (const edict_t *ent, const char *fmt, ...); - void (*sound) (const edict_t *ent, int channel, int soundindex, float volume, float attenuation, float timeofs); + void (*sound) (const edict_t *ent, enum soundchan_t channel, int soundindex, float volume, float attenuation, float timeofs); void (*positioned_sound) (vec3_t origin, edict_t *ent, int channel, int soundindex, float volume, float attenuation, float timeofs); // config strings hold all the index strings, the lightstyles, @@ -137,7 +149,7 @@ typedef struct void (*WriteAngle) (float f); // managed memory allocation - void *(*TagMalloc) (int size, int tag); + void *(*TagMalloc) (size_t size, int tag); void (*TagFree) (void *block); void (*FreeTags) (int tag); @@ -217,4 +229,182 @@ typedef struct } game_export_t; game_export_t *GetGameApi (game_import_t *import); -#endif \ No newline at end of file + +// generic rectangle +struct vrect_t +{ + int32_t x, y, width, height; +}; + +enum text_align_t +{ + LEFT, + CENTER, + RIGHT +}; + +// transient data from server +struct cg_server_data_t +{ + char layout[1024]; + int16_t inventory[MAX_ITEMS]; +}; + +constexpr int32_t PROTOCOL_VERSION_3XX = 34; +constexpr int32_t PROTOCOL_VERSION_DEMOS = 2022; +constexpr int32_t PROTOCOL_VERSION = 2023; + +struct player_state_t; + +// +// functions provided by main engine for client +// +struct cgame_import_t +{ + uint32_t tick_rate; + float frame_time_s; + uint32_t frame_time_ms; + + // print to appropriate places (console, log file, etc) + void (*Com_Print)(const char *msg); + + // config strings hold all the index strings, the lightstyles, + // and misc data like the sky definition and cdtrack. + // All of the current configstrings are sent to clients when + // they connect, and changes are sent to all connected clients. + const char *(*get_configstring)(int num); + + void (*Com_Error)(const char *message); + + // managed memory allocation + void *(*TagMalloc)(size_t size, int tag); + void (*TagFree)(void *block); + void (*FreeTags)(int tag); + + // console variable interaction + cvar_t *(*cvar)(const char *var_name, const char *value, enum cvar_flags_t flags); + cvar_t *(*cvar_set)(const char *var_name, const char *value); + cvar_t *(*cvar_forceset)(const char *var_name, const char *value); + + // add commands to the server console as if they were typed in + // for map changing, etc + void (*AddCommandString)(const char *text); + + // Fetch named extension from engine. + void *(*GetExtension)(const char *name); + + // Check whether current frame is valid + bool (*CL_FrameValid) (); + + // Get client frame time delta + float (*CL_FrameTime) (); + + // [Paril-KEX] cgame-specific stuff + uint64_t (*CL_ClientTime) (); + uint64_t (*CL_ClientRealTime) (); + int32_t (*CL_ServerFrame) (); + int32_t (*CL_ServerProtocol) (); + const char *(*CL_GetClientName) (int32_t index); + const char *(*CL_GetClientPic) (int32_t index); + const char *(*CL_GetClientDogtag) (int32_t index); + const char *(*CL_GetKeyBinding) (const char *binding); // fetch key bind for key, or empty string + bool (*Draw_RegisterPic) (const char *name); + void (*Draw_GetPicSize) (int *w, int *h, const char *name); // will return 0 0 if not found + void (*SCR_DrawChar)(int x, int y, int scale, int num, bool shadow); + void (*SCR_DrawPic) (int x, int y, int w, int h, const char *name); + void (*SCR_DrawColorPic)(int x, int y, int w, int h, const char* name, const rgba_t* color); + + // [Paril-KEX] kfont stuff + void(*SCR_SetAltTypeface)(bool enabled); + void (*SCR_DrawFontString)(const char *str, int x, int y, int scale, const rgba_t* color, bool shadow, enum text_align_t align); + vec2_t (*SCR_MeasureFontString)(const char *str, int scale); + float (*SCR_FontLineHeight)(int scale); + + // [Paril-KEX] for legacy text input (not used in lobbies) + bool (*CL_GetTextInput)(const char **msg, bool *is_team); + + // [Paril-KEX] FIXME this probably should be an export instead... + int32_t (*CL_GetWarnAmmoCount)(int32_t weapon_id); + + // === [KEX] Additional APIs === + // returns a *temporary string* ptr to a localized input + const char* (*Localize) (const char *base, const char **args, size_t num_args); + + // [Paril-KEX] Draw binding, for centerprint; returns y offset + int32_t (*SCR_DrawBind) (int32_t isplit, const char *binding, const char *purpose, int x, int y, int scale); + + // [Paril-KEX] + bool (*CL_InAutoDemoLoop) (); +}; + +// +// functions exported for client by game subsystem +// +struct cgame_export_t +{ + int apiversion; + + // the init/shutdown functions will be called between levels/connections + // and when the client initially loads. + void (*Init)(); + void (*Shutdown)(); + + // [Paril-KEX] hud drawing + void (*DrawHUD) ( + int32_t isplit, + const struct cg_server_data_t *data, + struct vrect_t hud_vrect, + struct vrect_t hud_safe, + int32_t scale, + int32_t playernum, + const struct player_state_t *ps + ); + + // [Paril-KEX] precache special pics used by hud + void (*TouchPics) (); + + // [Paril-KEX] layout flags; see layout_flags_t + enum layout_flags_t (*LayoutFlags) (const struct player_state_t *ps); + + // [Paril-KEX] fetch the current wheel weapon ID in use + int32_t (*GetActiveWeaponWheelWeapon) (const struct player_state_t *ps); + + // [Paril-KEX] fetch owned weapon IDs + uint32_t (*GetOwnedWeaponWheelWeapons) (const struct player_state_t *ps); + + // [Paril-KEX] fetch ammo count for given ammo id + int16_t (*GetWeaponWheelAmmoCount)(const struct player_state_t *ps, int32_t ammo_id); + + // [Paril-KEX] fetch powerup count for given powerup id + int16_t (*GetPowerupWheelCount)(const struct player_state_t *ps, int32_t powerup_id); + + // [Paril-KEX] fetch how much damage was registered by these stats + int16_t (*GetHitMarkerDamage)(const struct player_state_t *ps); + + // [KEX]: Pmove as export + void (*Pmove)(pmove_t *pmove); // player movement code called by server & client + + // [Paril-KEX] allow cgame to react to configstring changes + void (*ParseConfigString)(int32_t i, const char *s); + + // [Paril-KEX] parse centerprint-like messages + void (*ParseCenterPrint)(const char *str, int isplit, bool instant); + + // [Paril-KEX] tell the cgame to clear notify stuff + void (*ClearNotify)(int32_t isplit); + + // [Paril-KEX] tell the cgame to clear centerprint state + void (*ClearCenterprint)(int32_t isplit); + + // [Paril-KEX] be notified by the game DLL of a message of some sort + void (*NotifyMessage)(int32_t isplit, const char *msg, bool is_chat); + + // [Paril-KEX] + void (*GetMonsterFlashOffset)(enum monster_muzzleflash_id_t id, vec3_t offset); + + // Fetch named extension from cgame DLL. + void *(*GetExtension)(const char *name); +}; + + +#endif diff --git a/src/quake2/monsterframes/m_flash.c b/src/quake2/monsterframes/m_flash.c index 84576392..65f6d31f 100644 --- a/src/quake2/monsterframes/m_flash.c +++ b/src/quake2/monsterframes/m_flash.c @@ -5,7 +5,7 @@ // this file is included in both the game dll and quake2, // the game needs it to source shot locations, the client // needs it to position muzzle flashes -vec3_t monster_flash_offset [] = +vec3_t monster_flash_offset [212] = { // flash 0 is not used 0.0, 0.0, 0.0, diff --git a/src/quake2/p_client.c b/src/quake2/p_client.c index 785f58f1..61c56d55 100644 --- a/src/quake2/p_client.c +++ b/src/quake2/p_client.c @@ -214,7 +214,7 @@ int GetGender(edict_t *ent) { } char *GetPossesiveAdjective(edict_t *ent) { - int gender = GetGender(ent); + const int gender = GetGender(ent); char *info; switch( gender ) { @@ -235,7 +235,7 @@ char *GetPossesiveAdjective(edict_t *ent) { } char *GetReflexivePronoun(edict_t *ent) { - int gender = GetGender(ent); + const int gender = GetGender(ent); char *info; switch( gender ) { @@ -833,7 +833,7 @@ void TossClientWeapon (edict_t *self) qboolean quadfire; float dist; vec3_t v; - edict_t *enemy = NULL; + const edict_t *enemy = NULL; float spread; if(self->enemy && self->enemy != self) @@ -1102,8 +1102,8 @@ void InitClientPersistant (gclient_t *client) { //K03 Begin gitem_t *item; - - int spectator=client->pers.spectator; + + const int spectator=client->pers.spectator; if (debuginfo->value > 1) gi.dprintf("InitClientPersistant()\n"); @@ -1724,7 +1724,7 @@ void spectator_respawn (edict_t *ent) // exceed max_spectators if (ent->client->pers.spectator) { - char *value = Info_ValueForKey (ent->client->pers.userinfo, "spectator"); + const char *value = Info_ValueForKey (ent->client->pers.userinfo, "spectator"); if (*spectator_password->string && strcmp(spectator_password->string, "none") && strcmp(spectator_password->string, value)) { @@ -1753,7 +1753,7 @@ void spectator_respawn (edict_t *ent) } else { // he was a spectator and wants to join the game // he must have the right password - char *value = Info_ValueForKey (ent->client->pers.userinfo, "password"); + const char *value = Info_ValueForKey (ent->client->pers.userinfo, "password"); if (*password->string && strcmp(password->string, "none") && strcmp(password->string, value)) { safe_cprintf(ent, PRINT_HIGH, "Password incorrect.\n"); @@ -1938,6 +1938,7 @@ void PutClientInServer (edict_t *ent) client->ps.pmove.origin[0] = spawn_origin[0]*8; client->ps.pmove.origin[1] = spawn_origin[1]*8; client->ps.pmove.origin[2] = spawn_origin[2]*8; + //ZOID client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION; //ZOID @@ -1958,11 +1959,16 @@ void PutClientInServer (edict_t *ent) if (client->pers.weapon)//K03 client->ps.gunindex = gi.modelindex(client->pers.weapon->view_model); + client->ps.pmove.viewheight = ent->viewheight; + // clear entity state values ent->s.effects = 0; ent->s.skinnum = ent - g_edicts - 1; + // az: 255 = PLAYER MODEL. Repro sets mi2 as well. ent->s.modelindex = 255; // will use the skin specified model -// ent->s.modelindex2 = 255; // custom gun model +#ifdef VRX_REPRO + ent->s.modelindex2 = 255; // custom gun model +#endif ShowGun(ent); // ### Hentai ### special gun model ent->s.frame = 0; VectorCopy (spawn_origin, ent->s.origin); @@ -1970,9 +1976,13 @@ void PutClientInServer (edict_t *ent) VectorCopy (ent->s.origin, ent->s.old_origin); // set the delta angle +#ifndef VRX_REPRO for (i=0 ; i<3 ; i++) client->ps.pmove.delta_angles[i] = ANGLE2SHORT(spawn_angles[i] - client->resp.cmd_angles[i]); - +#else + for (i=0 ; i<3 ; i++) + client->ps.pmove.delta_angles[i] = (spawn_angles[i] - client->resp.cmd_angles[i]); +#endif ent->s.angles[PITCH] = 0; ent->s.angles[YAW] = spawn_angles[YAW]; ent->s.angles[ROLL] = 0; @@ -2258,7 +2268,11 @@ Changing levels will NOT cause this to be called again, but loadgames will. ============ */ +#ifndef VRX_REPRO qboolean ClientConnect (edict_t *ent, char *userinfo) +#else +bool ClientConnect (edict_t *ent, char *userinfo, const char* social_id, bool is_bot) +#endif { static int lastID = 1; char ip[16]; @@ -2278,8 +2292,6 @@ qboolean ClientConnect (edict_t *ent, char *userinfo) // Reset names! memset(ent->client->pers.netname, 0, sizeof(ent->client->pers.netname)-1); - - strncpy (ent->client->pers.netname, value, sizeof(ent->client->pers.netname)-1); // update current ip @@ -2296,8 +2308,6 @@ qboolean ClientConnect (edict_t *ent, char *userinfo) strncpy(ent->client->pers.current_ip, ip, sizeof(ent->client->pers.current_ip)-1); } - //Info_SetValueForKey(userinfo, "ip", value); - if (!ClientCanConnect(ent, userinfo)) return false; @@ -2540,6 +2550,12 @@ void think_trade(edict_t *ent); void BlinkStrike_think(edict_t* ent); void V_PickUpEntity(edict_t* ent); +trace_t SV_PM_Clip(const vec3_t start, const vec3_t *mins, const vec3_t *maxs, const vec3_t end, enum contents_t mask) +{ + return gire.clip(world, start, mins, maxs, end, mask); +} + + void ClientThink (edict_t *ent, usercmd_t *ucmd) { gclient_t *client; @@ -2614,9 +2630,12 @@ void ClientThink (edict_t *ent, usercmd_t *ucmd) memset (&pm, 0, sizeof(pm)); if (ent->movetype == MOVETYPE_NOCLIP) - client->ps.pmove.pm_type = PM_SPECTATOR; + // TODO - PM_SPECTATOR works differently from baseline. + client->ps.pmove.pm_type = PM_NOCLIP;//PM_SPECTATOR; else if (ent->deadflag) client->ps.pmove.pm_type = PM_DEAD; + else if (ent->flags & FL_COCOONED) + client->ps.pmove.pm_type = PM_FREEZE; else client->ps.pmove.pm_type = PM_NORMAL; //K03 Begin @@ -2638,7 +2657,7 @@ void ClientThink (edict_t *ent, usercmd_t *ucmd) //K03 End // reset jump flag - if (!ucmd->upmove) + if (cmd_standing(ucmd)) ent->client->jump = false; // double jump @@ -2660,21 +2679,35 @@ void ClientThink (edict_t *ent, usercmd_t *ucmd) ucmd->sidemove *= velocity_mod; } +#ifndef VRX_REPRO for (i=0 ; i<3 ; i++) { pm.s.origin[i] = ent->s.origin[i]*8; pm.s.velocity[i] = ent->velocity[i] * 8; } +#else + for (i=0 ; i<3 ; i++) + { + pm.s.origin[i] = ent->s.origin[i]; + pm.s.velocity[i] = ent->velocity[i]; + } +#endif if (memcmp(&client->old_pmove, &pm.s, sizeof(pm.s))) pm.snapinitial = true; pm.cmd = *ucmd; +#ifndef VRX_REPRO pm.trace = PM_trace; // adds default parms - - pm.pointcontents = gi.pointcontents; +#else + pm.player = ent; + pm.trace = gire.trace; + pm.clip = SV_PM_Clip; + VectorCopy(ent->client->ps.viewoffset, pm.viewoffset); + pm.pointcontents = gire.pointcontents; +#endif // perform a pmove gi.Pmove (&pm); @@ -2682,6 +2715,7 @@ void ClientThink (edict_t *ent, usercmd_t *ucmd) // az: for SPEED, run a Pmove twice // we don't wan't to compound on the existing velocity // thus we undo the change in velocity right after... +#ifndef VRX_REPRO if (velocity_mod > 1) { float oldZpos, oldZspeed; oldZpos = pm.s.origin[2]; @@ -2696,40 +2730,59 @@ void ClientThink (edict_t *ent, usercmd_t *ucmd) pm.s.origin[2] = oldZpos; pm.s.velocity[2] = oldZspeed; } +#endif // GHz START // if this is a morphed player, restore saved viewheight // this locks them into that viewheight - if (ent->mtype) + if (ent->mtype) { +#ifndef VRX_REPRO pm.viewheight = viewheight; +#else + pm.s.viewheight = viewheight; +#endif + } //GHz END - - // save results of pmove client->ps.pmove = pm.s; client->old_pmove = pm.s; for (i=0 ; i<3 ; i++) { +#ifndef VRX_REPRO ent->s.origin[i] = pm.s.origin[i]*0.125; ent->velocity[i] = pm.s.velocity[i]*0.125; +#else + // full precision + ent->s.origin[i] = pm.s.origin[i]; + ent->velocity[i] = pm.s.velocity[i]; +#endif } VectorCopy (pm.mins, ent->mins); VectorCopy (pm.maxs, ent->maxs); + // TODO +#ifndef VRX_REPRO if (!(ent->lockon == 1 && ent->enemy)){ client->resp.cmd_angles[0] = SHORT2ANGLE(ucmd->angles[0]); client->resp.cmd_angles[1] = SHORT2ANGLE(ucmd->angles[1]); client->resp.cmd_angles[2] = SHORT2ANGLE(ucmd->angles[2]); } +#else + if (!(ent->lockon == 1 && ent->enemy)){ + client->resp.cmd_angles[0] = (ucmd->angles[0]); + client->resp.cmd_angles[1] = (ucmd->angles[1]); + client->resp.cmd_angles[2] = (ucmd->angles[2]); + } +#endif //K03 Begin //4.07 can't superspeed while being hurt // pm = V_Think_ApplySuperSpeed(ent, ucmd, client, i, &pm, viewheight); - if (/*ent->groundentity && !pm.groundentity &&*/ (pm.cmd.upmove >= 10) /*&& (pm.waterlevel == 0)*/) + if (cmd_jumping(&pm.cmd)) { if (((ent->mtype == MORPH_BRAIN || ent->mtype == MORPH_MUTANT) && pm.waterlevel > 0) || (ent->groundentity && !pm.groundentity)) @@ -2744,7 +2797,11 @@ void ClientThink (edict_t *ent, usercmd_t *ucmd) { V_Player_Touchdown(ent); } +#ifndef VRX_REPRO ent->viewheight = pm.viewheight; +#else + ent->viewheight = pm.s.viewheight; +#endif ent->waterlevel = pm.waterlevel; ent->watertype = pm.watertype; ent->groundentity = pm.groundentity; @@ -2770,6 +2827,7 @@ void ClientThink (edict_t *ent, usercmd_t *ucmd) G_TouchTriggers (ent); // touch other objects +#ifndef VRX_REPRO for (i=0 ; itouch) continue; - other->touch (other, ent, NULL, NULL); + other->touch (other, ent, nullptr, nullptr); + } +#else + // touch other objects + for (i = 0; i < pm.touch.num; i++) + { + trace_t *tr = &pm.touch.traces[i]; + other = tr->ent; + + if (other->touch) + other->touch(other, ent, &tr->plane, tr->surface); } +#endif //3.0 begin doomie /************************************************************************* @@ -2839,7 +2909,7 @@ void ClientThink (edict_t *ent, usercmd_t *ucmd) // save light level the player is standing on for // monster sighting AI - ent->light_level = ucmd->lightlevel; + // ent->light_level = ucmd->; // fire weapon from final position if needed if (client->latched_buttons & BUTTON_ATTACK) @@ -2877,7 +2947,7 @@ void ClientThink (edict_t *ent, usercmd_t *ucmd) } if (client->resp.spectator) { - if (ucmd->upmove >= 10) { + if (cmd_jumping(ucmd)) { if (!(client->ps.pmove.pm_flags & PMF_JUMP_HELD)) { client->ps.pmove.pm_flags |= PMF_JUMP_HELD; if (client->chase_target) @@ -2885,8 +2955,11 @@ void ClientThink (edict_t *ent, usercmd_t *ucmd) else GetChaseTarget(ent); } - } else + } +#ifndef VRX_REPRO + else client->ps.pmove.pm_flags &= ~PMF_JUMP_HELD; +#endif } UpdateChaseCam(ent); @@ -2995,11 +3068,12 @@ void ClientBeginServerFrame (edict_t *ent) // run weapon animations if it hasn't been done by a ucmd_t if (!client->weapon_thunk -//ZOID + //ZOID && ent->movetype != MOVETYPE_NOCLIP -//ZOID - ) - Think_Weapon (ent); + //ZOID + ) { + Think_Weapon(ent); + } else client->weapon_thunk = false; diff --git a/src/quake2/p_hud.c b/src/quake2/p_hud.c index e44aa2bb..e60ce684 100644 --- a/src/quake2/p_hud.c +++ b/src/quake2/p_hud.c @@ -20,7 +20,7 @@ void MoveClientToIntermission(edict_t *ent) VectorCopy(level.intermission_angle, ent->client->ps.viewangles); ent->client->ps.pmove.pm_type = PM_FREEZE; ent->client->ps.gunindex = 0; - ent->client->ps.blend[3] = 0; + ent->client->ps.screen_blend[3] = 0; ent->client->ps.viewangles[ROLL] = 0; ent->client->ps.kick_angles[ROLL] = 0; @@ -1033,26 +1033,38 @@ void G_SetStats(edict_t *ent) // ent->client->ps.stats[STAT_LAYOUTS] = 0; - if (deathmatch->value) - { + if (deathmatch->value) { if (ent->client->pers.health <= 0 || level.intermissiontime - || ent->client->showscores || ent->client->pers.scanner_active || ent->client->layout.current_len) - ent->client->ps.stats[STAT_LAYOUTS] |= 1; + || ent->client->showscores || ent->client->pers.scanner_active +#ifndef VRX_REPRO + || ent->client->layout.current_len +#endif + ) + ent->client->ps.stats[STAT_LAYOUTS] |= LAYOUTS_LAYOUT; + +#ifdef VRX_REPRO + if (ent->client->layout.current_len) + ent->client->ps.stats[STAT_LAYOUTS] |= LAYOUTS_SIDEBAR; +#endif + if (ent->client->showinventory && ent->client->pers.health > 0) - ent->client->ps.stats[STAT_LAYOUTS] |= 2; + ent->client->ps.stats[STAT_LAYOUTS] |= LAYOUTS_INVENTORY; } else { if (ent->client->showscores || ent->client->showhelp) - ent->client->ps.stats[STAT_LAYOUTS] |= 1; + ent->client->ps.stats[STAT_LAYOUTS] |= LAYOUTS_LAYOUT; if (ent->client->showinventory && ent->client->pers.health > 0) - ent->client->ps.stats[STAT_LAYOUTS] |= 2; + ent->client->ps.stats[STAT_LAYOUTS] |= LAYOUTS_INVENTORY; } // // frags // - ent->client->ps.stats[STAT_FRAGS] = ent->client->resp.score; + ent->client->ps.stats[STAT_SCORE] = ent->client->resp.score; +#ifdef VRX_REPRO + ent->client->ps.stats[STAT_SCORE2] = ent->client->resp.score >> 16; +#endif // // help icon / current weapon if not shown @@ -1068,6 +1080,7 @@ void G_SetStats(edict_t *ent) //K03 Begin //ent->client->ps.stats[STAT_LEVEL] = ent->myskills.level; ent->client->ps.stats[STAT_STREAK] = ent->myskills.streak; + ent->client->ps.stats[STAT_XP_PERCENT] = vrx_get_xp_percent(ent->myskills.experience, ent->myskills.level); /*if (timelimit->value) time_left = (timelimit->value*60 - level.time); @@ -1082,7 +1095,7 @@ void G_SetStats(edict_t *ent) // az invasion stuff. if (invasion->value && level.time > pregame_time->value && !level.intermissiontime) { - int invtime = ceil(invasion_data.limitframe - level.time); + const int invtime = ceil(invasion_data.limitframe - level.time); if (invtime > 0) ent->client->ps.stats[STAT_INVASIONTIME] = invtime; else @@ -1107,8 +1120,20 @@ void G_SetStats(edict_t *ent) // id code //GHz End //GHz START - if (level.time > ent->lastdmg + 3) +#ifdef VRX_REPRO + // immediately clear the damage since we don't accumulate it. + // repro does the accumulating + ent->client->ps.stats[STAT_ID_DAMAGE] = ent->dmg_counter; + ent->client->ps.stats[STAT_ID_DAMAGE2] = ent->dmg_counter >> 16; + + ent->dmg_counter = 0; + +#else + if (level.time > ent->lastdmg + 3) { ent->client->ps.stats[STAT_ID_DAMAGE] = 0; + ent->dmg_counter = 0; + } +#endif //GHz END } @@ -1202,9 +1227,9 @@ void G_SetSpectatorStats(edict_t *ent) // layouts are independant in spectator cl->ps.stats[STAT_LAYOUTS] = 0; if (cl->pers.health <= 0 || level.intermissiontime || cl->showscores) - cl->ps.stats[STAT_LAYOUTS] |= 1; + cl->ps.stats[STAT_LAYOUTS] |= LAYOUTS_LAYOUT; if (cl->showinventory && cl->pers.health > 0) - cl->ps.stats[STAT_LAYOUTS] |= 2; + cl->ps.stats[STAT_LAYOUTS] |= LAYOUTS_INVENTORY; } diff --git a/src/quake2/p_move.c b/src/quake2/p_move.c new file mode 100644 index 00000000..a374fc3d --- /dev/null +++ b/src/quake2/p_move.c @@ -0,0 +1,1636 @@ +#include +#include +#include + +#define GAME_INCLUDE +#include "q_shared.h" +#include "q_recompat.h" + +#ifndef CONTENTS_CURRENT_UP +#define CONTENTS_CURRENT_UP CONTENT_CURRENTS_UP +#define CONTENTS_CURRENT_DOWN CONTENT_CURRENTS_DOWN +#endif + +static const vec3_t vec3_up = {0, 0, 1}; +static const vec3_t vec3_down = {0, 0, -1}; + + +typedef struct { + float distance; + vec3_t origin; +} good_pos_t; + +// [Paril-KEX] generic code to detect & fix a stuck object +stuck_result_t G_FixStuckObject_Generic(vec3_t origin, const vec3_t own_mins, const vec3_t own_maxs, + stuck_object_trace_fn_t trace) { + if (!trace(origin, own_mins, own_maxs, origin).startsolid) + return STUCK_GOOD_POSITION; + + good_pos_t good_positions[6]; + size_t num_good_positions = 0; + + struct { + int8_t normal[3]; + int8_t mins[3], maxs[3]; + } side_checks[] = { + {{0, 0, 1}, {-1, -1, 0}, {1, 1, 0}}, + {{0, 0, -1}, {-1, -1, 0}, {1, 1, 0}}, + {{1, 0, 0}, {0, -1, -1}, {0, 1, 1}}, + {{-1, 0, 0}, {0, -1, -1}, {0, 1, 1}}, + {{0, 1, 0}, {-1, 0, -1}, {1, 0, 1}}, + {{0, -1, 0}, {-1, 0, -1}, {1, 0, 1}}, + }; + + for (size_t sn = 0; sn < q_countof(side_checks); sn++) { + const void *side_v = &side_checks[sn]; + const struct { + int8_t normal[3]; + int8_t mins[3], maxs[3]; + } *side = side_v; + vec3_t start; + VectorCopy(origin, start); + vec3_t mins = {0}, maxs = {0}; + + for (size_t n = 0; n < 3; n++) { + if (side->normal[n] < 0) + start[n] += own_mins[n]; + else if (side->normal[n] > 0) + start[n] += own_maxs[n]; + + if (side->mins[n] == -1) + mins[n] = own_mins[n]; + else if (side->mins[n] == 1) + mins[n] = own_maxs[n]; + + if (side->maxs[n] == -1) + maxs[n] = own_mins[n]; + else if (side->maxs[n] == 1) + maxs[n] = own_maxs[n]; + } + + trace_t tr = trace(start, mins, maxs, start); + + int8_t needed_epsilon_fix = -1; + int8_t needed_epsilon_dir; + + if (tr.startsolid) { + for (size_t e = 0; e < 3; e++) { + if (side->normal[e] != 0) + continue; + + vec3_t ep_start; + VectorCopy(start, ep_start); + ep_start[e] += 1; + + tr = trace(ep_start, mins, maxs, ep_start); + + if (!tr.startsolid) { + VectorCopy(ep_start, start); + needed_epsilon_fix = (int8_t) e; + needed_epsilon_dir = 1; + break; + } + + ep_start[e] -= 2; + tr = trace(ep_start, mins, maxs, ep_start); + + if (!tr.startsolid) { + VectorCopy(ep_start, start); + needed_epsilon_fix = (int8_t) e; + needed_epsilon_dir = -1; + break; + } + } + } + + // no good + if (tr.startsolid) + continue; + + vec3_t opposite_start; + VectorCopy(origin, opposite_start); + const void *other_side_v = &side_checks[sn ^ 1]; + const struct { + int8_t normal[3]; + int8_t mins[3], maxs[3]; + } *other_side = other_side_v; + + for (size_t n = 0; n < 3; n++) { + if (other_side->normal[n] < 0) + opposite_start[n] += own_mins[n]; + else if (other_side->normal[n] > 0) + opposite_start[n] += own_maxs[n]; + } + + if (needed_epsilon_fix >= 0) + opposite_start[needed_epsilon_fix] += (float) needed_epsilon_dir; + + // potentially a good side; start from our center, push back to the opposite side + // to find how much clearance we have + tr = trace(start, mins, maxs, opposite_start); + + // ??? + if (tr.startsolid) + continue; + + // check the delta + vec3_t end; + VectorCopy(tr.endpos, end); + // push us very slightly away from the wall + for (size_t i = 0; i < 3; i++) + end[i] += (float) side->normal[i] * 0.125f; + + // calculate delta + vec3_t delta; + VectorSubtract(end, opposite_start, delta); + vec3_t new_origin; + VectorAdd(origin, delta, new_origin); + + if (needed_epsilon_fix >= 0) + new_origin[needed_epsilon_fix] += (float) needed_epsilon_dir; + + tr = trace(new_origin, own_mins, own_maxs, new_origin); + + // bad + if (tr.startsolid) + continue; + + VectorCopy(new_origin, good_positions[num_good_positions].origin); + good_positions[num_good_positions].distance = VectorLengthSqr(delta); + num_good_positions++; + } + + if (num_good_positions) { + // simple bubble sort for small array + for (size_t i = 0; i < num_good_positions; i++) { + for (size_t j = i + 1; j < num_good_positions; j++) { + if (good_positions[j].distance < good_positions[i].distance) { + good_pos_t temp = good_positions[i]; + good_positions[i] = good_positions[j]; + good_positions[j] = temp; + } + } + } + + VectorCopy(good_positions[0].origin, origin); + + return STUCK_FIXED; + } + + return STUCK_NO_GOOD_POSITION; +} + +// all of the locals will be zeroed before each +// pmove, just to make damn sure we don't have +// any differences when running on client or server + +struct pml_t { + vec3_t origin; // full float precision + vec3_t velocity; // full float precision + + vec3_t forward, right, up; + float frametime; + + csurface_t *groundsurface; + int groundcontents; + + vec3_t previous_origin; + vec3_t start_velocity; +}; + +pm_config_t pm_config; + +pmove_t *pm; +struct pml_t pml; + +// movement parameters +float pm_stopspeed = 100; +float pm_maxspeed = 300; +float pm_duckspeed = 100; +float pm_accelerate = 10; +float pm_wateraccelerate = 10; +float pm_friction = 6; +float pm_waterfriction = 1; +float pm_waterspeed = 400; +float pm_laddermod = 0.5f; + +/* + + walking up a step should kill some velocity + +*/ + +/* +================== +PM_ClipVelocity + +Slide off of the impacting object +returns the blocked flags (1 = floor, 2 = step / wall) +================== +*/ +#define STOP_EPSILON 0.1 + +void PM_ClipVelocity(const vec3_t in, const vec3_t normal, vec3_t out, float overbounce) { + float backoff; + float change; + int i; + + backoff = DotProduct(in, normal) * overbounce; + + for (i = 0; i < 3; i++) { + change = normal[i] * backoff; + out[i] = in[i] - change; + if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON) + out[i] = 0; + } +} + +trace_t PM_Clip(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, enum contents_t mask) { + return pm->clip(start, mins, maxs, end, mask); +} + +trace_t PM_Trace(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, enum contents_t mask) { + if (pm->s.pm_type == PM_SPECTATOR) + return PM_Clip(start, mins, maxs, end, MASK_SOLID); + + if (mask == 0) { + if (pm->s.pm_type == PM_DEAD || pm->s.pm_type == PM_GIB) + mask = MASK_DEADSOLID; + else if (pm->s.pm_type == PM_SPECTATOR) + mask = MASK_SOLID; + else + mask = MASK_PLAYERSOLID; + + if (pm->s.pm_flags & PMF_IGNORE_PLAYER_COLLISION) + mask &= ~CONTENTS_PLAYER; + } + + return pm->trace(start, mins, maxs, end, pm->player, mask); +} + +// only here to satisfy pm_trace_t +static trace_t PM_Trace_Auto(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end) { + return PM_Trace(start, mins, maxs, end, 0); +} + +/* +================== +PM_StepSlideMove + +Each intersection will try to step over the obstruction instead of +sliding along it. + +Returns a new origin, velocity, and contact entity +Does not modify any world state? +================== +*/ +#define MIN_STEP_NORMAL 0.7f // can't step up onto very steep slopes +#define MAX_CLIP_PLANES 5 + +static inline void PM_RecordTrace(touch_list_t *touch, trace_t *tr) { + if (touch->num == MAXTOUCH) + return; + + for (size_t i = 0; i < touch->num; i++) + if (touch->traces[i].ent == tr->ent) + return; + + touch->traces[touch->num++] = *tr; +} + +// [Paril-KEX] made generic so you can run this without +// needing a pml/pm +void PM_StepSlideMove_Generic(vec3_t origin, vec3_t velocity, float frametime, const vec3_t mins, const vec3_t maxs, + touch_list_t *touch, qboolean has_time, pm_trace_func_t trace_func) { + int bumpcount, numbumps; + vec3_t dir; + float d; + int numplanes; + vec3_t planes[MAX_CLIP_PLANES]; + vec3_t primal_velocity; + int i, j; + trace_t trace; + vec3_t end; + float time_left; + + numbumps = 4; + + VectorCopy(velocity, primal_velocity); + numplanes = 0; + + time_left = frametime; + + for (bumpcount = 0; bumpcount < numbumps; bumpcount++) { + for (i = 0; i < 3; i++) + end[i] = origin[i] + time_left * velocity[i]; + + trace = trace_func(origin, mins, maxs, end); + + if (trace.allsolid) { + // entity is trapped in another solid + velocity[2] = 0; // don't build up falling damage + + // save entity for contact + PM_RecordTrace(touch, &trace); + return; + } + + // [Paril-KEX] experimental attempt to fix stray collisions on curved + // surfaces; easiest to see on q2dm1 by running/jumping against the sides + // of the curved map. + if (trace.surface2) { + vec3_t clipped_a, clipped_b; + PM_ClipVelocity(velocity, trace.plane.normal, clipped_a, 1.01f); + PM_ClipVelocity(velocity, trace.plane2.normal, clipped_b, 1.01f); + + qboolean better = 0; + + for (int i = 0; i < 3; i++) { + if (fabsf(clipped_a[i]) < fabsf(clipped_b[i])) { + better = 1; + break; + } + } + + if (better) { + trace.plane = trace.plane2; + trace.surface = trace.surface2; + } + } + + if (trace.fraction > 0) { + // actually covered some distance + VectorCopy(trace.endpos, origin); + numplanes = 0; + } + + if (trace.fraction == 1) + break; // moved the entire distance + + // save entity for contact + PM_RecordTrace(touch, &trace); + + time_left -= time_left * trace.fraction; + + // slide along this plane + if (numplanes >= MAX_CLIP_PLANES) { + // this shouldn't really happen + VectorCopy(vec3_origin, velocity); + break; + } + + // + // if this is the same plane we hit before, nudge origin + // out along it, which fixes some epsilon issues with + // non-axial planes (xswamp, q2dm1 sometimes...) + // + for (i = 0; i < numplanes; i++) { + if (DotProduct(trace.plane.normal, planes[i]) > 0.99f) { + origin[0] += trace.plane.normal[0] * 0.01f; + origin[1] += trace.plane.normal[1] * 0.01f; + G_FixStuckObject_Generic(origin, mins, maxs, trace_func); + break; + } + } + + if (i < numplanes) + continue; + + VectorCopy(trace.plane.normal, planes[numplanes]); + numplanes++; + + // + // modify original_velocity so it parallels all of the clip planes + // + for (i = 0; i < numplanes; i++) { + PM_ClipVelocity(velocity, planes[i], velocity, 1.01f); + for (j = 0; j < numplanes; j++) + if (j != i) { + if (DotProduct(velocity, planes[j]) < 0) + break; // not ok + } + if (j == numplanes) + break; + } + + if (i != numplanes) { + // go along this plane + } else { + // go along the crease + if (numplanes != 2) { + VectorCopy(vec3_origin, velocity); + break; + } + CrossProduct(planes[0], planes[1], dir); + d = DotProduct(dir, velocity); + VectorScale(dir, d, velocity); + } + + // + // if velocity is against the original velocity, stop dead + // to avoid tiny oscillations in sloping corners + // + if (DotProduct(velocity, primal_velocity) <= 0) { + VectorCopy(vec3_origin, velocity); + break; + } + } + + if (has_time) { + VectorCopy(primal_velocity, velocity); + } +} + +static inline void PM_StepSlideMove_() { + PM_StepSlideMove_Generic(pml.origin, pml.velocity, pml.frametime, pm->mins, pm->maxs, &pm->touch, + (qboolean) pm->s.pm_time, PM_Trace_Auto); +} + +/* +================== +PM_StepSlideMove + +================== +*/ +void PM_StepSlideMove() { + vec3_t start_o, start_v; + vec3_t down_o, down_v; + trace_t trace; + float down_dist, up_dist; + // vec3_t delta; + vec3_t up, down; + + VectorCopy(pml.origin, start_o); + VectorCopy(pml.velocity, start_v); + + PM_StepSlideMove_(); + + VectorCopy(pml.origin, down_o); + VectorCopy(pml.velocity, down_v); + + VectorCopy(start_o, up); + up[2] += STEPSIZE; + + trace = PM_Trace(start_o, pm->mins, pm->maxs, up, 0); + if (trace.allsolid) + return; // can't step up + + float stepSize = trace.endpos[2] - start_o[2]; + + // try sliding above + VectorCopy(trace.endpos, pml.origin); + VectorCopy(start_v, pml.velocity); + + PM_StepSlideMove_(); + + // push down the final amount + VectorCopy(pml.origin, down); + down[2] -= stepSize; + + // [Paril-KEX] jitspoe suggestion for stair clip fix; store + // the old down position, and pick a better spot for downwards + // trace if the start origin's Z position is lower than the down end pt. + vec3_t original_down; + VectorCopy(down, original_down); + + if (start_o[2] < down[2]) + down[2] = start_o[2] - 1.f; + + trace = PM_Trace(pml.origin, pm->mins, pm->maxs, down, 0); + if (!trace.allsolid) { + // [Paril-KEX] from above, do the proper trace now + trace_t real_trace = PM_Trace(pml.origin, pm->mins, pm->maxs, original_down, 0); + VectorCopy(real_trace.endpos, pml.origin); + + // only an upwards jump is a stair clip + if (pml.velocity[2] > 0.f) { + pm->step_clip = 1; + } + } + + VectorCopy(pml.origin, up); + + // decide which one went farther + down_dist = (down_o[0] - start_o[0]) * (down_o[0] - start_o[0]) + (down_o[1] - start_o[1]) * ( + down_o[1] - start_o[1]); + up_dist = (up[0] - start_o[0]) * (up[0] - start_o[0]) + (up[1] - start_o[1]) * (up[1] - start_o[1]); + + if (down_dist > up_dist || trace.plane.normal[2] < MIN_STEP_NORMAL) { + VectorCopy(down_o, pml.origin); + VectorCopy(down_v, pml.velocity); + } + // [Paril-KEX] NB: this line being commented is crucial for ramp-jumps to work. + // thanks to Jitspoe for pointing this one out. + else // if (pm->s.pm_flags & PMF_ON_GROUND) + //!! Special case + // if we were walking along a plane, then we need to copy the Z over + pml.velocity[2] = down_v[2]; + + // Paril: step down stairs/slopes + if ((pm->s.pm_flags & PMF_ON_GROUND) && !(pm->s.pm_flags & PMF_ON_LADDER) && + (pm->waterlevel < WATER_WAIST || (!(pm->cmd.buttons & BUTTON_JUMP) && pml.velocity[2] <= 0))) { + VectorCopy(pml.origin, down); + down[2] -= STEPSIZE; + trace = PM_Trace(pml.origin, pm->mins, pm->maxs, down, 0); + if (trace.fraction < 1.f) { + VectorCopy(trace.endpos, pml.origin); + } + } +} + +/* +================== +PM_Friction + +Handles both ground friction and water friction +================== +*/ +void PM_Friction() { + float *vel; + float speed, newspeed, control; + float friction; + float drop; + + vel = &pml.velocity[0]; + + speed = sqrt(vel[0] * vel[0] + vel[1] * vel[1] + vel[2] * vel[2]); + if (speed < 1) { + vel[0] = 0; + vel[1] = 0; + return; + } + + drop = 0; + + // apply ground friction + if ((pm->groundentity && pml.groundsurface && !(pml.groundsurface->flags & SURF_SLICK)) || ( + pm->s.pm_flags & PMF_ON_LADDER)) { + friction = pm_friction; + control = speed < pm_stopspeed ? pm_stopspeed : speed; + drop += control * friction * pml.frametime; + } + + // apply water friction + if (pm->waterlevel && !(pm->s.pm_flags & PMF_ON_LADDER)) + drop += speed * pm_waterfriction * (float) pm->waterlevel * pml.frametime; + + // scale the velocity + newspeed = speed - drop; + if (newspeed < 0) { + newspeed = 0; + } + newspeed /= speed; + + vel[0] = vel[0] * newspeed; + vel[1] = vel[1] * newspeed; + vel[2] = vel[2] * newspeed; +} + +/* +============== +PM_Accelerate + +Handles user intended acceleration +============== +*/ +void PM_Accelerate(const vec3_t wishdir, float wishspeed, float accel) { + int i; + float addspeed, accelspeed, currentspeed; + + currentspeed = DotProduct(pml.velocity, wishdir); + addspeed = wishspeed - currentspeed; + if (addspeed <= 0) + return; + accelspeed = accel * pml.frametime * wishspeed; + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i = 0; i < 3; i++) + pml.velocity[i] += accelspeed * wishdir[i]; +} + +void PM_AirAccelerate(const vec3_t wishdir, float wishspeed, float accel) { + int i; + float addspeed, accelspeed, currentspeed, wishspd = wishspeed; + + if (wishspd > 30) + wishspd = 30; + currentspeed = DotProduct(pml.velocity, wishdir); + addspeed = wishspd - currentspeed; + if (addspeed <= 0) + return; + accelspeed = accel * wishspeed * pml.frametime; + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i = 0; i < 3; i++) + pml.velocity[i] += accelspeed * wishdir[i]; +} + +/* +============= +PM_AddCurrents +============= +*/ +void PM_AddCurrents(vec3_t wishvel) { + vec3_t v; + float s; + + // + // account for ladders + // + + if (pm->s.pm_flags & PMF_ON_LADDER) { + if (pm->cmd.buttons & (BUTTON_JUMP | BUTTON_CROUCH)) { + // [Paril-KEX]: if we're underwater, use full speed on ladders + const float ladder_speed = pm->waterlevel >= WATER_WAIST ? pm_maxspeed : 200; + + if (pm->cmd.buttons & BUTTON_JUMP) + wishvel[2] = ladder_speed; + else if (pm->cmd.buttons & BUTTON_CROUCH) + wishvel[2] = -ladder_speed; + } else if (pm->cmd.forwardmove) { + // [Paril-KEX] clamp the speed a bit so we're not too fast + const float ladder_speed = (pm->cmd.forwardmove < -200.f + ? -200.f + : (pm->cmd.forwardmove > 200.f ? 200.f : pm->cmd.forwardmove)); + + if (pm->cmd.forwardmove > 0) { + if (pm->viewangles[PITCH] < 15) + wishvel[2] = ladder_speed; + else + wishvel[2] = -ladder_speed; + } + // [Paril-KEX] allow using "back" arrow to go down on ladder + else if (pm->cmd.forwardmove < 0) { + // if we haven't touched ground yet, remove x/y so we don't + // slide off of the ladder + if (!pm->groundentity) + wishvel[0] = wishvel[1] = 0; + + wishvel[2] = ladder_speed; + } + } else + wishvel[2] = 0; + + // limit horizontal speed when on a ladder + // [Paril-KEX] unless we're on the ground + if (!pm->groundentity) { + // [Paril-KEX] instead of left/right not doing anything, + // have them move you perpendicular to the ladder plane + if (pm->cmd.sidemove) { + // clamp side speed so it's not jarring... + float ladder_speed = (pm->cmd.sidemove < -150.f + ? -150.f + : (pm->cmd.sidemove > 150.f ? 150.f : pm->cmd.sidemove)); + + if (pm->waterlevel < WATER_WAIST) + ladder_speed *= pm_laddermod; + + // check for ladder + vec3_t flatforward, spot; + flatforward[0] = pml.forward[0]; + flatforward[1] = pml.forward[1]; + flatforward[2] = 0; + VectorNormalize(flatforward); + + VectorMA(pml.origin, 1.0f, flatforward, spot); + trace_t trace = PM_Trace(pml.origin, pm->mins, pm->maxs, spot, CONTENTS_LADDER); + + if (trace.fraction != 1.f && (trace.contents & CONTENTS_LADDER)) { + vec3_t right; + CrossProduct(trace.plane.normal, vec3_up, right); + + wishvel[0] = wishvel[1] = 0; + VectorMA(wishvel, -ladder_speed, right, wishvel); + } + } else { + if (wishvel[0] < -25) + wishvel[0] = -25; + else if (wishvel[0] > 25) + wishvel[0] = 25; + + if (wishvel[1] < -25) + wishvel[1] = -25; + else if (wishvel[1] > 25) + wishvel[1] = 25; + } + } + } + + // + // add water currents + // + + if (pm->watertype & MASK_CURRENT) { + VectorClear(v); + + if (pm->watertype & CONTENTS_CURRENT_0) + v[0] += 1; + if (pm->watertype & CONTENTS_CURRENT_90) + v[1] += 1; + if (pm->watertype & CONTENTS_CURRENT_180) + v[0] -= 1; + if (pm->watertype & CONTENTS_CURRENT_270) + v[1] -= 1; + if (pm->watertype & CONTENT_CURRENTS_UP) + v[2] += 1; + if (pm->watertype & CONTENT_CURRENTS_DOWN) + v[2] -= 1; + + s = pm_waterspeed; + if ((pm->waterlevel == WATER_FEET) && (pm->groundentity)) + s /= 2; + + VectorMA(wishvel, s, v, wishvel); + } + + // + // add conveyor belt velocities + // + + if (pm->groundentity) { + VectorClear(v); + + if (pml.groundcontents & CONTENTS_CURRENT_0) + v[0] += 1; + if (pml.groundcontents & CONTENTS_CURRENT_90) + v[1] += 1; + if (pml.groundcontents & CONTENTS_CURRENT_180) + v[0] -= 1; + if (pml.groundcontents & CONTENTS_CURRENT_270) + v[1] -= 1; + if (pml.groundcontents & CONTENT_CURRENTS_UP) + v[2] += 1; + if (pml.groundcontents & CONTENT_CURRENTS_DOWN) + v[2] -= 1; + + for (int ci = 0; ci < 3; ci++) wishvel[ci] += v[ci] * 100; + } +} + +/* +=================== +PM_WaterMove + +=================== +*/ +void PM_WaterMove() { + int i; + vec3_t wishvel; + float wishspeed; + vec3_t wishdir; + + // + // user intentions + // + for (i = 0; i < 3; i++) + wishvel[i] = pml.forward[i] * pm->cmd.forwardmove + pml.right[i] * pm->cmd.sidemove; + + if (!pm->cmd.forwardmove && !pm->cmd.sidemove && + !(pm->cmd.buttons & (BUTTON_JUMP | BUTTON_CROUCH))) { + if (!pm->groundentity) + wishvel[2] -= 60; // drift towards bottom + } else { + if (pm->cmd.buttons & BUTTON_CROUCH) + wishvel[2] -= pm_waterspeed * 0.5f; + else if (pm->cmd.buttons & BUTTON_JUMP) + wishvel[2] += pm_waterspeed * 0.5f; + } + + PM_AddCurrents(wishvel); + + VectorCopy(wishvel, wishdir); + wishspeed = VectorNormalize(wishdir); + + if (wishspeed > pm_maxspeed) { + for (int wi = 0; wi < 3; wi++) wishvel[wi] *= pm_maxspeed / wishspeed; + wishspeed = pm_maxspeed; + } + wishspeed *= 0.5f; + + if ((pm->s.pm_flags & PMF_DUCKED) && wishspeed > pm_duckspeed) { + for (int wi = 0; wi < 3; wi++) wishvel[wi] *= pm_duckspeed / wishspeed; + wishspeed = pm_duckspeed; + } + + if (pm->s.pm_flags & PMF_SUPERSPEED) + wishspeed *= 3; + + PM_Accelerate(wishdir, wishspeed, pm_wateraccelerate); + + PM_StepSlideMove(); +} + +/* +=================== +PM_AirMove + +=================== +*/ +void PM_AirMove() { + int i; + vec3_t wishvel; + float fmove, smove; + vec3_t wishdir; + float wishspeed; + float maxspeed; + + fmove = pm->cmd.forwardmove; + smove = pm->cmd.sidemove; + + for (i = 0; i < 2; i++) + wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove; + wishvel[2] = 0; + + PM_AddCurrents(wishvel); + + VectorCopy(wishvel, wishdir); + wishspeed = VectorNormalize(wishdir); + + // + // clamp to server defined max speed + // + maxspeed = (pm->s.pm_flags & PMF_DUCKED) ? pm_duckspeed : pm_maxspeed; + + if (wishspeed > maxspeed) { + for (int wi = 0; wi < 3; wi++) wishvel[wi] *= maxspeed / wishspeed; + wishspeed = maxspeed; + } + + + if (pm->s.pm_flags & PMF_ON_LADDER) { + PM_Accelerate(wishdir, wishspeed, pm_accelerate); + if (!wishvel[2]) { + if (pml.velocity[2] > 0) { + pml.velocity[2] -= pm->s.gravity * pml.frametime; + if (pml.velocity[2] < 0) + pml.velocity[2] = 0; + } else { + pml.velocity[2] += pm->s.gravity * pml.frametime; + if (pml.velocity[2] > 0) + pml.velocity[2] = 0; + } + } + PM_StepSlideMove(); + } else if (pm->groundentity) { + // walking on ground + pml.velocity[2] = 0; //!!! this is before the accel + + const float mod_wishspeed = pm->s.pm_flags & PMF_SUPERSPEED ? wishspeed * 3 : wishspeed; + PM_Accelerate(wishdir, mod_wishspeed, pm_accelerate); + + // PGM -- fix for negative trigger_gravity fields + // pml.velocity[2] = 0; + if (pm->s.gravity > 0) + pml.velocity[2] = 0; + else + pml.velocity[2] -= pm->s.gravity * pml.frametime; + // PGM + + if (!pml.velocity[0] && !pml.velocity[1]) + return; + PM_StepSlideMove(); + } else { + // not on ground, so little effect on velocity + if (pm_config.airaccel) + PM_AirAccelerate(wishdir, wishspeed, pm_config.airaccel); + else + PM_Accelerate(wishdir, wishspeed, 1); + + // add gravity + const bool skipgravity = pm->s.pm_flags & PMF_CACODEMON && pm->cmd.buttons & BUTTON_JUMP; + if (pm->s.pm_type != PM_GRAPPLE && !skipgravity) + pml.velocity[2] -= pm->s.gravity * pml.frametime; + + PM_StepSlideMove(); + } +} + +static void PM_GetWaterLevel(const vec3_t position, enum water_level_t *level, enum contents_t *type) { + // + // get waterlevel, accounting for ducking + // + *level = WATER_NONE; + *type = CONTENTS_NONE; + + const int32_t sample2 = (int) (pm->s.viewheight - pm->mins[2]); + const int32_t sample1 = sample2 / 2; + + vec3_t point; + VectorCopy(position, point); + + point[2] += pm->mins[2] + 1; + + int cont = pm->pointcontents(point); + + if (cont & MASK_WATER) { + *type = cont; + *level = WATER_FEET; + point[2] = pml.origin[2] + pm->mins[2] + sample1; + cont = pm->pointcontents(point); + if (cont & MASK_WATER) { + *level = WATER_WAIST; + point[2] = pml.origin[2] + pm->mins[2] + sample2; + cont = pm->pointcontents(point); + if (cont & MASK_WATER) + *level = WATER_UNDER; + } + } +} + +/* +============= +PM_CatagorizePosition +============= +*/ +void PM_CatagorizePosition() { + vec3_t point; + trace_t trace; + + // if the player hull point one unit down is solid, the player + // is on ground + + // see if standing on something solid + point[0] = pml.origin[0]; + point[1] = pml.origin[1]; + point[2] = pml.origin[2] - 0.25f; + + if (pml.velocity[2] > 180 || pm->s.pm_type == PM_GRAPPLE) //!!ZOID changed from 100 to 180 (ramp accel) + { + pm->s.pm_flags &= ~PMF_ON_GROUND; + pm->groundentity = NULL; + } else { + trace = PM_Trace(pml.origin, pm->mins, pm->maxs, point, 0); + pm->groundplane = trace.plane; + pml.groundsurface = trace.surface; + pml.groundcontents = trace.contents; + + // [Paril-KEX] to attempt to fix edge cases where you get stuck + // wedged between a slope and a wall (which is irrecoverable + // most of the time), we'll allow the player to "stand" on + // slopes if they are right up against a wall + qboolean slanted_ground = trace.fraction < 1.0f && trace.plane.normal[2] < 0.7f; + + if (slanted_ground) { + vec3_t slant_end; + VectorAdd(pml.origin, trace.plane.normal, slant_end); + const trace_t slant = PM_Trace(pml.origin, pm->mins, pm->maxs, slant_end, 0); + + if (slant.fraction < 1.0f && !slant.startsolid) + slanted_ground = 0; + } + + if (trace.fraction == 1.0f || (slanted_ground && !trace.startsolid)) { + pm->groundentity = NULL; + pm->s.pm_flags &= ~PMF_ON_GROUND; + } else { + pm->groundentity = trace.ent; + + // hitting solid ground will end a waterjump + if (pm->s.pm_flags & PMF_TIME_WATERJUMP) { + pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT | PMF_TIME_TRICK); + pm->s.pm_time = 0; + } + + if (!(pm->s.pm_flags & PMF_ON_GROUND)) { + // just hit the ground + + // [Paril-KEX] + if (!pm_config.n64_physics && pml.velocity[2] >= 100.f && pm->groundplane.normal[2] >= 0.9f && !( + pm->s.pm_flags & PMF_DUCKED)) { + pm->s.pm_flags |= PMF_TIME_TRICK; + pm->s.pm_time = 64; + } + + // [Paril-KEX] calculate impact delta; this also fixes triple jumping + vec3_t clipped_velocity; + PM_ClipVelocity(pml.velocity, pm->groundplane.normal, clipped_velocity, 1.01f); + + pm->impact_delta = pml.start_velocity[2] - clipped_velocity[2]; + + pm->s.pm_flags |= PMF_ON_GROUND; + + if (pm_config.n64_physics || (pm->s.pm_flags & PMF_DUCKED)) { + pm->s.pm_flags |= PMF_TIME_LAND; + pm->s.pm_time = 128; + } + } + } + + if (pm->touch.num < MAXTOUCH) + pm->touch.traces[pm->touch.num++] = trace; + } + + // + // get waterlevel, accounting for ducking + // + PM_GetWaterLevel(pml.origin, &pm->waterlevel, &pm->watertype); +} + +/* +============= +PM_CheckJump +============= +*/ +void PM_CheckJump() { + if (pm->s.pm_type == PM_DEAD) + return; + + const bool cacodemon = (pm->s.pm_flags & PMF_CACODEMON); + if (pm->s.pm_flags & PMF_TIME_LAND && !cacodemon) { + // hasn't been long enough since landing to jump again + return; + } + + if (!(pm->cmd.buttons & BUTTON_JUMP)) { + // not holding jump + pm->s.pm_flags &= ~PMF_JUMP_HELD; + return; + } + + // must wait for jump to be released + if (pm->s.pm_flags & PMF_JUMP_HELD) + return; + + if (pm->waterlevel >= WATER_WAIST) { + // swimming, not jumping + pm->groundentity = NULL; + return; + } + + if (pm->groundentity == NULL && !cacodemon) + return; // in air, so no effect, except for cacodemon + + pm->s.pm_flags |= PMF_JUMP_HELD; + pm->jump_sound = 1; + pm->groundentity = NULL; + pm->s.pm_flags &= ~PMF_ON_GROUND; + + const float jump_height = 270.f; + + pml.velocity[2] += jump_height; + if (pml.velocity[2] < jump_height) + pml.velocity[2] = jump_height; +} + +/* +============= +PM_CheckSpecialMovement +============= +*/ +void PM_CheckSpecialMovement() { + vec3_t spot; + vec3_t flatforward; + trace_t trace; + + if (pm->s.pm_time) + return; + + pm->s.pm_flags &= ~PMF_ON_LADDER; + + // check for ladder + flatforward[0] = pml.forward[0]; + flatforward[1] = pml.forward[1]; + flatforward[2] = 0; + VectorNormalize(flatforward); + + VectorMA(pml.origin, 1, flatforward, spot); + trace = PM_Trace(pml.origin, pm->mins, pm->maxs, spot, CONTENTS_LADDER); + if ((trace.fraction < 1) && (trace.contents & CONTENTS_LADDER) && pm->waterlevel < WATER_WAIST) + pm->s.pm_flags |= PMF_ON_LADDER; + + if (!pm->s.gravity) + return; + + // check for water jump + // [Paril-KEX] don't try waterjump if we're moving against where we'll hop + if (!(pm->cmd.buttons & BUTTON_JUMP) + && pm->cmd.forwardmove <= 0) + return; + + if (pm->waterlevel != WATER_WAIST) + return; + // [Paril-KEX] + else if (pm->watertype & CONTENTS_NO_WATERJUMP) + return; + + // quick check that something is even blocking us forward + vec3_t spot40; + VectorMA(pml.origin, 40, flatforward, spot40); + trace = PM_Trace(pml.origin, pm->mins, pm->maxs, spot40, MASK_SOLID); + + // we aren't blocked, or what we're blocked by is something we can walk up + if (trace.fraction == 1.0f || trace.plane.normal[2] >= 0.7f) + return; + + // [Paril-KEX] improved waterjump + vec3_t waterjump_vel; + VectorScale(flatforward, 50, waterjump_vel); + waterjump_vel[2] = 350; + + // simulate what would happen if we jumped out here, and + // if we land on a dry spot we're good! + // simulate 1 sec worth of movement + touch_list_t touches; + vec3_t waterjump_origin; + VectorCopy(pml.origin, waterjump_origin); + const float time = 0.1f; + qboolean has_time = 1; + + int wj_max = (int32_t) (10 * (800.f / pm->s.gravity)); + if (wj_max > 50) wj_max = 50; + for (int i = 0; i < wj_max; i++) { + waterjump_vel[2] -= pm->s.gravity * time; + + if (waterjump_vel[2] < 0) + has_time = 0; + + PM_StepSlideMove_Generic(waterjump_origin, waterjump_vel, time, pm->mins, pm->maxs, &touches, has_time, + PM_Trace_Auto); + } + + // snap down to ground + vec3_t wj_down; + VectorSet(wj_down, waterjump_origin[0], waterjump_origin[1], waterjump_origin[2] - 2.f); + trace = PM_Trace(waterjump_origin, pm->mins, pm->maxs, wj_down, MASK_SOLID); + + // can't stand here + if (trace.fraction == 1.0f || trace.plane.normal[2] < 0.7f || + trace.endpos[2] < pml.origin[2]) + return; + + // we're currently standing on ground, and the snapped position + // is a step + if (pm->groundentity && fabsf(pml.origin[2] - trace.endpos[2]) <= STEPSIZE) + return; + + enum water_level_t level; + enum contents_t type; + + PM_GetWaterLevel(trace.endpos, &level, &type); + + // the water jump spot will be under water, so we're + // probably hitting something weird that isn't important + if (level >= WATER_WAIST) + return; + + // valid waterjump! + // jump out of water + VectorScale(flatforward, 50, pml.velocity); + pml.velocity[2] = 350; + + pm->s.pm_flags |= PMF_TIME_WATERJUMP; + pm->s.pm_time = 2048; +} + +/* +=============== +PM_FlyMove +=============== +*/ +void PM_FlyMove(qboolean doclip) { + float speed, drop, friction, control, newspeed; + float currentspeed, addspeed, accelspeed; + int i; + vec3_t wishvel; + float fmove, smove; + vec3_t wishdir; + float wishspeed; + + pm->s.viewheight = doclip ? 0 : 22; + + // friction + + speed = VectorLength(pml.velocity); + if (speed < 1) { + VectorCopy(vec3_origin, pml.velocity); + } else { + drop = 0; + + friction = pm_friction * 1.5f; // extra friction + control = speed < pm_stopspeed ? pm_stopspeed : speed; + drop += control * friction * pml.frametime; + + // scale the velocity + newspeed = speed - drop; + if (newspeed < 0) + newspeed = 0; + newspeed /= speed; + + for (int vi = 0; vi < 3; vi++) pml.velocity[vi] *= newspeed; + } + + // accelerate + fmove = pm->cmd.forwardmove; + smove = pm->cmd.sidemove; + + VectorNormalize(pml.forward); + VectorNormalize(pml.right); + + for (i = 0; i < 3; i++) + wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove; + + if (pm->cmd.buttons & BUTTON_JUMP) + wishvel[2] += 0.5f * pm_waterspeed; + if (pm->cmd.buttons & BUTTON_CROUCH) + wishvel[2] -= 0.5f * pm_waterspeed; + + VectorCopy(wishvel, wishdir); + wishspeed = VectorNormalize(wishdir); + + // + // clamp to server defined max speed + // + if (wishspeed > pm_maxspeed) { + for (int wi = 0; wi < 3; wi++) wishvel[wi] *= pm_maxspeed / wishspeed; + wishspeed = pm_maxspeed; + } + + // Paril: newer clients do this + wishspeed *= 2; + + currentspeed = DotProduct(pml.velocity, wishdir); + addspeed = wishspeed - currentspeed; + + if (addspeed > 0) { + accelspeed = pm_accelerate * pml.frametime * wishspeed; + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i = 0; i < 3; i++) + pml.velocity[i] += accelspeed * wishdir[i]; + } + + if (doclip) { + /*for (i = 0; i < 3; i++) + end[i] = pml.origin[i] + pml.frametime * pml.velocity[i]; + + trace = PM_Trace(pml.origin, pm->mins, pm->maxs, end); + + pml.origin = trace.endpos;*/ + + PM_StepSlideMove(); + } else { + // move + VectorMA(pml.origin, pml.frametime, pml.velocity, pml.origin); + } +} + +void PM_SetDimensions() { + pm->mins[0] = -16; + pm->mins[1] = -16; + + pm->maxs[0] = 16; + pm->maxs[1] = 16; + + if (pm->s.pm_type == PM_GIB) { + pm->mins[2] = 0; + pm->maxs[2] = 16; + pm->s.viewheight = 8; + return; + } + + pm->mins[2] = -24; + + if ((pm->s.pm_flags & PMF_DUCKED) || pm->s.pm_type == PM_DEAD) { + pm->maxs[2] = 4; + pm->s.viewheight = -2; + } else { + pm->maxs[2] = 32; + pm->s.viewheight = 22; + } +} + +static qboolean PM_AboveWater() { + vec3_t below; + VectorSet(below, pml.origin[0], pml.origin[1], pml.origin[2] - 8); + const qboolean solid_below = pm->trace((float *) pml.origin, (float *) pm->mins, (float *) pm->maxs, (float *) below, + pm->player, MASK_SOLID).fraction < 1.0f; + + if (solid_below) + return 0; + + const qboolean water_below = pm->trace(pml.origin, &pm->mins, &pm->maxs, below, pm->player, MASK_WATER).fraction < 1.0f; + + if (water_below) + return 1; + + return 0; +} + +/* +============== +PM_CheckDuck + +Sets mins, maxs, and pm->viewheight +============== +*/ +qboolean PM_CheckDuck() { + if (pm->s.pm_type == PM_GIB) + return 0; + + if (pm->s.pm_flags & PMF_NOCROUCH) { + return 0; + } + + trace_t trace; + qboolean flags_changed = 0; + + if (pm->s.pm_type == PM_DEAD) { + if (!(pm->s.pm_flags & PMF_DUCKED)) { + pm->s.pm_flags |= PMF_DUCKED; + flags_changed = 1; + } + } else if ( + (pm->cmd.buttons & BUTTON_CROUCH) && + (pm->groundentity || (pm->waterlevel <= WATER_FEET && !PM_AboveWater())) && + !(pm->s.pm_flags & PMF_ON_LADDER) && + !pm_config.n64_physics) { + // duck + if (!(pm->s.pm_flags & PMF_DUCKED)) { + // check that duck won't be blocked + const vec3_t check_maxs = {pm->maxs[0], pm->maxs[1], 4}; + trace = PM_Trace(pml.origin, pm->mins, check_maxs, pml.origin, 0); + if (!trace.allsolid) { + pm->s.pm_flags |= PMF_DUCKED; + flags_changed = 1; + } + } + } else { + // stand up if possible + if (pm->s.pm_flags & PMF_DUCKED) { + // try to stand up + const vec3_t check_maxs = {pm->maxs[0], pm->maxs[1], 32}; + trace = PM_Trace(pml.origin, pm->mins, check_maxs, pml.origin, 0); + if (!trace.allsolid) { + pm->s.pm_flags &= ~PMF_DUCKED; + flags_changed = 1; + } + } + } + + if (!flags_changed) + return 0; + + PM_SetDimensions(); + return 1; +} + +/* +============== +PM_DeadMove +============== +*/ +void PM_DeadMove() { + if (!pm->groundentity) + return; + + // extra friction + + float forward = VectorLength(pml.velocity); + forward -= 20; + if (forward <= 0) { + VectorClear(pml.velocity); + } else { + VectorNormalize(pml.velocity); + for (int vi = 0; vi < 3; vi++) pml.velocity[vi] *= forward; + } +} + +qboolean PM_GoodPosition() { + if (pm->s.pm_type == PM_NOCLIP) + return 1; + + const trace_t trace = PM_Trace(pm->s.origin, pm->mins, pm->maxs, pm->s.origin, 0); + + return !trace.allsolid; +} + +/* +================ +PM_SnapPosition + +On exit, the origin will have a value that is pre-quantized to the PMove +precision of the network channel and in a valid position. +================ +*/ +void PM_SnapPosition() { + VectorCopy(pml.velocity, pm->s.velocity); + VectorCopy(pml.origin, pm->s.origin); + + if (PM_GoodPosition()) + return; + + if (G_FixStuckObject_Generic(pm->s.origin, pm->mins, pm->maxs, PM_Trace_Auto) == STUCK_NO_GOOD_POSITION) { + VectorCopy(pml.previous_origin, pm->s.origin); + return; + } +} + +/* +================ +PM_InitialSnapPosition + +================ +*/ +void PM_InitialSnapPosition() { + int x, y, z; + vec3_t base; + const int offset[3] = {0, -1, 1}; + + VectorCopy(pm->s.origin, base); + + for (z = 0; z < 3; z++) { + pm->s.origin[2] = base[2] + offset[z]; + for (y = 0; y < 3; y++) { + pm->s.origin[1] = base[1] + offset[y]; + for (x = 0; x < 3; x++) { + pm->s.origin[0] = base[0] + offset[x]; + if (PM_GoodPosition()) { + VectorCopy(pm->s.origin, pml.origin); + VectorCopy(pm->s.origin, pml.previous_origin); + return; + } + } + } + } +} + +/* +================ +PM_ClampAngles + +================ +*/ +void PM_ClampAngles() { + if (pm->s.pm_flags & PMF_TIME_TELEPORT) { + pm->viewangles[YAW] = pm->cmd.angles[YAW] + pm->s.delta_angles[YAW]; + pm->viewangles[PITCH] = 0; + pm->viewangles[ROLL] = 0; + } else { + // circularly clamp the angles with deltas + for (int ai = 0; ai < 3; ai++) pm->viewangles[ai] = pm->cmd.angles[ai] + pm->s.delta_angles[ai]; + + // don't let the player look up or down more than 90 degrees + if (pm->viewangles[PITCH] > 89 && pm->viewangles[PITCH] < 180) + pm->viewangles[PITCH] = 89; + else if (pm->viewangles[PITCH] < 271 && pm->viewangles[PITCH] >= 180) + pm->viewangles[PITCH] = 271; + } + AngleVectors(pm->viewangles, pml.forward, pml.right, pml.up); +} + +// [Paril-KEX] +static void PM_ScreenEffects() { + // add for contents + vec3_t vieworg; + VectorAdd(pml.origin, pm->viewoffset, vieworg); + vieworg[2] += (float) pm->s.viewheight; + const int contents = pm->pointcontents(vieworg); + + if (contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) + pm->rdflags |= RDF_UNDERWATER; + else + pm->rdflags &= ~RDF_UNDERWATER; + + // screen blend effects omitted (G_AddBlend not available in pmove context) +} + +/* +================ +Pmove + +Can be called by either the server or the client +================ +*/ +void Pmove(pmove_t *pmove) { + pm = pmove; + + // clear results + pm->touch.num = 0; + VectorClear(pm->viewangles); + pm->s.viewheight = 0; + pm->groundentity = NULL; + pm->watertype = CONTENTS_NONE; + pm->waterlevel = WATER_NONE; + VectorClear(pm->screen_blend); + pm->rdflags = RDF_NONE; + pm->jump_sound = 0; + pm->step_clip = 0; + pm->impact_delta = 0; + + // clear all pmove local vars + memset(&pml, 0, sizeof(pml)); + + // convert origin and velocity to float values + VectorCopy(pm->s.origin, pml.origin); + VectorCopy(pm->s.velocity, pml.velocity); + + VectorCopy(pml.velocity, pml.start_velocity); + + // save old org in case we get stuck + VectorCopy(pm->s.origin, pml.previous_origin); + + pml.frametime = pm->cmd.msec * 0.001f; + + PM_ClampAngles(); + + if (pm->s.pm_type == PM_SPECTATOR || pm->s.pm_type == PM_NOCLIP) { + pm->s.pm_flags = PMF_NONE; + + if (pm->s.pm_type == PM_SPECTATOR) { + pm->mins[0] = -8; + pm->mins[1] = -8; + pm->maxs[0] = 8; + pm->maxs[1] = 8; + pm->mins[2] = -8; + pm->maxs[2] = 8; + } + + PM_FlyMove(pm->s.pm_type == PM_SPECTATOR); + PM_SnapPosition(); + return; + } + + if (pm->s.pm_type >= PM_DEAD) { + pm->cmd.forwardmove = 0; + pm->cmd.sidemove = 0; + pm->cmd.buttons &= ~(BUTTON_JUMP | BUTTON_CROUCH); + } + + if (pm->s.pm_type == PM_FREEZE) + return; // no movement at all + + // set mins, maxs, and viewheight + PM_SetDimensions(); + + // catagorize for ducking + PM_CatagorizePosition(); + + if (pm->snapinitial) + PM_InitialSnapPosition(); + + // set groundentity, watertype, and waterlevel + if (PM_CheckDuck()) + PM_CatagorizePosition(); + + if (pm->s.pm_type == PM_DEAD) + PM_DeadMove(); + + PM_CheckSpecialMovement(); + + // drop timing counter + if (pm->s.pm_time) { + if (pm->cmd.msec >= pm->s.pm_time) { + pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT | PMF_TIME_TRICK); + pm->s.pm_time = 0; + } else + pm->s.pm_time -= pm->cmd.msec; + } + + if (pm->s.pm_flags & PMF_TIME_TELEPORT) { + // teleport pause stays exactly in place + } else if (pm->s.pm_flags & PMF_TIME_WATERJUMP) { + // waterjump has no control, but falls + pml.velocity[2] -= pm->s.gravity * pml.frametime; + if (pml.velocity[2] < 0) { + // cancel as soon as we are falling down again + pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT | PMF_TIME_TRICK); + pm->s.pm_time = 0; + } + + PM_StepSlideMove(); + } else { + PM_CheckJump(); + + PM_Friction(); + + if (pm->waterlevel >= WATER_WAIST) + PM_WaterMove(); + else { + vec3_t angles; + + VectorCopy(pm->viewangles, angles); + if (angles[PITCH] > 180) + angles[PITCH] = angles[PITCH] - 360; + angles[PITCH] /= 3; + + AngleVectors(angles, pml.forward, pml.right, pml.up); + + PM_AirMove(); + } + } + + // set groundentity, watertype, and waterlevel for final spot + PM_CatagorizePosition(); + + // trick jump + if (pm->s.pm_flags & PMF_TIME_TRICK) + PM_CheckJump(); + + // [Paril-KEX] + PM_ScreenEffects(); + + PM_SnapPosition(); +} diff --git a/src/quake2/p_view.c b/src/quake2/p_view.c index 3f93bd7b..ade91ca2 100644 --- a/src/quake2/p_view.c +++ b/src/quake2/p_view.c @@ -50,7 +50,7 @@ void P_DamageFeedback (edict_t *player) { gclient_t *client; float side; - float realcount, count, kick; + float realcount, count; vec3_t v; int r, l; static vec3_t power_color = {0.0, 1.0, 0.0}; @@ -151,7 +151,7 @@ void P_DamageFeedback (edict_t *player) // // calculate view angle kicks // - kick = fabsf(client->damage_knockback); + float kick = abs(client->damage_knockback); if (kick && player->health > 0) // kick of 0 means no view adjust at all { kick = kick * 100 / player->health; @@ -287,8 +287,10 @@ void SV_CalcViewOffset (edict_t *ent) // add view height + // az: the viewheight as part of pm.s makes this unnecessary now +#ifndef VRX_REPRO v[2] += ent->viewheight; - +#endif // add fall height ratio = (ent->client->fall_time - level.time) / FALL_TIME; @@ -418,11 +420,15 @@ void SV_CalcBlend (edict_t *ent) vec3_t vieworg; int remaining; - ent->client->ps.blend[0] = ent->client->ps.blend[1] = - ent->client->ps.blend[2] = ent->client->ps.blend[3] = 0; + ent->client->ps.screen_blend[0] = ent->client->ps.screen_blend[1] = + ent->client->ps.screen_blend[2] = ent->client->ps.screen_blend[3] = 0; // add for contents VectorAdd (ent->s.origin, ent->client->ps.viewoffset, vieworg); +#ifdef VRX_REPRO + // viewheight no longer part of offset + vieworg[2] += ent->viewheight; +#endif contents = gi.pointcontents (vieworg); if (contents & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER) ) ent->client->ps.rdflags |= RDF_UNDERWATER; @@ -430,19 +436,19 @@ void SV_CalcBlend (edict_t *ent) ent->client->ps.rdflags &= ~RDF_UNDERWATER; if (contents & (CONTENTS_SOLID|CONTENTS_LAVA)) - SV_AddBlend (1.0, 0.3, 0.0, 0.6, ent->client->ps.blend); + SV_AddBlend (1.0, 0.3, 0.0, 0.6, ent->client->ps.screen_blend); else if (contents & CONTENTS_SLIME) - SV_AddBlend (0.0, 0.1, 0.05, 0.6, ent->client->ps.blend); + SV_AddBlend (0.0, 0.1, 0.05, 0.6, ent->client->ps.screen_blend); else if (contents & CONTENTS_WATER) - SV_AddBlend (0.5, 0.3, 0.2, 0.4, ent->client->ps.blend); + SV_AddBlend (0.5, 0.3, 0.2, 0.4, ent->client->ps.screen_blend); //GHz: lowlight vision effect if (ent->client->ps.rdflags & RDF_IRGOGGLES) - SV_AddBlend (1, 0, 0, 0.2, ent->client->ps.blend); + SV_AddBlend (1, 0, 0, 0.2, ent->client->ps.screen_blend); //K03 Begin if (ent->client->cloaking && (ent->svflags & SVF_NOCLIENT)) - SV_AddBlend (-1, -1, -1, 0.3, ent->client->ps.blend); + SV_AddBlend (-1, -1, -1, 0.3, ent->client->ps.screen_blend); if(ent->client->bfg_blend) - SV_AddBlend (0, 1, 0, 0.3, ent->client->ps.blend); + SV_AddBlend (0, 1, 0, 0.3, ent->client->ps.screen_blend); //K03 End // add for powerups @@ -452,7 +458,7 @@ void SV_CalcBlend (edict_t *ent) if (remaining == 30) // beginning to fade gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage2.wav"), 1, ATTN_NORM, 0); if (remaining > 30 || (remaining & 4) ) - SV_AddBlend (0, 0, 1, 0.08, ent->client->ps.blend); + SV_AddBlend (0, 0, 1, 0.08, ent->client->ps.screen_blend); } // RAFAEL else if (ent->client->quadfire_framenum > level.framenum) @@ -461,7 +467,7 @@ void SV_CalcBlend (edict_t *ent) if (remaining == 30) // beginning to fade gi.sound(ent, CHAN_ITEM, gi.soundindex("items/quadfire2.wav"), 1, ATTN_NORM, 0); if (remaining > 30 || (remaining & 4) ) - SV_AddBlend (1, 0.2, 0.5, 0.08, ent->client->ps.blend); + SV_AddBlend (1, 0.2, 0.5, 0.08, ent->client->ps.screen_blend); } else if (ent->client->invincible_framenum > level.framenum) { @@ -469,7 +475,7 @@ void SV_CalcBlend (edict_t *ent) if (remaining == 30) // beginning to fade gi.sound(ent, CHAN_ITEM, gi.soundindex("items/protect2.wav"), 1, ATTN_NORM, 0); if (remaining > 30 || (remaining & 4) ) - SV_AddBlend (1, 1, 0, 0.08, ent->client->ps.blend); + SV_AddBlend (1, 1, 0, 0.08, ent->client->ps.screen_blend); } else if (ent->client->enviro_framenum > level.framenum) { @@ -477,7 +483,7 @@ void SV_CalcBlend (edict_t *ent) if (remaining == 30) // beginning to fade gi.sound(ent, CHAN_ITEM, gi.soundindex("items/airout.wav"), 1, ATTN_NORM, 0); if (remaining > 30 || (remaining & 4) ) - SV_AddBlend (0, 1, 0, 0.08, ent->client->ps.blend); + SV_AddBlend (0, 1, 0, 0.08, ent->client->ps.screen_blend); } else if (ent->client->breather_framenum > level.framenum) { @@ -485,24 +491,24 @@ void SV_CalcBlend (edict_t *ent) if (remaining == 30) // beginning to fade gi.sound(ent, CHAN_ITEM, gi.soundindex("items/airout.wav"), 1, ATTN_NORM, 0); if (remaining > 30 || (remaining & 4) ) - SV_AddBlend (0.4, 1, 0.4, 0.04, ent->client->ps.blend); + SV_AddBlend (0.4, 1, 0.4, 0.04, ent->client->ps.screen_blend); } // add for damage if (ent->client->damage_alpha > 0) SV_AddBlend (ent->client->damage_blend[0],ent->client->damage_blend[1] - ,ent->client->damage_blend[2], ent->client->damage_alpha, ent->client->ps.blend); + ,ent->client->damage_blend[2], ent->client->damage_alpha, ent->client->ps.screen_blend); if (ent->client->bonus_alpha > 0) - SV_AddBlend (0.85, 0.7, 0.3, ent->client->bonus_alpha, ent->client->ps.blend); + SV_AddBlend (0.85, 0.7, 0.3, ent->client->bonus_alpha, ent->client->ps.screen_blend); // drop the damage value - ent->client->damage_alpha -= 0.06; + ent->client->damage_alpha -= 0.06 * 10.0 / sv_fps->value; if (ent->client->damage_alpha < 0) ent->client->damage_alpha = 0; // drop the bonus value - ent->client->bonus_alpha -= 0.1; + ent->client->bonus_alpha -= 0.1 * 10.0 / sv_fps->value; if (ent->client->bonus_alpha < 0) ent->client->bonus_alpha = 0; } @@ -852,7 +858,8 @@ void G_SetClientEvent (edict_t *ent) if ( ent->groundentity && xyspeed > 225) { // called with each player step - if ( (int)(current_client->bobtime+bobmove) != bobcycle + if ( (int)(current_client->bobtime+bobmove) != bobcycle + && level.framenum % qf2sf(1) == 0 // don'd do the funny rapidfire burst of steps lol && (ent->client->pers.inventory[ITEM_INDEX(FindItem("Stealth Boots"))] < 1) && !ent->mtype) { if ((ent->myskills.abilities[CLOAK].disable) || (ent->myskills.abilities[CLOAK].current_level < 1)) @@ -919,6 +926,10 @@ void G_SetClientFrame (edict_t *ent) if (ent->s.modelindex != 255) return; // not in the player model + // run at 10 fps. + if (level.framenum % qf2sf(1) != 0) + return; + client = ent->client; if (client->ps.pmove.pm_flags & PMF_DUCKED) @@ -1111,11 +1122,19 @@ void ClientEndServerFrame (edict_t *ent) // If it wasn't updated here, the view position would lag a frame // behind the body position when pushed -- "sinking into plats" // +#ifndef VRX_REPRO for (i=0 ; i<3 ; i++) { current_client->ps.pmove.origin[i] = ent->s.origin[i]*8.0; current_client->ps.pmove.velocity[i] = ent->velocity[i]*8.0; } +#else + for (i=0 ; i<3 ; i++) + { + current_client->ps.pmove.origin[i] = ent->s.origin[i]; + current_client->ps.pmove.velocity[i] = ent->velocity[i]; + } +#endif // // If the end of unit layout is displayed, don't give @@ -1124,7 +1143,7 @@ void ClientEndServerFrame (edict_t *ent) if (level.intermissiontime) { // FIXME: add view drifting here? - current_client->ps.blend[3] = 0; + current_client->ps.screen_blend[3] = 0; current_client->ps.fov = 90; G_SetStats (ent); return; @@ -1250,8 +1269,8 @@ void ClientEndServerFrame (edict_t *ent) else if (!ent->client->showscores && !ent->client->pers.scanner_active && !ent->client->menustorage.menu_active) { // once a sec - qboolean this_tick = !(level.framenum % (int)sv_fps->value); - qboolean has_cooldown = (ent->client->ability_delay - level.time) > -0.001; + const qboolean this_tick = !(level.framenum % (int)sv_fps->value); + const qboolean has_cooldown = (ent->client->ability_delay - level.time) > -0.001; if (this_tick || ent->client->layout.dirty || has_cooldown) { layout_generate_all(ent); diff --git a/src/quake2/q_recompat.c b/src/quake2/q_recompat.c new file mode 100644 index 00000000..076c631f --- /dev/null +++ b/src/quake2/q_recompat.c @@ -0,0 +1,351 @@ +// +// Created by zardoru on 01-03-26. +// + +#include "game.h" +#include "q_recompat.h" + +#include + +#include "bg_local.h" +#include "g_local.h" + + +void vrx_repro_shim(game_import_t *gi); + +repro_import_t gire; + +void vrx_repro_getgameapi(repro_import_t *pr, game_import_t *gi) { + memcpy(&gire, pr, sizeof(repro_import_t)); + vrx_repro_shim(gi); +} + +#define VA_PRELUDE(x) va_list argptr;\ + va_start(argptr, fmt);\ + int len = vsnprintf(NULL, 0, fmt, argptr);\ + char _##x[len+1];\ + vsnprintf(_##x, len + 1, fmt, argptr);\ + _##x[len]='\0';\ + va_end(argptr); + +void shim_bprintf (int printlevel, const char *fmt, ...) { + VA_PRELUDE(msg) + gire.Broadcast_Print(printlevel, _msg); +} + +void shim_dprintf (const char *fmt, ...) { + VA_PRELUDE(msg) + gire.Com_Print(_msg); +} +void shim_cprintf (const edict_t *ent, int printlevel, const char *fmt, ...) { + VA_PRELUDE(msg) + gire.Client_Print(ent, printlevel, _msg); +} +void shim_centerprintf (const edict_t *ent, const char *fmt, ...) { + VA_PRELUDE(msg) + gire.Center_Print(ent, _msg); +} + +void shim_error(const char* fmt, ...) { + VA_PRELUDE(msg) + gire.Com_Error(_msg); +} + + +// clear out one-offs +void repro_prep_frame () { + for (uint32_t i = 0; i < globals.num_edicts; i++) + g_edicts[i].s.event = EV_NONE; + + // for (auto player : active_players()) + // player->client->ps.stats[STAT_HIT_MARKER] = 0; + // + // globals.server_flags &= ~SERVER_FLAG_INTERMISSION; + // + // if ( level.intermissiontime ) { + // globals.server_flags |= SERVER_FLAG_INTERMISSION; + // } +} + +char* repro_write_game_json(bool autosave, size_t *out_size) { return nullptr; } +void repro_read_game_json(const char* json) { /* stub */ } +char* repro_write_level_json(bool autosave, size_t *out_size) { return nullptr; } +void repro_read_level_json(const char* json) {} + +bool IsSlotIgnored(edict_t *slot, edict_t **ignore, size_t num_ignore) +{ + for (size_t i = 0; i < num_ignore; i++) + if (slot == ignore[i]) + return true; + + return false; +} + +edict_t *ClientChooseSlot_Any(edict_t **ignore, size_t num_ignore) +{ + for (size_t i = 0; i < game.maxclients; i++) + if (!IsSlotIgnored(globals.edicts + i + 1, ignore, num_ignore) && !game.clients[i].pers.connected) + return globals.edicts + i + 1; + + return nullptr; +} + +// inline edict_t *ClientChooseSlot_Coop(const char *userinfo, const char *social_id, bool isBot, edict_t **ignore, size_t num_ignore) +// { +// char name[MAX_INFO_VALUE] = { 0 }; +// gi.Info_ValueForKey(userinfo, "name", name, sizeof(name)); +// +// // the host should always occupy slot 0, some systems rely on this +// // (CHECK: is this true? is it just bots?) +// { +// size_t num_players = 0; +// +// for (size_t i = 0; i < game.maxclients; i++) +// if (IsSlotIgnored(globals.edicts + i + 1, ignore, num_ignore) || game.clients[i].pers.connected) +// num_players++; +// +// if (!num_players) +// { +// gi.Com_PrintFmt("coop slot {} is host {}+{}\n", 1, name, social_id); +// return globals.edicts + 1; +// } +// } +// +// // grab matches from players that we have connected +// using match_type_t = int32_t; +// enum { +// MATCH_USERNAME, +// MATCH_SOCIAL, +// MATCH_BOTH, +// +// MATCH_TYPES +// }; +// +// struct { +// edict_t *slot = nullptr; +// size_t total = 0; +// } matches[MATCH_TYPES]; +// +// for (size_t i = 0; i < game.maxclients; i++) +// { +// if (IsSlotIgnored(globals.edicts + i + 1, ignore, num_ignore) || game.clients[i].pers.connected) +// continue; +// +// char check_name[MAX_INFO_VALUE] = { 0 }; +// gi.Info_ValueForKey(game.clients[i].pers.userinfo, "name", check_name, sizeof(check_name)); +// +// bool username_match = game.clients[i].pers.userinfo[0] && +// !strcmp(check_name, name); +// +// bool social_match = social_id && game.clients[i].pers.social_id[0] && +// !strcmp(game.clients[i].pers.social_id, social_id); +// +// match_type_t type = (match_type_t) 0; +// +// if (username_match) +// type |= MATCH_USERNAME; +// if (social_match) +// type |= MATCH_SOCIAL; +// +// if (!type) +// continue; +// +// matches[type].slot = globals.edicts + i + 1; +// matches[type].total++; +// } +// +// // pick matches in descending order, only if the total matches +// // is 1 in the particular set; this will prefer to pick +// // social+username matches first, then social, then username last. +// for (int32_t i = 2; i >= 0; i--) +// { +// if (matches[i].total == 1) +// { +// gi.Com_PrintFmt("coop slot {} restored for {}+{}\n", (ptrdiff_t) (matches[i].slot - globals.edicts), name, social_id); +// +// // spawn us a ghost now since we're gonna spawn eventually +// if (!matches[i].slot->inuse) +// { +// matches[i].slot->s.modelindex = MODELINDEX_PLAYER; +// matches[i].slot->solid = SOLID_BBOX; +// +// G_InitEdict(matches[i].slot); +// matches[i].slot->classname = "player"; +// InitClientResp(matches[i].slot->client); +// spawn_from_begin = true; +// PutClientInServer(matches[i].slot); +// spawn_from_begin = false; +// +// // make sure we have a known default +// matches[i].slot->svflags |= SVF_PLAYER; +// +// matches[i].slot->sv.init = false; +// matches[i].slot->classname = "player"; +// matches[i].slot->client->pers.connected = true; +// matches[i].slot->client->pers.spawned = true; +// P_AssignClientSkinnum(matches[i].slot); +// gi.linkentity(matches[i].slot); +// } +// +// return matches[i].slot; +// } +// } +// +// // in the case where we can't find a match, we're probably a new +// // player, so pick a slot that hasn't been occupied yet +// for (size_t i = 0; i < game.maxclients; i++) +// if (!IsSlotIgnored(globals.edicts + i + 1, ignore, num_ignore) && !game.clients[i].pers.userinfo[0]) +// { +// gi.Com_PrintFmt("coop slot {} issuing new for {}+{}\n", i + 1, name, social_id); +// return globals.edicts + i + 1; +// } +// +// // all slots have some player data in them, we're forced to replace one. +// edict_t *any_slot = ClientChooseSlot_Any(ignore, num_ignore); +// +// gi.Com_PrintFmt("coop slot {} any slot for {}+{}\n", !any_slot ? -1 : (ptrdiff_t) (any_slot - globals.edicts), name, social_id); +// +// return any_slot; +// } + + +edict_t *repro_choose_client_slot(const char *userinfo, const char *social_id, bool isBot, edict_t **ignore, size_t num_ignore, bool cinematic) +{ + // coop and non-bots is the only thing that we need to do special behavior on + // az: no coop supported yet + // if (!cinematic && coop->integer && !isBot) + // return ClientChooseSlot_Coop(userinfo, social_id, isBot, ignore, num_ignore); + + // just find any free slot + return ClientChooseSlot_Any(ignore, num_ignore); +} + +void *repro_get_extension(const char *name) +{ + return nullptr; +} + +void repro_bot_set_weapon(edict_t *botEdict, int weaponIndex, bool instantSwitch) +{ +} + +void repro_bot_trigger_edict(edict_t *botEdict, edict_t *edict) +{ +} + +void repro_bot_use_item(edict_t *botEdict, int32_t itemID) +{ +} + +int32_t repro_bot_get_item_id(const char *classname) +{ + return -1; +} + +void repro_edict_force_look_at_point(edict_t *edict, const vec3_t point) +{ +} + +bool repro_bot_picked_up_item(edict_t *botEdict, edict_t *itemEdict) +{ + return false; +} + +bool repro_visible_to_player(edict_t* ent, edict_t* player) +{ + return true; + // return !ent->item_picked_up_by[player->s.number - 1]; +} + + +// az: compared to og kex, we move this to levels +const shadow_light_data_t *repro_get_shadow_light_data(int32_t entity_number) +{ + for (int32_t i = 0; i < level.shadow_lights.count; i++) + { + if (level.shadow_lights.info[i].entity_number == entity_number) + return &level.shadow_lights.info[i].shadowlight; + } + + return nullptr; +} + +int shim_boxedicts(vec3_t mins, vec3_t maxs, edict_t **list, size_t maxcount, enum solidity_area_t areatype) { + return gire.BoxEdicts(mins, maxs, list, maxcount, areatype, nullptr, nullptr); +} + +void vrx_repro_shim(game_import_t *gi) { + gi->bprintf = shim_bprintf; + gi->dprintf = shim_dprintf; + gi->cprintf = shim_cprintf; + gi->centerprintf = shim_centerprintf; + gi->sound = gire.sound; + gi->positioned_sound = gire.positioned_sound; + + gi->configstring = gire.configstring; + + gi->error = shim_error; + + gi->modelindex = gire.modelindex; + gi->soundindex = gire.soundindex; + gi->imageindex = gire.imageindex; + + gi->setmodel = gire.setmodel; + + gi->trace = gire.trace; + gi->pointcontents = gire.pointcontents; + gi->inPVS = gire.inPVS; + gi->inPHS = gire.inPHS; + gi->SetAreaPortalState = gire.SetAreaPortalState; + gi->AreasConnected = gire.AreasConnected; + + gi->linkentity = gire.linkentity; + gi->unlinkentity = gire.unlinkentity; + gi->BoxEdicts = shim_boxedicts; + + gi->Pmove = Pmove; + + gi->multicast = gire.multicast; + gi->unicast = gire.unicast; + + gi->WriteChar = gire.WriteChar; + gi->WriteByte = gire.WriteByte; + gi->WriteShort = gire.WriteShort; + gi->WriteLong = gire.WriteLong; + gi->WriteFloat = gire.WriteFloat; + gi->WriteString = gire.WriteString; + gi->WritePosition = gire.WritePosition; + gi->WriteDir = gire.WriteDir; + gi->WriteAngle = gire.WriteAngle; + + gi->TagMalloc = gire.TagMalloc; + gi->TagFree = gire.TagFree; + gi->FreeTags = gire.FreeTags; + + gi->cvar = gire.cvar; + gi->cvar_set = gire.cvar_set; + gi->cvar_forceset = gire.cvar_forceset; + + gi->argc = gire.argc; + gi->argv = gire.argv; + gi->args = gire.args; + + gi->AddCommandString = gire.AddCommandString; + gi->DebugGraph = gire.DebugGraph; +} + + + +#ifdef VRX_REPRO +void pm_set_viewheight(pmove_t *pm, int viewheight) { +} + +#else +void pm_set_viewheight(pmove_t *pm, int viewheight) { + pm->viewheight = viewheight; +} + +int pm_get_viewheight(pmove_t *pm) { + return pm->viewheight; +} +#endif \ No newline at end of file diff --git a/src/quake2/q_recompat.h b/src/quake2/q_recompat.h new file mode 100644 index 00000000..2553737e --- /dev/null +++ b/src/quake2/q_recompat.h @@ -0,0 +1,395 @@ +#ifndef VORTEXQUAKE2_Q_RECOMPAT_H +#define VORTEXQUAKE2_Q_RECOMPAT_H +#include + +#include "q_shared.h" + +enum BoxEdictsResult_t +{ + Keep, // keep the given entity in the result and keep looping + Skip, // skip the given entity + + End = 64, // stop searching any further + + Flags = End +}; + + +enum goalReturnCode_t { + Error = 0, + Started, + InProgress, + Finished +}; + +typedef enum BoxEdictsResult_t (*BoxEdictsFilter_t)(edict_t *, void *); + +typedef enum { + PathReturnCode_ReachedGoal = 0, // we're at our destination + PathReturnCode_ReachedPathEnd, // we're as close to the goal as we can get with a path + PathReturnCode_TraversalPending, // the upcoming path segment is a traversal + PathReturnCode_RawPathFound, // user wanted ( and got ) just a raw path ( no processing ) + PathReturnCode_InProgress, // pathing in progress + PathReturnCode_StartPathErrors, // any code after this one indicates an error of some kind. + PathReturnCode_InvalidStart, // start position is invalid. + PathReturnCode_InvalidGoal, // goal position is invalid. + PathReturnCode_NoNavAvailable, // no nav file available for this map. + PathReturnCode_NoStartNode, // can't find a nav node near the start position + PathReturnCode_NoGoalNode, // can't find a nav node near the goal position + PathReturnCode_NoPathFound, // can't find a path from the start to the goal + PathReturnCode_MissingWalkOrSwimFlag // MUST have at least Walk or Water path flags set! +} PathReturnCode; + +typedef enum { + PathReturnCode_Walk, // can walk between the path points + PathReturnCode_WalkOffLedge, // will walk off a ledge going between path points + PathReturnCode_LongJump, // will need to perform a long jump between path points + PathReturnCode_BarrierJump, // will need to jump over a low barrier between path points + PathReturnCode_Elevator // will need to use an elevator between path points +} PathLinkType; + +enum { + PathFlags_All = (uint32_t)( -1 ), + PathFlags_Water = 1 << 0, // swim to your goal ( useful for fish/gekk/etc. ) + PathFlags_Walk = 1 << 1, // walk to your goal + PathFlags_WalkOffLedge = 1 << 2, // allow walking over ledges + PathFlags_LongJump = 1 << 3, // allow jumping over gaps + PathFlags_BarrierJump = 1 << 4, // allow jumping over low barriers + PathFlags_Elevator = 1 << 5 // allow using elevators +}; +typedef uint32_t PathFlags; + +typedef struct { + vec3_t start /*= { 0.0f, 0.0f, 0.0f }*/; + vec3_t goal /*= { 0.0f, 0.0f, 0.0f }*/; + PathFlags pathFlags /*= PathFlags::Walk*/; + float moveDist /*= 0.0f*/; + + struct DebugSettings { + float drawTime /*= 0.0f*/; // if > 0, how long ( in seconds ) to draw path in world + } debugging; + + struct NodeSettings { + bool ignoreNodeFlags /*= false*/; // true = ignore node flags when considering nodes + float minHeight /*= 0.0f*/; // 0 <= use default values + float maxHeight /*= 0.0f*/; // 0 <= use default values + float radius /*= 0.0f*/; // 0 <= use default values + } nodeSearch; + + struct TraversalSettings { + float dropHeight /*= 0.0f*/; // 0 = don't drop down + float jumpHeight /*= 0.0f*/; // 0 = don't jump up + } traversals; + + struct PathArray { + vec3_t * posArray /*= nullptr*/; // array to store raw path points + int64_t count /*= 0*/; // number of elements in array + } pathPoints; +} PathRequest; + +typedef struct { + int32_t numPathPoints /*= 0*/; + float pathDistSqr /*= 0.0f*/; + vec3_t firstMovePoint /*= { 0.0f, 0.0f, 0.0f }*/; + vec3_t secondMovePoint /*= { 0.0f, 0.0f, 0.0f }*/; + PathLinkType pathLinkType /*= PathLinkType::Walk*/; + PathReturnCode returnCode /*= PathReturnCode::StartPathErrors*/; +} PathInfo; + +typedef enum +{ + shadow_light_type_point, + shadow_light_type_cone +} shadow_light_type_t; + +typedef struct +{ + shadow_light_type_t lighttype; + float radius; + int resolution; + float intensity /*= 1*/; + float fade_start; + float fade_end; + int lightstyle /*= -1*/; + float coneangle /*= 45*/; + vec3_t conedirection; +} shadow_light_data_t; + +enum server_flags_t +{ + SERVER_FLAGS_NONE = 0, + SERVER_FLAG_SLOW_TIME = 1, + SERVER_FLAG_INTERMISSION = 2, + SERVER_FLAG_LOADING = 4 +}; + +// todo: cgame? +// todo: pmove +// todo: bots? + +typedef struct repro_import_s +{ + uint32_t tick_rate; + float frame_time_s; + uint32_t frame_time_ms; + + // broadcast to all clients + void (*Broadcast_Print)(enum print_type_t printlevel, char *message); + + // print to appropriate places (console, log file, etc) + void (*Com_Print)(char *msg); + + // print directly to a single client (or nullptr for server console) + void (*Client_Print)(const edict_t *ent, enum print_type_t printlevel, char *message); + + // center-print to player (legacy function) + void (*Center_Print)(const edict_t *ent, char *message); + + void (*sound)(const edict_t *ent, enum soundchan_t channel, int soundindex, float volume, float attenuation, float timeofs); + void (*positioned_sound)(vec3_t origin, edict_t *ent, enum soundchan_t channel, int soundindex, float volume, float attenuation, float timeofs); + // [Paril-KEX] like sound, but only send to the player indicated by the parameter; + // this is mainly to handle split screen properly + void (*local_sound)(edict_t *target, vec3_t* origin, edict_t *ent, enum soundchan_t channel, int soundindex, float volume, float attenuation, float timeofs, uint32_t dupe_key); + + // config strings hold all the index strings, the lightstyles, + // and misc data like the sky definition and cdtrack. + // All of the current configstrings are sent to clients when + // they connect, and changes are sent to all connected clients. + void (*configstring)(int num, const char *string); + char *(*get_configstring)(int num); + + void (*Com_Error)(const char *message); + + // the *index functions create configstrings and some internal server state + int (*modelindex)(const char *name); + int (*soundindex)(const char *name); + + // [Paril-KEX] imageindex can precache both pics for the HUD and + // textures used for RF_CUSTOMSKIN; to register an image as a texture, + // the path must be relative to the mod dir and end in an extension + // ie models/my_model/skin.tga + int (*imageindex)(const char *name); + + void (*setmodel)(edict_t *ent, const char *name); + + // collision detection + trace_t (*trace)(vec3_t start, vec3_t* mins, vec3_t* maxs, vec3_t end, edict_t *passent, enum contents_t contentmask); + // [Paril-KEX] clip the box against the specified entity + trace_t (*clip)(edict_t *entity, vec3_t start, vec3_t* mins, vec3_t* maxs, vec3_t end, enum contents_t contentmask); + enum contents_t (*pointcontents)(vec3_t point); + bool (*inPVS)(vec3_t p1, vec3_t p2, bool portals); + bool (*inPHS)(vec3_t p1, vec3_t p2, bool portals); + void (*SetAreaPortalState)(int portalnum, bool open); + bool (*AreasConnected)(int area1, int area2); + + // an entity will never be sent to a client or used for collision + // if it is not passed to linkentity. If the size, position, or + // solidity changes, it must be relinked. + void (*linkentity)(edict_t *ent); + void (*unlinkentity)(edict_t *ent); // call before removing an interactive edict + + // return a list of entities that touch the input absmin/absmax. + // if maxcount is 0, it will return a count but not attempt to fill "list". + // if maxcount > 0, once it reaches maxcount, it will keep going but not fill + // any more of list (the return count will cap at maxcount). + // the filter function can remove unnecessary entities from the final list; it is illegal + // to modify world links in this callback. + size_t (*BoxEdicts)(vec3_t mins, vec3_t maxs, edict_t **list, size_t maxcount, enum solidity_area_t areatype, BoxEdictsFilter_t filter, void *filter_data); + + // network messaging + void (*multicast)(vec3_t origin, multicast_t to, bool reliable); + // [Paril-KEX] `dupe_key` is a key unique to a group of calls to unicast + // that will prevent sending the message on this frame with the same key + // to the same player (for splitscreen players). + void (*unicast)(edict_t *ent, bool reliable, uint32_t dupe_key); + + void (*WriteChar)(int c); + void (*WriteByte)(int c); + void (*WriteShort)(int c); + void (*WriteLong)(int c); + void (*WriteFloat)(float f); + void (*WriteString)(char *s); + void (*WritePosition)(vec3_t pos); + void (*WriteDir)(vec3_t pos); // single byte encoded, very coarse + void (*WriteAngle)(float f); // legacy 8-bit angle + void (*WriteEntity)(edict_t *e); + + // managed memory allocation + void *(*TagMalloc)(size_t size, int tag); + void (*TagFree)(void *block); + void (*FreeTags)(int tag); + + // console variable interaction + cvar_t *(*cvar)(char *var_name, char *value, enum cvar_flags_t flags); + cvar_t *(*cvar_set)(char *var_name, char *value); + cvar_t *(*cvar_forceset)(char *var_name, char *value); + + // ClientCommand and ServerCommand parameter access + int (*argc)(); + char *(*argv)(int n); + char *(*args)(); // concatenation of all argv >= 1 + + // add commands to the server console as if they were typed in + // for map changing, etc + void (*AddCommandString)(const char *text); + + void (*DebugGraph)(float value, int color); + + // Fetch named extension from engine. + void *(*GetExtension)(char *name); + + // === [KEX] Additional APIs === + + // bots + void (*Bot_RegisterEdict)(edict_t * edict); + void (*Bot_UnRegisterEdict)(edict_t * edict); + enum goalReturnCode_t (*Bot_MoveToPoint)(edict_t * bot, vec3_t point, float moveTolerance); + enum goalReturnCode_t (*Bot_FollowActor)(edict_t * bot, edict_t * actor); + + // pathfinding - returns true if a path was found + bool (*GetPathToGoal)(PathRequest* request, PathInfo* info); + + // localization + void (*Loc_Print)(edict_t* ent, enum print_type_t level, char* base, char** args, size_t num_args); + + // drawing + void (*Draw_Line)(vec3_t start, vec3_t end, rgba_t* color, float lifeTime, bool depthTest); + void (*Draw_Point)(vec3_t point, float size, rgba_t* color, float lifeTime, bool depthTest); + void (*Draw_Circle)(vec3_t origin, float radius, rgba_t* color, float lifeTime, bool depthTest); + void (*Draw_Bounds)(vec3_t mins, vec3_t maxs, rgba_t* color, float lifeTime, bool depthTest); + void (*Draw_Sphere)(vec3_t origin, float radius, rgba_t* color, float lifeTime, bool depthTest); + void (*Draw_OrientedWorldText)(vec3_t origin, char * text, rgba_t* color, float size, float lifeTime, bool depthTest); + void (*Draw_StaticWorldText)(vec3_t origin, vec3_t angles, char * text, rgba_t* color, float size, float lifeTime, bool depthTest); + void (*Draw_Cylinder)(vec3_t origin, float halfHeight, float radius, rgba_t* color, float lifeTime, bool depthTest); + void (*Draw_Ray)(vec3_t origin, vec3_t direction, float length, float size, rgba_t* color, float lifeTime, bool depthTest); + void (*Draw_Arrow)(vec3_t start, vec3_t end, float size, rgba_t* lineColor, rgba_t* arrowColor, float lifeTime, bool depthTest); + + // scoreboard + void (*ReportMatchDetails_Multicast)(bool is_end); + + // get server frame # + uint32_t (*ServerFrame)(); + + // misc utils + void (*SendToClipBoard)(char * text); + + // info string stuff + size_t (*Info_ValueForKey) (char *s, char *key, char *buffer, size_t buffer_len); + bool (*Info_RemoveKey) (char *s, char *key); + bool (*Info_SetValueForKey) (char *s, char *key, char *value); +} repro_import_t; + +typedef struct repro_export_s { + int apiversion; + + // the init function will only be called when a game starts, + // not each time a level is loaded. Persistent data for clients + // and the server can be allocated in init + void (*PreInit)(void); // [Paril-KEX] called before InitGame, to potentially change maxclients + void (*Init)(void); + void (*Shutdown)(void); + + // each new level entered will cause a call to SpawnEntities + void (*SpawnEntities)(const char *mapname, const char *entstring, const char *spawnpoint); + + // Read/Write Game is for storing persistent cross level information + // about the world state and the clients. + // WriteGame is called every time a level is exited. + // ReadGame is called on a loadgame. + // returns pointer to tagmalloc'd allocated string. + // tagfree after use + char *(*WriteGameJson)(bool autosave, size_t *out_size); + void (*ReadGameJson)(const char *json); + + // ReadLevel is called after the default map information has been + // loaded with SpawnEntities + // returns pointer to tagmalloc'd allocated string. + // tagfree after use + char *(*WriteLevelJson)(bool transition, size_t *out_size); + void (*ReadLevelJson)(const char *json); + + // [Paril-KEX] game can tell the server whether a save is allowed + // currently or not. + bool (*CanSave)(void); + + // [Paril-KEX] choose a free gclient_t slot for the given social ID; for + // coop slot re-use. Return nullptr if none is available. You can not + // return a slot that is currently in use by another client; that must + // throw a fatal error. + edict_t *(*ClientChooseSlot) (const char *userinfo, const char *social_id, bool isBot, edict_t **ignore, size_t num_ignore, bool cinematic); + bool (*ClientConnect)(edict_t *ent, char *userinfo, const char *social_id, bool isBot); + void (*ClientBegin)(edict_t *ent); + void (*ClientUserinfoChanged)(edict_t *ent, const char *userinfo); + void (*ClientDisconnect)(edict_t *ent); + void (*ClientCommand)(edict_t *ent); + void (*ClientThink)(edict_t *ent, usercmd_t *cmd); + + void (*RunFrame)(bool main_loop); + // [Paril-KEX] allow the game DLL to clear per-frame stuff + void (*PrepFrame)(void); + + // ServerCommand will be called when an "sv " command is issued on the + // server console. + // The game can issue gi.argc() / gi.argv() commands to get the rest + // of the parameters + void (*ServerCommand)(void); + + // + // global variables shared between game and server + // + + // The edict array is allocated in the game dll so it + // can vary in size from one game to another. + // + // The size will be fixed when ge->Init() is called + struct edict_s *edicts; + size_t edict_size; + uint32_t num_edicts; // current number, <= max_edicts + uint32_t max_edicts; + + // [Paril-KEX] special flags to indicate something to the server + enum server_flags_t server_flags; + + // [KEX]: Pmove as export + void (*Pmove)(pmove_t *pmove); // player movement code called by server & client + + // Fetch named extension from game DLL. + void *(*GetExtension)(const char *name); + + void (*Bot_SetWeapon)(edict_t * botEdict, const int weaponIndex, const bool instantSwitch); + void (*Bot_TriggerEdict)(edict_t * botEdict, edict_t * edict); + void (*Bot_UseItem)(edict_t * botEdict, const int32_t itemID); + int32_t (*Bot_GetItemID)(const char * classname); + void (*Edict_ForceLookAtPoint)(edict_t * edict, const vec3_t point); + bool (*Bot_PickedUpItem )(edict_t * botEdict, edict_t * itemEdict); + + // [KEX]: Checks entity visibility instancing + bool (*Entity_IsVisibleToPlayer)(edict_t* ent, edict_t* player); + + // Fetch info from the shadow light, for culling + const shadow_light_data_t *(*GetShadowLightData)(int32_t entity_number); + + +} repro_export_t; + +extern repro_import_t gire; + +void vrx_repro_getgameapi(repro_import_t *pr, game_import_t *gi); +edict_t *repro_choose_client_slot(const char *userinfo, const char *social_id, bool isBot, edict_t **ignore, size_t num_ignore, bool cinematic); +void *repro_get_extension(const char *name); +void repro_prep_frame(void); +bool repro_visible_to_player(edict_t* ent, edict_t* player); +const shadow_light_data_t *repro_get_shadow_light_data(int32_t entity_number); + +char* repro_write_game_json(bool autosave, size_t *out_size) ; +void repro_read_game_json(const char* json) ; +char* repro_write_level_json(bool autosave, size_t *out_size) ; +void repro_read_level_json(const char* json) ; +void repro_bot_set_weapon(edict_t *botEdict, int weaponIndex, bool instantSwitch); +void repro_bot_trigger_edict(edict_t *botEdict, edict_t *edict); +void repro_bot_use_item(edict_t *botEdict, int32_t itemID); +int32_t repro_bot_get_item_id(const char *classname); +void repro_edict_force_look_at_point(edict_t *edict, const vec3_t point); +bool repro_bot_picked_up_item(edict_t *botEdict, edict_t *itemEdict); + +#endif //VORTEXQUAKE2_Q_RECOMPAT_H \ No newline at end of file diff --git a/src/quake2/q_shared.c b/src/quake2/q_shared.c index 25c7b2cb..7b059872 100644 --- a/src/quake2/q_shared.c +++ b/src/quake2/q_shared.c @@ -1,5 +1,7 @@ #include "q_shared.h" +#include + #include "g_local.h" vec3_t vec3_origin = {0,0,0}; @@ -44,6 +46,54 @@ int rand_clt_distribute(int min, int max, int itercnt) { return sum / itercnt + min; } +bool cmd_jumping(usercmd_t* self) { +#ifndef VRX_REPRO + return self->upmove > 0; +#else + return self->buttons & BUTTON_JUMP; +#endif +} + +void cmd_jump(usercmd_t *self) { +#ifndef VRX_REPRO + self->upmove = 400; +#else + self->buttons |= BUTTON_JUMP; +#endif +} + +#ifdef VRX_REPRO +void cmd_duck(usercmd_t *self) { + self->buttons |= BUTTON_CROUCH; +} + +void cmd_stand(usercmd_t *self) { + self->buttons &= ~(BUTTON_CROUCH | BUTTON_JUMP); +} + +bool cmd_ducking(usercmd_t *self) { + return self->buttons & BUTTON_CROUCH; +} + +bool cmd_standing(usercmd_t *self) { + return !(self->buttons & (BUTTON_CROUCH | BUTTON_JUMP)); +} +#else +void cmd_duck(usercmd_t *self) { + self->upmove = -400; +} + +bool cmd_ducking(usercmd_t *self) { + return self->upmove < 0; +} +void cmd_stand(usercmd_t *self) { + self->upmove = 0; +} + +bool cmd_standing(usercmd_t *self) { + return self->upmove == 0; +} +#endif void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees ) { float m[3][3]; @@ -1034,7 +1084,7 @@ Swap_Init */ void Swap_Init (void) { - byte swaptest[2] = {1,0}; + const byte swaptest[2] = {1,0}; // set the byte swapping variables in a portable manner if ( *(short *)swaptest == 1) @@ -1060,6 +1110,71 @@ void Swap_Init (void) } +constexpr size_t MAX_MODELS_OLD = 256; +constexpr size_t MAX_SOUNDS_OLD = 256; +constexpr size_t MAX_IMAGES_OLD = 256; + +enum +{ + CS_NAME_OLD, + CS_CDTRACK_OLD, + CS_SKY_OLD, + CS_SKYAXIS_OLD, // %f %f %f format + CS_SKYROTATE_OLD, + CS_STATUSBAR_OLD, // display program string + + CS_AIRACCEL_OLD = 29, // air acceleration control + CS_MAXCLIENTS_OLD, + CS_MAPCHECKSUM_OLD, // for catching cheater maps + + CS_MODELS_OLD, + CS_SOUNDS_OLD = (CS_MODELS_OLD + MAX_MODELS_OLD), + CS_IMAGES_OLD = (CS_SOUNDS_OLD + MAX_SOUNDS_OLD), + CS_LIGHTS_OLD = (CS_IMAGES_OLD + MAX_IMAGES_OLD), + CS_ITEMS_OLD = (CS_LIGHTS_OLD + MAX_LIGHTSTYLES), + CS_PLAYERSKINS_OLD = (CS_ITEMS_OLD + MAX_ITEMS), + CS_GENERAL_OLD = (CS_PLAYERSKINS_OLD + MAX_CLIENTS), + MAX_CONFIGSTRINGS_OLD = (CS_GENERAL_OLD + MAX_GENERAL) +}; + +struct configstring_remap_t CS_REMAP(int32_t id) +{ + // direct mapping + if (id < CS_STATUSBAR_OLD) + return (struct configstring_remap_t) { id * CS_MAX_STRING_LENGTH, CS_MAX_STRING_LENGTH }; + // statusbar needs a bit of special handling, since we have a different + // max configstring length and these are just segments of a longer string + else if (id < CS_AIRACCEL_OLD) + return (struct configstring_remap_t) { (CS_STATUSBAR * CS_MAX_STRING_LENGTH) + ((id - CS_STATUSBAR_OLD) * CS_MAX_STRING_LENGTH_OLD), (CS_AIRACCEL - CS_STATUSBAR) * CS_MAX_STRING_LENGTH }; + // offset + else if (id < CS_MODELS_OLD) + return (struct configstring_remap_t) { (id + (CS_AIRACCEL - CS_AIRACCEL_OLD)) * CS_MAX_STRING_LENGTH, CS_MAX_STRING_LENGTH }; + else if (id < CS_SOUNDS_OLD) + return (struct configstring_remap_t) { (id + (CS_MODELS - CS_MODELS_OLD)) * CS_MAX_STRING_LENGTH, CS_MAX_STRING_LENGTH }; + else if (id < CS_IMAGES_OLD) + return (struct configstring_remap_t) { (id + (CS_SOUNDS - CS_SOUNDS_OLD)) * CS_MAX_STRING_LENGTH, CS_MAX_STRING_LENGTH }; + else if (id < CS_LIGHTS_OLD) + return (struct configstring_remap_t) { (id + (CS_IMAGES - CS_IMAGES_OLD)) * CS_MAX_STRING_LENGTH, CS_MAX_STRING_LENGTH }; + else if (id < CS_ITEMS_OLD) + return (struct configstring_remap_t) { (id + (CS_LIGHTS - CS_LIGHTS_OLD)) * CS_MAX_STRING_LENGTH, CS_MAX_STRING_LENGTH }; + else if (id < CS_PLAYERSKINS_OLD) + return (struct configstring_remap_t) { (id + (CS_ITEMS - CS_ITEMS_OLD)) * CS_MAX_STRING_LENGTH, CS_MAX_STRING_LENGTH }; + else if (id < CS_GENERAL_OLD) + return (struct configstring_remap_t) { (id + (CS_PLAYERSKINS - CS_PLAYERSKINS_OLD)) * CS_MAX_STRING_LENGTH, CS_MAX_STRING_LENGTH }; + + // general also needs some special handling because it's both + // offset *and* allowed to overflow + return (struct configstring_remap_t){ (id + (CS_GENERAL - CS_GENERAL_OLD)) * CS_MAX_STRING_LENGTH_OLD, (MAX_CONFIGSTRINGS - CS_GENERAL) * CS_MAX_STRING_LENGTH }; +} + +// static_assert(CS_REMAP(CS_MODELS_OLD).start == (CS_MODELS * 96), "check CS_REMAP"); +// static_assert(CS_REMAP(CS_SOUNDS_OLD).start == (CS_SOUNDS * 96), "check CS_REMAP"); +// static_assert(CS_REMAP(CS_IMAGES_OLD).start == (CS_IMAGES * 96), "check CS_REMAP"); +// static_assert(CS_REMAP(CS_LIGHTS_OLD).start == (CS_LIGHTS * 96), "check CS_REMAP"); +// static_assert(CS_REMAP(CS_PLAYERSKINS_OLD).start == (CS_PLAYERSKINS * 96), "check CS_REMAP"); +// static_assert(CS_REMAP(CS_ITEMS_OLD).start == (CS_ITEMS * 96), "check CS_REMAP"); +// static_assert(CS_REMAP(CS_GENERAL_OLD).start == (CS_GENERAL * 64), "check CS_REMAP"); +// static_assert(CS_REMAP(CS_AIRACCEL_OLD).start == (CS_AIRACCEL * 96), "check CS_REMAP"); /* @@ -1074,10 +1189,10 @@ FIXME: make this buffer size safe someday char *va(const char *format, ...) { va_list argptr; - static char string[1024]; + static char string[2048]; va_start (argptr, format); - vsnprintf (string, 1024, format,argptr); + vsnprintf (string, 2048, format,argptr); va_end (argptr); return string; @@ -1241,6 +1356,39 @@ int Q_strcasecmp (const char *s1, const char *s2) return Q_strncasecmp (s1, s2, 99999); } +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t Q_strlcpy(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + + /* Copy as many bytes as will fit */ + if(n != 0 && --n != 0) + { + do + { + if((*d++ = *s++) == 0) + break; + } + while(--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if(n == 0) + { + if(siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while(*s++) + ; // counter loop + } + + return (s - src - 1); /* count does not include NUL */ +} void Com_sprintf (char *dest, int size, char *fmt, ...) @@ -1376,7 +1524,7 @@ void Info_SetValueForKey (char *s, char *key, char *value) { char newi[MAX_INFO_STRING], *v; int c; - int maxsize = MAX_INFO_STRING; + const int maxsize = MAX_INFO_STRING; if (strstr (key, "\\") || strstr (value, "\\") ) { diff --git a/src/server/defer.c b/src/server/defer.c index 0afe395f..4e5a114c 100644 --- a/src/server/defer.c +++ b/src/server/defer.c @@ -15,9 +15,12 @@ void defer_global_init() pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); -#if !(__GNUC__ && WIN32) +#if !(__GNUC__ && WIN32) && !(defined __APPLE__) pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_RECURSIVE); #endif +#if (__APPLE__) + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); +#endif pthread_mutex_init(&defer_mutex, &attr); diff --git a/src/server/misc_stuff.c b/src/server/misc_stuff.c index eaa3604c..336f4c03 100644 --- a/src/server/misc_stuff.c +++ b/src/server/misc_stuff.c @@ -4,7 +4,7 @@ void KickPlayerBack(edict_t *ent) { - edict_t *other=NULL; + const edict_t *other=NULL; while ((other = findradius(other, ent->s.origin, 175)) != NULL) { diff --git a/src/server/relay.c b/src/server/relay.c index dd637b3d..9c0eea98 100644 --- a/src/server/relay.c +++ b/src/server/relay.c @@ -9,6 +9,10 @@ #include #include +#ifdef __APPLE__ +#include +#endif + #ifndef SOCKET #define SOCKET int #endif @@ -50,9 +54,9 @@ void vrx_relay_connect() { hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; - cvar_t* server = gi.cvar("vrx_relay_server", "localhost", 0); - cvar_t* port = gi.cvar("vrx_relay_port", "9999", 0); - cvar_t* key = gi.cvar("vrx_relay_key", "", 0); + const cvar_t* server = gi.cvar("vrx_relay_server", "", 0); + const cvar_t* port = gi.cvar("vrx_relay_port", "9999", 0); + const cvar_t* key = gi.cvar("vrx_relay_key", "", 0); if (strlen(server->string) < 1) { @@ -62,14 +66,14 @@ void vrx_relay_connect() { gi.dprintf("RS: Connecting to relay server...\n"); - int rv = getaddrinfo(server->string, port->string, &hints, &servinfo); + const int rv = getaddrinfo(server->string, port->string, &hints, &servinfo); if (rv != 0) { gi.dprintf("RS: Failed to resolve relay server address. Errno: %s.\n", gai_strerror(rv)); return; } qboolean connected = false; - for (struct addrinfo* p = servinfo; p != NULL; p = p->ai_next) { + for (const struct addrinfo* p = servinfo; p != NULL; p = p->ai_next) { vrx_relay_socket = socket(p->ai_family, p->ai_socktype, p->ai_protocol); if (vrx_relay_socket == -1) { continue; @@ -77,11 +81,11 @@ void vrx_relay_connect() { char ip[INET6_ADDRSTRLEN]; if (p->ai_family == AF_INET) { - struct sockaddr_in* addr = (struct sockaddr_in*)p->ai_addr; + const struct sockaddr_in* addr = (struct sockaddr_in*)p->ai_addr; inet_ntop(p->ai_family, &addr->sin_addr, ip, sizeof ip); ip[INET_ADDRSTRLEN] = '\0'; } else { - struct sockaddr_in6* addr = (struct sockaddr_in6*)p->ai_addr; + const struct sockaddr_in6* addr = (struct sockaddr_in6*)p->ai_addr; inet_ntop(p->ai_family, &addr->sin6_addr, ip, sizeof ip); } @@ -136,7 +140,7 @@ void vrx_relay_disconnect() { void send_sbuffer(SOCKET s, msgpack_sbuffer* sbuf) { int sent = 0; - size_t size = sizeof (uint32_t) * 2 + sbuf->size; + const size_t size = sizeof (uint32_t) * 2 + sbuf->size; if (sbuf->size > UINT_MAX) { gi.dprintf("RS: Message size is too large.\n"); @@ -155,7 +159,7 @@ void send_sbuffer(SOCKET s, msgpack_sbuffer* sbuf) { memcpy(data + HEADER_SIZE, sbuf->data, sbuf->size); while (sent < size) { - int n = send(s, data + sent, size - sent, 0); + const int n = send(s, data + sent, size - sent, 0); if (n == -1) { #ifdef WIN32 int err = WSAGetLastError(); @@ -163,7 +167,7 @@ void send_sbuffer(SOCKET s, msgpack_sbuffer* sbuf) { continue; } #else - int err = errno; + const int err = errno; if (errno == EWOULDBLOCK) { continue; } @@ -364,7 +368,7 @@ qboolean vrx_relay_try_message_relay(msgpack_object_str *type, msgpack_object_ar memcpy(msg, message->ptr, message->size); for (int j = 1; j <= game.maxclients; j++) { - edict_t *other = &g_edicts[j]; + const edict_t *other = &g_edicts[j]; if (!other->inuse) continue; if (!other->client) @@ -390,7 +394,7 @@ qboolean vrx_relay_try_authorized(msgpack_object_str *type, msgpack_object_array return false; } - msgpack_object_array* result = arr->ptr[1].type == MSGPACK_OBJECT_ARRAY ? &arr->ptr[1].via.array : NULL; + const msgpack_object_array* result = arr->ptr[1].type == MSGPACK_OBJECT_ARRAY ? &arr->ptr[1].via.array : NULL; if (result == NULL) { gi.dprintf("RS: Received relay message does not have a valid message field.\n"); *invalid = true; @@ -432,11 +436,11 @@ relay_parse_result_t vrx_relay_parse_message(size_t* start) { return RESULT_NEED_MORE_DATA; } - uint8_t* curbuf = (uint8_t*)&pending_buf[*start]; + const uint8_t* curbuf = (uint8_t*)&pending_buf[*start]; // az: read the magic and size, little-endian #ifdef LITTLE_ENDIAN - uint32_t magic = curbuf[0] | curbuf[1] << 8 | curbuf[2] << 16 | curbuf[3] << 24; - uint32_t size = curbuf[4] | curbuf[5] << 8 | curbuf[6] << 16 | curbuf[7] << 24; + const uint32_t magic = curbuf[0] | curbuf[1] << 8 | curbuf[2] << 16 | curbuf[3] << 24; + const uint32_t size = curbuf[4] | curbuf[5] << 8 | curbuf[6] << 16 | curbuf[7] << 24; #elif BIG_ENDIAN uint32_t magic = curbuf[3] | curbuf[2] << 8 | curbuf[1] << 16 | curbuf[0] << 24; uint32_t size = curbuf[7] | curbuf[6] << 8 | curbuf[5] << 16 | curbuf[4] << 24; @@ -457,7 +461,7 @@ relay_parse_result_t vrx_relay_parse_message(size_t* start) { msgpack_unpacked result; msgpack_unpacked_init(&result); - msgpack_unpack_return ret = msgpack_unpack_next(&result, curbuf + HEADER_SIZE, size, &off); + const msgpack_unpack_return ret = msgpack_unpack_next(&result, curbuf + HEADER_SIZE, size, &off); if (ret == MSGPACK_UNPACK_CONTINUE) { return RESULT_NEED_MORE_DATA; } @@ -555,7 +559,7 @@ void vrx_relay_recv() { size_t start = 0; qboolean continue_parsing = true; while (continue_parsing) { - relay_parse_result_t res = vrx_relay_parse_message(&start); + const relay_parse_result_t res = vrx_relay_parse_message(&start); switch (res) { case RESULT_INVALID: diff --git a/src/server/v_cmd.c b/src/server/v_cmd.c index a3a9af60..839ed036 100644 --- a/src/server/v_cmd.c +++ b/src/server/v_cmd.c @@ -135,7 +135,7 @@ const gameCommand_s commands[] = { "laser", Cmd_BuildLaser }, { "sentry", cmd_SentryGun }, { "lasersight", Cmd_LaserSight_f }, - { "flashlight", FL_make }, + { "flashlight", FL_toggle }, { "monster", Cmd_Drone_f }, { "detpipes", Cmd_DetPipes_f }, { "vrxinfo", OpenMyinfoMenu }, @@ -235,7 +235,7 @@ void InitHash() for (i = 0; i < CommandTotal; i++) { - unsigned int index = fnv_32a_str(commands[i].FunctionName, FNV1_32A_INIT) % (MAXCOMMANDS); + const unsigned int index = fnv_32a_str(commands[i].FunctionName, FNV1_32A_INIT) % (MAXCOMMANDS); memcpy(&hashedList[index], &commands[i], sizeof(gameCommand_s)); } diff --git a/src/server/v_luasettings.c b/src/server/v_luasettings.c index ecf2d819..8cfe2e36 100644 --- a/src/server/v_luasettings.c +++ b/src/server/v_luasettings.c @@ -126,14 +126,14 @@ int q2lua_get_nextmap(lua_State *L) int q2lua_get_ability_name(lua_State *L) { - int index = luaL_checkinteger(State, 1); + const int index = luaL_checkinteger(State, 1); lua_pushstring(L, GetAbilityString(index)); return 1; } int q2lua_get_is_ability_in_use(lua_State *L) { - int index = luaL_checkinteger(State, 1); + const int index = luaL_checkinteger(State, 1); lua_pushboolean(L, vrx_get_ability_by_index(index) != NULL); return 1; } @@ -275,7 +275,7 @@ qboolean vrx_lua_start_table_iter(const char *tablename) int vrx_lua_iter_next_string(char **out) { - int retval = lua_next(State, -2); + const int retval = lua_next(State, -2); if (retval != 0) { *out = strdup(lua_tostring(State, -1)); diff --git a/src/server/v_maplist.c b/src/server/v_maplist.c index b922139d..dbcc88c2 100644 --- a/src/server/v_maplist.c +++ b/src/server/v_maplist.c @@ -118,7 +118,7 @@ int vrx_load_map_list(int mode) break; } - char* s = buf; + const char* s = buf; // skip spaces s += strspn(s, " \r\n\t"); diff --git a/src/server/v_newbie_tips.c b/src/server/v_newbie_tips.c index cc6a8e6b..9aaf5fc5 100644 --- a/src/server/v_newbie_tips.c +++ b/src/server/v_newbie_tips.c @@ -6,18 +6,18 @@ const char *messages[] = { // decino: max 40 chars // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n "Open the Vortex menu with the following \nkey: 'TAB', or use the 'inven' command. \n", - "You can set your respawn weapon with the\nfollowing command: 'vrxrespawn' \n", - "Damage and kill as many things possible,\nyou will gain EXP fast and level up! \n", - "Use your credits at the armory to buy \nstuff with the command: 'vrxarmory' \n", - "Want to change name or class? \nChange your name and reconnect. \n", - "Leveled up? Spend your points to become \nstronger and unique! \n", + "You can set your respawn weapon with the\n following command: 'vrxrespawn' \n", + "Damage and kill as many things possible,\n you will gain EXP fast and level up! \n", + " Use your credits at the armory to buy \n stuff with the command: 'vrxarmory' \n", + " Want to change name or class? \n Change your name and reconnect. \n", + "Leveled up? Spend your points to become \n stronger and unique! \n", "Weapon points will upgrade your weapons,\nresulting more damage and other effects.\n", - "You can teleport away during combat with\nthe command: 'use tball self' \n", - "Make sure you've set a password, use \n'set vrx_password u' \n", - "To vote for modes and maps use the \nfollowing command: 'vote' \n", - "You earn talent points every 2 levels, \nuse those to become even more unique! \n", - "Seen those colored discs? Those are \ncalled runes and enhance your skills \nwithout the need of upgrading it! \n", - "To get a full list of commands, use \n'vrxhelp' \n" + "You can teleport away during combat with\n the command: 'use tball self' \n", + " Make sure you've set a password, use \n' set vrx_password u' \n", + " To vote for modes and maps use the \n following command: 'vote' \n", + " You earn talent points every 2 levels, \n use those to become even more unique! \n", + " Seen those colored discs? Those are \n called runes and enhance your skills \nwithout the need of upgrading it! \n", + " To get a full list of commands, use \n 'vrxhelp' \n" }; static const size_t msg_count = sizeof(messages) / sizeof(char*); diff --git a/src/server/vote.c b/src/server/vote.c index 85d4a674..586f8253 100644 --- a/src/server/vote.c +++ b/src/server/vote.c @@ -302,7 +302,7 @@ void vrx_start_vote(edict_t *ent, int mode, int mapnum) //check for valid choice - int players = vrx_get_joined_players(false); + const int players = vrx_get_joined_players(false); if (mode && (maplist->nummaps > mapnum)) { if (maplist->maps[mapnum].min_players > players) @@ -361,7 +361,7 @@ void vrx_start_vote(edict_t *ent, int mode, int mapnum) G_PrintGreenText(tempBuffer2); gi.sound(&g_edicts[0], CHAN_VOICE, gi.soundindex("misc/comp_up.wav"), 1, ATTN_NONE, 0); - uint64_t timeRem = (voteTimeLeft-level.framenum) / (uint64_t)sv_fps->value; + const uint64_t timeRem = (voteTimeLeft-level.framenum) / (uint64_t)sv_fps->value; gi.bprintf (PRINT_HIGH, "Please place your vote by typing 'vote yes' or 'vote no' within the next %u seconds.\n", timeRem); } @@ -374,7 +374,7 @@ void vrx_start_vote(edict_t *ent, int mode, int mapnum) int V_VoteDone () { - int players = vrx_get_joined_players(false); + const int players = vrx_get_joined_players(false); if (players < 1) return 0; @@ -496,8 +496,8 @@ void ShowVoteMapMenu_handler(edict_t *ent, int option) if (option > 20000) { - int mode = (option / 1000) - 20; - int nextpage = option % 1000; //page number we will end up in (page 0 = main menu) + const int mode = (option / 1000) - 20; + const int nextpage = option % 1000; //page number we will end up in (page 0 = main menu) if (nextpage != 0) ShowVoteMapMenu(ent, nextpage, mode); else @@ -505,8 +505,8 @@ void ShowVoteMapMenu_handler(edict_t *ent, int option) } else { - int mode = option / 1000; - int mapnum = option % 1000; + const int mode = option / 1000; + const int mapnum = option % 1000; v_maplist_t *maplist = GetMapList(mode); if (!maplist) return; @@ -635,7 +635,7 @@ qboolean ThereIsOneLevelTen() int i; for (i = 1; i <= maxclients->value; i++) { - edict_t* cl = g_edicts+i; + const edict_t* cl = g_edicts+i; if (cl->client && !G_IsSpectator(cl) && cl->inuse) if (cl->myskills.level >= 10) return true; @@ -648,7 +648,7 @@ void ShowVoteModeMenu(edict_t *ent) int players, lastline=6, min_players; - char *cmd2 = gi.argv(1); + const char *cmd2 = gi.argv(1); //Voting enabled? if (!voting->value) diff --git a/src/v_shared.h b/src/v_shared.h index 0ac1c1e9..e6a4fd41 100644 --- a/src/v_shared.h +++ b/src/v_shared.h @@ -32,6 +32,9 @@ int vrx_get_ability_class(int ability); #define DEFAULT_SOFTMAX 10 #define GENERAL_SOFTMAX 5 +#define MAX_LEVEL 50 +void vrx_fill_xp_accum_table(); +int16_t vrx_get_xp_percent(long xp, int level); typedef struct { int index;