Graal Forums  

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

 
 
Thread Tools Search this Thread Display Modes
Prev Previous Post   Next Post Next
  #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
 

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 01:57 AM.


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