diff --git a/CODE-mp/Debug/JK2cgame/vc60.idb b/CODE-mp/Debug/JK2cgame/vc60.idb new file mode 100644 index 0000000..56f13f1 Binary files /dev/null and b/CODE-mp/Debug/JK2cgame/vc60.idb differ diff --git a/CODE-mp/Debug/JK2game/vc60.idb b/CODE-mp/Debug/JK2game/vc60.idb new file mode 100644 index 0000000..a5edb5a Binary files /dev/null and b/CODE-mp/Debug/JK2game/vc60.idb differ diff --git a/CODE-mp/Debug/botlib.lib b/CODE-mp/Debug/botlib.lib new file mode 100644 index 0000000..6528173 Binary files /dev/null and b/CODE-mp/Debug/botlib.lib differ diff --git a/CODE-mp/Debug/botlib/vc60.idb b/CODE-mp/Debug/botlib/vc60.idb new file mode 100644 index 0000000..b053406 Binary files /dev/null and b/CODE-mp/Debug/botlib/vc60.idb differ diff --git a/CODE-mp/Debug/cgamex86.dll b/CODE-mp/Debug/cgamex86.dll new file mode 100644 index 0000000..c85e8ea Binary files /dev/null and b/CODE-mp/Debug/cgamex86.dll differ diff --git a/CODE-mp/Debug/cgamex86.lib b/CODE-mp/Debug/cgamex86.lib new file mode 100644 index 0000000..ad6057a Binary files /dev/null and b/CODE-mp/Debug/cgamex86.lib differ diff --git a/CODE-mp/Debug/jk2/vc60.idb b/CODE-mp/Debug/jk2/vc60.idb new file mode 100644 index 0000000..7eab955 Binary files /dev/null and b/CODE-mp/Debug/jk2/vc60.idb differ diff --git a/CODE-mp/Debug/jk2mp.exe b/CODE-mp/Debug/jk2mp.exe new file mode 100644 index 0000000..e19af57 Binary files /dev/null and b/CODE-mp/Debug/jk2mp.exe differ diff --git a/CODE-mp/Debug/jk2mpgamex86.dll b/CODE-mp/Debug/jk2mpgamex86.dll new file mode 100644 index 0000000..b641e07 Binary files /dev/null and b/CODE-mp/Debug/jk2mpgamex86.dll differ diff --git a/CODE-mp/Debug/jk2mpgamex86.lib b/CODE-mp/Debug/jk2mpgamex86.lib new file mode 100644 index 0000000..0c36690 Binary files /dev/null and b/CODE-mp/Debug/jk2mpgamex86.lib differ diff --git a/CODE-mp/Debug/ui/vc60.idb b/CODE-mp/Debug/ui/vc60.idb new file mode 100644 index 0000000..7d20f62 Binary files /dev/null and b/CODE-mp/Debug/ui/vc60.idb differ diff --git a/CODE-mp/Debug/uix86.dll b/CODE-mp/Debug/uix86.dll new file mode 100644 index 0000000..05fe4b1 Binary files /dev/null and b/CODE-mp/Debug/uix86.dll differ diff --git a/CODE-mp/Debug/uix86.lib b/CODE-mp/Debug/uix86.lib new file mode 100644 index 0000000..df6e4f4 Binary files /dev/null and b/CODE-mp/Debug/uix86.lib differ diff --git a/CODE-mp/Final/JK2cgame/vc60.idb b/CODE-mp/Final/JK2cgame/vc60.idb new file mode 100644 index 0000000..e02be14 Binary files /dev/null and b/CODE-mp/Final/JK2cgame/vc60.idb differ diff --git a/CODE-mp/Final/JK2game/vc60.idb b/CODE-mp/Final/JK2game/vc60.idb new file mode 100644 index 0000000..a5cb5c1 Binary files /dev/null and b/CODE-mp/Final/JK2game/vc60.idb differ diff --git a/CODE-mp/Final/OpenAL32.dll b/CODE-mp/Final/OpenAL32.dll new file mode 100644 index 0000000..78195c4 Binary files /dev/null and b/CODE-mp/Final/OpenAL32.dll differ diff --git a/CODE-mp/Final/botlib.lib b/CODE-mp/Final/botlib.lib new file mode 100644 index 0000000..d764ecc Binary files /dev/null and b/CODE-mp/Final/botlib.lib differ diff --git a/CODE-mp/Final/botlib/vc60.idb b/CODE-mp/Final/botlib/vc60.idb new file mode 100644 index 0000000..f6ff768 Binary files /dev/null and b/CODE-mp/Final/botlib/vc60.idb differ diff --git a/CODE-mp/Final/cgamex86.dll b/CODE-mp/Final/cgamex86.dll new file mode 100644 index 0000000..88f13c8 Binary files /dev/null and b/CODE-mp/Final/cgamex86.dll differ diff --git a/CODE-mp/Final/cgamex86.lib b/CODE-mp/Final/cgamex86.lib new file mode 100644 index 0000000..9e7bece Binary files /dev/null and b/CODE-mp/Final/cgamex86.lib differ diff --git a/CODE-mp/Final/jk2/vc60.idb b/CODE-mp/Final/jk2/vc60.idb new file mode 100644 index 0000000..1b942c9 Binary files /dev/null and b/CODE-mp/Final/jk2/vc60.idb differ diff --git a/CODE-mp/Final/jk2/winquake.res b/CODE-mp/Final/jk2/winquake.res new file mode 100644 index 0000000..2f0a921 Binary files /dev/null and b/CODE-mp/Final/jk2/winquake.res differ diff --git a/CODE-mp/Final/jk2mp.exe b/CODE-mp/Final/jk2mp.exe new file mode 100644 index 0000000..730721e Binary files /dev/null and b/CODE-mp/Final/jk2mp.exe differ diff --git a/CODE-mp/Final/jk2mpgamex86.dll b/CODE-mp/Final/jk2mpgamex86.dll new file mode 100644 index 0000000..0bfc812 Binary files /dev/null and b/CODE-mp/Final/jk2mpgamex86.dll differ diff --git a/CODE-mp/Final/jk2mpgamex86.lib b/CODE-mp/Final/jk2mpgamex86.lib new file mode 100644 index 0000000..a37b24a Binary files /dev/null and b/CODE-mp/Final/jk2mpgamex86.lib differ diff --git a/CODE-mp/Final/ui/vc60.idb b/CODE-mp/Final/ui/vc60.idb new file mode 100644 index 0000000..f3acde1 Binary files /dev/null and b/CODE-mp/Final/ui/vc60.idb differ diff --git a/CODE-mp/Final/uix86.dll b/CODE-mp/Final/uix86.dll new file mode 100644 index 0000000..6df66d2 Binary files /dev/null and b/CODE-mp/Final/uix86.dll differ diff --git a/CODE-mp/Final/uix86.lib b/CODE-mp/Final/uix86.lib new file mode 100644 index 0000000..80bf03b Binary files /dev/null and b/CODE-mp/Final/uix86.lib differ diff --git a/CODE-mp/Release/Dedicated/vc60.idb b/CODE-mp/Release/Dedicated/vc60.idb new file mode 100644 index 0000000..433ffc6 Binary files /dev/null and b/CODE-mp/Release/Dedicated/vc60.idb differ diff --git a/CODE-mp/Release/JK2cgame/vc60.idb b/CODE-mp/Release/JK2cgame/vc60.idb new file mode 100644 index 0000000..77e545b Binary files /dev/null and b/CODE-mp/Release/JK2cgame/vc60.idb differ diff --git a/CODE-mp/Release/JK2game/vc60.idb b/CODE-mp/Release/JK2game/vc60.idb new file mode 100644 index 0000000..38f473c Binary files /dev/null and b/CODE-mp/Release/JK2game/vc60.idb differ diff --git a/CODE-mp/Release/botlib.lib b/CODE-mp/Release/botlib.lib new file mode 100644 index 0000000..ee7854d Binary files /dev/null and b/CODE-mp/Release/botlib.lib differ diff --git a/CODE-mp/Release/botlib/vc60.idb b/CODE-mp/Release/botlib/vc60.idb new file mode 100644 index 0000000..62b17fa Binary files /dev/null and b/CODE-mp/Release/botlib/vc60.idb differ diff --git a/CODE-mp/Release/cgamex86.dll b/CODE-mp/Release/cgamex86.dll new file mode 100644 index 0000000..79c1405 Binary files /dev/null and b/CODE-mp/Release/cgamex86.dll differ diff --git a/CODE-mp/Release/cgamex86.lib b/CODE-mp/Release/cgamex86.lib new file mode 100644 index 0000000..4f8de07 Binary files /dev/null and b/CODE-mp/Release/cgamex86.lib differ diff --git a/CODE-mp/Release/jk2/vc60.idb b/CODE-mp/Release/jk2/vc60.idb new file mode 100644 index 0000000..e3fcaf5 Binary files /dev/null and b/CODE-mp/Release/jk2/vc60.idb differ diff --git a/CODE-mp/Release/jk2/winquake.res b/CODE-mp/Release/jk2/winquake.res new file mode 100644 index 0000000..2f0a921 Binary files /dev/null and b/CODE-mp/Release/jk2/winquake.res differ diff --git a/CODE-mp/Release/jk2Ded.exe b/CODE-mp/Release/jk2Ded.exe new file mode 100644 index 0000000..8edd1fb Binary files /dev/null and b/CODE-mp/Release/jk2Ded.exe differ diff --git a/CODE-mp/Release/jk2mp.exe b/CODE-mp/Release/jk2mp.exe new file mode 100644 index 0000000..762283c Binary files /dev/null and b/CODE-mp/Release/jk2mp.exe differ diff --git a/CODE-mp/Release/jk2mpgamex86.dll b/CODE-mp/Release/jk2mpgamex86.dll new file mode 100644 index 0000000..1575ae1 Binary files /dev/null and b/CODE-mp/Release/jk2mpgamex86.dll differ diff --git a/CODE-mp/Release/jk2mpgamex86.lib b/CODE-mp/Release/jk2mpgamex86.lib new file mode 100644 index 0000000..a6ae150 Binary files /dev/null and b/CODE-mp/Release/jk2mpgamex86.lib differ diff --git a/CODE-mp/Release/ui/vc60.idb b/CODE-mp/Release/ui/vc60.idb new file mode 100644 index 0000000..4aa05a9 Binary files /dev/null and b/CODE-mp/Release/ui/vc60.idb differ diff --git a/CODE-mp/Release/uix86.dll b/CODE-mp/Release/uix86.dll new file mode 100644 index 0000000..954207a Binary files /dev/null and b/CODE-mp/Release/uix86.dll differ diff --git a/CODE-mp/Release/uix86.lib b/CODE-mp/Release/uix86.lib new file mode 100644 index 0000000..d451bf7 Binary files /dev/null and b/CODE-mp/Release/uix86.lib differ diff --git a/CODE-mp/base/vm/cgame.qvm b/CODE-mp/base/vm/cgame.qvm new file mode 100644 index 0000000..4cc1355 Binary files /dev/null and b/CODE-mp/base/vm/cgame.qvm differ diff --git a/CODE-mp/base/vm/jk2mpgame.qvm b/CODE-mp/base/vm/jk2mpgame.qvm new file mode 100644 index 0000000..a234e98 Binary files /dev/null and b/CODE-mp/base/vm/jk2mpgame.qvm differ diff --git a/CODE-mp/base/vm/ui.qvm b/CODE-mp/base/vm/ui.qvm index 9cc3c1d..6908606 100644 Binary files a/CODE-mp/base/vm/ui.qvm and b/CODE-mp/base/vm/ui.qvm differ diff --git a/CODE-mp/cgame/cg_drawtools.c b/CODE-mp/cgame/cg_drawtools.c index 73091b0..dfd1769 100644 --- a/CODE-mp/cgame/cg_drawtools.c +++ b/CODE-mp/cgame/cg_drawtools.c @@ -208,50 +208,69 @@ to a fixed color. Coordinates are at 640 by 480 virtual resolution ================== */ +#include "../../ui/menudef.h" // for "ITEM_TEXTSTYLE_SHADOWED" void CG_DrawStringExt( int x, int y, const char *string, const float *setColor, qboolean forceColor, qboolean shadow, int charWidth, int charHeight, int maxChars ) { - vec4_t color; - const char *s; - int xx; + if (trap_Language_IsAsian()) + { + // hack-a-doodle-do (post-release quick fix code)... + // + vec4_t color; + memcpy(color,setColor, sizeof(color)); // de-const it + CG_Text_Paint(x, y, 1.0f, // float scale, + color, // vec4_t color, + string, // const char *text, + 0.0f, // float adjust, + 0, // int limit, + shadow ? ITEM_TEXTSTYLE_SHADOWED : 0, // int style, + FONT_MEDIUM // iMenuFont + ) ; + } + else + { + vec4_t color; + const char *s; + int xx; - // draw the drop shadow - if (shadow) { - color[0] = color[1] = color[2] = 0; - color[3] = setColor[3]; - trap_R_SetColor( color ); + // draw the drop shadow + if (shadow) { + color[0] = color[1] = color[2] = 0; + color[3] = setColor[3]; + trap_R_SetColor( color ); + s = string; + xx = x; + while ( *s ) { + if ( Q_IsColorString( s ) ) { + s += 2; + continue; + } + CG_DrawChar( xx + 2, y + 2, charWidth, charHeight, *s ); + xx += charWidth; + s++; + } + } + + // draw the colored text s = string; xx = x; + trap_R_SetColor( setColor ); while ( *s ) { if ( Q_IsColorString( s ) ) { + if ( !forceColor ) { + memcpy( color, g_color_table[ColorIndex(*(s+1))], sizeof( color ) ); + color[3] = setColor[3]; + trap_R_SetColor( color ); + } s += 2; continue; } - CG_DrawChar( xx + 2, y + 2, charWidth, charHeight, *s ); + CG_DrawChar( xx, y, charWidth, charHeight, *s ); xx += charWidth; s++; } + trap_R_SetColor( NULL ); } - - // draw the colored text - s = string; - xx = x; - trap_R_SetColor( setColor ); - while ( *s ) { - if ( Q_IsColorString( s ) ) { - if ( !forceColor ) { - memcpy( color, g_color_table[ColorIndex(*(s+1))], sizeof( color ) ); - color[3] = setColor[3]; - trap_R_SetColor( color ); - } - s += 2; - continue; - } - CG_DrawChar( xx, y, charWidth, charHeight, *s ); - xx += charWidth; - s++; - } - trap_R_SetColor( NULL ); } void CG_DrawBigString( int x, int y, const char *s, float alpha ) { diff --git a/CODE-mp/cgame/cg_ents.c b/CODE-mp/cgame/cg_ents.c index d5616fa..334f3f2 100644 --- a/CODE-mp/cgame/cg_ents.c +++ b/CODE-mp/cgame/cg_ents.c @@ -524,7 +524,7 @@ static void CG_General( centity_t *cent ) { } else { - clEnt = &cg_entities[cent->currentState.modelindex2]; + clEnt = &cg_entities[cent->currentState.otherEntityNum2]; } if (!dismember_settings) @@ -793,6 +793,10 @@ static void CG_General( centity_t *cent ) { trap_G2API_GiveMeVectorFromMatrix(&matrix, ORIGIN, boltOrg); trap_G2API_GiveMeVectorFromMatrix(&matrix, NEGATIVE_Y, boltAng); + if (!boltAng[0] && !boltAng[1] && !boltAng[2]) + { + boltAng[1] = 1; + } trap_FX_PlayEffectID(trap_FX_RegisterEffect("blaster/smoke_bolton"), boltOrg, boltAng); cent->trailTime = cg.time + 400; diff --git a/CODE-mp/cgame/cg_event.c b/CODE-mp/cgame/cg_event.c index 052c7fe..d9a27a9 100644 --- a/CODE-mp/cgame/cg_event.c +++ b/CODE-mp/cgame/cg_event.c @@ -2236,7 +2236,9 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { // local player sounds are triggered in CG_CheckLocalSounds, // so ignore events on the player DEBUGNAME("EV_PAIN"); - if ( cent->currentState.number != cg.snap->ps.clientNum ) { + + if ( !cg_oldPainSounds.integer || (cent->currentState.number != cg.snap->ps.clientNum) ) + { CG_PainEvent( cent, es->eventParm ); } break; diff --git a/CODE-mp/cgame/cg_info.c b/CODE-mp/cgame/cg_info.c index 227c51b..3489ae8 100644 --- a/CODE-mp/cgame/cg_info.c +++ b/CODE-mp/cgame/cg_info.c @@ -167,6 +167,17 @@ void CG_DrawInformation( void ) { y += iPropHeight; } + { // display global MOTD at bottom (mirrors ui_main UI_DrawConnectScreen + char motdString[1024]; + trap_Cvar_VariableStringBuffer( "cl_motdString", motdString, sizeof( motdString ) ); + + if (motdString[0]) + { + UI_DrawProportionalString( 320, 425, motdString, + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); + } + } + // some extra space after hostname and motd y += 10; } diff --git a/CODE-mp/cgame/cg_local.h b/CODE-mp/cgame/cg_local.h index 8b9b4f1..a3ffabd 100644 --- a/CODE-mp/cgame/cg_local.h +++ b/CODE-mp/cgame/cg_local.h @@ -1313,6 +1313,11 @@ typedef struct { int capturelimit; int timelimit; int maxclients; + qboolean needpass; + qboolean jediVmerc; + int wDisable; + int fDisable; + char mapname[MAX_QPATH]; char redTeam[MAX_QPATH]; char blueTeam[MAX_QPATH]; @@ -1456,10 +1461,17 @@ extern vmCvar_t cg_zoomFov; extern vmCvar_t cg_swingAngles; +extern vmCvar_t cg_oldPainSounds; + #ifdef G2_COLLISION_ENABLED extern vmCvar_t cg_saberModelTraceEffect; #endif +extern vmCvar_t cg_fpls; + +extern vmCvar_t cg_saberDynamicMarks; +extern vmCvar_t cg_saberDynamicMarkTime; + extern vmCvar_t cg_saberContact; extern vmCvar_t cg_saberTrail; diff --git a/CODE-mp/cgame/cg_main.c b/CODE-mp/cgame/cg_main.c index 2de895b..c9739b5 100644 --- a/CODE-mp/cgame/cg_main.c +++ b/CODE-mp/cgame/cg_main.c @@ -410,10 +410,17 @@ vmCvar_t cg_zoomFov; vmCvar_t cg_swingAngles; +vmCvar_t cg_oldPainSounds; + #ifdef G2_COLLISION_ENABLED vmCvar_t cg_saberModelTraceEffect; #endif +vmCvar_t cg_fpls; + +vmCvar_t cg_saberDynamicMarks; +vmCvar_t cg_saberDynamicMarkTime; + vmCvar_t cg_saberContact; vmCvar_t cg_saberTrail; @@ -557,10 +564,17 @@ static cvarTable_t cvarTable[] = { // bk001129 { &cg_swingAngles, "cg_swingAngles", "1", 0 }, + { &cg_oldPainSounds, "cg_oldPainSounds", "0", 0 }, + #ifdef G2_COLLISION_ENABLED { &cg_saberModelTraceEffect, "cg_saberModelTraceEffect", "0", 0 }, #endif + { &cg_fpls, "cg_fpls", "0", 0 }, + + { &cg_saberDynamicMarks, "cg_saberDynamicMarks", "0", 0 }, + { &cg_saberDynamicMarkTime, "cg_saberDynamicMarkTime", "60000", 0 }, + { &cg_saberContact, "cg_saberContact", "1", 0 }, { &cg_saberTrail, "cg_saberTrail", "1", 0 }, diff --git a/CODE-mp/cgame/cg_players.c b/CODE-mp/cgame/cg_players.c index e8b6660..b4a0c98 100644 --- a/CODE-mp/cgame/cg_players.c +++ b/CODE-mp/cgame/cg_players.c @@ -265,7 +265,7 @@ retryModel: trap_G2API_CleanGhoul2Models(&(ci->ghoul2Model)); } - if (cgs.gametype >= GT_TEAM) + if ( cgs.gametype >= GT_TEAM && !cgs.jediVmerc ) { if (ci->team == TEAM_RED) { @@ -662,7 +662,22 @@ void CG_LoadClientInfo( clientInfo_t *ci ) { dir = ci->modelName; fallback = DEFAULT_MALE_SOUNDPATH; //(cgs.gametype >= GT_TEAM) ? DEFAULT_TEAM_MODEL : DEFAULT_MODEL; - fLen = trap_FS_FOpenFile(va("models/players/%s/sounds.cfg", dir), &f, FS_READ); + if ( !ci->skinName || !Q_stricmp( "default", ci->skinName ) ) + {//try default sounds.cfg first + fLen = trap_FS_FOpenFile(va("models/players/%s/sounds.cfg", dir), &f, FS_READ); + if ( !f ) + {//no? Look for _default sounds.cfg + fLen = trap_FS_FOpenFile(va("models/players/%s/sounds_default.cfg", dir), &f, FS_READ); + } + } + else + {//use the .skin associated with this skin + fLen = trap_FS_FOpenFile(va("models/players/%s/sounds_%s.cfg", dir, ci->skinName), &f, FS_READ); + if ( !f ) + {//fall back to default sounds + fLen = trap_FS_FOpenFile(va("models/players/%s/sounds.cfg", dir), &f, FS_READ); + } + } soundpath[0] = 0; @@ -1129,7 +1144,7 @@ void CG_NewClientInfo( int clientNum, qboolean entitiesInitialized ) { newInfo.ATST = wasATST; - if (cgs.gametype >= GT_TEAM) + if (cgs.gametype >= GT_TEAM && !cgs.jediVmerc ) { if (newInfo.team == TEAM_RED) { @@ -1190,23 +1205,29 @@ void CG_NewClientInfo( int clientNum, qboolean entitiesInitialized ) { if (entitiesInitialized && ci->ghoul2Model && (oldGhoul2 != ci->ghoul2Model)) { // Copy the new ghoul2 model to the centity. animation_t *anim; - // First check if we have a ghoul2 model on the client entity. + centity_t *cent = &cg_entities[clientNum]; anim = &bgGlobalAnimations[ (cg_entities[clientNum].currentState.legsAnim & ~ANIM_TOGGLEBIT) ]; if (anim) { int flags = BONE_ANIM_OVERRIDE_FREEZE; - int firstFrame = anim->firstFrame + anim->numFrames-1; + int firstFrame = anim->firstFrame; + int setFrame = -1; + float animSpeed = 50.0f / anim->frameLerp; if (anim->loopFrames != -1) { - flags = BONE_ANIM_OVERRIDE_LOOP; - firstFrame = anim->firstFrame; + flags |= BONE_ANIM_OVERRIDE_LOOP; + } + + if (cent->pe.legs.frame >= anim->firstFrame && cent->pe.legs.frame <= (anim->firstFrame + anim->numFrames)) + { + setFrame = cent->pe.legs.frame; } //rww - Set the animation again because it just got reset due to the model change - trap_G2API_SetBoneAnim(ci->ghoul2Model, 0, "model_root", firstFrame, anim->firstFrame + anim->numFrames, flags, 1.0f, cg.time, -1, 150); + trap_G2API_SetBoneAnim(ci->ghoul2Model, 0, "model_root", firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed, cg.time, setFrame, 150); cg_entities[clientNum].currentState.legsAnim = 0; } @@ -1216,16 +1237,22 @@ void CG_NewClientInfo( int clientNum, qboolean entitiesInitialized ) { if (anim) { int flags = BONE_ANIM_OVERRIDE_FREEZE; - int firstFrame = anim->firstFrame + anim->numFrames-1; + int firstFrame = anim->firstFrame; + int setFrame = -1; + float animSpeed = 50.0f / anim->frameLerp; if (anim->loopFrames != -1) { - flags = BONE_ANIM_OVERRIDE_LOOP; - firstFrame = anim->firstFrame; + flags |= BONE_ANIM_OVERRIDE_LOOP; + } + + if (cent->pe.torso.frame >= anim->firstFrame && cent->pe.torso.frame <= (anim->firstFrame + anim->numFrames)) + { + setFrame = cent->pe.torso.frame; } //rww - Set the animation again because it just got reset due to the model change - trap_G2API_SetBoneAnim(ci->ghoul2Model, 0, "lower_lumbar", anim->firstFrame + anim->numFrames-1, anim->firstFrame + anim->numFrames, flags, 1.0f, cg.time, -1, 150); + trap_G2API_SetBoneAnim(ci->ghoul2Model, 0, "lower_lumbar", firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed, cg.time, setFrame, 150); cg_entities[clientNum].currentState.torsoAnim = 0; } @@ -1235,26 +1262,7 @@ void CG_NewClientInfo( int clientNum, qboolean entitiesInitialized ) { trap_G2API_CleanGhoul2Models(&cg_entities[clientNum].ghoul2); } trap_G2API_DuplicateGhoul2Instance(ci->ghoul2Model, &cg_entities[clientNum].ghoul2); - - /* - if (cg_entities[clientNum].currentState.weapon > WP_NONE) - { - CG_CopyG2WeaponInstance(cg_entities[clientNum].currentState.weapon, cg_entities[clientNum].ghoul2); - } - */ - //It should catch this next update anyway. We just set all ghoul2weapon's to NULL above. } - /* - else if (ci->team == TEAM_SPECTATOR && cg_entities[clientNum].ghoul2 && trap_G2_HaveWeGhoul2Models(cg_entities[clientNum].ghoul2)) - { //this shouldn't actually happen now because we are not trying to register models for spectators. But just in case. - trap_G2API_CleanGhoul2Models(&cg_entities[clientNum].ghoul2); - if (ci->ghoul2Model && trap_G2_HaveWeGhoul2Models(ci->ghoul2Model)) - { - trap_G2API_DuplicateGhoul2Instance(ci->ghoul2Model, &cg_entities[clientNum].ghoul2); - } - } - */ - } @@ -2295,6 +2303,35 @@ void CG_G2SetBoneAngles(void *ghoul2, int modelIndex, const char *boneName, cons blendTime, currentTime); } +qboolean CG_InKnockDown( int anim ) +{ + switch ( (anim&~ANIM_TOGGLEBIT) ) + { + case BOTH_KNOCKDOWN1: + case BOTH_KNOCKDOWN2: + case BOTH_KNOCKDOWN3: + case BOTH_KNOCKDOWN4: + case BOTH_KNOCKDOWN5: + return qtrue; + break; + case BOTH_GETUP1: + case BOTH_GETUP2: + case BOTH_GETUP3: + case BOTH_GETUP4: + case BOTH_GETUP5: + case BOTH_FORCE_GETUP_F1: + case BOTH_FORCE_GETUP_F2: + case BOTH_FORCE_GETUP_B1: + case BOTH_FORCE_GETUP_B2: + case BOTH_FORCE_GETUP_B3: + case BOTH_FORCE_GETUP_B4: + case BOTH_FORCE_GETUP_B5: + return qtrue; + break; + } + return qfalse; +} + void CG_G2ClientSpineAngles( centity_t *cent, vec3_t viewAngles, const vec3_t angles, vec3_t thoracicAngles, vec3_t ulAngles, vec3_t llAngles ) { float legDif = 0; @@ -2323,6 +2360,11 @@ void CG_G2ClientSpineAngles( centity_t *cent, vec3_t viewAngles, const vec3_t an !BG_SaberInSpecialAttack(cent->currentState.torsoAnim&~ANIM_TOGGLEBIT) && !BG_SaberInSpecialAttack(cent->currentState.legsAnim&~ANIM_TOGGLEBIT) && + !CG_InKnockDown(cent->currentState.torsoAnim) && + !CG_InKnockDown(cent->currentState.legsAnim) && + !CG_InKnockDown(cgs.clientinfo[cent->currentState.number].torsoAnim) && + !CG_InKnockDown(cgs.clientinfo[cent->currentState.number].legsAnim) && + !BG_FlippingAnim( cgs.clientinfo[cent->currentState.number].legsAnim&~ANIM_TOGGLEBIT ) && !BG_SpinningSaberAnim( cgs.clientinfo[cent->currentState.number].legsAnim&~ANIM_TOGGLEBIT ) && !BG_SpinningSaberAnim( cgs.clientinfo[cent->currentState.number].torsoAnim&~ANIM_TOGGLEBIT ) && @@ -3801,7 +3843,6 @@ void CG_CreateSaberMarks( vec3_t start, vec3_t end, vec3_t normal ) numFragments = trap_CM_MarkFragments( 4, (const float (*)[3])originalPoints, projection, MAX_MARK_POINTS, markPoints[0], MAX_MARK_FRAGMENTS, markFragments ); - for ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ ) { // we have an upper limit on the complexity of polygons that we store persistantly @@ -3824,26 +3865,111 @@ void CG_CreateSaberMarks( vec3_t start, vec3_t end, vec3_t normal ) v->st[1] = 0.5 + DotProduct( delta, axis[2] ) * (0.15f + random() * 0.05f); } - // save it persistantly, do burn first - mark = CG_AllocMark(); - mark->time = cg.time; - mark->alphaFade = qtrue; - mark->markShader = cgs.media.rivetMarkShader; - mark->poly.numVerts = mf->numPoints; - mark->color[0] = mark->color[1] = mark->color[2] = mark->color[3] = 255; - memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) ); + if (cg_saberDynamicMarks.integer) + { + int i = 0; + int i_2 = 0; + addpolyArgStruct_t apArgs; + vec3_t x; - // And now do a glow pass - // by moving the start time back, we can hack it to fade out way before the burn does - mark = CG_AllocMark(); - mark->time = cg.time - 8500; - mark->alphaFade = qfalse; - mark->markShader = trap_R_RegisterShader("gfx/effects/saberDamageGlow" ); - mark->poly.numVerts = mf->numPoints; - mark->color[0] = 215 + random() * 40.0f; - mark->color[1] = 96 + random() * 32.0f; - mark->color[2] = mark->color[3] = random()*15.0f; - memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) ); + memset (&apArgs, 0, sizeof(apArgs)); + + while (i < 4) + { + while (i_2 < 3) + { + apArgs.p[i][i_2] = verts[i].xyz[i_2]; + + i_2++; + } + + i_2 = 0; + i++; + } + + i = 0; + i_2 = 0; + + while (i < 4) + { + while (i_2 < 2) + { + apArgs.ev[i][i_2] = verts[i].st[i_2]; + + i_2++; + } + + i_2 = 0; + i++; + } + + //When using addpoly, having a situation like this tends to cause bad results. + //(I assume it doesn't like trying to draw a polygon over two planes and extends + //the vertex out to some odd value) + VectorSubtract(apArgs.p[0], apArgs.p[3], x); + if (VectorLength(x) > 3.0f) + { + return; + } + + apArgs.numVerts = mf->numPoints; + VectorCopy(vec3_origin, apArgs.vel); + VectorCopy(vec3_origin, apArgs.accel); + + apArgs.alpha1 = 1.0f; + apArgs.alpha2 = 0.0f; + apArgs.alphaParm = 255.0f; + + VectorSet(apArgs.rgb1, 0.0f, 0.0f, 0.0f); + VectorSet(apArgs.rgb2, 0.0f, 0.0f, 0.0f); + + apArgs.rgbParm = 0.0f; + + apArgs.bounce = 0; + apArgs.motionDelay = 0; + apArgs.killTime = cg_saberDynamicMarkTime.integer; + apArgs.shader = cgs.media.rivetMarkShader; + apArgs.flags = 0x08000000|0x00000004; + + trap_FX_AddPoly(&apArgs); + + apArgs.shader = trap_R_RegisterShader("gfx/effects/saberDamageGlow"); + apArgs.rgb1[0] = 215 + random() * 40.0f; + apArgs.rgb1[1] = 96 + random() * 32.0f; + apArgs.rgb1[2] = apArgs.alphaParm = random()*15.0f; + + apArgs.rgb1[0] /= 255; + apArgs.rgb1[1] /= 255; + apArgs.rgb1[2] /= 255; + VectorCopy(apArgs.rgb1, apArgs.rgb2); + + apArgs.killTime = 100; + + trap_FX_AddPoly(&apArgs); + } + else + { + // save it persistantly, do burn first + mark = CG_AllocMark(); + mark->time = cg.time; + mark->alphaFade = qtrue; + mark->markShader = cgs.media.rivetMarkShader; + mark->poly.numVerts = mf->numPoints; + mark->color[0] = mark->color[1] = mark->color[2] = mark->color[3] = 255; + memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) ); + + // And now do a glow pass + // by moving the start time back, we can hack it to fade out way before the burn does + mark = CG_AllocMark(); + mark->time = cg.time - 8500; + mark->alphaFade = qfalse; + mark->markShader = trap_R_RegisterShader("gfx/effects/saberDamageGlow"); + mark->poly.numVerts = mf->numPoints; + mark->color[0] = 215 + random() * 40.0f; + mark->color[1] = 96 + random() * 32.0f; + mark->color[2] = mark->color[3] = random()*15.0f; + memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) ); + } } } @@ -4060,7 +4186,7 @@ Ghoul2 Insert Start scolor = cgs.clientinfo[cent->currentState.number].icolor1; - if (cgs.gametype >= GT_TEAM) + if (cgs.gametype >= GT_TEAM && !cgs.jediVmerc ) { if (cgs.clientinfo[cent->currentState.number].team == TEAM_RED) { @@ -5521,6 +5647,95 @@ void CG_G2Animated( centity_t *cent ) } //rww - here ends the majority of my g2animent stuff. +int cgFPLSState = 0; + +void CG_ForceFPLSPlayerModel(centity_t *cent, clientInfo_t *ci) +{ + int clientNum = cent->currentState.number; + animation_t *anim; + + if (cg_fpls.integer && !cg.renderingThirdPerson) + { + int skinHandle; + + skinHandle = trap_R_RegisterSkin("models/players/kyle/model_fpls2.skin"); + + trap_G2API_CleanGhoul2Models(&(ci->ghoul2Model)); + + ci->torsoSkin = skinHandle; + trap_G2API_InitGhoul2Model(&ci->ghoul2Model, "models/players/kyle/model.glm", 0, ci->torsoSkin, 0, 0, 0); + + ci->bolt_rhand = trap_G2API_AddBolt(ci->ghoul2Model, 0, "*r_hand"); + + trap_G2API_SetBoneAnim(ci->ghoul2Model, 0, "model_root", 0, 12, BONE_ANIM_OVERRIDE_LOOP, 1.0f, cg.time, -1, -1); + trap_G2API_SetBoneAngles(ci->ghoul2Model, 0, "upper_lumbar", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, NULL, 0, cg.time); + trap_G2API_SetBoneAngles(ci->ghoul2Model, 0, "cranium", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_Z, NEGATIVE_Y, POSITIVE_X, NULL, 0, cg.time); + + ci->bolt_lhand = trap_G2API_AddBolt(ci->ghoul2Model, 0, "*l_hand"); + ci->bolt_head = trap_G2API_AddBolt(ci->ghoul2Model, 0, "*head_top"); + + ci->bolt_motion = trap_G2API_AddBolt(ci->ghoul2Model, 0, "Motion"); + + //We need a lower lumbar bolt for footsteps + ci->bolt_llumbar = trap_G2API_AddBolt(ci->ghoul2Model, 0, "lower_lumbar"); + } + else + { + CG_RegisterClientModelname(ci, ci->modelName, ci->skinName, ci->teamName, cent->currentState.number); + } + + anim = &bgGlobalAnimations[ (cg_entities[clientNum].currentState.legsAnim & ~ANIM_TOGGLEBIT) ]; + + if (anim) + { + int flags = BONE_ANIM_OVERRIDE_FREEZE; + int firstFrame = anim->firstFrame; + int setFrame = -1; + float animSpeed = 50.0f / anim->frameLerp; + + if (anim->loopFrames != -1) + { + flags |= BONE_ANIM_OVERRIDE_LOOP; + } + + if (cent->pe.legs.frame >= anim->firstFrame && cent->pe.legs.frame <= (anim->firstFrame + anim->numFrames)) + { + setFrame = cent->pe.legs.frame; + } + + trap_G2API_SetBoneAnim(ci->ghoul2Model, 0, "model_root", firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed, cg.time, setFrame, 150); + + cg_entities[clientNum].currentState.legsAnim = 0; + } + + anim = &bgGlobalAnimations[ (cg_entities[clientNum].currentState.torsoAnim & ~ANIM_TOGGLEBIT) ]; + + if (anim) + { + int flags = BONE_ANIM_OVERRIDE_FREEZE; + int firstFrame = anim->firstFrame; + int setFrame = -1; + float animSpeed = 50.0f / anim->frameLerp; + + if (anim->loopFrames != -1) + { + flags |= BONE_ANIM_OVERRIDE_LOOP; + } + + if (cent->pe.torso.frame >= anim->firstFrame && cent->pe.torso.frame <= (anim->firstFrame + anim->numFrames)) + { + setFrame = cent->pe.torso.frame; + } + + trap_G2API_SetBoneAnim(ci->ghoul2Model, 0, "lower_lumbar", firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed, cg.time, setFrame, 150); + + cg_entities[clientNum].currentState.torsoAnim = 0; + } + + trap_G2API_CleanGhoul2Models(&(cent->ghoul2)); + trap_G2API_DuplicateGhoul2Instance(ci->ghoul2Model, ¢->ghoul2); + cg_entities[clientNum].ghoul2 = cent->ghoul2; +} /* =============== @@ -5709,7 +5924,10 @@ void CG_Player( centity_t *cent ) { renderfx = 0; if ( cent->currentState.number == cg.snap->ps.clientNum) { if (!cg.renderingThirdPerson) { - renderfx = RF_THIRD_PERSON; // only draw in mirrors + if (!cg_fpls.integer || cent->currentState.weapon != WP_SABER) + { + renderfx = RF_THIRD_PERSON; // only draw in mirrors + } } else { if (cg_cameraMode.integer) { iwantout = 1; @@ -5922,6 +6140,61 @@ doEssentialOne: trap_G2API_GetBoltMatrix(cent->ghoul2, 0, cgs.clientinfo[cent->currentState.number].bolt_lhand, &lHandMatrix, cent->turAngles, cent->lerpOrigin, cg.time, cgs.gameModels, cent->modelScale); gotLHandMatrix = qtrue; + if (cg.renderingThirdPerson) + { + if (cgFPLSState != 0) + { + CG_ForceFPLSPlayerModel(cent, ci); + cgFPLSState = 0; + return; + } + } + else if (ci->team == TEAM_SPECTATOR || (cg.snap && (cg.snap->ps.pm_flags & PMF_FOLLOW))) + { //don't allow this when spectating + if (cgFPLSState != 0) + { + trap_Cvar_Set("cg_fpls", "0"); + cg_fpls.integer = 0; + + CG_ForceFPLSPlayerModel(cent, ci); + cgFPLSState = 0; + return; + } + + if (cg_fpls.integer) + { + trap_Cvar_Set("cg_fpls", "0"); + } + } + else + { + if (cg_fpls.integer && cent->currentState.weapon == WP_SABER && cg.snap && cent->currentState.number == cg.snap->ps.clientNum) + { + + if (cgFPLSState != cg_fpls.integer) + { + CG_ForceFPLSPlayerModel(cent, ci); + cgFPLSState = cg_fpls.integer; + return; + } + + /* + mdxaBone_t headMatrix; + trap_G2API_GetBoltMatrix(cent->ghoul2, 0, cgs.clientinfo[cent->currentState.number].bolt_head, &headMatrix, cent->turAngles, cent->lerpOrigin, cg.time, cgs.gameModels, cent->modelScale); + trap_G2API_GiveMeVectorFromMatrix(&headMatrix, ORIGIN, cg.refdef.vieworg); + */ + } + else if (!cg_fpls.integer && cgFPLSState) + { + if (cgFPLSState != cg_fpls.integer) + { + CG_ForceFPLSPlayerModel(cent, ci); + cgFPLSState = cg_fpls.integer; + return; + } + } + } + if (cent->currentState.eFlags & EF_DEAD) { dead = qtrue; @@ -6002,6 +6275,10 @@ doEssentialTwo: CG_PlayerAnimation( cent, &legs.oldframe, &legs.frame, &legs.backlerp, &torso.oldframe, &torso.frame, &torso.backlerp ); + //Need these set because we use them in other functions (cent pointer differs from cg_entities values) + cg_entities[cent->currentState.number].pe.torso.frame = cent->pe.torso.frame; + cg_entities[cent->currentState.number].pe.legs.frame = cent->pe.legs.frame; + // add the talk baloon or disconnect icon CG_PlayerSprites( cent ); @@ -6010,13 +6287,6 @@ doEssentialTwo: cgs.clientinfo[cent->currentState.number].frame = cent->pe.torso.frame; } -/* if ( cent->gent->s.number == 0 && cg_thirdPersonAlpha.value < 1.0f ) - { - ent.renderfx |= RF_ALPHA_FADE; - ent.shaderRGBA[3] = (unsigned char)(cg_thirdPersonAlpha.value * 255.0f); - } -*/ - if (cent->isATST) { goto doEssentialThree; diff --git a/CODE-mp/cgame/cg_playerstate.c b/CODE-mp/cgame/cg_playerstate.c index 766a89b..3998a38 100644 --- a/CODE-mp/cgame/cg_playerstate.c +++ b/CODE-mp/cgame/cg_playerstate.c @@ -332,9 +332,14 @@ void CG_CheckLocalSounds( playerState_t *ps, playerState_t *ops ) { } // health changes of more than -3 should make pain sounds - if ( ps->stats[STAT_HEALTH] < (ops->stats[STAT_HEALTH] - 3)) { - if ( ps->stats[STAT_HEALTH] > 0 ) { - CG_PainEvent( &cg.predictedPlayerEntity, ps->stats[STAT_HEALTH] ); + if (cg_oldPainSounds.integer) + { + if ( ps->stats[STAT_HEALTH] < (ops->stats[STAT_HEALTH] - 3)) + { + if ( ps->stats[STAT_HEALTH] > 0 ) + { + CG_PainEvent( &cg.predictedPlayerEntity, ps->stats[STAT_HEALTH] ); + } } } diff --git a/CODE-mp/cgame/cg_scoreboard.c b/CODE-mp/cgame/cg_scoreboard.c index 5224d11..a90da7c 100644 --- a/CODE-mp/cgame/cg_scoreboard.c +++ b/CODE-mp/cgame/cg_scoreboard.c @@ -363,7 +363,12 @@ qboolean CG_DrawOldScoreboard( void ) { CG_DrawPic ( SB_SCORELINE_X - 40, y - 5, SB_SCORELINE_WIDTH + 80, 40, trap_R_RegisterShaderNoMip ( "gfx/menus/menu_buttonback.tga" ) ); - CG_Text_Paint ( SB_NAME_X, y, 1.0f, colorWhite, "Name", 0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_MEDIUM ); + // "NAME", "SCORE", "PING", "TIME" weren't localised, GODDAMMIT!!!!!!!! + // + // Unfortunately, since it's so sodding late now and post release I can't enable the localisation code (REM'd) since some of + // the localised strings don't fit - since no-one's ever seen them to notice this. Smegging brilliant. Thanks people. + // + CG_Text_Paint ( SB_NAME_X, y, 1.0f, colorWhite, /*CG_GetStripEdString("MENUS3", "NAME")*/"Name",0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_MEDIUM ); if (cgs.gametype == GT_TOURNAMENT) { char sWL[100]; @@ -373,10 +378,10 @@ qboolean CG_DrawOldScoreboard( void ) { } else { - CG_Text_Paint ( SB_SCORE_X, y, 1.0f, colorWhite, "Score", 0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_MEDIUM ); + CG_Text_Paint ( SB_SCORE_X, y, 1.0f, colorWhite, /*CG_GetStripEdString("MENUS3", "SCORE")*/"Score", 0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_MEDIUM ); } - CG_Text_Paint ( SB_PING_X, y, 1.0f, colorWhite, "Ping", 0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_MEDIUM ); - CG_Text_Paint ( SB_TIME_X, y, 1.0f, colorWhite, "Time", 0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_MEDIUM ); + CG_Text_Paint ( SB_PING_X, y, 1.0f, colorWhite, /*CG_GetStripEdString("MENUS0", "PING")*/"Ping", 0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_MEDIUM ); + CG_Text_Paint ( SB_TIME_X, y, 1.0f, colorWhite, /*CG_GetStripEdString("MENUS3", "TIME")*/"Time", 0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_MEDIUM ); y = SB_TOP; diff --git a/CODE-mp/cgame/cg_servercmds.c b/CODE-mp/cgame/cg_servercmds.c index 87b7c7e..b27b317 100644 --- a/CODE-mp/cgame/cg_servercmds.c +++ b/CODE-mp/cgame/cg_servercmds.c @@ -136,6 +136,10 @@ void CG_ParseServerinfo( void ) { info = CG_ConfigString( CS_SERVERINFO ); cgs.gametype = atoi( Info_ValueForKey( info, "g_gametype" ) ); trap_Cvar_Set("g_gametype", va("%i", cgs.gametype)); + cgs.needpass = atoi( Info_ValueForKey( info, "needpass" ) ); + cgs.jediVmerc = atoi( Info_ValueForKey( info, "g_jediVmerc" ) ); + cgs.wDisable = atoi( Info_ValueForKey( info, "wdisable" ) ); + cgs.fDisable = atoi( Info_ValueForKey( info, "fdisable" ) ); cgs.dmflags = atoi( Info_ValueForKey( info, "dmflags" ) ); cgs.teamflags = atoi( Info_ValueForKey( info, "teamflags" ) ); cgs.fraglimit = atoi( Info_ValueForKey( info, "fraglimit" ) ); @@ -145,6 +149,7 @@ void CG_ParseServerinfo( void ) { cgs.maxclients = atoi( Info_ValueForKey( info, "sv_maxclients" ) ); mapname = Info_ValueForKey( info, "mapname" ); + //rww - You must do this one here, Info_ValueForKey always uses the same memory pointer. trap_Cvar_Set ( "ui_about_mapname", mapname ); diff --git a/CODE-mp/cgame/cg_view.c b/CODE-mp/cgame/cg_view.c index 3286e55..eaa2c95 100644 --- a/CODE-mp/cgame/cg_view.c +++ b/CODE-mp/cgame/cg_view.c @@ -1559,7 +1559,14 @@ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demo if (cg.snap->ps.stats[STAT_HEALTH] > 0 && (cg.predictedPlayerState.weapon == WP_SABER || cg.predictedPlayerState.usingATST || cg.predictedPlayerState.forceHandExtend == HANDEXTEND_KNOCKDOWN || cg.predictedPlayerState.fallingToDeath)) { - cg.renderingThirdPerson = 1; + if (cg_fpls.integer && cg.predictedPlayerState.weapon == WP_SABER) + { //force to first person for fpls + cg.renderingThirdPerson = 0; + } + else + { + cg.renderingThirdPerson = 1; + } } else if (cg.snap->ps.zoomMode) { //always force first person when zoomed diff --git a/CODE-mp/client/cl_console.cpp b/CODE-mp/client/cl_console.cpp index b4c7ebc..e3e24f8 100644 --- a/CODE-mp/client/cl_console.cpp +++ b/CODE-mp/client/cl_console.cpp @@ -349,8 +349,8 @@ void CL_ConsolePrint( char *txt ) { color = ColorIndex(COLOR_WHITE); - while ( (c = *txt) != 0 ) { - if ( Q_IsColorString( txt ) ) { + while ( (c = (unsigned char) *txt) != 0 ) { + if ( Q_IsColorString( (unsigned char*) txt ) ) { color = ColorIndex( *(txt+1) ); txt += 2; continue; diff --git a/CODE-mp/client/cl_parse.cpp b/CODE-mp/client/cl_parse.cpp index 60eafef..0262a26 100644 --- a/CODE-mp/client/cl_parse.cpp +++ b/CODE-mp/client/cl_parse.cpp @@ -477,7 +477,7 @@ void CL_ParseDownload ( msg_t *msg ) { int block; // read the data - block = MSG_ReadShort ( msg ); + block = (unsigned short)MSG_ReadShort ( msg ); if ( !block ) { @@ -493,7 +493,7 @@ void CL_ParseDownload ( msg_t *msg ) { } } - size = MSG_ReadShort ( msg ); + size = (unsigned short)MSG_ReadShort ( msg ); if (size > 0) MSG_ReadData( msg, data, size ); diff --git a/CODE-mp/game/ai_main.c b/CODE-mp/game/ai_main.c index 3af71fc..5048e95 100644 --- a/CODE-mp/game/ai_main.c +++ b/CODE-mp/game/ai_main.c @@ -2198,6 +2198,11 @@ int BotIsAChickenWuss(bot_state_t *bs) return 0; } + if (g_gametype.integer == GT_SINGLE_PLAYER) + { + return 0; + } + if (g_gametype.integer == GT_JEDIMASTER && !bs->cur_ps.isJediMaster) { //Then you may know no fear. //Well, unless he's strong. @@ -3724,7 +3729,15 @@ void GetIdealDestination(bot_state_t *bs) if (tempInt != -1 && TotalTrailDistance(bs->wpCurrent->index, tempInt, bs) != -1) { bs->wpDestination = gWPArray[tempInt]; - bs->wpDestSwitchTime = level.time + Q_irand(1000, 5000); + + if (g_gametype.integer == GT_SINGLE_PLAYER) + { //be more aggressive + bs->wpDestSwitchTime = level.time + Q_irand(300, 1000); + } + else + { + bs->wpDestSwitchTime = level.time + Q_irand(1000, 5000); + } } } } @@ -6439,6 +6452,8 @@ void StandardBotAI(bot_state_t *bs, float thinktime) { if (BotGetWeaponRange(bs) == BWEAPONRANGE_SABER) { + int saberRange = SABER_ATTACK_RANGE; + VectorSubtract(bs->currentEnemy->client->ps.origin, bs->eye, a_fo); vectoangles(a_fo, a_fo); @@ -6478,7 +6493,12 @@ void StandardBotAI(bot_state_t *bs, float thinktime) } } - if (bs->frame_Enemy_Len <= SABER_ATTACK_RANGE) + if (g_gametype.integer == GT_SINGLE_PLAYER) + { + saberRange *= 3; + } + + if (bs->frame_Enemy_Len <= saberRange) { SaberCombatHandling(bs); diff --git a/CODE-mp/game/bg_local.h b/CODE-mp/game/bg_local.h index 804c255..1a63eb7 100644 --- a/CODE-mp/game/bg_local.h +++ b/CODE-mp/game/bg_local.h @@ -101,3 +101,4 @@ void PM_SetAnim(int setAnimParts,int anim,int setAnimFlags, int blendTime); void PM_WeaponLightsaber(void); void PM_SetSaberMove(short newMove); +void PM_SetForceJumpZStart(float value); diff --git a/CODE-mp/game/bg_misc.c b/CODE-mp/game/bg_misc.c index 6dd2d36..5b2c06d 100644 --- a/CODE-mp/game/bg_misc.c +++ b/CODE-mp/game/bg_misc.c @@ -161,12 +161,18 @@ int WeaponAttackAnim[WP_NUM_WEAPONS] = }; -//The magical function to end all functions. -//This will take the force power string in powerOut and parse through it, then legalize -//it based on the supposed rank and spit it into powerOut, returning true if it was legal -//to begin with and false if not. -//fpDisabled is actually only expected (needed) from the server, because the ui disables -//force power selection anyway when force powers are disabled on the server. +/* +================ +BG_LegalizedForcePowers + +The magical function to end all functions. +This will take the force power string in powerOut and parse through it, then legalize +it based on the supposed rank and spit it into powerOut, returning true if it was legal +to begin with and false if not. +fpDisabled is actually only expected (needed) from the server, because the ui disables +force power selection anyway when force powers are disabled on the server. +================ +*/ qboolean BG_LegalizedForcePowers(char *powerOut, int maxRank, qboolean freeSaber, int teamForce, int gametype, int fpDisabled) { char powerBuf[128]; @@ -254,7 +260,6 @@ qboolean BG_LegalizedForcePowers(char *powerOut, int maxRank, qboolean freeSaber { final_Powers[i] = 0; //This is only likely to happen with g_forceBasedTeams. Let it slide. - //maintainsValidity = 0; } if ( final_Powers[i] && @@ -410,16 +415,16 @@ qboolean BG_LegalizedForcePowers(char *powerOut, int maxRank, qboolean freeSaber final_Powers[FP_LEVITATION] = 1; } - /* - if (fpDisabled) + i = 0; + while (i < NUM_FORCE_POWERS) { - final_Powers[FP_LEVITATION] = 1; - final_Powers[FP_SABERATTACK] = 3; - final_Powers[FP_SABERDEFEND] = 3; - final_Powers[FP_SABERTHROW] = 0; + if (final_Powers[i] > FORCE_LEVEL_3) + { + final_Powers[i] = FORCE_LEVEL_3; + } + i++; } - */ - //Ahh. I have no idea why I did this, but I would say that it makes me a very bad man. + if (fpDisabled) { //If we specifically have attack or def disabled, force them up to level 3. It's the way //things work for the case of all powers disabled. @@ -1303,7 +1308,7 @@ qboolean BG_CanUseFPNow(int gametype, playerState_t *ps, int time, forcePowers_t if (ps->duelInProgress) { - if (power != FP_SABERATTACK && power != FP_SABERDEFEND && power != FP_SABERTHROW && + if (power != FP_SABERATTACK && power != FP_SABERDEFEND && /*power != FP_SABERTHROW &&*/ power != FP_LEVITATION) { if (!ps->saberLockFrame || power != FP_PUSH) @@ -1466,68 +1471,68 @@ void BG_CycleForce(playerState_t *ps, int direction) presel = x; if (direction == 1) - { + { //get the next power x++; } else - { + { //get the previous power x--; } if (x >= NUM_FORCE_POWERS) - { + { //cycled off the end.. cycle around to the first x = 0; } if (x < 0) - { + { //cycled off the beginning.. cycle around to the last x = NUM_FORCE_POWERS-1; } - i = forcePowerSorted[x]; + i = forcePowerSorted[x]; //the "sorted" value of this power while (x != presel) - { + { //loop around to the current force power if (ps->fd.forcePowersKnown & (1 << i) && i != ps->fd.forcePowerSelected) - { + { //we have the force power if (i != FP_LEVITATION && i != FP_SABERATTACK && i != FP_SABERDEFEND && i != FP_SABERTHROW) - { + { //it's selectable foundnext = i; break; } } if (direction == 1) - { + { //next x++; } else - { + { //previous x--; } if (x >= NUM_FORCE_POWERS) - { + { //loop around x = 0; } if (x < 0) - { + { //loop around x = NUM_FORCE_POWERS-1; } - i = forcePowerSorted[x]; + i = forcePowerSorted[x]; //set to the sorted value again } if (foundnext != -1) - { + { //found one, select it ps->fd.forcePowerSelected = foundnext; } } int BG_GetItemIndexByTag(int tag, int type) -{ +{ //Get the itemlist index from the tag and type int i = 0; while (i < bg_numItems) @@ -1553,37 +1558,37 @@ void BG_CycleInven(playerState_t *ps, int direction) original = i; if (direction == 1) - { + { //next i++; } else - { + { //previous i--; } while (i != original) { //go in a full loop until hitting something, if hit nothing then select nothing if (ps->stats[STAT_HOLDABLE_ITEMS] & (1 << i)) - { + { //we have it, select it. ps->stats[STAT_HOLDABLE_ITEM] = BG_GetItemIndexByTag(i, IT_HOLDABLE); break; } if (direction == 1) - { + { //next i++; } else - { + { //previous i--; } if (i < 0) - { + { //wrap around to the last i = HI_NUM_HOLDABLE; } else if (i >= HI_NUM_HOLDABLE) - { + { //wrap around to the first i = 0; } } @@ -2039,7 +2044,6 @@ void BG_TouchJumpPad( playerState_t *ps, entityState_t *jumppad ) { } else { effectNum = 1; } - //BG_AddPredictableEventToPlayerstate( EV_JUMP_PAD, effectNum, ps ); } // remember hitting this jumppad this frame ps->jumppad_ent = jumppad->number; @@ -2333,179 +2337,6 @@ PLAYER ANGLES ============================================================================= */ - -/* -================== -BG_SwingAngles -================== -*/ -static void BG_SwingAngles( float destination, float swingTolerance, float clampTolerance, - float speed, float *angle, qboolean *swinging, int frameTime ) { - float swing; - float move; - float scale; - - if ( !*swinging ) { - // see if a swing should be started - swing = AngleSubtract( *angle, destination ); - if ( swing > swingTolerance || swing < -swingTolerance ) { - *swinging = qtrue; - } - } - - if ( !*swinging ) { - return; - } - - // modify the speed depending on the delta - // so it doesn't seem so linear - swing = AngleSubtract( destination, *angle ); - scale = fabs( swing ); - if ( scale < swingTolerance * 0.5 ) { - scale = 0.5; - } else if ( scale < swingTolerance ) { - scale = 1.0; - } else { - scale = 2.0; - } - - // swing towards the destination angle - if ( swing >= 0 ) { - move = frameTime * scale * speed; - if ( move >= swing ) { - move = swing; - *swinging = qfalse; - } - *angle = AngleMod( *angle + move ); - } else if ( swing < 0 ) { - move = frameTime * scale * -speed; - if ( move <= swing ) { - move = swing; - *swinging = qfalse; - } - *angle = AngleMod( *angle + move ); - } - - // clamp to no more than tolerance - swing = AngleSubtract( destination, *angle ); - if ( swing > clampTolerance ) { - *angle = AngleMod( destination - (clampTolerance - 1) ); - } else if ( swing < -clampTolerance ) { - *angle = AngleMod( destination + (clampTolerance - 1) ); - } -} - -/* -================= -CG_AddPainTwitch -================= -*/ -#define PAIN_TWITCH_TIME 200 -static void BG_AddPainTwitch( int painTime, int painDirection, int currentTime, vec3_t torsoAngles ) { - int t; - float f; - - t = currentTime - painTime; - if ( t >= PAIN_TWITCH_TIME ) { - return; - } - - f = 1.0 - (float)t / PAIN_TWITCH_TIME; - - if ( painDirection ) { - torsoAngles[ROLL] += 20 * f; - } else { - torsoAngles[ROLL] -= 20 * f; - } -} - -void BG_G2PlayerAngles( vec3_t startAngles, vec3_t legs[3], vec3_t legsAngles, int painTime, int painDirection, int currentTime, - qboolean *torso_yawing, float *torso_yawAngle, qboolean *torso_pitching, float *torso_pitchAngle, qboolean *legs_yawing, float *legs_yawAngle, - int frameTime, vec3_t velocity, int legsAnim, int torsoAnim, qboolean dead, float movementDir, void *ghoul2, qhandle_t *modelList, int weapon){ - vec3_t torsoAngles, headAngles; - float dest; - static int movementOffsets[8] = { 0, 22, 45, -22, 0, 22, -45, -22 }; - float speed; - int dir; - - VectorCopy( startAngles, headAngles ); - headAngles[YAW] = AngleMod( headAngles[YAW] ); - VectorClear( legsAngles ); - VectorClear( torsoAngles ); - - // --------- yaw ------------- - - // allow yaw to drift a bit - if ( ( legsAnim & ~ANIM_TOGGLEBIT ) != WeaponReadyAnim[weapon] - || ( torsoAnim & ~ANIM_TOGGLEBIT ) != WeaponReadyAnim[weapon] ) { - // if not standing still, always point all in the same direction - *torso_yawing = qtrue; // always center - *torso_pitching = qtrue; // always center - *legs_yawing = qtrue; // always center - } - - // adjust legs for movement dir - if (dead ) { - // don't let dead bodies twitch - dir = 0; - } else { - dir = movementDir; -// if ( dir < 0 || dir > 7 ) { -// CG_Error( "Bad player movement angle" ); -// } - } - legsAngles[YAW] = headAngles[YAW] + movementOffsets[ dir ]; - torsoAngles[YAW] = headAngles[YAW] + 0.25 * movementOffsets[ dir ]; - - // torso - BG_SwingAngles( torsoAngles[YAW], 25, 90, /*cg_swingSpeed.value*/ 0.3, torso_yawAngle, torso_yawing, frameTime ); - BG_SwingAngles( legsAngles[YAW], 40, 90, /*cg_swingSpeed.value*/ 0.3, legs_yawAngle, legs_yawing, frameTime ); - - torsoAngles[YAW] = *torso_yawAngle; - legsAngles[YAW] = *legs_yawAngle; - - // --------- pitch ------------- - - // only show a fraction of the pitch angle in the torso - if ( headAngles[PITCH] > 180 ) { - dest = (-360 + headAngles[PITCH]) * 0.75; - } else { - dest = headAngles[PITCH] * 0.75; - } - BG_SwingAngles( dest, 15, 30, 0.1, torso_pitchAngle, torso_pitching, frameTime ); - torsoAngles[PITCH] = *torso_pitchAngle; - - // --------- roll ------------- - - // lean towards the direction of travel - speed = VectorNormalize( velocity ); - if ( speed ) { - vec3_t axis[3]; - float side; - - speed *= 0.05; - - AnglesToAxis( legsAngles, axis ); - side = speed * DotProduct( velocity, axis[1] ); - legsAngles[ROLL] -= side; - - side = speed * DotProduct( velocity, axis[0] ); - legsAngles[PITCH] += side; - } - - // pain twitch - BG_AddPainTwitch( painTime, painDirection, currentTime, torsoAngles ); - - // pull the angles back out of the hierarchial chain - AnglesSubtract( headAngles, torsoAngles, headAngles ); - AnglesSubtract( torsoAngles, legsAngles, torsoAngles ); - AnglesToAxis( legsAngles, legs ); - // we assume that model 0 is the player model. -//g2r trap_G2API_SetBoneAngles(ghoul2, 0, "upper_lumbar", torsoAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, modelList, 0, currentTime); -//g2r trap_G2API_SetBoneAngles(ghoul2, 0, "cranium", headAngles, BONE_ANGLES_POSTMULT, POSITIVE_Z, NEGATIVE_Y, POSITIVE_X, modelList,0, currentTime); - -} - #define MAX_POOL_SIZE 2048000 //1024000 static char bg_pool[MAX_POOL_SIZE]; diff --git a/CODE-mp/game/bg_panimate.c b/CODE-mp/game/bg_panimate.c index 4f2e4a8..c15dcf8 100644 --- a/CODE-mp/game/bg_panimate.c +++ b/CODE-mp/game/bg_panimate.c @@ -1077,15 +1077,13 @@ void PM_SetAnimFinal(int setAnimParts,int anim,int setAnimFlags, PM_StartTorsoAnim( anim ); if (setAnimFlags & SETANIM_FLAG_HOLD) - {//FIXME: allow to set a specific time? + { if (setAnimFlags & SETANIM_FLAG_HOLDLESS) { // Make sure to only wait in full 1/20 sec server frame intervals. int dur; int speedDif; dur = (animations[anim].numFrames-1) * fabs(animations[anim].frameLerp); - //dur = ((int)(dur/50.0)) * 50 / timeScaleMod; - //dur -= blendTime+fabs(animations[anim].frameLerp)*2; speedDif = dur - (dur * editAnimSpeed); dur += speedDif; if (dur > 1) @@ -1127,15 +1125,13 @@ setAnimLegs: PM_StartLegsAnim(anim); if (setAnimFlags & SETANIM_FLAG_HOLD) - {//FIXME: allow to set a specific time? + { if (setAnimFlags & SETANIM_FLAG_HOLDLESS) { // Make sure to only wait in full 1/20 sec server frame intervals. int dur; int speedDif; dur = (animations[anim].numFrames-1) * fabs(animations[anim].frameLerp); - //dur = ((int)(dur/50.0)) * 50 / timeScaleMod; - //dur -= blendTime+fabs(animations[anim].frameLerp)*2; speedDif = dur - (dur * editAnimSpeed); dur += speedDif; if (dur > 1) @@ -1152,11 +1148,6 @@ setAnimLegs: pm->ps->legsTimer = ((animations[anim].numFrames ) * fabs(animations[anim].frameLerp)); } - /* - PM_DebugLegsAnim(anim); - Com_Printf("%i\n", pm->ps->legsTimer); - */ - if (pm->ps->fd.forcePowersActive & (1 << FP_RAGE)) { pm->ps->legsTimer /= 1.3; @@ -1186,8 +1177,7 @@ void PM_SetAnim(int setAnimParts,int anim,int setAnimFlags, int blendTime) } if (BG_InRoll(pm->ps, pm->ps->legsAnim)) - { - //setAnimFlags |= SETANIM_FLAG_RESTART; + { //never interrupt a roll return; } diff --git a/CODE-mp/game/bg_pmove.c b/CODE-mp/game/bg_pmove.c index 0cf7ecc..3e7eda8 100644 --- a/CODE-mp/game/bg_pmove.c +++ b/CODE-mp/game/bg_pmove.c @@ -467,7 +467,7 @@ qboolean PM_ForceJumpingUp(void) } if ( pm->ps->groundEntityNum == ENTITYNUM_NONE && //in air - (pm->ps->pm_flags & PMF_JUMP_HELD) &&//forceJumpZStart && //jumped + (pm->ps->pm_flags & PMF_JUMP_HELD) && //jumped pm->ps->fd.forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_0 && //force-jump capable pm->ps->velocity[2] > 0 )//going up { @@ -506,7 +506,7 @@ static void PM_JumpForDir( void ) } if(!BG_InDeathAnim(pm->ps->legsAnim)) { - PM_SetAnim(SETANIM_LEGS,anim,SETANIM_FLAG_OVERRIDE, 100); // Only blend over 100ms + PM_SetAnim(SETANIM_LEGS,anim,SETANIM_FLAG_OVERRIDE, 100); } } @@ -514,14 +514,13 @@ void PM_SetPMViewAngle(playerState_t *ps, vec3_t angle, usercmd_t *ucmd) { int i; - // set the delta angle - for (i=0 ; i<3 ; i++) { + for (i=0 ; i<3 ; i++) + { // set the delta angle int cmdAngle; cmdAngle = ANGLE2SHORT(angle[i]); ps->delta_angles[i] = cmdAngle - ucmd->angles[i]; } - //VectorCopy( angle, ent->s.angles ); VectorCopy (angle, ps->viewangles); } @@ -555,8 +554,6 @@ qboolean PM_AdjustAngleForWallRun( playerState_t *ps, usercmd_t *ucmd, qboolean if ( trace.fraction < 1.0f ) {//still a wall there - //FIXME: don't pull around 90 turns - //FIXME: simulate stepping up steps here, somehow? if ( (ps->legsAnim&~ANIM_TOGGLEBIT) == BOTH_WALL_RUN_RIGHT ) { ucmd->rightmove = 127; @@ -572,7 +569,6 @@ qboolean PM_AdjustAngleForWallRun( playerState_t *ps, usercmd_t *ucmd, qboolean //make me face perpendicular to the wall ps->viewangles[YAW] = vectoyaw( trace.plane.normal )+yawAdjust; - //SetClientViewAngle( ent, ent->client->ps.viewangles ); PM_SetPMViewAngle(ps, ps->viewangles, ucmd); ucmd->angles[YAW] = ANGLE2SHORT( ps->viewangles[YAW] ) - ps->delta_angles[YAW]; @@ -587,7 +583,7 @@ qboolean PM_AdjustAngleForWallRun( playerState_t *ps, usercmd_t *ucmd, qboolean fwdAngles[YAW] = ps->viewangles[YAW]; AngleVectors( fwdAngles, fwd, NULL, NULL ); - //FIXME: or MA? + if ( ucmd->forwardmove < 0 ) {//slower speed = 100; @@ -621,12 +617,21 @@ qboolean PM_AdjustAngleForWallRun( playerState_t *ps, usercmd_t *ucmd, qboolean return qfalse; } +//Set the height for when a force jump was started. If it's 0, nuge it up (slight hack to prevent holding jump over slopes) +void PM_SetForceJumpZStart(float value) +{ + pm->ps->fd.forceJumpZStart = value; + if (!pm->ps->fd.forceJumpZStart) + { + pm->ps->fd.forceJumpZStart -= 0.1; + } +} + /* ============= PM_CheckJump ============= */ - static qboolean PM_CheckJump( void ) { if (pm->ps->usingATST) @@ -653,15 +658,9 @@ static qboolean PM_CheckJump( void ) { pm->ps->fd.forcePowersActive &= ~(1<cmd.buttons & BUTTON_FORCEJUMP ) - { - pm->ps->pm_flags |= PMF_JUMP_HELD; - } - */ if (pm->ps->fd.forcePowersActive & (1 << FP_LEVITATION)) - { + { //Force jump is already active.. continue draining power appropriately until we land. if (pm->ps->fd.forcePowerDebounce[FP_LEVITATION] < pm->cmd.serverTime) { BG_ForcePowerDrain( pm->ps, FP_LEVITATION, 5 ); @@ -677,7 +676,7 @@ static qboolean PM_CheckJump( void ) } if (pm->ps->forceJumpFlip) - { + { //Forced jump anim int anim = BOTH_FORCEINAIR1; int parts = SETANIM_BOTH; @@ -711,18 +710,15 @@ static qboolean PM_CheckJump( void ) { if ( pm->ps->gravity > 0 ) {//can't do this in zero-G - //FIXME: still able to pogo-jump... if ( PM_ForceJumpingUp() ) {//holding jump in air float curHeight = pm->ps->origin[2] - pm->ps->fd.forceJumpZStart; //check for max force jump level and cap off & cut z vel if ( ( curHeight<=forceJumpHeight[0] ||//still below minimum jump height (pm->ps->fd.forcePower&&pm->cmd.upmove>=10) ) &&////still have force power available and still trying to jump up - curHeight < forceJumpHeight[pm->ps->fd.forcePowerLevel[FP_LEVITATION]] )//still below maximum jump height + curHeight < forceJumpHeight[pm->ps->fd.forcePowerLevel[FP_LEVITATION]] && + pm->ps->fd.forceJumpZStart)//still below maximum jump height {//can still go up - //FIXME: after a certain amount of time of held jump, play force jump sound and flip if a dir is being held - //FIXME: if hit a wall... should we cut velocity or allow them to slide up it? - //FIXME: constantly drain force power at a rate by which the usage for maximum height would use up the full cost of force jump if ( curHeight > forceJumpHeight[0] ) {//passed normal jump height *2? if ( !(pm->ps->fd.forcePowersActive&(1<ps->fd.forcePowersActive |= (1<ps->fd.forceJumpSound = 1; //play flip - //FIXME: do this only when they stop the jump (below) or when they're just about to hit the peak of the jump if ((pm->cmd.forwardmove || pm->cmd.rightmove) && //pushing in a dir (pm->ps->legsAnim&~ANIM_TOGGLEBIT) != BOTH_FLIP_F &&//not already flipping (pm->ps->legsAnim&~ANIM_TOGGLEBIT) != BOTH_FLIP_B && (pm->ps->legsAnim&~ANIM_TOGGLEBIT) != BOTH_FLIP_R && (pm->ps->legsAnim&~ANIM_TOGGLEBIT) != BOTH_FLIP_L ) - {//FIXME: this could end up playing twice if the jump is very long... + { int anim = BOTH_FORCEINAIR1; int parts = SETANIM_BOTH; @@ -758,15 +753,15 @@ static qboolean PM_CheckJump( void ) anim = BOTH_FLIP_L; } if ( pm->ps->weaponTime ) - {//FIXME: really only care if we're in a saber attack anim... + { parts = SETANIM_LEGS; } PM_SetAnim( parts, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 150 ); } else if ( pm->ps->fd.forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 ) - {//FIXME: really want to know how far off ground we are, probably... - vec3_t facingFwd, facingRight, facingAngles;// = {0, pm->ps->viewangles[YAW], 0}; + { + vec3_t facingFwd, facingRight, facingAngles; int anim = -1; float dotR, dotF; @@ -811,7 +806,7 @@ static qboolean PM_CheckJump( void ) } } else - { + { //jump is already active (the anim has started) if ( pm->ps->legsTimer < 1 ) {//not in the middle of a legsAnim int anim = (pm->ps->legsAnim&~ANIM_TOGGLEBIT); @@ -835,7 +830,7 @@ static qboolean PM_CheckJump( void ) { int parts = SETANIM_BOTH; if ( pm->ps->weaponTime ) - {//FIXME: really only care if we're in a saber attack anim... + { parts = SETANIM_LEGS; } @@ -871,16 +866,6 @@ static qboolean PM_CheckJump( void ) pm->cmd.upmove = 0; return qfalse; } - /* - else if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) - { - int legsAnim = (pm->ps->legsAnim&~ANIM_TOGGLEBIT); - if ( legsAnim != BOTH_WALL_RUN_LEFT && legsAnim != BOTH_WALL_RUN_RIGHT ) - {//special case.. these let you jump off a wall - return qfalse; - } - } - */ } } @@ -911,19 +896,16 @@ static qboolean PM_CheckJump( void ) if ( trace.fraction <= 1.0f ) { VectorMA( pm->ps->velocity, JUMP_VELOCITY*2, forward, pm->ps->velocity ); - //FIXME: kicking off wall anim? At least check what anim we're in? PM_SetAnim(SETANIM_LEGS,BOTH_FORCEJUMP1,SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD|SETANIM_FLAG_RESTART, 150); }//else no surf close enough to push off of pm->cmd.upmove = 0; } else if ( pm->cmd.upmove > 0 && pm->waterlevel < 2 && pm->ps->fd.forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_0 && - !(pm->ps->pm_flags&PMF_JUMP_HELD) /*&& - WP_ForcePowerAvailable( pm->gent, FP_LEVITATION, 0 ) */ && + !(pm->ps->pm_flags&PMF_JUMP_HELD) && pm->ps->weapon == WP_SABER && !BG_HasYsalamiri(pm->gametype, pm->ps) && - BG_CanUseFPNow(pm->gametype, pm->ps, pm->cmd.serverTime, FP_LEVITATION) - ) + BG_CanUseFPNow(pm->gametype, pm->ps, pm->cmd.serverTime, FP_LEVITATION) ) { if ( pm->ps->groundEntityNum != ENTITYNUM_NONE ) {//on the ground @@ -956,39 +938,21 @@ static qboolean PM_CheckJump( void ) anim = BOTH_WALL_FLIP_LEFT; } } - /* - else if ( pm->cmd.forwardmove > 0 && pm->ps->fd.forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 ) - {//run up wall, flip backwards - vertPush = forceJumpStrength[FORCE_LEVEL_2]/2.25f; - anim = BOTH_WALL_FLIP_BACK1; - } - */ else if ( pm->cmd.forwardmove < 0 && !(pm->cmd.buttons&BUTTON_ATTACK) ) {//backflip vertPush = JUMP_VELOCITY; anim = BOTH_FLIP_BACK1;//PM_PickAnim( BOTH_FLIP_BACK1, BOTH_FLIP_BACK3 ); } - /* - else if ( VectorLengthSquared( pm->ps->velocity ) < 256 ) - {//not moving - if ( pm->ps->weapon == WP_SABER && (pm->cmd.buttons & BUTTON_ATTACK) && pm->ps->fd.saberAnimLevel == FORCE_LEVEL_2 ) - {//butterfly... FIXME: does direction matter? - vertPush = JUMP_VELOCITY; - anim = BOTH_BUTTERFLY_LEFT; - } - } - */ - //FIXME: Do we want special moves in MP? - vertPush += 128; //is gravity different in SP or something? + vertPush += 128; //give them an extra shove - if ( anim != -1 /*&& PM_HasAnimation( pm->gent, anim )*/ ) + if ( anim != -1 ) { vec3_t fwd, right, traceto, mins, maxs, fwdAngles; vec3_t idealNormal; trace_t trace; qboolean doTrace = qfalse; - int contents = /*CONTENTS_SOLID*/MASK_PLAYERSOLID; + int contents = MASK_PLAYERSOLID; VectorSet(mins, pm->mins[0],pm->mins[1],0); VectorSet(maxs, pm->maxs[0],pm->maxs[1],24); @@ -1002,7 +966,6 @@ static qboolean PM_CheckJump( void ) switch ( anim ) { case BOTH_WALL_FLIP_LEFT: - //contents |= CONTENTS_BODY; //NOTE: purposely falls through to next case! case BOTH_WALL_RUN_LEFT: doTrace = qtrue; @@ -1010,7 +973,6 @@ static qboolean PM_CheckJump( void ) break; case BOTH_WALL_FLIP_RIGHT: - //contents |= CONTENTS_BODY; //NOTE: purposely falls through to next case! case BOTH_WALL_RUN_RIGHT: doTrace = qtrue; @@ -1018,7 +980,6 @@ static qboolean PM_CheckJump( void ) break; case BOTH_WALL_FLIP_BACK1: - //contents |= CONTENTS_BODY; doTrace = qtrue; VectorMA( pm->ps->origin, 16, fwd, traceto ); break; @@ -1030,11 +991,9 @@ static qboolean PM_CheckJump( void ) VectorSubtract( pm->ps->origin, traceto, idealNormal ); VectorNormalize( idealNormal ); } - // gentity_t *traceEnt = &g_entities[trace.entityNum]; - - //if ( !doTrace || (trace.fraction < 1.0f&&((trace.entityNums.solid!=SOLID_BMODEL)||DotProduct(trace.plane.normal,idealNormal)>0.7)) ) + if ( !doTrace || (trace.fraction < 1.0f && (trace.entityNum < MAX_CLIENTS || DotProduct(trace.plane.normal,idealNormal) > 0.7)) ) - {//there is a wall there + {//there is a wall there.. or hit a client int parts; //move me to side if ( anim == BOTH_WALL_FLIP_LEFT ) @@ -1055,26 +1014,7 @@ static qboolean PM_CheckJump( void ) pm->ps->velocity[0] = pm->ps->velocity[1] = 0; VectorMA( pm->ps->velocity, -150, fwd, pm->ps->velocity ); } - //kick if jumping off an ent - /* - if ( doTrace && anim != BOTH_WALL_RUN_LEFT && anim != BOTH_WALL_RUN_RIGHT ) - { - if ( pm->gent && trace.entityNum < ENTITYNUM_WORLD ) - { - if ( traceEnt && traceEnt->client && traceEnt->health && traceEnt->takedamage ) - {//push them away and do pain - vec3_t oppDir; - float strength = VectorNormalize2( pm->ps->velocity, oppDir ); - VectorScale( oppDir, -1, oppDir ); - //FIXME: need knockdown anim - G_Damage( traceEnt, pm->gent, pm->gent, oppDir, traceEnt->currentOrigin, 10, DAMAGE_NO_ARMOR|DAMAGE_NO_HIT_LOC|DAMAGE_NO_KNOCKBACK, MOD_MELEE ); - NPC_SetAnim( traceEnt, SETANIM_BOTH, BOTH_KNOCKDOWN1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); - G_Throw( traceEnt, oppDir, strength ); - G_Sound( traceEnt, G_SoundIndex( va("sound/weapons/melee/punch%d", Q_irand(1, 4)) ) ); - } - } - } - */ + if ( doTrace && anim != BOTH_WALL_RUN_LEFT && anim != BOTH_WALL_RUN_RIGHT ) { if (trace.entityNum < MAX_CLIENTS) @@ -1083,8 +1023,6 @@ static qboolean PM_CheckJump( void ) } } - //FIXMEFIXME - //up if ( vertPush ) { @@ -1108,10 +1046,9 @@ static qboolean PM_CheckJump( void ) { pm->ps->weaponTime = pm->ps->torsoTimer; } - pm->ps->fd.forceJumpZStart = pm->ps->origin[2];//so we don't take damage if we land at same height - pm->ps->pm_flags |= PMF_JUMP_HELD;//PMF_JUMPING|PMF_SLOW_MO_FALL; + PM_SetForceJumpZStart(pm->ps->origin[2]);//so we don't take damage if we land at same height + pm->ps->pm_flags |= PMF_JUMP_HELD; pm->cmd.upmove = 0; - //WP_ForcePowerDrain( pm->gent, FP_LEVITATION, 0 ); pm->ps->fd.forceJumpSound = 1; } } @@ -1180,8 +1117,6 @@ static qboolean PM_CheckJump( void ) parts = SETANIM_BOTH; } PM_SetAnim( parts, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 0 ); - //FIXME: do damage to traceEnt, like above? - //pm->ps->pm_flags |= PMF_JUMPING|PMF_SLOW_MO_FALL; pm->cmd.upmove = 0; } } @@ -1193,10 +1128,9 @@ static qboolean PM_CheckJump( void ) else if ( pm->cmd.forwardmove > 0 //pushing forward && pm->ps->fd.forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 && pm->ps->velocity[2] > 200 - && /*(level.time - pm->ps->lastOnGround) <= 500*/ PM_GroundDistance() <= 80 //unfortunately we do not have a happy ground timer. + && PM_GroundDistance() <= 80 //unfortunately we do not have a happy ground timer like SP (this would use up more bandwidth if we wanted prediction workign right), so we'll just use the actual ground distance. && !BG_InSpecialJump(pm->ps->legsAnim)) {//run up wall, flip backwards - //FIXME: have to be moving... make sure it's opposite the wall... or at least forward? vec3_t fwd, traceto, mins, maxs, fwdAngles; trace_t trace; vec3_t idealNormal; @@ -1229,10 +1163,8 @@ static qboolean PM_CheckJump( void ) pm->ps->legsTimer -= 600; //I force this anim to play to the end to prevent landing on your head and suddenly flipping over. //It is a bit too long at the end though, so I'll just shorten it. - pm->ps->fd.forceJumpZStart = pm->ps->origin[2];//so we don't take damage if we land at same height - //pm->ps->pm_flags |= PMF_JUMPING|PMF_SLOW_MO_FALL; + PM_SetForceJumpZStart(pm->ps->origin[2]);//so we don't take damage if we land at same height pm->cmd.upmove = 0; - //G_SoundOnEnt( pm->gent, CHAN_BODY, "sound/weapons/force/jump.wav" ); pm->ps->fd.forceJumpSound = 1; BG_ForcePowerDrain( pm->ps, FP_LEVITATION, 5 ); @@ -1242,10 +1174,6 @@ static qboolean PM_CheckJump( void ) } } } - else - { - //FIXME: if in a butterfly, kick people away? - } } } @@ -1259,8 +1187,7 @@ static qboolean PM_CheckJump( void ) && !BG_FlippingAnim( pm->ps->legsAnim ) && !PM_SpinningAnim( pm->ps->legsAnim ) && !BG_SaberInSpecialAttack( pm->ps->torsoAnim ) - && ( BG_SaberInAttack( pm->ps->saberMove ) ) - /*&& PM_InAnimForSaberMove( pm->ps->torsoAnim, pm->ps->saberMove )*/ ) + && ( BG_SaberInAttack( pm->ps->saberMove ) ) ) {//not in an anim we shouldn't interrupt //see if it's not too late to start a special jump-attack float animLength = PM_AnimLength( 0, (animNumber_t)pm->ps->torsoAnim ); @@ -1269,8 +1196,7 @@ static qboolean PM_CheckJump( void ) //check for special-case jump attacks if ( pm->ps->fd.saberAnimLevel == FORCE_LEVEL_2 ) {//using medium attacks - if (/*pm->ps->velocity[2] > 100 &&*/ - PM_GroundDistance() < 32 && + if (PM_GroundDistance() < 32 && !BG_InSpecialJump(pm->ps->legsAnim)) { //FLIP AND DOWNWARD ATTACK trace_t tr; @@ -1314,17 +1240,9 @@ static qboolean PM_CheckJump( void ) } if ( pm->cmd.upmove > 0 ) {//no special jumps - /* - gentity_t *groundEnt = &g_entities[pm->ps->groundEntityNum]; - if ( groundEnt && groundEnt->NPC ) - {//Can't jump off of someone's head - return qfalse; - } - */ - pm->ps->velocity[2] = JUMP_VELOCITY; - pm->ps->fd.forceJumpZStart = pm->ps->origin[2];//so we don't take damage if we land at same height - pm->ps->pm_flags |= PMF_JUMP_HELD;//PMF_JUMPING; + PM_SetForceJumpZStart(pm->ps->origin[2]);//so we don't take damage if we land at same height + pm->ps->pm_flags |= PMF_JUMP_HELD; } //Jumping @@ -1332,7 +1250,7 @@ static qboolean PM_CheckJump( void ) pml.walking = qfalse; pm->ps->pm_flags |= PMF_JUMP_HELD; pm->ps->groundEntityNum = ENTITYNUM_NONE; - pm->ps->fd.forceJumpZStart = pm->ps->origin[2]; + PM_SetForceJumpZStart(pm->ps->origin[2]); PM_AddEvent( EV_JUMP ); @@ -1696,7 +1614,6 @@ static void PM_WalkMove( void ) { wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove; } // when going up or down slopes the wish velocity should Not be zero -// wishvel[2] = 0; VectorCopy (wishvel, wishdir); wishspeed = VectorNormalize(wishdir); @@ -1740,11 +1657,9 @@ static void PM_WalkMove( void ) { //Com_Printf("velocity = %1.1f %1.1f %1.1f\n", pm->ps->velocity[0], pm->ps->velocity[1], pm->ps->velocity[2]); //Com_Printf("velocity1 = %1.1f\n", VectorLength(pm->ps->velocity)); - if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) { + if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) + { pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime; - } else { - // don't reset the z velocity for slopes -// pm->ps->velocity[2] = 0; } vel = VectorLength(pm->ps->velocity); @@ -1766,7 +1681,6 @@ static void PM_WalkMove( void ) { PM_StepSlideMove( qfalse ); //Com_Printf("velocity2 = %1.1f\n", VectorLength(pm->ps->velocity)); - } @@ -1870,11 +1784,14 @@ PM_FootstepForSurface Returns an event number apropriate for the groundsurface ================ */ -static int PM_FootstepForSurface( void ) { - if ( pml.groundTrace.surfaceFlags & SURF_NOSTEPS ) { +static int PM_FootstepForSurface( void ) +{ + if ( pml.groundTrace.surfaceFlags & SURF_NOSTEPS ) + { return 0; } - if ( pml.groundTrace.surfaceFlags & SURF_METALSTEPS ) { + if ( pml.groundTrace.surfaceFlags & SURF_METALSTEPS ) + { return EV_FOOTSTEP_METAL; } return EV_FOOTSTEP; @@ -1895,22 +1812,19 @@ static int PM_TryRoll( void ) if (pm->ps->weapon != WP_SABER || BG_HasYsalamiri(pm->gametype, pm->ps) || !BG_CanUseFPNow(pm->gametype, pm->ps, pm->cmd.serverTime, FP_LEVITATION)) - { + { //Not using saber, or can't use jump return 0; } - //VectorSet(mins, pm->mins[0],pm->mins[1],pm->mins[2]+STEPSIZE); - //VectorSet(maxs, pm->maxs[0],pm->maxs[1],pm->gent->client->crouchheight); - VectorSet(mins, pm->mins[0],pm->mins[1],pm->mins[2]+STEPSIZE); VectorSet(maxs, pm->maxs[0],pm->maxs[1],CROUCH_MAXS_2); VectorSet(fwdAngles, 0, pm->ps->viewangles[YAW], 0); AngleVectors( fwdAngles, fwd, right, NULL ); - //FIXME: trace ahead for clearance to roll + if ( pm->cmd.forwardmove ) - { + { //check forward/backward rolls if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) { anim = BOTH_ROLL_B; @@ -1923,25 +1837,21 @@ static int PM_TryRoll( void ) } } else if ( pm->cmd.rightmove > 0 ) - { + { //right anim = BOTH_ROLL_R; VectorMA( pm->ps->origin, 64, right, traceto ); } else if ( pm->cmd.rightmove < 0 ) - { + { //left anim = BOTH_ROLL_L; VectorMA( pm->ps->origin, -64, right, traceto ); } - else - {//??? - } + if ( anim != -1 ) - { + { //We want to roll. Perform a trace to see if we can, and if so, send us into one. pm->trace( &trace, pm->ps->origin, mins, maxs, traceto, pm->ps->clientNum, CONTENTS_SOLID ); if ( trace.fraction >= 1.0f ) { - //PM_AddEvent( EV_ROLL ); - //Done later.. pm->ps->saberMove = LS_NONE; return anim; } @@ -2001,14 +1911,9 @@ static void PM_CrashLand( void ) { } } - /* - if (pm->ps->forceHandExtend == HANDEXTEND_NONE) - { - pm->ps->forceHandExtend = HANDEXTEND_WEAPONREADY; - } - */ if (pm->ps->weapon != WP_SABER) { //saber handles its own anims + //This will push us back into our weaponready stance from the land anim. if (pm->ps->weapon == WP_DISRUPTOR && pm->ps->zoomMode == 1) { PM_StartTorsoAnim( TORSO_WEAPONREADY4 ); @@ -2025,13 +1930,12 @@ static void PM_CrashLand( void ) { } } } - //just a stupid hack to push us back into our "idle" stance if (!BG_InSpecialJump(pm->ps->legsAnim) || pm->ps->legsTimer < 1 || (pm->ps->legsAnim&~ANIM_TOGGLEBIT) == BOTH_WALL_RUN_LEFT || (pm->ps->legsAnim&~ANIM_TOGGLEBIT) == BOTH_WALL_RUN_RIGHT) - { + { //Only set the timer if we're in an anim that can be interrupted (this would not be, say, a flip) if (!BG_InRoll(pm->ps, pm->ps->legsAnim) && pm->ps->inAirAnim) { if (!BG_SaberInSpecial(pm->ps->saberMove) || pm->ps->weapon != WP_SABER) @@ -2062,7 +1966,8 @@ static void PM_CrashLand( void ) { if ( pm->ps->pm_flags & PMF_DUCKED ) { - if( delta >= 2 && !PM_InOnGroundAnim( pm->ps->legsAnim ) && !PM_InKnockDown( pm->ps ) && !BG_InRoll(pm->ps, pm->ps->legsAnim) ) + if( delta >= 2 && !PM_InOnGroundAnim( pm->ps->legsAnim ) && !PM_InKnockDown( pm->ps ) && !BG_InRoll(pm->ps, pm->ps->legsAnim) && + pm->ps->forceHandExtend == HANDEXTEND_NONE ) {//roll! int anim = PM_TryRoll(); @@ -2078,7 +1983,6 @@ static void PM_CrashLand( void ) { if ( anim ) {//absorb some impact pm->ps->legsTimer = 0; - //delta /= 2; delta /= 3; // /= 2 just cancels out the above delta *= 2 when landing while crouched, the roll itself should absorb a little damage pm->ps->legsAnim = 0; PM_SetAnim(SETANIM_BOTH,anim,SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 150); @@ -2087,8 +1991,6 @@ static void PM_CrashLand( void ) { } } - // create a local entity event to play the sound - // SURF_NODAMAGE is used for bounce pads where you don't ever // want to take damage or play a crunch sound if ( !(pml.groundTrace.surfaceFlags & SURF_NODAMAGE) ) { @@ -2135,7 +2037,7 @@ static void PM_CrashLand( void ) { } if (didRoll) - { + { //Add the appropriate event.. PM_AddEventWithParm( EV_ROLL, delta_send ); } else @@ -2163,22 +2065,6 @@ static void PM_CrashLand( void ) { pm->ps->bobCycle = 0; } -/* -============= -PM_CheckStuck -============= -*/ -/* -void PM_CheckStuck(void) { - trace_t trace; - - pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, pm->ps->origin, pm->ps->clientNum, pm->tracemask); - if (trace.allsolid) { - //int shit = qtrue; - } -} -*/ - /* ============= PM_CorrectAllSolid @@ -2234,23 +2120,18 @@ static void PM_GroundTraceMissed( void ) { //rww - don't want to do this when handextend_choke, because you can be standing on the ground //while still holding your throat. - if ( pm->ps->pm_type == PM_FLOAT ) { + if ( pm->ps->pm_type == PM_FLOAT ) + { //we're assuming this is because you're being choked int parts = SETANIM_LEGS; - /* - if ( !pm->ps->weaponTime && pm->ps->forceHandExtend >= HANDEXTEND_CHOKE ) - {//still on ground, only set anim on torso - parts = SETANIM_BOTH; - } - */ + //rww - also don't use SETANIM_FLAG_HOLD, it will cause the legs to float around a bit before going into //a proper anim even when on the ground. PM_SetAnim(parts, BOTH_CHOKE3, SETANIM_FLAG_OVERRIDE, 100); - //pm->ps->torsoTimer = 1; - //pm->ps->legsTimer = 1; } //If the anim is choke3, act like we just went into the air because we aren't in a float - else if ( pm->ps->groundEntityNum != ENTITYNUM_NONE || (pm->ps->legsAnim&~ANIM_TOGGLEBIT) == BOTH_CHOKE3 ) { + else if ( pm->ps->groundEntityNum != ENTITYNUM_NONE || (pm->ps->legsAnim&~ANIM_TOGGLEBIT) == BOTH_CHOKE3 ) + { // we just transitioned into freefall if ( pm->debugLevel ) { Com_Printf("%i:lift\n", c_pmove); @@ -2264,18 +2145,18 @@ static void PM_GroundTraceMissed( void ) { pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); if ( trace.fraction == 1.0 || pm->ps->pm_type == PM_FLOAT ) { if ( pm->ps->velocity[2] <= 0 && !(pm->ps->pm_flags&PMF_JUMP_HELD)) - {//FIXME: if velocity[2] < 0 and didn't jump, use some falling anim - PM_SetAnim(SETANIM_LEGS,BOTH_INAIR1,SETANIM_FLAG_OVERRIDE, 100); // Only blend over 100ms + { + PM_SetAnim(SETANIM_LEGS,BOTH_INAIR1,SETANIM_FLAG_OVERRIDE, 100); pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP; } else if ( pm->cmd.forwardmove >= 0 ) { - PM_SetAnim(SETANIM_LEGS,BOTH_JUMP1,SETANIM_FLAG_OVERRIDE, 100); // Only blend over 100ms + PM_SetAnim(SETANIM_LEGS,BOTH_JUMP1,SETANIM_FLAG_OVERRIDE, 100); pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP; } else { - PM_SetAnim(SETANIM_LEGS,BOTH_JUMPBACK1,SETANIM_FLAG_OVERRIDE, 100); // Only blend over 100ms + PM_SetAnim(SETANIM_LEGS,BOTH_JUMPBACK1,SETANIM_FLAG_OVERRIDE, 100); pm->ps->pm_flags |= PMF_BACKWARDS_JUMP; } @@ -2297,8 +2178,8 @@ static void PM_GroundTraceMissed( void ) { } if (PM_InRollComplete(pm->ps, pm->ps->legsAnim)) - { //HACK -_- (filthy client won't catch an animation restart because it only checks frame against incoming frame, so if you roll when you land after rolling - //off of something it won't replay the roll anim unless we switch it off in the air) + { //Client won't catch an animation restart because it only checks frame against incoming frame, so if you roll when you land after rolling + //off of something it won't replay the roll anim unless we switch it off in the air. This fixes that. PM_SetAnim(SETANIM_BOTH,BOTH_INAIR1,SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 150); pm->ps->inAirAnim = qtrue; } @@ -2372,8 +2253,6 @@ static void PM_GroundTrace( void ) { if ( pm->debugLevel ) { Com_Printf("%i:steep\n", c_pmove); } - // FIXME: if they can't slide down the slope, let them - // walk (sharp crevices) pm->ps->groundEntityNum = ENTITYNUM_NONE; pml.groundPlane = qtrue; pml.walking = qfalse; @@ -2409,16 +2288,13 @@ static void PM_GroundTrace( void ) { pm->ps->groundEntityNum = trace.entityNum; pm->ps->lastOnGround = pm->cmd.serverTime; - // don't reset the z velocity for slopes -// pm->ps->velocity[2] = 0; - PM_AddTouchEnt( trace.entityNum ); } /* ============= -PM_SetWaterLevel FIXME: avoid this twice? certainly if not moving +PM_SetWaterLevel ============= */ static void PM_SetWaterLevel( void ) { @@ -2690,7 +2566,8 @@ static void PM_Footsteps( void ) { footstep = qfalse; - if ( pm->ps->pm_flags & PMF_DUCKED ) { + if ( pm->ps->pm_flags & PMF_DUCKED ) + { int rolled = 0; bobmove = 0.5; // ducked characters bob much faster @@ -2700,7 +2577,7 @@ static void PM_Footsteps( void ) { rolled = PM_TryRoll(); } if ( !rolled ) - { + { //if the roll failed or didn't attempt, do standard crouching anim stuff. if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) { if ((pm->ps->legsAnim&~ANIM_TOGGLEBIT) != BOTH_CROUCH1WALKBACK) { @@ -2723,7 +2600,7 @@ static void PM_Footsteps( void ) { } } else - { + { //otherwise send us into the roll pm->ps->legsTimer = 0; pm->ps->legsAnim = 0; PM_SetAnim(SETANIM_BOTH,rolled,SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 150); @@ -2733,17 +2610,6 @@ static void PM_Footsteps( void ) { pm->ps->pm_flags &= ~PMF_DUCKED; pm->ps->pm_flags |= PMF_ROLLING; } - // ducked characters never play footsteps - /* - } else if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) { - if ( !( pm->cmd.buttons & BUTTON_WALKING ) ) { - bobmove = 0.4; // faster speeds bob faster - footstep = qtrue; - } else { - bobmove = 0.3; - } - PM_ContinueLegsAnim( LEGS_BACK ); - */ } else if ((pm->ps->pm_flags & PMF_ROLLING) && !BG_InRoll(pm->ps, pm->ps->legsAnim) && !PM_InRollComplete(pm->ps, pm->ps->legsAnim)) @@ -2830,14 +2696,6 @@ static void PM_Footsteps( void ) { // if we just crossed a cycle boundary, play an apropriate footstep event if ( ( ( old + 64 ) ^ ( pm->ps->bobCycle + 64 ) ) & 128 ) { - /* - if ( pm->waterlevel == 0 ) { - // on ground will only play sounds if running - if ( footstep && !pm->noFootsteps ) { - PM_AddEvent( PM_FootstepForSurface() ); - } - } else - */ pm->ps->footstepTime = pm->cmd.serverTime + 300; if ( pm->waterlevel == 1 ) { // splashing @@ -3217,6 +3075,11 @@ int PM_ItemUsable(playerState_t *ps, int forcedUse) return 0; } + if (ps->duelInProgress) + { //not allowed to use holdables while in a private duel. + return 0; + } + if (!forcedUse) { forcedUse = bg_itemlist[ps->stats[STAT_HOLDABLE_ITEM]].giTag; @@ -3314,7 +3177,8 @@ PM_Weapon Generates weapon events and modifes the weapon counter ============== */ -static void PM_Weapon( void ) { +static void PM_Weapon( void ) +{ int addTime; int amount; int killAfterItem = 0; @@ -3401,6 +3265,8 @@ static void PM_Weapon( void ) { else if (pm->ps->forceHandExtend != HANDEXTEND_NONE) { //nothing else should be allowed to happen during this time, including weapon fire int desiredAnim = 0; + qboolean seperateOnTorso = qfalse; + int desiredOnTorso = 0; switch(pm->ps->forceHandExtend) { @@ -3418,12 +3284,6 @@ static void PM_Weapon( void ) { break; case HANDEXTEND_CHOKE: desiredAnim = BOTH_CHOKE3; //left-handed choke - /* - if ( pm->ps->weapon == WP_NONE || pm->ps->weapon == WP_MELEE ) - { - desiredAnim = BOTH_CHOKE1; //two-handed choke - } - */ break; case HANDEXTEND_DODGE: desiredAnim = pm->ps->forceDodgeAnim; @@ -3431,7 +3291,27 @@ static void PM_Weapon( void ) { case HANDEXTEND_KNOCKDOWN: if (pm->ps->forceDodgeAnim) { - if (pm->ps->forceDodgeAnim == 2) + if (pm->ps->forceDodgeAnim > 4) + { //this means that we want to play a sepereate anim on the torso + int originalDAnim = pm->ps->forceDodgeAnim-8; //-8 is the original legs anim + if (originalDAnim == 2) + { + desiredAnim = BOTH_FORCE_GETUP_B1; + } + else if (originalDAnim == 3) + { + desiredAnim = BOTH_FORCE_GETUP_B3; + } + else + { + desiredAnim = BOTH_GETUP1; + } + + //now specify the torso anim + seperateOnTorso = qtrue; + desiredOnTorso = BOTH_FORCEPUSH; + } + else if (pm->ps->forceDodgeAnim == 2) { desiredAnim = BOTH_FORCE_GETUP_B1; } @@ -3471,14 +3351,28 @@ static void PM_Weapon( void ) { break; } - PM_SetAnim(SETANIM_TORSO, desiredAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 100); - pm->ps->torsoTimer = 1; + if (!seperateOnTorso) + { //of seperateOnTorso, handle it after setting the legs + PM_SetAnim(SETANIM_TORSO, desiredAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 100); + pm->ps->torsoTimer = 1; + } if (pm->ps->forceHandExtend == HANDEXTEND_DODGE || pm->ps->forceHandExtend == HANDEXTEND_KNOCKDOWN || (pm->ps->forceHandExtend == HANDEXTEND_CHOKE && pm->ps->groundEntityNum == ENTITYNUM_NONE) ) { //special case, play dodge anim on whole body, choke anim too if off ground - PM_SetAnim(SETANIM_LEGS, desiredAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 100); - pm->ps->legsTimer = 1; + if (seperateOnTorso) + { + PM_SetAnim(SETANIM_LEGS, desiredAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 100); + pm->ps->legsTimer = 1; + + PM_SetAnim(SETANIM_TORSO, desiredOnTorso, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 100); + pm->ps->torsoTimer = 1; + } + else + { + PM_SetAnim(SETANIM_LEGS, desiredAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 100); + pm->ps->legsTimer = 1; + } } return; @@ -3876,10 +3770,6 @@ static void PM_Animate( void ) { if ( pm->cmd.buttons & BUTTON_GESTURE ) { if ( pm->ps->torsoTimer < 1 && pm->ps->forceHandExtend == HANDEXTEND_NONE && pm->ps->legsTimer < 1 && pm->ps->weaponTime < 1 && pm->ps->saberLockTime < pm->cmd.serverTime) { - /* - PM_StartTorsoAnim( BOTH_TALKGESTURE3 ); - pm->ps->torsoTimer = TIMER_GESTURE; - */ pm->ps->forceHandExtend = HANDEXTEND_TAUNT; @@ -4114,34 +4004,6 @@ void PM_AdjustAttackStates( pmove_t *pm ) } } - /* - // set the firing flag for continuous beam weapons - if ( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION - && ( pm->cmd.buttons & (BUTTON_ATTACK|BUTTON_ALT_ATTACK)) && pm->ps->ammo[ weaponData[pm->ps->weapon].ammoIndex ] ) - { - // Check more in depth here. - if ((pm->cmd.buttons & BUTTON_ATTACK) && - pm->ps->ammo[weaponData[pm->ps->weapon].ammoIndex] >= weaponData[pm->ps->weapon].energyPerShot) - { - pm->ps->eFlags |= EF_FIRING; - pm->ps->eFlags &= ~EF_ALT_FIRING; - } - else if ((pm->cmd.buttons & BUTTON_ALT_ATTACK) && - pm->ps->ammo[weaponData[pm->ps->weapon].ammoIndex] >= weaponData[pm->ps->weapon].altEnergyPerShot) - { - pm->ps->eFlags |= (EF_FIRING|EF_ALT_FIRING); // Both are set in the event of an alt fire - } - else - { - pm->ps->eFlags &= ~(EF_FIRING|EF_ALT_FIRING); - } - } - else - { - pm->ps->eFlags &= ~(EF_FIRING|EF_ALT_FIRING); - } - */ - // set the firing flag for continuous beam weapons, saber will fire even if out of ammo if ( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION && @@ -4288,6 +4150,10 @@ void BG_AdjustClientSpeed(playerState_t *ps, usercmd_t *cmd, int svTime) | BOTH_RUN1; } } + else if ( cmd->forwardmove < 0 && !(cmd->buttons&BUTTON_WALKING) && pm->ps->groundEntityNum != ENTITYNUM_NONE ) + {//running backwards is slower than running forwards (like SP) + ps->speed *= 0.75; + } if (ps->fd.forcePowersActive & (1 << FP_GRIP)) { @@ -4369,7 +4235,6 @@ void BG_AdjustClientSpeed(playerState_t *ps, usercmd_t *cmd, int svTime) ps->speed *= 0.85f; break; case FORCE_LEVEL_3: - //ps->speed *= 0.70f; ps->speed *= 0.55f; break; default: @@ -4479,7 +4344,6 @@ void PmoveSingle (pmove_t *pmove) { if ((pm->ps->legsAnim&~ANIM_TOGGLEBIT) == (BOTH_A2_STABBACK1) || (pm->ps->legsAnim&~ANIM_TOGGLEBIT) == (BOTH_ATTACK_BACK) || (pm->ps->legsAnim&~ANIM_TOGGLEBIT) == (BOTH_CROUCHATTACKBACK1) || - //(pm->ps->legsAnim&~ANIM_TOGGLEBIT) == (BOTH_LUNGE2_B__T_) || (pm->ps->legsAnim&~ANIM_TOGGLEBIT) == (BOTH_FORCELEAP2_T__B_) || (pm->ps->legsAnim&~ANIM_TOGGLEBIT) == (BOTH_JUMPFLIPSTABDOWN) || (pm->ps->legsAnim&~ANIM_TOGGLEBIT) == (BOTH_JUMPFLIPSLASHDOWN1)) @@ -4489,6 +4353,14 @@ void PmoveSingle (pmove_t *pmove) { pm->cmd.upmove = 0; } + if ((pm->ps->legsAnim&~ANIM_TOGGLEBIT) == BOTH_KISSER1LOOP || + (pm->ps->legsAnim&~ANIM_TOGGLEBIT) == BOTH_KISSEE1LOOP) + { + pm->cmd.forwardmove = 0; + pm->cmd.rightmove = 0; + pm->cmd.upmove = 0; + } + if (pm->ps->emplacedIndex) { if (pm->cmd.forwardmove < 0) @@ -4576,25 +4448,17 @@ void PmoveSingle (pmove_t *pmove) { PM_AdjustAngleForWallRun(pm->ps, &pm->cmd, qtrue); - if (pm->ps->saberMove == LS_A_JUMP_T__B_ || pm->ps->saberMove == LS_A_LUNGE) + if (pm->ps->saberMove == LS_A_JUMP_T__B_ || pm->ps->saberMove == LS_A_LUNGE || + pm->ps->saberMove == LS_A_BACK_CR || pm->ps->saberMove == LS_A_BACK || + pm->ps->saberMove == LS_A_BACKSTAB) { - /* - if (pm->ps->velocity[0] || - pm->ps->velocity[1] || - pm->ps->velocity[2]) - { //if we're doing a lunge and we have a velocity, force us to look in the direction we are - //flying with the lunge - vec3_t velAngles; + PM_SetPMViewAngle(pm->ps, pm->ps->viewangles, &pm->cmd); + } - vectoangles(pm->ps->velocity, velAngles); - PM_SetPMViewAngle(pm->ps, velAngles, &pm->cmd); - } - else - { //otherwise, if there is no valid velocity, just don't let us readjust the angles. - PM_SetPMViewAngle(pm->ps, pm->ps->viewangles, &pm->cmd); - } - */ - //FIXME: Use the above method, and don't let the angles mess up when you hit something. + if ((pm->ps->legsAnim&~ANIM_TOGGLEBIT) == BOTH_KISSER1LOOP || + (pm->ps->legsAnim&~ANIM_TOGGLEBIT) == BOTH_KISSEE1LOOP) + { + pm->ps->viewangles[PITCH] = 0; PM_SetPMViewAngle(pm->ps, pm->ps->viewangles, &pm->cmd); } @@ -4715,11 +4579,6 @@ void PmoveSingle (pmove_t *pmove) { PM_Use(); - if (pm->ps->pm_flags & PMF_UPDATE_ANIM) - { -// PM_UpdateGhoul2AnimFromState(); - } - // footstep events / legs animations PM_Footsteps(); @@ -4790,8 +4649,5 @@ void Pmove (pmove_t *pmove) { pmove->cmd.upmove = 20; } } - - //PM_CheckStuck(); - } diff --git a/CODE-mp/game/bg_public.h b/CODE-mp/game/bg_public.h index 2669d91..70c4b11 100644 --- a/CODE-mp/game/bg_public.h +++ b/CODE-mp/game/bg_public.h @@ -1032,9 +1032,6 @@ void BG_TouchJumpPad( playerState_t *ps, entityState_t *jumppad ); void BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean snap ); void BG_PlayerStateToEntityStateExtraPolate( playerState_t *ps, entityState_t *s, int time, qboolean snap ); -void BG_G2PlayerAngles( vec3_t startAngles, vec3_t legs[3], vec3_t legsAngles, int painTime, int painDirection, int currentTime, - qboolean *torso_yawing, float *torso_yawAngle, qboolean *torso_pitching, float *torso_pitchAngle, qboolean *legs_yawing, float *legs_yawAngle, - int frameTime, vec3_t velocity, int legsAnim, int torsoAnim, qboolean dead, float movementDir, void *ghoul2, qhandle_t *modelList, int weapon); qboolean BG_PlayerTouchesItem( playerState_t *ps, entityState_t *item, int atTime ); diff --git a/CODE-mp/game/bg_saber.c b/CODE-mp/game/bg_saber.c index 989ba5c..21543fb 100644 --- a/CODE-mp/game/bg_saber.c +++ b/CODE-mp/game/bg_saber.c @@ -30,6 +30,7 @@ void BG_ForcePowerDrain( playerState_t *ps, forcePowers_t forcePower, int overri return; } */ + //No longer grant infinite force with boon. if ( !drain ) { @@ -353,7 +354,6 @@ qboolean PM_SaberKataDone(int curmove, int newmove); int PM_SaberAnimTransitionAnim( int curmove, int newmove ) { - //FIXME: take FP_SABER_OFFENSE into account here somehow? int retmove = newmove; if ( curmove == LS_READY ) {//just standing there @@ -401,10 +401,8 @@ int PM_SaberAnimTransitionAnim( int curmove, int newmove ) case LS_A_TR2BL: case LS_A_T2B: if ( newmove == curmove ) - {//FIXME: need a spin or something or go to next level, but for now, just play the return - //going into another attack... - //allow endless chaining in level 1 attacks, several in level 2 and only one or a few in level 3 - //FIXME: don't let strong attacks chain to an attack in the opposite direction ( > 45 degrees?) + { + //going into an attack if ( PM_SaberKataDone( curmove, newmove ) ) {//done with this kata, must return to ready before attack again retmove = LS_R_TL2BR + (newmove-LS_A_TL2BR); @@ -555,12 +553,11 @@ int PM_SaberMoveQuadrantForMovement( usercmd_t *ucmd ) {//backward= T2B slash //or B2T uppercut? return Q_T; } - else //if ( curmove == LS_READY )//??? + else {//Not moving at all return Q_R; } } - //return Q_R;//???? } //=================================================================== @@ -702,7 +699,7 @@ qboolean PM_SaberKataDone(int curmove, int newmove) } } else - {//FIXME: have chainAngle influence fast and medium chains as well? + {//Perhaps have chainAngle influence fast and medium chains as well? For now, just do level 3. if (newmove == LS_A_TL2BR || newmove == LS_A_L2R || newmove == LS_A_BL2TR || @@ -756,7 +753,6 @@ void PM_SaberLockBreak( playerState_t *genemy, qboolean victory ) } else { - //loseAnim = BOTH_KNOCKDOWN4; punishLoser = qtrue; } break; @@ -770,7 +766,6 @@ void PM_SaberLockBreak( playerState_t *genemy, qboolean victory ) } else { - //loseAnim = BOTH_BF1BREAK; punishLoser = qtrue; } break; @@ -782,9 +777,8 @@ void PM_SaberLockBreak( playerState_t *genemy, qboolean victory ) } else { - genemy->saberMove = /*genemy->saberBounceMove =*/ LS_H1_BL; + genemy->saberMove = LS_H1_BL; genemy->saberBlocked = BLOCKED_PARRY_BROKEN; - //loseAnim = BOTH_H1_S1_BR; punishLoser = qtrue; } break; @@ -796,9 +790,8 @@ void PM_SaberLockBreak( playerState_t *genemy, qboolean victory ) } else { - genemy->saberMove = /*genemy->saberBounceMove =*/ LS_H1_BR; + genemy->saberMove = LS_H1_BR; genemy->saberBlocked = BLOCKED_PARRY_BROKEN; - //loseAnim = BOTH_H1_S1_BL; punishLoser = qtrue; } break; @@ -806,7 +799,7 @@ void PM_SaberLockBreak( playerState_t *genemy, qboolean victory ) PM_SetAnim( SETANIM_BOTH, winAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, -1 ); if (punishLoser) - { + { //someone lost the lock, so punish them by knocking them down vec3_t oppDir; int strength = 8; @@ -829,7 +822,7 @@ void PM_SaberLockBreak( playerState_t *genemy, qboolean victory ) pm->checkDuelLoss = genemy->clientNum+1; } else - { + { //If no one lost, then shove each player away from the other vec3_t oppDir; int strength = 4; @@ -849,8 +842,7 @@ void PM_SaberLockBreak( playerState_t *genemy, qboolean victory ) genemy->forceHandExtend = HANDEXTEND_WEAPONREADY; } - pm->ps->weaponTime = 0;//pm->ps->torsoTimer; - //The enemy unfortunately has no valid torso animation time at this point, so just use ours + pm->ps->weaponTime = 0; genemy->weaponTime = 0; pm->ps->saberLockTime = genemy->saberLockTime = 0; @@ -877,12 +869,7 @@ extern qboolean ValidAnimFileIndex ( int index ); void PM_SaberLocked( void ) { int remaining = 0; - /* - if ( pm->ps->weaponTime ) - {//can't attack yet - return; - } - */ + playerState_t *genemy = pm->bgClients[pm->ps->saberLockEnemy]; if ( !genemy ) { @@ -906,13 +893,15 @@ void PM_SaberLocked( void ) genemy->weaponTime = 0; dist = DistanceSquared(pm->ps->origin,genemy->origin); - if ( dist < 64 || dist > 6400 )//( dist < 128 || dist > 2304 ) - {//between 8 and 80 from each other//was 16 and 48 + if ( dist < 64 || dist > 6400 ) + {//between 8 and 80 from each other PM_SaberLockBreak( genemy, qfalse ); return; } if ( (pm->cmd.buttons & BUTTON_ATTACK) || pm->ps->saberLockAdvance ) {//holding attack + animation_t *anim; + if (pm->ps->saberLockAdvance) {//tapping animation_t *anim; @@ -968,24 +957,21 @@ void PM_SaberLocked( void ) { return; } - if( 1/*ValidAnimFileIndex( genemy->client->clientInfo.animFileIndex )*/ ) - { - animation_t *anim; - anim = &pm->animations[(genemy->torsoAnim&~ANIM_TOGGLEBIT)]; - if ( (genemy->torsoAnim&~ANIM_TOGGLEBIT) == BOTH_CWCIRCLELOCK || - (genemy->torsoAnim&~ANIM_TOGGLEBIT) == BOTH_BF1LOCK ) + anim = &pm->animations[(genemy->torsoAnim&~ANIM_TOGGLEBIT)]; + + if ( (genemy->torsoAnim&~ANIM_TOGGLEBIT) == BOTH_CWCIRCLELOCK || + (genemy->torsoAnim&~ANIM_TOGGLEBIT) == BOTH_BF1LOCK ) + { + if ( !PM_irand_timesync( 0, 2 ) ) { - if ( !PM_irand_timesync( 0, 2 ) ) - { - BG_AddPredictableEventToPlayerstate(EV_PAIN, floor((float)80/100*100.0f), genemy); - } - PM_SetAnimFrame( genemy, anim->firstFrame+remaining, qtrue, qtrue ); - } - else - { - PM_SetAnimFrame( genemy, anim->firstFrame+anim->numFrames-remaining, qtrue, qtrue ); + BG_AddPredictableEventToPlayerstate(EV_PAIN, floor((float)80/100*100.0f), genemy); } + PM_SetAnimFrame( genemy, anim->firstFrame+remaining, qtrue, qtrue ); + } + else + { + PM_SetAnimFrame( genemy, anim->firstFrame+anim->numFrames-remaining, qtrue, qtrue ); } } } @@ -1011,8 +997,6 @@ qboolean PM_SaberInBrokenParry( int move ) int PM_BrokenParryForParry( int move ) { - //FIXME: need actual anims for this - //FIXME: need to know which side of the saber was hit! For now, we presume the saber gets knocked away from the center switch ( move ) { case LS_PARRY_UP: @@ -1031,13 +1015,13 @@ int PM_BrokenParryForParry( int move ) return LS_H1_BR; break; case LS_READY: - return LS_H1_B_;//??? + return LS_H1_B_; break; } return LS_NONE; } -#define BACK_STAB_DISTANCE 128//64 +#define BACK_STAB_DISTANCE 128 qboolean PM_CanBackstab(void) { @@ -1068,7 +1052,6 @@ qboolean PM_CanBackstab(void) saberMoveName_t PM_SaberFlipOverAttackMove(trace_t *tr) { - //FIXME: check above for room enough to jump! vec3_t fwdAngles, jumpFwd; float zDiff = 0; playerState_t *psData; @@ -1076,13 +1059,11 @@ saberMoveName_t PM_SaberFlipOverAttackMove(trace_t *tr) VectorCopy( pm->ps->viewangles, fwdAngles ); fwdAngles[PITCH] = fwdAngles[ROLL] = 0; AngleVectors( fwdAngles, jumpFwd, NULL, NULL ); - VectorScale( jumpFwd, /*100*/50, pm->ps->velocity ); + VectorScale( jumpFwd, 50, pm->ps->velocity ); pm->ps->velocity[2] = 400; psData = pm->bgClients[tr->entityNum]; - pm->ps->velocity[2] *= 1;//(pm->gent->enemy->maxs[2]-pm->gent->enemy->mins[2])/64.0f; - //go higher for enemies higher than you, lower for those lower than you if (psData) { @@ -1108,7 +1089,7 @@ saberMoveName_t PM_SaberFlipOverAttackMove(trace_t *tr) pm->ps->velocity[2] = 400; } - pm->ps->fd.forceJumpZStart = pm->ps->origin[2];//so we don't take damage if we land at same height + PM_SetForceJumpZStart(pm->ps->origin[2]);//so we don't take damage if we land at same height PM_AddEvent( EV_JUMP ); pm->ps->fd.forceJumpSound = 1; @@ -1161,7 +1142,6 @@ saberMoveName_t PM_SaberLungeAttackMove( void ) //do the lunge AngleVectors( fwdAngles, jumpFwd, NULL, NULL ); VectorScale( jumpFwd, 150, pm->ps->velocity ); - //pm->ps->velocity[2] = 50; PM_AddEvent( EV_JUMP ); return LS_A_LUNGE; @@ -1174,9 +1154,9 @@ saberMoveName_t PM_SaberJumpAttackMove( void ) VectorCopy( pm->ps->viewangles, fwdAngles ); fwdAngles[PITCH] = fwdAngles[ROLL] = 0; AngleVectors( fwdAngles, jumpFwd, NULL, NULL ); - VectorScale( jumpFwd, /*200*/300, pm->ps->velocity ); - pm->ps->velocity[2] = 280;//180; - pm->ps->fd.forceJumpZStart = pm->ps->origin[2];//so we don't take damage if we land at same height + VectorScale( jumpFwd, 300, pm->ps->velocity ); + pm->ps->velocity[2] = 280; + PM_SetForceJumpZStart(pm->ps->origin[2]);//so we don't take damage if we land at same height PM_AddEvent( EV_JUMP ); pm->ps->fd.forceJumpSound = 1; @@ -1240,10 +1220,10 @@ saberMoveName_t PM_SaberAttackForMovement(saberMoveName_t curmove) if ( pm->cmd.forwardmove > 0 ) {//forward= T2B slash if (pm->ps->fd.saberAnimLevel == FORCE_LEVEL_2 && - /*pm->ps->groundEntityNum != ENTITYNUM_NONE &&*/ pm->ps->velocity[2] > 100 && PM_GroundDistance() < 32 && - !BG_InSpecialJump(pm->ps->legsAnim)) + !BG_InSpecialJump(pm->ps->legsAnim) && + !BG_SaberInSpecialAttack(pm->ps->torsoAnim)) { //FLIP AND DOWNWARD ATTACK trace_t tr; @@ -1253,8 +1233,10 @@ saberMoveName_t PM_SaberAttackForMovement(saberMoveName_t curmove) } } else if (pm->ps->fd.saberAnimLevel == FORCE_LEVEL_1 && + pm->ps->groundEntityNum != ENTITYNUM_NONE && (pm->ps->pm_flags & PMF_DUCKED) && - pm->ps->weaponTime <= 0) + pm->ps->weaponTime <= 0 && + !BG_SaberInSpecialAttack(pm->ps->torsoAnim)) { //LUNGE (weak) newmove = PM_SaberLungeAttackMove(); } @@ -1265,7 +1247,7 @@ saberMoveName_t PM_SaberAttackForMovement(saberMoveName_t curmove) } else if ( pm->cmd.forwardmove < 0 ) {//backward= T2B slash//B2T uppercut? - if (PM_CanBackstab()) + if (PM_CanBackstab() && !BG_SaberInSpecialAttack(pm->ps->torsoAnim)) { //BACKSTAB (attack varies by level) if (pm->ps->fd.saberAnimLevel >= FORCE_LEVEL_2) {//medium and higher attacks @@ -1309,7 +1291,6 @@ saberMoveName_t PM_SaberAttackForMovement(saberMoveName_t curmove) //prediction values. Under laggy conditions this will cause the appearance of rapid swing //sequence changes. - //newmove = PM_irand_timesync(LS_A_TL2BR, LS_A_T2B); newmove = LS_A_T2B; //decided we don't like random attacks when idle, use an overhead instead. } } @@ -1532,7 +1513,7 @@ void PM_WeaponLightsaber(void) case BLOCKED_ATK_BOUNCE: // If there is absolutely no blocked move in the chart, don't even mess with the animation. // OR if we are already in a block or parry. - if (pm->ps->saberMove >= LS_T1_BR__R/*LS_BOUNCE_TOP*/ )//|| saberMoveData[pm->ps->saberMove].bounceMove == LS_NONE ) + if (pm->ps->saberMove >= LS_T1_BR__R) {//an actual bounce? Other bounces before this are actually transitions? pm->ps->saberBlocked = BLOCKED_NONE; } @@ -1690,8 +1671,6 @@ weapChecks: // Check for WEAPON ATTACK // ********************************************************* - // NOTENOTE This is simply a client-side struct. Anything that is needed client and server should be moved to bg_weapon. - if(!delayed_fire) { // Start with the current move, and cross index it with the current control states. @@ -1704,7 +1683,7 @@ weapChecks: curmove = LS_READY; } // check for fire - if ( !(pm->cmd.buttons & (BUTTON_ATTACK/*|BUTTON_ALT_ATTACK*/)) ) + if ( !(pm->cmd.buttons & (BUTTON_ATTACK)) ) { if (pm->ps->weaponTime != 0) {//Still firing @@ -1798,12 +1777,6 @@ weapChecks: } else//if ( pm->cmd.buttons&BUTTON_ATTACK && !(pm->ps->pm_flags&PMF_ATTACK_HELD) )//only do this if just pressed attack button? {//get attack move from movement command - /* - if ( PM_SaberKataDone() ) - {//we came from a bounce and cannot chain to another attack because our kata is done - newmove = saberMoveData[curmove].chain_idle; - } - else */ saberMoveName_t checkMove = PM_SaberAttackForMovement(curmove); if (checkMove != -1) { @@ -1820,39 +1793,17 @@ weapChecks: {//we came from a bounce and cannot chain to another attack because our kata is done newmove = saberMoveData[curmove].chain_idle; } - /*else - { - saberMoveName_t checkMove = PM_SaberAttackForMovement(curmove); - if (checkMove != -1) - { - newmove = checkMove; - } - } - */ } - /* - if ( newmove == LS_NONE ) - {//FIXME: should we allow this? Are there some anims that you should never be able to chain into an attack? - //only curmove that might get in here is LS_NONE, LS_DRAW, LS_PUTAWAY and the LS_R_ returns... all of which are in Q_R - newmove = PM_AttackMoveForQuad( saberMoveData[curmove].endQuad ); - } - */ + if ( newmove != LS_NONE ) { //Now get the proper transition move newmove = PM_SaberAnimTransitionAnim( curmove, newmove ); - // NOTENOTE Had to remove this concept since there is no gent in pmove. - /* - if ( PM_HasAnimation( pm->gent, saberMoveData[newmove].animToUse ) ) - */ assert( bgGlobalAnimations[saberMoveData[newmove].animToUse].firstFrame != 0 || bgGlobalAnimations[saberMoveData[newmove].animToUse].numFrames != 0); - if (1) - { - anim = saberMoveData[newmove].animToUse; - } + anim = saberMoveData[newmove].animToUse; } } @@ -1890,7 +1841,7 @@ weapChecks: } if (anim == BOTH_RUN2 && !pm->cmd.forwardmove && !pm->cmd.rightmove) - { //semi-hacky + { //semi-hacky (if not moving on x-y and still playing the running anim, force the player out of it) anim = PM_GetSaberStance(); } newmove = LS_READY; @@ -2021,8 +1972,6 @@ void PM_SetSaberMove(short newMove) !PM_JumpingAnim( pm->ps->legsAnim ) && !BG_InSpecialJump( pm->ps->legsAnim ) && anim != PM_GetSaberStance() && - //!PM_CrouchAnim( pm->ps->legsAnim ) && - //pm->cmd.upmove >= 0 && pm->ps->groundEntityNum != ENTITYNUM_NONE && !(pm->ps->pm_flags & PMF_DUCKED)) { @@ -2047,7 +1996,7 @@ void PM_SetSaberMove(short newMove) pm->ps->saberMove = newMove; pm->ps->saberBlocking = saberMoveData[newMove].blocking; - pm->ps->torsoAnim = anim;//saberMoveData[newMove].animToUse; + pm->ps->torsoAnim = anim; if (pm->ps->weaponTime <= 0) { diff --git a/CODE-mp/game/bg_weapons.c b/CODE-mp/game/bg_weapons.c index a85ed6d..81bfe41 100644 --- a/CODE-mp/game/bg_weapons.c +++ b/CODE-mp/game/bg_weapons.c @@ -153,7 +153,7 @@ weaponData_t weaponData[WP_NUM_WEAPONS] = 1, // int energyPerShot; // Amount of energy used per shot 100, // int fireTime; // Amount of time between firings 8192, // int range; // Range of weapon - 25, // int altEnergyPerShot; // Amount of energy used for alt-fire + 15, // int altEnergyPerShot; // Amount of energy used for alt-fire 800, // int altFireTime; // Amount of time between alt-firings 8192, // int altRange; // Range of alt-fire 0, // int chargeSubTime; // ms interval for subtracting ammo during charge @@ -187,7 +187,7 @@ weaponData_t weaponData[WP_NUM_WEAPONS] = 10, // int energyPerShot; // Amount of energy used per shot 700, // int fireTime; // Amount of time between firings 8192, // int range; // Range of weapon - 25, // int altEnergyPerShot; // Amount of energy used for alt-fire + 15, // int altEnergyPerShot; // Amount of energy used for alt-fire 800, // int altFireTime; // Amount of time between alt-firings 8192, // int altRange; // Range of alt-fire 0, // int chargeSubTime; // ms interval for subtracting ammo during charge diff --git a/CODE-mp/game/g_active.c b/CODE-mp/game/g_active.c index ace3bf4..33b0774 100644 --- a/CODE-mp/game/g_active.c +++ b/CODE-mp/game/g_active.c @@ -1295,7 +1295,7 @@ void ClientThink_real( gentity_t *ent ) { pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY; } else if ( ent->r.svFlags & SVF_BOT ) { - pm.tracemask = MASK_PLAYERSOLID | CONTENTS_BOTCLIP; + pm.tracemask = MASK_PLAYERSOLID | CONTENTS_MONSTERCLIP; } else { pm.tracemask = MASK_PLAYERSOLID; @@ -1643,7 +1643,7 @@ void ClientThink_real( gentity_t *ent ) { // check for respawning if ( client->ps.stats[STAT_HEALTH] <= 0 ) { // wait for the attack button to be pressed - if ( level.time > client->respawnTime ) { + if ( level.time > client->respawnTime && !gDoSlowMoDuel ) { // forcerespawn is to prevent users from waiting out powerups if ( g_forcerespawn.integer > 0 && ( level.time - client->respawnTime ) > g_forcerespawn.integer * 1000 ) { @@ -1656,6 +1656,10 @@ void ClientThink_real( gentity_t *ent ) { respawn( ent ); } } + else if (gDoSlowMoDuel) + { + client->respawnTime = level.time + 1000; + } return; } diff --git a/CODE-mp/game/g_client.c b/CODE-mp/game/g_client.c index b5b250e..74de982 100644 --- a/CODE-mp/game/g_client.c +++ b/CODE-mp/game/g_client.c @@ -1277,7 +1277,10 @@ void ClientUserinfoChanged( int clientNum ) { trap_SetConfigstring( CS_PLAYERS+clientNum, s ); - //G_LogPrintf( "ClientUserinfoChanged: %i %s\n", clientNum, s ); + if (g_logClientInfo.integer) + { + G_LogPrintf( "ClientUserinfoChanged: %i %s\n", clientNum, s ); + } } @@ -1742,6 +1745,46 @@ void ClientSpawn(gentity_t *ent) { && !AllForceDisabled( g_forcePowerDisable.integer ) && g_trueJedi.integer ) { + if ( g_gametype.integer >= GT_TEAM && (client->sess.sessionTeam == TEAM_BLUE || client->sess.sessionTeam == TEAM_RED) ) + {//In Team games, force one side to be merc and other to be jedi + if ( level.numPlayingClients > 0 ) + {//already someone in the game + int i, forceTeam = TEAM_SPECTATOR; + for ( i = 0 ; i < level.maxclients ; i++ ) + { + if ( level.clients[i].pers.connected == CON_DISCONNECTED ) { + continue; + } + if ( level.clients[i].sess.sessionTeam == TEAM_BLUE || level.clients[i].sess.sessionTeam == TEAM_RED ) + {//in-game + if ( WP_HasForcePowers( &level.clients[i].ps ) ) + {//this side is using force + forceTeam = level.clients[i].sess.sessionTeam; + } + else + {//other team is using force + if ( level.clients[i].sess.sessionTeam == TEAM_BLUE ) + { + forceTeam = TEAM_RED; + } + else + { + forceTeam = TEAM_BLUE; + } + } + break; + } + } + if ( WP_HasForcePowers( &client->ps ) && client->sess.sessionTeam != forceTeam ) + {//using force but not on right team, switch him over + const char *teamName = TeamName( forceTeam ); + //client->sess.sessionTeam = forceTeam; + SetTeam( ent, (char *)teamName ); + return; + } + } + } + if ( WP_HasForcePowers( &client->ps ) ) { client->ps.trueNonJedi = qfalse; @@ -1758,13 +1801,23 @@ void ClientSpawn(gentity_t *ent) { { client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_BRYAR_PISTOL ); } + if (!wDisable || !(wDisable & (1 << WP_BLASTER))) + { + client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_BLASTER ); + } + if (!wDisable || !(wDisable & (1 << WP_BOWCASTER))) + { + client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_BOWCASTER ); + } client->ps.stats[STAT_WEAPONS] &= ~(1 << WP_SABER); client->ps.stats[STAT_WEAPONS] |= (1 << WP_STUN_BATON); + client->ps.ammo[AMMO_POWERCELL] = ammoData[AMMO_POWERCELL].max; client->ps.weapon = WP_BRYAR_PISTOL; } } else - { + {//jediVmerc is incompatible with this gametype, turn it off! + trap_Cvar_Set( "g_jediVmerc", "0" ); if (g_gametype.integer == GT_HOLOCRON) { //always get free saber level 1 in holocron diff --git a/CODE-mp/game/g_cmds.c b/CODE-mp/game/g_cmds.c index b2c6c9d..bfeefaf 100644 --- a/CODE-mp/game/g_cmds.c +++ b/CODE-mp/game/g_cmds.c @@ -503,8 +503,11 @@ void Cmd_Kill_f( gentity_t *ent ) { if (g_gametype.integer == GT_TOURNAMENT && level.numPlayingClients > 1 && !level.warmupTime) { - trap_SendServerCommand( ent-g_entities, va("print \"%s\n\"", G_GetStripEdString("SVINGAME", "ATTEMPTDUELKILL")) ); - return; + if (!g_allowDuelSuicide.integer) + { + trap_SendServerCommand( ent-g_entities, va("print \"%s\n\"", G_GetStripEdString("SVINGAME", "ATTEMPTDUELKILL")) ); + return; + } } ent->flags &= ~FL_GODMODE; @@ -646,7 +649,7 @@ void SetTeam( gentity_t *ent, char *s ) { //} } - if ( g_teamForceBalance.integer ) { + if ( g_teamForceBalance.integer && !g_trueJedi.integer ) { int counts[TEAM_NUM_TEAMS]; counts[TEAM_BLUE] = TeamCount( ent->client->ps.clientNum, TEAM_BLUE ); @@ -1407,6 +1410,109 @@ static const char *gameNames[] = { "Capture the Ysalamiri" }; +/* +================== +G_ClientNumberFromName + +Finds the client number of the client with the given name +================== +*/ +int G_ClientNumberFromName ( const char* name ) +{ + char s2[MAX_STRING_CHARS]; + char n2[MAX_STRING_CHARS]; + int i; + gclient_t* cl; + + // check for a name match + SanitizeString( (char*)name, s2 ); + for ( i=0, cl=level.clients ; i < level.numConnectedClients ; i++, cl++ ) + { + SanitizeString( cl->pers.netname, n2 ); + if ( !strcmp( n2, s2 ) ) + { + return i; + } + } + + return -1; +} + +/* +================== +SanitizeString2 + +Rich's revised version of SanitizeString +================== +*/ +void SanitizeString2( char *in, char *out ) +{ + int i = 0; + int r = 0; + + while (in[i]) + { + if (i >= MAX_NAME_LENGTH-1) + { //the ui truncates the name here.. + break; + } + + if (in[i] == '^') + { + if (in[i+1] >= 48 && //'0' + in[i+1] <= 57) //'9' + { //only skip it if there's a number after it for the color + i += 2; + continue; + } + else + { //just skip the ^ + i++; + continue; + } + } + + if (in[i] < 32) + { + i++; + continue; + } + + out[r] = in[i]; + r++; + i++; + } + out[r] = 0; +} + +/* +================== +G_ClientNumberFromStrippedName + +Same as above, but strips special characters out of the names before comparing. +================== +*/ +int G_ClientNumberFromStrippedName ( const char* name ) +{ + char s2[MAX_STRING_CHARS]; + char n2[MAX_STRING_CHARS]; + int i; + gclient_t* cl; + + // check for a name match + SanitizeString2( (char*)name, s2 ); + for ( i=0, cl=level.clients ; i < level.numConnectedClients ; i++, cl++ ) + { + SanitizeString2( cl->pers.netname, n2 ); + if ( !strcmp( n2, s2 ) ) + { + return i; + } + } + + return -1; +} + /* ================== Cmd_CallVote_f @@ -1466,7 +1572,8 @@ void Cmd_CallVote_f( gentity_t *ent ) { } // special case for g_gametype, check for bad values - if ( !Q_stricmp( arg1, "g_gametype" ) ) { + if ( !Q_stricmp( arg1, "g_gametype" ) ) + { i = atoi( arg2 ); if( i == GT_SINGLE_PLAYER || i < GT_FFA || i >= GT_MAX_GAME_TYPE) { trap_SendServerCommand( ent-g_entities, "print \"Invalid gametype.\n\"" ); @@ -1478,7 +1585,9 @@ void Cmd_CallVote_f( gentity_t *ent ) { Com_sprintf( level.voteString, sizeof( level.voteString ), "%s %d", arg1, i ); Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "%s %s", arg1, gameNames[i] ); - } else if ( !Q_stricmp( arg1, "map" ) ) { + } + else if ( !Q_stricmp( arg1, "map" ) ) + { // special case for map changes, we want to reset the nextmap setting // this allows a player to change maps, but not upset the map rotation char s[MAX_STRING_CHARS]; @@ -1497,7 +1606,46 @@ void Cmd_CallVote_f( gentity_t *ent ) { Com_sprintf( level.voteString, sizeof( level.voteString ), "%s %s", arg1, arg2 ); } Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "%s", level.voteString ); - } else if ( !Q_stricmp( arg1, "nextmap" ) ) { + } + else if ( !Q_stricmp ( arg1, "clientkick" ) ) + { + int n = atoi ( arg2 ); + + if ( n < 0 || n >= MAX_CLIENTS ) + { + trap_SendServerCommand( ent-g_entities, va("print \"invalid client number %d.\n\"", n ) ); + return; + } + + if ( g_entities[n].client->pers.connected == CON_DISCONNECTED ) + { + trap_SendServerCommand( ent-g_entities, va("print \"there is no client with the client number %d.\n\"", n ) ); + return; + } + + Com_sprintf ( level.voteString, sizeof(level.voteString ), "%s %s", arg1, arg2 ); + Com_sprintf ( level.voteDisplayString, sizeof(level.voteDisplayString), "kick %s", g_entities[n].client->pers.netname ); + } + else if ( !Q_stricmp ( arg1, "kick" ) ) + { + int clientid = G_ClientNumberFromName ( arg2 ); + + if ( clientid == -1 ) + { + clientid = G_ClientNumberFromStrippedName(arg2); + + if (clientid == -1) + { + trap_SendServerCommand( ent-g_entities, va("print \"there is no client named '%s' currently on the server.\n\"", arg2 ) ); + return; + } + } + + Com_sprintf ( level.voteString, sizeof(level.voteString ), "clientkick %d", clientid ); + Com_sprintf ( level.voteDisplayString, sizeof(level.voteDisplayString), "kick %s", g_entities[clientid].client->pers.netname ); + } + else if ( !Q_stricmp( arg1, "nextmap" ) ) + { char s[MAX_STRING_CHARS]; trap_Cvar_VariableStringBuffer( "nextmap", s, sizeof(s) ); @@ -1507,7 +1655,9 @@ void Cmd_CallVote_f( gentity_t *ent ) { } Com_sprintf( level.voteString, sizeof( level.voteString ), "vstr nextmap"); Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "%s", level.voteString ); - } else { + } + else + { Com_sprintf( level.voteString, sizeof( level.voteString ), "%s \"%s\"", arg1, arg2 ); Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "%s", level.voteString ); } @@ -2174,9 +2324,10 @@ void Cmd_EngageDuel_f(gentity_t *ent) } } +void PM_SetAnim(int setAnimParts,int anim,int setAnimFlags, int blendTime); + #ifdef _DEBUG extern stringID_table_t animTable[MAX_ANIMATIONS+1]; -void PM_SetAnim(int setAnimParts,int anim,int setAnimFlags, int blendTime); void Cmd_DebugSetSaberMove_f(gentity_t *self) { @@ -2206,7 +2357,7 @@ void Cmd_DebugSetSaberMove_f(gentity_t *self) Com_Printf("Anim for move: %s\n", animTable[saberMoveData[self->client->ps.saberMove].animToUse].name); } -void Cmd_DebugSetBodyAnim_f(gentity_t *self) +void Cmd_DebugSetBodyAnim_f(gentity_t *self, int flags) { int argNum = trap_Argc(); char arg[MAX_STRING_CHARS]; @@ -2249,12 +2400,28 @@ void Cmd_DebugSetBodyAnim_f(gentity_t *self) pmv.gametype = g_gametype.integer; pm = &pmv; - PM_SetAnim(SETANIM_BOTH, i, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 0); + PM_SetAnim(SETANIM_BOTH, i, flags, 0); Com_Printf("Set body anim to %s\n", arg); } #endif +void StandardSetBodyAnim(gentity_t *self, int anim, int flags) +{ + pmove_t pmv; + + memset (&pmv, 0, sizeof(pmv)); + pmv.ps = &self->client->ps; + pmv.animations = bgGlobalAnimations; + pmv.cmd = self->client->pers.cmd; + pmv.trace = trap_Trace; + pmv.pointcontents = trap_PointContents; + pmv.gametype = g_gametype.integer; + + pm = &pmv; + PM_SetAnim(SETANIM_BOTH, anim, flags, 0); +} + void DismembermentTest(gentity_t *self); #ifdef _DEBUG @@ -2478,6 +2645,7 @@ void ClientCommand( int clientNum ) { */ //I broke the ATST when I restructured it to use a single global anim set for all client animation. //You can fix it, but you'll have to implement unique animations (per character) again. +#ifdef _DEBUG //sigh.. else if (Q_stricmp(cmd, "headexplodey") == 0 && CheatsOk( ent )) { Cmd_Kill_f (ent); @@ -2493,6 +2661,67 @@ void ClientCommand( int clientNum ) { { G_CreateExampleAnimEnt(ent); } + else if (Q_stricmp(cmd, "loveandpeace") == 0 && CheatsOk( ent )) + { + trace_t tr; + vec3_t fPos; + + AngleVectors(ent->client->ps.viewangles, fPos, 0, 0); + + fPos[0] = ent->client->ps.origin[0] + fPos[0]*40; + fPos[1] = ent->client->ps.origin[1] + fPos[1]*40; + fPos[2] = ent->client->ps.origin[2] + fPos[2]*40; + + trap_Trace(&tr, ent->client->ps.origin, 0, 0, fPos, ent->s.number, ent->clipmask); + + if (tr.entityNum < MAX_CLIENTS && tr.entityNum != ent->s.number) + { + gentity_t *other = &g_entities[tr.entityNum]; + + if (other && other->inuse && other->client) + { + vec3_t entDir; + vec3_t otherDir; + vec3_t entAngles; + vec3_t otherAngles; + + if (ent->client->ps.weapon == WP_SABER && !ent->client->ps.saberHolstered) + { + Cmd_ToggleSaber_f(ent); + } + + if (other->client->ps.weapon == WP_SABER && !other->client->ps.saberHolstered) + { + Cmd_ToggleSaber_f(other); + } + + if ((ent->client->ps.weapon != WP_SABER || ent->client->ps.saberHolstered) && + (other->client->ps.weapon != WP_SABER || other->client->ps.saberHolstered)) + { + VectorSubtract( other->client->ps.origin, ent->client->ps.origin, otherDir ); + VectorCopy( ent->client->ps.viewangles, entAngles ); + entAngles[YAW] = vectoyaw( otherDir ); + SetClientViewAngle( ent, entAngles ); + + StandardSetBodyAnim(ent, BOTH_KISSER1LOOP, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD|SETANIM_FLAG_HOLDLESS); + ent->client->ps.saberMove = LS_NONE; + ent->client->ps.saberBlocked = 0; + ent->client->ps.saberBlocking = 0; + + VectorSubtract( ent->client->ps.origin, other->client->ps.origin, entDir ); + VectorCopy( other->client->ps.viewangles, otherAngles ); + otherAngles[YAW] = vectoyaw( entDir ); + SetClientViewAngle( other, otherAngles ); + + StandardSetBodyAnim(other, BOTH_KISSEE1LOOP, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD|SETANIM_FLAG_HOLDLESS); + other->client->ps.saberMove = LS_NONE; + other->client->ps.saberBlocked = 0; + other->client->ps.saberBlocking = 0; + } + } + } + } +#endif else if (Q_stricmp(cmd, "thedestroyer") == 0 && CheatsOk( ent ) && ent && ent->client && ent->client->ps.saberHolstered && ent->client->ps.weapon == WP_SABER) { Cmd_ToggleSaber_f(ent); @@ -2521,7 +2750,7 @@ void ClientCommand( int clientNum ) { } else if (Q_stricmp(cmd, "debugSetBodyAnim") == 0) { - Cmd_DebugSetBodyAnim_f(ent); + Cmd_DebugSetBodyAnim_f(ent, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD); } else if (Q_stricmp(cmd, "debugDismemberment") == 0) { @@ -2544,6 +2773,21 @@ void ClientCommand( int clientNum ) { DismembermentByNum(ent, iArg); } } + else if (Q_stricmp(cmd, "debugKnockMeDown") == 0) + { + ent->client->ps.forceHandExtend = HANDEXTEND_KNOCKDOWN; + ent->client->ps.forceDodgeAnim = 0; + if (trap_Argc() > 1) + { + ent->client->ps.forceHandExtendTime = level.time + 1100; + ent->client->ps.quickerGetup = qfalse; + } + else + { + ent->client->ps.forceHandExtendTime = level.time + 700; + ent->client->ps.quickerGetup = qtrue; + } + } #endif else diff --git a/CODE-mp/game/g_combat.c b/CODE-mp/game/g_combat.c index 3c55228..3904d6a 100644 --- a/CODE-mp/game/g_combat.c +++ b/CODE-mp/game/g_combat.c @@ -890,6 +890,527 @@ void CheckAlmostCapture( gentity_t *self, gentity_t *attacker ) { #endif } +qboolean G_InKnockDown( playerState_t *ps ) +{ + switch ( (ps->legsAnim&~ANIM_TOGGLEBIT) ) + { + case BOTH_KNOCKDOWN1: + case BOTH_KNOCKDOWN2: + case BOTH_KNOCKDOWN3: + case BOTH_KNOCKDOWN4: + case BOTH_KNOCKDOWN5: + return qtrue; + break; + case BOTH_GETUP1: + case BOTH_GETUP2: + case BOTH_GETUP3: + case BOTH_GETUP4: + case BOTH_GETUP5: + case BOTH_FORCE_GETUP_F1: + case BOTH_FORCE_GETUP_F2: + case BOTH_FORCE_GETUP_B1: + case BOTH_FORCE_GETUP_B2: + case BOTH_FORCE_GETUP_B3: + case BOTH_FORCE_GETUP_B4: + case BOTH_FORCE_GETUP_B5: + return qtrue; + break; + } + return qfalse; +} + +static int G_CheckSpecialDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, int hitLoc ) +{ + int deathAnim = -1; + + if ( BG_InRoll( &self->client->ps, self->client->ps.legsAnim ) ) + { + deathAnim = BOTH_DEATH_ROLL; //# Death anim from a roll + } + else if ( BG_FlippingAnim( self->client->ps.legsAnim ) ) + { + deathAnim = BOTH_DEATH_FLIP; //# Death anim from a flip + } + else if ( G_InKnockDown( &self->client->ps ) ) + {//since these happen a lot, let's handle them case by case + int animLength = bgGlobalAnimations[self->client->ps.legsAnim&~ANIM_TOGGLEBIT].numFrames * fabs(bgGlobalAnimations[self->client->ps.legsAnim&~ANIM_TOGGLEBIT].frameLerp); + switch ( self->client->ps.legsAnim&~ANIM_TOGGLEBIT ) + { + case BOTH_KNOCKDOWN1: + if ( animLength - self->client->ps.legsTimer > 100 ) + {//on our way down + if ( self->client->ps.legsTimer > 600 ) + {//still partially up + deathAnim = BOTH_DEATH_FALLING_UP; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_UP; + } + } + break; + case BOTH_KNOCKDOWN2: + if ( animLength - self->client->ps.legsTimer > 700 ) + {//on our way down + if ( self->client->ps.legsTimer > 600 ) + {//still partially up + deathAnim = BOTH_DEATH_FALLING_UP; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_UP; + } + } + break; + case BOTH_KNOCKDOWN3: + if ( animLength - self->client->ps.legsTimer > 100 ) + {//on our way down + if ( self->client->ps.legsTimer > 1300 ) + {//still partially up + deathAnim = BOTH_DEATH_FALLING_DN; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_DN; + } + } + break; + case BOTH_KNOCKDOWN4: + if ( animLength - self->client->ps.legsTimer > 300 ) + {//on our way down + if ( self->client->ps.legsTimer > 350 ) + {//still partially up + deathAnim = BOTH_DEATH_FALLING_UP; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_UP; + } + } + else + {//crouch death + vec3_t fwd; + float thrown = 0; + + AngleVectors( self->client->ps.viewangles, fwd, NULL, NULL ); + thrown = DotProduct( fwd, self->client->ps.velocity ); + + if ( thrown < -150 ) + { + deathAnim = BOTH_DEATHBACKWARD1; //# Death anim when crouched and thrown back + } + else + { + deathAnim = BOTH_DEATH_CROUCHED; //# Death anim when crouched + } + } + break; + case BOTH_KNOCKDOWN5: + if ( self->client->ps.legsTimer < 750 ) + {//flat + deathAnim = BOTH_DEATH_LYING_DN; + } + break; + case BOTH_GETUP1: + if ( self->client->ps.legsTimer < 350 ) + {//standing up + } + else if ( self->client->ps.legsTimer < 800 ) + {//crouching + vec3_t fwd; + float thrown = 0; + + AngleVectors( self->client->ps.viewangles, fwd, NULL, NULL ); + thrown = DotProduct( fwd, self->client->ps.velocity ); + if ( thrown < -150 ) + { + deathAnim = BOTH_DEATHBACKWARD1; //# Death anim when crouched and thrown back + } + else + { + deathAnim = BOTH_DEATH_CROUCHED; //# Death anim when crouched + } + } + else + {//lying down + if ( animLength - self->client->ps.legsTimer > 450 ) + {//partially up + deathAnim = BOTH_DEATH_FALLING_UP; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_UP; + } + } + break; + case BOTH_GETUP2: + if ( self->client->ps.legsTimer < 150 ) + {//standing up + } + else if ( self->client->ps.legsTimer < 850 ) + {//crouching + vec3_t fwd; + float thrown = 0; + + AngleVectors( self->client->ps.viewangles, fwd, NULL, NULL ); + thrown = DotProduct( fwd, self->client->ps.velocity ); + + if ( thrown < -150 ) + { + deathAnim = BOTH_DEATHBACKWARD1; //# Death anim when crouched and thrown back + } + else + { + deathAnim = BOTH_DEATH_CROUCHED; //# Death anim when crouched + } + } + else + {//lying down + if ( animLength - self->client->ps.legsTimer > 500 ) + {//partially up + deathAnim = BOTH_DEATH_FALLING_UP; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_UP; + } + } + break; + case BOTH_GETUP3: + if ( self->client->ps.legsTimer < 250 ) + {//standing up + } + else if ( self->client->ps.legsTimer < 600 ) + {//crouching + vec3_t fwd; + float thrown = 0; + AngleVectors( self->client->ps.viewangles, fwd, NULL, NULL ); + thrown = DotProduct( fwd, self->client->ps.velocity ); + + if ( thrown < -150 ) + { + deathAnim = BOTH_DEATHBACKWARD1; //# Death anim when crouched and thrown back + } + else + { + deathAnim = BOTH_DEATH_CROUCHED; //# Death anim when crouched + } + } + else + {//lying down + if ( animLength - self->client->ps.legsTimer > 150 ) + {//partially up + deathAnim = BOTH_DEATH_FALLING_DN; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_DN; + } + } + break; + case BOTH_GETUP4: + if ( self->client->ps.legsTimer < 250 ) + {//standing up + } + else if ( self->client->ps.legsTimer < 600 ) + {//crouching + vec3_t fwd; + float thrown = 0; + + AngleVectors( self->client->ps.viewangles, fwd, NULL, NULL ); + thrown = DotProduct( fwd, self->client->ps.velocity ); + + if ( thrown < -150 ) + { + deathAnim = BOTH_DEATHBACKWARD1; //# Death anim when crouched and thrown back + } + else + { + deathAnim = BOTH_DEATH_CROUCHED; //# Death anim when crouched + } + } + else + {//lying down + if ( animLength - self->client->ps.legsTimer > 850 ) + {//partially up + deathAnim = BOTH_DEATH_FALLING_DN; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_UP; + } + } + break; + case BOTH_GETUP5: + if ( self->client->ps.legsTimer > 850 ) + {//lying down + if ( animLength - self->client->ps.legsTimer > 1500 ) + {//partially up + deathAnim = BOTH_DEATH_FALLING_DN; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_DN; + } + } + break; + case BOTH_GETUP_CROUCH_B1: + if ( self->client->ps.legsTimer < 800 ) + {//crouching + vec3_t fwd; + float thrown = 0; + + AngleVectors( self->client->ps.viewangles, fwd, NULL, NULL ); + thrown = DotProduct( fwd, self->client->ps.velocity ); + + if ( thrown < -150 ) + { + deathAnim = BOTH_DEATHBACKWARD1; //# Death anim when crouched and thrown back + } + else + { + deathAnim = BOTH_DEATH_CROUCHED; //# Death anim when crouched + } + } + else + {//lying down + if ( animLength - self->client->ps.legsTimer > 400 ) + {//partially up + deathAnim = BOTH_DEATH_FALLING_UP; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_UP; + } + } + break; + case BOTH_GETUP_CROUCH_F1: + if ( self->client->ps.legsTimer < 800 ) + {//crouching + vec3_t fwd; + float thrown = 0; + + AngleVectors( self->client->ps.viewangles, fwd, NULL, NULL ); + thrown = DotProduct( fwd, self->client->ps.velocity ); + + if ( thrown < -150 ) + { + deathAnim = BOTH_DEATHBACKWARD1; //# Death anim when crouched and thrown back + } + else + { + deathAnim = BOTH_DEATH_CROUCHED; //# Death anim when crouched + } + } + else + {//lying down + if ( animLength - self->client->ps.legsTimer > 150 ) + {//partially up + deathAnim = BOTH_DEATH_FALLING_DN; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_DN; + } + } + break; + case BOTH_FORCE_GETUP_B1: + if ( self->client->ps.legsTimer < 325 ) + {//standing up + } + else if ( self->client->ps.legsTimer < 725 ) + {//spinning up + deathAnim = BOTH_DEATH_SPIN_180; //# Death anim when facing backwards + } + else if ( self->client->ps.legsTimer < 900 ) + {//crouching + vec3_t fwd; + float thrown = 0; + + AngleVectors( self->client->ps.viewangles, fwd, NULL, NULL ); + thrown = DotProduct( fwd, self->client->ps.velocity ); + + if ( thrown < -150 ) + { + deathAnim = BOTH_DEATHBACKWARD1; //# Death anim when crouched and thrown back + } + else + { + deathAnim = BOTH_DEATH_CROUCHED; //# Death anim when crouched + } + } + else + {//lying down + if ( animLength - self->client->ps.legsTimer > 50 ) + {//partially up + deathAnim = BOTH_DEATH_FALLING_UP; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_UP; + } + } + break; + case BOTH_FORCE_GETUP_B2: + if ( self->client->ps.legsTimer < 575 ) + {//standing up + } + else if ( self->client->ps.legsTimer < 875 ) + {//spinning up + deathAnim = BOTH_DEATH_SPIN_180; //# Death anim when facing backwards + } + else if ( self->client->ps.legsTimer < 900 ) + {//crouching + vec3_t fwd; + float thrown = 0; + + AngleVectors( self->client->ps.viewangles, fwd, NULL, NULL ); + thrown = DotProduct( fwd, self->client->ps.velocity ); + + if ( thrown < -150 ) + { + deathAnim = BOTH_DEATHBACKWARD1; //# Death anim when crouched and thrown back + } + else + { + deathAnim = BOTH_DEATH_CROUCHED; //# Death anim when crouched + } + } + else + {//lying down + //partially up + deathAnim = BOTH_DEATH_FALLING_UP; + } + break; + case BOTH_FORCE_GETUP_B3: + if ( self->client->ps.legsTimer < 150 ) + {//standing up + } + else if ( self->client->ps.legsTimer < 775 ) + {//flipping + deathAnim = BOTH_DEATHBACKWARD2; //backflip + } + else + {//lying down + //partially up + deathAnim = BOTH_DEATH_FALLING_UP; + } + break; + case BOTH_FORCE_GETUP_B4: + if ( self->client->ps.legsTimer < 325 ) + {//standing up + } + else + {//lying down + if ( animLength - self->client->ps.legsTimer > 150 ) + {//partially up + deathAnim = BOTH_DEATH_FALLING_UP; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_UP; + } + } + break; + case BOTH_FORCE_GETUP_B5: + if ( self->client->ps.legsTimer < 550 ) + {//standing up + } + else if ( self->client->ps.legsTimer < 1025 ) + {//kicking up + deathAnim = BOTH_DEATHBACKWARD2; //backflip + } + else + {//lying down + if ( animLength - self->client->ps.legsTimer > 50 ) + {//partially up + deathAnim = BOTH_DEATH_FALLING_UP; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_UP; + } + } + break; + case BOTH_FORCE_GETUP_B6: + if ( self->client->ps.legsTimer < 225 ) + {//standing up + } + else if ( self->client->ps.legsTimer < 425 ) + {//crouching up + vec3_t fwd; + float thrown = 0; + + AngleVectors( self->client->ps.viewangles, fwd, NULL, NULL ); + thrown = DotProduct( fwd, self->client->ps.velocity ); + + if ( thrown < -150 ) + { + deathAnim = BOTH_DEATHBACKWARD1; //# Death anim when crouched and thrown back + } + else + { + deathAnim = BOTH_DEATH_CROUCHED; //# Death anim when crouched + } + } + else if ( self->client->ps.legsTimer < 825 ) + {//flipping up + deathAnim = BOTH_DEATHFORWARD3; //backflip + } + else + {//lying down + if ( animLength - self->client->ps.legsTimer > 225 ) + {//partially up + deathAnim = BOTH_DEATH_FALLING_UP; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_UP; + } + } + break; + case BOTH_FORCE_GETUP_F1: + if ( self->client->ps.legsTimer < 275 ) + {//standing up + } + else if ( self->client->ps.legsTimer < 750 ) + {//flipping + deathAnim = BOTH_DEATH14; + } + else + {//lying down + if ( animLength - self->client->ps.legsTimer > 100 ) + {//partially up + deathAnim = BOTH_DEATH_FALLING_DN; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_DN; + } + } + break; + case BOTH_FORCE_GETUP_F2: + if ( self->client->ps.legsTimer < 1200 ) + {//standing + } + else + {//lying down + if ( animLength - self->client->ps.legsTimer > 225 ) + {//partially up + deathAnim = BOTH_DEATH_FALLING_DN; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_DN; + } + } + break; + } + } + + return deathAnim; +} + int G_PickDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, int hitLoc ) {//FIXME: play dead flop anims on body if in an appropriate _DEAD anim when this func is called int deathAnim = -1; @@ -1036,63 +1557,36 @@ int G_PickDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, int hit } if ( deathAnim == -1 ) { - //death anims - switch( hitLoc ) + if (self->client) { - case HL_FOOT_RT: - case HL_FOOT_LT: - if ( mod == MOD_SABER && !Q_irand( 0, 2 ) ) - { - return BOTH_DEATH10;//chest: back flip - } - else if ( !Q_irand( 0, 2 ) ) - { - deathAnim = BOTH_DEATH4;//back: forward - } - else if ( !Q_irand( 0, 1 ) ) - { - deathAnim = BOTH_DEATH5;//same as 4 - } - else - { - deathAnim = BOTH_DEATH15;//back: forward - } - break; - case HL_LEG_RT: - if ( !Q_irand( 0, 2 ) ) - { - deathAnim = BOTH_DEATH4;//back: forward - } - else if ( !Q_irand( 0, 1 ) ) - { - deathAnim = BOTH_DEATH5;//same as 4 - } - else - { - deathAnim = BOTH_DEATH15;//back: forward - } - break; - case HL_LEG_LT: - if ( !Q_irand( 0, 2 ) ) - { - deathAnim = BOTH_DEATH4;//back: forward - } - else if ( !Q_irand( 0, 1 ) ) - { - deathAnim = BOTH_DEATH5;//same as 4 - } - else - { - deathAnim = BOTH_DEATH15;//back: forward - } - break; - case HL_BACK: - if ( !VectorLengthSquared( objVelocity ) ) - { - deathAnim = BOTH_DEATH17;//head/back: croak - } - else + deathAnim = G_CheckSpecialDeathAnim( self, point, damage, mod, hitLoc ); + } + + if (deathAnim == -1) + { + //death anims + switch( hitLoc ) { + case HL_FOOT_RT: + case HL_FOOT_LT: + if ( mod == MOD_SABER && !Q_irand( 0, 2 ) ) + { + return BOTH_DEATH10;//chest: back flip + } + else if ( !Q_irand( 0, 2 ) ) + { + deathAnim = BOTH_DEATH4;//back: forward + } + else if ( !Q_irand( 0, 1 ) ) + { + deathAnim = BOTH_DEATH5;//same as 4 + } + else + { + deathAnim = BOTH_DEATH15;//back: forward + } + break; + case HL_LEG_RT: if ( !Q_irand( 0, 2 ) ) { deathAnim = BOTH_DEATH4;//back: forward @@ -1105,135 +1599,170 @@ int G_PickDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, int hit { deathAnim = BOTH_DEATH15;//back: forward } - } - break; - case HL_CHEST_RT: - case HL_ARM_RT: - case HL_HAND_RT: - case HL_BACK_RT: - if ( damage <= max_health*0.25 ) - { - deathAnim = BOTH_DEATH9;//chest right: snap, fall forward - } - else if ( damage <= max_health*0.5 ) - { - deathAnim = BOTH_DEATH3;//chest right: back - } - else if ( damage <= max_health*0.75 ) - { - deathAnim = BOTH_DEATH6;//chest right: spin - } - else - { - //TEMP HACK: play spinny deaths less often - if ( Q_irand( 0, 1 ) ) + break; + case HL_LEG_LT: + if ( !Q_irand( 0, 2 ) ) { - deathAnim = BOTH_DEATH8;//chest right: spin high + deathAnim = BOTH_DEATH4;//back: forward + } + else if ( !Q_irand( 0, 1 ) ) + { + deathAnim = BOTH_DEATH5;//same as 4 } else { - switch ( Q_irand( 0, 2 ) ) + deathAnim = BOTH_DEATH15;//back: forward + } + break; + case HL_BACK: + if ( !VectorLengthSquared( objVelocity ) ) + { + deathAnim = BOTH_DEATH17;//head/back: croak + } + else + { + if ( !Q_irand( 0, 2 ) ) { - default: - case 0: - deathAnim = BOTH_DEATH9;//chest right: snap, fall forward - break; - case 1: - deathAnim = BOTH_DEATH3;//chest right: back - break; - case 2: - deathAnim = BOTH_DEATH6;//chest right: spin - break; + deathAnim = BOTH_DEATH4;//back: forward + } + else if ( !Q_irand( 0, 1 ) ) + { + deathAnim = BOTH_DEATH5;//same as 4 + } + else + { + deathAnim = BOTH_DEATH15;//back: forward } } - } - break; - case HL_CHEST_LT: - case HL_ARM_LT: - case HL_HAND_LT: - case HL_BACK_LT: - if ( damage <= max_health*0.25 ) - { - deathAnim = BOTH_DEATH11;//chest left: snap, fall forward - } - else if ( damage <= max_health*0.5 ) - { - deathAnim = BOTH_DEATH7;//chest left: back - } - else if ( damage <= max_health*0.75 ) - { - deathAnim = BOTH_DEATH12;//chest left: spin - } - else - { - //TEMP HACK: play spinny deaths less often - if ( Q_irand( 0, 1 ) ) + break; + case HL_CHEST_RT: + case HL_ARM_RT: + case HL_HAND_RT: + case HL_BACK_RT: + if ( damage <= max_health*0.25 ) { - deathAnim = BOTH_DEATH14;//chest left: spin high + deathAnim = BOTH_DEATH9;//chest right: snap, fall forward } - else + else if ( damage <= max_health*0.5 ) { - switch ( Q_irand( 0, 2 ) ) + deathAnim = BOTH_DEATH3;//chest right: back + } + else if ( damage <= max_health*0.75 ) + { + deathAnim = BOTH_DEATH6;//chest right: spin + } + else + { + //TEMP HACK: play spinny deaths less often + if ( Q_irand( 0, 1 ) ) { - default: - case 0: - deathAnim = BOTH_DEATH11;//chest left: snap, fall forward - break; - case 1: - deathAnim = BOTH_DEATH7;//chest left: back - break; - case 2: - deathAnim = BOTH_DEATH12;//chest left: spin - break; + deathAnim = BOTH_DEATH8;//chest right: spin high + } + else + { + switch ( Q_irand( 0, 2 ) ) + { + default: + case 0: + deathAnim = BOTH_DEATH9;//chest right: snap, fall forward + break; + case 1: + deathAnim = BOTH_DEATH3;//chest right: back + break; + case 2: + deathAnim = BOTH_DEATH6;//chest right: spin + break; + } } } - } - break; - case HL_CHEST: - case HL_WAIST: - if ( damage <= max_health*0.25 || !VectorLengthSquared( objVelocity ) ) - { - if ( !Q_irand( 0, 1 ) ) + break; + case HL_CHEST_LT: + case HL_ARM_LT: + case HL_HAND_LT: + case HL_BACK_LT: + if ( damage <= max_health*0.25 ) { - deathAnim = BOTH_DEATH18;//gut: fall right + deathAnim = BOTH_DEATH11;//chest left: snap, fall forward + } + else if ( damage <= max_health*0.5 ) + { + deathAnim = BOTH_DEATH7;//chest left: back + } + else if ( damage <= max_health*0.75 ) + { + deathAnim = BOTH_DEATH12;//chest left: spin } else { - deathAnim = BOTH_DEATH19;//gut: fall left + //TEMP HACK: play spinny deaths less often + if ( Q_irand( 0, 1 ) ) + { + deathAnim = BOTH_DEATH14;//chest left: spin high + } + else + { + switch ( Q_irand( 0, 2 ) ) + { + default: + case 0: + deathAnim = BOTH_DEATH11;//chest left: snap, fall forward + break; + case 1: + deathAnim = BOTH_DEATH7;//chest left: back + break; + case 2: + deathAnim = BOTH_DEATH12;//chest left: spin + break; + } + } } - } - else if ( damage <= max_health*0.5 ) - { - deathAnim = BOTH_DEATH2;//chest: backward short - } - else if ( damage <= max_health*0.75 ) - { - if ( !Q_irand( 0, 1 ) ) + break; + case HL_CHEST: + case HL_WAIST: + if ( damage <= max_health*0.25 || !VectorLengthSquared( objVelocity ) ) { - deathAnim = BOTH_DEATH1;//chest: backward med + if ( !Q_irand( 0, 1 ) ) + { + deathAnim = BOTH_DEATH18;//gut: fall right + } + else + { + deathAnim = BOTH_DEATH19;//gut: fall left + } + } + else if ( damage <= max_health*0.5 ) + { + deathAnim = BOTH_DEATH2;//chest: backward short + } + else if ( damage <= max_health*0.75 ) + { + if ( !Q_irand( 0, 1 ) ) + { + deathAnim = BOTH_DEATH1;//chest: backward med + } + else + { + deathAnim = BOTH_DEATH16;//same as 1 + } } else { - deathAnim = BOTH_DEATH16;//same as 1 + deathAnim = BOTH_DEATH10;//chest: back flip } + break; + case HL_HEAD: + if ( damage <= max_health*0.5 ) + { + deathAnim = BOTH_DEATH17;//head/back: croak + } + else + { + deathAnim = BOTH_DEATH13;//head: stumble, fall back + } + break; + default: + break; } - else - { - deathAnim = BOTH_DEATH10;//chest: back flip - } - break; - case HL_HEAD: - if ( damage <= max_health*0.5 ) - { - deathAnim = BOTH_DEATH17;//head/back: croak - } - else - { - deathAnim = BOTH_DEATH13;//head: stumble, fall back - } - break; - default: - break; } } return deathAnim; @@ -1282,6 +1811,15 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int return; } + if (g_slowmoDuelEnd.integer && g_gametype.integer == GT_TOURNAMENT && attacker && attacker->inuse && attacker->client) + { + if (!gDoSlowMoDuel) + { + gDoSlowMoDuel = qtrue; + gSlowMoDuelTime = level.time; + } + } + if (inflictor && inflictor->activator && !inflictor->client && !attacker->client && inflictor->activator->client && inflictor->activator->inuse && inflictor->s.weapon == WP_TURRET) @@ -2180,7 +2718,7 @@ void G_Dismember( gentity_t *ent, vec3_t point, int limbType, float limbRollBase else { limb->s.modelindex = -1; - limb->s.modelindex2 = ent->s.number; + limb->s.otherEntityNum2 = ent->s.number; } trap_LinkEntity( limb ); @@ -2610,7 +3148,7 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, } - if ( g_trueJedi.integer ) + if ( g_trueJedi.integer && client ) {//less explosive damage for jedi, more saber damage for non-jedi if ( client->ps.trueJedi ) {//if the target is a trueJedi, reduce splash and explosive damage to 1/2 @@ -2629,7 +3167,7 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, case MOD_TRIP_MINE_SPLASH: case MOD_TIMED_MINE_SPLASH: case MOD_DET_PACK_SPLASH: - damage *= 0.5; + damage *= 0.75; break; } } diff --git a/CODE-mp/game/g_local.h b/CODE-mp/game/g_local.h index 87fd55a..1d407f5 100644 --- a/CODE-mp/game/g_local.h +++ b/CODE-mp/game/g_local.h @@ -792,6 +792,8 @@ void DeathmatchScoreboardMessage (gentity_t *client); // g_main.c // extern vmCvar_t g_ff_objectives; +extern qboolean gDoSlowMoDuel; +extern int gSlowMoDuelTime; void FindIntermissionPoint( void ); void SetLeader(int team, int client); @@ -964,10 +966,22 @@ extern vmCvar_t g_saberGhoul2Collision; extern vmCvar_t g_saberAlwaysBoxTrace; extern vmCvar_t g_saberBoxTraceSize; +extern vmCvar_t g_logClientInfo; + +extern vmCvar_t g_slowmoDuelEnd; + +extern vmCvar_t g_saberDamageScale; + +extern vmCvar_t g_useWhileThrowing; + extern vmCvar_t g_forceRegenTime; extern vmCvar_t g_spawnInvulnerability; extern vmCvar_t g_forcePowerDisable; extern vmCvar_t g_weaponDisable; + +extern vmCvar_t g_allowDuelSuicide; +extern vmCvar_t g_fraglimitVoteCorrection; + extern vmCvar_t g_duelWeaponDisable; extern vmCvar_t g_fraglimit; extern vmCvar_t g_duel_fraglimit; diff --git a/CODE-mp/game/g_main.c b/CODE-mp/game/g_main.c index 7b073dd..9ee38a5 100644 --- a/CODE-mp/game/g_main.c +++ b/CODE-mp/game/g_main.c @@ -40,11 +40,21 @@ vmCvar_t g_saberGhoul2Collision; vmCvar_t g_saberAlwaysBoxTrace; vmCvar_t g_saberBoxTraceSize; +vmCvar_t g_logClientInfo; + +vmCvar_t g_slowmoDuelEnd; + +vmCvar_t g_saberDamageScale; + +vmCvar_t g_useWhileThrowing; + vmCvar_t g_forceRegenTime; vmCvar_t g_spawnInvulnerability; vmCvar_t g_forcePowerDisable; vmCvar_t g_weaponDisable; vmCvar_t g_duelWeaponDisable; +vmCvar_t g_allowDuelSuicide; +vmCvar_t g_fraglimitVoteCorrection; vmCvar_t g_fraglimit; vmCvar_t g_duel_fraglimit; vmCvar_t g_timelimit; @@ -136,7 +146,7 @@ static cvarTable_t gameCvarTable[] = { // change anytime vars { &g_ff_objectives, "g_ff_objectives", "0", /*CVAR_SERVERINFO |*/ CVAR_NORESTART, 0, qtrue }, - { &g_trueJedi, "g_jediVmerc", "0", CVAR_INTERNAL |CVAR_SERVERINFO | CVAR_LATCH, 0, qtrue }, + { &g_trueJedi, "g_jediVmerc", "0", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE, 0, qtrue }, { &g_autoMapCycle, "g_autoMapCycle", "0", CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue }, { &g_dmflags, "dmflags", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue }, @@ -154,6 +164,14 @@ static cvarTable_t gameCvarTable[] = { { &g_saberAlwaysBoxTrace, "g_saberAlwaysBoxTrace", "0", 0, 0, qtrue }, { &g_saberBoxTraceSize, "g_saberBoxTraceSize", "2", 0, 0, qtrue }, + { &g_logClientInfo, "g_logClientInfo", "0", CVAR_ARCHIVE, 0, qtrue }, + + { &g_slowmoDuelEnd, "g_slowmoDuelEnd", "0", CVAR_ARCHIVE, 0, qtrue }, + + { &g_saberDamageScale, "g_saberDamageScale", "1", CVAR_ARCHIVE, 0, qtrue }, + + { &g_useWhileThrowing, "g_useWhileThrowing", "1", 0, 0, qtrue }, + { &g_forceRegenTime, "g_forceRegenTime", "200", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue }, { &g_spawnInvulnerability, "g_spawnInvulnerability", "3000", CVAR_ARCHIVE, 0, qtrue }, @@ -162,6 +180,10 @@ static cvarTable_t gameCvarTable[] = { { &g_weaponDisable, "g_weaponDisable", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_LATCH, 0, qtrue }, { &g_duelWeaponDisable, "g_duelWeaponDisable", "1", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_LATCH, 0, qtrue }, + { &g_allowDuelSuicide, "g_allowDuelSuicide", "0", CVAR_ARCHIVE, 0, qtrue }, + + { &g_fraglimitVoteCorrection, "g_fraglimitVoteCorrection", "1", CVAR_ARCHIVE, 0, qtrue }, + { &g_fraglimit, "fraglimit", "20", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue }, { &g_duel_fraglimit, "duel_fraglimit", "10", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue }, { &g_timelimit, "timelimit", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue }, @@ -1685,6 +1707,11 @@ void CheckExitRules( void ) { return; } + if (gDoSlowMoDuel) + { //don't go to intermission while in slow motion + return; + } + if (gEscaping) { int i = 0; @@ -2001,6 +2028,28 @@ void CheckVote( void ) { { //otherwise, just leave the map until a restart G_RefreshNextMap(level.votingGametypeTo, qfalse); } + + if (g_fraglimitVoteCorrection.integer) + { //This means to auto-correct fraglimit when voting to and from duel. + int currentGT = trap_Cvar_VariableIntegerValue("g_gametype"); + int currentFL = trap_Cvar_VariableIntegerValue("fraglimit"); + + if (level.votingGametypeTo == GT_TOURNAMENT && currentGT != GT_TOURNAMENT) + { + if (currentFL > 3 || !currentFL) + { //if voting to duel, and fraglimit is more than 3 (or unlimited), then set it down to 3 + trap_SendConsoleCommand(EXEC_APPEND, "fraglimit 3\n"); + } + } + else if (level.votingGametypeTo != GT_TOURNAMENT && currentGT == GT_TOURNAMENT) + { + if (currentFL && currentFL < 20) + { //if voting from duel, an fraglimit is less than 20, then set it up to 20 + trap_SendConsoleCommand(EXEC_APPEND, "fraglimit 20\n"); + } + } + } + level.votingGametype = qfalse; level.votingGametypeTo = 0; } @@ -2196,6 +2245,9 @@ void G_RunThink (gentity_t *ent) { int g_LastFrameTime = 0; int g_TimeSinceLastFrame = 0; +qboolean gDoSlowMoDuel = qfalse; +int gSlowMoDuelTime = 0; + /* ================ G_RunFrame @@ -2208,7 +2260,64 @@ void G_RunFrame( int levelTime ) { int i; gentity_t *ent; int msec; -int start, end; + int start, end; + + if (gDoSlowMoDuel) + { + if (level.restarted) + { + char buf[128]; + float tFVal = 0; + + trap_Cvar_VariableStringBuffer("timescale", buf, sizeof(buf)); + + tFVal = atof(buf); + + trap_Cvar_Set("timescale", "1"); + if (tFVal == 1.0f) + { + gDoSlowMoDuel = qfalse; + } + } + else + { + float timeDif = (level.time - gSlowMoDuelTime); //difference in time between when the slow motion was initiated and now + float useDif = 0; //the difference to use when actually setting the timescale + + if (timeDif < 150) + { + trap_Cvar_Set("timescale", "0.1f"); + } + else if (timeDif < 1150) + { + useDif = (timeDif/1000); //scale from 0.1 up to 1 + if (useDif < 0.1) + { + useDif = 0.1; + } + if (useDif > 1.0) + { + useDif = 1.0; + } + trap_Cvar_Set("timescale", va("%f", useDif)); + } + else + { + char buf[128]; + float tFVal = 0; + + trap_Cvar_VariableStringBuffer("timescale", buf, sizeof(buf)); + + tFVal = atof(buf); + + trap_Cvar_Set("timescale", "1"); + if (timeDif > 1500 && tFVal == 1.0f) + { + gDoSlowMoDuel = qfalse; + } + } + } + } // if we are waiting for the level to restart, do nothing if ( level.restarted ) { @@ -2295,7 +2404,7 @@ int start, end; { G_CheckClientTimeouts ( ent ); - if((!level.intermissiontime)&&!(ent->client->ps.pm_flags&PMF_FOLLOW)) + if((!level.intermissiontime)&&!(ent->client->ps.pm_flags&PMF_FOLLOW) && ent->client->sess.sessionTeam != TEAM_SPECTATOR) { WP_ForcePowersUpdate(ent, &ent->client->pers.cmd ); WP_SaberPositionUpdate(ent, &ent->client->pers.cmd); diff --git a/CODE-mp/game/g_misc.c b/CODE-mp/game/g_misc.c index 2d9d096..05662c8 100644 --- a/CODE-mp/game/g_misc.c +++ b/CODE-mp/game/g_misc.c @@ -1552,6 +1552,9 @@ void SP_fx_runner( gentity_t *ent ) //rww - here starts the main example g2animent stuff #define ANIMENT_TYPE_STORMTROOPER 0 #define ANIMENT_TYPE_RODIAN 1 +#define ANIMENT_TYPE_JAN 2 +#define ANIMENT_TYPE_CUSTOM 3 +#define MAX_ANIMENTS 4 #define TROOPER_PAIN_SOUNDS 4 #define TROOPER_DEATH_SOUNDS 3 @@ -1567,12 +1570,245 @@ int gRodianSound_Pain[RODIAN_PAIN_SOUNDS]; int gRodianSound_Death[RODIAN_DEATH_SOUNDS]; int gRodianSound_Alert[RODIAN_ALERT_SOUNDS]; +#define JAN_PAIN_SOUNDS 4 +#define JAN_DEATH_SOUNDS 3 +#define JAN_ALERT_SOUNDS 5 +int gJanSound_Pain[JAN_PAIN_SOUNDS]; +int gJanSound_Death[JAN_DEATH_SOUNDS]; +int gJanSound_Alert[JAN_ALERT_SOUNDS]; + int G_PickDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, int hitLoc ); void AnimEntFireWeapon( gentity_t *ent, qboolean altFire ); int GetNearestVisibleWP(vec3_t org, int ignore); int InFieldOfVision(vec3_t viewangles, float fov, vec3_t angles); extern float gBotEdit; +#define ANIMENT_ALIGNED_UNKNOWN 0 +#define ANIMENT_ALIGNED_BAD 1 +#define ANIMENT_ALIGNED_GOOD 2 + +#define ANIMENT_CUSTOMSOUND_PAIN 0 +#define ANIMENT_CUSTOMSOUND_DEATH 1 +#define ANIMENT_CUSTOMSOUND_ALERT 2 + +int gAnimEntTypes = 0; + +typedef struct animentCustomInfo_s +{ + int aeAlignment; + int aeIndex; + int aeWeapon; + char *modelPath; + char *soundPath; + void *next; +} animentCustomInfo_t; + +animentCustomInfo_t *animEntRoot = NULL; + +animentCustomInfo_t *ExampleAnimEntCustomData(gentity_t *self) +{ + animentCustomInfo_t *iter = animEntRoot; + int safetyCheck = 0; + + while (iter && safetyCheck < 30000) + { + if (iter->aeIndex == self->waterlevel) + { + return iter; + } + + iter = iter->next; + safetyCheck++; + } + + return NULL; +} + +animentCustomInfo_t *ExampleAnimEntCustomDataExists(gentity_t *self, int alignment, int weapon, char *modelname, + char *soundpath) +{ + animentCustomInfo_t *iter = animEntRoot; + int safetyCheck = 0; + + while (iter && safetyCheck < 30000) + { + if (iter->aeAlignment == alignment && + iter->aeWeapon == weapon && + !Q_stricmp(iter->modelPath, modelname) && + !Q_stricmp(iter->soundPath, soundpath)) + { + return iter; + } + + iter = iter->next; + safetyCheck++; + } + + return NULL; +} + +void ExampleAnimEntCustomDataEntry(gentity_t *self, int alignment, int weapon, char *modelname, char *soundpath) +{ + animentCustomInfo_t *find = ExampleAnimEntCustomDataExists(self, alignment, weapon, modelname, soundpath); + animentCustomInfo_t *lastValid = NULL; + int safetyCheck = 0; + + if (find) + { //data for this guy already exists. Set our waterlevel (aeIndex) to use this. + self->waterlevel = find->aeIndex; + return; + } + + find = animEntRoot; + + while (find && safetyCheck < 30000) + { //find the next null pointer + lastValid = find; + find = find->next; + safetyCheck++; + } + + if (!find) + { + find = BG_Alloc(sizeof(animentCustomInfo_t)); + + if (!find) + { //careful not to exceed the BG_Alloc limit! + return; + } + + find->aeAlignment = alignment; + self->waterlevel = gAnimEntTypes; + find->aeIndex = self->waterlevel; + find->aeWeapon = weapon; + find->next = NULL; + + find->modelPath = BG_Alloc(strlen(modelname)+1); + find->soundPath = BG_Alloc(strlen(soundpath)+1); + + if (!find->modelPath || !find->soundPath) + { + find->aeIndex = -1; + return; + } + + strcpy(find->modelPath, modelname); + strcpy(find->soundPath, soundpath); + + find->modelPath[strlen(modelname)] = 0; + find->soundPath[strlen(modelname)] = 0; + + if (lastValid) + { + lastValid->next = find; + } + + if (!animEntRoot) + { + animEntRoot = find; + } + + gAnimEntTypes++; + } +} + +void AnimEntCustomSoundPrecache(animentCustomInfo_t *aeInfo) +{ + if (!aeInfo) + { + return; + } + + G_SoundIndex(va("%s/pain25", aeInfo->soundPath)); + G_SoundIndex(va("%s/pain50", aeInfo->soundPath)); + G_SoundIndex(va("%s/pain75", aeInfo->soundPath)); + G_SoundIndex(va("%s/pain100", aeInfo->soundPath)); + + G_SoundIndex(va("%s/death1", aeInfo->soundPath)); + G_SoundIndex(va("%s/death2", aeInfo->soundPath)); + G_SoundIndex(va("%s/death3", aeInfo->soundPath)); + + G_SoundIndex(va("%s/detected1", aeInfo->soundPath)); + G_SoundIndex(va("%s/detected2", aeInfo->soundPath)); + G_SoundIndex(va("%s/detected3", aeInfo->soundPath)); + G_SoundIndex(va("%s/detected4", aeInfo->soundPath)); + G_SoundIndex(va("%s/detected5", aeInfo->soundPath)); +} + +void ExampleAnimEntCustomSound(gentity_t *self, int soundType) +{ + animentCustomInfo_t *aeInfo = ExampleAnimEntCustomData(self); + int customSounds[16]; + int numSounds = 0; + + if (!aeInfo) + { + return; + } + + if (soundType == ANIMENT_CUSTOMSOUND_PAIN) + { + customSounds[0] = G_SoundIndex(va("%s/pain25", aeInfo->soundPath)); + customSounds[1] = G_SoundIndex(va("%s/pain50", aeInfo->soundPath)); + customSounds[2] = G_SoundIndex(va("%s/pain75", aeInfo->soundPath)); + customSounds[3] = G_SoundIndex(va("%s/pain100", aeInfo->soundPath)); + numSounds = 4; + } + else if (soundType == ANIMENT_CUSTOMSOUND_DEATH) + { + customSounds[0] = G_SoundIndex(va("%s/death1", aeInfo->soundPath)); + customSounds[1] = G_SoundIndex(va("%s/death2", aeInfo->soundPath)); + customSounds[2] = G_SoundIndex(va("%s/death3", aeInfo->soundPath)); + numSounds = 3; + } + else if (soundType == ANIMENT_CUSTOMSOUND_ALERT) + { + customSounds[0] = G_SoundIndex(va("%s/detected1", aeInfo->soundPath)); + customSounds[1] = G_SoundIndex(va("%s/detected2", aeInfo->soundPath)); + customSounds[2] = G_SoundIndex(va("%s/detected3", aeInfo->soundPath)); + customSounds[3] = G_SoundIndex(va("%s/detected4", aeInfo->soundPath)); + customSounds[4] = G_SoundIndex(va("%s/detected5", aeInfo->soundPath)); + numSounds = 5; + } + + if (!numSounds) + { + return; + } + + G_Sound(self, CHAN_AUTO, customSounds[Q_irand(0, numSounds-1)]); +} + +int ExampleAnimEntAlignment(gentity_t *self) +{ + if (self->watertype == ANIMENT_TYPE_STORMTROOPER) + { + return ANIMENT_ALIGNED_BAD; + } + + if (self->watertype == ANIMENT_TYPE_RODIAN) + { + return ANIMENT_ALIGNED_BAD; + } + + if (self->watertype == ANIMENT_TYPE_JAN) + { + return ANIMENT_ALIGNED_GOOD; + } + + if (self->watertype == ANIMENT_TYPE_CUSTOM) + { + animentCustomInfo_t *aeInfo = ExampleAnimEntCustomData(self); + + if (aeInfo) + { + return aeInfo->aeAlignment; + } + } + + return ANIMENT_ALIGNED_UNKNOWN; +} + void ExampleAnimEntAlertOthers(gentity_t *self) { //alert all the other animents in the area @@ -1584,7 +1820,8 @@ void ExampleAnimEntAlertOthers(gentity_t *self) g_entities[i].s.eType == ET_GRAPPLE && g_entities[i].health > 0) { - if (g_entities[i].bolt_Motion == ENTITYNUM_NONE && trap_InPVS(self->r.currentOrigin, g_entities[i].r.currentOrigin)) + if (g_entities[i].bolt_Motion == ENTITYNUM_NONE && trap_InPVS(self->r.currentOrigin, g_entities[i].r.currentOrigin) && + ExampleAnimEntAlignment(self) == ExampleAnimEntAlignment(&g_entities[i])) { g_entities[i].bolt_Motion = self->bolt_Motion; g_entities[i].speed = level.time + 4000; //4 seconds til we forget about the enemy @@ -1600,7 +1837,7 @@ void ExampleAnimEnt_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attac { self->s.torsoAnim = G_PickDeathAnim(self, self->pos1, damage, mod, HL_NONE); - if (self->s.torsoAnim < 0 || self->s.torsoAnim >= MAX_TOTALANIMATIONS) + if (self->s.torsoAnim <= 0 || self->s.torsoAnim >= MAX_TOTALANIMATIONS) { //?! (bad) self->s.torsoAnim = BOTH_DEATH1; } @@ -1619,6 +1856,14 @@ void ExampleAnimEnt_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attac { G_Sound(self, CHAN_AUTO, gRodianSound_Death[Q_irand(0, RODIAN_DEATH_SOUNDS-1)]); } + else if (self->watertype == ANIMENT_TYPE_JAN) + { + G_Sound(self, CHAN_AUTO, gJanSound_Death[Q_irand(0, JAN_DEATH_SOUNDS-1)]); + } + else if (self->watertype == ANIMENT_TYPE_CUSTOM) + { + ExampleAnimEntCustomSound(self, ANIMENT_CUSTOMSOUND_DEATH); + } if (mod == MOD_SABER) { //Set the velocity up a bit to make the limb fly up more than it otherwise would. @@ -1647,6 +1892,12 @@ void ExampleAnimEnt_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attac VectorCopy(preDelta, self->s.pos.trDelta); } + if (self->bolt_Motion == ENTITYNUM_NONE && + (attacker->client || attacker->s.eType == ET_GRAPPLE)) + { + self->bolt_Motion = attacker->s.number; + } + if (self->bolt_Motion != ENTITYNUM_NONE) { ExampleAnimEntAlertOthers(self); @@ -1671,6 +1922,11 @@ void ExampleAnimEnt_Pain(gentity_t *self, gentity_t *attacker, int damage) self->s.legsAnim = painAnim; self->bolt_LArm = level.time + animLen; + if (self->s.torsoAnim <= 0 || self->s.torsoAnim >= MAX_TOTALANIMATIONS) + { + self->s.torsoAnim = self->s.legsAnim = BOTH_PAIN1; + } + if (self->watertype == ANIMENT_TYPE_STORMTROOPER) { G_Sound(self, CHAN_AUTO, gTrooperSound_Pain[Q_irand(0, TROOPER_PAIN_SOUNDS-1)]); @@ -1679,13 +1935,24 @@ void ExampleAnimEnt_Pain(gentity_t *self, gentity_t *attacker, int damage) { G_Sound(self, CHAN_AUTO, gRodianSound_Pain[Q_irand(0, RODIAN_PAIN_SOUNDS-1)]); } - - if (attacker && attacker->client && self->bolt_Motion == ENTITYNUM_NONE) + else if (self->watertype == ANIMENT_TYPE_JAN) { - self->bolt_Motion = attacker->s.number; - self->speed = level.time + 4000; //4 seconds til we forget about the enemy - ExampleAnimEntAlertOthers(self); - self->bolt_RArm = level.time + Q_irand(500, 1000); + G_Sound(self, CHAN_AUTO, gJanSound_Pain[Q_irand(0, JAN_PAIN_SOUNDS-1)]); + } + else if (self->watertype == ANIMENT_TYPE_CUSTOM) + { + ExampleAnimEntCustomSound(self, ANIMENT_CUSTOMSOUND_PAIN); + } + + if (attacker && (attacker->client || attacker->s.eType == ET_GRAPPLE) && self->bolt_Motion == ENTITYNUM_NONE) + { + if (attacker->s.number >= MAX_CLIENTS || (ExampleAnimEntAlignment(self) != ANIMENT_ALIGNED_GOOD && !(attacker->r.svFlags & SVF_BOT))) + { + self->bolt_Motion = attacker->s.number; + self->speed = level.time + 4000; //4 seconds til we forget about the enemy + ExampleAnimEntAlertOthers(self); + self->bolt_RArm = level.time + Q_irand(500, 1000); + } } } @@ -1844,10 +2111,27 @@ qboolean ExampleAnimEntClearLOS(gentity_t *self, vec3_t point) trap_Trace(&tr, self->r.currentOrigin, 0, 0, point, self->s.number, self->clipmask); - if (tr.fraction == 1 || - tr.entityNum < MAX_CLIENTS) - { //clear LOS, or would be hitting a client (they're all bad!), so fire. - return qtrue; + if (ExampleAnimEntAlignment(self) == ANIMENT_ALIGNED_GOOD) + { + if (tr.fraction == 1 || + (g_entities[tr.entityNum].s.eType == ET_GRAPPLE && ExampleAnimEntAlignment(&g_entities[tr.entityNum]) != ANIMENT_ALIGNED_GOOD) || + (self->bolt_Motion < MAX_CLIENTS && tr.entityNum == self->bolt_Motion)) + { //clear LOS, or would be hitting a bad animent, so fire. + return qtrue; + } + else if (g_entities[tr.entityNum].inuse && g_entities[tr.entityNum].client && (g_entities[tr.entityNum].r.svFlags & SVF_BOT)) + { + return qtrue; + } + } + else + { + if (tr.fraction == 1 || + tr.entityNum < MAX_CLIENTS || + (g_entities[tr.entityNum].s.eType == ET_GRAPPLE && ExampleAnimEntAlignment(&g_entities[tr.entityNum]) != ANIMENT_ALIGNED_BAD)) + { //clear LOS, or would be hitting a client (they're all bad!), so fire. + return qtrue; + } } return qfalse; @@ -1872,7 +2156,19 @@ void ExampleAnimEntWeaponHandling(gentity_t *self) { AnimEntFireWeapon(self, qfalse); G_AddEvent(self, EV_FIRE_WEAPON, 0); - self->bolt_RArm = level.time + Q_irand(700, 1000); + + if (self->s.weapon == WP_REPEATER) + { + self->bolt_RArm = level.time + Q_irand(1, 500); + } + else if (ExampleAnimEntAlignment(self) == ANIMENT_ALIGNED_GOOD) + { + self->bolt_RArm = level.time + Q_irand(200, 400); + } + else + { + self->bolt_RArm = level.time + Q_irand(700, 1000); + } } } } @@ -2002,30 +2298,92 @@ void ExampleAnimEntEnemyHandling(gentity_t *self, float enDist) int bestIndex = -1; float minDist = enDist; - while (i < MAX_CLIENTS) + if (ExampleAnimEntAlignment(self) == ANIMENT_ALIGNED_GOOD) { - if (g_entities[i].inuse && g_entities[i].client && g_entities[i].health > 0 && g_entities[i].client->sess.sessionTeam != TEAM_SPECTATOR) + while (i < MAX_GENTITIES) { - vec3_t checkLen; - float fCheckLen; - - VectorSubtract(self->r.currentOrigin, g_entities[i].client->ps.origin, checkLen); - - fCheckLen = VectorLength(checkLen); - - if (fCheckLen < (minDist - 128)) + if (g_entities[i].inuse && (g_entities[i].s.eType == ET_GRAPPLE || (g_entities[i].client && (g_entities[i].r.svFlags & SVF_BOT))) && ExampleAnimEntAlignment(&g_entities[i]) != ANIMENT_ALIGNED_GOOD && g_entities[i].health > 0 && !(g_entities[i].s.eFlags & EF_DEAD)) { - vec3_t enAngles; - VectorSubtract(g_entities[i].client->ps.origin, self->r.currentOrigin, enAngles); - vectoangles(enAngles, enAngles); - if ((InFieldOfVision(self->s.apos.trBase, 120, enAngles) || self->s.genericenemyindex > level.time) && ExampleAnimEntClearLOS(self, g_entities[i].client->ps.origin)) + vec3_t checkLen; + float fCheckLen; + + VectorSubtract(self->r.currentOrigin, g_entities[i].r.currentOrigin, checkLen); + + fCheckLen = VectorLength(checkLen); + + if (fCheckLen < (minDist - 128)) { - minDist = fCheckLen; - bestIndex = i; + vec3_t enAngles; + VectorSubtract(g_entities[i].r.currentOrigin, self->r.currentOrigin, enAngles); + vectoangles(enAngles, enAngles); + if ((InFieldOfVision(self->s.apos.trBase, 120, enAngles) || self->s.genericenemyindex > level.time) && ExampleAnimEntClearLOS(self, g_entities[i].r.currentOrigin)) + { + minDist = fCheckLen; + bestIndex = i; + } } } + i++; + } + } + else + { + while (i < MAX_CLIENTS) + { + if (g_entities[i].inuse && g_entities[i].client && !(g_entities[i].r.svFlags & SVF_BOT) && g_entities[i].health > 0 && !(g_entities[i].s.eFlags & EF_DEAD) && g_entities[i].client->sess.sessionTeam != TEAM_SPECTATOR) + { + vec3_t checkLen; + float fCheckLen; + + VectorSubtract(self->r.currentOrigin, g_entities[i].client->ps.origin, checkLen); + + fCheckLen = VectorLength(checkLen); + + if (fCheckLen < (minDist - 128)) + { + vec3_t enAngles; + VectorSubtract(g_entities[i].client->ps.origin, self->r.currentOrigin, enAngles); + vectoangles(enAngles, enAngles); + if ((InFieldOfVision(self->s.apos.trBase, 120, enAngles) || self->s.genericenemyindex > level.time) && ExampleAnimEntClearLOS(self, g_entities[i].client->ps.origin)) + { + minDist = fCheckLen; + bestIndex = i; + } + } + } + i++; + } + + if (bestIndex == -1) + { + i = 0; + + while (i < MAX_GENTITIES) + { + if (g_entities[i].inuse && g_entities[i].s.eType == ET_GRAPPLE && ExampleAnimEntAlignment(&g_entities[i]) != ANIMENT_ALIGNED_BAD && g_entities[i].health > 0 && !(g_entities[i].s.eFlags & EF_DEAD)) + { + vec3_t checkLen; + float fCheckLen; + + VectorSubtract(self->r.currentOrigin, g_entities[i].r.currentOrigin, checkLen); + + fCheckLen = VectorLength(checkLen); + + if (fCheckLen < (minDist - 128)) + { + vec3_t enAngles; + VectorSubtract(g_entities[i].r.currentOrigin, self->r.currentOrigin, enAngles); + vectoangles(enAngles, enAngles); + if ((InFieldOfVision(self->s.apos.trBase, 120, enAngles) || self->s.genericenemyindex > level.time) && ExampleAnimEntClearLOS(self, g_entities[i].r.currentOrigin)) + { + minDist = fCheckLen; + bestIndex = i; + } + } + } + i++; + } } - i++; } if (bestIndex != -1) @@ -2044,6 +2402,14 @@ void ExampleAnimEntEnemyHandling(gentity_t *self, float enDist) { G_Sound(self, CHAN_AUTO, gRodianSound_Alert[Q_irand(0, RODIAN_ALERT_SOUNDS-1)]); } + else if (self->watertype == ANIMENT_TYPE_JAN) + { + G_Sound(self, CHAN_AUTO, gJanSound_Alert[Q_irand(0, JAN_ALERT_SOUNDS-1)]); + } + else if (self->watertype == ANIMENT_TYPE_CUSTOM) + { + ExampleAnimEntCustomSound(self, ANIMENT_CUSTOMSOUND_ALERT); + } } } @@ -2099,6 +2465,24 @@ void ExampleAnimEntUpdateSelf(gentity_t *self) } } + if (self->bolt_Motion < MAX_CLIENTS && + (!g_entities[self->bolt_Motion].inuse || + !g_entities[self->bolt_Motion].client)) + { + self->bolt_Motion = ENTITYNUM_NONE; + } + + if (self->bolt_Motion != ENTITYNUM_NONE && + g_entities[self->bolt_Motion].inuse && + (g_entities[self->bolt_Motion].client || g_entities[self->bolt_Motion].s.eType == ET_GRAPPLE)) + { + if (g_entities[self->bolt_Motion].health < 1 || + (g_entities[self->bolt_Motion].s.eFlags & EF_DEAD)) + { + self->bolt_Motion = ENTITYNUM_NONE; + } + } + if (gWPNum > 0) { if (self->bolt_Motion != ENTITYNUM_NONE && @@ -2123,6 +2507,19 @@ void ExampleAnimEntUpdateSelf(gentity_t *self) hasEnemyLOS = ExampleAnimEntClearLOS(self, enemyOrigin); } + else if (self->bolt_Motion != ENTITYNUM_NONE && + g_entities[self->bolt_Motion].inuse && + g_entities[self->bolt_Motion].s.eType == ET_GRAPPLE) + { + vec3_t enSubVec; + VectorSubtract(self->r.currentOrigin, g_entities[self->bolt_Motion].r.currentOrigin, enSubVec); + + enDist = VectorLength(enSubVec); + + VectorCopy(g_entities[self->bolt_Motion].r.currentOrigin, enemyOrigin); + + hasEnemyLOS = ExampleAnimEntClearLOS(self, enemyOrigin); + } if (hasEnemyLOS && enDist < 512 && self->splashRadius < level.time) { @@ -2165,7 +2562,14 @@ void ExampleAnimEntUpdateSelf(gentity_t *self) if (self->bolt_Motion == ENTITYNUM_NONE) { - runSpeed = 6; + if (ExampleAnimEntAlignment(self) == ANIMENT_ALIGNED_GOOD) + { + runSpeed = 18; + } + else + { + runSpeed = 6; + } } didMove = ExampleAnimEntMove(self, goalPos, runSpeed); @@ -2189,24 +2593,57 @@ void ExampleAnimEntUpdateSelf(gentity_t *self) } } } + else if (self->bolt_Motion != ENTITYNUM_NONE && + g_entities[self->bolt_Motion].inuse && + g_entities[self->bolt_Motion].s.eType == ET_GRAPPLE) + { + if (self->speed < level.time || g_entities[self->bolt_Motion].health < 1) + { + self->bolt_Motion = ENTITYNUM_NONE; + } + else + { + if (self->bolt_Motion != originalEnemyIndex) + { + vec3_t enSubVec; + VectorSubtract(self->r.currentOrigin, g_entities[self->bolt_Motion].r.currentOrigin, enSubVec); + + enDist = VectorLength(enSubVec); + } + } + } ExampleAnimEntEnemyHandling(self, enDist); if (self->bolt_Motion != ENTITYNUM_NONE && g_entities[self->bolt_Motion].inuse && - g_entities[self->bolt_Motion].client) + (g_entities[self->bolt_Motion].client || g_entities[self->bolt_Motion].s.eType == ET_GRAPPLE)) { + vec3_t enOrigin; + + if (g_entities[self->bolt_Motion].client) + { + VectorCopy(g_entities[self->bolt_Motion].client->ps.origin, enOrigin); + } + else + { + VectorCopy(g_entities[self->bolt_Motion].r.currentOrigin, enOrigin); + } + if (originalEnemyIndex != self->bolt_Motion) { - VectorCopy(g_entities[self->bolt_Motion].client->ps.origin, enemyOrigin); + VectorCopy(enOrigin, enemyOrigin); - if (g_entities[self->bolt_Motion].client->pers.cmd.upmove < 0) + if (g_entities[self->bolt_Motion].client) { - enemyOrigin[2] -= 8; - } - else - { - enemyOrigin[2] += 8; + if (g_entities[self->bolt_Motion].client->pers.cmd.upmove < 0) + { + enemyOrigin[2] -= 8; + } + else + { + enemyOrigin[2] += 8; + } } hasEnemyLOS = ExampleAnimEntClearLOS(self, enemyOrigin); @@ -2219,7 +2656,7 @@ void ExampleAnimEntUpdateSelf(gentity_t *self) vec3_t selfAimOrg; vec3_t myZeroPitchAngles; - VectorCopy(g_entities[self->bolt_Motion].client->ps.origin, enAimOrg); + VectorCopy(enOrigin, enAimOrg); VectorCopy(self->r.currentOrigin, selfAimOrg); enAimOrg[2] = selfAimOrg[2]; @@ -2271,8 +2708,8 @@ void ExampleAnimEntUpdateSelf(gentity_t *self) if (didMove == 1) { - if (self->bolt_Motion == ENTITYNUM_NONE) - { + if (self->bolt_Motion == ENTITYNUM_NONE && ExampleAnimEntAlignment(self) != ANIMENT_ALIGNED_GOOD) + { //Good guys are always on "alert" self->s.torsoAnim = BOTH_WALK1; self->s.legsAnim = BOTH_WALK1; } @@ -2306,7 +2743,7 @@ void ExampleAnimEntUpdateSelf(gentity_t *self) VectorCopy(preserveAngles, self->s.apos.trBase); } -void G_SpawnExampleAnimEnt(vec3_t pos, int aeType) +void G_SpawnExampleAnimEnt(vec3_t pos, int aeType, animentCustomInfo_t *aeInfo) { gentity_t *animEnt; vec3_t playerMins; @@ -2355,11 +2792,37 @@ void G_SpawnExampleAnimEnt(vec3_t pos, int aeType) gRodianSound_Alert[4] = G_SoundIndex("sound/chars/rodian1/misc/detected5"); } } + else if (aeType == ANIMENT_TYPE_JAN) + { + if (!gJanSound_Pain[0]) + { + gJanSound_Pain[0] = G_SoundIndex("sound/chars/jan/misc/pain25"); + gJanSound_Pain[1] = G_SoundIndex("sound/chars/jan/misc/pain50"); + gJanSound_Pain[2] = G_SoundIndex("sound/chars/jan/misc/pain75"); + gJanSound_Pain[3] = G_SoundIndex("sound/chars/jan/misc/pain100"); + + gJanSound_Death[0] = G_SoundIndex("sound/chars/jan/misc/death1"); + gJanSound_Death[1] = G_SoundIndex("sound/chars/jan/misc/death2"); + gJanSound_Death[2] = G_SoundIndex("sound/chars/jan/misc/death3"); + + gJanSound_Alert[0] = G_SoundIndex("sound/chars/jan/misc/detected1"); + gJanSound_Alert[1] = G_SoundIndex("sound/chars/jan/misc/detected2"); + gJanSound_Alert[2] = G_SoundIndex("sound/chars/jan/misc/detected3"); + gJanSound_Alert[3] = G_SoundIndex("sound/chars/jan/misc/detected4"); + gJanSound_Alert[4] = G_SoundIndex("sound/chars/jan/misc/detected5"); + } + } animEnt = G_Spawn(); animEnt->watertype = aeType; //set the animent type + if (aeType == ANIMENT_TYPE_CUSTOM && aeInfo) + { + ExampleAnimEntCustomDataEntry(animEnt, aeInfo->aeAlignment, aeInfo->aeWeapon, aeInfo->modelPath, aeInfo->soundPath); + AnimEntCustomSoundPrecache(aeInfo); + } + animEnt->s.eType = ET_GRAPPLE; //ET_GRAPPLE is the reserved special type for G2 anim ents. if (animEnt->watertype == ANIMENT_TYPE_STORMTROOPER) @@ -2370,6 +2833,23 @@ void G_SpawnExampleAnimEnt(vec3_t pos, int aeType) { animEnt->s.modelindex = G_ModelIndex( "models/players/rodian/model.glm" ); } + else if (animEnt->watertype == ANIMENT_TYPE_JAN) + { + animEnt->s.modelindex = G_ModelIndex( "models/players/jan/model.glm" ); + } + else if (animEnt->watertype == ANIMENT_TYPE_CUSTOM) + { + animentCustomInfo_t *aeInfo = ExampleAnimEntCustomData(animEnt); + + if (aeInfo) + { + animEnt->s.modelindex = G_ModelIndex(aeInfo->modelPath); + } + else + { + animEnt->s.modelindex = G_ModelIndex( "models/players/stormtrooper/model.glm" ); + } + } else { G_Error("Unknown AnimEnt type!\n"); @@ -2385,6 +2865,23 @@ void G_SpawnExampleAnimEnt(vec3_t pos, int aeType) { animEnt->s.weapon = WP_DISRUPTOR; //These guys get disruptors instead of blasters. } + else if (animEnt->watertype == ANIMENT_TYPE_JAN) + { + animEnt->s.weapon = WP_BLASTER; + } + else if (animEnt->watertype == ANIMENT_TYPE_CUSTOM) + { + animentCustomInfo_t *aeInfo = ExampleAnimEntCustomData(animEnt); + + if (aeInfo) + { + animEnt->s.weapon = aeInfo->aeWeapon; + } + else + { + animEnt->s.weapon = WP_BLASTER; + } + } animEnt->s.modelGhoul2 = 1; //Deal with it like any other ghoul2 ent, as far as killing instances. @@ -2433,7 +2930,7 @@ qboolean gEscaping = qfalse; int gEscapeTime = 0; #ifdef ANIMENT_SPAWNER -int AESpawner_CountAnimEnts(void) +int AESpawner_CountAnimEnts(gentity_t *spawner, qboolean onlySameType) { int i = 0; int count = 0; @@ -2442,7 +2939,27 @@ int AESpawner_CountAnimEnts(void) { if (g_entities[i].inuse && g_entities[i].s.eType == ET_GRAPPLE) { - count++; + if (!onlySameType) + { + count++; + } + else + { + if (spawner->watertype == g_entities[i].watertype) + { + if (spawner->watertype == ANIMENT_TYPE_CUSTOM) + { + if (spawner->waterlevel == g_entities[i].waterlevel) + { //only count it if it's the same custom type template, indicated by equal "waterlevel" value. + count++; + } + } + else + { + count++; + } + } + } } i++; } @@ -2500,6 +3017,7 @@ qboolean AESpawner_PassAnimEntPVSCheck(gentity_t *ent) void AESpawner_Think(gentity_t *ent) { int animEntCount; + animentCustomInfo_t *aeInfo = NULL; if (gBotEdit) { @@ -2513,7 +3031,13 @@ void AESpawner_Think(gentity_t *ent) } else { - animEntCount = AESpawner_CountAnimEnts(); + qboolean onlySameType = qfalse; + + if (ent->bolt_RLeg) + { + onlySameType = qtrue; + } + animEntCount = AESpawner_CountAnimEnts(ent, onlySameType); } if (animEntCount < ent->bolt_LLeg) @@ -2533,7 +3057,11 @@ void AESpawner_Think(gentity_t *ent) { if (AESpawner_PassAnimEntPVSCheck(ent)) { - G_SpawnExampleAnimEnt(ent->s.origin, ent->watertype); + if (ent->watertype == ANIMENT_TYPE_CUSTOM) + { + aeInfo = ExampleAnimEntCustomData(ent); //we can get this info from the spawner, because it has its waterlevel set too. + } + G_SpawnExampleAnimEnt(ent->s.origin, ent->watertype, aeInfo); } } } @@ -2560,6 +3088,9 @@ void SP_misc_animent_spawner(gentity_t *ent) //0 is unlimited, but that could cause horrible disaster. G_SpawnInt( "spawntype", "0", &ent->watertype); //Spawn type. 0 is stormtrooper, 1 is rodian. + G_SpawnInt( "sametype", "1", &ent->bolt_RLeg); + //If 1, only counts other animates of the same type for deciding whether or not to spawn (as opposed to all types). + //Default is 1. //Just precache the assets now if (ent->watertype == ANIMENT_TYPE_STORMTROOPER) @@ -2600,6 +3131,52 @@ void SP_misc_animent_spawner(gentity_t *ent) G_ModelIndex( "models/players/rodian/model.glm" ); } + else if (ent->watertype == ANIMENT_TYPE_JAN) + { + gJanSound_Pain[0] = G_SoundIndex("sound/chars/jan/misc/pain25"); + gJanSound_Pain[1] = G_SoundIndex("sound/chars/jan/misc/pain50"); + gJanSound_Pain[2] = G_SoundIndex("sound/chars/jan/misc/pain75"); + gJanSound_Pain[3] = G_SoundIndex("sound/chars/jan/misc/pain100"); + + gJanSound_Death[0] = G_SoundIndex("sound/chars/jan/misc/death1"); + gJanSound_Death[1] = G_SoundIndex("sound/chars/jan/misc/death2"); + gJanSound_Death[2] = G_SoundIndex("sound/chars/jan/misc/death3"); + + gJanSound_Alert[0] = G_SoundIndex("sound/chars/jan/misc/detected1"); + gJanSound_Alert[1] = G_SoundIndex("sound/chars/jan/misc/detected2"); + gJanSound_Alert[2] = G_SoundIndex("sound/chars/jan/misc/detected3"); + gJanSound_Alert[3] = G_SoundIndex("sound/chars/jan/misc/detected4"); + gJanSound_Alert[4] = G_SoundIndex("sound/chars/jan/misc/detected5"); + + G_ModelIndex( "models/players/jan/model.glm" ); + } + else if (ent->watertype == ANIMENT_TYPE_CUSTOM) + { + int alignment = 1; + int weapon = 3; + char *model; + char *soundpath; + animentCustomInfo_t *aeInfo; + + G_SpawnInt( "ae_aligned", "1", &alignment ); + //Alignedment - 1 is bad, 2 is good. + G_SpawnInt( "ae_weapon", "3", &weapon); + //Weapon - Same values as normal weapons. + G_SpawnString( "ae_model", "models/players/stormtrooper/model.glm", &model); + //Model to use + G_SpawnString( "ae_soundpath", "sound/chars/jan/misc", &soundpath); + //Sound path to use + + ExampleAnimEntCustomDataEntry(ent, alignment, weapon, model, soundpath); + + aeInfo = ExampleAnimEntCustomData(ent); + + if (aeInfo) + { + AnimEntCustomSoundPrecache(aeInfo); + G_ModelIndex( aeInfo->modelPath ); + } + } ent->think = AESpawner_Think; ent->nextthink = level.time + Q_irand(50, 500); @@ -2689,6 +3266,28 @@ void SP_target_escapetrig(gentity_t *ent) void G_CreateExampleAnimEnt(gentity_t *ent) { vec3_t fwd, fwdPos; + animentCustomInfo_t aeInfo; + char arg[MAX_STRING_CHARS]; + int iArg = 0; + int argNum = trap_Argc(); + + memset(&aeInfo, 0, sizeof(aeInfo)); + + if (argNum > 1) + { + trap_Argv( 1, arg, sizeof( arg ) ); + + iArg = atoi(arg); + + if (iArg < 0) + { + iArg = 0; + } + if (iArg >= MAX_ANIMENTS) + { + iArg = MAX_ANIMENTS-1; + } + } AngleVectors(ent->client->ps.viewangles, fwd, 0, 0); @@ -2696,7 +3295,52 @@ void G_CreateExampleAnimEnt(gentity_t *ent) fwdPos[1] = ent->client->ps.origin[1] + fwd[1]*128; fwdPos[2] = ent->client->ps.origin[2] + fwd[2]*128; - G_SpawnExampleAnimEnt(fwdPos, 0); + if (iArg == ANIMENT_TYPE_CUSTOM) + { + char arg2[MAX_STRING_CHARS]; + + if (argNum > 2) + { + trap_Argv( 2, arg, sizeof( arg ) ); + aeInfo.aeAlignment = atoi(arg); + } + else + { + aeInfo.aeAlignment = ANIMENT_ALIGNED_BAD; + } + + if (argNum > 3) + { + trap_Argv( 3, arg, sizeof( arg ) ); + aeInfo.aeWeapon = atoi(arg); + } + else + { + aeInfo.aeWeapon = WP_BRYAR_PISTOL; + } + + if (argNum > 4) + { + trap_Argv( 4, arg, sizeof( arg ) ); + aeInfo.modelPath = arg; + } + else + { + aeInfo.modelPath = "models/players/stormtrooper/model.glm"; + } + + if (argNum > 5) + { + trap_Argv( 5, arg2, sizeof( arg2 ) ); + aeInfo.soundPath = arg2; + } + else + { + aeInfo.soundPath = "sound/chars/jan/misc"; + } + } + + G_SpawnExampleAnimEnt(fwdPos, iArg, &aeInfo); } //rww - here ends the main example g2animent stuff diff --git a/CODE-mp/game/g_team.c b/CODE-mp/game/g_team.c index 2d7cd85..d345808 100644 --- a/CODE-mp/game/g_team.c +++ b/CODE-mp/game/g_team.c @@ -190,7 +190,23 @@ qboolean OnSameTeam( gentity_t *ent1, gentity_t *ent2 ) { if (g_gametype.integer == GT_SINGLE_PLAYER) { - return qtrue; + qboolean ent1IsBot = qfalse; + qboolean ent2IsBot = qfalse; + + if (ent1->r.svFlags & SVF_BOT) + { + ent1IsBot = qtrue; + } + if (ent2->r.svFlags & SVF_BOT) + { + ent2IsBot = qtrue; + } + + if ((ent1IsBot && ent2IsBot) || (!ent1IsBot && !ent2IsBot)) + { + return qtrue; + } + return qfalse; } if ( g_gametype.integer < GT_TEAM ) { diff --git a/CODE-mp/game/g_weapon.c b/CODE-mp/game/g_weapon.c index a6453a9..880cf1c 100644 --- a/CODE-mp/game/g_weapon.c +++ b/CODE-mp/game/g_weapon.c @@ -816,7 +816,14 @@ static void WP_BowcasterMainFire( gentity_t *ent ) gentity_t *missile; int i; - count = ( level.time - ent->client->ps.weaponChargeTime ) / BOWCASTER_CHARGE_UNIT; + if (!ent->client) + { + count = 1; + } + else + { + count = ( level.time - ent->client->ps.weaponChargeTime ) / BOWCASTER_CHARGE_UNIT; + } if ( count < 1 ) { @@ -2524,8 +2531,16 @@ void WP_FireStunBaton( gentity_t *ent, qboolean alt_fire ) vec3_t mins, maxs, end; vec3_t muzzleStun; - VectorCopy(ent->client->ps.origin, muzzleStun); - muzzleStun[2] += ent->client->ps.viewheight-6; + if (!ent->client) + { + VectorCopy(ent->r.currentOrigin, muzzleStun); + muzzleStun[2] += 8; + } + else + { + VectorCopy(ent->client->ps.origin, muzzleStun); + muzzleStun[2] += ent->client->ps.viewheight-6; + } muzzleStun[0] += forward[0]*20; muzzleStun[1] += forward[1]*20; @@ -2557,7 +2572,8 @@ void WP_FireStunBaton( gentity_t *ent, qboolean alt_fire ) return; } - if (ent->client->ps.duelInProgress && + if (ent->client && + ent->client->ps.duelInProgress && ent->client->ps.duelIndex != tr_ent->s.number) { return; diff --git a/CODE-mp/game/q_shared.h b/CODE-mp/game/q_shared.h index 893cc84..e1268ae 100644 --- a/CODE-mp/game/q_shared.h +++ b/CODE-mp/game/q_shared.h @@ -672,7 +672,7 @@ extern vec4_t colorDkBlue; #define Q_COLOR_ESCAPE '^' // you MUST have the last bit on here about colour strings being less than 7 or taiwanese strings register as colour!!!! -#define Q_IsColorString(p) ( p && *(p) == Q_COLOR_ESCAPE && *((p)+1) && *((p)+1) != Q_COLOR_ESCAPE && *((p)+1) <= '7' ) +#define Q_IsColorString(p) ( p && *(p) == Q_COLOR_ESCAPE && *((p)+1) && *((p)+1) != Q_COLOR_ESCAPE && *((p)+1) <= '7' && *((p)+1) >= '0' ) #define COLOR_BLACK '0' diff --git a/CODE-mp/game/surfaceflags.h b/CODE-mp/game/surfaceflags.h index 77a142e..243cbe1 100644 --- a/CODE-mp/game/surfaceflags.h +++ b/CODE-mp/game/surfaceflags.h @@ -12,8 +12,8 @@ #define CONTENTS_WATER 0x00000004 #define CONTENTS_FOG 0x00000008 #define CONTENTS_PLAYERCLIP 0x00000010 -#define CONTENTS_MONSTERCLIP 0x00000020 -#define CONTENTS_BOTCLIP 0x00000040 +#define CONTENTS_MONSTERCLIP 0x00000020 // Physically block bots +#define CONTENTS_BOTCLIP 0x00000040 // A hint for bots - do not enter this brush by navigation (if possible) #define CONTENTS_SHOTCLIP 0x00000080 #define CONTENTS_BODY 0x00000100 // should never be on a brush, only in game #define CONTENTS_CORPSE 0x00000200 // should never be on a brush, only in game diff --git a/CODE-mp/game/w_force.c b/CODE-mp/game/w_force.c index 70ad534..ecd5a08 100644 --- a/CODE-mp/game/w_force.c +++ b/CODE-mp/game/w_force.c @@ -21,6 +21,8 @@ int ysalamiriLoopSound = 0; #define FORCE_VELOCITY_DAMAGE 0 +int ForceShootDrain( gentity_t *self ); + gentity_t *G_PreDefSound(vec3_t org, int pdSound) { gentity_t *te; @@ -481,11 +483,6 @@ void WP_SpawnInitForcePowers( gentity_t *ent ) if (HasSetSaberOnly()) { - /* - ent->client->ps.fd.forcePowerLevel[FP_SABERATTACK] = FORCE_LEVEL_3; - ent->client->ps.fd.forcePowerLevel[FP_SABERDEFEND] = FORCE_LEVEL_3; - ent->client->ps.fd.forcePowerLevel[FP_SABERTHROW] = FORCE_LEVEL_3; - */ if (ent->client->ps.fd.forcePowerLevel[FP_SABERATTACK] < FORCE_LEVEL_1) { ent->client->ps.fd.forcePowerLevel[FP_SABERATTACK] = FORCE_LEVEL_1; @@ -501,9 +498,6 @@ void WP_SpawnInitForcePowers( gentity_t *ent ) while (i < NUM_FORCE_POWERS) { - //Don't know why I was doing this here either. - //ent->client->ps.fd.forcePowerBaseLevel[i] = ent->client->ps.fd.forcePowerLevel[i]; - ent->client->ps.fd.forcePowerDebounce[i] = 0; ent->client->ps.fd.forcePowerDuration[i] = 0; @@ -511,8 +505,6 @@ void WP_SpawnInitForcePowers( gentity_t *ent ) } ent->client->ps.fd.forcePowerRegenDebounceTime = 0; - //I wonder why I was doing this. - //ent->client->ps.fd.forceUsingAdded = 0; ent->client->ps.fd.forceJumpZStart = 0; ent->client->ps.fd.forceJumpCharge = 0; ent->client->ps.fd.forceJumpSound = 0; @@ -722,28 +714,29 @@ int WP_AbsorbConversion(gentity_t *attacked, int atdAbsLevel, gentity_t *attacke } void WP_ForcePowerRegenerate( gentity_t *self, int overrideAmt ) -{ +{ //called on a regular interval to regenerate force power. if ( !self->client ) { return; } if ( overrideAmt ) - { + { //custom regen amount self->client->ps.fd.forcePower += overrideAmt; } else - { + { //otherwise, just 1 self->client->ps.fd.forcePower++; } + if ( self->client->ps.fd.forcePower > self->client->ps.fd.forcePowerMax ) - { + { //cap it off at the max (default 100) self->client->ps.fd.forcePower = self->client->ps.fd.forcePowerMax; } } void WP_ForcePowerStart( gentity_t *self, forcePowers_t forcePower, int overrideAmt ) -{ +{ //activate the given force power int duration = 0; qboolean hearable = qfalse; float hearDist = 0; @@ -753,10 +746,8 @@ void WP_ForcePowerStart( gentity_t *self, forcePowers_t forcePower, int override return; } - //FIXME: debounce some of these - - //and it in - //set up duration time + //hearable and hearDist are merely for the benefit of bots, and not related to if a sound is actually played. + //If duration is set, the force power will assume to be timer-based. switch( (int)forcePower ) { case FP_HEAL: @@ -829,7 +820,6 @@ void WP_ForcePowerStart( gentity_t *self, forcePowers_t forcePower, int override case FP_GRIP: hearable = qtrue; hearDist = 256; - //duration = 1000; self->client->ps.fd.forcePowersActive |= ( 1 << forcePower ); self->client->ps.powerups[PW_DISINT_4] = level.time + 60000; break; @@ -924,6 +914,7 @@ void WP_ForcePowerStart( gentity_t *self, forcePowers_t forcePower, int override default: break; } + if ( duration ) { self->client->ps.fd.forcePowerDuration[forcePower] = level.time + duration; @@ -958,12 +949,6 @@ void ForceHeal( gentity_t *self ) return; } - /*if ( WP_ForcePowerInUse(self, FP_HEAL)) - { - WP_ForcePowerStop(self, FP_HEAL); - return; - }*/ - if ( !WP_ForcePowerUsable( self, FP_HEAL ) ) { return; @@ -1013,8 +998,6 @@ void ForceHeal( gentity_t *self ) //NOTE: Decided to make all levels instant. G_Sound( self, CHAN_ITEM, G_SoundIndex("sound/weapons/force/heal.wav") ); - // No character heal voices -// G_Sound( self, CHAN_VOICE, G_SoundIndex(va( "sound/weapons/force/heal%d.mp3", Q_irand( 1, 4 ) )) ); } void WP_AddToClientBitflags(gentity_t *ent, int entNum) @@ -1136,7 +1119,6 @@ void ForceTeamHeal( gentity_t *self ) WP_AddToClientBitflags(te, pl[i]); //Now cramming it all into one event.. doing this many g_sound events at once was a Bad Thing. - //G_Sound( &g_entities[pl[i]], CHAN_ITEM, G_SoundIndex("sound/weapons/force/teamheal.wav") ); } i++; } @@ -1230,7 +1212,6 @@ void ForceTeamForceReplenish( gentity_t *self ) WP_AddToClientBitflags(te, pl[i]); //Now cramming it all into one event.. doing this many g_sound events at once was a Bad Thing. - //G_Sound( &g_entities[pl[i]], CHAN_ITEM, G_SoundIndex("sound/weapons/force/teamforce.wav") ); i++; } @@ -1281,14 +1262,13 @@ void ForceGrip( gentity_t *self ) !g_entities[tr.entityNum].client->ps.fd.forceGripCripple && g_entities[tr.entityNum].client->ps.fd.forceGripBeingGripped < level.time && ForcePowerUsableOn(self, &g_entities[tr.entityNum], FP_GRIP) && - //g_entities[tr.entityNum].client->ps.fd.forcePowerLevel[FP_ABSORB] < self->client->ps.fd.forcePowerLevel[FP_GRIP] && (g_friendlyFire.integer || !OnSameTeam(self, &g_entities[tr.entityNum])) ) //don't grip someone who's still crippled { self->client->ps.fd.forceGripEntityNum = tr.entityNum; g_entities[tr.entityNum].client->ps.fd.forceGripStarted = level.time; self->client->ps.fd.forceGripDamageDebounceTime = 0; - self->client->ps.forceHandExtend = HANDEXTEND_FORCEGRIP;//HANDEXTEND_FORCEPUSH; + self->client->ps.forceHandExtend = HANDEXTEND_FORCEGRIP; self->client->ps.forceHandExtendTime = level.time + 5000; } else @@ -1321,7 +1301,6 @@ void ForceSpeed( gentity_t *self, int forceDuration ) WP_ForcePowerStart( self, FP_SPEED, forceDuration ); G_Sound( self, CHAN_BODY, G_SoundIndex("sound/weapons/force/speed.wav") ); - //G_AddEvent(self, EV_STARTLOOPINGSOUND, speedLoopSound); G_Sound( self, TRACK_CHANNEL_2, speedLoopSound ); self->client->ps.fd.forceSpeedSmash = 2; //initial boost (will automax to whatever is appropriate for force level) self->client->ps.fd.forceSpeedDoDamage = 0; @@ -1499,14 +1478,10 @@ void ForceLightning( gentity_t *self ) } //Shoot lightning from hand -// self->client->ps.forceHandExtend = HANDEXTEND_FORCEPUSH; -// self->client->ps.forceHandExtendTime = level.time + 1000; - //rww - using grip anim now, to extend the burst time - self->client->ps.forceHandExtend = HANDEXTEND_FORCEGRIP;//HANDEXTEND_FORCEPUSH; + //using grip anim now, to extend the burst time + self->client->ps.forceHandExtend = HANDEXTEND_FORCEGRIP; self->client->ps.forceHandExtendTime = level.time + 20000; - - //G_SoundOnEnt( self, CHAN_BODY, "sound/weapons/force/lightning.wav" ); G_Sound( self, CHAN_BODY, G_SoundIndex("sound/weapons/force/lightning.wav") ); WP_ForcePowerStart( self, FP_LIGHTNING, 500 ); @@ -1559,7 +1534,7 @@ void ForceLightningDamage( gentity_t *self, gentity_t *traceEnt, vec3_t dir, vec if (dmg) { //rww - Shields can now absorb lightning too. - G_Damage( traceEnt, self, self, dir, impactPoint, dmg, /*DAMAGE_NO_ARMOR*/0, MOD_FORCE_DARK ); + G_Damage( traceEnt, self, self, dir, impactPoint, dmg, 0, MOD_FORCE_DARK ); } if ( traceEnt->client ) { @@ -1667,7 +1642,7 @@ void ForceShootLightning( gentity_t *self ) } //in PVS? - if ( !traceEnt->r.bmodel && !trap_InPVS( ent_org, /*self->client->renderInfo.handLPoint*/self->client->ps.origin ) ) + if ( !traceEnt->r.bmodel && !trap_InPVS( ent_org, self->client->ps.origin ) ) {//must be in PVS continue; } @@ -1682,7 +1657,6 @@ void ForceShootLightning( gentity_t *self ) // ok, we are within the radius, add us to the incoming list ForceLightningDamage( self, traceEnt, dir, ent_org ); } - } else {//trace-line @@ -1699,8 +1673,6 @@ void ForceShootLightning( gentity_t *self ) } } -int ForceShootDrain( gentity_t *self ); - void ForceDrain( gentity_t *self ) { if ( self->health <= 0 ) @@ -1920,8 +1892,6 @@ int ForceShootDrain( gentity_t *self ) continue; if ( !traceEnt->client->ps.fd.forcePower ) continue; -// if (traceEnt->client->ps.fd.forceSide == FORCE_DARKSIDE) // We no longer care if the victim is dark or light -// continue; if (OnSameTeam(self, traceEnt)) continue; //this is all to see if we need to start a saber attack, if it's in flight, this doesn't matter @@ -1958,7 +1928,7 @@ int ForceShootDrain( gentity_t *self ) } //in PVS? - if ( !traceEnt->r.bmodel && !trap_InPVS( ent_org, /*self->client->renderInfo.handLPoint*/self->client->ps.origin ) ) + if ( !traceEnt->r.bmodel && !trap_InPVS( ent_org, self->client->ps.origin ) ) {//must be in PVS continue; } @@ -1974,7 +1944,6 @@ int ForceShootDrain( gentity_t *self ) ForceDrainDamage( self, traceEnt, dir, ent_org ); gotOneOrMore = 1; } - } else {//trace-line @@ -1993,14 +1962,7 @@ int ForceShootDrain( gentity_t *self ) self->client->ps.activeForcePass = self->client->ps.fd.forcePowerLevel[FP_DRAIN] + FORCE_LEVEL_3; -/* if (self->client->ps.fd.forcePowerLevel[FP_DRAIN] == FORCE_LEVEL_1) - { - BG_ForcePowerDrain( &self->client->ps, FP_DRAIN, 0 ); - } - else*/ - { - 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, 5 ); //used to be 1, but this did, too, anger the God of Balance. self->client->ps.fd.forcePowerRegenDebounceTime = level.time + 500; @@ -2008,7 +1970,7 @@ int ForceShootDrain( gentity_t *self ) } void ForceJumpCharge( gentity_t *self, usercmd_t *ucmd ) -{ +{ //I guess this is unused now. Was used for the "charge" jump type. float forceJumpChargeInterval = forceJumpStrength[0] / (FORCE_JUMP_CHARGE_TIME/FRAMETIME); if ( self->health <= 0 ) @@ -2129,7 +2091,7 @@ int WP_GetVelocityForForceJump( gentity_t *self, vec3_t jumpVel, usercmd_t *ucmd VectorMA( self->client->ps.velocity, pushFwd, forward, jumpVel ); VectorMA( self->client->ps.velocity, pushRt, right, jumpVel ); - jumpVel[2] += self->client->ps.fd.forceJumpCharge;//forceJumpStrength; + jumpVel[2] += self->client->ps.fd.forceJumpCharge; if ( pushFwd > 0 && self->client->ps.fd.forceJumpCharge > 200 ) { return FJ_FORWARD; @@ -2147,7 +2109,7 @@ int WP_GetVelocityForForceJump( gentity_t *self, vec3_t jumpVel, usercmd_t *ucmd return FJ_LEFT; } else - {//FIXME: jump straight up anim + { return FJ_UP; } } @@ -2155,9 +2117,7 @@ int WP_GetVelocityForForceJump( gentity_t *self, vec3_t jumpVel, usercmd_t *ucmd void ForceJump( gentity_t *self, usercmd_t *ucmd ) { float forceJumpChargeInterval; -// int anim; vec3_t jumpVel; -// int parts = SETANIM_BOTH; if ( self->client->ps.fd.forcePowerDuration[FP_LEVITATION] > level.time ) { @@ -2171,10 +2131,6 @@ void ForceJump( gentity_t *self, usercmd_t *ucmd ) { return; } -// if ( self->client->ps.pm_flags&PMF_JUMP_HELD ) -// { -// return; -// } if ( self->health <= 0 ) { return; @@ -2184,41 +2140,7 @@ void ForceJump( gentity_t *self, usercmd_t *ucmd ) forceJumpChargeInterval = forceJumpStrength[self->client->ps.fd.forcePowerLevel[FP_LEVITATION]]/(FORCE_JUMP_CHARGE_TIME/FRAMETIME); - switch( WP_GetVelocityForForceJump( self, jumpVel, ucmd ) ) - { - case FJ_FORWARD: -// anim = BOTH_FLIP_F; - //dmEvent = DM_FLIP; - break; - case FJ_BACKWARD: -// anim = BOTH_FLIP_B; - //dmEvent = DM_FLIP; - break; - case FJ_RIGHT: -// anim = BOTH_FLIP_R; - //dmEvent = DM_FLIP; - break; - case FJ_LEFT: -// anim = BOTH_FLIP_L; - //dmEvent = DM_FLIP; - break; - default: - case FJ_UP: -// anim = BOTH_JUMP1; - //dmEvent = DM_JUMP; - break; - } - - if ( self->client->ps.weaponTime ) - {//FIXME: really only care if we're in a saber attack anim.. maybe trail length? -// parts = SETANIM_LEGS; - } - - //NPC_SetAnim( self, parts, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); - if ( !self->s.number ) - { - //G_DynaMixEvent( dmEvent ); - } + WP_GetVelocityForForceJump( self, jumpVel, ucmd ); //FIXME: sound effect self->client->ps.fd.forceJumpZStart = self->client->ps.origin[2];//remember this for when we land @@ -2304,12 +2226,6 @@ void ForceTelepathy(gentity_t *self) return; } -/* if ( WP_ForcePowerInUse(self, FP_TELEPATHY)) - { - WP_ForcePowerStop(self, FP_TELEPATHY); - return; - }*/ - if ( !WP_ForcePowerUsable( self, FP_TELEPATHY ) ) { return; @@ -2317,7 +2233,7 @@ void ForceTelepathy(gentity_t *self) if (self->client->ps.fd.forcePowerLevel[FP_TELEPATHY] == FORCE_LEVEL_2) { - visionArc = 360;//180; + visionArc = 360; } else if (self->client->ps.fd.forcePowerLevel[FP_TELEPATHY] == FORCE_LEVEL_3) { @@ -2353,7 +2269,6 @@ void ForceTelepathy(gentity_t *self) g_entities[tr.entityNum].client->sess.sessionTeam != TEAM_SPECTATOR) { WP_AddAsMindtricked(&self->client->ps.fd, tr.entityNum); - //self->client->ps.fd.forceMindtrickTargetIndex |= (1 << tr.entityNum); WP_ForcePowerStart( self, FP_TELEPATHY, 0 ); G_Sound( self, CHAN_AUTO, G_SoundIndex("sound/weapons/force/distract.wav") ); @@ -2365,7 +2280,6 @@ void ForceTelepathy(gentity_t *self) } else { - //self->client->ps.fd.forceMindtrickTargetIndex = ENTITYNUM_NONE; return; } } @@ -2497,7 +2411,6 @@ void ForceTelepathy(gentity_t *self) { gotatleastone = 1; WP_AddAsMindtricked(&self->client->ps.fd, ent->s.number); - //self->client->ps.fd.forceMindtrickTargetIndex |= (1 << ent->s.number); } e++; @@ -2539,10 +2452,12 @@ qboolean CanCounterThrow(gentity_t *self, qboolean pull) { return 0; } + if ( self->client->ps.powerups[PW_DISINT_4] > level.time ) { return 0; } + if (pull) { powerUse = FP_PULL; @@ -2565,6 +2480,45 @@ qboolean CanCounterThrow(gentity_t *self, qboolean pull) return 1; } +qboolean G_InGetUpAnim(playerState_t *ps) +{ + switch( (ps->legsAnim&~ANIM_TOGGLEBIT) ) + { + case BOTH_GETUP1: + case BOTH_GETUP2: + case BOTH_GETUP3: + case BOTH_GETUP4: + case BOTH_GETUP5: + case BOTH_FORCE_GETUP_F1: + case BOTH_FORCE_GETUP_F2: + case BOTH_FORCE_GETUP_B1: + case BOTH_FORCE_GETUP_B2: + case BOTH_FORCE_GETUP_B3: + case BOTH_FORCE_GETUP_B4: + case BOTH_FORCE_GETUP_B5: + return qtrue; + } + + switch( (ps->torsoAnim&~ANIM_TOGGLEBIT) ) + { + case BOTH_GETUP1: + case BOTH_GETUP2: + case BOTH_GETUP3: + case BOTH_GETUP4: + case BOTH_GETUP5: + case BOTH_FORCE_GETUP_F1: + case BOTH_FORCE_GETUP_F2: + case BOTH_FORCE_GETUP_B1: + case BOTH_FORCE_GETUP_B2: + case BOTH_FORCE_GETUP_B3: + case BOTH_FORCE_GETUP_B4: + case BOTH_FORCE_GETUP_B5: + return qtrue; + } + + return qfalse; +} + extern void Touch_Button(gentity_t *ent, gentity_t *other, trace_t *trace ); void ForceThrow( gentity_t *self, qboolean pull ) { @@ -2595,7 +2549,12 @@ void ForceThrow( gentity_t *self, qboolean pull ) visionArc = 0; - if (self->client->ps.forceHandExtend != HANDEXTEND_NONE) + if (self->client->ps.forceHandExtend != HANDEXTEND_NONE && (self->client->ps.forceHandExtend != HANDEXTEND_KNOCKDOWN || !G_InGetUpAnim(&self->client->ps))) + { + return; + } + + if (!g_useWhileThrowing.integer && self->client->ps.saberInFlight) { return; } @@ -2630,8 +2589,6 @@ void ForceThrow( gentity_t *self, qboolean pull ) if (!pull && self->client->ps.saberLockTime > level.time && self->client->ps.saberLockFrame) { G_Sound( self, CHAN_BODY, G_SoundIndex( "sound/weapons/force/push.wav" ) ); - //self->client->ps.forceHandExtend = HANDEXTEND_FORCEPUSH; - //self->client->ps.forceHandExtendTime = level.time + 1000; self->client->ps.powerups[PW_DISINT_4] = level.time + 1500; self->client->ps.saberLockHits += self->client->ps.fd.forcePowerLevel[FP_PUSH]*2; @@ -2646,16 +2603,31 @@ void ForceThrow( gentity_t *self, qboolean pull ) if ( pull ) { G_Sound( self, CHAN_BODY, G_SoundIndex( "sound/weapons/force/pull.wav" ) ); - self->client->ps.forceHandExtend = HANDEXTEND_FORCEPULL; - self->client->ps.forceHandExtendTime = level.time + 400; + if (self->client->ps.forceHandExtend == HANDEXTEND_NONE) + { + self->client->ps.forceHandExtend = HANDEXTEND_FORCEPULL; + self->client->ps.forceHandExtendTime = level.time + 400; + } + self->client->ps.powerups[PW_DISINT_4] = self->client->ps.forceHandExtendTime + 200; } else { G_Sound( self, CHAN_BODY, G_SoundIndex( "sound/weapons/force/push.wav" ) ); - self->client->ps.forceHandExtend = HANDEXTEND_FORCEPUSH; - self->client->ps.forceHandExtendTime = level.time + 1000; + if (self->client->ps.forceHandExtend == HANDEXTEND_NONE) + { + self->client->ps.forceHandExtend = HANDEXTEND_FORCEPUSH; + self->client->ps.forceHandExtendTime = level.time + 1000; + } + else if (self->client->ps.forceHandExtend == HANDEXTEND_KNOCKDOWN && G_InGetUpAnim(&self->client->ps)) + { + if (self->client->ps.forceDodgeAnim > 4) + { + self->client->ps.forceDodgeAnim -= 8; + } + self->client->ps.forceDodgeAnim += 8; //special case, play push on upper torso, but keep playing current knockdown anim on legs + } + self->client->ps.powerups[PW_DISINT_4] = level.time + 1100; } - self->client->ps.powerups[PW_DISINT_4] = self->client->ps.forceHandExtendTime + 200; VectorCopy( self->client->ps.viewangles, fwdangles ); AngleVectors( fwdangles, forward, right, NULL ); @@ -2755,7 +2727,6 @@ void ForceThrow( gentity_t *self, qboolean pull ) } } - //if (ent && !InFront(thispush_org, self->client->ps.origin, self->client->ps.viewangles, visionArc)) if (ent) { //not in the arc, don't consider it VectorCopy(self->client->ps.origin, tto); @@ -2792,7 +2763,6 @@ void ForceThrow( gentity_t *self, qboolean pull ) for ( e = 0 ; e < numListedEntities ; e++ ) { - //ent = entityList[ e ]; if (entityList[e] != ENTITYNUM_NONE && entityList[e] >= 0 && entityList[e] < MAX_GENTITIES) @@ -2812,13 +2782,11 @@ void ForceThrow( gentity_t *self, qboolean pull ) { continue; } -// if ( ent->owner == self && ent->s.weapon != WP_THERMAL )//can push your own thermals -// continue; if ( !(ent->inuse) ) continue; if ( ent->s.eType != ET_MISSILE ) { - if ( ent->s.eType != ET_ITEM /*&& ent->e_ThinkFunc != thinkF_G_RunObject*/ )//|| !(ent->flags&FL_DROPPED_ITEM) )//was only dropped items + if ( ent->s.eType != ET_ITEM ) { //FIXME: need pushable objects if ( Q_stricmp( "func_button", ent->classname ) == 0 ) @@ -2838,22 +2806,18 @@ void ForceThrow( gentity_t *self, qboolean pull ) { if ( Q_stricmp( "lightsaber", ent->classname ) != 0 ) {//not a lightsaber - // if ( !(ent->svFlags&SVF_GLASS_BRUSH) ) - // {//and not glass - if ( Q_stricmp( "func_door", ent->classname ) != 0 || !(ent->spawnflags & 2/*MOVER_FORCE_ACTIVATE*/) ) - {//not a force-usable door - if ( Q_stricmp( "limb", ent->classname ) ) - {//not a limb - continue; - } - } - else if ( ent->moverState != MOVER_POS1 && ent->moverState != MOVER_POS2 ) - {//not at rest + if ( Q_stricmp( "func_door", ent->classname ) != 0 || !(ent->spawnflags & 2/*MOVER_FORCE_ACTIVATE*/) ) + {//not a force-usable door + if ( Q_stricmp( "limb", ent->classname ) ) + {//not a limb continue; } - // } + } + else if ( ent->moverState != MOVER_POS1 && ent->moverState != MOVER_POS2 ) + {//not at rest + continue; + } } - //continue; } } } @@ -2924,8 +2888,6 @@ void ForceThrow( gentity_t *self, qboolean pull ) if ( ent_count ) { - //vec3_t fx_dir; - // we are done, do we have any to deflect? //method1: for ( x = 0; x < ent_count; x++ ) { @@ -3063,18 +3025,15 @@ void ForceThrow( gentity_t *self, qboolean pull ) if (modPowerLevel > otherPushPower && push_list[x]->client) { - //int levDif = modPowerLevel - otherPushPower; - - if (/*Q_irand(1, 5) <= levDif &&*/ - modPowerLevel == FORCE_LEVEL_3 && + if (modPowerLevel == FORCE_LEVEL_3 && push_list[x]->client->ps.forceHandExtend != HANDEXTEND_KNOCKDOWN) { dirLen = VectorLength(pushDir); - if (dirLen <= 128) + if (dirLen <= (64*((modPowerLevel - otherPushPower)-1))) { //can only do a knockdown if fairly close push_list[x]->client->ps.forceHandExtend = HANDEXTEND_KNOCKDOWN; - push_list[x]->client->ps.forceHandExtendTime = level.time + 1100; + push_list[x]->client->ps.forceHandExtendTime = level.time + 700; push_list[x]->client->ps.forceDodgeAnim = 0; //this toggles between 1 and 0, when it's 1 we should play the get up anim push_list[x]->client->ps.quickerGetup = qtrue; } @@ -3140,11 +3099,9 @@ void ForceThrow( gentity_t *self, qboolean pull ) else { G_ReflectMissile( self, push_list[x], forward ); - //deflect sound - //G_Sound( push_list[x], G_SoundIndex( va("sound/weapons/blaster/reflect%d.wav", Q_irand( 1, 3 ) ) ) ); } } - else if ( !Q_stricmp( "func_door", push_list[x]->classname ) && (push_list[x]->spawnflags&2/*MOVER_FORCE_ACTIVATE*/) ) + else if ( !Q_stricmp( "func_door", push_list[x]->classname ) && (push_list[x]->spawnflags&2) ) {//push/pull the door vec3_t pos1, pos2; @@ -3233,7 +3190,6 @@ void WP_ForcePowerStop( gentity_t *self, forcePowers_t forcePower ) case FP_LEVITATION: break; case FP_SPEED: - //G_AddEvent(self, EV_STOPLOOPINGSOUND, 0); if (wasActive & (1 << FP_SPEED)) { G_MuteSound(self->client->ps.fd.killSoundEntIndex[TRACK_CHANNEL_2-50], CHAN_VOICE); @@ -3248,7 +3204,7 @@ void WP_ForcePowerStop( gentity_t *self, forcePowers_t forcePower ) { G_Sound( self, CHAN_AUTO, G_SoundIndex("sound/weapons/force/distractstop.wav") ); } - self->client->ps.fd.forceMindtrickTargetIndex = 0;//ENTITYNUM_NONE; + self->client->ps.fd.forceMindtrickTargetIndex = 0; self->client->ps.fd.forceMindtrickTargetIndex2 = 0; self->client->ps.fd.forceMindtrickTargetIndex3 = 0; self->client->ps.fd.forceMindtrickTargetIndex4 = 0; @@ -3292,13 +3248,13 @@ void WP_ForcePowerStop( gentity_t *self, forcePowers_t forcePower ) case FP_LIGHTNING: if ( self->client->ps.fd.forcePowerLevel[FP_LIGHTNING] < FORCE_LEVEL_2 ) {//don't do it again for 3 seconds, minimum... FIXME: this should be automatic once regeneration is slower (normal) - self->client->ps.fd.forcePowerDebounce[FP_LIGHTNING] = level.time + 3000;//FIXME: define? + self->client->ps.fd.forcePowerDebounce[FP_LIGHTNING] = level.time + 3000; } else { - self->client->ps.fd.forcePowerDebounce[FP_LIGHTNING] = level.time + 1500;//500; //500 is still too powerful + self->client->ps.fd.forcePowerDebounce[FP_LIGHTNING] = level.time + 1500; } - if (self->client->ps.forceHandExtend == /*HANDEXTEND_FORCEPUSH*/HANDEXTEND_FORCEGRIP) + if (self->client->ps.forceHandExtend == HANDEXTEND_FORCEGRIP) { self->client->ps.forceHandExtendTime = 0; //reset hand position } @@ -3326,15 +3282,15 @@ void WP_ForcePowerStop( gentity_t *self, forcePowers_t forcePower ) break; case FP_DRAIN: if ( self->client->ps.fd.forcePowerLevel[FP_DRAIN] < FORCE_LEVEL_2 ) - {//don't do it again for 3 seconds, minimum... FIXME: this should be automatic once regeneration is slower (normal) - self->client->ps.fd.forcePowerDebounce[FP_DRAIN] = level.time + 3000;//FIXME: define? + {//don't do it again for 3 seconds, minimum... + self->client->ps.fd.forcePowerDebounce[FP_DRAIN] = level.time + 3000; } else { - self->client->ps.fd.forcePowerDebounce[FP_DRAIN] = level.time + 1500;//500; //500 is still too powerful + self->client->ps.fd.forcePowerDebounce[FP_DRAIN] = level.time + 1500; } - if (self->client->ps.forceHandExtend == /*HANDEXTEND_FORCEPUSH*/HANDEXTEND_FORCEGRIP) + if (self->client->ps.forceHandExtend == HANDEXTEND_FORCEGRIP) { self->client->ps.forceHandExtendTime = 0; //reset hand position } @@ -3447,7 +3403,8 @@ void DoGripAction(gentity_t *self, forcePowers_t forcePower) { //if we managed to lift him into the air for 2 seconds, give him a crack self->client->ps.fd.forceGripDamageDebounceTime = 1; G_Damage(gripEnt, self, self, NULL, NULL, 20, DAMAGE_NO_ARMOR, MOD_FORCE_DARK); - //NOTE: Must play custom sounds on the actual entity. Don't use G_Sound (it creates a temp entity for the sound) + + //Must play custom sounds on the actual entity. Don't use G_Sound (it creates a temp entity for the sound) G_EntitySound( gripEnt, CHAN_VOICE, G_SoundIndex(va( "*choke%d.wav", Q_irand( 1, 3 ) )) ); gripEnt->client->ps.forceHandExtend = HANDEXTEND_CHOKE; @@ -3532,7 +3489,8 @@ void DoGripAction(gentity_t *self, forcePowers_t forcePower) { //if we managed to lift him into the air for 2 seconds, give him a crack self->client->ps.fd.forceGripDamageDebounceTime = 1; G_Damage(gripEnt, self, self, NULL, NULL, 40, DAMAGE_NO_ARMOR, MOD_FORCE_DARK); - //NOTE: Must play custom sounds on the actual entity. Don't use G_Sound (it creates a temp entity for the sound) + + //Must play custom sounds on the actual entity. Don't use G_Sound (it creates a temp entity for the sound) G_EntitySound( gripEnt, CHAN_VOICE, G_SoundIndex(va( "*choke%d.wav", Q_irand( 1, 3 ) )) ); gripEnt->client->ps.forceHandExtend = HANDEXTEND_CHOKE; @@ -3640,9 +3598,7 @@ static void WP_UpdateMindtrickEnts(gentity_t *self) } else if ((level.time - self->client->dangerTime) < g_TimeSinceLastFrame*4) { //Untrick this entity if the tricker (self) fires while in his fov - if (/*InFront(self->client->ps.origin, ent->client->ps.origin, ent->client->ps.viewangles, 0.8f ) &&*/ - //NOTE: No longer has to be in fov, just in visible area of PVS - trap_InPVS(ent->client->ps.origin, self->client->ps.origin) && + if (trap_InPVS(ent->client->ps.origin, self->client->ps.origin) && OrgVisible(ent->client->ps.origin, self->client->ps.origin, ent->s.number)) { RemoveTrickedEnt(&self->client->ps.fd, i); @@ -3705,7 +3661,7 @@ static void WP_ForcePowerRun( gentity_t *self, forcePowers_t forcePower, usercmd self->client->ps.fd.forceHealTime = level.time + 1000; self->health++; self->client->ps.fd.forceHealAmount++; - //BG_ForcePowerDrain( &self->client->ps, forcePower, 0 ); + if ( self->health > self->client->ps.stats[STAT_MAX_HEALTH]) // Past max health { self->health = self->client->ps.stats[STAT_MAX_HEALTH]; @@ -3747,24 +3703,6 @@ static void WP_ForcePowerRun( gentity_t *self, forcePowers_t forcePower, usercmd {//done with jump WP_ForcePowerStop( self, forcePower ); } - else - { - /* - if (self->client->ps.fd.forcePowerDebounce[FP_LEVITATION] < level.time) - { - BG_ForcePowerDrain( &self->client->ps, forcePower, 5 ); - if (self->client->ps.fd.forcePowerLevel[FP_LEVITATION] >= FORCE_LEVEL_2) - { - self->client->ps.fd.forcePowerDebounce[FP_LEVITATION] = level.time + 300; - } - else - { - self->client->ps.fd.forcePowerDebounce[FP_LEVITATION] = level.time + 200; - } - } - */ - //NOTE: Now handled in bg code for prediction - } break; case FP_RAGE: if (self->health < 1) @@ -3802,7 +3740,7 @@ static void WP_ForcePowerRun( gentity_t *self, forcePowers_t forcePower, usercmd self->client->ps.stats[STAT_HEALTH] = self->health; break; case FP_DRAIN: - if (self->client->ps.forceHandExtend != /*HANDEXTEND_FORCEPUSH*/HANDEXTEND_FORCEGRIP) + if (self->client->ps.forceHandExtend != HANDEXTEND_FORCEGRIP) { WP_ForcePowerStop(self, forcePower); break; @@ -3826,8 +3764,7 @@ static void WP_ForcePowerRun( gentity_t *self, forcePowers_t forcePower, usercmd } break; case FP_LIGHTNING: - //self->client->ps.forceHandExtendTime = level.time + 200; - if (self->client->ps.forceHandExtend != /*HANDEXTEND_FORCEPUSH*/HANDEXTEND_FORCEGRIP) + if (self->client->ps.forceHandExtend != HANDEXTEND_FORCEGRIP) { //Animation for hand extend doesn't end with hand out, so we have to limit lightning intervals by animation intervals (once hand starts to go in in animation, lightning should stop) WP_ForcePowerStop(self, forcePower); break; @@ -4054,7 +3991,7 @@ int WP_DoSpecificPower( gentity_t *self, usercmd_t *ucmd, forcePowers_t forcepow } void FindGenericEnemyIndex(gentity_t *self) -{ +{ //Find another client that would be considered a threat. int i = 0; float tlen; gentity_t *ent; @@ -4072,7 +4009,6 @@ void FindGenericEnemyIndex(gentity_t *self) tlen = VectorLength(a); if (tlen < blen && - //InFieldOfVision(ent->client->ps.viewangles, 90, a) && InFront(ent->client->ps.origin, self->client->ps.origin, self->client->ps.viewangles, 0.8f ) && OrgVisible(self->client->ps.origin, ent->client->ps.origin, self->s.number)) { @@ -4203,7 +4139,6 @@ void SeekerDroneUpdate(gentity_t *self) } else { - //if (!InFieldOfVision(en->client->ps.viewangles, 90, a)) if (!InFront(en->client->ps.origin, self->client->ps.origin, self->client->ps.viewangles, 0.8f )) { self->client->ps.genericEnemyIndex = ENTITYNUM_NONE; @@ -4253,7 +4188,7 @@ void SeekerDroneUpdate(gentity_t *self) } void HolocronUpdate(gentity_t *self) -{ +{ //keep holocron status updated in holocron mode int i = 0; int noHRank = 0; @@ -4271,13 +4206,13 @@ void HolocronUpdate(gentity_t *self) while (i < NUM_FORCE_POWERS) { if (self->client->ps.holocronsCarried[i]) - { + { //carrying it, make sure we have the power self->client->ps.holocronBits |= (1 << i); self->client->ps.fd.forcePowersKnown |= (1 << i); self->client->ps.fd.forcePowerLevel[i] = FORCE_LEVEL_3; } else - { + { //otherwise, make sure the power is cleared from us self->client->ps.fd.forcePowerLevel[i] = 0; if (self->client->ps.holocronBits & (1 << i)) { @@ -4328,12 +4263,7 @@ void HolocronUpdate(gentity_t *self) } if (HasSetSaberOnly()) - { - /* - self->client->ps.fd.forcePowerLevel[FP_SABERATTACK] = FORCE_LEVEL_3; - self->client->ps.fd.forcePowerLevel[FP_SABERDEFEND] = FORCE_LEVEL_3; - self->client->ps.fd.forcePowerLevel[FP_SABERTHROW] = FORCE_LEVEL_3; - */ + { //if saberonly, we get these powers no matter what (still need the holocrons for level 3) if (self->client->ps.fd.forcePowerLevel[FP_SABERATTACK] < FORCE_LEVEL_1) { self->client->ps.fd.forcePowerLevel[FP_SABERATTACK] = FORCE_LEVEL_1; @@ -4346,7 +4276,7 @@ void HolocronUpdate(gentity_t *self) } void JediMasterUpdate(gentity_t *self) -{ +{ //keep jedi master status updated for JM gametype int i = 0; trap_Cvar_Update(&g_MaxHolocronCarry); @@ -4449,19 +4379,6 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) return; } -/* - if (g_trueJedi.integer) - { - if (self->client->ps.weapon != WP_SABER) - { - self->client->ps.forceRestricted = qtrue; - } - else - { - self->client->ps.forceRestricted = qfalse; - } - } -*/ if (self->client->ps.fd.saberAnimLevel > self->client->ps.fd.forcePowerLevel[FP_SABERATTACK]) { self->client->ps.fd.saberAnimLevel = self->client->ps.fd.forcePowerLevel[FP_SABERATTACK]; @@ -4512,33 +4429,48 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) self->client->ps.zoomTime = 0; } - if (self->client->ps.forceHandExtend != HANDEXTEND_NONE && + if (self->client->ps.forceHandExtend == HANDEXTEND_KNOCKDOWN && + self->client->ps.forceHandExtendTime >= level.time) + { + self->client->ps.saberMove = 0; + self->client->ps.saberBlocking = 0; + self->client->ps.saberBlocked = 0; + self->client->ps.weaponTime = 0; + } + else if (self->client->ps.forceHandExtend != HANDEXTEND_NONE && self->client->ps.forceHandExtendTime < level.time) { if (self->client->ps.forceHandExtend == HANDEXTEND_KNOCKDOWN && !self->client->ps.forceDodgeAnim) { - if (self->client->pers.cmd.upmove && - self->client->ps.fd.forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1) - { //force getup - G_PreDefSound(self->client->ps.origin, PDSOUND_FORCEJUMP); - self->client->ps.forceDodgeAnim = 2; - self->client->ps.forceHandExtendTime = level.time + 800;//1000; - - self->client->ps.velocity[2] = 300; - } - else if (self->client->ps.quickerGetup) + if (self->health < 1 || (self->client->ps.eFlags & EF_DEAD)) { - self->client->ps.quickerGetup = qfalse; - G_EntitySound( self, CHAN_VOICE, G_SoundIndex("*jump1.wav") ); - self->client->ps.forceDodgeAnim = 3; - self->client->ps.forceHandExtendTime = level.time + 600; - self->client->ps.velocity[2] = 200; + self->client->ps.forceHandExtend = HANDEXTEND_NONE; } else { - self->client->ps.forceDodgeAnim = 1; - self->client->ps.forceHandExtendTime = level.time + 1000; + if (self->client->pers.cmd.upmove && + self->client->ps.fd.forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1) + { //force getup + G_PreDefSound(self->client->ps.origin, PDSOUND_FORCEJUMP); + self->client->ps.forceDodgeAnim = 2; + self->client->ps.forceHandExtendTime = level.time + 500; + + self->client->ps.velocity[2] = 400; + } + else if (self->client->ps.quickerGetup) + { + self->client->ps.quickerGetup = qfalse; + G_EntitySound( self, CHAN_VOICE, G_SoundIndex("*jump1.wav") ); + self->client->ps.forceDodgeAnim = 3; + self->client->ps.forceHandExtendTime = level.time + 500; + self->client->ps.velocity[2] = 300; + } + else + { + self->client->ps.forceDodgeAnim = 1; + self->client->ps.forceHandExtendTime = level.time + 1000; + } } } else @@ -4565,7 +4497,7 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) if (self && self->client && (BG_HasYsalamiri(g_gametype.integer, &self->client->ps) || self->client->ps.fd.forceDeactivateAll)) - { + { //has ysalamiri.. or we want to forcefully stop all his active powers i = 0; while (i < NUM_FORCE_POWERS) @@ -4587,7 +4519,7 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) } } else - { + { //otherwise just do a check through them all to see if they need to be stopped for any reason. i = 0; while (i < NUM_FORCE_POWERS) @@ -4605,7 +4537,7 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) i = 0; if (self->client->ps.powerups[PW_FORCE_ENLIGHTENED_LIGHT] || self->client->ps.powerups[PW_FORCE_ENLIGHTENED_DARK]) - { + { //enlightenment if (!self->client->ps.fd.forceUsingAdded) { i = 0; @@ -4628,7 +4560,7 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) } } else if (self->client->ps.fd.forceUsingAdded) - { + { //we don't have enlightenment but we're still using enlightened powers, so clear them back to how they should be. i = 0; while (i < NUM_FORCE_POWERS) @@ -4652,20 +4584,13 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) i = 0; if (!(self->client->ps.fd.forcePowersActive & (1 << FP_TELEPATHY))) - { + { //clear the mindtrick index values self->client->ps.fd.forceMindtrickTargetIndex = 0; self->client->ps.fd.forceMindtrickTargetIndex2 = 0; self->client->ps.fd.forceMindtrickTargetIndex3 = 0; self->client->ps.fd.forceMindtrickTargetIndex4 = 0; } - /*if (self->s.number == 0) - //if (self->s.number == 1) - { - G_Printf("FP: %i\n", self->client->ps.fd.forcePower); - }*/ - - if (self->health < 1) { self->client->ps.fd.forceGripBeingGripped = 0; @@ -4700,11 +4625,9 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) self->client->ps.powerups[PW_SPEED] = level.time + 100; } - if (self->client->ps.fd.forceSpeedDoDamage && FORCE_VELOCITY_DAMAGE) + if (self->client->ps.fd.forceSpeedDoDamage && FORCE_VELOCITY_DAMAGE) //You used to be able to run into walls and crack your face on them (like JK1) { //we set the flag somewhere to do damage for some reason, so do it G_Damage (self, NULL, NULL, NULL, NULL, self->client->ps.fd.forceSpeedDoDamage, DAMAGE_NO_ARMOR, MOD_FALLING); - //self->client->ps.pm_time = 20000; - //self->client->ps.pm_flags |= PMF_TIME_KNOCKBACK; if (self->client->ps.fd.forceSpeedHitIndex != ENTITYNUM_NONE && g_entities[self->client->ps.fd.forceSpeedHitIndex].client) @@ -4715,8 +4638,6 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) self->client->ps.fd.forceSpeedHitIndex = ENTITYNUM_NONE; } - //placeholder sound: - //G_Sound(self, CHAN_BODY, G_SoundIndex("sound/test/objectBreak.wav")); self->client->ps.fd.forceSpeedDoDamage = 0; } @@ -4730,38 +4651,25 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) self->client->ps.fd.forcePowerDuration[i] = 0; } } - //return; goto powersetcheck; } -// if (!ucmd->upmove || (self->client->ps.groundEntityNum != ENTITYNUM_NONE && !self->client->ps.fd.forceJumpCharge)) -// { -// self->client->groundTime = 0; -// } - if (self->client->ps.groundEntityNum != ENTITYNUM_NONE) { self->client->fjDidJump = qfalse; } if (self->client->ps.fd.forceJumpCharge && self->client->ps.groundEntityNum == ENTITYNUM_NONE && self->client->fjDidJump) - { - if (ucmd->upmove < 10 && /*!(ucmd->buttons & BUTTON_FORCEJUMP) &&*/ (!(ucmd->buttons & BUTTON_FORCEPOWER) || self->client->ps.fd.forcePowerSelected != FP_LEVITATION)) + { //this was for the "charge" jump method... I guess + if (ucmd->upmove < 10 && (!(ucmd->buttons & BUTTON_FORCEPOWER) || self->client->ps.fd.forcePowerSelected != FP_LEVITATION)) { G_MuteSound(self->client->ps.fd.killSoundEntIndex[TRACK_CHANNEL_1-50], CHAN_VOICE); self->client->ps.fd.forceJumpCharge = 0; } } - /* - if ( (ucmd->buttons & BUTTON_FORCEJUMP) && !BG_HasYsalamiri(g_gametype.integer, &self->client->ps) && BG_CanUseFPNow(g_gametype.integer, &self->client->ps, level.time, FP_LEVITATION) ) - {//just charging up - ForceJumpCharge( self, ucmd ); - usingForce = qtrue; - } - */ #ifndef METROID_JUMP - else if ( /*!self->client->fjDidJump &&*/ (ucmd->upmove > 10) && (self->client->ps.pm_flags & PMF_JUMP_HELD) && self->client->ps.groundTime && (level.time - self->client->ps.groundTime) > 150 && !BG_HasYsalamiri(g_gametype.integer, &self->client->ps) && BG_CanUseFPNow(g_gametype.integer, &self->client->ps, level.time, FP_LEVITATION)/*&& !self->client->ps.fd.forceJumpZStart*/ ) + else if ( (ucmd->upmove > 10) && (self->client->ps.pm_flags & PMF_JUMP_HELD) && self->client->ps.groundTime && (level.time - self->client->ps.groundTime) > 150 && !BG_HasYsalamiri(g_gametype.integer, &self->client->ps) && BG_CanUseFPNow(g_gametype.integer, &self->client->ps, level.time, FP_LEVITATION) ) {//just charging up ForceJumpCharge( self, ucmd ); usingForce = qtrue; @@ -4772,7 +4680,7 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) } #endif - if (/*!(ucmd->buttons & BUTTON_FORCEJUMP) &&*/ !(self->client->ps.pm_flags & PMF_JUMP_HELD) && self->client->ps.fd.forceJumpCharge) + if (!(self->client->ps.pm_flags & PMF_JUMP_HELD) && self->client->ps.fd.forceJumpCharge) { if (!(ucmd->buttons & BUTTON_FORCEPOWER) || self->client->ps.fd.forcePowerSelected != FP_LEVITATION) @@ -4785,7 +4693,7 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) } if ( ucmd->buttons & BUTTON_FORCEGRIP ) - { + { //grip is one of the powers with its own button.. if it's held, call the specific grip power function. if (WP_DoSpecificPower( self, ucmd, FP_GRIP )) { usingForce = qtrue; @@ -4796,7 +4704,7 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) } } else - { + { //see if we're using it generically.. if not, stop. if (self->client->ps.fd.forcePowersActive & (1 << FP_GRIP)) { if (!(ucmd->buttons & BUTTON_FORCEPOWER) || self->client->ps.fd.forcePowerSelected != FP_GRIP) @@ -4807,12 +4715,12 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) } if ( ucmd->buttons & BUTTON_FORCE_LIGHTNING ) - { + { //lightning WP_DoSpecificPower(self, ucmd, FP_LIGHTNING); usingForce = qtrue; } else - { + { //see if we're using it generically.. if not, stop. if (self->client->ps.fd.forcePowersActive & (1 << FP_LIGHTNING)) { if (!(ucmd->buttons & BUTTON_FORCEPOWER) || self->client->ps.fd.forcePowerSelected != FP_LIGHTNING) @@ -4823,12 +4731,12 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) } if ( ucmd->buttons & BUTTON_FORCE_DRAIN ) - { + { //drain WP_DoSpecificPower(self, ucmd, FP_DRAIN); usingForce = qtrue; } else - { + { //see if we're using it generically.. if not, stop. if (self->client->ps.fd.forcePowersActive & (1 << FP_DRAIN)) { if (!(ucmd->buttons & BUTTON_FORCEPOWER) || self->client->ps.fd.forcePowerSelected != FP_DRAIN) @@ -4838,12 +4746,10 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) } } - if ( (ucmd->buttons & BUTTON_FORCEPOWER) /*&& - !BG_HasYsalamiri(g_gametype.integer, &self->client->ps)*/ && - // WP_ForcePowerUsable(self, self->client->ps.fd.forcePowerSelected) && + if ( (ucmd->buttons & BUTTON_FORCEPOWER) && BG_CanUseFPNow(g_gametype.integer, &self->client->ps, level.time, self->client->ps.fd.forcePowerSelected)) { - if (self->client->ps.fd.forcePowerSelected == FP_LEVITATION /*&& !self->client->fjDidJump*/) + if (self->client->ps.fd.forcePowerSelected == FP_LEVITATION) { ForceJumpCharge( self, ucmd ); usingForce = qtrue; @@ -4891,7 +4797,7 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) } } } - if ( /*!usingForce*/!self->client->ps.fd.forcePowersActive || self->client->ps.fd.forcePowersActive == (1 << FP_DRAIN) ) + if ( !self->client->ps.fd.forcePowersActive || self->client->ps.fd.forcePowersActive == (1 << FP_DRAIN) ) {//when not using the force, regenerate at 1 point per half second if ( !self->client->ps.saberInFlight && self->client->ps.fd.forcePowerRegenDebounceTime < level.time ) { @@ -4936,7 +4842,7 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) WP_ForcePowerRegenerate(self, holoregen); } - self->client->ps.fd.forcePowerRegenDebounceTime = level.time + g_forceRegenTime.integer; //500? + self->client->ps.fd.forcePowerRegenDebounceTime = level.time + g_forceRegenTime.integer; } } @@ -5007,9 +4913,6 @@ qboolean Jedi_DodgeEvasion( gentity_t *self, gentity_t *shooter, trace_t *tr, in } } - //check force speed power level to determine if I should be able to dodge it -// if ( Q_irand( 1, 10 ) > self->client->ps.fd.forcePowerLevel[FP_SPEED] ) - if (g_forceDodge.integer == 2) { if ( Q_irand( 1, 7 ) > self->client->ps.fd.forcePowerLevel[FP_SPEED] ) @@ -5019,8 +4922,7 @@ qboolean Jedi_DodgeEvasion( gentity_t *self, gentity_t *shooter, trace_t *tr, in } else { - //if ( Q_irand( 1, 4 ) > self->client->ps.fd.forcePowerLevel[FP_SEE] ) - //NOTE: We now dodge all the time, but only on level 3 + //We now dodge all the time, but only on level 3 if (self->client->ps.fd.forcePowerLevel[FP_SEE] < FORCE_LEVEL_3) {//more likely to fail on lower force sight level return qfalse; @@ -5037,25 +4939,24 @@ qboolean Jedi_DodgeEvasion( gentity_t *self, gentity_t *shooter, trace_t *tr, in case HL_FOOT_LT: case HL_LEG_RT: case HL_LEG_LT: - //case HL_WAIST: return qfalse; case HL_BACK_RT: dodgeAnim = BOTH_DODGE_FL; break; case HL_CHEST_RT: - dodgeAnim = BOTH_DODGE_FR;//BOTH_DODGE_BL; + dodgeAnim = BOTH_DODGE_FR; break; case HL_BACK_LT: dodgeAnim = BOTH_DODGE_FR; break; case HL_CHEST_LT: - dodgeAnim = BOTH_DODGE_FR;//BOTH_DODGE_BR; + dodgeAnim = BOTH_DODGE_FR; break; case HL_BACK: case HL_CHEST: case HL_WAIST: - dodgeAnim = BOTH_DODGE_FL;//Q_irand( BOTH_DODGE_FL, BOTH_DODGE_R ); + dodgeAnim = BOTH_DODGE_FL; break; case HL_ARM_RT: case HL_HAND_RT: @@ -5066,7 +4967,7 @@ qboolean Jedi_DodgeEvasion( gentity_t *self, gentity_t *shooter, trace_t *tr, in dodgeAnim = BOTH_DODGE_R; break; case HL_HEAD: - dodgeAnim = BOTH_DODGE_FL;//Q_irand( BOTH_DODGE_FL, BOTH_DODGE_BR ); + dodgeAnim = BOTH_DODGE_FL; break; default: return qfalse; @@ -5074,9 +4975,6 @@ qboolean Jedi_DodgeEvasion( gentity_t *self, gentity_t *shooter, trace_t *tr, in if ( dodgeAnim != -1 ) { - //set the dodge anim we chose - //NPC_SetAnim( self, SETANIM_BOTH, dodgeAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );//type - //Our own happy way of forcing an anim: self->client->ps.forceHandExtend = HANDEXTEND_DODGE; self->client->ps.forceDodgeAnim = dodgeAnim; diff --git a/CODE-mp/game/w_saber.c b/CODE-mp/game/w_saber.c index 6e9850b..0fc6747 100644 --- a/CODE-mp/game/w_saber.c +++ b/CODE-mp/game/w_saber.c @@ -14,7 +14,11 @@ int saberOffSound = 0; int saberOnSound = 0; int saberHumSound = 0; +//would be cleaner if these were renamed to BG_ and proto'd in a header. qboolean PM_SaberInTransition( int move ); +qboolean PM_SaberInDeflect( int move ); +qboolean PM_SaberInBrokenParry( int move ); +qboolean PM_SaberInBounce( int move ); float RandFloat(float min, float max) { return ((rand() * (max - min)) / 32768.0F) + min; @@ -58,6 +62,8 @@ void G_DebugBoxLines(vec3_t mins, vec3_t maxs, int duration) } #endif +#define PROPER_THROWN_VALUE 999 //Ah, well.. + void SaberUpdateSelf(gentity_t *ent) { if (ent->r.ownerNum == ENTITYNUM_NONE) @@ -79,11 +85,14 @@ void SaberUpdateSelf(gentity_t *ent) if (g_entities[ent->r.ownerNum].client->ps.saberInFlight && g_entities[ent->r.ownerNum].health > 0) { //let The Master take care of us now (we'll get treated like a missile until we return) ent->nextthink = level.time; + ent->bolt_Head = PROPER_THROWN_VALUE; return; } + ent->bolt_Head = 0; + if (g_entities[ent->r.ownerNum].client->ps.usingATST) - { + { //using atst ent->r.contents = 0; ent->clipmask = 0; } @@ -91,14 +100,13 @@ void SaberUpdateSelf(gentity_t *ent) (g_entities[ent->r.ownerNum].client->ps.pm_flags & PMF_FOLLOW) || g_entities[ent->r.ownerNum].health < 1 || g_entities[ent->r.ownerNum].client->ps.saberHolstered || - !g_entities[ent->r.ownerNum].client->ps.fd.forcePowerLevel[FP_SABERATTACK]/* || - !g_entities[ent->r.ownerNum].client->ps.fd.forcePowerLevel[FP_SABERTHROW]*/) - { + !g_entities[ent->r.ownerNum].client->ps.fd.forcePowerLevel[FP_SABERATTACK]) + { //owner is not using saber, spectating, dead, saber holstered, or has no attack level ent->r.contents = 0; ent->clipmask = 0; } else - { + { //Standard contents (saber is active) #ifdef DEBUG_SABER_BOX vec3_t dbgMins; vec3_t dbgMaxs; @@ -160,6 +168,7 @@ void WP_SaberInitBladeData( gentity_t *ent ) saberent->touch = SaberGotHit; saberent->think = SaberUpdateSelf; + saberent->bolt_Head = 0; saberent->nextthink = level.time + 50; saberSpinSound = G_SoundIndex("sound/weapons/saber/saberspin.wav"); @@ -168,64 +177,6 @@ void WP_SaberInitBladeData( gentity_t *ent ) saberHumSound = G_SoundIndex("sound/weapons/saber/saberhum1.wav"); } -#if 0 -static void G_SwingAngles( float destination, float swingTolerance, float clampTolerance, - float speed, float *angle, qboolean *swinging ) { - float swing; - float move; - float scale; - - if ( !*swinging ) { - // see if a swing should be started - swing = AngleSubtract( *angle, destination ); - if ( swing > swingTolerance || swing < -swingTolerance ) { - *swinging = qtrue; - } - } - - if ( !*swinging ) { - return; - } - - // modify the speed depending on the delta - // so it doesn't seem so linear - swing = AngleSubtract( destination, *angle ); - scale = fabs( swing ); - if ( scale < swingTolerance * 0.5 ) { - scale = 0.5; - } else if ( scale < swingTolerance ) { - scale = 1.0; - } else { - scale = 2.0; - } - - // swing towards the destination angle - if ( swing >= 0 ) { - move = FRAMETIME * scale * speed; - if ( move >= swing ) { - move = swing; - *swinging = qfalse; - } - *angle = AngleMod( *angle + move ); - } else if ( swing < 0 ) { - move = FRAMETIME * scale * -speed; - if ( move <= swing ) { - move = swing; - *swinging = qfalse; - } - *angle = AngleMod( *angle + move ); - } - - // clamp to no more than tolerance - swing = AngleSubtract( destination, *angle ); - if ( swing > clampTolerance ) { - *angle = AngleMod( destination - (clampTolerance - 1) ); - } else if ( swing < -clampTolerance ) { - *angle = AngleMod( destination + (clampTolerance - 1) ); - } -} -#endif - //NOTE: If C` is modified this function should be modified as well (and vice versa) void G_G2ClientSpineAngles( gentity_t *ent, vec3_t viewAngles, const vec3_t angles, vec3_t thoracicAngles, vec3_t ulAngles, vec3_t llAngles ) { @@ -291,8 +242,6 @@ void G_G2PlayerAngles( gentity_t *ent, vec3_t legs[3], vec3_t legsAngles){ float degrees_positive = 0; qboolean yawing = qfalse; vec3_t ulAngles, llAngles, viewAngles, angles, thoracicAngles = {0,0,0}; - //float pitchViewAng; - //float yawViewAng; VectorCopy( ent->client->ps.viewangles, headAngles ); headAngles[YAW] = AngleMod( headAngles[YAW] ); @@ -305,11 +254,6 @@ void G_G2PlayerAngles( gentity_t *ent, vec3_t legs[3], vec3_t legsAngles){ if ((( ent->s.legsAnim & ~ANIM_TOGGLEBIT ) != BOTH_STAND1) || ( ent->s.torsoAnim & ~ANIM_TOGGLEBIT ) != WeaponReadyAnim[ent->s.weapon] ) { - // if not standing still, always point all in the same direction - /*cent->pe.torso.yawing = qtrue; // always center - cent->pe.torso.pitching = qtrue; // always center - cent->pe.legs.yawing = qtrue; // always center - */ yawing = qtrue; } @@ -330,10 +274,6 @@ void G_G2PlayerAngles( gentity_t *ent, vec3_t legs[3], vec3_t legsAngles){ dest = headAngles[PITCH] * 0.75; } - //G_SwingAngles call disabled, at least for now. It isn't necessary on the server. -// pitchViewAng = ent->client->ps.viewangles[PITCH]; -// G_SwingAngles( dest, 15, 30, 0.1, &pitchViewAng, &yawing ); - torsoAngles[PITCH] = ent->client->ps.viewangles[PITCH]; // --------- roll ------------- @@ -343,28 +283,6 @@ void G_G2PlayerAngles( gentity_t *ent, vec3_t legs[3], vec3_t legsAngles){ VectorCopy( ent->s.pos.trDelta, velocity ); speed = VectorNormalize( velocity ); - /* - speed_desired = ent->client->ps.speed/4; - - if (!speed) - { - speed_dif = 0; - } - else - { - speed_dif = (speed/speed_desired); - } - - if (speed_dif > 1) - { - speed_dif = 1; - } - else if (speed_dif < 0) - { - speed_dif = 0; - } - */ - if ( speed ) { vec3_t axis[3]; float side; @@ -444,10 +362,6 @@ void G_G2PlayerAngles( gentity_t *ent, vec3_t legs[3], vec3_t legsAngles){ } } - //G_SwingAngles call disabled, at least for now. It isn't necessary on the server. -// yawViewAng = ent->client->ps.viewangles[YAW]; -// G_SwingAngles( legsAngles[YAW], 40, 90, /*cg_swingSpeed.value*/ 0.3, &yawViewAng, &yawing ); - legsAngles[YAW] = ent->client->ps.viewangles[YAW]; legsAngles[ROLL] = 0; @@ -459,8 +373,6 @@ void G_G2PlayerAngles( gentity_t *ent, vec3_t legs[3], vec3_t legsAngles){ AnglesToAxis( legsAngles, legs ); // we assume that model 0 is the player model. -// trap_G2API_SetBoneAngles(ent->client->ghoul2, 0, "upper_lumbar", torsoAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, NULL, 0, level.time); - VectorCopy( ent->client->ps.viewangles, viewAngles ); if (viewAngles[PITCH] > 290) @@ -478,14 +390,8 @@ void G_G2PlayerAngles( gentity_t *ent, vec3_t legs[3], vec3_t legsAngles){ trap_G2API_SetBoneAngles(ent->client->ghoul2, 0, "upper_lumbar", ulAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, NULL, 0, level.time); trap_G2API_SetBoneAngles(ent->client->ghoul2, 0, "lower_lumbar", llAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, NULL, 0, level.time); trap_G2API_SetBoneAngles(ent->client->ghoul2, 0, "thoracic", thoracicAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, NULL, 0, level.time); - - //trap_G2API_SetBoneAngles(ent->client->ghoul2, 0, "cranium", headAngles, BONE_ANGLES_POSTMULT, POSITIVE_Z, NEGATIVE_Y, POSITIVE_X, NULL, 0, level.time); } -qboolean PM_SaberInDeflect( int move ); -qboolean PM_SaberInBrokenParry( int move ); -qboolean PM_SaberInBounce( int move ); - qboolean SaberAttacking(gentity_t *self) { if (PM_SaberInParry(self->client->ps.saberMove)) @@ -512,7 +418,7 @@ qboolean SaberAttacking(gentity_t *self) if (BG_SaberInAttack(self->client->ps.saberMove)) { if (self->client->ps.weaponstate == WEAPON_FIRING && self->client->ps.saberBlocked == BLOCKED_NONE) - { + { //if we're firing and not blocking, then we're attacking. return qtrue; } } @@ -541,7 +447,6 @@ void WP_SaberBlockNonRandom( gentity_t *self, vec3_t hitloc, qboolean missileBlo qboolean WP_SabersCheckLock2( gentity_t *attacker, gentity_t *defender, sabersLockMode_t lockMode ) { -// animation_t *anim; int attAnim, defAnim = 0; float attStart = 0.5f; float idealDist = 48.0f; @@ -713,8 +618,8 @@ qboolean WP_SabersCheckLock( gentity_t *ent1, gentity_t *ent2 ) return qfalse; } dist = DistanceSquared(ent1->r.currentOrigin,ent2->r.currentOrigin); - if ( dist < 64 || dist > 6400 )//( dist < 128 || dist > 2304 ) - {//between 8 and 80 from each other//was 16 and 48 + if ( dist < 64 || dist > 6400 ) + {//between 8 and 80 from each other return qfalse; } @@ -747,10 +652,6 @@ qboolean WP_SabersCheckLock( gentity_t *ent1, gentity_t *ent2 ) { return qfalse; } -// if ( !InFOV( ent1, ent2, 40, 180 ) || !InFOV( ent2, ent1, 40, 180 ) ) -// { -// return qfalse; -// } if (!InFront( ent1->client->ps.origin, ent2->client->ps.origin, ent2->client->ps.viewangles, 0.4f )) { @@ -768,14 +669,7 @@ qboolean WP_SabersCheckLock( gentity_t *ent1, gentity_t *ent2 ) ent1->client->ps.torsoAnim == BOTH_A4_T__B_ || ent1->client->ps.torsoAnim == BOTH_A5_T__B_ ) {//ent1 is attacking top-down - /* - if ( ent2->client->ps.torsoAnim == BOTH_P1_S1_T_ || - ent2->client->ps.torsoAnim == BOTH_K1_S1_T_ ) - */ - {//ent2 is blocking at top - return WP_SabersCheckLock2( ent1, ent2, LOCK_TOP ); - } - //return qfalse; + return WP_SabersCheckLock2( ent1, ent2, LOCK_TOP ); } if ( ent2->client->ps.torsoAnim == BOTH_A1_T__B_ || @@ -784,14 +678,7 @@ qboolean WP_SabersCheckLock( gentity_t *ent1, gentity_t *ent2 ) ent2->client->ps.torsoAnim == BOTH_A4_T__B_ || ent2->client->ps.torsoAnim == BOTH_A5_T__B_ ) {//ent2 is attacking top-down - /* - if ( ent1->client->ps.torsoAnim == BOTH_P1_S1_T_ || - ent1->client->ps.torsoAnim == BOTH_K1_S1_T_ ) - */ - {//ent1 is blocking at top - return WP_SabersCheckLock2( ent2, ent1, LOCK_TOP ); - } - //return qfalse; + return WP_SabersCheckLock2( ent2, ent1, LOCK_TOP ); } if ( ent1->s.number == 0 && @@ -1226,21 +1113,15 @@ qboolean WP_GetSaberDeflectionAngle( gentity_t *attacker, gentity_t *defender, f } } else - { + { //old math-based method (probably broken) vec3_t att_HitDir, def_BladeDir, temp; float hitDot; - //VectorSubtract( attacker->client->renderInfo.muzzlePoint, attacker->client->renderInfo.muzzlePointOld, temp ); VectorCopy(attacker->client->lastSaberBase_Always, temp); - //VectorCopy(attacker->client->lastSaberDir_Always, att_HitDir); AngleVectors(attacker->client->lastSaberDir_Always, att_HitDir, 0, 0); AngleVectors(defender->client->lastSaberDir_Always, def_BladeDir, 0, 0); - //VectorMA( def_BladeDir, saberHitFraction, temp, def_BladeDir ); - - // VectorScale( att_HitDir, -1.0f, att_HitDir ); - // VectorScale( def_BladeDir, -1.0f, def_BladeDir ); //now compare hitDot = DotProduct( att_HitDir, def_BladeDir ); @@ -1356,7 +1237,6 @@ int G_KnockawayForParry( int move ) return LS_K1_BL;//push down and to right break; } - //return LS_NONE; } #define SABER_NONATTACK_DAMAGE 1 @@ -1368,7 +1248,7 @@ int G_GetAttackDamage(gentity_t *self, int minDmg, int maxDmg, float multPoint) int speedDif = 0; int totalDamage = maxDmg; float peakPoint = 0; - float attackAnimLength = bgGlobalAnimations[self->client->ps.torsoAnim].numFrames * fabs(bgGlobalAnimations[self->client->ps.torsoAnim].frameLerp); + float attackAnimLength = bgGlobalAnimations[self->client->ps.torsoAnim&~ANIM_TOGGLEBIT].numFrames * fabs(bgGlobalAnimations[self->client->ps.torsoAnim&~ANIM_TOGGLEBIT].frameLerp); float currentPoint = 0; float damageFactor = 0; float animSpeedFactor = 1.0f; @@ -1417,7 +1297,7 @@ int G_GetAttackDamage(gentity_t *self, int minDmg, int maxDmg, float multPoint) float G_GetAnimPoint(gentity_t *self) { int speedDif = 0; - float attackAnimLength = bgGlobalAnimations[self->client->ps.torsoAnim].numFrames * fabs(bgGlobalAnimations[self->client->ps.torsoAnim].frameLerp); + float attackAnimLength = bgGlobalAnimations[self->client->ps.torsoAnim&~ANIM_TOGGLEBIT].numFrames * fabs(bgGlobalAnimations[self->client->ps.torsoAnim&~ANIM_TOGGLEBIT].frameLerp); float currentPoint = 0; float animSpeedFactor = 1.0f; float animPercentage = 0; @@ -1507,7 +1387,7 @@ qboolean G_G2TraceCollide(trace_t *tr, vec3_t lastValidStart, vec3_t lastValidEn return qfalse; } else - { //Yay! + { //The ghoul2 trace result matches, so copy the collision position into the trace endpos and send it back. VectorCopy(G2Trace[0].mCollisionPosition, tr->endpos); return qtrue; } @@ -1518,6 +1398,19 @@ qboolean G_G2TraceCollide(trace_t *tr, vec3_t lastValidStart, vec3_t lastValidEn } #endif +qboolean G_SaberInBackAttack(int move) +{ + switch (move) + { + case LS_A_BACK: + case LS_A_BACK_CR: + case LS_A_BACKSTAB: + return qtrue; + } + + return qfalse; +} + //rww - MP version of the saber damage function. This is where all the things like blocking, triggering a parry, //triggering a broken parry, doing actual damage, etc. are done for the saber. It doesn't resemble the SP //version very much, but functionality is (hopefully) about the same. @@ -1600,8 +1493,6 @@ qboolean CheckSaberDamage(gentity_t *self, vec3_t saberStart, vec3_t saberEnd, q oldSaberEnd[1] = oldSaberStart[1] - (oldSaberDif[1]*trDif); oldSaberEnd[2] = oldSaberStart[2] - (oldSaberDif[2]*trDif); - //G_TestLine(oldSaberEnd, saberEnd, 0x0000ff, 50); - trap_Trace(&tr, saberEnd, saberTrMins, saberTrMaxs, saberStart, self->s.number, trMask); #ifdef G2_COLLISION_ENABLED VectorCopy(saberEnd, lastValidStart); @@ -1633,8 +1524,6 @@ qboolean CheckSaberDamage(gentity_t *self, vec3_t saberStart, vec3_t saberEnd, q oldSaberEnd[1] = oldSaberStart[1] - (oldSaberDif[1]*trDif); oldSaberEnd[2] = oldSaberStart[2] - (oldSaberDif[2]*trDif); - //G_TestLine(oldSaberEnd, saberEnd, 0x0000ff, 50); - trap_Trace(&tr, saberEnd, saberTrMins, saberTrMaxs, saberStart, self->s.number, trMask); #ifdef G2_COLLISION_ENABLED VectorCopy(saberEnd, lastValidStart); @@ -1650,12 +1539,6 @@ qboolean CheckSaberDamage(gentity_t *self, vec3_t saberStart, vec3_t saberEnd, q } else { - /* - if (self->s.number == 0) - { - G_TestLine(saberStart, saberEnd, 0x0000ff, 50); - } - */ trap_Trace(&tr, saberStart, saberTrMins, saberTrMaxs, saberEnd, self->s.number, trMask); #ifdef G2_COLLISION_ENABLED VectorCopy(saberStart, lastValidStart); @@ -1667,17 +1550,6 @@ qboolean CheckSaberDamage(gentity_t *self, vec3_t saberStart, vec3_t saberEnd, q #endif } - /* - if (tr.entityNum == ENTITYNUM_NONE && trMask == CONTENTS_LIGHTSABER) - { //didn't hit anything while checking with just the saber contents mask, do a normal trace. - trMask = (MASK_PLAYERSOLID|CONTENTS_LIGHTSABER|MASK_SHOT); - } - else - { - saberTraceDone = qtrue; - } - */ - //Doing this differently now saberTraceDone = qtrue; } @@ -1685,14 +1557,14 @@ qboolean CheckSaberDamage(gentity_t *self, vec3_t saberStart, vec3_t saberEnd, q self->client->ps.saberAttackWound < level.time) { //this animation is that of the last attack movement, and so it should do full damage qboolean saberInSpecial = BG_SaberInSpecial(self->client->ps.saberMove); + qboolean inBackAttack = G_SaberInBackAttack(self->client->ps.saberMove); - dmg = SABER_HITDAMAGE;//*self->client->ps.fd.saberAnimLevel; + dmg = SABER_HITDAMAGE; if (self->client->ps.fd.saberAnimLevel == 3) { - //dmg = 100; //new damage-ramping system - if (!saberInSpecial) + if (!saberInSpecial && !inBackAttack) { dmg = G_GetAttackDamage(self, 2, 120, 0.5f); } @@ -1701,6 +1573,10 @@ qboolean CheckSaberDamage(gentity_t *self, vec3_t saberStart, vec3_t saberEnd, q { dmg = G_GetAttackDamage(self, 2, 180, 0.65f); } + else if (inBackAttack) + { + dmg = G_GetAttackDamage(self, 2, 30, 0.5f); //can hit multiple times (and almost always does), so.. + } else { dmg = 100; @@ -1710,8 +1586,12 @@ qboolean CheckSaberDamage(gentity_t *self, vec3_t saberStart, vec3_t saberEnd, q { if (saberInSpecial && (self->client->ps.saberMove == LS_A_FLIP_STAB || self->client->ps.saberMove == LS_A_FLIP_SLASH)) - { //a well-timed hit with this can do a full 105 - dmg = G_GetAttackDamage(self, 2, 100, 0.5f); + { //a well-timed hit with this can do a full 85 + dmg = G_GetAttackDamage(self, 2, 80, 0.5f); + } + else if (inBackAttack) + { + dmg = G_GetAttackDamage(self, 2, 25, 0.5f); } else { @@ -1725,6 +1605,10 @@ qboolean CheckSaberDamage(gentity_t *self, vec3_t saberStart, vec3_t saberEnd, q { dmg = G_GetAttackDamage(self, 2, SABER_HITDAMAGE-5, 0.3f); } + else if (inBackAttack) + { + dmg = G_GetAttackDamage(self, 2, 30, 0.5f); + } else { dmg = SABER_HITDAMAGE; @@ -1736,43 +1620,42 @@ qboolean CheckSaberDamage(gentity_t *self, vec3_t saberStart, vec3_t saberEnd, q else if (self->client->ps.saberIdleWound < level.time) { //just touching, do minimal damage and only check for it every 200ms (mainly to cut down on network traffic for hit events) dmg = SABER_NONATTACK_DAMAGE; - //self->client->ps.saberIdleWound = level.time + g_saberDmgDelay_Idle.integer; idleDamage = qtrue; } - /* - if (self->client->ps.saberMove == LS_A_BACK || - self->client->ps.saberMove == LS_A_BACK_CR || - self->client->ps.saberMove == LS_A_BACKSTAB || - self->client->ps.saberMove == LS_A_JUMP_T__B_) - */ if (BG_SaberInSpecial(self->client->ps.saberMove)) { + qboolean inBackAttack = G_SaberInBackAttack(self->client->ps.saberMove); + unblockable = qtrue; self->client->ps.saberBlocked = 0; - if (self->client->ps.saberMove == LS_A_JUMP_T__B_) - { //do extra damage for special unblockables - dmg += 5; //This is very tiny, because this move has a huge damage ramp - } - else if (self->client->ps.saberMove == LS_A_FLIP_STAB || self->client->ps.saberMove == LS_A_FLIP_SLASH) + + if (!inBackAttack) { - dmg += 5; //ditto - if (dmg <= 40 || G_GetAnimPoint(self) <= 0.4f) - { //sort of a hack, don't want it doing big damage in the off points of the anim - dmg = 2; + if (self->client->ps.saberMove == LS_A_JUMP_T__B_) + { //do extra damage for special unblockables + dmg += 5; //This is very tiny, because this move has a huge damage ramp } - } - else if (self->client->ps.saberMove == LS_A_LUNGE) - { - dmg += 2; //and ditto again - if (G_GetAnimPoint(self) <= 0.4f) - { //same as above - dmg = 2; + else if (self->client->ps.saberMove == LS_A_FLIP_STAB || self->client->ps.saberMove == LS_A_FLIP_SLASH) + { + dmg += 5; //ditto + if (dmg <= 40 || G_GetAnimPoint(self) <= 0.4f) + { //sort of a hack, don't want it doing big damage in the off points of the anim + dmg = 2; + } + } + else if (self->client->ps.saberMove == LS_A_LUNGE) + { + dmg += 2; //and ditto again + if (G_GetAnimPoint(self) <= 0.4f) + { //same as above + dmg = 2; + } + } + else + { + dmg += 20; } - } - else - { - dmg += 20; } } @@ -1786,6 +1669,11 @@ qboolean CheckSaberDamage(gentity_t *self, vec3_t saberStart, vec3_t saberEnd, q return qfalse; } + if (dmg > SABER_NONATTACK_DAMAGE) + { + dmg *= g_saberDamageScale.value; + } + if (dmg > SABER_NONATTACK_DAMAGE && self->client->ps.isJediMaster) { //give the Jedi Master more saber attack power dmg *= 2; @@ -1799,9 +1687,8 @@ qboolean CheckSaberDamage(gentity_t *self, vec3_t saberStart, vec3_t saberEnd, q //when you visually cut right through them. Which sucks. if ((tr.fraction != 1 || tr.startsolid) && - /*(!g_entities[tr.entityNum].client || !g_entities[tr.entityNum].client->ps.usingATST) &&*/ - //g_entities[tr.entityNum].client && g_entities[tr.entityNum].takedamage && + (g_entities[tr.entityNum].health > 0 || !(g_entities[tr.entityNum].s.eFlags & EF_DISINTEGRATION)) && tr.entityNum != self->s.number) { gentity_t *te; @@ -1848,7 +1735,7 @@ qboolean CheckSaberDamage(gentity_t *self, vec3_t saberStart, vec3_t saberEnd, q int lockFactor = g_saberLockFactor.integer; if ((g_entities[tr.entityNum].client->ps.fd.forcePowerLevel[FP_SABERATTACK] - self->client->ps.fd.forcePowerLevel[FP_SABERATTACK]) > 1 && - Q_irand(1, 10) < lockFactor*2) //used to be < 7 + Q_irand(1, 10) < lockFactor*2) { //Just got blocked by someone with a decently higher attack level, so enter into a lock (where they have the advantage due to a higher attack lev) if (!G_ClientIdleInWorld(&g_entities[tr.entityNum])) { @@ -1975,8 +1862,6 @@ qboolean CheckSaberDamage(gentity_t *self, vec3_t saberStart, vec3_t saberEnd, q sabersClashed = qtrue; - //WP_SaberBlockNonRandom(self, tr.endpos, qfalse); - blockStuff: otherUnblockable = qfalse; @@ -2008,12 +1893,6 @@ blockStuff: return didHit; } - /* - if (otherOwner->client->ps.saberMove == LS_A_BACK || - otherOwner->client->ps.saberMove == LS_A_BACK_CR || - otherOwner->client->ps.saberMove == LS_A_BACKSTAB || - otherOwner->client->ps.saberMove == LS_A_JUMP_T__B_) - */ if (BG_SaberInSpecial(otherOwner->client->ps.saberMove)) { otherUnblockable = qtrue; @@ -2023,7 +1902,6 @@ blockStuff: if ( sabersClashed && dmg > SABER_NONATTACK_DAMAGE && self->client->ps.fd.saberAnimLevel < FORCE_LEVEL_3 && - /*PM_SaberInParry(otherOwner->client->ps.saberMove) &&*/ !PM_SaberInBounce(otherOwner->client->ps.saberMove) && !PM_SaberInParry(self->client->ps.saberMove) && !PM_SaberInBrokenParry(self->client->ps.saberMove) && @@ -2031,8 +1909,7 @@ blockStuff: !PM_SaberInBounce(self->client->ps.saberMove) && !PM_SaberInDeflect(self->client->ps.saberMove) && !PM_SaberInReflect(self->client->ps.saberMove) && - !unblockable /*&& - Q_irand(1, 10) <= 7*/) + !unblockable ) { //if (Q_irand(1, 10) <= 6) if (1) //for now, just always try a deflect. (deflect func can cause bounces too) @@ -2060,7 +1937,6 @@ blockStuff: } if ( ((self->client->ps.fd.saberAnimLevel < FORCE_LEVEL_3 && ((tryDeflectAgain && Q_irand(1, 10) <= 3) || (!tryDeflectAgain && Q_irand(1, 10) <= 7))) || (Q_irand(1, 10) <= 1 && otherOwner->client->ps.fd.saberAnimLevel >= FORCE_LEVEL_3)) - /*&& PM_SaberInParry(otherOwner->client->ps.saberMove)*/ && !PM_SaberInBounce(self->client->ps.saberMove) && !PM_SaberInBrokenParry(otherOwner->client->ps.saberMove) @@ -2091,7 +1967,7 @@ blockStuff: //make them (me) go into a broken parry self->client->ps.saberMove = BG_BrokenParryForAttack( self->client->ps.saberMove ); - self->client->ps.saberBlocked = BLOCKED_BOUNCE_MOVE;//BLOCKED_PARRY_BROKEN; + self->client->ps.saberBlocked = BLOCKED_BOUNCE_MOVE; if (g_saberDebugPrint.integer) { @@ -2101,7 +1977,7 @@ blockStuff: didDefense = qtrue; } else if ((self->client->ps.fd.saberAnimLevel > FORCE_LEVEL_2 || unblockable) && //if we're doing a special attack, we can send them into a broken parry too (MP only) - ( otherOwner->client->ps.fd.forcePowerLevel[FP_SABERDEFEND] < self->client->ps.fd.saberAnimLevel || (otherOwner->client->ps.fd.forcePowerLevel[FP_SABERDEFEND] == self->client->ps.fd.saberAnimLevel && (Q_irand(1, 10) >= otherOwner->client->ps.fd.saberAnimLevel*3 || unblockable)) ) && + ( otherOwner->client->ps.fd.forcePowerLevel[FP_SABERDEFEND] < self->client->ps.fd.saberAnimLevel || (otherOwner->client->ps.fd.forcePowerLevel[FP_SABERDEFEND] == self->client->ps.fd.saberAnimLevel && (Q_irand(1, 10) >= otherOwner->client->ps.fd.saberAnimLevel*1.5 || unblockable)) ) && PM_SaberInParry(otherOwner->client->ps.saberMove) && !PM_SaberInBrokenParry(otherOwner->client->ps.saberMove) && !PM_SaberInParry(self->client->ps.saberMove) && @@ -2160,17 +2036,6 @@ blockStuff: !PM_SaberInReflect(self->client->ps.saberMove) && !PM_SaberInReflect(otherOwner->client->ps.saberMove)) { - // Com_Printf("BLING\n"); - /* - WP_GetSaberDeflectionAngle(self, otherOwner, tr.fraction); - - if (SaberAttacking(self) && !unblockable && !BG_SaberInSpecial(otherOwner->client->ps.saberMove)) - { //make them bounce/deflect - WP_GetSaberDeflectionAngle(otherOwner, self, tr.fraction); - didDefense = qtrue; - } - */ - if (g_saberDebugPrint.integer) { Com_Printf("Client %i and client %i bounced off of each other's sabers\n", self->s.number, otherOwner->s.number); @@ -2180,7 +2045,6 @@ blockStuff: otherOwner->client->ps.saberBlocked = BLOCKED_ATK_BOUNCE; didOffense = qtrue; - // didDefense = qtrue; } } @@ -2197,10 +2061,9 @@ blockStuff: WP_SaberBlockNonRandom(otherOwner, tr.endpos, qfalse); } } - else if (!didDefense && dmg > SABER_NONATTACK_DAMAGE && !otherUnblockable) //if not more than idle damage, don't even bother blocking. -#else - if (!didDefense && dmg > SABER_NONATTACK_DAMAGE && !otherUnblockable) //if not more than idle damage, don't even bother blocking. + else #endif + if (!didDefense && dmg > SABER_NONATTACK_DAMAGE && !otherUnblockable) //if not more than idle damage, don't even bother blocking. { //block if (!PM_SaberInParry(otherOwner->client->ps.saberMove) && !PM_SaberInBrokenParry(otherOwner->client->ps.saberMove) && @@ -2245,12 +2108,6 @@ blockStuff: !PM_SaberInReflect(self->client->ps.saberMove) && !unblockable) { - /* - if (WP_GetSaberDeflectionAngle(self, otherOwner, tr.fraction)) - { - didOffense = qtrue; - } - */ self->client->ps.saberBlocked = BLOCKED_ATK_BOUNCE; didOffense = qtrue; } @@ -2263,7 +2120,6 @@ blockStuff: !PM_SaberInReflect(otherOwner->client->ps.saberMove) && !unblockable) { - //WP_GetSaberDeflectionAngle(otherOwner, self, tr.fraction); otherOwner->client->ps.saberBlocked = BLOCKED_ATK_BOUNCE; } if (g_saberDebugPrint.integer) @@ -2273,24 +2129,6 @@ blockStuff: } else if ((level.time - otherOwner->client->lastSaberStorageTime) < 500 && !unblockable) //make sure the stored saber data is updated { //They are higher, this means they can actually smash us into a broken parry - /* - vec3_t saberMidPoint; - - //Base the block point off of their saber's mid point - saberMidPoint[0] = otherOwner->client->lastSaberBase_Always[0] + otherOwner->client->lastSaberDir_Always[0]*20; - saberMidPoint[0] = otherOwner->client->lastSaberBase_Always[1] + otherOwner->client->lastSaberDir_Always[1]*20; - saberMidPoint[0] = otherOwner->client->lastSaberBase_Always[2] + otherOwner->client->lastSaberDir_Always[2]*20; - - //Send us into a parry - WP_SaberBlockNonRandom(self, saberMidPoint, qfalse); - - //And then break the parry - if (PM_SaberInParry(G_GetParryForBlock(self->client->ps.saberBlocked))) - { - self->client->ps.saberMove = BG_BrokenParryForParry( G_GetParryForBlock(self->client->ps.saberBlocked) ); - self->client->ps.saberBlocked = BLOCKED_PARRY_BROKEN; - } - */ //Using reflected anims instead now self->client->ps.saberMove = BG_BrokenParryForAttack(self->client->ps.saberMove); self->client->ps.saberBlocked = BLOCKED_PARRY_BROKEN; @@ -2357,7 +2195,7 @@ qboolean CheckThrownSaberDamaged(gentity_t *saberent, gentity_t *saberOwner, gen trap_InPVS(ent->client->ps.origin, saberent->r.currentOrigin) && ent->client->sess.sessionTeam != TEAM_SPECTATOR && ent->client->pers.connected) - { + { //hit a client if (ent->inuse && ent->client && ent->client->ps.duelInProgress && ent->client->ps.duelIndex != saberOwner->s.number) @@ -2376,27 +2214,15 @@ qboolean CheckThrownSaberDamaged(gentity_t *saberent, gentity_t *saberOwner, gen veclen = VectorLength(vecsub); if (veclen < dist) - { + { //within range trace_t tr; trap_Trace(&tr, saberent->r.currentOrigin, NULL, NULL, ent->client->ps.origin, saberent->s.number, MASK_SHOT); - /* - if (tr.startsolid || tr.allsolid) - { - if (!returning) - { //return to owner if startsolid - thrownSaberTouch(saberent, saberent, NULL); - } - - return qfalse; - } - */ - if (tr.fraction == 1 || tr.entityNum == ent->s.number) { //Slice them if (!saberOwner->client->ps.isJediMaster && WP_SaberCanBlock(ent, tr.endpos, 0, MOD_SABER, qfalse, 8)) - { + { //they blocked it WP_SaberBlockNonRandom(ent, tr.endpos, qfalse); te = G_TempEntity( tr.endpos, EV_SABER_BLOCK ); @@ -2417,7 +2243,7 @@ qboolean CheckThrownSaberDamaged(gentity_t *saberent, gentity_t *saberOwner, gen return qfalse; } else - { + { //a good hit vec3_t dir; VectorSubtract(tr.endpos, saberent->r.currentOrigin, dir); @@ -2459,7 +2285,7 @@ qboolean CheckThrownSaberDamaged(gentity_t *saberent, gentity_t *saberOwner, gen } else if (ent && !ent->client && ent->inuse && ent->takedamage && ent->health > 0 && ent->s.number != saberOwner->s.number && ent->s.number != saberent->s.number && trap_InPVS(ent->r.currentOrigin, saberent->r.currentOrigin)) - { + { //hit a non-client VectorSubtract(saberent->r.currentOrigin, ent->r.currentOrigin, vecsub); veclen = VectorLength(vecsub); @@ -2477,7 +2303,7 @@ qboolean CheckThrownSaberDamaged(gentity_t *saberent, gentity_t *saberOwner, gen VectorNormalize(dir); if (ent->s.eType == ET_GRAPPLE) - { + { //an animent G_Damage(ent, saberOwner, saberOwner, dir, tr.endpos, 40, 0, MOD_SABER); } else @@ -2509,7 +2335,7 @@ qboolean CheckThrownSaberDamaged(gentity_t *saberent, gentity_t *saberOwner, gen } void saberCheckRadiusDamage(gentity_t *saberent, int returning) -{ //we're going to cheat and damage players within the saber's radius, just for the sake of doing things more "efficiently" +{ //we're going to cheat and damage players within the saber's radius, just for the sake of doing things more "efficiently" (and because the saber entity has no server g2 instance) int i = 0; int dist = 0; gentity_t *ent; @@ -2534,7 +2360,7 @@ void saberCheckRadiusDamage(gentity_t *saberent, int returning) return; } - while (i < /*MAX_CLIENTS*/MAX_GENTITIES) + while (i < MAX_GENTITIES) { ent = &g_entities[i]; @@ -2647,8 +2473,6 @@ void MakeDeadSaber(gentity_t *ent) VectorSet( saberent->r.mins, -3.0f, -3.0f, -3.0f ); VectorSet( saberent->r.maxs, 3.0f, 3.0f, 3.0f ); - //saberent->mass = 10; - saberent->touch = SaberBounceSound; saberent->think = DeadSaberThink; @@ -2722,6 +2546,7 @@ void saberBackToOwner(gentity_t *saberent) { //He's dead, just go back to our normal saber status saberent->touch = SaberGotHit; saberent->think = SaberUpdateSelf; + saberent->bolt_Head = 0; saberent->nextthink = level.time; MakeDeadSaber(saberent); @@ -2741,8 +2566,6 @@ void saberBackToOwner(gentity_t *saberent) saberent->r.contents = CONTENTS_LIGHTSABER; - //saberent->s.apos.trDelta[1] = 0; - VectorSubtract(saberent->pos1, saberent->r.currentOrigin, dir); ownerLen = VectorLength(dir); @@ -2790,6 +2613,7 @@ void saberBackToOwner(gentity_t *saberent) saberent->touch = SaberGotHit; saberent->think = SaberUpdateSelf; + saberent->bolt_Head = 0; saberent->nextthink = level.time + 50; return; @@ -2805,7 +2629,6 @@ void saberBackToOwner(gentity_t *saberent) } saberMoveBack(saberent, qtrue); - //G_RunObject(saberent); saberent->nextthink = level.time; } @@ -2830,12 +2653,9 @@ void thrownSaberTouch (gentity_t *saberent, gentity_t *other, trace_t *trace) VectorCopy(saberent->r.currentOrigin, saberent->s.pos.trBase); - //saberent->damage = SABER_THROWN_RETURN_HIT_DAMAGE; - saberent->think = saberBackToOwner; saberent->nextthink = level.time; - //saberCheckRadiusDamage(saberent, 2); if (other && other->r.ownerNum < MAX_CLIENTS && (other->r.contents & CONTENTS_LIGHTSABER) && g_entities[other->r.ownerNum].client && @@ -2882,6 +2702,7 @@ void saberFirstThrown(gentity_t *saberent) { //He's dead, just go back to our normal saber status saberent->touch = SaberGotHit; saberent->think = SaberUpdateSelf; + saberent->bolt_Head = 0; saberent->nextthink = level.time; MakeDeadSaber(saberent); @@ -2962,25 +2783,20 @@ void saberFirstThrown(gentity_t *saberent) trap_Trace(&tr, traceFrom, NULL, NULL, traceTo, saberOwn->s.number, MASK_SOLID); } - //G_TestLine(traceFrom, tr.endpos, 0x000000ff, 100); + VectorSubtract(tr.endpos, saberent->r.currentOrigin, dir); - //if (tr.fraction != 1) + VectorNormalize(dir); + + VectorScale(dir, 500, saberent->s.pos.trDelta ); + saberent->s.pos.trTime = level.time; + + if (saberOwn->client->ps.fd.forcePowerLevel[FP_SABERTHROW] >= FORCE_LEVEL_3) + { //we'll treat them to a quicker update rate if their throw rank is high enough + saberent->speed = level.time + 100; + } + else { - VectorSubtract(tr.endpos, saberent->r.currentOrigin, dir); - - VectorNormalize(dir); - - VectorScale(dir, 500, saberent->s.pos.trDelta ); - saberent->s.pos.trTime = level.time; - - if (saberOwn->client->ps.fd.forcePowerLevel[FP_SABERTHROW] >= FORCE_LEVEL_3) - { //we'll treat them to a quicker update rate if their throw rank is high enough - saberent->speed = level.time + 100; - } - else - { - saberent->speed = level.time + 400; - } + saberent->speed = level.time + 400; } } @@ -2990,19 +2806,6 @@ runMin: G_RunObject(saberent); } -/* -void G_DebugDirection(vec3_t base, vec3_t dir) -{ - vec3_t dirPoint; - - dirPoint[0] = base[0] + dir[0]*64; - dirPoint[1] = base[1] + dir[1]*64; - dirPoint[2] = base[2] + dir[2]*64; - - G_TestLine(base, dirPoint, 0x0000ff, 100); -} -*/ - void WP_SaberPositionUpdate( gentity_t *self, usercmd_t *ucmd ) { //rww - keep the saber position as updated as possible on the server so that we can try to do realistic-looking contact stuff mdxaBone_t boltMatrix; @@ -3045,12 +2848,23 @@ void WP_SaberPositionUpdate( gentity_t *self, usercmd_t *ucmd ) if (!self || !self->client || !self->client->ghoul2 || - !g2SaberInstance || - self->health < 1) + !g2SaberInstance) { return; } + if (self->health < 1) + { //we don't want to waste precious CPU time calculating saber positions for corpses. But we want to avoid the saber ent position lagging on spawn, so.. + gentity_t *mySaber = &g_entities[self->client->ps.saberEntityNum]; + + //I guess it's good to keep the position updated even when contents are 0 + if (mySaber && ((mySaber->r.contents & CONTENTS_LIGHTSABER) || mySaber->r.contents == 0) && !self->client->ps.saberInFlight) + { //Since we haven't got a bolt position, place it on top of the player origin. + VectorCopy(self->client->ps.origin, mySaber->r.currentOrigin); + } + return; + } + if (self->client->ps.usingATST) { //we don't update the server's G2 instance in the case of ATST use, so.. return; @@ -3061,7 +2875,6 @@ void WP_SaberPositionUpdate( gentity_t *self, usercmd_t *ucmd ) self->client->ps.weaponstate == WEAPON_DROPPING) { returnAfterUpdate = 1; - //return; } if (self->client->ps.saberThrowDelay < level.time) @@ -3124,6 +2937,15 @@ void WP_SaberPositionUpdate( gentity_t *self, usercmd_t *ucmd ) if (returnAfterUpdate) { //We don't even need to do GetBoltMatrix if we're only in here to keep the g2 server instance in sync + //but keep our saber entity in sync too, just copy it over our origin. + gentity_t *mySaber = &g_entities[self->client->ps.saberEntityNum]; + + //I guess it's good to keep the position updated even when contents are 0 + if (mySaber && ((mySaber->r.contents & CONTENTS_LIGHTSABER) || mySaber->r.contents == 0) && !self->client->ps.saberInFlight) + { //Since we haven't got a bolt position, place it on top of the player origin. + VectorCopy(self->client->ps.origin, mySaber->r.currentOrigin); + } + goto finalUpdate; } @@ -3159,7 +2981,6 @@ void WP_SaberPositionUpdate( gentity_t *self, usercmd_t *ucmd ) { VectorCopy(boltOrigin, mySaber->r.currentOrigin); } - //VectorCopy(/*boltOrigin*/end, mySaber->r.currentOrigin); } } @@ -3184,7 +3005,7 @@ void WP_SaberPositionUpdate( gentity_t *self, usercmd_t *ucmd ) //startang[0] = 90; //Instead of this we'll sort of fake it and slowly tilt it down on the client via - //a perframe method + //a perframe method (which doesn't actually affect where or how the saber hits) saberent->r.svFlags &= ~(SVF_NOCLIENT); VectorCopy(startorg, saberent->s.pos.trBase); @@ -3214,7 +3035,7 @@ void WP_SaberPositionUpdate( gentity_t *self, usercmd_t *ucmd ) AngleVectors(self->client->ps.viewangles, dir, NULL, NULL); saberent->nextthink = level.time + FRAMETIME; - saberent->think = saberFirstThrown;//G_RunObject; + saberent->think = saberFirstThrown; saberent->damage = SABER_THROWN_HIT_DAMAGE; saberent->methodOfDeath = MOD_SABER; @@ -3222,6 +3043,8 @@ void WP_SaberPositionUpdate( gentity_t *self, usercmd_t *ucmd ) saberent->s.solid = 2; saberent->r.contents = CONTENTS_LIGHTSABER; + saberent->bolt_Head = 0; + VectorSet( saberent->r.mins, -24.0f, -24.0f, -8.0f ); VectorSet( saberent->r.maxs, 24.0f, 24.0f, 8.0f ); @@ -3248,6 +3071,16 @@ void WP_SaberPositionUpdate( gentity_t *self, usercmd_t *ucmd ) { VectorCopy(boltOrigin, saberent->pos1); trap_LinkEntity(saberent); + + if (saberent->bolt_Head == PROPER_THROWN_VALUE) + { //return to the owner now, this is a bad state to be in for here.. + saberent->bolt_Head = 0; + saberent->think = SaberUpdateSelf; + saberent->nextthink = level.time; + self->client->ps.saberInFlight = qfalse; + self->client->ps.saberThrowDelay = level.time + 500; + self->client->ps.saberCanThrow = qfalse; + } } } } @@ -3302,8 +3135,20 @@ void WP_SaberPositionUpdate( gentity_t *self, usercmd_t *ucmd ) int sN = 0; qboolean gotHit = qfalse; qboolean clientUnlinked[MAX_CLIENTS]; - + qboolean skipSaberTrace = qfalse; + if (!g_saberTraceSaberFirst.integer) + { + skipSaberTrace = qtrue; + } + else if (g_saberTraceSaberFirst.integer >= 2 && + g_gametype.integer != GT_TOURNAMENT && + !self->client->ps.duelInProgress) + { //if value is >= 2, and not in a duel, skip + skipSaberTrace = qtrue; + } + + if (skipSaberTrace) { //skip the saber-contents-only trace and get right to the full trace trMask = (MASK_PLAYERSOLID|CONTENTS_LIGHTSABER|MASK_SHOT); } @@ -3312,8 +3157,7 @@ void WP_SaberPositionUpdate( gentity_t *self, usercmd_t *ucmd ) while (sN < MAX_CLIENTS) { if (g_entities[sN].inuse && g_entities[sN].client && g_entities[sN].r.linked && g_entities[sN].health > 0 && (g_entities[sN].r.contents & CONTENTS_BODY)) - { //This was linking and relinking entities. But apparently you don't even have to do that to change contents (which is a very good thing) - //trap_UnlinkEntity(&g_entities[sN]); + { //Take this mask off before the saber trace, because we want to hit the saber first g_entities[sN].r.contents &= ~CONTENTS_BODY; clientUnlinked[sN] = qtrue; } @@ -3419,7 +3263,7 @@ void WP_SaberPositionUpdate( gentity_t *self, usercmd_t *ucmd ) while (sN < MAX_CLIENTS) { if (clientUnlinked[sN]) - { + { //Make clients clip properly again. if (g_entities[sN].inuse && g_entities[sN].health > 0) { g_entities[sN].r.contents |= CONTENTS_BODY; @@ -3498,7 +3342,7 @@ finalUpdate: aFlags = BONE_ANIM_OVERRIDE_FREEZE; } - aFlags |= BONE_ANIM_BLEND; //since client defaults to blend. Not sure if this will make much difference if any on client position, but it's here just for the sake of matching them. + aFlags |= BONE_ANIM_BLEND; //since client defaults to blend. Not sure if this will make much difference if any on server position, but it's here just for the sake of matching them. trap_G2API_SetBoneAnim(self->client->ghoul2, 0, "model_root", bgGlobalAnimations[legsAnim].firstFrame, bgGlobalAnimations[legsAnim].firstFrame+bgGlobalAnimations[legsAnim].numFrames, aFlags, animSpeedScale, level.time, -1, 150); self->client->ps.legsAnimExecute = legsAnim; @@ -3513,17 +3357,6 @@ finalUpdate: initialFrame = bgGlobalAnimations[f].firstFrame; - /* - if (bgGlobalAnimations[f].numFrames > 20) - { - initialFrame += 6; - } - else if (bgGlobalAnimations[f].numFrames > 3) - { //HACK: Force it a couple frames into the animation so it doesn't lag behind the client visual position as much.. - initialFrame += 2; - } - */ - BG_SaberStartTransAnim(self->client->ps.fd.saberAnimLevel, f, &animSpeedScale); animSpeed = 50.0f / bgGlobalAnimations[f].frameLerp; @@ -3622,8 +3455,7 @@ void WP_SaberBlockNonRandom( gentity_t *self, vec3_t hitloc, qboolean missileBlo rightdot = DotProduct(right, diff); zdiff = hitloc[2] - clEye[2]; - //FIXME: take torsoAngles into account? - if ( zdiff > 0 )//40 ) + if ( zdiff > 0 ) { if ( rightdot > 0.3 ) { @@ -3642,7 +3474,7 @@ void WP_SaberBlockNonRandom( gentity_t *self, vec3_t hitloc, qboolean missileBlo { if ( zdiff < -10 )//30 ) {//hmm, pretty low, but not low enough to use the low block, so we need to duck - //NPC should duck, but NPC should never get here + } if ( rightdot > 0.1 ) { @@ -3653,7 +3485,7 @@ void WP_SaberBlockNonRandom( gentity_t *self, vec3_t hitloc, qboolean missileBlo self->client->ps.saberBlocked = BLOCKED_UPPER_LEFT; } else - {//FIXME: this looks really weird if the shot is too low! + { self->client->ps.saberBlocked = BLOCKED_TOP; } } @@ -3669,73 +3501,18 @@ void WP_SaberBlockNonRandom( gentity_t *self, vec3_t hitloc, qboolean missileBlo } } - /* - if ( !self->s.number ) - { - gi.Printf( "EyeZ: %4.2f HitZ: %4.2f zdiff: %4.2f rdot: %4.2f\n", self->client->renderInfo.eyePoint[2], hitloc[2], zdiff, rightdot ); - switch ( self->client->ps.saberBlocked ) - { - case BLOCKED_TOP: - gi.Printf( "BLOCKED_TOP\n" ); - break; - case BLOCKED_UPPER_RIGHT: - gi.Printf( "BLOCKED_UPPER_RIGHT\n" ); - break; - case BLOCKED_UPPER_LEFT: - gi.Printf( "BLOCKED_UPPER_LEFT\n" ); - break; - case BLOCKED_LOWER_RIGHT: - gi.Printf( "BLOCKED_LOWER_RIGHT\n" ); - break; - case BLOCKED_LOWER_LEFT: - gi.Printf( "BLOCKED_LOWER_LEFT\n" ); - break; - default: - break; - } - } - */ - if ( missileBlock ) { self->client->ps.saberBlocked = WP_MissileBlockForBlock( self->client->ps.saberBlocked ); - //if ( !self->s.number ) - //{ - //G_DynaMixEvent( DM_BLOCK ); - //} - } - else - { - //if ( !self->s.number ) - //{ - //G_DynaMixEvent( DM_PARRY ); - //} } } void WP_SaberBlock( gentity_t *playerent, vec3_t hitloc, qboolean missileBlock ) { - //gentity_t *playerent; vec3_t diff, fwdangles={0,0,0}, right; float rightdot; float zdiff; - /* - if (saber && saber->owner) - { - playerent = saber->owner; - if (!playerent->client) - { - return; - } - } - else - { // Bad entity passed. - return; - } - */ - //I don't see what the point of this was anyway, saber isn't used anywhere in the function. - VectorSubtract(hitloc, playerent->client->ps.origin, diff); VectorNormalize(diff); @@ -3872,7 +3649,8 @@ int WP_SaberCanBlock(gentity_t *self, vec3_t point, int dflags, int mod, qboolea return 0; } - //Removed this for no, the new broken parry stuff should handle it. + //Removed this for now, the new broken parry stuff should handle it. This is how + //blocks were decided before the 1.03 patch (as you can see, it was STUPID.. for the most part) /* if (attackStr == FORCE_LEVEL_3) { @@ -3917,8 +3695,6 @@ int WP_SaberCanBlock(gentity_t *self, vec3_t point, int dflags, int mod, qboolea if (SaberAttacking(self)) { //attacking, can't block now - - //FIXME: Do a "saber box" check here to see if the enemy saber hit this guy's saber return 0; } diff --git a/CODE-mp/ghoul2/G2_misc.cpp b/CODE-mp/ghoul2/G2_misc.cpp index fba238b..6ae24f4 100644 --- a/CODE-mp/ghoul2/G2_misc.cpp +++ b/CODE-mp/ghoul2/G2_misc.cpp @@ -1089,7 +1089,8 @@ static bool G2_RadiusTracePolys( const mdxmSurface_t *surface, const vec3_t rayS { // we hit a triangle, so init a collision record... // - for (int i=0; i + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "JK2game"=".\game\JK2_game.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "ui"=".\ui\ui.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/CODE-mp/jk2mp-SDK.opt b/CODE-mp/jk2mp-SDK.opt new file mode 100644 index 0000000..fceafbf Binary files /dev/null and b/CODE-mp/jk2mp-SDK.opt differ diff --git a/CODE-mp/jk2mp.opt b/CODE-mp/jk2mp.opt index fef5d21..377d649 100644 Binary files a/CODE-mp/jk2mp.opt and b/CODE-mp/jk2mp.opt differ diff --git a/CODE-mp/qcommon/game_version.h b/CODE-mp/qcommon/game_version.h index ac19112..b073486 100644 --- a/CODE-mp/qcommon/game_version.h +++ b/CODE-mp/qcommon/game_version.h @@ -3,6 +3,6 @@ // Current version of the multi player game -#define Q3_VERSION "JK2MP: v1.03" +#define Q3_VERSION "JK2MP: v1.04" //end diff --git a/CODE-mp/qcommon/net_chan.cpp b/CODE-mp/qcommon/net_chan.cpp index f7cfcd8..68095b2 100644 --- a/CODE-mp/qcommon/net_chan.cpp +++ b/CODE-mp/qcommon/net_chan.cpp @@ -321,8 +321,8 @@ qboolean Netchan_Process( netchan_t *chan, msg_t *msg ) { // read the fragment information if ( fragmented ) { - fragmentStart = MSG_ReadShort( msg ); - fragmentLength = MSG_ReadShort( msg ); + fragmentStart = (unsigned short)MSG_ReadShort( msg ); + fragmentLength = (unsigned short)MSG_ReadShort( msg ); } else { fragmentStart = 0; // stop warning message fragmentLength = 0; @@ -425,10 +425,10 @@ qboolean Netchan_Process( netchan_t *chan, msg_t *msg ) { return qfalse; } - if ( chan->fragmentLength > msg->maxsize ) { + if ( chan->fragmentLength+4 > msg->maxsize ) { Com_Printf( "%s:fragmentLength %i > msg->maxsize\n" , NET_AdrToString (chan->remoteAddress ), - chan->fragmentLength ); + chan->fragmentLength+4 ); return qfalse; } @@ -437,10 +437,6 @@ qboolean Netchan_Process( netchan_t *chan, msg_t *msg ) { // make sure the sequence number is still there *(int *)msg->data = LittleLong( sequence ); - if ( chan->fragmentLength + 4 > MAX_MSGLEN ) - { - Com_Error( ERR_DROP, "Netchan_Process: length = %i",chan->fragmentLength + 4); - } Com_Memcpy( msg->data + 4, chan->fragmentBuffer, chan->fragmentLength ); msg->cursize = chan->fragmentLength + 4; chan->fragmentLength = 0; diff --git a/CODE-mp/qcommon/qcommon.h b/CODE-mp/qcommon/qcommon.h index 642b16f..f2d5728 100644 --- a/CODE-mp/qcommon/qcommon.h +++ b/CODE-mp/qcommon/qcommon.h @@ -196,7 +196,8 @@ PROTOCOL ============================================================== */ -#define PROTOCOL_VERSION 15 +//v1.03 #define PROTOCOL_VERSION 15 +#define PROTOCOL_VERSION 16 //v1.04 #define UPDATE_SERVER_NAME "updatejk2.ravensoft.com" #define MASTER_SERVER_NAME "masterjk2.ravensoft.com" diff --git a/CODE-mp/server/sv_ccmds.cpp b/CODE-mp/server/sv_ccmds.cpp index 5633efa..2de9085 100644 --- a/CODE-mp/server/sv_ccmds.cpp +++ b/CODE-mp/server/sv_ccmds.cpp @@ -671,6 +671,7 @@ static void SV_Status_f( void ) const char *s; int ping; char state[32]; + qboolean avoidTruncation = qfalse; // make sure server is running if ( !com_sv_running->integer ) @@ -679,6 +680,14 @@ static void SV_Status_f( void ) return; } + if ( Cmd_Argc() > 1 ) + { + if (!Q_stricmp("notrunc", Cmd_Argv(1))) + { + avoidTruncation = qtrue; + } + } + Com_Printf ("map: %s\n", sv_mapname->string ); Com_Printf ("num score ping name lastmsg address qport rate\n"); @@ -706,16 +715,33 @@ static void SV_Status_f( void ) ps = SV_GameClientNum( i ); s = NET_AdrToString( cl->netchan.remoteAddress ); - Com_Printf ("%3i %5i %s %-15.15s %7i %21s %5i %5i\n", - i, - ps->persistant[PERS_SCORE], - state, - cl->name, - svs.time - cl->lastPacketTime, - s, - cl->netchan.qport, - cl->rate - ); + + if (!avoidTruncation) + { + Com_Printf ("%3i %5i %s %-15.15s %7i %21s %5i %5i\n", + i, + ps->persistant[PERS_SCORE], + state, + cl->name, + svs.time - cl->lastPacketTime, + s, + cl->netchan.qport, + cl->rate + ); + } + else + { + Com_Printf ("%3i %5i %s %s %7i %21s %5i %5i\n", + i, + ps->persistant[PERS_SCORE], + state, + cl->name, + svs.time - cl->lastPacketTime, + s, + cl->netchan.qport, + cl->rate + ); + } } Com_Printf ("\n"); } diff --git a/CODE-mp/server/sv_main.cpp b/CODE-mp/server/sv_main.cpp index d38f15c..f8e4913 100644 --- a/CODE-mp/server/sv_main.cpp +++ b/CODE-mp/server/sv_main.cpp @@ -756,7 +756,7 @@ void SV_Frame( int msec ) { if (!com_dedicated->integer) SV_BotFrame( svs.time + sv.timeResidual ); - if ( com_dedicated->integer && sv.timeResidual < frameMsec ) { + if ( com_dedicated->integer && sv.timeResidual < frameMsec && (!com_timescale || com_timescale->value >= 1) ) { // NET_Sleep will give the OS time slices until either get a packet // or time enough for a server frame has gone by NET_Sleep(frameMsec - sv.timeResidual); diff --git a/CODE-mp/ui/ui.bat b/CODE-mp/ui/ui.bat index 551fbc8..2586e0c 100644 --- a/CODE-mp/ui/ui.bat +++ b/CODE-mp/ui/ui.bat @@ -20,8 +20,6 @@ set cc=lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\ @if errorlevel 1 goto quit %cc% ../ui_force.c @if errorlevel 1 goto quit -%cc% ../ui_util.c -@if errorlevel 1 goto quit %cc% ../ui_shared.c @if errorlevel 1 goto quit %cc% ../ui_gameinfo.c diff --git a/CODE-mp/ui/ui.dsp b/CODE-mp/ui/ui.dsp index 3ad8b27..f7a7e69 100644 --- a/CODE-mp/ui/ui.dsp +++ b/CODE-mp/ui/ui.dsp @@ -172,10 +172,6 @@ SOURCE=.\ui_shared.c SOURCE=.\ui_syscalls.c # End Source File -# Begin Source File - -SOURCE=.\ui_util.c -# End Source File # End Group # Begin Group "Header Files" diff --git a/CODE-mp/ui/ui.q3asm b/CODE-mp/ui/ui.q3asm index 469cba7..c44850c 100644 --- a/CODE-mp/ui/ui.q3asm +++ b/CODE-mp/ui/ui.q3asm @@ -3,7 +3,6 @@ ui_main ..\ui_syscalls ui_atoms ui_force -ui_util ui_shared ui_gameinfo bg_misc diff --git a/CODE-mp/ui/ui_local.h b/CODE-mp/ui/ui_local.h index 6c95192..a245218 100644 --- a/CODE-mp/ui/ui_local.h +++ b/CODE-mp/ui/ui_local.h @@ -777,6 +777,8 @@ typedef struct { char teamNames[MAX_CLIENTS][MAX_NAME_LENGTH]; int teamClientNums[MAX_CLIENTS]; + int playerIndexes[MAX_CLIENTS]; //so we can vote-kick by index + int mapCount; mapInfo mapList[MAX_MAPS]; diff --git a/CODE-mp/ui/ui_main.c b/CODE-mp/ui/ui_main.c index 905e8dc..d592807 100644 --- a/CODE-mp/ui/ui_main.c +++ b/CODE-mp/ui/ui_main.c @@ -1736,20 +1736,22 @@ void UpdateForceStatus() } - // Take the current team and force a skin color based on it. - switch((int)(trap_Cvar_VariableValue("ui_myteam"))) - { - case TEAM_RED: - uiSkinColor = TEAM_RED; - uiInfo.effectsColor = SABER_RED; - break; - case TEAM_BLUE: - uiSkinColor = TEAM_BLUE; - uiInfo.effectsColor = SABER_BLUE; - break; - default: - uiSkinColor = TEAM_FREE; - break; + if ( !UI_TrueJediEnabled() ) + {// Take the current team and force a skin color based on it. + switch((int)(trap_Cvar_VariableValue("ui_myteam"))) + { + case TEAM_RED: + uiSkinColor = TEAM_RED; + uiInfo.effectsColor = SABER_RED; + break; + case TEAM_BLUE: + uiSkinColor = TEAM_BLUE; + uiInfo.effectsColor = SABER_BLUE; + break; + default: + uiSkinColor = TEAM_FREE; + break; + } } } @@ -2373,6 +2375,7 @@ static void UI_BuildPlayerList() { if (info[0]) { Q_strncpyz( uiInfo.playerNames[uiInfo.playerCount], Info_ValueForKey( info, "n" ), MAX_NAME_LENGTH ); Q_CleanStr( uiInfo.playerNames[uiInfo.playerCount] ); + uiInfo.playerIndexes[uiInfo.playerCount] = n; uiInfo.playerCount++; team2 = atoi(Info_ValueForKey(info, "t")); if (team2 == team && n != uiInfo.playerNumber) { @@ -2989,32 +2992,34 @@ static qboolean UI_Handicap_HandleKey(int flags, float *special, int key) { } static qboolean UI_Effects_HandleKey(int flags, float *special, int key) { - if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_ENTER || key == A_KP_ENTER) { - - int team = (int)(trap_Cvar_VariableValue("ui_myteam")); - - if (team == TEAM_RED || team==TEAM_BLUE) - { - return qfalse; - } - - + if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_ENTER || key == A_KP_ENTER) { + + if ( !UI_TrueJediEnabled() ) + { + int team = (int)(trap_Cvar_VariableValue("ui_myteam")); + + if (team == TEAM_RED || team==TEAM_BLUE) + { + return qfalse; + } + } + if (key == A_MOUSE2) { - uiInfo.effectsColor--; + uiInfo.effectsColor--; } else { - uiInfo.effectsColor++; + uiInfo.effectsColor++; } - - if( uiInfo.effectsColor > 5 ) { - uiInfo.effectsColor = 0; + + if( uiInfo.effectsColor > 5 ) { + uiInfo.effectsColor = 0; } else if (uiInfo.effectsColor < 0) { - uiInfo.effectsColor = 5; + uiInfo.effectsColor = 5; } - - trap_Cvar_SetValue( "color1", /*uitogamecode[uiInfo.effectsColor]*/uiInfo.effectsColor ); - return qtrue; - } - return qfalse; + + trap_Cvar_SetValue( "color1", /*uitogamecode[uiInfo.effectsColor]*/uiInfo.effectsColor ); + return qtrue; + } + return qfalse; } static qboolean UI_ClanName_HandleKey(int flags, float *special, int key) { @@ -4419,7 +4424,8 @@ static void UI_RunMenuScript(char **args) } } else if (Q_stricmp(name, "voteKick") == 0) { if (uiInfo.playerIndex >= 0 && uiInfo.playerIndex < uiInfo.playerCount) { - trap_Cmd_ExecuteText( EXEC_APPEND, va("callvote kick \"%s\"\n",uiInfo.playerNames[uiInfo.playerIndex]) ); + //trap_Cmd_ExecuteText( EXEC_APPEND, va("callvote kick \"%s\"\n",uiInfo.playerNames[uiInfo.playerIndex]) ); + trap_Cmd_ExecuteText( EXEC_APPEND, va("callvote clientkick \"%i\"\n",uiInfo.playerIndexes[uiInfo.playerIndex]) ); } } else if (Q_stricmp(name, "voteGame") == 0) { if (ui_netGameType.integer >= 0 && ui_netGameType.integer < uiInfo.numGameTypes) { @@ -6922,7 +6928,7 @@ void UI_DrawConnectScreen( qboolean overlay ) { //UI_DrawProportionalString( 320, 96, "Press Esc to abort", UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, menu_text_color ); // display global MOTD at bottom - Text_PaintCenter(centerPoint, 600, scale, colorWhite, Info_ValueForKey( cstate.updateInfoString, "motd" ), 0, FONT_MEDIUM); + Text_PaintCenter(centerPoint, 425, scale, colorWhite, Info_ValueForKey( cstate.updateInfoString, "motd" ), 0, FONT_MEDIUM); // print any server info (server full, bad version, etc) if ( cstate.connState < CA_CONNECTED ) { Text_PaintCenter(centerPoint, yStart + 176, scale, colorWhite, cstate.messageString, 0, FONT_MEDIUM); @@ -7392,10 +7398,10 @@ static void UI_StartServerRefresh(qboolean full) ptr = UI_Cvar_VariableString("debug_protocol"); if (strlen(ptr)) { - trap_Cmd_ExecuteText( EXEC_NOW, va( "globalservers %d %s full empty\n", i, ptr)); + trap_Cmd_ExecuteText( EXEC_NOW, va( "globalservers %d %s\n", i, ptr)); } else { - trap_Cmd_ExecuteText( EXEC_NOW, va( "globalservers %d %d full empty\n", i, (int)trap_Cvar_VariableValue( "protocol" ) ) ); + trap_Cmd_ExecuteText( EXEC_NOW, va( "globalservers %d %d\n", i, (int)trap_Cvar_VariableValue( "protocol" ) ) ); } } } diff --git a/CODE-mp/ui/ui_shared.c b/CODE-mp/ui/ui_shared.c index 6e1d15e..7fb7d03 100644 --- a/CODE-mp/ui/ui_shared.c +++ b/CODE-mp/ui/ui_shared.c @@ -4087,13 +4087,13 @@ void BindingFromName(const char *cvar) { break; } DC->keynumToStringBuf( b1, g_nameBind1, 32 ); - Q_strupr(g_nameBind1); +// do NOT do this or it corrupts asian text!!! Q_strupr(g_nameBind1); b2 = g_bindings[i].bind2; if (b2 != -1) { DC->keynumToStringBuf( b2, g_nameBind2, 32 ); - Q_strupr(g_nameBind2); +// do NOT do this or it corrupts asian text!!! Q_strupr(g_nameBind2); trap_SP_GetStringTextString("MENUS3_KEYBIND_OR",sOR, sizeof(sOR)); @@ -4634,6 +4634,7 @@ void Item_ListBox_Paint(itemDef_t *item) { { imageStartX = listPtr->columnInfo[j+1].pos; } + DC->setColor( NULL ); if (optionalImage3 >= 0) { DC->drawHandlePic(imageStartX - listPtr->elementHeight*3, y+2, listPtr->elementHeight, listPtr->elementHeight, optionalImage3); } diff --git a/CODE-mp/ui/ui_util.c b/CODE-mp/ui/ui_util.c index 416d587..96d04e8 100644 --- a/CODE-mp/ui/ui_util.c +++ b/CODE-mp/ui/ui_util.c @@ -5,4 +5,7 @@ // // memory, string alloc - +void RichIsGettingTiredOfEmptyFileVMCompilerWarnings() +{ + int andUnderstandablySo = 0; +} diff --git a/CODE-mp/unix/makefile b/CODE-mp/unix/makefile index a9f86b0..41ca43d 100644 --- a/CODE-mp/unix/makefile +++ b/CODE-mp/unix/makefile @@ -77,7 +77,7 @@ DLL_ONLY=false # bk001205: no mo' -I/usr/include/glide, no FX # bk001205: no mo' -Dstricmp=strcasecmp, see q_shared.h #BASE_CFLAGS = -pipe -fsigned-char -x c++ -D_JK2 -D_M_IX86 -I/home/drews/STLport-4.5.3/stlport -I/opt/intel/compiler50/ia32/include - BASE_CFLAGS = -pipe -fsigned-char -Kc++ -D_JK2 -D_M_IX86 -I/opt/intel/compiler50/ia32/include + BASE_CFLAGS = -pipe -fsigned-char -Kc++ -D_JK2 -D_M_IX86 -I/opt/intel/compiler50/ia32/include # rcg010216: DLL_ONLY for PPC ifeq ($(strip $(DLL_ONLY)),true) BASE_CFLAGS += -DDLL_ONLY @@ -95,12 +95,12 @@ DLL_ONLY=false # DEBUG_CFLAGS=$(BASE_CFLAGS) -g -Wall -Werror -O ifeq ($(ARCH),axp) CC=pgcc - RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O6 -ffast-math -funroll-loops -fomit-frame-pointer -fexpensive-optimizations + RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O2 -unroll else ifeq ($(ARCH),ppc) NEWPGCC=/loki/global/ppc/bin/gcc CC=$(NEWPGCC) - RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O6 -fomit-frame-pointer -pipe -ffast-math -malign-loops=2 -malign-jumps=2 -malign-functions=2 -fno-strict-aliasing -fstrength-reduce + RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O2 -pipe -unroll else #NEWPGCC=/usr/local/gcc-2.95.2/bin/gcc # bk001205 #NEWPGCC=/loki/global/x86/bin/gcc @@ -112,7 +112,7 @@ DLL_ONLY=false # TTimo: legacy RELEASE_CFLAGS # NOTE: the -fomit-frame-pointer option leads to an unstable binary on my test box if it was built on the main box # but building on the Mdk 7.2 baseline seems to work - RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O6 -mcpu=pentiumpro -march=pentium -fomit-frame-pointer -pipe -ffast-math -malign-loops=2 -malign-jumps=2 -malign-functions=2 -fno-strict-aliasing -fstrength-reduce + RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O2 -unroll -tpp6 # TTimo: use this for building on P3 gcc 2.95.3 libc2.2 for all targets (experimental! -fomit-fram-pointer removed) # RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O6 -mcpu=pentiumpro -march=pentium -pipe -ffast-math -malign-loops=2 -malign-jumps=2 -malign-functions=2 -fno-strict-aliasing -fstrength-reduce endif @@ -129,7 +129,7 @@ DLL_ONLY=false THREAD_LDFLAGS=-lpthread #LDFLAGS=/opt/sxl/lib/sxlgcc3.a -lpthread -ldl -lm -lstdc++ -static -Wl --gc-sections - LDFLAGS=-ldl -lm -lstdc++ -static + LDFLAGS=-ldl -lm -static GLLDFLAGS=-L/usr/X11R6/lib -L$(MESADIR)/lib -lX11 -lXext -lXxf86dga -lXxf86vm TARGETS=\ @@ -213,7 +213,6 @@ Q3DOBJ = \ $(B)/ded/cm_polylib.o \ $(B)/ded/cm_test.o \ $(B)/ded/cm_trace.o \ - $(B)/ded/cm_shader.o \ $(B)/ded/cmd.o \ $(B)/ded/common.o \ $(B)/ded/cvar.o \ diff --git a/CODE-mp/unix/unix_net.c b/CODE-mp/unix/unix_net.c index bce5aa6..df314e2 100644 --- a/CODE-mp/unix/unix_net.c +++ b/CODE-mp/unix/unix_net.c @@ -254,7 +254,7 @@ qboolean Sys_IsLANAddress (netadr_t adr) { // choose which comparison to use based on the class of the address being tested // any local adresses of a different class than the address being tested will fail based on the first byte - +/* // Class A if( (adr.ip[0] & 0x80) == 0x00 ) { for ( i = 0 ; i < numIP ; i++ ) { @@ -279,7 +279,8 @@ qboolean Sys_IsLANAddress (netadr_t adr) { } return qfalse; } - +*/ + //we only look at class C since ISPs and Universities are using class A but we don't want to consider them on the same LAN. // Class C for ( i = 0 ; i < numIP ; i++ ) { if( adr.ip[0] == localIP[i][0] && adr.ip[1] == localIP[i][1] && adr.ip[2] == localIP[i][2] ) { @@ -412,6 +413,9 @@ void NET_GetLocalAddress( void ) { int ip; int n; + // Set this early so we can just return if there is an error + numIP = 0; + if ( gethostname( hostname, 256 ) == -1 ) { return; } @@ -431,14 +435,14 @@ void NET_GetLocalAddress( void ) { return; } - numIP = 0; - while( ( p = hostInfo->h_addr_list[numIP++] ) != NULL && numIP < MAX_IPS ) { + while( ( p = hostInfo->h_addr_list[numIP] ) != NULL && numIP < MAX_IPS ) { ip = ntohl( *(int *)p ); localIP[ numIP ][0] = p[0]; localIP[ numIP ][1] = p[1]; localIP[ numIP ][2] = p[2]; localIP[ numIP ][3] = p[3]; Com_Printf( "IP: %i.%i.%i.%i\n", ( ip >> 24 ) & 0xff, ( ip >> 16 ) & 0xff, ( ip >> 8 ) & 0xff, ip & 0xff ); + numIP++; } } #endif diff --git a/CODE-mp/win32/win_net.cpp b/CODE-mp/win32/win_net.cpp index 2f76271..538e860 100644 --- a/CODE-mp/win32/win_net.cpp +++ b/CODE-mp/win32/win_net.cpp @@ -397,6 +397,7 @@ qboolean Sys_IsLANAddress( netadr_t adr ) { return qtrue; } + /* // Class A if( (adr.ip[0] & 0x80) == 0x00 ) { for ( i = 0 ; i < numIP ; i++ ) { @@ -421,6 +422,8 @@ qboolean Sys_IsLANAddress( netadr_t adr ) { } return qfalse; } + */ + //we only look at class C since ISPs and Universities are using class A but we don't want to consider them on the same LAN. // Class C for ( i = 0 ; i < numIP ; i++ ) { @@ -707,6 +710,9 @@ void NET_GetLocalAddress( void ) { int ip; int n; + // Set this early so we can just return if there is an error + numIP = 0; + if( gethostname( hostname, 256 ) == SOCKET_ERROR ) { error = WSAGetLastError(); return; @@ -728,7 +734,6 @@ void NET_GetLocalAddress( void ) { return; } - numIP = 0; while( ( p = hostInfo->h_addr_list[numIP] ) != NULL && numIP < MAX_IPS ) { ip = ntohl( *(int *)p ); localIP[ numIP ][0] = p[0];