Graal Forums  

Go Back   Graal Forums > Development Forums > NPC Scripting > Code Gallery
FAQ Members List Calendar Search Today's Posts Mark Forums Read

Reply
 
Thread Tools Search this Thread Display Modes
  #1  
Old 04-29-2009, 09:36 PM
fowlplay4 fowlplay4 is offline
team canada
fowlplay4's Avatar
Join Date: Jul 2004
Location: Canada
Posts: 5,200
fowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond repute
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.
__________________
Quote:

Last edited by fowlplay4; 04-30-2009 at 12:19 AM..
Reply With Quote
  #2  
Old 04-29-2009, 09:43 PM
cbk1994 cbk1994 is offline
the fake one
cbk1994's Avatar
Join Date: Mar 2003
Location: San Francisco
Posts: 10,718
cbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond repute
Send a message via AIM to cbk1994
Why not just use move() serverside for syncing to other players?

Looks good, though you should use GS2 for showing the character, not GS1.
__________________
Reply With Quote
  #3  
Old 04-29-2009, 09:55 PM
fowlplay4 fowlplay4 is offline
team canada
fowlplay4's Avatar
Join Date: Jul 2004
Location: Canada
Posts: 5,200
fowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond repute
Quote:
Originally Posted by cbk1994 View Post
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.
__________________
Quote:
Reply With Quote
  #4  
Old 04-29-2009, 11:02 PM
Gambet Gambet is offline
Registered User
Join Date: Oct 2003
Posts: 2,712
Gambet is on a distinguished road
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.
Reply With Quote
  #5  
Old 04-29-2009, 11:04 PM
cbk1994 cbk1994 is offline
the fake one
cbk1994's Avatar
Join Date: Mar 2003
Location: San Francisco
Posts: 10,718
cbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond repute
Send a message via AIM to cbk1994
Quote:
Originally Posted by fowlplay4 View Post
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)
__________________
Reply With Quote
  #6  
Old 04-30-2009, 12:11 AM
fowlplay4 fowlplay4 is offline
team canada
fowlplay4's Avatar
Join Date: Jul 2004
Location: Canada
Posts: 5,200
fowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond repute
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.
__________________
Quote:
Reply With Quote
  #7  
Old 12-28-2012, 06:30 AM
fowlplay4 fowlplay4 is offline
team canada
fowlplay4's Avatar
Join Date: Jul 2004
Location: Canada
Posts: 5,200
fowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond repute
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();

__________________
Quote:
Reply With Quote
  #8  
Old 01-04-2013, 09:53 PM
MysticalDragon MysticalDragon is offline
Global Administration
MysticalDragon's Avatar
Join Date: Oct 2002
Location: Lynn Ma
Posts: 883
MysticalDragon is just really niceMysticalDragon is just really nice
Send a message via AIM to MysticalDragon Send a message via MSN to MysticalDragon
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
__________________
~Delteria Support
~Playerworld Support
~PWA Chief
http://support.toonslab.com
[email protected]



Reply With Quote
  #9  
Old 01-11-2013, 10:27 PM
Stowen Stowen is offline
Graalian since '01
Join Date: Sep 2005
Location: Massachusets, USA
Posts: 156
Stowen will become famous soon enough
Send a message via AIM to Stowen Send a message via MSN to Stowen
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.
__________________
Quote:
Originally Posted by Felix_Xenophobe View Post
He is no carpenter's son but Stowen will breathe life into pc graal.
Unholy Nation is my home.
Reply With Quote
  #10  
Old 01-13-2013, 05:53 AM
Draenin Draenin is offline
Magnificent Bastard
Draenin's Avatar
Join Date: Dec 2004
Location: Bermuda Triangle
Posts: 6,790
Draenin has much to be proud ofDraenin has much to be proud ofDraenin has much to be proud ofDraenin has much to be proud ofDraenin has much to be proud ofDraenin has much to be proud of
Send a message via AIM to Draenin Send a message via MSN to Draenin Send a message via Yahoo to Draenin
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?
Reply With Quote
  #11  
Old 01-13-2013, 06:30 AM
fowlplay4 fowlplay4 is offline
team canada
fowlplay4's Avatar
Join Date: Jul 2004
Location: Canada
Posts: 5,200
fowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond repute
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.
__________________
Quote:
Reply With Quote
  #12  
Old 05-19-2015, 10:40 PM
fowlplay4 fowlplay4 is offline
team canada
fowlplay4's Avatar
Join Date: Jul 2004
Location: Canada
Posts: 5,200
fowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond repute
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);

__________________
Quote:
Reply With Quote
  #13  
Old 06-08-2015, 10:29 PM
Draenin Draenin is offline
Magnificent Bastard
Draenin's Avatar
Join Date: Dec 2004
Location: Bermuda Triangle
Posts: 6,790
Draenin has much to be proud ofDraenin has much to be proud ofDraenin has much to be proud ofDraenin has much to be proud ofDraenin has much to be proud ofDraenin has much to be proud of
Send a message via AIM to Draenin Send a message via MSN to Draenin Send a message via Yahoo to Draenin
Quote:
Originally Posted by fowlplay4 View Post
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.
Reply With Quote
  #14  
Old 06-09-2015, 12:30 AM
scriptless scriptless is offline
Banned
Join Date: Dec 2008
Location: N-Pulse
Posts: 1,412
scriptless is a splendid one to beholdscriptless is a splendid one to beholdscriptless is a splendid one to beholdscriptless is a splendid one to behold
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; 
Reply With Quote
  #15  
Old 06-09-2015, 06:56 PM
BlueMelon BlueMelon is offline
asdfg
BlueMelon's Avatar
Join Date: Sep 2008
Posts: 1,481
BlueMelon is a splendid one to beholdBlueMelon is a splendid one to beholdBlueMelon is a splendid one to beholdBlueMelon is a splendid one to behold
Quote:
Originally Posted by scriptless View Post
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]
__________________
http://i.imgur.com/OOJbW.jpg
Reply With Quote
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 07:36 AM.


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