Long one (enemy spawning on map)

Ask and answer questions about making games and related topics. Unrelated topics go in that other forum.

Moderators: marionline, SDHawk

User avatar
guo
Metal Slime
Posts: 749
Joined: Fri Dec 04, 2009 9:12 pm

Long one (enemy spawning on map)

Post by guo »

Aloha, how are we all this evening?

I would like to have enemy npcs dynamically spawn just offscreen of the player, set to chase so that when they touch the player a battle is started.
The basic logic I would like to follow is:

Code: Select all

-When the battle counter is run down, it triggers an "instead of battle" script
-This script differs by formation zone (ie different enemies will be spawned by different formation zones)
-The script will first check around the player for intervening pass blocks & NPCs to find the best place to spawn an enemy.
    -In random order, checks NESW, and if no intervening blocks and the right distance away then the NPC is spawned
    -Tag set on that prevents other battles from being triggered
    -After a set period of time, enemy NPCs disappear, battle prevention tag disabled
I have a rough idea how to achieve this, but I would appreciate some help with a couple of steps - eg how to check for a suitable "spawn point".

Thanks in advance!
vvight.wordpress.com
User avatar
Pepsi Ranger
Liquid Metal Slime
Posts: 1457
Joined: Thu Nov 22, 2007 6:25 am
Location: South Florida

Post by Pepsi Ranger »

I'm sure TMC will chime in here with a better, more detailed explanation soon enough, but I think your first goal is to think about this from a preproduction standpoint rather than a scripted one. If you have locations that you don't want enemies spawning in, encase them in a forbidden zone. If an enemy spawns in a forbidden zone, trigger the script again.

If you have ideal zones that you do want to trigger the enemies in, consider "redrawing" the circle of zones that follows your hero, with Zone 1 being the circle of tiles under and immediately surrounding your hero (the battle trigger zone), Zone 2 being the zone that concentrically extends to near the edge of the screen and serves as a "continue chase," I can still smell you zone, Zone 3 being the zone within two or three tiles of the edge of the screen that times how long the enemy lingers there (affecting its chase behavior over time) and forces the enemy to abandon chase if it takes too long getting to Zone 2, and Zone 4 being the "spawn zone" where the enemy will appear. If the spawn tile within the spawn zone overlaps Zone 5, the forbidden zone, then the spawn should fail and the script should try again.

Regarding formations, Zones 6-infinity should correspond with designated fight formations and remain static throughout the map. Whichever zone the player is standing in when the chase is triggered should determine which enemy set comes after him.

One thing about redrawing zones, if you use this idea, and I contend that there's probably a better one, but this is what comes to mind at the moment, is that you have to remember to erase and redraw zones 1-4 with each step. Otherwise, you're going to end up with zones 1-4 overlapping all over the place. And in the case of spawn zones that happen over accepted terrain, but not for the triggered enemy type (example: spiders are triggered in the forest but spawn over a lake, which is valid for another enemy type, but not spiders), you may want to map out a series of zones that identify terrain types and use that as part of your pass/fail condition for spawning, or maybe have a backup formation set that's equally strong that can trigger in place of spiders (like deadly mosquitoes, for example).

Whatever you end up doing though, zones should probably be a factor. It's the easiest way to keep everything under control.
Place Obligatory Signature Here
User avatar
guo
Metal Slime
Posts: 749
Joined: Fri Dec 04, 2009 9:12 pm

Post by guo »

Omg Pepsi you have sent my mind spinning with possibilities now. This is going to be a bigger undertaking than I had originally envisioned earlier this evening!

I really like your ideas. As well as checking if the spawn tile overlaps zone 5 (forbidden zone) ,it would make sense to also check if there is already an NPC at that position. What would zone 1 be used for specifically?
I would also have a zone to define (eg) clifftops. Clifftop enemies only spawn when the player is in the clifftop zone, and the clifftop zone will be treated as a forbidden zone if the player is outside it.
vvight.wordpress.com
TMC
Metal King Slime
Posts: 4308
Joined: Sun Apr 10, 2011 9:19 am

Post by TMC »

What a coincidence, I just added a new script command (available in nightlies) that makes the wall checking you asked for trivial; check wall collision x/y.

For example, to pick a random direction and check that there are no walls between here and the screen edge...

Code: Select all

