• 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!

Lua Function [TFS 1.2] creature:setNoMove(bool) & creature:canMove()

Shawak

Intermediate OT User
Joined
Sep 11, 2008
Messages
1,984
Solutions
2
Reaction score
119
Location
Germany
GitHub
Shawak
creature.h add below

Code:
virtual bool isInGhostMode() const {
    return false;
}

add

Code:
bool noMove;
bool canMove() const {
    return !noMove;
}
void setNoMove(bool noMove) {
    this->noMove = noMove;
}

inside creature.cpp search for

Code:
ReturnValue ret = g_game.internalMoveCreature(this, dir, flags);

inside the onWalk() function and replace it with

Code:
ReturnValue ret = canMove() ? g_game.internalMoveCreature(this, dir, flags) : RETURNVALUE_NOTPOSSIBLE;

Also search for

Code:
   hiddenHealth = false;

and add
Code:
   noMove = false;

luascript.h below

Code:
static int luaCreatureGetPathTo(lua_State* L);

add

Code:
static int luaCreatureCanMove(lua_State* L);
static int luaCreatureSetNoMove(lua_State* L);

luascript.cpp below

Code:
int LuaScriptInterface::luaCreatureGetPathTo(lua_State* L)
{
   [...]
}

add

Code:
int LuaScriptInterface::luaCreatureSetNoMove(lua_State* L)
{
   // creature:setNoMove(canMove)
   Player* player = getUserdata<Player>(L, 1);
   if (!player) {
      lua_pushnil(L);
      return 1;
   }

   bool noMove = getBoolean(L, 2);
   if (player->canMove() == noMove) {
      player->setNoMove(noMove);
   }

   pushBoolean(L, true);
   return 1;
}

int LuaScriptInterface::luaCreatureCanMove(lua_State* L)
{
   // creature:canMove()
   Player* player = getUserdata<Player>(L, 1);
    if (player) {
      pushBoolean(L, player->canMove());
   } else {
      lua_pushnil(L);
   }
   return 1;
}

and after

Code:
   registerMethod("Creature", "getPathTo", LuaScriptInterface::luaCreatureGetPathTo);

add

Code:
   registerMethod("Creature", "canMove", LuaScriptInterface::luaCreatureCanMove);
   registerMethod("Creature", "setNoMove", LuaScriptInterface::luaCreatureSetNoMove);


That's it, now you should be able to use creature:setNoMove(bool) and creature:canMove() for any creature (player, monster, npc)

Example usage:

Code:
function onSay(player, words, param)
  local monster = Game.createMonster("wolf", player:getPosition())
  monster:setNoMove(true)

  addEvent(function(mid)
    Monster(mid):setNoMove(false)
    end, 3000, monster:getId())

  addEvent(function(mid)
    Monster(mid):setNoMove(true)
    end, 6000, monster:getId())

  addEvent(function(mid)
    Monster(mid):setNoMove(false)
    end, 9000, monster:getId())

  return true
end

Regards
 
Last edited:
what the difference between canMove and noMove method?
Where should canMove to be used?
 
creature:setNoMove(bool) is used to stop any movement of the creature, creature:canMove() returns whether the creature is currently allowed to move or not
 
creature.h add below

Code:
virtual bool isInGhostMode() const {
    return false;
}

add

Code:
bool noMove;
bool canMove() const {
    return !noMove;
}
void setNoMove(bool noMove) {
    this->noMove = noMove;
}

inside creature.cpp search for

Code:
ReturnValue ret = g_game.internalMoveCreature(this, dir, flags);

inside the onWalk() function and replace it with

Code:
ReturnValue ret = canMove() ? g_game.internalMoveCreature(this, dir, flags) : RETURNVALUE_NOTPOSSIBLE;

Also search for

Code:
   hiddenHealth = false;

and add
Code:
   noMove = false;

luascript.h below

Code:
static int luaCreatureGetPathTo(lua_State* L);

add

Code:
static int luaCreatureCanMove(lua_State* L);
static int luaCreatureSetNoMove(lua_State* L);

luascript.cpp below

Code:
int LuaScriptInterface::luaCreatureGetPathTo(lua_State* L)
{
   [...]
}

add

Code:
int LuaScriptInterface::luaCreatureSetNoMove(lua_State* L)
{
   // creature:setNoMove(canMove)
   Player* player = getUserdata<Player>(L, 1);
   if (!player) {
      lua_pushnil(L);
      return 1;
   }

   bool noMove = getBoolean(L, 2);
   if (player->canMove() == noMove) {
      player->setNoMove(noMove);
   }

   pushBoolean(L, true);
   return 1;
}

int LuaScriptInterface::luaCreatureCanMove(lua_State* L)
{
   // creature:canMove()
   Player* player = getUserdata<Player>(L, 1);
    if (player) {
      pushBoolean(L, player->canMove());
   } else {
      lua_pushnil(L);
   }
   return 1;
}

and after

Code:
   registerMethod("Creature", "getPathTo", LuaScriptInterface::luaCreatureGetPathTo);

add

