Help with boss script behavior

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

Moderators: marionline, SDHawk

Post Reply
User avatar
Foxley
Metal Slime
Posts: 832
Joined: Sat Nov 09, 2013 5:54 pm

Help with boss script behavior

Post by Foxley »

With the late deadline approaching for Willy's multicart thing, I'm just going to break down and ask people to help me script things I've been hesitant to even get started on. I know that I can figure out how to do these myself, but I'm running out of time and energy and don't want to delay the release.

For one of the bosses, I basically want the boss to have an attack pattern of:
-Appear at random spot in the room
-Open eye, shoot laser at hero (will be using my projectile script)
-Close eye
-Vanish
-Reappear someone else; repeat

The other boss will be this:
-Scroll back and forth at the top of the game area
-Create a ring of spinning objects around them, a la Leaf Shield from Megaman 2
-Shoot each object at the hero, rapidly and one at a time
-Have no 'shield' for a few seconds, then create another one; repeat

Any help would be appreciated.
User avatar
Bob the Hamster
Liquid Metal King Slime
Posts: 7460
Joined: Tue Oct 16, 2007 2:34 pm
Location: Hamster Republic (Ontario Enclave)
Contact:

Re: Help with boss script behavior

Post by Bob the Hamster »

Foxley wrote:For one of the bosses, I basically want the boss to have an attack pattern of:
-Appear at random spot in the room
-Open eye, shoot laser at hero (will be using my projectile script)
-Close eye
-Vanish
-Reappear someone else; repeat
Here, this might help!

I wrote the basic skeleton of this boss's behavior. You will have to customize the script slightly, especially the bits that animate the boss to open and close its eye, and the number of seconds to wait for each timer delay

Code: Select all

define constant(0, timer:boss) # A timer that you are not using for anything else
define constant(18, second) # this should be changed if you are not using the default frame-rate

global variable(0, boss) # change to an un-used variable
define constant(0, boss:npc id)

plotscript, eye laser boss:start, begin
  boss := npc reference(boss:npc id)
  # Any other initialization goes here
  eye laser boss:random position()
  set timer(timer:boss, 0, second * 2, @eye laser boss:open eye)
end

script, eye laser boss:open eye, begin
  # Animate the boss npc to open its eye
  set timer(timer:boss, 0, second / 2, @eye laser boss:shoot)
end

script, eye laser boss:shoot, begin
  # Trigger the actual laser projectile here
  set timer(timer:boss, 0, second / 2, @eye laser boss:close eye)
end

script, eye laser boss:close eye, begin
  # Animate the boss npc to close its eye
  set timer(timer:boss, 0, second * 2, @eye laser boss:vanish)
end

script, eye laser boss:vanish, begin
  # Move the boss off the current screen, or whatever
  set timer(timer:boss, 0, second * 3, @eye laser boss:reappear)
end

script, eye laser boss:reappear, begin
  eye laser boss:random position()
  set timer(timer:boss, 0, second * 1, @eye laser boss:open eye)
end

script, eye laser boss:random position, begin
  variable(dist)
  while(true) do(
    # Do this in a loop, so we can avoid random positions right on top of the hero
    set npc position(boss, random(1,14), random(1, 8))
    dist := abs(hero x(me) -- npc x(boss)) + abs(hero y(me) -- npc y(boss))
    if(dist >= 3) then(
      # We found a location that is okay, so break out of the while loop
      break
    )
  )
end
Last edited by Bob the Hamster on Wed Mar 15, 2017 12:54 am, edited 1 time in total.
User avatar
Foxley
Metal Slime
Posts: 832
Joined: Sat Nov 09, 2013 5:54 pm

Post by Foxley »

The timers and constants are making my head spin as I read this and try to make sense of it, but I'll try to make use of this. Thank you James!
User avatar
Bob the Hamster
Liquid Metal King Slime
Posts: 7460
Joined: Tue Oct 16, 2007 2:34 pm
Location: Hamster Republic (Ontario Enclave)
Contact:

Post by Bob the Hamster »

Opps! I just realized that all my "set timer" command were missing important @ symbols! I have edited my post to fix it

The set timer commands are just a way of saying, "run this other script in a few seconds"
User avatar
Foxley
Metal Slime
Posts: 832
Joined: Sat Nov 09, 2013 5:54 pm

Post by Foxley »

Unfortunately the timer approach isn't going to work, because it keeps running the timers even when the game is paused with the subscreen menu up. I think I need to figure out a way to use NPC and slice extras to make this guy work.
TMC
Metal King Slime
Posts: 4101
Joined: Sun Apr 10, 2011 9:19 am

Post by TMC »

This is fixable. Just stop all the relevant timers when the menu comes up, and resume them when it's closed, using "set timer(id)" with for loops over the timer ids. settimer preserves all timer settings that you don't specify, and stoptimer also preserves them, so they can be used to pause and resume.


Or, even easier, set the menu to suspend gameplay. That includes timers too.
User avatar
Bob the Hamster
Liquid Metal King Slime
Posts: 7460
Joined: Tue Oct 16, 2007 2:34 pm
Location: Hamster Republic (Ontario Enclave)
Contact:

Post by Bob the Hamster »

