osb/source/game/StarDamage.cpp

312 lines
11 KiB
C++
Raw Normal View History

2023-06-20 04:33:09 +00:00
#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;
}
}