variable(xgo, ygo, attempt)
for (attempt, 1, 20) do(  # try 20 times
  switch(random(1, 8)) do(
    case(1)  xgo := 160
    case(2)  xgo := -160
    case(3)  ygo := 100
    case(4)  ygo := -100
    case(5)  xgo := 100, ygo := -100
    case(6)  xgo := 100, ygo := 100
    case(7)  xgo := -100, ygo := -100
    case(8)  xgo := -100, ygo := 100
  )
  if (check wall collision x(hero x * 20, hero y * 20, 20, 20, xgo, ygo) == xgo &&
      check wall collision y(hero x * 20, hero y * 20, 20, 20, xgo, ygo) == ygo) then (
    # no walls...  do the spawning here
    break  # break out of the for loop
  ) else (
    # try again
    continue
  )
)
This doesn't check whether there are any NPCs in the way. You would need to use a for-loop and "npc at spot" to check that. That's a simple script (ok, admittedly in this case "check wall collision x" could be replaced with an equally simple script, since you don't need any of the fancy hitbox checking it can do...)

To jump on the zones band-wagon, using zones in a completely different way to what Pepsi described, you can draw 4 zones on the map to describe those areas where it's safe to spawn an enemy to the north, to the west, etc. Basically precomputing what the above script checks. Of course I don't recommend this, as it's very labour intensive and error prone.

If you're already using formation sets to trigger the instead-of-battle script, then why not use it to select which enemies to spawn, rather than using zones? Of course...unfortunately you can't yet name formation sets or give them extra data, as you can zones.
Last edited by TMC on Wed Jan 25, 2017 11:38 am, edited 3 times in total.
User avatar
guo
Metal Slime
Posts: 749
Joined: Fri Dec 04, 2009 9:12 pm

Post by guo »

Right as things get interesting, I have to leave town for 3 nights! I'm going to be mulling this over in my brain every spare moment I have.
vvight.wordpress.com
User avatar
Pepsi Ranger
Liquid Metal Slime
Posts: 1457
Joined: Thu Nov 22, 2007 6:25 am
Location: South Florida

Post by Pepsi Ranger »

guo wrote:What would zone 1 be used for specifically?
It's basically your hero's "personal space." If the enemy gets inside Zone 1, things happen. You'd probably want to set a brief half-second timer (the number of ticks would depend on your frame rate) to indicate when the action happens (or battle) though, to allow the enemy to get well into the zone first. Otherwise, it'll look odd having it trigger a fight or other action almost a full tile away, which is what would happen if it triggers immediately upon entering the zone.

On a slightly separate front, I don't know if TMC ever finished his plans for zones (for example, there was talk once upon a time about triggering scripts on entering zones, but that never happened), but I think the idea of floating zones (i.e. zones that follow the hero or NPC without need for drawing, erasing, and redrawing) would be useful at some point.

If you guys want a refresher on using zones, here's a call back to my articles on HamsterSpeak, called "Zoned In":

http://superwalrusland.com/ohr/issue49/index.html - (Zoned In #1)

http://superwalrusland.com/ohr/issue54/index.html - (Zoned In #2)

Note: I never did write the third installment, as HamsterSpeak shut down the following year and zones never really evolved past the features written in those first two parts.
Place Obligatory Signature Here
TMC
Metal King Slime
Posts: 4308
Joined: Sun Apr 10, 2011 9:19 am

Post by TMC »

I haven't touched zones in a long while. Zone triggers will be something to add when I'm working on script multitasking. Certainly not necessary in any way, but that's when we were planning to add lots of new script triggers.
User avatar
guo
Metal Slime
Posts: 749
Joined: Fri Dec 04, 2009 9:12 pm

Post by guo »

Nice articles, Pepsi.
If that shoreline is scripted to produce a family of crabs whenever you get close, this command will know whether you’re standing in the zone (assuming you’ve marked the shoreline with the zone you’re looking for).
Prescient!
vvight.wordpress.com
User avatar
guo
Metal Slime
Posts: 749
Joined: Fri Dec 04, 2009 9:12 pm

Post by guo »

I have a day off today, so I can actually work on this. I'll be spilling stream of consciousness and "planning" stages here:

Several scripts will be required, named conveniently so that other scripts can call on them when required.
  • -battle counter hits zero, instead of battle script is triggered.
    -picks a random direction of 8, checks the zone at the screen edge in that direction, store x/y coordinates
    -if player is on lower ground and zone is on an "elevated area", pick another direction and try again
    -a zone is found! the zone detected by "read zone" command will determine the random table of encounters
    -draw a random number, spawn an npc from the encounter table at the x/y coordinates determined earlier.
    -enemy spawns with "chase you" bits, triggering a script that starts the battle if they touch you
    -while an enemy is chasing you, a tag will be on that prevents further battles from being triggered
    -an on step script, checks how far the enemy is from you. if they are a certain distance away from you, start a timer. at the end of that timer, if
    they are still the same distance or further from you, fade screen out, remove npc, end script.
Some other ideas:
  • Enemies could have zones that they avoid - eg a mudman won't follow you into shallow water (mudmen? really?)
    If the script can't find a suitable place to spawn an enemy, draw from a list of other encounters, like conversations or something.
    Use TMCs collision script to check for intervening terrain - I prefer the zone route atm, because with this method I've realised it could severely limit the amount of encounters based on objects in the world.
    Low % chance of enemies spawning at multiple directions (eg if north AND south are suitable spawn zones, spawn 2 creatures!)
    Sound effect that increases in volume the closer you are to a random battle
I'll be working at this today and post results later in the afternoon.
vvight.wordpress.com
User avatar
guo
Metal Slime
Posts: 749
Joined: Fri Dec 04, 2009 9:12 pm

Post by guo »

Rudimentary script banged out, to be run as an instead of battle script.

Code: Select all

plotscript, enemy spawner, begin

	variable (x_dir, y_dir, enemyzone, enemyspawn)

	for (attempt, 1, 20) do(  # try 20 times 

		switch(random(1, 8)) do( 
			case(1)  x_dir := 160 
			case(2)  x_dir := -160 
			case(3)  y_dir := 100 
			case(4)  y_dir := -100 
			case(5)  x_dir := 100, y_dir := -100 
			case(6)  x_dir := 100, y_dir := 100 
			case(7)  x_dir := -100, y_dir := -100 
			case(8)  x_dir := -100, y_dir := 100 
		) 

	enemyzone := zone at spot (x_dir, y_dir)
	
	if (enemyzone == 1) then(

		#grass list
		enemyspawn := random (3, 6)
		spawn battle npc (enemyspawn, x_dir, y_dir)
		break
		)
	else if (enemyzone == 2) then(

		#forest list
		enemyspawn := random (7, 9)
		spawn battle npc (enemyspawn, x_dir, y_dir)
		break
		)
	else if (enemyzone == 3) then(
		
		#beach list
		enemyspawn := random (10, 11)
		spawn battle npc (enemyspawn, x_dir, y_dir)
		break
		)

	else ( continue )
	)

end
No possible "enemyzones" will be placed on impassable tiles, so it kind of bundles up the collision check at the same time. A second (or third, or more) pair of eyes on this script would be much appreciated.

Regards.
Last edited by guo on Wed Feb 01, 2017 12:33 am, edited 1 time in total.
vvight.wordpress.com
TMC
Metal King Slime
Posts: 4308
Joined: Sun Apr 10, 2011 9:19 am

Post by TMC »

Sorry, I see there was a bug in the script I posted. You should put "x_dir := 0, y_dir := 0" before the switch, or just ensure that it always sets both x_dir and y_dir.

"zone at spot (x_dir, y_dir)" isn't going to work. You need to give it a coordinate in tiles on the map. x_dir and y_dir are in pixels, but you could write "zone at spot (hero x + x_dir/20, hero y + y_dir /20)"

So you're not going to check that there aren't any walls between the hero and the spawn point, you're just going to mark in the map editor those areas that are safe to spawn?
Last edited by TMC on Wed Feb 01, 2017 11:13 am, edited 2 times in total.
User avatar
guo
Metal Slime
Posts: 749
Joined: Fri Dec 04, 2009 9:12 pm

Post by guo »

Thanks TMC. Yea, I won't check walls atm - Could be a pain if there's say a solitary rock in an otherwise empty field that stops an enemy from spawning. That script is rudimentary, however. After testing, I'll see if it's not worth adding the wall check after all.
vvight.wordpress.com
User avatar
guo
Metal Slime
Posts: 749
Joined: Fri Dec 04, 2009 9:12 pm

Post by guo »

So you're not going to check that there aren't any walls between the hero and the spawn point, you're just going to mark in the map editor those areas that are safe to spawn?
Basically I'm going the zone route because it lets me control from which list of enemies to spawn. Eg, if the script checks randomly to the east and determines that the enemy will be spawned in the "forest zone" , then it can generate the NPC based on that particular list.

I have updated the script, slightly, with a placeholder fix for when there isn't a suitable spot to spawn :

Code: Select all


global variable (1, pursuer)

---

plotscript, chasetimer, begin

	set timer (0, 20, 18, @avoidedchase)
	#a timer that lasts 20 seconds, at the end of which the chasing NPC is removed and the timer stops

end
		
---

plotscript, avoidedchase, begin
	delete npc (pursuer)
	stop timer (0)
	set tag (tag: beingchased, 0)
	set battle countdown (random (80, 160)
end
	
---

plotscript, enemy spawner, begin

	variable (x_dir, y_dir, enemyzone, enemyspawn)
	x_dir := 0, y_dir := 0


	if (checktag ( tag: beingchased ) == 0) then (

		for (attempt, 1, 20) do(  # try 20 times 

			switch(random(1, 8)) do( 
				case(1)  x_dir := 8
				case(2)  x_dir := -8 
				case(3)  y_dir := 5 
				case(4)  y_dir := -5 
				case(5)  x_dir := 5, y_dir := -5 
				case(6)  x_dir := 5, y_dir := 5 
				case(7)  x_dir := -5, y_dir := -5 
				case(8)  x_dir := -5, y_dir := 5 
			) 
	
		enemyzone := zone at spot (x_dir, y_dir, 0)
	
		if (enemyzone == 1) then(
	
			#grass list
			set tag (tag: beingchased, 1)
			enemyspawn := random (3, 6)
			pursuer := create npc (enemyspawn, x_dir, y_dir)
			chasetimer
			break
			)
		else if (enemyzone == 2) then(
	
			#forest list
			set tag (tag: beingchased, 1)
			enemyspawn := random (7, 9)
			pursuer := create npc (enemyspawn, x_dir, y_dir)
			chasetimer
			break
			)
		else if (enemyzone == 3) then(
			
			#beach list
			set tag (tag: beingchased, 1)
			enemyspawn := random (10, 11)
			pursuer := create npc (enemyspawn, x_dir, y_dir)
			chasetimer
			break
			)
	
		else ( 
			set battle countdown (random (40, 80))
			continue 
			)

	)
	else (
		set battle countdown (random (40, 80) )
		break
	)
	
end
	
---

plotscript, sampleenemytouch, npcref, begin
	delete npc (npcref)
	stop timer (0)
	fight formation ( "z" )
	set tag (tag: beingchased, 0)
end

Sorry, I know it's a bit all over the place and probably full of errors. My mind is more "arts" than "sciences", and I don't really have the mindset for coding. Doing my best though, appreciating all the help thrown my way.
Last edited by guo on Thu Feb 02, 2017 1:25 am, edited 6 times in total.
vvight.wordpress.com
User avatar
guo
Metal Slime
Posts: 749
Joined: Fri Dec 04, 2009 9:12 pm

Post by guo »

hero X (who)
Returns the specified hero's X position in tiles. Note that a hero's tile is the tile its top left corner is on.
Does this take into account the foot offset?

Also, Could I use a switch such as:

Code: Select all

switch(hero x (me), hero y (me)) 
   do (
        case (134, 31) bla bla bla
        case (144, 38) bla bla yada
        case (else)   do nada
)
?

This script will be tied to an on-step NPC, which when triggered will make the player jump in a certain direction. Different direction, distance depending on the players x & y coordinates.

Regards!

edit: Can't have 2 expressions for switch commands. D'oh! Is there an easier way to do this that I'm missing?

edit2: Is there a way to do an "if... and" ?
Last edited by guo on Thu Feb 02, 2017 2:37 am, edited 3 times in total.
vvight.wordpress.com
User avatar
Foxley
Metal Slime
Posts: 832
Joined: Sat Nov 09, 2013 5:54 pm

Post by Foxley »

I think you could nest your switches. Or if you only had a few values to look for, you could do: "if (this && that) then ()"

EDIT: Let me actually turn my suggestion into something useful real quick...

Code: Select all

if (hero x(me) == 134 && hero y(me) == 31) then (bla bla bla)
elseif (hero x(me) == 144 && hero y(me) == 38) then (bla bla yada)
else (do nada)
Last edited by Foxley on Thu Feb 02, 2017 2:53 am, edited 1 time in total.
Post Reply