1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-19 15:39:49 +00:00

Implement onNewExterior to spawn fish in generated exteriors

This commit is contained in:
Evil Eye 2023-06-13 17:04:22 +02:00
parent e35bf97603
commit f02dd0ef03
9 changed files with 102 additions and 8 deletions

View file

@ -11,6 +11,7 @@
namespace MWWorld
{
class CellStore;
class Ptr;
}
@ -47,6 +48,7 @@ namespace MWBase
virtual void objectRemovedFromScene(const MWWorld::Ptr& ptr) = 0;
virtual void itemConsumed(const MWWorld::Ptr& consumable, const MWWorld::Ptr& actor) = 0;
virtual void objectActivated(const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0;
virtual void exteriorCreated(MWWorld::CellStore& cell) = 0;
// TODO: notify LuaManager about other events
// virtual void objectOnHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object,
// const MWWorld::Ptr &attacker, const osg::Vec3f &hitPosition, bool successful) = 0;

View file

@ -71,6 +71,8 @@ namespace MWLua
scripts->onConsume(LObject(consumable));
}
void operator()(const OnNewExterior& event) const { mGlobalScripts.onNewExterior(GCell{ &event.mCell }); }
private:
MWWorld::Ptr getPtr(const ESM::RefNum& id) const
{

View file

@ -5,6 +5,8 @@
#include <components/esm3/cellref.hpp> // defines RefNum that is used as a unique id
#include "../mwworld/cellstore.hpp"
namespace MWLua
{
class GlobalScripts;
@ -38,7 +40,11 @@ namespace MWLua
ESM::RefNum mActor;
ESM::RefNum mConsumable;
};
using Event = std::variant<OnNewGame, OnActive, OnInactive, OnConsume, OnActivate>;
struct OnNewExterior
{
MWWorld::CellStore& mCell;
};
using Event = std::variant<OnNewGame, OnActive, OnInactive, OnConsume, OnActivate, OnNewExterior>;
void clear() { mQueue.clear(); }
void addToQueue(Event e) { mQueue.push_back(std::move(e)); }

View file

@ -20,7 +20,7 @@ namespace MWLua
: LuaUtil::ScriptsContainer(lua, "Global")
{
registerEngineHandlers({ &mObjectActiveHandlers, &mActorActiveHandlers, &mItemActiveHandlers,
&mNewGameHandlers, &mPlayerAddedHandlers, &mOnActivateHandlers });
&mNewGameHandlers, &mPlayerAddedHandlers, &mOnActivateHandlers, &mOnNewExteriorHandlers });
}
void newGameStarted() { callEngineHandlers(mNewGameHandlers); }
@ -32,6 +32,7 @@ namespace MWLua
{
callEngineHandlers(mOnActivateHandlers, obj, actor);
}
void onNewExterior(const GCell& cell) { callEngineHandlers(mOnNewExteriorHandlers, cell); }
private:
EngineHandlerList mObjectActiveHandlers{ "onObjectActive" };
@ -40,6 +41,7 @@ namespace MWLua
EngineHandlerList mNewGameHandlers{ "onNewGame" };
EngineHandlerList mPlayerAddedHandlers{ "onPlayerAdded" };
EngineHandlerList mOnActivateHandlers{ "onActivate" };
EngineHandlerList mOnNewExteriorHandlers{ "onNewExterior" };
};
}

View file

@ -71,6 +71,10 @@ namespace MWLua
{
mEngineEvents.addToQueue(EngineEvents::OnActivate{ getId(actor), getId(object) });
}
void exteriorCreated(MWWorld::CellStore& cell) override
{
mEngineEvents.addToQueue(EngineEvents::OnNewExterior{ cell });
}
MWBase::LuaManager::ActorControls* getActorControls(const MWWorld::Ptr&) const override;

View file

