Graal Forums

Graal Forums (https://forums.graalonline.com/forums/index.php)
-   Code Gallery (https://forums.graalonline.com/forums/forumdisplay.php?f=179)
-   -   NPC Movement / Actions (https://forums.graalonline.com/forums/showthread.php?t=85370)

fowlplay4 04-29-2009 09:36 PM

NPC Movement / Actions
 
To make it easier for level makers to add some NPC life into their levels I created this.

It allows the user to make an npc follow a simple movement path, and use some animation while staying the on clientside to avoid using the server's resources also looks a lot smoother.

Class: movement
PHP Code:

/*
   Allows for Simple Movement, and Actions to breathe
   npc life into the server.
*/

//#CLIENTSIDE

function onCreated() {
  if (!
this.speedthis.speed 6//Tiles Per Second.
  
this.actionpos 0;
  
doAction(0); 
}

function 
doAction(ind) {
  if (
ind == this.actions.size()) return;
  
temp.action this.actions[ind];
  
temp.data action.tokenize(":");
  if (
data[0].starts("!")) {
    
this.actions.delete(ind);
    
this.actionpos--;
    
data[0] = data[0].substring(1);
  }
  switch (
data[0]) {
    case 
"move":
      
doMove(data[1], data[2]);
      break;
    case 
"moveto":
      
temp.movex data[1] - this.x;
      
temp.movey data[2] - this.y;
      
doMove(movexmovey);
      break;
    case 
"reversemove":
      
this.reversing true;
      
this.reversepos this.moves.size();
      
onMovementFinished();
      break;
    case 
"action":
      
temp.act this.("action_" data[1]);
      for (
temp.actionact) {
        
this.actions.insert(this.actionpos+1+temp.i"!" action);
        
temp.i++;
      }
      
onNextStep();
      break;
    case 
"randomaction":
      if (
random(0,1) <= data[1]) {
        
temp.act this.("action_" data[2]);
        for (
temp.actionact) {
          
this.actions.insert(this.actionpos+1+temp.i"!" action);
          
temp.i++;
        }
      }
      else if (
data[3].length() > 0) {
        
temp.act this.("action_" data[3]);
        for (
temp.actionact) {
          
this.actions.insert(this.actionpos+1+temp.i"!" action);
          
temp.i++;
        }
      }
      
onNextStep();
      break;
    case 
"setdir":
      
this.dir data[1];
      break;
    case 
"setani":
      
setcharani(data[1], data[2]);
      
onNextStep();
      break;
    case 
"randomani":
      if (
random(0,1) <= data[1]) {
        
setcharani(data[2], data[3]);
      }
      
onNextStep();
      break;
    case 
"chat":
      
this.chat data[1];
      
temp.time = (!data[2] ? data[2]);
      
this.scheduleevent(time"ClearChat""");
      
onNextStep();
      break;
    case 
"randomchat":
      if (
random(0,1) <= data[1]) {
        
this.chat data[2];
        
temp.time = (!data[3] ? data[3]);
        
this.scheduleevent(time"ClearChat""");
      }
      
onNextStep();
      break;
    case 
"wait":
      
this.scheduleevent(data[1], "NextStep""");
      break;
    case 
"repeat":
      
this.actionpos 0;
      
doAction(this.actionpos);
      break;
  }
}

// Movement Functions

function GetDistance(temp.x1temp.y1temp.x2temp.y2) {
  
temp.toreturn = (temp.x2 temp.x1) ^ + (temp.y2 temp.y1) ^ 2;
  return (
temp.toreturn) ^ .5;
}

function 
doMove(dxdy) {
  
temp.distance GetDistance(this.x,this.y,this.x+dx,this.y+dy);
  
temp.time distance this.speed;
  
this.dir getdir((this.dx) - this.x,(this.dy) - this.y);
  
move(dxdytemp.time8);
  
setcharani(this.ani_walk"");
  if (!
this.reversingthis.moves.add({dxdy});
}

function 
onMovementFinished() {
  
setcharani(this.ani_idle"");
  if (
this.reversing) {
    
this.reversepos--;
    if (
this.reversepos <= -1) {
      
this.reversing false;
      
this.moves "";
      return 
onNextStep();
    }
    
temp.move this.moves[this.reversepos];
    return 
doMove(-temp.move[0], -temp.move[1]);
  }
  else 
onNextStep();
}

// Action Related Functions

function onClearChat() {
  
this.chat "";
}

function 
onNextStep() {
  
this.actionpos++;
  
doAction(this.actionpos);


You can easily use the above to make a fisherman walk up and down the riverside, and get him to stop and fish. Here's my example including the use of every action that is scripted into it.

PHP Code:

/**
Actions:
  move:dx:dy  - Moves NPC dx, dy
  moveto:x:y  - Moves NPC to x, y
  setdir:dir  - Sets NPC direction to dir
  reversemove - Does the Reverse of Every Move 
                it's made so far. Works like a 
                return home command.
    
  chat:chattext:length - Sets NPC Chat to chattext
                         for 3 seconds if no length
                         is decided.

  randomchat:0-1:chattext:length - Same Idea just with the
                                   random chance factor.
    
  setani:gani:param - Sets NPC Gani to gani, 
                      param isn't required.

  randomani:0-1:gani:param - Same idea as setani, just with
                             random chance factor.

  wait:seconds - NPC waits seconds before next action.

  repeat - NPC starts from the 1st action again.

  action:name - NPC does every thing in 
                this.action_actionname, view example below.

  randomaction:0-1:name - Same idea as action just with
                          random chance factor.
*/
//Near OSL, Fisherman NPC Example.
//#CLIENTSIDE 
function onCreated() {
  
// Initialize the attributes
  
showcharacter();
  
this.head "head4.png";
  
this.colors = {"orange""white""white""black""blue"};
  
this.shield "no-shield.gif";
  
this.dir 1;
  
//Ganis
  
this.ani_walk "walk"//Gani while walking.
  
this.ani_idle "idle"//Gani after finished moving.
  
this.speed 8// Movement Speed (tiles per second, default is 6)
  //Actions
  
this.actions = {
    
"move:4.8:0",       // Depending on the place you'll have
    
"move:0:-12",       // to change these.
    
"move:-4.8:-4.8",
    
"move:0:-4.8",
    
"move:-3.6:-2.4",
    
"action:fishing",
    
"reversemove",
    
"action:fishing",
    
"repeat"
  
};
  
//Sub-Actions Example.
  
this.action_fishing = {
    
"setani:zodiac_fishingattack",
    
"wait:5",
    
"randomaction:0.25:reel",
    
"wait:3",
    
"setani:zodiac_fishingattack",
    
"wait:1"
  
};
  
this.action_reel = {
    
"setani:zodiac_fishingreeling",
    
"randomchat:0.3:Almost had that one.. -sigh-:4"
  
};
  
join("movement");


In the future I may attempt to sync the movements over clients but it would require timevar3 and some tricky math to determine where the npc would be at a certain time but it's not really needed since this is mainly for aesthetics.

Edit: If you do need the actions sync'd on the serverside just remove the //#CLIENTSIDE from the scripts, however there is nothing that puts the script at "rest."

Feel free to PM me if you need help setting it up.

Enjoy.

cbk1994 04-29-2009 09:43 PM

Why not just use move() serverside for syncing to other players?

Looks good, though you should use GS2 for showing the character, not GS1.

fowlplay4 04-29-2009 09:55 PM

Quote:

Originally Posted by cbk1994 (Post 1487672)
Why not just use move() serverside for syncing to other players?

Looks good, though you should use GS2 for showing the character, not GS1.

Can get pretty choppy, but the script does work serverside provided you just remove the //#CLIENTSIDE from the class and npc using it.

I don't see GS1 support getting completely dropped anytime soon so I just kept as is from the level editor's template.

Gambet 04-29-2009 11:02 PM

That's actually pretty cool, servers could greatly benefit from interactive NPCs that don't just sit around all day and actually move about and do things like normal people. Reminds me of the Graal2001 police-NPCs that walked around town and screamed at you for getting in their way, though this system would allow for greater customization. Nice work. :)

cbk1994 04-29-2009 11:04 PM

Quote:

Originally Posted by fowlplay4 (Post 1487680)
Can get pretty choppy, but the script does work serverside provided you just remove the //#CLIENTSIDE from the class and npc using it.

Using move on serverside lets clientside do all the work, it's not choppy at all.
Quote:

I don't see GS1 support getting completely dropped anytime soon so I just kept as is from the level editor's template.
I don't either, but I hope so. There's no reason to encourage GS1 use (by "I hope so", I mean I hope for a server option or such to drop it)

fowlplay4 04-30-2009 12:11 AM

Well from my experience with this script multiple moves on the serverside can appear choppy/rushed, laggy players would see this more than the others.

But I guess we should be promoting GS2 so I changed that part in the script.

fowlplay4 12-28-2012 06:30 AM

Some updates I made to it when I used it on iClassic:

this.can_stop - boolean - set to true if you want to 'stop' the npc mid-movement.
npc_stop(); - stops the npc.
npc_continue(); - starts the npc back up again.
"emote:image:time" - new action to make the npc do an emote for a specified time (3 if not specified)
"levelvar:var:value" - sets a level variable to value


PHP Code:

//#CLIENTSIDE
function onCreated() {
  if (!
this.ani_idlethis.ani_idle "idle";
  if (!
this.ani_walkthis.ani_walk "walk";
  if (!
this.speedthis.speed 6//Tiles Per Second.
  
if (this.can_stop) {
    
// Breaks up movement actions to allow NPC to
    // stop properly.
    
this.actions parseMovement(this.actions);
    
temp.subactions getstringkeys("this.action_");
    for (
temp.subactiontemp.subactions) {
      
this.("action_" temp.subaction) = parseMovement(this.("action_" temp.subaction));
    }
  }
  
this.initxy = {
    
this.xthis.y
  
};
  
this.actionpos 0;
  
doAction(0); 
}

function 
parseMovement(old_actions) {
  
temp.new_actions = {};
  for (
temp.actionold_actions) {
    
temp.data temp.action.tokenize(":");
    switch (
data[0]) {
      case 
"move":
        
temp.new_actions.addarray(calcMoves(data[1], data[2]));
        break;
      case 
"moveto":
        
temp.movex data[1] - (this.64);
        
temp.movey data[2] - (this.64);
        
temp.new_actions.addarray(calcMoves(movexmovey));
        break;
      default:
        
temp.new_actions.add(temp.action);
        break;
    }
  }
  return 
temp.new_actions;
}

function 
calcMoves(dxdy) {
  
temp.distance GetDistance(this.xthis.ythis.dxthis.dy);
  
temp.time distance this.speed;
  
temp.frames temp.time 0.05;
  
temp.ndx dx * (temp.frames);
  
temp.ndy dy * (temp.frames);
  
temp.nmove format("move:%s:%s"temp.ndxtemp.ndy);
  for (
temp.0temp.temp.framestemp.i++) {
    
temp.moves.add(temp.nmove);
  }
  return 
temp.moves;
}

function 
doAction(ind) {
  if (
ind == this.actions.size()) return;
  if (
this.is_stopped || this.waiting) return;
  
temp.action this.actions[ind];
  
temp.data action.tokenize(":");
  if (
data[0].starts("!")) {
    
this.actions.delete(ind);
    
this.actionpos--;
    
data[0] = data[0].substring(1);
  }
  switch (
data[0]) {
    case 
"move":
      
doMove(data[1], data[2]);
      break;
    case 
"moveto":
      
temp.movex data[1] - (this.64);
      
temp.movey data[2] - (this.64);
      
doMove(movexmovey);
      break;
    case 
"reversemove":
      
this.reversing true;
      
this.reversepos this.moves.size();
      
onMovementFinished();
      break;
    case 
"action":
      
temp.act this.("action_" data[1]);
      for (
temp.actionact) {
        
this.actions.insert(this.actionpos+1+temp.i"!" action);
        
temp.i++;
      }
      
onNextStep();
      break;
    case 
"randomaction":
      if (
random(0,1) <= data[1]) {
        
temp.act this.("action_" data[2]);
        for (
temp.actionact) {
          
this.actions.insert(this.actionpos+1+temp.i"!" action);
          
temp.i++;
        }
      }
      
onNextStep();
      break;
    case 
"setdir":
      
this.dir data[1];
      
onNextStep();
      break;
    case 
"setani":
      
setcharani(data[1], data[2]);
      
onNextStep();
      break;
    case 
"emote":
      
temp.emote data[1];
      
temp.time = (!data[2] ? data[2]);
      if (
temp.emote == "emoticon_Zzz_stay.mng") {
        
showimg(200temp.emotethis.2.5this.- (92/16) + 1);
      } else { 
        
showani(200this.xthis.y0"emoticon"temp.emote);
      }
      
this.scheduleevent(time"ClearEmote""");
      
onNextStep();
      break;
    case 
"levelvar":
      
level.(@data[1]) = data[2];
      
onNextStep();
      break;
    case 
"randomani":
      if (
random(0,1) <= data[1]) {
        
setcharani(data[2], data[3]);
      }
      
onNextStep();
      break;
    case 
"chat":
      
this.chat data[1];
      
temp.time = (!data[2] ? data[2]);
      
this.scheduleevent(time"ClearChat""");
      
onNextStep();
      break;
    case 
"randomchat":
      if (
random(0,1) <= data[1]) {
        
this.chat data[2];
        
temp.time = (!data[3] ? data[3]);
        
this.scheduleevent(time"ClearChat""");
      }
      
onNextStep();
      break;
    case 
"showimg":
      
showimg(data[1], data[2], data[3], data[4]);
      break;
    case 
"hideimg":
      
hideimg(data[1]);
      break;
    case 
"setvar":
      
this.(@data[1]) = data[2];
      break;
    case 
"wait":
      
this.waiting true;
      
this.scheduleevent(data[1], "NextStep"true);
      break;
    case 
"repeat":
      
this.actionpos 0;
      
doAction(this.actionpos);
      break;
  }
}

// Movement Functions

function npc_stop() {
  
this.is_stopped true;
  
this.oani this.ani;
  
this.odir this.dir;
  
setcharani(this.ani_idle"");
}

function 
npc_continue() {
  
this.is_stopped false;
  
this.dir this.odir;
  
this.ani this.oani;
  
onMovementFinished();
}

function 
GetDistance(temp.x1temp.y1temp.x2temp.y2) {
  
temp.toreturn = (temp.x2 temp.x1) ^ + (temp.y2 temp.y1) ^ 2;
  return (
temp.toreturn) ^ .5;
}

function 
doMove(dxdy) {
  
temp.distance GetDistance(this.xthis.ythis.dxthis.dy);
  
temp.time distance this.speed;
  
this.dir getRealDir(dxdy);
  
move(dxdytemp.time8);
  if (
this.ani != this.ani_walksetcharani(this.ani_walk"");
  if (!
this.reversingthis.moves.add({dxdy});
}

function 
getRealDir(dxdy) {
  if (
dy && dx 0) return 3;
  if (
dy && dx 0) return 3;
  if (
dy && dx 0) return 1;
  if (
dy && dx 0) return 2;
  return 
getdir(dxdy);
}

function 
onMovementFinished() {
  if (
this.is_stopped || this.waiting) return;
  
temp.next_action this.actions[this.actionpos+1];
  if (
temp.next_action.pos("move") == -&& !this.reversing) {
    
setcharani(this.ani_idle"");
  }
  if (
this.reversing) {
    
this.reversepos--;
    if (
this.reversepos <= -1) {
      
this.reversing false;
      
this.moves "";
      
setcharani(this.ani_idle"");
      return 
onNextStep();
    }
    
temp.move this.moves[this.reversepos];
    return 
doMove(-temp.move[0], -temp.move[1]);
  }
  else 
onNextStep();
}

// Action Related Functions

function onClearChat() {
  
this.chat "";
}

function 
onClearEmote() {
  
hideimg(200);
}

function 
onNextStep(done_waiting) {
  if (
this.waiting && done_waiting) {
    
this.waiting false;
  }
  if (
this.is_stopped) return;
  
this.actionpos++;
  
doAction(this.actionpos);


Stop example:

PHP Code:

//#CLIENTSIDE
function onCreated() {
  
// your actions...
  
this.can_stop true;
  
join("movement");
}

function 
onPlayerTouchsMe() {
  
npc_stop();
  
this.dir = (player.dir 2) % 4;
  
waitfor(this"RandomEvent"3); // I would use a dialog script that uses waitfor here...
  
npc_continue();



MysticalDragon 01-04-2013 09:53 PM

great work!

Does it still support serverside if clientside tag is removed? Or is it not recommended?

*must spread reputation before giving fowplay rep etc

Stowen 01-11-2013 10:27 PM

When you reconnect, or just connect to the server, it completely stops functioning. I added this to the top, and it messed up the direction of the NPC:
PHP Code:

function onPlayerEnters() {
onCreated();


Other than that, excellent job! I really like this.

Draenin 01-13-2013 05:53 AM

I've been wondering lately if it would be possible to make a class NPC that could be written to move toward special marker classes that could be placed in some levels to give them a multi-step function that would be more dynamic than having to figure out the exact number of tiles they need to move in each direction.

However, my concern is that it might be slightly inaccurate, or less feasible to do it that way. What do you think?

fowlplay4 01-13-2013 06:30 AM

My example uses deltas but you can use specific coordinates, via moveto:x:y.

If you need that functionality just create a new action to interact with your way-point system.

fowlplay4 05-19-2015 10:40 PM

Added support for more verbose move commands.

e.g. movewest, moveup, movedownright, movenorth, etc.

move[up|down|left|right|north|east|west|south|][up|down|left|right|north|east|west|south|]

You can also specify an amount of tiles to move, otherwise it just moves by 1 tile.

{"moveeast", 3}

PHP Code:

//#CLIENTSIDE
function onCreated() {
  if (!
this.ani_idlethis.ani_idle "idle";
  if (!
this.ani_walkthis.ani_walk "walk";
  if (!
this.speedthis.speed 6//Tiles Per Second.
  
if (this.can_stop) {
    
// Breaks up movement actions to allow NPC to
    // stop properly.
    
this.actions parseMovement(this.actions);
    
temp.subactions getstringkeys("this.action_");
    for (
temp.subactiontemp.subactions) {
      
this.("action_" temp.subaction) = parseMovement(this.("action_" temp.subaction));
    }
  }
  
this.initxy = {
    
this.xthis.y
  
};
  
this.actionpos 0;
  
doAction(0); 
}

function 
parseMovement(old_actions) {
  
temp.new_actions = {};
  for (
temp.actionold_actions) {
    
temp.data temp.action.tokenize(":");
    switch (
data[0]) {
      case 
"move":
        
temp.new_actions.addarray(calcMoves(data[1], data[2]));
        break;
      case 
"moveto":
        
temp.movex data[1] - (this.64);
        
temp.movey data[2] - (this.64);
        
temp.new_actions.addarray(calcMoves(movexmovey));
        break;
      default:
        if (
data[0].starts("move")) {
          
// Determine Direction
          
if (data[0].pos("east") >= || data[0].pos("right") >= 0temp.dx 1;
          else if (
data[0].pos("west") >= || data[0].pos("left") >= 0temp.dx = -1;
          if (
data[0].pos("north") >= || data[0].pos("up") >= 0temp.dy = -1;
          else if (
data[0].pos("south") >= || data[0].pos("down") >= 0temp.dy 1;
          
// Check for Valid Deltas
          
if (temp.dx != || temp.dy != 0) {
            
temp.dx *= data[1] == data[1];
            
temp.dy *= data[1] == data[1];
            
temp.new_actions.addarray(calcMoves(temp.dxtemp.dy));
          }
        } else {
          
temp.new_actions.add(temp.action);
        }
        break;
    }
  }
  return 
temp.new_actions;
}

function 
calcMoves(dxdy) {
  
temp.distance GetDistance(this.xthis.ythis.dxthis.dy);
  
temp.time distance this.speed;
  
temp.frames temp.time 0.05;
  
temp.ndx dx * (temp.frames);
  
temp.ndy dy * (temp.frames);
  
temp.nmove format("move:%s:%s"temp.ndxtemp.ndy);
  for (
temp.0temp.temp.framestemp.i++) {
    
temp.moves.add(temp.nmove);
  }
  return 
temp.moves;
}

function 
doAction(ind) {
  if (
ind == this.actions.size()) return;
  if (
this.is_stopped || this.waiting) return;
  
temp.action this.actions[ind];
  
temp.data action.tokenize(":");
  if (
data[0].starts("!")) {
    
this.actions.delete(ind);
    
this.actionpos--;
    
data[0] = data[0].substring(1);
  }
  switch (
data[0]) {
    case 
"move":
      
doMove(data[1], data[2]);
      break;
    case 
"moveto":
      
temp.movex data[1] - (this.64);
      
temp.movey data[2] - (this.64);
      
doMove(movexmovey);
      break;
    case 
"reversemove":
      
this.reversing true;
      
this.reversepos this.moves.size();
      
onMovementFinished();
      break;
    case 
"action":
      
temp.act this.("action_" data[1]);
      for (
temp.actionact) {
        
this.actions.insert(this.actionpos+1+temp.i"!" action);
        
temp.i++;
      }
      
onNextStep();
      break;
    case 
"randomaction":
      if (
random(0,1) <= data[1]) {
        
temp.act this.("action_" data[2]);
        for (
temp.actionact) {
          
this.actions.insert(this.actionpos+1+temp.i"!" action);
          
temp.i++;
        }
      }
      
onNextStep();
      break;
    case 
"setdir":
      
this.dir data[1];
      
onNextStep();
      break;
    case 
"setani":
      
setcharani(data[1], data[2]);
      
onNextStep();
      break;
    case 
"emote":
      
temp.emote data[1];
      
temp.time = (!data[2] ? data[2]);
      if (
temp.emote == "emoticon_Zzz_stay.mng") {
        
showimg(200temp.emotethis.2.5this.- (92/16) + 1);
      } else { 
        
showani(200this.xthis.y0"emoticon"temp.emote);
      }
      
this.scheduleevent(time"ClearEmote""");
      
onNextStep();
      break;
    case 
"levelvar":
      
level.(@data[1]) = data[2];
      
onNextStep();
      break;
    case 
"randomani":
      if (
random(0,1) <= data[1]) {
        
setcharani(data[2], data[3]);
      }
      
onNextStep();
      break;
    case 
"chat":
      
this.chat data[1];
      
temp.time = (!data[2] ? data[2]);
      
this.scheduleevent(time"ClearChat""");
      
onNextStep();
      break;
    case 
"randomchat":
      if (
random(0,1) <= data[1]) {
        
this.chat data[2];
        
temp.time = (!data[3] ? data[3]);
        
this.scheduleevent(time"ClearChat""");
      }
      
onNextStep();
      break;
    case 
"showimg":
      
showimg(data[1], data[2], data[3], data[4]);
      break;
    case 
"hideimg":
      
hideimg(data[1]);
      break;
    case 
"setvar":
      
this.(@data[1]) = data[2];
      break;
    case 
"wait":
      
this.waiting true;
      
this.scheduleevent(data[1], "NextStep"true);
      break;
    case 
"repeat":
      
this.actionpos 0;
      
doAction(this.actionpos);
      break;
    default:
      
// Check if starts with move
      // Support for variable move commands. e.g. moveright, moveup, movedownleft, movenortheast
      
if (data[0].starts("move")) {
        
// Determine Direction
        
if (data[0].pos("east") >= || data[0].pos("right") >= 0temp.dx 1;
        else if (
data[0].pos("west") >= || data[0].pos("left") >= 0temp.dx = -1;
        if (
data[0].pos("north") >= || data[0].pos("up") >= 0temp.dy = -1;
        else if (
data[0].pos("south") >= || data[0].pos("down") >= 0temp.dy 1;
        
// Check for Valid Deltas
        
if (temp.dx != || temp.dy != 0) {
          
temp.dx *= data[1] == data[1];
          
temp.dy *= data[1] == data[1];
          
doMove(temp.dxtemp.dy);
        }
      }
      break;
  }
}

// Movement Functions

function npc_stop() {
  
this.is_stopped true;
  
this.oani this.ani;
  
this.odir this.dir;
  
setcharani(this.ani_idle"");
}

function 
npc_continue() {
  
this.is_stopped false;
  
this.dir this.odir;
  
this.ani this.oani;
  
onMovementFinished();
}

function 
GetDistance(temp.x1temp.y1temp.x2temp.y2) {
  
temp.toreturn = (temp.x2 temp.x1) ^ + (temp.y2 temp.y1) ^ 2;
  return (
temp.toreturn) ^ .5;
}

function 
doMove(dxdy) {
  
temp.distance GetDistance(this.xthis.ythis.dxthis.dy);
  
temp.time distance this.speed;
  
this.dir getRealDir(dxdy);
  
move(dxdytemp.time8);
  if (
this.ani != this.ani_walksetcharani(this.ani_walk"");
  if (!
this.reversingthis.moves.add({dxdy});
}

function 
getRealDir(dxdy) {
  if (
dy && dx 0) return 3;
  if (
dy && dx 0) return 3;
  if (
dy && dx 0) return 1;
  if (
dy && dx 0) return 2;
  return 
getdir(dxdy);
}

function 
onMovementFinished() {
  if (
this.is_stopped || this.waiting) return;
  
temp.next_action this.actions[this.actionpos+1];
  if (
temp.next_action.pos("move") == -&& !this.reversing) {
    
setcharani(this.ani_idle"");
  }
  if (
this.reversing) {
    
this.reversepos--;
    if (
this.reversepos <= -1) {
      
this.reversing false;
      
this.moves "";
      
setcharani(this.ani_idle"");
      return 
onNextStep();
    }
    
temp.move this.moves[this.reversepos];
    return 
doMove(-temp.move[0], -temp.move[1]);
  }
  else 
onNextStep();
}

// Action Related Functions

function onClearChat() {
  
this.chat "";
}

function 
onClearEmote() {
  
hideimg(200);
}

function 
onNextStep(done_waiting) {
  if (
this.waiting && done_waiting) {
    
this.waiting false;
  }
  if (
this.is_stopped) return;
  
this.actionpos++;
  
doAction(this.actionpos);



Draenin 06-08-2015 10:29 PM

Quote:

Originally Posted by fowlplay4 (Post 1736318)
Added support for more verbose move commands.

e.g. movewest, moveup, movedownright, movenorth, etc.

move[up|down|left|right|north|east|west|south|][up|down|left|right|north|east|west|south|]

You can also specify an amount of tiles to move, otherwise it just moves by 1 tile.

I seriously cannot give you enough rep for this improvement. If people aren't using this script already, they definitely should be doing so right about now. :D

scriptless 06-09-2015 12:30 AM

;)Yeah this script is great. I made a slight addition to the script on N-Pulse so I could join to a class with this script in it. And in my script that the class joins from I can add new commands, and use them without having to edit the class.

PHP Code:

case "func":
  (@
data[1])(data[2]);
break; 


BlueMelon 06-09-2015 06:56 PM

Quote:

Originally Posted by scriptless (Post 1736648)
;)Yeah this script is great. I made a slight addition to the script on N-Pulse so I could join to a class with this script in it. And in my script that the class joins from I can add new commands, and use them without having to edit the class.

PHP Code:

case "func":
  (@
data[1])(data[2]);
break; 


ohman
might want to add a whitelist to data[1]


All times are GMT +2. The time now is 12:02 PM.

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2025, vBulletin Solutions Inc.
Copyright (C) 1998-2019 Toonslab All Rights Reserved.