bool IsExtrinsicsPossible(const matf & P2, const TrackedPoint & point) { matf P1(3,4,0.0f); //TODO do not recreate each call P1(0,0) = P1(1,1) = P1(2,2) = 1.0f; matf p3d = Triangulate(P1, P2, point); //return p3d(2,0) >= 0; return IsInFront(P1, p3d) && IsInFront(P2, p3d); //TODO IsInFront(P1 ...) is trivial, since P1 is identity }
void CCarrier::ReAttackGrenade () { CoopCheck (); if (IsInFront(Entity, *Entity->Enemy) && (FrameCalc + 13) > Level.Frame) // four grenades { CurrentMove = &CarrierMoveAttackGrenade; return; } CurrentMove = &CarrierMoveAttackPostGrenade; }
void CCarrier::ReAttackMachinegun () { CoopCheck(); if (IsInFront(Entity, *Entity->Enemy)) { if (frand() <= 0.5) { if ((frand() < 0.7) || (MonsterSlots <= 2)) CurrentMove = &CarrierMoveAttackMG; else CurrentMove = &CarrierMoveSpawn; } else CurrentMove = &CarrierMoveAttackPostMG; } else CurrentMove = &CarrierMoveAttackPostMG; }
bool CCarrier::CheckAttack () { if ((Entity->Enemy->EntityFlags & EF_HURTABLE) && entity_cast<IHurtableEntity>(*Entity->Enemy)->Health > 0) { // see if any entities are in the way of the shot vec3f spot1 = Entity->State.GetOrigin() + vec3f(0, 0, Entity->ViewHeight), spot2 = Entity->Enemy->State.GetOrigin() + vec3f(0, 0, Entity->Enemy->ViewHeight); CTrace tr (spot1, spot2, Entity, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_SLIME|CONTENTS_LAVA); // do we have a clear shot? if (tr.Entity != Entity->Enemy) { // go ahead and spawn stuff if we're mad a a client if ((Entity->Enemy->EntityFlags & EF_PLAYER) && MonsterSlots > 2) { AttackState = AS_BLIND; return true; } // PGM - we want them to go ahead and shoot at info_notnulls if they can. if (Entity->Enemy->GetSolid() != SOLID_NOT || tr.Fraction < 1.0) //PGM return false; } } EnemyInfront = IsInFront(Entity, *Entity->Enemy); bool EnemyInback = IsInBack(Entity, *Entity->Enemy); bool EnemyBelow = IsBelow (Entity, *Entity->Enemy); EnemyRange = Range (Entity, *Entity->Enemy); IdealYaw = (Entity->Enemy->State.GetOrigin() - Entity->State.GetOrigin()).ToYaw(); // PMM - shoot out the back if appropriate if ((EnemyInback) || (!EnemyInfront && EnemyBelow)) { // this is using wait because the attack is supposed to be independent if (Level.Frame >= RefireWait) { RefireWait = Level.Frame + CARRIER_ROCKET_TIME; Attack (); if (frand() < 0.6) AttackState = AS_SLIDING; else AttackState = AS_STRAIGHT; return true; } } // melee attack if (EnemyRange == RANGE_MELEE) { AttackState = AS_MISSILE; return true; } float chance = 0.0f; if (AIFlags & AI_STAND_GROUND) chance = 0.4f; else { switch (EnemyRange) { case RANGE_MELEE: case RANGE_NEAR: case RANGE_MID: chance = 0.8f; break; case RANGE_FAR: chance = 0.5f; break; }; } // PGM - go ahead and shoot every time if it's a info_notnull if ((Entity->Enemy->GetSolid() == SOLID_NOT) || (frand () < chance)) { AttackState = AS_MISSILE; return true; } if (AIFlags & AI_FLY) { if (frand() < 0.6) AttackState = AS_SLIDING; else AttackState = AS_STRAIGHT; } return false; }
void CCarrier::Attack () { AIFlags &= ~AI_HOLD_FRAME; if (!Entity->Enemy) return; bool EnemyInback = IsInBack(Entity, *Entity->Enemy); EnemyInfront = IsInFront (Entity, *Entity->Enemy); bool EnemyBelow = IsBelow (Entity, *Entity->Enemy); if (BadArea) { if ((EnemyInback) || (EnemyBelow)) CurrentMove = &CarrierMoveAttackRocket; else if ((frand() < 0.1) || (Level.Frame < AttackFinished)) CurrentMove = &CarrierMovePreAttackMG; else { Entity->PlaySound (CHAN_WEAPON, Sounds[SOUND_RAIL]); CurrentMove = &CarrierMoveAttackRail; } return; } if (AttackState == AS_BLIND) { CurrentMove = &CarrierMoveSpawn; return; } if (!EnemyInback && !EnemyInfront && !EnemyBelow) // to side and not under { if ((frand() < 0.1) || (Level.Frame < AttackFinished)) CurrentMove = &CarrierMovePreAttackMG; else { Entity->PlaySound (CHAN_WEAPON, Sounds[SOUND_RAIL]); CurrentMove = &CarrierMoveAttackRail; } return; } if (EnemyInfront) { float range = (Entity->Enemy->State.GetOrigin() - Entity->State.GetOrigin()).Length(); if (range <= 125) { if ((frand() < 0.8) || (Level.Frame < AttackFinished)) CurrentMove = &CarrierMovePreAttackMG; else { Entity->PlaySound (CHAN_WEAPON, Sounds[SOUND_RAIL]); CurrentMove = &CarrierMoveAttackRail; } } else if (range < 600) { float luck = frand(); if (MonsterSlots > 2) { if (luck <= 0.20) CurrentMove = &CarrierMovePreAttackMG; else if (luck <= 0.40) CurrentMove = &CarrierMoveAttackPreGrenade; else if ((luck <= 0.7) && !(Level.Frame < AttackFinished)) { Entity->PlaySound (CHAN_WEAPON, Sounds[SOUND_RAIL]); CurrentMove = &CarrierMoveAttackRail; } else CurrentMove = &CarrierMoveSpawn; } else { if (luck <= 0.30) CurrentMove = &CarrierMovePreAttackMG; else if (luck <= 0.65) CurrentMove = &CarrierMoveAttackPreGrenade; else if (Level.Frame >= AttackFinished) { Entity->PlaySound (CHAN_WEAPON, Sounds[SOUND_RAIL]); CurrentMove = &CarrierMoveAttackRail; } else CurrentMove = &CarrierMovePreAttackMG; } } else // won't use grenades at this range { float luck = frand(); if (MonsterSlots > 2) { if (luck < 0.3) CurrentMove = &CarrierMovePreAttackMG; else if ((luck < 0.65) && !(Level.Frame < AttackFinished)) { Entity->PlaySound (CHAN_WEAPON, Sounds[SOUND_RAIL]); RailFireSpot = Entity->Enemy->State.GetOrigin() + vec3f(0, 0, Entity->Enemy->ViewHeight); CurrentMove = &CarrierMoveAttackRail; } else CurrentMove = &CarrierMoveSpawn; } else { if ((luck < 0.45f) || (Level.Frame < AttackFinished)) CurrentMove = &CarrierMovePreAttackMG; else { Entity->PlaySound (CHAN_WEAPON, Sounds[SOUND_RAIL]); CurrentMove = &CarrierMoveAttackRail; } } } } else if ((EnemyBelow) || (EnemyInback)) CurrentMove = &CarrierMoveAttackRocket; }