• 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!
  • If you're using Gesior 2012 or MyAAC, please review this thread for information about a serious security vulnerability and a fix.

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

Infernum

Senator
Joined
Feb 14, 2015
Messages
5,640
Solutions
559
Reaction score
3,916
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:

Aeronx

Intermediate OT User
Joined
Dec 17, 2015
Messages
721
Solutions
9
Reaction score
110
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.
 

Nekiro

Legendary OT User
TFS Developer
Joined
Sep 7, 2015
Messages
2,635
Solutions
126
Reaction score
2,035
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
 

Aeronx

Intermediate OT User
Joined
Dec 17, 2015
Messages
721
Solutions
9
Reaction score
110
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.
 

2Rec

Excellent OT User
Joined
Jul 31, 2013
Messages
550
Solutions
48
Reaction score
884
Monsters are not spawned as summons. Master is being set afterwards.
Maybe try your code with addEvent or sth.
 

Aeronx

Intermediate OT User
Joined
Dec 17, 2015
Messages
721
Solutions
9
Reaction score
110
AddEvent doesnt work either. It doesnt recognize the summon/master.
 

Nekiro

Legendary OT User
TFS Developer
Joined
Sep 7, 2015
Messages
2,635
Solutions
126
Reaction score
2,035
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.
 

bayview

Banned User
Joined
Jan 25, 2018
Messages
611
Solutions
25
Reaction score
323
I have a different method which doesn't require all of this creatureevents ;) and the Monsters respawn after they die :)
C++:
monster:setSpawnPosition([interval])
 

Ninja

Global Moderator
Staff member
Global Moderator
Joined
Apr 6, 2010
Messages
5,947
Solutions
34
Reaction score
1,580
Location
Sweden
Not printing either.
The event ’onSpawn’ is called before ’Game::internalPlaceCreature’ which means that the monster’s ID has yet to be assigned.
 

flaviiojr

Active Member
Joined
Jan 20, 2017
Messages
230
Solutions
13
Reaction score
37
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...
 
OP
OP
Infernum

Infernum

Senator
Joined
Feb 14, 2015
Messages
5,640
Solutions
559
Reaction score
3,916
you can't directly change the actual monster spawn
 
OP
OP
Infernum

Infernum

Senator
Joined
Feb 14, 2015
Messages
5,640
Solutions
559
Reaction score
3,916
yes, return false if self:getName() is Amazon
 
OP
OP
Infernum

Infernum

Senator
Joined
Feb 14, 2015
Messages
5,640
Solutions
559
Reaction score
3,916
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
 

flaviiojr

Active Member
Joined
Jan 20, 2017
Messages
230
Solutions
13
Reaction score
37
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
 
Top