You can also do "suspend timers" and "resume timers" if you want ALL timers to be paused in your menu.

And in my original example, I forgot about what to do after the boss dies:

Code: Select all

script, eye laser boss:victory, begin
    stop timer(timer:boss)
end
User avatar
Foxley
Metal Slime
Posts: 832
Joined: Sat Nov 09, 2013 5:54 pm

Post by Foxley »

I am a mess. Obviously, timers can be paused and resumed. Just wasn't thinking straight.
TMC
Metal King Slime
Posts: 4101
Joined: Sun Apr 10, 2011 9:19 am

Post by TMC »

Haha, I wasn't thinking straight either: I forgot about suspend timers and resume timers.
User avatar
Foxley
Metal Slime
Posts: 832
Joined: Sat Nov 09, 2013 5:54 pm

Post by Foxley »

I did it!

Image


Next: damage calculations and needing to script the boss's weak point - take a wild guess what sort of weakness that's going to be, for a one-eyed boss monster in a Zelda clone.

Also I ended up writing my own script using not-timers but did use your organizational scheme for it, so thank you for giving me a head start James. Mine's admittedly a lot messier looking.

Code: Select all

script, idol start, begin
	variable (rand, ex, why)
	seed random
	rand := random (1, 6)

	for (why, (room y * 8) +2, (room y + 1) * 8 +1, 1) do (
		for (ex, room x * 16, (room x + 1) * 16 --1, 1) do (
			if (read zone (20+rand, ex, why)) then (set NPC position (8, ex, why))
		)
	)
	idol phase := 1
	set npc direction (8, up)
	set slice extra (get npc slice(8), extra 0, 30)
end

script, check idol, begin
	variable (counter)
	counter := get slice extra (get npc slice (8), extra 0)
	
	switch (idol phase) do (
		case (1) do (	## Flicker in/appear
			if (counter > 0) then (
				if (get slice visible (get npc slice(8))) then (
					set slice visible (get npc slice(8), false)
				) else (set slice visible (get npc slice(8), true))
				set slice extra (get npc slice(8), extra 0, counter --1)
			) else (
				set slice visible (get npc slice(8), true)
				set slice extra (get npc slice(8), extra 0, 30)
				set npc direction (8, right)
				increment (idol phase)
			)
		)
		case (2) do (	## Start to open eye
			if (counter > 0) then (
				set slice extra (get npc slice(8), extra 0, counter --1)
			) else (
				set slice extra (get npc slice(8), extra 0, 30)
				set npc direction (8, down)
				idol shots := create ellipse (11, 11, 6, 41)
				set parent (idol shots, get npc slice(8))
				set slice x (idol shots, 5)
				set slice y (idol shots, -10)
				increment (idol phase)
			)
		)
		case (3) do ( 	## Eye open, charge laser
			if (counter > 0) then (
				if (get slice visible (idol shots)) then (
					set slice visible (idol shots, false)
				) else (set slice visible (idol shots, true))
				set slice extra (get npc slice(8), extra 0, counter --1)
			) else (		## Shoot charged laser
				set slice extra (get npc slice(8), extra 0, 50)
				shoot projectile (npc reference(8), idol shots, 12)
				play sound (0)
				increment (idol phase)
			)
		)
		case (4) do (		## Shot laser, waiting
			if (counter > 0) then (
				set slice extra (get npc slice(8), extra 0, counter --1)
			) else (	## Start closing eye
				set slice extra (get npc slice(8), extra 0, 30)
				set npc direction (8, right)
				increment (idol phase)
			)
		)
		case (5) do (		## Eye closing
			if (counter > 0) then (
				set slice extra (get npc slice(8), extra 0, counter --1)
			) else (		## Start vanishing
				set slice extra (get npc slice(8), extra 0, 30)
				set npc direction (8, up)
				increment (idol phase)
			)
		)
		case (6) do (		## Vanishing
			if (counter > 0) then (
				if (get slice visible (get npc slice(8))) then (
					set slice visible (get npc slice(8), false)
				) else (set slice visible (get npc slice(8), true))
				set slice extra (get npc slice(8), extra 0, counter --1)
			) else (		## Vanish; initiate pause before reappearance
				set slice extra (get npc slice(8), extra 0, 80)	#Longer pause!
				set slice visible (get npc slice(8), false)
				increment (idol phase)
			)
		)
		case (7) do (		## Boss gone, waiting to reappear
			if (counter > 0) then (
				set slice extra (get npc slice(8), extra 0, counter --1)
			) else (		## Reset the boss
				if (idol shots) then (
					free slice (idol shots)
					idol shots := 0
				)
				idol start
			)
		)
	)
end
TMC
Metal King Slime
Posts: 4101
Joined: Sun Apr 10, 2011 9:19 am

Post by TMC »

Great; actually, a state machine is a great solution, I would probably prefer that to using timers.

The boss looks like it acts really slowly, but could still be a challenge because its projectile is so fast. I suggest reducing the amount of down-time a little bit, and making the project shoot from the eye rather than the center? Are you going to add more to the boss behaviour, like a random amount of time before appearing, disappearing, or shooting? That could make it more interesting for cheap.
Post Reply