• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Feature [TFS 1.2] Monster:onSpawn(position, startup, artificial)

Infernum

Senator
Joined
Feb 14, 2015
Messages
5,643
Solutions
559
Reaction score
3,945
Arguments:
position:
  • the position the monster is placed at
startup:
  • true: the monster is spawned on server startup
  • false: the monster is spawned after server startup
artificial:
  • true: the monster is spawned from a spawn on the map
  • false: the monster is spawned artificially via Game.createMonster(name, pos)

Return value:
  • true: allows the monster to be spawned and placed on the map
  • false: disallows the monster to be spawned and placed on the map
events.h


under
C++:
struct EventsInfo {
put
C++:
// Monster
int32_t monsterOnSpawn = -1;



under
C++:
bool load();
put
C++:
// Monster
bool eventMonsterOnSpawn(Monster* monster, const Position& position, bool startup, bool artificial);


events.cpp


replace
C++:
if (className == "Creature")
with
C++:
if (className == "Monster") {
   if (methodName == "onSpawn") {
       info.monsterOnSpawn = event;
   }
} else if (className == "Creature") {



above
C++:
// Creature
bool Events::eventCreatureOnChangeOutfit(Creature* creature, const Outfit_t& outfit)
add
C++:
// Monster
bool Events::eventMonsterOnSpawn(Monster* monster, const Position& position, bool startup, bool artificial)
{
   // Monster:onSpawn(position)
   if (info.monsterOnSpawn == -1) {
       return true;
   }

   if (!scriptInterface.reserveScriptEnv()) {
       std::cout << "[Error - Events::monsterOnSpawn] Call stack overflow" << std::endl;
       return false;
   }

   ScriptEnvironment* env = scriptInterface.getScriptEnv();
   env->setScriptId(info.monsterOnSpawn, &scriptInterface);

   lua_State* L = scriptInterface.getLuaState();
   scriptInterface.pushFunction(info.monsterOnSpawn);

   LuaScriptInterface::pushUserdata<Monster>(L, monster);
   LuaScriptInterface::setMetatable(L, -1, "Monster");
   LuaScriptInterface::pushPosition(L, position);
   LuaScriptInterface::pushBoolean(L, startup);
   LuaScriptInterface::pushBoolean(L, artificial);

   return scriptInterface.callFunction(4);
}


luascript.cpp


under
C++:
#include "databasetasks.h"
add
C++:
#include "events.h"
under
C++:
extern Spells* g_spells;
add
C++:
extern Events* g_events;

replace the entire function
C++:
int LuaScriptInterface::luaGameCreateMonster(lua_State* L)
with
C++:
int LuaScriptInterface::luaGameCreateMonster(lua_State* L)
{
   // Game.createMonster(monsterName, position[, extended = false[, force = false]])
   Monster* monster = Monster::createMonster(getString(L, 1));
   if (!monster) {
       lua_pushnil(L);
       return 1;
   }

   const Position& position = getPosition(L, 2);
   bool extended = getBoolean(L, 3, false);
   bool force = getBoolean(L, 4, false);
   bool result = g_events->eventMonsterOnSpawn(monster, position, false, true);
   if (result) {
       if (g_game.placeCreature(monster, position, extended, force)) {
           pushUserdata<Monster>(L, monster);
           setMetatable(L, -1, "Monster");
       } else {
           delete monster;
           lua_pushnil(L);
       }
   } else {
       delete monster;
       lua_pushnil(L);
   }
   return 1;
}


spawn.cpp


under
C++:
#include "pugicast.h"
add
C++:
#include "events.h"
under
C++:
extern Game g_game;
add
C++:
extern Events* g_events;


replace the entire function
C++:
bool Spawn::spawnMonster(uint32_t spawnId, MonsterType* mType, const Position& pos, Direction dir, bool startup /*= false*/)
with
C++:
bool Spawn::spawnMonster(uint32_t spawnId, MonsterType* mType, const Position& pos, Direction dir, bool startup /*= false*/)
{
   std::unique_ptr<Monster> monster_ptr(new Monster(mType));
   bool result = g_events->eventMonsterOnSpawn(monster_ptr.get(), pos, startup, false);
   if (result) {
       if (startup) {
           //No need to send out events to the surrounding since there is no one out there to listen!
           if (!g_game.internalPlaceCreature(monster_ptr.get(), pos, true)) {
               return false;
           }
       } else {
           if (!g_game.placeCreature(monster_ptr.get(), pos, false, true)) {
               return false;
           }
       }
   }

   Monster* monster = monster_ptr.release();
   monster->setDirection(dir);
   monster->setSpawn(this);
   monster->setMasterPos(pos);
   monster->incrementReferenceCounter();

   if (result) {
       spawnedMap.insert(spawned_pair(spawnId, monster));
   }
   spawnMap[spawnId].lastSpawn = OTSYS_TIME();
   return result;
}
data/events/scripts/monster.lua

Lua:
function Monster:onSpawn(position, startup, artificial)
   return true
end

data/events/events.xml

XML:
<!-- Monster methods -->
<event class="Monster" method="onSpawn" enabled="1" />
Lua:
function Monster:onSpawn(position, startup, artificial)
   -- register a creature event on all artificial monsters
   if artificial then
       self:registerEvent("some creature event")
   end
   return true
end
 
Last edited by a moderator:
Hello @Static_ !
I've been doing some testing with your code but i am unable to use this:
Code:
function Monster:onSpawn(position, startup, artificial)
print('works')
print('artificial')
   if artificial then

      print(isSummon(self))
      print(getCreatureMaster(self))

   end

return true
end

it always print works, true, false and 0 even when its a summon. Why? (its obviosuly a summon) self:isMonster() prints true.
 
Hello @Static_ !
I've been doing some testing with your code but i am unable to use this:
Code:
function Monster:onSpawn(position, startup, artificial)
print('works')
print('artificial')
   if artificial then

      print(isSummon(self))
      print(getCreatureMaster(self))

   end

return true
end

it always print works, true, false and 0 even when its a summon. Why? (its obviosuly a summon) self:isMonster() prints true.

local master = self:getMaster()
if not master then
-- is not summon
end
 
local master = self:getMaster()
if not master then
-- is not summon
end
Tested that already. Master nil. And i confirm 100% its a summon. Tested with other codes and it says its a summon.
Thats why i was wondering why doesnt work with this code.
 
Monsters are not spawned as summons. Master is being set afterwards.
Maybe try your code with addEvent or sth.
 
AddEvent doesnt work either. It doesnt recognize the summon/master.
 
AddEvent doesnt work either. It doesnt recognize the summon/master.
Code:
local function getMaster(creatureId)
    local creature = Creature(creatureId)
    if not creature then
        return true
    end
    print(creature:getMaster())
end

function Monster:onSpawn(position, startup, artificial)
    if artificial then
        addEvent(getMaster, 2 * 1000, self:getId())
    end
    return true
end

And it depends on how you set the creature as summon.
 
I have a different method which doesn't require all of this creatureevents ;) and the Monsters respawn after they die :)
C++:
monster:setSpawnPosition([interval])
 
Not printing either.
The event ’onSpawn’ is called before ’Game::internalPlaceCreature’ which means that the monster’s ID has yet to be assigned.
 
how would you change the respawn of the monsters?
Ex.: When initializing an amazon is born, only that later it will be born in the place of Valkyries...
 
you can't directly change the actual monster spawn
 
yes, return false if self:getName() is Amazon
 
i just did lol
but if you really need it to be more clear
Lua:
if self:getName() == "Amazon" then
    return false
end
it will keep executing anyways when it's supposed to spawn because you can't change the actual respawn
 
i just did lol
but if you really need it to be more clear
Lua:
if self:getName() == "Amazon" then
    return false
end
it will keep executing anyways when it's supposed to spawn because you can't change the actual respawn
example: when you start the server, you are set up to be born an amazon, but upon dying, the amazon will not be born, a valkyrie will be born instead of her spawn, and she wanted the valkyrie cycle to be normal as a respawn
 
Back
Top