diff options
Diffstat (limited to 'source/game/StarDamage.cpp')
-rw-r--r-- | source/game/StarDamage.cpp | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/source/game/StarDamage.cpp b/source/game/StarDamage.cpp new file mode 100644 index 0000000..83c88ce --- /dev/null +++ b/source/game/StarDamage.cpp @@ -0,0 +1,311 @@ +#include "StarDamage.hpp" +#include "StarJsonExtra.hpp" +#include "StarDataStreamExtra.hpp" +#include "StarRoot.hpp" + +namespace Star { + +DamageSource::DamageSource() + : damageType(DamageType::NoDamage), damage(0.0), sourceEntityId(NullEntityId), rayCheck(false) {} + +DamageSource::DamageSource(Json const& config) { + if (auto dtype = config.optString("damageType")) + damageType = DamageTypeNames.getLeft(*dtype); + else + damageType = DamageType::Damage; + + if (config.contains("poly")) + damageArea = jsonToPolyF(config.get("poly")); + else if (config.contains("line")) + damageArea = jsonToLine2F(config.get("line")); + else + throw StarException("No 'poly' or 'line' key in DamageSource config"); + + damage = config.getFloat("damage"); + + trackSourceEntity = config.getBool("trackSourceEntity", true); + sourceEntityId = config.getInt("sourceEntityId", NullEntityId); + + if (auto tconfig = config.opt("team")) { + team = EntityDamageTeam(*tconfig); + } else { + team.type = TeamTypeNames.getLeft(config.getString("teamType", "passive")); + team.team = config.getUInt("teamNumber", 0); + } + + damageRepeatGroup = config.optString("damageRepeatGroup"); + damageRepeatTimeout = config.optFloat("damageRepeatTimeout"); + + damageSourceKind = config.getString("damageSourceKind", ""); + + statusEffects = config.getArray("statusEffects", {}).transformed(jsonToEphemeralStatusEffect); + + auto knockbackJson = config.get("knockback", Json(0.0f)); + if (knockbackJson.isType(Json::Type::Array)) + knockback = jsonToVec2F(knockbackJson); + else + knockback = knockbackJson.toFloat(); + + rayCheck = config.getBool("rayCheck", false); +} + +DamageSource::DamageSource(DamageType damageType, + DamageArea damageArea, + float damage, + bool trackSourceEntity, + EntityId sourceEntityId, + EntityDamageTeam team, + Maybe<String> damageRepeatGroup, + Maybe<float> damageRepeatTimeout, + String damageSourceKind, + List<EphemeralStatusEffect> statusEffects, + Knockback knockback, + bool rayCheck) + : damageType(move(damageType)), + damageArea(move(damageArea)), + damage(move(damage)), + trackSourceEntity(move(trackSourceEntity)), + sourceEntityId(move(sourceEntityId)), + team(move(team)), + damageRepeatGroup(move(damageRepeatGroup)), + damageRepeatTimeout(move(damageRepeatTimeout)), + damageSourceKind(move(damageSourceKind)), + statusEffects(move(statusEffects)), + knockback(move(knockback)), + rayCheck(move(rayCheck)) {} + +Json DamageSource::toJson() const { + Json damageAreaJson; + if (auto p = damageArea.ptr<PolyF>()) + damageAreaJson = jsonFromPolyF(*p); + else if (auto l = damageArea.ptr<Line2F>()) + damageAreaJson = jsonFromLine2F(*l); + + Json knockbackJson; + if (auto p = knockback.ptr<float>()) + knockbackJson = *p; + else if (auto p = knockback.ptr<Vec2F>()) + knockbackJson = jsonFromVec2F(*p); + + return JsonObject{{"damageType", DamageTypeNames.getRight(damageType)}, + {"damageArea", damageAreaJson}, + {"damage", damage}, + {"trackSourceEntity", trackSourceEntity}, + {"sourceEntityId", sourceEntityId}, + {"team", team.toJson()}, + {"damageRepeatGroup", jsonFromMaybe(damageRepeatGroup)}, + {"damageRepeatTimeout", jsonFromMaybe(damageRepeatTimeout)}, + {"damageSourceKind", damageSourceKind}, + {"statusEffects", statusEffects.transformed(jsonFromEphemeralStatusEffect)}, + {"knockback", knockbackJson}, + {"rayCheck", rayCheck}}; +} + +bool DamageSource::intersectsWithPoly(WorldGeometry const& geometry, PolyF const& targetPoly) const { + if (auto poly = damageArea.ptr<PolyF>()) + return geometry.polyIntersectsPoly(*poly, targetPoly); + else if (auto line = damageArea.ptr<Line2F>()) + return geometry.lineIntersectsPoly(*line, targetPoly); + else + return false; +} + +Vec2F DamageSource::knockbackMomentum(WorldGeometry const& worldGeometry, Vec2F const& targetCenter) const { + if (auto v = knockback.ptr<Vec2F>()) { + return *v; + } else if (auto s = knockback.ptr<float>()) { + if (*s != 0) { + if (auto poly = damageArea.ptr<PolyF>()) + return worldGeometry.diff(targetCenter, poly->center()).normalized() * *s; + else if (auto line = damageArea.ptr<Line2F>()) + return vnorm(line->diff()) * *s; + } + } + + return Vec2F(); +} + +bool DamageSource::operator==(DamageSource const& rhs) const { + return tie(damageType, damageArea, damage, trackSourceEntity, sourceEntityId, team, damageSourceKind, statusEffects, knockback, rayCheck) + == tie(rhs.damageType, + rhs.damageArea, + rhs.damage, + rhs.trackSourceEntity, + rhs.sourceEntityId, + rhs.team, + rhs.damageSourceKind, + rhs.statusEffects, + rhs.knockback, + rhs.rayCheck); +} + +DamageSource& DamageSource::translate(Vec2F const& position) { + if (auto poly = damageArea.ptr<PolyF>()) + poly->translate(position); + else if (auto line = damageArea.ptr<Line2F>()) + line->translate(position); + return *this; +} + +DataStream& operator<<(DataStream& ds, DamageSource const& damageSource) { + ds.write(damageSource.damageType); + ds.write(damageSource.damageArea); + ds.write(damageSource.damage); + ds.write(damageSource.trackSourceEntity); + ds.write(damageSource.sourceEntityId); + ds.write(damageSource.team); + ds.write(damageSource.damageRepeatGroup); + ds.write(damageSource.damageRepeatTimeout); + ds.write(damageSource.damageSourceKind); + ds.write(damageSource.statusEffects); + ds.write(damageSource.knockback); + ds.write(damageSource.rayCheck); + return ds; +} + +DataStream& operator>>(DataStream& ds, DamageSource& damageSource) { + ds.read(damageSource.damageType); + ds.read(damageSource.damageArea); + ds.read(damageSource.damage); + ds.read(damageSource.trackSourceEntity); + ds.read(damageSource.sourceEntityId); + ds.read(damageSource.team); + ds.read(damageSource.damageRepeatGroup); + ds.read(damageSource.damageRepeatTimeout); + ds.read(damageSource.damageSourceKind); + ds.read(damageSource.statusEffects); + ds.read(damageSource.knockback); + ds.read(damageSource.rayCheck); + return ds; +} + +DamageRequest::DamageRequest() + : hitType(HitType::Hit), damageType(DamageType::Damage), damage(0.0f), sourceEntityId(NullEntityId) {} + +DamageRequest::DamageRequest(Json const& v) { + hitType = HitTypeNames.getLeft(v.getString("hitType", "hit")); + damageType = DamageTypeNames.getLeft(v.getString("damageType", "damage")); + damage = v.getFloat("damage"); + knockbackMomentum = jsonToVec2F(v.get("knockbackMomentum", JsonArray{0, 0})); + sourceEntityId = v.getInt("sourceEntityId", NullEntityId); + damageSourceKind = v.getString("damageSourceKind", ""); + statusEffects = v.getArray("statusEffects", {}).transformed(jsonToEphemeralStatusEffect); +} + +DamageRequest::DamageRequest(HitType hitType, + DamageType damageType, + float damage, + Vec2F const& knockbackMomentum, + EntityId sourceEntityId, + String const& damageSourceKind, + List<EphemeralStatusEffect> const& statusEffects) + : hitType(hitType), + damageType(damageType), + damage(damage), + knockbackMomentum(knockbackMomentum), + sourceEntityId(sourceEntityId), + damageSourceKind(damageSourceKind), + statusEffects(statusEffects) {} + +Json DamageRequest::toJson() const { + return JsonObject{{"hitType", HitTypeNames.getRight(hitType)}, + {"damageType", DamageTypeNames.getRight(damageType)}, + {"damage", damage}, + {"knockbackMomentum", jsonFromVec2F(knockbackMomentum)}, + {"sourceEntityId", sourceEntityId}, + {"damageSourceKind", damageSourceKind}, + {"statusEffects", statusEffects.transformed(jsonFromEphemeralStatusEffect)}}; +} + +DataStream& operator<<(DataStream& ds, DamageRequest const& damageRequest) { + ds << damageRequest.hitType; + ds << damageRequest.damageType; + ds << damageRequest.damage; + ds << damageRequest.knockbackMomentum; + ds << damageRequest.sourceEntityId; + ds << damageRequest.damageSourceKind; + ds << damageRequest.statusEffects; + return ds; +} + +DataStream& operator>>(DataStream& ds, DamageRequest& damageRequest) { + ds >> damageRequest.hitType; + ds >> damageRequest.damageType; + ds >> damageRequest.damage; + ds >> damageRequest.knockbackMomentum; + ds >> damageRequest.sourceEntityId; + ds >> damageRequest.damageSourceKind; + ds >> damageRequest.statusEffects; + return ds; +} + +DamageNotification::DamageNotification() : sourceEntityId(), targetEntityId(), damageDealt(), healthLost() {} + +DamageNotification::DamageNotification(Json const& v) { + sourceEntityId = v.getInt("sourceEntityId"); + targetEntityId = v.getInt("targetEntityId"); + position = jsonToVec2F(v.get("position")); + damageDealt = v.getFloat("damageDealt"); + healthLost = v.getFloat("healthLost"); + hitType = HitTypeNames.getLeft(v.getString("hitType")); + damageSourceKind = v.getString("damageSourceKind"); + targetMaterialKind = v.getString("targetMaterialKind"); +} + +DamageNotification::DamageNotification(EntityId sourceEntityId, + EntityId targetEntityId, + Vec2F position, + float damageDealt, + float healthLost, + HitType hitType, + String damageSourceKind, + String targetMaterialKind) + : sourceEntityId(sourceEntityId), + targetEntityId(targetEntityId), + position(position), + damageDealt(damageDealt), + healthLost(healthLost), + hitType(hitType), + damageSourceKind(move(damageSourceKind)), + targetMaterialKind(move(targetMaterialKind)) {} + +Json DamageNotification::toJson() const { + return JsonObject{{"sourceEntityId", sourceEntityId}, + {"targetEntityId", targetEntityId}, + {"position", jsonFromVec2F(position)}, + {"damageDealt", damageDealt}, + {"healthLost", healthLost}, + {"hitType", HitTypeNames.getRight(hitType)}, + {"damageSourceKind", damageSourceKind}, + {"targetMaterialKind", targetMaterialKind}}; +} + +DataStream& operator<<(DataStream& ds, DamageNotification const& damageNotification) { + ds.viwrite(damageNotification.sourceEntityId); + ds.viwrite(damageNotification.targetEntityId); + ds.vfwrite(damageNotification.position[0], 0.01f); + ds.vfwrite(damageNotification.position[1], 0.01f); + ds.write(damageNotification.damageDealt); + ds.write(damageNotification.healthLost); + ds.write(damageNotification.hitType); + ds.write(damageNotification.damageSourceKind); + ds.write(damageNotification.targetMaterialKind); + + return ds; +} + +DataStream& operator>>(DataStream& ds, DamageNotification& damageNotification) { + ds.viread(damageNotification.sourceEntityId); + ds.viread(damageNotification.targetEntityId); + ds.vfread(damageNotification.position[0], 0.01f); + ds.vfread(damageNotification.position[1], 0.01f); + ds.read(damageNotification.damageDealt); + ds.read(damageNotification.healthLost); + ds.read(damageNotification.hitType); + ds.read(damageNotification.damageSourceKind); + ds.read(damageNotification.targetMaterialKind); + + return ds; +} + +} |