Code:
   registerMethod("Creature", "canMove", LuaScriptInterface::luaCreatureCanMove);
   registerMethod("Creature", "setNoMove", LuaScriptInterface::luaCreatureSetNoMove);


That's it, now you should be able to use creature:setNoMove(bool) and creature:canMove() for any creature (player, monster, npc)

Example usage:

Code:
function onSay(player, words, param)
  local monster = Game.createMonster("wolf", player:getPosition())
  monster:setNoMove(true)

  addEvent(function(mid)
    Monster(mid):setNoMove(false)
    end, 3000, monster:getId())

  addEvent(function(mid)
    Monster(mid):setNoMove(true)
    end, 6000, monster:getId())

  addEvent(function(mid)
    Monster(mid):setNoMove(false)
    end, 9000, monster:getId())

  return true
end

Regards
I think, it's a good idea to make this as merge request in TFS 1.2 :)
 
nice, tested and it works fine, but I saw an issue, when you set creature:setNoMove(true) when the player try walk get the message "not possible" but the player seems to move, as when you try walk through players in PZ
 
nice, tested and it works fine, but I saw an issue, when you set creature:setNoMove(true) when the player try walk get the message "not possible" but the player seems to move, as when you try walk through players in PZ
yeah, he's not removing the movement, just preventing the player from actually moving. It's only the client that can see this.
 
yeah, he's not removing the movement, just preventing the player from actually moving. It's only the client that can see this.
how we can hadle about it ? remove the moviment and also prevent it ? it is in the function CanWalk() ?
 
how we can hadle about it ? remove the moviment and also prevent it ? it is in the function CanWalk() ?
nope, I believe that'd be handled in the client. I have a couple of solutions in my head, but the most proper way would be to revoke the movement animation if false;. And that part is handled in the client => it's possible to do in otclient for example.
 
awesome thanks. There is a bug though; you can still move both yourself or someone else by simply 'pushing' characters using your mouse :oops:
 
Without actually checking it, this should be easy be fixed by repalcing

Code:
bool isPushable() const override {
    return getWalkDelay() <= 0;
}

with

Code:
bool isPushable() const override {
    return canMove() && getWalkDelay() <= 0;
}

in creatures.h
 
Without actually checking it, this should be easy be fixed by repalcing

Code:
bool isPushable() const override {
    return getWalkDelay() <= 0;
}

with

Code:
bool isPushable() const override {
    return canMove() && getWalkDelay() <= 0;
}

in creatures.h

awesome! there is limitation though: it works only for player, so I decided to modify main code a bit to check if that will also work on pushable monsters

C++:
int32_t LuaScriptInterface::luaCreatureSetNoMove(lua_State* L)
{
   // creature:setNoMove(canMove)
    Creature* creature = getUserdata<Creature>(L, 1);
    if (!creature) {
        lua_pushnil(L);
        return 1;
    }
   bool noMove = getBoolean(L, 2);
   if (creature->canMove() == noMove) {
      creature->setNoMove(noMove);
   }
   pushBoolean(L, true);
   return 1;
}
int LuaScriptInterface::luaCreatureCanMove(lua_State* L)
{
   // creature:canMove()
   Creature* creature = getUserdata<Creature>(L, 1);
    if (creature) {
      pushBoolean(L, creature->canMove());
   } else {
      lua_pushnil(L);
   }
   return 1;
}

it doesn't work unfortunately
 
Did you register the methods in lauscripts.cpp? What exactly doesnt work? Like does the monster still move or do you can't even call the function?
 
Did you register the methods in lauscripts.cpp? What exactly doesnt work? Like does the monster still move or do you can't even call the function?

Oh haha, let me make it more clear

Things that work:
- Players are unable to move
- Monsters are unable to move
- You cannot push players with setNoMove(true)

but
- You can still push monsters with setNoMove(true)
 
monster.cpp has it's own isPushable()

Code:
bool isPushable() const override {
    return mType->info.pushable && baseSpeed != 0;
}

to

Code:
bool isPushable() const override {
    return canMove() && mType->info.pushable && baseSpeed != 0;
}
 
monster.cpp has it's own isPushable()

Code:
bool isPushable() const override {
    return mType->info.pushable && baseSpeed != 0;
}

to

Code:
bool isPushable() const override {
    return canMove() && mType->info.pushable && baseSpeed != 0;
}

Shawk it works ! :D

I actually thought that it will not work because there is no function canMove() included in monster.h but only within the actual creature.h so I am a bit confused why it works

But then I found this line:

C++:
class Monster : public Creature
{

so its actually getting the info from the Creature Class. Derived classes and stuff I guess. I should've looked more carefully

Well thank you
 
@Shawak I have found another bug and I would be grateful if you could help me fix it because this function is really amazing. I have tested it on clean TFS btw

So what you have to do to reproduce the bug is

1. Freeze the character with player:setNoMove(true)
2. Move 17 steps in one direction (I am not sure why 17)
3. It will execute this function for some reason: Game::playerSetAttackedCreature in game.cpp

*4. If you have selected target when performing steps above, it will deselect target automatically

I have found this bug when working on one of my functions, but in order to make sure it wasn't my fault I downloaded the source from github again and compiled only with your changes
 
Back
Top