ID:139779
 
Code:
mob
rat
hp=5
maxhp=5
icon='ICONS.dmi'
icon_state="Rat"
attackable=1
xpgiven=1
New()
walkloop
var/mob/M
var/walky = rand(1,8)
for(M as mob in get_step(src,src.dir))
if(!M.client){goto nxt}
M.hp -= 1
if(M.hp <= 0) {
oview()<<"<font color=red>[src] has killed [M]!"
if(!M.client){del(M);goto nxt}
M.loc = locate(1,1,2)
M.hp = M.maxhp
}
nxt
var/mob/P
for(P in oview(1))
if(P.client) {
dir = get_dir(src,P)
sleep(4)
goto walkloop
}
for(P in view())
if(P.client) {
step_to(src,P)
sleep(3)
goto walkloop
}
if(walky == 1) {
step(src,NORTH)
sleep(10)
goto walkloop
}
if(walky == 2) {
step(src,SOUTH)
sleep(10)
goto walkloop
}
if(walky == 3) {
step(src,EAST)
sleep(10)
goto walkloop
}
if(walky == 4) {
step(src,WEST)
sleep(10)
goto walkloop
}
if(walky == 5) {
step(src,NORTHWEST)
sleep(10)
goto walkloop
}
if(walky == 6) {
step(src,NORTHEAST)
sleep(10)
goto walkloop
}
if(walky == 7) {
step(src,SOUTHWEST)
sleep(10)
goto walkloop
}
if(walky == 8) {
step(src,SOUTHEAST)
sleep(10)
goto walkloop
}


Problem description: Well, as long as you're right next to the enemy, they'll attack you, but they won't chase you. Anyone know why?

Well... I wrote this out pretty quick (last 10 minutes). If you copy/paste any part of it, do so at your own risk. A couple quick points...

- Reduce your code by sharing variables and procs between mobs and especially your monsters.

- Use walk_rand to move your mobs around randomly

- Trigger monsters as players get near them. You can also improve performance by placing triggers around your world which let the player know when they should or shouldn't be looking for monsters. While in a safe town, there may be no need to look for monsters.

- If a monster is triggered but the player leaves the area, put the monster to sleep after a short time. This help with perf.


mob
{
icon='icons.dmi'
density = 1
var
{
m_iTickSpeed;
m_iLag;
m_HP;
}
proc
{
AttackSelf(var/damage)
{
m_HP -= damage
if (m_HP < 1)
{
KillSelf();
}
}
KillSelf()
{
// Do what ever...
}
}
player
{
icon_state="player"
New()
{
m_HP = 100;
m_iTickSpeed = 10;
PlayerTick()
..();
}
proc
{
PlayerTick()
{
//
// Are there any monsters near me?
//
for(var/mob/monster/m in view(8))
{
//
// If I'm idle, give me something to do
// otherwise, leave me alone, I'm already doing stuff
//
if (m.m_sStatus == "idle")
{
m.m_sStatus = "busy";
m.MonsterTick(); // Kick start monster into action
}
}
Spawn(m_iTickSpeed)
{
PlayerTick()
}
}
}
}
monster
{
var
{
m_sStatus = "idle";
m_iTickSpeed;
m_iLag;
m_iAttackRange;
m_iAttackPower;
m_iIdleTimeout;
mob/m_Target
}
rat
{
icon_state = "Rat"
New()
m_iTickSpeed = 10;
m_iLag = 1;
m_iAttackRange = 3;
m_iAttackPower = roll(1d4); // Randomize every rats attack power so you never know exactly what your up against.
..()
}
proc
{
//
// Every monster will time out after 30 seconds of no activity
//
MonsterTick(var/iIdleTimeout = 30)
{
//
// Do I already have a target?
//
if (!m_Target)
{
//
// Look for all players around me
//
for(var/mob/player/p in view(8))
{
iIdleTimeout = 30; // Reset
//
// Is this player close enough for me to attack
//
if (get_dist(src, p) <= m_iAttackRange)
{
m_Target = p;
break;
}
}
}
//
// Do I have a target to go after or should I walk randomly?
//
if (m_Target)
{
dir = get_dir(src, m_Target); // Face the target

//
// Am I close enough to attack?
//
if (get_dist(src, m_Target) <= 1)
{
m_Target.AttackSelf(m_iAttackPower); // Player handles attacks against himself so he can handle his own death as well.
}
else
{
walk_to(src, m_Target, 1, m_iLag)
}
}
else
{
walk_rand(src, iLag);
}
//
// If we spent too much time doing nothing, stop what Im doing and save resources.
//
if (iIdleTimeout--)
{
Spawn(m_iTickSpeed)
{
MonsterTick(iIdleTimeout);
}
}

m_sStatus = "idle"; // Returning to idle state
}
}
}
}
Never, ever, ever use goto. For any purpose. Ever.
In response to Garthor
mob
rat
hp=5
maxhp=5
icon='ICONS.dmi'
icon_state="Rat"
attackable=1
xpgiven=1
New()
var/mob/M
walk_rand(src,4)
for(M as mob in get_step(src,src.dir))
if(!M.client)
var/mob/P
for(P in oview(1))
if(P.client) {
dir = get_dir(src,P)
sleep(4)
}
for(P in view())
if(P.client) {
step_to(src,P)
sleep(3)
}
M.hp -= 1
if(M.hp <= 0)
oview()<<"<font color=red>[src] has killed [M]!"
if(!M.client)
M.loc = locate(1,1,2)
M.hp = M.maxhp
var/mob/P
for(P in oview(1))
if(P.client) {
dir = get_dir(src,P)
sleep(4)
}
for(P in view())
if(P.client) {
step_to(src,P)
sleep(3)
}