@ -19,6 +19,9 @@
#include "cellstore.hpp"
#include "esmstore.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/luamanager.hpp"
namespace MWWorld
{
namespace
@ -55,7 +58,7 @@ namespace MWWorld
return store.insert(record);
}
Cell createExteriorCell(ESM::ExteriorCellLocation location, ESMStore& store)
std::tuple<Cell, bool> createExteriorCell(ESM::ExteriorCellLocation location, ESMStore& store)
{
if (ESM::isEsm4Ext(location.mWorldspace))
{
@ -63,17 +66,19 @@ namespace MWWorld
throw std::runtime_error(
"Exterior ESM4 world is not found: " + location.mWorldspace.toDebugString());
const ESM4::Cell* cell = store.get<ESM4::Cell>().searchExterior(location);
if (cell == nullptr)
bool created = cell == nullptr;
if (created)
cell = createEsm4Cell(location, store);
assert(cell != nullptr);
return MWWorld::Cell(*cell);
return { MWWorld::Cell(*cell), created };
}
const ESM::Cell* cell = store.get<ESM::Cell>().search(location.mX, location.mY);
if (cell == nullptr)
bool created = cell == nullptr;
if (created)
cell = createEsmCell(location, store);
assert(cell != nullptr);
return Cell(*cell);
return { Cell(*cell), created };
}
std::optional<Cell> createCell(ESM::RefId id, const ESMStore& store)
@ -165,10 +170,12 @@ namespace MWWorld
if (it == mExteriors.end())
{
Cell cell = createExteriorCell(location, mStore);
auto [cell, created] = createExteriorCell(location, mStore);
const ESM::RefId id = cell.getId();
cellStore = &emplaceCellStore(id, std::move(cell), mStore, mReaders, mCells);
mExteriors.emplace(location, cellStore);
if (created)
MWBase::Environment::get().getLuaManager()->exteriorCreated(*cellStore);
}
else
{

View file

@ -65,6 +65,7 @@ set(BUILTIN_DATA_FILES
scripts/omw/activationhandlers.lua
scripts/omw/ai.lua
scripts/omw/cellhandlers.lua
scripts/omw/camera/camera.lua
scripts/omw/camera/head_bobbing.lua
scripts/omw/camera/third_person.lua

View file

@ -7,6 +7,7 @@ PLAYER: scripts/omw/settings/player.lua
# Mechanics
GLOBAL: scripts/omw/activationhandlers.lua
GLOBAL: scripts/omw/cellhandlers.lua
PLAYER: scripts/omw/mechanics/playercontroller.lua
PLAYER: scripts/omw/playercontrols.lua
PLAYER: scripts/omw/camera/camera.lua

View file

@ -0,0 +1,69 @@
local types = require('openmw.types')
local util = require('openmw.util')
local world = require('openmw.world')
local CELL_SIZE = 8192
local function getRandomPosition(cellX, cellY)
local x = math.random(7892)
local y = math.random(7892)
local z = -math.random(1748)
return util.vector3(cellX + x, cellY + y, z)
end
local function getRandomOffset()
local x = math.random(1000)
local y = math.random(1000)
local z = math.random(1000)
local v = util.vector3(x, y, z)
return v:normalize() * 100
end
local function getPlayerLevel()
for i, actor in pairs(world.activeActors) do
if (types.Player.objectIsInstance(actor)) then
return types.Player.stats.level(actor).current
end
end
end
local function spawnFish(cell)
if (cell.worldSpaceId ~= 'sys::default') then
return
end
local spawnCount = math.random(0, 10)
if (spawnCount < 1) then
return
end
local list = types.LevelledCreature.record('h2o_all_lev-2')
if (list == nil) then
return
end
local cellX = cell.gridX * CELL_SIZE
local cellY = cell.gridY * CELL_SIZE
local level = getPlayerLevel()
if (spawnCount <= 5) then -- spawn a number of random creatures selected from the list
while(spawnCount > 0) do
local id = list:getRandomId(level)
if (id ~= '') then
local ref = world.createObject(id)
ref:teleport(cell, getRandomPosition(cellX, cellY))
end
spawnCount = spawnCount - 1
end
else -- spawn a horde of a single creature selected from the list
local id = list:getRandomId(level)
if (id ~= '') then
local basePos = getRandomPosition(cellX, cellY)
while(spawnCount > 0) do
local ref = world.createObject(id)
ref:teleport(cell, basePos + getRandomOffset())
spawnCount = spawnCount - 1
end
end
end
end
return {
engineHandlers = { onNewExterior = spawnFish }
}