void SabBeh_AttackVsBlock( gentity_t *attacker, sabmech_t *mechAttacker, gentity_t *blocker, sabmech_t *mechBlocker, vec3_t hitLoc, qboolean hitSaberBlade, qboolean *attackerMishap, qboolean *blockerMishap) {//set the saber behavior for an attacking vs blocking/parrying blade impact qboolean startSaberLock = qfalse; qboolean parried = G_BlockIsParry(blocker, attacker, hitLoc); qboolean atkparry = G_InAttackParry(blocker); qboolean atkfake = (attacker->client->ps.userInt3 & (1 << FLAG_ATTACKFAKE)) ? qtrue : qfalse; G_BlockIsQuickParry(blocker,attacker,hitLoc);//Return value was never used, so I just call it now if(parried && blocker->r.svFlags & SVF_BOT && BOT_ATTACKPARRYRATE * botstates[blocker->s.number]->settings.skill > Q_irand(0,999)) {//bot performed an attack parry (by cheating a bit) //G_Printf("%i: %i: Bot Cheat Attack Parried\n", level.time, blocker->s.number); atkparry = qtrue; } /* if(parried && atkparry) { G_Printf("%i: %i: Attack Parried\n", level.time, blocker->s.number); } */ if(BG_SuperBreakWinAnim(attacker->client->ps.torsoAnim)) {//attacker was attempting a superbreak and he hit someone who could block the move, rail him for screwing up. *attackerMishap = SabBeh_RollBalance(attacker, mechAttacker, qtrue,qfalse); SabBeh_AddBalance(attacker, mechAttacker, 2, qtrue); #ifdef _DEBUG mechAttacker->behaveMode = SABBEHAVE_ATTACKPARRIED; #endif SabBeh_AddBalance(blocker, mechBlocker, -1, qfalse); #ifdef _DEBUG mechBlocker->behaveMode = SABBEHAVE_BLOCK; #endif } else if(atkfake) {//attacker faked before making this attack, treat like standard attack/attack if(parried) {//defender parried the attack fake. *attackerMishap = SabBeh_RollBalance(attacker, mechAttacker, atkparry,qtrue); SabBeh_AddBalance(attacker, mechAttacker, MPCOST_PARRIED_ATTACKFAKE, qtrue); #ifdef _DEBUG mechAttacker->behaveMode = SABBEHAVE_ATTACK; #endif if (blocker->client->pers.cmd.buttons & BUTTON_15 && blocker->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE] >= FORCE_LEVEL_2) { attacker->client->ps.userInt3 |= (1 << FLAG_QUICKPARRY); } else { attacker->client->ps.userInt3 |= ( 1 << FLAG_PARRIED ); } SabBeh_AddBalance(blocker, mechBlocker, MPCOST_PARRYING_ATTACKFAKE, qfalse); #ifdef _DEBUG mechBlocker->behaveMode = SABBEHAVE_BLOCK; #endif } else if(atkparry) { saberKnockOutOfHand(&g_entities[attacker->client->ps.saberEntityNum], attacker, vec3_origin); } else {//otherwise, the defender stands a good chance of having his defensives broken. SabBeh_AddBalance(attacker, mechAttacker, -1, qtrue); if(attacker->client->ps.fd.saberAnimLevel == SS_DESANN) SabBeh_AddBalance(blocker, mechBlocker, 2, qfalse); #ifdef _DEBUG mechAttacker->behaveMode = SABBEHAVE_ATTACK; #endif if (WP_SabersCheckLock(attacker, blocker)) { attacker->client->ps.userInt3 |= ( 1 << FLAG_LOCKWINNER ); attacker->client->ps.saberBlocked = BLOCKED_NONE; blocker->client->ps.saberBlocked = BLOCKED_NONE; startSaberLock = qtrue; } #ifdef _DEBUG mechBlocker->behaveMode = SABBEHAVE_BLOCKFAKED; #endif } } else if(hitSaberBlade && BG_InSlowBounce(&blocker->client->ps) && blocker->client->ps.userInt3 & (1 << FLAG_OLDSLOWBOUNCE) && attacker->client->ps.fd.saberAnimLevel == SS_TAVION) {//blocker's saber was directly hit while in a slow bounce, disarm the blocker! mechBlocker->doButterFingers = qtrue; blocker->client->ps.saberAttackChainCount = 0; #ifdef _DEBUG mechBlocker->behaveMode = SABBEHAVE_BLOCKFAKED; #endif //set attacker SabBeh_AddBalance(attacker, mechAttacker, -3, qtrue); #ifdef _DEBUG mechAttacker->behaveMode = SABBEHAVE_ATTACK; #endif } else {//standard attack //set blocker #ifdef _DEBUG mechBlocker->behaveMode = SABBEHAVE_BLOCK; #endif //set attacker if(parried) { //parry values if(attacker->client->ps.saberMove == LS_A_LUNGE || attacker->client->ps.saberMove == LS_SPINATTACK || attacker->client->ps.saberMove == LS_SPINATTACK_DUAL) {//attacker's lunge was parried, force mishap. *attackerMishap = SabBeh_RollBalance(attacker, mechAttacker, qtrue,atkparry); } else { *attackerMishap = SabBeh_RollBalance(attacker, mechAttacker, atkparry,atkparry); } SabBeh_AddBalance(attacker, mechAttacker, MPCOST_PARRIED, qtrue); #ifdef _DEBUG mechAttacker->behaveMode = SABBEHAVE_ATTACKPARRIED; #endif //[QuickParry] if (blocker->client->pers.cmd.buttons & BUTTON_15 && blocker->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE] >= FORCE_LEVEL_2) { attacker->client->ps.userInt3 |= ( 1 << FLAG_QUICKPARRY); } else { attacker->client->ps.userInt3 |= ( 1 << FLAG_PARRIED ); } //[/QuickParry] SabBeh_AddBalance(blocker, mechBlocker, MPCOST_PARRYING, qfalse); } else {//blocked values SabBeh_AddBalance(attacker, mechAttacker, -1, qtrue); if(attacker->client->ps.fd.saberAnimLevel == SS_TAVION) {//aqua styles deals MP to players that don't parry it. SabBeh_AddBalance(blocker, mechBlocker, 2, qfalse); } else if(attacker->client->ps.fd.saberAnimLevel == SS_STRONG) { blocker->client->ps.fd.forcePower -= 2; } else if(attacker->client->ps.fd.saberAnimLevel==SS_TAVION && attacker->client->skillLevel[SK_GREENSTYLE] == FORCE_LEVEL_3 && (attacker->client->ps.userInt3 & FLAG_QUICKPARRY)) { SabBeh_AddBalance(blocker, mechBlocker, 2, qfalse); } #ifdef _DEBUG mechAttacker->behaveMode = SABBEHAVE_ATTACKBLOCKED; #endif //SabBeh_AddBalance(blocker, 1, qfalse); } } if(!OnSameTeam(attacker, blocker) || g_friendlySaber.integer) {//don't do parries or charge/regen DP unless we're in a situation where we can actually hurt the target. if(parried) {//parries don't cost any DP and they have a special animation //qboolean regenSound = qfalse; mechBlocker->doParry = qtrue; } else if(!startSaberLock) {//normal saber blocks //update the blocker's block move blocker->client->ps.saberLockFrame = 0; //break out of saberlocks. WP_SaberBlockNonRandom(blocker, hitLoc, qfalse); } } //do saber DP cost. /* // debugger message. G_Printf("%i: %i: Saber Block Cost: %i atk: %s %s blk: %s %s\n", level.time, blocker->s.number, OJP_SaberBlockCost(blocker, attacker, hitLoc), GetStringForID( animTable, attacker->client->ps.torsoAnim ), GetStringForID( SaberMoveTable, attacker->client->ps.saberMove ), GetStringForID( animTable, blocker->client->ps.torsoAnim ), GetStringForID( SaberMoveTable, blocker->client->ps.saberMove ) ); */ //[ExpSys] -- [DUALRAWR] G_DodgeDrain(blocker, attacker, OJP_SaberBlockCost(blocker, attacker, hitLoc)); //[/ExpSys] //costs FP as well. BG_AddFatigue(&blocker->client->ps, 1); }
//G_Printf("%i: Bounced Bolt @ Level %i\n", player->s.number, otherDefLevel); void OJP_HandleBoltBlock(gentity_t *bolt, gentity_t *player, trace_t *trace) { //handles all the behavior needed to saber block a blaster bolt. //I created this function to unite the duplicated code in G_MissileImpact vec3_t fwd; gentity_t *saberBoltEffect; int otherDefLevel=ReflectionLevel(player); int randMax = 0; gentity_t *prevOwner = &g_entities[bolt->r.ownerNum]; //previous owner of the bolt. Used for awarding experience to attacker. qboolean manualDeflect = ((player->client->pers.cmd.buttons & BUTTON_ATTACK) ? qtrue : qfalse); //create the bolt saber block effect saberBoltEffect = G_TempEntity( bolt->r.currentOrigin, EV_SABER_BLOCK ); VectorCopy(bolt->r.currentOrigin, saberBoltEffect->s.origin); VectorCopy(trace->plane.normal, saberBoltEffect->s.angles); saberBoltEffect->s.eventParm = 0; saberBoltEffect->s.weapon = 0;//saberNum saberBoltEffect->s.legsAnim = 0;//bladeNum if(manualDeflect) { if(otherDefLevel == FORCE_LEVEL_3) { //manual reflection, bounce to the crosshair, roughly int rand = Q_irand(1,100); rand = ( rand <= 50 ? player->client->shotsBlocked+1 : 9001 ); } else if(otherDefLevel == FORCE_LEVEL_2) { //natural reflection, bounce back to the attacker. int rand = Q_irand(1,100); if(rand <= 25) { randMax=player->client->shotsBlocked+1; } else randMax=9001; } else { //just deflect the attack int rand = Q_irand(1,100); if(rand <= 15) { randMax=player->client->shotsBlocked+1; } else randMax=9001; } } else { //determine reflection level. if(otherDefLevel == FORCE_LEVEL_3) { //manual reflection, bounce to the crosshair, roughly randMax=2; } else if(otherDefLevel == FORCE_LEVEL_2) { //natural reflection, bounce back to the attacker. randMax=5; } else { //just deflect the attack randMax=7; } } //G_Printf("%i: Bounced Bolt @ Level %i\n", player->s.number, otherDefLevel); AngleVectors(player->client->ps.viewangles, fwd, NULL, NULL); player->client->shotsBlocked++; if(player->client->shotsBlocked >= randMax && player->client->ps.fd.saberAnimLevel != SS_MEDIUM && player->client->ps.fd.saberAnimLevel != SS_TAVION && player->client->ps.fd.saberAnimLevel != SS_FAST) { gentity_t *owner = &g_entities[player->r.ownerNum]; float distance = VectorDistance(owner->r.currentOrigin, prevOwner->r.currentOrigin); player->client->shotsBlocked=0; if(distance < 80.0f) { //attempted upclose exception G_DeflectMissile(player, bolt, fwd); } else { vec3_t bounce_dir, angs; float speed; int i=0; //gentity_t *owner = ent; //int isowner = 0; if(!manualDeflect) { for(i=0; i<3; i++) { fwd[i]=1.5f; } } //add some slop factor to the manual reflections. if(player->client->pers.cmd.forwardmove >= 0) { float slopFactor = (MISHAP_MAXINACCURACY-6) * (FORCE_LEVEL_3 - player->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE])/FORCE_LEVEL_3; //[MoreRandom] slopFactor += Q_irand(1,5); vectoangles( fwd, angs ); //angs[PITCH] += flrand(-slopFactor, slopFactor); //angs[YAW] += flrand(-slopFactor, slopFactor); angs[PITCH] += flrand(1, slopFactor); angs[YAW] += flrand(1, slopFactor); AngleVectors( angs, fwd, NULL, NULL ); } else { vectoangles( fwd, angs ); angs[PITCH]+=flrand(1,3); angs[YAW]+=flrand(1,3); AngleVectors( angs, fwd, NULL, NULL ); } //G_Printf("%i: %i: Level 3 Reflect\n", level.time, player->s.number); //save the original speed speed = VectorNormalize( bolt->s.pos.trDelta ); VectorCopy(fwd, bounce_dir); VectorScale( bounce_dir, speed, bolt->s.pos.trDelta ); bolt->s.pos.trTime = level.time; // move a bit on the very first frame VectorCopy( bolt->r.currentOrigin, bolt->s.pos.trBase ); if ( bolt->s.weapon != WP_SABER && bolt->s.weapon != G2_MODEL_PART ) { //you are mine, now! bolt->r.ownerNum = player->s.number; } if ( bolt->s.weapon == WP_ROCKET_LAUNCHER ) { //stop homing bolt->think = 0; bolt->nextthink = 0; } } } else G_DeflectMissile(player, bolt, fwd); /* if (otherDefLevel <= FORCE_LEVEL_1) {//only randomly deflect away the bolt G_DeflectMissile(player, bolt, fwd); } else if (otherDefLevel == FORCE_LEVEL_2) {//bounce the bolt back to sender //G_Printf("%i: %i: Level 2 Reflect\n", level.time, player->s.number); G_DeflectMissile(player, bolt, fwd); } else if(otherDefLevel == FORCE_LEVEL_3 && distance < 80.0f &&(BG_SaberInAttack( player->client->ps.saberMove ) || PM_SaberInStart( player->client->ps.saberMove))) {//manual reflection, bounce to the crosshair, roughly G_DeflectMissile(player, bolt, fwd);; } else if(player->client->ps.fd.saberAnimLevel == SS_FAST || player->client->ps.fd.saberAnimLevel == SS_MEDIUM || player->client->ps.fd.saberAnimLevel == SS_TAVION) { G_DeflectMissile(player, bolt, fwd); } else {//FORCE_LEVEL_3, reflect the bolt to whereever the player is aiming. gentity_t *owner = &g_entities[player->r.ownerNum]; float distance = VectorDistance(owner->r.currentOrigin, prevOwner->r.currentOrigin); if(distance < 80.0f) {//attempted upclose exception G_DeflectMissile(player, bolt, fwd); } else { vec3_t bounce_dir, angs; float speed; //gentity_t *owner = ent; //int isowner = 0; //add some slop factor to the manual reflections. if(player->client->pers.cmd.forwardmove >= 0) { float slopFactor = (MISHAP_MAXINACCURACY-6) * (FORCE_LEVEL_3 - player->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE])/FORCE_LEVEL_3; //[MoreRandom] float distance = VectorDistance(player->r.currentOrigin,prevOwner->r.currentOrigin); slopFactor += Q_irand(1,5); vectoangles( fwd, angs ); //angs[PITCH] += flrand(-slopFactor, slopFactor); //angs[YAW] += flrand(-slopFactor, slopFactor); angs[PITCH] += flrand(1, slopFactor); angs[YAW] += flrand(1, slopFactor); AngleVectors( angs, fwd, NULL, NULL ); } else { vectoangles( fwd, angs ); angs[PITCH]+=flrand(1,3); angs[YAW]+=flrand(1,3); AngleVectors( angs, fwd, NULL, NULL ); } //G_Printf("%i: %i: Level 3 Reflect\n", level.time, player->s.number); //save the original speed speed = VectorNormalize( bolt->s.pos.trDelta ); VectorCopy(fwd, bounce_dir); VectorScale( bounce_dir, speed, bolt->s.pos.trDelta ); bolt->s.pos.trTime = level.time; // move a bit on the very first frame VectorCopy( bolt->r.currentOrigin, bolt->s.pos.trBase ); if ( bolt->s.weapon != WP_SABER && bolt->s.weapon != G2_MODEL_PART ) {//you are mine, now! bolt->r.ownerNum = player->s.number; } if ( bolt->s.weapon == WP_ROCKET_LAUNCHER ) {//stop homing bolt->think = 0; bolt->nextthink = 0; } } } */ //For jedi AI player->client->ps.saberEventFlags |= SEF_DEFLECTED; //deduce DP cost //[ExpSys] bolt->activator = prevOwner; if(otherDefLevel == FORCE_LEVEL_3 && player->client->pers.cmd.forwardmove < 0) { int amount = OJP_SaberBlockCost(player, bolt, trace->endpos); amount/=100*40; G_DodgeDrain(player, prevOwner, amount); } else G_DodgeDrain(player, prevOwner, OJP_SaberBlockCost(player, bolt, trace->endpos)); //[ExpSys] //[SaberLockSys] player->client->ps.saberLockFrame = 0; //break out of saberlocks. //[/SaberLockSys] //debounce time between blocks. player->client->ps.saberBlockTime = level.time + (600 - (player->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE]*200)); }