v1.4.4
This commit is contained in:
commit
9c94d113d3
10260 changed files with 1237388 additions and 0 deletions
21
source/game/interfaces/StarActivatableItem.hpp
Normal file
21
source/game/interfaces/StarActivatableItem.hpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
#ifndef STAR_ACTIVATABLE_ITEM_HPP
|
||||
#define STAR_ACTIVATABLE_ITEM_HPP
|
||||
|
||||
#include "StarConfig.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(ActivatableItem);
|
||||
|
||||
class ActivatableItem {
|
||||
public:
|
||||
virtual ~ActivatableItem() {}
|
||||
virtual bool active() const = 0;
|
||||
virtual void setActive(bool active) = 0;
|
||||
virtual bool usable() const = 0;
|
||||
virtual void activate() = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
17
source/game/interfaces/StarAggressiveEntity.hpp
Normal file
17
source/game/interfaces/StarAggressiveEntity.hpp
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef STAR_AGGRESSIVE_ENTITY_HPP
|
||||
#define STAR_AGGRESSIVE_ENTITY_HPP
|
||||
|
||||
#include "StarEntity.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(AggressiveEntity);
|
||||
|
||||
class AggressiveEntity : public virtual Entity {
|
||||
public:
|
||||
virtual bool aggressive() const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
21
source/game/interfaces/StarAnchorableEntity.cpp
Normal file
21
source/game/interfaces/StarAnchorableEntity.cpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
#include "StarAnchorableEntity.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
bool EntityAnchorState::operator==(EntityAnchorState const& eas) const {
|
||||
return tie(entityId, positionIndex) == tie(eas.entityId, eas.positionIndex);
|
||||
}
|
||||
|
||||
DataStream& operator>>(DataStream& ds, EntityAnchorState& anchorState) {
|
||||
ds.read(anchorState.entityId);
|
||||
ds.readVlqS(anchorState.positionIndex);
|
||||
return ds;
|
||||
}
|
||||
|
||||
DataStream& operator<<(DataStream& ds, EntityAnchorState const& anchorState) {
|
||||
ds.write(anchorState.entityId);
|
||||
ds.writeVlqS(anchorState.positionIndex);
|
||||
return ds;
|
||||
}
|
||||
|
||||
}
|
39
source/game/interfaces/StarAnchorableEntity.hpp
Normal file
39
source/game/interfaces/StarAnchorableEntity.hpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
#ifndef STAR_ANCHORABLE_ENTITY_HPP
|
||||
#define STAR_ANCHORABLE_ENTITY_HPP
|
||||
|
||||
#include "StarEntity.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_STRUCT(EntityAnchor);
|
||||
|
||||
struct EntityAnchor {
|
||||
virtual ~EntityAnchor() = default;
|
||||
|
||||
Vec2F position;
|
||||
// If set, the entity should place the bottom center of its collision poly on
|
||||
// the given position at exit
|
||||
Maybe<Vec2F> exitBottomPosition;
|
||||
Direction direction;
|
||||
float angle;
|
||||
};
|
||||
|
||||
struct EntityAnchorState {
|
||||
EntityId entityId;
|
||||
size_t positionIndex;
|
||||
|
||||
bool operator==(EntityAnchorState const& eas) const;
|
||||
};
|
||||
|
||||
DataStream& operator>>(DataStream& ds, EntityAnchorState& anchorState);
|
||||
DataStream& operator<<(DataStream& ds, EntityAnchorState const& anchorState);
|
||||
|
||||
class AnchorableEntity : public virtual Entity {
|
||||
public:
|
||||
virtual size_t anchorCount() const = 0;
|
||||
virtual EntityAnchorConstPtr anchor(size_t anchorPositionIndex) const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
268
source/game/interfaces/StarBeamItem.cpp
Normal file
268
source/game/interfaces/StarBeamItem.cpp
Normal file
|
@ -0,0 +1,268 @@
|
|||
#include "StarBeamItem.hpp"
|
||||
#include "StarJsonExtra.hpp"
|
||||
#include "StarImageProcessing.hpp"
|
||||
#include "StarRoot.hpp"
|
||||
#include "StarAssets.hpp"
|
||||
#include "StarRandom.hpp"
|
||||
#include "StarItem.hpp"
|
||||
#include "StarToolUserEntity.hpp"
|
||||
#include "StarWorld.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
BeamItem::BeamItem(Json config) {
|
||||
config = Root::singleton().assets()->json("/player.config:beamGunConfig").setAll(config.toObject());
|
||||
|
||||
m_image = config.get("image").toString();
|
||||
m_endImages = jsonToStringList(config.get("endImages"));
|
||||
m_endType = EndType::Invalid;
|
||||
m_segmentsPerUnit = config.get("segmentsPerUnit").toFloat();
|
||||
m_nearControlPointElasticity = config.get("nearControlPointElasticity").toFloat();
|
||||
m_farControlPointElasticity = config.get("farControlPointElasticity").toFloat();
|
||||
m_nearControlPointDistance = config.get("nearControlPointDistance").toFloat();
|
||||
m_handPosition = jsonToVec2F(config.get("handPosition"));
|
||||
m_firePosition = jsonToVec2F(config.get("firePosition"));
|
||||
m_range = 1.0f;
|
||||
m_targetSegmentRun = config.get("targetSegmentRun").toFloat();
|
||||
m_minBeamWidth = config.get("minBeamWidth").toFloat();
|
||||
m_maxBeamWidth = config.get("maxBeamWidth").toFloat();
|
||||
m_beamWidthDev = config.getFloat("beamWidthDev", (m_maxBeamWidth - m_minBeamWidth) / 3);
|
||||
m_minBeamJitter = config.get("minBeamJitter").toFloat();
|
||||
m_maxBeamJitter = config.get("maxBeamJitter").toFloat();
|
||||
m_beamJitterDev = config.getFloat("beamJitterDev", (m_maxBeamJitter * 2) / 3);
|
||||
m_minBeamTrans = config.get("minBeamTrans").toFloat();
|
||||
m_maxBeamTrans = config.get("maxBeamTrans").toFloat();
|
||||
m_beamTransDev = config.getFloat("beamTransDev", (m_maxBeamTrans - m_minBeamTrans) / 3);
|
||||
m_minBeamLines = config.get("minBeamLines").toInt();
|
||||
m_maxBeamLines = config.get("maxBeamLines").toInt();
|
||||
m_innerBrightnessScale = config.get("innerBrightnessScale").toFloat();
|
||||
m_firstStripeThickness = config.get("firstStripeThickness").toFloat();
|
||||
m_secondStripeThickness = config.get("secondStripeThickness").toFloat();
|
||||
m_color = {255, 255, 255, 255};
|
||||
m_particleGenerateCooldown = .25;
|
||||
m_inRangeLastUpdate = false;
|
||||
}
|
||||
|
||||
void BeamItem::init(ToolUserEntity* owner, ToolHand hand) {
|
||||
ToolUserItem::init(owner, hand);
|
||||
|
||||
m_beamCurve = CSplineF();
|
||||
|
||||
if (initialized()) {
|
||||
m_color = owner->favoriteColor();
|
||||
m_range = owner->beamGunRadius();
|
||||
return;
|
||||
}
|
||||
|
||||
throw ItemException("BeamItem::init: Beam Gun not init'd properly, or user not recognized as Tool User.");
|
||||
}
|
||||
|
||||
void BeamItem::update(FireMode, bool, HashSet<MoveControlType> const&) {
|
||||
if (m_particleGenerateCooldown >= 0)
|
||||
m_particleGenerateCooldown -= WorldTimestep;
|
||||
|
||||
if (!initialized())
|
||||
throw ItemException("BeamItem::update: Beam Gun not init'd properly, or user not recognized as Tool User.");
|
||||
|
||||
m_beamCurve.origin() = owner()->handPosition(hand(), (m_firePosition - m_handPosition) / TilePixels);
|
||||
|
||||
if (m_endType == EndType::TileGroup)
|
||||
m_beamCurve.dest() = world()->geometry().diff(owner()->aimPosition().round(), owner()->position());
|
||||
else if (m_endType == EndType::Wire)
|
||||
m_beamCurve.dest() = world()->geometry().diff(owner()->aimPosition(), owner()->position());
|
||||
else
|
||||
m_beamCurve.dest() = world()->geometry().diff(centerOfTile(owner()->aimPosition()), owner()->position());
|
||||
|
||||
if (m_beamCurve.dest().magnitudeSquared() < m_beamCurve.origin().magnitudeSquared())
|
||||
m_beamCurve[2] = m_beamCurve.dest();
|
||||
else
|
||||
m_beamCurve[2] = m_beamCurve[2] + (m_beamCurve.dest() - m_beamCurve[2]) * m_farControlPointElasticity;
|
||||
|
||||
Vec2F desiredNearControlPoint = (m_beamCurve.dest() - m_beamCurve.origin()) * m_nearControlPointDistance;
|
||||
|
||||
if (m_beamCurve.dest().magnitudeSquared() < m_beamCurve.origin().magnitudeSquared())
|
||||
m_beamCurve[1] = m_beamCurve.origin();
|
||||
else if (owner()->facingDirection() != getAngleSide(m_beamCurve[1].angle()).second)
|
||||
m_beamCurve[1] = desiredNearControlPoint;
|
||||
else
|
||||
m_beamCurve[1] = m_beamCurve[1] + (desiredNearControlPoint - m_beamCurve[1]) * m_nearControlPointElasticity;
|
||||
}
|
||||
|
||||
List<Drawable> BeamItem::nonRotatedDrawables() const {
|
||||
return beamDrawables();
|
||||
}
|
||||
|
||||
float BeamItem::getAngle(float angle) {
|
||||
if (m_beamCurve.dest().magnitudeSquared() < m_beamCurve.origin().magnitudeSquared()
|
||||
|| m_beamCurve.origin() == m_beamCurve[1])
|
||||
return angle;
|
||||
return getAngleSide(m_beamCurve[1].angle()).first;
|
||||
}
|
||||
|
||||
List<Drawable> BeamItem::drawables() const {
|
||||
return {Drawable::makeImage(m_image, 1.0f / TilePixels, true, -handPosition() / TilePixels)};
|
||||
}
|
||||
|
||||
Vec2F BeamItem::handPosition() const {
|
||||
return m_handPosition;
|
||||
}
|
||||
|
||||
Vec2F BeamItem::firePosition() const {
|
||||
return m_firePosition;
|
||||
}
|
||||
|
||||
void BeamItem::setRange(float range) {
|
||||
m_range = range;
|
||||
}
|
||||
|
||||
float BeamItem::getAppropriateOpacity() const {
|
||||
float curveLen = m_beamCurve.length();
|
||||
const float rangeEffect = (m_range - curveLen) / m_range;
|
||||
|
||||
auto projectOntoRange = [&](float min, float max) { return rangeEffect * (max - min) + min; };
|
||||
auto rangeRand = [&](float dev, float min, float max) {
|
||||
return clamp<float>(Random::nrandf(dev, projectOntoRange(min, max)), min, max);
|
||||
};
|
||||
|
||||
int numLines = projectOntoRange(m_minBeamLines, m_maxBeamLines);
|
||||
float res = (1 - rangeRand(m_beamTransDev, m_minBeamTrans, m_maxBeamTrans));
|
||||
if (numLines > 0) {
|
||||
for (auto line = 0; line < numLines - 1; line++)
|
||||
res *= (1 - rangeRand(m_beamTransDev, m_minBeamTrans, m_maxBeamTrans));
|
||||
}
|
||||
return 1 - res;
|
||||
}
|
||||
|
||||
void BeamItem::setEnd(EndType type) {
|
||||
m_endType = type;
|
||||
}
|
||||
|
||||
List<Drawable> BeamItem::beamDrawables(bool canPlace) const {
|
||||
List<Drawable> res;
|
||||
|
||||
float curveLen = m_beamCurve.length();
|
||||
const float rangeEffect = (m_range - curveLen) / m_range;
|
||||
|
||||
auto projectOntoRange = [&](float min, float max) { return rangeEffect * (max - min) + min; };
|
||||
auto rangeRand = [&](float dev, float min, float max) {
|
||||
return clamp<float>(Random::nrandf(dev, projectOntoRange(min, max)), min, max);
|
||||
};
|
||||
|
||||
if (initialized()) {
|
||||
Vec2F endPoint;
|
||||
if (m_endType == EndType::TileGroup)
|
||||
endPoint = owner()->aimPosition().round();
|
||||
else if (m_endType == EndType::Wire)
|
||||
endPoint = owner()->aimPosition();
|
||||
else
|
||||
endPoint = centerOfTile(owner()->aimPosition());
|
||||
|
||||
if ((endPoint - owner()->position()).magnitude() <= m_range && curveLen <= m_range) {
|
||||
m_inRangeLastUpdate = true;
|
||||
int numLines = projectOntoRange(m_minBeamLines, m_maxBeamLines);
|
||||
Vec4B mainColor = m_color;
|
||||
if (!canPlace) {
|
||||
Color temp = Color::rgba(m_color);
|
||||
temp.setHue(temp.hue() + 120);
|
||||
mainColor = temp.toRgba();
|
||||
}
|
||||
m_lastUpdateColor = mainColor;
|
||||
|
||||
String endImage = "";
|
||||
if (m_endType != EndType::Invalid) {
|
||||
endImage = m_endImages[(unsigned)m_endType];
|
||||
}
|
||||
|
||||
if (!endImage.empty()) {
|
||||
if (!canPlace) {
|
||||
ImageOperation op = HueShiftImageOperation::hueShiftDegrees(120);
|
||||
endImage = strf("%s?%s", endImage, imageOperationToString(op));
|
||||
}
|
||||
|
||||
Drawable ball = Drawable::makeImage(endImage, 1.0f / TilePixels, true, m_beamCurve.dest());
|
||||
Color ballColor = Color::White;
|
||||
ballColor.setAlphaF(getAppropriateOpacity());
|
||||
ball.color = ballColor;
|
||||
res.push_back(ball);
|
||||
}
|
||||
|
||||
for (auto line = 0; line < numLines; line++) {
|
||||
float lineThickness = rangeRand(m_beamWidthDev, m_minBeamWidth, m_maxBeamWidth);
|
||||
float beamTransparency = rangeRand(m_beamTransDev, m_minBeamTrans, m_maxBeamTrans);
|
||||
mainColor[3] = mainColor[3] * beamTransparency;
|
||||
Vec2F previousLoc = m_beamCurve.origin(); // lines meet at origin and dest.
|
||||
Color innerStripe = Color::rgba(mainColor);
|
||||
innerStripe.setValue(1 - (1 - innerStripe.value()) / m_innerBrightnessScale);
|
||||
innerStripe.setSaturation(innerStripe.saturation() / m_innerBrightnessScale);
|
||||
Vec4B firstStripe = innerStripe.toRgba();
|
||||
innerStripe.setValue(1 - (1 - innerStripe.value()) / m_innerBrightnessScale);
|
||||
innerStripe.setSaturation(innerStripe.saturation() / m_innerBrightnessScale);
|
||||
Vec4B secondStripe = innerStripe.toRgba();
|
||||
|
||||
for (auto i = 1; i < (int)(curveLen * m_targetSegmentRun - .5); i++) { // one less than full length
|
||||
float pos = (float)i / (float)(int)(curveLen * m_targetSegmentRun + .5); // project the discrete steps evenly
|
||||
|
||||
Vec2F currentLoc =
|
||||
m_beamCurve.pointAt(pos) + Vec2F(rangeRand(m_beamJitterDev, -m_maxBeamJitter, m_maxBeamJitter),
|
||||
rangeRand(m_beamJitterDev, -m_maxBeamJitter, m_maxBeamJitter));
|
||||
res.push_back(
|
||||
Drawable::makeLine(Line2F(previousLoc, currentLoc), lineThickness, Color::rgba(mainColor), Vec2F()));
|
||||
res.push_back(Drawable::makeLine(Line2F(previousLoc, currentLoc),
|
||||
lineThickness * m_firstStripeThickness,
|
||||
Color::rgba(firstStripe),
|
||||
Vec2F()));
|
||||
res.push_back(Drawable::makeLine(Line2F(previousLoc, currentLoc),
|
||||
lineThickness * m_secondStripeThickness,
|
||||
Color::rgba(secondStripe),
|
||||
Vec2F()));
|
||||
previousLoc = std::move(currentLoc);
|
||||
}
|
||||
res.push_back(Drawable::makeLine(
|
||||
Line2F(previousLoc, m_beamCurve.dest()), lineThickness, Color::rgba(mainColor), Vec2F()));
|
||||
res.push_back(Drawable::makeLine(Line2F(previousLoc, m_beamCurve.dest()),
|
||||
lineThickness * m_firstStripeThickness,
|
||||
Color::rgba(firstStripe),
|
||||
Vec2F()));
|
||||
res.push_back(Drawable::makeLine(Line2F(previousLoc, m_beamCurve.dest()),
|
||||
lineThickness * m_secondStripeThickness,
|
||||
Color::rgba(secondStripe),
|
||||
Vec2F()));
|
||||
}
|
||||
} else {
|
||||
if (m_inRangeLastUpdate) {
|
||||
m_inRangeLastUpdate = false;
|
||||
m_particleGenerateCooldown = .25; // TODO, expose to json
|
||||
List<Particle> beamLeftovers;
|
||||
for (auto i = 1; i < (int)(curveLen * m_targetSegmentRun * 2 - .5); i++) { // one less than full length
|
||||
float pos =
|
||||
(float)i / (float)(int)(curveLen * m_targetSegmentRun * 2 + .5); // project the discrete steps evenly
|
||||
float curveLoc = m_beamCurve.arcLenPara(pos);
|
||||
|
||||
Particle beamParticle;
|
||||
beamParticle.type = Particle::Type::Ember;
|
||||
beamParticle.position = m_beamCurve.pointAt(curveLoc);
|
||||
beamParticle.size = 1.0f;
|
||||
|
||||
Color randomColor = Color::rgba(m_lastUpdateColor);
|
||||
randomColor.setValue(1 - (1 - randomColor.value()) / Random::randf(1, 4));
|
||||
randomColor.setSaturation(randomColor.saturation() / Random::randf(1, 4));
|
||||
|
||||
beamParticle.color = randomColor;
|
||||
beamParticle.velocity = Vec2F::filled(Random::randf());
|
||||
beamParticle.finalVelocity = Vec2F(0.0f, -20.0f);
|
||||
beamParticle.approach = Vec2F(0.0f, 5.0f);
|
||||
beamParticle.timeToLive = 0.25f;
|
||||
beamParticle.destructionAction = Particle::DestructionAction::Shrink;
|
||||
beamParticle.destructionTime = 0.2f;
|
||||
beamLeftovers.append(beamParticle);
|
||||
}
|
||||
|
||||
owner()->addParticles(beamLeftovers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
78
source/game/interfaces/StarBeamItem.hpp
Normal file
78
source/game/interfaces/StarBeamItem.hpp
Normal file
|
@ -0,0 +1,78 @@
|
|||
#ifndef STAR_BEAM_ITEM_HPP
|
||||
#define STAR_BEAM_ITEM_HPP
|
||||
|
||||
#include "StarSpline.hpp"
|
||||
#include "StarGameTypes.hpp"
|
||||
#include "StarNonRotatedDrawablesItem.hpp"
|
||||
#include "StarToolUserItem.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(Item);
|
||||
STAR_CLASS(ToolUserEntity);
|
||||
STAR_CLASS(World);
|
||||
|
||||
STAR_CLASS(BeamItem);
|
||||
|
||||
class BeamItem : public virtual NonRotatedDrawablesItem, public virtual ToolUserItem {
|
||||
public:
|
||||
enum class EndType { Invalid = -1, Object, Tile, TileGroup, Wire };
|
||||
|
||||
BeamItem(Json config);
|
||||
virtual ~BeamItem() = default;
|
||||
|
||||
virtual void init(ToolUserEntity* owner, ToolHand hand) override;
|
||||
virtual void update(FireMode fireMode, bool shifting, HashSet<MoveControlType> const& moves) override;
|
||||
|
||||
virtual List<Drawable> nonRotatedDrawables() const override;
|
||||
|
||||
virtual float getAngle(float angle);
|
||||
virtual List<Drawable> drawables() const;
|
||||
virtual Vec2F handPosition() const;
|
||||
virtual Vec2F firePosition() const;
|
||||
virtual void setRange(float range);
|
||||
virtual float getAppropriateOpacity() const;
|
||||
virtual void setEnd(EndType type);
|
||||
|
||||
protected:
|
||||
List<Drawable> beamDrawables(bool canPlace = true) const;
|
||||
|
||||
String m_image;
|
||||
StringList m_endImages;
|
||||
EndType m_endType;
|
||||
|
||||
float m_segmentsPerUnit;
|
||||
float m_nearControlPointElasticity;
|
||||
float m_farControlPointElasticity;
|
||||
float m_nearControlPointDistance;
|
||||
Vec2F m_handPosition;
|
||||
Vec2F m_firePosition;
|
||||
float m_range;
|
||||
|
||||
float m_targetSegmentRun;
|
||||
float m_minBeamWidth;
|
||||
float m_maxBeamWidth;
|
||||
float m_beamWidthDev;
|
||||
float m_minBeamJitter;
|
||||
float m_maxBeamJitter;
|
||||
float m_beamJitterDev;
|
||||
float m_minBeamTrans;
|
||||
float m_maxBeamTrans;
|
||||
float m_beamTransDev;
|
||||
int m_minBeamLines;
|
||||
int m_maxBeamLines;
|
||||
float m_innerBrightnessScale;
|
||||
float m_firstStripeThickness;
|
||||
float m_secondStripeThickness;
|
||||
Vec4B m_color;
|
||||
|
||||
mutable bool m_inRangeLastUpdate;
|
||||
mutable Vec4B m_lastUpdateColor;
|
||||
mutable float m_particleGenerateCooldown;
|
||||
|
||||
CSplineF m_beamCurve;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
19
source/game/interfaces/StarChattyEntity.hpp
Normal file
19
source/game/interfaces/StarChattyEntity.hpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef STAR_CHATTY_ENTITY_HPP
|
||||
#define STAR_CHATTY_ENTITY_HPP
|
||||
|
||||
#include "StarChatAction.hpp"
|
||||
#include "StarEntity.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(ChattyEntity);
|
||||
|
||||
class ChattyEntity : public virtual Entity {
|
||||
public:
|
||||
virtual Vec2F mouthPosition() const = 0;
|
||||
virtual List<ChatAction> pullPendingChatActions() = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
15
source/game/interfaces/StarContainerEntity.cpp
Normal file
15
source/game/interfaces/StarContainerEntity.cpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
#include "StarContainerEntity.hpp"
|
||||
#include "StarItemBag.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
size_t ContainerEntity::containerSize() const {
|
||||
return itemBag()->size();
|
||||
}
|
||||
|
||||
List<ItemPtr> ContainerEntity::containerItems() const {
|
||||
return itemBag()->items();
|
||||
}
|
||||
|
||||
}
|
||||
|
50
source/game/interfaces/StarContainerEntity.hpp
Normal file
50
source/game/interfaces/StarContainerEntity.hpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
#ifndef STAR_CONTAINER_ENTITY_HPP
|
||||
#define STAR_CONTAINER_ENTITY_HPP
|
||||
|
||||
#include "StarGameTypes.hpp"
|
||||
#include "StarTileEntity.hpp"
|
||||
#include "StarItemDescriptor.hpp"
|
||||
#include "StarRpcPromise.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(Item);
|
||||
STAR_CLASS(ItemBag);
|
||||
STAR_CLASS(ContainerEntity);
|
||||
|
||||
// All container methods may be called on both master and slave entities.
|
||||
class ContainerEntity : public virtual TileEntity {
|
||||
public:
|
||||
size_t containerSize() const;
|
||||
List<ItemPtr> containerItems() const;
|
||||
|
||||
virtual Json containerGuiConfig() const = 0;
|
||||
virtual String containerDescription() const = 0;
|
||||
virtual String containerSubTitle() const = 0;
|
||||
virtual ItemDescriptor iconItem() const = 0;
|
||||
|
||||
virtual ItemBagConstPtr itemBag() const = 0;
|
||||
|
||||
virtual void containerOpen() = 0;
|
||||
virtual void containerClose() = 0;
|
||||
|
||||
virtual void startCrafting() = 0;
|
||||
virtual void stopCrafting() = 0;
|
||||
virtual bool isCrafting() const = 0;
|
||||
virtual float craftingProgress() const = 0;
|
||||
|
||||
virtual void burnContainerContents() = 0;
|
||||
|
||||
virtual RpcPromise<ItemPtr> addItems(ItemPtr const& items) = 0;
|
||||
virtual RpcPromise<ItemPtr> putItems(size_t slot, ItemPtr const& items) = 0;
|
||||
virtual RpcPromise<ItemPtr> takeItems(size_t slot, size_t count = NPos) = 0;
|
||||
virtual RpcPromise<ItemPtr> swapItems(size_t slot, ItemPtr const& items, bool tryCombine = true) = 0;
|
||||
virtual RpcPromise<ItemPtr> applyAugment(size_t slot, ItemPtr const& augment) = 0;
|
||||
virtual RpcPromise<bool> consumeItems(ItemDescriptor const& descriptor) = 0;
|
||||
virtual RpcPromise<bool> consumeItems(size_t slot, size_t count) = 0;
|
||||
virtual RpcPromise<List<ItemPtr>> clearContainer() = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
11
source/game/interfaces/StarDamageBarEntity.cpp
Normal file
11
source/game/interfaces/StarDamageBarEntity.cpp
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include "StarDamageBarEntity.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
EnumMap<DamageBarType> const DamageBarTypeNames{
|
||||
{DamageBarType::Default, "Default"},
|
||||
{DamageBarType::None, "None"},
|
||||
{DamageBarType::Special, "Special"}
|
||||
};
|
||||
|
||||
}
|
27
source/game/interfaces/StarDamageBarEntity.hpp
Normal file
27
source/game/interfaces/StarDamageBarEntity.hpp
Normal file
|
@ -0,0 +1,27 @@
|
|||
#ifndef STAR_DAMAGE_BAR_ENTITY_HPP
|
||||
#define STAR_DAMAGE_BAR_ENTITY_HPP
|
||||
|
||||
#include "StarPortraitEntity.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(DamageBarEntity);
|
||||
|
||||
enum class DamageBarType : uint8_t {
|
||||
Default,
|
||||
None,
|
||||
Special
|
||||
};
|
||||
extern EnumMap<DamageBarType> const DamageBarTypeNames;
|
||||
|
||||
class DamageBarEntity : public virtual PortraitEntity {
|
||||
public:
|
||||
virtual float health() const = 0;
|
||||
virtual float maxHealth() const = 0;
|
||||
virtual String name() const = 0;
|
||||
virtual DamageBarType damageBar() const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
18
source/game/interfaces/StarDurabilityItem.hpp
Normal file
18
source/game/interfaces/StarDurabilityItem.hpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef STAR_DURABILITY_ITEM_HPP
|
||||
#define STAR_DURABILITY_ITEM_HPP
|
||||
|
||||
#include "StarConfig.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(DurabilityItem);
|
||||
|
||||
class DurabilityItem {
|
||||
public:
|
||||
virtual ~DurabilityItem() {}
|
||||
virtual float durabilityStatus() = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
18
source/game/interfaces/StarEffectSourceItem.hpp
Normal file
18
source/game/interfaces/StarEffectSourceItem.hpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef STAR_EFFECT_SOURCE_ITEM_HPP
|
||||
#define STAR_EFFECT_SOURCE_ITEM_HPP
|
||||
|
||||
#include "StarString.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(EffectSourceItem);
|
||||
|
||||
class EffectSourceItem {
|
||||
public:
|
||||
virtual ~EffectSourceItem() {}
|
||||
virtual StringSet effectSources() const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
18
source/game/interfaces/StarEmoteEntity.hpp
Normal file
18
source/game/interfaces/StarEmoteEntity.hpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef STAR_EMOTE_ENTITY_HPP
|
||||
#define STAR_EMOTE_ENTITY_HPP
|
||||
|
||||
#include "StarHumanoid.hpp"
|
||||
#include "StarEntity.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(EmoteEntity);
|
||||
|
||||
class EmoteEntity : public virtual Entity {
|
||||
public:
|
||||
virtual void playEmote(HumanoidEmote emote) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
194
source/game/interfaces/StarEntity.cpp
Normal file
194
source/game/interfaces/StarEntity.cpp
Normal file
|
@ -0,0 +1,194 @@
|
|||
#include "StarEntity.hpp"
|
||||
#include "StarDamageManager.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
EnumMap<ClientEntityMode> const ClientEntityModeNames{
|
||||
{ClientEntityMode::ClientSlaveOnly, "ClientSlaveOnly"},
|
||||
{ClientEntityMode::ClientMasterAllowed, "ClientMasterAllowed"},
|
||||
{ClientEntityMode::ClientPresenceMaster, "ClientPresenceMaster"}
|
||||
};
|
||||
|
||||
EnumMap<EntityType> const EntityTypeNames{
|
||||
{EntityType::Plant, "plant"},
|
||||
{EntityType::Object, "object"},
|
||||
{EntityType::Vehicle, "vehicle"},
|
||||
{EntityType::ItemDrop, "itemDrop"},
|
||||
{EntityType::PlantDrop, "plantDrop"},
|
||||
{EntityType::Projectile, "projectile"},
|
||||
{EntityType::Stagehand, "stagehand"},
|
||||
{EntityType::Monster, "monster"},
|
||||
{EntityType::Npc, "npc"},
|
||||
{EntityType::Player, "player"}
|
||||
};
|
||||
|
||||
Entity::~Entity() {}
|
||||
|
||||
void Entity::init(World* world, EntityId entityId, EntityMode mode) {
|
||||
if (!world)
|
||||
throw EntityException("Entity::init called with null world pointer");
|
||||
if (entityId == NullEntityId)
|
||||
throw EntityException("Entity::init called with null entity id");
|
||||
if (m_world)
|
||||
throw EntityException("Entity::init called when already initialized");
|
||||
|
||||
m_world = world;
|
||||
m_entityMode = mode;
|
||||
m_entityId = entityId;
|
||||
}
|
||||
|
||||
void Entity::uninit() {
|
||||
m_world = nullptr;
|
||||
m_entityMode = {};
|
||||
m_entityId = NullEntityId;
|
||||
}
|
||||
|
||||
pair<ByteArray, uint64_t> Entity::writeNetState(uint64_t) {
|
||||
return {ByteArray(), 0};
|
||||
}
|
||||
|
||||
void Entity::readNetState(ByteArray, float) {}
|
||||
|
||||
void Entity::enableInterpolation(float) {}
|
||||
|
||||
void Entity::disableInterpolation() {}
|
||||
|
||||
RectF Entity::collisionArea() const {
|
||||
return RectF::null();
|
||||
}
|
||||
|
||||
bool Entity::ephemeral() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
ClientEntityMode Entity::clientEntityMode() const {
|
||||
return ClientEntityMode::ClientSlaveOnly;
|
||||
}
|
||||
|
||||
bool Entity::masterOnly() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
String Entity::description() const {
|
||||
return "";
|
||||
}
|
||||
|
||||
List<LightSource> Entity::lightSources() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
List<DamageSource> Entity::damageSources() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
void Entity::hitOther(EntityId, DamageRequest const&) {}
|
||||
|
||||
void Entity::damagedOther(DamageNotification const&) {}
|
||||
|
||||
Maybe<HitType> Entity::queryHit(DamageSource const&) const {
|
||||
return {};
|
||||
}
|
||||
|
||||
Maybe<PolyF> Entity::hitPoly() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
List<DamageNotification> Entity::applyDamage(DamageRequest const&) {
|
||||
return {};
|
||||
}
|
||||
|
||||
List<DamageNotification> Entity::selfDamageNotifications() {
|
||||
return {};
|
||||
}
|
||||
|
||||
bool Entity::shouldDestroy() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void Entity::destroy(RenderCallback*) {}
|
||||
|
||||
Maybe<Json> Entity::receiveMessage(ConnectionId, String const&, JsonArray const&) {
|
||||
return {};
|
||||
}
|
||||
|
||||
void Entity::update(uint64_t) {}
|
||||
|
||||
void Entity::render(RenderCallback*) {}
|
||||
|
||||
EntityId Entity::entityId() const {
|
||||
return m_entityId;
|
||||
}
|
||||
|
||||
EntityDamageTeam Entity::getTeam() const {
|
||||
return m_team;
|
||||
}
|
||||
|
||||
bool Entity::inWorld() const {
|
||||
if (m_world) {
|
||||
starAssert(m_world && m_entityId != NullEntityId && m_entityMode);
|
||||
return true;
|
||||
} else {
|
||||
starAssert(!m_world && m_entityId == NullEntityId && !m_entityMode);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
World* Entity::world() const {
|
||||
if (!m_world)
|
||||
throw EntityException("world() called while uninitialized");
|
||||
|
||||
return m_world;
|
||||
}
|
||||
|
||||
World* Entity::worldPtr() const {
|
||||
return m_world;
|
||||
}
|
||||
|
||||
bool Entity::persistent() const {
|
||||
return m_persistent;
|
||||
}
|
||||
|
||||
bool Entity::keepAlive() const {
|
||||
return m_keepAlive;
|
||||
}
|
||||
|
||||
Maybe<String> Entity::uniqueId() const {
|
||||
return m_uniqueId;
|
||||
}
|
||||
|
||||
Maybe<EntityMode> Entity::entityMode() const {
|
||||
return m_entityMode;
|
||||
}
|
||||
|
||||
bool Entity::isMaster() const {
|
||||
return m_entityMode == EntityMode::Master;
|
||||
}
|
||||
|
||||
bool Entity::isSlave() const {
|
||||
return m_entityMode == EntityMode::Slave;
|
||||
}
|
||||
|
||||
Entity::Entity() {
|
||||
m_world = nullptr;
|
||||
m_entityId = NullEntityId;
|
||||
m_persistent = false;
|
||||
m_keepAlive = false;
|
||||
}
|
||||
|
||||
void Entity::setPersistent(bool persistent) {
|
||||
m_persistent = persistent;
|
||||
}
|
||||
|
||||
void Entity::setKeepAlive(bool keepAlive) {
|
||||
m_keepAlive = keepAlive;
|
||||
}
|
||||
|
||||
void Entity::setUniqueId(Maybe<String> uniqueId) {
|
||||
m_uniqueId = uniqueId;
|
||||
}
|
||||
|
||||
void Entity::setTeam(EntityDamageTeam newTeam) {
|
||||
m_team = newTeam;
|
||||
}
|
||||
|
||||
}
|
229
source/game/interfaces/StarEntity.hpp
Normal file
229
source/game/interfaces/StarEntity.hpp
Normal file
|
@ -0,0 +1,229 @@
|
|||
#ifndef STAR_ENTITY_HPP
|
||||
#define STAR_ENTITY_HPP
|
||||
|
||||
#include "StarCasting.hpp"
|
||||
#include "StarDamage.hpp"
|
||||
#include "StarLightSource.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(RenderCallback);
|
||||
STAR_CLASS(World);
|
||||
STAR_STRUCT(DamageNotification);
|
||||
STAR_CLASS(Entity);
|
||||
|
||||
STAR_EXCEPTION(EntityException, StarException);
|
||||
|
||||
// Specifies how the client should treat an entity created on the client,
|
||||
// whether it should always be sent to the server and be a slave on the client,
|
||||
// whether it is allowed to be master on the client, and whether client master
|
||||
// entities should contribute to client presence.
|
||||
enum class ClientEntityMode {
|
||||
// Always a slave on the client
|
||||
ClientSlaveOnly,
|
||||
// Can be a master on the client
|
||||
ClientMasterAllowed,
|
||||
// Can be a master on the client, and when it is contributes to client
|
||||
// presence.
|
||||
ClientPresenceMaster
|
||||
};
|
||||
extern EnumMap<ClientEntityMode> const ClientEntityModeNames;
|
||||
|
||||
// The top-level entity type. The enum order is intended to be in the order in
|
||||
// which entities should be updated every tick
|
||||
enum class EntityType : uint8_t {
|
||||
Plant,
|
||||
Object,
|
||||
Vehicle,
|
||||
ItemDrop,
|
||||
PlantDrop,
|
||||
Projectile,
|
||||
Stagehand,
|
||||
Monster,
|
||||
Npc,
|
||||
Player
|
||||
};
|
||||
extern EnumMap<EntityType> const EntityTypeNames;
|
||||
|
||||
class Entity {
|
||||
public:
|
||||
virtual ~Entity();
|
||||
|
||||
virtual EntityType entityType() const = 0;
|
||||
|
||||
// Called when an entity is first inserted into a World. Calling base class
|
||||
// init sets the world pointer, entityId, and entityMode.
|
||||
virtual void init(World* world, EntityId entityId, EntityMode mode);
|
||||
|
||||
// Should do whatever steps necessary to take an entity out of a world,
|
||||
// default implementation clears the world pointer, entityMode, and entityId.
|
||||
virtual void uninit();
|
||||
|
||||
// Write state data that changes over time, and is used to keep slaves in
|
||||
// sync. Can return empty and this is the default. May be called
|
||||
// uninitalized. Should return the delta to be written to the slave, along
|
||||
// with the version to pass into writeDeltaState on the next call. The first
|
||||
// delta written to a slave entity will always be the delta starting with 0.
|
||||
virtual pair<ByteArray, uint64_t> writeNetState(uint64_t fromVersion = 0);
|
||||
// Will be called with deltas written by writeDeltaState, including if the
|
||||
// delta is empty. interpolationTime will be provided if interpolation is
|
||||
// enabled.
|
||||
virtual void readNetState(ByteArray data, float interpolationTime = 0.0);
|
||||
|
||||
virtual void enableInterpolation(float extrapolationHint);
|
||||
virtual void disableInterpolation();
|
||||
|
||||
// Base position of this entity, bound boxes, drawables, and other entity
|
||||
// positions are relative to this.
|
||||
virtual Vec2F position() const = 0;
|
||||
|
||||
// Largest bounding-box of this entity. Any damage boxes / drawables / light
|
||||
// or sound *sources* must be contained within this bounding box. Used for
|
||||
// all top-level spatial queries.
|
||||
virtual RectF metaBoundBox() const = 0;
|
||||
|
||||
// By default returns a null rect, if non-null, it defines the area around
|
||||
// this entity where it is likely for the entity to physically collide with
|
||||
// collision geometry.
|
||||
virtual RectF collisionArea() const;
|
||||
|
||||
// Should this entity allow object / block placement over it, and can the
|
||||
// entity immediately be despawned without terribly bad effects?
|
||||
virtual bool ephemeral() const;
|
||||
|
||||
// How should this entity be treated if created on the client? Defaults to
|
||||
// ClientSlave.
|
||||
virtual ClientEntityMode clientEntityMode() const;
|
||||
// Should this entity only exist on the master side?
|
||||
virtual bool masterOnly() const;
|
||||
|
||||
virtual String description() const;
|
||||
|
||||
// Gameplay affecting light sources (separate from light sources added during
|
||||
// rendering)
|
||||
virtual List<LightSource> lightSources() const;
|
||||
|
||||
// All damage sources for this frame.
|
||||
virtual List<DamageSource> damageSources() const;
|
||||
|
||||
// Return the damage that would result from being hit by the given damage
|
||||
// source. Will be called on master and slave entities. Culling based on
|
||||
// team damage and self damage will be done outside of this query.
|
||||
virtual Maybe<HitType> queryHit(DamageSource const& source) const;
|
||||
|
||||
// Return the polygonal area in which the entity can be hit. Not used for
|
||||
// actual hit computation, only for determining more precisely where a
|
||||
// hit intersection occurred (e.g. by projectiles)
|
||||
virtual Maybe<PolyF> hitPoly() const;
|
||||
|
||||
// Apply a request to damage this entity. Will only be called on Master
|
||||
// entities. DamageRequest might be adjusted based on protection and other
|
||||
// effects
|
||||
virtual List<DamageNotification> applyDamage(DamageRequest const& damage);
|
||||
|
||||
// Pull any pending damage notifications applied internally, only called on
|
||||
// Master entities.
|
||||
virtual List<DamageNotification> selfDamageNotifications();
|
||||
|
||||
// Called on master entities when a DamageRequest has been generated due to a
|
||||
// DamageSource from this entity being applied to another entity. Will be
|
||||
// called on the *causing* entity of the damage.
|
||||
virtual void hitOther(EntityId targetEntityId, DamageRequest const& damageRequest);
|
||||
|
||||
// Called on master entities when this entity has damaged another entity.
|
||||
// Only called on the *source entity* of the damage, which may be different
|
||||
// than the causing entity.
|
||||
virtual void damagedOther(DamageNotification const& damage);
|
||||
|
||||
// Returning true here indicates that this entity should be removed from the
|
||||
// world, default returns false.
|
||||
virtual bool shouldDestroy() const;
|
||||
// Will be called once before removing the entity from the World on both
|
||||
// master and slave entities.
|
||||
virtual void destroy(RenderCallback* renderCallback);
|
||||
|
||||
// Entities can send other entities potentially remote messages and get
|
||||
// responses back from them, and should implement this to receive and respond
|
||||
// to messages. If the message is NOT handled, should return Nothing,
|
||||
// otherwise should return some Json value.
|
||||
// This will only ever be called on master entities.
|
||||
virtual Maybe<Json> receiveMessage(ConnectionId sendingConnection, String const& message, JsonArray const& args);
|
||||
|
||||
virtual void update(uint64_t currentStep);
|
||||
|
||||
virtual void render(RenderCallback* renderer);
|
||||
|
||||
EntityId entityId() const;
|
||||
|
||||
EntityDamageTeam getTeam() const;
|
||||
|
||||
// Returns true if an entity is initialized in a world, and thus has a valid
|
||||
// world pointer, entity id, and entity mode.
|
||||
bool inWorld() const;
|
||||
|
||||
// Throws an exception if not currently in a world.
|
||||
World* world() const;
|
||||
// Returns nullptr if not currently in a world.
|
||||
World* worldPtr() const;
|
||||
|
||||
// Specifies if the entity is to be saved to disk alongside the sector or
|
||||
// despawned.
|
||||
bool persistent() const;
|
||||
|
||||
// Entity should keep any sector it is in alive. Default implementation
|
||||
// returns false.
|
||||
bool keepAlive() const;
|
||||
|
||||
// If set, then the entity will be discoverable by its unique id and will be
|
||||
// indexed in the stored world. Unique ids must be different across all
|
||||
// entities in a single world.
|
||||
Maybe<String> uniqueId() const;
|
||||
|
||||
// EntityMode will only be set if the entity is initialized, if the entity is
|
||||
// uninitialized then isMaster and isSlave will both return false.
|
||||
Maybe<EntityMode> entityMode() const;
|
||||
bool isMaster() const;
|
||||
bool isSlave() const;
|
||||
|
||||
protected:
|
||||
Entity();
|
||||
|
||||
void setPersistent(bool persistent);
|
||||
void setKeepAlive(bool keepAlive);
|
||||
void setUniqueId(Maybe<String> uniqueId);
|
||||
void setTeam(EntityDamageTeam newTeam);
|
||||
|
||||
private:
|
||||
EntityId m_entityId;
|
||||
Maybe<EntityMode> m_entityMode;
|
||||
bool m_persistent;
|
||||
bool m_keepAlive;
|
||||
Maybe<String> m_uniqueId;
|
||||
World* m_world;
|
||||
EntityDamageTeam m_team;
|
||||
};
|
||||
|
||||
template <typename EntityT>
|
||||
using EntityCallbackOf = function<void(shared_ptr<EntityT> const&)>;
|
||||
|
||||
template <typename EntityT>
|
||||
using EntityFilterOf = function<bool(shared_ptr<EntityT> const&)>;
|
||||
|
||||
typedef EntityCallbackOf<Entity> EntityCallback;
|
||||
typedef EntityFilterOf<Entity> EntityFilter;
|
||||
|
||||
// Filters based first on dynamic casting to the given type, then optionally on
|
||||
// the given derived type filter.
|
||||
template <typename EntityT>
|
||||
EntityFilter entityTypeFilter(function<bool(shared_ptr<EntityT> const&)> filter = {}) {
|
||||
return [filter](EntityPtr const& e) -> bool {
|
||||
if (auto entity = as<EntityT>(e)) {
|
||||
return !filter || filter(entity);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
300
source/game/interfaces/StarFireableItem.cpp
Normal file
300
source/game/interfaces/StarFireableItem.cpp
Normal file
|
@ -0,0 +1,300 @@
|
|||
#include "StarFireableItem.hpp"
|
||||
#include "StarJsonExtra.hpp"
|
||||
#include "StarWorldLuaBindings.hpp"
|
||||
#include "StarConfigLuaBindings.hpp"
|
||||
#include "StarItemLuaBindings.hpp"
|
||||
#include "StarFireableItemLuaBindings.hpp"
|
||||
#include "StarItem.hpp"
|
||||
#include "StarWorld.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
FireableItem::FireableItem()
|
||||
: m_fireTimer(0),
|
||||
m_cooldownTime(10),
|
||||
m_windupTime(0),
|
||||
m_fireWhenReady(false),
|
||||
m_startWhenReady(false),
|
||||
m_cooldown(false),
|
||||
m_alreadyInit(false),
|
||||
m_requireEdgeTrigger(false),
|
||||
m_attemptedFire(false),
|
||||
m_fireOnRelease(false),
|
||||
m_timeFiring(0.0f),
|
||||
m_startTimingFire(false),
|
||||
m_inUse(false),
|
||||
m_walkWhileFiring(false),
|
||||
m_stopWhileFiring(false),
|
||||
m_mode(FireMode::None) {}
|
||||
|
||||
FireableItem::FireableItem(Json const& params) : FireableItem() {
|
||||
setParams(params);
|
||||
m_fireableParams = params;
|
||||
}
|
||||
|
||||
FireableItem::FireableItem(FireableItem const& rhs) : ToolUserItem(rhs), StatusEffectItem(rhs) {
|
||||
m_fireTimer = rhs.m_fireTimer;
|
||||
m_cooldownTime = rhs.m_cooldownTime;
|
||||
m_windupTime = rhs.m_windupTime;
|
||||
m_fireWhenReady = rhs.m_fireWhenReady;
|
||||
m_startWhenReady = rhs.m_startWhenReady;
|
||||
m_cooldown = rhs.m_cooldown;
|
||||
m_alreadyInit = rhs.m_alreadyInit;
|
||||
m_requireEdgeTrigger = rhs.m_requireEdgeTrigger;
|
||||
m_attemptedFire = rhs.m_attemptedFire;
|
||||
m_fireOnRelease = rhs.m_fireOnRelease;
|
||||
m_timeFiring = rhs.m_timeFiring;
|
||||
m_startTimingFire = rhs.m_startTimingFire;
|
||||
m_inUse = rhs.m_inUse;
|
||||
m_walkWhileFiring = rhs.m_walkWhileFiring;
|
||||
m_stopWhileFiring = rhs.m_stopWhileFiring;
|
||||
m_fireableParams = rhs.m_fireableParams;
|
||||
m_handPosition = rhs.m_handPosition;
|
||||
m_mode = rhs.m_mode;
|
||||
}
|
||||
|
||||
void FireableItem::init(ToolUserEntity* owner, ToolHand hand) {
|
||||
ToolUserItem::init(owner, hand);
|
||||
|
||||
m_fireWhenReady = false;
|
||||
m_startWhenReady = false;
|
||||
|
||||
auto scripts = m_fireableParams.opt("scripts").apply(jsonToStringList);
|
||||
if (entityMode() == EntityMode::Master && scripts) {
|
||||
if (!m_scriptComponent) {
|
||||
m_scriptComponent.emplace();
|
||||
m_scriptComponent->setScripts(*scripts);
|
||||
}
|
||||
m_scriptComponent->addCallbacks(
|
||||
"config", LuaBindings::makeConfigCallbacks(bind(&Item::instanceValue, as<Item>(this), _1, _2)));
|
||||
m_scriptComponent->addCallbacks("fireableItem", LuaBindings::makeFireableItemCallbacks(this));
|
||||
m_scriptComponent->addCallbacks("item", LuaBindings::makeItemCallbacks(as<Item>(this)));
|
||||
m_scriptComponent->init(world());
|
||||
}
|
||||
}
|
||||
|
||||
void FireableItem::uninit() {
|
||||
if (m_scriptComponent) {
|
||||
m_scriptComponent->uninit();
|
||||
m_scriptComponent->removeCallbacks("config");
|
||||
m_scriptComponent->removeCallbacks("fireableItem");
|
||||
m_scriptComponent->removeCallbacks("item");
|
||||
}
|
||||
|
||||
ToolUserItem::uninit();
|
||||
}
|
||||
|
||||
void FireableItem::fire(FireMode mode, bool, bool edgeTriggered) {
|
||||
m_attemptedFire = true;
|
||||
if (ready()) {
|
||||
m_inUse = true;
|
||||
m_startTimingFire = true;
|
||||
m_mode = mode;
|
||||
if (!m_requireEdgeTrigger || edgeTriggered) {
|
||||
setFireTimer(windupTime() + cooldownTime());
|
||||
if (!m_fireOnRelease) {
|
||||
m_fireWhenReady = true;
|
||||
m_startWhenReady = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_scriptComponent)
|
||||
m_scriptComponent->invoke("attemptedFire");
|
||||
}
|
||||
|
||||
void FireableItem::endFire(FireMode mode, bool) {
|
||||
if (m_scriptComponent)
|
||||
m_scriptComponent->invoke("endFire");
|
||||
|
||||
m_attemptedFire = false;
|
||||
if (m_fireOnRelease && m_timeFiring) {
|
||||
m_mode = mode;
|
||||
triggerCooldown();
|
||||
fireTriggered();
|
||||
}
|
||||
}
|
||||
|
||||
FireMode FireableItem::fireMode() const {
|
||||
return m_mode;
|
||||
}
|
||||
|
||||
float FireableItem::cooldownTime() const {
|
||||
return m_cooldownTime;
|
||||
}
|
||||
|
||||
void FireableItem::setCooldownTime(float cooldownTime) {
|
||||
m_cooldownTime = cooldownTime;
|
||||
}
|
||||
|
||||
float FireableItem::fireTimer() const {
|
||||
return m_fireTimer;
|
||||
}
|
||||
|
||||
void FireableItem::setFireTimer(float fireTimer) {
|
||||
m_fireTimer = fireTimer;
|
||||
}
|
||||
|
||||
bool FireableItem::ready() const {
|
||||
return fireTimer() <= 0;
|
||||
}
|
||||
|
||||
bool FireableItem::firing() const {
|
||||
return m_timeFiring > 0;
|
||||
}
|
||||
|
||||
bool FireableItem::inUse() const {
|
||||
return m_inUse;
|
||||
}
|
||||
|
||||
bool FireableItem::walkWhileFiring() const {
|
||||
return m_walkWhileFiring;
|
||||
}
|
||||
|
||||
bool FireableItem::stopWhileFiring() const {
|
||||
return m_stopWhileFiring;
|
||||
}
|
||||
|
||||
bool FireableItem::windup() const {
|
||||
if (ready())
|
||||
return false;
|
||||
|
||||
if (m_scriptComponent)
|
||||
m_scriptComponent->invoke("triggerWindup");
|
||||
|
||||
return fireTimer() > cooldownTime();
|
||||
}
|
||||
|
||||
void FireableItem::update(FireMode fireMode, bool shifting, HashSet<MoveControlType> const&) {
|
||||
if (m_scriptComponent)
|
||||
m_scriptComponent->invoke("update", WorldTimestep, FireModeNames.getRight(fireMode), shifting);
|
||||
|
||||
if (m_attemptedFire) {
|
||||
if (m_startTimingFire) {
|
||||
m_timeFiring += WorldTimestep;
|
||||
if (m_scriptComponent)
|
||||
m_scriptComponent->invoke("continueFire", WorldTimestep);
|
||||
}
|
||||
} else {
|
||||
m_timeFiring = 0.0f;
|
||||
m_startTimingFire = false;
|
||||
}
|
||||
m_attemptedFire = false;
|
||||
|
||||
if (entityMode() == EntityMode::Master) {
|
||||
if (fireTimer() > 0.0f) {
|
||||
setFireTimer(fireTimer() - WorldTimestep);
|
||||
if (fireTimer() < 0.0f) {
|
||||
setFireTimer(0.0f);
|
||||
m_inUse = false;
|
||||
}
|
||||
}
|
||||
if (fireTimer() <= 0) {
|
||||
m_cooldown = false;
|
||||
}
|
||||
if (m_startWhenReady) {
|
||||
m_startWhenReady = false;
|
||||
startTriggered();
|
||||
}
|
||||
if (m_fireWhenReady) {
|
||||
if (fireTimer() <= cooldownTime()) {
|
||||
m_fireWhenReady = false;
|
||||
fireTriggered();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FireableItem::triggerCooldown() {
|
||||
setFireTimer(cooldownTime());
|
||||
m_cooldown = true;
|
||||
if (m_scriptComponent)
|
||||
m_scriptComponent->invoke("triggerCooldown");
|
||||
}
|
||||
|
||||
bool FireableItem::coolingDown() const {
|
||||
return m_cooldown;
|
||||
}
|
||||
|
||||
void FireableItem::setCoolingDown(bool coolingdown) {
|
||||
m_cooldown = coolingdown;
|
||||
}
|
||||
|
||||
float FireableItem::timeFiring() const {
|
||||
return m_timeFiring;
|
||||
}
|
||||
|
||||
void FireableItem::setTimeFiring(float timeFiring) {
|
||||
m_timeFiring = timeFiring;
|
||||
}
|
||||
|
||||
Vec2F FireableItem::handPosition() const {
|
||||
return m_handPosition;
|
||||
}
|
||||
|
||||
Vec2F FireableItem::firePosition() const {
|
||||
return Vec2F();
|
||||
}
|
||||
|
||||
Json FireableItem::fireableParam(String const& key) const {
|
||||
return m_fireableParams.get(key);
|
||||
}
|
||||
|
||||
Json FireableItem::fireableParam(String const& key, Json const& defaultVal) const {
|
||||
return m_fireableParams.get(key, defaultVal);
|
||||
}
|
||||
|
||||
bool FireableItem::validAimPos(Vec2F const&) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void FireableItem::setParams(Json const& params) {
|
||||
if (!m_alreadyInit) {
|
||||
// cannot use setWindupTime or setCooldownTime here, because object is not fully constructed
|
||||
m_windupTime = params.getFloat("windupTime", 0.0f);
|
||||
m_cooldownTime = params.getFloat("cooldown", params.getFloat("fireTime", 0.15f) - m_windupTime);
|
||||
if (params.contains("handPosition")) {
|
||||
m_handPosition = jsonToVec2F(params.get("handPosition"));
|
||||
}
|
||||
m_requireEdgeTrigger = params.getBool("edgeTrigger", false);
|
||||
m_fireOnRelease = params.getBool("fireOnRelease", false);
|
||||
m_walkWhileFiring = params.getBool("walkWhileFiring", false);
|
||||
m_stopWhileFiring = params.getBool("stopWhileFiring", false);
|
||||
m_alreadyInit = true;
|
||||
}
|
||||
}
|
||||
|
||||
void FireableItem::setFireableParam(String const& key, Json const& value) {
|
||||
m_fireableParams = m_fireableParams.set(key, value);
|
||||
}
|
||||
|
||||
void FireableItem::startTriggered() {
|
||||
if (m_scriptComponent)
|
||||
m_scriptComponent->invoke("startTriggered");
|
||||
}
|
||||
|
||||
void FireableItem::fireTriggered() {
|
||||
if (m_scriptComponent)
|
||||
m_scriptComponent->invoke("fireTriggered");
|
||||
}
|
||||
|
||||
Vec2F FireableItem::ownerFirePosition() const {
|
||||
if (!initialized())
|
||||
throw StarException("FireableItem uninitialized in ownerFirePosition");
|
||||
|
||||
return owner()->handPosition(hand(), (this->firePosition() - handPosition()) / TilePixels);
|
||||
}
|
||||
|
||||
float FireableItem::windupTime() const {
|
||||
return m_windupTime;
|
||||
}
|
||||
|
||||
void FireableItem::setWindupTime(float time) {
|
||||
m_windupTime = time;
|
||||
}
|
||||
|
||||
List<PersistentStatusEffect> FireableItem::statusEffects() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
91
source/game/interfaces/StarFireableItem.hpp
Normal file
91
source/game/interfaces/StarFireableItem.hpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
#ifndef STAR_FIREABLE_ITEM_HPP
|
||||
#define STAR_FIREABLE_ITEM_HPP
|
||||
|
||||
#include "StarToolUserItem.hpp"
|
||||
#include "StarStatusEffectItem.hpp"
|
||||
#include "StarLuaComponents.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(FireableItem);
|
||||
|
||||
class FireableItem : public virtual ToolUserItem, public virtual StatusEffectItem {
|
||||
public:
|
||||
FireableItem();
|
||||
FireableItem(Json const& params);
|
||||
virtual ~FireableItem() {}
|
||||
|
||||
FireableItem(FireableItem const& fireableItem);
|
||||
|
||||
virtual void fire(FireMode mode, bool shifting, bool edgeTriggered);
|
||||
virtual void endFire(FireMode mode, bool shifting);
|
||||
virtual FireMode fireMode() const;
|
||||
virtual float fireTimer() const;
|
||||
virtual void setFireTimer(float fireTimer);
|
||||
virtual float cooldownTime() const;
|
||||
virtual void setCooldownTime(float cooldownTime);
|
||||
virtual float windupTime() const;
|
||||
virtual void setWindupTime(float time);
|
||||
virtual bool ready() const;
|
||||
virtual bool firing() const;
|
||||
virtual bool inUse() const;
|
||||
virtual bool walkWhileFiring() const;
|
||||
virtual bool stopWhileFiring() const;
|
||||
virtual bool windup() const;
|
||||
virtual void triggerCooldown();
|
||||
virtual bool coolingDown() const;
|
||||
virtual void setCoolingDown(bool coolingdown);
|
||||
virtual float timeFiring() const;
|
||||
virtual void setTimeFiring(float timeFiring);
|
||||
virtual Vec2F firePosition() const;
|
||||
virtual Vec2F handPosition() const;
|
||||
|
||||
virtual void init(ToolUserEntity* owner, ToolHand hand) override;
|
||||
virtual void uninit() override;
|
||||
virtual void update(FireMode fireMode, bool shifting, HashSet<MoveControlType> const& moves) override;
|
||||
|
||||
virtual List<PersistentStatusEffect> statusEffects() const override;
|
||||
|
||||
virtual bool validAimPos(Vec2F const& aimPos);
|
||||
|
||||
Json fireableParam(String const& key) const;
|
||||
Json fireableParam(String const& key, Json const& defaultVal) const;
|
||||
|
||||
protected:
|
||||
void setParams(Json const& params);
|
||||
void setFireableParam(String const& key, Json const& value);
|
||||
virtual void startTriggered();
|
||||
virtual void fireTriggered();
|
||||
|
||||
// firePosition translated by the hand in the owner's space
|
||||
Vec2F ownerFirePosition() const;
|
||||
|
||||
float m_fireTimer;
|
||||
float m_cooldownTime;
|
||||
float m_windupTime;
|
||||
bool m_fireWhenReady;
|
||||
bool m_startWhenReady;
|
||||
bool m_cooldown;
|
||||
bool m_alreadyInit;
|
||||
bool m_requireEdgeTrigger;
|
||||
|
||||
bool m_attemptedFire;
|
||||
bool m_fireOnRelease;
|
||||
float m_timeFiring;
|
||||
bool m_startTimingFire;
|
||||
bool m_inUse;
|
||||
bool m_walkWhileFiring;
|
||||
bool m_stopWhileFiring;
|
||||
|
||||
mutable Maybe<LuaWorldComponent<LuaBaseComponent>> m_scriptComponent;
|
||||
|
||||
Json m_fireableParams;
|
||||
|
||||
Vec2F m_handPosition;
|
||||
|
||||
FireMode m_mode;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
37
source/game/interfaces/StarInspectableEntity.hpp
Normal file
37
source/game/interfaces/StarInspectableEntity.hpp
Normal file
|
@ -0,0 +1,37 @@
|
|||
#ifndef STAR_INSPECTABLE_ENTITY_HPP
|
||||
#define STAR_INSPECTABLE_ENTITY_HPP
|
||||
|
||||
#include "StarTileEntity.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(InspectableEntity);
|
||||
|
||||
class InspectableEntity : public virtual TileEntity {
|
||||
public:
|
||||
// Default implementation returns true
|
||||
virtual bool inspectable() const;
|
||||
|
||||
// If this entity can be entered into the player log, will return the log
|
||||
// identifier.
|
||||
virtual Maybe<String> inspectionLogName() const;
|
||||
|
||||
// Long description to display when inspected, if any
|
||||
virtual Maybe<String> inspectionDescription(String const& species) const;
|
||||
};
|
||||
|
||||
inline bool InspectableEntity::inspectable() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
inline Maybe<String> InspectableEntity::inspectionLogName() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
inline Maybe<String> InspectableEntity::inspectionDescription(String const&) const {
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
25
source/game/interfaces/StarInteractiveEntity.cpp
Normal file
25
source/game/interfaces/StarInteractiveEntity.cpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
#include "StarInteractiveEntity.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
RectF InteractiveEntity::interactiveBoundBox() const {
|
||||
return metaBoundBox();
|
||||
}
|
||||
|
||||
bool InteractiveEntity::isInteractive() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
List<QuestArcDescriptor> InteractiveEntity::offeredQuests() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
StringSet InteractiveEntity::turnInQuests() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
Vec2F InteractiveEntity::questIndicatorPosition() const {
|
||||
return position();
|
||||
}
|
||||
|
||||
}
|
34
source/game/interfaces/StarInteractiveEntity.hpp
Normal file
34
source/game/interfaces/StarInteractiveEntity.hpp
Normal file
|
@ -0,0 +1,34 @@
|
|||
#ifndef STAR_INTERACTIVE_ENTITY_HPP
|
||||
#define STAR_INTERACTIVE_ENTITY_HPP
|
||||
|
||||
#include "StarInteractionTypes.hpp"
|
||||
#include "StarEntity.hpp"
|
||||
#include "StarQuestDescriptor.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(InteractiveEntity);
|
||||
|
||||
class InteractiveEntity : public virtual Entity {
|
||||
public:
|
||||
// Interaction always takes place on the *server*, whether the interactive
|
||||
// entity is master or slave there.
|
||||
virtual InteractAction interact(InteractRequest const& request) = 0;
|
||||
|
||||
// Defaults to metaBoundBox
|
||||
virtual RectF interactiveBoundBox() const;
|
||||
|
||||
// Defaults to true
|
||||
virtual bool isInteractive() const;
|
||||
|
||||
// Defaults to empty
|
||||
virtual List<QuestArcDescriptor> offeredQuests() const;
|
||||
virtual StringSet turnInQuests() const;
|
||||
|
||||
// Defaults to position()
|
||||
virtual Vec2F questIndicatorPosition() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
63
source/game/interfaces/StarLoungingEntities.cpp
Normal file
63
source/game/interfaces/StarLoungingEntities.cpp
Normal file
|
@ -0,0 +1,63 @@
|
|||
#include "StarLoungingEntities.hpp"
|
||||
#include "StarWorld.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
EnumMap<LoungeOrientation> const LoungeOrientationNames{{LoungeOrientation::None, "none"},
|
||||
{LoungeOrientation::Sit, "sit"},
|
||||
{LoungeOrientation::Lay, "lay"},
|
||||
{LoungeOrientation::Stand, "stand"}};
|
||||
|
||||
EnumMap<LoungeControl> const LoungeControlNames{{LoungeControl::Left, "Left"},
|
||||
{LoungeControl::Right, "Right"},
|
||||
{LoungeControl::Down, "Down"},
|
||||
{LoungeControl::Up, "Up"},
|
||||
{LoungeControl::Jump, "Jump"},
|
||||
{LoungeControl::PrimaryFire, "PrimaryFire"},
|
||||
{LoungeControl::AltFire, "AltFire"},
|
||||
{LoungeControl::Special1, "Special1"},
|
||||
{LoungeControl::Special2, "Special2"},
|
||||
{LoungeControl::Special3, "Special3"}};
|
||||
|
||||
EntityAnchorConstPtr LoungeableEntity::anchor(size_t anchorPositionIndex) const {
|
||||
return loungeAnchor(anchorPositionIndex);
|
||||
}
|
||||
|
||||
void LoungeableEntity::loungeControl(size_t, LoungeControl) {}
|
||||
|
||||
void LoungeableEntity::loungeAim(size_t, Vec2F const&) {}
|
||||
|
||||
Set<EntityId> LoungeableEntity::entitiesLoungingIn(size_t positionIndex) const {
|
||||
Set<EntityId> loungingInEntities;
|
||||
for (auto const& p : entitiesLounging()) {
|
||||
if (p.second == positionIndex)
|
||||
loungingInEntities.add(p.first);
|
||||
}
|
||||
return loungingInEntities;
|
||||
}
|
||||
|
||||
Set<pair<EntityId, size_t>> LoungeableEntity::entitiesLounging() const {
|
||||
Set<pair<EntityId, size_t>> loungingInEntities;
|
||||
world()->forEachEntity(metaBoundBox().translated(position()),
|
||||
[&](EntityPtr const& entity) {
|
||||
if (auto lounger = as<LoungingEntity>(entity)) {
|
||||
if (auto anchorStatus = lounger->loungingIn()) {
|
||||
if (anchorStatus->entityId == entityId())
|
||||
loungingInEntities.add({entity->entityId(), anchorStatus->positionIndex});
|
||||
}
|
||||
}
|
||||
});
|
||||
return loungingInEntities;
|
||||
}
|
||||
|
||||
bool LoungingEntity::inConflictingLoungeAnchor() const {
|
||||
if (auto loungeAnchorState = loungingIn()) {
|
||||
if (auto loungeableEntity = world()->get<LoungeableEntity>(loungeAnchorState->entityId)) {
|
||||
auto entitiesLoungingIn = loungeableEntity->entitiesLoungingIn(loungeAnchorState->positionIndex);
|
||||
return entitiesLoungingIn.size() > 1 || !entitiesLoungingIn.contains(entityId());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
71
source/game/interfaces/StarLoungingEntities.hpp
Normal file
71
source/game/interfaces/StarLoungingEntities.hpp
Normal file
|
@ -0,0 +1,71 @@
|
|||
#ifndef STAR_LOUNGING_ENTITIES_HPP
|
||||
#define STAR_LOUNGING_ENTITIES_HPP
|
||||
|
||||
#include "StarDrawable.hpp"
|
||||
#include "StarAnchorableEntity.hpp"
|
||||
#include "StarStatusTypes.hpp"
|
||||
#include "StarEntityRenderingTypes.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(World);
|
||||
|
||||
STAR_STRUCT(LoungeAnchor);
|
||||
STAR_CLASS(LoungeableEntity);
|
||||
STAR_CLASS(LoungingEntity);
|
||||
|
||||
enum class LoungeOrientation { None, Sit, Lay, Stand };
|
||||
extern EnumMap<LoungeOrientation> const LoungeOrientationNames;
|
||||
|
||||
enum class LoungeControl { Left, Right, Down, Up, Jump, PrimaryFire, AltFire, Special1, Special2, Special3 };
|
||||
extern EnumMap<LoungeControl> const LoungeControlNames;
|
||||
|
||||
struct LoungeAnchor : EntityAnchor {
|
||||
LoungeOrientation orientation;
|
||||
EntityRenderLayer loungeRenderLayer;
|
||||
bool controllable;
|
||||
List<PersistentStatusEffect> statusEffects;
|
||||
StringSet effectEmitters;
|
||||
Maybe<String> emote;
|
||||
Maybe<String> dance;
|
||||
Maybe<String> directives;
|
||||
JsonObject armorCosmeticOverrides;
|
||||
Maybe<String> cursorOverride;
|
||||
bool cameraFocus;
|
||||
};
|
||||
|
||||
// Extends an AnchorableEntity to have more specific effects when anchoring,
|
||||
// such as status effects and lounge controls. All LoungeableEntity methods
|
||||
// may be called on both the master and slave.
|
||||
class LoungeableEntity : public AnchorableEntity {
|
||||
public:
|
||||
virtual size_t anchorCount() const override = 0;
|
||||
EntityAnchorConstPtr anchor(size_t anchorPositionIndex) const override;
|
||||
virtual LoungeAnchorConstPtr loungeAnchor(size_t anchorPositionIndex) const = 0;
|
||||
|
||||
// Default does nothing.
|
||||
virtual void loungeControl(size_t anchorPositionIndex, LoungeControl loungeControl);
|
||||
virtual void loungeAim(size_t anchorPositionIndex, Vec2F const& aimPosition);
|
||||
|
||||
// Queries around this entity's metaBoundBox for any LoungingEntities
|
||||
// reporting that they are lounging in this entity, and returns ones that are
|
||||
// lounging in the given position.
|
||||
Set<EntityId> entitiesLoungingIn(size_t anchorPositionIndex) const;
|
||||
// Returns pairs of entity ids, and the position they are lounging in.
|
||||
Set<pair<EntityId, size_t>> entitiesLounging() const;
|
||||
};
|
||||
|
||||
// Any lounging entity should report the entity it is lounging in on both
|
||||
// master and slave, so that lounging entities can cooperate and avoid lounging
|
||||
// in the same spot.
|
||||
class LoungingEntity : public virtual Entity {
|
||||
public:
|
||||
virtual Maybe<EntityAnchorState> loungingIn() const = 0;
|
||||
// Returns true if the entity is in a lounge achor, but other entities are
|
||||
// also reporting being in that lounge anchor.
|
||||
bool inConflictingLoungeAnchor() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
20
source/game/interfaces/StarNametagEntity.hpp
Normal file
20
source/game/interfaces/StarNametagEntity.hpp
Normal file
|
@ -0,0 +1,20 @@
|
|||
#ifndef STAR_NAMETAG_ENTITY_HPP
|
||||
#define STAR_NAMETAG_ENTITY_HPP
|
||||
|
||||
#include "StarEntity.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(NametagEntity);
|
||||
|
||||
class NametagEntity : public virtual Entity {
|
||||
public:
|
||||
virtual String name() const = 0;
|
||||
virtual Maybe<String> statusText() const = 0;
|
||||
virtual bool displayNametag() const = 0;
|
||||
virtual Vec3B nametagColor() const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
18
source/game/interfaces/StarNonRotatedDrawablesItem.hpp
Normal file
18
source/game/interfaces/StarNonRotatedDrawablesItem.hpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef STAR_NON_ROTATED_DRAWABLES_ITEM_HPP
|
||||
#define STAR_NON_ROTATED_DRAWABLES_ITEM_HPP
|
||||
|
||||
#include "StarDrawable.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(NonRotatedDrawablesItem);
|
||||
|
||||
class NonRotatedDrawablesItem {
|
||||
public:
|
||||
virtual ~NonRotatedDrawablesItem() {}
|
||||
virtual List<Drawable> nonRotatedDrawables() const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
85
source/game/interfaces/StarPhysicsEntity.cpp
Normal file
85
source/game/interfaces/StarPhysicsEntity.cpp
Normal file
|
@ -0,0 +1,85 @@
|
|||
#include "StarPhysicsEntity.hpp"
|
||||
#include "StarJsonExtra.hpp"
|
||||
#include "StarDataStreamExtra.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
PhysicsMovingCollision PhysicsMovingCollision::fromJson(Json const& json) {
|
||||
PhysicsMovingCollision pmc;
|
||||
pmc.position = json.opt("position").apply(jsonToVec2F).value();
|
||||
pmc.collision = jsonToPolyF(json.get("collision"));
|
||||
pmc.collisionKind = CollisionKindNames.getLeft(json.getString("collisionKind", "block"));
|
||||
pmc.categoryFilter = jsonToPhysicsCategoryFilter(json);
|
||||
return pmc;
|
||||
}
|
||||
|
||||
RectF PhysicsMovingCollision::boundBox() const {
|
||||
return collision.boundBox().translated(position);
|
||||
}
|
||||
|
||||
void PhysicsMovingCollision::translate(Vec2F const& pos) {
|
||||
position += pos;
|
||||
}
|
||||
|
||||
bool PhysicsMovingCollision::operator==(PhysicsMovingCollision const& rhs) const {
|
||||
return tie(position, collision, collisionKind, categoryFilter) == tie(rhs.position, rhs.collision, rhs.collisionKind, rhs.categoryFilter);
|
||||
}
|
||||
|
||||
DataStream& operator>>(DataStream& ds, PhysicsMovingCollision& pmc) {
|
||||
ds >> pmc.position;
|
||||
ds >> pmc.collision;
|
||||
ds >> pmc.collisionKind;
|
||||
ds >> pmc.categoryFilter;
|
||||
return ds;
|
||||
}
|
||||
|
||||
DataStream& operator<<(DataStream& ds, PhysicsMovingCollision const& pmc) {
|
||||
ds << pmc.position;
|
||||
ds << pmc.collision;
|
||||
ds << pmc.collisionKind;
|
||||
ds << pmc.categoryFilter;
|
||||
return ds;
|
||||
}
|
||||
|
||||
MovingCollisionId::MovingCollisionId() : physicsEntityId(NullEntityId), collisionIndex(0) {}
|
||||
|
||||
MovingCollisionId::MovingCollisionId(EntityId physicsEntityId, size_t collisionIndex)
|
||||
: physicsEntityId(physicsEntityId), collisionIndex(collisionIndex) {}
|
||||
|
||||
bool MovingCollisionId::operator==(MovingCollisionId const& rhs) {
|
||||
return tie(physicsEntityId, collisionIndex) == tie(rhs.physicsEntityId, rhs.collisionIndex);
|
||||
}
|
||||
|
||||
bool MovingCollisionId::valid() const {
|
||||
return physicsEntityId != NullEntityId;
|
||||
}
|
||||
|
||||
MovingCollisionId::operator bool() const {
|
||||
return valid();
|
||||
}
|
||||
|
||||
DataStream& operator>>(DataStream& ds, MovingCollisionId& mci) {
|
||||
ds.read(mci.physicsEntityId);
|
||||
ds.readVlqS(mci.collisionIndex);
|
||||
return ds;
|
||||
}
|
||||
|
||||
DataStream& operator<<(DataStream& ds, MovingCollisionId const& mci) {
|
||||
ds.write(mci.physicsEntityId);
|
||||
ds.writeVlqS(mci.collisionIndex);
|
||||
return ds;
|
||||
}
|
||||
|
||||
List<PhysicsForceRegion> PhysicsEntity::forceRegions() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
size_t PhysicsEntity::movingCollisionCount() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Maybe<PhysicsMovingCollision> PhysicsEntity::movingCollision(size_t) const {
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
61
source/game/interfaces/StarPhysicsEntity.hpp
Normal file
61
source/game/interfaces/StarPhysicsEntity.hpp
Normal file
|
@ -0,0 +1,61 @@
|
|||
#ifndef STAR_PHYSICS_ENTITY_HPP
|
||||
#define STAR_PHYSICS_ENTITY_HPP
|
||||
|
||||
#include "StarPoly.hpp"
|
||||
#include "StarVariant.hpp"
|
||||
#include "StarJson.hpp"
|
||||
#include "StarEntity.hpp"
|
||||
#include "StarForceRegions.hpp"
|
||||
#include "StarCollisionBlock.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(PhysicsEntity);
|
||||
|
||||
struct PhysicsMovingCollision {
|
||||
static PhysicsMovingCollision fromJson(Json const& json);
|
||||
|
||||
RectF boundBox() const;
|
||||
|
||||
void translate(Vec2F const& pos);
|
||||
|
||||
bool operator==(PhysicsMovingCollision const& rhs) const;
|
||||
|
||||
Vec2F position;
|
||||
PolyF collision;
|
||||
CollisionKind collisionKind;
|
||||
PhysicsCategoryFilter categoryFilter;
|
||||
};
|
||||
|
||||
DataStream& operator>>(DataStream& ds, PhysicsMovingCollision& pmc);
|
||||
DataStream& operator<<(DataStream& ds, PhysicsMovingCollision const& pmc);
|
||||
|
||||
struct MovingCollisionId {
|
||||
MovingCollisionId();
|
||||
MovingCollisionId(EntityId physicsEntityId, size_t collisionIndex);
|
||||
|
||||
bool operator==(MovingCollisionId const& rhs);
|
||||
|
||||
// Returns true if the MovingCollisionId is not empty, i.e. default
|
||||
// constructed
|
||||
bool valid() const;
|
||||
operator bool() const;
|
||||
|
||||
EntityId physicsEntityId;
|
||||
size_t collisionIndex;
|
||||
};
|
||||
|
||||
DataStream& operator>>(DataStream& ds, MovingCollisionId& mci);
|
||||
DataStream& operator<<(DataStream& ds, MovingCollisionId const& mci);
|
||||
|
||||
class PhysicsEntity : public virtual Entity {
|
||||
public:
|
||||
virtual List<PhysicsForceRegion> forceRegions() const;
|
||||
|
||||
virtual size_t movingCollisionCount() const;
|
||||
virtual Maybe<PhysicsMovingCollision> movingCollision(size_t positionIndex) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
13
source/game/interfaces/StarPointableItem.cpp
Normal file
13
source/game/interfaces/StarPointableItem.cpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
#include "StarPointableItem.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
float PointableItem::getAngleDir(float angle, Direction) {
|
||||
return getAngle(angle);
|
||||
}
|
||||
|
||||
float PointableItem::getAngle(float angle) {
|
||||
return angle;
|
||||
}
|
||||
|
||||
}
|
22
source/game/interfaces/StarPointableItem.hpp
Normal file
22
source/game/interfaces/StarPointableItem.hpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
#ifndef STAR_POINTABLE_ITEM_HPP
|
||||
#define STAR_POINTABLE_ITEM_HPP
|
||||
|
||||
#include "StarGameTypes.hpp"
|
||||
#include "StarDrawable.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(PointableItem);
|
||||
|
||||
class PointableItem {
|
||||
public:
|
||||
virtual ~PointableItem() {}
|
||||
|
||||
virtual float getAngleDir(float aimAngle, Direction facingDirection);
|
||||
virtual float getAngle(float angle);
|
||||
virtual List<Drawable> drawables() const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
19
source/game/interfaces/StarPortraitEntity.hpp
Normal file
19
source/game/interfaces/StarPortraitEntity.hpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef STAR_PORTRAIT_ENTITY_HPP
|
||||
#define STAR_PORTRAIT_ENTITY_HPP
|
||||
|
||||
#include "StarDrawable.hpp"
|
||||
#include "StarEntity.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(PortraitEntity);
|
||||
|
||||
class PortraitEntity : public virtual Entity {
|
||||
public:
|
||||
virtual List<Drawable> portrait(PortraitMode mode) const = 0;
|
||||
virtual String name() const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
20
source/game/interfaces/StarPreviewTileTool.hpp
Normal file
20
source/game/interfaces/StarPreviewTileTool.hpp
Normal file
|
@ -0,0 +1,20 @@
|
|||
#ifndef STAR_PREVIEW_TILE_TOOL_HPP
|
||||
#define STAR_PREVIEW_TILE_TOOL_HPP
|
||||
|
||||
#include "StarList.hpp"
|
||||
|
||||
STAR_STRUCT(PreviewTile);
|
||||
|
||||
STAR_CLASS(PreviewTileTool);
|
||||
|
||||
namespace Star {
|
||||
|
||||
class PreviewTileTool {
|
||||
public:
|
||||
virtual ~PreviewTileTool() {}
|
||||
virtual List<PreviewTile> preview(bool shifting) const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
19
source/game/interfaces/StarPreviewableItem.hpp
Normal file
19
source/game/interfaces/StarPreviewableItem.hpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef STAR_PREVIEWABLE_ITEM
|
||||
#define STAR_PREVIEWABLE_ITEM
|
||||
|
||||
#include "StarDrawable.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(Player);
|
||||
STAR_CLASS(PreviewableItem);
|
||||
|
||||
class PreviewableItem {
|
||||
public:
|
||||
virtual ~PreviewableItem() {}
|
||||
virtual List<Drawable> preview(PlayerPtr const& viewer = {}) const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
25
source/game/interfaces/StarScriptedEntity.hpp
Normal file
25
source/game/interfaces/StarScriptedEntity.hpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
#ifndef STAR_SCRIPTED_ENTITY_HPP
|
||||
#define STAR_SCRIPTED_ENTITY_HPP
|
||||
|
||||
#include "StarEntity.hpp"
|
||||
#include "StarLua.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(ScriptedEntity);
|
||||
|
||||
// All ScriptedEntity methods should only be called on master entities
|
||||
class ScriptedEntity : public virtual Entity {
|
||||
public:
|
||||
// Call a script function directly with the given arguments, should return
|
||||
// nothing only on failure.
|
||||
virtual Maybe<LuaValue> callScript(String const& func, LuaVariadic<LuaValue> const& args) = 0;
|
||||
|
||||
// Execute the given code directly in the underlying context, return nothing
|
||||
// on failure.
|
||||
virtual Maybe<LuaValue> evalScript(String const& code) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
18
source/game/interfaces/StarStatusEffectEntity.hpp
Normal file
18
source/game/interfaces/StarStatusEffectEntity.hpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef STAR_STATUS_EFFECT_ENTITY_HPP
|
||||
#define STAR_STATUS_EFFECT_ENTITY_HPP
|
||||
|
||||
#include "StarEntity.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(StatusEffectEntity);
|
||||
|
||||
class StatusEffectEntity : public virtual Entity {
|
||||
public:
|
||||
virtual List<PersistentStatusEffect> statusEffects() const = 0;
|
||||
virtual PolyF statusEffectArea() const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
18
source/game/interfaces/StarStatusEffectItem.hpp
Normal file
18
source/game/interfaces/StarStatusEffectItem.hpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef STAR_STATUS_EFFECT_ITEM_HPP
|
||||
#define STAR_STATUS_EFFECT_ITEM_HPP
|
||||
|
||||
#include "StarStatusTypes.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(StatusEffectItem);
|
||||
|
||||
class StatusEffectItem {
|
||||
public:
|
||||
virtual ~StatusEffectItem() {}
|
||||
virtual List<PersistentStatusEffect> statusEffects() const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
53
source/game/interfaces/StarSwingableItem.cpp
Normal file
53
source/game/interfaces/StarSwingableItem.cpp
Normal file
|
@ -0,0 +1,53 @@
|
|||
#include "StarSwingableItem.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
SwingableItem::SwingableItem() {
|
||||
m_swingAimFactor = 0;
|
||||
m_swingStart = 0;
|
||||
m_swingFinish = 0;
|
||||
}
|
||||
|
||||
SwingableItem::SwingableItem(Json const& params) : FireableItem(params) {
|
||||
setParams(params);
|
||||
}
|
||||
|
||||
void SwingableItem::setParams(Json const& params) {
|
||||
m_swingStart = params.getFloat("swingStart", 60) * Constants::pi / 180;
|
||||
m_swingFinish = params.getFloat("swingFinish", -40) * Constants::pi / 180;
|
||||
m_swingAimFactor = params.getFloat("swingAimFactor", 1);
|
||||
m_coolingDownAngle = params.optFloat("coolingDownAngle").apply([](float angle) { return angle * Constants::pi / 180; });
|
||||
FireableItem::setParams(params);
|
||||
}
|
||||
|
||||
float SwingableItem::getAngleDir(float angle, Direction) {
|
||||
return getAngle(angle);
|
||||
}
|
||||
|
||||
float SwingableItem::getAngle(float aimAngle) {
|
||||
if (!ready()) {
|
||||
if (coolingDown()) {
|
||||
if (m_coolingDownAngle)
|
||||
return *m_coolingDownAngle + aimAngle * m_swingAimFactor;
|
||||
else
|
||||
return -Constants::pi / 2;
|
||||
}
|
||||
|
||||
if (m_timeFiring < windupTime())
|
||||
return m_swingStart + (m_swingFinish - m_swingStart) * m_timeFiring / windupTime() + aimAngle * m_swingAimFactor;
|
||||
|
||||
return m_swingFinish + (m_swingStart - m_swingFinish) * fireTimer() / (cooldownTime() + windupTime()) + aimAngle * m_swingAimFactor;
|
||||
}
|
||||
|
||||
return -Constants::pi / 2;
|
||||
}
|
||||
|
||||
float SwingableItem::getItemAngle(float aimAngle) {
|
||||
return getAngle(aimAngle);
|
||||
}
|
||||
|
||||
String SwingableItem::getArmFrame() {
|
||||
return "rotation";
|
||||
}
|
||||
|
||||
}
|
36
source/game/interfaces/StarSwingableItem.hpp
Normal file
36
source/game/interfaces/StarSwingableItem.hpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
#ifndef STAR_SWINGABLE_ITEM_HPP
|
||||
#define STAR_SWINGABLE_ITEM_HPP
|
||||
|
||||
#include "StarFireableItem.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(SwingableItem);
|
||||
|
||||
class SwingableItem : public FireableItem {
|
||||
public:
|
||||
SwingableItem();
|
||||
SwingableItem(Json const& params);
|
||||
virtual ~SwingableItem() {}
|
||||
|
||||
// These can be different
|
||||
// Default implementation is the same though
|
||||
virtual float getAngleDir(float aimAngle, Direction facingDirection);
|
||||
virtual float getAngle(float aimAngle);
|
||||
virtual float getItemAngle(float aimAngle);
|
||||
virtual String getArmFrame();
|
||||
|
||||
virtual List<Drawable> drawables() const = 0;
|
||||
|
||||
void setParams(Json const& params);
|
||||
|
||||
protected:
|
||||
float m_swingStart;
|
||||
float m_swingFinish;
|
||||
float m_swingAimFactor;
|
||||
Maybe<float> m_coolingDownAngle;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
101
source/game/interfaces/StarTileEntity.cpp
Normal file
101
source/game/interfaces/StarTileEntity.cpp
Normal file
|
@ -0,0 +1,101 @@
|
|||
#include "StarTileEntity.hpp"
|
||||
#include "StarWorld.hpp"
|
||||
#include "StarRoot.hpp"
|
||||
#include "StarLiquidsDatabase.hpp"
|
||||
#include "StarDataStreamExtra.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
DataStream& operator<<(DataStream& ds, MaterialSpace const& materialSpace) {
|
||||
ds.write(materialSpace.space);
|
||||
ds.write(materialSpace.material);
|
||||
return ds;
|
||||
}
|
||||
|
||||
DataStream& operator>>(DataStream& ds, MaterialSpace& materialSpace) {
|
||||
ds.read(materialSpace.space);
|
||||
ds.read(materialSpace.material);
|
||||
return ds;
|
||||
}
|
||||
|
||||
TileEntity::TileEntity() {
|
||||
setPersistent(true);
|
||||
}
|
||||
|
||||
Vec2F TileEntity::position() const {
|
||||
return Vec2F(tilePosition());
|
||||
}
|
||||
|
||||
List<Vec2I> TileEntity::spaces() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
List<Vec2I> TileEntity::roots() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
List<MaterialSpace> TileEntity::materialSpaces() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
bool TileEntity::damageTiles(List<Vec2I> const&, Vec2F const&, TileDamage const&) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TileEntity::isInteractive() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<Vec2I> TileEntity::interactiveSpaces() const {
|
||||
return spaces();
|
||||
}
|
||||
|
||||
InteractAction TileEntity::interact(InteractRequest const& request) {
|
||||
_unused(request);
|
||||
return InteractAction();
|
||||
}
|
||||
|
||||
List<QuestArcDescriptor> TileEntity::offeredQuests() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
StringSet TileEntity::turnInQuests() const {
|
||||
return StringSet();
|
||||
}
|
||||
|
||||
Vec2F TileEntity::questIndicatorPosition() const {
|
||||
return position();
|
||||
}
|
||||
|
||||
bool TileEntity::anySpacesOccupied(List<Vec2I> const& spaces) const {
|
||||
Vec2I tp = tilePosition();
|
||||
for (auto pos : spaces) {
|
||||
pos += tp;
|
||||
if (isConnectableMaterial(world()->material(pos, TileLayer::Foreground)))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TileEntity::allSpacesOccupied(List<Vec2I> const& spaces) const {
|
||||
Vec2I tp = tilePosition();
|
||||
for (auto pos : spaces) {
|
||||
pos += tp;
|
||||
if (!isConnectableMaterial(world()->material(pos, TileLayer::Foreground)))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float TileEntity::spacesLiquidFillLevel(List<Vec2I> const& relativeSpaces) const {
|
||||
float total = 0.0f;
|
||||
for (auto pos : relativeSpaces) {
|
||||
pos += tilePosition();
|
||||
total += world()->liquidLevel(pos).level;
|
||||
}
|
||||
return total / relativeSpaces.size();
|
||||
}
|
||||
|
||||
}
|
97
source/game/interfaces/StarTileEntity.hpp
Normal file
97
source/game/interfaces/StarTileEntity.hpp
Normal file
|
@ -0,0 +1,97 @@
|
|||
#ifndef STAR_TILE_ENTITY_HPP
|
||||
#define STAR_TILE_ENTITY_HPP
|
||||
|
||||
#include "StarEntity.hpp"
|
||||
#include "StarTileDamage.hpp"
|
||||
#include "StarInteractiveEntity.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(TileEntity);
|
||||
|
||||
struct MaterialSpace {
|
||||
MaterialSpace();
|
||||
MaterialSpace(Vec2I space, MaterialId material);
|
||||
|
||||
bool operator==(MaterialSpace const& rhs) const;
|
||||
|
||||
Vec2I space;
|
||||
MaterialId material;
|
||||
};
|
||||
|
||||
DataStream& operator<<(DataStream& ds, MaterialSpace const& materialSpace);
|
||||
DataStream& operator>>(DataStream& ds, MaterialSpace& materialSpace);
|
||||
|
||||
// Entities that derive from TileEntity are those that can be placed in the
|
||||
// tile grid, and occupy tile spaces, possibly affecting collision.
|
||||
class TileEntity : public virtual InteractiveEntity {
|
||||
public:
|
||||
TileEntity();
|
||||
|
||||
// position() here is simply the tilePosition (but Vec2F)
|
||||
virtual Vec2F position() const override;
|
||||
|
||||
// The base tile position of this object.
|
||||
virtual Vec2I tilePosition() const = 0;
|
||||
virtual void setTilePosition(Vec2I const& pos) = 0;
|
||||
|
||||
// TileEntities occupy the given spaces in tile space. This is relative to
|
||||
// the current base position, and may include negative positions. A 1x1
|
||||
// object would occupy just (0, 0).
|
||||
virtual List<Vec2I> spaces() const;
|
||||
|
||||
// Blocks that should be marked as "root", so that they are non-destroyable
|
||||
// until this entity is destroyable. Should be outside of spaces(), and
|
||||
// after placement should remain static for the lifetime of the entity.
|
||||
virtual List<Vec2I> roots() const;
|
||||
|
||||
// TileEntities may register some of their occupied spaces with metamaterials
|
||||
// to generate collidable regions
|
||||
virtual List<MaterialSpace> materialSpaces() const;
|
||||
|
||||
// Returns whether the entity was destroyed
|
||||
virtual bool damageTiles(List<Vec2I> const& positions, Vec2F const& sourcePosition, TileDamage const& tileDamage);
|
||||
|
||||
// Forces the tile entity to do an immediate check if it has been invalidly
|
||||
// placed in some way. The tile entity may do this check on its own, but
|
||||
// less often.
|
||||
virtual bool checkBroken() = 0;
|
||||
|
||||
// If the entity accepts interaction through right clicking, by default,
|
||||
// returns false.
|
||||
virtual bool isInteractive() const override;
|
||||
// By default, does nothing. Will be called only on the server.
|
||||
virtual InteractAction interact(InteractRequest const& request) override;
|
||||
// Specific subset spaces that are interactive, by default, just returns
|
||||
// spaces()
|
||||
virtual List<Vec2I> interactiveSpaces() const;
|
||||
|
||||
virtual List<QuestArcDescriptor> offeredQuests() const override;
|
||||
virtual StringSet turnInQuests() const override;
|
||||
virtual Vec2F questIndicatorPosition() const override;
|
||||
|
||||
protected:
|
||||
// Checks whether any of a given spaces list (relative to current tile
|
||||
// position) is occupied by a real material. (Does not include tile
|
||||
// entities).
|
||||
bool anySpacesOccupied(List<Vec2I> const& relativeSpaces) const;
|
||||
|
||||
// Checks that *all* spaces are occupied by a real material.
|
||||
bool allSpacesOccupied(List<Vec2I> const& relativeSpaces) const;
|
||||
|
||||
float spacesLiquidFillLevel(List<Vec2I> const& relativeSpaces) const;
|
||||
};
|
||||
|
||||
inline MaterialSpace::MaterialSpace()
|
||||
: material(NullMaterialId) {}
|
||||
|
||||
inline MaterialSpace::MaterialSpace(Vec2I space, MaterialId material)
|
||||
: space(space), material(material) {}
|
||||
|
||||
inline bool MaterialSpace::operator==(MaterialSpace const& rhs) const {
|
||||
return tie(space, material) == tie(rhs.space, rhs.material);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
104
source/game/interfaces/StarToolUserEntity.hpp
Normal file
104
source/game/interfaces/StarToolUserEntity.hpp
Normal file
|
@ -0,0 +1,104 @@
|
|||
#ifndef STAR_TOOL_USER_ENTITY_HPP
|
||||
#define STAR_TOOL_USER_ENTITY_HPP
|
||||
|
||||
#include "StarEntity.hpp"
|
||||
#include "StarParticle.hpp"
|
||||
#include "StarStatusTypes.hpp"
|
||||
#include "StarInteractionTypes.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(Item);
|
||||
STAR_CLASS(ToolUserEntity);
|
||||
STAR_CLASS(ActorMovementController);
|
||||
STAR_CLASS(StatusController);
|
||||
|
||||
// FIXME: This interface is a complete mess.
|
||||
class ToolUserEntity : public virtual Entity {
|
||||
public:
|
||||
// Translates the given arm position into it's final entity space position
|
||||
// based on the given facing direction, and arm angle, and an offset from the
|
||||
// rotation center of the arm.
|
||||
virtual Vec2F armPosition(ToolHand hand, Direction facingDirection, float armAngle, Vec2F offset = {}) const = 0;
|
||||
// The offset to give to armPosition to get the position of the hand.
|
||||
virtual Vec2F handOffset(ToolHand hand, Direction facingDirection) const = 0;
|
||||
|
||||
// Gets the world position of the current aim point.
|
||||
virtual Vec2F aimPosition() const = 0;
|
||||
|
||||
virtual bool isAdmin() const = 0;
|
||||
virtual Vec4B favoriteColor() const = 0;
|
||||
virtual String species() const = 0;
|
||||
|
||||
virtual void requestEmote(String const& emote) = 0;
|
||||
|
||||
virtual ActorMovementController* movementController() = 0;
|
||||
virtual StatusController* statusController() = 0;
|
||||
|
||||
// FIXME: This is effectively unusable, because since tool user items control
|
||||
// the angle and facing direction of the owner, and this uses the facing
|
||||
// direction and angle as input, the result will always be behind.
|
||||
virtual Vec2F handPosition(ToolHand hand, Vec2F const& handOffset = Vec2F()) const = 0;
|
||||
|
||||
// FIXME: This was used for an Item to get an ItemPtr to itself, which was
|
||||
// super bad and weird, but it COULD be used to get the item in the owner's
|
||||
// other hand, which is LESS bad.
|
||||
virtual ItemPtr handItem(ToolHand hand) const = 0;
|
||||
|
||||
// FIXME: What is the difference between interactRadius (which defines a tool
|
||||
// range) and inToolRange (which also defines a tool range indirectly).
|
||||
// inToolRange() implements based on the center of the tile of the aim
|
||||
// position (NOT the aim position!) but inToolRange(Vec2F) uses the given
|
||||
// position, which is again redundant. Also, what is beamGunRadius and why
|
||||
// is it different than interact radius? Can different tools have a
|
||||
// different interact radius?
|
||||
virtual float interactRadius() const = 0;
|
||||
virtual bool inToolRange() const = 0;
|
||||
virtual bool inToolRange(Vec2F const& position) const = 0;
|
||||
virtual float beamGunRadius() const = 0;
|
||||
|
||||
// FIXME: Too specific to Player, just cast to Player if you have to and do
|
||||
// that, NPCs cannot possibly implement these properly (and do not implement
|
||||
// them at all).
|
||||
virtual void queueUIMessage(String const& message) = 0;
|
||||
virtual void interact(InteractAction const& action) = 0;
|
||||
|
||||
// FIXME: Ditto here, instrumentPlaying() is just an accessor to the songbook
|
||||
// for when the songbook has had a song selected, and the instrument decides
|
||||
// when to cancel music anyway, also instrumentEquipped(String) is a straight
|
||||
// up ridiculous way of notifying the Player that the player itself is
|
||||
// holding an instrument, which it already knows.
|
||||
virtual bool instrumentPlaying() = 0;
|
||||
virtual void instrumentEquipped(String const& instrumentKind) = 0;
|
||||
|
||||
// FIXME: how is this related to the hand position and isn't it already
|
||||
// included in the hand position and why is it necessary?
|
||||
virtual Vec2F armAdjustment() const = 0;
|
||||
|
||||
// FIXME: These were all fine, just need to be fixed because now we have the
|
||||
// movement controller itself and can use that directly
|
||||
virtual Vec2F position() const = 0;
|
||||
virtual Vec2F velocity() const = 0;
|
||||
virtual Direction facingDirection() const = 0;
|
||||
virtual Direction walkingDirection() const = 0;
|
||||
|
||||
// FIXME: Ditto here, except we now have the status controller directly.
|
||||
virtual float powerMultiplier() const = 0;
|
||||
virtual bool fullEnergy() const = 0;
|
||||
virtual float energy() const = 0;
|
||||
virtual bool consumeEnergy(float energy) = 0;
|
||||
virtual bool energyLocked() const = 0;
|
||||
virtual void addEphemeralStatusEffects(List<EphemeralStatusEffect> const& statusEffects) = 0;
|
||||
virtual ActiveUniqueStatusEffectSummary activeUniqueStatusEffectSummary() const = 0;
|
||||
|
||||
// FIXME: This is a dumb way of getting limited animation support
|
||||
virtual void addEffectEmitters(StringSet const& emitters) = 0;
|
||||
virtual void addParticles(List<Particle> const& particles) = 0;
|
||||
virtual void addSound(String const& sound, float volume = 1.0f) = 0;
|
||||
|
||||
virtual void setCameraFocusEntity(Maybe<EntityId> const& cameraFocusEntity) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
59
source/game/interfaces/StarToolUserItem.cpp
Normal file
59
source/game/interfaces/StarToolUserItem.cpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
#include "StarToolUserItem.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
ToolUserItem::ToolUserItem() : m_owner(nullptr) {}
|
||||
|
||||
void ToolUserItem::init(ToolUserEntity* owner, ToolHand hand) {
|
||||
m_owner = owner;
|
||||
m_hand = hand;
|
||||
}
|
||||
|
||||
void ToolUserItem::uninit() {
|
||||
m_owner = nullptr;
|
||||
m_hand = {};
|
||||
}
|
||||
|
||||
void ToolUserItem::update(FireMode, bool, HashSet<MoveControlType> const&) {}
|
||||
|
||||
bool ToolUserItem::initialized() const {
|
||||
return (bool)m_owner;
|
||||
}
|
||||
|
||||
ToolUserEntity* ToolUserItem::owner() const {
|
||||
if (!m_owner)
|
||||
throw ToolUserItemException("Not initialized in ToolUserItem::owner");
|
||||
return m_owner;
|
||||
}
|
||||
|
||||
EntityMode ToolUserItem::entityMode() const {
|
||||
if (!m_owner)
|
||||
throw ToolUserItemException("Not initialized in ToolUserItem::entityMode");
|
||||
return *m_owner->entityMode();
|
||||
}
|
||||
|
||||
ToolHand ToolUserItem::hand() const {
|
||||
if (!m_owner)
|
||||
throw ToolUserItemException("Not initialized in ToolUserItem::hand");
|
||||
return *m_hand;
|
||||
}
|
||||
|
||||
World* ToolUserItem::world() const {
|
||||
if (!m_owner)
|
||||
throw ToolUserItemException("Not initialized in ToolUserItem::world");
|
||||
return m_owner->world();
|
||||
}
|
||||
|
||||
List<DamageSource> ToolUserItem::damageSources() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
List<PolyF> ToolUserItem::shieldPolys() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
List<PhysicsForceRegion> ToolUserItem::forceRegions() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
49
source/game/interfaces/StarToolUserItem.hpp
Normal file
49
source/game/interfaces/StarToolUserItem.hpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
#ifndef STAR_TOOL_USER_ITEM_HPP
|
||||
#define STAR_TOOL_USER_ITEM_HPP
|
||||
|
||||
#include "StarToolUserEntity.hpp"
|
||||
#include "StarPhysicsEntity.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_EXCEPTION(ToolUserItemException, StarException);
|
||||
|
||||
STAR_CLASS(ToolUserItem);
|
||||
|
||||
// FIXME: You know what another name for an item that a tool user uses is? A
|
||||
// Tool. Three words when one will do, rename.
|
||||
class ToolUserItem {
|
||||
public:
|
||||
ToolUserItem();
|
||||
virtual ~ToolUserItem() = default;
|
||||
|
||||
// Owner must be initialized when a ToolUserItem is initialized and
|
||||
// uninitialized before the owner is uninitialized.
|
||||
virtual void init(ToolUserEntity* owner, ToolHand hand);
|
||||
virtual void uninit();
|
||||
|
||||
// Default implementation does nothing
|
||||
virtual void update(FireMode fireMode, bool shifting, HashSet<MoveControlType> const& moves);
|
||||
|
||||
// Default implementations return empty list
|
||||
virtual List<DamageSource> damageSources() const;
|
||||
virtual List<PolyF> shieldPolys() const;
|
||||
virtual List<PhysicsForceRegion> forceRegions() const;
|
||||
|
||||
bool initialized() const;
|
||||
|
||||
// owner, entityMode, hand, and world throw ToolUserException if
|
||||
// initialized() is false
|
||||
ToolUserEntity* owner() const;
|
||||
EntityMode entityMode() const;
|
||||
ToolHand hand() const;
|
||||
World* world() const;
|
||||
|
||||
private:
|
||||
ToolUserEntity* m_owner;
|
||||
Maybe<ToolHand> m_hand;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
20
source/game/interfaces/StarWarpTargetEntity.hpp
Normal file
20
source/game/interfaces/StarWarpTargetEntity.hpp
Normal file
|
@ -0,0 +1,20 @@
|
|||
#ifndef STAR_WARP_TARGET_ENTITY_HPP
|
||||
#define STAR_WARP_TARGET_ENTITY_HPP
|
||||
|
||||
#include "StarWarping.hpp"
|
||||
#include "StarTileEntity.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(WarpTargetEntity);
|
||||
|
||||
class WarpTargetEntity : public virtual TileEntity {
|
||||
public:
|
||||
// Foot position for things teleporting onto this entity, relative to root
|
||||
// position.
|
||||
virtual Vec2F footPosition() const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
28
source/game/interfaces/StarWireEntity.hpp
Normal file
28
source/game/interfaces/StarWireEntity.hpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef STAR_WIRE_ENTITY_HPP
|
||||
#define STAR_WIRE_ENTITY_HPP
|
||||
|
||||
#include "StarWiring.hpp"
|
||||
#include "StarTileEntity.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(WireEntity);
|
||||
|
||||
class WireEntity : public virtual TileEntity {
|
||||
public:
|
||||
virtual ~WireEntity() {}
|
||||
|
||||
virtual size_t nodeCount(WireDirection direction) const = 0;
|
||||
virtual Vec2I nodePosition(WireNode wireNode) const = 0;
|
||||
virtual List<WireConnection> connectionsForNode(WireNode wireNode) const = 0;
|
||||
virtual bool nodeState(WireNode wireNode) const = 0;
|
||||
|
||||
virtual void addNodeConnection(WireNode wireNode, WireConnection nodeConnection) = 0;
|
||||
virtual void removeNodeConnection(WireNode wireNode, WireConnection nodeConnection) = 0;
|
||||
|
||||
virtual void evaluate(WireCoordinator* coordinator) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
153
source/game/interfaces/StarWorld.cpp
Normal file
153
source/game/interfaces/StarWorld.cpp
Normal file
|
@ -0,0 +1,153 @@
|
|||
#include "StarWorld.hpp"
|
||||
#include "StarScriptedEntity.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
bool World::isServer() const {
|
||||
return connection() == ServerConnectionId;
|
||||
}
|
||||
|
||||
bool World::isClient() const {
|
||||
return !isServer();
|
||||
}
|
||||
|
||||
List<EntityPtr> World::entityQuery(RectF const& boundBox, EntityFilter selector) const {
|
||||
List<EntityPtr> list;
|
||||
forEachEntity(boundBox, [&](EntityPtr const& entity) {
|
||||
if (!selector || selector(entity))
|
||||
list.append(entity);
|
||||
});
|
||||
return list;
|
||||
}
|
||||
|
||||
List<EntityPtr> World::entityLineQuery(Vec2F const& begin, Vec2F const& end, EntityFilter selector) const {
|
||||
List<EntityPtr> list;
|
||||
forEachEntityLine(begin, end, [&](EntityPtr const& entity) {
|
||||
if (!selector || selector(entity))
|
||||
list.append(entity);
|
||||
});
|
||||
return list;
|
||||
}
|
||||
|
||||
List<TileEntityPtr> World::entitiesAtTile(Vec2I const& pos, EntityFilter selector) const {
|
||||
List<TileEntityPtr> list;
|
||||
forEachEntityAtTile(pos, [&](TileEntityPtr entity) {
|
||||
if (!selector || selector(entity))
|
||||
list.append(move(entity));
|
||||
});
|
||||
return list;
|
||||
}
|
||||
|
||||
List<Vec2I> World::findEmptyTiles(Vec2I pos, unsigned maxDist, size_t maxAmount, bool excludeEphemeral) const {
|
||||
List<Vec2I> res;
|
||||
if (!tileIsOccupied(pos, TileLayer::Foreground, excludeEphemeral))
|
||||
res.append(pos);
|
||||
|
||||
if (res.size() >= maxAmount)
|
||||
return res;
|
||||
|
||||
// searches manhattan distance counterclockwise from right
|
||||
for (int distance = 1; distance <= (int)maxDist; distance++) {
|
||||
const int totalSpots = 4 * distance;
|
||||
int xDiff = distance;
|
||||
int yDiff = 0;
|
||||
int dx = -1;
|
||||
int dy = 1;
|
||||
for (int i = 0; i < totalSpots; i++) {
|
||||
if (!tileIsOccupied(pos + Vec2I(xDiff, yDiff), TileLayer::Foreground)) {
|
||||
res.append(pos + Vec2I(xDiff, yDiff));
|
||||
if (res.size() >= maxAmount) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
xDiff += dx;
|
||||
yDiff += dy;
|
||||
if (abs(xDiff) == distance)
|
||||
dx *= -1;
|
||||
if (abs(yDiff) == distance)
|
||||
dy *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool World::canModifyTile(Vec2I const& pos, TileModification const& modification, bool allowEntityOverlap) const {
|
||||
return !validTileModifications({{pos, modification}}, allowEntityOverlap).empty();
|
||||
}
|
||||
|
||||
bool World::modifyTile(Vec2I const& pos, TileModification const& modification, bool allowEntityOverlap) {
|
||||
return applyTileModifications({{pos, modification}}, allowEntityOverlap).empty();
|
||||
}
|
||||
|
||||
TileDamageResult World::damageTile(Vec2I const& tilePosition, TileLayer layer, Vec2F const& sourcePosition, TileDamage const& tileDamage, Maybe<EntityId> sourceEntity) {
|
||||
return damageTiles({tilePosition}, layer, sourcePosition, tileDamage, sourceEntity);
|
||||
}
|
||||
|
||||
EntityPtr World::closestEntityInSight(Vec2F const& center, float radius, CollisionSet const& collisionSet, EntityFilter selector) const {
|
||||
return closestEntity(center, radius, [=](EntityPtr const& entity) {
|
||||
return selector(entity) && !lineTileCollision(center, entity->position(), collisionSet);
|
||||
});
|
||||
}
|
||||
|
||||
bool World::pointCollision(Vec2F const& point, CollisionSet const& collisionSet) const {
|
||||
bool collided = false;
|
||||
|
||||
forEachCollisionBlock(RectI::withCenter(Vec2I(point), {3, 3}), [&](CollisionBlock const& block) {
|
||||
if (collided || !isColliding(block.kind, collisionSet))
|
||||
return;
|
||||
|
||||
if (block.poly.contains(point))
|
||||
collided = true;
|
||||
});
|
||||
|
||||
return collided;
|
||||
}
|
||||
|
||||
Maybe<pair<Vec2F, Maybe<Vec2F>>> World::lineCollision(Line2F const& line, CollisionSet const& collisionSet) const {
|
||||
auto geometry = this->geometry();
|
||||
Maybe<PolyF> intersectPoly;
|
||||
Maybe<PolyF::LineIntersectResult> closestIntersection;
|
||||
|
||||
forEachCollisionBlock(RectI::integral(RectF::boundBoxOf(line.min(), line.max()).padded(1)), [&](CollisionBlock const& block) {
|
||||
if (block.poly.isNull() || !isColliding(block.kind, collisionSet))
|
||||
return;
|
||||
|
||||
Vec2F nearMin = geometry.nearestTo(block.poly.center(), line.min());
|
||||
auto intersection = block.poly.lineIntersection(Line2F(nearMin, nearMin + line.diff()));
|
||||
if (intersection && (!closestIntersection || intersection->along < closestIntersection->along)) {
|
||||
intersectPoly = block.poly;
|
||||
closestIntersection = intersection;
|
||||
}
|
||||
});
|
||||
|
||||
if (closestIntersection) {
|
||||
auto point = line.eval(closestIntersection->along);
|
||||
auto normal = closestIntersection->intersectedSide.apply([&](uint64_t side) { return intersectPoly->normal(side); });
|
||||
return make_pair(point, normal);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool World::polyCollision(PolyF const& poly, CollisionSet const& collisionSet) const {
|
||||
auto geometry = this->geometry();
|
||||
Vec2F polyCenter = poly.center();
|
||||
PolyF translatedPoly;
|
||||
bool collided = false;
|
||||
|
||||
forEachCollisionBlock(RectI::integral(poly.boundBox()).padded(1), [&](CollisionBlock const& block) {
|
||||
if (collided || !isColliding(block.kind, collisionSet))
|
||||
return;
|
||||
|
||||
Vec2F center = block.poly.center();
|
||||
Vec2F newCenter = geometry.nearestTo(polyCenter, center);
|
||||
translatedPoly = block.poly;
|
||||
translatedPoly.translate(newCenter - center);
|
||||
if (poly.intersects(translatedPoly))
|
||||
collided = true;
|
||||
});
|
||||
|
||||
return collided;
|
||||
}
|
||||
|
||||
}
|
259
source/game/interfaces/StarWorld.hpp
Normal file
259
source/game/interfaces/StarWorld.hpp
Normal file
|
@ -0,0 +1,259 @@
|
|||
#ifndef STAR_WORLD_HPP
|
||||
#define STAR_WORLD_HPP
|
||||
|
||||
#include "StarTileEntity.hpp"
|
||||
#include "StarInteractionTypes.hpp"
|
||||
#include "StarCollisionBlock.hpp"
|
||||
#include "StarForceRegions.hpp"
|
||||
#include "StarWorldGeometry.hpp"
|
||||
#include "StarTileModification.hpp"
|
||||
#include "StarLuaRoot.hpp"
|
||||
#include "StarRpcPromise.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(World);
|
||||
STAR_CLASS(TileEntity);
|
||||
STAR_CLASS(ScriptedEntity);
|
||||
|
||||
typedef function<void(World*)> WorldAction;
|
||||
|
||||
class World {
|
||||
public:
|
||||
virtual ~World() {}
|
||||
|
||||
// Will remain constant throughout the life of the world.
|
||||
virtual ConnectionId connection() const = 0;
|
||||
virtual WorldGeometry geometry() const = 0;
|
||||
|
||||
// Update frame counter. Returns the frame that is *currently* being
|
||||
// updated, not the *last* frame, so during the first call to update(), this
|
||||
// would return 1
|
||||
virtual uint64_t currentStep() const = 0;
|
||||
|
||||
// All methods that take int parameters wrap around or clamp so that all int
|
||||
// values are valid world indexes.
|
||||
|
||||
virtual MaterialId material(Vec2I const& position, TileLayer layer) const = 0;
|
||||
virtual MaterialHue materialHueShift(Vec2I const& position, TileLayer layer) const = 0;
|
||||
virtual ModId mod(Vec2I const& position, TileLayer layer) const = 0;
|
||||
virtual MaterialHue modHueShift(Vec2I const& position, TileLayer layer) const = 0;
|
||||
virtual MaterialColorVariant colorVariant(Vec2I const& position, TileLayer layer) const = 0;
|
||||
virtual LiquidLevel liquidLevel(Vec2I const& pos) const = 0;
|
||||
virtual LiquidLevel liquidLevel(RectF const& region) const = 0;
|
||||
|
||||
// Tests a tile modification list and returns the ones that are valid.
|
||||
virtual TileModificationList validTileModifications(TileModificationList const& modificationList, bool allowEntityOverlap) const = 0;
|
||||
// Apply a list of tile modifications in the best order to apply as many
|
||||
// possible, and returns the modifications that could not be applied.
|
||||
virtual TileModificationList applyTileModifications(TileModificationList const& modificationList, bool allowEntityOverlap) = 0;
|
||||
|
||||
virtual bool isTileProtected(Vec2I const& pos) const = 0;
|
||||
|
||||
virtual EntityPtr entity(EntityId entityId) const = 0;
|
||||
// *If* the entity is initialized immediately and locally, then will use the
|
||||
// passed in pointer directly and initialize it, and entity will have a valid
|
||||
// id in this world and be ready for use. This is always the case on the
|
||||
// server, but not *always* the case on the client.
|
||||
virtual void addEntity(EntityPtr const& entity) = 0;
|
||||
|
||||
virtual EntityPtr closestEntity(Vec2F const& center, float radius, EntityFilter selector = {}) const = 0;
|
||||
|
||||
virtual void forAllEntities(EntityCallback entityCallback) const = 0;
|
||||
|
||||
// Query here is a fuzzy query based on metaBoundBox
|
||||
virtual void forEachEntity(RectF const& boundBox, EntityCallback entityCallback) const = 0;
|
||||
// Fuzzy metaBoundBox query for intersecting the given line.
|
||||
virtual void forEachEntityLine(Vec2F const& begin, Vec2F const& end, EntityCallback entityCallback) const = 0;
|
||||
// Performs action for all entities that occupies the given tile position
|
||||
// (only entity types laid out in the tile grid).
|
||||
virtual void forEachEntityAtTile(Vec2I const& pos, EntityCallbackOf<TileEntity> entityCallback) const = 0;
|
||||
|
||||
// Like forEachEntity, but stops scanning when entityFilter returns true, and
|
||||
// returns the EntityPtr found, otherwise returns a null pointer.
|
||||
virtual EntityPtr findEntity(RectF const& boundBox, EntityFilter entityFilter) const = 0;
|
||||
virtual EntityPtr findEntityLine(Vec2F const& begin, Vec2F const& end, EntityFilter entityFilter) const = 0;
|
||||
virtual EntityPtr findEntityAtTile(Vec2I const& pos, EntityFilterOf<TileEntity> entityFilter) const = 0;
|
||||
|
||||
// Is the given tile layer and position occupied by an entity or block?
|
||||
virtual bool tileIsOccupied(Vec2I const& pos, TileLayer layer, bool includeEphemeral = false) const = 0;
|
||||
|
||||
// Iterate over the collision block for each tile in the region. Collision
|
||||
// polys for tiles can extend to a maximum of 1 tile outside of the natural
|
||||
// tile bounds.
|
||||
virtual void forEachCollisionBlock(RectI const& region, function<void(CollisionBlock const&)> const& iterator) const = 0;
|
||||
|
||||
// Is there some connectable tile / tile based entity in this position? If
|
||||
// tilesOnly is true, only checks to see whether that tile is a connectable
|
||||
// material.
|
||||
virtual bool isTileConnectable(Vec2I const& pos, TileLayer layer, bool tilesOnly = false) const = 0;
|
||||
|
||||
// Returns whether or not a given point is inside any colliding tile. If
|
||||
// collisionSet is Dynamic or Static, then does not intersect with platforms.
|
||||
virtual bool pointTileCollision(Vec2F const& point, CollisionSet const& collisionSet = DefaultCollisionSet) const = 0;
|
||||
|
||||
// Returns whether line intersects with any colliding tiles.
|
||||
virtual bool lineTileCollision(Vec2F const& begin, Vec2F const& end, CollisionSet const& collisionSet = DefaultCollisionSet) const = 0;
|
||||
virtual Maybe<pair<Vec2F, Vec2I>> lineTileCollisionPoint(Vec2F const& begin, Vec2F const& end, CollisionSet const& collisionSet = DefaultCollisionSet) const = 0;
|
||||
|
||||
// Returns a list of all the collidable tiles along the given line.
|
||||
virtual List<Vec2I> collidingTilesAlongLine(Vec2F const& begin, Vec2F const& end, CollisionSet const& collisionSet = DefaultCollisionSet, int maxSize = -1, bool includeEdges = true) const = 0;
|
||||
|
||||
// Returns whether the given rect contains any colliding tiles.
|
||||
virtual bool rectTileCollision(RectI const& region, CollisionSet const& collisionSet = DefaultCollisionSet) const = 0;
|
||||
|
||||
// Damage multiple tiles, avoiding duplication (objects or plants that occupy
|
||||
// more than one tile
|
||||
// position are only damaged once)
|
||||
virtual TileDamageResult damageTiles(List<Vec2I> const& tilePositions, TileLayer layer, Vec2F const& sourcePosition, TileDamage const& tileDamage, Maybe<EntityId> sourceEntity = {}) = 0;
|
||||
|
||||
virtual InteractiveEntityPtr getInteractiveInRange(Vec2F const& targetPosition, Vec2F const& sourcePosition, float maxRange) const = 0;
|
||||
// Can the target entity be reached from the given position within the given radius?
|
||||
virtual bool canReachEntity(Vec2F const& position, float radius, EntityId targetEntity, bool preferInteractive = true) const = 0;
|
||||
virtual RpcPromise<InteractAction> interact(InteractRequest const& request) = 0;
|
||||
|
||||
virtual float gravity(Vec2F const& pos) const = 0;
|
||||
virtual float windLevel(Vec2F const& pos) const = 0;
|
||||
virtual float lightLevel(Vec2F const& pos) const = 0;
|
||||
virtual bool breathable(Vec2F const& pos) const = 0;
|
||||
virtual float threatLevel() const = 0;
|
||||
virtual StringList environmentStatusEffects(Vec2F const& pos) const = 0;
|
||||
virtual StringList weatherStatusEffects(Vec2F const& pos) const = 0;
|
||||
virtual bool exposedToWeather(Vec2F const& pos) const = 0;
|
||||
virtual bool isUnderground(Vec2F const& pos) const = 0;
|
||||
virtual bool disableDeathDrops() const = 0;
|
||||
virtual List<PhysicsForceRegion> forceRegions() const = 0;
|
||||
|
||||
// Gets / sets world-wide properties
|
||||
virtual Json getProperty(String const& propertyName, Json const& def = {}) const = 0;
|
||||
virtual void setProperty(String const& propertyName, Json const& property) = 0;
|
||||
|
||||
virtual void timer(int stepsDelay, WorldAction worldAction) = 0;
|
||||
virtual double epochTime() const = 0;
|
||||
virtual uint32_t day() const = 0;
|
||||
virtual float dayLength() const = 0;
|
||||
virtual float timeOfDay() const = 0;
|
||||
|
||||
virtual LuaRootPtr luaRoot() = 0;
|
||||
|
||||
// Locate a unique entity, if the target is local, the promise will be
|
||||
// finished before being returned. If the unique entity is not found, the
|
||||
// promise will fail.
|
||||
virtual RpcPromise<Vec2F> findUniqueEntity(String const& uniqueEntityId) = 0;
|
||||
|
||||
// Send a message to a local or remote scripted entity. If the target is
|
||||
// local, the promise will be finished before being returned. Entity id can
|
||||
// either be EntityId or a uniqueId.
|
||||
virtual RpcPromise<Json> sendEntityMessage(Variant<EntityId, String> const& entity, String const& message, JsonArray const& args = {}) = 0;
|
||||
|
||||
// Helper non-virtual methods.
|
||||
|
||||
bool isServer() const;
|
||||
bool isClient() const;
|
||||
|
||||
List<EntityPtr> entityQuery(RectF const& boundBox, EntityFilter selector = {}) const;
|
||||
List<EntityPtr> entityLineQuery(Vec2F const& begin, Vec2F const& end, EntityFilter selector = {}) const;
|
||||
|
||||
List<TileEntityPtr> entitiesAtTile(Vec2I const& pos, EntityFilter filter = EntityFilter()) const;
|
||||
|
||||
// Find tiles near the given point that are not occupied (according to
|
||||
// tileIsOccupied)
|
||||
List<Vec2I> findEmptyTiles(Vec2I pos, unsigned maxDist = 5, size_t maxAmount = 1, bool excludeEphemeral = false) const;
|
||||
|
||||
// Do tile modification that only uses a single tile.
|
||||
bool canModifyTile(Vec2I const& pos, TileModification const& modification, bool allowEntityOverlap) const;
|
||||
bool modifyTile(Vec2I const& pos, TileModification const& modification, bool allowEntityOverlap);
|
||||
|
||||
TileDamageResult damageTile(Vec2I const& tilePosition, TileLayer layer, Vec2F const& sourcePosition, TileDamage const& tileDamage, Maybe<EntityId> sourceEntity = {});
|
||||
|
||||
// Returns closest entity for which lineCollision between the given center
|
||||
// position and the entity position returns false.
|
||||
EntityPtr closestEntityInSight(Vec2F const& center, float radius, CollisionSet const& collisionSet = DefaultCollisionSet, EntityFilter selector = {}) const;
|
||||
|
||||
// Returns whether point collides with any collision geometry.
|
||||
bool pointCollision(Vec2F const& point, CollisionSet const& collisionSet = DefaultCollisionSet) const;
|
||||
|
||||
// Returns first point along line that collides with any collision geometry, along
|
||||
// with the normal of the intersected line, if any.
|
||||
Maybe<pair<Vec2F, Maybe<Vec2F>>> lineCollision(Line2F const& line, CollisionSet const& collisionSet = DefaultCollisionSet) const;
|
||||
|
||||
// Returns whether poly collides with any collision geometry.
|
||||
bool polyCollision(PolyF const& poly, CollisionSet const& collisionSet = DefaultCollisionSet) const;
|
||||
|
||||
// Helper template methods. Only queries entities of the given template
|
||||
// type, and casts them to the appropriate pointer type.
|
||||
|
||||
template <typename EntityT>
|
||||
shared_ptr<EntityT> get(EntityId entityId) const;
|
||||
|
||||
template <typename EntityT>
|
||||
List<shared_ptr<EntityT>> query(RectF const& boundBox, EntityFilterOf<EntityT> selector = {}) const;
|
||||
|
||||
template <typename EntityT>
|
||||
shared_ptr<EntityT> closest(Vec2F const& center, float radius, EntityFilterOf<EntityT> selector = {}) const;
|
||||
|
||||
template <typename EntityT>
|
||||
shared_ptr<EntityT> closestInSight(Vec2F const& center, float radius, CollisionSet const& collisionSet, EntityFilterOf<EntityT> selector = {}) const;
|
||||
|
||||
template <typename EntityT>
|
||||
List<shared_ptr<EntityT>> lineQuery(Vec2F const& begin, Vec2F const& end, EntityFilterOf<EntityT> selector = {}) const;
|
||||
|
||||
template <typename EntityT>
|
||||
List<shared_ptr<EntityT>> atTile(Vec2I const& pos) const;
|
||||
};
|
||||
|
||||
template <typename EntityT>
|
||||
shared_ptr<EntityT> World::get(EntityId entityId) const {
|
||||
return as<EntityT>(entity(entityId));
|
||||
}
|
||||
|
||||
template <typename EntityT>
|
||||
List<shared_ptr<EntityT>> World::query(RectF const& boundBox, EntityFilterOf<EntityT> selector) const {
|
||||
List<shared_ptr<EntityT>> list;
|
||||
forEachEntity(boundBox, [&](EntityPtr const& entity) {
|
||||
if (auto e = as<EntityT>(entity)) {
|
||||
if (!selector || selector(e))
|
||||
list.append(move(e));
|
||||
}
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
template <typename EntityT>
|
||||
shared_ptr<EntityT> World::closest(Vec2F const& center, float radius, EntityFilterOf<EntityT> selector) const {
|
||||
return as<EntityT>(closestEntity(center, radius, entityTypeFilter<EntityT>(selector)));
|
||||
}
|
||||
|
||||
template <typename EntityT>
|
||||
shared_ptr<EntityT> World::closestInSight(
|
||||
Vec2F const& center, float radius, CollisionSet const& collisionSet, EntityFilterOf<EntityT> selector) const {
|
||||
return as<EntityT>(closestEntityInSight(center, radius, collisionSet, entityTypeFilter<EntityT>(selector)));
|
||||
}
|
||||
|
||||
template <typename EntityT>
|
||||
List<shared_ptr<EntityT>> World::lineQuery(
|
||||
Vec2F const& begin, Vec2F const& end, EntityFilterOf<EntityT> selector) const {
|
||||
List<shared_ptr<EntityT>> list;
|
||||
forEachEntityLine(begin, end, [&](EntityPtr entity) {
|
||||
if (auto e = as<EntityT>(move(entity))) {
|
||||
if (!selector || selector(e))
|
||||
list.append(move(e));
|
||||
}
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
template <typename EntityT>
|
||||
List<shared_ptr<EntityT>> World::atTile(Vec2I const& pos) const {
|
||||
List<shared_ptr<EntityT>> list;
|
||||
forEachEntityAtTile(pos, [&](TileEntityPtr const& entity) {
|
||||
if (auto e = as<EntityT>(entity))
|
||||
list.append(move(e));
|
||||
});
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue