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:
parent
e35bf97603
commit
f02dd0ef03
9 changed files with 102 additions and 8 deletions
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)); }
|
||||||
|
|
|
@ -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" };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
69
files/data/scripts/omw/cellhandlers.lua
Normal file
69
files/data/scripts/omw/cellhandlers.lua
Normal 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 }
|
||||||
|
}
|
Loading…
Reference in a new issue