Add collision cycling to Material items
This commit is contained in:
parent
ec4f70340e
commit
d65bc3cc8d
@ -2,7 +2,8 @@
|
||||
"opensb": {
|
||||
"groups": {
|
||||
"camera": { "name": "Camera" },
|
||||
"voice": { "name": "Voice" }
|
||||
"voice": { "name": "Voice" },
|
||||
"building": { "name": "Building" }
|
||||
},
|
||||
"name": "Open^#ebd74a;Starbound",
|
||||
"binds": {
|
||||
@ -11,7 +12,7 @@
|
||||
"type": "key",
|
||||
"value": "="
|
||||
}],
|
||||
"group" : "camera",
|
||||
"group": "camera",
|
||||
"name": "Zoom In"
|
||||
},
|
||||
"zoomOut": {
|
||||
@ -19,13 +20,18 @@
|
||||
"type": "key",
|
||||
"value": "-"
|
||||
}],
|
||||
"group" : "camera",
|
||||
"group": "camera",
|
||||
"name": "Zoom Out"
|
||||
},
|
||||
"pushToTalk": {
|
||||
"default": [],
|
||||
"group" : "voice",
|
||||
"group": "voice",
|
||||
"name": "Push To Talk"
|
||||
},
|
||||
"materialCycleCollision": {
|
||||
"default": [],
|
||||
"group": "building",
|
||||
"name": "Cycle Material Collision"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
BIN
assets/opensb/interface/building/collisionblock.png
Normal file
BIN
assets/opensb/interface/building/collisionblock.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 219 B |
BIN
assets/opensb/interface/building/collisionempty.png
Normal file
BIN
assets/opensb/interface/building/collisionempty.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 176 B |
BIN
assets/opensb/interface/building/collisionplatform.png
Normal file
BIN
assets/opensb/interface/building/collisionplatform.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 178 B |
BIN
assets/opensb/sfx/tools/cyclematcollision.ogg
Normal file
BIN
assets/opensb/sfx/tools/cyclematcollision.ogg
Normal file
Binary file not shown.
@ -196,6 +196,7 @@ SET (star_game_HEADERS
|
||||
interfaces/StarPointableItem.hpp
|
||||
interfaces/StarPortraitEntity.hpp
|
||||
interfaces/StarPreviewableItem.hpp
|
||||
interfaces/StarRenderableItem.hpp
|
||||
interfaces/StarScriptedEntity.hpp
|
||||
interfaces/StarStatusEffectEntity.hpp
|
||||
interfaces/StarStatusEffectItem.hpp
|
||||
|
@ -22,7 +22,7 @@ enum class TileCollisionOverride : uint8_t {
|
||||
None,
|
||||
Empty,
|
||||
Platform,
|
||||
Dynamic
|
||||
Block
|
||||
};
|
||||
|
||||
inline CollisionKind collisionKindFromOverride(TileCollisionOverride const& over) {
|
||||
@ -31,8 +31,8 @@ inline CollisionKind collisionKindFromOverride(TileCollisionOverride const& over
|
||||
return CollisionKind::None;
|
||||
case TileCollisionOverride::Platform:
|
||||
return CollisionKind::Platform;
|
||||
case TileCollisionOverride::Dynamic:
|
||||
return CollisionKind::Dynamic;
|
||||
case TileCollisionOverride::Block:
|
||||
return CollisionKind::Block;
|
||||
default:
|
||||
return CollisionKind::Null;
|
||||
}
|
||||
|
@ -535,21 +535,16 @@ void ToolUser::render(RenderCallback* renderCallback, bool inToolRange, bool shi
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: Why isn't material item a PreviewTileTool, why is inToolRange
|
||||
// passed in again, what is the difference here between the owner's tool
|
||||
// range, can't MaterialItem figure this out?
|
||||
if (inToolRange) {
|
||||
if (auto materialItem = as<MaterialItem>(m_primaryHandItem.get()))
|
||||
renderCallback->addTilePreviews(materialItem->preview(shifting));
|
||||
else if (auto liquidItem = as<LiquidItem>(m_primaryHandItem.get()))
|
||||
renderCallback->addTilePreviews(liquidItem->preview(shifting));
|
||||
}
|
||||
|
||||
if (auto pri = as<PreviewTileTool>(m_primaryHandItem.get()))
|
||||
renderCallback->addTilePreviews(pri->preview(shifting));
|
||||
else if (auto alt = as<PreviewTileTool>(m_altHandItem.get()))
|
||||
renderCallback->addTilePreviews(alt->preview(shifting));
|
||||
|
||||
if (auto ren = as<RenderableItem>(m_primaryHandItem.get()))
|
||||
ren->render(renderCallback, renderLayer);
|
||||
if (auto ren = as<RenderableItem>(m_altHandItem.get()))
|
||||
ren->render(renderCallback, renderLayer);
|
||||
|
||||
for (auto item : {m_primaryHandItem.get(), m_altHandItem.get()}) {
|
||||
if (auto activeItem = as<ActiveItem>(item)) {
|
||||
for (auto drawablePair : activeItem->entityDrawables())
|
||||
|
19
source/game/interfaces/StarRenderableItem.hpp
Normal file
19
source/game/interfaces/StarRenderableItem.hpp
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef STAR_RENDERABLE_ITEM_HPP
|
||||
#define STAR_RENDERABLE_ITEM_HPP
|
||||
|
||||
#include "StarEntityRendering.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(RenderableItem);
|
||||
|
||||
class RenderableItem {
|
||||
public:
|
||||
virtual ~RenderableItem() {}
|
||||
|
||||
virtual void render(RenderCallback* renderCallback, EntityRenderLayer renderLayer) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -7,6 +7,7 @@
|
||||
#include "StarWorld.hpp"
|
||||
#include "StarWorldClient.hpp"
|
||||
#include "StarWorldTemplate.hpp"
|
||||
#include "StarInput.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
@ -47,6 +48,8 @@ MaterialItem::MaterialItem(Json const& config, String const& directory, Json con
|
||||
m_placeSounds.append(materialDatabase->defaultFootstepSound());
|
||||
}
|
||||
m_shifting = false;
|
||||
m_lastTileAreaRadiusCache = 0.0f;
|
||||
m_collisionOverride = TileCollisionOverride::None;
|
||||
}
|
||||
|
||||
ItemPtr MaterialItem::clone() const {
|
||||
@ -56,7 +59,7 @@ ItemPtr MaterialItem::clone() const {
|
||||
void MaterialItem::init(ToolUserEntity* owner, ToolHand hand) {
|
||||
FireableItem::init(owner, hand);
|
||||
BeamItem::init(owner, hand);
|
||||
owner->addSound(Random::randValueFrom(m_placeSounds), 0.8f, 2.0f);
|
||||
owner->addSound(Random::randValueFrom(m_placeSounds), 1.0f, 2.0f);
|
||||
}
|
||||
|
||||
void MaterialItem::uninit() {
|
||||
@ -71,6 +74,44 @@ void MaterialItem::update(float dt, FireMode fireMode, bool shifting, HashSet<Mo
|
||||
else
|
||||
setEnd(BeamItem::EndType::TileGroup);
|
||||
m_shifting = shifting;
|
||||
|
||||
if (auto presses = Input::singleton().bindDown("opensb", "materialCycleCollision")) {
|
||||
CollisionKind baseKind = Root::singleton().materialDatabase()->materialCollisionKind(m_material);
|
||||
for (size_t i = 0; i != *presses; ++i) {
|
||||
constexpr auto limit = (uint8_t)TileCollisionOverride::Block + 1;
|
||||
while (true) {
|
||||
m_collisionOverride = (TileCollisionOverride)(((uint8_t)m_collisionOverride + 1) % limit);
|
||||
if (collisionKindFromOverride(m_collisionOverride) != baseKind)
|
||||
break;
|
||||
}
|
||||
}
|
||||
owner()->addSound("/sfx/tools/cyclematcollision.ogg", 1.0f, Random::randf(0.9f, 1.1f));
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialItem::render(RenderCallback* renderCallback, EntityRenderLayer renderLayer) {
|
||||
if (m_collisionOverride != TileCollisionOverride::None) {
|
||||
float pulseLevel = 1.f - 0.3f * 0.5f * ((float)sin(2 * Constants::pi * 4.0 * Time::monotonicTime()) + 1.f);
|
||||
Color color = Color::rgba(owner()->favoriteColor()).mix(Color::White);
|
||||
color.setAlphaF(color.alphaF() * pulseLevel * 0.95f);
|
||||
auto addIndicator = [&](String const& path) {
|
||||
Vec2F basePosition = Vec2F(0.5f, 0.5f);
|
||||
auto indicator = Drawable::makeImage(path, 1.0f / TilePixels, true, basePosition);
|
||||
indicator.fullbright = true;
|
||||
indicator.color = color;
|
||||
for (auto& tilePos : tileArea(calcRadius(m_shifting))) {
|
||||
indicator.position = basePosition + Vec2F(tilePos);
|
||||
renderCallback->addDrawable(indicator, RenderLayerForegroundTile);
|
||||
}
|
||||
};
|
||||
|
||||
if (m_collisionOverride == TileCollisionOverride::Empty)
|
||||
addIndicator("/interface/building/collisionempty.png");
|
||||
else if (m_collisionOverride == TileCollisionOverride::Platform)
|
||||
addIndicator("/interface/building/collisionplatform.png");
|
||||
else if (m_collisionOverride == TileCollisionOverride::Block)
|
||||
addIndicator("/interface/building/collisionblock.png");
|
||||
}
|
||||
}
|
||||
|
||||
List<Drawable> MaterialItem::nonRotatedDrawables() const {
|
||||
@ -84,18 +125,12 @@ void MaterialItem::fire(FireMode mode, bool shifting, bool edgeTriggered) {
|
||||
auto layer = (mode == FireMode::Primary || !twoHanded() ? TileLayer::Foreground : TileLayer::Background);
|
||||
TileModificationList modifications;
|
||||
|
||||
float radius;
|
||||
|
||||
if (!shifting)
|
||||
radius = m_blockRadius;
|
||||
else
|
||||
radius = m_altBlockRadius;
|
||||
|
||||
if (!multiplaceEnabled())
|
||||
radius = 1;
|
||||
float radius = calcRadius(shifting);
|
||||
|
||||
auto geo = world()->geometry();
|
||||
auto aimPosition = owner()->aimPosition();
|
||||
auto& tilePositions = tileArea(radius);
|
||||
|
||||
if (!m_lastAimPosition)
|
||||
m_lastAimPosition = aimPosition;
|
||||
|
||||
@ -106,7 +141,7 @@ void MaterialItem::fire(FireMode mode, bool shifting, bool edgeTriggered) {
|
||||
float magnitude = diff.magnitude();
|
||||
float limit = max(4.f, 64.f / radius);
|
||||
if (magnitude > limit) {
|
||||
m_lastAimPosition = aimPosition + diff.normalized() * limit;
|
||||
diff = diff.normalized() * limit;
|
||||
magnitude = limit;
|
||||
}
|
||||
|
||||
@ -116,8 +151,8 @@ void MaterialItem::fire(FireMode mode, bool shifting, bool edgeTriggered) {
|
||||
size_t total = 0;
|
||||
for (int i = 0; i != steps; ++i) {
|
||||
auto placementOrigin = aimPosition + diff * (1.0f - ((float)i / steps));
|
||||
for (Vec2I pos : tileAreaBrush(radius, placementOrigin, true))
|
||||
modifications.append({ pos, PlaceMaterial{layer, materialId(), placementHueShift(pos)} });
|
||||
for (Vec2I& pos : tilePositions)
|
||||
modifications.append({ pos, PlaceMaterial{layer, materialId(), placementHueShift(pos), m_collisionOverride} });
|
||||
|
||||
// Make sure not to make any more modifications than we have consumables.
|
||||
if (modifications.size() > count())
|
||||
@ -147,6 +182,22 @@ MaterialId MaterialItem::materialId() const {
|
||||
return m_material;
|
||||
}
|
||||
|
||||
float MaterialItem::calcRadius(bool shifting) const {
|
||||
if (!multiplaceEnabled())
|
||||
return 1;
|
||||
else
|
||||
return !shifting ? m_blockRadius : m_altBlockRadius;
|
||||
}
|
||||
|
||||
List<Vec2I>& MaterialItem::tileArea(float radius) const {
|
||||
auto aimPosition = owner()->aimPosition();
|
||||
if (!m_lastAimPosition || *m_lastAimPosition != aimPosition || m_lastTileAreaRadiusCache != radius) {
|
||||
m_lastTileAreaRadiusCache = radius;
|
||||
m_tileAreasCache = tileAreaBrush(radius, owner()->aimPosition(), true);
|
||||
}
|
||||
return m_tileAreasCache;
|
||||
}
|
||||
|
||||
MaterialHue MaterialItem::materialHueShift() const {
|
||||
return m_materialHueShift;
|
||||
}
|
||||
@ -155,16 +206,9 @@ bool MaterialItem::canPlace(bool shifting) const {
|
||||
if (initialized()) {
|
||||
MaterialId material = materialId();
|
||||
|
||||
float radius;
|
||||
if (!shifting)
|
||||
radius = m_blockRadius;
|
||||
else
|
||||
radius = m_altBlockRadius;
|
||||
float radius = calcRadius(shifting);
|
||||
|
||||
if (!multiplaceEnabled())
|
||||
radius = 1;
|
||||
|
||||
for (auto pos : tileAreaBrush(radius, owner()->aimPosition(), true)) {
|
||||
for (auto& pos : tileArea(radius)) {
|
||||
MaterialHue hueShift = placementHueShift(pos);
|
||||
if (world()->canModifyTile(pos, PlaceMaterial{TileLayer::Foreground, material, hueShift}, false)
|
||||
|| world()->canModifyTile(pos, PlaceMaterial{TileLayer::Background, material, hueShift}, false))
|
||||
@ -178,6 +222,18 @@ bool MaterialItem::multiplaceEnabled() const {
|
||||
return m_multiplace && count() > 1;
|
||||
}
|
||||
|
||||
float& MaterialItem::blockRadius() {
|
||||
return m_blockRadius;
|
||||
}
|
||||
|
||||
float& MaterialItem::altBlockRadius() {
|
||||
return m_altBlockRadius;
|
||||
}
|
||||
|
||||
TileCollisionOverride& MaterialItem::collisionOverride() {
|
||||
return m_collisionOverride;
|
||||
}
|
||||
|
||||
List<PreviewTile> MaterialItem::preview(bool shifting) const {
|
||||
List<PreviewTile> result;
|
||||
if (initialized()) {
|
||||
@ -187,19 +243,8 @@ List<PreviewTile> MaterialItem::preview(bool shifting) const {
|
||||
auto material = materialId();
|
||||
auto color = DefaultMaterialColorVariant;
|
||||
|
||||
float radius;
|
||||
|
||||
if (!shifting)
|
||||
radius = m_blockRadius;
|
||||
else
|
||||
radius = m_altBlockRadius;
|
||||
|
||||
if (!multiplaceEnabled())
|
||||
radius = 1;
|
||||
|
||||
size_t c = 0;
|
||||
|
||||
for (auto pos : tileAreaBrush(radius, owner()->aimPosition(), true)) {
|
||||
for (auto& pos : tileArea(calcRadius(shifting))) {
|
||||
MaterialHue hueShift = placementHueShift(pos);
|
||||
if (c >= count())
|
||||
break;
|
||||
|
@ -5,12 +5,15 @@
|
||||
#include "StarFireableItem.hpp"
|
||||
#include "StarBeamItem.hpp"
|
||||
#include "StarEntityRendering.hpp"
|
||||
#include "StarPreviewTileTool.hpp"
|
||||
#include "StarRenderableItem.hpp"
|
||||
#include "StarCollisionBlock.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(MaterialItem);
|
||||
|
||||
class MaterialItem : public Item, public FireableItem, public BeamItem {
|
||||
class MaterialItem : public Item, public FireableItem, public PreviewTileTool, public RenderableItem, public BeamItem {
|
||||
public:
|
||||
MaterialItem(Json const& config, String const& directory, Json const& settings);
|
||||
virtual ~MaterialItem() {}
|
||||
@ -20,6 +23,7 @@ public:
|
||||
void init(ToolUserEntity* owner, ToolHand hand) override;
|
||||
void uninit() override;
|
||||
void update(float dt, FireMode fireMode, bool shifting, HashSet<MoveControlType> const& moves) override;
|
||||
void render(RenderCallback* renderCallback, EntityRenderLayer renderLayer) override;
|
||||
|
||||
List<Drawable> nonRotatedDrawables() const override;
|
||||
|
||||
@ -32,10 +36,14 @@ public:
|
||||
bool canPlace(bool shifting) const;
|
||||
bool multiplaceEnabled() const;
|
||||
|
||||
// FIXME: Why isn't this a PreviewTileTool then??
|
||||
List<PreviewTile> preview(bool shifting) const;
|
||||
float& blockRadius();
|
||||
float& altBlockRadius();
|
||||
TileCollisionOverride& collisionOverride();
|
||||
|
||||
List<PreviewTile> preview(bool shifting) const override;
|
||||
private:
|
||||
float calcRadius(bool shifting) const;
|
||||
List<Vec2I>& tileArea(float radius) const;
|
||||
MaterialHue placementHueShift(Vec2I const& position) const;
|
||||
|
||||
MaterialId m_material;
|
||||
@ -47,6 +55,10 @@ private:
|
||||
bool m_multiplace;
|
||||
StringList m_placeSounds;
|
||||
Maybe<Vec2F> m_lastAimPosition;
|
||||
TileCollisionOverride m_collisionOverride;
|
||||
|
||||
mutable float m_lastTileAreaRadiusCache;
|
||||
mutable List<Vec2I> m_tileAreasCache;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -1949,8 +1949,8 @@ namespace LuaBindings {
|
||||
layerName = layerName.substr(0, split);
|
||||
if (overrideName == "empty" || overrideName == "none")
|
||||
placeMaterial.collisionOverride = TileCollisionOverride::Empty;
|
||||
else if (overrideName == "dynamic" || overrideName == "block")
|
||||
placeMaterial.collisionOverride = TileCollisionOverride::Dynamic;
|
||||
else if (overrideName == "block")
|
||||
placeMaterial.collisionOverride = TileCollisionOverride::Block;
|
||||
else if (overrideName == "platform")
|
||||
placeMaterial.collisionOverride = TileCollisionOverride::Platform;
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user