ID:109796
 
Keywords: ai, combat, enemy, tutorial
Next up, we're going to create some basic enemies for our game, and the AI that will drive them to murder us.
If you haven't already read Tutorial #7, you should check it out first. Or, start at the beginning, if you're new to the series!

Making the Enemies
Now to actually make these enemies! Finally...

Step 4.1 Create a new Code File named Enemies.dm

Step 4.2 Create the /Enemies type and some enemy mobs using the following code
mob/Enemies
Red_Guy
icon='EnemyRed.dmi'
Level=1
Exp=5
MaxHP=100
Str=10
Def=5
Green_Guy
icon='EnemyGreen.dmi'
Level=2
Exp=10
MaxHP=150
Str=11
Def=6
http://www.angelfire.com/hero/straygames/Tutorial/ EnemiesDM.png
This will create 2 enemies of the type /mob/Enemies, Red Guy and Green Guy, underscores will be converted to spaces in-game.
We set the icons on both of them, followed by setting up their basic stats.
These are the same stat variables that we setup for our Player way back in Tutorials #3 and #4
As mentioned before, we'll just be using our Exp variable to represent how much Exp killing them will reward.

Step 4.3 Now to start up the enemies and their AI
mob/Enemies/New()
src.HP=src.MaxHP
spawn(-1) src.CombatAI()
return ..()
New() is a proc that will automatically be called whenever something is created.
If the object is placed on the map, it will run when the game starts up. Otherwise, it will happen whenever you create a new object through the game's code, or load an object from a file.
You may have noticed that we didn't set the HP of our enemies, only their MaxHP. Instead of writing 2 lines with the same value for countless enemies, we'll just set it in New() for all of them.
spawn() is another built in proc. It will allow you to process multiple things without waiting for each to complete.
Passing -1 as the argument in spawn() will make sure the code still happens in order. This will help prevent runtime errors and timing issues.
spawning()ing off our CombatAI will prevent everything from locking up when a new enemy is created, since their CombatAI will run for as long as they exist.
Lastly, we return ..(), ..() represents the parent proc, we call this to perform any default actions, like setting a location.

Step 4.4 Its almost over! We just need to write some simple combat AI. This code also goes in Enemies.dm
mob/Enemies/proc/CombatAI()
while(src)
for(var/mob/Player/M in oview())
if(get_dist(src,M)<=1)
src.dir=get_dir(src,M)
src.Attack()
else
step_to(src,M)
break
sleep(rand(4,8))
First line creates another proc, only for /mob/Enemies, CombatAI(). This means Players, or other non-Enemy NPCs won't be able to access/use it.
while(src) will cause everything tabbed under it to repeat for as long as src exists.
The first thing we do in this while loop, is a for loop through all of the /Player types in oview() of the enemy.
If we find any /Players we take some action:
We'll check the distance to the target using the built in get_dist() proc.
If within 1 tile from the target Player (next to them):
The enemy will turn towards them using get_dir()
Then it will use the Attack() verb we created in the previous Tutorial.

If they weren't next to the Player: The enemy will walk towards them using the built in step_to() proc.
step_to() uses built in path finding, so the enemy will make its way around walls and such.

After doing one of these 2 actions, we use break to exit the for() loop. This will prevent the enemy from trying to hunt multiple Players at once.
Then, at the very end, we sleep() for a random amount of time between 4 and 8 ticks using rand().
Notice how this sleep() is tabbed into the while() level. If we didn't have a delay at the end of our while() loop, it would just run non-stop, and effectively freeze/crash the game.


That should get your basic battle system going, and your game into a truly playable state. Enemies can be placed on the map the same way turfs were, way back in the Creating a Map section of Tutorial #1

Contine to Tutorial #9: Interface & Macros
If you're going to break out of the loop after the first iteration, you might as well just use locate() instead, and save yourself some cycles.

However, I would suggest keeping the loop and instead utilizing it to locate the closest player. This way, the AI won't freak out and keep switching between targets on opposite sides of the room (since you aren't storing their target, any variation in the ordering of mobs in oview() will result in this)
locate() could work. Looping through them the way it does now will automatically pick the closest target, though. In some sort of bottom left to top right order, if there are multiple targets the same distance away. Target storing will most likely be implemented in a later version of the AI.
I'll be darned; I never knew oview() and the others were sorted like that. You learn something new every day.

