Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/game/StarDamage.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/game/StarDamage.cpp')
-rw-r--r--source/game/StarDamage.cpp311
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;
+}
+
+}