Alright, so I just posted the things wherever the goto variable was, so it goes to them. Now what? The enemy doesn't even face them to attack now.
In response to Colin1011
In response to Tsfreaks
        proc
{
PlayerTick()
{
//
// Are there any monsters near me?
//
for(var/mob/monster/m in view(8))
{
//
// If I'm idle, give me something to do
// otherwise, leave me alone, I'm already doing stuff
//
if (m.m_sStatus == "idle")
{
m.m_sStatus = "busy";
m.MonsterTick(); // Kick start monster into action
}
}
Spawn(m_iTickSpeed)
{
PlayerTick()
}
}
}
}

For that part of the code, it says 'proc definition not allowed inside another proc.' For line 58, which is the '{' between Spawn(m_iTickSpeed) and PlayerTick().
In response to Colin1011
then fix it, the indentation is just messed up, if you're going to try to make a game right now this should haveshould been a no-brainer.
In response to Masschaos100
Just because you know what's going on doesn't mean I do. I went over all the indentation, and even made sure I had used tab on every line. It's not working.
In response to Colin1011
try this:

mob
{
icon='icons.dmi'
density = 1
var
{
m_iTickSpeed;
m_iLag;
m_HP;
}
proc
{
AttackSelf(var/damage)
{
m_HP -= damage
if (m_HP < 1)
{
KillSelf();
}
}
KillSelf()
{
// Do what ever...
}
}
player
{
icon_state="player"
New()
{
m_HP = 100;
m_iTickSpeed = 10;
PlayerTick()
..();
}
proc//the indentation error was here, it SHOULD be fixed now unless there's something im not looking at
{
PlayerTick()
{
//
// Are there any monsters near me?
//
for(var/mob/monster/m in view(8))
{
//
// If I'm idle, give me something to do
// otherwise, leave me alone, I'm already doing stuff
//
if (m.m_sStatus == "idle")
{
m.m_sStatus = "busy";
m.MonsterTick(); // Kick start monster into action
}
}
Spawn(m_iTickSpeed)
{
PlayerTick()
}
}
}
}
monster
{
var
{
m_sStatus = "idle";
m_iTickSpeed;
m_iLag;
m_iAttackRange;
m_iAttackPower;
m_iIdleTimeout;
mob/m_Target
}
rat
{
icon_state = "Rat"
New()
m_iTickSpeed = 10;
m_iLag = 1;
m_iAttackRange = 3;
m_iAttackPower = roll(1d4); // Randomize every rats attack power so you never know exactly what your up against.
..()
}
proc
{
//
// Every monster will time out after 30 seconds of no activity
//
MonsterTick(var/iIdleTimeout = 30)
{
//
// Do I already have a target?
//
if (!m_Target)
{
//
// Look for all players around me
//
for(var/mob/player/p in view(8))
{
iIdleTimeout = 30; // Reset
//
// Is this player close enough for me to attack
//
if (get_dist(src, p) <= m_iAttackRange)
{
m_Target = p;
break;
}
}
}
//
// Do I have a target to go after or should I walk randomly?
//
if (m_Target)
{
dir = get_dir(src, m_Target); // Face the target

//
// Am I close enough to attack?
//
if (get_dist(src, m_Target) <= 1)
{
m_Target.AttackSelf(m_iAttackPower); // Player handles attacks against himself so he can handle his own death as well.
}
else
{
walk_to(src, m_Target, 1, m_iLag)
}
}
else
{
walk_rand(src, iLag);
}
//
// If we spent too much time doing nothing, stop what Im doing and save resources.
//
if (iIdleTimeout--)
{
Spawn(m_iTickSpeed)
{
MonsterTick(iIdleTimeout);
}
}

m_sStatus = "idle"; // Returning to idle state
}
}
}
}
In response to Masschaos100
mob
{
icon='ICONS.dmi'
density = 1
var
{
m_iTickSpeed;
m_iLag;
m_hp;
}
proc
{
AttackSelf(var/damage)
{
m_hp -= damage
if (m_hp < 1)
{
KillSelf();
}
}
KillSelf()
{
src<<"You got knocked out!"
src.loc=locate(1,1,2)
src.hp=src.maxhp
// Do what ever...
}
}
player
{
if(src.male==1)
icon_state="Player_male"
if(src.female==1)
icon_state="Player_female"
New()
{
m_hp = 100;
m_iTickSpeed = 10;
PlayerTick()
..();
}
proc
{
PlayerTick()
{
//
// Are there any monsters near me?
//
for(var/mob/monster/m in view(8))
{
//
// If I'm idle, give me something to do
// otherwise, leave me alone, I'm already doing stuff
//
if (m.m_sStatus == "idle")
{
m.m_sStatus = "busy";
m.MonsterTick(); // Kick start monster into action
}
}
Spawn(m_iTickSpeed)
{
PlayerTick()
}
}
}
}
monster
{
var
{
m_sStatus = "idle";
m_iTickSpeed;
m_iLag;
m_iAttackRange;
m_iAttackPower;
m_iIdleTimeout;
mob/m_Target
}
Rat
{
icon_state = "Rat"
New()
m_iTickSpeed = 10;
m_iLag = 1;
m_iAttackRange = 3;
m_iAttackPower = roll(1d4); // Randomize every rats attack power so you never know exactly what your up against.
..()
}
proc
{
//
// Every monster will time out after 30 seconds of no activity
//
MonsterTick(var/iIdleTimeout = 30)
{
//
// Do I already have a target?
//
if (!m_Target)
{
//
// Look for all players around me
//
for(var/mob/player/p in view(8))
{
iIdleTimeout = 30; // Reset
//
// Is this player close enough for me to attack
//
if (get_dist(src, p) <= m_iAttackRange)
{
m_Target = p;
break;
}
}
}
//
// Do I have a target to go after or should I walk randomly?
//
if (m_Target)
{
dir = get_dir(src, m_Target); // Face the target

//
// Am I close enough to attack?
//
if (get_dist(src, m_Target) <= 1)
{
m_Target.AttackSelf(m_iAttackPower); // Player handles attacks against himself so he can handle his own death as well.
}
else
{
walk_to(src, m_Target, 1, m_iLag)
}
}
else
{
walk_rand(src, iLag);
}
//
// If we spent too much time doing nothing, stop what Im doing and save resources.
//
if (iIdleTimeout--)
{
Spawn(m_iTickSpeed)
{
MonsterTick(iIdleTimeout);
}
}

m_sStatus = "idle"; // Returning to idle state
}
}
}
}

