void CTurtle::Update(float fElapsedTime) { m_vAnimations[m_nCurrAnimation].Update(fElapsedTime); if(GetExperience() >= (100 * GetLevel())) { CBattleMap::GetInstance()->PlaySFX(CAssets::GetInstance()->aBMcowabungaSnd); SetExperience(0/*GetExperience()-(100* GetLevel())*/); SetLevel(GetLevel() + 1); SetHealthMax((int)((float)GetMaxHealth() * 1.25f)); SetHealth((int)((float)GetMaxHealth())); SetBaseAP(GetBaseAP()+2); SetStrength( (int)( (float)GetStrength() * 1.2f ) ); SetDefense( (int) ( (float)GetDefense() * 1.2f ) ); SetAccuracy( (int) ( (float)GetAccuracy() * 1.2f ) ); SetSpeed( (int) ( (float)GetSpeed() * 1.2f ) ); } if( GetHealth() <= 0) { if(GetAlive() == true) { CBattleMap::GetInstance()->DecrementNumChars(); CBattleMap::GetInstance()->DecrementNumTurtles(); CBattleMap::GetInstance()->SetTurtleDead(); SetAlive(false); if(GetCurrAnimNum() != 9) SetCurrAnim(9); SetPosZ(0.9f); } } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- Vector CBaseTFPlayer::GenerateFireVector( Vector *viewVector ) { // Calculate the weapon spread from the player's accuracy float flAcc = (GetAccuracy() * 0.5) / ACCURACY_DISTANCE; float flAccuracyAngle = RAD2DEG( atan( flAcc ) ); // If the user passed in a viewVector, use it, otherwise use player's v_angle Vector angShootAngles = viewVector ? *viewVector : pl->v_angle; if ( flAccuracyAngle ) { float x, y, z; do { x = random->RandomFloat(-0.5,0.5) + random->RandomFloat(-0.5,0.5); y = random->RandomFloat(-0.5,0.5) + random->RandomFloat(-0.5,0.5); z = x*x+y*y; } while (z > 1); angShootAngles.x = UTIL_AngleMod( angShootAngles.x + (x * flAccuracyAngle) ); angShootAngles.y = UTIL_AngleMod( angShootAngles.y + (y * flAccuracyAngle) ); } Vector forward; AngleVectors( angShootAngles, &forward ); return forward; }
void CprobeIGC::Update(Time now) { if (now >= m_timeExpire) GetMyMission()->GetIgcSite()->KillProbeEvent(this); else { { float dt = m_probeType->GetRipcordDelay(); if (dt >= 0.0f) { Time timeActivate = m_time0 + dt; if ((GetMyLastUpdate() < timeActivate) && (now >= timeActivate)) { GetMyMission()->GetIgcSite()->ActivateTeleportProbe(this); } } } if (m_projectileType) { if (m_nextFire < now) { IclusterIGC* pcluster = GetCluster(); assert (pcluster); //We'll be able to take a shot float lifespan = GetProjectileLifespan(); IsideIGC* pside = GetSide(); const Vector& myPosition = GetPosition(); float speed = m_projectileType->GetSpeed(); if (m_ammo != 0) speed *= GetSide()->GetGlobalAttributeSet().GetAttribute(c_gaSpeedAmmo); float accuracy = GetAccuracy(); float dtimeBurst = GetDtBurst(); float dispersion = m_probeType->GetDispersion(); Time lastUpdate = GetMyLastUpdate(); if (m_nextFire < lastUpdate) m_nextFire = lastUpdate; assert (m_nextFire <= now); TmodelIGC<IprobeIGC>::Update(now); float dtUpdate = m_nextFire - lastUpdate; //If we have a target ... find the closest enemy ship who is a valid target ExpendableAbilityBitMask eabm = m_probeType->GetCapabilities(); float distance2Min = speed * lifespan / 1.2f; distance2Min *= distance2Min; Vector directionMin; ImodelIGC* pmodelTarget = NULL; if (eabm & c_eabmShootOnlyTarget) { if (m_target && (m_target->GetCluster() == pcluster)) { ObjectType type = m_target->GetObjectType(); ValidTarget((type == OT_ship) ? ((IshipIGC*)(ImodelIGC*)m_target)->GetSourceShip() : m_target, pside, myPosition, dtUpdate, accuracy, speed, lifespan, type, &pmodelTarget, &distance2Min, &directionMin); } } else { if (eabm & c_eabmShootShips) { //Threats to stations get highest priority GetTarget((const ModelListIGC*)(pcluster->GetShips()), pside, myPosition, dtUpdate, accuracy, speed, lifespan, OT_ship, &pmodelTarget, &distance2Min, &directionMin); } if (eabm & c_eabmShootMissiles) { GetTarget((const ModelListIGC*)(pcluster->GetMissiles()), pside, myPosition, dtUpdate, accuracy, speed, lifespan, OT_missile, &pmodelTarget, &distance2Min, &directionMin); } if (eabm & c_eabmShootStations) { GetTarget((const ModelListIGC*)(pcluster->GetStations()), pside, myPosition, dtUpdate, accuracy, speed, lifespan, OT_station, &pmodelTarget, &distance2Min, &directionMin); } } if (pmodelTarget) { if (m_launcher && (m_launcher->GetMission() != GetMyMission())) m_launcher = NULL; //It is going to shoot ... make it visible to everyone in the sector if (!m_bSeenByAll) { m_bSeenByAll = true; for (SideLinkIGC* psl = m_pMission->GetSides()->first(); (psl != NULL); psl = psl->next()) { IsideIGC* psideOther = psl->data(); if (!SeenBySide(psideOther)) { //Does this side have any scanners in the sector? ClusterSite* pcs = pcluster->GetClusterSite(); const ScannerListIGC* psl = pcs->GetScanners(psideOther->GetObjectID()); if ((psl->n() != 0) || (m_pMission->GetMissionParams()->bAllowAlliedViz && psideOther->AlliedSides(psideOther,pside))) //ALLY 7/3/09 VISIBILITY 7/11/09 imago SetSideVisibility(psideOther, true); else m_bSeenByAll = false; } } } //We have a target ... fire along directionMin (modulo dispersion) Orientation o = GetOrientation(); o.TurnTo(directionMin); SetOrientation(o); Vector position = myPosition + m_probeType->GetEmissionPt() * o; DataProjectileIGC dataProjectile; dataProjectile.projectileTypeID = m_projectileType->GetObjectID(); short nShots = 0; do { //Permute the "forward" direction slightly by a random amount dataProjectile.forward = directionMin; if (dispersion != 0.0f) { float r = random(0.0f, dispersion); float a = random(0.0f, 2.0f * pi); dataProjectile.forward += (r * cos(a)) * o.GetRight(); dataProjectile.forward += (r * sin(a)) * o.GetUp(); dataProjectile.forward.SetNormalize(); } //We never move, so skip all the velocity calculations dataProjectile.velocity = speed * dataProjectile.forward; dataProjectile.lifespan = lifespan; IprojectileIGC* p = (IprojectileIGC*)(m_pMission->CreateObject(m_nextFire, OT_projectile, &dataProjectile, sizeof(dataProjectile))); assert (p); { p->SetLauncher(m_launcher ? ((ImodelIGC*)m_launcher) : ((ImodelIGC*)this)); p->SetPosition(position); p->SetCluster(pcluster); p->Release(); } nShots++; m_nextFire += dtimeBurst; } while (m_nextFire < now); if (m_ammo > 0) { m_ammo -= nShots; if (m_ammo <= 0) { m_ammo = 0; GetMyMission()->GetIgcSite()->KillProbeEvent(this); } } } else { //No shots this cycle m_nextFire = now; } } } TmodelIGC<IprobeIGC>::Update(now); } }
void CCharacter::RefreshBuff( ) { bool bflag = false; for( UINT i=0;i<32;i++) { if(MagicStatus[i].Buff == 0) continue; clock_t etime = clock() - MagicStatus[i].BuffTime; if( etime >= MagicStatus[i].Duration * CLOCKS_PER_SEC ) { Log(MSG_INFO,"Magic Status %i, vanish after: %i", MagicStatus[i].Status, MagicStatus[i].Duration); switch(MagicStatus[i].Status) { case STATUS_HP_8: case STATUS_HP_18: case STATUS_HP_30: case STATUS_HP_43: case STATUS_HP_58: case STATUS_HP_75: case STATUS_SUMMON_HP: case STATUS_HP_92: case STATUS_HP_111: case STATUS_HP_131: case STATUS_HP_152: case STATUS_HP_174: case STATUS_HP_197: case STATUS_HP_221: case STATUS_HP_246: case STATUS_HP_272: case STATUS_HP_299: case STATUS_HP_326: case STATUS_HP_354: case STATUS_HP_383: case STATUS_HP_413: case STATUS_HP_443: case STATUS_HP_475: case STATUS_HP_539: case STATUS_HP_572: case STATUS_HP_5_PC: case 115: { Status->HPHeal = 0xff; } break; case STATUS_MP_6: case STATUS_MP_10: case STATUS_MP_14: case STATUS_MP_18: case STATUS_MP_21: case STATUS_MP_25: case STATUS_MP_29: case STATUS_MP_33: case STATUS_MP_36: case STATUS_MP_40: case STATUS_MP_44: case STATUS_MP_48: case STATUS_MP_51: case STATUS_MP_55: case STATUS_MP_59: case STATUS_MP_63: case STATUS_MP_66: case STATUS_MP_70: case STATUS_MP_74: case STATUS_MP_78: case STATUS_MP_81: case STATUS_MP_85: case STATUS_MP_89: case STATUS_MP_93: case STATUS_MP_96: case 116: { Status->MPHeal = 0xff; } break; case 18: // attack power up case 19: // attack power down case 48: // attack power up { if(i == BUFF_ATTACK_UP_POS) { Status->Attack_up = 0xff; } else { Status->Attack_down = 0xff; } Stats->Attack_Power = GetAttackPower( ); } break; case 20: // def up case 21: // def down case 49: // def up { if(i==BUFF_DEFENSE_UP_POS) { Status->Defense_up= 0xff; } else { Status->Defense_down = 0xff; } Stats->Defense = GetDefense( ); } break; case 24: //Accuracy up case 25: //Accuracy down case 51: //attack Accuracy up. { if(i==BUFF_HITRATE_UP_POS) { Status->Accuracy_up= 0xff; } else { Status->Accuracy_down = 0xff; } Stats->Accuracy = GetAccuracy( ); } break; case 22: // macic resistance up case 23: // magic resistance down case 50: // magic resistance up { if(i==BUFF_MDEFENSE_UP_POS) { Status->Magic_Defense_up = 0xff; } else { Status->Magic_Defense_down = 0xff; } Stats->Magic_Defense = GetMagicDefense( ); } break; case 28: //dodge up case 29: //dodge down case 53: //dodge rate up { if(i==BUFF_DODGE_UP_POS) { Status->Dodge_up = 0xff; } else { Status->Dodge_down = 0xff; } Stats->Dodge = GetDodge( ); } break; case 14: //dash case 15: //slow case 46: //movement speed increased { if(i==BUFF_DASH_UP_POS) { Status->Dash_up = 0xff; } else { Status->Dash_down = 0xff; } Stats->Move_Speed = GetMoveSpeed( ); } break; case 16: // haste attack case 17: // slow attack case 47: // attack speed up { if(i==BUFF_HASTE_UP_POS) { Status->Haste_up = 0xff; } else { Status->Haste_down = 0xff; } //Stats->Attack_Speed_Percent = GetAttackSpeedPercent( ); } break; case 26: // crit up case 27: // crit down case 52: // crit up { if(i==BUFF_CRITICAL_UP_POS) { Status->Critical_up = 0xff; } else { Status->Critical_down = 0xff; } Stats->Critical = GetCritical( ); } break; case 12: // max HP up case 44: // max HP up { if(i==BUFF_MAX_HP_POS) { Status->HP_up = 0xff; } else { Status->HP_down = 0xff; } Stats->MaxHP = GetMaxHP( ); if(Stats->HP > Stats->MaxHP) { Stats->HP = Stats->MaxHP; } } break; case 13: // max MP up case 45: // max MP up { if(i==BUFF_MAX_MP_POS) { Status->MP_up = 0xff; } else { Status->MP_down = 0xff; } Stats->MaxMP = GetMaxMP( ); if(Stats->MP > Stats->MaxMP) { Stats->MP = Stats->MaxMP; } } break; case 32: // faint { Status->Faint = 0xff; Status->CanMove = true; Status->CanCastSkill = true; Status->CanAttack = true; //printf("removing stun\n"); } break; case 7: case 8: case 9: case 10: case 11: case 89: //poisoned { Status->Poisoned = 0xff; //printf("removing poison\n"); } break; case 30: // muted { Status->Muted = 0xff; Status->CanCastSkill = true; } break; case 31: // sleep May need to be fixed later to accomodate multiple status effects. { Status->Sleep = 0xff; Status->CanMove = true; Status->CanCastSkill = true; Status->CanAttack = true; } break; case 36: //A_Extra_Damage: case 54: //A_GMExtra_Damage: case 83: //Valkyrie Charm: { if(i==BUFF_DUMMY_DAMAGE_POS) { Status->ExtraDamage_up = 0xff; Stats->ExtraDamage_add = 0;//We put extardamage add value to 0 if we lost the adddmg buff } else { Status->ExtraDamage_down = 0xff; Stats->ExtraDamage_add = 0;//We put extardamage add value to 0 if we lost the adddmg buff } } break; case 56: //Taunt { Status->Taunt = 0xff; //printf("removing Taunt\n"); } break; case 58: case 61: case 74: case 77: case 78: case 79: case 80: //flame { Status->Flamed = 0xff; } break; case 33://Stealth,Camoflauge { if(IsAttacking( )) { MagicStatus[i].Duration = 0; } Status->Stealth = 0xff; //printf("removing Stealth\n"); } break; case 86://Stealth,Weary { Status->Weary = 0xff; Status->CanCastSkill = true; //printf("removing Weary\n"); } break; case 34://Cloaking { Status->Cloaking = 0xff; //printf("removing Cloaking\n"); } break; case 35: //ShieldDamage: { if(i==BUFF_SHIELD_DAMAGE_POS) { Status->ShieldDamage_up = 0xff; //Stats->ShieldDamage = 0xff; } else { Status->ShieldDamage_down = 0xff; //Stats->ShieldDamage = 0xff; } } break; case 55://Detect { Status->Detect = 0xff; Status->Cloaking = 0xff; Status->Stealth = 0xff; //printf("Detect Done\n"); } break; case 38://Purify { //Buff_Down Status->Attack_down = 0xff; Status->Defense_down = 0xff; Status->Accuracy_down = 0xff; Status->Magic_Defense_down = 0xff; Status->Dodge_down = 0xff; Status->Dash_down = 0xff; Status->Haste_down = 0xff; Status->Critical_down = 0xff; Status->HP_down = 0xff; Status->MP_down = 0xff; Status->ExtraDamage_down = 0xff; Status->ShieldDamage_down = 0xff; Status->ALL_down = 0xff; //Bad Status //Status->Stun = 0xff; Status->Poisoned = 0xff; Status->Muted = 0xff; Status->Sleep = 0xff; Status->Flamed = 0xff; Status->Faint = 0xff; //Stats Stats->Attack_Power = GetAttackPower( ); Stats->Defense = GetDefense( ); Stats->Accuracy = GetAccuracy( ); Stats->Magic_Defense = GetMagicDefense( ); Stats->Dodge = GetDodge( ); Stats->Move_Speed = GetMoveSpeed( ); Stats->Attack_Speed = GetAttackSpeed( ); //Stats->Attack_Speed_Percent = GetAttackSpeedPercent(); Stats->Critical = GetCritical( ); Stats->MaxHP = GetMaxHP( ); Stats->MaxMP = GetMaxMP( ); //printf("Purify Done\n"); } break; case 39:// Dispell { //Buff_Down Status->Attack_down = 0xff; Status->Defense_down = 0xff; Status->Accuracy_down = 0xff; Status->Magic_Defense_down = 0xff; Status->Dodge_down = 0xff; Status->Dash_down = 0xff; Status->Haste_down = 0xff; Status->Critical_down = 0xff; Status->HP_down = 0xff; Status->MP_down = 0xff; Status->ExtraDamage_down = 0xff; Status->ShieldDamage_down = 0xff; Status->ALL_down = 0xff; //Buff_Up Status->Attack_up = 0xff; Status->Defense_up = 0xff; Status->Accuracy_up = 0xff; Status->Magic_Defense_up = 0xff; Status->Dodge_up = 0xff; Status->Dash_up = 0xff; Status->Haste_up = 0xff; Status->Critical_up = 0xff; Status->HP_up = 0xff; Status->MP_up = 0xff; Status->ExtraDamage_up = 0xff; Status->ShieldDamage_up = 0xff; Status->ALL_up = 0xff; //Bad Status //Status->Stun = 0xff; Status->Poisoned = 0xff; Status->Muted = 0xff; Status->Sleep = 0xff; Status->Flamed = 0xff; Status->Faint = 0xff; //Stats Stats->Attack_Power = GetAttackPower( ); Stats->Defense = GetDefense( ); Stats->Accuracy = GetAccuracy( ); Stats->Magic_Defense = GetMagicDefense( ); Stats->Dodge = GetDodge( ); Stats->Move_Speed = GetMoveSpeed( ); Stats->Attack_Speed = GetAttackSpeed( ); Stats->Critical = GetCritical( ); Stats->MaxHP = GetMaxHP( ); Stats->MaxMP = GetMaxMP( ); //printf("Dispell Done\n"); } break; default: { Log(MSG_WARNING,"Unknow skill status in charfunctions %u.",MagicStatus[i].Status); } } BEGINPACKET( pak,0x7b7 ); ADDWORD ( pak, clientid ); ADDDWORD ( pak, GServer->BuildBuffs( this ) ); GServer->SendToVisible( &pak, this ); MagicStatus[i].Status = 0; MagicStatus[i].Buff = 0; MagicStatus[i].BuffTime = 0; MagicStatus[i].Duration = 0; MagicStatus[i].Value = 0; bflag = true; } else if ( ((MagicStatus[i].Status >= 7 && MagicStatus[i].Status <= 11) || MagicStatus[i].Status == 89) && etime > 1*CLOCKS_PER_SEC) //Do poison dmg every 1.5 seconds { Stats->HP -= MagicStatus[i].Status; //Actually take 7, 8, 9, 10 or 11 from the health. Based on the Status itself, LMA: can be 89 noc too. MagicStatus[i].BuffTime += 1*CLOCKS_PER_SEC; MagicStatus[i].Duration -= 1; //printf("did %i poison dmg to the player, still %i seconds and %i HP remain \n", MagicStatus[i].Status, MagicStatus[i].Duration, Stats->HP); //Log(MSG_WARNING,"did %i poison dmg to the player / monster, still %i seconds and %I64i HP remain", MagicStatus[i].Status, MagicStatus[i].Duration, Stats->HP); //LMA: If dead, let's the client resynch if(IsDead()) { BEGINPACKET( pak, 0x79f ); ADDWORD ( pak, clientid ); ADDDWORD ( pak, 1); GServer->SendToVisible( &pak, this ); Log(MSG_INFO,"death poison for %i, amount: %i",clientid,MagicStatus[i].Status); } //A bunch of messy code to send dmg packet BEGINPACKET( pak, 0x7b6 ); ADDWORD ( pak, clientid ); ADDWORD ( pak, 0 ); ADDDWORD ( pak, 0x000007f8 ); ADDBYTE ( pak, 0x00 ); ADDDWORD ( pak, MagicStatus[i].Status ); //If Enemy is killed if( IsDead()) { //printf("char died\n"); CDrop* thisdrop = NULL; ADDDWORD ( pak, 16 ); if( !IsSummon( ) && !IsPlayer( )) { //LMA: No drop if already dead and drop done. if(drop_dead) { Log(MSG_WARNING,"Trying to make a monster (CID %u, type %u) drop again but already did.",clientid,char_montype); } else { thisdrop = GetDrop( ); if( thisdrop!=NULL) { CMap* map = GServer->MapList.Index[thisdrop->posMap]; map->AddDrop( thisdrop ); } } } //GServer->SendToVisible( &pak, this, thisdrop ); GServer->SendToVisible( &pak, this); } else { //If enemy is still alive ADDDWORD ( pak, 4 ); GServer->SendToVisible( &pak, this ); } } else if ( MagicStatus[i].Status == 58 || MagicStatus[i].Status == 61 || MagicStatus[i].Status == 71 || MagicStatus[i].Status >= 77 && MagicStatus[i].Status <= 80 || MagicStatus[i].Status == 88 && etime > 1*CLOCKS_PER_SEC) //Do flame dmg every 1.5 seconds { Stats->HP -= MagicStatus[i].Status; MagicStatus[i].BuffTime += 1*CLOCKS_PER_SEC; MagicStatus[i].Duration -= 1; printf("did %i flame dmg to the player, still %i seconds and %i HP remain \n", MagicStatus[i].Status, MagicStatus[i].Duration, Stats->HP); //LMA: If dead, let's the client resynch if(IsDead()) { BEGINPACKET( pak, 0x79f ); ADDWORD ( pak, clientid ); ADDDWORD ( pak, 1); GServer->SendToVisible( &pak, this ); Log(MSG_INFO,"death flame for %i, amount: %i",clientid,MagicStatus[i].Status); } //A bunch of messy code to send dmg packet BEGINPACKET( pak, 0x7b6 ); ADDWORD ( pak, clientid ); ADDWORD ( pak, 0 ); ADDDWORD ( pak, 0x000007f8 ); ADDBYTE ( pak, 0x00 ); ADDDWORD ( pak, MagicStatus[i].Status ); //If Enemy is killed if( IsDead()) { //printf("char died\n"); CDrop* thisdrop = NULL; ADDDWORD ( pak, 16 ); if( !IsSummon( ) && !IsPlayer( )) { //LMA: No drop if already dead and drop done. if(drop_dead) { Log(MSG_WARNING,"Trying to make a monster (CID %u, type %u) drop again but already did.",clientid,char_montype); } else { thisdrop = GetDrop( ); if( thisdrop!=NULL) { CMap* map = GServer->MapList.Index[thisdrop->posMap]; map->AddDrop( thisdrop ); } } } //GServer->SendToVisible( &pak, this, thisdrop ); GServer->SendToVisible( &pak, this); } else { //If enemy is still alive ADDDWORD ( pak, 4 ); GServer->SendToVisible( &pak, this ); } } } for( UINT i=0;i<32;i++) { if(MagicStatus2[i].Buff == 0) continue; clock_t etime = clock() - MagicStatus2[i].BuffTime; if( etime >= MagicStatus2[i].Duration * CLOCKS_PER_SEC ) { CPlayer* thisplayer = GServer->GetClientByID(clientid); Log(MSG_INFO,"Magic Status %i, vanish after: %i", MagicStatus2[i].Status, MagicStatus2[i].Duration); switch(MagicStatus2[i].Status) { case 126: // ALLbuff up { if(i == BUFF_ATTACK_UP_POS) { Status->Attack_up = 0xff; thisplayer->Attr->ALLbuff = 0; } else { Status->Attack_down = 0xff; thisplayer->Attr->ALLbuff = 0; } } default: { Log(MSG_WARNING,"Unknow skill status in charfunctions %u.",MagicStatus[i].Status); } } BEGINPACKET( pak,0x7b7 ); ADDWORD ( pak, clientid ); ADDDWORD ( pak, GServer->BuildBuffs( this ) ); GServer->SendToVisible( &pak, this ); MagicStatus2[i].Status = 0; MagicStatus2[i].Buff = 0; MagicStatus2[i].BuffTime = 0; MagicStatus2[i].Duration = 0; MagicStatus2[i].Value = 0; } } // if(bflag) // { // BEGINPACKET( pak,0x7b7 ); // ADDWORD ( pak, clientid ); // ADDDWORD ( pak, GServer->BuildBuffs( this ) ); // GServer->SendToVisible( &pak, this ); // } }
// Attacks a target object. void CHSLaser::AttackObject(CHSObject *cSource, CHSObject *cTarget, CHSConsole *cConsole, int iSysType) { dbref dbUser; int iAttackRoll; int iDefendRoll; int i; CHSObject *cCTarget; double sX, sY, sZ; // Source object coords double tX, tY, tZ; // Target object coords; // Grab the user of the console. dbUser = hsInterface.ConsoleUser(cConsole->m_objnum); // Can we attack that object? if (cSource->GetType() == HST_SHIP) { CHSSysCloak *cCloak; CHSShip *ptr; float rval; ptr = (CHSShip *)cSource; // Look for the cloaking device. cCloak = (CHSSysCloak *)ptr->GetEngSystem(HSS_CLOAK); if (cCloak) if (cCloak->GetEngaged()) { if (dbUser != NOTHING) hsStdError(dbUser, "You cannot fire while cloaked."); return; } } if (!CanAttackObject(cTarget)) { if (dbUser != NOTHING) hsStdError(dbUser, "You cannot attack that target with that weapon."); } // Calculate distance to object sX = cSource->GetX(); sY = cSource->GetY(); sZ = cSource->GetZ(); tX = cTarget->GetX(); tY = cTarget->GetY(); tZ = cTarget->GetZ(); double dDistance; dDistance = Dist3D(sX, sY, sZ, tX, tY, tZ) + .00001; // Size of a target ship matters relative to distance. // The closer a target gets to the ship, the larger // it effectively is. That is to say it takes up more // of the view angle. When the target is right next // to the ship, in front of the gun, it is essentially // the broad side of a barn, which everyone can hit. // Thus, to handle this we'll calculate the size of // the target and the viewing angle it takes up. double dSize; // Size of the side of the target double dAngle; // Amount of viewing angle taken up by size dSize = cTarget->GetSize(); dSize = (.7 * dSize) * (.7 * dSize); // Halve the size, and divide by distance. This // gives us the tangent of the angle taken up by // the target. dSize = (dSize * .5) / dDistance; // Take the inverse tangent to get angle. dAngle = atan(dSize); // Double the angle because we used half of the size // to get the angle of a right triangle. dAngle *= 2; // We now have the viewing angle consumed by the // target. There's a maximum possible value of 180, // so divide by that to determine how much of the viewing // angle is taken up by the target. dSize = dAngle * .005555; // Subtract from 1 to get maximum values of 1 when the // angle is small. dSize = 1 - dSize; // Now multiply by 6 to get relative difficulty of hitting // target. iDefendRoll = (int) (6 * dSize) + getrandom(6); iAttackRoll = GetAccuracy() + getrandom(6); // Simulate difficulty when a target is moving. // If the target is moving toward or away from the // attacker, it's not very difficult. Thus, we // calculate the change in angle for the target // during one cycle. The maximum change is 180 // degrees. CHSVector tVec; CHSVector aVec; tVec = cTarget->GetMotionVector(); aVec = cSource->GetMotionVector(); // Calculate vector to target now. double dx, dy, dz; dx = tX - sX; dy = tY - sY; dz = tZ - sZ; // Make a unit vector dx /= dDistance; dy /= dDistance; dz /= dDistance; CHSVector nowVec(dx, dy, dz); // Now calculate coordinate for source and target // in one cycle. double sX2, sY2, sZ2; double tX2, tY2, tZ2; double aSpeed, tSpeed; // Grab both object speeds, and bring them down // to per-second levels. aSpeed = cSource->GetSpeed() * .0002778; tSpeed = cTarget->GetSpeed() * .0002778; // Calculate coordinates for next cycle. sX2 = sX + (aVec.i() * aSpeed); sY2 = sY + (aVec.j() * aSpeed); sZ2 = sZ + (aVec.k() * aSpeed); tX2 = tX + (tVec.i() * tSpeed); tY2 = tY + (tVec.j() * tSpeed); tZ2 = tZ + (tVec.k() * tSpeed); // Calculate vector to target after next cycle dx = tX2 - sX2; dy = tY2 - sY2; dz = tZ2 - sZ2; // Divide by distance to make a unit vector double dDistance2; dDistance2 = Dist3D(sX2, sY2, sZ2, tX2, tY2, tZ2); dx /= dDistance2; dy /= dDistance2; dz /= dDistance2; CHSVector nextVec(dx, dy, dz); // Calculate the dot product between the previous // and the next cycle vectors. double dp; dp = nowVec.DotProduct(nextVec); // Calculate the angle change. This is in radians. dAngle = acos(dp); // Now divide angle change by 2pi to get change in angle // from 0 to 1, where 1 is a huge change in angle and, // therefore, high difficulty. dAngle *= .15915; // Add up to 6 points of defense for "evasion" by angle // change. iDefendRoll += (int) (6 * dAngle); // If distance is farther than our range, the shot always // misses. double range; range = GetRange(); CHSUniverse *uDest; char tbuf[256]; char fstat1[128]; char fstat2[128]; if (dDistance >= range || iDefendRoll > iAttackRoll) { sprintf(fstat1, "%s%smisses%s",ANSI_HILITE,ANSI_GREEN,ANSI_NORMAL); sprintf(fstat2, "%s%smissed%s",ANSI_HILITE,ANSI_GREEN,ANSI_NORMAL); } else { sprintf(fstat1, "%s%shits%s",ANSI_HILITE,ANSI_RED,ANSI_NORMAL); sprintf(fstat2, "%s%shit%s",ANSI_HILITE,ANSI_RED,ANSI_NORMAL); } uDest = uaUniverses.FindUniverse(cSource->GetUID()); CHSSysSensors *cSensors; SENSOR_CONTACT *cContactS; SENSOR_CONTACT *cContactD; for (i = 0; i < HS_MAX_ACTIVE_OBJECTS; i++) { cCTarget = uDest->GetActiveUnivObject(i); if (!cCTarget) continue; if (cCTarget == cSource || cCTarget == cTarget) continue; cSensors = (CHSSysSensors *)cCTarget->GetEngSystem(HSS_SENSORS); if (!cSensors) continue; cContactS = cSensors->GetContact(cSource); cContactD = cSensors->GetContact(cTarget); if (!cContactS && !cContactD) continue; if (!cContactS && cContactD) { if (cContactD->status == DETECTED) { sprintf(tbuf, "%s[%s%s%d%s%s]%s - Unknown contact is being fired upon and %s",cTarget->GetObjectColor(),ANSI_NORMAL,ANSI_HILITE,cContactD->m_id,ANSI_NORMAL,cTarget->GetObjectColor(),ANSI_NORMAL, fstat2); cCTarget->HandleMessage(tbuf, MSG_SENSOR, (long *)cCTarget); } else if (cContactD->status == IDENTIFIED) { sprintf(tbuf, "%s[%s%s%d%s%s]%s - The %s is being fired upon and %s",cTarget->GetObjectColor(),ANSI_NORMAL,ANSI_HILITE,cContactD->m_id,ANSI_NORMAL,cTarget->GetObjectColor(),ANSI_NORMAL, cSource->GetName(), fstat2); cCTarget->HandleMessage(tbuf, MSG_SENSOR, (long *)cCTarget); } continue; } if (cContactS && !cContactD) { if (cContactS->status == DETECTED) { sprintf(tbuf, "%s[%s%s%d%s%s]%s - Unknown contact is firing upon something",cSource->GetObjectColor(),ANSI_NORMAL,ANSI_HILITE,cContactS->m_id,ANSI_NORMAL,cSource->GetObjectColor(),ANSI_NORMAL); cCTarget->HandleMessage(tbuf, MSG_SENSOR, (long *)cCTarget); } else if (cContactS->status == IDENTIFIED) { sprintf(tbuf, "%s[%s%s%d%s%s]%s - The %s is firing upon something",cSource->GetObjectColor(),ANSI_NORMAL,ANSI_HILITE,cContactS->m_id,ANSI_NORMAL,cSource->GetObjectColor(),ANSI_NORMAL, cSource->GetName()); cCTarget->HandleMessage(tbuf, MSG_SENSOR, (long *)cCTarget); } continue; } if (cContactS && cContactD) if (cContactS->status == DETECTED && cContactD->status == DETECTED) { sprintf(tbuf, "%s[%s%s%d%s%s]%s - Unknown contact fires and %s unknown contact %s[%s%s%d%s%s]%s",cSource->GetObjectColor(),ANSI_NORMAL,ANSI_HILITE,cContactS->m_id,ANSI_NORMAL,cSource->GetObjectColor(),ANSI_NORMAL, fstat1,cTarget->GetObjectColor(),ANSI_NORMAL,ANSI_HILITE,cContactD->m_id,ANSI_NORMAL,cTarget->GetObjectColor(),ANSI_NORMAL); cCTarget->HandleMessage(tbuf,MSG_SENSOR, (long *)cCTarget); } else if (cContactS->status == IDENTIFIED && cContactD->status == IDENTIFIED) { sprintf(tbuf, "%s[%s%s%d%s%s]%s - The %s fires and %s the %s",cSource->GetObjectColor(),ANSI_NORMAL,ANSI_HILITE,cContactS->m_id,ANSI_NORMAL,cSource->GetObjectColor(),ANSI_NORMAL, cSource->GetName(), fstat1, cTarget->GetName()); cCTarget->HandleMessage(tbuf, MSG_SENSOR, (long *)cCTarget); } else if (cContactS->status == IDENTIFIED && cContactD->status == DETECTED) { sprintf(tbuf, "%s[%s%s%d%s%s]%s - The %s fires and %s unknown contact %s[%s%s%d%s%s]%s",cSource->GetObjectColor(),ANSI_NORMAL,ANSI_HILITE,cContactS->m_id,ANSI_NORMAL,cSource->GetObjectColor(),ANSI_NORMAL, cSource->GetName(), fstat1,cTarget->GetObjectColor(),ANSI_NORMAL,ANSI_HILITE,cContactD->m_id,ANSI_NORMAL,cTarget->GetObjectColor(),ANSI_NORMAL); cCTarget->HandleMessage(tbuf, MSG_SENSOR, (long *)cCTarget); } else if (cContactS->status == DETECTED && cContactD->status == IDENTIFIED) { sprintf(tbuf, "%s[%s%s%d%s%s]%s - Unknown contact fires and %s the %s",cSource->GetObjectColor(),ANSI_NORMAL,ANSI_HILITE,cContactS->m_id,ANSI_NORMAL,cSource->GetObjectColor(),ANSI_NORMAL, fstat1, cTarget->GetName()); cCTarget->HandleMessage(tbuf, MSG_SENSOR, (long *)cCTarget); } } if (dDistance >= range) { if (dbUser != NOTHING) hsStdError( dbUser, "Your shot dissipates short of its target."); strcpy(tbuf, "An incoming energy shot has missed us."); cTarget->HandleMessage(tbuf, MSG_COMBAT, (long *)cSource); } else if (iAttackRoll > iDefendRoll) { // The weapon hits! // Determine strength based on base weapon // strength and range to target. int strength; strength = GetStrength(); if (dDistance > (range * .333)) { strength = (int)(strength * (.333 + (1 - (dDistance / (range + .0001))))); } // If iSysType is not HSS_NOTYPE, then do a roll // against the accuracy of the weapon to see if // the system gets hit. if (iSysType != HSS_NOTYPE) { UINT ARoll, SRoll; ARoll = getrandom(GetAccuracy()); SRoll = getrandom(10); if (SRoll > ARoll) iSysType = HSS_NOTYPE; // Didn't succeed } // Tell the target to take damage cTarget->HandleDamage(cSource, this, strength, cConsole, iSysType); } else { // The weapon misses. :( if (dbUser != NOTHING) hsStdError(dbUser, "Your shot skims past your target and out into space."); strcpy(tbuf, "An incoming energy shot has missed us."); cTarget->HandleMessage(tbuf, MSG_COMBAT, (long *)cSource); } Regenerate(); }