Graal Forums  

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

Reply
 
Thread Tools Search this Thread Display Modes
  #1  
Old 03-18-2010, 10:55 PM
Gambet Gambet is offline
Registered User
Join Date: Oct 2003
Posts: 2,712
Gambet is on a distinguished road
GBaddy v.3.0.

Read about version one.
Read about version two.

Updates

. Code optimization: Restyled the script to make it more legible, added some new comments, and I added checks for onwater() via the new function:

- checkBlockedTile(xValue, yValue) - boolean - checks if the denoted tile is not walkable

I also added the following function:

- resetIfBaddyGetsStuck() - Automatically called to reset the baddy if it gets stuck on a wall, gets stuck in water, or gets glitched due to things like players pausing in the middle of battle and such.

. Smarter AI: The baddy has a greater chance of healing itself once it's in a weak state (1/3 of its total hp or less). Also, although there are instances where you can put the baddies in a glitched state, they will no longer remain glitched thanks to the newly added resetIfBaddyGetsStuck() function.

Important: As suggested by Jerret (fowlplay4), I added a string in the onCreated() function (this.className) that you can change to whatever name you plan on calling the class so that the script will function properly without needing to change anything else (I didn't bother to add any of the chat stuff that he suggested since it seems like it would be a silly thing to include). Also, you need to remove the period in the middle of: function onWas.Hit().

I don't remember if I changed or added anything else, but this version is much better than the previous ones. It isn't anywhere near perfect, but this is something where I generally just change things around or add things to it, I don't really have much drive to rescript it so look at it as a learning source.

PHP Code:
/*
 *GBaddy - v.3.0
 *@author Gambet
*/

enum {
  
WALK,
  
ATTACK,
  
DEAD
}

function 
onCreated() {
  
this.className "public_gambet_gbaddy"//Change this string to match the name of the class this script is in
  
  
showcharacter();
  
this.bodyimg "body2.png";
  
this.shieldimg "no-shield.png";
  
this.nick "gBaddy";
  
this.ap 0;
  
this.health = {1010}; //{Current Health, Maximum Health}
  
this.mov_speed 0.45//The larger the number, the faster the baddy moves
  
this.count int(random(1040));
  
this.start_coordinates = {this.xthis.y};
  
this.mode WALK;
 
  for (
temp.0temp.5temp.a++) this.colors[a] = "black";
  if (
this.ani != "idle"setcharani("idle","");
  
  
setTimer(0.1);
}

function 
onPlayerEnters() {
  
onTimeOut(); //Wake up the NPC (in case it was sleeping due to no players being in the level)
  
this.headimg "head" int(random(01000)) @ ".png"//NPC changes head image each time you enter the level
}

function 
onTimeOut() {
  if (
players.size() > 0
    
setTimer(0.1);
  else
    
setTimer(0); //Sleep if no players in level
    
  
if (this.mode == WALK) { //Baddy walks around the level when no player is within its attack radius
    
this.to_check findnearestplayer(this.xthis.y);
    
temp.new_x this.vecx(this.dir) * this.mov_speed;
    
temp.new_y this.vecy(this.dir) * this.mov_speed;
    
this.count--;
    
    if (
this.count 0) {
      
temp.to_add_x new_x 1.5 vecx(this.dir);
      
temp.to_add_y new_y vecy(this.dir);
      
      if (
checkBlockedTile(to_add_xto_add_y)) 
        
this.dir = (this.dir 2) % 4;
      else {
        
setcharani("walk""");
        
this.new_x;
        
this.new_y;
      }
    } else {
      
this.count int(random(1040));
      
this.dir = (this.dir int(random(02)) * 2) % 4;
    }
    
    
resetIfBaddyGetsStuck();
  } else if (
this.mode == ATTACK) { //Attack targeted player
    
this.plyr this.to_check;
    
this.dist_x this.plyr.this.x;
    
this.dist_y this.plyr.this.y;
    
this.len = (this.dist_x this.dist_x this.dist_y this.dist_y) ^ 0.5;
    
this.add_x = (this.dist_x this.len);
    
this.add_y = (this.dist_y this.len);
    
this.check_x this.1.5;
    
this.check_y this.2;    
     
    if (!
checkBlockedTile(this.check_x+this.add_xthis.check_y+this.add_y)) {
      
damagePlayer();
      
moveBaddy();
    } else if ((!
checkBlockedTile(this.check_x+this.add_xthis.check_y)) || (!checkBlockedTile(this.check_xthis.check_y+this.add_y))) {
      
damagePlayer();
    }
    
    if ((
this.health[1] / 3) >= this.health[0]) { //If low on health and other gbaddies in level, call for help
      
for (nnpcs) {
        if (
n.isinclass(this.className)) {
          if (
n.mode != ATTACK) { //Check to see if gbaddy being called for help isn't already attacking a player
            
n.mode ATTACK;
            
this.chat "Help!";
            
n.to_check this.plyr;
          }
        }
      }
    }
    
    
resetIfBaddyGetsStuck();
  }
  
  if (
this.mode != DEAD && this.mode != ATTACK) {
    if (
this.to_check.x in |this.x-10this.x+10| && this.to_check.y in |this.y-10this.y+10|) { //Aggro radius - gbaddy will attack a player within this range
      
if (this.mode != ATTACKthis.mode ATTACK;
    } else
      
this.mode WALK;
  }
  
  
setTimer(0.1); 
}

function 
moveBaddy() {
  
setcharani("walk""");
  
this.+= this.add_x * (this.mov_speed 0.6);
  
this.+= this.add_y * (this.mov_speed 0.6);

  if (
abs(this.dist_x) > abs(this.dist_y)) {
    if (
this.dist_x 0
      
this.dir 3
    else 
      
this.dir 1;
  } else {
    if (
this.dist_y 0
      
this.dir 2
    else 
      
this.dir 0;
  }
  
  if (
this.resetTimer != ""this.resetTimer "";


function 
damagePlayer() { //Controls how the gbaddy reacts to the player (the gbaddy either damages the player or heals itself)
  
temp.randomize = (this.health[0] <= (this.health[1] / 3)) ? int(random(80101)) : int(random(0101)); //Greater chance of gbaddy healing itself when weak
  
temp.plyr findPlayer(this.plyr);

  if (
plyr.hearts 0) {
    if (
randomize in |094|) //Attack player with sword
      
setcharani("sword""");
    else if (
randomize in |9498|) //Cause explosion 
      
putexplosion2(33this.xthis.y);
    else if (
randomize in |98101|) { //Heal
      
if (this.health[0] < this.health[1]) {
        if ((
this.health[0] + 5) < this.health[1]) healBaddy(int(random(06)));
        else if ((
this.health[0] + 5) >= this.health[1]) healBaddy(this.health[1]);
      }
    }
  } else
    
baddyReset();


function 
healBaddy(amount) { //The gbaddy can heal itself as one of its possible actions
  
if ((this.health[0] + amount) < this.health[1]) {
    
this.health[0] += amount;
    
this.chat "*Healed for " amount "*";
  } else {
    
this.health[0] = amount;
    
this.chat "*Fully Healed*";
  }
  
  
setcharani("lift""");
  
scheduleevent(1"HideChat""idle");
}

function 
resetIfBaddyGetsStuck() {
  if (
this.checkCoords[0] != this.&& this.checkCoords[1] != this.y) {
    
this.checkCoords = {this.xthis.y};
    
this.resetTimer "";
  } else {
    
this.resetTimer += 1/100;
    if (
this.resetTimer >= 0.4baddyReset();
  }
}

function 
baddyReset() {
  
this.this.start_coordinates[0];
  
this.this.start_coordinates[1];
  
this.health[0] = this.health[1];
  
this.mode WALK;
  
this.resetTimer "";
}

function 
onWas.Hit() { //gBaddy is attacked by a player's sword
  
if (this.health[0] - ((player.swordpower 2) + 0.5) > 0) {
    if (
this.ani != "hurt") {
      
setcharani("hurt""");
      
temp.knockbackAmount 3;
      switch(
this.plyr.dir) { //Knockback
        
case "2":
          if (!
checkBlockedTile(this.xthis.y+knockbackAmount)) 
            
this.+= knockbackAmount;
        break;
        case 
"0":
          if (!
checkBlockedTile(this.xthis.y-knockbackAmount))
            
this.-= knockbackAmount;
        break;
        case 
"1":
          if (!
checkBlockedTile(this.x-knockbackAmountthis.y))
            
this.-= knockbackAmount;
        break;
        case 
"3":
          if (!
checkBlockedTile(this.x+knockbackAmountthis.y))        
            
this.+= knockbackAmount;
        break;
      }
      
scheduleevent(1"Counter""");
    }
          
    
this.health[0] -= (player.swordpower 2) + 0.5;
    
this.chat this.health[0] @ "/" this.health[1];
    
scheduleevent(2"HideChat""");
  } else {
    if (
this.mode != DEAD) {
      
this.mode DEAD;
      
this.health[0] = 0;
      
setcharani("dead""");
      
this.chat this.health[0] @ "/" this.health[1];
      
scheduleevent(8"Respawn""");
    }
  }
}

function 
checkBlockedTile(xValueyValue) { //Check if tile is not walkable 
  
if (onwall(xValueyValue) || onwater(xValueyValue)) 
    return 
true;
  else 
    return 
false;
}

function 
onRespawn() {
  if (
this.mode == DEAD) {
    
setcharani("idle","");
    
this.chat "";
    
this.health[0] = this.health[1];
    
this.mode WALK;
  }
}

function 
onCounter() {
  if (
this.health[0] > 0setcharani("sword","");
}

function 
onHideChat() {
  if (
params[0] == "idle") {
    
this.chat "";
    
setcharani("idle""");
  } else {
    
this.chat "";
  }


Enjoy.
Reply With Quote
  #2  
Old 03-19-2010, 01:33 AM
jkldogg jkldogg is offline
J.Rollin (killaz)
jkldogg's Avatar
Join Date: Feb 2010
Location: USA
Posts: 675
jkldogg can only hope to improve
Send a message via AIM to jkldogg Send a message via MSN to jkldogg
anyway to make guns hurt the baddy instead of swords?
__________________

PSN: jkldogg



The best post ever made on the graal forums.
After playing Graal Online for many years, JKL decides to make a forum account. Isn't life funny?
Reply With Quote
  #3  
Old 03-19-2010, 01:40 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
Quote:
Originally Posted by jkldogg View Post
anyway to make guns hurt the baddy instead of swords?
Projectiles that hit it will trigger onActionProjectile(), and depending on the parameters of the projectiles you can have it react accordingly.

Also if the projectile is shot on the server-side it will also trigger onActionSProjectile().

PHP Code:
// NPC was hit by a shoot projectile that originated on the client-side.
function onActionProjectile() {
  
// Handle accordingly
}

// NPC was hit by a shoot projectile that originated on the server-side.
function onActionSProjectile() {
  
// Handle accordingly

__________________
Quote:
Reply With Quote
  #4  
Old 03-19-2010, 05:45 PM
DrakilorP2P DrakilorP2P is offline
Registered User
DrakilorP2P's Avatar
Join Date: Apr 2006
Posts: 755
DrakilorP2P is just really niceDrakilorP2P is just really nice
Quote:
Originally Posted by fowlplay4 View Post
Projectiles that hit it will trigger onActionProjectile(), and depending on the parameters of the projectiles you can have it react accordingly.

Also if the projectile is shot on the server-side it will also trigger onActionSProjectile().

PHP Code:
// NPC was hit by a shoot projectile that originated on the client-side.
function onActionProjectile() {
  
// Handle accordingly
}

// NPC was hit by a shoot projectile that originated on the server-side.
function onActionSProjectile() {
  
// Handle accordingly

I think this should be built into the next version.
Reply With Quote
  #5  
Old 04-22-2012, 04:47 AM
r3ckless r3ckless is offline
Owner of Corinthia
Join Date: Dec 2011
Location: MAssachusetts, USA
Posts: 131
r3ckless is an unknown quantity at this point
Send a message via AIM to r3ckless Send a message via MSN to r3ckless
Sorry to revive this, but for some reason the baddy doesn't hurt the player when it uses it's sword? Any idea's on a fix to this?

Again, sorry to reply to such an old thread.
__________________

Yep.

Reply With Quote
  #6  
Old 04-22-2012, 04:58 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
If you use replaceani("sword", "somethingelse"); then "sword" doesn't hurt as an ani anymore.

The script doesn't actually use hitobjects() or anything like that to actually hit the player. You can modify that behavior where it changes it's ani to sword.
__________________
Quote:
Reply With Quote
  #7  
Old 04-22-2012, 05:11 AM
r3ckless r3ckless is offline
Owner of Corinthia
Join Date: Dec 2011
Location: MAssachusetts, USA
Posts: 131
r3ckless is an unknown quantity at this point
Send a message via AIM to r3ckless Send a message via MSN to r3ckless
I figured it out, you need to add "this.swordpower" or the sword won't work properly. Thank you, though.
__________________

Yep.

Reply With Quote
Reply


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 03:30 PM.


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