Now it has both Enemies.dm:42:error: inconsistent indentation or missing '}' and Enemies.dm:62:error: proc definition not allowed inside another proc...
In response to Colin1011
The brackets aren't balanced properly.
In response to Colin1011
I did you a favor and rewrote the whole thing(line by line) :D

mob
icon = 'icons.dmi'
density = 1
var
m_iTickSpeed
m_iLag
m_HP
proc
AttackSelf(var/damage)
m_HP -= damage
if(m_HP<1)
KillSelf()
KillSelf()
//Do Whatever
player
icon_state = "player"
New()
m_HP = 100
m_iTickSpeed = 10
PlayerTick()
..()
proc
PlayerTick()
//
//Are there any monsters near me?
//
for(var/mob/monster/m in oview(8))
//
//If I'm idle, give me something to do
//otherwise, leave me alone, I'm already doing stuff
//
if(m.m_sStatus == "idle")
m.m_sStatus = "busy"
m.MonsterTick()// Kick start monster into action
spawn(m_iTickSpeed)
PlayerTick()
monster
var
m_sStatus="idle"
m_iAttackRange
m_iAttackPower
m_iIdleTimeout
mob/tmp/m_Target//i changed this to tmp so no references are saved
rat
icon_state = "Rat"
New()
..()
m_iTickSpeed=10
m_iLag=1
m_iAttackRange = 39
m_iAttackPower = roll("1d4")
proc
MonsterTick(var/iIdleTimeout = 30)
//
//Do I already have a target?
//
if(!m_Target)
//
//Look for all players around me
//
for(var/mob/player/P in view(8))
iIdleTimeout = 30 // Reset
//
//Is this player close enough for me to attack?
//
if(get_dist(src, P) <= m_iAttackRange)
m_Target = P
break
//
//Do I have a target to go after or should i walk randomly?
//
if(m_Target)
dir = get_dir(src, m_Target)//Face the target.
//
//Am i close enough to attack?
//
if(get_dist(src, m_Target) <= 1)
m_Target.AttackSelf(m_iAttackPower)// Player handles attacks against himself so he can handle his own death as well.
else
walk_to(src, m_Target, 1, m_iLag)
else
walk_rand(src,m_iLag)
//
//If we spent too much time doing nothing, stop what Im doing and save resources.
//
if(iIdleTimeout--)
spawn(m_iTickSpeed)
MonsterTick(iIdleTimeout)
m_sStatus = "idle"; // Returning to idle state
In response to Colin1011
It looks like you just need to tab the players proc in. I was out all day so thanks to those who are helping with it.

