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
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 ..()
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))
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
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)