diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bc10b1b995..f9459df477 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -62,6 +62,15 @@ jobs: shell: bash run: cmake --build . --config ${{ matrix.build_type }} -j $NUMBER_OF_PROCESSORS + - name: Copy PK3s + if: ${{ matrix.build_type == 'Release' }} + working-directory: ${{ github.workspace }} + shell: bash + run: | + mkdir -p ./build/bin/JediAcademy/base/ + cp ./pk3/assets_fpls.pk3 ./build/bin/JediAcademy/base/ + cp ./pk3/jk2binds.pk3 ./build/bin/JediAcademy/base/ + - name: Install if: ${{ matrix.build_type == 'Release' }} working-directory: ${{ github.workspace }}/build @@ -137,6 +146,14 @@ jobs: shell: bash run: cmake --install . + - name: Copy PK3s + if: ${{ matrix.build_type == 'Release' }} + working-directory: ${{ github.workspace }} + shell: bash + run: | + cp ./pk3/assets_fpls.pk3 ./install/JediAcademy/base/ + cp ./pk3/jk2binds.pk3 ./install/JediAcademy/base/ + - name: Create OpenJK binary archive if: ${{ matrix.build_type == 'Release' }} working-directory: ${{ github.workspace }}/install/JediAcademy @@ -210,6 +227,15 @@ jobs: shell: bash run: cmake --install . + - name: Copy PK3s + if: ${{ matrix.build_type == 'Release' }} + working-directory: ${{ github.workspace }} + shell: bash + run: | + mkdir -p ./install/JediAcademy/openjk_sp.${{ matrix.arch }}.app/Contents/MacOS/base/ + cp ./pk3/assets_fpls.pk3 ./install/JediAcademy/openjk_sp.${{ matrix.arch }}.app/Contents/MacOS/base/ + cp ./pk3/jk2binds.pk3 ./install/JediAcademy/openjk_sp.${{ matrix.arch }}.app/Contents/MacOS/base/ + - name: Create OpenJK binary archive if: ${{ matrix.build_type == 'Release' }} working-directory: ${{ github.workspace }}/install/JediAcademy diff --git a/code/cgame/cg_consolecmds.cpp b/code/cgame/cg_consolecmds.cpp index eb4b79a7aa..2fc24edae3 100644 --- a/code/cgame/cg_consolecmds.cpp +++ b/code/cgame/cg_consolecmds.cpp @@ -119,7 +119,7 @@ void CG_ToggleBinoculars( void ) cg.zoomMode = 1; cg.zoomLocked = qfalse; - if ( cg.weaponSelect == WP_SABER ) + if ( cg.weaponSelect == WP_SABER || cg.weaponSelect == WP_MELEE ) { cg.weaponSelect = WP_NONE; } @@ -151,6 +151,10 @@ void CG_ToggleBinoculars( void ) // FIXME: this is pretty damn ugly but whatever cg.weaponSelect = WP_SABER; } + else if( cg.weaponSelect == WP_NONE && cg.snap->ps.stats[STAT_WEAPONS] & ( 1 << WP_MELEE ) ) + { + cg.weaponSelect = WP_MELEE; + } } } @@ -177,6 +181,12 @@ void CG_ToggleLAGoggles( void ) cg.zoomMode = 3; cg.zoomLocked = qfalse; + + if ( cg.weaponSelect == WP_SABER || cg.weaponSelect == WP_MELEE ) + { + cg.weaponSelect = WP_NONE; + } + if ( cg.overrides.active & CG_OVERRIDE_FOV ) { cg_zoomFov = cg.overrides.fov; @@ -193,6 +203,16 @@ void CG_ToggleLAGoggles( void ) cg.zoomMode = 0; cg.zoomTime = cg.time; cgi_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.media.zoomEnd ); + + if( cg.weaponSelect == WP_NONE && cg.snap->ps.stats[STAT_WEAPONS] & ( 1 << WP_SABER ) ) + { + // FIXME: this is pretty damn ugly but whatever + cg.weaponSelect = WP_SABER; + } + else if( cg.weaponSelect == WP_NONE && cg.snap->ps.stats[STAT_WEAPONS] & ( 1 << WP_MELEE ) ) + { + cg.weaponSelect = WP_MELEE; + } } } diff --git a/code/cgame/cg_draw.cpp b/code/cgame/cg_draw.cpp index f6c589aabc..58d55de56a 100644 --- a/code/cgame/cg_draw.cpp +++ b/code/cgame/cg_draw.cpp @@ -328,7 +328,7 @@ static void CG_DrawAmmo(const centity_t *cent,const int xPos,const int yPos) return; } - if ( cent->currentState.weapon == WP_STUN_BATON ) + if ( cent->currentState.weapon == WP_STUN_BATON || cent->currentState.weapon == WP_MELEE ) { return; } @@ -3991,7 +3991,7 @@ static void CG_Draw2D( void ) { if ( !(cent->gent && cent->gent->s.eFlags & (EF_LOCKED_TO_WEAPON )))//|EF_IN_ATST { - //CG_DrawIconBackground(); + CG_DrawIconBackground(); } CG_DrawWeaponSelect(); @@ -4145,8 +4145,8 @@ void CG_DrawIconBackground(void) // Use weapon background? else if (((cg.weaponSelectTime+WEAPON_SELECT_TIME)>cg.time) || (cgs.media.currentBackground == ICON_WEAPONS)) { - background = 0; - //background = cgs.media.weaponIconBackground; + //background = 0; + background = cgs.media.weaponIconBackground; } // Use force background? else diff --git a/code/cgame/cg_event.cpp b/code/cgame/cg_event.cpp index 635dfe14d9..91555d36c4 100644 --- a/code/cgame/cg_event.cpp +++ b/code/cgame/cg_event.cpp @@ -253,6 +253,34 @@ static void CG_UseItem( centity_t *cent ) } +/* +============== +CG_UnsafeEventType +Returns qtrue for event types that access cent->gent directly (and don't require it +to be the player / entity 0). +============== +*/ +qboolean CG_UnsafeEventType(int eventType) +{//from JKEnhanced + switch (eventType) + { + case EV_CHANGE_WEAPON: + case EV_DISRUPTOR_SNIPER_SHOT: + case EV_DISRUPTOR_SNIPER_MISS: + case EV_CONC_ALT_MISS: + case EV_DISINTEGRATION: + case EV_GRENADE_BOUNCE: + case EV_MISSILE_HIT: + case EV_MISSILE_MISS: + case EV_PAIN: + case EV_PLAY_EFFECT: + case EV_TARGET_BEAM_DRAW: + return qtrue; + break; + default: + return qfalse; + } +} /* ============== @@ -287,6 +315,14 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { return; } + //When skipping a cutscene the timescale is drastically increased, causing entities to be freed + //and possibly reused between the snapshot currentState and the actual state of the gent when accessed. + //We try to avoid this issue by ignoring events on entities that have been freed since the snapshot. + if (cent->gent->freetime > cg.snap->serverTime && CG_UnsafeEventType(event)) + {//from JKEnhanced + return; + } + //ci = ¢->gent->client->clientInfo; clientNum = cent->gent->s.number; diff --git a/code/cgame/cg_local.h b/code/cgame/cg_local.h index 8c0960f8b4..c13d8b29b4 100644 --- a/code/cgame/cg_local.h +++ b/code/cgame/cg_local.h @@ -624,6 +624,7 @@ extern vmCvar_t cg_thirdPersonPitchOffset; extern vmCvar_t cg_thirdPersonVertOffset; extern vmCvar_t cg_thirdPersonCameraDamp; extern vmCvar_t cg_thirdPersonTargetDamp; +// extern vmCvar_t cg_saberAutoThird; extern vmCvar_t cg_gunAutoFirst; extern vmCvar_t cg_stereoSeparation; diff --git a/code/cgame/cg_main.cpp b/code/cgame/cg_main.cpp index db6f7dc4e0..6b6c9fc834 100644 --- a/code/cgame/cg_main.cpp +++ b/code/cgame/cg_main.cpp @@ -299,6 +299,7 @@ vmCvar_t cg_thirdPersonPitchOffset; vmCvar_t cg_thirdPersonVertOffset; vmCvar_t cg_thirdPersonCameraDamp; vmCvar_t cg_thirdPersonTargetDamp; +// vmCvar_t cg_saberAutoThird; vmCvar_t cg_gunAutoFirst; vmCvar_t cg_thirdPersonAlpha; @@ -352,7 +353,7 @@ static cvarTable_t cvarTable[] = { { &cg_autoswitch, "cg_autoswitch", "1", CVAR_ARCHIVE }, { &cg_drawGun, "cg_drawGun", "1", CVAR_ARCHIVE }, { &cg_fov, "cg_fov", "80", CVAR_ARCHIVE }, - { &cg_fovAspectAdjust, "cg_fovAspectAdjust", "0", CVAR_ARCHIVE }, + { &cg_fovAspectAdjust, "cg_fovAspectAdjust", "1", CVAR_ARCHIVE }, { &cg_stereoSeparation, "cg_stereoSeparation", "0.4", CVAR_ARCHIVE }, { &cg_shadows, "cg_shadows", "1", CVAR_ARCHIVE }, { &cg_renderToTextureFX, "cg_renderToTextureFX", "1", CVAR_ARCHIVE }, @@ -424,6 +425,7 @@ static cvarTable_t cvarTable[] = { { &cg_thirdPersonAlpha, "cg_thirdPersonAlpha", "1.0", CVAR_ARCHIVE }, { &cg_thirdPersonAutoAlpha, "cg_thirdPersonAutoAlpha", "0", 0 }, // NOTE: also declare this in UI_Init + // { &cg_saberAutoThird, "cg_saberAutoThird", "1", CVAR_ARCHIVE }, { &cg_gunAutoFirst, "cg_gunAutoFirst", "1", CVAR_ARCHIVE }, { &cg_pano, "pano", "0", 0 }, @@ -1368,7 +1370,7 @@ static void CG_RegisterGraphics( void ) { // FIXME: do these conditionally cgi_R_RegisterShader( "gfx/2d/workingCamera" ); cgi_R_RegisterShader( "gfx/2d/brokenCamera" ); - //cgi_R_RegisterShader( "gfx/effects/irid_shield" ); // for galak, but he doesn't have his own weapon so I can't register the shader there. + cgi_R_RegisterShader( "gfx/effects/irid_shield" ); // for galak, but he doesn't have his own weapon so I can't register the shader there. //interface for ( i = 0 ; i < NUM_CROSSHAIRS ; i++ ) { diff --git a/code/cgame/cg_players.cpp b/code/cgame/cg_players.cpp index 9a6e6aa4f8..080af137c3 100644 --- a/code/cgame/cg_players.cpp +++ b/code/cgame/cg_players.cpp @@ -4599,6 +4599,8 @@ CG_AddRefEntityWithPowerups Adds a piece with modifications or duplications for powerups =============== */ +extern vmCvar_t cg_thirdPersonAlpha; +extern qboolean G_ControlledByPlayer(gentity_t* self); void CG_AddRefEntityWithPowerups( refEntity_t *ent, int powerups, centity_t *cent ) { if ( !cent ) @@ -4634,6 +4636,26 @@ void CG_AddRefEntityWithPowerups( refEntity_t *ent, int powerups, centity_t *cen ent->shaderRGBA[2] = gent->client->renderInfo.customRGBA[2]; ent->shaderRGBA[3] = gent->client->renderInfo.customRGBA[3]; + //cg_thirdpersonAlpha fix from JKEnhanced + if ((cent->gent->s.number == 0 || G_ControlledByPlayer(cent->gent))) + { + float alpha = 1.0f; + if ((cg.overrides.active & CG_OVERRIDE_3RD_PERSON_APH)) + { + alpha = cg.overrides.thirdPersonAlpha; + } + else + { + alpha = cg_thirdPersonAlpha.value; + } + + if (alpha < 1.0f) + { + ent->renderfx |= RF_ALPHA_FADE; + ent->shaderRGBA[3] *= alpha; + } + } + // If certain states are active, we don't want to add in the regular body if ( !gent->client->ps.powerups[PW_CLOAKED] && !gent->client->ps.powerups[PW_UNCLOAKING] && @@ -4789,11 +4811,13 @@ void CG_AddRefEntityWithPowerups( refEntity_t *ent, int powerups, centity_t *cen // FORCE speed does blur trails //------------------------------------------------------ + static int speedTrailDebounce; if ( cg_speedTrail.integer && (gent->client->ps.forcePowersActive & (1 << FP_SPEED) //in force speed || cent->gent->client->ps.legsAnim == BOTH_FORCELONGLEAP_START//or force long jump - FIXME: only 1st half of that anim? || cent->gent->client->ps.legsAnim == BOTH_FORCELONGLEAP_ATTACK )//or force long jump attack - && (gent->s.number || cg.renderingThirdPerson) ) // looks dumb doing this with first peron mode on + && (gent->s.number || cg.renderingThirdPerson) // looks dumb doing this with first peron mode on + && --speedTrailDebounce <= 0 ) //debounce to avoid model render overload { //FIXME: debounce this localEntity_t *ex; @@ -4822,6 +4846,7 @@ void CG_AddRefEntityWithPowerups( refEntity_t *ent, int powerups, centity_t *cen ex->color[0] = ex->color[1] = ex->color[2] = 255.0f; } ex->color[3] = 50.0f; + speedTrailDebounce = 3; } // Personal Shields @@ -4853,9 +4878,9 @@ void CG_AddRefEntityWithPowerups( refEntity_t *ent, int powerups, centity_t *cen // Galak Mech shield bubble //------------------------------------------------------ - if ( powerups & ( 1 << PW_GALAK_SHIELD )) + if ( (powerups & ( 1 << PW_GALAK_SHIELD )) && gent->client->NPC_class == CLASS_GALAKMECH ) { -/* refEntity_t tent; + refEntity_t tent; memset( &tent, 0, sizeof( refEntity_t )); @@ -4882,7 +4907,7 @@ void CG_AddRefEntityWithPowerups( refEntity_t *ent, int powerups, centity_t *cen tent.endTime = gent->fx_time + 1000; // if you want the shell to build around the guy, pass in a time that is 1000ms after the start of the turn-on-effect tent.customShader = cgi_R_RegisterShader( "gfx/effects/irid_shield" ); - cgi_R_AddRefEntityToScene( &tent );*/ + cgi_R_AddRefEntityToScene( &tent ); } // Invincibility -- effect needs work @@ -6812,7 +6837,7 @@ CG_Player =============== */ extern qboolean G_GetRootSurfNameWithVariant( gentity_t *ent, const char *rootSurfName, char *returnSurfName, int returnSize ); -extern qboolean G_ControlledByPlayer( gentity_t *self ); +// extern qboolean G_ControlledByPlayer( gentity_t *self ); extern qboolean G_RagDoll(gentity_t *ent, vec3_t forcedAngles); int cg_saberOnSoundTime[MAX_GENTITIES] = {0}; @@ -6838,7 +6863,7 @@ void CG_Player( centity_t *cent ) { return; } - if( cent->gent->s.number == 0 && cg.weaponSelect == WP_NONE && cg.zoomMode == 1 ) + if( cent->gent->s.number == 0 && (cg.weaponSelect == WP_NONE || cg.weaponSelect == WP_MELEE || cg.weaponSelect == WP_SABER) && (cg.zoomMode == 1 || cg.zoomMode == 3) ) { // HACK return; @@ -7212,26 +7237,37 @@ Ghoul2 Insert Start */ //HACK - add swoop model -extern vmCvar_t cg_thirdPersonAlpha; - - if ( (cent->gent->s.number == 0 || G_ControlledByPlayer( cent->gent )) ) - { - float alpha = 1.0f; - if ( (cg.overrides.active&CG_OVERRIDE_3RD_PERSON_APH) ) - { - alpha = cg.overrides.thirdPersonAlpha; - } - else - { - alpha = cg_thirdPersonAlpha.value; - } - - if ( alpha < 1.0f ) - { - ent.renderfx |= RF_ALPHA_FADE; - ent.shaderRGBA[3] = (unsigned char)(alpha * 255.0f); - } +// extern vmCvar_t cg_thirdPersonAlpha; + +// if ( (cent->gent->s.number == 0 || G_ControlledByPlayer( cent->gent )) ) +// { +// float alpha = 1.0f; +// if ( (cg.overrides.active&CG_OVERRIDE_3RD_PERSON_APH) ) +// { +// alpha = cg.overrides.thirdPersonAlpha; +// } +// else +// { +// alpha = cg_thirdPersonAlpha.value; +// } + +// if ( alpha < 1.0f ) +// { +// ent.renderfx |= RF_ALPHA_FADE; +// ent.shaderRGBA[3] = (unsigned char)(alpha * 255.0f); +// } +// } + + /*if ( !cg.renderingThirdPerson + && ( cg.snap->ps.weapon == WP_SABER || cg.snap->ps.weapon == WP_MELEE ) + && !cent->gent->s.number ) + {// Yeah um, this needs to not do this quite this way + ent.customSkin = cgi_R_RegisterSkin( "models/players/kyle/model_fpls.skin" ); //precached in g_client.cpp } + else + { + ent.customSkin = 0; + }*/ if ( cg_debugHealthBars.integer ) { diff --git a/code/cgame/cg_view.cpp b/code/cgame/cg_view.cpp index 7b8b2a9d4f..be8381d628 100644 --- a/code/cgame/cg_view.cpp +++ b/code/cgame/cg_view.cpp @@ -463,7 +463,7 @@ static void CG_CalcIdealThirdPersonViewLocation(void) VectorMA(cameraIdealTarget, -(cg_thirdPersonRange.value), camerafwd, cameraIdealLoc); } - if ( cg.renderingThirdPerson && (cg.snap->ps.forcePowersActive&(1<client->ps.forcePowerDuration[FP_SPEED] ) + /*if ( cg.renderingThirdPerson && (cg.snap->ps.forcePowersActive&(1<client->ps.forcePowerDuration[FP_SPEED] ) { float timeLeft = player->client->ps.forcePowerDuration[FP_SPEED] - cg.time; float length = FORCE_SPEED_DURATION*forceSpeedValue[player->client->ps.forcePowerLevel[FP_SPEED]]; @@ -480,7 +480,7 @@ static void CG_CalcIdealThirdPersonViewLocation(void) { VectorMA(cameraIdealLoc, amt, camerafwd, cameraIdealLoc); } - } + }*/ } diff --git a/code/cgame/cg_weapons.cpp b/code/cgame/cg_weapons.cpp index 09a5b20ad4..ee4b22297b 100644 --- a/code/cgame/cg_weapons.cpp +++ b/code/cgame/cg_weapons.cpp @@ -2648,6 +2648,38 @@ void CG_Weapon_f( void ) i++; } } + else if (num == WP_BLASTER_PISTOL || num == WP_BRYAR_PISTOL) //from JKEnhanced + { + int weap, i = 0; + + weap = cg.snap->ps.weapon; + + while (i < 2) + { + if (weap == WP_BLASTER_PISTOL) + { + weap = WP_BRYAR_PISTOL; + } + else if (weap == WP_BRYAR_PISTOL) + { + weap = WP_BLASTER_PISTOL; + } + else + { + weap = num; + } + + if (cg.snap->ps.ammo[weaponData[weap].ammoIndex] > 0) + { + if (CG_WeaponSelectable(weap, cg.snap->ps.weapon, qfalse)) + { + num = weap; + break; + } + } + i++; + } + } if (!CG_WeaponSelectable(num, cg.snap->ps.weapon, qfalse)) { diff --git a/code/client/cl_cin.cpp b/code/client/cl_cin.cpp index 7cf2db8c2f..e86a171321 100644 --- a/code/client/cl_cin.cpp +++ b/code/client/cl_cin.cpp @@ -1879,6 +1879,9 @@ static void PlayCinematic(const char *arg, const char *s, qboolean qbInGame) qboolean bIsForeign = (qboolean)(s_language && Q_stricmp(s_language->string,"english") && Q_stricmp(s_language->string,"")); const char *psAudioFile = NULL; qhandle_t hCrawl = 0; + // find the current mapname + const char *info = cl.gameState.stringData + cl.gameState.stringOffsets[ CS_SERVERINFO ]; + const char *mapname = Info_ValueForKey( info, "mapname" ); if (!Q_stricmp(arg,"video/jk0101_sw.roq")) { psAudioFile = "music/cinematic_1"; @@ -1890,7 +1893,19 @@ static void PlayCinematic(const char *arg, const char *s, qboolean qbInGame) hCrawl = re.RegisterShaderNoMip( "menu/video/tc_0" ); } #else - hCrawl = re.RegisterShaderNoMip( va("menu/video/tc_%s",se_language->string) ); + hCrawl = re.RegisterShaderNoMip( va("menu/video/tc_%s_%s",mapname,se_language->string) ); + if (!hCrawl) + { + hCrawl = re.RegisterShaderNoMip( va("menu/video/tc_%s_english",mapname) );//failed, so go back to mapname + english + } + if (!hCrawl) + { + hCrawl = re.RegisterShaderNoMip( va("menu/video/tc_%s",mapname) );//failed, so go back to mapname + } + if (!hCrawl) + { + hCrawl = re.RegisterShaderNoMip( va("menu/video/tc_%s",se_language->string) );//failed, so go back to set language + } if (!hCrawl) { hCrawl = re.RegisterShaderNoMip( "menu/video/tc_english" );//failed, so go back to english diff --git a/code/client/snd_dma.cpp b/code/client/snd_dma.cpp index bb539e4cd6..6e4bbd757f 100644 --- a/code/client/snd_dma.cpp +++ b/code/client/snd_dma.cpp @@ -4805,14 +4805,14 @@ static qboolean S_UpdateBackgroundTrack_Actual( MusicInfo_t *pMusicInfo, qboolea // or if it's a dynamic music specifier (which can't literally exist), in which case it should set // a return flag then exit... // - char sTestName[MAX_QPATH*2];// *2 so COM_DefaultExtension doesn't do an ERR_DROP if there was no space + char sTestName[MAX_QPATH/**2*/];// *2 so COM_DefaultExtension doesn't do an ERR_DROP if there was no space // for an extension, since this is a "soft" test - Q_strncpyz( sTestName, sMusic_BackgroundLoop, sizeof(sTestName)); + Q_strncpyz( sTestName, sMusic_BackgroundLoop, sizeof(sTestName) - 4 ); COM_DefaultExtension(sTestName, sizeof(sTestName), ".mp3"); if (S_FileExists( sTestName )) { - S_StartBackgroundTrack_Actual( pMusicInfo, qfalse, sMusic_BackgroundLoop, sMusic_BackgroundLoop ); + S_StartBackgroundTrack_Actual( pMusicInfo, qfalse, sTestName, sTestName ); } else { diff --git a/code/client/snd_mix.cpp b/code/client/snd_mix.cpp index d245590db1..b0f135d460 100644 --- a/code/client/snd_mix.cpp +++ b/code/client/snd_mix.cpp @@ -124,7 +124,7 @@ void S_TransferPaintBuffer(int endtime) p = (int *) paintbuffer; count = (endtime - s_paintedtime) * dma.channels; out_mask = dma.samples - 1; - out_idx = s_paintedtime * dma.channels & out_mask; + out_idx = (unsigned int)s_paintedtime * dma.channels & out_mask; step = 3 - dma.channels; if (dma.samplebits == 16) diff --git a/code/game/AI_GalakBoss.cpp b/code/game/AI_GalakBoss.cpp new file mode 100644 index 0000000000..5f27eeedeb --- /dev/null +++ b/code/game/AI_GalakBoss.cpp @@ -0,0 +1,1277 @@ +/* +=========================================================================== +Copyright (C) 2000 - 2013, Raven Software, Inc. +Copyright (C) 2001 - 2013, Activision, Inc. +Copyright (C) 2013 - 2015, OpenJK contributors + +This file is part of the OpenJK source code. + +OpenJK is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, see . +=========================================================================== +*/ +#include "b_local.h" +#include "g_functions.h" +#include "g_nav.h" +#include "g_navigator.h" +#include "../cgame/cg_local.h" +#include "anims.h" +#include "wp_saber.h" + +extern qboolean G_StandardHumanoid( gentity_t *self ); +extern void G_AddVoiceEvent( gentity_t *self, int event, int speakDebounceTime ); +extern qboolean Q3_TaskIDPending( gentity_t *ent, taskID_t taskType ); +extern void NPC_AimAdjust( int change ); +extern qboolean WP_LobFire( gentity_t *self, vec3_t start, vec3_t target, vec3_t mins, vec3_t maxs, int clipmask, + vec3_t velocity, qboolean tracePath, int ignoreEntNum, int enemyNum, + float minSpeed, float maxSpeed, float idealSpeed, qboolean mustHit ); +extern qboolean InFront( vec3_t spot, vec3_t from, vec3_t fromAngles, float threshHold = 0.0f ); +extern void G_SoundAtSpot( vec3_t org, int soundIndex, qboolean broadcast ); +extern void G_SoundOnEnt (gentity_t *ent, soundChannel_t channel, const char *soundPath); +extern qboolean PM_CrouchAnim( int anim ); +//extern void NPC_Mark1_Part_Explode(gentity_t *self,int bolt); + +#define MELEE_DIST_SQUARED 6400//80*80 +#define MIN_LOB_DIST_SQUARED 65536//256*256 +#define MAX_LOB_DIST_SQUARED 200704//448*448 +#define REPEATER_ALT_SIZE 3 // half of bbox size +#define GENERATOR_HEALTH 25 +#define TURN_ON 0x00000000 +#define TURN_OFF 0x00000100 +#define GALAK_SHIELD_HEALTH 500 + +static vec3_t shieldMins = {-60, -60, -24 }; +static vec3_t shieldMaxs = {60, 60, 80}; + +extern qboolean NPC_CheckPlayerTeamStealth( void ); + +static qboolean enemyLOS; +static qboolean enemyCS; +static qboolean hitAlly; +static qboolean faceEnemy; +static qboolean AImove; +static qboolean shoot; +static float enemyDist; +static vec3_t impactPos; + +void NPC_GalakMech_Precache( void ) +{ + G_SoundIndex( "sound/weapons/galak/skewerhit.wav" ); + G_SoundIndex( "sound/weapons/galak/lasercharge.wav" ); + G_SoundIndex( "sound/weapons/galak/lasercutting.wav" ); + G_SoundIndex( "sound/weapons/galak/laserdamage.wav" ); + + G_EffectIndex( "galak/trace_beam" ); + G_EffectIndex( "galak/beam_warmup" ); +// G_EffectIndex( "small_chunks"); + G_EffectIndex( "env/med_explode2"); + G_EffectIndex( "env/small_explode2"); + G_EffectIndex( "galak/explode"); + G_EffectIndex( "blaster/smoke_bolton"); +// G_EffectIndex( "env/exp_trail_comp"); +} + +void NPC_GalakMech_Init( gentity_t *ent ) +{ + if (ent->NPC->behaviorState != BS_CINEMATIC) + { + ent->client->ps.stats[STAT_ARMOR] = GALAK_SHIELD_HEALTH; + ent->NPC->investigateCount = ent->NPC->investigateDebounceTime = 0; + ent->flags |= FL_SHIELDED;//reflect normal shots + ent->client->ps.powerups[PW_GALAK_SHIELD] = Q3_INFINITE;//temp, for effect + ent->fx_time = level.time; + VectorSet( ent->mins, -60, -60, -24 ); + VectorSet( ent->maxs, 60, 60, 80 ); + ent->flags |= FL_NO_KNOCKBACK;//don't get pushed + TIMER_Set( ent, "attackDelay", 0 ); //FIXME: Slant for difficulty levels + TIMER_Set( ent, "flee", 0 ); + TIMER_Set( ent, "smackTime", 0 ); + TIMER_Set( ent, "beamDelay", 0 ); + TIMER_Set( ent, "noLob", 0 ); + TIMER_Set( ent, "noRapid", 0 ); + TIMER_Set( ent, "talkDebounce", 0 ); + gi.G2API_SetSurfaceOnOff( &ent->ghoul2[ent->playerModel], "torso_shield_off", TURN_ON ); + gi.G2API_SetSurfaceOnOff( &ent->ghoul2[ent->playerModel], "torso_galakface_off", TURN_OFF ); + gi.G2API_SetSurfaceOnOff( &ent->ghoul2[ent->playerModel], "torso_galakhead_off", TURN_OFF ); + gi.G2API_SetSurfaceOnOff( &ent->ghoul2[ent->playerModel], "torso_eyes_mouth_off", TURN_OFF ); + gi.G2API_SetSurfaceOnOff( &ent->ghoul2[ent->playerModel], "torso_collar_off", TURN_OFF ); + gi.G2API_SetSurfaceOnOff( &ent->ghoul2[ent->playerModel], "torso_galaktorso_off", TURN_OFF ); + } + else + { +// gi.G2API_SetSurfaceOnOff( &ent->ghoul2[ent->playerModel], "helmet", TURN_OFF ); + gi.G2API_SetSurfaceOnOff( &ent->ghoul2[ent->playerModel], "torso_shield_off", TURN_OFF ); + gi.G2API_SetSurfaceOnOff( &ent->ghoul2[ent->playerModel], "torso_galakface_off", TURN_ON ); + gi.G2API_SetSurfaceOnOff( &ent->ghoul2[ent->playerModel], "torso_galakhead_off", TURN_ON ); + gi.G2API_SetSurfaceOnOff( &ent->ghoul2[ent->playerModel], "torso_eyes_mouth_off", TURN_ON ); + gi.G2API_SetSurfaceOnOff( &ent->ghoul2[ent->playerModel], "torso_collar_off", TURN_ON ); + gi.G2API_SetSurfaceOnOff( &ent->ghoul2[ent->playerModel], "torso_galaktorso_off", TURN_ON ); + } + +} + +//----------------------------------------------------------------- +static void GM_CreateExplosion( gentity_t *self, const int boltID, qboolean doSmall = qfalse ) +{ + if ( boltID >=0 ) + { + mdxaBone_t boltMatrix; + vec3_t org, dir; + + gi.G2API_GetBoltMatrix( self->ghoul2, self->playerModel, + boltID, + &boltMatrix, self->currentAngles, self->currentOrigin, (cg.time?cg.time:level.time), + NULL, self->s.modelScale ); + + gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, org ); + gi.G2API_GiveMeVectorFromMatrix( boltMatrix, NEGATIVE_Y, dir ); + + if ( doSmall ) + { + G_PlayEffect( "env/small_explode2", org, dir ); + } + else + { + G_PlayEffect( "env/med_explode2", org, dir ); + } + } +} + +/* +------------------------- +GM_Dying +------------------------- +*/ + +void GM_Dying( gentity_t *self ) +{ + if ( level.time - self->s.time < 4000 ) + {//FIXME: need a real effect + self->s.powerups |= ( 1 << PW_SHOCKED ); + self->client->ps.powerups[PW_SHOCKED] = level.time + 1000; + if ( TIMER_Done( self, "dyingExplosion" ) ) + { + int newBolt; + switch ( Q_irand( 1, 14 ) ) + { + // Find place to generate explosion + case 1: + if (!gi.G2API_GetSurfaceRenderStatus( &self->ghoul2[self->playerModel], "r_hand" )) + {//r_hand still there + GM_CreateExplosion( self, self->handRBolt, qtrue ); + gi.G2API_SetSurfaceOnOff( &self->ghoul2[self->playerModel], "r_hand", TURN_OFF ); + } + else if (!gi.G2API_GetSurfaceRenderStatus( &self->ghoul2[self->playerModel], "r_arm_middle" )) + {//r_arm_middle still there + newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*r_arm_elbow" ); + gi.G2API_SetSurfaceOnOff( &self->ghoul2[self->playerModel], "r_arm_middle", TURN_OFF ); + } + break; + case 2: + //FIXME: do only once? + if (!gi.G2API_GetSurfaceRenderStatus( &self->ghoul2[self->playerModel], "l_hand" )) + {//l_hand still there + GM_CreateExplosion( self, self->handLBolt ); + gi.G2API_SetSurfaceOnOff( &self->ghoul2[self->playerModel], "l_hand", TURN_OFF ); + } + else if (!gi.G2API_GetSurfaceRenderStatus( &self->ghoul2[self->playerModel], "l_arm_wrist" )) + {//l_arm_wrist still there + newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*l_arm_cap_l_hand" ); + gi.G2API_SetSurfaceOnOff( &self->ghoul2[self->playerModel], "l_arm_wrist", TURN_OFF ); + } + else if (!gi.G2API_GetSurfaceRenderStatus( &self->ghoul2[self->playerModel], "l_arm_middle" )) + {//l_arm_middle still there + newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*l_arm_cap_l_hand" ); + gi.G2API_SetSurfaceOnOff( &self->ghoul2[self->playerModel], "l_arm_middle", TURN_OFF ); + } + else if (!gi.G2API_GetSurfaceRenderStatus( &self->ghoul2[self->playerModel], "l_arm_augment" )) + {//l_arm_augment still there + newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*l_arm_elbow" ); + gi.G2API_SetSurfaceOnOff( &self->ghoul2[self->playerModel], "l_arm_augment", TURN_OFF ); + } + break; + case 3: + case 4: + newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*hip_fr" ); + GM_CreateExplosion( self, newBolt ); + break; + case 5: + case 6: + newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*shldr_l" ); + GM_CreateExplosion( self, newBolt ); + break; + case 7: + case 8: + newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*uchest_r" ); + GM_CreateExplosion( self, newBolt ); + break; + case 9: + case 10: + GM_CreateExplosion( self, self->headBolt ); + break; + case 11: + newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*l_leg_knee" ); + GM_CreateExplosion( self, newBolt, qtrue ); + break; + case 12: + newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*r_leg_knee" ); + GM_CreateExplosion( self, newBolt, qtrue ); + break; + case 13: + newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*l_leg_foot" ); + GM_CreateExplosion( self, newBolt, qtrue ); + break; + case 14: + newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*r_leg_foot" ); + GM_CreateExplosion( self, newBolt, qtrue ); + break; + } + + TIMER_Set( self, "dyingExplosion", Q_irand( 300, 1100 ) ); + } + } + else + {//one final, huge explosion + G_PlayEffect( "galak/explode", self->currentOrigin ); +// G_PlayEffect( "small_chunks", self->currentOrigin ); +// G_PlayEffect( "env/exp_trail_comp", self->currentOrigin, self->currentAngles ); + self->nextthink = level.time + FRAMETIME; + self->e_ThinkFunc = thinkF_G_FreeEntity; + } +} + +/* +------------------------- +NPC_GM_Pain +------------------------- +*/ + +extern void NPC_SetPainEvent( gentity_t *self ); +void NPC_GM_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *other, const vec3_t point, int damage, int mod,int hitLoc ) +{ + if ( self->client->ps.powerups[PW_GALAK_SHIELD] == 0 ) + {//shield is currently down + //FIXME: allow for radius damage? + if ( (hitLoc==HL_GENERIC1) && (self->locationDamage[HL_GENERIC1] > GENERATOR_HEALTH) ) + { + int newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*antenna_base" ); + if ( newBolt != -1 ) + { + GM_CreateExplosion( self, newBolt ); + } + + gi.G2API_SetSurfaceOnOff( &self->ghoul2[self->playerModel], "torso_shield_off", TURN_OFF ); + gi.G2API_SetSurfaceOnOff( &self->ghoul2[self->playerModel], "torso_antenna", TURN_OFF ); + gi.G2API_SetSurfaceOnOff( &self->ghoul2[self->playerModel], "torso_antenna_base_cap_off", TURN_ON ); + self->client->ps.powerups[PW_GALAK_SHIELD] = 0;//temp, for effect + self->client->ps.stats[STAT_ARMOR] = 0;//no more armor + self->NPC->investigateDebounceTime = 0;//stop recharging + + // NPC_SetAnim( self, SETANIM_BOTH, BOTH_ALERT1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + TIMER_Set( self, "attackDelay", self->client->ps.torsoAnimTimer ); + G_AddEvent( self, Q_irand( EV_DEATH1, EV_DEATH3 ), self->health ); + } + } + else + {//store the point for shield impact + if ( point ) + { + VectorCopy( point, self->pos4 ); + self->client->poisonTime = level.time; + } + } + + if ( !self->lockCount && !self->client->ps.torsoAnimTimer ) + {//don't interrupt laser sweep attack or other special attacks/moves + if ( self->count < 4 && self->health > 100 && hitLoc != HL_GENERIC1 ) + { + if ( self->delay < level.time ) + { + int speech; + switch( self->count ) + { + default: + case 0: + speech = EV_PUSHED1; + break; + case 1: + speech = EV_PUSHED2; + break; + case 2: + speech = EV_PUSHED3; + break; + case 3: + speech = EV_DETECTED1; + break; + } + self->count++; + self->NPC->blockedSpeechDebounceTime = 0; + G_AddVoiceEvent( self, speech, Q_irand( 3000, 5000 ) ); + self->delay = level.time + Q_irand( 5000, 7000 ); + } + } + else + { + NPC_Pain( self, inflictor, other, point, damage, mod, hitLoc ); + } + } + else if ( hitLoc == HL_GENERIC1 ) + { + NPC_SetPainEvent( self ); + self->s.powerups |= ( 1 << PW_SHOCKED ); + self->client->ps.powerups[PW_SHOCKED] = level.time + Q_irand( 500, 2500 ); + } + + if ( inflictor && inflictor->lastEnemy == self ) + {//He force-pushed my own lobfires back at me + if ( mod == MOD_REPEATER_ALT && !Q_irand( 0, 2 ) ) + { + if ( TIMER_Done( self, "noRapid" ) ) + { + self->NPC->scriptFlags &= ~SCF_ALT_FIRE; + self->alt_fire = qfalse; + TIMER_Set( self, "noLob", Q_irand( 2000, 6000 ) ); + } + else + {//hopefully this will make us fire the laser + TIMER_Set( self, "noLob", Q_irand( 1000, 2000 ) ); + } + } + else if ( mod == MOD_REPEATER && !Q_irand( 0, 5 ) ) + { + if ( TIMER_Done( self, "noLob" ) ) + { + self->NPC->scriptFlags |= SCF_ALT_FIRE; + self->alt_fire = qtrue; + TIMER_Set( self, "noRapid", Q_irand( 2000, 6000 ) ); + } + else + {//hopefully this will make us fire the laser + TIMER_Set( self, "noRapid", Q_irand( 1000, 2000 ) ); + } + } + } +} + +/* +------------------------- +GM_HoldPosition +------------------------- +*/ + +static void GM_HoldPosition( void ) +{ + NPC_FreeCombatPoint( NPCInfo->combatPoint, qtrue ); + if ( !Q3_TaskIDPending( NPC, TID_MOVE_NAV ) ) + {//don't have a script waiting for me to get to my point, okay to stop trying and stand + NPCInfo->goalEntity = NULL; + } +} + +/* +------------------------- +GM_Move +------------------------- +*/ +static qboolean GM_Move( void ) +{ + NPCInfo->combatMove = qtrue;//always move straight toward our goal + + qboolean moved = NPC_MoveToGoal( qtrue ); + // navInfo_t info; + + // //Get the move info + // NAV_GetLastMove( info ); + + // //FIXME: if we bump into another one of our guys and can't get around him, just stop! + // //If we hit our target, then stop and fire! + // if ( info.flags & NIF_COLLISION ) + // { + // if ( info.blocker == NPC->enemy ) + // { + // GM_HoldPosition(); + // } + // } + if (NPCInfo->blockedEntity && NPCInfo->blockedEntity == NPC->enemy) + { + GM_HoldPosition(); + } + + //If our move failed, then reset + if ( moved == qfalse ) + {//FIXME: if we're going to a combat point, need to pick a different one + if ( !Q3_TaskIDPending( NPC, TID_MOVE_NAV ) ) + {//can't transfer movegoal or stop when a script we're running is waiting to complete + GM_HoldPosition(); + } + } + + return moved; +} + +/* +------------------------- +NPC_BSGM_Patrol +------------------------- +*/ + +void NPC_BSGM_Patrol( void ) +{ + if ( NPC_CheckPlayerTeamStealth() ) + { + NPC_UpdateAngles( qtrue, qtrue ); + return; + } + + //If we have somewhere to go, then do that + if ( UpdateGoal() ) + { + ucmd.buttons |= BUTTON_WALKING; + NPC_MoveToGoal( qtrue ); + } + + NPC_UpdateAngles( qtrue, qtrue ); +} + +/* +------------------------- +GM_CheckMoveState +------------------------- +*/ + +static void GM_CheckMoveState( void ) +{ + if ( Q3_TaskIDPending( NPC, TID_MOVE_NAV ) ) + {//moving toward a goal that a script is waiting on, so don't stop for anything! + AImove = qtrue; + } + + //See if we're moving towards a goal, not the enemy + if ( ( NPCInfo->goalEntity != NPC->enemy ) && ( NPCInfo->goalEntity != NULL ) ) + { + //Did we make it? + if ( STEER::Reached(NPC, NPCInfo->goalEntity, 16, qfalse) || + ( !Q3_TaskIDPending( NPC, TID_MOVE_NAV ) && enemyLOS && enemyDist <= 10000 ) ) + {//either hit our navgoal or our navgoal was not a crucial (scripted) one (maybe a combat point) and we're scouting and found our enemy + NPC_ReachedGoal(); + //don't attack right away + TIMER_Set( NPC, "attackDelay", Q_irand( 250, 500 ) ); //FIXME: Slant for difficulty levels + return; + } + } +} + +/* +------------------------- +GM_CheckFireState +------------------------- +*/ + +static void GM_CheckFireState( void ) +{ + if ( enemyCS ) + {//if have a clear shot, always try + return; + } + + if ( !VectorCompare( NPC->client->ps.velocity, vec3_origin ) ) + {//if moving at all, don't do this + return; + } + + //See if we should continue to fire on their last position + if ( !hitAlly && NPCInfo->enemyLastSeenTime > 0 ) + { + if ( level.time - NPCInfo->enemyLastSeenTime < 10000 ) + { + if ( !Q_irand( 0, 10 ) ) + { + //Fire on the last known position + vec3_t muzzle, dir, angles; + qboolean tooClose = qfalse; + qboolean tooFar = qfalse; + + CalcEntitySpot( NPC, SPOT_HEAD, muzzle ); + if ( VectorCompare( impactPos, vec3_origin ) ) + {//never checked ShotEntity this frame, so must do a trace... + trace_t tr; + //vec3_t mins = {-2,-2,-2}, maxs = {2,2,2}; + vec3_t forward, end; + AngleVectors( NPC->client->ps.viewangles, forward, NULL, NULL ); + VectorMA( muzzle, 8192, forward, end ); + gi.trace( &tr, muzzle, vec3_origin, vec3_origin, end, NPC->s.number, MASK_SHOT, G2_NOCOLLIDE, 0 ); + VectorCopy( tr.endpos, impactPos ); + } + + //see if impact would be too close to me + float distThreshold = 16384/*128*128*/;//default + if ( NPC->s.weapon == WP_REPEATER ) + { + if ( NPCInfo->scriptFlags&SCF_ALT_FIRE ) + { + distThreshold = 65536/*256*256*/; + } + } + + float dist = DistanceSquared( impactPos, muzzle ); + + if ( dist < distThreshold ) + {//impact would be too close to me + tooClose = qtrue; + } + else if ( level.time - NPCInfo->enemyLastSeenTime > 5000 ) + {//we've haven't seen them in the last 5 seconds + //see if it's too far from where he is + distThreshold = 65536/*256*256*/;//default + if ( NPC->s.weapon == WP_REPEATER ) + { + if ( NPCInfo->scriptFlags&SCF_ALT_FIRE ) + { + distThreshold = 262144/*512*512*/; + } + } + dist = DistanceSquared( impactPos, NPCInfo->enemyLastSeenLocation ); + if ( dist > distThreshold ) + {//impact would be too far from enemy + tooFar = qtrue; + } + } + + if ( !tooClose && !tooFar ) + {//okay too shoot at last pos + VectorSubtract( NPCInfo->enemyLastSeenLocation, muzzle, dir ); + VectorNormalize( dir ); + vectoangles( dir, angles ); + + NPCInfo->desiredYaw = angles[YAW]; + NPCInfo->desiredPitch = angles[PITCH]; + + shoot = qtrue; + faceEnemy = qfalse; + return; + } + } + } + } +} + +void NPC_GM_StartLaser( void ) +{ + if ( !NPC->lockCount ) + {//haven't already started a laser attack + //warm up for the beam attack + // NPC_SetAnim( NPC, SETANIM_TORSO, TORSO_RAISEWEAP2, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + TIMER_Set( NPC, "beamDelay", NPC->client->ps.torsoAnimTimer ); + TIMER_Set( NPC, "attackDelay", NPC->client->ps.torsoAnimTimer+3000 ); + NPC->lockCount = 1; + //turn on warmup effect + G_PlayEffect( "galak/beam_warmup", NPC->s.number ); + G_SoundOnEnt( NPC, CHAN_AUTO, "sound/weapons/galak/lasercharge.wav" ); + } +} + +void GM_StartGloat( void ) +{ + NPC->wait = 0; + /*gi.G2API_SetSurfaceOnOff( &NPC->ghoul2[NPC->playerModel], "torso_galakface_off", TURN_ON ); + gi.G2API_SetSurfaceOnOff( &NPC->ghoul2[NPC->playerModel], "torso_galakhead_off", TURN_ON ); + gi.G2API_SetSurfaceOnOff( &NPC->ghoul2[NPC->playerModel], "torso_eyes_mouth_off", TURN_ON ); + gi.G2API_SetSurfaceOnOff( &NPC->ghoul2[NPC->playerModel], "torso_collar_off", TURN_ON ); + gi.G2API_SetSurfaceOnOff( &NPC->ghoul2[NPC->playerModel], "torso_galaktorso_off", TURN_ON ); + NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_STAND2TO1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + NPC->client->ps.legsAnimTimer += 500; + NPC->client->ps.torsoAnimTimer += 500;*/ + G_AddVoiceEvent( NPC, Q_irand( EV_VICTORY1, EV_VICTORY3 ), 3000 ); + NPC->enemy == NULL; +} +/* +------------------------- +NPC_BSGM_Attack +------------------------- +*/ + +void NPC_BSGM_Attack( void ) +{ + //Don't do anything if we're hurt + if ( NPC->painDebounceTime > level.time ) + { + NPC_UpdateAngles( qtrue, qtrue ); + return; + } + + //FIXME: if killed enemy, use victory anim + if ( NPC->enemy && NPC->enemy->health <= 0 + && !NPC->enemy->s.number ) + {//my enemy is dead + /*if ( NPC->client->ps.torsoAnim == BOTH_STAND2TO1 ) + { + if ( NPC->client->ps.torsoAnimTimer <= 500 ) + { + G_AddVoiceEvent( NPC, Q_irand( EV_VICTORY1, EV_VICTORY3 ), 3000 ); + NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_TRIUMPHANT1START, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + NPC->client->ps.legsAnimTimer += 500; + NPC->client->ps.torsoAnimTimer += 500; + } + } + else if ( NPC->client->ps.torsoAnim == BOTH_TRIUMPHANT1START ) + { + if ( NPC->client->ps.torsoAnimTimer <= 500 ) + { + NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_TRIUMPHANT1STARTGESTURE, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + NPC->client->ps.legsAnimTimer += 500; + NPC->client->ps.torsoAnimTimer += 500; + } + } + else if ( NPC->client->ps.torsoAnim == BOTH_TRIUMPHANT1STARTGESTURE ) + { + if ( NPC->client->ps.torsoAnimTimer <= 500 ) + { + NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_TRIUMPHANT1STOP, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + NPC->client->ps.legsAnimTimer += 500; + NPC->client->ps.torsoAnimTimer += 500; + } + } + else if ( NPC->client->ps.torsoAnim == BOTH_TRIUMPHANT1STOP ) + { + if ( NPC->client->ps.torsoAnimTimer <= 500 ) + { + NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_STAND1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + NPC->client->ps.legsAnimTimer = -1; + NPC->client->ps.torsoAnimTimer = -1; + } + } + else*/ if ( NPC->wait ) + { + if ( TIMER_Done( NPC, "gloatTime" ) ) + { + GM_StartGloat(); + } + else if ( DistanceHorizontalSquared( NPC->client->renderInfo.eyePoint, NPC->enemy->currentOrigin ) > 4096 && (NPCInfo->scriptFlags&SCF_CHASE_ENEMIES) )//64 squared + { + NPCInfo->goalEntity = NPC->enemy; + GM_Move(); + } + else + {//got there + GM_StartGloat(); + } + } + NPC_FaceEnemy( qtrue ); + NPC_UpdateAngles( qtrue, qtrue ); + return; + } + //If we don't have an enemy, just idle + if ( NPC_CheckEnemyExt() == qfalse || !NPC->enemy ) + { + NPC->enemy = NULL; + NPC_BSGM_Patrol(); + return; + } + + enemyLOS = enemyCS = qfalse; + AImove = qtrue; + faceEnemy = qfalse; + shoot = qfalse; + hitAlly = qfalse; + VectorClear( impactPos ); + enemyDist = DistanceSquared( NPC->currentOrigin, NPC->enemy->currentOrigin ); + + if ( NPC->client->ps.torsoAnim == BOTH_ATTACK4 || + NPC->client->ps.torsoAnim == BOTH_ATTACK5 ) + { + shoot = qfalse; + if ( TIMER_Done( NPC, "smackTime" ) && !NPCInfo->blockedDebounceTime ) + {//time to smack + //recheck enemyDist and InFront + if ( enemyDist < MELEE_DIST_SQUARED && InFront( NPC->enemy->currentOrigin, NPC->currentOrigin, NPC->client->ps.viewangles, 0.3f ) ) + { + vec3_t smackDir; + VectorSubtract( NPC->enemy->currentOrigin, NPC->currentOrigin, smackDir ); + smackDir[2] += 30; + VectorNormalize( smackDir ); + //hurt them + G_Sound( NPC->enemy, G_SoundIndex( "sound/weapons/galak/skewerhit.wav" ) ); + G_Damage( NPC->enemy, NPC, NPC, smackDir, NPC->currentOrigin, (g_spskill->integer+1)*Q_irand( 5, 10), DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK, MOD_CRUSH ); + if ( NPC->client->ps.torsoAnim == BOTH_ATTACK4 ) + {//smackdown + int knockAnim = BOTH_KNOCKDOWN1; + if ( PM_CrouchAnim( NPC->enemy->client->ps.legsAnim ) ) + {//knockdown from crouch + knockAnim = BOTH_KNOCKDOWN4; + } + //throw them + smackDir[2] = 1; + VectorNormalize( smackDir ); + G_Throw( NPC->enemy, smackDir, 50 ); + NPC_SetAnim( NPC->enemy, SETANIM_BOTH, knockAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + } + else + {//uppercut + //throw them + G_Throw( NPC->enemy, smackDir, 100 ); + //make them backflip + NPC_SetAnim( NPC->enemy, SETANIM_BOTH, BOTH_KNOCKDOWN5, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + } + //done with the damage + NPCInfo->blockedDebounceTime = 1; + } + } + } + else if ( NPC->lockCount ) //already shooting laser + {//sometimes use the laser beam attack, but only after he's taken down our generator + shoot = qfalse; + if ( NPC->lockCount == 1 ) + {//charging up + if ( TIMER_Done( NPC, "beamDelay" ) ) + {//time to start the beam + int laserAnim; + if ( Q_irand( 0, 1 ) ) + { + laserAnim = BOTH_ATTACK2; + } + else + { + laserAnim = BOTH_ATTACK7; + } + NPC_SetAnim( NPC, SETANIM_BOTH, laserAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + TIMER_Set( NPC, "attackDelay", NPC->client->ps.torsoAnimTimer + Q_irand( 1000, 3000 ) ); + //turn on beam effect + NPC->lockCount = 2; + G_PlayEffect( "galak/trace_beam", NPC->s.number ); + NPC->s.loopSound = G_SoundIndex( "sound/weapons/galak/lasercutting.wav" ); + if ( !NPCInfo->coverTarg ) + {//for moving looping sound at end of trace + NPCInfo->coverTarg = G_Spawn(); + if ( NPCInfo->coverTarg ) + { + G_SetOrigin( NPCInfo->coverTarg, NPC->client->renderInfo.muzzlePoint ); + NPCInfo->coverTarg->svFlags |= SVF_BROADCAST; + NPCInfo->coverTarg->s.loopSound = G_SoundIndex( "sound/weapons/galak/lasercutting.wav" ); + } + } + } + } + else + {//in the actual attack now + if ( !NPC->client->ps.torsoAnimTimer ) + {//attack done! + NPC->lockCount = 0; + G_FreeEntity( NPCInfo->coverTarg ); + NPC->s.loopSound = 0; + // NPC_SetAnim( NPC, SETANIM_TORSO, TORSO_DROPWEAP2, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + TIMER_Set( NPC, "attackDelay", NPC->client->ps.torsoAnimTimer ); + } + else + {//attack still going + //do the trace and damage + trace_t trace; + vec3_t end, mins={-3,-3,-3}, maxs={3,3,3}; + VectorMA( NPC->client->renderInfo.muzzlePoint, 1024, NPC->client->renderInfo.muzzleDir, end ); + gi.trace( &trace, NPC->client->renderInfo.muzzlePoint, mins, maxs, end, NPC->s.number, MASK_SHOT, G2_NOCOLLIDE, 0 ); + if ( trace.allsolid || trace.startsolid ) + {//oops, in a wall + if ( NPCInfo->coverTarg ) + { + G_SetOrigin( NPCInfo->coverTarg, NPC->client->renderInfo.muzzlePoint ); + } + } + else + {//clear + if ( trace.fraction < 1.0f ) + {//hit something + gentity_t *traceEnt = &g_entities[trace.entityNum]; + if ( traceEnt && traceEnt->takedamage ) + {//damage it + G_SoundAtSpot( trace.endpos, G_SoundIndex( "sound/weapons/galak/laserdamage.wav" ), qfalse ); + G_Damage( traceEnt, NPC, NPC, NPC->client->renderInfo.muzzleDir, trace.endpos, 10, 0, MOD_ENERGY ); + } + } + if ( NPCInfo->coverTarg ) + { + G_SetOrigin( NPCInfo->coverTarg, trace.endpos ); + } + if ( !Q_irand( 0, 5 ) ) + { + G_SoundAtSpot( trace.endpos, G_SoundIndex( "sound/weapons/galak/laserdamage.wav" ), qfalse ); + } + } + } + } + } + else + {//Okay, we're not in a special attack, see if we should switch weapons or start a special attack + /* + if ( NPC->s.weapon == WP_REPEATER + && !(NPCInfo->scriptFlags & SCF_ALT_FIRE)//using rapid-fire + && NPC->enemy->s.weapon == WP_SABER //enemy using saber + && NPC->client && (NPC->client->ps.saberEventFlags&SEF_DEFLECTED) + && !Q_irand( 0, 50 ) ) + {//he's deflecting my shots, switch to the laser or the lob fire for a while + TIMER_Set( NPC, "noRapid", Q_irand( 2000, 6000 ) ); + NPCInfo->scriptFlags |= SCF_ALT_FIRE; + NPC->alt_fire = qtrue; + if ( NPC->locationDamage[HL_GENERIC1] > GENERATOR_HEALTH && (Q_irand( 0, 1 )||enemyDist < MAX_LOB_DIST_SQUARED) ) + {//shield down, use laser + NPC_GM_StartLaser(); + } + } + else*/ + if ( !NPC->client->ps.powerups[PW_GALAK_SHIELD] + && enemyDist < MELEE_DIST_SQUARED + && InFront( NPC->enemy->currentOrigin, NPC->currentOrigin, NPC->client->ps.viewangles, 0.3f ) + && G_StandardHumanoid( NPC->enemy ) )//within 80 and in front + {//our shield is down, and enemy within 80, if very close, use melee attack to slap away + if ( TIMER_Done( NPC, "attackDelay" ) ) + { + //animate me + int swingAnim; + if ( NPC->locationDamage[HL_GENERIC1] > GENERATOR_HEALTH ) + {//generator down, use random melee + swingAnim = Q_irand( BOTH_ATTACK4, BOTH_ATTACK5 );//smackdown or uppercut + } + else + {//always knock-away + swingAnim = BOTH_ATTACK5;//uppercut + } + //FIXME: swing sound + NPC_SetAnim( NPC, SETANIM_BOTH, swingAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + TIMER_Set( NPC, "attackDelay", NPC->client->ps.torsoAnimTimer + Q_irand( 1000, 3000 ) ); + //delay the hurt until the proper point in the anim + TIMER_Set( NPC, "smackTime", 600 ); + NPCInfo->blockedDebounceTime = 0; + //FIXME: say something? + } + } + else if ( !NPC->lockCount && NPC->locationDamage[HL_GENERIC1] > GENERATOR_HEALTH + && TIMER_Done( NPC, "attackDelay" ) + && InFront( NPC->enemy->currentOrigin, NPC->currentOrigin, NPC->client->ps.viewangles, 0.3f ) + && ((!Q_irand( 0, 10*(2-g_spskill->integer))&& enemyDist > MIN_LOB_DIST_SQUARED&& enemyDist < MAX_LOB_DIST_SQUARED) + ||(!TIMER_Done( NPC, "noLob" )&&!TIMER_Done( NPC, "noRapid" ))) + && NPC->enemy->s.weapon != WP_TURRET ) + {//sometimes use the laser beam attack, but only after he's taken down our generator + shoot = qfalse; + NPC_GM_StartLaser(); + } + else if ( enemyDist < MIN_LOB_DIST_SQUARED + && (NPC->enemy->s.weapon != WP_TURRET || Q_stricmp( "PAS", NPC->enemy->classname )) + && TIMER_Done( NPC, "noRapid" ) )//256 + {//enemy within 256 + if ( (NPC->client->ps.weapon == WP_REPEATER) && (NPCInfo->scriptFlags & SCF_ALT_FIRE) ) + {//shooting an explosive, but enemy too close, switch to primary fire + NPCInfo->scriptFlags &= ~SCF_ALT_FIRE; + NPC->alt_fire = qfalse; + //FIXME: use weap raise & lower anims + NPC_ChangeWeapon( WP_REPEATER ); + } + } + else if ( (enemyDist > MAX_LOB_DIST_SQUARED || (NPC->enemy->s.weapon == WP_TURRET && !Q_stricmp( "PAS", NPC->enemy->classname ))) + && TIMER_Done( NPC, "noLob" ) )//448 + {//enemy more than 448 away and we are ready to try lob fire again + if ( (NPC->client->ps.weapon == WP_REPEATER) && !(NPCInfo->scriptFlags & SCF_ALT_FIRE) ) + {//enemy far enough away to use lobby explosives + NPCInfo->scriptFlags |= SCF_ALT_FIRE; + NPC->alt_fire = qtrue; + //FIXME: use weap raise & lower anims + NPC_ChangeWeapon( WP_REPEATER ); + } + } + } + + //can we see our target? + if ( NPC_ClearLOS( NPC->enemy ) ) + { + NPCInfo->enemyLastSeenTime = level.time;//used here for aim debouncing, not always a clear LOS + enemyLOS = qtrue; + + if ( NPC->client->ps.weapon == WP_NONE ) + { + enemyCS = qfalse;//not true, but should stop us from firing + NPC_AimAdjust( -1 );//adjust aim worse longer we have no weapon + } + else + {//can we shoot our target? + if ( ((NPC->client->ps.weapon == WP_REPEATER && (NPCInfo->scriptFlags&SCF_ALT_FIRE))) && enemyDist < MIN_LOB_DIST_SQUARED )//256 + { + enemyCS = qfalse;//not true, but should stop us from firing + hitAlly = qtrue;//us! + //FIXME: if too close, run away! + } + else + { + int hit = NPC_ShotEntity( NPC->enemy, impactPos ); + gentity_t *hitEnt = &g_entities[hit]; + if ( hit == NPC->enemy->s.number + || ( hitEnt && hitEnt->client && hitEnt->client->playerTeam == NPC->client->enemyTeam ) + || ( hitEnt && hitEnt->takedamage ) ) + {//can hit enemy or will hit glass or other breakable, so shoot anyway + enemyCS = qtrue; + NPC_AimAdjust( 2 );//adjust aim better longer we have clear shot at enemy + VectorCopy( NPC->enemy->currentOrigin, NPCInfo->enemyLastSeenLocation ); + } + else + {//Hmm, have to get around this bastard + NPC_AimAdjust( 1 );//adjust aim better longer we can see enemy + if ( hitEnt && hitEnt->client && hitEnt->client->playerTeam == NPC->client->playerTeam ) + {//would hit an ally, don't fire!!! + hitAlly = qtrue; + } + else + {//Check and see where our shot *would* hit... if it's not close to the enemy (within 256?), then don't fire + } + } + } + } + } + else if ( gi.inPVS( NPC->enemy->currentOrigin, NPC->currentOrigin ) ) + { + if ( TIMER_Done( NPC, "talkDebounce" ) && !Q_irand( 0, 10 ) ) + { + if ( NPCInfo->enemyCheckDebounceTime < 8 ) + { + int speech = -1; + switch( NPCInfo->enemyCheckDebounceTime ) + { + case 0: + case 1: + case 2: + speech = EV_CHASE1 + NPCInfo->enemyCheckDebounceTime; + break; + case 3: + case 4: + case 5: + speech = EV_COVER1 + NPCInfo->enemyCheckDebounceTime-3; + break; + case 6: + case 7: + speech = EV_ESCAPING1 + NPCInfo->enemyCheckDebounceTime-6; + break; + } + NPCInfo->enemyCheckDebounceTime++; + if ( speech != -1 ) + { + G_AddVoiceEvent( NPC, speech, Q_irand( 3000, 5000 ) ); + TIMER_Set( NPC, "talkDebounce", Q_irand( 5000, 7000 ) ); + } + } + } + + NPCInfo->enemyLastSeenTime = level.time; + + int hit = NPC_ShotEntity( NPC->enemy, impactPos ); + gentity_t *hitEnt = &g_entities[hit]; + if ( hit == NPC->enemy->s.number + || ( hitEnt && hitEnt->client && hitEnt->client->playerTeam == NPC->client->enemyTeam ) + || ( hitEnt && hitEnt->takedamage ) ) + {//can hit enemy or will hit glass or other breakable, so shoot anyway + enemyCS = qtrue; + } + else + { + faceEnemy = qtrue; + NPC_AimAdjust( -1 );//adjust aim worse longer we cannot see enemy + } + } + + if ( enemyLOS ) + { + faceEnemy = qtrue; + } + else + { + if ( !NPCInfo->goalEntity ) + { + NPCInfo->goalEntity = NPC->enemy; + } + if ( NPCInfo->goalEntity == NPC->enemy ) + {//for now, always chase the enemy + AImove = qtrue; + } + } + if ( enemyCS ) + { + shoot = qtrue; + //NPCInfo->enemyCheckDebounceTime = level.time;//actually used here as a last actual LOS + } + else + { + if ( !NPCInfo->goalEntity ) + { + NPCInfo->goalEntity = NPC->enemy; + } + if ( NPCInfo->goalEntity == NPC->enemy ) + {//for now, always chase the enemy + AImove = qtrue; + } + } + + //Check for movement to take care of + GM_CheckMoveState(); + + //See if we should override shooting decision with any special considerations + GM_CheckFireState(); + + if ( NPC->client->ps.weapon == WP_REPEATER && (NPCInfo->scriptFlags&SCF_ALT_FIRE) && shoot && TIMER_Done( NPC, "attackDelay" ) ) + { + vec3_t muzzle; + vec3_t angles; + vec3_t target; + vec3_t velocity = {0,0,0}; + vec3_t mins = {-REPEATER_ALT_SIZE,-REPEATER_ALT_SIZE,-REPEATER_ALT_SIZE}, maxs = {REPEATER_ALT_SIZE,REPEATER_ALT_SIZE,REPEATER_ALT_SIZE}; + + CalcEntitySpot( NPC, SPOT_WEAPON, muzzle ); + + VectorCopy( NPC->enemy->currentOrigin, target ); + + target[0] += Q_flrand( -5, 5 )+(Q_flrand(-1.0f, 1.0f)*(6-NPCInfo->currentAim)*2); + target[1] += Q_flrand( -5, 5 )+(Q_flrand(-1.0f, 1.0f)*(6-NPCInfo->currentAim)*2); + target[2] += Q_flrand( -5, 5 )+(Q_flrand(-1.0f, 1.0f)*(6-NPCInfo->currentAim)*2); + + //Find the desired angles + qboolean clearshot = WP_LobFire( NPC, muzzle, target, mins, maxs, MASK_SHOT|CONTENTS_LIGHTSABER, + velocity, qtrue, NPC->s.number, NPC->enemy->s.number, + 300, 1100, 1500, qtrue ); + if ( VectorCompare( vec3_origin, velocity ) || (!clearshot&&enemyLOS&&enemyCS) ) + {//no clear lob shot and no lob shot that will hit something breakable + if ( enemyLOS && enemyCS && TIMER_Done( NPC, "noRapid" ) ) + {//have a clear straight shot, so switch to primary + NPCInfo->scriptFlags &= ~SCF_ALT_FIRE; + NPC->alt_fire = qfalse; + NPC_ChangeWeapon( WP_REPEATER ); + //keep this weap for a bit + TIMER_Set( NPC, "noLob", Q_irand( 500, 1000 ) ); + } + else + { + shoot = qfalse; + } + } + else + { + vectoangles( velocity, angles ); + + NPCInfo->desiredYaw = AngleNormalize360( angles[YAW] ); + NPCInfo->desiredPitch = AngleNormalize360( angles[PITCH] ); + + VectorCopy( velocity, NPC->client->hiddenDir ); + NPC->client->hiddenDist = VectorNormalize ( NPC->client->hiddenDir ); + } + } + else if ( faceEnemy ) + {//face the enemy + NPC_FaceEnemy( qtrue ); + } + + if ( !TIMER_Done( NPC, "standTime" ) ) + { + AImove = qfalse; + } + if ( !(NPCInfo->scriptFlags&SCF_CHASE_ENEMIES) ) + {//not supposed to chase my enemies + if ( NPCInfo->goalEntity == NPC->enemy ) + {//goal is my entity, so don't move + AImove = qfalse; + } + } + + if ( AImove && !NPC->lockCount ) + {//move toward goal + if ( NPCInfo->goalEntity + // && NPC->client->ps.legsAnim != BOTH_ALERT1 + && NPC->client->ps.legsAnim != BOTH_ATTACK2 + && NPC->client->ps.legsAnim != BOTH_ATTACK4 + && NPC->client->ps.legsAnim != BOTH_ATTACK5 + && NPC->client->ps.legsAnim != BOTH_ATTACK7 ) + { + AImove = GM_Move(); + } + else + { + AImove = qfalse; + } + } + + if ( !TIMER_Done( NPC, "flee" ) ) + {//running away + faceEnemy = qfalse; + } + + //FIXME: check scf_face_move_dir here? + + if ( !faceEnemy ) + {//we want to face in the dir we're running + if ( !AImove ) + {//if we haven't moved, we should look in the direction we last looked? + VectorCopy( NPC->client->ps.viewangles, NPCInfo->lastPathAngles ); + } + if ( AImove ) + {//don't run away and shoot + NPCInfo->desiredYaw = NPCInfo->lastPathAngles[YAW]; + NPCInfo->desiredPitch = 0; + shoot = qfalse; + } + } + NPC_UpdateAngles( qtrue, qtrue ); + + if ( NPCInfo->scriptFlags & SCF_DONT_FIRE ) + { + shoot = qfalse; + } + + if ( NPC->enemy && NPC->enemy->enemy ) + { + if ( NPC->enemy->s.weapon == WP_SABER && NPC->enemy->enemy->s.weapon == WP_SABER ) + {//don't shoot at an enemy jedi who is fighting another jedi, for fear of injuring one or causing rogue blaster deflections (a la Obi Wan/Vader duel at end of ANH) + shoot = qfalse; + } + } + //FIXME: don't shoot right away! + if ( shoot ) + {//try to shoot if it's time + if ( TIMER_Done( NPC, "attackDelay" ) ) + { + if( !(NPCInfo->scriptFlags & SCF_FIRE_WEAPON) ) // we've already fired, no need to do it again here + { + WeaponThink( qtrue ); + } + } + } + + //also: + if ( NPC->enemy->s.weapon == WP_TURRET && !Q_stricmp( "PAS", NPC->enemy->classname ) ) + {//crush turrets + if ( G_BoundsOverlap( NPC->absmin, NPC->absmax, NPC->enemy->absmin, NPC->enemy->absmax ) ) + {//have to do this test because placed turrets are not solid to NPCs (so they don't obstruct navigation) + if ( NPC->client->ps.powerups[PW_GALAK_SHIELD] > 0 ) + { + NPC->client->ps.powerups[PW_BATTLESUIT] = level.time + ARMOR_EFFECT_TIME; + G_Damage( NPC->enemy, NPC, NPC, NULL, NPC->currentOrigin, 100, DAMAGE_NO_KNOCKBACK, MOD_ELECTROCUTE ); + } + else + { + G_Damage( NPC->enemy, NPC, NPC, NULL, NPC->currentOrigin, 100, DAMAGE_NO_KNOCKBACK, MOD_CRUSH ); + } + } + } + else if ( NPCInfo->touchedByPlayer != NULL && NPCInfo->touchedByPlayer == NPC->enemy ) + {//touched enemy + if ( NPC->client->ps.powerups[PW_GALAK_SHIELD] > 0 ) + {//zap him! + //animate me + NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK6, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + TIMER_Set( NPC, "attackDelay", NPC->client->ps.torsoAnimTimer ); + TIMER_Set( NPC, "standTime", NPC->client->ps.legsAnimTimer ); + //FIXME: debounce this? + NPCInfo->touchedByPlayer = NULL; + //FIXME: some shield effect? + NPC->client->ps.powerups[PW_BATTLESUIT] = level.time + ARMOR_EFFECT_TIME; + vec3_t smackDir; + VectorSubtract( NPC->enemy->currentOrigin, NPC->currentOrigin, smackDir ); + smackDir[2] += 30; + VectorNormalize( smackDir ); + G_Damage( NPC->enemy, NPC, NPC, smackDir, NPC->currentOrigin, (g_spskill->integer+1)*Q_irand( 5, 10), DAMAGE_NO_KNOCKBACK, MOD_ELECTROCUTE ); + //throw them + G_Throw( NPC->enemy, smackDir, 100 ); + NPC->enemy->s.powerups |= ( 1 << PW_SHOCKED ); + if ( NPC->enemy->client ) + { + NPC->enemy->client->ps.powerups[PW_SHOCKED] = level.time + 1000; + } + //stop any attacks + ucmd.buttons = 0; + } + } + + if ( NPCInfo->movementSpeech < 3 && NPCInfo->blockedSpeechDebounceTime <= level.time ) + { + if ( NPC->enemy && NPC->enemy->health > 0 && NPC->enemy->painDebounceTime > level.time ) + { + if ( NPC->enemy->health < 50 && NPCInfo->movementSpeech == 2 ) + { + G_AddVoiceEvent( NPC, EV_ANGER2, Q_irand( 2000, 4000 ) ); + NPCInfo->movementSpeech = 3; + } + else if ( NPC->enemy->health < 75 && NPCInfo->movementSpeech == 1 ) + { + G_AddVoiceEvent( NPC, EV_ANGER1, Q_irand( 2000, 4000 ) ); + NPCInfo->movementSpeech = 2; + } + else if ( NPC->enemy->health < 100 && NPCInfo->movementSpeech == 0 ) + { + G_AddVoiceEvent( NPC, EV_ANGER3, Q_irand( 2000, 4000 ) ); + NPCInfo->movementSpeech = 1; + } + } + } +} + +void NPC_BSGM_Default( void ) +{ + if( NPCInfo->scriptFlags & SCF_FIRE_WEAPON ) + { + WeaponThink( qtrue ); + } + + if ( NPC->client->ps.stats[STAT_ARMOR] <= 0 ) + {//armor gone + if ( !NPCInfo->investigateDebounceTime ) + {//start regenerating the armor + gi.G2API_SetSurfaceOnOff( &NPC->ghoul2[NPC->playerModel], "torso_shield_off", TURN_OFF ); + NPC->flags &= ~FL_SHIELDED;//no more reflections + VectorSet( NPC->mins, -20, -20, -24 ); + VectorSet( NPC->maxs, 20, 20, 64 ); + NPC->client->crouchheight = NPC->client->standheight = 64; + if ( NPC->locationDamage[HL_GENERIC1] < GENERATOR_HEALTH ) + {//still have the generator bolt-on + if ( NPCInfo->investigateCount < 12 ) + { + NPCInfo->investigateCount++; + } + NPCInfo->investigateDebounceTime = level.time + (NPCInfo->investigateCount * 5000); + } + } + else if ( NPCInfo->investigateDebounceTime < level.time ) + {//armor regenerated, turn shield back on + //do a trace and make sure we can turn this back on? + trace_t tr; + gi.trace( &tr, NPC->currentOrigin, shieldMins, shieldMaxs, NPC->currentOrigin, NPC->s.number, NPC->clipmask, G2_NOCOLLIDE, 0 ); + if ( !tr.startsolid ) + { + VectorCopy( shieldMins, NPC->mins ); + VectorCopy( shieldMaxs, NPC->maxs ); + NPC->client->crouchheight = NPC->client->standheight = shieldMaxs[2]; + NPC->client->ps.stats[STAT_ARMOR] = GALAK_SHIELD_HEALTH; + NPCInfo->investigateDebounceTime = 0; + NPC->flags |= FL_SHIELDED;//reflect normal shots + NPC->fx_time = level.time; + gi.G2API_SetSurfaceOnOff( &NPC->ghoul2[NPC->playerModel], "torso_shield_off", TURN_ON ); + } + } + } + if ( NPC->client->ps.stats[STAT_ARMOR] > 0 ) + {//armor present + NPC->client->ps.powerups[PW_GALAK_SHIELD] = Q3_INFINITE;//temp, for effect + gi.G2API_SetSurfaceOnOff( &NPC->ghoul2[NPC->playerModel], "torso_shield_off", TURN_ON ); + } + else + { + gi.G2API_SetSurfaceOnOff( &NPC->ghoul2[NPC->playerModel], "torso_shield_off", TURN_OFF ); + } + + if( !NPC->enemy ) + {//don't have an enemy, look for one + NPC_BSGM_Patrol(); + } + else //if ( NPC->enemy ) + {//have an enemy + NPC_BSGM_Attack(); + } +} diff --git a/code/game/CMakeLists.txt b/code/game/CMakeLists.txt index cf1ad54a65..ccd875c9e6 100644 --- a/code/game/CMakeLists.txt +++ b/code/game/CMakeLists.txt @@ -42,6 +42,7 @@ set(SPGameGameFiles "${SPDir}/game/AI_Civilian.cpp" "${SPDir}/game/AI_Default.cpp" "${SPDir}/game/AI_Droid.cpp" + "${SPDir}/game/AI_GalakBoss.cpp" "${SPDir}/game/AI_GalakMech.cpp" "${SPDir}/game/AI_Grenadier.cpp" "${SPDir}/game/AI_HazardTrooper.cpp" diff --git a/code/game/NPC.cpp b/code/game/NPC.cpp index d1c794e0e0..dab21270bb 100644 --- a/code/game/NPC.cpp +++ b/code/game/NPC.cpp @@ -48,6 +48,7 @@ extern void Mark1_dying( gentity_t *self ); extern void NPC_BSCinematic( void ); extern int GetTime ( int lastTime ); extern void G_CheckCharmed( gentity_t *self ); +extern void NPC_BSGM_Default( void ); extern qboolean Boba_Flying( gentity_t *self ); extern qboolean RT_Flying( gentity_t *self ); extern qboolean Jedi_CultistDestroyer( gentity_t *self ); @@ -83,6 +84,7 @@ visibility_t enemyVisibility; void NPC_SetAnim(gentity_t *ent,int setAnimParts,int anim,int setAnimFlags, int iBlend); static bState_t G_CurrentBState( gNPC_t *gNPC ); +extern void GM_Dying( gentity_t *self ); extern int eventClearTime; @@ -93,6 +95,11 @@ void CorpsePhysics( gentity_t *self ) ClientThink( self->s.number, &ucmd ); VectorCopy( self->s.origin, self->s.origin2 ); + if ( self->client->NPC_class == CLASS_GALAKMECH ) + { + GM_Dying( self ); + } + //FIXME: match my pitch and roll for the slope of my groundPlane if ( self->client->ps.groundEntityNum != ENTITYNUM_NONE && !(self->flags&FL_DISINTEGRATED) ) {//on the ground @@ -2025,6 +2032,9 @@ void NPC_RunBehavior( int team, int bState ) case CLASS_MARK2: NPC_BehaviorSet_Mark2( bState ); return; + case CLASS_GALAKMECH: + NPC_BSGM_Default(); + return; default: break; } diff --git a/code/game/NPC_spawn.cpp b/code/game/NPC_spawn.cpp index 7e3f820a89..9c773f83cd 100644 --- a/code/game/NPC_spawn.cpp +++ b/code/game/NPC_spawn.cpp @@ -43,6 +43,8 @@ extern void Q3_SetParm (int entID, int parmNum, const char *parmValue); extern void PM_SetTorsoAnimTimer( gentity_t *ent, int *torsoAnimTimer, int time ); extern void PM_SetLegsAnimTimer( gentity_t *ent, int *legsAnimTimer, int time ); +extern void NPC_GalakMech_Init( gentity_t *ent ); + extern int WP_SaberInitBladeData( gentity_t *ent ); extern void ST_ClearTimers( gentity_t *ent ); extern void Jedi_ClearTimers( gentity_t *ent ); @@ -617,6 +619,10 @@ void NPC_SetMiscDefaultData( gentity_t *ent ) } break; } + if ( !Q_stricmp( "galak_mech", ent->NPC_type ) ) + {//starts with armor + NPC_GalakMech_Init( ent ); + } } } break; @@ -2349,6 +2355,16 @@ SHY - Spawner is shy */ void SP_NPC_Galak( gentity_t *self) { + if ( self->spawnflags & 1 ) + { + self->NPC_type = "Galak_Mech"; + } + else + { + self->NPC_type = "Galak"; + } + + SP_NPC_spawner( self ); } /*QUAKED NPC_Desann(1 0 0) (-16 -16 -24) (16 16 40) x x x x CEILING CINEMATIC NOTSOLID STARTINSOLID SHY diff --git a/code/game/NPC_stats.cpp b/code/game/NPC_stats.cpp index 1e3ea43cbb..ebbe579e45 100644 --- a/code/game/NPC_stats.cpp +++ b/code/game/NPC_stats.cpp @@ -1418,6 +1418,7 @@ extern void NPC_ATST_Precache(void); extern void NPC_Sentry_Precache(void); extern void NPC_Mark1_Precache(void); extern void NPC_Mark2_Precache(void); +extern void NPC_GalakMech_Precache( void ); extern void NPC_Protocol_Precache( void ); extern void Boba_Precache( void ); extern void RT_Precache( void ); @@ -1525,6 +1526,10 @@ void NPC_PrecacheByClassName( const char* type ) { NPC_Protocol_Precache(); } + else if ( !Q_stricmp( "galak_mech", type )) + { + NPC_GalakMech_Precache(); + } else if ( !Q_stricmp( "boba_fett", type )) { Boba_Precache(); diff --git a/code/game/bg_pmove.cpp b/code/game/bg_pmove.cpp index 46643fd41f..f9d8aeb64f 100644 --- a/code/game/bg_pmove.cpp +++ b/code/game/bg_pmove.cpp @@ -1759,7 +1759,7 @@ static qboolean PM_CheckJump( void ) switch ( anim ) { case BOTH_WALL_FLIP_LEFT: - if ( g_debugMelee->integer ) + if ( g_debugMelee->integer || pm->ps->forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 ) { contents |= CONTENTS_BODY; } @@ -1770,7 +1770,7 @@ static qboolean PM_CheckJump( void ) break; case BOTH_WALL_FLIP_RIGHT: - if ( g_debugMelee->integer ) + if ( g_debugMelee->integer || pm->ps->forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 ) { contents |= CONTENTS_BODY; } @@ -1781,7 +1781,7 @@ static qboolean PM_CheckJump( void ) break; case BOTH_WALL_FLIP_BACK1: - if ( g_debugMelee->integer ) + if ( g_debugMelee->integer || pm->ps->forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 ) { contents |= CONTENTS_BODY; } @@ -1790,7 +1790,7 @@ static qboolean PM_CheckJump( void ) break; case BOTH_FORCEWALLRUNFLIP_START: - if ( g_debugMelee->integer ) + if ( g_debugMelee->integer || pm->ps->forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 ) { contents |= CONTENTS_BODY; } @@ -2179,28 +2179,29 @@ static qboolean PM_CheckJump( void ) && pm->ps->forceRageRecoveryTime < pm->cmd.serverTime //not in a force Rage recovery period && pm->ps->forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 //have force jump 2 or higher && (level.time - pm->ps->lastOnGround) <= 250//just jumped - && (pm->ps->legsAnim == BOTH_JUMP1 || pm->ps->legsAnim == BOTH_INAIR1 )//not in a flip or spin or anything + && (pm->ps->legsAnim == BOTH_JUMP1 || pm->ps->legsAnim == BOTH_INAIR1) )//not in a flip or spin or anything {//run up wall, flip backwards //FIXME: have to be moving... make sure it's opposite the wall... or at least forward? int wallWalkAnim = BOTH_WALL_FLIP_BACK1; int parts = SETANIM_LEGS; int contents = CONTENTS_SOLID; qboolean kick = qtrue; - if ( pm->ps->forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_2 ) - { - wallWalkAnim = BOTH_FORCEWALLRUNFLIP_START; - parts = SETANIM_BOTH; - kick = qfalse; - } - else - { + int highJump = pm->ps->forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_2; + // if ( highJump ) + // { + // wallWalkAnim = BOTH_FORCEWALLRUNFLIP_START; + // parts = SETANIM_BOTH; + // kick = qfalse; + // } + // else + // { contents |= CONTENTS_BODY; if ( !pm->ps->weaponTime ) { parts = SETANIM_BOTH; } - } - if ( PM_HasAnimation( pm->gent, wallWalkAnim ) ) + // } + if ( PM_HasAnimation( pm->gent, wallWalkAnim ) && (highJump ? PM_HasAnimation( pm->gent, BOTH_FORCEWALLRUNFLIP_START ) : true) ) { vec3_t fwd, traceto, mins = {pm->mins[0],pm->mins[1],0}, maxs = {pm->maxs[0],pm->maxs[1],24}, fwdAngles = {0, pm->ps->viewangles[YAW], 0}; trace_t trace; @@ -2209,7 +2210,7 @@ static qboolean PM_CheckJump( void ) AngleVectors( fwdAngles, fwd, NULL, NULL ); VectorMA( pm->ps->origin, 32, fwd, traceto ); - pm->trace( &trace, pm->ps->origin, mins, maxs, traceto, pm->ps->clientNum, contents );//FIXME: clip brushes too? + pm->trace( &trace, pm->ps->origin, mins, maxs, traceto, pm->ps->clientNum, contents, G2_NOCOLLIDE, 0 );//FIXME: clip brushes too? VectorSubtract( pm->ps->origin, traceto, idealNormal ); VectorNormalize( idealNormal ); gentity_t *traceEnt = &g_entities[trace.entityNum]; @@ -2218,6 +2219,12 @@ static qboolean PM_CheckJump( void ) &&((trace.entityNums.solid!=SOLID_BMODEL)||DotProduct(trace.plane.normal,idealNormal)>0.7) ) {//there is a wall there pm->ps->velocity[0] = pm->ps->velocity[1] = 0; + if ( highJump && kick && traceEnt && !(traceEnt->s.eType == ET_PLAYER) ) + { + wallWalkAnim = BOTH_FORCEWALLRUNFLIP_START; + parts = SETANIM_BOTH; + kick = qfalse; + } if ( wallWalkAnim == BOTH_FORCEWALLRUNFLIP_START ) { pm->ps->velocity[2] = forceJumpStrength[FORCE_LEVEL_3]/2.0f; @@ -6710,6 +6717,17 @@ qboolean PM_InRoll( playerState_t *ps ) return qfalse; } +qboolean PM_RestAnim( int anim ) +{ + switch ( anim ) + { + case BOTH_MEDITATE: // default taunt + return qtrue; + break; + } + return qfalse; +} + qboolean PM_CrouchAnim( int anim ) { switch ( anim ) @@ -8916,7 +8934,7 @@ static void PM_BeginWeaponChange( int weapon ) { // eezstreet edit: also ignore if we change to WP_NONE..sorta hacky fix for binoculars using WP_SABER if ( pm->ps->clientNum == 0 && cg.weaponSelect != WP_NONE ) { - if ( cg.zoomMode > 0 && cg.zoomMode < 3 ) + if ( (cg.zoomMode > 0 && cg.zoomMode < 3) || (cg.zoomMode == 3 && cg.weaponSelect == WP_SABER) ) { cg.zoomMode = 0; cg.zoomTime = cg.time; @@ -9034,7 +9052,7 @@ static void PM_FinishWeaponChange( void ) { if ( pm->gent ) { WP_SaberInitBladeData( pm->gent ); - if ( (pm->ps->clientNum < MAX_CLIENTS||PM_ControlledByPlayer()) ) + if ( (pm->ps->clientNum < MAX_CLIENTS||PM_ControlledByPlayer()) /*&& cg_saberAutoThird.integer*/ ) { gi.cvar_set( "cg_thirdperson", "1" ); } diff --git a/code/game/g_active.cpp b/code/game/g_active.cpp index e8b19398bc..9f846bd3d9 100644 --- a/code/game/g_active.cpp +++ b/code/game/g_active.cpp @@ -84,6 +84,7 @@ extern void PM_CmdForRoll( playerState_t *ps, usercmd_t *pCmd ); extern qboolean PM_InAttackRoll( int anim ); extern qboolean PM_CrouchAnim( int anim ); extern qboolean PM_FlippingAnim( int anim ); +extern qboolean PM_RestAnim( int anim ); extern qboolean PM_InCartwheel( int anim ); extern qboolean PM_StandingAnim( int anim ); extern qboolean PM_InForceGetUp( playerState_t *ps ); @@ -1726,6 +1727,26 @@ void ClientTimerActions( gentity_t *ent, int msec ) { ent->flags &= ~FL_OVERCHARGED_HEALTH; } } + if ( (ent->health > 0 && ent->health < ent->client->ps.stats[STAT_MAX_HEALTH]/4) && + (ent->client->ps.forcePowerLevel[FP_SEE] >= FORCE_LEVEL_1) && + (ent->painDebounceTime < level.time) ) + {//gradually increase health back to 25% of max if force sight >= 1 + ent->health++; + ent->client->ps.stats[STAT_HEALTH] = ent->health; + } + if ( PM_RestAnim( ent->client->ps.legsAnim ) && + (ent->health > 0 && ent->health < ent->client->ps.stats[STAT_MAX_HEALTH]) && + (ent->client->ps.forcePower >= ent->client->ps.forcePowerMax) && + (ent->client->ps.forcePowerLevel[FP_SEE] >= FORCE_LEVEL_1) && + (ent->painDebounceTime < level.time) ) + {//regen health to max when force is max (force sight must be >= 1) + ent->health++; + + if ( ent->health >= ent->client->ps.stats[STAT_MAX_HEALTH]/3 ) + { + gi.G2API_ClearSkinGore(ent->ghoul2); + } + } } } @@ -3912,7 +3933,7 @@ qboolean G_CheckClampUcmd( gentity_t *ent, usercmd_t *ucmd ) { if ( ent->client->ps.torsoAnimTimer < 100 ) { - ent->client->ps.legsAnimTimer = 100; + ent->client->ps.torsoAnimTimer = 100; } } if ( ent->client->ps.legsAnimTimer > 0 || ent->client->ps.torsoAnimTimer > 0 ) @@ -4908,14 +4929,14 @@ extern cvar_t *g_skippingcin; ucmd->upmove = 0; PM_AdjustAnglesToGripper( ent, ucmd ); } - if ( ent->client->ps.leanofs ) + /*if ( ent->client->ps.leanofs ) {//no shooting while leaning ucmd->buttons &= ~BUTTON_ATTACK; if ( ent->client->ps.weapon != WP_DISRUPTOR ) {//can still zoom around corners ucmd->buttons &= ~BUTTON_ALT_ATTACK; } - } + }*/ } else { diff --git a/code/game/g_client.cpp b/code/game/g_client.cpp index 053a8f10d9..736a7ff5c4 100644 --- a/code/game/g_client.cpp +++ b/code/game/g_client.cpp @@ -1290,6 +1290,16 @@ qboolean G_SetG2PlayerModelInfo( gentity_t *ent, const char *modelName, const ch { ent->handRBolt = ent->headBolt = gi.G2API_AddBolt(&ent->ghoul2[ent->playerModel], "*head_f1"); } + else if ( !Q_stricmp( "galak_mech", modelName )) + { + ent->genericBolt1 = gi.G2API_AddBolt(&ent->ghoul2[ent->playerModel], "*antenna_effect"); + ent->headBolt = gi.G2API_AddBolt(&ent->ghoul2[ent->playerModel], "*head_eyes"); + ent->torsoBolt = gi.G2API_AddBolt(&ent->ghoul2[ent->playerModel], "torso"); + ent->crotchBolt = gi.G2API_AddBolt(&ent->ghoul2[ent->playerModel], "hips"); + ent->handRBolt = gi.G2API_AddBolt(&ent->ghoul2[ent->playerModel], "*flasha"); + ent->genericBolt3 = gi.G2API_AddBolt(&ent->ghoul2[ent->playerModel], "*flashb"); + ent->handLBolt = gi.G2API_AddBolt(&ent->ghoul2[ent->playerModel], "*flashc"); + } else if ( !Q_stricmp( "rancor", modelName ) || !Q_stricmp( "mutant_rancor", modelName )) { @@ -1334,6 +1344,7 @@ qboolean G_SetG2PlayerModelInfo( gentity_t *ent, const char *modelName, const ch ent->elbowLBolt = gi.G2API_AddBolt(&ent->ghoul2[ent->playerModel], "*bicep_lg"); ent->elbowRBolt = gi.G2API_AddBolt(&ent->ghoul2[ent->playerModel], "*bicep_rg"); ent->handLBolt = gi.G2API_AddBolt(&ent->ghoul2[ent->playerModel], "*hand_l"); + ent->handRBolt = gi.G2API_AddBolt(&ent->ghoul2[ent->playerModel], "*r_hand");//use the standard bone r_hand ent->kneeLBolt = gi.G2API_AddBolt(&ent->ghoul2[ent->playerModel], "*thigh_lg"); ent->kneeRBolt = gi.G2API_AddBolt(&ent->ghoul2[ent->playerModel], "*thigh_rg"); ent->footLBolt = gi.G2API_AddBolt(&ent->ghoul2[ent->playerModel], "*foot_lg"); @@ -2153,6 +2164,21 @@ qboolean ClientSpawn(gentity_t *ent, SavedGameJustLoaded_e eSavedGameJustLoaded gi.linkentity (ent); + if ( ent->client->NPC_class == CLASS_ATST ) + {//try and eject out of ATST + GEntity_UseFunc( ent->activator, ent, ent ); + + if ( ent->client->ps.stats[STAT_WEAPONS] & ( 1 << WP_BLASTER ) ) + { + ent->client->ps.weapon = WP_BLASTER; + } + else + { + ent->client->ps.weapon = WP_NONE; + } + ent->client->ps.weaponstate = WEAPON_READY; + } + // run the presend to set anything else ClientEndFrame( ent ); @@ -2179,6 +2205,12 @@ qboolean ClientSpawn(gentity_t *ent, SavedGameJustLoaded_e eSavedGameJustLoaded //setup sabers G_ReloadSaberData( ent ); //force power levels should already be set + + //make sure we always have the binocular inventory item + if ( client->ps.inventory[INV_ELECTROBINOCULARS] < 1 ) + { + client->ps.inventory[INV_ELECTROBINOCULARS] = 1; + } } else { @@ -2261,8 +2293,8 @@ qboolean ClientSpawn(gentity_t *ent, SavedGameJustLoaded_e eSavedGameJustLoaded // give default weapons //these are precached in g_items, ClearRegisteredItems() client->ps.stats[STAT_WEAPONS] = ( 1 << WP_NONE ); - //client->ps.inventory[INV_ELECTROBINOCULARS] = 1; - //ent->client->ps.inventory[INV_BACTA_CANISTER] = 1; + client->ps.inventory[INV_ELECTROBINOCULARS] = 1; + ent->client->ps.inventory[INV_BACTA_CANISTER] = 1; // give EITHER the saber or the stun baton..never both if ( spawnPoint->spawnflags & 32 ) // STUN_BATON @@ -2348,6 +2380,12 @@ qboolean ClientSpawn(gentity_t *ent, SavedGameJustLoaded_e eSavedGameJustLoaded // Player_RestoreFromPrevLevel(ent, eSavedGameJustLoaded); + //make sure we always have the binocular inventory item + if ( client->ps.inventory[INV_ELECTROBINOCULARS] < 1 ) + { + client->ps.inventory[INV_ELECTROBINOCULARS] = 1; + } + //FIXME: put this BEFORE the Player_RestoreFromPrevLevel check above? if (eSavedGameJustLoaded == eNO) {//fresh start diff --git a/code/game/g_combat.cpp b/code/game/g_combat.cpp index 32fee2e01d..aa7ae69814 100644 --- a/code/game/g_combat.cpp +++ b/code/game/g_combat.cpp @@ -2336,7 +2336,8 @@ qboolean G_DoDismemberment( gentity_t *self, vec3_t point, int mod, int damage, if ( ( g_dismemberment->integer || g_saberRealisticCombat->integer > 1 ) && mod == MOD_SABER )//only lightsaber {//FIXME: don't do strcmps here if ( G_StandardHumanoid( self ) - && (force||g_dismemberProbabilities->value>0.0f||G_Dismemberable2( self, hitLoc )) ) + && (force||g_dismemberProbabilities->value>0.0f||G_Dismemberable2( self, hitLoc )) + && !(self->flags&FL_DISINTEGRATED) && self->contents != CONTENTS_NONE )//can't be dismembered if disintegrated {//either it's a forced dismemberment or we're using probabilities (which are checked before this) or we've done enough damage to this location //FIXME: check the hitLoc and hitDir against the cap tag for the place //where the split will be- if the hit dir is roughly perpendicular to diff --git a/code/game/g_emplaced.cpp b/code/game/g_emplaced.cpp index 9ef53cf6e3..682f9f510f 100644 --- a/code/game/g_emplaced.cpp +++ b/code/game/g_emplaced.cpp @@ -1041,7 +1041,7 @@ extern void CG_ChangeWeapon( int num ); if ( ent->s.number < MAX_CLIENTS ) { - if ( ent->client->ps.weapon == WP_SABER ) + if ( ent->client->ps.weapon == WP_SABER /*&& cg_saberAutoThird.integer*/ ) { gi.cvar_set( "cg_thirdperson", "1" ); } diff --git a/code/game/g_functions.cpp b/code/game/g_functions.cpp index 822f4413e5..69e7cb06e3 100644 --- a/code/game/g_functions.cpp +++ b/code/game/g_functions.cpp @@ -364,6 +364,7 @@ void GEntity_PainFunc(gentity_t *self, gentity_t *inflictor, gentity_t *attacker PAINCASE( NPC_Remote_Pain ) PAINCASE( emplaced_gun_pain ) PAINCASE( NPC_Mark1_Pain ) + PAINCASE( NPC_GM_Pain ) PAINCASE( NPC_Sentry_Pain ) PAINCASE( NPC_Mark2_Pain ) PAINCASE( PlayerPain ) diff --git a/code/game/g_functions.h b/code/game/g_functions.h index 07a4d24bba..67318548c9 100644 --- a/code/game/g_functions.h +++ b/code/game/g_functions.h @@ -572,6 +572,7 @@ extern void NPC_Seeker_Pain (gentity_t *self, gentity_t *inflictor, gentity_t extern void NPC_Remote_Pain (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, const vec3_t point, int damage, int mod,int hitLoc=HL_NONE); extern void emplaced_gun_pain (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, const vec3_t point, int damage, int mod,int hitLoc=HL_NONE); extern void NPC_Mark1_Pain (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, const vec3_t point, int damage, int mod,int hitLoc=HL_NONE); +extern void NPC_GM_Pain (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, const vec3_t point, int damage, int mod,int hitLoc=HL_NONE); extern void NPC_Sentry_Pain (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, const vec3_t point, int damage, int mod,int hitLoc=HL_NONE); extern void NPC_Mark2_Pain (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, const vec3_t point, int damage, int mod,int hitLoc=HL_NONE); extern void PlayerPain (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, const vec3_t point, int damage, int mod,int hitLoc=HL_NONE); diff --git a/code/game/g_items.cpp b/code/game/g_items.cpp index 96d6099c0f..c4f2725939 100644 --- a/code/game/g_items.cpp +++ b/code/game/g_items.cpp @@ -1272,7 +1272,7 @@ void ClearRegisteredItems( void ) { //these are given in g_client, ClientSpawn(), but MUST be registered HERE, BEFORE cgame starts. //RegisterItem( FindItemForWeapon( WP_NONE ) ); //has no item RegisterItem( FindItemForInventory( INV_ELECTROBINOCULARS )); - //RegisterItem( FindItemForInventory( INV_BACTA_CANISTER )); + RegisterItem( FindItemForInventory( INV_BACTA_CANISTER )); // saber or baton is cached in SP_info_player_deathmatch now. extern void Player_CacheFromPrevLevel(void);//g_client.cpp diff --git a/code/game/g_main.cpp b/code/game/g_main.cpp index dceac508eb..d3285ad0a7 100644 --- a/code/game/g_main.cpp +++ b/code/game/g_main.cpp @@ -661,7 +661,7 @@ void G_InitCvars( void ) { g_saberAutoBlocking = gi.cvar( "g_saberAutoBlocking", "1", CVAR_CHEAT );//must press +block button to do any blocking g_saberRealisticCombat = gi.cvar( "g_saberMoreRealistic", "0", CVAR_ARCHIVE );//makes collision more precise, increases damage - debug_subdivision = gi.cvar( "debug_subdivision", "0", CVAR_ARCHIVE );//debug for dismemberment + debug_subdivision = gi.cvar( "debug_subdivision", "1", CVAR_ARCHIVE );//debug for dismemberment g_dismemberProbabilities = gi.cvar ( "g_dismemberProbabilities", "1", CVAR_ARCHIVE );//0 = ignore probabilities, 1 = use probabilities g_saberDamageCapping = gi.cvar( "g_saberDamageCapping", "1", CVAR_CHEAT );//caps damage of sabers vs players and NPC who use sabers g_saberMoveSpeed = gi.cvar( "g_saberMoveSpeed", "1", CVAR_CHEAT );//how fast you run while attacking with a saber diff --git a/code/game/g_svcmds.cpp b/code/game/g_svcmds.cpp index 0374e14091..bcd2c58e12 100644 --- a/code/game/g_svcmds.cpp +++ b/code/game/g_svcmds.cpp @@ -479,6 +479,18 @@ void Svcmd_SaberAttackCycle_f( void ) return; } + if (self->client->ps.forcePowerLevel[FP_SABER_OFFENSE] >= FORCE_LEVEL_1) + {//give medium style at offense level 1, as in JK2 + self->client->ps.saberStylesKnown |= (1<client->ps.forcePowerLevel[FP_SABER_OFFENSE] >= FORCE_LEVEL_2) + {//give fast style at offense level 2, as in JK2 + self->client->ps.saberStylesKnown |= (1<client->ps.forcePowerLevel[FP_SABER_OFFENSE] >= FORCE_LEVEL_3) + {//give strong style at offense level 3, as in JK2 + self->client->ps.saberStylesKnown |= (1<client->ps.saberStylesKnown; if ( self->client->ps.dualSabers && self->client->ps.saber[0].Active() diff --git a/code/game/game.vcproj b/code/game/game.vcproj index bf5598bce4..452349dba4 100644 --- a/code/game/game.vcproj +++ b/code/game/game.vcproj @@ -450,6 +450,10 @@ RelativePath=".\AI_Droid.cpp" > + + diff --git a/code/game/weapons.h b/code/game/weapons.h index 7845cd5dd5..49880ced0e 100644 --- a/code/game/weapons.h +++ b/code/game/weapons.h @@ -84,7 +84,7 @@ typedef enum //# weapon_e } weapon_t; #define FIRST_WEAPON WP_SABER // this is the first weapon for next and prev weapon switching -#define MAX_PLAYER_WEAPONS WP_STUN_BATON // this is the max you can switch to and get with the give all. - FIXME: it's actually this one *minus* one... why? +#define MAX_PLAYER_WEAPONS WP_BRYAR_PISTOL // this is the max you can switch to and get with the give all. - FIXME: it's actually this one *minus* one... why? // AMMO_NONE must be first and AMMO_MAX must be last, cause weapon load validates based off of these vals typedef enum //# ammo_e diff --git a/code/game/wp_saber.cpp b/code/game/wp_saber.cpp index ae6985decf..3cf349b1d1 100644 --- a/code/game/wp_saber.cpp +++ b/code/game/wp_saber.cpp @@ -103,6 +103,7 @@ extern saberMoveName_t PM_BrokenParryForAttack( int move ); extern saberMoveName_t PM_KnockawayForParry( int move ); extern qboolean PM_FlippingAnim( int anim ); extern qboolean PM_RollingAnim( int anim ); +extern qboolean PM_RestAnim( int anim ); extern qboolean PM_CrouchAnim( int anim ); extern qboolean PM_SaberInIdle( int move ); extern qboolean PM_SaberInReflect( int move ); @@ -281,15 +282,15 @@ float forceSpeedRangeMod[NUM_FORCE_POWER_LEVELS] = float forceSpeedFOVMod[NUM_FORCE_POWER_LEVELS] = { 0.0f,//none - 20.0f, - 30.0f, - 40.0f + 0.0f,//20.0f, + 0.0f,//30.0f, + 0.0f//40.0f }; int forceGripDamage[NUM_FORCE_POWER_LEVELS] = { 0,//none - 0, + 3,//0, 6, 9 }; @@ -936,18 +937,18 @@ int WP_SaberInitBladeData( gentity_t *ent ) } - if (ent->client->ps.saberStylesKnown & (1<client->ps.saberAnimLevel = SS_FAST; - } - else if (ent->client->ps.saberStylesKnown & (1<client->ps.saberAnimLevel = SS_STRONG; - } - else - { + // if (ent->client->ps.saberStylesKnown & (1<client->ps.saberAnimLevel = SS_FAST; + // } + // else if (ent->client->ps.saberStylesKnown & (1<client->ps.saberAnimLevel = SS_STRONG; + // } + // else + // { ent->client->ps.saberAnimLevel = SS_MEDIUM; - } + // } } else @@ -2915,7 +2916,7 @@ qboolean WP_SaberDamageForTrace( int ignore, vec3_t start, vec3_t end, float dmg } } - if ( !g_saberNoEffects && hitEffect != 0 ) + if ( !g_saberNoEffects && hitEffect != 0 && !(hitEnt->flags&FL_DISINTEGRATED) && hitEnt->contents != CONTENTS_NONE )//don't play hit effects if hit entity was disintegrated { G_PlayEffect( hitEffect, tr.endpos, dir );//"saber_cut" } @@ -2924,7 +2925,8 @@ qboolean WP_SaberDamageForTrace( int ignore, vec3_t start, vec3_t end, float dmg {//we were doing a ghoul trace if ( !attacker || !attacker->client - || attacker->client->ps.saberLockTime < level.time ) + || attacker->client->ps.saberLockTime < level.time + && !(hitEnt->flags&FL_DISINTEGRATED) && hitEnt->contents != CONTENTS_NONE )//don't play hit effects if hit entity was disintegrated { if ( !WP_SaberDamageEffects( &tr, start, len, dmg, dir, bladeVec, attacker->client->enemyTeam, saberType, &attacker->client->ps.saber[saberNum], bladeNum ) ) {//didn't hit a ghoul ent @@ -7041,6 +7043,8 @@ void WP_SaberThrow( gentity_t *self, usercmd_t *ucmd ) } //need to recalc this because we just moved it VectorSubtract( self->client->renderInfo.handRPoint, saberent->currentOrigin, saberDiff ); + //remember when it launched so it can return automagically + saberent->aimDebounceTime = level.time; } else {//couldn't throw it @@ -7071,6 +7075,12 @@ void WP_SaberThrow( gentity_t *self, usercmd_t *ucmd ) } return; } + if ( (!self->s.number && level.time - saberent->aimDebounceTime > 15000) + || (self->s.number && level.time - saberent->aimDebounceTime > 5000) ) + {//(only for player) been missing for 15 seconds, automagicially return + WP_SaberCatch( self, saberent, qfalse ); + return; + } } if ( saberent->s.pos.trType != TR_STATIONARY ) @@ -7087,6 +7097,12 @@ void WP_SaberThrow( gentity_t *self, usercmd_t *ucmd ) return; } } + if ( (!self->s.number && level.time - saberent->aimDebounceTime > 15000) + || (self->s.number && level.time - saberent->aimDebounceTime > 5000) ) + {//(only for player) been missing for 15 seconds, automagicially return + WP_SaberCatch( self, saberent, qfalse ); + return; + } WP_RunSaber( self, saberent ); } else @@ -10237,7 +10253,7 @@ void ForceHeal( gentity_t *self ) //start health going up //NPC_SetAnim( self, SETANIM_TORSO, ?, SETANIM_FLAG_OVERRIDE ); WP_ForcePowerStart( self, FP_HEAL, 0 ); - if ( self->client->ps.forcePowerLevel[FP_HEAL] < FORCE_LEVEL_2 ) + if ( self->client->ps.forcePowerLevel[FP_HEAL] < FORCE_LEVEL_2 && !PM_RestAnim( self->client->ps.legsAnim ) ) {//must meditate //FIXME: holster weapon (select WP_NONE?) //FIXME: BOTH_FORCEHEAL_START @@ -11029,7 +11045,31 @@ void ForceLightningDamage( gentity_t *self, gentity_t *traceEnt, vec3_t dir, flo } else { - dmg = Q_irand( 1, 3 );//*self->client->ps.forcePowerLevel[FP_LIGHTNING]; + //dmg = Q_irand( 1, 3 );//*self->client->ps.forcePowerLevel[FP_LIGHTNING]; + dmg = 1; + if ( self->client->NPC_class == CLASS_REBORN + && self->client->ps.weapon == WP_NONE ) + {//Cultist: looks fancy, but does less damage + } + else + { + if ( dist < 50 ) + { + dmg += 2; + } + else if ( dist < 100 ) + { + dmg += 1; + } + if ( dot > 0.95f ) + { + dmg += 2; + } + else if ( dot > 0.75f ) + { + dmg += 1; + } + } } if ( traceEnt->client @@ -12583,6 +12623,11 @@ int WP_AbsorbConversion(gentity_t *attacked, int atdAbsLevel, gentity_t *attacke return -1; } + if (Q_irand( 0, atPowerLevel ) > Q_irand( 1, atdAbsLevel )) + { //chance of attacker's high level power breaking through entirely + return -1; + } + //Subtract absorb power level from the offensive force power getLevel = atPowerLevel; getLevel -= atdAbsLevel; @@ -14375,6 +14420,16 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) { WP_ForcePowerRegenerate( self, self->client->ps.forcePowerRegenAmount ); self->client->ps.forcePowerRegenDebounceTime = level.time + self->client->ps.forcePowerRegenRate; + + if ( PM_CrouchAnim( self->client->ps.legsAnim ) ) + {//regen force much faster when crouched + WP_ForcePowerRegenerate( self, 2 ); + } + else if ( PM_RestAnim( self->client->ps.legsAnim ) ) + {//regen force extremly fast when meditating + WP_ForcePowerRegenerate( self, 4 ); + } + if ( self->client->ps.forceRageRecoveryTime >= level.time ) {//regen half as fast self->client->ps.forcePowerRegenDebounceTime += self->client->ps.forcePowerRegenRate; diff --git a/code/qcommon/common.cpp b/code/qcommon/common.cpp index 0e64a80b97..3b9296fb38 100644 --- a/code/qcommon/common.cpp +++ b/code/qcommon/common.cpp @@ -1094,12 +1094,12 @@ void Com_Init( char *commandLine ) { //Swap_Init (); Cbuf_Init (); - Com_InitZoneMemoryVars(); - Cmd_Init (); - // override anything from the config files with command line args Com_StartupVariable( NULL ); + Com_InitZoneMemoryVars(); + Cmd_Init (); + // done early so bind command exists CL_InitKeyCommands(); @@ -1196,6 +1196,7 @@ void Com_Init( char *commandLine ) { Cbuf_AddText ("cinematic openinglogos\n"); } } + CL_StartHunkUsers(); com_fullyInitialized = qtrue; Com_Printf ("--- Common Initialization Complete ---\n"); diff --git a/code/rd-vanilla/tr_curve.cpp b/code/rd-vanilla/tr_curve.cpp index 875da70e33..5f30e685c2 100644 --- a/code/rd-vanilla/tr_curve.cpp +++ b/code/rd-vanilla/tr_curve.cpp @@ -194,7 +194,7 @@ static int neighbors[8][2] = { break; // edge of patch } VectorSubtract( ctrl[y][x].xyz, base, temp ); - if ( VectorNormalize2( temp, temp ) == 0 ) { + if ( VectorNormalize( temp ) < 0.001f ) { continue; // degenerate edge, get more dist } else { good[k] = qtrue; @@ -210,7 +210,7 @@ static int neighbors[8][2] = { continue; // didn't get two points } CrossProduct( around[(k+1)&7], around[k], normal ); - if ( VectorNormalize2( normal, normal ) == 0 ) { + if ( VectorNormalize( normal ) < 0.001f ) { continue; } VectorAdd( normal, sum, sum ); diff --git a/code/rd-vanilla/tr_init.cpp b/code/rd-vanilla/tr_init.cpp index 13c72e66ee..149ce3f343 100644 --- a/code/rd-vanilla/tr_init.cpp +++ b/code/rd-vanilla/tr_init.cpp @@ -1522,7 +1522,7 @@ void R_Register( void ) r_ext_texture_env_add = ri.Cvar_Get( "r_ext_texture_env_add", "1", CVAR_ARCHIVE_ND | CVAR_LATCH); r_ext_texture_filter_anisotropic = ri.Cvar_Get( "r_ext_texture_filter_anisotropic", "16", CVAR_ARCHIVE_ND ); - r_DynamicGlow = ri.Cvar_Get( "r_DynamicGlow", "0", CVAR_ARCHIVE_ND ); + r_DynamicGlow = ri.Cvar_Get( "r_DynamicGlow", "1", CVAR_ARCHIVE_ND ); r_DynamicGlowPasses = ri.Cvar_Get( "r_DynamicGlowPasses", "5", CVAR_ARCHIVE_ND ); r_DynamicGlowDelta = ri.Cvar_Get( "r_DynamicGlowDelta", "0.8f", CVAR_ARCHIVE_ND ); r_DynamicGlowIntensity = ri.Cvar_Get( "r_DynamicGlowIntensity", "1.13f", CVAR_ARCHIVE_ND ); diff --git a/code/rd-vanilla/tr_main.cpp b/code/rd-vanilla/tr_main.cpp index da619736ae..78b04953f5 100644 --- a/code/rd-vanilla/tr_main.cpp +++ b/code/rd-vanilla/tr_main.cpp @@ -1219,9 +1219,9 @@ void R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs ) { // if we overflowed MAX_DRAWSURFS, the drawsurfs // wrapped around in the buffer and we will be missing // the first surfaces, not the last ones - if ( numDrawSurfs > MAX_DRAWSURFS ) { - numDrawSurfs = MAX_DRAWSURFS; - } + // if ( numDrawSurfs > MAX_DRAWSURFS ) { + // numDrawSurfs = MAX_DRAWSURFS; + // } // sort the drawsurfs by sort type, then orientation, then shader R_RadixSort( drawSurfs, numDrawSurfs ); @@ -1505,6 +1505,7 @@ or a mirror / remote location */ void R_RenderView (viewParms_t *parms) { int firstDrawSurf; + int numDrawSurfs; if ( parms->viewportWidth <= 0 || parms->viewportHeight <= 0 ) { return; @@ -1546,6 +1547,14 @@ void R_RenderView (viewParms_t *parms) { R_GenerateDrawSurfs(); + // if we overflowed MAX_DRAWSURFS, the drawsurfs + // wrapped around in the buffer and we will be missing + // the first surfaces, not the last ones + numDrawSurfs = tr.refdef.numDrawSurfs; + if (numDrawSurfs > MAX_DRAWSURFS) { + numDrawSurfs = MAX_DRAWSURFS; + } + R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf ); // draw main system development information (surface outlines, etc) diff --git a/code/ui/ui_atoms.cpp b/code/ui/ui_atoms.cpp index 21488388bb..1daa8af564 100644 --- a/code/ui/ui_atoms.cpp +++ b/code/ui/ui_atoms.cpp @@ -294,9 +294,11 @@ void UI_Init( int apiVersion, uiimport_t *uiimport, qboolean inGameLoad ) ui.Cvar_Create( "ui_prisonerobj_mintotal", "0", CVAR_ROM|CVAR_SAVEGAME|CVAR_NORESTART); ui.Cvar_Create( "g_dismemberment", "3", CVAR_ARCHIVE );//0 = none, 1 = arms and hands, 2 = legs, 3 = waist and head + // ui.Cvar_Create( "cg_saberAutoThird", "1", CVAR_ARCHIVE ); ui.Cvar_Create( "cg_gunAutoFirst", "1", CVAR_ARCHIVE ); ui.Cvar_Create( "cg_crosshairIdentifyTarget", "1", CVAR_ARCHIVE ); ui.Cvar_Create( "g_subtitles", "0", CVAR_ARCHIVE ); + ui.Cvar_Create( "cg_footsteps", "3", CVAR_ARCHIVE ); ui.Cvar_Create( "cg_marks", "1", CVAR_ARCHIVE ); ui.Cvar_Create( "d_slowmodeath", "3", CVAR_ARCHIVE ); ui.Cvar_Create( "cg_shadows", "1", CVAR_ARCHIVE ); diff --git a/code/ui/ui_shared.cpp b/code/ui/ui_shared.cpp index 2f5cbdf877..3d8bbe3ce0 100644 --- a/code/ui/ui_shared.cpp +++ b/code/ui/ui_shared.cpp @@ -5504,10 +5504,12 @@ static const char *g_bindCommands[] = { "+strafe", "+use", "+useforce", + "bow", //add bow "centerview", "cg_thirdperson !", "datapad", "exitview", + "flourish", //add flourish #ifndef JK2_MODE "force_absorb", #endif @@ -5525,6 +5527,7 @@ static const char *g_bindCommands[] = { "force_throw", "forcenext", "forceprev", + "gloat", //add gloat "invnext", "invprev", "invuse", @@ -5534,6 +5537,7 @@ static const char *g_bindCommands[] = { #else "load quick", #endif + "meditate", //add meditate "saberAttackCycle", #ifdef JK2_MODE "save quik*", diff --git a/codemp/cgame/cg_weapons.c b/codemp/cgame/cg_weapons.c index 4bb3b55524..543e0c04f4 100644 --- a/codemp/cgame/cg_weapons.c +++ b/codemp/cgame/cg_weapons.c @@ -915,13 +915,13 @@ WEAPON SELECTION void CG_DrawIconBackground(void) { - int /*height, xAdd, x2, y2,*/ t; + int height, /*xAdd,*/ x2, y2, t; // int prongLeftX,prongRightX; float inTime = cg.invenSelectTime+WEAPON_SELECT_TIME; float wpTime = cg.weaponSelectTime+WEAPON_SELECT_TIME; float fpTime = cg.forceSelectTime+WEAPON_SELECT_TIME; -// int drawType = cgs.media.weaponIconBackground; -// int yOffset = 0; + int drawType = cgs.media.weaponIconBackground; + int yOffset = 0; // don't display if dead if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) @@ -934,26 +934,26 @@ void CG_DrawIconBackground(void) return; } -// x2 = 30; -// y2 = SCREEN_HEIGHT-70; + x2 = 30; + y2 = SCREEN_HEIGHT-70; //prongLeftX =x2+37; //prongRightX =x2+544; if (inTime > wpTime) { -// drawType = cgs.media.inventoryIconBackground; + drawType = cgs.media.inventoryIconBackground; cg.iconSelectTime = cg.invenSelectTime; } else { -// drawType = cgs.media.weaponIconBackground; + drawType = cgs.media.weaponIconBackground; cg.iconSelectTime = cg.weaponSelectTime; } if (fpTime > inTime && fpTime > wpTime) { -// drawType = cgs.media.forceIconBackground; + drawType = cgs.media.forceIconBackground; cg.iconSelectTime = cg.forceSelectTime; } @@ -973,9 +973,9 @@ void CG_DrawIconBackground(void) // xAdd = (int) 8*cg.iconHUDPercent; - // height = (int) (60.0f*cg.iconHUDPercent); - //CG_DrawPic( x2+60, y2+30+yOffset, 460, -height, drawType); // Top half - //CG_DrawPic( x2+60, y2+30-2+yOffset, 460, height, drawType); // Bottom half + height = (int) (60.0f*cg.iconHUDPercent); + CG_DrawPic( x2+60, y2+30+yOffset, 460, -height, drawType); // Top half + CG_DrawPic( x2+60, y2+30-2+yOffset, 460, height, drawType); // Bottom half } else @@ -1009,27 +1009,27 @@ void CG_DrawIconBackground(void) cg.iconHUDPercent=1; } - //trap->R_SetColor( colorTable[CT_WHITE] ); - //height = (int) (60.0f*cg.iconHUDPercent); - //CG_DrawPic( x2+60, y2+30+yOffset, 460, -height, drawType); // Top half - //CG_DrawPic( x2+60, y2+30-2+yOffset, 460, height, drawType); // Bottom half + trap->R_SetColor( colorTable[CT_WHITE] ); + height = (int) (60.0f*cg.iconHUDPercent); + CG_DrawPic( x2+60, y2+30+yOffset, 460, -height, drawType); // Top half + CG_DrawPic( x2+60, y2+30-2+yOffset, 460, height, drawType); // Bottom half // And now for the prongs -/* if ((cg.inventorySelectTime+WEAPON_SELECT_TIME)>cg.time) + if (inTime>cg.time) { cgs.media.currentBackground = ICON_INVENTORY; - background = &cgs.media.inventoryProngsOn; + // background = &cgs.media.inventoryProngsOn; } - else if ((cg.weaponSelectTime+WEAPON_SELECT_TIME)>cg.time) + else if (wpTime>cg.time) { cgs.media.currentBackground = ICON_WEAPONS; } else { cgs.media.currentBackground = ICON_FORCE; - background = &cgs.media.forceProngsOn; + // background = &cgs.media.forceProngsOn; } -*/ + // Side Prongs // trap->R_SetColor( colorTable[CT_WHITE]); // xAdd = (int) 8*cg.iconHUDPercent; diff --git a/codemp/cgame/cg_xcvar.h b/codemp/cgame/cg_xcvar.h index ceb9bd8d39..4070a8050d 100644 --- a/codemp/cgame/cg_xcvar.h +++ b/codemp/cgame/cg_xcvar.h @@ -79,14 +79,14 @@ XCVAR_DEF( cg_debugSaber, "0", NULL, CVAR_CHEAT ) XCVAR_DEF( cg_debugPosition, "0", NULL, CVAR_CHEAT ) XCVAR_DEF( cg_debugEvents, "0", NULL, CVAR_CHEAT ) XCVAR_DEF( cg_duelHeadAngles, "0", NULL, CVAR_NONE ) -XCVAR_DEF( cg_dismember, "0", NULL, CVAR_ARCHIVE ) +XCVAR_DEF( cg_dismember, "2", NULL, CVAR_ARCHIVE ) XCVAR_DEF( cg_deferPlayers, "1", NULL, CVAR_ARCHIVE ) XCVAR_DEF( cg_errorDecay, "100", NULL, CVAR_NONE ) XCVAR_DEF( cg_fallingBob, "1", NULL, CVAR_ARCHIVE ) XCVAR_DEF( cg_footsteps, "3", NULL, CVAR_ARCHIVE ) XCVAR_DEF( cg_forceModel, "0", CG_ForceModelChange, CVAR_ARCHIVE ) XCVAR_DEF( cg_fov, "80", NULL, CVAR_ARCHIVE ) -XCVAR_DEF( cg_fovAspectAdjust, "0", NULL, CVAR_ARCHIVE ) +XCVAR_DEF( cg_fovAspectAdjust, "1", NULL, CVAR_ARCHIVE ) XCVAR_DEF( cg_fovViewmodel, "0", NULL, CVAR_ARCHIVE ) XCVAR_DEF( cg_fovViewmodelAdjust, "1", NULL, CVAR_ARCHIVE ) #if 0 diff --git a/codemp/client/snd_dma.cpp b/codemp/client/snd_dma.cpp index 736203492a..36369d10dc 100644 --- a/codemp/client/snd_dma.cpp +++ b/codemp/client/snd_dma.cpp @@ -4805,14 +4805,14 @@ static qboolean S_UpdateBackgroundTrack_Actual( MusicInfo_t *pMusicInfo, qboolea // or if it's a dynamic music specifier (which can't literally exist), in which case it should set // a return flag then exit... // - char sTestName[MAX_QPATH*2];// *2 so COM_DefaultExtension doesn't do an ERR_DROP if there was no space + char sTestName[MAX_QPATH/**2*/];// *2 so COM_DefaultExtension doesn't do an ERR_DROP if there was no space // for an extension, since this is a "soft" test - Q_strncpyz( sTestName, sMusic_BackgroundLoop, sizeof(sTestName)); + Q_strncpyz( sTestName, sMusic_BackgroundLoop, sizeof(sTestName) - 4 ); COM_DefaultExtension(sTestName, sizeof(sTestName), ".mp3"); if (S_FileExists( sTestName )) { - S_StartBackgroundTrack_Actual( pMusicInfo, qfalse, sMusic_BackgroundLoop, sMusic_BackgroundLoop ); + S_StartBackgroundTrack_Actual( pMusicInfo, qfalse, sTestName, sTestName ); } else { diff --git a/codemp/client/snd_mix.cpp b/codemp/client/snd_mix.cpp index e418b4802b..1ac1ed5cd9 100644 --- a/codemp/client/snd_mix.cpp +++ b/codemp/client/snd_mix.cpp @@ -224,7 +224,7 @@ void S_TransferPaintBuffer(int endtime) p = (int *) paintbuffer; count = (endtime - s_paintedtime) * dma.channels; out_mask = dma.samples - 1; - out_idx = s_paintedtime * dma.channels & out_mask; + out_idx = (unsigned int)s_paintedtime * dma.channels & out_mask; step = 3 - dma.channels; if (dma.samplebits == 16) diff --git a/codemp/game/bg_misc.c b/codemp/game/bg_misc.c index b283dcc446..933cbc6388 100644 --- a/codemp/game/bg_misc.c +++ b/codemp/game/bg_misc.c @@ -163,15 +163,15 @@ char *forceMasteryLevels[NUM_FORCE_MASTERY_LEVELS] = }; int forceMasteryPoints[NUM_FORCE_MASTERY_LEVELS] = -{ - 0, // FORCE_MASTERY_UNINITIATED, - 5, // FORCE_MASTERY_INITIATE, - 10, // FORCE_MASTERY_PADAWAN, - 20, // FORCE_MASTERY_JEDI, - 30, // FORCE_MASTERY_JEDI_GUARDIAN, - 50, // FORCE_MASTERY_JEDI_ADEPT, - 75, // FORCE_MASTERY_JEDI_KNIGHT, - 100 // FORCE_MASTERY_JEDI_MASTER, +{//231 points to max all powers (including team powers in team game modes) + 0, // FORCE_MASTERY_UNINITIATED, //0 + 10, // FORCE_MASTERY_INITIATE, //5 + 20, // FORCE_MASTERY_PADAWAN, //10 + 40, // FORCE_MASTERY_JEDI, //20 + 60, // FORCE_MASTERY_JEDI_GUARDIAN, //30 + 100, // FORCE_MASTERY_JEDI_ADEPT, //50 + 150, // FORCE_MASTERY_JEDI_KNIGHT, //75 + 200 // FORCE_MASTERY_JEDI_MASTER, //100 }; int bgForcePowerCost[NUM_FORCE_POWERS][NUM_FORCE_POWER_LEVELS] = //0 == neutral @@ -495,7 +495,8 @@ qboolean BG_LegalizedForcePowers(char *powerOut, size_t powerOutSize, int maxRan { //if this power doesn't match the side we're on, then 0 it now. if (final_Powers[i] && forcePowerDarkLight[i] && - forcePowerDarkLight[i] != final_Side) + forcePowerDarkLight[i] != final_Side && + teamForce) { final_Powers[i] = 0; //This is only likely to happen with g_forceBasedTeams. Let it slide. diff --git a/codemp/game/bg_panimate.c b/codemp/game/bg_panimate.c index fa65f9d724..83b700b5fa 100644 --- a/codemp/game/bg_panimate.c +++ b/codemp/game/bg_panimate.c @@ -65,6 +65,17 @@ qboolean BG_SaberStanceAnim( int anim ) return qfalse; } +qboolean BG_RestAnim( int anim ) +{ + switch ( anim ) + { + case BOTH_MEDITATE: // default taunt + return qtrue; + break; + } + return qfalse; +} + qboolean BG_CrouchAnim( int anim ) { switch ( anim ) diff --git a/codemp/game/bg_pmove.c b/codemp/game/bg_pmove.c index 894867f1c4..bb94426bd5 100644 --- a/codemp/game/bg_pmove.c +++ b/codemp/game/bg_pmove.c @@ -2201,7 +2201,7 @@ static qboolean PM_CheckJump( void ) vec3_t idealNormal={0}, wallNormal={0}; trace_t trace; qboolean doTrace = qfalse; - int contents = MASK_SOLID;//MASK_PLAYERSOLID; + int contents = MASK_PLAYERSOLID;//MASK_SOLID;//MASK_PLAYERSOLID; VectorSet(mins, pm->mins[0],pm->mins[1],0); VectorSet(maxs, pm->maxs[0],pm->maxs[1],24); @@ -2271,7 +2271,6 @@ static qboolean PM_CheckJump( void ) VectorMA( pm->ps->velocity, -150, fwd, pm->ps->velocity ); } - /* if ( doTrace && anim != BOTH_WALL_RUN_LEFT && anim != BOTH_WALL_RUN_RIGHT ) { if (trace.entityNum < MAX_CLIENTS) @@ -2279,7 +2278,6 @@ static qboolean PM_CheckJump( void ) pm->ps->forceKickFlip = trace.entityNum+1; //let the server know that this person gets kicked by this client } } - */ //up if ( vertPush ) @@ -2496,21 +2494,22 @@ static qboolean PM_CheckJump( void ) //FIXME: have to be moving... make sure it's opposite the wall... or at least forward? int wallWalkAnim = BOTH_WALL_FLIP_BACK1; int parts = SETANIM_LEGS; - int contents = MASK_SOLID;//MASK_PLAYERSOLID;//CONTENTS_SOLID; - //qboolean kick = qtrue; - if ( pm->ps->fd.forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_2 ) - { - wallWalkAnim = BOTH_FORCEWALLRUNFLIP_START; - parts = SETANIM_BOTH; - //kick = qfalse; - } - else - { + int contents = MASK_PLAYERSOLID;//MASK_SOLID;//MASK_PLAYERSOLID;//CONTENTS_SOLID; + qboolean kick = qtrue; + int highJump = pm->ps->fd.forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_2; + // if ( highJump ) + // { + // wallWalkAnim = BOTH_FORCEWALLRUNFLIP_START; + // parts = SETANIM_BOTH; + // kick = qfalse; + // } + // else + // { if ( !pm->ps->weaponTime ) { parts = SETANIM_BOTH; } - } + // } //if ( PM_HasAnimation( pm->gent, wallWalkAnim ) ) if (1) //sure, we have it! Because I SAID SO. { @@ -2535,6 +2534,12 @@ static qboolean PM_CheckJump( void ) &&((trace.entityNums.solid!=SOLID_BMODEL)||DotProduct(trace.plane.normal,idealNormal)>0.7) ) {//there is a wall there pm->ps->velocity[0] = pm->ps->velocity[1] = 0; + if ( highJump && kick && traceEnt && !(traceEnt->s.eType == ET_PLAYER || traceEnt->s.eType == ET_NPC) ) + { + wallWalkAnim = BOTH_FORCEWALLRUNFLIP_START; + parts = SETANIM_BOTH; + kick = qfalse; + } if ( wallWalkAnim == BOTH_FORCEWALLRUNFLIP_START ) { pm->ps->velocity[2] = forceJumpStrength[FORCE_LEVEL_3]/2.0f; @@ -2556,12 +2561,10 @@ static qboolean PM_CheckJump( void ) BG_ForcePowerDrain( pm->ps, FP_LEVITATION, 5 ); //kick if jumping off an ent - /* if ( kick && traceEnt && (traceEnt->s.eType == ET_PLAYER || traceEnt->s.eType == ET_NPC) ) { //kick that thang! pm->ps->forceKickFlip = traceEnt->s.number+1; } - */ pm->cmd.rightmove = pm->cmd.forwardmove= 0; } } @@ -5319,7 +5322,7 @@ static void PM_Footsteps( void ) { bobmove = 0.5; // ducked characters bob much faster - if ( ( (PM_RunningAnim( pm->ps->legsAnim )&&VectorLengthSquared(pm->ps->velocity)>=40000/*200*200*/) || PM_CanRollFromSoulCal( pm->ps ) ) && + if ( ( (PM_RunningAnim( pm->ps->legsAnim )/*&&VectorLengthSquared(pm->ps->velocity)>=40000/*200*200*/) || PM_CanRollFromSoulCal( pm->ps ) ) && !BG_InRoll(pm->ps, pm->ps->legsAnim) ) {//roll! rolled = PM_TryRoll(); @@ -10352,7 +10355,7 @@ void PmoveSingle (pmove_t *pmove) { { if ( pm->ps->torsoTimer < 100 ) { - pm->ps->legsTimer = 100; + pm->ps->torsoTimer = 100; } pm->ps->forceHandExtend = HANDEXTEND_TAUNT; pm->ps->forceHandExtendTime = pm->cmd.serverTime + 100; diff --git a/codemp/game/bg_saber.c b/codemp/game/bg_saber.c index 7abb1642fd..1a772fb2af 100644 --- a/codemp/game/bg_saber.c +++ b/codemp/game/bg_saber.c @@ -2258,9 +2258,9 @@ saberMoveName_t PM_SaberAttackForMovement(saberMoveName_t curmove) && (pm->cmd.buttons&BUTTON_ATTACK)//hitting attack && PM_GroundDistance() < 70.0f //not too high above ground && ( pm->cmd.upmove > 0 || (pm->ps->pm_flags & PMF_JUMP_HELD) )//focus-holding player - && BG_EnoughForcePowerForMove( SABER_ALT_ATTACK_POWER_LR ) )//have enough power + /* && BG_EnoughForcePowerForMove( SABER_ALT_ATTACK_POWER_LR ) */ )//have enough power {//cartwheel right - BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_LR); + // BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_LR); if ( overrideJumpRightAttackMove != LS_INVALID ) {//overridden with another move return overrideJumpRightAttackMove; @@ -2319,9 +2319,9 @@ saberMoveName_t PM_SaberAttackForMovement(saberMoveName_t curmove) && (pm->cmd.buttons&BUTTON_ATTACK)//hitting attack && PM_GroundDistance() < 70.0f //not too high above ground && ( pm->cmd.upmove > 0 || (pm->ps->pm_flags & PMF_JUMP_HELD) )//focus-holding player - && BG_EnoughForcePowerForMove( SABER_ALT_ATTACK_POWER_LR ) )//have enough power + /* && BG_EnoughForcePowerForMove( SABER_ALT_ATTACK_POWER_LR ) */ )//have enough power {//cartwheel left - BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_LR); + // BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_LR); if ( overrideJumpLeftAttackMove != LS_INVALID ) {//overridden with another move @@ -2387,14 +2387,14 @@ saberMoveName_t PM_SaberAttackForMovement(saberMoveName_t curmove) !BG_SaberInAttack(pm->ps->saberMove) && pm->ps->weaponTime <= 0 && pm->ps->forceHandExtend == HANDEXTEND_NONE && - (pm->cmd.buttons & BUTTON_ATTACK)&& - BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB) ) + (pm->cmd.buttons & BUTTON_ATTACK)/* && + BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB) */ ) { //DUAL/STAFF JUMP ATTACK newmove = PM_SaberJumpAttackMove2(); if ( newmove != LS_A_T2B && newmove != LS_NONE ) { - BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB); + // BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB); } } else if (!noSpecials&& @@ -2402,8 +2402,8 @@ saberMoveName_t PM_SaberAttackForMovement(saberMoveName_t curmove) pm->ps->velocity[2] > 100 && PM_GroundDistance() < 32 && !BG_InSpecialJump(pm->ps->legsAnim) && - !BG_SaberInSpecialAttack(pm->ps->torsoAnim)&& - BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB)) + !BG_SaberInSpecialAttack(pm->ps->torsoAnim)/* && + BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB) */) { //FLIP AND DOWNWARD ATTACK //trace_t tr; @@ -2413,7 +2413,7 @@ saberMoveName_t PM_SaberAttackForMovement(saberMoveName_t curmove) if ( newmove != LS_A_T2B && newmove != LS_NONE ) { - BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB); + // BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB); } } } @@ -2422,8 +2422,8 @@ saberMoveName_t PM_SaberAttackForMovement(saberMoveName_t curmove) pm->ps->velocity[2] > 100 && PM_GroundDistance() < 32 && !BG_InSpecialJump(pm->ps->legsAnim) && - !BG_SaberInSpecialAttack(pm->ps->torsoAnim)&& - BG_EnoughForcePowerForMove( SABER_ALT_ATTACK_POWER_FB )) + !BG_SaberInSpecialAttack(pm->ps->torsoAnim)/* && + BG_EnoughForcePowerForMove( SABER_ALT_ATTACK_POWER_FB ) */) { //DFA //trace_t tr; @@ -2433,7 +2433,7 @@ saberMoveName_t PM_SaberAttackForMovement(saberMoveName_t curmove) if ( newmove != LS_A_T2B && newmove != LS_NONE ) { - BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB); + // BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB); } } } @@ -2441,24 +2441,24 @@ saberMoveName_t PM_SaberAttackForMovement(saberMoveName_t curmove) pm->ps->groundEntityNum != ENTITYNUM_NONE && (pm->ps->pm_flags & PMF_DUCKED) && pm->ps->weaponTime <= 0 && - !BG_SaberInSpecialAttack(pm->ps->torsoAnim)&& - BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB)) + !BG_SaberInSpecialAttack(pm->ps->torsoAnim)/* && + BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB) */) { //LUNGE (weak) newmove = PM_SaberLungeAttackMove( noSpecials ); if ( newmove != LS_A_T2B && newmove != LS_NONE ) { - BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB); + // BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB); } } else if ( !noSpecials ) { saberMoveName_t stabDownMove = PM_CheckStabDown(); if (stabDownMove != LS_NONE - && BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB) ) + /* && BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB) */ ) { newmove = stabDownMove; - BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB); + // BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB); } else { @@ -2797,7 +2797,7 @@ void PM_WeaponLightsaber(void) { if ( (pm->cmd.buttons&BUTTON_ATTACK) ) { - if ( BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB) && !pm->ps->saberInFlight ) + if ( /* BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB) && */ !pm->ps->saberInFlight ) { if ( PM_CanDoRollStab() ) { @@ -2808,7 +2808,7 @@ void PM_WeaponLightsaber(void) PM_AddEvent(EV_SABER_UNHOLSTER); } PM_SetSaberMove( LS_ROLL_STAB ); - BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB); + // BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB); } } } diff --git a/codemp/game/g_active.c b/codemp/game/g_active.c index 5f1f90c44e..b326f64c2f 100644 --- a/codemp/game/g_active.c +++ b/codemp/game/g_active.c @@ -28,6 +28,8 @@ along with this program; if not, see . extern void Jedi_Cloak( gentity_t *self ); extern void Jedi_Decloak( gentity_t *self ); +extern qboolean BG_RestAnim( int anim ); + qboolean PM_SaberInTransition( int move ); qboolean PM_SaberInStart( int move ); qboolean PM_SaberInReturn( int move ); @@ -820,6 +822,21 @@ void ClientTimerActions( gentity_t *ent, int msec ) { if ( client->ps.stats[STAT_ARMOR] > client->ps.stats[STAT_MAX_HEALTH] ) { client->ps.stats[STAT_ARMOR]--; } + + //gradually increase health back to 25% of max if force sight >= 1 + if ( (ent->health > 0 && ent->health < client->ps.stats[STAT_MAX_HEALTH]/4) && + (client->ps.fd.forcePowerLevel[FP_SEE] >= FORCE_LEVEL_1) && + (ent->painDebounceTime < level.time) ) { + ent->health++; + } + + //regen health to max when force is max (force sight must be >= 1) + if ( BG_RestAnim( client->ps.legsAnim ) && + (ent->health > 0 && ent->health < client->ps.stats[STAT_MAX_HEALTH]) && + (client->ps.fd.forcePower >= client->ps.fd.forcePowerMax) && + (client->ps.fd.forcePowerLevel[FP_SEE] >= FORCE_LEVEL_1) ) { + ent->health++; + } } } @@ -1603,13 +1620,13 @@ void G_SetTauntAnim( gentity_t *ent, int taunt ) { //hack, don't do while moving return; } - if ( taunt != TAUNT_TAUNT ) + /*if ( taunt != TAUNT_TAUNT ) //always allow all taunts {//normal taunt always allowed if ( level.gametype != GT_DUEL && level.gametype != GT_POWERDUEL ) {//no taunts unless in Duel return; } - } + }*/ // fix: rocket lock bug BG_ClearRocketLock(&ent->client->ps); @@ -1698,16 +1715,19 @@ void G_SetTauntAnim( gentity_t *ent, int taunt ) { anim = BOTH_BOW; } - if ( ent->client->ps.saberHolstered == 1 - && ent->client->saber[1].model[0] ) - {//turn off second saber - G_Sound( ent, CHAN_WEAPON, ent->client->saber[1].soundOff ); - } - else if ( ent->client->ps.saberHolstered == 0 ) - {//turn off first - G_Sound( ent, CHAN_WEAPON, ent->client->saber[0].soundOff ); + if ( ent->client->ps.weapon == WP_SABER ) + { + if ( ent->client->ps.saberHolstered == 1 + && ent->client->saber[1].model[0] ) + {//turn off second saber + G_Sound( ent, CHAN_WEAPON, ent->client->saber[1].soundOff ); + } + else if ( ent->client->ps.saberHolstered == 0 ) + {//turn off first + G_Sound( ent, CHAN_WEAPON, ent->client->saber[0].soundOff ); + } + ent->client->ps.saberHolstered = 2; } - ent->client->ps.saberHolstered = 2; break; case TAUNT_MEDITATE: if ( ent->client->saber[0].meditateAnim != -1 ) @@ -1723,16 +1743,19 @@ void G_SetTauntAnim( gentity_t *ent, int taunt ) { anim = BOTH_MEDITATE; } - if ( ent->client->ps.saberHolstered == 1 - && ent->client->saber[1].model[0] ) - {//turn off second saber - G_Sound( ent, CHAN_WEAPON, ent->client->saber[1].soundOff ); - } - else if ( ent->client->ps.saberHolstered == 0 ) - {//turn off first - G_Sound( ent, CHAN_WEAPON, ent->client->saber[0].soundOff ); + if ( ent->client->ps.weapon == WP_SABER ) + { + if ( ent->client->ps.saberHolstered == 1 + && ent->client->saber[1].model[0] ) + {//turn off second saber + G_Sound( ent, CHAN_WEAPON, ent->client->saber[1].soundOff ); + } + else if ( ent->client->ps.saberHolstered == 0 ) + {//turn off first + G_Sound( ent, CHAN_WEAPON, ent->client->saber[0].soundOff ); + } + ent->client->ps.saberHolstered = 2; } - ent->client->ps.saberHolstered = 2; break; case TAUNT_FLOURISH: if ( ent->client->ps.weapon == WP_SABER ) @@ -1782,56 +1805,59 @@ void G_SetTauntAnim( gentity_t *ent, int taunt ) } break; case TAUNT_GLOAT: - if ( ent->client->saber[0].gloatAnim != -1 ) - { - anim = ent->client->saber[0].gloatAnim; - } - else if ( ent->client->saber[1].model[0] - && ent->client->saber[1].gloatAnim != -1 ) - { - anim = ent->client->saber[1].gloatAnim; - } - else + if ( ent->client->ps.weapon == WP_SABER ) { - switch ( ent->client->ps.fd.saberAnimLevel ) + if ( ent->client->saber[0].gloatAnim != -1 ) { - case SS_FAST: - case SS_TAVION: - anim = BOTH_VICTORY_FAST; - break; - case SS_MEDIUM: - anim = BOTH_VICTORY_MEDIUM; - break; - case SS_STRONG: - case SS_DESANN: - if ( ent->client->ps.saberHolstered ) - {//turn on first - G_Sound( ent, CHAN_WEAPON, ent->client->saber[0].soundOn ); - } - ent->client->ps.saberHolstered = 0; - anim = BOTH_VICTORY_STRONG; - break; - case SS_DUAL: - if ( ent->client->ps.saberHolstered == 1 - && ent->client->saber[1].model[0] ) - {//turn on second saber - G_Sound( ent, CHAN_WEAPON, ent->client->saber[1].soundOn ); - } - else if ( ent->client->ps.saberHolstered == 2 ) - {//turn on first - G_Sound( ent, CHAN_WEAPON, ent->client->saber[0].soundOn ); - } - ent->client->ps.saberHolstered = 0; - anim = BOTH_VICTORY_DUAL; - break; - case SS_STAFF: - if ( ent->client->ps.saberHolstered ) - {//turn on first - G_Sound( ent, CHAN_WEAPON, ent->client->saber[0].soundOn ); + anim = ent->client->saber[0].gloatAnim; + } + else if ( ent->client->saber[1].model[0] + && ent->client->saber[1].gloatAnim != -1 ) + { + anim = ent->client->saber[1].gloatAnim; + } + else + { + switch ( ent->client->ps.fd.saberAnimLevel ) + { + case SS_FAST: + case SS_TAVION: + anim = BOTH_VICTORY_FAST; + break; + case SS_MEDIUM: + anim = BOTH_VICTORY_MEDIUM; + break; + case SS_STRONG: + case SS_DESANN: + if ( ent->client->ps.saberHolstered ) + {//turn on first + G_Sound( ent, CHAN_WEAPON, ent->client->saber[0].soundOn ); + } + ent->client->ps.saberHolstered = 0; + anim = BOTH_VICTORY_STRONG; + break; + case SS_DUAL: + if ( ent->client->ps.saberHolstered == 1 + && ent->client->saber[1].model[0] ) + {//turn on second saber + G_Sound( ent, CHAN_WEAPON, ent->client->saber[1].soundOn ); + } + else if ( ent->client->ps.saberHolstered == 2 ) + {//turn on first + G_Sound( ent, CHAN_WEAPON, ent->client->saber[0].soundOn ); + } + ent->client->ps.saberHolstered = 0; + anim = BOTH_VICTORY_DUAL; + break; + case SS_STAFF: + if ( ent->client->ps.saberHolstered ) + {//turn on first + G_Sound( ent, CHAN_WEAPON, ent->client->saber[0].soundOn ); + } + ent->client->ps.saberHolstered = 0; + anim = BOTH_VICTORY_STAFF; + break; } - ent->client->ps.saberHolstered = 0; - anim = BOTH_VICTORY_STAFF; - break; } } break; diff --git a/codemp/game/g_xcvar.h b/codemp/game/g_xcvar.h index df9ee8094a..f35a4fd665 100644 --- a/codemp/game/g_xcvar.h +++ b/codemp/game/g_xcvar.h @@ -87,7 +87,7 @@ XCVAR_DEF( g_debugServerSkel, "0", NULL, CVAR_CHEAT, qfalse ) #ifdef _DEBUG XCVAR_DEF( g_disableServerG2, "0", NULL, CVAR_NONE, qtrue ) #endif -XCVAR_DEF( g_dismember, "0", NULL, CVAR_ARCHIVE, qtrue ) +XCVAR_DEF( g_dismember, "100", NULL, CVAR_ARCHIVE, qtrue ) XCVAR_DEF( g_doWarmup, "0", NULL, CVAR_NONE, qtrue ) //XCVAR_DEF( g_engineModifications, "1", NULL, CVAR_ARCHIVE, qfalse ) XCVAR_DEF( g_ff_objectives, "0", NULL, CVAR_CHEAT|CVAR_NORESTART, qtrue ) diff --git a/codemp/game/w_force.c b/codemp/game/w_force.c index 034df35b9c..fa90fb5dc8 100644 --- a/codemp/game/w_force.c +++ b/codemp/game/w_force.c @@ -35,6 +35,8 @@ extern void NPC_UseResponse( gentity_t *self, gentity_t *user, qboolean useWhenD extern void Jedi_Decloak( gentity_t *self ); extern qboolean BG_FullBodyTauntAnim( int anim ); +extern qboolean BG_RestAnim( int anim ); +extern qboolean BG_CrouchAnim( int anim ); extern bot_state_t *botstates[MAX_CLIENTS]; @@ -813,6 +815,11 @@ int WP_AbsorbConversion(gentity_t *attacked, int atdAbsLevel, gentity_t *attacke return -1; } + if (Q_irand( 0, atPowerLevel ) > Q_irand( 1, atdAbsLevel )) + { //chance of attacker's high level power breaking through entirely + return -1; + } + //Subtract absorb power level from the offensive force power getLevel = atPowerLevel; getLevel -= atdAbsLevel; @@ -1103,7 +1110,7 @@ void ForceHeal( gentity_t *self ) if (self->client->ps.fd.forcePowerLevel[FP_HEAL] == FORCE_LEVEL_3) { - self->health += 25; //This was 50, but that angered the Balance God. + self->health += 50; //This was 50, but that angered the Balance God. //25; if (self->health > self->client->ps.stats[STAT_MAX_HEALTH]) { @@ -1113,7 +1120,7 @@ void ForceHeal( gentity_t *self ) } else if (self->client->ps.fd.forcePowerLevel[FP_HEAL] == FORCE_LEVEL_2) { - self->health += 10; + self->health += 30; //10; if (self->health > self->client->ps.stats[STAT_MAX_HEALTH]) { @@ -1123,7 +1130,7 @@ void ForceHeal( gentity_t *self ) } else { - self->health += 5; + self->health += 15; //5; if (self->health > self->client->ps.stats[STAT_MAX_HEALTH]) { @@ -1691,7 +1698,7 @@ void ForceLightningDamage( gentity_t *self, gentity_t *traceEnt, vec3_t dir, vec } if (ForcePowerUsableOn(self, traceEnt, FP_LIGHTNING)) { - int dmg = Q_irand(1,2); //Q_irand( 1, 3 ); + int dmg = Q_irand( 1, 3 ); //Q_irand( 1, 2 ); int modPowerLevel = -1; @@ -1714,7 +1721,7 @@ void ForceLightningDamage( gentity_t *self, gentity_t *traceEnt, vec3_t dir, vec } else if (modPowerLevel == 2) { - dmg = 1; + dmg = 2; traceEnt->client->noLightningTime = level.time + 100; } } @@ -1965,7 +1972,6 @@ void ForceDrainDamage( gentity_t *self, gentity_t *traceEnt, vec3_t dir, vec3_t dmg = 2; } } - //G_Damage( traceEnt, self, self, dir, impactPoint, dmg, 0, MOD_FORCE_DARK ); if (dmg) { @@ -1974,6 +1980,11 @@ void ForceDrainDamage( gentity_t *self, gentity_t *traceEnt, vec3_t dir, vec3_t if (traceEnt->client->ps.fd.forcePower < 0) { traceEnt->client->ps.fd.forcePower = 0; + + if (dmg) + { + G_Damage( traceEnt, self, self, dir, impactPoint, dmg, 0, MOD_FORCE_DARK ); + } } if (self->client->ps.stats[STAT_HEALTH] < self->client->ps.stats[STAT_MAX_HEALTH] && @@ -2014,11 +2025,11 @@ void ForceDrainDamage( gentity_t *self, gentity_t *traceEnt, vec3_t dir, vec3_t { if ( !Q_irand( 0, 2 ) ) { - //G_Sound( traceEnt, CHAN_BODY, G_SoundIndex( "sound/weapons/force/lightninghit.wav" ) ); + //G_Sound( traceEnt, CHAN_BODY, G_SoundIndex( va("sound/weapons/force/lightninghit%i", Q_irand(1, 3) )) ); } - // traceEnt->s.powerups |= ( 1 << PW_DISINT_1 ); + // traceEnt->s.powerups |= ( 1 << PW_DISINT_1 ); - // traceEnt->client->ps.powerups[PW_DISINT_1] = level.time + 500; + // traceEnt->client->ps.powerups[PW_DISINT_1] = level.time + 500; } */ @@ -2161,7 +2172,7 @@ int ForceShootDrain( gentity_t *self ) self->client->ps.activeForcePass = self->client->ps.fd.forcePowerLevel[FP_DRAIN] + FORCE_LEVEL_3; - BG_ForcePowerDrain( &self->client->ps, FP_DRAIN, 5 ); //used to be 1, but this did, too, anger the God of Balance. + BG_ForcePowerDrain( &self->client->ps, FP_DRAIN, 1 ); //used to be 1, but this did, too, anger the God of Balance. //5 self->client->ps.fd.forcePowerRegenDebounceTime = level.time + 500; @@ -5427,7 +5438,11 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) if ( self->client->ps.powerups[PW_FORCE_BOON] ) WP_ForcePowerRegenerate( self, 6 ); else if ( self->client->ps.isJediMaster && level.gametype == GT_JEDIMASTER ) - WP_ForcePowerRegenerate( self, 4 ); //jedi master regenerates 4 times as fast + WP_ForcePowerRegenerate( self, 4 ); //jedi master regenerates 4 times as fast + else if ( BG_CrouchAnim( self->client->ps.legsAnim ) ) + WP_ForcePowerRegenerate( self, 2 ); //regen force much faster when crouched + else if ( BG_RestAnim( self->client->ps.legsAnim ) ) + WP_ForcePowerRegenerate( self, 4 ); //regen force extremly fast when meditating else WP_ForcePowerRegenerate( self, 0 ); } diff --git a/codemp/game/w_saber.h b/codemp/game/w_saber.h index f501a8fb55..b9b8e76789 100644 --- a/codemp/game/w_saber.h +++ b/codemp/game/w_saber.h @@ -49,11 +49,11 @@ along with this program; if not, see . #define SABER_REFLECT_MISSILE_CONE 0.2f #define FORCE_POWER_MAX 100 -#define MAX_GRIP_DISTANCE 256 +#define MAX_GRIP_DISTANCE 512//256 #define MAX_TRICK_DISTANCE 512 #define FORCE_JUMP_CHARGE_TIME 6400//3000.0f #define GRIP_DRAIN_AMOUNT 30 -#define FORCE_LIGHTNING_RADIUS 300 +#define FORCE_LIGHTNING_RADIUS 512//300 #define MAX_DRAIN_DISTANCE 512 typedef enum forceJump_e diff --git a/codemp/rd-dedicated/tr_init.cpp b/codemp/rd-dedicated/tr_init.cpp index 794c307989..38544877ff 100644 --- a/codemp/rd-dedicated/tr_init.cpp +++ b/codemp/rd-dedicated/tr_init.cpp @@ -324,7 +324,7 @@ void R_Register( void ) r_ext_compiled_vertex_array = ri.Cvar_Get( "r_ext_compiled_vertex_array", "1", CVAR_ARCHIVE_ND|CVAR_LATCH, "" ); r_ext_texture_env_add = ri.Cvar_Get( "r_ext_texture_env_add", "1", CVAR_ARCHIVE_ND|CVAR_LATCH, "" ); r_ext_texture_filter_anisotropic = ri.Cvar_Get( "r_ext_texture_filter_anisotropic", "16", CVAR_ARCHIVE_ND, "" ); - r_DynamicGlow = ri.Cvar_Get( "r_DynamicGlow", "0", CVAR_ARCHIVE_ND, "" ); + r_DynamicGlow = ri.Cvar_Get( "r_DynamicGlow", "1", CVAR_ARCHIVE_ND, "" ); r_DynamicGlowPasses = ri.Cvar_Get( "r_DynamicGlowPasses", "5", CVAR_ARCHIVE_ND, "" ); r_DynamicGlowDelta = ri.Cvar_Get( "r_DynamicGlowDelta", "0.8f", CVAR_ARCHIVE_ND, "" ); r_DynamicGlowIntensity = ri.Cvar_Get( "r_DynamicGlowIntensity", "1.13f", CVAR_ARCHIVE_ND, "" ); @@ -372,7 +372,7 @@ void R_Register( void ) // rjr - removed for hacking // r_dlightBacks = ri.Cvar_Get( "r_dlightBacks", "1", CVAR_CHEAT, "" ); r_finish = ri.Cvar_Get( "r_finish", "0", CVAR_ARCHIVE_ND, "" ); - r_textureMode = ri.Cvar_Get( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST", CVAR_ARCHIVE, "" ); + r_textureMode = ri.Cvar_Get( "r_textureMode", "GL_LINEAR_MIPMAP_LINEAR", CVAR_ARCHIVE, "" ); r_swapInterval = ri.Cvar_Get( "r_swapInterval", "0", SWAPINTERVAL_FLAGS, "" ); r_markcount = ri.Cvar_Get( "r_markcount", "100", CVAR_ARCHIVE_ND, "" ); r_gamma = ri.Cvar_Get( "r_gamma", "1", CVAR_ARCHIVE_ND, "" ); diff --git a/codemp/rd-rend2/tr_curve.cpp b/codemp/rd-rend2/tr_curve.cpp index 90c24c4950..49d507d2ae 100644 --- a/codemp/rd-rend2/tr_curve.cpp +++ b/codemp/rd-rend2/tr_curve.cpp @@ -185,7 +185,7 @@ static int neighbors[8][2] = { break; // edge of patch } VectorSubtract( ctrl[y][x].xyz, base, temp ); - if ( VectorNormalize2( temp, temp ) == 0 ) { + if ( VectorNormalize( temp ) < 0.001f ) { continue; // degenerate edge, get more dist } else { good[k] = qtrue; @@ -201,7 +201,7 @@ static int neighbors[8][2] = { continue; // didn't get two points } CrossProduct( around[(k+1)&7], around[k], normal ); - if ( VectorNormalize2( normal, normal ) == 0 ) { + if ( VectorNormalize( normal ) < 0.001f ) { continue; } VectorAdd( normal, sum, sum ); diff --git a/codemp/rd-rend2/tr_init.cpp b/codemp/rd-rend2/tr_init.cpp index 183fbcae90..a22a91bc4b 100644 --- a/codemp/rd-rend2/tr_init.cpp +++ b/codemp/rd-rend2/tr_init.cpp @@ -1436,13 +1436,13 @@ void R_Register( void ) r_ext_multi_draw_arrays = ri.Cvar_Get( "r_ext_multi_draw_arrays", "1", CVAR_ARCHIVE | CVAR_LATCH, "Unused" ); r_ext_texture_float = ri.Cvar_Get( "r_ext_texture_float", "1", CVAR_ARCHIVE | CVAR_LATCH, "Disable/enable floating-point textures" ); r_arb_half_float_pixel = ri.Cvar_Get( "r_arb_half_float_pixel", "1", CVAR_ARCHIVE | CVAR_LATCH, "Disable/enable ARB_half_float GL extension" ); - r_ext_framebuffer_multisample = ri.Cvar_Get( "r_ext_multisample", "0", CVAR_ARCHIVE | CVAR_LATCH, "Disable/enable framebuffer MSAA" ); + r_ext_framebuffer_multisample = ri.Cvar_Get( "r_ext_multisample", "8", CVAR_ARCHIVE | CVAR_LATCH, "Disable/enable framebuffer MSAA" ); r_arb_seamless_cube_map = ri.Cvar_Get( "r_arb_seamless_cube_map", "0", CVAR_ARCHIVE | CVAR_LATCH, "Disable/enable seamless cube map filtering GL extension" ); r_arb_vertex_type_2_10_10_10_rev = ri.Cvar_Get( "r_arb_vertex_type_2_10_10_10_rev", "1", CVAR_ARCHIVE | CVAR_LATCH, "Disable/enable 1010102 UI data type" ); r_arb_buffer_storage = ri.Cvar_Get( "r_arb_buffer_storage", "0", CVAR_ARCHIVE | CVAR_LATCH, "Disable/enable buffer storage GL extension" ); r_ext_texture_filter_anisotropic = ri.Cvar_Get( "r_ext_texture_filter_anisotropic", "16", CVAR_ARCHIVE, "Disable/enable anisotropic texture filtering" ); - r_dynamicGlow = ri.Cvar_Get( "r_dynamicGlow", "0", CVAR_ARCHIVE, "" ); + r_dynamicGlow = ri.Cvar_Get( "r_dynamicGlow", "1", CVAR_ARCHIVE, "" ); r_dynamicGlowPasses = ri.Cvar_Get( "r_dynamicGlowPasses", "5", CVAR_ARCHIVE, "" ); r_dynamicGlowDelta = ri.Cvar_Get( "r_dynamicGlowDelta", "0.8f", CVAR_ARCHIVE, "" ); r_dynamicGlowIntensity = ri.Cvar_Get( "r_dynamicGlowIntensity", "1.13f", CVAR_ARCHIVE, "" ); @@ -1549,7 +1549,7 @@ void R_Register( void ) r_drawSun = ri.Cvar_Get( "r_drawSun", "0", CVAR_ARCHIVE, "" ); r_dynamiclight = ri.Cvar_Get( "r_dynamiclight", "1", CVAR_ARCHIVE, "" ); r_finish = ri.Cvar_Get ("r_finish", "0", CVAR_ARCHIVE, ""); - r_textureMode = ri.Cvar_Get( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST", CVAR_ARCHIVE, "" ); + r_textureMode = ri.Cvar_Get( "r_textureMode", "GL_LINEAR_MIPMAP_LINEAR", CVAR_ARCHIVE, "" ); r_markcount = ri.Cvar_Get( "r_markcount", "100", CVAR_ARCHIVE, "" ); r_gamma = ri.Cvar_Get( "r_gamma", "1", CVAR_ARCHIVE, "" ); r_facePlaneCull = ri.Cvar_Get ("r_facePlaneCull", "1", CVAR_ARCHIVE, "" ); diff --git a/codemp/rd-vanilla/tr_curve.cpp b/codemp/rd-vanilla/tr_curve.cpp index e3d75834f1..2f1878ee8f 100644 --- a/codemp/rd-vanilla/tr_curve.cpp +++ b/codemp/rd-vanilla/tr_curve.cpp @@ -193,7 +193,7 @@ static int neighbors[8][2] = { break; // edge of patch } VectorSubtract( ctrl[y][x].xyz, base, temp ); - if ( VectorNormalize2( temp, temp ) == 0 ) { + if ( VectorNormalize( temp ) < 0.001f ) { continue; // degenerate edge, get more dist } else { good[k] = qtrue; @@ -209,7 +209,7 @@ static int neighbors[8][2] = { continue; // didn't get two points } CrossProduct( around[(k+1)&7], around[k], normal ); - if ( VectorNormalize2( normal, normal ) == 0 ) { + if ( VectorNormalize( normal ) < 0.001f ) { continue; } VectorAdd( normal, sum, sum ); diff --git a/codemp/rd-vanilla/tr_init.cpp b/codemp/rd-vanilla/tr_init.cpp index ef4944ab0c..d49f89a4f8 100644 --- a/codemp/rd-vanilla/tr_init.cpp +++ b/codemp/rd-vanilla/tr_init.cpp @@ -1574,7 +1574,7 @@ void R_Register( void ) r_ext_texture_filter_anisotropic = ri.Cvar_Get( "r_ext_texture_filter_anisotropic", "16", CVAR_ARCHIVE_ND, "" ); r_gammaShaders = ri.Cvar_Get( "r_gammaShaders", "0", CVAR_ARCHIVE_ND|CVAR_LATCH, "" ); r_environmentMapping = ri.Cvar_Get( "r_environmentMapping", "1", CVAR_ARCHIVE_ND, "" ); - r_DynamicGlow = ri.Cvar_Get( "r_DynamicGlow", "0", CVAR_ARCHIVE_ND, "" ); + r_DynamicGlow = ri.Cvar_Get( "r_DynamicGlow", "1", CVAR_ARCHIVE_ND, "" ); r_DynamicGlowPasses = ri.Cvar_Get( "r_DynamicGlowPasses", "5", CVAR_ARCHIVE_ND, "" ); r_DynamicGlowDelta = ri.Cvar_Get( "r_DynamicGlowDelta", "0.8f", CVAR_ARCHIVE_ND, "" ); r_DynamicGlowIntensity = ri.Cvar_Get( "r_DynamicGlowIntensity", "1.13f", CVAR_ARCHIVE_ND, "" ); @@ -1613,7 +1613,7 @@ void R_Register( void ) // rjr - removed for hacking // r_dlightBacks = ri.Cvar_Get( "r_dlightBacks", "1", CVAR_CHEAT, "" ); r_finish = ri.Cvar_Get( "r_finish", "0", CVAR_ARCHIVE_ND, "" ); - r_textureMode = ri.Cvar_Get( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST", CVAR_ARCHIVE, "" ); + r_textureMode = ri.Cvar_Get( "r_textureMode", "GL_LINEAR_MIPMAP_LINEAR", CVAR_ARCHIVE, "" ); r_markcount = ri.Cvar_Get( "r_markcount", "100", CVAR_ARCHIVE_ND, "" ); r_gamma = ri.Cvar_Get( "r_gamma", "1", CVAR_ARCHIVE_ND, "" ); r_facePlaneCull = ri.Cvar_Get( "r_facePlaneCull", "1", CVAR_ARCHIVE_ND, "" ); diff --git a/codemp/rd-vanilla/tr_main.cpp b/codemp/rd-vanilla/tr_main.cpp index d649836c23..a4a3871828 100644 --- a/codemp/rd-vanilla/tr_main.cpp +++ b/codemp/rd-vanilla/tr_main.cpp @@ -1151,9 +1151,9 @@ void R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs ) { // if we overflowed MAX_DRAWSURFS, the drawsurfs // wrapped around in the buffer and we will be missing // the first surfaces, not the last ones - if ( numDrawSurfs > MAX_DRAWSURFS ) { - numDrawSurfs = MAX_DRAWSURFS; - } + // if ( numDrawSurfs > MAX_DRAWSURFS ) { + // numDrawSurfs = MAX_DRAWSURFS; + // } // sort the drawsurfs by sort type, then orientation, then shader R_RadixSort( drawSurfs, numDrawSurfs ); @@ -1388,6 +1388,7 @@ or a mirror / remote location */ void R_RenderView (viewParms_t *parms) { int firstDrawSurf; + int numDrawSurfs; if ( parms->viewportWidth <= 0 || parms->viewportHeight <= 0 ) { return; @@ -1410,6 +1411,14 @@ void R_RenderView (viewParms_t *parms) { R_GenerateDrawSurfs(); + // if we overflowed MAX_DRAWSURFS, the drawsurfs + // wrapped around in the buffer and we will be missing + // the first surfaces, not the last ones + numDrawSurfs = tr.refdef.numDrawSurfs; + if (numDrawSurfs > MAX_DRAWSURFS) { + numDrawSurfs = MAX_DRAWSURFS; + } + R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf ); // draw main system development information (surface outlines, etc) diff --git a/codemp/ui/ui_force.c b/codemp/ui/ui_force.c index 898ad36880..b5376d9d2c 100644 --- a/codemp/ui/ui_force.c +++ b/codemp/ui/ui_force.c @@ -494,6 +494,7 @@ void UI_ReadLegalForce(void) int forcePowerRank = 0; int currank = 0; int forceTeam = 0; + int forceBasedTeams = atoi( Info_ValueForKey( info, "g_forceBasedTeams" ) ); qboolean updateForceLater = qfalse; //First, stick them into a string. @@ -514,7 +515,7 @@ void UI_ReadLegalForce(void) info[0] = '\0'; trap->GetConfigString(CS_SERVERINFO, info, sizeof(info)); - if (atoi( Info_ValueForKey( info, "g_forceBasedTeams" ) )) + if (forceBasedTeams) { switch((int)(trap->Cvar_VariableValue("ui_myteam"))) { @@ -604,7 +605,7 @@ void UI_ReadLegalForce(void) continue; // skip this power } - if (uiForcePowerDarkLight[c] && uiForcePowerDarkLight[c] != uiForceSide) + if (uiForcePowerDarkLight[c] && uiForcePowerDarkLight[c] != uiForceSide && forceBasedTeams) { //Apparently the user has crafted a force config that has powers that don't fit with the config's side. continue; // skip this power } @@ -868,14 +869,14 @@ qboolean UI_ForceSide_HandleKey(int flags, float *special, int key, int num, int uiForceSide = num; // Resetting power ranks based on if light or dark side is chosen - while (x < NUM_FORCE_POWERS) + /*while (x < NUM_FORCE_POWERS) { if (uiForcePowerDarkLight[x] && uiForceSide != uiForcePowerDarkLight[x]) { uiForcePowersRank[x] = 0; } x++; - } + }*/ UpdateForceUsed(); @@ -1022,11 +1023,11 @@ qboolean UI_ForcePowerRank_HandleKey(int flags, float *special, int key, int num } // If we are not on the same side as a power, or if we are not of any rank at all. - if (uiForcePowerDarkLight[forcepower] && uiForceSide != uiForcePowerDarkLight[forcepower]) + /*if (uiForcePowerDarkLight[forcepower] && uiForceSide != uiForcePowerDarkLight[forcepower]) { return qtrue; } - else if (forcepower == FP_SABER_DEFENSE || forcepower == FP_SABERTHROW) + else*/ if (forcepower == FP_SABER_DEFENSE || forcepower == FP_SABERTHROW) { // Saberdefend and saberthrow can't be bought if there is no saberattack if (uiForcePowersRank[FP_SABER_OFFENSE] < 1) { @@ -1136,6 +1137,7 @@ void UI_ForceConfigHandle( int oldindex, int newindex ) char singleBuf[64]; char info[MAX_INFO_VALUE]; int forceTeam = 0; + int forceBasedTeams = atoi( Info_ValueForKey( info, "g_forceBasedTeams" ) ); if (oldindex == 0) { //switching out from custom config, so first shove the current values into the custom storage @@ -1215,7 +1217,7 @@ void UI_ForceConfigHandle( int oldindex, int newindex ) info[0] = '\0'; trap->GetConfigString(CS_SERVERINFO, info, sizeof(info)); - if (atoi( Info_ValueForKey( info, "g_forceBasedTeams" ) )) + if (forceBasedTeams) { switch((int)(trap->Cvar_VariableValue("ui_myteam"))) { @@ -1321,7 +1323,7 @@ void UI_ForceConfigHandle( int oldindex, int newindex ) continue; // skip this power } - if (uiForcePowerDarkLight[c] && uiForcePowerDarkLight[c] != uiForceSide) + if (uiForcePowerDarkLight[c] && uiForcePowerDarkLight[c] != uiForceSide && forceBasedTeams) { //Apparently the user has crafted a force config that has powers that don't fit with the config's side. continue; // skip this power } diff --git a/codemp/ui/ui_xcvar.h b/codemp/ui/ui_xcvar.h index dbc4841c4d..60827dcade 100644 --- a/codemp/ui/ui_xcvar.h +++ b/codemp/ui/ui_xcvar.h @@ -36,6 +36,7 @@ along with this program; if not, see . XCVAR_DEF( capturelimit, "0", NULL, CVAR_ARCHIVE|CVAR_NORESTART|CVAR_SERVERINFO ) // fixme init'd to 8 in game module XCVAR_DEF( cg_drawCrosshair, "1", NULL, CVAR_ARCHIVE ) XCVAR_DEF( cg_drawCrosshairNames, "1", NULL, CVAR_ARCHIVE ) +XCVAR_DEF( cg_footsteps, "3", NULL, CVAR_ARCHIVE ) XCVAR_DEF( cg_marks, "1", NULL, CVAR_ARCHIVE ) XCVAR_DEF( cg_selectedPlayer, "0", NULL, CVAR_ARCHIVE|CVAR_INTERNAL ) XCVAR_DEF( cg_selectedPlayerName, "", NULL, CVAR_ARCHIVE|CVAR_INTERNAL ) diff --git a/pk3/assets_fpls.pk3 b/pk3/assets_fpls.pk3 new file mode 100644 index 0000000000..c21976fc3b Binary files /dev/null and b/pk3/assets_fpls.pk3 differ diff --git a/pk3/jk2binds.pk3 b/pk3/jk2binds.pk3 new file mode 100755 index 0000000000..d5d792dec5 Binary files /dev/null and b/pk3/jk2binds.pk3 differ diff --git a/shared/sdl/sdl_window.cpp b/shared/sdl/sdl_window.cpp index 8ff66a8e4b..6bae4ca16d 100644 --- a/shared/sdl/sdl_window.cpp +++ b/shared/sdl/sdl_window.cpp @@ -748,7 +748,7 @@ window_t WIN_Init( const windowDesc_t *windowDesc, glconfig_t *glConfig ) r_depthbits = Cvar_Get( "r_depthbits", "0", CVAR_ARCHIVE_ND|CVAR_LATCH ); r_colorbits = Cvar_Get( "r_colorbits", "0", CVAR_ARCHIVE_ND|CVAR_LATCH ); r_ignorehwgamma = Cvar_Get( "r_ignorehwgamma", "0", CVAR_ARCHIVE_ND|CVAR_LATCH ); - r_ext_multisample = Cvar_Get( "r_ext_multisample", "0", CVAR_ARCHIVE_ND|CVAR_LATCH ); + r_ext_multisample = Cvar_Get( "r_ext_multisample", "8", CVAR_ARCHIVE_ND|CVAR_LATCH ); Cvar_Get( "r_availableModes", "", CVAR_ROM ); // Create the window and set up the context