Sorry to interrupt, then.
;)
This is completely opinion based, but i feel that making simple, clear comments saying what each piece of the code does, would cut down on how long your tutorials are. You're doing a fine job making them, this is just an opinion of mine.

If something needs to be explained more, then do it under the code.

Just to make it clear, I'm not too lazy to read it all.
That's a good idea
Culd you make tutorial obout monsters shoot a projectile, when they are facing the player, but not right in front of them?
this is my AI so far
    New()
..()

spawn while(src)
sleep(rand(15,18))
var/mob/target
target=locate(/mob/player) in oview(7,src)
if(target)
if(src.aggresive)
while(target in oview(7))
if(target.x == src.x&&target.y != src.y && target.y > src.y) step(src,NORTH)
else if(target.x == src.x&&target.y != src.y && target.y < src.y) step(src,SOUTH)
else if(target.x != src.x&&target.y == src.y && target.x < src.x) step(src,WEST)
else if(target.x != src.x&&target.y == src.y && target.x > src.x) step(src,EAST)
else if(target.x> src.x&&target.y > src.y)
switch(rand(1,2))
if(1) step(src,EAST)
if(2) step(src,NORTH)
else if(target.x < src.x && target.y < src.y)
switch(rand(1,2))
if(1) step(src,WEST)
if(2) step(src,SOUTH)
else if(target.x < src.x&&target.y > src.y)
switch(rand(1,2))
if(1) step(src,WEST)
if(2) step(src,NORTH)
else if(target.x > src.x && target.y < src.y)
switch(rand(1,2))
if(1) step(src,EAST)
if(2) step(src,SOUTH)
.....

Thanks.
If your goal is to prevent AI from walking diagonally, you would probably be better off using something like this:
mob/Enemies
Move(var/turf/NewTurf,var/StepDir) //Move() is built-in
switch(StepDir)
if(NORTHWEST) pick(step(src,NORTH),step(src,WEST))
if(NORTHEAST) pick(step(src,NORTH),step(src,EAST))
if(SOUTHWEST) pick(step(src,SOUTH),step(src,WEST))
if(SOUTHEAST) pick(step(src,SOUTH),step(src,EAST))
else return ..(NewTurf,StepDir)
Then, you can still use the the built in movement functions, like step_to(), normally.

            if(target)
if(src.aggresive)
while(target in oview(7))
Those could all be combined into the while()
while(src.aggressive && target && get_dist(src,Target)<=7)
Using get_dist(), instead of in oview(), will be more efficient.

You'll also need a sleep() for that 2nd while(). And sleep()s should generally be placed at the end of the loop, to prevent run-time errors.
Wow, this is a really cool set of tutorials. I am looking forward to part 9. I totally take back ever bad thing I have ever said about you. XD Just kidding. But seriously... Good job. I like the usage of pictures and information. It is rather similar to how Lummox JR makes his tutorials which is great because personally I think it is easier to learn this way.

My only suggestion would be to instead of making a link to the picture, just have the image show in the post using the img tags. It might make your blog look a little longer than it is. But it will definitely cut back on having to go through a bunch of windows. I also think it helps to make the presentation a little smoother.Just as a side note. Keep up the good work. :P
It'd be nice if there were some kind of spoiler tags. So you could click a link, have it extend to show the image (or whatever was inside the tags), and then click again to only show the link.
That would be a good idea. Perhaps that is something you should suggest in the feature tracker?
Your tutorials are really helpful! Though, this one is confusing me a little..They attack and do everything like that, but they're invisible until they attack..Did I do something wrong?
Yup, something icon/icon_state related
These are easier to understand then the one the people who work on the site give you, also faster. :)
I think I learn more in 3hours on this, then 4days on that.
amazing thx so much
Thanks so much
Annoying when I mess up. cant wait to tutorial 9. any idea when its coming out?
These tutorials are for the learning of DM language, not the rip your codes here so you can make a 1 map game.
When this is used, NPCs will attack eachother; usually something ought not to happen. To fix this, in the CombatAI() proc, after the for(...) part add in if(M.key==null) continue.
Page: 1 2