Decided to script a typical baddy.
Features :
- Highlight customizable settings
- Sword and Bow attacks
- Solid wall detection
- Goes ‘agro’ on anyone near him swinging his sword if he happens to be hit(AKA cheap ‘chase player that hit me detection’)
- Cuts down bushes in his path to try to reach you
Also taking any suggestions to improve him!
[php]
i// NPC made by Shiny
if (created) {
showcharacter;
setcharprop #n,Bad Guy; // Name
setcharprop #1,sword1.png; // Sword image
setcharprop #2,shield1.png; // Shield image
setcharprop #3,head1212.png; // Head image
setcharprop #8,body.png; // Body image
setcharprop #C0,black; // Skin color
setcharprop #C1,black; // Coat color
setcharprop #C2,black; // Sleeve color
setcharprop #C3,black; // Shoe color
setcharprop #C4,black; // Belt color
swordpower = 1; // Sword power
dir = 2; // Starting direction
hearts = 3; // Heart count
darts = 5; // Dart count
this.speed = .45; // Chase speed
this.sight = 15; // How far it can see
this.bowcooldown = 2; // How long between shooting
this.bowfreezetime = .5; // Freeze time from shooting
this.swordfreezetime = .35; // Freeze time from swinging sword
this.hurtrecoil = .35; // How long they recoil from a hit
this.hurtpause = .75; // How long they freeze from a hit
this.patience = 5; // How long they will wait until giving up when they can’t get to player
setstring this.animations,idle,walk,walk,sword2,shoot,hurt,dead;
this.orghearts = hearts;
this.orgdarts = darts;
this.mode = 0;
this.freezetimer = 0;
hurtdx = 0;
hurtdy = 0;
this.bushtiles = {
0x2, 0x3,
0x12, 0x13,
0x35E,0x35F,
0x36E,0x36F,
0xA02,0xA03,
0xA12,0xA13,
};
this.bushreplace = {
0x2A5,0x2A6,
0x2B5,0x2B6,
0x388,0x389,
0x389,0x388,
0xC90,0xC91,
0xCA0,0xCA1,
};
timeout = 0.05;
}
if (playerenters) {
if (hearts <= 0) {
hearts = this.orghearts;
hurtdx = 0;
hurtdy = 0;
this.target = -1;
darts = this.orgdarts;
this.freezetimer = 0;
this.mode = 0;
}
timeout = 0.05;
}
if (timeout) {
if (this.mode != 6) {
if (this.freezetimer =< 0){
if (this.mode == 0) {
this.target = -1;
FindPlayer();
} else if (this.mode == 2) {
if (this.target == -1 || players[this.target].hearts <= 0) this.mode = 0;
dx = (players[this.target].x+1.5) - (x+1.5);
dy = (players[this.target].y+2) - (y+2);
dist = (dx^2 + dy^2)^.5;
dir = getdir(dx,dy);
if (dist =< 4 || (dist < 5 && strequals(#m(this.target),sword2))) {
CheckBushes();
this.mode = 3;
this.freezetimer = this.swordfreezetime;
}
this.cansee = 1;
for (i=1;i<((dist < this.sight) ? int(dist) : this.sight);i++) {
if (onwall(x+1.5+(dx/dist)*i+.5,y+2+(dy/dist)*i+.5)) this.cansee = 0;
}
if (this.cansee == 0) this.findtolerance += 0.05;
else this.findtolerance = 0;
if (this.findtolerance > this.patience) this.mode = 0;
if (dist > 3) {
if (dist > this.sight) {
if (this.shootcooldown <= 0 && darts>0 && ((dir in {0,2} && abs(dx) < 2) || (dir in {1,3} && abs(dy) < 2))) {
shootarrow dir;
darts--;
this.mode = 4;
this.freezetimer = this.bowfreezetime;
this.shootcooldown = this.bowcooldown;
}
this.farchase += 0.05;
} else {
this.shootcooldown = 0;
this.farchase = 0;
}
if (this.farchase > this.patience) this.mode = 0;
if (!onwall2(x+.5+(1/16)+vecx(dx>0?3:1)*this.speed,y+1+(1/16),2-2/16,2-2/16)) x += (dx/dist)*this.speed;
else x = int(x)+.5;
if (!onwall2(x+.5+(1/16)+,y+1+(1/16)+vecy(dy>0?2:0)*this.speed,2-2/16,2-2/16)) y += (dy/dist)*this.speed;
else y = int(y+.5);
CheckBushes();
}
} else if (this.mode in {3,4,5}) {
if (this.freezetimer == 0) this.mode = 2;
}
if(!strequals(#m(-1),#I(this.animations,this.mode))) setcharani #I(this.animations,this.mode),;
} else if (this.mode == 5) {
if (!onwall2(x+.5+vecx(hurtdx>0?3:1),y+1,2,2)) x += hurtdx;
else x = int(x)+.5;
if (!onwall2(x+.5,y+1+vecy(hurtdy>0?2:0),2,2)) y += hurtdy;
else y = int(y+.5);
}
if (this.shootcooldown > 0) this.shootcooldown -= 0.05;
if (this.freezetimer > 0) this.freezetimer -= 0.05;
if (this.hurtcounter > 0) this.hurtcounter -= 0.05;
else if (this.mode == 5) this.mode = 2;
}
timeout = 0.05;
}
if (washit && this.mode!=5 && hearts > 0) {
hearts -= playerswordpower/2;
if (hearts <= 0) {
this.mode = 6;
setcharani dead,;
dontblock;
} else {
dx = (x+1.5)-(playerx+1.5);
dy = (y+2)-(playery+2);
dist = (dx^2 + dy^2)^.5;
hurtdx = dx/dist;
hurtdy = dy/dist;
this.mode = 5;
this.freezetimer = this.hurtpause;
this.hurtcounter = this.hurtrecoil;
setcharani hurt,;
if (this.target == -1) FindPlayer();
}
}
function FindPlayer() {
for (i=0;i<playerscount;i++) {
if (players[i].hearts>0 && players[i].id>=0) {
dx = (players[i].x+1.5) - (x+1.5);
dy = (players[i].y+2) - (y+2);
dist = (dx^2 + dy^2)^.5;
checkdir = getdir(dx,dy);
this.agro = this.mode == 5 && this.target == -1;
if (this.agro == 1) {
if (strequals(#m(i),sword2)) {
if (dist < this.sight) this.target = i;
}
} else {
if (dist < this.sight && checkdir == dir) {
this.cansee = 1;
for (j=1;j<((dist < this.sight) ? int(dist) : this.sight);j++) {
if (onwall(x+1.5+(dx/dist)*j+.5,y+2+(dy/dist)*j+.5)) this.cansee = 0;
}
if (this.cansee == 1) {
this.target = i;
this.mode = 2;
break;
}
}
}
}
}
}
function CheckBushes() {
bushtype = -1;
px = int(x+(dir==1? -0.5: (dir==3? 3.5: 1.5)));
py = int(y+(dir==0? 0: (dir==2? 4: 2)));
for (i=0; i<(arraylen(this.bushtiles)-1)/4; i++) {
for (j=0;j<4;j++) {
if (tiles[px,py] == this.bushtiles[(i4)+j]) {
bushtype = i;
break;
}
}
}
if (bushtype >= 0) {
this.mode = 3;
this.freezetimer = this.swordfreezetime;
for (i=0;i<4;i++) {
if (tiles[px-1+(i%2),py-1+int(i/2)] == this.bushtiles[bushtype4]) {
px = px-1+(i%2);
py = py-1+int(i/2);
break;
}
}
replacebush = true;
for (i=0;i<4;i++) {
if (tiles[px+i%2,py+int(i/2)] != this.bushtiles[(bushtype4)+i]) {
replacebush = false;
break;
}
}
if (replacebush == true) {
for (i=0;i<4;i++) {
tiles[px+i%2,py+int(i/2)] = this.bushreplace[(bushtype4)+i];
}
putleaps 0,px,py;
updateboard px,py,2,2;
}
}
}
[/php]
I may also be posting more enemies here that function differently from your typical character baddy.
Interesting tidbit: Did you know the custom NPC baddies(placed with the editor) have some sort of makeshift, minimal pathfinding detection? I’ve been playing with them in my test level and they can do a decent job of navigating around obstacles, regardless of where I am. They almost ‘follow’ my path around things. It’s interesting, and I never really noticed it.