1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-21 07:09:42 +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 namespace MWWorld
{ {
class CellStore;
class Ptr; class Ptr;
} }
@ -47,6 +48,7 @@ namespace MWBase
virtual void objectRemovedFromScene(const MWWorld::Ptr& ptr) = 0; virtual void objectRemovedFromScene(const MWWorld::Ptr& ptr) = 0;
virtual void itemConsumed(const MWWorld::Ptr& consumable, const MWWorld::Ptr& actor) = 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 objectActivated(const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0;
virtual void exteriorCreated(MWWorld::CellStore& cell) = 0;
// TODO: notify LuaManager about other events // TODO: notify LuaManager about other events
// virtual void objectOnHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, // 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; // const MWWorld::Ptr &attacker, const osg::Vec3f &hitPosition, bool successful) = 0;

View file

@ -71,6 +71,8 @@ namespace MWLua
scripts->onConsume(LObject(consumable)); scripts->onConsume(LObject(consumable));
} }
void operator()(const OnNewExterior& event) const { mGlobalScripts.onNewExterior(GCell{ &event.mCell }); }
private: private:
MWWorld::Ptr getPtr(const ESM::RefNum& id) const 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 <components/esm3/cellref.hpp> // defines RefNum that is used as a unique id
#include "../mwworld/cellstore.hpp"
namespace MWLua namespace MWLua
{ {
class GlobalScripts; class GlobalScripts;
@ -38,7 +40,11 @@ namespace MWLua
ESM::RefNum mActor; ESM::RefNum mActor;
ESM::RefNum mConsumable; 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 clear() { mQueue.clear(); }
void addToQueue(Event e) { mQueue.push_back(std::move(e)); } void addToQueue(Event e) { mQueue.push_back(std::move(e)); }

View file

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

View file

@ -71,6 +71,10 @@ namespace MWLua
{ {
mEngineEvents.addToQueue(EngineEvents::OnActivate{ getId(actor), getId(object) }); 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; MWBase::LuaManager::ActorControls* getActorControls(const MWWorld::Ptr&) const override;

View file

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

View file

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

View file

@ -7,6 +7,7 @@ PLAYER: scripts/omw/settings/player.lua
# Mechanics # Mechanics
GLOBAL: scripts/omw/activationhandlers.lua GLOBAL: scripts/omw/activationhandlers.lua
GLOBAL: scripts/omw/cellhandlers.lua
PLAYER: scripts/omw/mechanics/playercontroller.lua PLAYER: scripts/omw/mechanics/playercontroller.lua
PLAYER: scripts/omw/playercontrols.lua PLAYER: scripts/omw/playercontrols.lua
PLAYER: scripts/omw/camera/camera.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 }
}