player
{
if(src.male==1)
icon_state="Player_male"
if(src.female==1)
icon_state="Player_female"
New()
{
m_hp = 100;
m_iTickSpeed = 10;
PlayerTick()
..();
}
proc
{
PlayerTick()
{
//
// Are there any monsters near me?
//
for(var/mob/monster/m in view(8))
{
//
// If I'm idle, give me something to do
// otherwise, leave me alone, I'm already doing stuff
//
if (m.m_sStatus == "idle")
{
m.m_sStatus = "busy";
m.MonsterTick(); // Kick start monster into action
}
}
Spawn(m_iTickSpeed)
{
PlayerTick()
}
}
}
}
In response to Tsfreaks
Doesn't work, same errors. You guys can stop helping; this combat system isn't gonna work out.
In response to Colin1011
The "problem" is that your probably biting off more that you can chew right now. I recommend starting out with some simple games or examples instead of tackling the "dream" game right off the bat.

Take a feature you really want to see in your dream game and try to make it into a mini-game. It doesn't have to be release quality, just give yourself a little "How would I do this?" challenge...

Your monster system seems to be a good candidate. Here's your first challenge if you choose to participate.

Make me a demo (from scratch) that has monsters moving randomly around a 10x10 map. There must be at least one solid object (a rock) on the map which monsters cannot move into.

Art is not a factor. The letter 'M' moving around on the map will suffice.

Pass this challenge (I'll code review and provide a little feedback) and I'll give you another one if you desire.

ts
Hey Colin,

Your code looked like it should work, so I gave it a quick test. It indeed works, so I believe the reason your enemies aren't giving chase is not related to this block of code in particular. Here is the code I used to test:

world
maxx = 10
maxy = 10

mob/verb/test()
var
x = rand(1,10)
y = x
z = 1
new /mob/rat(locate(x,y,z))

// filler variables, to please the compiler
mob/var
hp = 10
xpgiven = 1
attackable = 1
maxhp = 10

// [the code you posted here]


You can try this out for yourself (create a new project and compile the code), and let me know if it works.

(As a side note, that's a cleverly arranged assortment of gotos you've got there. It's not a very good practice but props for making a functioning loop with them :) -- though it did give me a bit of a headache!)
In response to Toadfish
It works when I do it on a seperate project. Strange. Do you have any idea why that might be?
In response to Colin1011
As I said, that means the issue lies elsewhere. Look in other places for code that might affect the AI's behaviour. I would first look at things that affect a mob's movement in particular (movement delay, for example, if you have any).
In response to Toadfish
You were exactly right! Aha! There's a frozen var that I have to undo for players when they log in. Dude, thanks a bunch for this.
In response to Colin1011
Sure thing.