//============================================================ //============================================================ //== == //== Game Dynamics Routines == //== == //============================================================ //============================================================ //======================================================== Includes #include "Globals.h" #include "UnivUtilities.h" #include "Dynamics.h" #include "SoundUtils.h" #include "Render.h" #include "Ball.h" //======================================================== Functions //======================================================== DoPersonBallMerged void DoPersonBallMerged (playerType *who) { register long xMomentum, zMomentum; short strategum; PlaySoundSMS(kBallPickUpSound); // calc. components of momentum xMomentum = (who->xVel * kPersonMass) + (theBall.xVel * kBallMass); zMomentum = (who->zVel * kPersonMass) + (theBall.zVel * kBallMass); // momentum / mass = velocity who->xVel = xMomentum / kPersonBallMass; who->zVel = zMomentum / kPersonBallMass; if ((who->persona == kHumanPlayer) || (who->persona == kNetHuman)) { who->mouseWasLetUp = FALSE; } else { if (who->persona == kMisterEaze) { who->strategy = (short)RandomCoin(); } else if (who->persona == kMissTeak) { strategum = RandomInt(100); if (strategum < who->teaksThresh) who->strategy = kRunDiagonal; else who->strategy = kRunCircle; } } theBall.eraseTheBall = TRUE; drawThisFrame = TRUE; who->posture = kCarrying; theBall.mode = kBallHeld; if (who->selector == kPlayerSelector) { whosGotBall = kPlayerHasBall; theBall.modifier = kPlayerHolding; theOpponent.loopsBallHeld = 0; // zero out the other's timer if (thePlayer.loopsBallHeld == 0) // ??? thePlayer.loopsBallHeld = kLoopLimitOnHeldBall; } else { whosGotBall = kOpponentHasBall; theBall.modifier = kOpponentHolding; thePlayer.loopsBallHeld = 0; if (theOpponent.loopsBallHeld == 0) theOpponent.loopsBallHeld = kLoopLimitOnHeldBall; } UpdateBallTimers(&thePlayer); UpdateBallTimers(&theOpponent); UpdateArrows(); } //======================================================== DoPersonBallParted void DoPersonBallParted (playerType *who) { #define kBallDiskDistance 1216 #define kOffsetMultiplier 2 short deltaPX, deltaPZ; PlaySoundSMS(kBallDropSound); deltaPX = boardForceTable[who->direction][kXComponent] * kPersonImpulse; deltaPZ = boardForceTable[who->direction][kZComponent] * kPersonImpulse; theBall.xVel = who->xVel + (deltaPX / kBallMass); // momentum => velocity theBall.zVel = who->zVel + (deltaPZ / kBallMass); // x & z components theBall.xPos = who->xPos + (deltaPX * kOffsetMultiplier); // get ball clearÉ theBall.zPos = who->zPos + (deltaPZ * kOffsetMultiplier); // of disk. BallRectFromPosition(); who->xVel -= deltaPX / kPersonMass; who->zVel -= deltaPZ / kPersonMass; who->posture = kCrouching; theBall.mode = kBallRolling; whosGotBall = kBallRollsFreely; if (who->selector == kPlayerSelector) { theBall.modifier = kPlayerLastHeld; } else { theBall.modifier = kOpponentLastHeld; } if (thePlayer.persona == kMissTeak) { oldDistSquared = ((long)(thePlayer.xPos) * (long)(thePlayer.xPos)) + ((long)(thePlayer.zPos) * (long)(thePlayer.zPos)); } else if (theOpponent.persona == kMissTeak) { oldDistSquared = ((long)(theOpponent.xPos) * (long)(theOpponent.xPos)) + ((long)(theOpponent.zPos) * (long)(theOpponent.zPos)); } if ((who->persona == kHumanPlayer) || (who->persona == kNetHuman)) who->mouseWasLetUp = FALSE; UpdateArrows(); } //======================================================== DoPersonBallCollided void DoPersonBallCollided (playerType *who) { #define kPBLimitScale 512L // 1024 occ. probs, 2048 more probs short original2XVel, original2ZVel; long distX, distZ; long new1XVel, new1ZVel, new2XVel, new2ZVel; long distSquared, scalar1, scalar2; who->xPos -= (who->xVel / kVelocitySensitive); who->zPos -= (who->zVel / kVelocitySensitive); theBall.xVel -= theBall.xVel / kPBEnergyAbsorbed; theBall.zVel -= theBall.zVel / kPBEnergyAbsorbed; who->xVel -= who->xVel / kPBEnergyAbsorbed; who->zVel -= who->zVel / kPBEnergyAbsorbed; theBall.xVel /= kPersonSmallMass; theBall.zVel /= kPersonSmallMass; who->xVel /= kBallMass; who->zVel /= kBallMass; original2XVel = who->xVel; original2ZVel = who->zVel;; theBall.xVel -= original2XVel; theBall.zVel -= original2ZVel; who->xVel = 0; who->zVel = 0; distX = (long)who->xPos - (long)theBall.xPos; distZ = (long)who->zPos - (long)theBall.zPos; distSquared = ((distX * distX) + (distZ * distZ)) / kPBLimitScale; scalar1 = (((long)-theBall.xVel * distZ) + ((long)theBall.zVel * distX)) / kPBLimitScale; scalar2 = (((long)theBall.xVel * distX) + ((long)theBall.zVel * distZ)) / kPBLimitScale; if (distSquared != 0) { new1XVel = -scalar1 * distZ / distSquared; new1ZVel = scalar1 * distX / distSquared; new2XVel = scalar2 * distX / distSquared; new2ZVel = scalar2 * distZ / distSquared; } if (theBall.justHitWall == 0) { theBall.xVel = (short)new1XVel + original2XVel; theBall.zVel = (short)new1ZVel + original2ZVel; } who->xVel = (short)new2XVel + original2XVel; who->zVel = (short)new2ZVel + original2ZVel; theBall.xVel *= kPersonSmallMass; theBall.zVel *= kPersonSmallMass; who->xVel *= kBallMass; who->zVel *= kBallMass; } //======================================================== DoPersonPersonCollided void DoPersonPersonCollided (void) { #define kLimitScale 1024L short original2XVel, original2ZVel; long distX, distZ; long new1XVel, new1ZVel, new2XVel, new2ZVel; long distSquared, scalar1, scalar2; PlaySoundSMS(kClashSound); thePlayer.justHitOpponent = kLoopsImpactless; theOpponent.justHitOpponent = kLoopsImpactless; thePlayer.justHitWall = 0; theOpponent.justHitWall = 0; thePlayer.xVel -= thePlayer.xVel / kEnergyAbsorbed; thePlayer.zVel -= thePlayer.zVel / kEnergyAbsorbed; theOpponent.xVel -= theOpponent.xVel / kEnergyAbsorbed; theOpponent.zVel -= theOpponent.zVel / kEnergyAbsorbed; original2XVel = theOpponent.xVel; original2ZVel = theOpponent.zVel;; thePlayer.xVel -= original2XVel; thePlayer.zVel -= original2ZVel; theOpponent.xVel = 0; theOpponent.zVel = 0; distX = (long)theOpponent.xPos - (long)thePlayer.xPos; distZ = (long)theOpponent.zPos - (long)thePlayer.zPos; distSquared = ((distX * distX) + (distZ * distZ)) / kLimitScale; scalar1 = (((long)-thePlayer.xVel * distZ) + ((long)thePlayer.zVel * distX)) / kLimitScale; scalar2 = (((long)thePlayer.xVel * distX) + ((long)thePlayer.zVel * distZ)) / kLimitScale; if (distSquared != 0) { new1XVel = -scalar1 * distZ / distSquared; new1ZVel = scalar1 * distX / distSquared; new2XVel = scalar2 * distX / distSquared; new2ZVel = scalar2 * distZ / distSquared; } thePlayer.xVel = (short)new1XVel + original2XVel; thePlayer.zVel = (short)new1ZVel + original2ZVel; theOpponent.xVel = (short)new2XVel + original2XVel; theOpponent.zVel = (short)new2ZVel + original2ZVel; } //======================================================== CheckPersonBallCollision void CheckPersonBallCollision (playerType *who) { #define kSqrImpactDistancePB 1478656L // r. of ball = 416, r. disk = 800 long sqrXDistance, sqrDistance; // Add these & square the result. if ((who->mode != kInArena) || (theBall.mode != kBallRolling) || (who->justHitBall != 0)) { return; } sqrXDistance = ((long)theBall.xPos - who->xPos) * ((long)theBall.xPos - who->xPos); if (sqrXDistance < kSqrImpactDistancePB) // check x 1st (one mult. only) { sqrDistance = sqrXDistance + ((long)theBall.zPos - who->zPos) * ((long)theBall.zPos - who->zPos); if (sqrDistance < kSqrImpactDistancePB) { if ((who->posture == kCrouching) && (who->mouseWasLetUp)) { DoPersonBallMerged(who); } else { PlaySoundSMS(kClashSound); DoPersonBallCollided(who); who->justHitBall = kLoopsImpactless; CheckUpOnBall(); if (who->selector == kPlayerSelector) { theBall.modifier = kPlayerLastHeld; } else { theBall.modifier = kOpponentLastHeld; } } } } } //======================================================== CheckPersonPersonCollision void CheckPersonPersonCollision (void) { #define kSqrImpactDistancePO 2560000L // 2 * r. disk = 800 long sqrXDistance, sqrDistance; // Add these & square the result. if ((thePlayer.mode != kInArena) || (theOpponent.mode != kInArena) || (thePlayer.justHitOpponent != 0)) { return; } sqrXDistance = ((long)theOpponent.xPos - thePlayer.xPos) * ((long)theOpponent.xPos - thePlayer.xPos); if (sqrXDistance < kSqrImpactDistancePO) // check x first (one multiply only) { sqrDistance = sqrXDistance + ((long)theOpponent.zPos - thePlayer.zPos) * ((long)theOpponent.zPos - thePlayer.zPos); if (sqrDistance < kSqrImpactDistancePO) { DoPersonPersonCollided(); do { thePlayer.xPos += (thePlayer.xVel / kVelocitySensitive); thePlayer.zPos += (thePlayer.zVel / kVelocitySensitive); theOpponent.xPos += (theOpponent.xVel / kVelocitySensitive); theOpponent.zPos += (theOpponent.zVel / kVelocitySensitive); sqrXDistance = ((long)theOpponent.xPos - thePlayer.xPos) * ((long)theOpponent.xPos - thePlayer.xPos); sqrDistance = sqrXDistance + ((long)theOpponent.zPos - thePlayer.zPos) * ((long)theOpponent.zPos - thePlayer.zPos); } while (sqrDistance < kSqrImpactDistancePO); } } } //======================================================== GetPlaceOnArena short GetPlaceOnArena (short xPos, short zPos) { register short indexX, indexZ; short signX, signZ; short forceX, forceZ; indexX = xPos; if (indexX < 0) { indexX = -indexX; signX = -1; } else { signX = 1; } indexX /= 512; indexZ = zPos; if (indexZ < 0) { indexZ = -indexZ; signZ = -1; } else { signZ = 1; } indexZ /= 512; if (xPos < 0) { switch (leftGoalLeague) { case kLittleLeague: forceX = *(littleForceTable + indexX * 82 + indexZ * 2 + kXComponent); break; case kJuniorVarsity: forceX = *(juniorForceTable + indexX * 82 + indexZ * 2 + kXComponent); break; case kVarsity: forceX = *(varsityForceTable + indexX * 82 + indexZ * 2 + kXComponent); break; case kMinorLeague: forceX = *(minorForceTable + indexX * 82 + indexZ * 2 + kXComponent); break; case kProfessional: forceX = *(proForceTable + indexX * 82 + indexZ * 2 + kXComponent); break; default: forceX = 0; break; } } else { switch (rightGoalLeague) { case kLittleLeague: forceX = *(littleForceTable + indexX * 82 + indexZ * 2 + kXComponent); break; case kJuniorVarsity: forceX = *(juniorForceTable + indexX * 82 + indexZ * 2 + kXComponent); break; case kVarsity: forceX = *(varsityForceTable + indexX * 82 + indexZ * 2 + kXComponent); break; case kMinorLeague: forceX = *(minorForceTable + indexX * 82 + indexZ * 2 + kXComponent); break; case kProfessional: forceX = *(proForceTable + indexX * 82 + indexZ * 2 + kXComponent); break; default: forceX = 0; break; } } return (forceX); } //======================================================== HandlePersonWallCollision void HandlePersonWallCollision (playerType *who) { short tempVel, wheresIt; if (who->justHitWall != 0) { who->flag = kIsNormal; return; } if (who->xPos < 0) { if (who->xVel > who->zVel) return; } else { if (-who->xVel > who->zVel) return; } PlaySoundSMS(kRicochetSound); who->flag = kIsRebounding; who->justHitWall = kLoopsImpactless; who->xPos -= (who->xVel / kVelocitySensitive); who->zPos -= (who->zVel / kVelocitySensitive); if (who->xPos < 0) { tempVel = who->xVel; who->xVel = who->zVel; who->zVel = tempVel; } else { tempVel = who->xVel; who->xVel = -who->zVel; who->zVel = -tempVel; } wheresIt = GetPlaceOnArena(who->xPos, who->zPos); if ((wheresIt == kBackBoard) || (wheresIt == kGoalPath)) { if (who->zVel > 0) who->zVel *= -1; if (who->xPos < 0) { if (who->xVel < 0) who->xVel *= -1; } else { if (who->xVel > 0) who->xVel *= -1; } } } //======================================================== CheckUpOnBall void CheckUpOnBall (void) { short wheresIt; wheresIt = GetPlaceOnArena(theBall.xPos, theBall.zPos); if (wheresIt == kBackBoard) { if (theBall.zVel > 0) theBall.zVel *= -1; if (theBall.xPos < 0) { if (theBall.xVel < 0) theBall.xVel *= -1; } else { if (theBall.xVel > 0) theBall.xVel *= -1; } } } //======================================================== HandleBallWallCollision void HandleBallWallCollision (void) { short tempVel; if (theBall.justHitWall != 0) { theBall.flag = kIsNormal; return; } if (theBall.xPos < 0) { if (theBall.xVel > theBall.zVel) return; } else { if (-theBall.xVel > theBall.zVel) return; } PlaySoundSMS(kRicochetSound); theBall.flag = kIsRebounding; theBall.justHitWall = kLoopsImpactless; thePlayer.justHitBall = 0; theOpponent.justHitBall = 0; theBall.xPos -= (theBall.xVel / kVelocitySensitive); theBall.zPos -= (theBall.zVel / kVelocitySensitive); if (theBall.xPos < 0) { tempVel = theBall.xVel; theBall.xVel = theBall.zVel; theBall.zVel = tempVel; } else { tempVel = theBall.xVel; theBall.xVel = -theBall.zVel; theBall.zVel = -tempVel; } CheckUpOnBall(); } //======================================================== HandleCollisions void HandleCollisions (void) { if (netGameInSession) { if (imTheMaster) { CheckPersonBallCollision(&thePlayer); CheckPersonBallCollision(&theOpponent); } else { CheckPersonBallCollision(&theOpponent); CheckPersonBallCollision(&thePlayer); } } else { CheckPersonBallCollision(&thePlayer); CheckPersonBallCollision(&theOpponent); } CheckPersonPersonCollision(); if (thePlayer.justHitWall > 0) { thePlayer.justHitWall--; if (thePlayer.justHitWall == kFrameToDampen) { thePlayer.xVel -= thePlayer.xVel / kPersonDampening; thePlayer.zVel -= thePlayer.zVel / kPersonDampening; } } if (thePlayer.justHitBall > 0) thePlayer.justHitBall--; if (thePlayer.justHitOpponent > 0) thePlayer.justHitOpponent--; if (theOpponent.justHitWall > 0) { theOpponent.justHitWall--; if (theOpponent.justHitWall == kFrameToDampen) { theOpponent.xVel -= theOpponent.xVel / kPersonDampening; theOpponent.zVel -= theOpponent.zVel / kPersonDampening; } } if (theOpponent.justHitBall > 0) theOpponent.justHitBall--; if (theOpponent.justHitOpponent > 0) theOpponent.justHitOpponent--; if (theBall.justHitWall > 0) { theBall.justHitWall--; if (theBall.justHitWall == kFrameToDampen) { theBall.xVel /= kBallDampening; theBall.zVel /= kBallDampening; } } }