Item Drop Improvements
This commit is contained in:
parent
90267c6105
commit
c11d20894b
8
assets/opensb/itemdrop.config.patch
Normal file
8
assets/opensb/itemdrop.config.patch
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"directives" : "",
|
||||||
|
"pickupDistance" : 0.5,
|
||||||
|
"afterTakenLife" : 2.5,
|
||||||
|
"overheadTime" : 0.5,
|
||||||
|
"overheadApproach" : 2000,
|
||||||
|
"overheadRandomizedDistance" : 0.25
|
||||||
|
}
|
BIN
assets/opensb/sfx/interface/item_pickup.ogg
Normal file
BIN
assets/opensb/sfx/interface/item_pickup.ogg
Normal file
Binary file not shown.
@ -7,6 +7,7 @@
|
|||||||
#include "StarEntityRendering.hpp"
|
#include "StarEntityRendering.hpp"
|
||||||
#include "StarWorld.hpp"
|
#include "StarWorld.hpp"
|
||||||
#include "StarDataStreamExtra.hpp"
|
#include "StarDataStreamExtra.hpp"
|
||||||
|
#include "StarPlayer.hpp"
|
||||||
|
|
||||||
namespace Star {
|
namespace Star {
|
||||||
|
|
||||||
@ -179,13 +180,25 @@ RectF ItemDrop::collisionArea() const {
|
|||||||
void ItemDrop::update(float dt, uint64_t) {
|
void ItemDrop::update(float dt, uint64_t) {
|
||||||
if (isMaster()) {
|
if (isMaster()) {
|
||||||
if (m_owningEntity.get() != NullEntityId) {
|
if (m_owningEntity.get() != NullEntityId) {
|
||||||
auto owningEntity = world()->entity(m_owningEntity.get());
|
if (auto owningEntity = world()->entity(m_owningEntity.get())) {
|
||||||
if (owningEntity) {
|
|
||||||
Vec2F position = m_movementController.position();
|
Vec2F position = m_movementController.position();
|
||||||
Vec2F diff = world()->geometry().diff(owningEntity->position(), position);
|
bool overhead = m_dropAge.elapsedTime() < m_overheadTime;
|
||||||
|
Vec2F targetPosition = owningEntity->position();
|
||||||
|
if (overhead) {
|
||||||
|
targetPosition += m_overheadOffset;
|
||||||
|
auto rect = owningEntity->collisionArea();
|
||||||
|
if (!rect.isNull())
|
||||||
|
targetPosition[1] += rect.yMax() + 1.5;
|
||||||
|
else
|
||||||
|
targetPosition[1] += 1.5f;
|
||||||
|
}
|
||||||
|
Vec2F diff = world()->geometry().diff(targetPosition, position);
|
||||||
float magnitude = diff.magnitude();
|
float magnitude = diff.magnitude();
|
||||||
m_movementController.approachVelocity(diff.normalized() * m_config.getFloat("velocity"), m_config.getFloat("velocityApproach"));
|
Vec2F velocity = diff.normalized() * m_velocity * min(1.0f, magnitude);
|
||||||
if (magnitude < m_config.getFloat("pickupDistance"))
|
if (auto playerEntity = as<Player>(owningEntity))
|
||||||
|
velocity += playerEntity->velocity();
|
||||||
|
m_movementController.approachVelocity(velocity, overhead ? m_overheadApproach : m_velocityApproach);
|
||||||
|
if (!overhead && magnitude < m_pickupDistance)
|
||||||
m_mode.set(Mode::Dead);
|
m_mode.set(Mode::Dead);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -199,12 +212,12 @@ void ItemDrop::update(float dt, uint64_t) {
|
|||||||
m_movementController.applyParameters(parameters);
|
m_movementController.applyParameters(parameters);
|
||||||
} else {
|
} else {
|
||||||
// Rarely, check for other drops near us and combine with them if possible.
|
// Rarely, check for other drops near us and combine with them if possible.
|
||||||
if (canTake() && m_mode.get() == Mode::Available && Random::randf() < m_config.getFloat("combineChance")) {
|
if (canTake() && m_mode.get() == Mode::Available && Random::randf() < m_combineChance) {
|
||||||
world()->findEntity(RectF::withCenter(position(), Vec2F::filled(m_config.getFloat("combineRadius"))), [&](EntityPtr const& entity) {
|
world()->findEntity(RectF::withCenter(position(), Vec2F::filled(m_combineRadius)), [&](EntityPtr const& entity) {
|
||||||
if (auto closeDrop = as<ItemDrop>(entity)) {
|
if (auto closeDrop = as<ItemDrop>(entity)) {
|
||||||
// Make sure not to try to merge with ourselves here.
|
// Make sure not to try to merge with ourselves here.
|
||||||
if (closeDrop.get() != this && closeDrop->canTake()
|
if (closeDrop.get() != this && closeDrop->canTake()
|
||||||
&& vmag(position() - closeDrop->position()) < m_config.getFloat("combineRadius")) {
|
&& vmag(position() - closeDrop->position()) < m_combineRadius) {
|
||||||
if (m_item->couldStack(closeDrop->item()) == closeDrop->item()->count()) {
|
if (m_item->couldStack(closeDrop->item()) == closeDrop->item()->count()) {
|
||||||
m_item->stackWith(closeDrop->take());
|
m_item->stackWith(closeDrop->take());
|
||||||
m_dropAge.setElapsedTime(min(m_dropAge.elapsedTime(), closeDrop->m_dropAge.elapsedTime()));
|
m_dropAge.setElapsedTime(min(m_dropAge.elapsedTime(), closeDrop->m_dropAge.elapsedTime()));
|
||||||
@ -240,10 +253,10 @@ void ItemDrop::update(float dt, uint64_t) {
|
|||||||
m_mode.set(Mode::Available);
|
m_mode.set(Mode::Available);
|
||||||
if (!m_eternal && m_mode.get() == Mode::Available && m_dropAge.elapsedTime() > m_item->timeToLive())
|
if (!m_eternal && m_mode.get() == Mode::Available && m_dropAge.elapsedTime() > m_item->timeToLive())
|
||||||
m_mode.set(Mode::Dead);
|
m_mode.set(Mode::Dead);
|
||||||
if (m_mode.get() == Mode::Taken && m_dropAge.elapsedTime() > m_config.getFloat("afterTakenLife"))
|
if (m_mode.get() == Mode::Taken && m_dropAge.elapsedTime() > m_afterTakenLife)
|
||||||
m_mode.set(Mode::Dead);
|
m_mode.set(Mode::Dead);
|
||||||
|
|
||||||
if (m_mode.get() <= Mode::Available && m_ageItemsTimer.elapsedTime() > m_config.getDouble("ageItemsEvery", 10)) {
|
if (m_mode.get() <= Mode::Available && m_ageItemsTimer.elapsedTime() > m_ageItemsEvery) {
|
||||||
Root::singleton().itemDatabase()->ageItem(m_item, m_ageItemsTimer.elapsedTime());
|
Root::singleton().itemDatabase()->ageItem(m_item, m_ageItemsTimer.elapsedTime());
|
||||||
m_itemDescriptor.set(m_item->descriptor());
|
m_itemDescriptor.set(m_item->descriptor());
|
||||||
updateCollisionPoly();
|
updateCollisionPoly();
|
||||||
@ -261,9 +274,20 @@ bool ItemDrop::shouldDestroy() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ItemDrop::render(RenderCallback* renderCallback) {
|
void ItemDrop::render(RenderCallback* renderCallback) {
|
||||||
for (auto& drawable : m_item->dropDrawables()) {
|
if (!m_drawables) {
|
||||||
drawable.translate(position());
|
m_drawables = m_item->dropDrawables();
|
||||||
renderCallback->addDrawable(move(drawable), RenderLayerItemDrop);
|
if (Directives dropDirectives = m_config.getString("directives", "")) {
|
||||||
|
for (auto& drawable : *m_drawables) {
|
||||||
|
if (drawable.isImage())
|
||||||
|
drawable.imagePart().addDirectives(dropDirectives, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EntityRenderLayer renderLayer = m_mode.get() == Mode::Taken ? RenderLayerForegroundTile : RenderLayerItemDrop;
|
||||||
|
Vec2F dropPosition = position();
|
||||||
|
for (auto& drawable : *m_drawables) {
|
||||||
|
drawable.position = dropPosition;
|
||||||
|
renderCallback->addDrawable(drawable, renderLayer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,6 +363,18 @@ ItemDrop::ItemDrop() {
|
|||||||
m_netGroup.addNetElement(&m_movementController);
|
m_netGroup.addNetElement(&m_movementController);
|
||||||
m_netGroup.addNetElement(&m_itemDescriptor);
|
m_netGroup.addNetElement(&m_itemDescriptor);
|
||||||
|
|
||||||
|
m_afterTakenLife = m_config.getFloat("afterTakenLife");
|
||||||
|
m_overheadTime = m_config.getFloat("overheadTime");
|
||||||
|
m_pickupDistance = m_config.getFloat("pickupDistance");
|
||||||
|
m_velocity = m_config.getFloat("velocity");
|
||||||
|
m_velocityApproach = m_config.getFloat("velocityApproach");
|
||||||
|
m_overheadApproach = m_config.getFloat("overheadApproach");
|
||||||
|
m_overheadOffset = Vec2F(m_config.getFloat("overheadRandomizedDistance"), 0).rotate(Constants::pi * 2.0 * Random::randf());
|
||||||
|
|
||||||
|
m_combineChance = m_config.getFloat("combineChance");
|
||||||
|
m_combineRadius = m_config.getFloat("combineRadius");
|
||||||
|
m_ageItemsEvery = m_config.getDouble("ageItemsEvery", 10);
|
||||||
|
|
||||||
m_eternal = false;
|
m_eternal = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "StarItemDescriptor.hpp"
|
#include "StarItemDescriptor.hpp"
|
||||||
#include "StarGameTimers.hpp"
|
#include "StarGameTimers.hpp"
|
||||||
#include "StarEntity.hpp"
|
#include "StarEntity.hpp"
|
||||||
|
#include "StarDrawable.hpp"
|
||||||
|
|
||||||
namespace Star {
|
namespace Star {
|
||||||
|
|
||||||
@ -96,6 +97,17 @@ private:
|
|||||||
Json m_config;
|
Json m_config;
|
||||||
ItemPtr m_item;
|
ItemPtr m_item;
|
||||||
RectF m_boundBox;
|
RectF m_boundBox;
|
||||||
|
float m_afterTakenLife;
|
||||||
|
float m_overheadTime;
|
||||||
|
float m_pickupDistance;
|
||||||
|
float m_velocity;
|
||||||
|
float m_velocityApproach;
|
||||||
|
float m_overheadApproach;
|
||||||
|
Vec2F m_overheadOffset;
|
||||||
|
|
||||||
|
float m_combineChance;
|
||||||
|
float m_combineRadius;
|
||||||
|
double m_ageItemsEvery;
|
||||||
|
|
||||||
NetElementTopGroup m_netGroup;
|
NetElementTopGroup m_netGroup;
|
||||||
NetElementEnum<Mode> m_mode;
|
NetElementEnum<Mode> m_mode;
|
||||||
@ -108,6 +120,8 @@ private:
|
|||||||
EpochTimer m_dropAge;
|
EpochTimer m_dropAge;
|
||||||
GameTimer m_intangibleTimer;
|
GameTimer m_intangibleTimer;
|
||||||
EpochTimer m_ageItemsTimer;
|
EpochTimer m_ageItemsTimer;
|
||||||
|
|
||||||
|
Maybe<List<Drawable>> m_drawables;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1150,6 +1150,8 @@ ItemPtr Player::pickupItems(ItemPtr const& items) {
|
|||||||
|
|
||||||
if (items->pickupSound().size()) {
|
if (items->pickupSound().size()) {
|
||||||
m_effectsAnimator->setSoundPool("pickup", {items->pickupSound()});
|
m_effectsAnimator->setSoundPool("pickup", {items->pickupSound()});
|
||||||
|
float pitch = 1.f - ((float)items->count() / (float)items->maxStack()) * 0.5f;
|
||||||
|
m_effectsAnimator->setSoundPitchMultiplier("pickup", clamp(pitch * Random::randf(0.9f, 1.1f), 0.f, 2.f));
|
||||||
m_effectsAnimator->playSound("pickup");
|
m_effectsAnimator->playSound("pickup");
|
||||||
}
|
}
|
||||||
auto itemDb = Root::singleton().itemDatabase();
|
auto itemDb = Root::singleton().itemDatabase();
|
||||||
|
Loading…
Reference in New Issue
Block a user