void TableShape::handleDamages(const QList<Damage*>& damages) { QList<Damage*>::ConstIterator end(damages.end()); for (QList<Damage*>::ConstIterator it = damages.begin(); it != end; ++it) { Damage* damage = *it; if (!damage) continue; if (damage->type() == Damage::Cell) { CellDamage* cellDamage = static_cast<CellDamage*>(damage); const Region region = cellDamage->region(); if (cellDamage->changes() & CellDamage::Appearance) d->sheetView->invalidateRegion(region); continue; } if (damage->type() == Damage::Sheet) { SheetDamage* sheetDamage = static_cast<SheetDamage*>(damage); if (sheetDamage->changes() & SheetDamage::PropertiesChanged) d->sheetView->invalidate(); continue; } } update(); }
void Attributs::looseLiveFromDamage(const Damage &damage) { for(int i=0 ; i<damage.getMaxIndex() ; i++) { live -= damage.getValue(i).getValue(); } }
/* Damage Stack resolve process: 1 - apply damages to targets. For each of them, send an event to the GameObserver (for Damage triggers) 2 - Once this is done, send a "Damage Stakc Resolved" event to the GameObserver 3 - Once that message is received on the DamageStack's side, do the "afterDamage" effects (send to graveyard, etc...) Using events in 2 and 3 guarantees that the "send to graveyard" effect will only apply AFTER Damaged triggers are applied */ int DamageStack::resolve() { for (int i = (int)(mObjects.size()) - 1; i >= 0; i--) { Damage * damage = (Damage*) mObjects[i]; if (damage->state == NOT_RESOLVED) damage->resolve(); } ((Interruptible*)this)->getObserver()->receiveEvent(NEW WEventDamageStackResolved()); return 1; }
void Attack::loadAttackData(GameObjectData* dataObj) { for(GameObjectData* damageData : dataObj->getObjectList("damages")) { Damage dam; dam.load(damageData); _damages.push_back(dam); } if(dataObj->hasFloat("duration")) _duration = dataObj->getFloat("duration"); }
void View::Rotate (Graphic* g, Event& e) { Coord l, b, r, t; float cx, cy; damage->Incur(g); g->GetBox(l, b, r, t); g->GetCenter(cx, cy); RotatingRect rr(output, canvas, l, b, r, t, round(cx), round(cy), e.x,e.y); Track(e, rr); g->Rotate(rr.CurrentAngle(), cx, cy); g->Touch(); damage->Incur(g); Update(); }
void Attributs::applyAttackRelativeBonnus(Damage &damage) const { for(unsigned i=0; i<damage.getValues().size() ; i++) { for(unsigned a=0 ; a<relativeFightBonus.size() ; a++) { if(damage.getValues().at(i).getType() == relativeFightBonus.at(a).getType() ) { int newDamage = damage.getValues().at(i).getValue(); newDamage += (newDamage * relativeFightBonus.at(a).getValue()) / 100; //one value point -> add 1% damage damage.getValues().at(i).setValue(newDamage); } } } }
void DamageStack::Render() { float currenty = y; for (size_t i = 0; i < mObjects.size(); i++) { Damage * damage = (Damage*) mObjects[i]; if (damage->state == NOT_RESOLVED) { damage->x = x; damage->y = currenty; currenty += damage->mHeight; damage->Render(); } } }
void ViewerGraphic::Update () { GraphicComp* parent = (GraphicComp*) _view->GetGraphicComp()->GetParent(); if (parent != nil) { FullGraphic gs; totalGSGraphic(parent->GetGraphic(), gs); if (Different(this, &gs)) { Damage* damage = _view->GetViewer()->GetDamage(); damage->Incur(this); *(Graphic*)this = *(Graphic*)(&gs); damage->Incur(this); } } }
void Attack::Act(IGame& game) const { State attacker = game.Get(actor); auto& targetActor = dynamic_cast<const Identity&>(target); State victim(game.Get(targetActor)); if (!part) { Engage(attacker); game.Adjust(actor, attacker, skill.name); game.Adjust(targetActor, victim, L"Miss " + skill.name); return; } auto skillLevel = attacker.SkillLevel(skill, &victim); if (skillLevel.Value() == 0) { Engage(attacker); game.Adjust(actor, attacker, skill.name); game.Adjust(targetActor, victim, L"Resist " + skill.name + L":" + skillLevel.Description()); return; } auto damage = attacker.AttackDamage(skill, skillLevel); Damage pain = damage - victim.Mitigation(*part); if (!victim.Hurt(*part, pain, actor.Description()+L"'"+skill.description)) { Engage(attacker); game.Adjust(actor, attacker, skill.name); game.Adjust(targetActor, victim, L"Mitigate " + skill.name + L"@" + part->Name() + L":" + pain.ActionDescription()); return; } Engage(attacker); game.Adjust(actor, attacker, skill.name); game.Adjust(targetActor, victim, L"Hit " + skill.name + L"@" + part->Name() + L":" + pain.ActionDescription()); }
int Character::takeDamage(Damage dmg) { //TODO: handle damage resists int roll = dmg.roll(); modifyHitPoints(-1 * roll); return roll; }
void View::Scale (Graphic* g, Event& e) { Coord l, b, r, t; float cx, cy, scale; damage->Incur(g); g->GetBox(l, b, r, t); g->GetCenter(cx, cy); ScalingRect sr(output, canvas, l, b, r, t, round(cx), round(cy)); Track(e, sr); scale = sr.CurrentScaling(); g->Scale(scale, scale, cx, cy); g->Touch(); damage->Incur(g); Update(); }
void View::Move (Graphic* g, Event& e) { Coord l, b, r, t, newl, newb; float dx, dy, mag = GetMagnification(); damage->Incur(g); g->GetBox(l, b, r, t); SlidingRect sr(output, canvas, l, b, r, t, e.x, e.y); Track(e, sr); sr.GetCurrent(newl, newb, r, t); dx = (newl - l) / mag; // get distance moved, corrected to reflect dy = (newb - b) / mag; // current magnification g->Translate(dx, dy); g->Touch(); // so that new position will be written out damage->Incur(g); Update(); }
void Attributs::applyAttackFixBonnus(Damage &damage) const { for(unsigned i=0; i<damage.getValues().size() ; i++) { int newDamage = damage.getValues().at(i).getValue(); newDamage += fixDamageBonnus; for(unsigned a=0 ; a<fixFightBonus.size() ; a++) { if(damage.getValues().at(i).getType() == fixFightBonus.at(a).getType() ) { newDamage += fixFightBonus.at(a).getValue(); //add fix attack bonnus //exit for loop: (there are only one couple) a = values.size(); } } damage.getValues().at(i).setValue(newDamage); } }
void Attributs::applyDefenseRelativeResistances(Damage &damage) const { for(unsigned i=0; i<damage.getValues().size() ; i++) { for(unsigned a=0 ; a<relativeResistances.size() ; a++) { if(damage.getValues().at(i).getType() == relativeResistances.at(a).getType() ) { int newDamage = damage.getValues().at(i).getValue(); newDamage -= (newDamage * relativeResistances.at(a).getValue()) / 100; //one value point -> add 1% resistances if(newDamage<0) { newDamage = 0; } damage.getValues().at(i).setValue(newDamage); } } } }
void Attributs::applyDefenseFixResistances(Damage &damage) const { for(unsigned i=0; i<damage.getValues().size() ; i++) { for(unsigned a=0 ; a<fixResistances.size() ; a++) { if(damage.getValues().at(i).getType() == fixResistances.at(a).getType() ) { int newDamage = damage.getValues().at(i).getValue(); newDamage -= fixResistances.at(a).getValue(); //add fix attack bonnus if(newDamage<0) { newDamage = 0; } damage.getValues().at(i).setValue(newDamage); } } } }
void Attributs::applyAttackValues(Damage &damage) const { for(unsigned i=0; i<damage.getValues().size() ; i++) { int newDamage = damage.getValues().at(i).getValue(); int damageBonnus = powerBonnus; for(unsigned a=0 ; a<values.size() ; a++) { if(damage.getValues().at(i).getType() == values.at(a).getType() ) { damageBonnus += values.at(a).getValue(); //one value point -> add 1% damage //exit for loop: (there are only one couple) a = values.size(); } } newDamage += newDamage*damageBonnus/100; damage.getValues().at(i).setValue(newDamage); } }
bool Creature::doReflectionDamage(Damage damage, Creature* target, ReflectedDamageType printZero) { int dmg = damage.getReflected() ? damage.getReflected() : damage.getPhysicalReflected(); // don't quit if we want to print 0 if(!dmg && printZero == REFLECTED_NONE) return(false); if(damage.getReflected() || printZero == REFLECTED_MAGIC) { target->printColor("Your shield of magic reflects %s%d^x damage.\n", target->customColorize("*CC:DAMAGE*").c_str(), dmg); printColor("%M's shield of magic flares up and hits you for %s%d^x damage.\n", target, customColorize("*CC:DAMAGE*").c_str(), dmg); broadcastGroup(false, this, "%M's shield of magic flares up and hits %N for *CC:DAMAGE*%d^x damage.\n", target, this, dmg); } else { switch(damage.getPhysicalReflectedType()) { case REFLECTED_FIRE_SHIELD: default: target->printColor("Your shield of fire reflects %s%d^x damage.\n", target->customColorize("*CC:DAMAGE*").c_str(), dmg); printColor("%M's shield of fire flares up and hits you for %s%d^x damage.\n", target, customColorize("*CC:DAMAGE*").c_str(), dmg); broadcastGroup(false, this, "%M's shield of fire flares up and hits %N for *CC:DAMAGE*%d^x damage.\n", target, this, dmg); break; } } if(damage.getDoubleReflected()) { Damage reflectedDamage; reflectedDamage.setReflected(damage.getDoubleReflected()); target->doReflectionDamage(reflectedDamage, this); } // we may have gotten this far for printing reasons (even on zero), but really, go no further if(!dmg) return(false); if(target->isPlayer() && isMonster()) getAsMonster()->adjustThreat(target, dmg); hp.decrease(dmg); if(hp.getCur() <= 0) return(true); return(false); }
void SheetAccessModel::handleDamages(const QList<Damage*>& damages) { QList<Damage*>::ConstIterator end(damages.end()); for (QList<Damage*>::ConstIterator it = damages.begin(); it != end; ++it) { Damage* damage = *it; if (!damage) { continue; } if (damage->type() == Damage::Sheet) { SheetDamage* sheetDamage = static_cast<SheetDamage*>(damage); kDebug(36007) << "Processing\t" << *sheetDamage; if (sheetDamage->changes() & SheetDamage::Name) { Sheet *sheet = sheetDamage->sheet(); // We should never receive signals from sheets that are not in our model Q_ASSERT(d->cols.contains(sheet)); const int sheetIndex = d->cols[sheet]; setHeaderData(sheetIndex, Qt::Horizontal, sheet->sheetName()); } continue; } } }
void CanvasItem::handleDamages(const QList<Damage*>& damages) { QRegion paintRegion; enum { Nothing, Everything, Clipped } paintMode = Nothing; QList<Damage*>::ConstIterator end(damages.end()); for (QList<Damage*>::ConstIterator it = damages.begin(); it != end; ++it) { Damage* damage = *it; if (!damage) continue; if (damage->type() == Damage::Cell) { CellDamage* cellDamage = static_cast<CellDamage*>(damage); kDebug(36007) << "Processing\t" << *cellDamage; Sheet* const damagedSheet = cellDamage->sheet(); if (cellDamage->changes() & CellDamage::Appearance) { const Region& region = cellDamage->region(); sheetView(damagedSheet)->invalidateRegion(region); paintMode = Everything; } continue; } if (damage->type() == Damage::Sheet) { SheetDamage* sheetDamage = static_cast<SheetDamage*>(damage); kDebug(36007) << *sheetDamage; const SheetDamage::Changes changes = sheetDamage->changes(); if (changes & (SheetDamage::Name | SheetDamage::Shown)) { // d->tabBar->setTabs(doc()->map()->visibleSheets()); paintMode = Everything; } if (changes & (SheetDamage::Shown | SheetDamage::Hidden)) { // updateShowSheetMenu(); paintMode = Everything; } // The following changes only affect the active sheet. if (sheetDamage->sheet() != d->activeSheet) { continue; } if (changes.testFlag(SheetDamage::ContentChanged)) { update(); paintMode = Everything; } if (changes.testFlag(SheetDamage::PropertiesChanged)) { sheetView(d->activeSheet)->invalidate(); paintMode = Everything; } if (sheetDamage->changes() & SheetDamage::ColumnsChanged) columnHeader()->update(); if (sheetDamage->changes() & SheetDamage::RowsChanged) rowHeader()->update(); continue; } if (damage->type() == Damage::Selection) { SelectionDamage* selectionDamage = static_cast<SelectionDamage*>(damage); kDebug(36007) << "Processing\t" << *selectionDamage; const Region region = selectionDamage->region(); if (paintMode == Clipped) { const QRectF rect = cellCoordinatesToView(region.boundingRect()); paintRegion += rect.toRect().adjusted(-3, -3, 4, 4); } else { paintMode = Everything; } continue; } kDebug(36007) << "Unhandled\t" << *damage; } // At last repaint the dirty cells. if (paintMode == Clipped) { update(paintRegion.boundingRect()); } else if (paintMode == Everything) { update(); } }
/** * @param damage damage description for this weapon detonation * Point defense and air cannons should use a different model */ void tcDamageModel::CalculateTotalDamage(tcWeaponObject* weapon, tcGameObject* target, Damage& damage) { if ((weapon == 0) || (target == 0)) { wxASSERT(false); return; } bool goodDetonation = weapon->IsGoodDetonation(); damage.Clear(); const tcWeaponDamage* weaponDamage = GetWeaponDamageModel(weapon); /* if missile is targeted and has scored direct hit, then apply ** kinetic damage from missile (big fragment) and apply ** internal damage assuming missile has delayed warhead that explodes ** after penetrating target exterior */ if (weapon->IsDirectHit() && (weapon->GetIntendedTarget() == target->mnID)) { float speed_collide = weapon->mcKin.CalculateRangeRate(target->mcKin); if (speed_collide < 0) { wxASSERT(false); speed_collide = 0; // opening range rate case, shouldnt happen } float kinEnergy_J = 0.5*weapon->GetMassKg()*speed_collide*speed_collide; // fractional damage from kinetic energy of impact damage.kinetic_J = kinEnergy_J; damage.isPenetration = weaponDamage->isPenetration; // treat blast and frag as the same for now damage.explosive_kg = weaponDamage->blastCharge_kg + weaponDamage->fragCharge_kg + weaponDamage->fragMetal_kg; return; } // no damage for direct hit weapons to other targets, or if weapon is a dud if (weapon->IsDirectHit() || (!goodDetonation)) return; tcBallisticWeapon* ballistic = dynamic_cast<tcBallisticWeapon*>(weapon); if ((ballistic != 0) && ballistic->IsClusterBomb()) { CalculateTotalDamageCluster(ballistic, target, damage); return; } // determine if this is an underwater or underground explosion bool underwaterExplosion = ((weapon->mcKin.mfAlt_m <= -1.0f) && (weapon->mcTerrain.mfHeight_m < -1.0f)); bool targetUnderwater = (target->mcKin.mfAlt_m <= 0) && (target->mcTerrain.mfHeight_m < -1.0f); bool targetAbovewater = (target->mcKin.mfAlt_m >= -3.0f); // target can be both under and above water bool affectsTarget = (underwaterExplosion && targetUnderwater) || (!underwaterExplosion && targetAbovewater); if (!affectsTarget) return; float range_m = 1000.0f * weapon->mcKin.RangeToKmAlt(target->mcKin); //float cumulativeDamage = 0; if (underwaterExplosion) { float damageRange_m = range_m; Vec3 collisionPoint; float collisionRange_m; if (damageRange_m < 250.0f) // dont check collisions for distance platforms affected by blast { // check collision along ray to origin if (target->CalculateCollisionPointOrigin(weapon, collisionPoint, collisionRange_m)) { // wxASSERT(collisionRange_m < damageRange_m); damageRange_m = std::min(damageRange_m, collisionRange_m); } // check collision along "up" ray if (target->CalculateCollisionPointDir(weapon, Vec3(0, 1, 0), collisionPoint, collisionRange_m)) { damageRange_m = std::min(damageRange_m, collisionRange_m); } } damageRange_m = std::max(damageRange_m, 10.0f); // don't allow anything closer than 10 m damage.waterBlast_psi = CalculateWaterBlastOverpressure(damageRange_m, weaponDamage->blastCharge_kg); #ifdef _DEBUG fprintf(stdout, "Underwater explosion, %s, range: %.1f m, blast: %.1f PSI\n", target->mzClass.c_str(), damageRange_m, damage.waterBlast_psi); #endif return; // no thermal or frag damage underwater } float minRange_m = std::min(0.05f * target->GetSpan(), 50.0f); minRange_m = std::max(minRange_m, 5.0f); range_m = std::max(range_m, minRange_m); damage.blast_psi = CalculateBlastOverpressure(range_m, weaponDamage->blastCharge_kg); damage.thermal_J_cm2 = CalculateRadiationIntensity(range_m, weaponDamage->radCharge_kg); if (weaponDamage->fragCharge_kg > 0) { FragWeapon fragWeap; fragWeap.charge_kg = weaponDamage->fragCharge_kg; fragWeap.metal_kg = weaponDamage->fragMetal_kg; fragWeap.fragment_kg = weaponDamage->fragFragment_kg; fragWeap.spread_factor = weaponDamage->fragSpread; float targetRadius_m = 0.5*target->GetSpan(); float targetArea_m2 = 0.5 * C_PI * targetRadius_m * targetRadius_m; // approx for now, 0.5 for rect shape float fragRange_m = std::max(range_m, targetRadius_m); tcDamageModel::FragHits fragHits = CalculateFragmentImpact(fragRange_m, target->mcKin.mfAlt_m, fragWeap, targetArea_m2); damage.fragHits = fragHits.hits; damage.fragEnergy_J = fragHits.ke_J; } return; }
Damage Player::getTotalDamageReceived() const { Damage total = affectedPlayers->getTotalDamageDealtOnPlayer(getName()); int dpm = amountPerMinute(total.getTotal()); total.setDPM(dpm); return total; }
void View::Draw () { damage->Reset(); GraphicBlock::Draw(); }
void View::Update () { UpdatePerspective(); damage->Repair(); }
// This is a NPC implementation of damage system (incomplete) bool NPC::ApplyDamage(Damage &d) { _log(ITEM__TRACE, "%u: Applying %.1f total damage from %u", GetID(), d.GetTotal(), d.source->GetID()); double total_damage = 0; bool killed = false; int random_damage = 0; double random_damage_mult = 1.0; //apply resistances... //damageResistance? //Shield: double available_shield = m_shieldCharge; Damage shield_damage = d.MultiplyDup( m_self->GetAttribute(AttrShieldKineticDamageResonance).get_float(), m_self->GetAttribute(AttrShieldThermalDamageResonance).get_float(), m_self->GetAttribute(AttrShieldEmDamageResonance).get_float(), m_self->GetAttribute(AttrShieldExplosiveDamageResonance).get_float() ); //other: //emDamageResistanceBonus //explosiveDamageResistanceBonus //kineticDamageResistanceBonus //thermalDamageResistanceBonus // //TODO: deal with seepage from shield into armor. //shieldUniformity //uniformity (chance of seeping through to armor) /* * Here we calculates the uniformity thing. * I think this must be calculated based on * the type of damage -> resistance basis. * double shield_uniformity = available_shield / m_self->shieldCapacity(); if( shield_uniformity < ( 1.0 - m_self->shieldUniformity() ) ) { /* * As far i can see mostly npc/entities have a * chance of transpassing when the shield is below 25% / } */ // Make a random value to use in msg's and attack multiplier random_damage = static_cast<int32>(MakeRandomInt(0, 5)); random_damage_mult = (double)(random_damage / 10.0); // Not sure about this, but with this we get some random hits... :) //total_shield_damage += total_shield_damage * random_damage_mult; shield_damage.SumWithMultFactor( random_damage_mult ); double total_shield_damage = shield_damage.GetTotal(); if(total_shield_damage <= available_shield) { //we can take all this damage with our shield... double new_charge = m_shieldCharge - total_shield_damage; m_shieldCharge = new_charge; total_damage += total_shield_damage; _log(ITEM__TRACE, "%s(%u): Applying entire %.1f damage to shields. New charge: %.1f", GetName(), GetID(), total_shield_damage, new_charge); } else { //first determine how much we can actually apply to //the shield, the rest goes further down. double consumed_shield_ratio = available_shield / shield_damage.GetTotal(); d *= 1.0 - consumed_shield_ratio; if(available_shield > 0) { total_damage += available_shield; _log(ITEM__TRACE, "%s(%us): Shield depleated with %.1f damage. %.1f damage remains.", GetName(), GetID(), available_shield, d.GetTotal()); //set shield to 0, it is fully depleated. m_shieldCharge = 0; } //Armor: double available_armor = m_self->GetAttribute(AttrArmorHP).get_float() - m_armorDamage; Damage armor_damage = d.MultiplyDup( m_self->GetAttribute(AttrArmorKineticDamageResonance).get_float(), m_self->GetAttribute(AttrArmorThermalDamageResonance).get_float(), m_self->GetAttribute(AttrArmorEmDamageResonance).get_float(), m_self->GetAttribute(AttrArmorExplosiveDamageResonance).get_float() ); //other: //activeEmResistanceBonus //activeExplosiveResistanceBonus //activeThermicResistanceBonus //activeKineticResistanceBonus //passiveEmDamageResistanceBonus //passiveExplosiveDamageResistanceBonus //passiveKineticDamageResistanceBonus //passiveThermicDamageResistanceBonus //TODO: figure out how much passes through to structure/modules. //armorUniformity // Not sure about this, but with this we get some random hits... :) //total_armor_damage += total_armor_damage * random_damage_mult; armor_damage.SumWithMultFactor( random_damage_mult ); double total_armor_damage = armor_damage.GetTotal(); if(total_armor_damage <= available_armor) { //we can take all this damage with our armor... double new_damage = m_armorDamage + total_armor_damage; m_armorDamage = new_damage; total_damage += total_armor_damage; _log(ITEM__TRACE, "%s(%u): Applying entire %.1f damage to armor. New armor damage: %.1f", GetName(), GetID(), total_armor_damage, new_damage); } else { //first determine how much we can actually apply to //the armor, the rest goes further down. double consumed_armor_ratio = available_armor / armor_damage.GetTotal(); d *= 1.0 - consumed_armor_ratio; if(available_armor > 0) { total_damage += available_armor; _log(ITEM__TRACE, "%s(%u): Armor depleated with %.1f damage. %.1f damage remains.", GetName(), GetID(), available_armor, d.GetTotal()); //all armor has been penetrated. m_armorDamage = m_self->GetAttribute(AttrArmorHP).get_float(); } //Hull/Structure: //The base hp and damage attributes represent structure. double available_hull = m_self->GetAttribute(AttrHp).get_float() - m_hullDamage; Damage hull_damage = d.MultiplyDup( m_self->GetAttribute(AttrHullKineticDamageResonance).get_float(), m_self->GetAttribute(AttrHullThermalDamageResonance).get_float(), m_self->GetAttribute(AttrHullEmDamageResonance).get_float(), m_self->GetAttribute(AttrHullExplosiveDamageResonance).get_float() ); //other: //passiveEmDamageResonanceMultiplier //passiveThermalDamageResonanceMultiplier //passiveKineticDamageResonanceMultiplier //passiveExplosiveDamageResonanceMultiplier //activeEmDamageResonance //activeThermalDamageResonance //activeKineticDamageResonance //activeExplosiveDamageResonance //structureUniformity // Not sure about this, but with this we get some random hits... :) //total_hull_damage += total_hull_damage * random_damage_mult; hull_damage.SumWithMultFactor( random_damage_mult ); double total_hull_damage = hull_damage.GetTotal(); total_damage += total_hull_damage; if(total_hull_damage < available_hull) { //we can take all this damage with our hull... double new_damage = m_hullDamage + total_hull_damage; m_hullDamage = new_damage; _log(ITEM__TRACE, "%s(%u): Applying entire %.1f damage to structure. New structure damage: %.1f", GetName(), GetID(), total_hull_damage, new_damage); } else { //dead.... _log(ITEM__TRACE, "%s(%u): %.1f damage has depleated our structure. Time to explode.", GetName(), GetID(), total_hull_damage); killed = true; //m_hullDamage = m_self->hp(); m_hullDamage = m_self->GetAttribute(AttrHp).get_float(); } //TODO: deal with damaging modules. no idea the mechanics on this. } } //if( total_damage <= 0.0 ) // return(killed); PyTuple *up; //Notifications to ourself: Notify_OnEffectHit noeh; noeh.itemID = d.source->GetID(); noeh.effectID = d.effect; noeh.targetID = GetID(); noeh.damage = total_damage; up = noeh.Encode(); QueueDestinyEvent(&up); PySafeDecRef( up ); //NOTE: could send out the RD version of this message instead of the R version, which //includes "weapon" and "owner" instead of "source". Notify_OnDamageMessage_Self ondam; //ondam.messageID = "AttackHit2R"; //TODO: randomize/select this somehow. ondam.messageID = DamageMessageIDs_Self[random_damage]; ondam.damage = total_damage; ondam.source = d.source->GetID(); ondam.splash = ""; up = ondam.Encode(); QueueDestinyEvent(&up); PySafeDecRef( up ); //Notifications to others: //I am not sure what the correct scope of this broadcast //should be. For now, it goes to anybody targeting us. if(targets.IsTargetedBySomething()) { up = noeh.Encode(); targets.QueueTBDestinyEvent(&up); PySafeDecRef( up ); Notify_OnDamageMessage_Other ondamo; //ondamo.messageID = "AttackHit3"; //TODO: select this based on the severity of the hit... ondamo.messageID = DamageMessageIDs_Other[random_damage]; ondamo.format_type = fmtMapping_itemTypeName; ondamo.weaponType = d.weapon->typeID(); ondamo.damage = total_damage; ondamo.target = GetID(); ondamo.splash = ""; up = ondamo.Encode(); targets.QueueTBDestinyEvent(&up); PySafeDecRef( up ); } if(killed == true) { Killed(d); } else { _SendDamageStateChanged(); } return(killed); }
int splDispelAlign(Creature* player, cmd* cmnd, SpellData* spellData, const char* spell, int align) { Creature* target=0; Damage damage; if((target = player->findMagicVictim(cmnd->str[2], cmnd->val[2], spellData, true, false, "Cast on what?\n", "You don't see that here.\n")) == nullptr) return(0); if(player == target) { // mobs can't cast on themselves! if(!player->getAsPlayer()) return(0); // turn into a boolean! // are they in alignment? if(align == PINKISH) align = player->getAlignment() <= align; else align = player->getAlignment() >= align; if(spellData->how == CastType::CAST || spellData->how == CastType::SCROLL || spellData->how == CastType::WAND) player->print("You cannot cast that spell on yourself.\n"); else if(spellData->how == CastType::POTION && !align) player->print("Nothing happens.\n"); else if(spellData->how == CastType::POTION && align) { player->smashInvis(); damage.set(mrand(spellData->level * 2, spellData->level * 4)); damage.add(MAX(0, bonus((int) player->piety.getCur()))); player->modifyDamage(player, MAGICAL, damage); player->print("You feel as if your soul is savagely ripped apart!\n"); player->printColor("You take %s%d^x points of damage!\n", player->customColorize("*CC:DAMAGE*").c_str(), damage.get()); broadcast(player->getSock(), player->getParent(), "%M screams and doubles over in pain!", player); player->hp.decrease(damage.get()); if(player->hp.getCur() < 1) { player->print("Your body explodes. You're dead!\n"); broadcast(player->getSock(), player->getParent(), "%M's body explodes! %s's dead!", player, player->upHeShe()); player->getAsPlayer()->die(EXPLODED); } } } else { if(player->spellFail( spellData->how)) return(0); cmnd->str[2][0] = up(cmnd->str[2][0]); target = player->getParent()->findCreature(player, cmnd->str[2], cmnd->val[2], false); if(!target) { player->print("That's not here.\n"); return(0); } if(!player->canAttack(target)) return(0); if( (target->getLevel() > spellData->level + 7) || (!player->isStaff() && target->isStaff()) ) { player->print("Your magic would be too weak to harm %N.\n", target); return(0); } player->smashInvis(); // turn into a boolean! // are they in alignment? if(align == PINKISH) align = target->getAlignment() <= align; else align = target->getAlignment() >= align; if(spellData->how == CastType::CAST || spellData->how == CastType::SCROLL || spellData->how == CastType::WAND) { player->print("You cast %s on %N.\n", spell, target); broadcast(player->getSock(), target->getSock(), player->getParent(), "%M casts a %s spell on %N.", player, spell, target); if(target->getAsPlayer()) { target->wake("Terrible nightmares disturb your sleep!"); target->print("%M casts a %s spell on you.\n", player, spell); } if(!align) { player->print("Nothing happens.\n"); } else { damage.set(mrand(spellData->level * 2, spellData->level * 4)); damage.add(abs(player->getAlignment()/100)); damage.add(MAX(0, bonus((int) player->piety.getCur()))); target->modifyDamage(player, MAGICAL, damage); if(target->chkSave(SPL, player,0)) damage.set(damage.get() / 2); player->printColor("The spell did %s%d^x damage.\n", player->customColorize("*CC:DAMAGE*").c_str(), damage.get()); player->print("%M screams in agony as %s soul is ripped apart!\n", target, target->hisHer()); target->printColor("You take %s%d^x points of damage as your soul is ripped apart!\n", target->customColorize("*CC:DAMAGE*").c_str(), damage.get()); broadcastGroup(false, target, "%M cast a %s spell on ^M%N^x for *CC:DAMAGE*%d^x damage, %s%s\n", player, spell, target, damage.get(), target->heShe(), target->getStatusStr(damage.get())); broadcast(player->getSock(), target->getSock(), player->getParent(), "%M screams and doubles over in pain!", target); // if the target is reflecting magic, force printing a message (it will say 0 damage) player->doReflectionDamage(damage, target, target->isEffected("reflect-magic") ? REFLECTED_MAGIC : REFLECTED_NONE); if(spellData->how == CastType::CAST && player->isPlayer()) player->getAsPlayer()->statistics.offensiveCast(); player->doDamage(target, damage.get(), NO_CHECK); if(target->hp.getCur() < 1) { target->print("Your body explodes! You die!\n"); broadcast(player->getSock(), target->getSock(), player->getParent(), "%M's body explodes! %s's dead!", target, target->upHeShe()); player->print("%M's body explodes! %s's dead!\n", target, target->upHeShe()); target->die(player); return(2); } } } } return(1); }
void CSubStructure::hit(const b2Transform& trafo, Damage damage, vector2d position, vector2d direction) { // check that position is not inside the ship, otherwise move! // first, raytrace against armour to find hit segment b2RayCastInput rcin{position, position + direction, 1000}; b2RayCastOutput rcout; ArmourSegment* armour_hit{}; for(auto& seg : mArmour) { b2EdgeShape temp; temp.Set(seg.p1, seg.p2); if(temp.RayCast(&rcout, rcin, trafo, 0)) { rcin.maxFraction = rcout.fraction; armour_hit = seg.armour.get(); } } // if there was an armour segment that was hit. if(armour_hit) { damage = armour_hit->hit(damage); } // now, for the internal segments struct HitCell { float frac; IStructureCell* cell; }; rcin.maxFraction = 10000; std::vector<HitCell> hit_cells; for(auto& cell : mCells) { if(physics::raycast(rcout, cell->shape(), rcin, trafo)) { rcin.maxFraction = rcout.fraction; hit_cells.push_back(HitCell{rcout.fraction, cell.get()}); } } // sort hits std::sort( hit_cells.begin(), hit_cells.end(), [](HitCell a, HitCell b) { return a.frac < b.frac; } ); // now go through all cells and hit the components /// \todo make damage processing more interesting here! float internal_damage = 0.5 * damage.getTotalDamage(); mStructurePoints -= internal_damage; for(auto& hc : hit_cells) { IStructureCell* cell = hc.cell; std::size_t comp_count = cell->component_count(); float cmp_dmg = internal_damage / comp_count; for(auto& c : cell->components()) { internal_damage -= c.damage(cmp_dmg); } } /// \todo hit event listener, including ship destruction }