// ----------------------------------------------------------------------------- //extract angles from a m_data.matrix const CAngleVector CFixMatrix::ExtractAnglesVec (void) const { CAngleVector a; fix sinh, cosh, cosp; if (m_data.mat [FVEC][X] == 0 && m_data.mat [FVEC][Z] == 0) //zero head a [HA] = 0; else a [HA] = FixAtan2 (m_data.mat [FVEC][Z], m_data.mat [FVEC][X]); FixSinCos (a [HA], &sinh, &cosh); if (abs (sinh) > abs (cosh)) //sine is larger, so use it cosp = FixDiv (m_data.mat [FVEC][X], sinh); else //cosine is larger, so use it cosp = FixDiv (m_data.mat [FVEC][Z], cosh); if (cosp==0 && m_data.mat [FVEC][Y]==0) a [PA] = 0; else a [PA] = FixAtan2 (cosp, -m_data.mat [FVEC][Y]); if (cosp == 0) //the cosine of pitch is zero. we're pitched straight up. say no bank a [BA] = 0; else { fix sinb, cosb; sinb = FixDiv (m_data.mat [RVEC][Y], cosp); cosb = FixDiv (m_data.mat [UVEC][Y], cosp); if (sinb==0 && cosb==0) a [BA] = 0; else a [BA] = FixAtan2 (cosb, sinb); } return a; }
//------------------------------------------------------------------------------ //compute the corners of a rod. fills in vertbuf. int CalcRodCorners (g3sPoint *btmPoint, fix xBtmWidth, g3sPoint *topPoint, fix xTopWidth) { vmsVector vDelta, vTop, vTemp, vRodNorm; ubyte andCodes; int i; //compute vector from one point to other, do cross product with vector //from eye to get perpendicular vDelta = btmPoint->p3_vec - topPoint->p3_vec; //unscale for aspect #if RESCALE_ROD vDelta.p.x = FixDiv (vDelta.p.x, viewInfo.scale.p.x); vDelta.p.y = FixDiv (vDelta.p.y, viewInfo.scale.p.y); #endif //calc Perp vector //do lots of normalizing to prevent overflowing. When this code works, //it should be optimized vmsVector::Normalize(vDelta); vTop = topPoint->p3_vec; vmsVector::Normalize(vTop); vRodNorm = vmsVector::Cross(vDelta, vTop); vmsVector::Normalize(vRodNorm); //scale for aspect #if RESCALE_ROD vRodNorm.p.x = FixMul (vRodNorm.p.x, viewInfo.scale.p.x); vRodNorm.p.y = FixMul (vRodNorm.p.y, viewInfo.scale.p.y); #endif //now we have the usable edge. generate four points //vTop points vTemp = vRodNorm * xTopWidth; vTemp[Z] = 0; rodPoints [0].p3_vec = topPoint->p3_vec + vTemp; rodPoints [1].p3_vec = topPoint->p3_vec - vTemp; vTemp = vRodNorm * xBtmWidth; vTemp[Z] = 0; rodPoints [2].p3_vec = btmPoint->p3_vec - vTemp; rodPoints [3].p3_vec = btmPoint->p3_vec + vTemp; //now code the four points for (i = 0, andCodes = 0xff; i < 4; i++) andCodes &= G3EncodePoint (rodPoints + i); if (andCodes) return 1; //1 means off screen //clear flags for new points (not projected) for (i = 0; i < 4; i++) { rodPoints [i].p3_flags = 0; rodPoints [i].p3_index = -1; } return 0; }
//sets the tPlayer facing curseg/curside, normal to face0 of curside, and //far enough away to see all of curside int SetPlayerFromCursegMinusOne() { vmsVector view_vec,view_vec2,side_center; vmsVector corner_v[4]; vmsVector upvec; g3sPoint corner_p[4]; int i; fix max,viewDist=f1_0*10; static int edgenum=0; int newseg; view_vec = Cursegp->sides[Curside].normals[0]; VmVecNegate(&view_vec); COMPUTE_SIDE_CENTER(&side_center,Cursegp,Curside); VmVecCopyScale(&view_vec2,&view_vec,viewDist); VmVecSub(&gameData.objs.console->position.vPos,&side_center,&view_vec2); VmVecSub(&upvec, &gameData.segs.vertices[Cursegp->verts[sideToVerts[Curside][edgenum%4]]], &gameData.segs.vertices[Cursegp->verts[sideToVerts[Curside][(edgenum+3)%4]]]); edgenum++; VmVector2Matrix(&gameData.objs.console->position.mOrient,&view_vec,&upvec,NULL); GrSetCurrentCanvas(Canv_editor_game); G3StartFrame(); G3SetViewMatrix(&gameData.objs.console->position.vPos,&gameData.objs.console->position.mOrient,gameStates.render.xZoom, 1); for (i=max=0;i<4;i++) { corner_v[i] = gameData.segs.vertices[Cursegp->verts[sideToVerts[Curside][i]]]; G3TransformAndEncodePoint(&corner_p[i],&corner_v[i]); if (labs(corner_p[i].p3_x) > max) max = labs(corner_p[i].p3_x); if (labs(corner_p[i].p3_y) > max) max = labs(corner_p[i].p3_y); } viewDist = FixMul(viewDist,FixDiv(FixDiv(max,SIDE_VIEW_FRAC),corner_p[0].p3_z); VmVecCopyScale(&view_vec2,&view_vec,viewDist); VmVecSub(&gameData.objs.console->position.vPos,&side_center,&view_vec2); //RelinkObject(OBJ_IDX (gameData.objs.console), SEG_IDX(Cursegp) ); //UpdateObjectSeg(gameData.objs.console); //might have backed right out of curseg newseg = FindSegByPoint(&gameData.objs.console->position.vPos, SEG_IDX(Cursegp), 1, 0); if (newseg != -1) RelinkObject(OBJ_IDX (gameData.objs.console),newseg); UpdateFlags |= UF_ED_STATE_CHANGED | UF_GAME_VIEW_CHANGED; return 1; }
void CShrapnel::Move (void) { fix xSpeed = FixDiv (m_info.xSpeed, I2X (25) / 1000); CFixVector vOffs; time_t nTicks; if ((nTicks = gameStates.app.nSDLTicks - m_info.tUpdate) < 25) return; xSpeed = (fix) (xSpeed / gameStates.gameplay.slowmo [0].fSpeed); for (; nTicks >= 25; nTicks -= 25) { if (--(m_info.nTurn)) vOffs = m_info.vOffs; else { m_info.nTurn = ((m_info.xTTL > I2X (1) / 2) ? 2 : 4) + d_rand () % 4; vOffs = m_info.vDir; vOffs [X] = FixMul (vOffs [X], 2 * d_rand ()); vOffs [Y] = FixMul (vOffs [Y], 2 * d_rand ()); vOffs [Z] = FixMul (vOffs [Z], 2 * d_rand ()); CFixVector::Normalize (vOffs); m_info.vOffs = vOffs; } vOffs *= xSpeed; m_info.vPos += vOffs; } if (m_info.nSmoke >= 0) particleManager.SetPos (m_info.nSmoke, &m_info.vPos, NULL, -1); m_info.tUpdate = gameStates.app.nSDLTicks - nTicks; }
void DigiGetSoundLoc ( vmsMatrix * mListener, vmsVector * vListenerPos, short nListenerSeg, vmsVector * vSoundPos, short nSoundSeg, fix maxVolume, int *volume, int *pan, fix maxDistance) { vmsVector vecToSound; fix angleFromEar, cosang,sinang; fix distance; fix pathDistance; *volume = 0; *pan = 0; maxDistance = (5 * maxDistance) / 4; // Make all sounds travel 1.25 times as far. // Warning: Made the VmVecNormalizedDir be VmVecNormalizedDirQuick and got illegal values to acos in the fang computation. distance = VmVecNormalizedDirQuick (&vecToSound, vSoundPos, vListenerPos); if (distance < maxDistance) { int nSearchSegs = f2i (maxDistance / 20); if (nSearchSegs < 1) nSearchSegs = 1; pathDistance = FindConnectedDistance (vListenerPos, nListenerSeg, vSoundPos, nSoundSeg, nSearchSegs, WID_RENDPAST_FLAG + WID_FLY_FLAG); if (pathDistance > -1) { *volume = maxVolume - FixDiv (pathDistance, maxDistance); if (*volume <= 0) *volume = 0; else { angleFromEar = VmVecDeltaAngNorm (&mListener->rVec, &vecToSound, &mListener->uVec); FixSinCos (angleFromEar, &sinang, &cosang); if (gameConfig.bReverseChannels) cosang = -cosang; *pan = (cosang + F1_0) / 2; } } } }
//------------------------------------------------------------------------------ //performs aspect scaling on global view matrix void ScaleMatrix (int bOglScale) { viewInfo.view [1] = viewInfo.view [0]; //so we can use unscaled if we want viewInfo.viewf [1] = viewInfo.viewf [0]; //so we can use unscaled if we want viewInfo.scale = viewInfo.windowScale; if (viewInfo.zoom <= f1_0) //xZoom in by scaling z viewInfo.scale.p.z = FixMul (viewInfo.scale.p.z, viewInfo.zoom); else { //xZoom out by scaling x&y fix s = FixDiv (f1_0, viewInfo.zoom); viewInfo.scale.p.x = FixMul (viewInfo.scale.p.x, s); viewInfo.scale.p.y = FixMul (viewInfo.scale.p.y, s); } //viewInfo.scale.p.x = viewInfo.scale.p.y = viewInfo.scale.p.z = F1_0; //now scale matrix elements if (bOglScale) //glScalef (f2fl (viewInfo.scale.p.x), f2fl (viewInfo.scale.p.y), -f2fl (viewInfo.scale.p.z)); glScalef (1, 1, -1); else { //VmVecScale (&viewInfo.view [0].rVec, viewInfo.scale.p.x); //VmVecScale (&viewInfo.view [0].uVec, viewInfo.scale.p.y); //viewInfo.scale.p.x = viewInfo.scale.p.y = viewInfo.scale.p.z = F1_0; VmVecScale (&viewInfo.view [0].fVec, -viewInfo.scale.p.z); glScalef (1, 1, 1); } VmsMatToFloat (viewInfo.viewf, viewInfo.view); }
//------------------------------------------------------------------------------ //performs aspect scaling on global view matrix void ScaleMatrix (int bOglScale) { viewInfo.view [1] = viewInfo.view [0]; //so we can use unscaled if we want viewInfo.viewf [1] = viewInfo.viewf [0]; //so we can use unscaled if we want viewInfo.scale = viewInfo.windowScale; if (viewInfo.zoom <= f1_0) //xZoom in by scaling z viewInfo.scale[Z] = FixMul (viewInfo.scale[Z], viewInfo.zoom); else { //xZoom out by scaling x&y fix s = FixDiv (f1_0, viewInfo.zoom); viewInfo.scale[X] = FixMul (viewInfo.scale[X], s); viewInfo.scale[Y] = FixMul (viewInfo.scale[Y], s); } viewInfo.scalef = viewInfo.scale.ToFloat(); //viewInfo.scale[X] = viewInfo.scale[Y] = viewInfo.scale[Z] = F1_0; //now scale matrix elements if (bOglScale) { //glScalef (X2F (viewInfo.scale[X]), X2F (viewInfo.scale[Y]), -X2F (viewInfo.scale[Z])); glScalef (1, 1, -1); } else { //VmVecScale (&viewInfo.view [0].rVec, viewInfo.scale[X]); //VmVecScale (&viewInfo.view [0].uVec, viewInfo.scale[Y]); //viewInfo.scale[X] = viewInfo.scale[Y] = viewInfo.scale[Z] = F1_0; viewInfo.view [0][FVEC] *= (-viewInfo.scale[Z]); glScalef (1, 1, 1); } viewInfo.viewf[0] = viewInfo.view[0].ToFloat(); }
fix ComputeHeadlightLightOnObject (tObject *objP) { int i; fix light; // Let's just illuminate players and robots for speed reasons, ok? if ((objP->nType != OBJ_ROBOT) && (objP->nType != OBJ_PLAYER)) return 0; light = 0; for (i = 0; i < nHeadLights; i++) { fix dot, dist; vmsVector vecToObj; tObject *lightObjP; lightObjP = Headlights [i]; VmVecSub (&vecToObj, &objP->position.vPos, &lightObjP->position.vPos); dist = VmVecNormalize (&vecToObj); if (dist > 0) { dot = VmVecDot (&lightObjP->position.mOrient.fVec, &vecToObj); if (dot < F1_0/2) light += FixDiv (HEADLIGHT_SCALE, FixMul (HEADLIGHT_SCALE, dist)); // Do the normal thing, but darken around headlight. else light += FixMul (FixMul (dot, dot), HEADLIGHT_SCALE)/8; } } return light; }
int FindLineQuadIntersectionSub (CFixVector& intersection, CFixVector *vPlanePoint, CFixVector *vPlaneNorm, CFixVector *p0, CFixVector *p1, fix rad) { CFixVector d, w; double num, den; w = *vPlanePoint - *p0; d = *p1 - *p0; num = double (CFixVector::Dot (*vPlaneNorm, w) - rad) / 65536.0; den = double (CFixVector::Dot (*vPlaneNorm, d)) / 65536.0; if (fabs (den) < 1e-10) return 0; if (fabs (num) > fabs (den)) return 0; #if 0 //do check for potential overflow if (labs (num) / (I2X (1) / 2) >= labs (den)) return 0; #endif #if 0 d *= FixDiv (num, den); intersection = (*p0) + d; #else num /= den; intersection [0] = fix (double ((*p0) [0]) + double (d [0]) * num); intersection [1] = fix (double ((*p0) [1]) + double (d [1]) * num); intersection [2] = fix (double ((*p0) [2]) + double (d [2]) * num); #endif return 1; }
int GrSetMode (u_int32_t mode) { uint w, h; //int bForce = (nCurrentVGAMode < 0); if (mode <= 0) return 0; w = SM_W (mode); h = SM_H (mode); nCurrentVGAMode = mode; screen.Destroy (); screen.Init (); screen.SetMode (mode); screen.SetWidth (w); screen.SetHeight (h); //screen.Aspect () = FixDiv(screen.Width ()*3,screen.Height ()*4); screen.SetAspect (FixDiv (screen.Width (), (fix) (screen.Height () * ((double) w / (double) h)))); screen.Canvas ()->CBitmap::Init (BM_OGL, 0, 0, w, h, 1, NULL); screen.Canvas ()->CreateBuffer (); screen.Canvas ()->SetPalette (paletteManager.Default ()); //just need some valid palette here //screen.Canvas ()->props.rowSize = screen->pitch; //screen.Canvas ()->Buffer () = reinterpret_cast<ubyte*> (screen->pixels); CCanvas::SetCurrent (NULL); CCanvas::Current ()->SetFont (fontManager.Current ()); /***/PrintLog (" initializing OpenGL window\n"); if (!SdlGlInitWindow (w, h, 0)) //platform specific code return 0; /***/PrintLog (" initializing OpenGL view port\n"); ogl.Viewport (0, 0, w, h); /***/PrintLog (" initializing OpenGL screen mode\n"); ogl.SetScreenMode (); ogl.GetVerInfo (); GrUpdate (0); return 0; }
//------------------------------------------------------------------------------ //compute the corners of a rod. fills in vertbuf. int CalcRodCorners (g3sPoint *bot_point, fix bot_width, g3sPoint *top_point, fix top_width) { vmsVector delta_vec, top, tempv, rod_norm; ubyte codes_and; int i; //compute vector from one point to other, do cross product with vector //from eye to get perpendiclar VmVecSub (&delta_vec, &bot_point->p3_vec, &top_point->p3_vec); //unscale for aspect delta_vec.x = FixDiv (delta_vec.x, viewInfo.scale.x); delta_vec.y = FixDiv (delta_vec.y, viewInfo.scale.y); //calc perp vector //do lots of normalizing to prevent overflowing. When this code works, //it should be optimized VmVecNormalize (&delta_vec); VmVecCopyNormalize (&top, &top_point->p3_vec); VmVecCross (&rod_norm, &delta_vec, &top); VmVecNormalize (&rod_norm); //scale for aspect rod_norm.x = FixMul (rod_norm.x, viewInfo.scale.x); rod_norm.y = FixMul (rod_norm.y, viewInfo.scale.y); //now we have the usable edge. generate four points //top points VmVecCopyScale (&tempv, &rod_norm, top_width); tempv.z = 0; VmVecAdd (&rodPoints [0].p3_vec, &top_point->p3_vec, &tempv); VmVecSub (&rodPoints [1].p3_vec, &top_point->p3_vec, &tempv); VmVecCopyScale (&tempv, &rod_norm, bot_width); tempv.z = 0; VmVecSub (&rodPoints [2].p3_vec, &bot_point->p3_vec, &tempv); VmVecAdd (&rodPoints [3].p3_vec, &bot_point->p3_vec, &tempv); //now code the four points for (i = 0, codes_and = 0xff; i < 4; i++) codes_and &= G3EncodePoint (rodPoints + i); if (codes_and) return 1; //1 means off screen //clear flags for new points (not projected) for (i = 0; i < 4; i++) { rodPoints [i].p3Flags = 0; rodPoints [i].p3_index = -1; } return 0; }
// ---------------------------------------------------------------------- // General purpose robot-dies-with-death-roll-and-groan code. // Return true if CObject just died. // scale: I2X (4) for boss, much smaller for much smaller guys int DoRobotDyingFrame (CObject *objP, fix StartTime, fix xRollDuration, sbyte *bDyingSoundPlaying, short deathSound, fix xExplScale, fix xSoundScale) { fix xRollVal, temp; fix xSoundDuration; CSoundSample *soundP; if (!xRollDuration) xRollDuration = I2X (1)/4; xRollVal = FixDiv (gameData.time.xGame - StartTime, xRollDuration); FixSinCos (FixMul (xRollVal, xRollVal), &temp, &objP->mType.physInfo.rotVel[X]); FixSinCos (xRollVal, &temp, &objP->mType.physInfo.rotVel[Y]); FixSinCos (xRollVal-I2X (1)/8, &temp, &objP->mType.physInfo.rotVel[Z]); temp = gameData.time.xGame - StartTime; objP->mType.physInfo.rotVel[X] = temp / 9; objP->mType.physInfo.rotVel[Y] = temp / 5; objP->mType.physInfo.rotVel[Z] = temp / 7; if (gameOpts->sound.digiSampleRate) { soundP = gameData.pig.sound.soundP + audio.XlatSound (deathSound); xSoundDuration = FixDiv (soundP->nLength [soundP->bHires], gameOpts->sound.digiSampleRate); } else xSoundDuration = I2X (1); if (StartTime + xRollDuration - xSoundDuration < gameData.time.xGame) { if (!*bDyingSoundPlaying) { #if TRACE console.printf (CON_DBG, "Starting death sound!\n"); #endif *bDyingSoundPlaying = 1; audio.CreateObjectSound (deathSound, SOUNDCLASS_ROBOT, objP->Index (), 0, xSoundScale, xSoundScale * 256); // I2X (5)12 means play twice as loud } else if (d_rand () < gameData.time.xFrame*16) CreateSmallFireballOnObject (objP, (I2X (1) + d_rand ()) * (16 * xExplScale/I2X (1)) / 8, 0); } else if (d_rand () < gameData.time.xFrame * 8) CreateSmallFireballOnObject (objP, (I2X (1)/2 + d_rand ()) * (16 * xExplScale / I2X (1)) / 8, 1); return (StartTime + xRollDuration < gameData.time.xGame); }
// ---------------------------------------------------------------------- // General purpose robot-dies-with-death-roll-and-groan code. // Return true if tObject just died. // scale: F1_0*4 for boss, much smaller for much smaller guys int DoRobotDyingFrame (tObject *objP, fix StartTime, fix xRollDuration, sbyte *bDyingSoundPlaying, short deathSound, fix xExplScale, fix xSoundScale) { fix xRollVal, temp; fix xSoundDuration; tDigiSound *soundP; if (!xRollDuration) xRollDuration = F1_0/4; xRollVal = FixDiv (gameData.time.xGame - StartTime, xRollDuration); FixSinCos (FixMul (xRollVal, xRollVal), &temp, &objP->mType.physInfo.rotVel.p.x); FixSinCos (xRollVal, &temp, &objP->mType.physInfo.rotVel.p.y); FixSinCos (xRollVal-F1_0/8, &temp, &objP->mType.physInfo.rotVel.p.z); temp = gameData.time.xGame - StartTime; objP->mType.physInfo.rotVel.p.x = temp / 9; objP->mType.physInfo.rotVel.p.y = temp / 5; objP->mType.physInfo.rotVel.p.z = temp / 7; if (gameOpts->sound.digiSampleRate) { soundP = gameData.pig.sound.pSounds + DigiXlatSound (deathSound); xSoundDuration = FixDiv (soundP->nLength [soundP->bHires], gameOpts->sound.digiSampleRate); } else xSoundDuration = F1_0; if (StartTime + xRollDuration - xSoundDuration < gameData.time.xGame) { if (!*bDyingSoundPlaying) { #if TRACE con_printf (CONDBG, "Starting death sound!\n"); #endif *bDyingSoundPlaying = 1; DigiLinkSoundToObject2 (deathSound, OBJ_IDX (objP), 0, xSoundScale, xSoundScale * 256, SOUNDCLASS_ROBOT); // F1_0*512 means play twice as loud } else if (d_rand () < gameData.time.xFrame*16) CreateSmallFireballOnObject (objP, (F1_0 + d_rand ()) * (16 * xExplScale/F1_0) / 8, 0); } else if (d_rand () < gameData.time.xFrame * 8) CreateSmallFireballOnObject (objP, (F1_0/2 + d_rand ()) * (16 * xExplScale / F1_0) / 8, 1); return (StartTime + xRollDuration < gameData.time.xGame); }
const CFixMatrix CFixMatrix::Inverse (void) { fix xDet = Det (); CFixMatrix m; m.m_data.mat [RVEC][X] = FixDiv (FixMul (m_data.mat [UVEC][Y], m_data.mat [FVEC][Z]) - FixMul (m_data.mat [UVEC][Z], m_data.mat [FVEC][Y]), xDet); m.m_data.mat [RVEC][Y] = FixDiv (FixMul (m_data.mat [RVEC][Z], m_data.mat [FVEC][Y]) - FixMul (m_data.mat [RVEC][Y], m_data.mat [FVEC][Z]), xDet); m.m_data.mat [RVEC][Z] = FixDiv (FixMul (m_data.mat [RVEC][Y], m_data.mat [UVEC][Z]) - FixMul (m_data.mat [RVEC][Z], m_data.mat [UVEC][Y]), xDet); m.m_data.mat [UVEC][X] = FixDiv (FixMul (m_data.mat [UVEC][Z], m_data.mat [FVEC][X]) - FixMul (m_data.mat [UVEC][X], m_data.mat [FVEC][Z]), xDet); m.m_data.mat [UVEC][Y] = FixDiv (FixMul (m_data.mat [RVEC][X], m_data.mat [FVEC][Z]) - FixMul (m_data.mat [RVEC][Z], m_data.mat [FVEC][X]), xDet); m.m_data.mat [UVEC][Z] = FixDiv (FixMul (m_data.mat [RVEC][Z], m_data.mat [UVEC][X]) - FixMul (m_data.mat [RVEC][X], m_data.mat [UVEC][Z]), xDet); m.m_data.mat [FVEC][X] = FixDiv (FixMul (m_data.mat [UVEC][X], m_data.mat [FVEC][Y]) - FixMul (m_data.mat [UVEC][Y], m_data.mat [FVEC][X]), xDet); m.m_data.mat [FVEC][Y] = FixDiv (FixMul (m_data.mat [RVEC][Y], m_data.mat [FVEC][X]) - FixMul (m_data.mat [RVEC][X], m_data.mat [FVEC][Y]), xDet); m.m_data.mat [FVEC][Z] = FixDiv (FixMul (m_data.mat [RVEC][X], m_data.mat [UVEC][Y]) - FixMul (m_data.mat [RVEC][Y], m_data.mat [UVEC][X]), xDet); return m; }
// -------------------------------------------------------------------------------------------------------------------- // Lead the CPlayerData, returning point to fire at in vFirePoint. // Rules: // Player not cloaked // Player must be moving at a speed >= MIN_LEAD_SPEED // Player not farther away than MAX_LEAD_DISTANCE // dot (vector_to_player, player_direction) must be in -LEAD_RANGE,LEAD_RANGE // if firing a matter weapon, less leading, based on skill level. int LeadPlayer (CObject *objP, CFixVector *vFirePoint, CFixVector *vBelievedPlayerPos, int nGuns, CFixVector *vFire) { fix dot, xPlayerSpeed, xDistToPlayer, xMaxWeaponSpeed, xProjectedTime; CFixVector vPlayerMovementDir, vVecToPlayer; int nWeaponType; CWeaponInfo *wiP; tRobotInfo *botInfoP; if (LOCALPLAYER.flags & PLAYER_FLAGS_CLOAKED) return 0; vPlayerMovementDir = gameData.objs.consoleP->mType.physInfo.velocity; xPlayerSpeed = CFixVector::Normalize(vPlayerMovementDir); if (xPlayerSpeed < MIN_LEAD_SPEED) return 0; vVecToPlayer = *vBelievedPlayerPos - *vFirePoint; xDistToPlayer = CFixVector::Normalize(vVecToPlayer); if (xDistToPlayer > MAX_LEAD_DISTANCE) return 0; dot = CFixVector::Dot (vVecToPlayer, vPlayerMovementDir); if ((dot < -LEAD_RANGE) || (dot > LEAD_RANGE)) return 0; // Looks like it might be worth trying to lead the player. botInfoP = &ROBOTINFO (objP->info.nId); nWeaponType = botInfoP->nWeaponType; if ((nGuns == 0) && (botInfoP->nSecWeaponType != -1)) nWeaponType = botInfoP->nSecWeaponType; wiP = gameData.weapons.info + nWeaponType; xMaxWeaponSpeed = wiP->speed [gameStates.app.nDifficultyLevel]; if (xMaxWeaponSpeed < I2X (1)) return 0; // Matter weapons: // At Rookie or Trainee, don't lead at all. // At higher skill levels, don't lead as well. Accomplish this by screwing up xMaxWeaponSpeed. if (wiP->matter) { if (gameStates.app.nDifficultyLevel <= 1) return 0; else xMaxWeaponSpeed *= (NDL-gameStates.app.nDifficultyLevel); } xProjectedTime = FixDiv (xDistToPlayer, xMaxWeaponSpeed); (*vFire)[X] = ComputeLeadComponent ((*vBelievedPlayerPos)[X], (*vFirePoint)[X], gameData.objs.consoleP->mType.physInfo.velocity[X], xProjectedTime); (*vFire)[Y] = ComputeLeadComponent ((*vBelievedPlayerPos)[Y], (*vFirePoint)[Y], gameData.objs.consoleP->mType.physInfo.velocity[Y], xProjectedTime); (*vFire)[Z] = ComputeLeadComponent ((*vBelievedPlayerPos)[Z], (*vFirePoint)[Z], gameData.objs.consoleP->mType.physInfo.velocity[Z], xProjectedTime); CFixVector::Normalize(*vFire); Assert (CFixVector::Dot (*vFire, objP->info.position.mOrient.FVec ()) < I2X (3)/2); // Make sure not firing at especially strange angle. If so, try to correct. If still bad, give up after one try. if (CFixVector::Dot (*vFire, objP->info.position.mOrient.FVec ()) < I2X (1)/2) { *vFire += vVecToPlayer; *vFire *= I2X (1)/2; if (CFixVector::Dot (*vFire, objP->info.position.mOrient.FVec ()) < I2X (1)/2) { return 0; } } return 1; }
void CObject::CheckAfterburnerBlobDrop (void) { if (gameStates.render.bDropAfterburnerBlob) { Assert (this == gameData.objs.consoleP); DropAfterburnerBlobs (this, 2, I2X (5) / 2, -1, NULL, 0); // -1 means use default lifetime if (IsMultiGame) MultiSendDropBlobs ((char) gameData.multiplayer.nLocalPlayer); gameStates.render.bDropAfterburnerBlob = 0; } if ((info.nType == OBJ_WEAPON) && (gameData.weapons.info [info.nId].nAfterburnerSize)) { int nObject, bSmoke; fix vel; fix delay, lifetime, nSize; #if 1 if ((info.nType == OBJ_WEAPON) && gameData.objs.bIsMissile [info.nId]) { if (SHOW_SMOKE && gameOpts->render.particles.bMissiles) return; if ((gameStates.app.bNostalgia || EGI_FLAG (bThrusterFlames, 1, 1, 0)) && (info.nId != MERCURYMSL_ID)) return; } #endif if ((vel = mType.physInfo.velocity.Mag()) > I2X (200)) delay = I2X (1) / 16; else if (vel > I2X (40)) delay = FixDiv (I2X (13), vel); else delay = DEG90; if ((bSmoke = SHOW_SMOKE && gameOpts->render.particles.bMissiles)) { nSize = I2X (3); lifetime = I2X (1) / 12; delay = 0; } else { nSize = I2X (gameData.weapons.info [info.nId].nAfterburnerSize) / 16; lifetime = 3 * delay / 2; if (!IsMultiGame) { delay /= 2; lifetime *= 2; } } nObject = OBJ_IDX (this); if (bSmoke || (gameData.objs.xLastAfterburnerTime [nObject] + delay < gameData.time.xGame) || (gameData.objs.xLastAfterburnerTime [nObject] > gameData.time.xGame)) { DropAfterburnerBlobs (this, 1, nSize, lifetime, NULL, bSmoke); gameData.objs.xLastAfterburnerTime [nObject] = gameData.time.xGame; } } }
// ----------------------------------------------------------------------------- // Applies an instantaneous whack on an tObject, resulting in an instantaneous // change in orientation. void PhysApplyRot (tObject *objP, vmsVector *vForce) { fix rate, vecmag; if (objP->movementType != MT_PHYSICS) return; vecmag = VmVecMag (vForce)/8; if (vecmag < F1_0/256) rate = 4*F1_0; else if (vecmag < objP->mType.physInfo.mass >> 14) rate = 4*F1_0; else { rate = FixDiv (objP->mType.physInfo.mass, vecmag); if (objP->nType == OBJ_ROBOT) { if (rate < F1_0/4) rate = F1_0/4; // Changed by mk, 10/24/95, claw guys should not slow down when attacking! if (!gameData.bots.pInfo [objP->id].thief && !gameData.bots.pInfo [objP->id].attackType) { if (objP->cType.aiInfo.SKIP_AI_COUNT * gameData.time.xFrame < 3*F1_0/4) { fix tval = FixDiv (F1_0, 8*gameData.time.xFrame); int addval; addval = f2i (tval); if ((d_rand () * 2) < (tval & 0xffff)) addval++; objP->cType.aiInfo.SKIP_AI_COUNT += addval; } } } else { if (rate < F1_0/2) rate = F1_0/2; } } // Turn amount inversely proportional to mass. Third parameter is seconds to do 360 turn. physics_turn_towards_vector (vForce, objP, rate); }
//------------------------------------------------------------------------------ //compute aspect ratio for this canvas void CTransformation::ComputeAspect (void) { fix s = FixMulDiv (screen.Aspect (), CCanvas::Current ()->Height (), CCanvas::Current ()->Width ()); if (s <= I2X (1)) { //scale x m_info.aspect [X] = s; m_info.aspect [Y] = I2X (1); } else { m_info.aspect [Y] = FixDiv (I2X (1), s); m_info.aspect [X] = I2X (1); } m_info.aspect [Z] = I2X (1); //always 1 }
// ------------------------------------------------------------------------------------------------------ // Note: This is the old AITurnTowardsVector code. // PhysApplyRot used to call AITurnTowardsVector until I fixed it, which broke PhysApplyRot. void physics_turn_towards_vector (vmsVector *goal_vector, tObject *objP, fix rate) { vmsAngVec dest_angles, cur_angles; fix delta_p, delta_h; vmsVector *rotvel_ptr = &objP->mType.physInfo.rotVel; // Make this tObject turn towards the goal_vector. Changes orientation, doesn't change direction of movement. // If no one moves, will be facing goal_vector in 1 second. // Detect null vector. if ((goal_vector->x == 0) && (goal_vector->y == 0) && (goal_vector->z == 0)) return; // Make morph gameData.objs.objects turn more slowly. if (objP->controlType == CT_MORPH) rate *= 2; VmExtractAnglesVector (&dest_angles, goal_vector); VmExtractAnglesVector (&cur_angles, &objP->orient.fVec); delta_p = (dest_angles.p - cur_angles.p); delta_h = (dest_angles.h - cur_angles.h); if (delta_p > F1_0/2) delta_p = dest_angles.p - cur_angles.p - F1_0; if (delta_p < -F1_0/2) delta_p = dest_angles.p - cur_angles.p + F1_0; if (delta_h > F1_0/2) delta_h = dest_angles.h - cur_angles.h - F1_0; if (delta_h < -F1_0/2) delta_h = dest_angles.h - cur_angles.h + F1_0; delta_p = FixDiv (delta_p, rate); delta_h = FixDiv (delta_h, rate); if (abs (delta_p) < F1_0/16) delta_p *= 4; if (abs (delta_h) < F1_0/16) delta_h *= 4; PhysicsSetRotVelAndSaturate (&rotvel_ptr->x, delta_p); PhysicsSetRotVelAndSaturate (&rotvel_ptr->y, delta_h); rotvel_ptr->z = 0; }
void DigiGetSoundLoc ( vmsMatrix *mListener, vmsVector *vListenerPos, short nListenerSeg, vmsVector *vSoundPos, short nSoundSeg, fix maxVolume, int *volume, int *pan, fix maxDistance, int nDecay) { vmsVector vecToSound; fix angleFromEar, cosang, sinang; fix distance, pathDistance; float fDecay; *volume = 0; *pan = 0; if (nDecay) maxDistance *= 2; else maxDistance = (5 * maxDistance) / 4; // Make all sounds travel 1.25 times as far. distance = VmVecNormalizedDir (&vecToSound, vSoundPos, vListenerPos); if (distance < maxDistance) { int nSearchSegs = f2i (maxDistance / 10); if (nSearchSegs < 1) nSearchSegs = 1; pathDistance = FindConnectedDistance (vListenerPos, nListenerSeg, vSoundPos, nSoundSeg, nSearchSegs, WID_RENDPAST_FLAG | WID_FLY_FLAG, 0); if (pathDistance > -1) { if (!nDecay) *volume = maxVolume - FixDiv (pathDistance, maxDistance); else if (nDecay == 1) { fDecay = (float) exp (-log (2.0f) * 4.0f * f2fl (pathDistance) / f2fl (maxDistance / 2)); *volume = (int) (maxVolume * fDecay); } else { fDecay = 1.0f - f2fl (pathDistance) / f2fl (maxDistance); *volume = (int) (maxVolume * fDecay * fDecay * fDecay); } if (*volume <= 0) *volume = 0; else { angleFromEar = VmVecDeltaAngNorm (&mListener->rVec, &vecToSound, &mListener->uVec); FixSinCos (angleFromEar, &sinang, &cosang); if (gameConfig.bReverseChannels || gameOpts->sound.bHires) cosang = -cosang; *pan = (cosang + F1_0) / 2; } } } }
void PhysApplyForce (tObject *objP, vmsVector *vForce) { // Put in by MK on 2/13/96 for force getting applied to Omega blobs, which have 0 mass, // in collision with crazy reactor robot thing on d2levf-s. if (objP->mType.physInfo.mass == 0) return; if (objP->movementType != MT_PHYSICS) return; #ifdef TACTILE if (TactileStick && obj==&gameData.objs.objects [gameData.multi.players [gameData.multi.nLocalPlayer].nObject]) Tactile_apply_force (vForce, &objP->orient); #endif //Add in acceleration due to force if (!gameData.objs.speedBoost [OBJ_IDX (objP)].bBoosted || (objP != gameData.objs.console)) VmVecScaleInc (&objP->mType.physInfo.velocity, vForce, FixDiv (f1_0, objP->mType.physInfo.mass)); }
int GrSetMode(int mode) { unsigned int w,h,t,r; if (mode == SM_ORIGINAL) return 0; switch (mode) { case SM(320,200): w = 320; r = 320; h = 200; t=BM_LINEAR;//BM_DIRECTX;; break; default: return 1; } GrPaletteStepClear(); memset( grdCurScreen, 0, sizeof(grs_screen); grdCurScreen->sc_mode = mode; grdCurScreen->sc_w = w; grdCurScreen->sc_h = h; grdCurScreen->sc_aspect = FixDiv(grdCurScreen->sc_w*3,grdCurScreen->sc_h*4); GrInitCanvas(&grdCurScreen->sc_canvas, (unsigned char *)BM_D3D_DISPLAY, t, w, h); GrSetCurrentCanvas(NULL); if (!(backbuffer = createdib())) return 1; grdCurScreen->sc_canvas.cv_bitmap.bm_texBuf = backbuffer; grdCurScreen->sc_canvas.cv_bitmap.bm_props.type = BM_LINEAR; grdCurScreen->sc_canvas.cv_bitmap.bm_props.x = 0; grdCurScreen->sc_canvas.cv_bitmap.bm_props.y = 0; grdCurScreen->sc_canvas.cv_bitmap.bm_props.w = w; grdCurScreen->sc_canvas.cv_bitmap.bm_props.h = h; grdCurScreen->sc_canvas.cv_bitmap.bm_props.rowsize = w; gamefont_choose_game_font(w,h); return 0; }
void RenderFastShadows (fix nEyeOffset, int nWindow, short nStartSeg) { #if 0//OOF_TEST_CUBE # if 1 for (bShadowTest = 1; bShadowTest >= 0; bShadowTest--) # else for (bShadowTest = 0; bShadowTest < 2; bShadowTest++) # endif #endif { gameStates.render.nShadowPass = 2; OglStartFrame (0, 0); gameData.render.shadows.nFrame = !gameData.render.shadows.nFrame; //RenderObjectShadows (); RenderMine (nStartSeg, nEyeOffset, nWindow); } #if DBG if (!bShadowTest) #endif { gameStates.render.nShadowPass = 3; OglStartFrame (0, 0); if (gameStates.render.bShadowMaps) { #if DBG if (gameStates.render.bExternalView) #else if (gameStates.render.bExternalView && (!IsMultiGame || IsCoopGame || EGI_FLAG (bEnableCheats, 0, 0, 0))) #endif G3SetViewMatrix(gameData.render.mine.viewerEye, externalView.pPos ? externalView.pPos->mOrient : gameData.objs.viewerP->info.position.mOrient, gameStates.render.xZoom, 1); else G3SetViewMatrix(gameData.render.mine.viewerEye, gameData.objs.viewerP->info.position.mOrient, FixDiv (gameStates.render.xZoom, gameStates.render.nZoomFactor), 1); ApplyShadowMaps (nStartSeg, nEyeOffset, nWindow); } else { RenderShadowQuad (0); } } }
void BuildTerrainLightMap () { int i, j; fix l, l2, lMin = 0x7fffffff, lMax = 0; if (gameData.render.terrain.pLightMap) D2_FREE (gameData.render.terrain.pLightMap) else atexit (FreeTerrainLightMap); //first time gameData.render.terrain.pPoints = (vmsVector *) D2_ALLOC (GRID_SIZE * sizeof (vmsVector)); gameData.render.terrain.pLightMap = (fix *) D2_ALLOC (GRID_SIZE * sizeof (fix)); ComputeTerrainPoints (); for (i = 0; i < gameData.render.terrain.nGridW; i++) { for (j = 0; j < gameData.render.terrain.nGridH; j++) { l = GetAvgTerrainLight (i, j); if (l > lMax) lMax = l; if (l < lMin) lMin = l; if (lMin < 0) l = GetAvgTerrainLight (i, j); } } for (i = 0; i < gameData.render.terrain.nGridW; i++) { for (j = 0; j < gameData.render.terrain.nGridH; j++) { l = GetAvgTerrainLight (i, j); if (lMin == lMax) LIGHT (i, j) = l;// >> 8; else { l2 = FixDiv ((l - lMin), (lMax - lMin)); if (l2 == f1_0) l2--; LIGHT (i, j) = l2;// >> 8; } } } D2_FREE (gameData.render.terrain.pPoints); }
void BuildTerrainLightmap () { int i, j; fix l, l2, lMin = 0x7fffffff, lMax = 0; if (gameData.render.terrain.lightmap.Buffer ()) gameData.render.terrain.lightmap.Destroy (); else atexit (FreeTerrainLightmap); //first time gameData.render.terrain.points.Create (GRID_SIZE); gameData.render.terrain.lightmap.Create (GRID_SIZE); ComputeTerrainPoints (); for (i = 0; i < gameData.render.terrain.nGridW; i++) { for (j = 0; j < gameData.render.terrain.nGridH; j++) { l = GetAvgTerrainLight (i, j); if (l > lMax) lMax = l; if (l < lMin) lMin = l; if (lMin < 0) l = GetAvgTerrainLight (i, j); } } for (i = 0; i < gameData.render.terrain.nGridW; i++) { for (j = 0; j < gameData.render.terrain.nGridH; j++) { l = GetAvgTerrainLight (i, j); if (lMin == lMax) LIGHT (i, j) = l;// >> 8; else { l2 = FixDiv ((l - lMin), (lMax - lMin)); if (l2 == I2X (1)) l2--; LIGHT (i, j) = l2;// >> 8; } } } gameData.render.terrain.points.Destroy (); }
void DigiGetSoundLoc ( vms_matrix * listener, vms_vector * listener_pos, short listener_seg, vms_vector * sound_pos, short sound_seg, fix max_volume, int *volume, int *pan, fix max_distance) { vms_vector vector_to_sound; fix angle_from_ear, cosang,sinang; fix distance; fix path_distance; *volume = 0; *pan = 0; max_distance = (max_distance*5)/4; // Make all sounds travel 1.25 times as far. // Warning: Made the VmVecNormalizedDir be VmVecNormalizedDirQuick and got illegal values to acos in the fang computation. distance = VmVecNormalizedDirQuick (&vector_to_sound, sound_pos, listener_pos); if (distance < max_distance) { int num_search_segs = f2i (max_distance/20); if (num_search_segs < 1) num_search_segs = 1; path_distance = FindConnectedDistance (listener_pos, listener_seg, sound_pos, sound_seg, num_search_segs, WID_RENDPAST_FLAG+WID_FLY_FLAG); if (path_distance > -1) { *volume = max_volume - FixDiv (path_distance,max_distance); ////mprintf ((0, "Sound path distance %.2f, volume is %d / %d\n", f2fl (distance), *volume, max_volume)); if (*volume > 0) { angle_from_ear = VmVecDeltaAngNorm (&listener->rvec,&vector_to_sound,&listener->uvec); fix_sincos (angle_from_ear,&sinang,&cosang); ////mprintf ((0, "volume is %.2f\n", f2fl (*volume))); if (gameConfig.bReverseChannels) cosang *= -1; *pan = (cosang + F1_0)/2; } else { *volume = 0; } } } }
// -------------------------------------------------------------------------------------------------------------------- // Note: Parameter gameData.ai.vVecToPlayer is only passed now because guns which aren't on the forward vector from the // center of the robot will not fire right at the player. We need to aim the guns at the player. Barring that, we cheat. // When this routine is complete, the parameter gameData.ai.vVecToPlayer should not be necessary. void AIFireLaserAtPlayer (CObject *objP, CFixVector *vFirePoint, int nGun, CFixVector *vBelievedPlayerPos) { short nShot, nObject = objP->Index (); tAILocalInfo *ailP = gameData.ai.localInfo + nObject; tRobotInfo *botInfoP = &ROBOTINFO (objP->info.nId); CFixVector vFire; CFixVector bpp_diff; short nWeaponType; fix aim, dot; int count, i; Assert (nObject >= 0); // If this robot is only awake because a camera woke it up, don't fire. if (objP->cType.aiInfo.SUB_FLAGS & SUB_FLAGS_CAMERA_AWAKE) return; if (!gameStates.app.cheats.bRobotsFiring) return; if (objP->info.controlType == CT_MORPH) return; // If player is exploded, stop firing. if (gameStates.app.bPlayerExploded) return; if (objP->cType.aiInfo.xDyingStartTime) return; // No firing while in death roll. // Don't let the boss fire while in death roll. Sorry, this is the easiest way to do this. // If you try to key the boss off objP->cType.aiInfo.xDyingStartTime, it will hose the endlevel stuff. if (ROBOTINFO (objP->info.nId).bossFlag) { i = gameData.bosses.Find (nObject); if ((i < 0) || (gameData.bosses [i].m_nDyingStartTime)) return; } // If CPlayerData is cloaked, maybe don't fire based on how long cloaked and randomness. if (LOCALPLAYER.flags & PLAYER_FLAGS_CLOAKED) { fix xCloakTime = gameData.ai.cloakInfo [nObject % MAX_AI_CLOAK_INFO].lastTime; if ((gameData.time.xGame - xCloakTime > CLOAK_TIME_MAX/4) && (d_rand () > FixDiv (gameData.time.xGame - xCloakTime, CLOAK_TIME_MAX)/2)) { SetNextFireTime (objP, ailP, botInfoP, nGun); return; } } // Handle problem of a robot firing through a CWall because its gun tip is on the other // CSide of the CWall than the robot's center. For speed reasons, we normally only compute // the vector from the gun point to the player. But we need to know whether the gun point // is separated from the robot's center by a CWall. If so, don't fire! if (objP->cType.aiInfo.SUB_FLAGS & SUB_FLAGS_GUNSEG) { // Well, the gun point is in a different CSegment than the robot's center. // This is almost always ok, but it is not ok if something solid is in between. int nGunSeg = FindSegByPos (*vFirePoint, objP->info.nSegment, 1, 0); // See if these segments are connected, which should almost always be the case. short nConnSide = SEGMENTS [nGunSeg].ConnectedSide (&SEGMENTS [objP->info.nSegment]); if (nConnSide != -1) { // They are connected via nConnSide in CSegment objP->info.nSegment. // See if they are unobstructed. if (!(SEGMENTS [objP->info.nSegment].IsDoorWay (nConnSide, NULL) & WID_FLY_FLAG)) { // Can't fly through, so don't let this bot fire through! return; } } else { // Well, they are not directly connected, so use FindVectorIntersection to see if they are unobstructed. tFVIQuery fq; tFVIData hit_data; int fate; fq.startSeg = objP->info.nSegment; fq.p0 = &objP->info.position.vPos; fq.p1 = vFirePoint; fq.radP0 = fq.radP1 = 0; fq.thisObjNum = objP->Index (); fq.ignoreObjList = NULL; fq.flags = FQ_TRANSWALL; fate = FindVectorIntersection (&fq, &hit_data); if (fate != HIT_NONE) { Int3 (); // This bot's gun is poking through a CWall, so don't fire. MoveTowardsSegmentCenter (objP); // And decrease chances it will happen again. return; } } } // Set position to fire at based on difficulty level and robot's aiming ability aim = I2X (FIRE_K) - (FIRE_K-1)* (botInfoP->aim << 8); // I2X (1) in bitmaps.tbl = same as used to be. Worst is 50% more error. // Robots aim more poorly during seismic disturbance. if (gameStates.gameplay.seismic.nMagnitude) { fix temp = I2X (1) - abs (gameStates.gameplay.seismic.nMagnitude); if (temp < I2X (1)/2) temp = I2X (1)/2; aim = FixMul (aim, temp); } // Lead the CPlayerData half the time. // Note that when leading the CPlayerData, aim is perfect. This is probably acceptable since leading is so hacked in. // Problem is all robots will lead equally badly. if (d_rand () < 16384) { if (LeadPlayer (objP, vFirePoint, vBelievedPlayerPos, nGun, &vFire)) // Stuff direction to fire at in vFirePoint. goto player_led; } dot = 0; count = 0; // Don't want to sit in this loop foreverd:\temp\dm_test. i = (NDL - gameStates.app.nDifficultyLevel - 1) * 4; while ((count < 4) && (dot < I2X (1)/4)) { bpp_diff[X] = (*vBelievedPlayerPos)[X] + FixMul ((d_rand ()-16384) * i, aim); bpp_diff[Y] = (*vBelievedPlayerPos)[Y] + FixMul ((d_rand ()-16384) * i, aim); bpp_diff[Z] = (*vBelievedPlayerPos)[Z] + FixMul ((d_rand ()-16384) * i, aim); CFixVector::NormalizedDir(vFire, bpp_diff, *vFirePoint); dot = CFixVector::Dot (objP->info.position.mOrient.FVec (), vFire); count++; } player_led: nWeaponType = botInfoP->nWeaponType; if ((botInfoP->nSecWeaponType != -1) && ((nWeaponType < 0) || !nGun)) nWeaponType = botInfoP->nSecWeaponType; if (nWeaponType < 0) return; if (0 > (nShot = CreateNewLaserEasy (&vFire, vFirePoint, objP->Index (), (ubyte) nWeaponType, 1))) return; lightClusterManager.AddForAI (objP, nObject, nShot); objP->Shots ().nObject = nShot; objP->Shots ().nSignature = OBJECTS [nShot].info.nSignature; if (IsMultiGame) { AIMultiSendRobotPos (nObject, -1); MultiSendRobotFire (nObject, objP->cType.aiInfo.CURRENT_GUN, &vFire); } #if 1 if (++(objP->cType.aiInfo.CURRENT_GUN) >= botInfoP->nGuns) { if ((botInfoP->nGuns == 1) || (botInfoP->nSecWeaponType == -1)) objP->cType.aiInfo.CURRENT_GUN = 0; else objP->cType.aiInfo.CURRENT_GUN = 1; } #endif CreateAwarenessEvent (objP, PA_NEARBY_ROBOT_FIRED); SetNextFireTime (objP, ailP, botInfoP, nGun); }
void ReadFlyingControls (CObject *objP) { fix forwardThrustTime; CObject* gmObjP; int bMulti; if (gameData.time.xFrame <= 0) return; if (gameStates.app.bPlayerIsDead || gameStates.app.bEnterGame) { StopPlayerMovement (); FlushInput (); /* VmVecZero(&objP->mType.physInfo.rotThrust); VmVecZero(&objP->mType.physInfo.thrust); VmVecZero(&objP->mType.physInfo.velocity); */ gameStates.app.bEnterGame--; return; } if ((objP->info.nType != OBJ_PLAYER) || (objP->info.nId != gameData.multiplayer.nLocalPlayer)) return; //references to CPlayerShip require that this obj be the CPlayerData tGuidedMissileInfo *gmiP = gameData.objs.guidedMissile + gameData.multiplayer.nLocalPlayer; gmObjP = gmiP->objP; if (gmObjP && (gmObjP->info.nSignature == gmiP->nSignature)) { CAngleVector vRotAngs; CFixMatrix mRot, mOrient; fix speed; //this is a horrible hack. guided missile stuff should not be //handled in the middle of a routine that is dealing with the CPlayerData objP->mType.physInfo.rotThrust.SetZero (); vRotAngs [PA] = Controls [0].pitchTime / 2 + gameStates.gameplay.seismic.nMagnitude / 64; vRotAngs [BA] = Controls [0].bankTime / 2 + gameStates.gameplay.seismic.nMagnitude / 16; vRotAngs [HA] = Controls [0].headingTime / 2 + gameStates.gameplay.seismic.nMagnitude / 64; mRot = CFixMatrix::Create (vRotAngs); mOrient = gmObjP->info.position.mOrient * mRot; gmObjP->info.position.mOrient = mOrient; speed = WI_speed (gmObjP->info.nId, gameStates.app.nDifficultyLevel); gmObjP->mType.physInfo.velocity = gmObjP->info.position.mOrient.FVec () * speed; if(IsMultiGame) MultiSendGuidedInfo (gmObjP, 0); } else { #if DBG if (Controls [0].headingTime) Controls [0].headingTime = Controls [0].headingTime; #endif objP->mType.physInfo.rotThrust = CFixVector::Create (Controls [0].pitchTime, Controls [0].headingTime, //Controls [0].headingTime ? I2X (1) / 4 : 0; //Controls [0].headingTime; Controls [0].bankTime); } forwardThrustTime = Controls [0].forwardThrustTime; if ((LOCALPLAYER.flags & PLAYER_FLAGS_AFTERBURNER) && (d_rand () < OBJECTS [gameData.multiplayer.nLocalPlayer].DriveDamage ())) { if (Controls [0].afterburnerState) { //CPlayerData has key down fix afterburner_scale; int oldCount,newCount; //add in value from 0..1 afterburner_scale = I2X (1) + min (I2X (1) / 2, gameData.physics.xAfterburnerCharge) * 2; forwardThrustTime = FixMul (gameData.time.xFrame, afterburner_scale); //based on full thrust oldCount = (gameData.physics.xAfterburnerCharge / (DROP_DELTA_TIME / AFTERBURNER_USE_SECS)); if (!gameStates.gameplay.bAfterburnerCheat) gameData.physics.xAfterburnerCharge -= gameData.time.xFrame / AFTERBURNER_USE_SECS; if (gameData.physics.xAfterburnerCharge < 0) gameData.physics.xAfterburnerCharge = 0; newCount = (gameData.physics.xAfterburnerCharge / (DROP_DELTA_TIME / AFTERBURNER_USE_SECS)); if (gameStates.app.bNostalgia && (oldCount != newCount)) gameStates.render.bDropAfterburnerBlob = 1; //drop blob (after physics called) } else { fix xChargeUp = min (gameData.time.xFrame / 8, I2X (1) - gameData.physics.xAfterburnerCharge); //recharge over 8 seconds if (xChargeUp > 0) { fix xCurEnergy = LOCALPLAYER.energy - I2X (10); xCurEnergy = max (xCurEnergy, 0) / 10; //don't drop below 10 if (xCurEnergy > 0) { //maybe limit charge up by energy xChargeUp = min (xChargeUp, xCurEnergy / 10); if (xChargeUp > 0) { gameData.physics.xAfterburnerCharge += xChargeUp; LOCALPLAYER.energy -= xChargeUp * 100 / 10; //full charge uses 10% of energy } } } } } // Set CObject's thrust vector for forward/backward objP->mType.physInfo.thrust = objP->info.position.mOrient.FVec () * forwardThrustTime; // slide left/right objP->mType.physInfo.thrust += objP->info.position.mOrient.RVec () * Controls [0].sidewaysThrustTime; // slide up/down objP->mType.physInfo.thrust += objP->info.position.mOrient.UVec () * Controls [0].verticalThrustTime; objP->mType.physInfo.thrust *= 2 * objP->DriveDamage (); if (!gameStates.input.bSkipControls) memcpy (&gameData.physics.playerThrust, &objP->mType.physInfo.thrust, sizeof (gameData.physics.playerThrust)); bMulti = IsMultiGame; if ((objP->mType.physInfo.flags & PF_WIGGLE) && !gameData.objs.speedBoost [objP->Index ()].bBoosted) { #if 1//!DBG WiggleObject (objP); #endif } // As of now, objP->mType.physInfo.thrust & objP->mType.physInfo.rotThrust are // in units of time... In other words, if thrust==gameData.time.xFrame, that // means that the user was holding down the MaxThrust key for the // whole frame. So we just scale them up by the max, and divide by // gameData.time.xFrame to make them independant of framerate // Prevent divide overflows on high frame rates. // In a signed divide, you get an overflow if num >= div<<15 fix ft = gameData.time.xFrame; // Note, you must check for ft < I2X (1)/2, else you can get an overflow on the << 15. if ((ft < I2X (1)/2) && ((ft << 15) <= gameData.pig.ship.player->maxThrust)) ft = (gameData.pig.ship.player->maxThrust >> 15) + 1; objP->mType.physInfo.thrust *= FixDiv (gameData.pig.ship.player->maxThrust, ft); if ((ft < I2X (1)/2) && ((ft << 15) <= gameData.pig.ship.player->maxRotThrust)) ft = (gameData.pig.ship.player->maxThrust >> 15) + 1; objP->mType.physInfo.rotThrust *= FixDiv (gameData.pig.ship.player->maxRotThrust, ft); }
// -------------------------------------------------------------------------------------------------------------------- // Computes point at which projectile fired by robot can hit CPlayerData given positions, CPlayerData vel, elapsed time inline fix ComputeLeadComponent (fix player_pos, fix robot_pos, fix player_vel, fix elapsedTime) { return FixDiv (player_pos - robot_pos, elapsedTime) + player_vel; }
int GetCloakInfo (CObject *objP, fix xCloakStartTime, fix xCloakEndTime, tCloakInfo *ciP) { tCloakInfo ci = {0, CLOAKED_FADE_LEVEL, I2X (1), I2X (1), I2X (1), 0, 0}; int i; if (!(xCloakStartTime || xCloakEndTime)) { if (objP->info.nType == OBJ_PLAYER) { xCloakStartTime = gameData.multiplayer.players [objP->info.nId].cloakTime; xCloakEndTime = gameData.multiplayer.players [objP->info.nId].cloakTime + CLOAK_TIME_MAX; } else if (objP->info.nType == OBJ_ROBOT) { if (!ROBOTINFO (objP->info.nId).bossFlag) { xCloakStartTime = gameData.time.xGame - I2X (10); xCloakEndTime = gameData.time.xGame + I2X (10); } else if (0 <= (i = gameData.bosses.Find (objP->Index ()))) { xCloakStartTime = gameData.bosses [i].m_nCloakStartTime; xCloakEndTime = gameData.bosses [i].m_nCloakEndTime; } } } if (xCloakStartTime != 0x7fffffff) ci.xTotalTime = xCloakEndTime - xCloakStartTime; else ci.xTotalTime = gameData.time.xGame; if (objP->info.nType == OBJ_PLAYER) { ci.xFadeinDuration = CLOAK_FADEIN_DURATION_PLAYER; ci.xFadeoutDuration = CLOAK_FADEOUT_DURATION_PLAYER; } else if (objP->info.nType == OBJ_ROBOT) { ci.xFadeinDuration = CLOAK_FADEIN_DURATION_ROBOT; ci.xFadeoutDuration = CLOAK_FADEOUT_DURATION_ROBOT; } else return 0; ci.xDeltaTime = gameData.time.xGame - ((xCloakStartTime == 0x7fffffff) ? 0 : xCloakStartTime); #if 0 if (ci.xDeltaTime < ci.xFadeinDuration) { // make object transparent during second half ci.nFadeValue = X2I (FixDiv (ci.xFadeinDuration - ci.xDeltaTime, ci.xFadeinDuration) * CLOAKED_FADE_LEVEL); ci.bFading = 1; } #else // only decrease light during first half of cloak initiation time if (ci.xDeltaTime < ci.xFadeinDuration / 2) { ci.xLightScale = FixDiv (ci.xFadeinDuration / 2 - ci.xDeltaTime, ci.xFadeinDuration / 2); ci.bFading = -1; } else if (ci.xDeltaTime < ci.xFadeinDuration) { // make object transparent during second half ci.nFadeValue = X2I (FixDiv (ci.xDeltaTime - ci.xFadeinDuration / 2, ci.xFadeinDuration / 2) * CLOAKED_FADE_LEVEL); ci.bFading = 1; } #endif else if ((xCloakStartTime == 0x7fffffff) || (gameData.time.xGame < xCloakEndTime - ci.xFadeoutDuration)) { static int nCloakDelta = 0, nCloakDir = 1; static fix xCloakTimer = 0; //note, if more than one cloaked CObject is visible at once, the //pulse rate will change! xCloakTimer -= gameData.time.xFrame; while (xCloakTimer < 0) { xCloakTimer += ci.xFadeoutDuration / 12; nCloakDelta += nCloakDir; if (nCloakDelta == 0 || nCloakDelta == 4) nCloakDir = -nCloakDir; } ci.nFadeValue = CLOAKED_FADE_LEVEL - nCloakDelta; } else if (gameData.time.xGame < xCloakEndTime - ci.xFadeoutDuration / 2) { ci.nFadeValue = X2I (FixDiv (ci.xTotalTime - ci.xFadeoutDuration / 2 - ci.xDeltaTime, ci.xFadeoutDuration / 2) * CLOAKED_FADE_LEVEL); ci.bFading = -1; } else { ci.xLightScale = (fix) ((float) (ci.xFadeoutDuration / 2 - (ci.xTotalTime - ci.xDeltaTime) / (float) (ci.xFadeoutDuration / 2))); ci.bFading = 1; } if (ciP) *ciP = ci; return ci.bFading; }