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

Shawak

Intermediate OT User
Joined
Sep 11, 2008
Messages
1,976
Best answers
2
Reaction score
101
Location
Germany
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:

whitevo

Feeling good, thats what I do.
Joined
Jan 2, 2015
Messages
3,449
Best answers
1
Reaction score
602
Location
Estonia
what the difference between canMove and noMove method?
Where should canMove to be used?
 
OP
Shawak

Shawak

Intermediate OT User
Joined
Sep 11, 2008
Messages
1,976
Best answers
2
Reaction score
101
Location
Germany
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
 

jaicob

Active Member
Joined
Feb 16, 2009
Messages
102
Best answers
2
Reaction score
39
Thank you! very useful indeed :)
 

hellboy

Well-Known Member
Joined
Apr 6, 2008
Messages
414
Best answers
3
Reaction score
64
Location
getPlayerTown (getCreatureByName("Hellboy"))
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 :)
 
OP
Shawak

Shawak

Intermediate OT User
Joined
Sep 11, 2008
Messages
1,976
Best answers
2
Reaction score
101
Location
Germany
It's not since marksaman dont want this method in his repo
 

silveralol

Advanced OT User
Joined
Mar 16, 2010
Messages
1,461
Best answers
8
Reaction score
184
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
 

tokenzz

:thinking:
Joined
Feb 2, 2013
Messages
783
Best answers
2
Reaction score
313
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.
 

silveralol

Advanced OT User
Joined
Mar 16, 2010
Messages
1,461
Best answers
8
Reaction score
184
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() ?
 

tokenzz

:thinking:
Joined
Feb 2, 2013
Messages
783
Best answers
2
Reaction score
313
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.
 

mackerel

Active Member
Joined
Apr 26, 2017
Messages
336
Best answers
12
Reaction score
49
awesome thanks. There is a bug though; you can still move both yourself or someone else by simply 'pushing' characters using your mouse :oops:
 
OP
Shawak

Shawak

Intermediate OT User
Joined
Sep 11, 2008
Messages
1,976
Best answers
2
Reaction score
101
Location
Germany
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
 

mackerel

Active Member
Joined
Apr 26, 2017
Messages
336
Best answers
12
Reaction score
49
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
 
OP
Shawak

Shawak

Intermediate OT User
Joined
Sep 11, 2008
Messages
1,976
Best answers
2
Reaction score
101
Location
Germany
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?
 

mackerel

Active Member
Joined
Apr 26, 2017
Messages
336
Best answers
12
Reaction score
49
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)
 
OP
Shawak

Shawak

Intermediate OT User
Joined
Sep 11, 2008
Messages
1,976
Best answers
2
Reaction score
101
Location
Germany
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;
}
 

mackerel

Active Member
Joined
Apr 26, 2017
Messages
336
Best answers
12
Reaction score
49
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
 

mackerel

Active Member
Joined
Apr 26, 2017
Messages
336
Best answers
12
Reaction score
49
@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
 
Top